groovy-native-ui 1.0.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.
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import('../dist/index.js').catch((err) => {
3
+ console.error('Failed to load groovy-ui CLI:', err);
4
+ process.exit(1);
5
+ });
@@ -0,0 +1,74 @@
1
+ // src/registry/components/button.ts
2
+ var buttonRegistry = {
3
+ button: {
4
+ name: "button",
5
+ description: "A customizable button component",
6
+ type: "registry:ui",
7
+ registryDependencies: [],
8
+ dependencies: [],
9
+ // npm packages needed
10
+ files: [
11
+ {
12
+ type: "registry:ui",
13
+ // Points to raw GitHub URL of your component
14
+ path: "src/components/ui/Button.tsx",
15
+ target: "components/ui/Button.tsx"
16
+ // Where to copy in user's project
17
+ }
18
+ ]
19
+ }
20
+ };
21
+
22
+ // src/registry/index.ts
23
+ var REGISTRY_BASE_URL = "https://raw.githubusercontent.com/Shauray018/groovy-ui/refs/heads/main/groovy-ui-components";
24
+ var REGISTRY = {
25
+ ...buttonRegistry
26
+ // ...alertRegistry,
27
+ // ...cardRegistry,
28
+ };
29
+ function getComponent(name) {
30
+ return REGISTRY[name];
31
+ }
32
+ function getAllComponents() {
33
+ return Object.values(REGISTRY).filter((comp) => comp.type === "registry:ui");
34
+ }
35
+ function resolveAllDependencies(componentName) {
36
+ const resolved = /* @__PURE__ */ new Set();
37
+ const queue = [componentName];
38
+ while (queue.length > 0) {
39
+ const current = queue.shift();
40
+ if (resolved.has(current)) continue;
41
+ resolved.add(current);
42
+ const component = getComponent(current);
43
+ if (!component) continue;
44
+ const deps = component.registryDependencies || [];
45
+ deps.forEach((dep) => {
46
+ if (!resolved.has(dep)) {
47
+ queue.push(dep);
48
+ }
49
+ });
50
+ }
51
+ return Array.from(resolved);
52
+ }
53
+ async function fetchComponentTemplate(file) {
54
+ const url = `${REGISTRY_BASE_URL}/${file.path}`;
55
+ console.log(`Fetching component from: ${url}`);
56
+ try {
57
+ const response = await fetch(url);
58
+ if (!response.ok) {
59
+ throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);
60
+ }
61
+ return await response.text();
62
+ } catch (error) {
63
+ throw new Error(`Failed to fetch component template from ${url}: ${error}`);
64
+ }
65
+ }
66
+
67
+ export {
68
+ REGISTRY,
69
+ getComponent,
70
+ getAllComponents,
71
+ resolveAllDependencies,
72
+ fetchComponentTemplate
73
+ };
74
+ //# sourceMappingURL=chunk-3BUGHI3R.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/registry/components/button.ts","../src/registry/index.ts"],"sourcesContent":["import { Registry } from '../index.js';\n\nexport const buttonRegistry: Registry = {\n button: {\n name: 'button',\n description: 'A customizable button component',\n type: 'registry:ui',\n registryDependencies: [],\n dependencies: [], // npm packages needed\n files: [\n {\n type: 'registry:ui',\n // Points to raw GitHub URL of your component\n path: 'src/components/ui/Button.tsx',\n target: 'components/ui/Button.tsx', // Where to copy in user's project\n },\n ],\n },\n};","// src/registry/index.ts\n\nexport interface RegistryFile {\n type: 'registry:ui' | 'registry:example' | 'registry:hook' | 'registry:theme';\n path: string;\n target: string;\n}\n\nexport interface RegistryComponent {\n name: string;\n description: string;\n type: 'registry:ui' | 'registry:example' | 'registry:hook' | 'registry:theme';\n registryDependencies?: string[];\n dependencies?: string[];\n hooks?: string[];\n theme?: string[];\n files: RegistryFile[];\n}\n\nexport type Registry = Record<string, RegistryComponent>;\n\n// āœ… YOUR ACTUAL RAW GITHUB URL\nconst REGISTRY_BASE_URL = 'https://raw.githubusercontent.com/Shauray018/groovy-ui/refs/heads/main/groovy-ui-components';\n\n// Import component registries\nimport { buttonRegistry } from './components/button.js';\n// import { alertRegistry } from './components/alert.js';\n// import { cardRegistry } from './components/card.js';\n\n// Combine all registries\nexport const REGISTRY: Registry = {\n ...buttonRegistry,\n // ...alertRegistry,\n // ...cardRegistry,\n};\n\n// Helper functions\nexport function getComponent(name: string): RegistryComponent | undefined {\n return REGISTRY[name];\n}\n\nexport function getAllComponents(): RegistryComponent[] {\n return Object.values(REGISTRY).filter(comp => comp.type === 'registry:ui');\n}\n\nexport function resolveAllDependencies(componentName: string): string[] {\n const resolved = new Set<string>();\n const queue = [componentName];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n \n if (resolved.has(current)) continue;\n resolved.add(current);\n\n const component = getComponent(current);\n if (!component) continue;\n\n const deps = component.registryDependencies || [];\n deps.forEach(dep => {\n if (!resolved.has(dep)) {\n queue.push(dep);\n }\n });\n }\n\n return Array.from(resolved);\n}\n\nexport async function fetchComponentTemplate(\n file: RegistryFile\n): Promise<string> {\n // Construct the full URL to the raw file\n const url = `${REGISTRY_BASE_URL}/${file.path}`;\n \n console.log(`Fetching component from: ${url}`); // For debugging\n \n try {\n const response = await fetch(url);\n \n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);\n }\n \n return await response.text();\n } catch (error) {\n throw new Error(`Failed to fetch component template from ${url}: ${error}`);\n }\n}"],"mappings":";AAEO,IAAM,iBAA2B;AAAA,EACtC,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,IACN,sBAAsB,CAAC;AAAA,IACvB,cAAc,CAAC;AAAA;AAAA,IACf,OAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA;AAAA,QAEN,MAAM;AAAA,QACN,QAAQ;AAAA;AAAA,MACV;AAAA,IACF;AAAA,EACF;AACF;;;ACIA,IAAM,oBAAoB;AAQnB,IAAM,WAAqB;AAAA,EAChC,GAAG;AAAA;AAAA;AAGL;AAGO,SAAS,aAAa,MAA6C;AACxE,SAAO,SAAS,IAAI;AACtB;AAEO,SAAS,mBAAwC;AACtD,SAAO,OAAO,OAAO,QAAQ,EAAE,OAAO,UAAQ,KAAK,SAAS,aAAa;AAC3E;AAEO,SAAS,uBAAuB,eAAiC;AACtE,QAAM,WAAW,oBAAI,IAAY;AACjC,QAAM,QAAQ,CAAC,aAAa;AAE5B,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,UAAU,MAAM,MAAM;AAE5B,QAAI,SAAS,IAAI,OAAO,EAAG;AAC3B,aAAS,IAAI,OAAO;AAEpB,UAAM,YAAY,aAAa,OAAO;AACtC,QAAI,CAAC,UAAW;AAEhB,UAAM,OAAO,UAAU,wBAAwB,CAAC;AAChD,SAAK,QAAQ,SAAO;AAClB,UAAI,CAAC,SAAS,IAAI,GAAG,GAAG;AACtB,cAAM,KAAK,GAAG;AAAA,MAChB;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO,MAAM,KAAK,QAAQ;AAC5B;AAEA,eAAsB,uBACpB,MACiB;AAEjB,QAAM,MAAM,GAAG,iBAAiB,IAAI,KAAK,IAAI;AAE7C,UAAQ,IAAI,4BAA4B,GAAG,EAAE;AAE7C,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,GAAG;AAEhC,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,mBAAmB,GAAG,KAAK,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAAA,IACrF;AAEA,WAAO,MAAM,SAAS,KAAK;AAAA,EAC7B,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,2CAA2C,GAAG,KAAK,KAAK,EAAE;AAAA,EAC5E;AACF;","names":[]}
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,648 @@
1
+ import {
2
+ fetchComponentTemplate,
3
+ getAllComponents,
4
+ getComponent,
5
+ resolveAllDependencies
6
+ } from "./chunk-3BUGHI3R.js";
7
+
8
+ // src/index.ts
9
+ import { Command } from "commander";
10
+
11
+ // src/commands/add.ts
12
+ import path3 from "path";
13
+ import inquirer from "inquirer";
14
+ import ora from "ora";
15
+
16
+ // src/utils/logger.ts
17
+ import chalk from "chalk";
18
+ var groovyBanner = `
19
+ ${chalk.cyan(" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557")}
20
+ ${chalk.cyan("\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D")}
21
+ ${chalk.cyan("\u2588\u2588\u2551 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2554\u255D ")}
22
+ ${chalk.cyan("\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D \u255A\u2588\u2588\u2554\u255D ")}
23
+ ${chalk.cyan("\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u255A\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 ")}
24
+ ${chalk.cyan(" \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D ")}
25
+
26
+ ${chalk.gray("Expo React Native CLI, UI Components Library")}
27
+ `;
28
+ var logger = {
29
+ info: (message, ...args) => {
30
+ console.log(chalk.blue("\u2139"), message, ...args);
31
+ },
32
+ success: (message, ...args) => {
33
+ console.log(chalk.green("\u2713"), message, ...args);
34
+ },
35
+ warn: (message, ...args) => {
36
+ console.log(chalk.yellow("\u26A0"), message, ...args);
37
+ },
38
+ error: (message, ...args) => {
39
+ console.error(chalk.red("\u2717"), message, ...args);
40
+ },
41
+ debug: (message, ...args) => {
42
+ if (process.env.DEBUG) {
43
+ console.log(chalk.gray("\u{1F41B}"), message, ...args);
44
+ }
45
+ },
46
+ plain: (message, ...args) => {
47
+ console.log(message, ...args);
48
+ },
49
+ header: (message) => {
50
+ console.log("\n" + chalk.bold.cyan(message) + "\n");
51
+ },
52
+ banner: () => {
53
+ console.log(groovyBanner);
54
+ },
55
+ break: () => {
56
+ console.log("");
57
+ },
58
+ newline: () => {
59
+ console.log();
60
+ }
61
+ };
62
+
63
+ // src/utils/filesystem.ts
64
+ import fs from "fs-extra";
65
+ import path from "path";
66
+ async function validateProjectStructure(projectPath) {
67
+ const packageJsonPath = path.join(projectPath, "package.json");
68
+ if (!await fs.pathExists(packageJsonPath)) {
69
+ return false;
70
+ }
71
+ try {
72
+ const packageJson = await fs.readJson(packageJsonPath);
73
+ const hasReactNative = packageJson.dependencies?.["react-native"] || packageJson.devDependencies?.["react-native"];
74
+ const hasExpo = packageJson.dependencies?.["expo"] || packageJson.devDependencies?.["expo"];
75
+ return !!(hasReactNative || hasExpo);
76
+ } catch (error) {
77
+ return false;
78
+ }
79
+ }
80
+ async function ensureDirectoryExists(dirPath) {
81
+ await fs.ensureDir(dirPath);
82
+ }
83
+ async function writeComponentFile(filePath, content) {
84
+ await fs.writeFile(filePath, content, "utf-8");
85
+ }
86
+ async function fileExists(filePath) {
87
+ return fs.pathExists(filePath);
88
+ }
89
+ async function checkComponentConflicts(components, projectPath) {
90
+ const conflicts = [];
91
+ const { getComponent: getComponent2 } = await import("./registry-ZMFJ6C6R.js");
92
+ for (const componentName of components) {
93
+ const component = getComponent2(componentName);
94
+ if (!component) continue;
95
+ for (const file of component.files) {
96
+ const targetPath = path.join(projectPath, file.target);
97
+ if (await fileExists(targetPath)) {
98
+ conflicts.push(file.target);
99
+ }
100
+ }
101
+ }
102
+ return conflicts;
103
+ }
104
+
105
+ // src/utils/dependencies.ts
106
+ import { execa, execaSync } from "execa";
107
+ import fs2 from "fs-extra";
108
+ import path2 from "path";
109
+ function detectPackageManager() {
110
+ const cwd = process.cwd();
111
+ if (fs2.existsSync(path2.join(cwd, "bun.lockb"))) return "bun";
112
+ if (fs2.existsSync(path2.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
113
+ if (fs2.existsSync(path2.join(cwd, "yarn.lock"))) return "yarn";
114
+ if (fs2.existsSync(path2.join(cwd, "package-lock.json"))) return "npm";
115
+ try {
116
+ execaSync("bun", ["--version"]);
117
+ return "bun";
118
+ } catch {
119
+ }
120
+ try {
121
+ execaSync("pnpm", ["--version"]);
122
+ return "pnpm";
123
+ } catch {
124
+ }
125
+ try {
126
+ execaSync("yarn", ["--version"]);
127
+ return "yarn";
128
+ } catch {
129
+ }
130
+ return "npm";
131
+ }
132
+ async function installPackageDependencies(dependencies, packageManager, projectPath) {
133
+ const commands = {
134
+ npm: ["install", ...dependencies],
135
+ yarn: ["add", ...dependencies],
136
+ pnpm: ["add", ...dependencies],
137
+ bun: ["add", ...dependencies]
138
+ };
139
+ const args = commands[packageManager];
140
+ if (!args) {
141
+ throw new Error(`Unsupported package manager: ${packageManager}`);
142
+ }
143
+ await execa(packageManager, args, {
144
+ cwd: projectPath,
145
+ stdio: "inherit"
146
+ });
147
+ }
148
+
149
+ // src/commands/add.ts
150
+ async function selectComponentsInteractively() {
151
+ const components = getAllComponents();
152
+ if (components.length === 0) {
153
+ logger.error("No components available in registry");
154
+ process.exit(1);
155
+ }
156
+ const { selected } = await inquirer.prompt([
157
+ {
158
+ type: "checkbox",
159
+ name: "selected",
160
+ message: "Select components to install:",
161
+ choices: components.map((comp) => ({
162
+ name: `${comp.name.padEnd(15)} - ${comp.description}`,
163
+ value: comp.name
164
+ })),
165
+ validate: (input) => {
166
+ if (input.length === 0) {
167
+ return "Please select at least one component";
168
+ }
169
+ return true;
170
+ }
171
+ }
172
+ ]);
173
+ return selected;
174
+ }
175
+ function getPackageManager(options) {
176
+ if (options.npm) return "npm";
177
+ if (options.yarn) return "yarn";
178
+ if (options.pnpm) return "pnpm";
179
+ if (options.bun) return "bun";
180
+ return detectPackageManager();
181
+ }
182
+ async function addCommand(components, options = {}) {
183
+ const projectPath = process.cwd();
184
+ logger.info("\u{1F3A8} Adding Groovy UI components to your project...");
185
+ logger.break();
186
+ const spinner = ora("Validating project structure...").start();
187
+ const isValidProject = await validateProjectStructure(projectPath);
188
+ if (!isValidProject) {
189
+ spinner.fail("Invalid project structure");
190
+ logger.error("This command must be run in a React Native/Expo project");
191
+ logger.info("Make sure you have a package.json with react-native or expo");
192
+ logger.break();
193
+ logger.info('Did you forget to run "groovy-ui init" first?');
194
+ process.exit(1);
195
+ }
196
+ spinner.succeed("Project structure validated");
197
+ if (components.length === 0) {
198
+ logger.break();
199
+ components = await selectComponentsInteractively();
200
+ }
201
+ const invalidComponents = components.filter((name) => !getComponent(name));
202
+ if (invalidComponents.length > 0) {
203
+ logger.error(`Unknown components: ${invalidComponents.join(", ")}`);
204
+ logger.break();
205
+ logger.info("Available components:");
206
+ getAllComponents().forEach(
207
+ (comp) => logger.plain(` \u2022 ${comp.name.padEnd(20)} ${comp.description}`)
208
+ );
209
+ process.exit(1);
210
+ }
211
+ spinner.start("Resolving dependencies...");
212
+ const allComponentsToInstall = /* @__PURE__ */ new Set();
213
+ const allPackageDependencies = /* @__PURE__ */ new Set();
214
+ const allHooks = /* @__PURE__ */ new Set();
215
+ const allThemes = /* @__PURE__ */ new Set();
216
+ for (const componentName of components) {
217
+ const dependencies = resolveAllDependencies(componentName);
218
+ dependencies.forEach((dep) => {
219
+ allComponentsToInstall.add(dep);
220
+ const component = getComponent(dep);
221
+ if (component) {
222
+ (component.dependencies || []).forEach(
223
+ (pkg) => allPackageDependencies.add(pkg)
224
+ );
225
+ (component.hooks || []).forEach((hook) => allHooks.add(hook));
226
+ (component.theme || []).forEach((theme) => allThemes.add(theme));
227
+ }
228
+ });
229
+ }
230
+ spinner.succeed("Dependencies resolved");
231
+ logger.break();
232
+ logger.info("Components to install:");
233
+ Array.from(allComponentsToInstall).forEach((comp) => {
234
+ const component = getComponent(comp);
235
+ const type = component?.type !== "registry:ui" ? ` (${component?.type.replace("registry:", "")})` : "";
236
+ logger.plain(` \u2022 ${comp}${type}`);
237
+ });
238
+ if (allPackageDependencies.size > 0) {
239
+ logger.break();
240
+ logger.info("Package dependencies:");
241
+ Array.from(allPackageDependencies).forEach(
242
+ (dep) => logger.plain(` \u2022 ${dep}`)
243
+ );
244
+ }
245
+ const conflicts = await checkComponentConflicts(
246
+ Array.from(allComponentsToInstall),
247
+ projectPath
248
+ );
249
+ if (conflicts.length > 0 && !options.overwrite) {
250
+ logger.break();
251
+ logger.warn("The following files already exist:");
252
+ conflicts.forEach((file) => logger.plain(` \u2022 ${file}`));
253
+ if (!options.yes) {
254
+ const { proceed } = await inquirer.prompt([
255
+ {
256
+ type: "confirm",
257
+ name: "proceed",
258
+ message: "Do you want to overwrite these files?",
259
+ default: false
260
+ }
261
+ ]);
262
+ if (!proceed) {
263
+ logger.info("Installation cancelled");
264
+ return;
265
+ }
266
+ }
267
+ }
268
+ if (options.dryRun) {
269
+ logger.break();
270
+ logger.info("[DRY RUN] Would install the above components");
271
+ return;
272
+ }
273
+ if (allPackageDependencies.size > 0) {
274
+ const packageManager = getPackageManager(options);
275
+ logger.break();
276
+ spinner.start("Installing package dependencies...");
277
+ try {
278
+ await installPackageDependencies(
279
+ Array.from(allPackageDependencies),
280
+ packageManager,
281
+ projectPath
282
+ );
283
+ spinner.succeed("Package dependencies installed");
284
+ } catch (error) {
285
+ spinner.fail("Failed to install package dependencies");
286
+ logger.error(String(error));
287
+ logger.warn("You may need to install dependencies manually");
288
+ }
289
+ }
290
+ logger.break();
291
+ spinner.start("Installing components...");
292
+ try {
293
+ let filesInstalled = 0;
294
+ for (const componentName of allComponentsToInstall) {
295
+ const component = getComponent(componentName);
296
+ if (!component) continue;
297
+ for (const file of component.files) {
298
+ const targetPath = path3.join(projectPath, file.target);
299
+ await ensureDirectoryExists(path3.dirname(targetPath));
300
+ try {
301
+ const content = await fetchComponentTemplate(file);
302
+ await writeComponentFile(targetPath, content);
303
+ filesInstalled++;
304
+ } catch (error) {
305
+ spinner.fail(`Failed to fetch ${file.path}`);
306
+ logger.error(String(error));
307
+ throw error;
308
+ }
309
+ }
310
+ }
311
+ spinner.succeed(`Components installed (${filesInstalled} files)`);
312
+ } catch (error) {
313
+ spinner.fail("Failed to install components");
314
+ logger.error(String(error));
315
+ process.exit(1);
316
+ }
317
+ await updateComponentIndex(projectPath, Array.from(allComponentsToInstall));
318
+ logger.break();
319
+ logger.success("\u2728 All done! Components have been added to your project.");
320
+ logger.break();
321
+ logger.info("Installed components:");
322
+ Array.from(allComponentsToInstall).forEach((comp) => {
323
+ logger.plain(` \u2022 ${comp}`);
324
+ });
325
+ logger.break();
326
+ logger.info("Next steps:");
327
+ logger.plain(" 1. Import the components in your app:");
328
+ logger.plain(` import { Button } from '@/components/ui/button';`);
329
+ logger.break();
330
+ logger.plain(" 2. Use them:");
331
+ logger.plain(` <Button title="Hello" onPress={() => {}} />`);
332
+ logger.break();
333
+ logger.info("Happy coding! \u{1F680}");
334
+ }
335
+ async function updateComponentIndex(projectPath, components) {
336
+ const indexPath = path3.join(projectPath, "components", "ui", "index.ts");
337
+ try {
338
+ const fs4 = await import("fs-extra");
339
+ let content = "";
340
+ if (await fs4.pathExists(indexPath)) {
341
+ content = await fs4.readFile(indexPath, "utf-8");
342
+ }
343
+ const newExports = [];
344
+ for (const componentName of components) {
345
+ const component = getComponent(componentName);
346
+ if (!component || component.type !== "registry:ui") continue;
347
+ const pascalName = componentName.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
348
+ const exportLine = `export { ${pascalName} } from './${componentName}';`;
349
+ const typeExportLine = `export type { ${pascalName}Props } from './${componentName}';`;
350
+ if (!content.includes(exportLine)) {
351
+ newExports.push(exportLine);
352
+ newExports.push(typeExportLine);
353
+ }
354
+ }
355
+ if (newExports.length > 0) {
356
+ const updatedContent = content + "\n" + newExports.join("\n") + "\n";
357
+ await fs4.writeFile(indexPath, updatedContent, "utf-8");
358
+ }
359
+ } catch (error) {
360
+ logger.warn("Could not update component index automatically");
361
+ }
362
+ }
363
+
364
+ // src/commands/init.ts
365
+ import inquirer2 from "inquirer";
366
+ import ora2 from "ora";
367
+ import path4 from "path";
368
+ import fs3 from "fs-extra";
369
+ async function initCommand(options = {}) {
370
+ const projectPath = process.cwd();
371
+ logger.info("\u{1F3A8} Initializing Groovy UI in your project...");
372
+ logger.break();
373
+ const spinner = ora2("Checking project structure...").start();
374
+ const isValidProject = await validateProjectStructure(projectPath);
375
+ if (!isValidProject) {
376
+ spinner.fail("Not a valid React Native or Expo project");
377
+ logger.error("This command must be run in a React Native or Expo project");
378
+ logger.info("Make sure you have a package.json with react-native or expo");
379
+ logger.break();
380
+ logger.info("To create a new Expo project:");
381
+ logger.plain(" npx create-expo-app my-app");
382
+ process.exit(1);
383
+ }
384
+ spinner.succeed("Valid React Native/Expo project detected");
385
+ const componentsDir = path4.join(projectPath, "components", "ui");
386
+ const alreadyInitialized = await fs3.pathExists(componentsDir);
387
+ if (alreadyInitialized && !options.yes) {
388
+ logger.warn("Groovy UI appears to be already initialized");
389
+ logger.plain(`Found existing directory: ${componentsDir}`);
390
+ logger.break();
391
+ const { proceed } = await inquirer2.prompt([
392
+ {
393
+ type: "confirm",
394
+ name: "proceed",
395
+ message: "Continue anyway?",
396
+ default: false
397
+ }
398
+ ]);
399
+ if (!proceed) {
400
+ logger.info("Initialization cancelled");
401
+ return;
402
+ }
403
+ }
404
+ logger.break();
405
+ spinner.start("Creating folder structure...");
406
+ try {
407
+ await ensureDirectoryExists(path4.join(projectPath, "components", "ui"));
408
+ await ensureDirectoryExists(path4.join(projectPath, "lib", "utils"));
409
+ await ensureDirectoryExists(path4.join(projectPath, "hooks"));
410
+ spinner.succeed("Folder structure created");
411
+ } catch (error) {
412
+ spinner.fail("Failed to create folder structure");
413
+ throw error;
414
+ }
415
+ spinner.start("Setting up utilities...");
416
+ try {
417
+ const cnUtilPath = path4.join(projectPath, "lib", "utils", "cn.ts");
418
+ const cnUtilContent = `/**
419
+ * Utility for merging class names
420
+ */
421
+ export function cn(...classes: (string | undefined | null | false)[]): string {
422
+ return classes.filter(Boolean).join(' ');
423
+ }
424
+ `;
425
+ await writeComponentFile(cnUtilPath, cnUtilContent);
426
+ const colorsUtilPath = path4.join(projectPath, "lib", "utils", "colors.ts");
427
+ const colorsUtilContent = `/**
428
+ * Color utilities for your components
429
+ */
430
+ export const colors = {
431
+ primary: '#007AFF',
432
+ secondary: '#8E8E93',
433
+ success: '#34C759',
434
+ warning: '#FF9500',
435
+ error: '#FF3B30',
436
+ background: '#FFFFFF',
437
+ text: '#000000',
438
+ border: '#E5E5EA',
439
+ muted: '#F2F2F7',
440
+ };
441
+
442
+ export type ColorName = keyof typeof colors;
443
+
444
+ export function getColor(name: ColorName): string {
445
+ return colors[name];
446
+ }
447
+ `;
448
+ await writeComponentFile(colorsUtilPath, colorsUtilContent);
449
+ spinner.succeed("Utilities created");
450
+ } catch (error) {
451
+ spinner.fail("Failed to create utilities");
452
+ throw error;
453
+ }
454
+ spinner.start("Creating component index...");
455
+ try {
456
+ const indexPath = path4.join(projectPath, "components", "ui", "index.ts");
457
+ const indexContent = `/**
458
+ * Groovy UI Components
459
+ *
460
+ * Export all your UI components from here
461
+ * Components will be automatically added when you run: groovy-ui add <component>
462
+ *
463
+ * Example usage:
464
+ * import { Button, Alert, Card } from '@/components/ui';
465
+ */
466
+
467
+ // Components will be exported here automatically
468
+ // Example:
469
+ // export { Button } from './button';
470
+ // export type { ButtonProps } from './button';
471
+ `;
472
+ await writeComponentFile(indexPath, indexContent);
473
+ spinner.succeed("Component index created");
474
+ } catch (error) {
475
+ spinner.fail("Failed to create component index");
476
+ throw error;
477
+ }
478
+ spinner.start("Creating documentation...");
479
+ try {
480
+ const readmePath = path4.join(projectPath, "components", "README.md");
481
+ const readmeContent = `# Groovy UI Components
482
+
483
+ This directory contains your UI components from Groovy UI.
484
+
485
+ ## Structure
486
+
487
+ \`\`\`
488
+ components/
489
+ \u251C\u2500\u2500 ui/ # Core UI components
490
+ \u2502 \u251C\u2500\u2500 button.tsx
491
+ \u2502 \u251C\u2500\u2500 alert.tsx
492
+ \u2502 \u251C\u2500\u2500 card.tsx
493
+ \u2502 \u2514\u2500\u2500 index.ts # Export all components
494
+ \u2514\u2500\u2500 README.md # This file
495
+ \`\`\`
496
+
497
+ ## Adding Components
498
+
499
+ Add new components using the Groovy UI CLI:
500
+
501
+ \`\`\`bash
502
+ # Add a single component
503
+ npx groovy-ui add button
504
+
505
+ # Add multiple components
506
+ npx groovy-ui add alert card modal
507
+
508
+ # Interactive selection
509
+ npx groovy-ui add
510
+ \`\`\`
511
+
512
+ ## Usage
513
+
514
+ Import components from the ui directory:
515
+
516
+ \`\`\`tsx
517
+ import { Button, Alert } from '@/components/ui';
518
+
519
+ export default function App() {
520
+ return (
521
+ <Button
522
+ title="Click me"
523
+ onPress={() => alert('Hello!')}
524
+ variant="primary"
525
+ />
526
+ );
527
+ }
528
+ \`\`\`
529
+
530
+ ## Customization
531
+
532
+ All components are copied to your project as source code, so you can:
533
+
534
+ - \u270F\uFE0F Modify styles to match your design system
535
+ - \u2795 Add or remove features as needed
536
+ - \u{1F527} Extend functionality
537
+ - \u{1F3A8} Change behavior and appearance
538
+
539
+ **The components are yours to customize!**
540
+
541
+ ## Available Components
542
+
543
+ - **Button**: Customizable button with variants and sizes
544
+ - **Alert**: Display important messages with different severity levels
545
+ - **Card**: Container component with header and footer
546
+ - **Modal**: Full-screen or centered modal dialogs
547
+ - **Input**: Text input with labels and validation
548
+ - And more...
549
+
550
+ ## TypeScript Support
551
+
552
+ All components are written in TypeScript with full type safety:
553
+
554
+ \`\`\`tsx
555
+ import { ButtonProps } from '@/components/ui';
556
+
557
+ const MyButton: React.FC<ButtonProps> = (props) => {
558
+ return <Button {...props} />;
559
+ };
560
+ \`\`\`
561
+
562
+ ## Learn More
563
+
564
+ - Documentation: [groovy-ui.dev](https://groovy-ui.dev)
565
+ - Examples: [github.com/groovy-ui/examples](https://github.com/groovy-ui/examples)
566
+ - Issues: [github.com/groovy-ui/issues](https://github.com/groovy-ui/issues)
567
+ `;
568
+ await writeComponentFile(readmePath, readmeContent);
569
+ spinner.succeed("Documentation created");
570
+ } catch (error) {
571
+ spinner.fail("Failed to create documentation");
572
+ }
573
+ const tsconfigPath = path4.join(projectPath, "tsconfig.json");
574
+ if (await fs3.pathExists(tsconfigPath)) {
575
+ spinner.start("Checking TypeScript configuration...");
576
+ try {
577
+ const tsconfig = await fs3.readJson(tsconfigPath);
578
+ const hasPathAlias = tsconfig?.compilerOptions?.paths?.["@/*"];
579
+ if (!hasPathAlias) {
580
+ spinner.warn("Path alias @/* not found in tsconfig.json");
581
+ logger.break();
582
+ logger.info("\u{1F4DD} Add this to your tsconfig.json for better imports:");
583
+ logger.plain(`
584
+ {
585
+ "compilerOptions": {
586
+ "baseUrl": ".",
587
+ "paths": {
588
+ "@/*": ["./*"]
589
+ }
590
+ }
591
+ }
592
+ `);
593
+ } else {
594
+ spinner.succeed("TypeScript configuration looks good");
595
+ }
596
+ } catch (error) {
597
+ spinner.warn("Could not validate TypeScript configuration");
598
+ }
599
+ }
600
+ try {
601
+ const gitignorePath = path4.join(projectPath, ".gitignore");
602
+ if (await fs3.pathExists(gitignorePath)) {
603
+ let gitignoreContent = await fs3.readFile(gitignorePath, "utf-8");
604
+ if (!gitignoreContent.includes("# groovy-ui")) {
605
+ const groovyIgnore = `
606
+
607
+ # groovy-ui
608
+ # Uncomment if you don't want to track component customizations
609
+ # components/ui/
610
+ `;
611
+ gitignoreContent += groovyIgnore;
612
+ await fs3.writeFile(gitignorePath, gitignoreContent, "utf-8");
613
+ }
614
+ }
615
+ } catch (error) {
616
+ }
617
+ logger.break();
618
+ logger.success("\u2728 Groovy UI initialized successfully!");
619
+ logger.break();
620
+ logger.info("Created folder structure:");
621
+ logger.plain(" components/");
622
+ logger.plain(" \u251C\u2500\u2500 ui/ # Your UI components");
623
+ logger.plain(" \u2514\u2500\u2500 README.md # Documentation");
624
+ logger.plain(" lib/");
625
+ logger.plain(" \u2514\u2500\u2500 utils/ # Utility functions");
626
+ logger.plain(" hooks/ # Custom React hooks");
627
+ logger.break();
628
+ logger.info("Next steps:");
629
+ logger.plain(" 1. Add components:");
630
+ logger.plain(" npx groovy-ui add button");
631
+ logger.plain(" npx groovy-ui add alert card modal");
632
+ logger.break();
633
+ logger.plain(" 2. Import in your app:");
634
+ logger.plain(" import { Button } from '@/components/ui/button';");
635
+ logger.break();
636
+ logger.plain(" 3. Use the components:");
637
+ logger.plain(' <Button title="Hello" onPress={() => {}} />');
638
+ logger.break();
639
+ logger.info("Happy coding! \u{1F680}");
640
+ }
641
+
642
+ // src/index.ts
643
+ var program = new Command();
644
+ program.name("groovy-ui").description("Add beautiful UI components to your React Native project").version("0.1.0");
645
+ program.command("init").description("Initialize groovy-ui in your project").option("-y, --yes", "Skip confirmation prompts").action(initCommand);
646
+ program.command("add [components...]").description("Add UI components to your project").option("-o, --overwrite", "Overwrite existing components").option("-y, --yes", "Skip confirmation prompts").action(addCommand);
647
+ program.parse();
648
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/add.ts","../src/utils/logger.ts","../src/utils/filesystem.ts","../src/utils/dependencies.ts","../src/commands/init.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { addCommand } from './commands/add.js';\nimport { initCommand } from './commands/init.js';\n\nconst program = new Command();\n\nprogram\n .name('groovy-ui')\n .description('Add beautiful UI components to your React Native project')\n .version('0.1.0');\n\nprogram\n .command('init')\n .description('Initialize groovy-ui in your project')\n .option('-y, --yes', 'Skip confirmation prompts')\n .action(initCommand);\n\nprogram\n .command('add [components...]')\n .description('Add UI components to your project')\n .option('-o, --overwrite', 'Overwrite existing components')\n .option('-y, --yes', 'Skip confirmation prompts')\n .action(addCommand);\n\nprogram.parse();","// src/commands/add.ts\nimport path from 'path';\nimport inquirer from 'inquirer';\nimport ora from 'ora';\nimport {\n REGISTRY,\n getComponent,\n resolveAllDependencies,\n fetchComponentTemplate,\n getAllComponents,\n} from '../registry/index.js';\nimport { logger } from '../utils/logger.js';\nimport {\n validateProjectStructure,\n checkComponentConflicts,\n ensureDirectoryExists,\n writeComponentFile,\n} from '../utils/filesystem.js';\nimport {\n installPackageDependencies,\n detectPackageManager,\n type PackageManager,\n} from '../utils/dependencies.js';\n\ninterface AddCommandOptions {\n overwrite?: boolean;\n dryRun?: boolean;\n yes?: boolean;\n npm?: boolean;\n yarn?: boolean;\n pnpm?: boolean;\n bun?: boolean;\n}\n\nasync function selectComponentsInteractively(): Promise<string[]> {\n const components = getAllComponents();\n \n if (components.length === 0) {\n logger.error('No components available in registry');\n process.exit(1);\n }\n \n const { selected } = await inquirer.prompt([\n {\n type: 'checkbox',\n name: 'selected',\n message: 'Select components to install:',\n choices: components.map(comp => ({\n name: `${comp.name.padEnd(15)} - ${comp.description}`,\n value: comp.name,\n })),\n validate: (input) => {\n if (input.length === 0) {\n return 'Please select at least one component';\n }\n return true;\n },\n },\n ]);\n\n return selected;\n}\n\nfunction getPackageManager(options: AddCommandOptions): PackageManager {\n if (options.npm) return 'npm';\n if (options.yarn) return 'yarn';\n if (options.pnpm) return 'pnpm';\n if (options.bun) return 'bun';\n \n return detectPackageManager();\n}\n\nexport async function addCommand(\n components: string[],\n options: AddCommandOptions = {}\n): Promise<void> {\n const projectPath = process.cwd();\n\n logger.info('šŸŽØ Adding Groovy UI components to your project...');\n logger.break();\n\n // Step 1: Validate project structure\n const spinner = ora('Validating project structure...').start();\n const isValidProject = await validateProjectStructure(projectPath);\n\n if (!isValidProject) {\n spinner.fail('Invalid project structure');\n logger.error('This command must be run in a React Native/Expo project');\n logger.info('Make sure you have a package.json with react-native or expo');\n logger.break();\n logger.info('Did you forget to run \"groovy-ui init\" first?');\n process.exit(1);\n }\n spinner.succeed('Project structure validated');\n\n // Step 2: Interactive component selection if none provided\n if (components.length === 0) {\n logger.break();\n components = await selectComponentsInteractively();\n }\n\n // Step 3: Validate components exist\n const invalidComponents = components.filter((name) => !getComponent(name));\n if (invalidComponents.length > 0) {\n logger.error(`Unknown components: ${invalidComponents.join(', ')}`);\n logger.break();\n logger.info('Available components:');\n getAllComponents().forEach((comp) =>\n logger.plain(` • ${comp.name.padEnd(20)} ${comp.description}`)\n );\n process.exit(1);\n }\n\n // Step 4: Resolve all dependencies\n spinner.start('Resolving dependencies...');\n const allComponentsToInstall = new Set<string>();\n const allPackageDependencies = new Set<string>();\n const allHooks = new Set<string>();\n const allThemes = new Set<string>();\n\n for (const componentName of components) {\n const dependencies = resolveAllDependencies(componentName);\n dependencies.forEach((dep) => {\n allComponentsToInstall.add(dep);\n\n const component = getComponent(dep);\n if (component) {\n (component.dependencies || []).forEach((pkg) =>\n allPackageDependencies.add(pkg)\n );\n (component.hooks || []).forEach((hook) => allHooks.add(hook));\n (component.theme || []).forEach((theme) => allThemes.add(theme));\n }\n });\n }\n spinner.succeed('Dependencies resolved');\n\n // Step 5: Show what will be installed\n logger.break();\n logger.info('Components to install:');\n Array.from(allComponentsToInstall).forEach((comp) => {\n const component = getComponent(comp);\n const type =\n component?.type !== 'registry:ui'\n ? ` (${component?.type.replace('registry:', '')})`\n : '';\n logger.plain(` • ${comp}${type}`);\n });\n\n if (allPackageDependencies.size > 0) {\n logger.break();\n logger.info('Package dependencies:');\n Array.from(allPackageDependencies).forEach((dep) =>\n logger.plain(` • ${dep}`)\n );\n }\n\n // Step 6: Check for conflicts\n const conflicts = await checkComponentConflicts(\n Array.from(allComponentsToInstall),\n projectPath\n );\n\n if (conflicts.length > 0 && !options.overwrite) {\n logger.break();\n logger.warn('The following files already exist:');\n conflicts.forEach((file) => logger.plain(` • ${file}`));\n\n if (!options.yes) {\n const { proceed } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'proceed',\n message: 'Do you want to overwrite these files?',\n default: false,\n },\n ]);\n\n if (!proceed) {\n logger.info('Installation cancelled');\n return;\n }\n }\n }\n\n // Step 7: Dry run\n if (options.dryRun) {\n logger.break();\n logger.info('[DRY RUN] Would install the above components');\n return;\n }\n\n // Step 8: Install package dependencies first\n if (allPackageDependencies.size > 0) {\n const packageManager = getPackageManager(options);\n logger.break();\n spinner.start('Installing package dependencies...');\n\n try {\n await installPackageDependencies(\n Array.from(allPackageDependencies),\n packageManager,\n projectPath\n );\n spinner.succeed('Package dependencies installed');\n } catch (error) {\n spinner.fail('Failed to install package dependencies');\n logger.error(String(error));\n logger.warn('You may need to install dependencies manually');\n }\n }\n\n // Step 9: Install components\n logger.break();\n spinner.start('Installing components...');\n\n try {\n let filesInstalled = 0;\n\n for (const componentName of allComponentsToInstall) {\n const component = getComponent(componentName);\n if (!component) continue;\n\n for (const file of component.files) {\n const targetPath = path.join(projectPath, file.target);\n\n // Ensure directory exists\n await ensureDirectoryExists(path.dirname(targetPath));\n\n // Fetch and write component file\n try {\n const content = await fetchComponentTemplate(file);\n await writeComponentFile(targetPath, content);\n filesInstalled++;\n } catch (error) {\n spinner.fail(`Failed to fetch ${file.path}`);\n logger.error(String(error));\n throw error;\n }\n }\n }\n\n spinner.succeed(`Components installed (${filesInstalled} files)`);\n } catch (error) {\n spinner.fail('Failed to install components');\n logger.error(String(error));\n process.exit(1);\n }\n\n // Step 10: Update component index\n await updateComponentIndex(projectPath, Array.from(allComponentsToInstall));\n\n // Step 11: Success message\n logger.break();\n logger.success('✨ All done! Components have been added to your project.');\n logger.break();\n\n logger.info('Installed components:');\n Array.from(allComponentsToInstall).forEach((comp) => {\n logger.plain(` • ${comp}`);\n });\n\n logger.break();\n logger.info('Next steps:');\n logger.plain(' 1. Import the components in your app:');\n logger.plain(` import { Button } from '@/components/ui/button';`);\n logger.break();\n logger.plain(' 2. Use them:');\n logger.plain(` <Button title=\"Hello\" onPress={() => {}} />`);\n logger.break();\n\n logger.info('Happy coding! šŸš€');\n}\n\nasync function updateComponentIndex(\n projectPath: string,\n components: string[]\n): Promise<void> {\n const indexPath = path.join(projectPath, 'components', 'ui', 'index.ts');\n\n try {\n // Read existing index\n const fs = await import('fs-extra');\n let content = '';\n\n if (await fs.pathExists(indexPath)) {\n content = await fs.readFile(indexPath, 'utf-8');\n }\n\n // Add exports for new components\n const newExports: string[] = [];\n\n for (const componentName of components) {\n const component = getComponent(componentName);\n if (!component || component.type !== 'registry:ui') continue;\n\n // Convert component name to PascalCase for export\n const pascalName = componentName\n .split('-')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join('');\n\n const exportLine = `export { ${pascalName} } from './${componentName}';`;\n const typeExportLine = `export type { ${pascalName}Props } from './${componentName}';`;\n\n // Check if already exported\n if (!content.includes(exportLine)) {\n newExports.push(exportLine);\n newExports.push(typeExportLine);\n }\n }\n\n if (newExports.length > 0) {\n // Append new exports\n const updatedContent = content + '\\n' + newExports.join('\\n') + '\\n';\n await fs.writeFile(indexPath, updatedContent, 'utf-8');\n }\n } catch (error) {\n // Non-critical error, just log it\n logger.warn('Could not update component index automatically');\n }\n}","import chalk from 'chalk';\n\n// ASCII Art for GROOVY\nconst groovyBanner = `\n${chalk.cyan(' ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā•—')}\n${chalk.cyan('ā–ˆā–ˆā•”ā•ā•ā•ā•ā• ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•— ā–ˆā–ˆā•”ā•ā•ā•ā–ˆā–ˆā•— ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•— ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā•šā–ˆā–ˆā•— ā–ˆā–ˆā•”ā•')}\n${chalk.cyan('ā–ˆā–ˆā•‘ ā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā• ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā•šā–ˆā–ˆā–ˆā–ˆā•”ā• ')}\n${chalk.cyan('ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•— ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā•šā–ˆā–ˆā•— ā–ˆā–ˆā•”ā• ā•šā–ˆā–ˆā•”ā• ')}\n${chalk.cyan('ā•šā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā•šā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā• ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā• ā•šā–ˆā–ˆā–ˆā–ˆā•”ā• ā–ˆā–ˆā•‘ ')}\n${chalk.cyan(' ā•šā•ā•ā•ā•ā•ā• ā•šā•ā• ā•šā•ā• ā•šā•ā•ā•ā•ā•ā• ā•šā•ā•ā•ā•ā•ā• ā•šā•ā•ā•ā•ā•ā• ā•šā•ā• ')}\n\n${chalk.gray('Expo React Native CLI, UI Components Library')}\n`;\n\nexport const logger = {\n info: (message: string, ...args: any[]) => {\n console.log(chalk.blue('ℹ'), message, ...args);\n },\n\n success: (message: string, ...args: any[]) => {\n console.log(chalk.green('āœ“'), message, ...args);\n },\n\n warn: (message: string, ...args: any[]) => {\n console.log(chalk.yellow('⚠'), message, ...args);\n },\n\n error: (message: string, ...args: any[]) => {\n console.error(chalk.red('āœ—'), message, ...args);\n },\n\n debug: (message: string, ...args: any[]) => {\n if (process.env.DEBUG) {\n console.log(chalk.gray('šŸ›'), message, ...args);\n }\n },\n\n plain: (message: string, ...args: any[]) => {\n console.log(message, ...args);\n },\n\n header: (message: string) => {\n console.log('\\n' + chalk.bold.cyan(message) + '\\n');\n },\n\n banner: () => {\n console.log(groovyBanner);\n },\n\n break: () => {\n console.log('');\n },\n\n newline: () => {\n console.log();\n },\n};\n","// src/utils/filesystem.ts\nimport fs from 'fs-extra';\nimport path from 'path';\n\n/**\n * Validates if the current directory is a valid React Native/Expo project\n */\nexport async function validateProjectStructure(\n projectPath: string\n): Promise<boolean> {\n const packageJsonPath = path.join(projectPath, 'package.json');\n\n if (!(await fs.pathExists(packageJsonPath))) {\n return false;\n }\n\n try {\n const packageJson = await fs.readJson(packageJsonPath);\n\n // Check if it's a React Native or Expo project\n const hasReactNative =\n packageJson.dependencies?.['react-native'] ||\n packageJson.devDependencies?.['react-native'];\n const hasExpo =\n packageJson.dependencies?.['expo'] ||\n packageJson.devDependencies?.['expo'];\n\n return !!(hasReactNative || hasExpo);\n } catch (error) {\n return false;\n }\n}\n\n/**\n * Ensures a directory exists, creating it if necessary\n */\nexport async function ensureDirectoryExists(dirPath: string): Promise<void> {\n await fs.ensureDir(dirPath);\n}\n\n/**\n * Writes content to a file\n */\nexport async function writeComponentFile(\n filePath: string,\n content: string\n): Promise<void> {\n await fs.writeFile(filePath, content, 'utf-8');\n}\n\n/**\n * Checks if a file exists\n */\nexport async function fileExists(filePath: string): Promise<boolean> {\n return fs.pathExists(filePath);\n}\n\n/**\n * Checks for component conflicts (existing files)\n */\nexport async function checkComponentConflicts(\n components: string[],\n projectPath: string\n): Promise<string[]> {\n const conflicts: string[] = [];\n \n // Dynamic import to avoid circular dependency\n const { getComponent } = await import('../registry/index.js');\n\n for (const componentName of components) {\n const component = getComponent(componentName);\n if (!component) continue;\n\n for (const file of component.files) {\n const targetPath = path.join(projectPath, file.target);\n if (await fileExists(targetPath)) {\n conflicts.push(file.target);\n }\n }\n }\n\n return conflicts;\n}\n\n/**\n * Reads package.json from the project\n */\nexport async function readPackageJson(projectPath: string): Promise<any> {\n const packageJsonPath = path.join(projectPath, 'package.json');\n return fs.readJson(packageJsonPath);\n}\n\n/**\n * Writes package.json to the project\n */\nexport async function writePackageJson(\n projectPath: string,\n data: any\n): Promise<void> {\n const packageJsonPath = path.join(projectPath, 'package.json');\n await fs.writeJson(packageJsonPath, data, { spaces: 2 });\n}\n\n/**\n * Reads a file's content\n */\nexport async function readFile(filePath: string): Promise<string> {\n return fs.readFile(filePath, 'utf-8');\n}\n\n/**\n * Copies a template directory to a destination\n */\nexport async function copyTemplate(\n templatePath: string,\n destPath: string\n): Promise<void> {\n await fs.copy(templatePath, destPath, {\n overwrite: true,\n errorOnExist: false,\n });\n}","// src/utils/dependencies.ts\nimport { execa, execaSync } from 'execa';\nimport fs from 'fs-extra';\nimport path from 'path';\n\nexport type PackageManager = 'npm' | 'yarn' | 'pnpm' | 'bun';\n\n/**\n * Detects the package manager being used based on lock files\n */\nexport function detectPackageManager(): PackageManager {\n const cwd = process.cwd();\n\n // Check lock files in order of preference\n if (fs.existsSync(path.join(cwd, 'bun.lockb'))) return 'bun';\n if (fs.existsSync(path.join(cwd, 'pnpm-lock.yaml'))) return 'pnpm';\n if (fs.existsSync(path.join(cwd, 'yarn.lock'))) return 'yarn';\n if (fs.existsSync(path.join(cwd, 'package-lock.json'))) return 'npm';\n\n // Check if any package manager is in PATH\n try {\n execaSync('bun', ['--version']);\n return 'bun';\n } catch {}\n\n try {\n execaSync('pnpm', ['--version']);\n return 'pnpm';\n } catch {}\n\n try {\n execaSync('yarn', ['--version']);\n return 'yarn';\n } catch {}\n\n // Default to npm (most common)\n return 'npm';\n}\n\n/**\n * Installs package dependencies using the specified package manager\n */\nexport async function installPackageDependencies(\n dependencies: string[],\n packageManager: PackageManager,\n projectPath: string\n): Promise<void> {\n const commands: Record<PackageManager, string[]> = {\n npm: ['install', ...dependencies],\n yarn: ['add', ...dependencies],\n pnpm: ['add', ...dependencies],\n bun: ['add', ...dependencies],\n };\n\n const args = commands[packageManager];\n\n if (!args) {\n throw new Error(`Unsupported package manager: ${packageManager}`);\n }\n\n await execa(packageManager, args, {\n cwd: projectPath,\n stdio: 'inherit',\n });\n}\n\n/**\n * Checks which dependencies are already installed\n */\nexport async function checkExistingDependencies(\n dependencies: string[],\n projectPath: string\n): Promise<{ installed: string[]; missing: string[] }> {\n const packageJsonPath = path.join(projectPath, 'package.json');\n const packageJson = await fs.readJson(packageJsonPath);\n\n const allDeps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n const installed: string[] = [];\n const missing: string[] = [];\n\n for (const dep of dependencies) {\n // Handle scoped packages like @react-navigation/native\n const depName = dep.includes('@') && dep.startsWith('@') \n ? dep.split('@').slice(0, 2).join('@')\n : dep.split('@')[0];\n\n if (allDeps[depName]) {\n installed.push(dep);\n } else {\n missing.push(dep);\n }\n }\n\n return { installed, missing };\n}\n\n/**\n * Gets the run command for a script based on package manager\n */\nexport function getRunCommand(\n packageManager: PackageManager,\n script: string\n): string {\n const commands: Record<PackageManager, string> = {\n npm: `npm run ${script}`,\n yarn: `yarn ${script}`,\n pnpm: `pnpm ${script}`,\n bun: `bun run ${script}`,\n };\n\n return commands[packageManager];\n}\n\n/**\n * Gets the install command for the package manager\n */\nexport function getInstallCommand(packageManager: PackageManager): string {\n const commands: Record<PackageManager, string> = {\n npm: 'npm install',\n yarn: 'yarn',\n pnpm: 'pnpm install',\n bun: 'bun install',\n };\n\n return commands[packageManager];\n}","// src/commands/init.ts\nimport inquirer from 'inquirer';\nimport ora from 'ora';\nimport path from 'path';\nimport fs from 'fs-extra';\nimport { logger } from '../utils/logger.js';\nimport {\n validateProjectStructure,\n ensureDirectoryExists,\n writeComponentFile,\n} from '../utils/filesystem.js';\n\ninterface InitCommandOptions {\n yes?: boolean;\n components?: boolean;\n}\n\nexport async function initCommand(\n options: InitCommandOptions = {}\n): Promise<void> {\n const projectPath = process.cwd();\n\n logger.info('šŸŽØ Initializing Groovy UI in your project...');\n logger.break();\n\n // Step 1: Validate this is a React Native/Expo project\n const spinner = ora('Checking project structure...').start();\n const isValidProject = await validateProjectStructure(projectPath);\n\n if (!isValidProject) {\n spinner.fail('Not a valid React Native or Expo project');\n logger.error('This command must be run in a React Native or Expo project');\n logger.info('Make sure you have a package.json with react-native or expo');\n logger.break();\n logger.info('To create a new Expo project:');\n logger.plain(' npx create-expo-app my-app');\n process.exit(1);\n }\n spinner.succeed('Valid React Native/Expo project detected');\n\n // Step 2: Check if groovy-ui is already initialized\n const componentsDir = path.join(projectPath, 'components', 'ui');\n const alreadyInitialized = await fs.pathExists(componentsDir);\n\n if (alreadyInitialized && !options.yes) {\n logger.warn('Groovy UI appears to be already initialized');\n logger.plain(`Found existing directory: ${componentsDir}`);\n logger.break();\n\n const { proceed } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'proceed',\n message: 'Continue anyway?',\n default: false,\n },\n ]);\n\n if (!proceed) {\n logger.info('Initialization cancelled');\n return;\n }\n }\n\n // Step 3: Create folder structure\n logger.break();\n spinner.start('Creating folder structure...');\n\n try {\n // Create components/ui directory\n await ensureDirectoryExists(path.join(projectPath, 'components', 'ui'));\n\n // Create lib/utils directory (for utility functions)\n await ensureDirectoryExists(path.join(projectPath, 'lib', 'utils'));\n\n // Create hooks directory\n await ensureDirectoryExists(path.join(projectPath, 'hooks'));\n\n spinner.succeed('Folder structure created');\n } catch (error) {\n spinner.fail('Failed to create folder structure');\n throw error;\n }\n\n // Step 4: Create utility files\n spinner.start('Setting up utilities...');\n\n try {\n // Create cn utility (for conditional classNames)\n const cnUtilPath = path.join(projectPath, 'lib', 'utils', 'cn.ts');\n const cnUtilContent = `/**\n * Utility for merging class names\n */\nexport function cn(...classes: (string | undefined | null | false)[]): string {\n return classes.filter(Boolean).join(' ');\n}\n`;\n await writeComponentFile(cnUtilPath, cnUtilContent);\n\n // Create colors utility (for theme colors)\n const colorsUtilPath = path.join(projectPath, 'lib', 'utils', 'colors.ts');\n const colorsUtilContent = `/**\n * Color utilities for your components\n */\nexport const colors = {\n primary: '#007AFF',\n secondary: '#8E8E93',\n success: '#34C759',\n warning: '#FF9500',\n error: '#FF3B30',\n background: '#FFFFFF',\n text: '#000000',\n border: '#E5E5EA',\n muted: '#F2F2F7',\n};\n\nexport type ColorName = keyof typeof colors;\n\nexport function getColor(name: ColorName): string {\n return colors[name];\n}\n`;\n await writeComponentFile(colorsUtilPath, colorsUtilContent);\n\n spinner.succeed('Utilities created');\n } catch (error) {\n spinner.fail('Failed to create utilities');\n throw error;\n }\n\n // Step 5: Create a basic index file for components\n spinner.start('Creating component index...');\n\n try {\n const indexPath = path.join(projectPath, 'components', 'ui', 'index.ts');\n const indexContent = `/**\n * Groovy UI Components\n * \n * Export all your UI components from here\n * Components will be automatically added when you run: groovy-ui add <component>\n * \n * Example usage:\n * import { Button, Alert, Card } from '@/components/ui';\n */\n\n// Components will be exported here automatically\n// Example:\n// export { Button } from './button';\n// export type { ButtonProps } from './button';\n`;\n await writeComponentFile(indexPath, indexContent);\n\n spinner.succeed('Component index created');\n } catch (error) {\n spinner.fail('Failed to create component index');\n throw error;\n }\n\n // Step 6: Create a README\n spinner.start('Creating documentation...');\n\n try {\n const readmePath = path.join(projectPath, 'components', 'README.md');\n const readmeContent = `# Groovy UI Components\n\nThis directory contains your UI components from Groovy UI.\n\n## Structure\n\n\\`\\`\\`\ncomponents/\nā”œā”€ā”€ ui/ # Core UI components\n│ ā”œā”€ā”€ button.tsx\n│ ā”œā”€ā”€ alert.tsx\n│ ā”œā”€ā”€ card.tsx\n│ └── index.ts # Export all components\n└── README.md # This file\n\\`\\`\\`\n\n## Adding Components\n\nAdd new components using the Groovy UI CLI:\n\n\\`\\`\\`bash\n# Add a single component\nnpx groovy-ui add button\n\n# Add multiple components\nnpx groovy-ui add alert card modal\n\n# Interactive selection\nnpx groovy-ui add\n\\`\\`\\`\n\n## Usage\n\nImport components from the ui directory:\n\n\\`\\`\\`tsx\nimport { Button, Alert } from '@/components/ui';\n\nexport default function App() {\n return (\n <Button \n title=\"Click me\" \n onPress={() => alert('Hello!')} \n variant=\"primary\"\n />\n );\n}\n\\`\\`\\`\n\n## Customization\n\nAll components are copied to your project as source code, so you can:\n\n- āœļø Modify styles to match your design system\n- āž• Add or remove features as needed\n- šŸ”§ Extend functionality\n- šŸŽØ Change behavior and appearance\n\n**The components are yours to customize!**\n\n## Available Components\n\n- **Button**: Customizable button with variants and sizes\n- **Alert**: Display important messages with different severity levels\n- **Card**: Container component with header and footer\n- **Modal**: Full-screen or centered modal dialogs\n- **Input**: Text input with labels and validation\n- And more...\n\n## TypeScript Support\n\nAll components are written in TypeScript with full type safety:\n\n\\`\\`\\`tsx\nimport { ButtonProps } from '@/components/ui';\n\nconst MyButton: React.FC<ButtonProps> = (props) => {\n return <Button {...props} />;\n};\n\\`\\`\\`\n\n## Learn More\n\n- Documentation: [groovy-ui.dev](https://groovy-ui.dev)\n- Examples: [github.com/groovy-ui/examples](https://github.com/groovy-ui/examples)\n- Issues: [github.com/groovy-ui/issues](https://github.com/groovy-ui/issues)\n`;\n await writeComponentFile(readmePath, readmeContent);\n\n spinner.succeed('Documentation created');\n } catch (error) {\n spinner.fail('Failed to create documentation');\n // Don't throw - README is optional\n }\n\n // Step 7: Check TypeScript configuration\n const tsconfigPath = path.join(projectPath, 'tsconfig.json');\n if (await fs.pathExists(tsconfigPath)) {\n spinner.start('Checking TypeScript configuration...');\n\n try {\n const tsconfig = await fs.readJson(tsconfigPath);\n const hasPathAlias = tsconfig?.compilerOptions?.paths?.['@/*'];\n\n if (!hasPathAlias) {\n spinner.warn('Path alias @/* not found in tsconfig.json');\n logger.break();\n logger.info('šŸ“ Add this to your tsconfig.json for better imports:');\n logger.plain(`\n{\n \"compilerOptions\": {\n \"baseUrl\": \".\",\n \"paths\": {\n \"@/*\": [\"./*\"]\n }\n }\n}\n`);\n } else {\n spinner.succeed('TypeScript configuration looks good');\n }\n } catch (error) {\n spinner.warn('Could not validate TypeScript configuration');\n }\n }\n\n // Step 8: Create .gitignore entry (optional)\n try {\n const gitignorePath = path.join(projectPath, '.gitignore');\n if (await fs.pathExists(gitignorePath)) {\n let gitignoreContent = await fs.readFile(gitignorePath, 'utf-8');\n\n // Check if groovy-ui section exists\n if (!gitignoreContent.includes('# groovy-ui')) {\n // Add groovy-ui section\n const groovyIgnore = `\n\n# groovy-ui\n# Uncomment if you don't want to track component customizations\n# components/ui/\n`;\n gitignoreContent += groovyIgnore;\n await fs.writeFile(gitignorePath, gitignoreContent, 'utf-8');\n }\n }\n } catch (error) {\n // Non-critical, ignore\n }\n\n // Success!\n logger.break();\n logger.success('✨ Groovy UI initialized successfully!');\n logger.break();\n\n // Show folder structure\n logger.info('Created folder structure:');\n logger.plain(' components/');\n logger.plain(' ā”œā”€ā”€ ui/ # Your UI components');\n logger.plain(' └── README.md # Documentation');\n logger.plain(' lib/');\n logger.plain(' └── utils/ # Utility functions');\n logger.plain(' hooks/ # Custom React hooks');\n logger.break();\n\n logger.info('Next steps:');\n logger.plain(' 1. Add components:');\n logger.plain(' npx groovy-ui add button');\n logger.plain(' npx groovy-ui add alert card modal');\n logger.break();\n\n logger.plain(' 2. Import in your app:');\n logger.plain(\" import { Button } from '@/components/ui/button';\");\n logger.break();\n\n logger.plain(' 3. Use the components:');\n logger.plain(' <Button title=\"Hello\" onPress={() => {}} />');\n logger.break();\n\n logger.info('Happy coding! šŸš€');\n}"],"mappings":"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","names":["path","getComponent","fs","path","path","fs","inquirer","ora","path","fs","ora","path","fs","inquirer"]}
@@ -0,0 +1,15 @@
1
+ import {
2
+ REGISTRY,
3
+ fetchComponentTemplate,
4
+ getAllComponents,
5
+ getComponent,
6
+ resolveAllDependencies
7
+ } from "./chunk-3BUGHI3R.js";
8
+ export {
9
+ REGISTRY,
10
+ fetchComponentTemplate,
11
+ getAllComponents,
12
+ getComponent,
13
+ resolveAllDependencies
14
+ };
15
+ //# sourceMappingURL=registry-ZMFJ6C6R.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "groovy-native-ui",
3
+ "version": "1.0.0",
4
+ "description": "CLI for adding Groovy UI components to your React Native project",
5
+ "type": "module",
6
+ "bin": {
7
+ "groovy-ui": "./bin/groovy-ui.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "bin"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsup src/index.ts --format esm --dts --clean",
15
+ "dev": "tsup src/index.ts --format esm --dts --watch",
16
+ "test:local": "npm run build && npm link"
17
+ },
18
+ "dependencies": {
19
+ "chalk": "^5.3.0",
20
+ "commander": "^11.0.0",
21
+ "execa": "^8.0.0",
22
+ "fs-extra": "^11.1.0",
23
+ "inquirer": "^9.2.0",
24
+ "node-fetch": "^3.3.0",
25
+ "ora": "^7.0.0"
26
+ },
27
+ "devDependencies": {
28
+ "@types/fs-extra": "^11.0.4",
29
+ "@types/inquirer": "^9.0.9",
30
+ "@types/node": "^20.19.27",
31
+ "tsup": "^8.5.1",
32
+ "typescript": "^5.9.3"
33
+ }
34
+ }
package/readme.md ADDED
@@ -0,0 +1,10 @@
1
+ # Groovy Native UI
2
+
3
+ Beautiful, customizable UI components for React Native and Expo projects.
4
+
5
+ ## Installation
6
+ ```bash
7
+ npx groovy-native-ui init
8
+ npx groovy-native-ui add button
9
+ ```
10
+ ...