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.
- package/bin/groovy-ui.js +5 -0
- package/dist/chunk-3BUGHI3R.js +74 -0
- package/dist/chunk-3BUGHI3R.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +648 -0
- package/dist/index.js.map +1 -0
- package/dist/registry-ZMFJ6C6R.js +15 -0
- package/dist/registry-ZMFJ6C6R.js.map +1 -0
- package/package.json +34 -0
- package/readme.md +10 -0
package/bin/groovy-ui.js
ADDED
|
@@ -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":[]}
|
package/dist/index.d.ts
ADDED
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
|
+
}
|