@cyberbloxai/ui-kit 0.2.0 → 0.2.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.
Files changed (3) hide show
  1. package/README.md +13 -2
  2. package/package.json +2 -4
  3. package/src/cli.js +327 -24
package/README.md CHANGED
@@ -21,17 +21,28 @@ CyberBlox UI Kit is a modular, themeable component library designed for building
21
21
  There are two ways to use CyberBlox UI:
22
22
 
23
23
  ### 1. shadcn-style (Recommended)
24
- This copies the component source code directly into your project, allowing you to customize everything.
24
+ This copies the component source code directly into your project, allowing you to customize everything. It also handles dependencies and installs necessary npm packages automatically.
25
25
 
26
26
  ```bash
27
- # 1. Initialize the project (sets up utils)
27
+ # 1. Initialize the project (creates components.json and lib/utils.ts)
28
28
  npx @cyberbloxai/ui-kit init
29
29
 
30
30
  # 2. Add components as needed
31
31
  npx @cyberbloxai/ui-kit add button
32
32
  npx @cyberbloxai/ui-kit add dialog
33
+ npx @cyberbloxai/ui-kit add alert-dialog # This will also add 'button' automatically!
33
34
  ```
34
35
 
36
+ **What happens during `init`?**
37
+ - A `components.json` file is created in your root directory.
38
+ - `lib/utils.ts` is created with the `cn` helper.
39
+
40
+ **What happens during `add`?**
41
+ - The component's `.tsx` file is copied to your `components/ui` folder.
42
+ - Any internal dependencies (like `button` for `alert-dialog`) are also added.
43
+ - Any required npm packages (like `@radix-ui/react-dialog`) are installed automatically.
44
+
45
+
35
46
  ### 2. Standard Library Style
36
47
  Install it as a traditional npm package.
37
48
 
package/package.json CHANGED
@@ -1,10 +1,8 @@
1
1
  {
2
2
  "name": "@cyberbloxai/ui-kit",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Production-ready UI component library built on Radix UI + Tailwind CSS. Supports shadcn-style component installation.",
5
- "bin": {
6
- "cyberblox": "./src/cli.js"
7
- },
5
+ "bin": "./src/cli.js",
8
6
  "repository": {
9
7
  "type": "git",
10
8
  "url": "git+https://github.com/abhishekjohn1507/uni-kit-forge.git"
package/src/cli.js CHANGED
@@ -3,12 +3,11 @@
3
3
  import fs from 'fs';
4
4
  import path from 'path';
5
5
  import { fileURLToPath } from 'url';
6
+ import { execSync } from 'child_process';
6
7
 
7
8
  const __filename = fileURLToPath(import.meta.url);
8
9
  const __dirname = path.dirname(__filename);
9
10
 
10
- // This script will be located in node_modules/@cyberbloxai/ui-kit/src/cli.js
11
- // We need to find the source components directory relative to this script.
12
11
  const packageRoot = path.join(__dirname, '..');
13
12
  const componentsSrc = path.join(packageRoot, 'src', 'components', 'ui');
14
13
  const utilsSrc = path.join(packageRoot, 'src', 'lib', 'utils.ts');
@@ -16,9 +15,240 @@ const utilsSrc = path.join(packageRoot, 'src', 'lib', 'utils.ts');
16
15
  const args = process.argv.slice(2);
17
16
  const command = args[0];
18
17
 
19
- function getTargetDir() {
20
- const isSrcExists = fs.existsSync(path.join(process.cwd(), 'src'));
21
- return isSrcExists ? path.join(process.cwd(), 'src') : process.cwd();
18
+ const DEFAULT_CONFIG = {
19
+ "$schema": "https://ui.shadcn.com/schema.json",
20
+ "style": "default",
21
+ "rsc": false,
22
+ "tsx": true,
23
+ "tailwind": {
24
+ "config": "tailwind.config.js",
25
+ "css": "src/index.css",
26
+ "baseColor": "slate",
27
+ "cssVariables": true,
28
+ "prefix": ""
29
+ },
30
+ "aliases": {
31
+ "components": "@/components",
32
+ "utils": "@/lib/utils",
33
+ "ui": "@/components/ui",
34
+ "lib": "@/lib",
35
+ "hooks": "@/hooks"
36
+ }
37
+ };
38
+
39
+ // Component dependencies map
40
+ const COMPONENT_REGISTRY = {
41
+ "accordion": {
42
+ "dependencies": ["@radix-ui/react-accordion"],
43
+ "registryDependencies": ["lucide-react"]
44
+ },
45
+ "alert-dialog": {
46
+ "dependencies": ["@radix-ui/react-alert-dialog", "button"],
47
+ "registryDependencies": ["lucide-react"]
48
+ },
49
+ "alert": {
50
+ "dependencies": [],
51
+ "registryDependencies": ["lucide-react", "class-variance-authority"]
52
+ },
53
+ "aspect-ratio": {
54
+ "dependencies": ["@radix-ui/react-aspect-ratio"],
55
+ "registryDependencies": []
56
+ },
57
+ "avatar": {
58
+ "dependencies": ["@radix-ui/react-avatar"],
59
+ "registryDependencies": []
60
+ },
61
+ "badge": {
62
+ "dependencies": [],
63
+ "registryDependencies": ["class-variance-authority"]
64
+ },
65
+ "breadcrumb": {
66
+ "dependencies": ["@radix-ui/react-slot"],
67
+ "registryDependencies": ["lucide-react"]
68
+ },
69
+ "button": {
70
+ "dependencies": ["@radix-ui/react-slot"],
71
+ "registryDependencies": ["class-variance-authority", "lucide-react"]
72
+ },
73
+ "calendar": {
74
+ "dependencies": ["react-day-picker", "date-fns", "button"],
75
+ "registryDependencies": ["lucide-react"]
76
+ },
77
+ "card": {
78
+ "dependencies": [],
79
+ "registryDependencies": []
80
+ },
81
+ "carousel": {
82
+ "dependencies": ["embla-carousel-react", "button"],
83
+ "registryDependencies": ["lucide-react"]
84
+ },
85
+ "checkbox": {
86
+ "dependencies": ["@radix-ui/react-checkbox"],
87
+ "registryDependencies": ["lucide-react"]
88
+ },
89
+ "collapsible": {
90
+ "dependencies": ["@radix-ui/react-collapsible"],
91
+ "registryDependencies": []
92
+ },
93
+ "command": {
94
+ "dependencies": ["cmdk", "dialog"],
95
+ "registryDependencies": ["lucide-react"]
96
+ },
97
+ "context-menu": {
98
+ "dependencies": ["@radix-ui/react-context-menu"],
99
+ "registryDependencies": ["lucide-react"]
100
+ },
101
+ "dialog": {
102
+ "dependencies": ["@radix-ui/react-dialog"],
103
+ "registryDependencies": ["lucide-react"]
104
+ },
105
+ "drawer": {
106
+ "dependencies": ["vaul"],
107
+ "registryDependencies": ["lucide-react"]
108
+ },
109
+ "dropdown-menu": {
110
+ "dependencies": ["@radix-ui/react-dropdown-menu"],
111
+ "registryDependencies": ["lucide-react"]
112
+ },
113
+ "form": {
114
+ "dependencies": ["@radix-ui/react-label", "@radix-ui/react-slot", "react-hook-form", "@hookform/resolvers", "zod", "label"],
115
+ "registryDependencies": ["lucide-react"]
116
+ },
117
+ "hover-card": {
118
+ "dependencies": ["@radix-ui/react-hover-card"],
119
+ "registryDependencies": []
120
+ },
121
+ "input-otp": {
122
+ "dependencies": ["input-otp"],
123
+ "registryDependencies": ["lucide-react"]
124
+ },
125
+ "input": {
126
+ "dependencies": [],
127
+ "registryDependencies": []
128
+ },
129
+ "label": {
130
+ "dependencies": ["@radix-ui/react-label"],
131
+ "registryDependencies": ["class-variance-authority"]
132
+ },
133
+ "menubar": {
134
+ "dependencies": ["@radix-ui/react-menubar"],
135
+ "registryDependencies": ["lucide-react"]
136
+ },
137
+ "navigation-menu": {
138
+ "dependencies": ["@radix-ui/react-navigation-menu"],
139
+ "registryDependencies": ["lucide-react", "class-variance-authority"]
140
+ },
141
+ "pagination": {
142
+ "dependencies": ["button"],
143
+ "registryDependencies": ["lucide-react"]
144
+ },
145
+ "popover": {
146
+ "dependencies": ["@radix-ui/react-popover"],
147
+ "registryDependencies": []
148
+ },
149
+ "progress": {
150
+ "dependencies": ["@radix-ui/react-progress"],
151
+ "registryDependencies": []
152
+ },
153
+ "radio-group": {
154
+ "dependencies": ["@radix-ui/react-radio-group"],
155
+ "registryDependencies": ["lucide-react"]
156
+ },
157
+ "resizable": {
158
+ "dependencies": ["react-resizable-panels"],
159
+ "registryDependencies": ["lucide-react"]
160
+ },
161
+ "scroll-area": {
162
+ "dependencies": ["@radix-ui/react-scroll-area"],
163
+ "registryDependencies": []
164
+ },
165
+ "select": {
166
+ "dependencies": ["@radix-ui/react-select"],
167
+ "registryDependencies": ["lucide-react"]
168
+ },
169
+ "separator": {
170
+ "dependencies": ["@radix-ui/react-separator"],
171
+ "registryDependencies": []
172
+ },
173
+ "sheet": {
174
+ "dependencies": ["@radix-ui/react-dialog"],
175
+ "registryDependencies": ["lucide-react", "class-variance-authority"]
176
+ },
177
+ "sidebar": {
178
+ "dependencies": ["@radix-ui/react-slot", "button", "input", "separator", "sheet", "skeleton", "tooltip"],
179
+ "registryDependencies": ["lucide-react", "class-variance-authority"]
180
+ },
181
+ "skeleton": {
182
+ "dependencies": [],
183
+ "registryDependencies": []
184
+ },
185
+ "slider": {
186
+ "dependencies": ["@radix-ui/react-slider"],
187
+ "registryDependencies": []
188
+ },
189
+ "sonner": {
190
+ "dependencies": ["sonner", "next-themes"],
191
+ "registryDependencies": []
192
+ },
193
+ "switch": {
194
+ "dependencies": ["@radix-ui/react-switch"],
195
+ "registryDependencies": []
196
+ },
197
+ "table": {
198
+ "dependencies": [],
199
+ "registryDependencies": []
200
+ },
201
+ "tabs": {
202
+ "dependencies": ["@radix-ui/react-tabs"],
203
+ "registryDependencies": []
204
+ },
205
+ "textarea": {
206
+ "dependencies": [],
207
+ "registryDependencies": []
208
+ },
209
+ "use-toast": {
210
+ "dependencies": [],
211
+ "registryDependencies": []
212
+ },
213
+ "toast": {
214
+ "dependencies": ["@radix-ui/react-toast"],
215
+ "registryDependencies": ["lucide-react", "class-variance-authority"]
216
+ },
217
+ "toaster": {
218
+ "dependencies": ["toast", "use-toast"],
219
+ "registryDependencies": []
220
+ },
221
+ "toggle-group": {
222
+ "dependencies": ["@radix-ui/react-toggle-group", "toggle"],
223
+ "registryDependencies": []
224
+ },
225
+ "toggle": {
226
+ "dependencies": ["@radix-ui/react-toggle"],
227
+ "registryDependencies": ["class-variance-authority"]
228
+ },
229
+ "tooltip": {
230
+ "dependencies": ["@radix-ui/react-tooltip"],
231
+ "registryDependencies": []
232
+ }
233
+ };
234
+
235
+ function getProjectConfig() {
236
+ const configPath = path.join(process.cwd(), 'components.json');
237
+ if (fs.existsSync(configPath)) {
238
+ return JSON.parse(fs.readFileSync(configPath, 'utf8'));
239
+ }
240
+ return null;
241
+ }
242
+
243
+ function resolveAlias(alias, config) {
244
+ const aliases = config.aliases || {};
245
+ if (alias.startsWith('@/')) {
246
+ // Basic @/ support - assuming it maps to src/ or project root
247
+ const isSrcExists = fs.existsSync(path.join(process.cwd(), 'src'));
248
+ const base = isSrcExists ? 'src' : '';
249
+ return path.join(process.cwd(), base, alias.replace('@/', ''));
250
+ }
251
+ return path.join(process.cwd(), alias);
22
252
  }
23
253
 
24
254
  function copyFile(src, dest) {
@@ -26,41 +256,111 @@ function copyFile(src, dest) {
26
256
  if (!fs.existsSync(destDir)) {
27
257
  fs.mkdirSync(destDir, { recursive: true });
28
258
  }
29
- fs.copyFileSync(src, dest);
259
+
260
+ let content = fs.readFileSync(src, 'utf8');
261
+
262
+ // Basic path replacement: replace @/ with project root relative paths if needed
263
+ // In a real shadcn CLI, this is more complex (respecting aliases)
264
+
265
+ fs.writeFileSync(dest, content);
30
266
  console.log(` Created ${path.relative(process.cwd(), dest)}`);
31
267
  }
32
268
 
33
- function init() {
34
- console.log('Initializing CyberBlox UI components...');
35
- const targetBase = getTargetDir();
269
+ function installDependencies(deps) {
270
+ if (!deps || deps.length === 0) return;
271
+
272
+ console.log(` Installing dependencies: ${deps.join(', ')}...`);
273
+ try {
274
+ const command = fs.existsSync(path.join(process.cwd(), 'yarn.lock'))
275
+ ? `yarn add ${deps.join(' ')}`
276
+ : `npm install ${deps.join(' ')}`;
277
+ execSync(command, { stdio: 'inherit' });
278
+ } catch (error) {
279
+ console.warn(' Failed to install dependencies automatically. Please install them manually.');
280
+ }
281
+ }
282
+
283
+ async function init() {
284
+ console.log('Initializing CyberBlox UI...');
285
+
286
+ const configPath = path.join(process.cwd(), 'components.json');
287
+ if (fs.existsSync(configPath)) {
288
+ console.log(' components.json already exists.');
289
+ } else {
290
+ fs.writeFileSync(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2));
291
+ console.log(' Created components.json');
292
+ }
293
+
294
+ const config = getProjectConfig() || DEFAULT_CONFIG;
295
+ const utilsDest = resolveAlias(config.aliases.utils + '.ts', config);
36
296
 
37
- // Copy utils
38
- const utilsDest = path.join(targetBase, 'lib', 'utils.ts');
39
297
  copyFile(utilsSrc, utilsDest);
40
298
 
41
- console.log('\nSuccess! Now you can add components using:');
42
- console.log('npx cyberblox add [component-name]');
299
+ console.log('\nSuccess! Project initialized.');
300
+ console.log('Now you can add components using:');
301
+ console.log('npx @cyberbloxai/ui-kit add [component-name]');
43
302
  }
44
303
 
45
304
  function addComponent(name) {
46
305
  if (!name) {
47
- console.error('Please specify a component name, e.g., npx cyberblox add button');
306
+ console.error('Please specify a component name.');
48
307
  process.exit(1);
49
308
  }
50
309
 
51
- const fileName = name.endsWith('.tsx') ? name : `${name}.tsx`;
310
+ const config = getProjectConfig();
311
+ if (!config) {
312
+ console.error('Project not initialized. Run "npx @cyberbloxai/ui-kit init" first.');
313
+ process.exit(1);
314
+ }
315
+
316
+ const registryItem = COMPONENT_REGISTRY[name];
317
+
318
+ // Recursive add for internal dependencies
319
+ if (registryItem && registryItem.dependencies) {
320
+ registryItem.dependencies.forEach(dep => {
321
+ if (!dep.startsWith('@')) { // It's an internal component
322
+ addComponent(dep);
323
+ }
324
+ });
325
+ }
326
+
327
+ const fileName = name.endsWith('.tsx') || name.endsWith('.ts') ? name : `${name}.tsx`;
52
328
  const srcPath = path.join(componentsSrc, fileName);
53
329
 
330
+ // Also check in hooks if not found in components
331
+ let finalSrcPath = srcPath;
332
+ let targetDir = resolveAlias(config.aliases.ui, config);
333
+
54
334
  if (!fs.existsSync(srcPath)) {
55
- console.error(`Component "${name}" not found in library.`);
56
- process.exit(1);
335
+ const hookPath = path.join(packageRoot, 'src', 'hooks', fileName);
336
+ const libPath = path.join(packageRoot, 'src', 'lib', fileName);
337
+
338
+ if (fs.existsSync(hookPath)) {
339
+ finalSrcPath = hookPath;
340
+ targetDir = resolveAlias(config.aliases.hooks || '@/hooks', config);
341
+ } else if (fs.existsSync(libPath)) {
342
+ finalSrcPath = libPath;
343
+ targetDir = resolveAlias(config.aliases.lib || '@/lib', config);
344
+ } else {
345
+ console.error(`Component or file "${name}" not found.`);
346
+ return;
347
+ }
57
348
  }
58
349
 
59
- const targetBase = getTargetDir();
60
- const destPath = path.join(targetBase, 'components', 'ui', fileName);
350
+ const destPath = path.join(targetDir, path.basename(finalSrcPath));
61
351
 
62
- copyFile(srcPath, destPath);
63
- console.log(`\nComponent "${name}" added successfully!`);
352
+ if (fs.existsSync(destPath)) {
353
+ console.log(` File ${path.basename(finalSrcPath)} already exists. Skipping.`);
354
+ } else {
355
+ copyFile(finalSrcPath, destPath);
356
+
357
+ // Install npm dependencies
358
+ if (registryItem && registryItem.dependencies) {
359
+ const npmDeps = registryItem.dependencies.filter(d => d.startsWith('@') || !COMPONENT_REGISTRY[d]);
360
+ const regDeps = registryItem.registryDependencies || [];
361
+ installDependencies([...new Set([...npmDeps, ...regDeps])]);
362
+ }
363
+ }
64
364
  }
65
365
 
66
366
  function listComponents() {
@@ -83,11 +383,14 @@ switch (command) {
83
383
  case 'list':
84
384
  listComponents();
85
385
  break;
386
+ case 'help':
387
+ case '--help':
388
+ case '-h':
86
389
  default:
87
390
  console.log('CyberBlox UI CLI');
88
391
  console.log('\nUsage:');
89
- console.log(' npx cyberblox init - Setup lib/utils.ts');
90
- console.log(' npx cyberblox add [name] - Add a component to your project');
91
- console.log(' npx cyberblox list - List all available components');
392
+ console.log(' npx @cyberbloxai/ui-kit init - Setup components.json and utils');
393
+ console.log(' npx @cyberbloxai/ui-kit add [name] - Add a component');
394
+ console.log(' npx @cyberbloxai/ui-kit list - List components');
92
395
  break;
93
396
  }