@gilav21/shadcn-angular 0.0.25 → 0.0.26
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/dist/commands/add.d.ts +2 -0
- package/dist/commands/add.js +169 -114
- package/dist/commands/add.spec.js +17 -23
- package/dist/commands/diff.d.ts +8 -0
- package/dist/commands/diff.js +99 -0
- package/dist/commands/help.js +15 -6
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +171 -185
- package/dist/commands/list.d.ts +1 -0
- package/dist/commands/list.js +50 -0
- package/dist/index.js +21 -1
- package/dist/registry/index.d.ts +122 -12
- package/dist/registry/index.js +56 -168
- package/dist/utils/config.d.ts +1 -1
- package/dist/utils/config.js +22 -2
- package/dist/utils/paths.d.ts +7 -0
- package/dist/utils/paths.js +43 -0
- package/dist/utils/shortcut-registry.js +1 -13
- package/package.json +1 -1
- package/scripts/sync-registry.ts +347 -0
- package/src/commands/add.spec.ts +22 -32
- package/src/commands/add.ts +211 -137
- package/src/commands/diff.ts +133 -0
- package/src/commands/help.ts +15 -6
- package/src/commands/init.ts +329 -314
- package/src/commands/list.ts +66 -0
- package/src/index.ts +24 -1
- package/src/registry/index.ts +71 -180
- package/src/utils/config.ts +22 -3
- package/src/utils/paths.ts +52 -0
- package/src/utils/shortcut-registry.ts +1 -15
- package/vitest.config.ts +7 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { getConfig } from '../utils/config.js';
|
|
5
|
+
import { registry, getComponentNames } from '../registry/index.js';
|
|
6
|
+
import { resolveProjectPath, aliasToProjectPath } from '../utils/paths.js';
|
|
7
|
+
|
|
8
|
+
type Status = 'installed' | 'not installed';
|
|
9
|
+
|
|
10
|
+
interface ComponentStatus {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly status: Status;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function list() {
|
|
16
|
+
const cwd = process.cwd();
|
|
17
|
+
|
|
18
|
+
const config = await getConfig(cwd);
|
|
19
|
+
if (!config) {
|
|
20
|
+
console.log(chalk.red('Error: components.json not found.'));
|
|
21
|
+
console.log(chalk.dim('Run `npx @gilav21/shadcn-angular init` first.'));
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const uiBasePath = aliasToProjectPath(config.aliases.ui || 'src/components/ui');
|
|
26
|
+
const targetDir = resolveProjectPath(cwd, uiBasePath);
|
|
27
|
+
|
|
28
|
+
const statuses: ComponentStatus[] = [];
|
|
29
|
+
|
|
30
|
+
for (const name of getComponentNames()) {
|
|
31
|
+
const component = registry[name];
|
|
32
|
+
const allPresent = await allFilesExist(component.files, targetDir);
|
|
33
|
+
statuses.push({
|
|
34
|
+
name,
|
|
35
|
+
status: allPresent ? 'installed' : 'not installed',
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const installed = statuses.filter(s => s.status === 'installed').sort((a, b) => a.name.localeCompare(b.name));
|
|
40
|
+
const notInstalled = statuses.filter(s => s.status === 'not installed').sort((a, b) => a.name.localeCompare(b.name));
|
|
41
|
+
|
|
42
|
+
console.log(chalk.bold(`\nInstalled (${installed.length}):`));
|
|
43
|
+
if (installed.length === 0) {
|
|
44
|
+
console.log(chalk.dim(' None'));
|
|
45
|
+
} else {
|
|
46
|
+
for (const s of installed) {
|
|
47
|
+
console.log(chalk.green(' ✓ ') + s.name);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log(chalk.bold(`\nAvailable (${notInstalled.length}):`));
|
|
52
|
+
for (const s of notInstalled) {
|
|
53
|
+
console.log(chalk.dim(' - ') + s.name);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log('');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function allFilesExist(files: readonly string[], targetDir: string): Promise<boolean> {
|
|
60
|
+
for (const file of files) {
|
|
61
|
+
if (!await fs.pathExists(path.join(targetDir, file))) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
2
3
|
import { Command } from 'commander';
|
|
3
4
|
import { init } from './commands/init.js';
|
|
4
5
|
import { add } from './commands/add.js';
|
|
6
|
+
import { diff } from './commands/diff.js';
|
|
7
|
+
import { list } from './commands/list.js';
|
|
5
8
|
import { help } from './commands/help.js';
|
|
6
9
|
|
|
10
|
+
const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf-8')) as { version: string };
|
|
11
|
+
|
|
7
12
|
const program = new Command();
|
|
8
13
|
|
|
9
14
|
program
|
|
10
15
|
.name('shadcn-angular')
|
|
11
16
|
.description('CLI for adding shadcn-angular components to your Angular project')
|
|
12
|
-
.version(
|
|
17
|
+
.version(pkg.version);
|
|
13
18
|
|
|
14
19
|
program
|
|
15
20
|
.command('init')
|
|
16
21
|
.description('Initialize shadcn-angular in your project')
|
|
17
22
|
.option('-y, --yes', 'Skip confirmation prompt')
|
|
18
23
|
.option('-d, --defaults', 'Use default configuration')
|
|
24
|
+
.option('--remote', 'Force remote fetch from GitHub registry')
|
|
19
25
|
.option('-b, --branch <branch>', 'GitHub branch to fetch components from', 'master')
|
|
26
|
+
.option('-r, --registry <url>', 'Custom registry base URL (e.g., https://gitlab.com/org/repo/-/raw/main/packages/components)')
|
|
20
27
|
.action(init);
|
|
21
28
|
|
|
22
29
|
program
|
|
@@ -28,9 +35,25 @@ program
|
|
|
28
35
|
.option('-a, --all', 'Add all available components')
|
|
29
36
|
.option('-p, --path <path>', 'The path to add the component to')
|
|
30
37
|
.option('--remote', 'Force remote fetch from GitHub registry')
|
|
38
|
+
.option('--dry-run', 'Show what would be installed without making changes')
|
|
31
39
|
.option('-b, --branch <branch>', 'GitHub branch to fetch components from', 'master')
|
|
40
|
+
.option('-r, --registry <url>', 'Custom registry base URL (overrides components.json)')
|
|
32
41
|
.action(add);
|
|
33
42
|
|
|
43
|
+
program
|
|
44
|
+
.command('diff')
|
|
45
|
+
.description('Show differences between local and remote component versions')
|
|
46
|
+
.argument('[components...]', 'Components to diff (all installed if omitted)')
|
|
47
|
+
.option('--remote', 'Force remote fetch from GitHub registry')
|
|
48
|
+
.option('-b, --branch <branch>', 'GitHub branch to fetch from', 'master')
|
|
49
|
+
.option('-r, --registry <url>', 'Custom registry base URL')
|
|
50
|
+
.action(diff);
|
|
51
|
+
|
|
52
|
+
program
|
|
53
|
+
.command('list')
|
|
54
|
+
.description('List all components and their install status')
|
|
55
|
+
.action(list);
|
|
56
|
+
|
|
34
57
|
program
|
|
35
58
|
.command('help')
|
|
36
59
|
.description('Show detailed usage information')
|
package/src/registry/index.ts
CHANGED
|
@@ -7,25 +7,25 @@ export interface OptionalDependency {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export interface ComponentDefinition {
|
|
10
|
-
name: string;
|
|
11
|
-
files: string[];
|
|
12
|
-
peerFiles?: string[];
|
|
13
|
-
dependencies?: string[];
|
|
14
|
-
optionalDependencies?: readonly OptionalDependency[];
|
|
15
|
-
npmDependencies?: string[];
|
|
16
|
-
libFiles?: string[];
|
|
17
|
-
shortcutDefinitions?: {
|
|
18
|
-
exportName: string;
|
|
19
|
-
componentName: string;
|
|
20
|
-
sourceFile: string;
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly files: readonly string[];
|
|
12
|
+
readonly peerFiles?: readonly string[];
|
|
13
|
+
readonly dependencies?: readonly string[];
|
|
14
|
+
readonly optionalDependencies?: readonly OptionalDependency[];
|
|
15
|
+
readonly npmDependencies?: readonly string[];
|
|
16
|
+
readonly libFiles?: readonly string[];
|
|
17
|
+
readonly shortcutDefinitions?: readonly {
|
|
18
|
+
readonly exportName: string;
|
|
19
|
+
readonly componentName: string;
|
|
20
|
+
readonly sourceFile: string;
|
|
21
21
|
}[];
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
function defineRegistry<T extends Record<string, ComponentDefinition>>(reg: T): { readonly [K in keyof T]: ComponentDefinition } {
|
|
25
|
+
return reg;
|
|
26
|
+
}
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
// Files are relative to the components/ui directory
|
|
28
|
-
export const registry: Record<string, ComponentDefinition> = {
|
|
28
|
+
export const registry = defineRegistry({
|
|
29
29
|
accordion: {
|
|
30
30
|
name: 'accordion',
|
|
31
31
|
files: ['accordion.component.ts'],
|
|
@@ -33,7 +33,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
33
33
|
autocomplete: {
|
|
34
34
|
name: 'autocomplete',
|
|
35
35
|
files: ['autocomplete.component.ts', 'highlight.pipe.ts'],
|
|
36
|
-
dependencies: ['
|
|
36
|
+
dependencies: ['badge', 'command', 'popover'],
|
|
37
37
|
},
|
|
38
38
|
alert: {
|
|
39
39
|
name: 'alert',
|
|
@@ -66,12 +66,11 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
66
66
|
},
|
|
67
67
|
'button-group': {
|
|
68
68
|
name: 'button-group',
|
|
69
|
-
files: ['button-group.component.ts']
|
|
70
|
-
dependencies: ['button']
|
|
69
|
+
files: ['button-group.component.ts']
|
|
71
70
|
},
|
|
72
71
|
calendar: {
|
|
73
72
|
name: 'calendar',
|
|
74
|
-
files: ['calendar.
|
|
73
|
+
files: ['calendar-locales.ts', 'calendar.component.ts'],
|
|
75
74
|
dependencies: ['button', 'select'],
|
|
76
75
|
},
|
|
77
76
|
card: {
|
|
@@ -93,7 +92,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
93
92
|
'color-picker': {
|
|
94
93
|
name: 'color-picker',
|
|
95
94
|
files: ['color-picker.component.ts'],
|
|
96
|
-
dependencies: ['
|
|
95
|
+
dependencies: ['input', 'popover', 'tabs'],
|
|
97
96
|
},
|
|
98
97
|
confetti: {
|
|
99
98
|
name: 'confetti',
|
|
@@ -114,7 +113,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
114
113
|
},
|
|
115
114
|
'context-menu': {
|
|
116
115
|
name: 'context-menu',
|
|
117
|
-
files: ['context-menu.component.ts'
|
|
116
|
+
files: ['context-menu.component.ts'],
|
|
118
117
|
},
|
|
119
118
|
'date-picker': {
|
|
120
119
|
name: 'date-picker',
|
|
@@ -124,7 +123,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
124
123
|
chat: {
|
|
125
124
|
name: 'chat',
|
|
126
125
|
files: ['chat.component.ts'],
|
|
127
|
-
dependencies: ['avatar', 'button', '
|
|
126
|
+
dependencies: ['avatar', 'button', 'scroll-area', 'textarea'],
|
|
128
127
|
},
|
|
129
128
|
'streaming-text': {
|
|
130
129
|
name: 'streaming-text',
|
|
@@ -138,7 +137,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
138
137
|
'code-block': {
|
|
139
138
|
name: 'code-block',
|
|
140
139
|
files: ['code-block.component.ts'],
|
|
141
|
-
dependencies: ['button'
|
|
140
|
+
dependencies: ['button'],
|
|
142
141
|
},
|
|
143
142
|
'text-reveal': {
|
|
144
143
|
name: 'text-reveal',
|
|
@@ -146,31 +145,11 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
146
145
|
},
|
|
147
146
|
'data-table': {
|
|
148
147
|
name: 'data-table',
|
|
149
|
-
files: [
|
|
150
|
-
'data-table/data-table.component.ts',
|
|
151
|
-
'data-table/data-table-column-header.component.ts',
|
|
152
|
-
'data-table/data-table-pagination.component.ts',
|
|
153
|
-
'data-table/data-table-multiselect-filter.component.ts',
|
|
154
|
-
'data-table/data-table.types.ts',
|
|
155
|
-
'data-table/data-table.utils.ts',
|
|
156
|
-
'data-table/index.ts',
|
|
157
|
-
],
|
|
148
|
+
files: ['calendar-locales.ts', 'data-table/component-pool.service.ts', 'data-table/data-table-column-header.component.ts', 'data-table/data-table-date-filter.component.ts', 'data-table/data-table-multiselect-filter.component.ts', 'data-table/data-table-pagination.component.ts', 'data-table/data-table.component.ts', 'data-table/data-table.types.ts', 'data-table/data-table.utils.ts', 'data-table/index.ts'],
|
|
158
149
|
peerFiles: [
|
|
159
150
|
'context-menu-integrations.ts',
|
|
160
151
|
],
|
|
161
|
-
dependencies: [
|
|
162
|
-
'table',
|
|
163
|
-
'input',
|
|
164
|
-
'button',
|
|
165
|
-
'checkbox',
|
|
166
|
-
'select',
|
|
167
|
-
'pagination',
|
|
168
|
-
'popover',
|
|
169
|
-
'component-outlet',
|
|
170
|
-
'icon',
|
|
171
|
-
'command',
|
|
172
|
-
'badge',
|
|
173
|
-
],
|
|
152
|
+
dependencies: ['badge', 'button', 'calendar', 'checkbox', 'command', 'component-outlet', 'context-menu', 'icon', 'input', 'pagination', 'popover', 'select', 'table'],
|
|
174
153
|
libFiles: ['xlsx.ts'],
|
|
175
154
|
optionalDependencies: [
|
|
176
155
|
{ name: 'context-menu', description: 'Enables right-click context menus on rows and headers' },
|
|
@@ -182,18 +161,12 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
182
161
|
},
|
|
183
162
|
dock: {
|
|
184
163
|
name: 'dock',
|
|
185
|
-
files: [
|
|
186
|
-
'dock.component.ts',
|
|
187
|
-
'dock-item.component.ts',
|
|
188
|
-
'dock-icon.component.ts',
|
|
189
|
-
'dock-label.component.ts',
|
|
190
|
-
],
|
|
191
|
-
dependencies: ['icon'],
|
|
164
|
+
files: ['dock-icon.component.ts', 'dock-item.component.ts', 'dock-label.component.ts', 'dock.component.ts'],
|
|
192
165
|
},
|
|
193
166
|
'tree-select': {
|
|
194
167
|
name: 'tree-select',
|
|
195
168
|
files: ['tree-select.component.ts'],
|
|
196
|
-
dependencies: ['popover', 'tree'
|
|
169
|
+
dependencies: ['popover', 'tree'],
|
|
197
170
|
},
|
|
198
171
|
'virtual-scroll': {
|
|
199
172
|
name: 'virtual-scroll',
|
|
@@ -222,7 +195,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
222
195
|
},
|
|
223
196
|
icon: {
|
|
224
197
|
name: 'icon',
|
|
225
|
-
files: ['icon.component.ts'],
|
|
198
|
+
files: ['icon.component.ts', 'icon.token.ts'],
|
|
226
199
|
},
|
|
227
200
|
|
|
228
201
|
'file-upload': {
|
|
@@ -234,19 +207,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
234
207
|
name: 'file-viewer',
|
|
235
208
|
files: ['file-viewer.component.ts'],
|
|
236
209
|
dependencies: ['spinner'],
|
|
237
|
-
libFiles: [
|
|
238
|
-
'file-type-detector.ts',
|
|
239
|
-
'inflate.ts',
|
|
240
|
-
'zip-reader.ts',
|
|
241
|
-
'image-validator.ts',
|
|
242
|
-
'ole2-reader.ts',
|
|
243
|
-
'pptx-parser.ts',
|
|
244
|
-
'xlsx-reader.ts',
|
|
245
|
-
'docx-parser.ts',
|
|
246
|
-
'doc-enhanced-parser.ts',
|
|
247
|
-
'ppt-parser.ts',
|
|
248
|
-
'svg-sanitizer.ts',
|
|
249
|
-
],
|
|
210
|
+
libFiles: ['doc-enhanced-parser.ts', 'docx-parser.ts', 'file-type-detector.ts', 'image-validator.ts', 'inflate.ts', 'ole2-reader.ts', 'ppt-parser.ts', 'pptx-parser.ts', 'svg-sanitizer.ts', 'xlsx-reader.ts', 'zip-reader.ts'],
|
|
250
211
|
},
|
|
251
212
|
'hover-card': {
|
|
252
213
|
name: 'hover-card',
|
|
@@ -254,12 +215,11 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
254
215
|
},
|
|
255
216
|
input: {
|
|
256
217
|
name: 'input',
|
|
257
|
-
files: ['input.
|
|
218
|
+
files: ['input-group.token.ts', 'input.component.ts'],
|
|
258
219
|
},
|
|
259
220
|
'input-group': {
|
|
260
221
|
name: 'input-group',
|
|
261
222
|
files: ['input-group.component.ts', 'input-group.token.ts'],
|
|
262
|
-
dependencies: ['input'],
|
|
263
223
|
},
|
|
264
224
|
'input-otp': {
|
|
265
225
|
name: 'input-otp',
|
|
@@ -332,7 +292,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
332
292
|
sidebar: {
|
|
333
293
|
name: 'sidebar',
|
|
334
294
|
files: ['sidebar.component.ts'],
|
|
335
|
-
dependencies: ['scroll-area', 'tooltip'
|
|
295
|
+
dependencies: ['scroll-area', 'tooltip'],
|
|
336
296
|
},
|
|
337
297
|
skeleton: {
|
|
338
298
|
name: 'skeleton',
|
|
@@ -364,7 +324,7 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
364
324
|
},
|
|
365
325
|
textarea: {
|
|
366
326
|
name: 'textarea',
|
|
367
|
-
files: ['
|
|
327
|
+
files: ['input-group.token.ts', 'textarea.component.ts'],
|
|
368
328
|
},
|
|
369
329
|
timeline: {
|
|
370
330
|
name: 'timeline',
|
|
@@ -389,60 +349,29 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
389
349
|
tree: {
|
|
390
350
|
name: 'tree',
|
|
391
351
|
files: ['tree.component.ts'],
|
|
392
|
-
dependencies: ['icon'],
|
|
393
352
|
optionalDependencies: [
|
|
394
353
|
{ name: 'context-menu', description: 'Enables right-click context menus on tree nodes' },
|
|
395
354
|
],
|
|
396
355
|
},
|
|
397
356
|
'speed-dial': {
|
|
398
357
|
name: 'speed-dial',
|
|
399
|
-
files: ['speed-dial.component.ts']
|
|
400
|
-
dependencies: ['button']
|
|
358
|
+
files: ['speed-dial.component.ts']
|
|
401
359
|
},
|
|
402
360
|
'chip-list': {
|
|
403
361
|
name: 'chip-list',
|
|
404
|
-
files: ['chip-list.component.ts'],
|
|
405
|
-
dependencies: ['badge', 'button', 'input'
|
|
362
|
+
files: ['chip-list.component.ts', 'input-group.token.ts'],
|
|
363
|
+
dependencies: ['badge', 'button', 'input'],
|
|
406
364
|
},
|
|
407
365
|
'emoji-picker': {
|
|
408
366
|
name: 'emoji-picker',
|
|
409
|
-
files: ['emoji-
|
|
367
|
+
files: ['emoji-data.ts', 'emoji-picker.component.ts'],
|
|
410
368
|
dependencies: ['input', 'scroll-area', 'tooltip'],
|
|
411
369
|
},
|
|
412
370
|
'rich-text-editor': {
|
|
413
371
|
name: 'rich-text-editor',
|
|
414
|
-
files: [
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
'rich-text-sanitizer.service.ts',
|
|
418
|
-
'rich-text-markdown.service.ts',
|
|
419
|
-
'rich-text-paste-normalizer.service.ts',
|
|
420
|
-
'rich-text-command-registry.service.ts',
|
|
421
|
-
'rich-text-mention.component.ts',
|
|
422
|
-
'rich-text-image-resizer.component.ts',
|
|
423
|
-
'rich-text-locales.ts',
|
|
424
|
-
],
|
|
425
|
-
dependencies: [
|
|
426
|
-
'button',
|
|
427
|
-
'separator',
|
|
428
|
-
'popover',
|
|
429
|
-
'emoji-picker',
|
|
430
|
-
'autocomplete',
|
|
431
|
-
'select',
|
|
432
|
-
'input',
|
|
433
|
-
'dialog',
|
|
434
|
-
'scroll-area',
|
|
435
|
-
],
|
|
436
|
-
libFiles: [
|
|
437
|
-
'pdf-parser.ts',
|
|
438
|
-
'image-validator.ts',
|
|
439
|
-
'svg-sanitizer.ts',
|
|
440
|
-
'shortcut-binding.service.ts',
|
|
441
|
-
'docx-parser.ts',
|
|
442
|
-
'docx-to-editor-html.ts',
|
|
443
|
-
'zip-reader.ts',
|
|
444
|
-
'inflate.ts',
|
|
445
|
-
],
|
|
372
|
+
files: ['rich-text-command-registry.service.ts', 'rich-text-editor.component.ts', 'rich-text-image-resizer.component.ts', 'rich-text-locales.ts', 'rich-text-markdown.service.ts', 'rich-text-mention.component.ts', 'rich-text-paste-normalizer.service.ts', 'rich-text-sanitizer.service.ts', 'rich-text-toolbar.component.ts'],
|
|
373
|
+
dependencies: ['autocomplete', 'button', 'dialog', 'emoji-picker', 'popover', 'scroll-area', 'separator'],
|
|
374
|
+
libFiles: ['docx-parser.ts', 'docx-to-editor-html.ts', 'image-validator.ts', 'inflate.ts', 'pdf-parser.ts', 'shortcut-binding.service.ts', 'svg-sanitizer.ts', 'zip-reader.ts'],
|
|
446
375
|
shortcutDefinitions: [
|
|
447
376
|
{
|
|
448
377
|
exportName: 'RICH_TEXT_SHORTCUT_DEFINITIONS',
|
|
@@ -454,102 +383,54 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
454
383
|
// Chart Components
|
|
455
384
|
'pie-chart': {
|
|
456
385
|
name: 'pie-chart',
|
|
457
|
-
files: [
|
|
458
|
-
'charts/pie-chart.component.ts',
|
|
459
|
-
'charts/chart.types.ts',
|
|
460
|
-
'charts/chart.utils.ts',
|
|
461
|
-
],
|
|
386
|
+
files: ['charts/chart.types.ts', 'charts/chart.utils.ts', 'charts/pie-chart.component.ts'],
|
|
462
387
|
},
|
|
463
388
|
'pie-chart-drilldown': {
|
|
464
389
|
name: 'pie-chart-drilldown',
|
|
465
|
-
files: [
|
|
466
|
-
'charts/pie-chart-drilldown.component.ts',
|
|
467
|
-
'charts/chart.types.ts',
|
|
468
|
-
'charts/chart.utils.ts',
|
|
469
|
-
],
|
|
390
|
+
files: ['charts/chart.types.ts', 'charts/chart.utils.ts', 'charts/pie-chart-drilldown.component.ts'],
|
|
470
391
|
},
|
|
471
392
|
'bar-chart': {
|
|
472
393
|
name: 'bar-chart',
|
|
473
|
-
files: [
|
|
474
|
-
'charts/bar-chart.component.ts',
|
|
475
|
-
'charts/chart.types.ts',
|
|
476
|
-
'charts/chart.utils.ts',
|
|
477
|
-
],
|
|
394
|
+
files: ['charts/bar-chart.component.ts', 'charts/chart.types.ts', 'charts/chart.utils.ts'],
|
|
478
395
|
},
|
|
479
396
|
'bar-chart-drilldown': {
|
|
480
397
|
name: 'bar-chart-drilldown',
|
|
481
|
-
files: [
|
|
482
|
-
'charts/bar-chart-drilldown.component.ts',
|
|
483
|
-
'charts/chart.types.ts',
|
|
484
|
-
'charts/chart.utils.ts',
|
|
485
|
-
],
|
|
398
|
+
files: ['charts/bar-chart-drilldown.component.ts', 'charts/chart.types.ts', 'charts/chart.utils.ts'],
|
|
486
399
|
},
|
|
487
400
|
'stacked-bar-chart': {
|
|
488
401
|
name: 'stacked-bar-chart',
|
|
489
|
-
files: [
|
|
490
|
-
'charts/stacked-bar-chart.component.ts',
|
|
491
|
-
'charts/chart.types.ts',
|
|
492
|
-
'charts/chart.utils.ts',
|
|
493
|
-
],
|
|
402
|
+
files: ['charts/chart.types.ts', 'charts/chart.utils.ts', 'charts/stacked-bar-chart.component.ts'],
|
|
494
403
|
},
|
|
495
404
|
'column-range-chart': {
|
|
496
405
|
name: 'column-range-chart',
|
|
497
|
-
files: [
|
|
498
|
-
'charts/column-range-chart.component.ts',
|
|
499
|
-
'charts/chart.types.ts',
|
|
500
|
-
'charts/chart.utils.ts',
|
|
501
|
-
],
|
|
406
|
+
files: ['charts/chart.types.ts', 'charts/chart.utils.ts', 'charts/column-range-chart.component.ts'],
|
|
502
407
|
},
|
|
503
408
|
'bar-race-chart': {
|
|
504
409
|
name: 'bar-race-chart',
|
|
505
|
-
files: [
|
|
506
|
-
'charts/bar-race-chart.component.ts',
|
|
507
|
-
'charts/chart.types.ts',
|
|
508
|
-
'charts/chart.utils.ts',
|
|
509
|
-
],
|
|
410
|
+
files: ['charts/bar-race-chart.component.ts', 'charts/chart.types.ts', 'charts/chart.utils.ts'],
|
|
510
411
|
},
|
|
511
412
|
'org-chart': {
|
|
512
413
|
name: 'org-chart',
|
|
513
|
-
files: [
|
|
514
|
-
'charts/org-chart.component.ts',
|
|
515
|
-
'charts/chart.types.ts',
|
|
516
|
-
'charts/chart.utils.ts',
|
|
517
|
-
],
|
|
414
|
+
files: ['charts/chart.types.ts', 'charts/chart.utils.ts', 'charts/org-chart.component.ts'],
|
|
518
415
|
},
|
|
519
416
|
'bento-grid': {
|
|
520
417
|
name: 'bento-grid',
|
|
521
|
-
dependencies: ['
|
|
522
|
-
files: [
|
|
523
|
-
'bento-grid.component.ts',
|
|
524
|
-
],
|
|
418
|
+
dependencies: ['component-outlet', 'context-menu'],
|
|
419
|
+
files: ['bento-grid.component.ts'],
|
|
525
420
|
},
|
|
526
421
|
'page-builder': {
|
|
527
422
|
name: 'page-builder',
|
|
528
|
-
dependencies: [
|
|
529
|
-
|
|
530
|
-
'button',
|
|
531
|
-
'input',
|
|
532
|
-
'label',
|
|
533
|
-
'select',
|
|
534
|
-
'switch',
|
|
535
|
-
'slider',
|
|
536
|
-
'icon'
|
|
537
|
-
],
|
|
538
|
-
files: [
|
|
539
|
-
'page-builder/page-builder.component.ts',
|
|
540
|
-
'page-builder/page-builder.types.ts',
|
|
541
|
-
'page-builder/property-editor.component.ts',
|
|
542
|
-
'page-builder/page-renderer.component.ts'
|
|
543
|
-
],
|
|
423
|
+
dependencies: ['bento-grid', 'icon', 'select', 'switch'],
|
|
424
|
+
files: ['page-builder/page-builder.component.ts', 'page-builder/page-builder.types.ts', 'page-builder/property-editor.component.ts'],
|
|
544
425
|
},
|
|
545
426
|
'component-outlet': {
|
|
546
427
|
name: 'component-outlet',
|
|
547
|
-
files: ['component-outlet.directive.ts'],
|
|
428
|
+
files: ['component-outlet.directive.ts', 'data-table/component-pool.service.ts'],
|
|
548
429
|
},
|
|
549
430
|
'split-button': {
|
|
550
431
|
name: 'split-button',
|
|
551
432
|
files: ['split-button.component.ts'],
|
|
552
|
-
dependencies: ['button'
|
|
433
|
+
dependencies: ['button'],
|
|
553
434
|
},
|
|
554
435
|
// Animations
|
|
555
436
|
'gradient-text': {
|
|
@@ -616,16 +497,26 @@ export const registry: Record<string, ComponentDefinition> = {
|
|
|
616
497
|
name: 'particles',
|
|
617
498
|
files: ['particles.component.ts'],
|
|
618
499
|
},
|
|
619
|
-
// Kanban
|
|
620
500
|
kanban: {
|
|
621
501
|
name: 'kanban',
|
|
622
|
-
files: ['kanban.
|
|
502
|
+
files: ['kanban-locales.ts', 'kanban.component.ts'],
|
|
623
503
|
libFiles: ['shortcut-binding.service.ts'],
|
|
624
|
-
dependencies: [
|
|
625
|
-
'badge', 'avatar', 'scroll-area', 'separator',
|
|
626
|
-
'button', 'input', 'textarea', 'label',
|
|
627
|
-
'chip-list', 'autocomplete',
|
|
628
|
-
'dialog', 'alert-dialog', 'context-menu',
|
|
629
|
-
],
|
|
504
|
+
dependencies: ['alert-dialog', 'autocomplete', 'avatar', 'badge', 'button', 'chip-list', 'context-menu', 'dialog', 'input', 'label', 'scroll-area', 'separator', 'textarea'],
|
|
630
505
|
},
|
|
631
|
-
|
|
506
|
+
'shortcut-bindings-dialog': {
|
|
507
|
+
name: 'shortcut-bindings-dialog',
|
|
508
|
+
files: ['shortcut-bindings-dialog.component.ts'],
|
|
509
|
+
libFiles: ['shortcut-binding.service.ts'],
|
|
510
|
+
dependencies: ['accordion', 'badge', 'button', 'dialog', 'scroll-area'],
|
|
511
|
+
},
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
export type ComponentName = keyof typeof registry;
|
|
515
|
+
|
|
516
|
+
export function isComponentName(name: string): name is ComponentName {
|
|
517
|
+
return name in registry;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
export function getComponentNames(): ComponentName[] {
|
|
521
|
+
return Object.keys(registry) as ComponentName[];
|
|
522
|
+
}
|
package/src/utils/config.ts
CHANGED
|
@@ -2,8 +2,8 @@ import fs from 'fs-extra';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
4
|
export interface Config {
|
|
5
|
-
$schema: string;
|
|
6
5
|
style: 'default';
|
|
6
|
+
registry?: string;
|
|
7
7
|
tailwind: {
|
|
8
8
|
css: string;
|
|
9
9
|
baseColor: 'neutral' | 'slate' | 'stone' | 'gray' | 'zinc';
|
|
@@ -19,7 +19,6 @@ export interface Config {
|
|
|
19
19
|
|
|
20
20
|
export function getDefaultConfig(): Config {
|
|
21
21
|
return {
|
|
22
|
-
$schema: 'https://shadcn-angular.dev/schema.json',
|
|
23
22
|
style: 'default',
|
|
24
23
|
tailwind: {
|
|
25
24
|
css: 'src/styles.scss',
|
|
@@ -35,6 +34,21 @@ export function getDefaultConfig(): Config {
|
|
|
35
34
|
};
|
|
36
35
|
}
|
|
37
36
|
|
|
37
|
+
function validateConfig(data: unknown): data is Config {
|
|
38
|
+
if (!data || typeof data !== 'object') return false;
|
|
39
|
+
const obj = data as Record<string, unknown>;
|
|
40
|
+
|
|
41
|
+
if (!obj['tailwind'] || typeof obj['tailwind'] !== 'object') return false;
|
|
42
|
+
const tw = obj['tailwind'] as Record<string, unknown>;
|
|
43
|
+
if (typeof tw['css'] !== 'string' || typeof tw['baseColor'] !== 'string') return false;
|
|
44
|
+
|
|
45
|
+
if (!obj['aliases'] || typeof obj['aliases'] !== 'object') return false;
|
|
46
|
+
const aliases = obj['aliases'] as Record<string, unknown>;
|
|
47
|
+
if (typeof aliases['components'] !== 'string' || typeof aliases['utils'] !== 'string' || typeof aliases['ui'] !== 'string') return false;
|
|
48
|
+
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
|
|
38
52
|
export async function getConfig(cwd: string): Promise<Config | null> {
|
|
39
53
|
const configPath = path.join(cwd, 'components.json');
|
|
40
54
|
|
|
@@ -43,7 +57,12 @@ export async function getConfig(cwd: string): Promise<Config | null> {
|
|
|
43
57
|
}
|
|
44
58
|
|
|
45
59
|
try {
|
|
46
|
-
|
|
60
|
+
const data: unknown = await fs.readJson(configPath);
|
|
61
|
+
if (!validateConfig(data)) {
|
|
62
|
+
console.error('Error: components.json is missing required fields (tailwind.css, tailwind.baseColor, aliases.components, aliases.utils, aliases.ui).');
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return data;
|
|
47
66
|
} catch {
|
|
48
67
|
return null;
|
|
49
68
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
|
|
8
|
+
export function validateBranch(branch: string): void {
|
|
9
|
+
if (!/^[\w.\-/]+$/.test(branch)) {
|
|
10
|
+
throw new Error(`Invalid branch name: ${branch}`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function getDefaultRegistryBaseUrl(branch: string): string {
|
|
15
|
+
validateBranch(branch);
|
|
16
|
+
return `https://raw.githubusercontent.com/gilav21/shadcn-angular/${branch}/packages/components`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function getRegistryBaseUrl(branch: string, customRegistry?: string): string {
|
|
20
|
+
const base = customRegistry ?? getDefaultRegistryBaseUrl(branch);
|
|
21
|
+
return `${base}/ui`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function getLibRegistryBaseUrl(branch: string, customRegistry?: string): string {
|
|
25
|
+
const base = customRegistry ?? getDefaultRegistryBaseUrl(branch);
|
|
26
|
+
return `${base}/lib`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function getLocalComponentsDir(): string | null {
|
|
30
|
+
const localPath = path.resolve(__dirname, '../../../../components/ui');
|
|
31
|
+
return fs.existsSync(localPath) ? localPath : null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function getLocalLibDir(): string | null {
|
|
35
|
+
const localPath = path.resolve(__dirname, '../../../../components/lib');
|
|
36
|
+
return fs.existsSync(localPath) ? localPath : null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function resolveProjectPath(cwd: string, inputPath: string): string {
|
|
40
|
+
const resolved = path.resolve(cwd, inputPath);
|
|
41
|
+
const relative = path.relative(cwd, resolved);
|
|
42
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
43
|
+
throw new Error(`Path must stay inside the project directory: ${inputPath}`);
|
|
44
|
+
}
|
|
45
|
+
return resolved;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function aliasToProjectPath(aliasOrPath: string): string {
|
|
49
|
+
return aliasOrPath.startsWith('@/')
|
|
50
|
+
? path.join('src', aliasOrPath.slice(2))
|
|
51
|
+
: aliasOrPath;
|
|
52
|
+
}
|