inai-react-components 1.4.1 → 1.5.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,iBAAiB,EAEtB,KAAK,kBAAkB,EAExB,MAAM,aAAa,CAAC;AAoBrB,MAAM,WAAW,UAAU;IACzB,kDAAkD;IAClD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kDAAkD;IAClD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oDAAoD;IACpD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kDAAkD;IAClD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,kEAAkE;IAClE,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACjD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG;IAChD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd,CAsCA;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE;IAAE,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAAC,SAAS,EAAE,iBAAiB,EAAE,CAAA;CAAE,EAC1G,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,iBAAiB,GAAG,IAAI,CAc1B;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,iBAAiB,EAC5B,cAAc,EAAE,kBAAkB,GACjC,MAAM,CAiBR;AA4JD,wBAAsB,MAAM,CAC1B,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,SAAS,CAAC,CAmMpB;AAqCD,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACnD,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAsB,UAAU,CAC9B,aAAa,CAAC,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAqIf"}
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,iBAAiB,EAEtB,KAAK,kBAAkB,EAExB,MAAM,aAAa,CAAC;AAwBrB,MAAM,WAAW,UAAU;IACzB,kDAAkD;IAClD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kDAAkD;IAClD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oDAAoD;IACpD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kDAAkD;IAClD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,kEAAkE;IAClE,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACjD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG;IAChD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd,CAsCA;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE;IAAE,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAAC,SAAS,EAAE,iBAAiB,EAAE,CAAA;CAAE,EAC1G,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,iBAAiB,GAAG,IAAI,CAc1B;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,iBAAiB,EAC5B,cAAc,EAAE,kBAAkB,GACjC,MAAM,CAiBR;AA2TD,wBAAsB,MAAM,CAC1B,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,SAAS,CAAC,CAmMpB;AAqCD,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACnD,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAsB,UAAU,CAC9B,aAAa,CAAC,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAqIf"}
@@ -10,7 +10,7 @@ import { saveSnapshot, sha256, } from "../utils/snapshot.js";
10
10
  import { fuzzySearchNames } from "../utils/fuzzy-search.js";
11
11
  import { normalizeThemeCss, getLocalTailwindCssTemplate, getLegacyTailwindCssTemplate, } from "./init.js";
12
12
  import { autoInstallDeps } from "../utils/auto-install.js";
13
- import { resolveLocalDir, getSourceRoot } from "../utils/paths.js";
13
+ import { resolveLocalDir, getSourceRoot, rewriteCompanyUiImports, } from "../utils/paths.js";
14
14
  /**
15
15
  * Parse a component spec into its registry namespace, type prefix and name.
16
16
  *
@@ -107,6 +107,19 @@ async function installOne(component, registry, componentsJson, registryDir, root
107
107
  const baseTargetDir = getTargetDir(component, componentsJson);
108
108
  const isMultiFile = component.type === "block" || component.type === "template";
109
109
  const targetDir = isMultiFile ? path.join(baseTargetDir, name) : baseTargetDir;
110
+ // Prefixes used by source files. Stripping them preserves each
111
+ // component/block's internal subdirectory structure.
112
+ //
113
+ // Components: `packages/ui/src/<name>.tsx` and
114
+ // `packages/ui/src/<name>/sub.tsx` → strip `packages/ui/src/`
115
+ // so compound subdirs (`data-table/`) land as-is under
116
+ // `<componentDir>/`.
117
+ //
118
+ // Blocks/templates: `apps/docs/src/registry/blocks/<name>/**` → strip
119
+ // `apps/docs/src/registry/blocks/<name>/` so nested `parts/`
120
+ // subfolders are preserved under `<blocksDir>/<name>/`.
121
+ const UI_PREFIX = "packages/ui/src/";
122
+ const BLOCK_PREFIX = `apps/docs/src/registry/blocks/${name}/`;
110
123
  const copiedFiles = [];
111
124
  const skippedFiles = [];
112
125
  // Track captured content for the snapshot (only for files that were
@@ -114,15 +127,30 @@ async function installOne(component, registry, componentsJson, registryDir, root
114
127
  const capturedFiles = {};
115
128
  for (const filePath of component.files) {
116
129
  const registryFilePath = path.join(registryDir, filePath);
117
- const fileName = path.basename(filePath);
118
- const localFilePath = path.join(rootDir, targetDir, fileName);
130
+ // Destination path relative to `targetDir`. The prefix stripping
131
+ // preserves intra-component directory structure (compound subdirs,
132
+ // blocks' `parts/` folders, etc.). Flattening to basename here was
133
+ // the cause of broken `./parts/*` and `../data` imports in templates.
134
+ let destRel;
135
+ if (isMultiFile && filePath.startsWith(BLOCK_PREFIX)) {
136
+ destRel = filePath.slice(BLOCK_PREFIX.length);
137
+ }
138
+ else if (!isMultiFile && filePath.startsWith(UI_PREFIX)) {
139
+ destRel = filePath.slice(UI_PREFIX.length);
140
+ }
141
+ else {
142
+ // Fallback for legacy registry entries without the expected prefix.
143
+ destRel = path.basename(filePath);
144
+ }
145
+ const localFilePath = path.join(rootDir, targetDir, destRel);
146
+ const displayName = isMultiFile ? `${name}/${destRel}` : destRel;
119
147
  if (!fs.existsSync(registryFilePath)) {
120
148
  continue;
121
149
  }
122
150
  const exists = fs.existsSync(localFilePath);
123
151
  if (exists && !options.force) {
124
152
  if (options.skipExisting) {
125
- skippedFiles.push(isMultiFile ? `${name}/${fileName}` : fileName);
153
+ skippedFiles.push(displayName);
126
154
  continue;
127
155
  }
128
156
  if (options.dryRun) {
@@ -136,7 +164,7 @@ async function installOne(component, registry, componentsJson, registryDir, root
136
164
  initial: false,
137
165
  });
138
166
  if (!res.overwrite) {
139
- skippedFiles.push(isMultiFile ? `${name}/${fileName}` : fileName);
167
+ skippedFiles.push(displayName);
140
168
  continue;
141
169
  }
142
170
  }
@@ -144,7 +172,14 @@ async function installOne(component, registry, componentsJson, registryDir, root
144
172
  throw new Error(`File "${path.relative(rootDir, localFilePath)}" already exists. Use --force to overwrite or --skip-existing to ignore (stdin is not a TTY, cannot prompt).`);
145
173
  }
146
174
  }
147
- const content = fs.readFileSync(registryFilePath, "utf-8");
175
+ let content = fs.readFileSync(registryFilePath, "utf-8");
176
+ // Blocks and templates reference sibling components via
177
+ // `from "@company/ui/<name>"`. Rewrite those to point at the user's
178
+ // locally-installed components using the project's alias prefix, so
179
+ // the block compiles without `@company/ui` being in node_modules.
180
+ if (isMultiFile) {
181
+ content = rewriteCompanyUiImports(content, componentsJson);
182
+ }
148
183
  if (options.dryRun) {
149
184
  console.log(chalk.dim(` [dry-run] would write ${path.relative(rootDir, localFilePath)}`));
150
185
  }
@@ -158,19 +193,38 @@ async function installOne(component, registry, componentsJson, registryDir, root
158
193
  content,
159
194
  };
160
195
  }
161
- copiedFiles.push(isMultiFile ? `${name}/${fileName}` : fileName);
162
- }
163
- // Internal deps (lib/cn, lib/animations, ...) — installed under the
164
- // project's detected sourceRoot so they match where `init` placed cn.ts.
165
- const sourceRoot = getSourceRoot(componentsJson);
196
+ copiedFiles.push(displayName);
197
+ }
198
+ // Internal deps (lib/cn, lib/animations, lib/i18n-context, ...).
199
+ //
200
+ // Placement matters: source components import via `./lib/<name>.js`
201
+ // (sibling), so lib files MUST land in `<componentDir>/lib/` — NOT in
202
+ // `<sourceRoot>/lib/`. Otherwise the relative imports break at runtime.
203
+ //
204
+ // Extensions: most lib files are `.ts` but `i18n-context.tsx` contains
205
+ // JSX and must be copied as `.tsx`. We probe both in order.
206
+ const componentsDir = resolveLocalDir(componentsJson.aliases.components, componentsJson);
166
207
  const copiedInternalDeps = [];
167
208
  for (const dep of component.internalDeps) {
168
- const depFileName = dep.split("/").pop() + ".ts";
169
- const depSourcePath = path.join(registryDir, "packages", "ui", "src", dep + ".ts");
170
- const depTargetPath = path.join(rootDir, sourceRoot, "lib", depFileName);
171
- if (!fs.existsSync(depSourcePath)) {
209
+ const depBase = dep.split("/").pop();
210
+ const tsSource = path.join(registryDir, "packages", "ui", "src", dep + ".ts");
211
+ const tsxSource = path.join(registryDir, "packages", "ui", "src", dep + ".tsx");
212
+ let depSourcePath;
213
+ let depFileName;
214
+ if (fs.existsSync(tsSource)) {
215
+ depSourcePath = tsSource;
216
+ depFileName = `${depBase}.ts`;
217
+ }
218
+ else if (fs.existsSync(tsxSource)) {
219
+ depSourcePath = tsxSource;
220
+ depFileName = `${depBase}.tsx`;
221
+ }
222
+ else {
172
223
  continue;
173
224
  }
225
+ // e.g. componentsDir = "app/components/ui" → target:
226
+ // "app/components/ui/lib/i18n-context.tsx"
227
+ const depTargetPath = path.join(rootDir, componentsDir, "lib", depFileName);
174
228
  const content = fs.readFileSync(depSourcePath, "utf-8");
175
229
  if (options.dryRun) {
176
230
  console.log(chalk.dim(` [dry-run] would write ${path.relative(rootDir, depTargetPath)}`));
@@ -181,6 +235,84 @@ async function installOne(component, registry, componentsJson, registryDir, root
181
235
  }
182
236
  copiedInternalDeps.push(dep);
183
237
  }
238
+ // Block/template lib: blocks import via `../../lib/animations` and
239
+ // `../../lib/styles` relative to `<blocksDir>/<blockName>/page.tsx`,
240
+ // which resolves two levels up to `path.dirname(blocksDir)/lib/`.
241
+ // Copy the global block lib from `apps/docs/src/registry/lib/` there.
242
+ if (isMultiFile) {
243
+ const blocksDir = resolveLocalDir(componentsJson.aliases.blocks, componentsJson);
244
+ const blockLibDest = path.join(rootDir, path.dirname(blocksDir), "lib");
245
+ for (const libFile of ["animations.ts", "styles.ts"]) {
246
+ const src = path.join(registryDir, "apps", "docs", "src", "registry", "lib", libFile);
247
+ if (!fs.existsSync(src))
248
+ continue;
249
+ const dest = path.join(blockLibDest, libFile);
250
+ if (fs.existsSync(dest) && !options.force)
251
+ continue;
252
+ if (options.dryRun) {
253
+ console.log(chalk.dim(` [dry-run] would write ${path.relative(rootDir, dest)}`));
254
+ }
255
+ else {
256
+ fs.mkdirSync(blockLibDest, { recursive: true });
257
+ fs.copyFileSync(src, dest);
258
+ }
259
+ }
260
+ // Some data-heavy blocks (data-table-full, template-admin-dashboard,
261
+ // detail-panel-table, etc.) import from `../../../lib/api-client` and
262
+ // `../../../lib/api-types`, which resolves to `<sourceRoot>/lib/`.
263
+ // These are integration points with the user's backend that can't be
264
+ // shipped as real code — but we can write minimal stubs so the project
265
+ // compiles out of the box. Stubs are only written if the file doesn't
266
+ // already exist; if the user has a real implementation it stays intact.
267
+ const sourceRoot = getSourceRoot(componentsJson);
268
+ const userLibDir = path.join(rootDir, sourceRoot, "lib");
269
+ const stubApiTypes = path.join(userLibDir, "api-types.ts");
270
+ const stubApiClient = path.join(userLibDir, "api-client.ts");
271
+ if (!fs.existsSync(stubApiTypes) && !options.dryRun) {
272
+ fs.mkdirSync(userLibDir, { recursive: true });
273
+ fs.writeFileSync(stubApiTypes, `// Stub generated by inai-react-components. Replace with your real API types.
274
+ // These types satisfy the shape expected by data-heavy blocks
275
+ // (data-table-full, template-admin-dashboard, detail-panel-table, ...).
276
+ // If you already have a typed API layer, delete this file and point the
277
+ // block imports at your own module instead.
278
+
279
+ export interface PaginatedResponse<T> {
280
+ data: T[];
281
+ total: number;
282
+ page: number;
283
+ pageSize: number;
284
+ }
285
+ `);
286
+ }
287
+ if (!fs.existsSync(stubApiClient) && !options.dryRun) {
288
+ fs.mkdirSync(userLibDir, { recursive: true });
289
+ fs.writeFileSync(stubApiClient, `// Stub generated by inai-react-components. Replace with your real API client.
290
+ // Data-heavy blocks call \`fetchPaginated\` and \`downloadCsv\` at runtime.
291
+ // Without a real implementation the app will throw when you interact with
292
+ // those features — wire these up to your backend (fetch, tRPC, REST, etc.).
293
+
294
+ import type { PaginatedResponse } from "./api-types.js";
295
+
296
+ export async function fetchPaginated<T>(
297
+ endpoint: string,
298
+ _params: Record<string, unknown>
299
+ ): Promise<PaginatedResponse<T>> {
300
+ throw new Error(
301
+ \`fetchPaginated stub called for "\${endpoint}". Replace <sourceRoot>/lib/api-client.ts with your real API client.\`
302
+ );
303
+ }
304
+
305
+ export async function downloadCsv(
306
+ endpoint: string,
307
+ _params: Record<string, unknown>
308
+ ): Promise<void> {
309
+ throw new Error(
310
+ \`downloadCsv stub called for "\${endpoint}". Replace <sourceRoot>/lib/api-client.ts with your real CSV exporter.\`
311
+ );
312
+ }
313
+ `);
314
+ }
315
+ }
184
316
  // Update components.json (skipped in dry-run).
185
317
  if (!options.dryRun) {
186
318
  const registryVersion = registry.version;
@@ -273,11 +273,12 @@ export declare function getLegacyTailwindCssTemplate(theme: Theme, fontBody: Fon
273
273
  export declare function normalizeThemeCss(css: string, theme: string): string;
274
274
  /**
275
275
  * Copies the i18n base files (context, types, defaults) from the registry
276
- * to the project's <sourceRoot>/lib/. Required because ~75 components import
277
- * `useUIMessages` from `./lib/i18n-context.js` — without these files, every
278
- * subsequent `add` of an i18n-aware component would produce a broken import.
276
+ * to `<componentPath>/lib/`. Required because ~75 components import
277
+ * `useUIMessages` from `./lib/i18n-context.js` — the lib directory must
278
+ * live as a SIBLING of the component `.tsx` files so relative imports
279
+ * resolve correctly.
279
280
  */
280
- export declare function copyI18nFiles(registryDir: string | undefined, targetDir: string, sourceRoot: string): string[];
281
+ export declare function copyI18nFiles(registryDir: string | undefined, targetDir: string, componentPath: string): string[];
281
282
  export declare function runInit(config: InitConfig, targetDir: string, repoUrl?: string): Promise<{
282
283
  success: boolean;
283
284
  filesCreated: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -347,16 +347,17 @@ function copyTokensToProject(registryDir, targetDir, theme, sourceRoot) {
347
347
  }
348
348
  /**
349
349
  * Copies the i18n base files (context, types, defaults) from the registry
350
- * to the project's <sourceRoot>/lib/. Required because ~75 components import
351
- * `useUIMessages` from `./lib/i18n-context.js` — without these files, every
352
- * subsequent `add` of an i18n-aware component would produce a broken import.
350
+ * to `<componentPath>/lib/`. Required because ~75 components import
351
+ * `useUIMessages` from `./lib/i18n-context.js` — the lib directory must
352
+ * live as a SIBLING of the component `.tsx` files so relative imports
353
+ * resolve correctly.
353
354
  */
354
- export function copyI18nFiles(registryDir, targetDir, sourceRoot) {
355
+ export function copyI18nFiles(registryDir, targetDir, componentPath) {
355
356
  if (!registryDir)
356
357
  return [];
357
358
  const files = ["i18n-context.tsx", "i18n-types.ts", "i18n-defaults.ts"];
358
359
  const srcBase = path.join(registryDir, "packages", "ui", "src", "lib");
359
- const destBase = path.join(targetDir, sourceRoot, "lib");
360
+ const destBase = path.join(targetDir, componentPath, "lib");
360
361
  fs.mkdirSync(destBase, { recursive: true });
361
362
  const copied = [];
362
363
  for (const file of files) {
@@ -364,7 +365,7 @@ export function copyI18nFiles(registryDir, targetDir, sourceRoot) {
364
365
  if (!fs.existsSync(src))
365
366
  continue;
366
367
  fs.copyFileSync(src, path.join(destBase, file));
367
- copied.push(`${sourceRoot}/lib/${file}`);
368
+ copied.push(`${componentPath}/lib/${file}`);
368
369
  }
369
370
  return copied;
370
371
  }
@@ -381,12 +382,15 @@ export async function runInit(config, targetDir, repoUrl) {
381
382
  fs.mkdirSync(componentDir, { recursive: true });
382
383
  const blockDir = path.join(targetDir, config.blockPath);
383
384
  fs.mkdirSync(blockDir, { recursive: true });
384
- // 3. Create cn.ts utility under the detected source root
385
- const utilsDir = path.join(targetDir, sourceRoot, "lib");
386
- fs.mkdirSync(utilsDir, { recursive: true });
387
- const cnPath = path.join(utilsDir, "cn.ts");
385
+ // 3. Create cn.ts utility as a sibling of the components directory.
386
+ // Components import via `./lib/cn.js`, so lib/ MUST live directly
387
+ // next to the installed component files — `<componentPath>/lib/`,
388
+ // not `<sourceRoot>/lib/`.
389
+ const libDir = path.join(targetDir, config.componentPath, "lib");
390
+ fs.mkdirSync(libDir, { recursive: true });
391
+ const cnPath = path.join(libDir, "cn.ts");
388
392
  fs.writeFileSync(cnPath, getCnTemplate());
389
- filesCreated.push(`${sourceRoot}/lib/cn.ts`);
393
+ filesCreated.push(`${config.componentPath}/lib/cn.ts`);
390
394
  // 4. Copy tokens and create CSS
391
395
  const cssRelPath = config.cssEntryPoint ?? `${sourceRoot}/index.css`;
392
396
  const cssPath = path.join(targetDir, cssRelPath);
@@ -396,8 +400,9 @@ export async function runInit(config, targetDir, repoUrl) {
396
400
  const registryDir = getCacheDir();
397
401
  const tokenFiles = copyTokensToProject(registryDir, targetDir, config.theme, sourceRoot);
398
402
  filesCreated.push(...tokenFiles);
399
- // Copy i18n base files so components importing useUIMessages resolve
400
- const i18nFiles = copyI18nFiles(registryDir, targetDir, sourceRoot);
403
+ // Copy i18n base files next to the components so their
404
+ // `./lib/i18n-context.js` imports resolve.
405
+ const i18nFiles = copyI18nFiles(registryDir, targetDir, config.componentPath);
401
406
  filesCreated.push(...i18nFiles);
402
407
  fs.writeFileSync(cssPath, getLocalTailwindCssTemplate(config.theme, config.fontBody, config.fontHeading, config.radius));
403
408
  }
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ const program = new Command();
17
17
  program
18
18
  .name("inai-ui")
19
19
  .description("CLI for InAI UI component library")
20
- .version("1.4.1");
20
+ .version("1.5.1");
21
21
  program
22
22
  .command("init [repo-url]")
23
23
  .description("Initialize InAI UI in your project. Optionally pass a Git repo URL to fetch components remotely.")
@@ -23,4 +23,38 @@ export declare function resolveLocalDir(alias: string, componentsJson: Pick<Comp
23
23
  * `components.json` files without a `layout` field.
24
24
  */
25
25
  export declare function getSourceRoot(componentsJson: Pick<ComponentsJsonFile, "layout">): string;
26
+ /**
27
+ * Compute the import-alias form of `aliases.components` for use when
28
+ * rewriting `@company/ui/*` imports in block and template files.
29
+ *
30
+ * Rules:
31
+ * 1. If the stored alias already starts with a known alias prefix
32
+ * (`@/`, `~/`, `$/`), return it as-is. Block imports written with
33
+ * this prefix will resolve through the user's `tsconfig.json` paths.
34
+ * 2. Otherwise it's a raw filesystem path (e.g. `app/components/ui`).
35
+ * Strip `layout.sourceRoot` and prepend `layout.aliasPrefix` to
36
+ * produce an alias form (e.g. `~/components/ui`). This matches what
37
+ * the user's tsconfig `paths` maps, so the rewritten imports resolve
38
+ * without needing the user to configure anything extra.
39
+ * 3. If the stored alias doesn't match the layout's sourceRoot, return
40
+ * it as-is (the user may have chosen a non-standard location and we
41
+ * assume their tsconfig handles it).
42
+ */
43
+ export declare function getComponentsImportAlias(componentsJson: Pick<ComponentsJsonFile, "aliases" | "layout">): string;
44
+ /**
45
+ * Rewrite `@company/ui/*` imports in a block or template file to point
46
+ * at the user's locally-installed components. Without this, block files
47
+ * that `import { Button } from "@company/ui/button"` would fail at
48
+ * compile time because `@company/ui` doesn't exist in the consumer project.
49
+ *
50
+ * Transformations:
51
+ * - `from "@company/ui/data-table"` → `from "~/components/ui/data-table"`
52
+ * - `from "@company/ui/data-table/sub"` → `from "~/components/ui/data-table/sub"`
53
+ * - `from "@company/ui/lib/animations"` → `from "~/components/ui/lib/animations"`
54
+ * - `from "@company/ui"` (bare barrel) → no rewrite (logged as unsupported)
55
+ *
56
+ * The alias prefix (`~/`, `@/`, etc.) is derived from the project layout
57
+ * so it matches the user's `tsconfig.json` paths.
58
+ */
59
+ export declare function rewriteCompanyUiImports(source: string, componentsJson: Pick<ComponentsJsonFile, "aliases" | "layout">): string;
26
60
  //# sourceMappingURL=paths.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAIhE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAC,GACjD,MAAM,CAQR;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAC,GACjD,MAAM,CAER"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAIhE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAC,GACjD,MAAM,CAQR;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAC,GACjD,MAAM,CAER;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CACtC,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,GAAG,QAAQ,CAAC,GAC7D,MAAM,CAYR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,GAAG,QAAQ,CAAC,GAC7D,MAAM,CAaR"}
@@ -33,3 +33,57 @@ export function resolveLocalDir(alias, componentsJson) {
33
33
  export function getSourceRoot(componentsJson) {
34
34
  return componentsJson.layout?.sourceRoot ?? "src";
35
35
  }
36
+ /**
37
+ * Compute the import-alias form of `aliases.components` for use when
38
+ * rewriting `@company/ui/*` imports in block and template files.
39
+ *
40
+ * Rules:
41
+ * 1. If the stored alias already starts with a known alias prefix
42
+ * (`@/`, `~/`, `$/`), return it as-is. Block imports written with
43
+ * this prefix will resolve through the user's `tsconfig.json` paths.
44
+ * 2. Otherwise it's a raw filesystem path (e.g. `app/components/ui`).
45
+ * Strip `layout.sourceRoot` and prepend `layout.aliasPrefix` to
46
+ * produce an alias form (e.g. `~/components/ui`). This matches what
47
+ * the user's tsconfig `paths` maps, so the rewritten imports resolve
48
+ * without needing the user to configure anything extra.
49
+ * 3. If the stored alias doesn't match the layout's sourceRoot, return
50
+ * it as-is (the user may have chosen a non-standard location and we
51
+ * assume their tsconfig handles it).
52
+ */
53
+ export function getComponentsImportAlias(componentsJson) {
54
+ const raw = componentsJson.aliases.components;
55
+ // Already in alias form
56
+ for (const prefix of ["@/", "~/", "$/"]) {
57
+ if (raw.startsWith(prefix))
58
+ return raw;
59
+ }
60
+ // Raw path — convert to alias form via layout
61
+ const layout = componentsJson.layout;
62
+ if (layout && raw.startsWith(`${layout.sourceRoot}/`)) {
63
+ return `${layout.aliasPrefix}${raw.slice(layout.sourceRoot.length + 1)}`;
64
+ }
65
+ return raw;
66
+ }
67
+ /**
68
+ * Rewrite `@company/ui/*` imports in a block or template file to point
69
+ * at the user's locally-installed components. Without this, block files
70
+ * that `import { Button } from "@company/ui/button"` would fail at
71
+ * compile time because `@company/ui` doesn't exist in the consumer project.
72
+ *
73
+ * Transformations:
74
+ * - `from "@company/ui/data-table"` → `from "~/components/ui/data-table"`
75
+ * - `from "@company/ui/data-table/sub"` → `from "~/components/ui/data-table/sub"`
76
+ * - `from "@company/ui/lib/animations"` → `from "~/components/ui/lib/animations"`
77
+ * - `from "@company/ui"` (bare barrel) → no rewrite (logged as unsupported)
78
+ *
79
+ * The alias prefix (`~/`, `@/`, etc.) is derived from the project layout
80
+ * so it matches the user's `tsconfig.json` paths.
81
+ */
82
+ export function rewriteCompanyUiImports(source, componentsJson) {
83
+ const compImport = getComponentsImportAlias(componentsJson);
84
+ // Handle subpath imports (@company/ui/xxx)
85
+ let result = source.replace(/(from\s+["'])@company\/ui\/([^"']+)(["'])/g, (_, pre, sub, post) => `${pre}${compImport}/${sub}${post}`);
86
+ // Handle side-effect imports like `import "@company/ui/xxx"`
87
+ result = result.replace(/(import\s+["'])@company\/ui\/([^"']+)(["'])/g, (_, pre, sub, post) => `${pre}${compImport}/${sub}${post}`);
88
+ return result;
89
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inai-react-components",
3
- "version": "1.4.1",
3
+ "version": "1.5.1",
4
4
  "description": "CLI for InAI UI component library — install components from a private registry into your React project",
5
5
  "private": false,
6
6
  "type": "module",