@gilav21/shadcn-angular 0.0.11 → 0.0.13

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.
@@ -6,6 +6,7 @@ import chalk from 'chalk';
6
6
  import ora from 'ora';
7
7
  import { getConfig } from '../utils/config.js';
8
8
  import { registry } from '../registry/index.js';
9
+ import { installPackages } from '../utils/package-manager.js';
9
10
  const __filename = fileURLToPath(import.meta.url);
10
11
  const __dirname = path.dirname(__filename);
11
12
  // Base URL for the component registry (GitHub raw content)
@@ -231,6 +232,26 @@ export async function add(components, options) {
231
232
  else {
232
233
  spinner.info('No new components installed.');
233
234
  }
235
+ if (finalComponents.length > 0) {
236
+ const npmDependencies = new Set();
237
+ for (const name of finalComponents) {
238
+ const component = registry[name];
239
+ if (component.npmDependencies) {
240
+ component.npmDependencies.forEach(dep => npmDependencies.add(dep));
241
+ }
242
+ }
243
+ if (npmDependencies.size > 0) {
244
+ const depSpinner = ora('Installing dependencies...').start();
245
+ try {
246
+ await installPackages(Array.from(npmDependencies), { cwd });
247
+ depSpinner.succeed('Dependencies installed.');
248
+ }
249
+ catch (e) {
250
+ depSpinner.fail('Failed to install dependencies.');
251
+ console.error(e);
252
+ }
253
+ }
254
+ }
234
255
  if (componentsToSkip.length > 0) {
235
256
  console.log('\n' + chalk.dim('Components skipped (up to date):'));
236
257
  componentsToSkip.forEach(name => {
@@ -2,6 +2,7 @@ export interface ComponentDefinition {
2
2
  name: string;
3
3
  files: string[];
4
4
  dependencies?: string[];
5
+ npmDependencies?: string[];
5
6
  }
6
7
  export type ComponentName = keyof typeof registry;
7
8
  export declare const registry: Record<string, ComponentDefinition>;
@@ -82,13 +82,36 @@ export const registry = {
82
82
  },
83
83
  'context-menu': {
84
84
  name: 'context-menu',
85
- files: ['context-menu.component.ts'],
85
+ files: ['context-menu.component.ts', 'context-menu-integrations.ts'],
86
86
  },
87
87
  'date-picker': {
88
88
  name: 'date-picker',
89
89
  files: ['date-picker.component.ts'],
90
90
  dependencies: ['calendar'],
91
91
  },
92
+ chat: {
93
+ name: 'chat',
94
+ files: ['chat.component.ts'],
95
+ dependencies: ['avatar', 'button', 'textarea', 'scroll-area'],
96
+ },
97
+ 'streaming-text': {
98
+ name: 'streaming-text',
99
+ files: ['streaming-text.component.ts'],
100
+ },
101
+ sparkles: {
102
+ name: 'sparkles',
103
+ files: ['sparkles.component.ts'],
104
+ dependencies: ['button'],
105
+ },
106
+ 'code-block': {
107
+ name: 'code-block',
108
+ files: ['code-block.component.ts'],
109
+ dependencies: ['button', 'scroll-area'],
110
+ },
111
+ 'text-reveal': {
112
+ name: 'text-reveal',
113
+ files: ['text-reveal.component.ts'],
114
+ },
92
115
  'data-table': {
93
116
  name: 'data-table',
94
117
  files: [
@@ -112,6 +135,29 @@ export const registry = {
112
135
  name: 'dialog',
113
136
  files: ['dialog.component.ts'],
114
137
  },
138
+ dock: {
139
+ name: 'dock',
140
+ files: [
141
+ 'dock.component.ts',
142
+ 'dock-item.component.ts',
143
+ 'dock-icon.component.ts',
144
+ 'dock-label.component.ts',
145
+ ],
146
+ },
147
+ 'tree-select': {
148
+ name: 'tree-select',
149
+ files: ['tree-select.component.ts'],
150
+ dependencies: ['popover', 'tree'],
151
+ },
152
+ 'virtual-scroll': {
153
+ name: 'virtual-scroll',
154
+ files: ['virtual-scroll.component.ts'],
155
+ },
156
+ 'input-mask': {
157
+ name: 'input-mask',
158
+ files: ['input-mask.directive.ts'],
159
+ dependencies: ['input'],
160
+ },
115
161
  drawer: {
116
162
  name: 'drawer',
117
163
  files: ['drawer.component.ts'],
@@ -217,6 +263,7 @@ export const registry = {
217
263
  sidebar: {
218
264
  name: 'sidebar',
219
265
  files: ['sidebar.component.ts'],
266
+ dependencies: ['scroll-area', 'tooltip'],
220
267
  },
221
268
  skeleton: {
222
269
  name: 'skeleton',
@@ -374,4 +421,16 @@ export const registry = {
374
421
  'charts/chart.utils.ts',
375
422
  ],
376
423
  },
424
+ 'bento-grid': {
425
+ name: 'bento-grid',
426
+ dependencies: ['context-menu'],
427
+ files: [
428
+ 'bento-grid.component.ts',
429
+ ],
430
+ },
431
+ 'split-button': {
432
+ name: 'split-button',
433
+ files: ['split-button.component.ts'],
434
+ dependencies: ['button', 'dropdown-menu'],
435
+ },
377
436
  };
@@ -0,0 +1,6 @@
1
+ export type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';
2
+ export declare function getPackageManager(cwd: string): Promise<PackageManager>;
3
+ export declare function installPackages(packages: string[], options: {
4
+ cwd: string;
5
+ dev?: boolean;
6
+ }): Promise<void>;
@@ -0,0 +1,49 @@
1
+ import { execa } from 'execa';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ export async function getPackageManager(cwd) {
5
+ const userAgent = process.env['npm_config_user_agent'];
6
+ if (userAgent) {
7
+ if (userAgent.startsWith('yarn'))
8
+ return 'yarn';
9
+ if (userAgent.startsWith('pnpm'))
10
+ return 'pnpm';
11
+ if (userAgent.startsWith('bun'))
12
+ return 'bun';
13
+ return 'npm';
14
+ }
15
+ // Check for lock files
16
+ if (await fs.pathExists(path.join(cwd, 'yarn.lock')))
17
+ return 'yarn';
18
+ if (await fs.pathExists(path.join(cwd, 'pnpm-lock.yaml')))
19
+ return 'pnpm';
20
+ if (await fs.pathExists(path.join(cwd, 'bun.lockb')))
21
+ return 'bun';
22
+ return 'npm';
23
+ }
24
+ export async function installPackages(packages, options) {
25
+ const packageManager = await getPackageManager(options.cwd);
26
+ const args = [];
27
+ if (packageManager === 'npm') {
28
+ args.push('install');
29
+ if (options.dev)
30
+ args.push('-D');
31
+ }
32
+ else if (packageManager === 'yarn') {
33
+ args.push('add');
34
+ if (options.dev)
35
+ args.push('-D');
36
+ }
37
+ else if (packageManager === 'pnpm') {
38
+ args.push('add');
39
+ if (options.dev)
40
+ args.push('-D');
41
+ }
42
+ else if (packageManager === 'bun') {
43
+ args.push('add');
44
+ if (options.dev)
45
+ args.push('-d');
46
+ }
47
+ args.push(...packages);
48
+ await execa(packageManager, args, { cwd: options.cwd });
49
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gilav21/shadcn-angular",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "description": "CLI for adding shadcn-angular components to your project",
5
5
  "bin": {
6
6
  "shadcn-angular": "./dist/index.js"
@@ -32,4 +32,4 @@
32
32
  "@types/prompts": "^2.4.9",
33
33
  "typescript": "^5.5.0"
34
34
  }
35
- }
35
+ }
@@ -6,6 +6,7 @@ import chalk from 'chalk';
6
6
  import ora from 'ora';
7
7
  import { getConfig } from '../utils/config.js';
8
8
  import { registry, type ComponentName } from '../registry/index.js';
9
+ import { installPackages } from '../utils/package-manager.js';
9
10
 
10
11
  const __filename = fileURLToPath(import.meta.url);
11
12
  const __dirname = path.dirname(__filename);
@@ -264,6 +265,27 @@ export async function add(components: string[], options: AddOptions) {
264
265
  spinner.info('No new components installed.');
265
266
  }
266
267
 
268
+ if (finalComponents.length > 0) {
269
+ const npmDependencies = new Set<string>();
270
+ for (const name of finalComponents) {
271
+ const component = registry[name];
272
+ if (component.npmDependencies) {
273
+ component.npmDependencies.forEach(dep => npmDependencies.add(dep));
274
+ }
275
+ }
276
+
277
+ if (npmDependencies.size > 0) {
278
+ const depSpinner = ora('Installing dependencies...').start();
279
+ try {
280
+ await installPackages(Array.from(npmDependencies), { cwd });
281
+ depSpinner.succeed('Dependencies installed.');
282
+ } catch (e) {
283
+ depSpinner.fail('Failed to install dependencies.');
284
+ console.error(e);
285
+ }
286
+ }
287
+ }
288
+
267
289
  if (componentsToSkip.length > 0) {
268
290
  console.log('\n' + chalk.dim('Components skipped (up to date):'));
269
291
  componentsToSkip.forEach(name => {
@@ -5,6 +5,7 @@ export interface ComponentDefinition {
5
5
  name: string;
6
6
  files: string[]; // Relative paths to component files
7
7
  dependencies?: string[]; // Other components this depends on
8
+ npmDependencies?: string[]; // NPM packages this depends on
8
9
  }
9
10
 
10
11
  export type ComponentName = keyof typeof registry;
@@ -91,13 +92,36 @@ export const registry: Record<string, ComponentDefinition> = {
91
92
  },
92
93
  'context-menu': {
93
94
  name: 'context-menu',
94
- files: ['context-menu.component.ts'],
95
+ files: ['context-menu.component.ts', 'context-menu-integrations.ts'],
95
96
  },
96
97
  'date-picker': {
97
98
  name: 'date-picker',
98
99
  files: ['date-picker.component.ts'],
99
100
  dependencies: ['calendar'],
100
101
  },
102
+ chat: {
103
+ name: 'chat',
104
+ files: ['chat.component.ts'],
105
+ dependencies: ['avatar', 'button', 'textarea', 'scroll-area'],
106
+ },
107
+ 'streaming-text': {
108
+ name: 'streaming-text',
109
+ files: ['streaming-text.component.ts'],
110
+ },
111
+ sparkles: {
112
+ name: 'sparkles',
113
+ files: ['sparkles.component.ts'],
114
+ dependencies: ['button'],
115
+ },
116
+ 'code-block': {
117
+ name: 'code-block',
118
+ files: ['code-block.component.ts'],
119
+ dependencies: ['button', 'scroll-area'],
120
+ },
121
+ 'text-reveal': {
122
+ name: 'text-reveal',
123
+ files: ['text-reveal.component.ts'],
124
+ },
101
125
  'data-table': {
102
126
  name: 'data-table',
103
127
  files: [
@@ -121,6 +145,29 @@ export const registry: Record<string, ComponentDefinition> = {
121
145
  name: 'dialog',
122
146
  files: ['dialog.component.ts'],
123
147
  },
148
+ dock: {
149
+ name: 'dock',
150
+ files: [
151
+ 'dock.component.ts',
152
+ 'dock-item.component.ts',
153
+ 'dock-icon.component.ts',
154
+ 'dock-label.component.ts',
155
+ ],
156
+ },
157
+ 'tree-select': {
158
+ name: 'tree-select',
159
+ files: ['tree-select.component.ts'],
160
+ dependencies: ['popover', 'tree'],
161
+ },
162
+ 'virtual-scroll': {
163
+ name: 'virtual-scroll',
164
+ files: ['virtual-scroll.component.ts'],
165
+ },
166
+ 'input-mask': {
167
+ name: 'input-mask',
168
+ files: ['input-mask.directive.ts'],
169
+ dependencies: ['input'],
170
+ },
124
171
  drawer: {
125
172
  name: 'drawer',
126
173
  files: ['drawer.component.ts'],
@@ -137,6 +184,7 @@ export const registry: Record<string, ComponentDefinition> = {
137
184
  name: 'field',
138
185
  files: ['field.component.ts'],
139
186
  },
187
+
140
188
  'file-upload': {
141
189
  name: 'file-upload',
142
190
  files: ['file-upload.component.ts'],
@@ -226,6 +274,7 @@ export const registry: Record<string, ComponentDefinition> = {
226
274
  sidebar: {
227
275
  name: 'sidebar',
228
276
  files: ['sidebar.component.ts'],
277
+ dependencies: ['scroll-area', 'tooltip'],
229
278
  },
230
279
  skeleton: {
231
280
  name: 'skeleton',
@@ -383,4 +432,16 @@ export const registry: Record<string, ComponentDefinition> = {
383
432
  'charts/chart.utils.ts',
384
433
  ],
385
434
  },
435
+ 'bento-grid': {
436
+ name: 'bento-grid',
437
+ dependencies: ['context-menu'],
438
+ files: [
439
+ 'bento-grid.component.ts',
440
+ ],
441
+ },
442
+ 'split-button': {
443
+ name: 'split-button',
444
+ files: ['split-button.component.ts'],
445
+ dependencies: ['button', 'dropdown-menu'],
446
+ },
386
447
  };
@@ -0,0 +1,50 @@
1
+ import { execa } from 'execa';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+
5
+ export type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';
6
+
7
+ export async function getPackageManager(cwd: string): Promise<PackageManager> {
8
+ const userAgent = process.env['npm_config_user_agent'];
9
+
10
+ if (userAgent) {
11
+ if (userAgent.startsWith('yarn')) return 'yarn';
12
+ if (userAgent.startsWith('pnpm')) return 'pnpm';
13
+ if (userAgent.startsWith('bun')) return 'bun';
14
+ return 'npm';
15
+ }
16
+
17
+ // Check for lock files
18
+ if (await fs.pathExists(path.join(cwd, 'yarn.lock'))) return 'yarn';
19
+ if (await fs.pathExists(path.join(cwd, 'pnpm-lock.yaml'))) return 'pnpm';
20
+ if (await fs.pathExists(path.join(cwd, 'bun.lockb'))) return 'bun';
21
+
22
+ return 'npm';
23
+ }
24
+
25
+ export async function installPackages(
26
+ packages: string[],
27
+ options: { cwd: string; dev?: boolean }
28
+ ) {
29
+ const packageManager = await getPackageManager(options.cwd);
30
+
31
+ const args: string[] = [];
32
+
33
+ if (packageManager === 'npm') {
34
+ args.push('install');
35
+ if (options.dev) args.push('-D');
36
+ } else if (packageManager === 'yarn') {
37
+ args.push('add');
38
+ if (options.dev) args.push('-D');
39
+ } else if (packageManager === 'pnpm') {
40
+ args.push('add');
41
+ if (options.dev) args.push('-D');
42
+ } else if (packageManager === 'bun') {
43
+ args.push('add');
44
+ if (options.dev) args.push('-d');
45
+ }
46
+
47
+ args.push(...packages);
48
+
49
+ await execa(packageManager, args, { cwd: options.cwd });
50
+ }