magic-native-ui 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Abhijit Pradhan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # magic-native-ui
2
+
3
+ The CLI that adds [Magic Native UI](https://native-ui.magicwebs.ai) components to an Expo app. It
4
+ copies source files into your project — there is no component library to install.
5
+
6
+ Requires Expo SDK 57+ (React Native 0.86+), React 19 and Tailwind CSS v4.
7
+
8
+ ## Usage
9
+
10
+ ```bash
11
+ npx magic-native-ui@latest init
12
+ npx magic-native-ui@latest add button dialog card
13
+ ```
14
+
15
+ ## Commands
16
+
17
+ | Command | Description |
18
+ | --- | --- |
19
+ | `init` | Writes `components.json`, creates the Tailwind entry stylesheet with theme tokens, configures Metro for Uniwind, adds the `@/*` alias and `uniwind-env.d.ts`, and installs the base dependencies. |
20
+ | `add [components...]` | Adds components and everything they depend on. With no arguments it prompts. |
21
+ | `list` (`ls`) | Lists the components in the registry. |
22
+ | `view <component>` | Shows a component's dependencies and files. |
23
+ | `diff [component]` | Reports which installed components have drifted from the registry. |
24
+
25
+ ### Flags
26
+
27
+ `init` — `-y/--yes`, `--css <path>`, `--base-color <color>`, `--registry <url>`, `--skip-install`,
28
+ `-c/--cwd <dir>`
29
+
30
+ `add` — `-y/--yes`, `-o/--overwrite`, `-a/--all`, `-p/--path <dir>`, `--dry-run`, `--skip-install`,
31
+ `--registry <url>`, `-c/--cwd <dir>`
32
+
33
+ ## components.json
34
+
35
+ ```json
36
+ {
37
+ "style": "default",
38
+ "tsx": true,
39
+ "tailwind": { "css": "global.css", "baseColor": "neutral" },
40
+ "iconLibrary": "lucide",
41
+ "aliases": {
42
+ "components": "@/components",
43
+ "ui": "@/components/ui",
44
+ "lib": "@/lib",
45
+ "utils": "@/lib/utils",
46
+ "hooks": "@/hooks"
47
+ },
48
+ "registry": "https://native-ui.magicwebs.ai/r",
49
+ "metroConfig": "metro.config.js"
50
+ }
51
+ ```
52
+
53
+ Aliases are resolved through your `tsconfig.json` `paths`, and registry sources are rewritten to
54
+ match them on the way in.
55
+
56
+ `MAGIC_NATIVE_UI_REGISTRY` overrides the default registry URL, which is useful when developing
57
+ against a local registry.
58
+
59
+ ## Development
60
+
61
+ ```bash
62
+ bun install
63
+ bun run build # tsup -> dist/index.js
64
+ bun run typecheck
65
+ ```
package/dist/index.js ADDED
@@ -0,0 +1,816 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Command } from "commander";
5
+ import { z as z3 } from "zod";
6
+
7
+ // src/commands/add.ts
8
+ import * as p from "@clack/prompts";
9
+ import path4 from "path";
10
+ import pc2 from "picocolors";
11
+
12
+ // src/utils/logger.ts
13
+ import pc from "picocolors";
14
+ var logger = {
15
+ info: (message) => console.log(`${pc.cyan("info")} ${message}`),
16
+ success: (message) => console.log(`${pc.green("done")} ${message}`),
17
+ warn: (message) => console.log(`${pc.yellow("warn")} ${message}`),
18
+ error: (message) => console.error(`${pc.red("error")} ${message}`),
19
+ plain: (message = "") => console.log(message)
20
+ };
21
+ var CliError = class extends Error {
22
+ constructor(message) {
23
+ super(message);
24
+ this.name = "CliError";
25
+ }
26
+ };
27
+
28
+ // src/registry/schema.ts
29
+ import { z } from "zod";
30
+ var registryFileSchema = z.object({
31
+ path: z.string(),
32
+ content: z.string().optional(),
33
+ type: z.string(),
34
+ target: z.string().optional()
35
+ });
36
+ var registryItemSchema = z.object({
37
+ $schema: z.string().optional(),
38
+ name: z.string(),
39
+ type: z.string(),
40
+ title: z.string().optional(),
41
+ description: z.string().optional(),
42
+ dependencies: z.array(z.string()).optional().default([]),
43
+ devDependencies: z.array(z.string()).optional().default([]),
44
+ registryDependencies: z.array(z.string()).optional().default([]),
45
+ files: z.array(registryFileSchema).optional().default([])
46
+ });
47
+ var registryIndexSchema = z.object({
48
+ name: z.string(),
49
+ homepage: z.string().optional(),
50
+ items: z.array(
51
+ z.object({
52
+ name: z.string(),
53
+ type: z.string(),
54
+ title: z.string().optional(),
55
+ description: z.string().optional(),
56
+ registryDependencies: z.array(z.string()).optional()
57
+ })
58
+ )
59
+ });
60
+
61
+ // src/registry/api.ts
62
+ var cache = /* @__PURE__ */ new Map();
63
+ async function fetchJson(url) {
64
+ const cached = cache.get(url);
65
+ if (cached !== void 0) {
66
+ return cached;
67
+ }
68
+ let response;
69
+ try {
70
+ response = await fetch(url);
71
+ } catch (error) {
72
+ throw new CliError(
73
+ `Could not reach the registry at ${url}.
74
+ ${error instanceof Error ? error.message : String(error)}`
75
+ );
76
+ }
77
+ if (response.status === 404) {
78
+ throw new CliError(`Not found in the registry: ${url}`);
79
+ }
80
+ if (!response.ok) {
81
+ throw new CliError(`Registry responded with ${response.status} for ${url}`);
82
+ }
83
+ const json = await response.json();
84
+ cache.set(url, json);
85
+ return json;
86
+ }
87
+ function itemUrl(registry, nameOrUrl) {
88
+ if (nameOrUrl.startsWith("http://") || nameOrUrl.startsWith("https://")) {
89
+ return nameOrUrl;
90
+ }
91
+ return `${registry.replace(/\/$/, "")}/${nameOrUrl}.json`;
92
+ }
93
+ async function getRegistryIndex(registry) {
94
+ return registryIndexSchema.parse(await fetchJson(`${registry.replace(/\/$/, "")}/index.json`));
95
+ }
96
+ async function getRegistryItem(registry, nameOrUrl) {
97
+ return registryItemSchema.parse(await fetchJson(itemUrl(registry, nameOrUrl)));
98
+ }
99
+ async function resolveItemTree(registry, names, seen = /* @__PURE__ */ new Set(), acc = []) {
100
+ for (const name of names) {
101
+ if (seen.has(name)) continue;
102
+ seen.add(name);
103
+ const item = await getRegistryItem(registry, name);
104
+ await resolveItemTree(registry, item.registryDependencies, seen, acc);
105
+ acc.push(item);
106
+ }
107
+ return acc;
108
+ }
109
+
110
+ // src/utils/config.ts
111
+ import { existsSync } from "fs";
112
+ import { readFile, writeFile } from "fs/promises";
113
+ import path from "path";
114
+ import { z as z2 } from "zod";
115
+
116
+ // src/utils/json.ts
117
+ function parseJsonc(source) {
118
+ let out = "";
119
+ let inString = false;
120
+ let inLine = false;
121
+ let inBlock = false;
122
+ for (let i = 0; i < source.length; i++) {
123
+ const char = source[i];
124
+ const next = source[i + 1];
125
+ if (inLine) {
126
+ if (char === "\n") {
127
+ inLine = false;
128
+ out += char;
129
+ }
130
+ continue;
131
+ }
132
+ if (inBlock) {
133
+ if (char === "*" && next === "/") {
134
+ inBlock = false;
135
+ i++;
136
+ }
137
+ continue;
138
+ }
139
+ if (inString) {
140
+ out += char;
141
+ if (char === "\\") {
142
+ out += source[i + 1] ?? "";
143
+ i++;
144
+ } else if (char === '"') {
145
+ inString = false;
146
+ }
147
+ continue;
148
+ }
149
+ if (char === '"') {
150
+ inString = true;
151
+ out += char;
152
+ continue;
153
+ }
154
+ if (char === "/" && next === "/") {
155
+ inLine = true;
156
+ i++;
157
+ continue;
158
+ }
159
+ if (char === "/" && next === "*") {
160
+ inBlock = true;
161
+ i++;
162
+ continue;
163
+ }
164
+ out += char;
165
+ }
166
+ return JSON.parse(out.replace(/,(\s*[}\]])/g, "$1"));
167
+ }
168
+
169
+ // src/utils/config.ts
170
+ var CONFIG_FILE = "components.json";
171
+ var DEFAULT_REGISTRY = process.env.MAGIC_NATIVE_UI_REGISTRY ?? "https://native-ui.magicwebs.ai/r";
172
+ var configSchema = z2.object({
173
+ $schema: z2.string().optional(),
174
+ style: z2.string().default("default"),
175
+ tsx: z2.boolean().default(true),
176
+ tailwind: z2.object({
177
+ css: z2.string(),
178
+ baseColor: z2.string().default("neutral")
179
+ }),
180
+ iconLibrary: z2.string().default("lucide"),
181
+ aliases: z2.object({
182
+ components: z2.string().default("@/components"),
183
+ ui: z2.string().default("@/components/ui"),
184
+ lib: z2.string().default("@/lib"),
185
+ utils: z2.string().default("@/lib/utils"),
186
+ hooks: z2.string().default("@/hooks")
187
+ }),
188
+ registry: z2.string().default(DEFAULT_REGISTRY),
189
+ metroConfig: z2.string().default("metro.config.js")
190
+ });
191
+ async function readTsconfigPaths(cwd) {
192
+ const tsconfigPath = path.join(cwd, "tsconfig.json");
193
+ if (!existsSync(tsconfigPath)) {
194
+ return { baseUrl: ".", paths: {} };
195
+ }
196
+ try {
197
+ const tsconfig = parseJsonc(await readFile(tsconfigPath, "utf8"));
198
+ return {
199
+ baseUrl: tsconfig.compilerOptions?.baseUrl ?? ".",
200
+ paths: tsconfig.compilerOptions?.paths ?? {}
201
+ };
202
+ } catch {
203
+ return { baseUrl: ".", paths: {} };
204
+ }
205
+ }
206
+ function resolveAlias(cwd, alias, baseUrl, paths) {
207
+ for (const [pattern, targets] of Object.entries(paths)) {
208
+ const prefix = pattern.replace(/\*$/, "");
209
+ const target = targets[0];
210
+ if (!target || !alias.startsWith(prefix)) continue;
211
+ return path.resolve(cwd, baseUrl, target.replace(/\*$/, "") + alias.slice(prefix.length));
212
+ }
213
+ return path.resolve(cwd, alias.replace(/^@\//, ""));
214
+ }
215
+ async function resolveConfig(cwd, config) {
216
+ const { baseUrl, paths } = await readTsconfigPaths(cwd);
217
+ const resolve = (alias) => resolveAlias(cwd, alias, baseUrl, paths);
218
+ return {
219
+ ...config,
220
+ resolvedPaths: {
221
+ cwd,
222
+ css: path.resolve(cwd, config.tailwind.css),
223
+ ui: resolve(config.aliases.ui),
224
+ lib: resolve(config.aliases.lib),
225
+ utils: resolve(config.aliases.utils),
226
+ hooks: resolve(config.aliases.hooks),
227
+ components: resolve(config.aliases.components)
228
+ }
229
+ };
230
+ }
231
+ async function readConfig(cwd) {
232
+ const configPath = path.join(cwd, CONFIG_FILE);
233
+ if (!existsSync(configPath)) {
234
+ throw new CliError(
235
+ `No ${CONFIG_FILE} found in ${cwd}.
236
+ Run "magic-native-ui init" first.`
237
+ );
238
+ }
239
+ const parsed = configSchema.safeParse(parseJsonc(await readFile(configPath, "utf8")));
240
+ if (!parsed.success) {
241
+ throw new CliError(`${CONFIG_FILE} is invalid:
242
+ ${z2.prettifyError(parsed.error)}`);
243
+ }
244
+ return resolveConfig(cwd, parsed.data);
245
+ }
246
+ async function writeConfig(cwd, config) {
247
+ await writeFile(
248
+ path.join(cwd, CONFIG_FILE),
249
+ `${JSON.stringify(config, null, 2)}
250
+ `,
251
+ "utf8"
252
+ );
253
+ }
254
+
255
+ // src/utils/project.ts
256
+ import { existsSync as existsSync2 } from "fs";
257
+ import { readFile as readFile2 } from "fs/promises";
258
+ import path2 from "path";
259
+ async function readPackageJson(cwd) {
260
+ const file = path2.join(cwd, "package.json");
261
+ if (!existsSync2(file)) return null;
262
+ try {
263
+ return parseJsonc(await readFile2(file, "utf8"));
264
+ } catch {
265
+ return null;
266
+ }
267
+ }
268
+ function detectPackageManager(cwd) {
269
+ if (existsSync2(path2.join(cwd, "bun.lock")) || existsSync2(path2.join(cwd, "bun.lockb"))) return "bun";
270
+ if (existsSync2(path2.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
271
+ if (existsSync2(path2.join(cwd, "yarn.lock"))) return "yarn";
272
+ return "npm";
273
+ }
274
+ function findCssEntry(cwd) {
275
+ const candidates = [
276
+ "global.css",
277
+ "src/global.css",
278
+ "app/global.css",
279
+ "styles/global.css",
280
+ "src/styles/global.css"
281
+ ];
282
+ return candidates.find((candidate) => existsSync2(path2.join(cwd, candidate))) ?? null;
283
+ }
284
+ function findMetroConfig(cwd) {
285
+ const candidates = ["metro.config.js", "metro.config.cjs", "metro.config.mjs"];
286
+ return candidates.find((candidate) => existsSync2(path2.join(cwd, candidate))) ?? null;
287
+ }
288
+ async function getProjectInfo(cwd) {
289
+ const pkg = await readPackageJson(cwd);
290
+ const deps = { ...pkg?.dependencies, ...pkg?.devDependencies };
291
+ return {
292
+ cwd,
293
+ packageManager: detectPackageManager(cwd),
294
+ isExpo: Boolean(deps.expo) || existsSync2(path2.join(cwd, "app.json")),
295
+ isTypeScript: existsSync2(path2.join(cwd, "tsconfig.json")),
296
+ hasSrcDir: existsSync2(path2.join(cwd, "src")),
297
+ expoVersion: deps.expo ?? null,
298
+ reactNativeVersion: deps["react-native"] ?? null,
299
+ metroConfig: findMetroConfig(cwd),
300
+ cssEntry: findCssEntry(cwd)
301
+ };
302
+ }
303
+ function installCommand(packageManager, packages, dev = false) {
304
+ const devFlag = dev ? packageManager === "npm" ? "--save-dev" : "-D" : null;
305
+ const verb = packageManager === "npm" ? "install" : "add";
306
+ return [packageManager, verb, ...devFlag ? [devFlag] : [], ...packages];
307
+ }
308
+
309
+ // src/utils/updaters/dependencies.ts
310
+ import { spawn } from "child_process";
311
+ async function installDependencies(cwd, packageManager, packages, dev = false) {
312
+ if (packages.length === 0) return;
313
+ const [command, ...args] = installCommand(packageManager, packages, dev);
314
+ logger.info(`Installing ${packages.join(", ")}`);
315
+ await new Promise((resolve, reject) => {
316
+ const child = spawn(command, args, {
317
+ cwd,
318
+ stdio: "inherit",
319
+ // npm/yarn/pnpm ship as .cmd shims on Windows, which need a shell.
320
+ shell: process.platform === "win32"
321
+ });
322
+ child.on("error", reject);
323
+ child.on("close", (code) => {
324
+ if (code === 0) {
325
+ resolve();
326
+ return;
327
+ }
328
+ reject(new CliError(`${command} exited with code ${code}`));
329
+ });
330
+ });
331
+ }
332
+
333
+ // src/utils/updaters/files.ts
334
+ import { existsSync as existsSync3 } from "fs";
335
+ import { mkdir, writeFile as writeFile2 } from "fs/promises";
336
+ import path3 from "path";
337
+
338
+ // src/utils/transform.ts
339
+ function transformImports(content, config) {
340
+ const { aliases } = config;
341
+ return content.replaceAll("@/registry/lib/utils", aliases.utils).replace(/@\/registry\/lib\/([\w.-]+)/g, `${aliases.lib}/$1`).replace(/@\/registry\/ui\/([\w.-]+)/g, `${aliases.ui}/$1`).replace(/@\/registry\/hooks\/([\w.-]+)/g, `${aliases.hooks}/$1`);
342
+ }
343
+ function targetPathFor(file, config) {
344
+ const fileName = file.target ?? file.path.split("/").pop();
345
+ switch (file.type) {
346
+ case "registry:ui":
347
+ return `${config.resolvedPaths.ui}/${fileName}`;
348
+ case "registry:hook":
349
+ return `${config.resolvedPaths.hooks}/${fileName}`;
350
+ case "registry:lib":
351
+ return `${config.resolvedPaths.lib}/${fileName}`;
352
+ case "registry:component":
353
+ return `${config.resolvedPaths.components}/${fileName}`;
354
+ default:
355
+ return `${config.resolvedPaths.cwd}/${fileName}`;
356
+ }
357
+ }
358
+
359
+ // src/utils/updaters/files.ts
360
+ async function writeRegistryFiles(items, config, options) {
361
+ const results = [];
362
+ for (const item of items) {
363
+ for (const file of item.files) {
364
+ if (file.content === void 0) continue;
365
+ const target = targetPathFor(file, config);
366
+ const relative = path3.relative(config.resolvedPaths.cwd, target).replaceAll("\\", "/");
367
+ if (existsSync3(target) && !options.overwrite) {
368
+ results.push({ path: relative, status: "skipped" });
369
+ continue;
370
+ }
371
+ if (!options.dryRun) {
372
+ await mkdir(path3.dirname(target), { recursive: true });
373
+ await writeFile2(target, transformImports(file.content, config), "utf8");
374
+ }
375
+ results.push({ path: relative, status: "written" });
376
+ }
377
+ }
378
+ return results;
379
+ }
380
+
381
+ // src/commands/add.ts
382
+ function applyPathOverride(config, override) {
383
+ if (!override) return config;
384
+ const target = path4.resolve(config.resolvedPaths.cwd, override);
385
+ return {
386
+ ...config,
387
+ resolvedPaths: {
388
+ ...config.resolvedPaths,
389
+ ui: target,
390
+ lib: target,
391
+ hooks: target,
392
+ components: target,
393
+ utils: path4.join(target, "utils")
394
+ }
395
+ };
396
+ }
397
+ async function add(components, options) {
398
+ const baseConfig = await readConfig(options.cwd);
399
+ const config = applyPathOverride(baseConfig, options.path);
400
+ const registry = options.registry || config.registry;
401
+ p.intro(pc2.bold("magic-native-ui add"));
402
+ let names = components;
403
+ if (options.all) {
404
+ const index = await getRegistryIndex(registry);
405
+ names = index.items.filter((item) => item.type === "registry:ui").map((item) => item.name);
406
+ }
407
+ if (names.length === 0) {
408
+ if (options.yes) {
409
+ throw new CliError("No components specified. Pass names, or use --all.");
410
+ }
411
+ const index = await getRegistryIndex(registry);
412
+ const selected = await p.multiselect({
413
+ message: "Which components would you like to add?",
414
+ options: index.items.filter((item) => item.type === "registry:ui").map((item) => ({
415
+ value: item.name,
416
+ label: item.title ?? item.name,
417
+ hint: item.description
418
+ })),
419
+ required: true
420
+ });
421
+ if (p.isCancel(selected)) {
422
+ p.cancel("Cancelled.");
423
+ return;
424
+ }
425
+ names = selected;
426
+ }
427
+ const spinner3 = p.spinner();
428
+ spinner3.start(`Resolving ${names.join(", ")}`);
429
+ const items = await resolveItemTree(registry, names);
430
+ spinner3.stop(`Resolved ${items.length} item${items.length === 1 ? "" : "s"}`);
431
+ const written = await writeRegistryFiles(items, config, {
432
+ overwrite: options.overwrite,
433
+ dryRun: options.dryRun
434
+ });
435
+ for (const file of written) {
436
+ if (file.status === "written") {
437
+ p.log.success(`${options.dryRun ? "Would write" : "Wrote"} ${file.path}`);
438
+ } else {
439
+ p.log.warn(`Skipped ${file.path} (already exists \u2014 pass --overwrite to replace)`);
440
+ }
441
+ }
442
+ const pkg = await readPackageJson(options.cwd);
443
+ const installed = new Set(Object.keys({ ...pkg?.dependencies, ...pkg?.devDependencies }));
444
+ const missing = [...new Set(items.flatMap((item) => item.dependencies))].filter(
445
+ (dependency) => !installed.has(dependency.replace(/@[^@/]+$/, ""))
446
+ );
447
+ if (missing.length > 0 && !options.dryRun && !options.skipInstall) {
448
+ const project = await getProjectInfo(options.cwd);
449
+ await installDependencies(options.cwd, project.packageManager, missing);
450
+ } else if (missing.length > 0) {
451
+ p.log.info(`Dependencies needed: ${missing.join(", ")}`);
452
+ }
453
+ p.outro(pc2.green(options.dryRun ? "Dry run complete." : "Done."));
454
+ }
455
+
456
+ // src/commands/diff.ts
457
+ import { existsSync as existsSync4 } from "fs";
458
+ import { readFile as readFile3 } from "fs/promises";
459
+ import path5 from "path";
460
+ import pc3 from "picocolors";
461
+ async function diff(name, options) {
462
+ const config = await readConfig(options.cwd);
463
+ const registry = options.registry || config.registry;
464
+ const names = name ? [name] : (await getRegistryIndex(registry)).items.filter((item) => item.type === "registry:ui").map((item) => item.name);
465
+ const changed = [];
466
+ for (const itemName of names) {
467
+ const item = await getRegistryItem(registry, itemName);
468
+ for (const file of item.files) {
469
+ if (file.content === void 0) continue;
470
+ const target = targetPathFor(file, config);
471
+ if (!existsSync4(target)) continue;
472
+ const local = await readFile3(target, "utf8");
473
+ if (local !== transformImports(file.content, config)) {
474
+ changed.push(path5.relative(options.cwd, target).replaceAll("\\", "/"));
475
+ }
476
+ }
477
+ }
478
+ logger.plain();
479
+ if (changed.length === 0) {
480
+ logger.plain(pc3.green("Every installed component matches the registry."));
481
+ logger.plain();
482
+ return;
483
+ }
484
+ logger.plain(pc3.bold("Differs from the registry:"));
485
+ for (const file of changed) {
486
+ logger.plain(` ${pc3.yellow(file)}`);
487
+ }
488
+ logger.plain();
489
+ logger.plain(pc3.dim('Run "magic-native-ui add <name> --overwrite" to reset one.'));
490
+ logger.plain();
491
+ }
492
+
493
+ // src/commands/init.ts
494
+ import * as p2 from "@clack/prompts";
495
+ import path9 from "path";
496
+ import pc4 from "picocolors";
497
+
498
+ // src/utils/updaters/css.ts
499
+ import { existsSync as existsSync5 } from "fs";
500
+ import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
501
+ import path6 from "path";
502
+ var REQUIRED_IMPORTS = ["@import 'tailwindcss';", "@import 'uniwind';"];
503
+ async function updateCss(cssPath, themeCss) {
504
+ await mkdir2(path6.dirname(cssPath), { recursive: true });
505
+ if (!existsSync5(cssPath)) {
506
+ await writeFile3(cssPath, `${REQUIRED_IMPORTS.join("\n")}
507
+
508
+ ${themeCss}`, "utf8");
509
+ return { created: true, addedImports: REQUIRED_IMPORTS, addedTheme: true };
510
+ }
511
+ const existing = await readFile4(cssPath, "utf8");
512
+ const missingImports = REQUIRED_IMPORTS.filter(
513
+ (statement) => !existing.includes(statement.replace(/'/g, "'")) && !existing.includes(statement.replace(/'/g, '"'))
514
+ );
515
+ const hasTheme = existing.includes("--color-background");
516
+ let next = existing;
517
+ if (missingImports.length > 0) {
518
+ next = `${missingImports.join("\n")}
519
+ ${next}`;
520
+ }
521
+ if (!hasTheme) {
522
+ next = `${next.trimEnd()}
523
+
524
+ ${themeCss}`;
525
+ }
526
+ if (next !== existing) {
527
+ await writeFile3(cssPath, next, "utf8");
528
+ }
529
+ return { created: false, addedImports: missingImports, addedTheme: !hasTheme };
530
+ }
531
+
532
+ // src/utils/updaters/metro.ts
533
+ import { existsSync as existsSync6 } from "fs";
534
+ import { readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
535
+ import path7 from "path";
536
+ function template(cssEntry) {
537
+ return `const { getDefaultConfig } = require('expo/metro-config')
538
+ const { withUniwindConfig } = require('uniwind/metro')
539
+
540
+ const config = getDefaultConfig(__dirname)
541
+
542
+ // React Native still uses deep imports such as \`react-native/rn-get-polyfills\`,
543
+ // which break when package exports are enabled. Uniwind (with culori) and Radix
544
+ // - used by @rn-primitives on web - need the opposite, so exports are disabled
545
+ // globally and re-enabled for just those packages.
546
+ const PACKAGE_EXPORTS_ALLOWLIST = ['uniwind', 'culori', '@radix-ui']
547
+
548
+ config.resolver.unstable_enablePackageExports = false
549
+ config.resolver.resolveRequest = (context, moduleName, platform) => {
550
+ if (PACKAGE_EXPORTS_ALLOWLIST.some((prefix) => moduleName.startsWith(prefix))) {
551
+ return context.resolveRequest(
552
+ { ...context, unstable_enablePackageExports: true },
553
+ moduleName,
554
+ platform
555
+ )
556
+ }
557
+
558
+ return context.resolveRequest(context, moduleName, platform)
559
+ }
560
+
561
+ // \`withUniwindConfig\` must stay the outermost wrapper.
562
+ module.exports = withUniwindConfig(config, {
563
+ cssEntryFile: './${cssEntry.replaceAll("\\", "/")}',
564
+ dtsFile: './uniwind-types.d.ts',
565
+ })
566
+ `;
567
+ }
568
+ async function updateMetroConfig(cwd, metroConfigFile, cssEntry) {
569
+ const target = path7.join(cwd, metroConfigFile);
570
+ if (!existsSync6(target)) {
571
+ await writeFile4(target, template(cssEntry), "utf8");
572
+ return { status: "created", file: metroConfigFile };
573
+ }
574
+ const existing = await readFile5(target, "utf8");
575
+ if (existing.includes("withUniwindConfig")) {
576
+ return { status: "already-configured", file: metroConfigFile };
577
+ }
578
+ return { status: "needs-manual-edit", file: metroConfigFile };
579
+ }
580
+
581
+ // src/utils/updaters/tsconfig.ts
582
+ import { existsSync as existsSync7 } from "fs";
583
+ import { readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
584
+ import path8 from "path";
585
+ async function ensurePathAlias(cwd, alias = "@/*", target = "./*") {
586
+ const file = path8.join(cwd, "tsconfig.json");
587
+ if (!existsSync7(file)) return false;
588
+ const raw = await readFile6(file, "utf8");
589
+ let tsconfig;
590
+ try {
591
+ tsconfig = parseJsonc(raw);
592
+ } catch {
593
+ return false;
594
+ }
595
+ if (tsconfig.compilerOptions?.paths?.[alias]) return false;
596
+ tsconfig.compilerOptions ??= {};
597
+ tsconfig.compilerOptions.baseUrl ??= ".";
598
+ tsconfig.compilerOptions.paths ??= {};
599
+ tsconfig.compilerOptions.paths[alias] = [target];
600
+ await writeFile5(file, `${JSON.stringify(tsconfig, null, 2)}
601
+ `, "utf8");
602
+ return true;
603
+ }
604
+ var UNIWIND_ENV = `/// <reference types="uniwind/types" />
605
+ `;
606
+ async function ensureUniwindTypes(cwd) {
607
+ const file = path8.join(cwd, "uniwind-env.d.ts");
608
+ if (existsSync7(file)) return false;
609
+ await writeFile5(file, UNIWIND_ENV, "utf8");
610
+ return true;
611
+ }
612
+
613
+ // src/commands/init.ts
614
+ var BASE_COLORS = ["neutral", "slate", "stone", "zinc", "gray"];
615
+ var BASE_DEPENDENCIES = [
616
+ "uniwind",
617
+ "tailwindcss",
618
+ "clsx",
619
+ "tailwind-merge",
620
+ "class-variance-authority"
621
+ ];
622
+ function cancelled(value) {
623
+ if (p2.isCancel(value)) {
624
+ p2.cancel("Cancelled.");
625
+ process.exit(0);
626
+ }
627
+ }
628
+ async function init(options) {
629
+ const project = await getProjectInfo(options.cwd);
630
+ p2.intro(pc4.bold("magic-native-ui init"));
631
+ if (!project.isExpo) {
632
+ p2.log.warn(
633
+ 'This does not look like an Expo project (no "expo" dependency and no app.json). Continuing anyway.'
634
+ );
635
+ }
636
+ if (!project.isTypeScript) {
637
+ p2.log.warn("No tsconfig.json found \u2014 components are written as .tsx regardless.");
638
+ }
639
+ let cssEntry = options.cssEntry ?? project.cssEntry ?? "global.css";
640
+ let baseColor = options.baseColor ?? "neutral";
641
+ if (!options.yes) {
642
+ const answeredCss = await p2.text({
643
+ message: "Where is your Tailwind entry CSS file?",
644
+ initialValue: cssEntry,
645
+ placeholder: "global.css"
646
+ });
647
+ cancelled(answeredCss);
648
+ cssEntry = answeredCss;
649
+ const answeredColor = await p2.select({
650
+ message: "Which base colour?",
651
+ initialValue: baseColor,
652
+ options: BASE_COLORS.map((color) => ({ value: color, label: color }))
653
+ });
654
+ cancelled(answeredColor);
655
+ baseColor = answeredColor;
656
+ }
657
+ const config = configSchema.parse({
658
+ $schema: "https://native-ui.magicwebs.ai/schema.json",
659
+ style: "default",
660
+ tsx: true,
661
+ tailwind: { css: cssEntry, baseColor },
662
+ iconLibrary: "lucide",
663
+ aliases: {
664
+ components: "@/components",
665
+ ui: "@/components/ui",
666
+ lib: "@/lib",
667
+ utils: "@/lib/utils",
668
+ hooks: "@/hooks"
669
+ },
670
+ registry: options.registry || DEFAULT_REGISTRY,
671
+ metroConfig: project.metroConfig ?? "metro.config.js"
672
+ });
673
+ const resolved = await resolveConfig(options.cwd, config);
674
+ const spinner3 = p2.spinner();
675
+ spinner3.start("Writing configuration");
676
+ await writeConfig(options.cwd, config);
677
+ spinner3.stop(`Wrote ${CONFIG_FILE}`);
678
+ spinner3.start("Fetching theme and utilities");
679
+ const [theme, utils] = await Promise.all([
680
+ getRegistryItem(config.registry, "theme"),
681
+ getRegistryItem(config.registry, "utils")
682
+ ]);
683
+ spinner3.stop("Fetched theme and utilities");
684
+ const themeCss = theme.files[0]?.content;
685
+ if (!themeCss) {
686
+ throw new CliError("The registry theme item contains no CSS.");
687
+ }
688
+ const cssResult = await updateCss(resolved.resolvedPaths.css, themeCss);
689
+ p2.log.success(
690
+ cssResult.created ? `Created ${cssEntry}` : `Updated ${cssEntry}${cssResult.addedTheme ? " (added theme tokens)" : ""}`
691
+ );
692
+ const metroResult = await updateMetroConfig(options.cwd, config.metroConfig, cssEntry);
693
+ if (metroResult.status === "created") {
694
+ p2.log.success(`Created ${metroResult.file}`);
695
+ } else if (metroResult.status === "already-configured") {
696
+ p2.log.info(`${metroResult.file} already wraps withUniwindConfig`);
697
+ } else {
698
+ p2.log.warn(
699
+ `${metroResult.file} exists but does not use withUniwindConfig.
700
+ Wrap your exported config with it, outermost:
701
+ ` + pc4.dim(` const { withUniwindConfig } = require('uniwind/metro')
702
+ `) + pc4.dim(` module.exports = withUniwindConfig(config, { cssEntryFile: './${cssEntry}' })`)
703
+ );
704
+ }
705
+ if (await ensurePathAlias(options.cwd)) {
706
+ p2.log.success('Added the "@/*" path alias to tsconfig.json');
707
+ }
708
+ if (await ensureUniwindTypes(options.cwd)) {
709
+ p2.log.success("Created uniwind-env.d.ts (enables className typing)");
710
+ }
711
+ await writeRegistryFiles([utils], resolved, { overwrite: true, dryRun: false });
712
+ p2.log.success(`Added ${path9.relative(options.cwd, resolved.resolvedPaths.utils)}.ts`);
713
+ if (!options.skipInstall) {
714
+ await installDependencies(options.cwd, project.packageManager, BASE_DEPENDENCIES);
715
+ } else {
716
+ p2.log.info(`Skipped install. Run: ${project.packageManager} add ${BASE_DEPENDENCIES.join(" ")}`);
717
+ }
718
+ p2.note(
719
+ [
720
+ `1. Import the stylesheet in your root layout: ${pc4.cyan(`import './${cssEntry}'`)}`,
721
+ `2. Add ${pc4.cyan("<PortalHost />")} as the last child of that layout (needed by Dialog).`,
722
+ `3. Add a component: ${pc4.cyan("npx magic-native-ui add button")}`
723
+ ].join("\n"),
724
+ "Next steps"
725
+ );
726
+ p2.outro(pc4.green("Ready."));
727
+ }
728
+
729
+ // src/commands/list.ts
730
+ import pc5 from "picocolors";
731
+ async function list(options) {
732
+ const registry = options.registry ?? await readConfig(options.cwd).then((config) => config.registry).catch(() => DEFAULT_REGISTRY);
733
+ const index = await getRegistryIndex(registry);
734
+ const components = index.items.filter((item) => item.type === "registry:ui");
735
+ const width = Math.max(...components.map((item) => item.name.length));
736
+ logger.plain();
737
+ logger.plain(pc5.bold(`${index.name} \u2014 ${components.length} components`));
738
+ logger.plain();
739
+ for (const item of components) {
740
+ logger.plain(` ${pc5.cyan(item.name.padEnd(width))} ${pc5.dim(item.description ?? "")}`);
741
+ }
742
+ logger.plain();
743
+ }
744
+
745
+ // src/commands/view.ts
746
+ import pc6 from "picocolors";
747
+ async function view(name, options) {
748
+ const registry = options.registry ?? await readConfig(options.cwd).then((config) => config.registry).catch(() => DEFAULT_REGISTRY);
749
+ const item = await getRegistryItem(registry, name);
750
+ logger.plain();
751
+ logger.plain(`${pc6.bold(item.title ?? item.name)} ${pc6.dim(item.type)}`);
752
+ if (item.description) {
753
+ logger.plain(item.description);
754
+ }
755
+ logger.plain();
756
+ if (item.dependencies.length > 0) {
757
+ logger.plain(`${pc6.bold("npm dependencies")} ${item.dependencies.join(", ")}`);
758
+ }
759
+ if (item.registryDependencies.length > 0) {
760
+ logger.plain(`${pc6.bold("registry dependencies")} ${item.registryDependencies.join(", ")}`);
761
+ }
762
+ logger.plain(`${pc6.bold("files")} ${item.files.map((f) => f.path).join(", ")}`);
763
+ logger.plain();
764
+ }
765
+
766
+ // src/index.ts
767
+ var program = new Command();
768
+ program.name("magic-native-ui").description("Add Magic Native UI components to your Expo app.").version("0.1.0");
769
+ program.command("init").description("configure the current project and install the base dependencies").option("-c, --cwd <dir>", "working directory", process.cwd()).option("-y, --yes", "accept the defaults without prompting", false).option("--css <path>", "path to the Tailwind entry stylesheet").option("--base-color <color>", "neutral, slate, stone, zinc or gray").option("--registry <url>", "registry base URL", DEFAULT_REGISTRY).option("--skip-install", "do not install npm dependencies", false).action(async (options) => {
770
+ await init({
771
+ cwd: options.cwd,
772
+ yes: options.yes,
773
+ registry: options.registry,
774
+ cssEntry: options.css,
775
+ baseColor: options.baseColor,
776
+ skipInstall: options.skipInstall
777
+ });
778
+ });
779
+ program.command("add").description("add components to your project").argument("[components...]", "component names").option("-c, --cwd <dir>", "working directory", process.cwd()).option("-y, --yes", "skip prompts", false).option("-o, --overwrite", "overwrite existing files", false).option("-a, --all", "add every component", false).option("-p, --path <dir>", "write all files to this directory").option("--dry-run", "show what would happen without writing", false).option("--skip-install", "do not install npm dependencies", false).option("--registry <url>", "registry base URL").action(async (components, options) => {
780
+ await add(components, {
781
+ cwd: options.cwd,
782
+ yes: options.yes,
783
+ overwrite: options.overwrite,
784
+ all: options.all,
785
+ dryRun: options.dryRun,
786
+ skipInstall: options.skipInstall,
787
+ path: options.path,
788
+ registry: options.registry
789
+ });
790
+ });
791
+ program.command("list").alias("ls").description("list the components in the registry").option("-c, --cwd <dir>", "working directory", process.cwd()).option("--registry <url>", "registry base URL").action(async (options) => {
792
+ await list(options);
793
+ });
794
+ program.command("view").description("show details for a single registry item").argument("<component>", "component name").option("-c, --cwd <dir>", "working directory", process.cwd()).option("--registry <url>", "registry base URL").action(async (component, options) => {
795
+ await view(component, options);
796
+ });
797
+ program.command("diff").description("check installed components against the registry").argument("[component]", "component name; omit to check all").option("-c, --cwd <dir>", "working directory", process.cwd()).option("--registry <url>", "registry base URL").action(async (component, options) => {
798
+ await diff(component, options);
799
+ });
800
+ async function main() {
801
+ try {
802
+ await program.parseAsync(process.argv);
803
+ } catch (error) {
804
+ if (error instanceof CliError) {
805
+ logger.error(error.message);
806
+ } else if (error instanceof z3.ZodError) {
807
+ logger.error(`Registry response did not match the expected schema:
808
+ ${z3.prettifyError(error)}`);
809
+ } else {
810
+ logger.error(error instanceof Error ? error.message : String(error));
811
+ }
812
+ process.exit(1);
813
+ }
814
+ }
815
+ void main();
816
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/add.ts","../src/utils/logger.ts","../src/registry/schema.ts","../src/registry/api.ts","../src/utils/config.ts","../src/utils/json.ts","../src/utils/project.ts","../src/utils/updaters/dependencies.ts","../src/utils/updaters/files.ts","../src/utils/transform.ts","../src/commands/diff.ts","../src/commands/init.ts","../src/utils/updaters/css.ts","../src/utils/updaters/metro.ts","../src/utils/updaters/tsconfig.ts","../src/commands/list.ts","../src/commands/view.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { z } from 'zod'\n\nimport { add } from '@/commands/add'\nimport { diff } from '@/commands/diff'\nimport { init } from '@/commands/init'\nimport { list } from '@/commands/list'\nimport { view } from '@/commands/view'\nimport { DEFAULT_REGISTRY } from '@/utils/config'\nimport { CliError, logger } from '@/utils/logger'\n\nconst program = new Command()\n\nprogram\n .name('magic-native-ui')\n .description('Add Magic Native UI components to your Expo app.')\n .version('0.1.0')\n\nprogram\n .command('init')\n .description('configure the current project and install the base dependencies')\n .option('-c, --cwd <dir>', 'working directory', process.cwd())\n .option('-y, --yes', 'accept the defaults without prompting', false)\n .option('--css <path>', 'path to the Tailwind entry stylesheet')\n .option('--base-color <color>', 'neutral, slate, stone, zinc or gray')\n .option('--registry <url>', 'registry base URL', DEFAULT_REGISTRY)\n .option('--skip-install', 'do not install npm dependencies', false)\n .action(async (options) => {\n await init({\n cwd: options.cwd,\n yes: options.yes,\n registry: options.registry,\n cssEntry: options.css,\n baseColor: options.baseColor,\n skipInstall: options.skipInstall,\n })\n })\n\nprogram\n .command('add')\n .description('add components to your project')\n .argument('[components...]', 'component names')\n .option('-c, --cwd <dir>', 'working directory', process.cwd())\n .option('-y, --yes', 'skip prompts', false)\n .option('-o, --overwrite', 'overwrite existing files', false)\n .option('-a, --all', 'add every component', false)\n .option('-p, --path <dir>', 'write all files to this directory')\n .option('--dry-run', 'show what would happen without writing', false)\n .option('--skip-install', 'do not install npm dependencies', false)\n .option('--registry <url>', 'registry base URL')\n .action(async (components: string[], options) => {\n await add(components, {\n cwd: options.cwd,\n yes: options.yes,\n overwrite: options.overwrite,\n all: options.all,\n dryRun: options.dryRun,\n skipInstall: options.skipInstall,\n path: options.path,\n registry: options.registry,\n })\n })\n\nprogram\n .command('list')\n .alias('ls')\n .description('list the components in the registry')\n .option('-c, --cwd <dir>', 'working directory', process.cwd())\n .option('--registry <url>', 'registry base URL')\n .action(async (options) => {\n await list(options)\n })\n\nprogram\n .command('view')\n .description('show details for a single registry item')\n .argument('<component>', 'component name')\n .option('-c, --cwd <dir>', 'working directory', process.cwd())\n .option('--registry <url>', 'registry base URL')\n .action(async (component: string, options) => {\n await view(component, options)\n })\n\nprogram\n .command('diff')\n .description('check installed components against the registry')\n .argument('[component]', 'component name; omit to check all')\n .option('-c, --cwd <dir>', 'working directory', process.cwd())\n .option('--registry <url>', 'registry base URL')\n .action(async (component: string | undefined, options) => {\n await diff(component, options)\n })\n\nasync function main() {\n try {\n await program.parseAsync(process.argv)\n } catch (error) {\n if (error instanceof CliError) {\n logger.error(error.message)\n } else if (error instanceof z.ZodError) {\n logger.error(`Registry response did not match the expected schema:\\n${z.prettifyError(error)}`)\n } else {\n logger.error(error instanceof Error ? error.message : String(error))\n }\n\n process.exit(1)\n }\n}\n\nvoid main()\n","import * as p from '@clack/prompts'\nimport path from 'node:path'\nimport pc from 'picocolors'\n\nimport { getRegistryIndex, resolveItemTree } from '@/registry/api'\nimport { readConfig, type ResolvedConfig } from '@/utils/config'\nimport { CliError } from '@/utils/logger'\nimport { getProjectInfo, readPackageJson } from '@/utils/project'\nimport { installDependencies } from '@/utils/updaters/dependencies'\nimport { writeRegistryFiles } from '@/utils/updaters/files'\n\nexport type AddOptions = {\n cwd: string\n yes: boolean\n overwrite: boolean\n all: boolean\n dryRun: boolean\n skipInstall: boolean\n path?: string\n registry?: string\n}\n\n/** `--path` sends every file to one directory instead of the configured aliases. */\nfunction applyPathOverride(config: ResolvedConfig, override?: string): ResolvedConfig {\n if (!override) return config\n\n const target = path.resolve(config.resolvedPaths.cwd, override)\n\n return {\n ...config,\n resolvedPaths: {\n ...config.resolvedPaths,\n ui: target,\n lib: target,\n hooks: target,\n components: target,\n utils: path.join(target, 'utils'),\n },\n }\n}\n\nexport async function add(components: string[], options: AddOptions) {\n const baseConfig = await readConfig(options.cwd)\n const config = applyPathOverride(baseConfig, options.path)\n const registry = options.registry || config.registry\n\n p.intro(pc.bold('magic-native-ui add'))\n\n let names = components\n\n if (options.all) {\n const index = await getRegistryIndex(registry)\n names = index.items.filter((item) => item.type === 'registry:ui').map((item) => item.name)\n }\n\n if (names.length === 0) {\n if (options.yes) {\n throw new CliError('No components specified. Pass names, or use --all.')\n }\n\n const index = await getRegistryIndex(registry)\n const selected = await p.multiselect({\n message: 'Which components would you like to add?',\n options: index.items\n .filter((item) => item.type === 'registry:ui')\n .map((item) => ({\n value: item.name,\n label: item.title ?? item.name,\n hint: item.description,\n })),\n required: true,\n })\n\n if (p.isCancel(selected)) {\n p.cancel('Cancelled.')\n return\n }\n\n names = selected as string[]\n }\n\n const spinner = p.spinner()\n\n spinner.start(`Resolving ${names.join(', ')}`)\n const items = await resolveItemTree(registry, names)\n spinner.stop(`Resolved ${items.length} item${items.length === 1 ? '' : 's'}`)\n\n const written = await writeRegistryFiles(items, config, {\n overwrite: options.overwrite,\n dryRun: options.dryRun,\n })\n\n for (const file of written) {\n if (file.status === 'written') {\n p.log.success(`${options.dryRun ? 'Would write' : 'Wrote'} ${file.path}`)\n } else {\n p.log.warn(`Skipped ${file.path} (already exists — pass --overwrite to replace)`)\n }\n }\n\n // Only install what the project is actually missing.\n const pkg = await readPackageJson(options.cwd)\n const installed = new Set(Object.keys({ ...pkg?.dependencies, ...pkg?.devDependencies }))\n const missing = [...new Set(items.flatMap((item) => item.dependencies))].filter(\n (dependency) => !installed.has(dependency.replace(/@[^@/]+$/, ''))\n )\n\n if (missing.length > 0 && !options.dryRun && !options.skipInstall) {\n const project = await getProjectInfo(options.cwd)\n await installDependencies(options.cwd, project.packageManager, missing)\n } else if (missing.length > 0) {\n p.log.info(`Dependencies needed: ${missing.join(', ')}`)\n }\n\n p.outro(pc.green(options.dryRun ? 'Dry run complete.' : 'Done.'))\n}\n","import pc from 'picocolors'\n\nexport const logger = {\n info: (message: string) => console.log(`${pc.cyan('info')} ${message}`),\n success: (message: string) => console.log(`${pc.green('done')} ${message}`),\n warn: (message: string) => console.log(`${pc.yellow('warn')} ${message}`),\n error: (message: string) => console.error(`${pc.red('error')} ${message}`),\n plain: (message = '') => console.log(message),\n}\n\n/** Thrown for problems the user can fix; reported without a stack trace. */\nexport class CliError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'CliError'\n }\n}\n","import { z } from 'zod'\n\nexport const registryFileSchema = z.object({\n path: z.string(),\n content: z.string().optional(),\n type: z.string(),\n target: z.string().optional(),\n})\n\nexport const registryItemSchema = z.object({\n $schema: z.string().optional(),\n name: z.string(),\n type: z.string(),\n title: z.string().optional(),\n description: z.string().optional(),\n dependencies: z.array(z.string()).optional().default([]),\n devDependencies: z.array(z.string()).optional().default([]),\n registryDependencies: z.array(z.string()).optional().default([]),\n files: z.array(registryFileSchema).optional().default([]),\n})\n\nexport const registryIndexSchema = z.object({\n name: z.string(),\n homepage: z.string().optional(),\n items: z.array(\n z.object({\n name: z.string(),\n type: z.string(),\n title: z.string().optional(),\n description: z.string().optional(),\n registryDependencies: z.array(z.string()).optional(),\n })\n ),\n})\n\nexport type RegistryFile = z.infer<typeof registryFileSchema>\nexport type RegistryItem = z.infer<typeof registryItemSchema>\nexport type RegistryIndex = z.infer<typeof registryIndexSchema>\n","import { CliError } from '@/utils/logger'\nimport { registryIndexSchema, registryItemSchema, type RegistryIndex, type RegistryItem } from './schema'\n\nconst cache = new Map<string, unknown>()\n\nasync function fetchJson(url: string): Promise<unknown> {\n const cached = cache.get(url)\n\n if (cached !== undefined) {\n return cached\n }\n\n let response: Response\n\n try {\n response = await fetch(url)\n } catch (error) {\n throw new CliError(\n `Could not reach the registry at ${url}.\\n ${error instanceof Error ? error.message : String(error)}`\n )\n }\n\n if (response.status === 404) {\n throw new CliError(`Not found in the registry: ${url}`)\n }\n\n if (!response.ok) {\n throw new CliError(`Registry responded with ${response.status} for ${url}`)\n }\n\n const json = await response.json()\n cache.set(url, json)\n\n return json\n}\n\n/**\n * Items can be referenced by name (resolved against the configured registry) or\n * by a full URL, which is how cross-registry dependencies work.\n */\nfunction itemUrl(registry: string, nameOrUrl: string) {\n if (nameOrUrl.startsWith('http://') || nameOrUrl.startsWith('https://')) {\n return nameOrUrl\n }\n\n return `${registry.replace(/\\/$/, '')}/${nameOrUrl}.json`\n}\n\nexport async function getRegistryIndex(registry: string): Promise<RegistryIndex> {\n return registryIndexSchema.parse(await fetchJson(`${registry.replace(/\\/$/, '')}/index.json`))\n}\n\nexport async function getRegistryItem(registry: string, nameOrUrl: string): Promise<RegistryItem> {\n return registryItemSchema.parse(await fetchJson(itemUrl(registry, nameOrUrl)))\n}\n\n/**\n * Walks `registryDependencies` depth-first so dependencies are written before\n * the components that import them, and each item is fetched only once.\n */\nexport async function resolveItemTree(\n registry: string,\n names: string[],\n seen = new Set<string>(),\n acc: RegistryItem[] = []\n): Promise<RegistryItem[]> {\n for (const name of names) {\n if (seen.has(name)) continue\n seen.add(name)\n\n const item = await getRegistryItem(registry, name)\n\n await resolveItemTree(registry, item.registryDependencies, seen, acc)\n acc.push(item)\n }\n\n return acc\n}\n","import { existsSync } from 'node:fs'\nimport { readFile, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\nimport { z } from 'zod'\n\nimport { parseJsonc } from '@/utils/json'\nimport { CliError } from '@/utils/logger'\n\nexport const CONFIG_FILE = 'components.json'\nexport const DEFAULT_REGISTRY =\n process.env.MAGIC_NATIVE_UI_REGISTRY ?? 'https://native-ui.magicwebs.ai/r'\n\nexport const configSchema = z.object({\n $schema: z.string().optional(),\n style: z.string().default('default'),\n tsx: z.boolean().default(true),\n tailwind: z.object({\n css: z.string(),\n baseColor: z.string().default('neutral'),\n }),\n iconLibrary: z.string().default('lucide'),\n aliases: z.object({\n components: z.string().default('@/components'),\n ui: z.string().default('@/components/ui'),\n lib: z.string().default('@/lib'),\n utils: z.string().default('@/lib/utils'),\n hooks: z.string().default('@/hooks'),\n }),\n registry: z.string().default(DEFAULT_REGISTRY),\n metroConfig: z.string().default('metro.config.js'),\n})\n\nexport type Config = z.infer<typeof configSchema>\n\nexport type ResolvedConfig = Config & {\n resolvedPaths: {\n cwd: string\n css: string\n ui: string\n lib: string\n utils: string\n hooks: string\n components: string\n }\n}\n\ntype TsconfigPaths = Record<string, string[]>\n\nasync function readTsconfigPaths(cwd: string): Promise<{ baseUrl: string; paths: TsconfigPaths }> {\n const tsconfigPath = path.join(cwd, 'tsconfig.json')\n\n if (!existsSync(tsconfigPath)) {\n return { baseUrl: '.', paths: {} }\n }\n\n try {\n const tsconfig = parseJsonc<{\n compilerOptions?: { baseUrl?: string; paths?: TsconfigPaths }\n }>(await readFile(tsconfigPath, 'utf8'))\n\n return {\n baseUrl: tsconfig.compilerOptions?.baseUrl ?? '.',\n paths: tsconfig.compilerOptions?.paths ?? {},\n }\n } catch {\n return { baseUrl: '.', paths: {} }\n }\n}\n\n/** Turns an import alias such as `@/components/ui` into an absolute directory. */\nexport function resolveAlias(\n cwd: string,\n alias: string,\n baseUrl: string,\n paths: TsconfigPaths\n): string {\n for (const [pattern, targets] of Object.entries(paths)) {\n const prefix = pattern.replace(/\\*$/, '')\n const target = targets[0]\n\n if (!target || !alias.startsWith(prefix)) continue\n\n return path.resolve(cwd, baseUrl, target.replace(/\\*$/, '') + alias.slice(prefix.length))\n }\n\n // No matching tsconfig path: treat `@/x` as `./x`.\n return path.resolve(cwd, alias.replace(/^@\\//, ''))\n}\n\nexport async function resolveConfig(cwd: string, config: Config): Promise<ResolvedConfig> {\n const { baseUrl, paths } = await readTsconfigPaths(cwd)\n const resolve = (alias: string) => resolveAlias(cwd, alias, baseUrl, paths)\n\n return {\n ...config,\n resolvedPaths: {\n cwd,\n css: path.resolve(cwd, config.tailwind.css),\n ui: resolve(config.aliases.ui),\n lib: resolve(config.aliases.lib),\n utils: resolve(config.aliases.utils),\n hooks: resolve(config.aliases.hooks),\n components: resolve(config.aliases.components),\n },\n }\n}\n\nexport async function readConfig(cwd: string): Promise<ResolvedConfig> {\n const configPath = path.join(cwd, CONFIG_FILE)\n\n if (!existsSync(configPath)) {\n throw new CliError(\n `No ${CONFIG_FILE} found in ${cwd}.\\n Run \"magic-native-ui init\" first.`\n )\n }\n\n const parsed = configSchema.safeParse(parseJsonc(await readFile(configPath, 'utf8')))\n\n if (!parsed.success) {\n throw new CliError(`${CONFIG_FILE} is invalid:\\n${z.prettifyError(parsed.error)}`)\n }\n\n return resolveConfig(cwd, parsed.data)\n}\n\nexport async function writeConfig(cwd: string, config: Config) {\n await writeFile(\n path.join(cwd, CONFIG_FILE),\n `${JSON.stringify(config, null, 2)}\\n`,\n 'utf8'\n )\n}\n","/**\n * tsconfig.json and friends allow comments and trailing commas, which\n * JSON.parse rejects. This strips both while preserving string contents.\n */\nexport function parseJsonc<T = unknown>(source: string): T {\n let out = ''\n let inString = false\n let inLine = false\n let inBlock = false\n\n for (let i = 0; i < source.length; i++) {\n const char = source[i]!\n const next = source[i + 1]\n\n if (inLine) {\n if (char === '\\n') {\n inLine = false\n out += char\n }\n continue\n }\n\n if (inBlock) {\n if (char === '*' && next === '/') {\n inBlock = false\n i++\n }\n continue\n }\n\n if (inString) {\n out += char\n if (char === '\\\\') {\n out += source[i + 1] ?? ''\n i++\n } else if (char === '\"') {\n inString = false\n }\n continue\n }\n\n if (char === '\"') {\n inString = true\n out += char\n continue\n }\n\n if (char === '/' && next === '/') {\n inLine = true\n i++\n continue\n }\n\n if (char === '/' && next === '*') {\n inBlock = true\n i++\n continue\n }\n\n out += char\n }\n\n return JSON.parse(out.replace(/,(\\s*[}\\]])/g, '$1')) as T\n}\n","import { existsSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport path from 'node:path'\n\nimport { parseJsonc } from '@/utils/json'\n\nexport type PackageManager = 'bun' | 'pnpm' | 'yarn' | 'npm'\n\nexport type ProjectInfo = {\n cwd: string\n packageManager: PackageManager\n isExpo: boolean\n isTypeScript: boolean\n hasSrcDir: boolean\n expoVersion: string | null\n reactNativeVersion: string | null\n metroConfig: string | null\n cssEntry: string | null\n}\n\nexport type PackageJson = {\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n}\n\nexport async function readPackageJson(cwd: string): Promise<PackageJson | null> {\n const file = path.join(cwd, 'package.json')\n\n if (!existsSync(file)) return null\n\n try {\n return parseJsonc<PackageJson>(await readFile(file, 'utf8'))\n } catch {\n return null\n }\n}\n\nexport function detectPackageManager(cwd: string): PackageManager {\n if (existsSync(path.join(cwd, 'bun.lock')) || existsSync(path.join(cwd, 'bun.lockb'))) return 'bun'\n if (existsSync(path.join(cwd, 'pnpm-lock.yaml'))) return 'pnpm'\n if (existsSync(path.join(cwd, 'yarn.lock'))) return 'yarn'\n\n return 'npm'\n}\n\n/** Looks for an existing Tailwind entry stylesheet in the usual places. */\nfunction findCssEntry(cwd: string): string | null {\n const candidates = [\n 'global.css',\n 'src/global.css',\n 'app/global.css',\n 'styles/global.css',\n 'src/styles/global.css',\n ]\n\n return candidates.find((candidate) => existsSync(path.join(cwd, candidate))) ?? null\n}\n\nfunction findMetroConfig(cwd: string): string | null {\n const candidates = ['metro.config.js', 'metro.config.cjs', 'metro.config.mjs']\n\n return candidates.find((candidate) => existsSync(path.join(cwd, candidate))) ?? null\n}\n\nexport async function getProjectInfo(cwd: string): Promise<ProjectInfo> {\n const pkg = await readPackageJson(cwd)\n const deps = { ...pkg?.dependencies, ...pkg?.devDependencies }\n\n return {\n cwd,\n packageManager: detectPackageManager(cwd),\n isExpo: Boolean(deps.expo) || existsSync(path.join(cwd, 'app.json')),\n isTypeScript: existsSync(path.join(cwd, 'tsconfig.json')),\n hasSrcDir: existsSync(path.join(cwd, 'src')),\n expoVersion: deps.expo ?? null,\n reactNativeVersion: deps['react-native'] ?? null,\n metroConfig: findMetroConfig(cwd),\n cssEntry: findCssEntry(cwd),\n }\n}\n\nexport function installCommand(packageManager: PackageManager, packages: string[], dev = false) {\n const devFlag = dev ? (packageManager === 'npm' ? '--save-dev' : '-D') : null\n const verb = packageManager === 'npm' ? 'install' : 'add'\n\n return [packageManager, verb, ...(devFlag ? [devFlag] : []), ...packages]\n}\n","import { spawn } from 'node:child_process'\n\nimport { installCommand, type PackageManager } from '@/utils/project'\nimport { CliError, logger } from '@/utils/logger'\n\nexport async function installDependencies(\n cwd: string,\n packageManager: PackageManager,\n packages: string[],\n dev = false\n) {\n if (packages.length === 0) return\n\n const [command, ...args] = installCommand(packageManager, packages, dev)\n\n logger.info(`Installing ${packages.join(', ')}`)\n\n await new Promise<void>((resolve, reject) => {\n const child = spawn(command!, args, {\n cwd,\n stdio: 'inherit',\n // npm/yarn/pnpm ship as .cmd shims on Windows, which need a shell.\n shell: process.platform === 'win32',\n })\n\n child.on('error', reject)\n child.on('close', (code) => {\n if (code === 0) {\n resolve()\n return\n }\n\n reject(new CliError(`${command} exited with code ${code}`))\n })\n })\n}\n","import { existsSync } from 'node:fs'\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\n\nimport type { RegistryItem } from '@/registry/schema'\nimport type { ResolvedConfig } from '@/utils/config'\nimport { targetPathFor, transformImports } from '@/utils/transform'\n\nexport type WrittenFile = {\n path: string\n status: 'written' | 'skipped'\n}\n\nexport async function writeRegistryFiles(\n items: RegistryItem[],\n config: ResolvedConfig,\n options: { overwrite: boolean; dryRun: boolean }\n): Promise<WrittenFile[]> {\n const results: WrittenFile[] = []\n\n for (const item of items) {\n for (const file of item.files) {\n if (file.content === undefined) continue\n\n const target = targetPathFor(file, config)\n const relative = path.relative(config.resolvedPaths.cwd, target).replaceAll('\\\\', '/')\n\n if (existsSync(target) && !options.overwrite) {\n results.push({ path: relative, status: 'skipped' })\n continue\n }\n\n if (!options.dryRun) {\n await mkdir(path.dirname(target), { recursive: true })\n await writeFile(target, transformImports(file.content, config), 'utf8')\n }\n\n results.push({ path: relative, status: 'written' })\n }\n }\n\n return results\n}\n","import type { ResolvedConfig } from '@/utils/config'\nimport type { RegistryFile } from '@/registry/schema'\n\n/**\n * Registry sources import through `@/registry/...`. Those are rewritten to the\n * aliases the target project actually uses, the same way shadcn does it.\n */\nexport function transformImports(content: string, config: ResolvedConfig): string {\n const { aliases } = config\n\n return content\n .replaceAll('@/registry/lib/utils', aliases.utils)\n .replace(/@\\/registry\\/lib\\/([\\w.-]+)/g, `${aliases.lib}/$1`)\n .replace(/@\\/registry\\/ui\\/([\\w.-]+)/g, `${aliases.ui}/$1`)\n .replace(/@\\/registry\\/hooks\\/([\\w.-]+)/g, `${aliases.hooks}/$1`)\n}\n\n/** Maps a registry file onto its destination directory in the user's project. */\nexport function targetPathFor(file: RegistryFile, config: ResolvedConfig): string {\n const fileName = file.target ?? file.path.split('/').pop()!\n\n switch (file.type) {\n case 'registry:ui':\n return `${config.resolvedPaths.ui}/${fileName}`\n case 'registry:hook':\n return `${config.resolvedPaths.hooks}/${fileName}`\n case 'registry:lib':\n return `${config.resolvedPaths.lib}/${fileName}`\n case 'registry:component':\n return `${config.resolvedPaths.components}/${fileName}`\n default:\n return `${config.resolvedPaths.cwd}/${fileName}`\n }\n}\n","import { existsSync } from 'node:fs'\nimport { readFile } from 'node:fs/promises'\nimport path from 'node:path'\nimport pc from 'picocolors'\n\nimport { getRegistryIndex, getRegistryItem } from '@/registry/api'\nimport { readConfig } from '@/utils/config'\nimport { logger } from '@/utils/logger'\nimport { targetPathFor, transformImports } from '@/utils/transform'\n\n/**\n * Reports which installed components have drifted from the registry. Content is\n * compared after the import rewrite, so alias differences are not false hits.\n */\nexport async function diff(name: string | undefined, options: { cwd: string; registry?: string }) {\n const config = await readConfig(options.cwd)\n const registry = options.registry || config.registry\n\n const names = name\n ? [name]\n : (await getRegistryIndex(registry)).items\n .filter((item) => item.type === 'registry:ui')\n .map((item) => item.name)\n\n const changed: string[] = []\n\n for (const itemName of names) {\n const item = await getRegistryItem(registry, itemName)\n\n for (const file of item.files) {\n if (file.content === undefined) continue\n\n const target = targetPathFor(file, config)\n\n if (!existsSync(target)) continue\n\n const local = await readFile(target, 'utf8')\n\n if (local !== transformImports(file.content, config)) {\n changed.push(path.relative(options.cwd, target).replaceAll('\\\\', '/'))\n }\n }\n }\n\n logger.plain()\n\n if (changed.length === 0) {\n logger.plain(pc.green('Every installed component matches the registry.'))\n logger.plain()\n\n return\n }\n\n logger.plain(pc.bold('Differs from the registry:'))\n\n for (const file of changed) {\n logger.plain(` ${pc.yellow(file)}`)\n }\n\n logger.plain()\n logger.plain(pc.dim('Run \"magic-native-ui add <name> --overwrite\" to reset one.'))\n logger.plain()\n}\n","import * as p from '@clack/prompts'\nimport path from 'node:path'\nimport pc from 'picocolors'\n\nimport { getRegistryItem } from '@/registry/api'\nimport {\n CONFIG_FILE,\n configSchema,\n DEFAULT_REGISTRY,\n resolveConfig,\n writeConfig,\n type Config,\n} from '@/utils/config'\nimport { CliError, logger } from '@/utils/logger'\nimport { getProjectInfo } from '@/utils/project'\nimport { installDependencies } from '@/utils/updaters/dependencies'\nimport { updateCss } from '@/utils/updaters/css'\nimport { writeRegistryFiles } from '@/utils/updaters/files'\nimport { updateMetroConfig } from '@/utils/updaters/metro'\nimport { ensurePathAlias, ensureUniwindTypes } from '@/utils/updaters/tsconfig'\n\nconst BASE_COLORS = ['neutral', 'slate', 'stone', 'zinc', 'gray'] as const\n\nconst BASE_DEPENDENCIES = [\n 'uniwind',\n 'tailwindcss',\n 'clsx',\n 'tailwind-merge',\n 'class-variance-authority',\n]\n\nexport type InitOptions = {\n cwd: string\n yes: boolean\n registry: string\n cssEntry?: string\n baseColor?: string\n skipInstall: boolean\n}\n\nfunction cancelled(value: unknown): never | void {\n if (p.isCancel(value)) {\n p.cancel('Cancelled.')\n process.exit(0)\n }\n}\n\nexport async function init(options: InitOptions) {\n const project = await getProjectInfo(options.cwd)\n\n p.intro(pc.bold('magic-native-ui init'))\n\n if (!project.isExpo) {\n p.log.warn(\n 'This does not look like an Expo project (no \"expo\" dependency and no app.json). Continuing anyway.'\n )\n }\n\n if (!project.isTypeScript) {\n p.log.warn('No tsconfig.json found — components are written as .tsx regardless.')\n }\n\n let cssEntry = options.cssEntry ?? project.cssEntry ?? 'global.css'\n let baseColor = options.baseColor ?? 'neutral'\n\n if (!options.yes) {\n const answeredCss = await p.text({\n message: 'Where is your Tailwind entry CSS file?',\n initialValue: cssEntry,\n placeholder: 'global.css',\n })\n cancelled(answeredCss)\n cssEntry = answeredCss as string\n\n const answeredColor = await p.select({\n message: 'Which base colour?',\n initialValue: baseColor,\n options: BASE_COLORS.map((color) => ({ value: color, label: color })),\n })\n cancelled(answeredColor)\n baseColor = answeredColor as string\n }\n\n const config: Config = configSchema.parse({\n $schema: 'https://native-ui.magicwebs.ai/schema.json',\n style: 'default',\n tsx: true,\n tailwind: { css: cssEntry, baseColor },\n iconLibrary: 'lucide',\n aliases: {\n components: '@/components',\n ui: '@/components/ui',\n lib: '@/lib',\n utils: '@/lib/utils',\n hooks: '@/hooks',\n },\n registry: options.registry || DEFAULT_REGISTRY,\n metroConfig: project.metroConfig ?? 'metro.config.js',\n } satisfies Partial<Config>)\n\n const resolved = await resolveConfig(options.cwd, config)\n const spinner = p.spinner()\n\n spinner.start('Writing configuration')\n await writeConfig(options.cwd, config)\n spinner.stop(`Wrote ${CONFIG_FILE}`)\n\n // Theme tokens and the cn() helper come from the registry, so the CLI and the\n // documented source never drift apart.\n spinner.start('Fetching theme and utilities')\n const [theme, utils] = await Promise.all([\n getRegistryItem(config.registry, 'theme'),\n getRegistryItem(config.registry, 'utils'),\n ])\n spinner.stop('Fetched theme and utilities')\n\n const themeCss = theme.files[0]?.content\n\n if (!themeCss) {\n throw new CliError('The registry theme item contains no CSS.')\n }\n\n const cssResult = await updateCss(resolved.resolvedPaths.css, themeCss)\n p.log.success(\n cssResult.created\n ? `Created ${cssEntry}`\n : `Updated ${cssEntry}${cssResult.addedTheme ? ' (added theme tokens)' : ''}`\n )\n\n const metroResult = await updateMetroConfig(options.cwd, config.metroConfig, cssEntry)\n\n if (metroResult.status === 'created') {\n p.log.success(`Created ${metroResult.file}`)\n } else if (metroResult.status === 'already-configured') {\n p.log.info(`${metroResult.file} already wraps withUniwindConfig`)\n } else {\n p.log.warn(\n `${metroResult.file} exists but does not use withUniwindConfig.\\n` +\n `Wrap your exported config with it, outermost:\\n` +\n pc.dim(` const { withUniwindConfig } = require('uniwind/metro')\\n`) +\n pc.dim(` module.exports = withUniwindConfig(config, { cssEntryFile: './${cssEntry}' })`)\n )\n }\n\n if (await ensurePathAlias(options.cwd)) {\n p.log.success('Added the \"@/*\" path alias to tsconfig.json')\n }\n\n if (await ensureUniwindTypes(options.cwd)) {\n p.log.success('Created uniwind-env.d.ts (enables className typing)')\n }\n\n await writeRegistryFiles([utils], resolved, { overwrite: true, dryRun: false })\n p.log.success(`Added ${path.relative(options.cwd, resolved.resolvedPaths.utils)}.ts`)\n\n if (!options.skipInstall) {\n await installDependencies(options.cwd, project.packageManager, BASE_DEPENDENCIES)\n } else {\n p.log.info(`Skipped install. Run: ${project.packageManager} add ${BASE_DEPENDENCIES.join(' ')}`)\n }\n\n p.note(\n [\n `1. Import the stylesheet in your root layout: ${pc.cyan(`import './${cssEntry}'`)}`,\n `2. Add ${pc.cyan('<PortalHost />')} as the last child of that layout (needed by Dialog).`,\n `3. Add a component: ${pc.cyan('npx magic-native-ui add button')}`,\n ].join('\\n'),\n 'Next steps'\n )\n\n p.outro(pc.green('Ready.'))\n}\n\nexport { logger }\n","import { existsSync } from 'node:fs'\nimport { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\n\nconst REQUIRED_IMPORTS = [\"@import 'tailwindcss';\", \"@import 'uniwind';\"]\n\n/**\n * Creates the Tailwind entry stylesheet, or tops up an existing one. Both\n * imports are required by Uniwind, and the theme block is only appended when\n * the project has no design tokens yet, so re-running never duplicates them.\n */\nexport async function updateCss(cssPath: string, themeCss: string) {\n await mkdir(path.dirname(cssPath), { recursive: true })\n\n if (!existsSync(cssPath)) {\n await writeFile(cssPath, `${REQUIRED_IMPORTS.join('\\n')}\\n\\n${themeCss}`, 'utf8')\n\n return { created: true, addedImports: REQUIRED_IMPORTS, addedTheme: true }\n }\n\n const existing = await readFile(cssPath, 'utf8')\n const missingImports = REQUIRED_IMPORTS.filter(\n (statement) => !existing.includes(statement.replace(/'/g, \"'\")) && !existing.includes(statement.replace(/'/g, '\"'))\n )\n\n const hasTheme = existing.includes('--color-background')\n let next = existing\n\n if (missingImports.length > 0) {\n next = `${missingImports.join('\\n')}\\n${next}`\n }\n\n if (!hasTheme) {\n next = `${next.trimEnd()}\\n\\n${themeCss}`\n }\n\n if (next !== existing) {\n await writeFile(cssPath, next, 'utf8')\n }\n\n return { created: false, addedImports: missingImports, addedTheme: !hasTheme }\n}\n","import { existsSync } from 'node:fs'\nimport { readFile, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\n\nfunction template(cssEntry: string) {\n return `const { getDefaultConfig } = require('expo/metro-config')\nconst { withUniwindConfig } = require('uniwind/metro')\n\nconst config = getDefaultConfig(__dirname)\n\n// React Native still uses deep imports such as \\`react-native/rn-get-polyfills\\`,\n// which break when package exports are enabled. Uniwind (with culori) and Radix\n// - used by @rn-primitives on web - need the opposite, so exports are disabled\n// globally and re-enabled for just those packages.\nconst PACKAGE_EXPORTS_ALLOWLIST = ['uniwind', 'culori', '@radix-ui']\n\nconfig.resolver.unstable_enablePackageExports = false\nconfig.resolver.resolveRequest = (context, moduleName, platform) => {\n if (PACKAGE_EXPORTS_ALLOWLIST.some((prefix) => moduleName.startsWith(prefix))) {\n return context.resolveRequest(\n { ...context, unstable_enablePackageExports: true },\n moduleName,\n platform\n )\n }\n\n return context.resolveRequest(context, moduleName, platform)\n}\n\n// \\`withUniwindConfig\\` must stay the outermost wrapper.\nmodule.exports = withUniwindConfig(config, {\n cssEntryFile: './${cssEntry.replaceAll('\\\\', '/')}',\n dtsFile: './uniwind-types.d.ts',\n})\n`\n}\n\nexport type MetroResult =\n | { status: 'created'; file: string }\n | { status: 'already-configured'; file: string }\n | { status: 'needs-manual-edit'; file: string }\n\n/**\n * Writes a Metro config when the project has none. An existing config is never\n * rewritten — it may contain project-specific setup — so the caller is told to\n * print manual instructions instead.\n */\nexport async function updateMetroConfig(\n cwd: string,\n metroConfigFile: string,\n cssEntry: string\n): Promise<MetroResult> {\n const target = path.join(cwd, metroConfigFile)\n\n if (!existsSync(target)) {\n await writeFile(target, template(cssEntry), 'utf8')\n\n return { status: 'created', file: metroConfigFile }\n }\n\n const existing = await readFile(target, 'utf8')\n\n if (existing.includes('withUniwindConfig')) {\n return { status: 'already-configured', file: metroConfigFile }\n }\n\n return { status: 'needs-manual-edit', file: metroConfigFile }\n}\n","import { existsSync } from 'node:fs'\nimport { readFile, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\n\nimport { parseJsonc } from '@/utils/json'\n\ntype Tsconfig = {\n compilerOptions?: {\n baseUrl?: string\n paths?: Record<string, string[]>\n }\n include?: string[]\n}\n\n/**\n * Ensures the `@/*` alias exists so the rewritten imports resolve. Returns\n * false when nothing needed changing.\n */\nexport async function ensurePathAlias(cwd: string, alias = '@/*', target = './*') {\n const file = path.join(cwd, 'tsconfig.json')\n\n if (!existsSync(file)) return false\n\n const raw = await readFile(file, 'utf8')\n let tsconfig: Tsconfig\n\n try {\n tsconfig = parseJsonc<Tsconfig>(raw)\n } catch {\n return false\n }\n\n if (tsconfig.compilerOptions?.paths?.[alias]) return false\n\n tsconfig.compilerOptions ??= {}\n tsconfig.compilerOptions.baseUrl ??= '.'\n tsconfig.compilerOptions.paths ??= {}\n tsconfig.compilerOptions.paths[alias] = [target]\n\n await writeFile(file, `${JSON.stringify(tsconfig, null, 2)}\\n`, 'utf8')\n\n return true\n}\n\nconst UNIWIND_ENV = `/// <reference types=\"uniwind/types\" />\\n`\n\n/**\n * Without this reference TypeScript does not know that React Native components\n * accept `className`, and every component reports an error.\n */\nexport async function ensureUniwindTypes(cwd: string) {\n const file = path.join(cwd, 'uniwind-env.d.ts')\n\n if (existsSync(file)) return false\n\n await writeFile(file, UNIWIND_ENV, 'utf8')\n\n return true\n}\n","import pc from 'picocolors'\n\nimport { getRegistryIndex } from '@/registry/api'\nimport { readConfig, DEFAULT_REGISTRY } from '@/utils/config'\nimport { logger } from '@/utils/logger'\n\nexport async function list(options: { cwd: string; registry?: string }) {\n const registry =\n options.registry ??\n (await readConfig(options.cwd)\n .then((config) => config.registry)\n .catch(() => DEFAULT_REGISTRY))\n\n const index = await getRegistryIndex(registry)\n const components = index.items.filter((item) => item.type === 'registry:ui')\n const width = Math.max(...components.map((item) => item.name.length))\n\n logger.plain()\n logger.plain(pc.bold(`${index.name} — ${components.length} components`))\n logger.plain()\n\n for (const item of components) {\n logger.plain(` ${pc.cyan(item.name.padEnd(width))} ${pc.dim(item.description ?? '')}`)\n }\n\n logger.plain()\n}\n","import pc from 'picocolors'\n\nimport { getRegistryItem } from '@/registry/api'\nimport { readConfig, DEFAULT_REGISTRY } from '@/utils/config'\nimport { logger } from '@/utils/logger'\n\nexport async function view(name: string, options: { cwd: string; registry?: string }) {\n const registry =\n options.registry ??\n (await readConfig(options.cwd)\n .then((config) => config.registry)\n .catch(() => DEFAULT_REGISTRY))\n\n const item = await getRegistryItem(registry, name)\n\n logger.plain()\n logger.plain(`${pc.bold(item.title ?? item.name)} ${pc.dim(item.type)}`)\n\n if (item.description) {\n logger.plain(item.description)\n }\n\n logger.plain()\n\n if (item.dependencies.length > 0) {\n logger.plain(`${pc.bold('npm dependencies')} ${item.dependencies.join(', ')}`)\n }\n\n if (item.registryDependencies.length > 0) {\n logger.plain(`${pc.bold('registry dependencies')} ${item.registryDependencies.join(', ')}`)\n }\n\n logger.plain(`${pc.bold('files')} ${item.files.map((f) => f.path).join(', ')}`)\n logger.plain()\n}\n"],"mappings":"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","names":["z","path","pc","z","z","existsSync","readFile","path","path","existsSync","readFile","existsSync","writeFile","path","path","existsSync","writeFile","path","pc","spinner","existsSync","readFile","path","pc","existsSync","readFile","path","pc","p","path","pc","existsSync","mkdir","readFile","writeFile","path","existsSync","readFile","writeFile","path","existsSync","readFile","writeFile","path","path","existsSync","readFile","writeFile","pc","spinner","path","pc","pc","pc","pc","z"]}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "magic-native-ui",
3
+ "version": "0.1.0",
4
+ "description": "Add Magic Native UI components to your Expo app.",
5
+ "type": "module",
6
+ "bin": {
7
+ "magic-native-ui": "./dist/index.js"
8
+ },
9
+ "files": ["dist"],
10
+ "scripts": {
11
+ "build": "tsup",
12
+ "dev": "tsup --watch",
13
+ "typecheck": "tsc --noEmit",
14
+ "start": "node dist/index.js",
15
+ "prepublishOnly": "npm run typecheck && npm run build"
16
+ },
17
+ "keywords": ["react-native", "expo", "uniwind", "tailwind", "ui", "components"],
18
+ "author": "Abhijit Pradhan (https://github.com/avijit969)",
19
+ "license": "MIT",
20
+ "homepage": "https://native-ui.magicwebs.ai",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/avijit969/magic-native-ui-cli.git"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/avijit969/magic-native-ui-cli/issues"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "dependencies": {
32
+ "@clack/prompts": "^1.8.0",
33
+ "commander": "^15.0.0",
34
+ "picocolors": "^1.1.1",
35
+ "zod": "^4.6.2"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^24.0.0",
39
+ "tsup": "^8.5.0",
40
+ "typescript": "~5.9.2"
41
+ },
42
+ "engines": {
43
+ "node": ">=20"
44
+ }
45
+ }