react-apps-ui 1.0.11 → 1.0.13

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/README.md CHANGED
@@ -64,11 +64,11 @@ The code is now yours! You will find it beautifully organized in your project fo
64
64
  import { ActionButton } from "@/components/ui/action-button";
65
65
 
66
66
  export default function App() {
67
- return (
68
- <ActionButton onPress="{()"> console.log("Pressed!")}>
69
- Click Me
70
- </ActionButton>
71
- );
67
+ return (
68
+ <ActionButton onPress={() => console.log("Pressed!")}>
69
+ Click Me
70
+ </ActionButton>
71
+ );
72
72
  }
73
73
  ```
74
74
 
package/dist/index.js CHANGED
@@ -17,7 +17,49 @@ program
17
17
  .name("react-apps-ui")
18
18
  .description("Add high-quality components to your React Native app")
19
19
  .version("1.0.0");
20
+ // Helper to filter out packages that are already in package.json
21
+ function filterMissingDeps(deps) {
22
+ const packageJsonPath = path_1.default.join(process.cwd(), "package.json");
23
+ if (!fs_1.default.existsSync(packageJsonPath))
24
+ return deps;
25
+ try {
26
+ const pkg = JSON.parse(fs_1.default.readFileSync(packageJsonPath, "utf-8"));
27
+ const installed = {
28
+ ...(pkg.dependencies || {}),
29
+ ...(pkg.devDependencies || {}),
30
+ };
31
+ return deps.filter((dep) => {
32
+ let pkgName = dep;
33
+ if (dep.startsWith("@")) {
34
+ pkgName = "@" + dep.slice(1).split("@")[0];
35
+ }
36
+ else {
37
+ pkgName = dep.split("@")[0];
38
+ }
39
+ return !installed[pkgName];
40
+ });
41
+ }
42
+ catch {
43
+ return deps;
44
+ }
45
+ }
20
46
  // --- THE INIT COMMAND ---
47
+ // 1. Define the foundational architecture for each engine
48
+ const BASE_DEPS = {
49
+ "mobile-nativewind": {
50
+ npm: [
51
+ "class-variance-authority",
52
+ "tailwind-merge",
53
+ "clsx",
54
+ "lucide-react-native", // Added for the IconName type
55
+ ],
56
+ registry: ["theme", "utils"], // Pulls your cn() utility and theme
57
+ },
58
+ "mobile-stylesheet": {
59
+ npm: ["lucide-react-native"], // Added for the IconName type
60
+ registry: ["theme", "utils"],
61
+ },
62
+ };
21
63
  program
22
64
  .command("init")
23
65
  .description("Configure your Expo project and install the ThemeProvider")
@@ -43,6 +85,8 @@ program
43
85
  console.log(chalk_1.default.red("Initialization cancelled."));
44
86
  return;
45
87
  }
88
+ const engineKey = response.engine;
89
+ const setup = BASE_DEPS[engineKey];
46
90
  // 2. USE THE REGISTRY_URL to fetch the correct JSON manifest
47
91
  const manifestUrl = `${REGISTRY_URL}/${response.engine}.json`;
48
92
  console.log(chalk_1.default.dim(`\nFetching registry from GitHub...`));
@@ -51,59 +95,79 @@ program
51
95
  if (!res.ok)
52
96
  throw new Error(`Failed to fetch registry: ${res.statusText}`);
53
97
  const registry = await res.json();
54
- // 3. Find the "theme" component inside the giant JSON
55
- const themeComponent = registry.find((item) => item.name === "theme");
56
- if (!themeComponent) {
57
- console.log(chalk_1.default.red("Error: Could not find 'theme' in the registry."));
58
- return;
59
- }
60
- console.log(chalk_1.default.green(`✓ Found theme provider. Installing...`));
61
98
  // Check if the user's project uses a 'src' directory
62
99
  const hasSrcDir = fs_1.default.existsSync(path_1.default.join(process.cwd(), "src"));
63
- // 4. Loop through the files and write them smartly
64
- for (const file of themeComponent.files) {
65
- // A. Force the target to be a string so it can never be undefined
66
- const safeTarget = String(file.target || file.name || "unknown-file");
67
- let finalTargetPath = path_1.default.join(process.cwd(), safeTarget);
68
- //B. Safely check includes on the guaranteed string
69
- const isRootConfig = safeTarget.includes("tailwind") ||
70
- safeTarget.endsWith(".config.js") ||
71
- safeTarget.endsWith(".json");
72
- if (hasSrcDir && !isRootConfig) {
73
- finalTargetPath = path_1.default.join(process.cwd(), "src", safeTarget);
100
+ // 3. Loop through the required BASE REGISTRY components (theme, utils, etc.)
101
+ for (const compName of setup.registry) {
102
+ const componentData = registry.find((item) => item.name === compName);
103
+ if (!componentData) {
104
+ console.log(chalk_1.default.red(`Error: Could not find '${compName}' in the registry.`));
105
+ continue;
74
106
  }
75
- // Ensure the folder exists
76
- fs_1.default.mkdirSync(path_1.default.dirname(finalTargetPath), {
77
- recursive: true,
78
- });
79
- // SAFE WRITE: Check if the file already exists
80
- if (fs_1.default.existsSync(finalTargetPath)) {
81
- if (file.type === "css" ||
82
- finalTargetPath.endsWith(".css")) {
83
- console.log(chalk_1.default.yellow(` ⚠️ ${file.target} already exists. Appending theme variables safely...`));
84
- try {
85
- // C. Read the file and forcefully convert it to a String
86
- const rawContent = fs_1.default.readFileSync(finalTargetPath, "utf-8");
87
- const safeExistingContent = String(rawContent || "");
88
- // D. Safely check includes (This line can no longer crash!)
89
- if (!safeExistingContent.includes("--background:")) {
90
- fs_1.default.appendFileSync(finalTargetPath, `\n/* React Apps UI Theme */\n${file.content || ""}`, "utf-8");
107
+ console.log(chalk_1.default.green(`✓ Found ${compName}. Installing...`));
108
+ // 4. Loop through the files and write them smartly
109
+ for (const file of componentData.files) {
110
+ // A. Force the target to be a string so it can never be undefined
111
+ const safeTarget = String(file.target || file.name || "unknown-file");
112
+ let finalTargetPath = path_1.default.join(process.cwd(), safeTarget);
113
+ //B. Safely check includes on the guaranteed string
114
+ const isRootConfig = safeTarget.includes("tailwind") ||
115
+ safeTarget.endsWith(".config.js") ||
116
+ safeTarget.endsWith(".json");
117
+ if (hasSrcDir && !isRootConfig) {
118
+ finalTargetPath = path_1.default.join(process.cwd(), "src", safeTarget);
119
+ }
120
+ // Ensure the folder exists
121
+ fs_1.default.mkdirSync(path_1.default.dirname(finalTargetPath), {
122
+ recursive: true,
123
+ });
124
+ // SAFE WRITE: Check if the file already exists
125
+ if (fs_1.default.existsSync(finalTargetPath)) {
126
+ if (file.type === "css" ||
127
+ finalTargetPath.endsWith(".css")) {
128
+ console.log(chalk_1.default.yellow(` ⚠️ ${file.target} already exists. Appending theme variables safely...`));
129
+ try {
130
+ // C. Read the file and forcefully convert it to a String
131
+ const rawContent = fs_1.default.readFileSync(finalTargetPath, "utf-8");
132
+ const safeExistingContent = String(rawContent || "");
133
+ // D. Safely check includes (This line can no longer crash!)
134
+ if (!safeExistingContent.includes("--background:")) {
135
+ fs_1.default.appendFileSync(finalTargetPath, `\n/* React Apps UI Theme */\n${file.content || ""}`, "utf-8");
136
+ }
137
+ }
138
+ catch (err) {
139
+ console.log(chalk_1.default.red(` ❌ Error reading or appending to ${safeTarget}`));
91
140
  }
92
141
  }
93
- catch (err) {
94
- console.log(chalk_1.default.red(` Error reading or appending to ${safeTarget}`));
142
+ else {
143
+ console.log(chalk_1.default.yellow(` ⚠️ ${file.target} already exists. Skipping to prevent overwrite.`));
95
144
  }
96
145
  }
97
146
  else {
98
- console.log(chalk_1.default.yellow(` ⚠️ ${file.target} already exists. Skipping to prevent overwrite.`));
147
+ // File doesn't exist, safe to write normally
148
+ fs_1.default.writeFileSync(finalTargetPath, file.content, "utf-8");
149
+ console.log(chalk_1.default.green(` Created ${safeTarget}`));
99
150
  }
100
151
  }
101
- else {
102
- // File doesn't exist, safe to write normally
103
- fs_1.default.writeFileSync(finalTargetPath, file.content, "utf-8");
104
- console.log(chalk_1.default.green(` Created ${safeTarget}`));
152
+ }
153
+ // 5. INSTALL FOUNDATIONAL NPM DEPENDENCIES (Skipping already installed)
154
+ const missingBaseDeps = filterMissingDeps(setup.npm);
155
+ if (missingBaseDeps.length > 0) {
156
+ const depList = missingBaseDeps.join(" ");
157
+ console.log(chalk_1.default.blue(`\n📦 Installing missing foundational NPM dependencies: ${depList}...`));
158
+ try {
159
+ (0, child_process_1.execSync)(`npm install ${depList} --legacy-peer-deps`, {
160
+ stdio: "inherit",
161
+ });
162
+ console.log(chalk_1.default.green("✓ Dependencies installed successfully."));
163
+ }
164
+ catch (err) {
165
+ console.log(chalk_1.default.red("❌ Failed to install dependencies. You may need to install them manually."));
105
166
  }
106
167
  }
168
+ else {
169
+ console.log(chalk_1.default.green("\n✓ All foundational NPM dependencies are already installed. Skipping."));
170
+ }
107
171
  console.log(chalk_1.default.blue("\n🎉 Initialization complete!"));
108
172
  console.log(chalk_1.default.dim("Wrap your app in the <ThemeProvider> to get started."));
109
173
  }
@@ -179,7 +243,7 @@ program
179
243
  }
180
244
  }
181
245
  }
182
- // 5. INSTALL NPM DEPENDENCIES
246
+ // 5. INSTALL NPM DEPENDENCIES (Skipping already installed)
183
247
  const depsToInstall = new Set();
184
248
  // Collect all dependencies from the components we just added
185
249
  for (const compName of componentsToAdd) {
@@ -188,18 +252,24 @@ program
188
252
  compData.dependencies.forEach((dep) => depsToInstall.add(dep));
189
253
  }
190
254
  }
191
- if (depsToInstall.size > 0) {
192
- const depList = Array.from(depsToInstall).join(" ");
193
- console.log(chalk_1.default.blue(`\n📦 Installing NPM dependencies: ${depList}...`));
255
+ // Filter out anything already installed in user's package.json
256
+ const missingDeps = filterMissingDeps(Array.from(depsToInstall));
257
+ if (missingDeps.length > 0) {
258
+ const depList = missingDeps.join(" ");
259
+ console.log(chalk_1.default.blue(`\n📦 Installing missing NPM dependencies: ${depList}...`));
194
260
  try {
195
- // This runs 'npm install' directly in the user's terminal
196
- (0, child_process_1.execSync)(`npm install ${depList}`, { stdio: "inherit" });
261
+ (0, child_process_1.execSync)(`npm install ${depList} --legacy-peer-deps`, {
262
+ stdio: "inherit",
263
+ });
197
264
  console.log(chalk_1.default.green("✓ Dependencies installed successfully."));
198
265
  }
199
266
  catch (err) {
200
267
  console.log(chalk_1.default.red("❌ Failed to install dependencies. You may need to install them manually."));
201
268
  }
202
269
  }
270
+ else if (depsToInstall.size > 0) {
271
+ console.log(chalk_1.default.green("\n✓ Required NPM dependencies are already installed. Skipping."));
272
+ }
203
273
  console.log(chalk_1.default.blue("\n🎉 Components installed successfully!"));
204
274
  }
205
275
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-apps-ui",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "A universal, Shadcn-inspired UI component CLI for Web, React Native, and Expo.",
5
5
  "author": "Anand Vyas",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -17,7 +17,51 @@ program
17
17
  .description("Add high-quality components to your React Native app")
18
18
  .version("1.0.0");
19
19
 
20
+ // Helper to filter out packages that are already in package.json
21
+ function filterMissingDeps(deps: string[]): string[] {
22
+ const packageJsonPath = path.join(process.cwd(), "package.json");
23
+ if (!fs.existsSync(packageJsonPath)) return deps;
24
+
25
+ try {
26
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
27
+ const installed = {
28
+ ...(pkg.dependencies || {}),
29
+ ...(pkg.devDependencies || {}),
30
+ };
31
+
32
+ return deps.filter((dep) => {
33
+ let pkgName = dep;
34
+ if (dep.startsWith("@")) {
35
+ pkgName = "@" + dep.slice(1).split("@")[0];
36
+ } else {
37
+ pkgName = dep.split("@")[0];
38
+ }
39
+ return !installed[pkgName];
40
+ });
41
+ } catch {
42
+ return deps;
43
+ }
44
+ }
45
+
20
46
  // --- THE INIT COMMAND ---
47
+
48
+ // 1. Define the foundational architecture for each engine
49
+ const BASE_DEPS: Record<string, { npm: string[]; registry: string[] }> = {
50
+ "mobile-nativewind": {
51
+ npm: [
52
+ "class-variance-authority",
53
+ "tailwind-merge",
54
+ "clsx",
55
+ "lucide-react-native", // Added for the IconName type
56
+ ],
57
+ registry: ["theme", "utils"], // Pulls your cn() utility and theme
58
+ },
59
+ "mobile-stylesheet": {
60
+ npm: ["lucide-react-native"], // Added for the IconName type
61
+ registry: ["theme", "utils"],
62
+ },
63
+ };
64
+
21
65
  program
22
66
  .command("init")
23
67
  .description("Configure your Expo project and install the ThemeProvider")
@@ -46,6 +90,9 @@ program
46
90
  return;
47
91
  }
48
92
 
93
+ const engineKey = response.engine as keyof typeof BASE_DEPS;
94
+ const setup = BASE_DEPS[engineKey];
95
+
49
96
  // 2. USE THE REGISTRY_URL to fetch the correct JSON manifest
50
97
  const manifestUrl = `${REGISTRY_URL}/${response.engine}.json`;
51
98
  console.log(chalk.dim(`\nFetching registry from GitHub...`));
@@ -56,104 +103,145 @@ program
56
103
  throw new Error(`Failed to fetch registry: ${res.statusText}`);
57
104
 
58
105
  const registry = await res.json();
59
-
60
- // 3. Find the "theme" component inside the giant JSON
61
- const themeComponent = registry.find(
62
- (item: any) => item.name === "theme",
63
- );
64
-
65
- if (!themeComponent) {
66
- console.log(
67
- chalk.red("Error: Could not find 'theme' in the registry."),
68
- );
69
- return;
70
- }
71
-
72
- console.log(chalk.green(`✓ Found theme provider. Installing...`));
73
-
74
106
  // Check if the user's project uses a 'src' directory
75
107
  const hasSrcDir = fs.existsSync(path.join(process.cwd(), "src"));
76
108
 
77
- // 4. Loop through the files and write them smartly
78
- for (const file of themeComponent.files) {
79
- // A. Force the target to be a string so it can never be undefined
80
- const safeTarget = String(
81
- file.target || file.name || "unknown-file",
109
+ // 3. Loop through the required BASE REGISTRY components (theme, utils, etc.)
110
+ for (const compName of setup.registry) {
111
+ const componentData = registry.find(
112
+ (item: any) => item.name === compName,
82
113
  );
83
- let finalTargetPath = path.join(process.cwd(), safeTarget);
84
-
85
- //B. Safely check includes on the guaranteed string
86
- const isRootConfig =
87
- safeTarget.includes("tailwind") ||
88
- safeTarget.endsWith(".config.js") ||
89
- safeTarget.endsWith(".json");
90
-
91
- if (hasSrcDir && !isRootConfig) {
92
- finalTargetPath = path.join(
93
- process.cwd(),
94
- "src",
95
- safeTarget,
114
+
115
+ if (!componentData) {
116
+ console.log(
117
+ chalk.red(
118
+ `Error: Could not find '${compName}' in the registry.`,
119
+ ),
96
120
  );
121
+ continue;
97
122
  }
98
123
 
99
- // Ensure the folder exists
100
- fs.mkdirSync(path.dirname(finalTargetPath), {
101
- recursive: true,
102
- });
103
-
104
- // SAFE WRITE: Check if the file already exists
105
- if (fs.existsSync(finalTargetPath)) {
106
- if (
107
- file.type === "css" ||
108
- finalTargetPath.endsWith(".css")
109
- ) {
110
- console.log(
111
- chalk.yellow(
112
- ` ⚠️ ${file.target} already exists. Appending theme variables safely...`,
113
- ),
124
+ console.log(chalk.green(`✓ Found ${compName}. Installing...`));
125
+
126
+ // 4. Loop through the files and write them smartly
127
+ for (const file of componentData.files) {
128
+ // A. Force the target to be a string so it can never be undefined
129
+ const safeTarget = String(
130
+ file.target || file.name || "unknown-file",
131
+ );
132
+ let finalTargetPath = path.join(process.cwd(), safeTarget);
133
+
134
+ //B. Safely check includes on the guaranteed string
135
+ const isRootConfig =
136
+ safeTarget.includes("tailwind") ||
137
+ safeTarget.endsWith(".config.js") ||
138
+ safeTarget.endsWith(".json");
139
+
140
+ if (hasSrcDir && !isRootConfig) {
141
+ finalTargetPath = path.join(
142
+ process.cwd(),
143
+ "src",
144
+ safeTarget,
114
145
  );
146
+ }
115
147
 
116
- try {
117
- // C. Read the file and forcefully convert it to a String
118
- const rawContent = fs.readFileSync(
119
- finalTargetPath,
120
- "utf-8",
121
- );
122
- const safeExistingContent = String(
123
- rawContent || "",
148
+ // Ensure the folder exists
149
+ fs.mkdirSync(path.dirname(finalTargetPath), {
150
+ recursive: true,
151
+ });
152
+
153
+ // SAFE WRITE: Check if the file already exists
154
+ if (fs.existsSync(finalTargetPath)) {
155
+ if (
156
+ file.type === "css" ||
157
+ finalTargetPath.endsWith(".css")
158
+ ) {
159
+ console.log(
160
+ chalk.yellow(
161
+ ` ⚠️ ${file.target} already exists. Appending theme variables safely...`,
162
+ ),
124
163
  );
125
164
 
126
- // D. Safely check includes (This line can no longer crash!)
127
- if (
128
- !safeExistingContent.includes("--background:")
129
- ) {
130
- fs.appendFileSync(
165
+ try {
166
+ // C. Read the file and forcefully convert it to a String
167
+ const rawContent = fs.readFileSync(
131
168
  finalTargetPath,
132
- `\n/* React Apps UI Theme */\n${file.content || ""}`,
133
169
  "utf-8",
134
170
  );
171
+ const safeExistingContent = String(
172
+ rawContent || "",
173
+ );
174
+
175
+ // D. Safely check includes (This line can no longer crash!)
176
+ if (
177
+ !safeExistingContent.includes(
178
+ "--background:",
179
+ )
180
+ ) {
181
+ fs.appendFileSync(
182
+ finalTargetPath,
183
+ `\n/* React Apps UI Theme */\n${file.content || ""}`,
184
+ "utf-8",
185
+ );
186
+ }
187
+ } catch (err) {
188
+ console.log(
189
+ chalk.red(
190
+ ` ❌ Error reading or appending to ${safeTarget}`,
191
+ ),
192
+ );
135
193
  }
136
- } catch (err) {
194
+ } else {
137
195
  console.log(
138
- chalk.red(
139
- ` Error reading or appending to ${safeTarget}`,
196
+ chalk.yellow(
197
+ ` ⚠️ ${file.target} already exists. Skipping to prevent overwrite.`,
140
198
  ),
141
199
  );
142
200
  }
143
201
  } else {
144
- console.log(
145
- chalk.yellow(
146
- ` ⚠️ ${file.target} already exists. Skipping to prevent overwrite.`,
147
- ),
202
+ // File doesn't exist, safe to write normally
203
+ fs.writeFileSync(
204
+ finalTargetPath,
205
+ file.content,
206
+ "utf-8",
148
207
  );
208
+ console.log(chalk.green(` Created ${safeTarget}`));
149
209
  }
150
- } else {
151
- // File doesn't exist, safe to write normally
152
- fs.writeFileSync(finalTargetPath, file.content, "utf-8");
153
- console.log(chalk.green(` Created ${safeTarget}`));
154
210
  }
155
211
  }
156
212
 
213
+ // 5. INSTALL FOUNDATIONAL NPM DEPENDENCIES (Skipping already installed)
214
+ const missingBaseDeps = filterMissingDeps(setup.npm);
215
+
216
+ if (missingBaseDeps.length > 0) {
217
+ const depList = missingBaseDeps.join(" ");
218
+ console.log(
219
+ chalk.blue(
220
+ `\n📦 Installing missing foundational NPM dependencies: ${depList}...`,
221
+ ),
222
+ );
223
+ try {
224
+ execSync(`npm install ${depList} --legacy-peer-deps`, {
225
+ stdio: "inherit",
226
+ });
227
+ console.log(
228
+ chalk.green("✓ Dependencies installed successfully."),
229
+ );
230
+ } catch (err) {
231
+ console.log(
232
+ chalk.red(
233
+ "❌ Failed to install dependencies. You may need to install them manually.",
234
+ ),
235
+ );
236
+ }
237
+ } else {
238
+ console.log(
239
+ chalk.green(
240
+ "\n✓ All foundational NPM dependencies are already installed. Skipping.",
241
+ ),
242
+ );
243
+ }
244
+
157
245
  console.log(chalk.blue("\n🎉 Initialization complete!"));
158
246
  console.log(
159
247
  chalk.dim(
@@ -279,7 +367,7 @@ program
279
367
  }
280
368
  }
281
369
 
282
- // 5. INSTALL NPM DEPENDENCIES
370
+ // 5. INSTALL NPM DEPENDENCIES (Skipping already installed)
283
371
  const depsToInstall = new Set<string>();
284
372
 
285
373
  // Collect all dependencies from the components we just added
@@ -292,16 +380,19 @@ program
292
380
  }
293
381
  }
294
382
 
295
- if (depsToInstall.size > 0) {
296
- const depList = Array.from(depsToInstall).join(" ");
383
+ // Filter out anything already installed in user's package.json
384
+ const missingDeps = filterMissingDeps(Array.from(depsToInstall));
385
+ if (missingDeps.length > 0) {
386
+ const depList = missingDeps.join(" ");
297
387
  console.log(
298
388
  chalk.blue(
299
- `\n📦 Installing NPM dependencies: ${depList}...`,
389
+ `\n📦 Installing missing NPM dependencies: ${depList}...`,
300
390
  ),
301
391
  );
302
392
  try {
303
- // This runs 'npm install' directly in the user's terminal
304
- execSync(`npm install ${depList}`, { stdio: "inherit" });
393
+ execSync(`npm install ${depList} --legacy-peer-deps`, {
394
+ stdio: "inherit",
395
+ });
305
396
  console.log(
306
397
  chalk.green("✓ Dependencies installed successfully."),
307
398
  );
@@ -312,6 +403,12 @@ program
312
403
  ),
313
404
  );
314
405
  }
406
+ } else if (depsToInstall.size > 0) {
407
+ console.log(
408
+ chalk.green(
409
+ "\n✓ Required NPM dependencies are already installed. Skipping.",
410
+ ),
411
+ );
315
412
  }
316
413
 
317
414
  console.log(chalk.blue("\n🎉 Components installed successfully!"));