@ng-cn/core 1.0.2 → 1.0.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ng-cn/core",
3
- "version": "1.0.02",
3
+ "version": "1.0.03",
4
4
  "description": "Beautifully designed Angular components built with Tailwind CSS v4 - The official Angular port of shadcn/ui",
5
5
  "keywords": [
6
6
  "angular",
@@ -9,12 +9,43 @@ Angular schematics for installing shadcn-angular components individually.
9
9
  First, add shadcn-angular to your project:
10
10
 
11
11
  ```bash
12
- ng add shadcn-angular
12
+ ng add @ng-cn/core
13
13
  ```
14
14
 
15
15
  This will:
16
16
  - Install required dependencies (lucide-angular, class-variance-authority, clsx, tailwind-merge, @angular/cdk)
17
17
  - Set up the project for shadcn-angular components
18
+ - **Prompt you to select components** to install initially (multi-select checkbox)
19
+
20
+ ### Interactive Component Selection
21
+
22
+ When running `ng add @ng-cn/core`, you'll be presented with an interactive multi-select prompt:
23
+
24
+ ```
25
+ ? Which components would you like to add? (Press space to select, enter to confirm)
26
+ ❯◯ Button - Displays a button or a component that looks like a button
27
+ ◯ Card - Displays a card with header, content, and footer
28
+ ◯ Input - Displays a form input field
29
+ ◯ Label - Renders an accessible label associated with controls
30
+ ◯ Checkbox - A control that allows toggling between checked and not checked
31
+ ...
32
+ ```
33
+
34
+ Use **space** to select/deselect components and **enter** to confirm your selection.
35
+
36
+ ### Skip Component Selection
37
+
38
+ If you want to skip the component selection prompt:
39
+
40
+ ```bash
41
+ ng add @ng-cn/core --components=button,card,input
42
+ ```
43
+
44
+ Or to skip adding any components initially:
45
+
46
+ ```bash
47
+ ng add @ng-cn/core --components=
48
+ ```
18
49
 
19
50
  ### Install Individual Components
20
51
 
@@ -3,6 +3,7 @@ interface NgAddOptions {
3
3
  project?: string;
4
4
  skipInstall?: boolean;
5
5
  skipStyles?: boolean;
6
+ components?: string[];
6
7
  }
7
8
  export declare function ngAdd(options: NgAddOptions): Rule;
8
9
  export {};
@@ -279,6 +279,27 @@ function ngAdd(options) {
279
279
  context.logger.info(' ✓ Path aliases already set');
280
280
  }
281
281
  }
282
+ // Install selected components
283
+ if (options.components && options.components.length > 0) {
284
+ context.logger.info('');
285
+ context.logger.info('📦 Selected Components');
286
+ const packageJson = JSON.parse(tree.read(packageJsonPath).toString('utf-8'));
287
+ for (const component of options.components) {
288
+ const packageName = `@ng-cn/${component}`;
289
+ if (!packageJson.dependencies?.[packageName]) {
290
+ packageJson.dependencies = packageJson.dependencies || {};
291
+ packageJson.dependencies[packageName] = 'latest';
292
+ context.logger.info(` + ${packageName}`);
293
+ }
294
+ else {
295
+ context.logger.info(` ✓ ${packageName} already installed`);
296
+ }
297
+ }
298
+ tree.overwrite(packageJsonPath, JSON.stringify(packageJson, null, 2));
299
+ if (!options.skipInstall) {
300
+ context.addTask(new tasks_1.NodePackageInstallTask());
301
+ }
302
+ }
282
303
  // Success message with ASCII art banner
283
304
  context.logger.info('');
284
305
  context.logger.info('');
@@ -291,10 +312,23 @@ function ngAdd(options) {
291
312
  context.logger.info('');
292
313
  context.logger.info(' ✅ Setup complete! shadcn for Angular');
293
314
  context.logger.info('');
315
+ // Show selected components summary if any were installed
316
+ if (options.components && options.components.length > 0) {
317
+ context.logger.info('╭──────────────────────────────────────────────────╮');
318
+ context.logger.info('│ ✨ Components installed: │');
319
+ context.logger.info('│ │');
320
+ for (const component of options.components) {
321
+ const paddedComponent = `@ng-cn/${component}`.padEnd(40);
322
+ context.logger.info(`│ ${paddedComponent}│`);
323
+ }
324
+ context.logger.info('│ │');
325
+ context.logger.info('╰──────────────────────────────────────────────────╯');
326
+ context.logger.info('');
327
+ }
294
328
  context.logger.info('╭──────────────────────────────────────────────────╮');
295
329
  context.logger.info('│ 🚀 Next steps: │');
296
330
  context.logger.info('│ │');
297
- context.logger.info('│ 1. Add components: │');
331
+ context.logger.info('│ 1. Add more components: │');
298
332
  context.logger.info('│ ng g @ng-cn/core:c button │');
299
333
  context.logger.info('│ ng g @ng-cn/core:c card │');
300
334
  context.logger.info('│ │');
@@ -302,7 +336,7 @@ function ngAdd(options) {
302
336
  context.logger.info('│ npm i @ng-cn/button @ng-cn/card │');
303
337
  context.logger.info('│ │');
304
338
  context.logger.info('│ 3. Import and use: │');
305
- context.logger.info("│ import { Button } from '@/ui/button'; │");
339
+ context.logger.info("│ import { Button } from '@ng-cn/button'; │");
306
340
  context.logger.info('│ │');
307
341
  context.logger.info('│ 📚 Docs: https://shadcn-angular.tigayon.com │');
308
342
  context.logger.info('╰──────────────────────────────────────────────────╯');
@@ -6,6 +6,7 @@ interface NgAddOptions {
6
6
  project?: string;
7
7
  skipInstall?: boolean;
8
8
  skipStyles?: boolean;
9
+ components?: string[];
9
10
  }
10
11
 
11
12
  // CSS Variables template for shadcn theming
@@ -302,6 +303,31 @@ export function ngAdd(options: NgAddOptions): Rule {
302
303
  }
303
304
  }
304
305
 
306
+ // Install selected components
307
+ if (options.components && options.components.length > 0) {
308
+ context.logger.info('');
309
+ context.logger.info('📦 Selected Components');
310
+
311
+ const packageJson = JSON.parse(tree.read(packageJsonPath)!.toString('utf-8'));
312
+
313
+ for (const component of options.components) {
314
+ const packageName = `@ng-cn/${component}`;
315
+ if (!packageJson.dependencies?.[packageName]) {
316
+ packageJson.dependencies = packageJson.dependencies || {};
317
+ packageJson.dependencies[packageName] = 'latest';
318
+ context.logger.info(` + ${packageName}`);
319
+ } else {
320
+ context.logger.info(` ✓ ${packageName} already installed`);
321
+ }
322
+ }
323
+
324
+ tree.overwrite(packageJsonPath, JSON.stringify(packageJson, null, 2));
325
+
326
+ if (!options.skipInstall) {
327
+ context.addTask(new NodePackageInstallTask());
328
+ }
329
+ }
330
+
305
331
  // Success message with ASCII art banner
306
332
  context.logger.info('');
307
333
  context.logger.info('');
@@ -314,10 +340,25 @@ export function ngAdd(options: NgAddOptions): Rule {
314
340
  context.logger.info('');
315
341
  context.logger.info(' ✅ Setup complete! shadcn for Angular');
316
342
  context.logger.info('');
343
+
344
+ // Show selected components summary if any were installed
345
+ if (options.components && options.components.length > 0) {
346
+ context.logger.info('╭──────────────────────────────────────────────────╮');
347
+ context.logger.info('│ ✨ Components installed: │');
348
+ context.logger.info('│ │');
349
+ for (const component of options.components) {
350
+ const paddedComponent = `@ng-cn/${component}`.padEnd(40);
351
+ context.logger.info(`│ ${paddedComponent}│`);
352
+ }
353
+ context.logger.info('│ │');
354
+ context.logger.info('╰──────────────────────────────────────────────────╯');
355
+ context.logger.info('');
356
+ }
357
+
317
358
  context.logger.info('╭──────────────────────────────────────────────────╮');
318
359
  context.logger.info('│ 🚀 Next steps: │');
319
360
  context.logger.info('│ │');
320
- context.logger.info('│ 1. Add components: │');
361
+ context.logger.info('│ 1. Add more components: │');
321
362
  context.logger.info('│ ng g @ng-cn/core:c button │');
322
363
  context.logger.info('│ ng g @ng-cn/core:c card │');
323
364
  context.logger.info('│ │');
@@ -325,7 +366,7 @@ export function ngAdd(options: NgAddOptions): Rule {
325
366
  context.logger.info('│ npm i @ng-cn/button @ng-cn/card │');
326
367
  context.logger.info('│ │');
327
368
  context.logger.info('│ 3. Import and use: │');
328
- context.logger.info("│ import { Button } from '@/ui/button'; │");
369
+ context.logger.info("│ import { Button } from '@ng-cn/button'; │");
329
370
  context.logger.info('│ │');
330
371
  context.logger.info('│ 📚 Docs: https://shadcn-angular.tigayon.com │');
331
372
  context.logger.info('╰──────────────────────────────────────────────────╯');
@@ -20,6 +20,49 @@
20
20
  "type": "boolean",
21
21
  "default": false,
22
22
  "description": "Skip creating ng-cn.scss styles file."
23
+ },
24
+ "components": {
25
+ "type": "array",
26
+ "items": {
27
+ "type": "string"
28
+ },
29
+ "default": [],
30
+ "description": "Components to install initially.",
31
+ "x-prompt": {
32
+ "message": "Which components would you like to add? (Press space to select, enter to confirm)",
33
+ "type": "list",
34
+ "multiselect": true,
35
+ "items": [
36
+ { "value": "button", "label": "Button - Displays a button or a component that looks like a button" },
37
+ { "value": "card", "label": "Card - Displays a card with header, content, and footer" },
38
+ { "value": "input", "label": "Input - Displays a form input field" },
39
+ { "value": "label", "label": "Label - Renders an accessible label associated with controls" },
40
+ { "value": "checkbox", "label": "Checkbox - A control that allows toggling between checked and not checked" },
41
+ { "value": "select", "label": "Select - Displays a list of options for the user to pick from" },
42
+ { "value": "dialog", "label": "Dialog - A window overlaid on the primary window" },
43
+ { "value": "toast", "label": "Toast - A succinct message that is displayed temporarily" },
44
+ { "value": "dropdown-menu", "label": "Dropdown Menu - Displays a menu when triggered" },
45
+ { "value": "tabs", "label": "Tabs - A set of layered sections of content" },
46
+ { "value": "table", "label": "Table - A responsive table component" },
47
+ { "value": "avatar", "label": "Avatar - An image element with a fallback for representing the user" },
48
+ { "value": "badge", "label": "Badge - Displays a badge or a component that looks like a badge" },
49
+ { "value": "alert", "label": "Alert - Displays a callout for user attention" },
50
+ { "value": "tooltip", "label": "Tooltip - A popup that displays information related to an element" },
51
+ { "value": "progress", "label": "Progress - Displays an indicator showing the completion progress" },
52
+ { "value": "skeleton", "label": "Skeleton - Use to show a placeholder while content is loading" },
53
+ { "value": "separator", "label": "Separator - Visually or semantically separates content" },
54
+ { "value": "switch", "label": "Switch - A control that allows toggling between checked and not checked" },
55
+ { "value": "textarea", "label": "Textarea - Displays a form textarea" },
56
+ { "value": "accordion", "label": "Accordion - A vertically stacked set of interactive headings" },
57
+ { "value": "sheet", "label": "Sheet - Extends the Dialog component to display complementary content" },
58
+ { "value": "popover", "label": "Popover - Displays rich content in a portal, triggered by a button" },
59
+ { "value": "calendar", "label": "Calendar - A date field component for entering and editing dates" },
60
+ { "value": "command", "label": "Command - Fast, composable, unstyled command menu" },
61
+ { "value": "form", "label": "Form - Building forms with validation" },
62
+ { "value": "sidebar", "label": "Sidebar - A composable, themeable and customizable sidebar" },
63
+ { "value": "spinner", "label": "Spinner - Loading indicator animations" }
64
+ ]
65
+ }
23
66
  }
24
67
  }
25
68
  }
@@ -57,15 +57,15 @@ const MOCK_STYLES_CSS = `/* You can add global styles to this file, and also imp
57
57
 
58
58
  async function runTests() {
59
59
  console.log('\n🧪 Testing ng-add schematic...\n');
60
-
60
+
61
61
  const runner = new SchematicTestRunner('schematics', collectionPath);
62
-
62
+
63
63
  // Create a mock project tree using HostTree
64
64
  const appTree = new HostTree();
65
65
  appTree.create('/package.json', MOCK_PACKAGE_JSON);
66
66
  appTree.create('/tsconfig.json', MOCK_TSCONFIG);
67
67
  appTree.create('/src/styles.css', MOCK_STYLES_CSS);
68
-
68
+
69
69
  console.log('📁 Created mock project with:');
70
70
  console.log(' - /package.json');
71
71
  console.log(' - /tsconfig.json (with comments)');
@@ -74,9 +74,9 @@ async function runTests() {
74
74
  try {
75
75
  // Run the ng-add schematic
76
76
  const tree = await runner.runSchematic('ng-add', { skipInstall: true }, appTree);
77
-
77
+
78
78
  console.log('✅ Schematic executed successfully!\n');
79
-
79
+
80
80
  // Verify files were created
81
81
  const expectedFiles = [
82
82
  '/src/app/lib/utils/cn.ts',
@@ -84,7 +84,7 @@ async function runTests() {
84
84
  '/src/app/lib/components/ui/.gitkeep',
85
85
  '/src/ng-cn.scss'
86
86
  ];
87
-
87
+
88
88
  console.log('📄 Checking created files:');
89
89
  for (const file of expectedFiles) {
90
90
  if (tree.exists(file)) {
@@ -93,13 +93,13 @@ async function runTests() {
93
93
  console.log(` ❌ Missing: ${file}`);
94
94
  }
95
95
  }
96
-
96
+
97
97
  // Verify tsconfig was updated
98
98
  console.log('\n⚙️ Checking tsconfig.json:');
99
99
  const tsconfigContent = tree.read('/tsconfig.json').toString('utf-8');
100
100
  const tsconfig = JSON.parse(tsconfigContent);
101
101
  const paths = tsconfig.compilerOptions?.paths || {};
102
-
102
+
103
103
  const expectedPaths = ['@/*', '@/lib/*', '@/ui/*', '@/utils/*'];
104
104
  for (const p of expectedPaths) {
105
105
  if (paths[p]) {
@@ -108,7 +108,7 @@ async function runTests() {
108
108
  console.log(` ❌ Missing path alias: ${p}`);
109
109
  }
110
110
  }
111
-
111
+
112
112
  // Verify styles were imported
113
113
  console.log('\n🎨 Checking styles:');
114
114
  const stylesContent = tree.read('/src/styles.css').toString('utf-8');
@@ -117,7 +117,7 @@ async function runTests() {
117
117
  } else {
118
118
  console.log(' ❌ ng-cn.scss not imported');
119
119
  }
120
-
120
+
121
121
  // Verify dependencies
122
122
  console.log('\n📦 Checking dependencies:');
123
123
  const packageJsonContent = tree.read('/package.json').toString('utf-8');
@@ -130,9 +130,9 @@ async function runTests() {
130
130
  console.log(` ❌ Missing: ${dep}`);
131
131
  }
132
132
  }
133
-
133
+
134
134
  console.log('\n✨ All tests passed!\n');
135
-
135
+
136
136
  } catch (error) {
137
137
  console.error('\n❌ Schematic failed with error:');
138
138
  console.error(error);