newcandies 0.1.1 → 0.1.3

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/dist/index.js CHANGED
@@ -14,6 +14,9 @@ var TEMPLATE_MAP = {
14
14
  },
15
15
  "boilerplate/supersimplenotes": {
16
16
  extraDeps: ["@react-native-community/netinfo"]
17
+ },
18
+ "app-brief/react-query/sproutsy": {
19
+ extraDeps: ["@tanstack/react-query"]
17
20
  }
18
21
  };
19
22
  var TEMPLATES = {
@@ -32,7 +35,7 @@ var TEMPLATES = {
32
35
  "mini-app-brief": { categories: [{ value: "forms", label: "forms", variants: [{ value: "lite", label: "lite" }] }] },
33
36
  "default": [{ value: "default", label: "Default (Expo Router + Uniwind)" }]
34
37
  };
35
- var program = new Command().name("newcandies").option("-t, --type <type>").option("--template <name>").option("--category <name>").option("--variant <name>").option("-n, --navigator <navigator>", "stack|tabs", "tabs").option("-y, --yes").option("--pm <pm>", "npm|pnpm|yarn|bun").option("--no-install").parse(process.argv);
38
+ var program = new Command().name("newcandies").option("-t, --type <type>").option("--template <name>").option("--category <name>").option("--variant <name>").option("-y, --yes").option("--pm <pm>", "npm|pnpm|yarn|bun").option("--no-install").parse(process.argv);
36
39
  var opts = program.opts();
37
40
  async function main() {
38
41
  console.clear();
@@ -75,17 +78,6 @@ async function main() {
75
78
  const cat = cats.find((c) => c.value === results.category);
76
79
  return p.select({ message: "Pick variant", options: cat.variants });
77
80
  },
78
- navigator: async () => {
79
- if (opts.navigator) return opts.navigator;
80
- return p.select({
81
- message: "Navigator",
82
- options: [
83
- { value: "stack", label: "Stack" },
84
- { value: "tabs", label: "Tabs" }
85
- ],
86
- initialValue: "tabs"
87
- });
88
- },
89
81
  install: async () => {
90
82
  if (opts.yes !== void 0) return !!opts.yes;
91
83
  if (opts.install === false) return false;
@@ -112,7 +104,8 @@ async function main() {
112
104
  const s = p.spinner();
113
105
  s.start("Scaffolding");
114
106
  await fs.ensureDir(dest);
115
- await writeBaseline({ dest, name: project.name, navigator: project.navigator });
107
+ const withQuery = project.type === "app-brief" && project.category === "react-query" && project.variant === "sproutsy";
108
+ await writeBaseline({ dest, name: project.name, withQuery });
116
109
  await applyTemplateOverlay({ dest, type: project.type, template: project.template, category: project.category, variant: project.variant });
117
110
  s.stop("Files ready");
118
111
  const extraDeps = resolveExtraDeps({ type: project.type, template: project.template, category: project.category, variant: project.variant });
@@ -134,7 +127,35 @@ function TEMPLATESafe(type) {
134
127
  if (Array.isArray(t)) return t;
135
128
  return [{ value: "default", label: "Default (Expo Router + Uniwind)" }];
136
129
  }
137
- async function writeBaseline({ dest, name, navigator }) {
130
+ async function writeBaseline({ dest, name, withQuery }) {
131
+ const baseDeps = {
132
+ // Expo core + platform libs
133
+ expo: "latest",
134
+ "expo-constants": "~18.0.10",
135
+ "expo-font": "~14.0.9",
136
+ "expo-linking": "~8.0.8",
137
+ "expo-router": "~6.0.14",
138
+ "expo-splash-screen": "~31.0.10",
139
+ "expo-status-bar": "~3.0.8",
140
+ "expo-web-browser": "~15.0.9",
141
+ // React ecosystem
142
+ react: "19.1.0",
143
+ "react-dom": "19.1.0",
144
+ "react-native": "0.81.5",
145
+ "react-native-web": "~0.21.0",
146
+ // RN libs
147
+ "react-native-reanimated": "~4.1.1",
148
+ "react-native-gesture-handler": "latest",
149
+ "react-native-safe-area-context": "~5.6.0",
150
+ "react-native-screens": "~4.16.0",
151
+ "react-native-worklets": "0.5.1",
152
+ // Styling
153
+ tailwindcss: "^4.1.16",
154
+ uniwind: "^1.0.0"
155
+ };
156
+ if (withQuery) {
157
+ baseDeps["@tanstack/react-query"] = "latest";
158
+ }
138
159
  const pkg = {
139
160
  name,
140
161
  version: "0.0.0",
@@ -144,16 +165,54 @@ async function writeBaseline({ dest, name, navigator }) {
144
165
  start: "expo start",
145
166
  android: "expo run:android",
146
167
  ios: "expo run:ios"
168
+ },
169
+ dependencies: baseDeps,
170
+ devDependencies: {
171
+ "@types/react": "~19.1.0",
172
+ typescript: "~5.9.2"
147
173
  }
148
174
  };
149
175
  await fs.writeJSON(path.join(dest, "package.json"), pkg, { spaces: 2 });
176
+ const slug = String(name).toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
177
+ const pkgNameSegment = slug.replace(/-/g, "") || "app";
178
+ const bundleId = `com.example.${pkgNameSegment}`;
150
179
  const appJson = {
151
180
  expo: {
152
181
  name,
153
- slug: name,
154
- scheme: "newcandies",
182
+ slug,
183
+ version: "1.0.0",
184
+ orientation: "portrait",
185
+ icon: "./assets/images/icon.png",
186
+ scheme: slug,
187
+ userInterfaceStyle: "automatic",
188
+ newArchEnabled: true,
189
+ splash: {
190
+ image: "./assets/images/splash-icon.png",
191
+ resizeMode: "contain",
192
+ backgroundColor: "#ffffff"
193
+ },
194
+ ios: {
195
+ supportsTablet: true,
196
+ bundleIdentifier: bundleId
197
+ },
198
+ android: {
199
+ adaptiveIcon: {
200
+ foregroundImage: "./assets/images/adaptive-icon.png",
201
+ backgroundColor: "#ffffff"
202
+ },
203
+ edgeToEdgeEnabled: true,
204
+ predictiveBackGestureEnabled: false,
205
+ package: bundleId
206
+ },
207
+ web: {
208
+ bundler: "metro",
209
+ output: "static",
210
+ favicon: "./assets/images/favicon.png"
211
+ },
155
212
  plugins: ["expo-router"],
156
- experiments: { typedRoutes: true }
213
+ experiments: {
214
+ typedRoutes: true
215
+ }
157
216
  }
158
217
  };
159
218
  await fs.writeJSON(path.join(dest, "app.json"), appJson, { spaces: 2 });
@@ -193,6 +252,16 @@ module.exports = withUniwindConfig(config, {
193
252
  await fs.writeJSON(path.join(dest, "tsconfig.json"), tsconfig, { spaces: 2 });
194
253
  const appDir = path.join(dest, "app");
195
254
  await fs.ensureDir(appDir);
255
+ const easJson = {
256
+ cli: { version: ">= 7.0.0" },
257
+ build: {
258
+ development: { developmentClient: true, distribution: "internal" },
259
+ preview: { distribution: "internal" },
260
+ production: {}
261
+ },
262
+ submit: { production: {} }
263
+ };
264
+ await fs.writeJSON(path.join(dest, "eas.json"), easJson, { spaces: 2 });
196
265
  const globalCss = `@import 'tailwindcss';
197
266
  @import 'uniwind';
198
267
 
@@ -212,25 +281,56 @@ module.exports = withUniwindConfig(config, {
212
281
  }
213
282
  `;
214
283
  await fs.writeFile(path.join(appDir, "global.css"), globalCss);
215
- if (navigator === "tabs") {
216
- const tabsDir = path.join(appDir, "(tabs)");
217
- await fs.ensureDir(tabsDir);
218
- const layout = `import 'react-native-gesture-handler';
219
- import '../global.css';
220
- import { Tabs } from 'expo-router';
284
+ {
285
+ const rootLayout = withQuery ? `import 'react-native-gesture-handler';
286
+ import './global.css';
287
+ import { Slot } from 'expo-router';
221
288
  import { GestureHandlerRootView } from 'react-native-gesture-handler';
222
289
  import { SafeAreaProvider } from 'react-native-safe-area-context';
290
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
223
291
 
224
- const TabsLayout = () => {
292
+ const queryClient = new QueryClient();
293
+
294
+ const RootLayout = () => {
295
+ return (
296
+ <GestureHandlerRootView style={{ flex: 1 }}>
297
+ <SafeAreaProvider>
298
+ <QueryClientProvider client={queryClient}>
299
+ <Slot />
300
+ </QueryClientProvider>
301
+ </SafeAreaProvider>
302
+ </GestureHandlerRootView>
303
+ );
304
+ };
305
+
306
+ export default RootLayout;
307
+ ` : `import 'react-native-gesture-handler';
308
+ import './global.css';
309
+ import { Slot } from 'expo-router';
310
+ import { GestureHandlerRootView } from 'react-native-gesture-handler';
311
+ import { SafeAreaProvider } from 'react-native-safe-area-context';
312
+
313
+ const RootLayout = () => {
225
314
  return (
226
315
  <GestureHandlerRootView style={{ flex: 1 }}>
227
316
  <SafeAreaProvider>
228
- <Tabs screenOptions={{ headerShown: false }} />
317
+ <Slot />
229
318
  </SafeAreaProvider>
230
319
  </GestureHandlerRootView>
231
320
  );
232
321
  };
233
322
 
323
+ export default RootLayout;
324
+ `;
325
+ await fs.writeFile(path.join(appDir, "_layout.tsx"), rootLayout);
326
+ const tabsDir = path.join(appDir, "(tabs)");
327
+ await fs.ensureDir(tabsDir);
328
+ const layout = `import { Tabs } from 'expo-router';
329
+
330
+ const TabsLayout = () => {
331
+ return <Tabs screenOptions={{ headerShown: false }} />;
332
+ };
333
+
234
334
  export default TabsLayout;
235
335
  `;
236
336
  await fs.writeFile(path.join(tabsDir, "_layout.tsx"), layout);
@@ -256,43 +356,14 @@ const Settings = () => (
256
356
  export default Settings;
257
357
  `;
258
358
  await fs.writeFile(path.join(tabsDir, "settings.tsx"), settings);
259
- } else {
260
- const layout = `import 'react-native-gesture-handler';
261
- import './global.css';
262
- import { Stack } from 'expo-router';
263
- import { GestureHandlerRootView } from 'react-native-gesture-handler';
264
- import { SafeAreaProvider } from 'react-native-safe-area-context';
265
-
266
- const RootLayout = () => {
267
- return (
268
- <GestureHandlerRootView style={{ flex: 1 }}>
269
- <SafeAreaProvider>
270
- <Stack screenOptions={{ headerShown: false }} />
271
- </SafeAreaProvider>
272
- </GestureHandlerRootView>
273
- );
274
- };
275
-
276
- export default RootLayout;
277
- `;
278
- await fs.writeFile(path.join(appDir, "_layout.tsx"), layout);
279
- const index = `import { View, Text } from 'react-native';
280
-
281
- const Home = () => {
282
- return (
283
- <View className="flex-1 items-center justify-center bg-background">
284
- <Text className="text-foreground text-xl">Hello from Stack + Uniwind + Router</Text>
285
- </View>
286
- );
287
- };
288
-
289
- export default Home;
290
- `;
291
- await fs.writeFile(path.join(appDir, "index.tsx"), index);
292
359
  }
293
360
  }
294
361
  async function applyTemplateOverlay({ dest, type, template, category, variant }) {
295
362
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
363
+ const defaultSrc = path.join(__dirname, "..", "templates", "default");
364
+ if (await fs.pathExists(defaultSrc)) {
365
+ await fs.copy(defaultSrc, dest, { overwrite: false, errorOnExist: false });
366
+ }
296
367
  let src = null;
297
368
  if (type === "app-brief" || type === "mini-app-brief") {
298
369
  if (category && variant) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "newcandies",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Scaffold Expo Router + Uniwind React Native apps with layered templates.",
5
5
  "type": "module",
6
6
  "bin": {