@gilav21/shadcn-angular 0.0.14 → 0.0.16
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.js +67 -4
- package/dist/commands/init.js +75 -46
- package/dist/registry/index.d.ts +5 -0
- package/dist/registry/index.js +106 -6
- package/dist/utils/config.d.ts +0 -1
- package/dist/utils/config.js +0 -1
- package/dist/utils/shortcut-registry.d.ts +7 -0
- package/dist/utils/shortcut-registry.js +58 -0
- package/package.json +1 -1
- package/src/commands/add.ts +95 -22
- package/src/commands/init.ts +147 -118
- package/src/registry/index.ts +111 -6
- package/src/utils/config.ts +0 -2
- package/src/utils/shortcut-registry.ts +79 -0
package/dist/commands/add.js
CHANGED
|
@@ -7,10 +7,12 @@ import ora from 'ora';
|
|
|
7
7
|
import { getConfig } from '../utils/config.js';
|
|
8
8
|
import { registry } from '../registry/index.js';
|
|
9
9
|
import { installPackages } from '../utils/package-manager.js';
|
|
10
|
+
import { writeShortcutRegistryIndex } from '../utils/shortcut-registry.js';
|
|
10
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
12
|
const __dirname = path.dirname(__filename);
|
|
12
13
|
// Base URL for the component registry (GitHub raw content)
|
|
13
14
|
const REGISTRY_BASE_URL = 'https://raw.githubusercontent.com/gilav21/shadcn-angular/master/packages/components/ui';
|
|
15
|
+
const LIB_REGISTRY_BASE_URL = 'https://raw.githubusercontent.com/gilav21/shadcn-angular/master/packages/components/lib';
|
|
14
16
|
// Components source directory (relative to CLI dist folder) for local dev
|
|
15
17
|
function getLocalComponentsDir() {
|
|
16
18
|
// From dist/commands/add.js -> packages/components/ui
|
|
@@ -25,6 +27,26 @@ function getLocalComponentsDir() {
|
|
|
25
27
|
}
|
|
26
28
|
return null;
|
|
27
29
|
}
|
|
30
|
+
function getLocalLibDir() {
|
|
31
|
+
const fromDist = path.resolve(__dirname, '../../../components/lib');
|
|
32
|
+
if (fs.existsSync(fromDist)) {
|
|
33
|
+
return fromDist;
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
function resolveProjectPath(cwd, inputPath) {
|
|
38
|
+
const resolved = path.resolve(cwd, inputPath);
|
|
39
|
+
const relative = path.relative(cwd, resolved);
|
|
40
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
41
|
+
throw new Error(`Path must stay inside the project directory: ${inputPath}`);
|
|
42
|
+
}
|
|
43
|
+
return resolved;
|
|
44
|
+
}
|
|
45
|
+
function aliasToProjectPath(aliasOrPath) {
|
|
46
|
+
return aliasOrPath.startsWith('@/')
|
|
47
|
+
? path.join('src', aliasOrPath.slice(2))
|
|
48
|
+
: aliasOrPath;
|
|
49
|
+
}
|
|
28
50
|
async function fetchComponentContent(file, options) {
|
|
29
51
|
const localDir = getLocalComponentsDir();
|
|
30
52
|
// 1. Prefer local if available and not forced remote
|
|
@@ -50,6 +72,36 @@ async function fetchComponentContent(file, options) {
|
|
|
50
72
|
throw error;
|
|
51
73
|
}
|
|
52
74
|
}
|
|
75
|
+
async function fetchLibContent(file, options) {
|
|
76
|
+
const localDir = getLocalLibDir();
|
|
77
|
+
if (localDir && !options.remote) {
|
|
78
|
+
const localPath = path.join(localDir, file);
|
|
79
|
+
if (await fs.pathExists(localPath)) {
|
|
80
|
+
return fs.readFile(localPath, 'utf-8');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const url = `${LIB_REGISTRY_BASE_URL}/${file}`;
|
|
84
|
+
const response = await fetch(url);
|
|
85
|
+
if (!response.ok) {
|
|
86
|
+
throw new Error(`Failed to fetch library file from ${url}: ${response.statusText}`);
|
|
87
|
+
}
|
|
88
|
+
return response.text();
|
|
89
|
+
}
|
|
90
|
+
function collectInstalledShortcutEntries(targetDir) {
|
|
91
|
+
const entries = [];
|
|
92
|
+
for (const definition of Object.values(registry)) {
|
|
93
|
+
if (!definition.shortcutDefinitions?.length) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
for (const shortcutDefinition of definition.shortcutDefinitions) {
|
|
97
|
+
const sourcePath = path.join(targetDir, shortcutDefinition.sourceFile);
|
|
98
|
+
if (fs.existsSync(sourcePath)) {
|
|
99
|
+
entries.push(shortcutDefinition);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return entries;
|
|
104
|
+
}
|
|
53
105
|
export async function add(components, options) {
|
|
54
106
|
const cwd = process.cwd();
|
|
55
107
|
// Load config
|
|
@@ -103,9 +155,8 @@ export async function add(components, options) {
|
|
|
103
155
|
}
|
|
104
156
|
};
|
|
105
157
|
componentsToAdd.forEach(c => resolveDeps(c));
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
: path.join(cwd, 'src/components/ui');
|
|
158
|
+
const uiBasePath = options.path ?? aliasToProjectPath(config.aliases.ui || 'src/components/ui');
|
|
159
|
+
const targetDir = resolveProjectPath(cwd, uiBasePath);
|
|
109
160
|
// Check for existing files and diff
|
|
110
161
|
const componentsToInstall = [];
|
|
111
162
|
const componentsToSkip = [];
|
|
@@ -125,7 +176,7 @@ export async function add(components, options) {
|
|
|
125
176
|
// Transform imports for comparison
|
|
126
177
|
const utilsAlias = config.aliases.utils;
|
|
127
178
|
remoteContent = remoteContent.replace(/(\.\.\/)+lib\/utils/g, utilsAlias);
|
|
128
|
-
const normalize = (str) => str.replace(/\
|
|
179
|
+
const normalize = (str) => str.replace(/\r\n/g, '\n').trim();
|
|
129
180
|
if (normalize(localContent) !== normalize(remoteContent)) {
|
|
130
181
|
hasChanges = true;
|
|
131
182
|
}
|
|
@@ -252,6 +303,18 @@ export async function add(components, options) {
|
|
|
252
303
|
}
|
|
253
304
|
}
|
|
254
305
|
}
|
|
306
|
+
const shortcutEntries = collectInstalledShortcutEntries(targetDir);
|
|
307
|
+
if (shortcutEntries.length > 0) {
|
|
308
|
+
const utilsPathResolved = resolveProjectPath(cwd, aliasToProjectPath(config.aliases.utils) + '.ts');
|
|
309
|
+
const utilsDir = path.dirname(utilsPathResolved);
|
|
310
|
+
const shortcutServicePath = path.join(utilsDir, 'shortcut-binding.service.ts');
|
|
311
|
+
if (!await fs.pathExists(shortcutServicePath)) {
|
|
312
|
+
const shortcutServiceContent = await fetchLibContent('shortcut-binding.service.ts', options);
|
|
313
|
+
await fs.ensureDir(utilsDir);
|
|
314
|
+
await fs.writeFile(shortcutServicePath, shortcutServiceContent);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
await writeShortcutRegistryIndex(cwd, config, shortcutEntries);
|
|
255
318
|
if (componentsToSkip.length > 0) {
|
|
256
319
|
console.log('\n' + chalk.dim('Components skipped (up to date):'));
|
|
257
320
|
componentsToSkip.forEach(name => {
|
package/dist/commands/init.js
CHANGED
|
@@ -1,12 +1,53 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
3
4
|
import prompts from 'prompts';
|
|
4
5
|
import chalk from 'chalk';
|
|
5
6
|
import ora from 'ora';
|
|
6
|
-
import { execa } from 'execa';
|
|
7
7
|
import { getDefaultConfig } from '../utils/config.js';
|
|
8
8
|
import { getStylesTemplate } from '../templates/styles.js';
|
|
9
9
|
import { getUtilsTemplate } from '../templates/utils.js';
|
|
10
|
+
import { installPackages } from '../utils/package-manager.js';
|
|
11
|
+
import { writeShortcutRegistryIndex } from '../utils/shortcut-registry.js';
|
|
12
|
+
const LIB_REGISTRY_BASE_URL = 'https://raw.githubusercontent.com/gilav21/shadcn-angular/master/packages/components/lib';
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = path.dirname(__filename);
|
|
15
|
+
function getLocalLibDir() {
|
|
16
|
+
const fromDist = path.resolve(__dirname, '../../../components/lib');
|
|
17
|
+
if (fs.existsSync(fromDist)) {
|
|
18
|
+
return fromDist;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
async function fetchLibFileContent(file) {
|
|
23
|
+
const localLibDir = getLocalLibDir();
|
|
24
|
+
if (localLibDir) {
|
|
25
|
+
const localPath = path.join(localLibDir, file);
|
|
26
|
+
if (await fs.pathExists(localPath)) {
|
|
27
|
+
return fs.readFile(localPath, 'utf-8');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const url = `${LIB_REGISTRY_BASE_URL}/${file}`;
|
|
31
|
+
const response = await fetch(url);
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
throw new Error(`Failed to fetch library file from ${url}: ${response.statusText}`);
|
|
34
|
+
}
|
|
35
|
+
return response.text();
|
|
36
|
+
}
|
|
37
|
+
function resolveProjectPath(cwd, inputPath) {
|
|
38
|
+
const resolved = path.resolve(cwd, inputPath);
|
|
39
|
+
const relative = path.relative(cwd, resolved);
|
|
40
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
41
|
+
throw new Error(`Path must stay inside the project directory: ${inputPath}`);
|
|
42
|
+
}
|
|
43
|
+
return resolved;
|
|
44
|
+
}
|
|
45
|
+
function resolveAliasOrPath(cwd, aliasOrPath) {
|
|
46
|
+
const normalized = aliasOrPath.startsWith('@/')
|
|
47
|
+
? path.join('src', aliasOrPath.slice(2))
|
|
48
|
+
: aliasOrPath;
|
|
49
|
+
return resolveProjectPath(cwd, normalized);
|
|
50
|
+
}
|
|
10
51
|
export async function init(options) {
|
|
11
52
|
console.log(chalk.bold('\n🎨 Welcome to shadcn-angular!\n'));
|
|
12
53
|
const cwd = process.cwd();
|
|
@@ -20,20 +61,24 @@ export async function init(options) {
|
|
|
20
61
|
// Check if already initialized
|
|
21
62
|
const componentsJsonPath = path.join(cwd, 'components.json');
|
|
22
63
|
if (await fs.pathExists(componentsJsonPath)) {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
64
|
+
const overwrite = options.yes
|
|
65
|
+
? true
|
|
66
|
+
: (await prompts({
|
|
67
|
+
type: 'confirm',
|
|
68
|
+
name: 'overwrite',
|
|
69
|
+
message: 'components.json already exists. Overwrite?',
|
|
70
|
+
initial: false,
|
|
71
|
+
})).overwrite;
|
|
29
72
|
if (!overwrite) {
|
|
30
73
|
console.log(chalk.dim('Initialization cancelled.'));
|
|
31
74
|
return;
|
|
32
75
|
}
|
|
33
76
|
}
|
|
34
77
|
let config;
|
|
78
|
+
let createShortcutRegistry = true;
|
|
35
79
|
if (options.defaults || options.yes) {
|
|
36
80
|
config = getDefaultConfig();
|
|
81
|
+
createShortcutRegistry = true;
|
|
37
82
|
}
|
|
38
83
|
else {
|
|
39
84
|
const THEME_COLORS = {
|
|
@@ -115,6 +160,12 @@ export async function init(options) {
|
|
|
115
160
|
message: 'Where is your global styles file?',
|
|
116
161
|
initial: 'src/styles.scss',
|
|
117
162
|
},
|
|
163
|
+
{
|
|
164
|
+
type: 'confirm',
|
|
165
|
+
name: 'createShortcutRegistry',
|
|
166
|
+
message: 'Would you like to create a shortcut registry scaffold?',
|
|
167
|
+
initial: true,
|
|
168
|
+
},
|
|
118
169
|
]);
|
|
119
170
|
config = {
|
|
120
171
|
$schema: 'https://shadcn-angular.dev/schema.json',
|
|
@@ -130,8 +181,8 @@ export async function init(options) {
|
|
|
130
181
|
utils: responses.utilsPath.replace('src/', '@/').replace('.ts', ''),
|
|
131
182
|
ui: responses.componentsPath.replace('src/', '@/'),
|
|
132
183
|
},
|
|
133
|
-
iconLibrary: 'lucide-angular',
|
|
134
184
|
};
|
|
185
|
+
createShortcutRegistry = responses.createShortcutRegistry ?? true;
|
|
135
186
|
}
|
|
136
187
|
const spinner = ora('Initializing project...').start();
|
|
137
188
|
try {
|
|
@@ -144,19 +195,28 @@ export async function init(options) {
|
|
|
144
195
|
// So we should rely on config to reconstruct the path, or better yet, if we are in 'defaults' mode, check what config is.
|
|
145
196
|
// If config came from defaults, aliases are set.
|
|
146
197
|
// We can reverse-map alias to path: @/ -> src/
|
|
147
|
-
const utilsPathResolved = config.aliases.utils
|
|
148
|
-
const utilsDir = path.dirname(
|
|
198
|
+
const utilsPathResolved = resolveAliasOrPath(cwd, config.aliases.utils + '.ts');
|
|
199
|
+
const utilsDir = path.dirname(utilsPathResolved); // utils usually ends in path/to/utils
|
|
149
200
|
await fs.ensureDir(utilsDir);
|
|
150
|
-
await fs.writeFile(
|
|
201
|
+
await fs.writeFile(utilsPathResolved, getUtilsTemplate());
|
|
151
202
|
spinner.text = 'Created utils.ts';
|
|
203
|
+
const shortcutServicePath = path.join(utilsDir, 'shortcut-binding.service.ts');
|
|
204
|
+
const shortcutServiceContent = await fetchLibFileContent('shortcut-binding.service.ts');
|
|
205
|
+
await fs.writeFile(shortcutServicePath, shortcutServiceContent);
|
|
206
|
+
spinner.text = 'Created shortcut-binding.service.ts';
|
|
207
|
+
if (createShortcutRegistry) {
|
|
208
|
+
await writeShortcutRegistryIndex(cwd, config, []);
|
|
209
|
+
spinner.text = 'Created shortcut-registry.index.ts';
|
|
210
|
+
}
|
|
152
211
|
// Create tailwind.css file in the same directory as the global styles
|
|
153
|
-
const
|
|
212
|
+
const userStylesPath = resolveProjectPath(cwd, config.tailwind.css);
|
|
213
|
+
const stylesDir = path.dirname(userStylesPath);
|
|
154
214
|
const tailwindCssPath = path.join(stylesDir, 'tailwind.css');
|
|
155
215
|
// Write the tailwind.css file with all Tailwind directives
|
|
216
|
+
await fs.ensureDir(stylesDir);
|
|
156
217
|
await fs.writeFile(tailwindCssPath, getStylesTemplate(config.tailwind.baseColor, config.tailwind.theme));
|
|
157
218
|
spinner.text = 'Created tailwind.css';
|
|
158
219
|
// Add import to the user's global styles file if not already present
|
|
159
|
-
const userStylesPath = path.join(cwd, config.tailwind.css);
|
|
160
220
|
let userStyles = await fs.pathExists(userStylesPath)
|
|
161
221
|
? await fs.readFile(userStylesPath, 'utf-8')
|
|
162
222
|
: '';
|
|
@@ -168,8 +228,7 @@ export async function init(options) {
|
|
|
168
228
|
spinner.text = 'Added tailwind.css import to styles';
|
|
169
229
|
}
|
|
170
230
|
// Create components/ui directory
|
|
171
|
-
const
|
|
172
|
-
const uiDir = path.join(cwd, uiPathResolved);
|
|
231
|
+
const uiDir = resolveAliasOrPath(cwd, config.aliases.ui);
|
|
173
232
|
await fs.ensureDir(uiDir);
|
|
174
233
|
spinner.text = 'Created components directory';
|
|
175
234
|
// Install dependencies
|
|
@@ -178,12 +237,11 @@ export async function init(options) {
|
|
|
178
237
|
'clsx',
|
|
179
238
|
'tailwind-merge',
|
|
180
239
|
'class-variance-authority',
|
|
181
|
-
'lucide-angular',
|
|
182
240
|
'tailwindcss',
|
|
183
241
|
'postcss',
|
|
184
242
|
'@tailwindcss/postcss'
|
|
185
243
|
];
|
|
186
|
-
await
|
|
244
|
+
await installPackages(dependencies, { cwd });
|
|
187
245
|
// Setup PostCSS - create .postcssrc.json which is the preferred format for Angular
|
|
188
246
|
spinner.text = 'Configuring PostCSS...';
|
|
189
247
|
const postcssrcPath = path.join(cwd, '.postcssrc.json');
|
|
@@ -195,35 +253,6 @@ export async function init(options) {
|
|
|
195
253
|
};
|
|
196
254
|
await fs.writeJson(postcssrcPath, configContent, { spaces: 4 });
|
|
197
255
|
}
|
|
198
|
-
// Configure app.config.ts with Lucide icons
|
|
199
|
-
spinner.text = 'Configuring icons in app.config.ts...';
|
|
200
|
-
const appConfigPath = path.join(cwd, 'src/app/app.config.ts');
|
|
201
|
-
if (await fs.pathExists(appConfigPath)) {
|
|
202
|
-
let appConfigContent = await fs.readFile(appConfigPath, 'utf-8');
|
|
203
|
-
// Add imports
|
|
204
|
-
if (!appConfigContent.includes('LucideAngularModule')) {
|
|
205
|
-
const iconImports = "import { LucideAngularModule, ArrowDown, ArrowUp, ChevronsUpDown, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from 'lucide-angular';";
|
|
206
|
-
appConfigContent = iconImports + '\n' + appConfigContent;
|
|
207
|
-
}
|
|
208
|
-
if (!appConfigContent.includes('importProvidersFrom')) {
|
|
209
|
-
appConfigContent = "import { importProvidersFrom } from '@angular/core';\n" + appConfigContent;
|
|
210
|
-
}
|
|
211
|
-
// Add provider
|
|
212
|
-
const providerCode = `
|
|
213
|
-
importProvidersFrom(LucideAngularModule.pick({
|
|
214
|
-
ArrowDown,
|
|
215
|
-
ArrowUp,
|
|
216
|
-
ChevronsUpDown,
|
|
217
|
-
ChevronLeft,
|
|
218
|
-
ChevronRight,
|
|
219
|
-
ChevronsLeft,
|
|
220
|
-
ChevronsRight
|
|
221
|
-
}))`;
|
|
222
|
-
if (!appConfigContent.includes('LucideAngularModule.pick')) {
|
|
223
|
-
appConfigContent = appConfigContent.replace(/providers:\s*\[/, `providers: [${providerCode},`);
|
|
224
|
-
await fs.writeFile(appConfigPath, appConfigContent);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
256
|
spinner.succeed(chalk.green('Project initialized successfully!'));
|
|
228
257
|
console.log('\n' + chalk.bold('Next steps:'));
|
|
229
258
|
console.log(chalk.dim(' 1. Add components: ') + chalk.cyan('npx @gilav21/shadcn-angular add button'));
|
package/dist/registry/index.d.ts
CHANGED
|
@@ -3,6 +3,11 @@ export interface ComponentDefinition {
|
|
|
3
3
|
files: string[];
|
|
4
4
|
dependencies?: string[];
|
|
5
5
|
npmDependencies?: string[];
|
|
6
|
+
shortcutDefinitions?: {
|
|
7
|
+
exportName: string;
|
|
8
|
+
componentName: string;
|
|
9
|
+
sourceFile: string;
|
|
10
|
+
}[];
|
|
6
11
|
}
|
|
7
12
|
export type ComponentName = keyof typeof registry;
|
|
8
13
|
export declare const registry: Record<string, ComponentDefinition>;
|
package/dist/registry/index.js
CHANGED
|
@@ -39,6 +39,7 @@ export const registry = {
|
|
|
39
39
|
button: {
|
|
40
40
|
name: 'button',
|
|
41
41
|
files: ['button.component.ts'],
|
|
42
|
+
dependencies: ['ripple'],
|
|
42
43
|
},
|
|
43
44
|
'button-group': {
|
|
44
45
|
name: 'button-group',
|
|
@@ -79,6 +80,13 @@ export const registry = {
|
|
|
79
80
|
name: 'command',
|
|
80
81
|
files: ['command.component.ts'],
|
|
81
82
|
dependencies: ['dialog'],
|
|
83
|
+
shortcutDefinitions: [
|
|
84
|
+
{
|
|
85
|
+
exportName: 'COMMAND_DIALOG_SHORTCUT_DEFINITIONS',
|
|
86
|
+
componentName: 'command-dialog',
|
|
87
|
+
sourceFile: 'command.component.ts',
|
|
88
|
+
},
|
|
89
|
+
],
|
|
82
90
|
},
|
|
83
91
|
'context-menu': {
|
|
84
92
|
name: 'context-menu',
|
|
@@ -130,6 +138,7 @@ export const registry = {
|
|
|
130
138
|
'pagination',
|
|
131
139
|
'popover',
|
|
132
140
|
'component-outlet',
|
|
141
|
+
'icon',
|
|
133
142
|
],
|
|
134
143
|
},
|
|
135
144
|
dialog: {
|
|
@@ -144,11 +153,12 @@ export const registry = {
|
|
|
144
153
|
'dock-icon.component.ts',
|
|
145
154
|
'dock-label.component.ts',
|
|
146
155
|
],
|
|
156
|
+
dependencies: ['icon'],
|
|
147
157
|
},
|
|
148
158
|
'tree-select': {
|
|
149
159
|
name: 'tree-select',
|
|
150
160
|
files: ['tree-select.component.ts'],
|
|
151
|
-
dependencies: ['popover', 'tree'],
|
|
161
|
+
dependencies: ['popover', 'tree', 'icon'],
|
|
152
162
|
},
|
|
153
163
|
'virtual-scroll': {
|
|
154
164
|
name: 'virtual-scroll',
|
|
@@ -175,6 +185,10 @@ export const registry = {
|
|
|
175
185
|
name: 'field',
|
|
176
186
|
files: ['field.component.ts'],
|
|
177
187
|
},
|
|
188
|
+
icon: {
|
|
189
|
+
name: 'icon',
|
|
190
|
+
files: ['icon.component.ts'],
|
|
191
|
+
},
|
|
178
192
|
'file-upload': {
|
|
179
193
|
name: 'file-upload',
|
|
180
194
|
files: ['file-upload.component.ts'],
|
|
@@ -264,7 +278,7 @@ export const registry = {
|
|
|
264
278
|
sidebar: {
|
|
265
279
|
name: 'sidebar',
|
|
266
280
|
files: ['sidebar.component.ts'],
|
|
267
|
-
dependencies: ['scroll-area', 'tooltip'],
|
|
281
|
+
dependencies: ['scroll-area', 'tooltip', 'icon'],
|
|
268
282
|
},
|
|
269
283
|
skeleton: {
|
|
270
284
|
name: 'skeleton',
|
|
@@ -321,6 +335,7 @@ export const registry = {
|
|
|
321
335
|
tree: {
|
|
322
336
|
name: 'tree',
|
|
323
337
|
files: ['tree.component.ts'],
|
|
338
|
+
dependencies: ['icon'],
|
|
324
339
|
},
|
|
325
340
|
'speed-dial': {
|
|
326
341
|
name: 'speed-dial',
|
|
@@ -335,7 +350,7 @@ export const registry = {
|
|
|
335
350
|
'emoji-picker': {
|
|
336
351
|
name: 'emoji-picker',
|
|
337
352
|
files: ['emoji-picker.component.ts', 'emoji-data.ts'],
|
|
338
|
-
dependencies: ['
|
|
353
|
+
dependencies: ['input', 'scroll-area', 'tooltip'],
|
|
339
354
|
},
|
|
340
355
|
'rich-text-editor': {
|
|
341
356
|
name: 'rich-text-editor',
|
|
@@ -344,18 +359,30 @@ export const registry = {
|
|
|
344
359
|
'rich-text-toolbar.component.ts',
|
|
345
360
|
'rich-text-sanitizer.service.ts',
|
|
346
361
|
'rich-text-markdown.service.ts',
|
|
362
|
+
'rich-text-paste-normalizer.service.ts',
|
|
363
|
+
'rich-text-command-registry.service.ts',
|
|
347
364
|
'rich-text-mention.component.ts',
|
|
348
365
|
'rich-text-image-resizer.component.ts',
|
|
366
|
+
'rich-text-locales.ts',
|
|
349
367
|
],
|
|
350
368
|
dependencies: [
|
|
351
369
|
'button',
|
|
352
370
|
'separator',
|
|
353
371
|
'popover',
|
|
354
372
|
'emoji-picker',
|
|
373
|
+
'autocomplete',
|
|
355
374
|
'select',
|
|
356
375
|
'input',
|
|
376
|
+
'dialog',
|
|
357
377
|
'scroll-area',
|
|
358
378
|
],
|
|
379
|
+
shortcutDefinitions: [
|
|
380
|
+
{
|
|
381
|
+
exportName: 'RICH_TEXT_SHORTCUT_DEFINITIONS',
|
|
382
|
+
componentName: 'rich-text-editor',
|
|
383
|
+
sourceFile: 'rich-text-editor.component.ts',
|
|
384
|
+
},
|
|
385
|
+
],
|
|
359
386
|
},
|
|
360
387
|
// Chart Components
|
|
361
388
|
'pie-chart': {
|
|
@@ -424,7 +451,7 @@ export const registry = {
|
|
|
424
451
|
},
|
|
425
452
|
'bento-grid': {
|
|
426
453
|
name: 'bento-grid',
|
|
427
|
-
dependencies: ['context-menu', 'component-outlet'],
|
|
454
|
+
dependencies: ['context-menu', 'component-outlet', 'icon'],
|
|
428
455
|
files: [
|
|
429
456
|
'bento-grid.component.ts',
|
|
430
457
|
],
|
|
@@ -438,12 +465,14 @@ export const registry = {
|
|
|
438
465
|
'label',
|
|
439
466
|
'select',
|
|
440
467
|
'switch',
|
|
441
|
-
'slider'
|
|
468
|
+
'slider',
|
|
469
|
+
'icon'
|
|
442
470
|
],
|
|
443
471
|
files: [
|
|
444
472
|
'page-builder/page-builder.component.ts',
|
|
445
473
|
'page-builder/page-builder.types.ts',
|
|
446
|
-
'page-builder/property-editor.component.ts'
|
|
474
|
+
'page-builder/property-editor.component.ts',
|
|
475
|
+
'page-builder/page-renderer.component.ts'
|
|
447
476
|
],
|
|
448
477
|
},
|
|
449
478
|
'component-outlet': {
|
|
@@ -455,4 +484,75 @@ export const registry = {
|
|
|
455
484
|
files: ['split-button.component.ts'],
|
|
456
485
|
dependencies: ['button', 'dropdown-menu'],
|
|
457
486
|
},
|
|
487
|
+
// Animations
|
|
488
|
+
'gradient-text': {
|
|
489
|
+
name: 'gradient-text',
|
|
490
|
+
files: ['gradient-text.component.ts'],
|
|
491
|
+
},
|
|
492
|
+
'flip-text': {
|
|
493
|
+
name: 'flip-text',
|
|
494
|
+
files: ['flip-text.component.ts'],
|
|
495
|
+
},
|
|
496
|
+
meteors: {
|
|
497
|
+
name: 'meteors',
|
|
498
|
+
files: ['meteors.component.ts'],
|
|
499
|
+
},
|
|
500
|
+
'shine-border': {
|
|
501
|
+
name: 'shine-border',
|
|
502
|
+
files: ['shine-border.component.ts'],
|
|
503
|
+
},
|
|
504
|
+
'scroll-progress': {
|
|
505
|
+
name: 'scroll-progress',
|
|
506
|
+
files: ['scroll-progress.component.ts'],
|
|
507
|
+
},
|
|
508
|
+
'blur-fade': {
|
|
509
|
+
name: 'blur-fade',
|
|
510
|
+
files: ['blur-fade.component.ts'],
|
|
511
|
+
},
|
|
512
|
+
ripple: {
|
|
513
|
+
name: 'ripple',
|
|
514
|
+
files: ['ripple.directive.ts'],
|
|
515
|
+
},
|
|
516
|
+
marquee: {
|
|
517
|
+
name: 'marquee',
|
|
518
|
+
files: ['marquee.component.ts'],
|
|
519
|
+
},
|
|
520
|
+
'word-rotate': {
|
|
521
|
+
name: 'word-rotate',
|
|
522
|
+
files: ['word-rotate.component.ts'],
|
|
523
|
+
},
|
|
524
|
+
'morphing-text': {
|
|
525
|
+
name: 'morphing-text',
|
|
526
|
+
files: ['morphing-text.component.ts'],
|
|
527
|
+
},
|
|
528
|
+
'typing-animation': {
|
|
529
|
+
name: 'typing-animation',
|
|
530
|
+
files: ['typing-animation.component.ts'],
|
|
531
|
+
},
|
|
532
|
+
'wobble-card': {
|
|
533
|
+
name: 'wobble-card',
|
|
534
|
+
files: ['wobble-card.component.ts'],
|
|
535
|
+
},
|
|
536
|
+
magnetic: {
|
|
537
|
+
name: 'magnetic',
|
|
538
|
+
files: ['magnetic.directive.ts'],
|
|
539
|
+
},
|
|
540
|
+
orbit: {
|
|
541
|
+
name: 'orbit',
|
|
542
|
+
files: ['orbit.component.ts'],
|
|
543
|
+
},
|
|
544
|
+
'stagger-children': {
|
|
545
|
+
name: 'stagger-children',
|
|
546
|
+
files: ['stagger-children.component.ts'],
|
|
547
|
+
},
|
|
548
|
+
particles: {
|
|
549
|
+
name: 'particles',
|
|
550
|
+
files: ['particles.component.ts'],
|
|
551
|
+
},
|
|
552
|
+
// Kanban
|
|
553
|
+
kanban: {
|
|
554
|
+
name: 'kanban',
|
|
555
|
+
files: ['kanban.component.ts'],
|
|
556
|
+
dependencies: ['badge', 'avatar', 'scroll-area', 'separator'],
|
|
557
|
+
},
|
|
458
558
|
};
|
package/dist/utils/config.d.ts
CHANGED
package/dist/utils/config.js
CHANGED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Config } from './config.js';
|
|
2
|
+
export interface ShortcutRegistryEntry {
|
|
3
|
+
exportName: string;
|
|
4
|
+
componentName: string;
|
|
5
|
+
sourceFile: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function writeShortcutRegistryIndex(cwd: string, config: Config, entries: ShortcutRegistryEntry[]): Promise<string>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
function aliasToProjectPath(aliasOrPath) {
|
|
4
|
+
return aliasOrPath.startsWith('@/')
|
|
5
|
+
? path.join('src', aliasOrPath.slice(2))
|
|
6
|
+
: aliasOrPath;
|
|
7
|
+
}
|
|
8
|
+
function resolveProjectPath(cwd, inputPath) {
|
|
9
|
+
const resolved = path.resolve(cwd, inputPath);
|
|
10
|
+
const relative = path.relative(cwd, resolved);
|
|
11
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
12
|
+
throw new Error(`Path must stay inside the project directory: ${inputPath}`);
|
|
13
|
+
}
|
|
14
|
+
return resolved;
|
|
15
|
+
}
|
|
16
|
+
function getShortcutRegistryIndexPath(cwd, config) {
|
|
17
|
+
const utilsFilePath = resolveProjectPath(cwd, aliasToProjectPath(config.aliases.utils) + '.ts');
|
|
18
|
+
const utilsDir = path.dirname(utilsFilePath);
|
|
19
|
+
return path.join(utilsDir, 'shortcut-registry.index.ts');
|
|
20
|
+
}
|
|
21
|
+
export async function writeShortcutRegistryIndex(cwd, config, entries) {
|
|
22
|
+
const registryPath = getShortcutRegistryIndexPath(cwd, config);
|
|
23
|
+
await fs.ensureDir(path.dirname(registryPath));
|
|
24
|
+
const uniqueEntries = Array.from(new Map(entries.map(entry => [entry.exportName, entry])).values())
|
|
25
|
+
.sort((a, b) => a.exportName.localeCompare(b.exportName));
|
|
26
|
+
const uiAlias = config.aliases.ui;
|
|
27
|
+
const utilsAliasDir = config.aliases.utils.includes('/')
|
|
28
|
+
? config.aliases.utils.slice(0, config.aliases.utils.lastIndexOf('/'))
|
|
29
|
+
: config.aliases.utils;
|
|
30
|
+
const shortcutServiceImport = `${utilsAliasDir}/shortcut-binding.service`;
|
|
31
|
+
const imports = uniqueEntries
|
|
32
|
+
.map(entry => {
|
|
33
|
+
const importPath = `${uiAlias}/${entry.sourceFile.replace(/\.ts$/, '')}`;
|
|
34
|
+
return `import { ${entry.exportName} } from '${importPath}';`;
|
|
35
|
+
})
|
|
36
|
+
.join('\n');
|
|
37
|
+
const catalogItems = uniqueEntries
|
|
38
|
+
.map(entry => ` { componentName: '${entry.componentName}', definitions: ${entry.exportName} },`)
|
|
39
|
+
.join('\n');
|
|
40
|
+
const content = `// Auto-generated by shadcn-angular CLI. Do not edit manually.
|
|
41
|
+
import type { ShortcutBindingService, ShortcutDefinition } from '${shortcutServiceImport}';
|
|
42
|
+
${imports ? `${imports}\n` : ''}
|
|
43
|
+
export const GENERATED_SHORTCUT_CATALOG: ReadonlyArray<{
|
|
44
|
+
componentName: string;
|
|
45
|
+
definitions: ReadonlyArray<ShortcutDefinition>;
|
|
46
|
+
}> = [
|
|
47
|
+
${catalogItems}
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
export function registerGeneratedShortcutCatalog(shortcuts: ShortcutBindingService): void {
|
|
51
|
+
for (const entry of GENERATED_SHORTCUT_CATALOG) {
|
|
52
|
+
shortcuts.defineShortcuts(entry.componentName, [...entry.definitions]);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
`;
|
|
56
|
+
await fs.writeFile(registryPath, content);
|
|
57
|
+
return registryPath;
|
|
58
|
+
}
|