newcandies 0.1.4 → 0.1.6

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.
Files changed (2) hide show
  1. package/dist/index.js +161 -66
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -151,7 +151,8 @@ async function writeBaseline({ dest, name, withQuery }) {
151
151
  "react-native-worklets": "0.5.1",
152
152
  // Styling
153
153
  tailwindcss: "^4.1.16",
154
- uniwind: "^1.0.0"
154
+ uniwind: "^1.0.0",
155
+ "@expo/vector-icons": "latest"
155
156
  };
156
157
  if (withQuery) {
157
158
  baseDeps["@tanstack/react-query"] = "latest";
@@ -285,80 +286,184 @@ module.exports = withUniwindConfig(config, {
285
286
  `;
286
287
  await fs.writeFile(path.join(dest, "global.css"), globalCss);
287
288
  {
288
- const rootLayout = withQuery ? `import 'react-native-gesture-handler';
289
- import '../global.css';
290
- import { Slot } from 'expo-router';
291
- import { GestureHandlerRootView } from 'react-native-gesture-handler';
292
- import { SafeAreaProvider } from 'react-native-safe-area-context';
293
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
289
+ const rootLayout = withQuery ? `import FontAwesome from "@expo/vector-icons/FontAwesome";
290
+ import { useFonts } from "expo-font";
291
+ import { Stack } from "expo-router";
292
+ import * as SplashScreen from "expo-splash-screen";
293
+ import { useEffect } from "react";
294
+ import "react-native-reanimated";
295
+ import "../global.css";
296
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
297
+
298
+ export { ErrorBoundary } from "expo-router";
299
+
300
+ export const unstable_settings = {
301
+ initialRouteName: "(tabs)",
302
+ };
303
+
304
+ SplashScreen.preventAutoHideAsync();
294
305
 
295
306
  const queryClient = new QueryClient();
296
307
 
297
- const RootLayout = () => {
308
+ export default function RootLayout() {
309
+ const [loaded, error] = useFonts({
310
+ SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
311
+ ...FontAwesome.font,
312
+ });
313
+
314
+ useEffect(() => {
315
+ if (error) throw error;
316
+ }, [error]);
317
+
318
+ useEffect(() => {
319
+ if (loaded) {
320
+ SplashScreen.hideAsync();
321
+ }
322
+ }, [loaded]);
323
+
324
+ if (!loaded) {
325
+ return null;
326
+ }
327
+
298
328
  return (
299
- <GestureHandlerRootView style={{ flex: 1 }}>
300
- <SafeAreaProvider>
301
- <QueryClientProvider client={queryClient}>
302
- <Slot />
303
- </QueryClientProvider>
304
- </SafeAreaProvider>
305
- </GestureHandlerRootView>
329
+ <QueryClientProvider client={queryClient}>
330
+ <RootLayoutNav />
331
+ </QueryClientProvider>
306
332
  );
307
- };
308
-
309
- export default RootLayout;
310
- ` : `import 'react-native-gesture-handler';
311
- import '../global.css';
312
- import { Slot } from 'expo-router';
313
- import { GestureHandlerRootView } from 'react-native-gesture-handler';
314
- import { SafeAreaProvider } from 'react-native-safe-area-context';
333
+ }
315
334
 
316
- const RootLayout = () => {
335
+ function RootLayoutNav() {
317
336
  return (
318
- <GestureHandlerRootView style={{ flex: 1 }}>
319
- <SafeAreaProvider>
320
- <Slot />
321
- </SafeAreaProvider>
322
- </GestureHandlerRootView>
337
+ <Stack>
338
+ <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
339
+ <Stack.Screen name="modal" options={{ presentation: "modal" }} />
340
+ </Stack>
323
341
  );
342
+ }
343
+ ` : `import FontAwesome from "@expo/vector-icons/FontAwesome";
344
+ import { useFonts } from "expo-font";
345
+ import { Stack } from "expo-router";
346
+ import * as SplashScreen from "expo-splash-screen";
347
+ import { useEffect } from "react";
348
+ import "react-native-reanimated";
349
+ import "../global.css";
350
+
351
+ export { ErrorBoundary } from "expo-router";
352
+
353
+ export const unstable_settings = {
354
+ initialRouteName: "(tabs)",
324
355
  };
325
356
 
326
- export default RootLayout;
357
+ SplashScreen.preventAutoHideAsync();
358
+
359
+ export default function RootLayout() {
360
+ const [loaded, error] = useFonts({
361
+ SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
362
+ ...FontAwesome.font,
363
+ });
364
+
365
+ useEffect(() => {
366
+ if (error) throw error;
367
+ }, [error]);
368
+
369
+ useEffect(() => {
370
+ if (loaded) {
371
+ SplashScreen.hideAsync();
372
+ }
373
+ }, [loaded]);
374
+
375
+ if (!loaded) {
376
+ return null;
377
+ }
378
+
379
+ return <RootLayoutNav />;
380
+ }
381
+
382
+ function RootLayoutNav() {
383
+ return (
384
+ <Stack>
385
+ <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
386
+ <Stack.Screen name="modal" options={{ presentation: "modal" }} />
387
+ </Stack>
388
+ );
389
+ }
327
390
  `;
328
391
  await fs.writeFile(path.join(appDir, "_layout.tsx"), rootLayout);
329
392
  const tabsDir = path.join(appDir, "(tabs)");
330
393
  await fs.ensureDir(tabsDir);
331
- const layout = `import { Tabs } from 'expo-router';
394
+ const layout = `import React from 'react';
395
+ import FontAwesome from '@expo/vector-icons/FontAwesome';
396
+ import { Link, Tabs } from 'expo-router';
397
+ import { Pressable } from 'react-native';
332
398
 
333
- const TabsLayout = () => {
334
- return <Tabs screenOptions={{ headerShown: false }} />;
335
- };
399
+ function TabBarIcon(props: { name: React.ComponentProps<typeof FontAwesome>['name']; color: string; }) {
400
+ return <FontAwesome size={28} style={{ marginBottom: -3 }} {...props} />;
401
+ }
336
402
 
337
- export default TabsLayout;
403
+ export default function TabLayout() {
404
+ return (
405
+ <Tabs screenOptions={{ headerShown: true }}>
406
+ <Tabs.Screen
407
+ name="index"
408
+ options={{
409
+ title: 'Tab One',
410
+ tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
411
+ headerRight: () => (
412
+ <Link href="/modal" asChild>
413
+ <Pressable>
414
+ {({ pressed }) => (
415
+ <FontAwesome name="info-circle" size={25} color={"#1f2937"} style={{ marginRight: 15, opacity: pressed ? 0.5 : 1 }} />
416
+ )}
417
+ </Pressable>
418
+ </Link>
419
+ ),
420
+ }}
421
+ />
422
+ <Tabs.Screen
423
+ name="two"
424
+ options={{
425
+ title: 'Tab Two',
426
+ tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
427
+ }}
428
+ />
429
+ </Tabs>
430
+ );
431
+ }
338
432
  `;
339
433
  await fs.writeFile(path.join(tabsDir, "_layout.tsx"), layout);
340
- const home = `import { View, Text } from 'react-native';
434
+ const tabOne = `import { View, Text } from 'react-native';
341
435
 
342
- const Home = () => (
343
- <View className="flex-1 items-center justify-center bg-background">
344
- <Text className="text-foreground text-xl">Home Tab</Text>
345
- </View>
346
- );
347
-
348
- export default Home;
436
+ export default function Index() {
437
+ return (
438
+ <View className="flex-1 items-center justify-center bg-background">
439
+ <Text className="text-foreground text-xl">Tab One</Text>
440
+ </View>
441
+ );
442
+ }
349
443
  `;
350
- await fs.writeFile(path.join(tabsDir, "index.tsx"), home);
351
- const settings = `import { View, Text } from 'react-native';
444
+ await fs.writeFile(path.join(tabsDir, "index.tsx"), tabOne);
445
+ const tabTwo = `import { View, Text } from 'react-native';
352
446
 
353
- const Settings = () => (
354
- <View className="flex-1 items-center justify-center bg-background">
355
- <Text className="text-foreground text-xl">Settings Tab</Text>
356
- </View>
357
- );
447
+ export default function Two() {
448
+ return (
449
+ <View className="flex-1 items-center justify-center bg-background">
450
+ <Text className="text-foreground text-xl">Tab Two</Text>
451
+ </View>
452
+ );
453
+ }
454
+ `;
455
+ await fs.writeFile(path.join(tabsDir, "two.tsx"), tabTwo);
456
+ const modal = `import { View, Text } from 'react-native';
358
457
 
359
- export default Settings;
458
+ export default function Modal() {
459
+ return (
460
+ <View className="flex-1 items-center justify-center bg-background">
461
+ <Text className="text-foreground text-xl">Modal screen</Text>
462
+ </View>
463
+ );
464
+ }
360
465
  `;
361
- await fs.writeFile(path.join(tabsDir, "settings.tsx"), settings);
466
+ await fs.writeFile(path.join(appDir, "modal.tsx"), modal);
362
467
  }
363
468
  }
364
469
  async function applyTemplateOverlay({ dest, type, template, category, variant }) {
@@ -388,20 +493,10 @@ function resolveExtraDeps({ type, template, category, variant }) {
388
493
  const spec = key ? TEMPLATE_MAP[key] : void 0;
389
494
  return spec?.extraDeps ?? [];
390
495
  }
391
- async function installDeps(pm, cwd, extraDeps) {
392
- const base = [
393
- "expo",
394
- "expo-router",
395
- "react",
396
- "react-native",
397
- "react-native-reanimated",
398
- "react-native-gesture-handler",
399
- "react-native-safe-area-context",
400
- "react-native-screens",
401
- "tailwindcss",
402
- "uniwind"
403
- ];
404
- await execa("npx", ["expo", "install", ...base, ...extraDeps], { cwd, stdio: "inherit" });
496
+ async function installDeps(pm, cwd, _extraDeps) {
497
+ const cmd = pm === "bun" ? "bun" : pm;
498
+ const args = pm === "bun" ? ["install"] : ["install"];
499
+ await execa(cmd, args, { cwd, stdio: "inherit" });
405
500
  }
406
501
  main().catch((e) => {
407
502
  p.log.error(e?.message ?? String(e));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "newcandies",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Scaffold Expo Router + Uniwind React Native apps with layered templates.",
5
5
  "type": "module",
6
6
  "bin": {