@gilav21/shadcn-angular 0.0.16 → 0.0.18

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.
@@ -173,9 +173,8 @@ export async function add(components, options) {
173
173
  const localContent = await fs.readFile(targetPath, 'utf-8');
174
174
  try {
175
175
  let remoteContent = await fetchComponentContent(file, options);
176
- // Transform imports for comparison
177
- const utilsAlias = config.aliases.utils;
178
- remoteContent = remoteContent.replace(/(\.\.\/)+lib\/utils/g, utilsAlias);
176
+ // Transform all lib/ imports for comparison
177
+ remoteContent = remoteContent.replace(/(\.\.\/)+lib\//g, config.aliases.utils + '/');
179
178
  const normalize = (str) => str.replace(/\r\n/g, '\n').trim();
180
179
  if (normalize(localContent) !== normalize(remoteContent)) {
181
180
  hasChanges = true;
@@ -255,9 +254,8 @@ export async function add(components, options) {
255
254
  let content = contentCache.get(file);
256
255
  if (!content) {
257
256
  content = await fetchComponentContent(file, options);
258
- // Transform imports if not already transformed (cached is transformed)
259
- const utilsAlias = config.aliases.utils;
260
- content = content.replace(/(\.\.\/)+lib\/utils/g, utilsAlias);
257
+ // Transform all lib/ imports if not already transformed (cached is transformed)
258
+ content = content.replace(/(\.\.\/)+lib\//g, config.aliases.utils + '/');
261
259
  }
262
260
  await fs.ensureDir(path.dirname(targetPath));
263
261
  await fs.writeFile(targetPath, content);
@@ -283,6 +281,32 @@ export async function add(components, options) {
283
281
  else {
284
282
  spinner.info('No new components installed.');
285
283
  }
284
+ // Install required lib utility files
285
+ if (finalComponents.length > 0) {
286
+ const requiredLibFiles = new Set();
287
+ for (const name of allComponents) {
288
+ const component = registry[name];
289
+ if (component.libFiles) {
290
+ component.libFiles.forEach(f => requiredLibFiles.add(f));
291
+ }
292
+ }
293
+ if (requiredLibFiles.size > 0) {
294
+ const libDir = resolveProjectPath(cwd, aliasToProjectPath(config.aliases.utils));
295
+ await fs.ensureDir(libDir);
296
+ for (const libFile of requiredLibFiles) {
297
+ const libTargetPath = path.join(libDir, libFile);
298
+ if (!await fs.pathExists(libTargetPath) || options.overwrite) {
299
+ try {
300
+ const libContent = await fetchLibContent(libFile, options);
301
+ await fs.writeFile(libTargetPath, libContent);
302
+ }
303
+ catch (err) {
304
+ console.warn(chalk.yellow(`Could not install lib file ${libFile}: ${err.message}`));
305
+ }
306
+ }
307
+ }
308
+ }
309
+ }
286
310
  if (finalComponents.length > 0) {
287
311
  const npmDependencies = new Set();
288
312
  for (const name of finalComponents) {
@@ -305,12 +329,11 @@ export async function add(components, options) {
305
329
  }
306
330
  const shortcutEntries = collectInstalledShortcutEntries(targetDir);
307
331
  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');
332
+ const libDir2 = resolveProjectPath(cwd, aliasToProjectPath(config.aliases.utils));
333
+ const shortcutServicePath = path.join(libDir2, 'shortcut-binding.service.ts');
311
334
  if (!await fs.pathExists(shortcutServicePath)) {
312
335
  const shortcutServiceContent = await fetchLibContent('shortcut-binding.service.ts', options);
313
- await fs.ensureDir(utilsDir);
336
+ await fs.ensureDir(libDir2);
314
337
  await fs.writeFile(shortcutServicePath, shortcutServiceContent);
315
338
  }
316
339
  }
@@ -195,12 +195,11 @@ export async function init(options) {
195
195
  // So we should rely on config to reconstruct the path, or better yet, if we are in 'defaults' mode, check what config is.
196
196
  // If config came from defaults, aliases are set.
197
197
  // We can reverse-map alias to path: @/ -> src/
198
- const utilsPathResolved = resolveAliasOrPath(cwd, config.aliases.utils + '.ts');
199
- const utilsDir = path.dirname(utilsPathResolved); // utils usually ends in path/to/utils
200
- await fs.ensureDir(utilsDir);
201
- await fs.writeFile(utilsPathResolved, getUtilsTemplate());
198
+ const libDir = resolveAliasOrPath(cwd, config.aliases.utils);
199
+ await fs.ensureDir(libDir);
200
+ await fs.writeFile(path.join(libDir, 'utils.ts'), getUtilsTemplate());
202
201
  spinner.text = 'Created utils.ts';
203
- const shortcutServicePath = path.join(utilsDir, 'shortcut-binding.service.ts');
202
+ const shortcutServicePath = path.join(libDir, 'shortcut-binding.service.ts');
204
203
  const shortcutServiceContent = await fetchLibFileContent('shortcut-binding.service.ts');
205
204
  await fs.writeFile(shortcutServicePath, shortcutServiceContent);
206
205
  spinner.text = 'Created shortcut-binding.service.ts';
@@ -3,6 +3,7 @@ export interface ComponentDefinition {
3
3
  files: string[];
4
4
  dependencies?: string[];
5
5
  npmDependencies?: string[];
6
+ libFiles?: string[];
6
7
  shortcutDefinitions?: {
7
8
  exportName: string;
8
9
  componentName: string;
@@ -140,6 +140,7 @@ export const registry = {
140
140
  'component-outlet',
141
141
  'icon',
142
142
  ],
143
+ libFiles: ['xlsx.ts'],
143
144
  },
144
145
  dialog: {
145
146
  name: 'dialog',
@@ -376,6 +377,7 @@ export const registry = {
376
377
  'dialog',
377
378
  'scroll-area',
378
379
  ],
380
+ libFiles: ['pdf-parser.ts', 'image-validator.ts', 'svg-sanitizer.ts'],
379
381
  shortcutDefinitions: [
380
382
  {
381
383
  exportName: 'RICH_TEXT_SHORTCUT_DEFINITIONS',
@@ -6,7 +6,7 @@ import { twMerge } from 'tailwind-merge';
6
6
  * Utility function for merging Tailwind CSS classes with proper precedence
7
7
  */
8
8
  export function cn(...inputs: ClassValue[]): string {
9
- return twMerge(clsx(inputs));
9
+ return twMerge(clsx(inputs));
10
10
  }
11
11
 
12
12
  /**
@@ -17,5 +17,35 @@ export function isRtl(el: HTMLElement): boolean {
17
17
  return getComputedStyle(el).direction === 'rtl';
18
18
  }
19
19
 
20
+ /**
21
+ * Returns the bounding rect of the nearest ancestor that clips overflow
22
+ * (overflow: hidden | auto | scroll | clip on either axis).
23
+ * Falls back to the full viewport rect when no such ancestor exists.
24
+ *
25
+ * Use this instead of \`window.innerWidth/innerHeight\` when calculating
26
+ * popup collision boundaries so that containers like sidebars or
27
+ * fixed-height scroll panes are respected.
28
+ */
29
+ export function getClippingRect(element: HTMLElement): DOMRect {
30
+ let parent = element.parentElement;
31
+ while (parent && parent !== document.documentElement) {
32
+ const style = window.getComputedStyle(parent);
33
+ if (
34
+ /^(hidden|auto|scroll|clip)$/.test(style.overflowX) ||
35
+ /^(hidden|auto|scroll|clip)$/.test(style.overflowY)
36
+ ) {
37
+ return parent.getBoundingClientRect();
38
+ }
39
+ parent = parent.parentElement;
40
+ }
41
+ return new DOMRect(0, 0, window.innerWidth, window.innerHeight);
42
+ }
43
+
44
+ /**
45
+ * Check if the user prefers reduced motion via the OS-level accessibility setting.
46
+ */
47
+ export function prefersReducedMotion(): boolean {
48
+ return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
49
+ }
20
50
  `;
21
51
  }
@@ -12,7 +12,7 @@ export function getDefaultConfig() {
12
12
  },
13
13
  aliases: {
14
14
  components: '@/components',
15
- utils: '@/components/lib/utils',
15
+ utils: '@/components/lib',
16
16
  ui: '@/components/ui',
17
17
  },
18
18
  };
@@ -14,9 +14,8 @@ function resolveProjectPath(cwd, inputPath) {
14
14
  return resolved;
15
15
  }
16
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');
17
+ const libDir = resolveProjectPath(cwd, aliasToProjectPath(config.aliases.utils));
18
+ return path.join(libDir, 'shortcut-registry.index.ts');
20
19
  }
21
20
  export async function writeShortcutRegistryIndex(cwd, config, entries) {
22
21
  const registryPath = getShortcutRegistryIndexPath(cwd, config);
@@ -24,10 +23,7 @@ export async function writeShortcutRegistryIndex(cwd, config, entries) {
24
23
  const uniqueEntries = Array.from(new Map(entries.map(entry => [entry.exportName, entry])).values())
25
24
  .sort((a, b) => a.exportName.localeCompare(b.exportName));
26
25
  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`;
26
+ const shortcutServiceImport = `${config.aliases.utils}/shortcut-binding.service`;
31
27
  const imports = uniqueEntries
32
28
  .map(entry => {
33
29
  const importPath = `${uiAlias}/${entry.sourceFile.replace(/\.ts$/, '')}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gilav21/shadcn-angular",
3
- "version": "0.0.16",
3
+ "version": "0.0.18",
4
4
  "description": "CLI for adding shadcn-angular components to your project",
5
5
  "bin": {
6
6
  "shadcn-angular": "./dist/index.js"