veloria-ui 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +206 -0
- package/LICENSE +21 -0
- package/README.md +253 -0
- package/dist/cli/index.js +511 -0
- package/dist/index.d.mts +1317 -0
- package/dist/index.d.ts +1317 -0
- package/dist/index.js +5373 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +5130 -0
- package/dist/index.mjs.map +1 -0
- package/dist/provider.d.mts +15 -0
- package/dist/provider.d.ts +15 -0
- package/dist/provider.js +1197 -0
- package/dist/provider.js.map +1 -0
- package/dist/provider.mjs +1161 -0
- package/dist/provider.mjs.map +1 -0
- package/dist/tailwind.d.ts +25 -0
- package/dist/tailwind.js +129 -0
- package/package.json +138 -0
- package/src/cli/index.ts +303 -0
- package/src/cli/registry.ts +139 -0
- package/src/components/advanced-forms/index.tsx +975 -0
- package/src/components/basic/Button.tsx +135 -0
- package/src/components/basic/IconButton.tsx +69 -0
- package/src/components/basic/index.tsx +446 -0
- package/src/components/data-display/index.tsx +1158 -0
- package/src/components/feedback/index.tsx +1051 -0
- package/src/components/forms/index.tsx +476 -0
- package/src/components/layout/index.tsx +296 -0
- package/src/components/media/index.tsx +437 -0
- package/src/components/navigation/index.tsx +484 -0
- package/src/components/overlay/index.tsx +473 -0
- package/src/components/utility/index.tsx +566 -0
- package/src/hooks/index.ts +602 -0
- package/src/hooks/use-toast.tsx +74 -0
- package/src/index.ts +396 -0
- package/src/provider.tsx +54 -0
- package/src/styles/atlas.css +252 -0
- package/src/tailwind.ts +124 -0
- package/src/types/index.ts +95 -0
- package/src/utils/cn.ts +66 -0
package/src/cli/index.ts
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* veloria-ui CLI
|
|
5
|
+
*
|
|
6
|
+
* Copies Veloria UI components into your project so you own the code.
|
|
7
|
+
* Works exactly like shadcn/ui's CLI — pick what you want, paste it in.
|
|
8
|
+
*
|
|
9
|
+
* By JohnDev19 — https://github.com/JohnDev19/Veloria-UI
|
|
10
|
+
* Docs: https://veloria-ui.vercel.app/
|
|
11
|
+
*
|
|
12
|
+
* Commands:
|
|
13
|
+
* veloria-ui init — project setup wizard
|
|
14
|
+
* veloria-ui add button card modal — copy components into your project
|
|
15
|
+
* veloria-ui list — browse all 102 components
|
|
16
|
+
* veloria-ui list --category forms — filter by category
|
|
17
|
+
* veloria-ui diff button — compare local vs latest
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import path from "path";
|
|
21
|
+
import { Command } from "commander";
|
|
22
|
+
import chalk from "chalk";
|
|
23
|
+
import ora from "ora";
|
|
24
|
+
import prompts from "prompts";
|
|
25
|
+
import fs from "fs-extra";
|
|
26
|
+
import { execa } from "execa";
|
|
27
|
+
import { REGISTRY, COMPONENTS_BY_NAME, CATEGORIES, type Category } from "./registry";
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
29
|
+
const PKG_VERSION: string = (require("../../package.json") as { version: string }).version;
|
|
30
|
+
|
|
31
|
+
// ─── Banner ───────────────────────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
const banner = `
|
|
34
|
+
${chalk.bold.blue(" ╦ ╦╔═╗╦ ╔═╗╦═╗╦╔═╗")}
|
|
35
|
+
${chalk.bold.blue(" ╚╗╔╝║╣ ║ ║ ║╠╦╝║╠═╣")}
|
|
36
|
+
${chalk.bold.blue(" ╚╝ ╚═╝╩═╝╚═╝╩╚═╩╩ ╩")}
|
|
37
|
+
${chalk.dim("Build anything. Ship faster.")}
|
|
38
|
+
${chalk.dim("by JohnDev19 · https://github.com/JohnDev19/Veloria-UI")}
|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
// ─── Program ──────────────────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
const program = new Command();
|
|
44
|
+
|
|
45
|
+
program
|
|
46
|
+
.name("veloria-ui")
|
|
47
|
+
.description("veloria-ui CLI — copy components into your project")
|
|
48
|
+
.version(PKG_VERSION, "-v, --version")
|
|
49
|
+
.addHelpText("before", banner);
|
|
50
|
+
|
|
51
|
+
// ─── init ─────────────────────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
program
|
|
54
|
+
.command("init")
|
|
55
|
+
.description("Set up veloria-ui in your project")
|
|
56
|
+
.option("--typescript", "Use TypeScript", true)
|
|
57
|
+
.option("--tailwind", "Configure Tailwind", true)
|
|
58
|
+
.option("--no-install", "Skip dependency install")
|
|
59
|
+
.option("-y, --yes", "Skip all prompts, use defaults")
|
|
60
|
+
.action(async (opts) => {
|
|
61
|
+
console.log(chalk.bold.blue("\n Veloria UI Init\n") + chalk.dim(" Let's get you set up…\n"));
|
|
62
|
+
|
|
63
|
+
const cwd = process.cwd();
|
|
64
|
+
const pkgPath = path.join(cwd, "package.json");
|
|
65
|
+
|
|
66
|
+
if (!fs.existsSync(pkgPath)) {
|
|
67
|
+
console.error(chalk.red("\n No package.json found. Run from your project root.\n"));
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const pkg = fs.readJsonSync(pkgPath) as Record<string, unknown>;
|
|
72
|
+
const isNext = !!((pkg.dependencies as Record<string, string>)?.next ||
|
|
73
|
+
(pkg.devDependencies as Record<string, string>)?.next);
|
|
74
|
+
|
|
75
|
+
const answers = opts.yes
|
|
76
|
+
? { componentsDir: "components/ui", cssPath: isNext ? "app/globals.css" : "src/index.css", pm: detectPM(cwd) }
|
|
77
|
+
: await prompts([
|
|
78
|
+
{ type: "text", name: "componentsDir", message: "Where should components go?", initial: "components/ui" },
|
|
79
|
+
{ type: "text", name: "cssPath", message: "Path to your global CSS file?", initial: isNext ? "app/globals.css" : "src/index.css" },
|
|
80
|
+
{ type: "select", name: "pm", message: "Package manager?",
|
|
81
|
+
choices: [{ title: "npm", value: "npm" }, { title: "pnpm", value: "pnpm" },
|
|
82
|
+
{ title: "yarn", value: "yarn" }, { title: "bun", value: "bun" }] },
|
|
83
|
+
]);
|
|
84
|
+
|
|
85
|
+
if (!answers.componentsDir) return;
|
|
86
|
+
|
|
87
|
+
// Write atlas.config.json
|
|
88
|
+
fs.writeJsonSync(path.join(cwd, "atlas.config.json"), {
|
|
89
|
+
$schema: "https://veloria-ui.vercel.app/schema.json",
|
|
90
|
+
style: "default",
|
|
91
|
+
typescript: opts.typescript ?? true,
|
|
92
|
+
tailwind: { config: "tailwind.config.ts", css: answers.cssPath, baseColor: "slate", cssVariables: true },
|
|
93
|
+
aliases: { components: `@/${answers.componentsDir}`, utils: "@/lib/utils" },
|
|
94
|
+
}, { spaces: 2 });
|
|
95
|
+
console.log(chalk.green(" ✓ Created atlas.config.json"));
|
|
96
|
+
|
|
97
|
+
// Write lib/utils.ts if missing
|
|
98
|
+
const utilsPath = path.join(cwd, "lib", "utils.ts");
|
|
99
|
+
if (!fs.existsSync(utilsPath)) {
|
|
100
|
+
await fs.ensureDir(path.dirname(utilsPath));
|
|
101
|
+
await fs.writeFile(utilsPath,
|
|
102
|
+
`import { type ClassValue, clsx } from "clsx";\nimport { twMerge } from "tailwind-merge";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n`
|
|
103
|
+
);
|
|
104
|
+
console.log(chalk.green(" ✓ Created lib/utils.ts"));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Install core deps
|
|
108
|
+
if (opts.install !== false) {
|
|
109
|
+
const pm = answers.pm as string;
|
|
110
|
+
const spinner = ora(`Installing core deps with ${pm}…`).start();
|
|
111
|
+
try {
|
|
112
|
+
const deps = ["clsx", "tailwind-merge", "class-variance-authority", "@radix-ui/react-slot"];
|
|
113
|
+
const cmd = pm === "pnpm" ? ["pnpm", "add", ...deps]
|
|
114
|
+
: pm === "bun" ? ["bun", "add", ...deps]
|
|
115
|
+
: pm === "yarn" ? ["yarn", "add", ...deps]
|
|
116
|
+
: ["npm", "install", ...deps];
|
|
117
|
+
await execa(cmd[0], cmd.slice(1), { cwd });
|
|
118
|
+
spinner.succeed(chalk.green("Core deps installed"));
|
|
119
|
+
} catch {
|
|
120
|
+
spinner.warn(chalk.yellow("Auto-install failed — run manually:"));
|
|
121
|
+
console.log(chalk.dim(" npm install clsx tailwind-merge class-variance-authority @radix-ui/react-slot\n"));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
console.log(`
|
|
126
|
+
${chalk.bold.green(" Veloria UI is ready!")}
|
|
127
|
+
|
|
128
|
+
${chalk.dim("Next steps:")}
|
|
129
|
+
${chalk.cyan("1.")} Add components: ${chalk.bold("npx veloria-ui add button card modal")}
|
|
130
|
+
${chalk.cyan("2.")} Browse all: ${chalk.bold("npx veloria-ui list")}
|
|
131
|
+
${chalk.cyan("3.")} Docs: ${chalk.bold("https://veloria-ui.vercel.app/")}
|
|
132
|
+
${chalk.cyan("4.")} Issues: ${chalk.bold("https://github.com/JohnDev19/Veloria-UI/issues")}
|
|
133
|
+
`);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// ─── add ──────────────────────────────────────────────────────────────────
|
|
137
|
+
|
|
138
|
+
program
|
|
139
|
+
.command("add [components...]")
|
|
140
|
+
.alias("a")
|
|
141
|
+
.description("Copy one or more components into your project")
|
|
142
|
+
.option("-d, --dir <path>", "Output directory", "components/ui")
|
|
143
|
+
.option("--overwrite", "Replace existing files")
|
|
144
|
+
.option("--no-install", "Skip npm dep install")
|
|
145
|
+
.action(async (components: string[], opts) => {
|
|
146
|
+
const cwd = process.cwd();
|
|
147
|
+
|
|
148
|
+
if (!components?.length) {
|
|
149
|
+
console.log(chalk.red("\n Specify at least one component.\n"));
|
|
150
|
+
console.log(` ${chalk.dim("Example:")} ${chalk.cyan("npx veloria-ui add button card modal\n")}`);
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Resolve components + their veloria-ui registry deps
|
|
155
|
+
const toAdd = new Set<string>();
|
|
156
|
+
function resolve(name: string) {
|
|
157
|
+
const key = name.toLowerCase().replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
158
|
+
const meta = COMPONENTS_BY_NAME.get(key) || COMPONENTS_BY_NAME.get(name);
|
|
159
|
+
if (!meta) {
|
|
160
|
+
console.error(chalk.red(`\n "${name}" not found in the registry.\n`));
|
|
161
|
+
console.log(` Run ${chalk.cyan("npx veloria-ui list")} to see what's available.\n`);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
toAdd.add(meta.name);
|
|
165
|
+
meta.registryDeps?.forEach(resolve);
|
|
166
|
+
}
|
|
167
|
+
components.forEach(resolve);
|
|
168
|
+
if (!toAdd.size) return;
|
|
169
|
+
|
|
170
|
+
const configPath = path.join(cwd, "atlas.config.json");
|
|
171
|
+
const config = fs.existsSync(configPath)
|
|
172
|
+
? fs.readJsonSync(configPath) as { aliases?: { components?: string } }
|
|
173
|
+
: null;
|
|
174
|
+
const aliasDir = config?.aliases?.components?.replace(/^@\//, "");
|
|
175
|
+
const targetDir = path.join(cwd, opts.dir ?? aliasDir ?? "components/ui");
|
|
176
|
+
|
|
177
|
+
console.log(chalk.bold.blue("\n Veloria UI Add\n") + chalk.dim(` Adding: ${[...toAdd].join(", ")}\n`));
|
|
178
|
+
|
|
179
|
+
const allDeps = new Set<string>();
|
|
180
|
+
for (const name of toAdd) COMPONENTS_BY_NAME.get(name)!.deps.forEach((d) => allDeps.add(d));
|
|
181
|
+
|
|
182
|
+
// Write component stubs
|
|
183
|
+
for (const name of toAdd) {
|
|
184
|
+
const spinner = ora(`Adding ${chalk.bold(name)}`).start();
|
|
185
|
+
const pascal = name.split("-").map((p) => p[0].toUpperCase() + p.slice(1)).join("");
|
|
186
|
+
const dir = path.join(targetDir, name);
|
|
187
|
+
await fs.ensureDir(dir);
|
|
188
|
+
const file = path.join(dir, "index.tsx");
|
|
189
|
+
|
|
190
|
+
if (fs.existsSync(file) && !opts.overwrite) {
|
|
191
|
+
spinner.warn(chalk.yellow(`${name} already exists (--overwrite to replace)`));
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
await fs.writeFile(file,
|
|
196
|
+
`/**
|
|
197
|
+
* Veloria UI — ${pascal}
|
|
198
|
+
*
|
|
199
|
+
* Added by the veloria-ui CLI. This file is yours — edit it however you want.
|
|
200
|
+
* Re-export from veloria-ui to stay in sync, or paste the full source here
|
|
201
|
+
* to customise the internals.
|
|
202
|
+
*
|
|
203
|
+
* Docs: https://veloria-ui.vercel.app/components/${name}
|
|
204
|
+
* Source: https://github.com/JohnDev19/Veloria-UI
|
|
205
|
+
*/
|
|
206
|
+
|
|
207
|
+
export { ${pascal} } from "veloria-ui";
|
|
208
|
+
export type { ${pascal}Props } from "veloria-ui";
|
|
209
|
+
`);
|
|
210
|
+
spinner.succeed(chalk.green(`${name} → ${path.relative(cwd, file)}`));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Install npm deps
|
|
214
|
+
if (opts.install !== false && allDeps.size > 0) {
|
|
215
|
+
const pm = detectPM(cwd);
|
|
216
|
+
const spinner = ora(`Installing ${allDeps.size} package(s)…`).start();
|
|
217
|
+
try {
|
|
218
|
+
const deps = [...allDeps];
|
|
219
|
+
const cmd = pm === "pnpm" ? ["pnpm", "add", ...deps]
|
|
220
|
+
: pm === "bun" ? ["bun", "add", ...deps]
|
|
221
|
+
: pm === "yarn" ? ["yarn", "add", ...deps]
|
|
222
|
+
: ["npm", "install", ...deps];
|
|
223
|
+
await execa(cmd[0], cmd.slice(1), { cwd });
|
|
224
|
+
spinner.succeed(chalk.green(`Installed: ${deps.join(", ")}`));
|
|
225
|
+
} catch {
|
|
226
|
+
spinner.warn(chalk.yellow("Auto-install failed — run manually:"));
|
|
227
|
+
console.log(chalk.dim(` npm install ${[...allDeps].join(" ")}\n`));
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const exNames = [...toAdd].map((n) => n.split("-").map((p) => p[0].toUpperCase() + p.slice(1)).join("")).join(", ");
|
|
232
|
+
console.log(`\n${chalk.bold.green(" Done!")} ${path.relative(cwd, targetDir)}\n\n ${chalk.cyan(`import { ${exNames} } from "@/components/ui/${[...toAdd][0]}"`)}\n`);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// ─── list ─────────────────────────────────────────────────────────────────
|
|
236
|
+
|
|
237
|
+
program
|
|
238
|
+
.command("list")
|
|
239
|
+
.alias("ls")
|
|
240
|
+
.description("List all available components")
|
|
241
|
+
.option("-c, --category <category>", "Filter by category")
|
|
242
|
+
.action((opts) => {
|
|
243
|
+
const filterCat = opts.category?.toLowerCase() as Category | undefined;
|
|
244
|
+
console.log(chalk.bold.blue("\n veloria-ui Components\n"));
|
|
245
|
+
|
|
246
|
+
const cats = filterCat ? [filterCat] : CATEGORIES;
|
|
247
|
+
for (const cat of cats) {
|
|
248
|
+
const items = REGISTRY.filter((c) => c.category === cat);
|
|
249
|
+
if (!items.length) continue;
|
|
250
|
+
const label = cat.replace("-", " ").replace(/^\w/, (c) => c.toUpperCase());
|
|
251
|
+
console.log(chalk.bold(` ${label} (${items.length})`));
|
|
252
|
+
for (const c of items) {
|
|
253
|
+
console.log(` ${chalk.cyan(c.name.padEnd(22))} ${chalk.dim(c.description)}`);
|
|
254
|
+
}
|
|
255
|
+
console.log();
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
console.log(chalk.dim(` ${REGISTRY.length} components total\n`) +
|
|
259
|
+
chalk.dim(" Add one: ") + chalk.cyan("npx veloria-ui add <name>\n"));
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// ─── diff ─────────────────────────────────────────────────────────────────
|
|
263
|
+
|
|
264
|
+
program
|
|
265
|
+
.command("diff [component]")
|
|
266
|
+
.description("Compare your local copy to the latest version")
|
|
267
|
+
.action((component?: string) => {
|
|
268
|
+
if (!component) {
|
|
269
|
+
console.log(chalk.dim("\n Usage: npx veloria-ui diff <component>\n"));
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
console.log(chalk.bold.blue(`\n diff: ${component}\n`) +
|
|
273
|
+
chalk.dim(" Comparing local copy to latest in the veloria-ui registry…\n"));
|
|
274
|
+
// Full diff requires fetching from the registry — tracked here:
|
|
275
|
+
// https://github.com/JohnDev19/Veloria-UI/issues
|
|
276
|
+
console.log(chalk.yellow(" ⚠ Registry diff isn't wired up yet."));
|
|
277
|
+
console.log(chalk.dim(` Check the latest source at:\n`) +
|
|
278
|
+
chalk.cyan(` https://github.com/JohnDev19/Veloria-UI/tree/main/src/components\n`));
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// ─── Error handling ───────────────────────────────────────────────────────
|
|
282
|
+
|
|
283
|
+
program.on("command:*", (operands) => {
|
|
284
|
+
console.error(chalk.red(`\n Unknown command: "${operands[0]}"\n`));
|
|
285
|
+
program.help();
|
|
286
|
+
process.exit(1);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
program.parse(process.argv);
|
|
290
|
+
|
|
291
|
+
if (!process.argv.slice(2).length) {
|
|
292
|
+
console.log(banner);
|
|
293
|
+
program.help();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────
|
|
297
|
+
|
|
298
|
+
function detectPM(cwd: string): string {
|
|
299
|
+
if (fs.existsSync(path.join(cwd, "bun.lockb"))) return "bun";
|
|
300
|
+
if (fs.existsSync(path.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
301
|
+
if (fs.existsSync(path.join(cwd, "yarn.lock"))) return "yarn";
|
|
302
|
+
return "npm";
|
|
303
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Veloria UI component registry.
|
|
3
|
+
*
|
|
4
|
+
* Every component lives here: name, category, description, and the npm deps
|
|
5
|
+
* it needs. The `add` command reads this to know what to install.
|
|
6
|
+
*
|
|
7
|
+
* — JohnDev19
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export interface ComponentMeta {
|
|
11
|
+
name: string;
|
|
12
|
+
category: Category;
|
|
13
|
+
description: string;
|
|
14
|
+
deps: string[];
|
|
15
|
+
/** Other veloria-ui components this one depends on */
|
|
16
|
+
registryDeps?: string[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type Category =
|
|
20
|
+
| "basic"
|
|
21
|
+
| "layout"
|
|
22
|
+
| "navigation"
|
|
23
|
+
| "forms"
|
|
24
|
+
| "advanced-forms"
|
|
25
|
+
| "data-display"
|
|
26
|
+
| "feedback"
|
|
27
|
+
| "overlay"
|
|
28
|
+
| "media"
|
|
29
|
+
| "utility";
|
|
30
|
+
|
|
31
|
+
export const REGISTRY: ComponentMeta[] = [
|
|
32
|
+
// Basic
|
|
33
|
+
{ name: "button", category: "basic", description: "Solid, outline, ghost, soft, link, danger variants. Loading state, icon slots.", deps: ["@radix-ui/react-slot", "class-variance-authority", "clsx", "tailwind-merge"] },
|
|
34
|
+
{ name: "icon-button", category: "basic", description: "Square or circular icon-only button.", deps: ["@radix-ui/react-slot", "class-variance-authority", "clsx", "tailwind-merge"] },
|
|
35
|
+
{ name: "link", category: "basic", description: "Anchor with external link indicator and underline control.", deps: ["@radix-ui/react-slot"] },
|
|
36
|
+
{ name: "badge", category: "basic", description: "Compact label — 5 color variants, optional dot.", deps: ["class-variance-authority", "clsx", "tailwind-merge"] },
|
|
37
|
+
{ name: "avatar", category: "basic", description: "Image with fallback initials, status ring, 6 sizes.", deps: ["@radix-ui/react-avatar"] },
|
|
38
|
+
{ name: "avatar-group", category: "basic", description: "Stacked avatars with overflow count.", deps: ["@radix-ui/react-avatar"], registryDeps: ["avatar"] },
|
|
39
|
+
{ name: "divider", category: "basic", description: "Horizontal/vertical separator with optional center label.", deps: ["@radix-ui/react-separator"] },
|
|
40
|
+
{ name: "tag", category: "basic", description: "Closable colored tag with icon slot.", deps: [] },
|
|
41
|
+
{ name: "chip", category: "basic", description: "Toggleable chip with avatar/icon and remove button.", deps: [] },
|
|
42
|
+
{ name: "tooltip", category: "basic", description: "Radix tooltip, all four sides, configurable delay.", deps: ["@radix-ui/react-tooltip"] },
|
|
43
|
+
// Layout
|
|
44
|
+
{ name: "container", category: "layout", description: "Responsive max-width wrapper with padding control.", deps: [] },
|
|
45
|
+
{ name: "stack", category: "layout", description: "Flex column/row with gap, align, justify, divider.", deps: [] },
|
|
46
|
+
{ name: "grid", category: "layout", description: "CSS Grid with column/row/gap config.", deps: [] },
|
|
47
|
+
{ name: "flex", category: "layout", description: "Flex with full directional control.", deps: [] },
|
|
48
|
+
{ name: "section", category: "layout", description: "Semantic section with vertical padding presets.", deps: [] },
|
|
49
|
+
{ name: "spacer", category: "layout", description: "Invisible spacing element.", deps: [] },
|
|
50
|
+
{ name: "aspect-ratio", category: "layout", description: "Radix aspect-ratio container.", deps: ["@radix-ui/react-aspect-ratio"] },
|
|
51
|
+
{ name: "center", category: "layout", description: "Flex centering helper.", deps: [] },
|
|
52
|
+
{ name: "scroll-area", category: "layout", description: "Custom scrollbar via Radix ScrollArea.", deps: ["@radix-ui/react-scroll-area"] },
|
|
53
|
+
{ name: "masonry", category: "layout", description: "CSS multi-column masonry grid.", deps: [] },
|
|
54
|
+
// Navigation
|
|
55
|
+
{ name: "navbar", category: "navigation", description: "Sticky, glass-blur top bar.", deps: [] },
|
|
56
|
+
{ name: "sidebar", category: "navigation", description: "Collapsible side nav with width transition.", deps: [] },
|
|
57
|
+
{ name: "menu", category: "navigation", description: "Vertical nav menu with active/disabled states.", deps: [] },
|
|
58
|
+
{ name: "dropdown-menu", category: "navigation", description: "Full Radix Dropdown with all sub-primitives.", deps: ["@radix-ui/react-dropdown-menu"] },
|
|
59
|
+
{ name: "breadcrumb", category: "navigation", description: "Accessible trail with custom separator.", deps: [] },
|
|
60
|
+
{ name: "pagination", category: "navigation", description: "Page numbers with ellipsis and prev/next.", deps: [] },
|
|
61
|
+
{ name: "tabs", category: "navigation", description: "Line, pills, enclosed variants. Radix powered.", deps: ["@radix-ui/react-tabs"] },
|
|
62
|
+
{ name: "command-palette",category: "navigation", description: "⌘K command palette.", deps: ["cmdk", "@radix-ui/react-dialog"], registryDeps: ["command-dialog"] },
|
|
63
|
+
{ name: "navigation-menu",category: "navigation", description: "Radix Navigation Menu for complex navbars.", deps: ["@radix-ui/react-navigation-menu"] },
|
|
64
|
+
{ name: "stepper", category: "navigation", description: "Horizontal/vertical multi-step indicator.", deps: [] },
|
|
65
|
+
// Forms
|
|
66
|
+
{ name: "input", category: "forms", description: "Left/right icon slots, sizes, error state.", deps: ["class-variance-authority"] },
|
|
67
|
+
{ name: "textarea", category: "forms", description: "Multi-line input with resize control.", deps: [] },
|
|
68
|
+
{ name: "select", category: "forms", description: "Full Radix Select with all sub-primitives.", deps: ["@radix-ui/react-select"] },
|
|
69
|
+
{ name: "checkbox", category: "forms", description: "With label, description, error state.", deps: ["@radix-ui/react-checkbox"] },
|
|
70
|
+
{ name: "radio-group", category: "forms", description: "Per-option labels and descriptions.", deps: ["@radix-ui/react-radio-group"] },
|
|
71
|
+
{ name: "switch", category: "forms", description: "Three sizes, label, description.", deps: ["@radix-ui/react-switch"] },
|
|
72
|
+
{ name: "slider", category: "forms", description: "Single-thumb range slider.", deps: ["@radix-ui/react-slider"] },
|
|
73
|
+
{ name: "range-slider", category: "forms", description: "Dual-thumb slider.", deps: ["@radix-ui/react-slider"], registryDeps: ["slider"] },
|
|
74
|
+
{ name: "date-picker", category: "forms", description: "Native date input wrapper.", deps: [] },
|
|
75
|
+
{ name: "time-picker", category: "forms", description: "Native time input wrapper.", deps: [] },
|
|
76
|
+
// Advanced Forms
|
|
77
|
+
{ name: "file-upload", category: "advanced-forms", description: "Drag-and-drop zone with click-to-upload fallback.", deps: [] },
|
|
78
|
+
{ name: "otp-input", category: "advanced-forms", description: "PIN/OTP with auto-advance and paste support.", deps: [] },
|
|
79
|
+
{ name: "color-picker", category: "advanced-forms", description: "Swatches + hex input.", deps: [] },
|
|
80
|
+
{ name: "search-input", category: "advanced-forms", description: "Search with loading state and clear button.", deps: [] },
|
|
81
|
+
{ name: "password-input", category: "advanced-forms", description: "Password with show/hide toggle.", deps: [] },
|
|
82
|
+
{ name: "combobox", category: "advanced-forms", description: "Searchable single-value select.", deps: [] },
|
|
83
|
+
{ name: "multi-select", category: "advanced-forms", description: "Multi-value select with chips.", deps: [] },
|
|
84
|
+
{ name: "form-field", category: "advanced-forms", description: "Form field wrapper with spacing.", deps: [] },
|
|
85
|
+
{ name: "form-label", category: "advanced-forms", description: "Label with required/optional indicators.", deps: [] },
|
|
86
|
+
{ name: "form-error", category: "advanced-forms", description: "Accessible error message.", deps: [] },
|
|
87
|
+
// Data Display
|
|
88
|
+
{ name: "card", category: "data-display", description: "Surface with header/content/footer slots. 5 variants.", deps: [] },
|
|
89
|
+
{ name: "table", category: "data-display", description: "Full HTML table system.", deps: [] },
|
|
90
|
+
{ name: "data-table", category: "data-display", description: "Sortable data table with loading and empty states.", deps: [] },
|
|
91
|
+
{ name: "list", category: "data-display", description: "Simple, bordered, and divided lists.", deps: [] },
|
|
92
|
+
{ name: "list-item", category: "data-display", description: "List item with icon and extra slot.", deps: [] },
|
|
93
|
+
{ name: "statistic", category: "data-display", description: "Key metric with trend indicator.", deps: [] },
|
|
94
|
+
{ name: "timeline", category: "data-display", description: "Vertical events with color-coded icons.", deps: [] },
|
|
95
|
+
{ name: "calendar", category: "data-display", description: "Month picker with highlighted dates.", deps: [] },
|
|
96
|
+
{ name: "chart", category: "data-display", description: "Chart wrapper — bring your own chart library.", deps: [] },
|
|
97
|
+
{ name: "code-block", category: "data-display", description: "Code display with copy button and line numbers.", deps: [] },
|
|
98
|
+
// Feedback
|
|
99
|
+
{ name: "alert", category: "feedback", description: "Info/success/warning/danger with optional dismiss.", deps: ["class-variance-authority"] },
|
|
100
|
+
{ name: "toast", category: "feedback", description: "Radix Toast with all sub-primitives.", deps: ["@radix-ui/react-toast"] },
|
|
101
|
+
{ name: "snackbar", category: "feedback", description: "Positioned message with action.", deps: [] },
|
|
102
|
+
{ name: "progress", category: "feedback", description: "Linear bar with color variants.", deps: ["@radix-ui/react-progress"] },
|
|
103
|
+
{ name: "circular-progress", category: "feedback", description: "SVG ring with indeterminate mode.", deps: [] },
|
|
104
|
+
{ name: "skeleton", category: "feedback", description: "Pulse placeholder for text, rect, circle.", deps: [] },
|
|
105
|
+
{ name: "loading-spinner",category: "feedback", description: "Accessible SVG spinner.", deps: [] },
|
|
106
|
+
{ name: "empty-state", category: "feedback", description: "Icon + title + description + action.", deps: [] },
|
|
107
|
+
{ name: "status-indicator", category: "feedback", description: "Online/offline/busy/away dot with pulse.", deps: [] },
|
|
108
|
+
{ name: "notification", category: "feedback", description: "Notification item with avatar, timestamp, unread dot.", deps: [] },
|
|
109
|
+
// Overlay
|
|
110
|
+
{ name: "modal", category: "overlay", description: "Preset dialog — sm to full size variants.", deps: ["@radix-ui/react-dialog"] },
|
|
111
|
+
{ name: "dialog", category: "overlay", description: "Full Radix Dialog primitive suite.", deps: ["@radix-ui/react-dialog"] },
|
|
112
|
+
{ name: "drawer", category: "overlay", description: "Slides in from any edge.", deps: ["@radix-ui/react-dialog"] },
|
|
113
|
+
{ name: "popover", category: "overlay", description: "Floating panel.", deps: ["@radix-ui/react-popover"] },
|
|
114
|
+
{ name: "hover-card", category: "overlay", description: "Rich hover preview.", deps: ["@radix-ui/react-hover-card"] },
|
|
115
|
+
{ name: "context-menu", category: "overlay", description: "Right-click menu.", deps: ["@radix-ui/react-context-menu"] },
|
|
116
|
+
{ name: "command-dialog", category: "overlay", description: "⌘K palette.", deps: ["cmdk", "@radix-ui/react-dialog"] },
|
|
117
|
+
{ name: "sheet", category: "overlay", description: "Drawer alias.", deps: ["@radix-ui/react-dialog"], registryDeps: ["drawer"] },
|
|
118
|
+
{ name: "lightbox", category: "overlay", description: "Full-screen image overlay.", deps: ["@radix-ui/react-dialog"] },
|
|
119
|
+
{ name: "image-viewer", category: "overlay", description: "Lightbox alias.", deps: ["@radix-ui/react-dialog"], registryDeps: ["lightbox"] },
|
|
120
|
+
// Media
|
|
121
|
+
{ name: "image", category: "media", description: "Image with fallback, aspect ratio, fit, caption.", deps: [] },
|
|
122
|
+
{ name: "video-player", category: "media", description: "HTML5 video with captions/subtitles support.", deps: [] },
|
|
123
|
+
{ name: "audio-player", category: "media", description: "Custom audio UI with seek bar, cover art.", deps: [] },
|
|
124
|
+
{ name: "carousel", category: "media", description: "Autoplay, dots, arrows, loop, slidesPerView.", deps: [] },
|
|
125
|
+
{ name: "gallery", category: "media", description: "Responsive image grid with click handler.", deps: [] },
|
|
126
|
+
// Utility
|
|
127
|
+
{ name: "theme-switcher", category: "utility", description: "Icon / toggle / select variants.", deps: [] },
|
|
128
|
+
{ name: "copy-button", category: "utility", description: "Icon or labelled copy button with success feedback.", deps: [] },
|
|
129
|
+
{ name: "keyboard-shortcut", category: "utility", description: "Styled <kbd> shortcut display.", deps: [] },
|
|
130
|
+
{ name: "resizable-panel",category: "utility", description: "Drag-to-resize panel with min/max constraints.", deps: [] },
|
|
131
|
+
{ name: "drag-drop-area", category: "utility", description: "Accessible file drop zone.", deps: [] },
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
export const COMPONENTS_BY_NAME = new Map(REGISTRY.map((c) => [c.name, c]));
|
|
135
|
+
|
|
136
|
+
export const CATEGORIES: Category[] = [
|
|
137
|
+
"basic", "layout", "navigation", "forms", "advanced-forms",
|
|
138
|
+
"data-display", "feedback", "overlay", "media", "utility",
|
|
139
|
+
];
|