inai-react-components 1.5.0 → 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;AA2OD,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,10 +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
- // Prefix used by component source files. Stripping it preserves the
111
- // component's internal subdirectory structure (e.g. `data-table/context.tsx`
112
- // stays inside a `data-table/` subfolder in the user's project).
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>/`.
113
121
  const UI_PREFIX = "packages/ui/src/";
122
+ const BLOCK_PREFIX = `apps/docs/src/registry/blocks/${name}/`;
114
123
  const copiedFiles = [];
115
124
  const skippedFiles = [];
116
125
  // Track captured content for the snapshot (only for files that were
@@ -118,19 +127,19 @@ async function installOne(component, registry, componentsJson, registryDir, root
118
127
  const capturedFiles = {};
119
128
  for (const filePath of component.files) {
120
129
  const registryFilePath = path.join(registryDir, filePath);
121
- // Destination path relative to `targetDir`:
122
- // - Blocks/templates (multi-file) already nest under `<targetDir>/<name>/`,
123
- // so we take the basename of each file (flat within the block dir).
124
- // - Components strip the `packages/ui/src/` prefix so compound components
125
- // like `data-table` keep their internal `data-table/` subfolder.
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.
126
134
  let destRel;
127
- if (isMultiFile) {
128
- destRel = path.basename(filePath);
135
+ if (isMultiFile && filePath.startsWith(BLOCK_PREFIX)) {
136
+ destRel = filePath.slice(BLOCK_PREFIX.length);
129
137
  }
130
- else if (filePath.startsWith(UI_PREFIX)) {
138
+ else if (!isMultiFile && filePath.startsWith(UI_PREFIX)) {
131
139
  destRel = filePath.slice(UI_PREFIX.length);
132
140
  }
133
141
  else {
142
+ // Fallback for legacy registry entries without the expected prefix.
134
143
  destRel = path.basename(filePath);
135
144
  }
136
145
  const localFilePath = path.join(rootDir, targetDir, destRel);
@@ -163,7 +172,14 @@ async function installOne(component, registry, componentsJson, registryDir, root
163
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).`);
164
173
  }
165
174
  }
166
- 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
+ }
167
183
  if (options.dryRun) {
168
184
  console.log(chalk.dim(` [dry-run] would write ${path.relative(rootDir, localFilePath)}`));
169
185
  }
@@ -241,6 +257,61 @@ async function installOne(component, registry, componentsJson, registryDir, root
241
257
  fs.copyFileSync(src, dest);
242
258
  }
243
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
+ }
244
315
  }
245
316
  // Update components.json (skipped in dry-run).
246
317
  if (!options.dryRun) {
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.5.0");
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.5.0",
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",