expo-bbase 1.6.1 → 1.7.1

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
@@ -37,11 +37,12 @@ __export(src_exports, {
37
37
  });
38
38
  module.exports = __toCommonJS(src_exports);
39
39
  var import_chalk = __toESM(require("chalk"));
40
- var import_prompts = __toESM(require("prompts"));
40
+ var import_commander = require("commander");
41
+ var import_execa = require("execa");
42
+ var import_fs_extra2 = __toESM(require("fs-extra"));
41
43
  var import_ora = __toESM(require("ora"));
42
44
  var import_path2 = __toESM(require("path"));
43
- var import_fs_extra2 = __toESM(require("fs-extra"));
44
- var import_commander = require("commander");
45
+ var import_prompts = __toESM(require("prompts"));
45
46
 
46
47
  // src/commands/create.ts
47
48
  function registerCreateCommand(program) {
@@ -2527,19 +2528,6 @@ var uiReusablesModule = {
2527
2528
  },
2528
2529
  devDependencies: {},
2529
2530
  files: [
2530
- // ─── lib/utils.ts ────────────────────────────────────────────────────
2531
- {
2532
- path: "lib/utils.ts",
2533
- content: lines(
2534
- 'import { type ClassValue, clsx } from "clsx";',
2535
- 'import { twMerge } from "tailwind-merge";',
2536
- "",
2537
- "export function cn(...inputs: ClassValue[]) {",
2538
- " return twMerge(clsx(inputs));",
2539
- "}",
2540
- ""
2541
- )
2542
- },
2543
2531
  // ─── components/ui/text.tsx ──────────────────────────────────────────
2544
2532
  {
2545
2533
  path: "components/ui/text.tsx",
@@ -3152,8 +3140,8 @@ import { Stack } from "expo-router";
3152
3140
  import * as SplashScreen from "expo-splash-screen";
3153
3141
  import { useEffect } from "react";
3154
3142
  import { useColorScheme } from "react-native";
3155
-
3156
- import { Colors } from "@/constants/Colors";
3143
+ import { PortalHost } from "@rn-primitives/portal";
3144
+ import { NAV_THEME } from "@/lib/theme";
3157
3145
 
3158
3146
  SplashScreen.preventAutoHideAsync();
3159
3147
 
@@ -3174,11 +3162,12 @@ export default function RootLayout() {
3174
3162
  }
3175
3163
 
3176
3164
  return (
3177
- <ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
3165
+ <ThemeProvider value={colorScheme === "dark" ? NAV_THEME.dark : NAV_THEME.light}>
3178
3166
  <Stack>
3179
3167
  <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
3180
3168
  <Stack.Screen name="+not-found" />
3181
3169
  </Stack>
3170
+ <PortalHost />
3182
3171
  </ThemeProvider>
3183
3172
  );
3184
3173
  }
@@ -3190,19 +3179,10 @@ export default function RootLayout() {
3190
3179
  content: `import { Tabs } from "expo-router";
3191
3180
  import { Platform } from "react-native";
3192
3181
 
3193
- import { Colors } from "@/constants/Colors";
3194
- import { useColorScheme } from "@/hooks/useColorScheme";
3195
-
3196
3182
  export default function TabLayout() {
3197
- const colorScheme = useColorScheme();
3198
-
3199
3183
  return (
3200
3184
  <Tabs
3201
3185
  screenOptions={{
3202
- tabBarActiveTintColor: Colors[colorScheme ?? "light"].tint,
3203
- headerStyle: {
3204
- backgroundColor: Colors[colorScheme ?? "light"].background,
3205
- },
3206
3186
  headerShadowVisible: false,
3207
3187
  tabBarStyle: Platform.select({
3208
3188
  ios: {
@@ -3216,14 +3196,14 @@ export default function TabLayout() {
3216
3196
  name="index"
3217
3197
  options={{
3218
3198
  title: "Home",
3219
- tabBarIcon: () => null,
3199
+ tabBarIcon: ({ color }) => <IconSymbol size={28} name="house.fill" color={color} />,
3220
3200
  }}
3221
3201
  />
3222
3202
  <Tabs.Screen
3223
3203
  name="explore"
3224
3204
  options={{
3225
3205
  title: "Explore",
3226
- tabBarIcon: () => null,
3206
+ tabBarIcon: ({ color }) => <IconSymbol size={28} name="paperplane.fill" color={color} />,
3227
3207
  }}
3228
3208
  />
3229
3209
  </Tabs>
@@ -3234,258 +3214,152 @@ export default function TabLayout() {
3234
3214
  // ─── app/(tabs)/index.tsx ───────────────────────────────────────────
3235
3215
  {
3236
3216
  path: "app/(tabs)/index.tsx",
3237
- content: `import { Image, StyleSheet, Platform } from "react-native";
3238
- import { HelloWave } from "@/components/HelloWave";
3239
- import { ThemedText } from "@/components/Themed";
3240
- import { ThemedView } from "@/components/Themed";
3241
- import { Link } from "expo-router";
3217
+ content: `import { Text, View } from "react-native";
3242
3218
 
3243
3219
  export default function HomeScreen() {
3244
3220
  return (
3245
- <ThemedView style={styles.container}>
3246
- <ThemedView style={styles.titleContainer}>
3247
- <ThemedText type="title">${projectName}</ThemedText>
3248
- <HelloWave />
3249
- </ThemedView>
3250
- <ThemedView style={styles.stepContainer}>
3251
- <ThemedText type="subtitle">Step 1: Try it</ThemedText>
3252
- <ThemedText>
3253
- Edit <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> to see changes.
3254
- Press{" "}
3255
- <ThemedText type="defaultSemiBold">
3256
- {Platform.select({ ios: "cmd + d", android: "cmd + m" })}
3257
- </ThemedText>{" "}
3258
- to open developer tools.
3259
- </ThemedText>
3260
- </ThemedView>
3261
- <ThemedView style={styles.stepContainer}>
3262
- <ThemedText type="subtitle">Step 2: Explore</ThemedText>
3263
- <ThemedText>
3264
- Tap the Explore tab to learn more about what's included in this starter.
3265
- </ThemedText>
3266
- <Link href="/explore">
3267
- <ThemedText type="link">Go to Explore \u2192</ThemedText>
3268
- </Link>
3269
- </ThemedView>
3270
- </ThemedView>
3221
+ <View className="flex-1 items-center justify-center p-6">
3222
+ <Text className="text-foreground text-2xl font-bold">${projectName}</Text>
3223
+ <Text className="text-muted-foreground mt-2">Welcome to your new app</Text>
3224
+ </View>
3271
3225
  );
3272
3226
  }
3273
-
3274
- const styles = StyleSheet.create({
3275
- container: {
3276
- flex: 1,
3277
- alignItems: "center",
3278
- justifyContent: "center",
3279
- },
3280
- titleContainer: {
3281
- flexDirection: "row",
3282
- alignItems: "center",
3283
- gap: 8,
3284
- },
3285
- stepContainer: {
3286
- gap: 8,
3287
- marginBottom: 8,
3288
- },
3289
- });
3290
3227
  `
3291
3228
  },
3292
3229
  // ─── app/(tabs)/explore.tsx ─────────────────────────────────────────
3293
3230
  {
3294
3231
  path: "app/(tabs)/explore.tsx",
3295
- content: `import { StyleSheet, Image, Platform } from "react-native";
3296
- import { ThemedText } from "@/components/Themed";
3297
- import { ThemedView } from "@/components/Themed";
3232
+ content: `import { Text, View } from "react-native";
3298
3233
 
3299
3234
  export default function ExploreScreen() {
3300
3235
  return (
3301
- <ThemedView style={styles.container}>
3302
- <ThemedText type="title">Explore</ThemedText>
3303
- <ThemedText style={styles.subtitle}>
3304
- This screen shows what you can do with this scaffolded project.
3305
- </ThemedText>
3306
- </ThemedView>
3236
+ <View className="flex-1 items-center justify-center p-6">
3237
+ <Text className="text-foreground text-2xl font-bold">Explore</Text>
3238
+ <Text className="text-muted-foreground mt-2">Discover new features</Text>
3239
+ </View>
3307
3240
  );
3308
3241
  }
3309
-
3310
- const styles = StyleSheet.create({
3311
- container: {
3312
- flex: 1,
3313
- alignItems: "center",
3314
- justifyContent: "center",
3315
- },
3316
- subtitle: {
3317
- fontSize: 16,
3318
- textAlign: "center",
3319
- marginTop: 8,
3320
- },
3321
- });
3322
3242
  `
3323
3243
  },
3324
3244
  // ─── app/+not-found.tsx ─────────────────────────────────────────────
3325
3245
  {
3326
3246
  path: "app/+not-found.tsx",
3327
3247
  content: `import { Link, Stack } from "expo-router";
3328
- import { StyleSheet } from "react-native";
3329
- import { ThemedText } from "@/components/Themed";
3330
- import { ThemedView } from "@/components/Themed";
3248
+ import { Text, View } from "react-native";
3331
3249
 
3332
3250
  export default function NotFoundScreen() {
3333
3251
  return (
3334
3252
  <>
3335
3253
  <Stack.Screen options={{ title: "Oops!" }} />
3336
- <ThemedView style={styles.container}>
3337
- <ThemedText type="title">This screen doesn't exist.</ThemedText>
3338
- <Link href="/" style={styles.link}>
3339
- <ThemedText type="link">Go to home screen!</ThemedText>
3254
+ <View className="flex-1 items-center justify-center p-5">
3255
+ <Text className="text-foreground text-2xl font-bold">This screen doesn't exist.</Text>
3256
+ <Link href="/" className="mt-4 py-4">
3257
+ <Text className="text-primary underline">Go to home screen!</Text>
3340
3258
  </Link>
3341
- </ThemedView>
3259
+ </View>
3342
3260
  </>
3343
3261
  );
3344
3262
  }
3345
-
3346
- const styles = StyleSheet.create({
3347
- container: {
3348
- flex: 1,
3349
- alignItems: "center",
3350
- justifyContent: "center",
3351
- padding: 20,
3352
- },
3353
- link: {
3354
- marginTop: 15,
3355
- paddingVertical: 15,
3356
- },
3357
- });
3358
3263
  `
3359
3264
  },
3360
- // ─── src/components/Themed.tsx ───────────────────────────────────────
3265
+ // ─── lib/utils.ts (rnr official cn helper) ───────────────────────────
3361
3266
  {
3362
- path: "components/Themed.tsx",
3363
- content: `import { Text, type TextProps, View, type ViewProps } from "react-native";
3364
- import { useColorScheme } from "@/hooks/useColorScheme";
3365
- import { Colors } from "@/constants/Colors";
3366
-
3367
- /** Themed text component that adapts to light/dark mode */
3368
- export function ThemedText({
3369
- style,
3370
- type = "default",
3371
- ...rest
3372
- }: TextProps & { type?: "default" | "title" | "defaultSemiBold" | "subtitle" | "link" }) {
3373
- const colorScheme = useColorScheme();
3374
- const color = Colors[colorScheme ?? "light"].text;
3375
-
3376
- return (
3377
- <Text
3378
- style={[
3379
- { color },
3380
- type === "default" ? { fontSize: 16, lineHeight: 24 } : undefined,
3381
- type === "title" ? { fontSize: 28, fontWeight: "bold", lineHeight: 32 } : undefined,
3382
- type === "defaultSemiBold" ? { fontSize: 16, lineHeight: 24, fontWeight: "600" } : undefined,
3383
- type === "subtitle" ? { fontSize: 20, fontWeight: "bold" } : undefined,
3384
- type === "link" ? { fontSize: 16, lineHeight: 24, color: Colors[colorScheme ?? "light"].tint } : undefined,
3385
- style,
3386
- ]}
3387
- {...rest}
3388
- />
3389
- );
3390
- }
3391
-
3392
- /** Themed view component that adapts to light/dark mode */
3393
- export function ThemedView({ style, ...rest }: ViewProps) {
3394
- const colorScheme = useColorScheme();
3395
- const backgroundColor = Colors[colorScheme ?? "light"].background;
3267
+ path: "lib/utils.ts",
3268
+ content: `import { clsx, type ClassValue } from "clsx";
3269
+ import { twMerge } from "tailwind-merge";
3396
3270
 
3397
- return <View style={[{ backgroundColor }, style]} {...rest} />;
3271
+ export function cn(...inputs: ClassValue[]) {
3272
+ return twMerge(clsx(inputs));
3398
3273
  }
3399
3274
  `
3400
3275
  },
3401
- // ─── src/components/HelloWave.tsx ────────────────────────────────────
3276
+ // ─── lib/theme.ts (rnr official theme) ───────────────────────────────
3402
3277
  {
3403
- path: "components/HelloWave.tsx",
3404
- content: `import { useEffect } from "react";
3405
- import { Animated, Easing } from "react-native";
3406
- import { ThemedText } from "./Themed";
3407
-
3408
- export function HelloWave() {
3409
- const rotationAnim = new Animated.Value(0);
3410
-
3411
- useEffect(() => {
3412
- Animated.loop(
3413
- Animated.sequence([
3414
- Animated.timing(rotationAnim, {
3415
- toValue: 1,
3416
- duration: 150,
3417
- easing: Easing.linear,
3418
- useNativeDriver: true,
3419
- }),
3420
- Animated.timing(rotationAnim, {
3421
- toValue: 0,
3422
- duration: 150,
3423
- easing: Easing.linear,
3424
- useNativeDriver: true,
3425
- }),
3426
- ])
3427
- ).start();
3428
- }, [rotationAnim]);
3278
+ path: "lib/theme.ts",
3279
+ content: `import { DarkTheme, DefaultTheme, type Theme } from '@react-navigation/native';
3429
3280
 
3430
- return (
3431
- <Animated.View
3432
- style={{
3433
- transform: [
3434
- {
3435
- rotate: rotationAnim.interpolate({
3436
- inputRange: [0, 1],
3437
- outputRange: ["0deg", "14deg"],
3438
- }),
3439
- },
3440
- ],
3441
- }}
3442
- >
3443
- <ThemedText style={{ fontSize: 28 }}>\u{1F44B}</ThemedText>
3444
- </Animated.View>
3445
- );
3446
- }
3447
- `
3448
- },
3449
- // ─── src/hooks/useColorScheme.ts ─────────────────────────────────────
3450
- {
3451
- path: "hooks/useColorScheme.ts",
3452
- content: `import { useColorScheme as useRNColorScheme } from "react-native";
3281
+ export const THEME = {
3282
+ light: {
3283
+ background: 'hsl(0 0% 100%)',
3284
+ foreground: 'hsl(0 0% 3.9%)',
3285
+ card: 'hsl(0 0% 100%)',
3286
+ cardForeground: 'hsl(0 0% 3.9%)',
3287
+ popover: 'hsl(0 0% 100%)',
3288
+ popoverForeground: 'hsl(0 0% 3.9%)',
3289
+ primary: 'hsl(0 0% 9%)',
3290
+ primaryForeground: 'hsl(0 0% 98%)',
3291
+ secondary: 'hsl(0 0% 96.1%)',
3292
+ secondaryForeground: 'hsl(0 0% 9%)',
3293
+ muted: 'hsl(0 0% 96.1%)',
3294
+ mutedForeground: 'hsl(0 0% 45.1%)',
3295
+ accent: 'hsl(0 0% 96.1%)',
3296
+ accentForeground: 'hsl(0 0% 9%)',
3297
+ destructive: 'hsl(0 84.2% 60.2%)',
3298
+ border: 'hsl(0 0% 89.8%)',
3299
+ input: 'hsl(0 0% 89.8%)',
3300
+ ring: 'hsl(0 0% 63%)',
3301
+ radius: '0.625rem',
3302
+ chart1: 'hsl(12 76% 61%)',
3303
+ chart2: 'hsl(173 58% 39%)',
3304
+ chart3: 'hsl(197 37% 24%)',
3305
+ chart4: 'hsl(43 74% 66%)',
3306
+ chart5: 'hsl(27 87% 67%)',
3307
+ },
3308
+ dark: {
3309
+ background: 'hsl(0 0% 3.9%)',
3310
+ foreground: 'hsl(0 0% 98%)',
3311
+ card: 'hsl(0 0% 3.9%)',
3312
+ cardForeground: 'hsl(0 0% 98%)',
3313
+ popover: 'hsl(0 0% 3.9%)',
3314
+ popoverForeground: 'hsl(0 0% 98%)',
3315
+ primary: 'hsl(0 0% 98%)',
3316
+ primaryForeground: 'hsl(0 0% 9%)',
3317
+ secondary: 'hsl(0 0% 14.9%)',
3318
+ secondaryForeground: 'hsl(0 0% 98%)',
3319
+ muted: 'hsl(0 0% 14.9%)',
3320
+ mutedForeground: 'hsl(0 0% 63.9%)',
3321
+ accent: 'hsl(0 0% 14.9%)',
3322
+ accentForeground: 'hsl(0 0% 98%)',
3323
+ destructive: 'hsl(0 70.9% 59.4%)',
3324
+ border: 'hsl(0 0% 14.9%)',
3325
+ input: 'hsl(0 0% 14.9%)',
3326
+ ring: 'hsl(300 0% 45%)',
3327
+ radius: '0.625rem',
3328
+ chart1: 'hsl(220 70% 50%)',
3329
+ chart2: 'hsl(160 60% 45%)',
3330
+ chart3: 'hsl(30 80% 55%)',
3331
+ chart4: 'hsl(280 65% 60%)',
3332
+ chart5: 'hsl(340 75% 55%)',
3333
+ },
3334
+ };
3453
3335
 
3454
- /**
3455
- * Returns the current color scheme (light or dark).
3456
- * Defaults to "light" if the system preference is not available.
3457
- */
3458
- export function useColorScheme(): "light" | "dark" {
3459
- return useRNColorScheme() ?? "light";
3460
- }
3461
- `
3462
- },
3463
- // ─── src/constants/Colors.ts ─────────────────────────────────────────
3464
- {
3465
- path: "constants/Colors.ts",
3466
- content: `/**
3467
- * Color tokens for light and dark themes.
3468
- * Used by Themed components and navigation theming.
3469
- */
3470
- export const Colors = {
3336
+ export const NAV_THEME: Record<'light' | 'dark', Theme> = {
3471
3337
  light: {
3472
- text: "#11181C",
3473
- background: "#fff",
3474
- tint: "#0a7ea4",
3475
- tabIconDefault: "#687076",
3476
- tabIconSelected: "#0a7ea4",
3338
+ ...DefaultTheme,
3339
+ colors: {
3340
+ background: THEME.light.background,
3341
+ border: THEME.light.border,
3342
+ card: THEME.light.card,
3343
+ notification: THEME.light.destructive,
3344
+ primary: THEME.light.primary,
3345
+ text: THEME.light.foreground,
3346
+ },
3477
3347
  },
3478
3348
  dark: {
3479
- text: "#ECEDEE",
3480
- background: "#151718",
3481
- tint: "#fff",
3482
- tabIconDefault: "#9BA1A6",
3483
- tabIconSelected: "#fff",
3349
+ ...DarkTheme,
3350
+ colors: {
3351
+ background: THEME.dark.background,
3352
+ border: THEME.dark.border,
3353
+ card: THEME.dark.card,
3354
+ notification: THEME.dark.destructive,
3355
+ primary: THEME.dark.primary,
3356
+ text: THEME.dark.foreground,
3357
+ },
3484
3358
  },
3485
3359
  };
3486
3360
  `
3487
3361
  },
3488
- // ─── src/types/index.ts ─────────────────────────────────────────────
3362
+ // ─── types/index.ts ─────────────────────────────────────────────────
3489
3363
  {
3490
3364
  path: "types/index.ts",
3491
3365
  content: `/** Global type definitions */
@@ -3551,61 +3425,109 @@ export {};
3551
3425
  }
3552
3426
  `
3553
3427
  },
3554
- // ─── tailwind.config.js ──────────────────────────────────────────────
3428
+ // ─── components.json (rnr CLI compatibility) ─────────────────────────
3429
+ {
3430
+ path: "components.json",
3431
+ content: `{
3432
+ "$schema": "https://ui.shadcn.com/schema.json",
3433
+ "style": "new-york",
3434
+ "rsc": false,
3435
+ "tsx": true,
3436
+ "tailwind": {
3437
+ "config": "tailwind.config.js",
3438
+ "css": "global.css",
3439
+ "baseColor": "neutral",
3440
+ "cssVariables": true
3441
+ },
3442
+ "aliases": {
3443
+ "components": "@/components",
3444
+ "utils": "@/lib/utils",
3445
+ "ui": "@/components/ui",
3446
+ "lib": "@/lib",
3447
+ "hooks": "@/hooks"
3448
+ }
3449
+ }
3450
+ `
3451
+ },
3452
+ // ─── tailwind.config.js (rnr official) ──────────────────────────────
3555
3453
  {
3556
3454
  path: "tailwind.config.js",
3557
- content: `/** @type {import('tailwindcss').Config} */
3455
+ content: `const { hairlineWidth } = require('nativewind/theme');
3456
+
3457
+ /** @type {import('tailwindcss').Config} */
3558
3458
  module.exports = {
3559
- content: [
3560
- "./app/**/*.{js,jsx,ts,tsx}",
3561
- "./components/**/*.{js,jsx,ts,tsx}",
3562
- "./modules/**/*.{js,jsx,ts,tsx}",
3563
- ],
3564
- presets: [require("nativewind/preset")],
3459
+ darkMode: 'class',
3460
+ content: ['./app/**/*.{ts,tsx}', './components/**/*.{ts,tsx}'],
3461
+ presets: [require('nativewind/preset')],
3565
3462
  theme: {
3566
3463
  extend: {
3567
3464
  colors: {
3568
- border: "hsl(var(--border))",
3569
- input: "hsl(var(--input))",
3570
- ring: "hsl(var(--ring))",
3571
- background: "hsl(var(--background))",
3572
- foreground: "hsl(var(--foreground))",
3465
+ border: 'hsl(var(--border))',
3466
+ input: 'hsl(var(--input))',
3467
+ ring: 'hsl(var(--ring))',
3468
+ background: 'hsl(var(--background))',
3469
+ foreground: 'hsl(var(--foreground))',
3573
3470
  primary: {
3574
- DEFAULT: "hsl(var(--primary))",
3575
- foreground: "hsl(var(--primary-foreground))",
3471
+ DEFAULT: 'hsl(var(--primary))',
3472
+ foreground: 'hsl(var(--primary-foreground))',
3576
3473
  },
3577
3474
  secondary: {
3578
- DEFAULT: "hsl(var(--secondary))",
3579
- foreground: "hsl(var(--secondary-foreground))",
3475
+ DEFAULT: 'hsl(var(--secondary))',
3476
+ foreground: 'hsl(var(--secondary-foreground))',
3580
3477
  },
3581
3478
  destructive: {
3582
- DEFAULT: "hsl(var(--destructive))",
3583
- foreground: "hsl(var(--destructive-foreground))",
3479
+ DEFAULT: 'hsl(var(--destructive))',
3480
+ foreground: 'hsl(var(--destructive-foreground))',
3584
3481
  },
3585
3482
  muted: {
3586
- DEFAULT: "hsl(var(--muted))",
3587
- foreground: "hsl(var(--muted-foreground))",
3483
+ DEFAULT: 'hsl(var(--muted))',
3484
+ foreground: 'hsl(var(--muted-foreground))',
3588
3485
  },
3589
3486
  accent: {
3590
- DEFAULT: "hsl(var(--accent))",
3591
- foreground: "hsl(var(--accent-foreground))",
3487
+ DEFAULT: 'hsl(var(--accent))',
3488
+ foreground: 'hsl(var(--accent-foreground))',
3592
3489
  },
3593
3490
  popover: {
3594
- DEFAULT: "hsl(var(--popover))",
3595
- foreground: "hsl(var(--popover-foreground))",
3491
+ DEFAULT: 'hsl(var(--popover))',
3492
+ foreground: 'hsl(var(--popover-foreground))',
3596
3493
  },
3597
3494
  card: {
3598
- DEFAULT: "hsl(var(--card))",
3599
- foreground: "hsl(var(--card-foreground))",
3495
+ DEFAULT: 'hsl(var(--card))',
3496
+ foreground: 'hsl(var(--card-foreground))',
3600
3497
  },
3601
3498
  },
3499
+ borderRadius: {
3500
+ lg: 'var(--radius)',
3501
+ md: 'calc(var(--radius) - 2px)',
3502
+ sm: 'calc(var(--radius) - 4px)',
3503
+ },
3504
+ borderWidth: {
3505
+ hairline: hairlineWidth(),
3506
+ },
3507
+ keyframes: {
3508
+ 'accordion-down': {
3509
+ from: { height: '0' },
3510
+ to: { height: 'var(--radix-accordion-content-height)' },
3511
+ },
3512
+ 'accordion-up': {
3513
+ from: { height: 'var(--radix-accordion-content-height)' },
3514
+ to: { height: '0' },
3515
+ },
3516
+ },
3517
+ animation: {
3518
+ 'accordion-down': 'accordion-down 0.2s ease-out',
3519
+ 'accordion-up': 'accordion-up 0.2s ease-out',
3520
+ },
3602
3521
  },
3603
3522
  },
3604
- plugins: [],
3523
+ future: {
3524
+ hoverOnlyWhenSupported: true,
3525
+ },
3526
+ plugins: [require('tailwindcss-animate')],
3605
3527
  };
3606
3528
  `
3607
3529
  },
3608
- // ─── metro.config.js ─────────────────────────────────────────────────
3530
+ // ─── metro.config.js (rnr official: inlineRem: 16) ──────────────────
3609
3531
  {
3610
3532
  path: "metro.config.js",
3611
3533
  content: `const { getDefaultConfig } = require("expo/metro-config");
@@ -3613,7 +3535,7 @@ const { withNativeWind } = require("nativewind/metro");
3613
3535
 
3614
3536
  const config = getDefaultConfig(__dirname);
3615
3537
 
3616
- module.exports = withNativeWind(config, { input: "./global.css" });
3538
+ module.exports = withNativeWind(config, { input: "./global.css", inlineRem: 16 });
3617
3539
  `
3618
3540
  },
3619
3541
  // ─── babel.config.js ─────────────────────────────────────────────────
@@ -3631,7 +3553,7 @@ module.exports = withNativeWind(config, { input: "./global.css" });
3631
3553
  };
3632
3554
  `
3633
3555
  },
3634
- // ─── global.css (NativeWind CSS variables for rnr components) ─────────
3556
+ // ─── global.css (rnr official CSS variables) ─────────────────────────
3635
3557
  {
3636
3558
  path: "global.css",
3637
3559
  content: `@tailwind base;
@@ -3641,46 +3563,55 @@ module.exports = withNativeWind(config, { input: "./global.css" });
3641
3563
  @layer base {
3642
3564
  :root {
3643
3565
  --background: 0 0% 100%;
3644
- --foreground: 240 10% 3.9%;
3566
+ --foreground: 0 0% 3.9%;
3645
3567
  --card: 0 0% 100%;
3646
- --card-foreground: 240 10% 3.9%;
3568
+ --card-foreground: 0 0% 3.9%;
3647
3569
  --popover: 0 0% 100%;
3648
- --popover-foreground: 240 10% 3.9%;
3649
- --primary: 240 5.9% 10%;
3570
+ --popover-foreground: 0 0% 3.9%;
3571
+ --primary: 0 0% 9%;
3650
3572
  --primary-foreground: 0 0% 98%;
3651
- --secondary: 240 4.8% 95.9%;
3652
- --secondary-foreground: 240 5.9% 10%;
3653
- --muted: 240 4.8% 95.9%;
3654
- --muted-foreground: 240 3.8% 46.1%;
3655
- --accent: 240 4.8% 95.9%;
3656
- --accent-foreground: 240 5.9% 10%;
3573
+ --secondary: 0 0% 96.1%;
3574
+ --secondary-foreground: 0 0% 9%;
3575
+ --muted: 0 0% 96.1%;
3576
+ --muted-foreground: 0 0% 45.1%;
3577
+ --accent: 0 0% 96.1%;
3578
+ --accent-foreground: 0 0% 9%;
3657
3579
  --destructive: 0 84.2% 60.2%;
3658
- --destructive-foreground: 0 0% 98%;
3659
- --border: 240 5.9% 90%;
3660
- --input: 240 5.9% 90%;
3661
- --ring: 240 5.9% 10%;
3580
+ --border: 0 0% 89.8%;
3581
+ --input: 0 0% 89.8%;
3582
+ --ring: 0 0% 63%;
3583
+ --radius: 0.625rem;
3584
+ --chart-1: 12 76% 61%;
3585
+ --chart-2: 173 58% 39%;
3586
+ --chart-3: 197 37% 24%;
3587
+ --chart-4: 43 74% 66%;
3588
+ --chart-5: 27 87% 67%;
3662
3589
  }
3663
3590
 
3664
- .dark {
3665
- --background: 240 10% 3.9%;
3591
+ .dark:root {
3592
+ --background: 0 0% 3.9%;
3666
3593
  --foreground: 0 0% 98%;
3667
- --card: 240 10% 3.9%;
3594
+ --card: 0 0% 3.9%;
3668
3595
  --card-foreground: 0 0% 98%;
3669
- --popover: 240 10% 3.9%;
3596
+ --popover: 0 0% 3.9%;
3670
3597
  --popover-foreground: 0 0% 98%;
3671
3598
  --primary: 0 0% 98%;
3672
- --primary-foreground: 240 5.9% 10%;
3673
- --secondary: 240 3.7% 15.9%;
3599
+ --primary-foreground: 0 0% 9%;
3600
+ --secondary: 0 0% 14.9%;
3674
3601
  --secondary-foreground: 0 0% 98%;
3675
- --muted: 240 3.7% 15.9%;
3676
- --muted-foreground: 240 5% 64.9%;
3677
- --accent: 240 3.7% 15.9%;
3602
+ --muted: 0 0% 14.9%;
3603
+ --muted-foreground: 0 0% 63.9%;
3604
+ --accent: 0 0% 14.9%;
3678
3605
  --accent-foreground: 0 0% 98%;
3679
- --destructive: 0 62.8% 30.6%;
3680
- --destructive-foreground: 0 0% 98%;
3681
- --border: 240 3.7% 15.9%;
3682
- --input: 240 3.7% 15.9%;
3683
- --ring: 240 4.9% 83.9%;
3606
+ --destructive: 0 70.9% 59.4%;
3607
+ --border: 0 0% 14.9%;
3608
+ --input: 0 0% 14.9%;
3609
+ --ring: 300 0% 45%;
3610
+ --chart-1: 220 70% 50%;
3611
+ --chart-2: 160 60% 45%;
3612
+ --chart-3: 30 80% 55%;
3613
+ --chart-4: 280 65% 60%;
3614
+ --chart-5: 340 75% 55%;
3684
3615
  }
3685
3616
  }
3686
3617
  `
@@ -3738,14 +3669,15 @@ function generateLoginTabsTemplates(projectName) {
3738
3669
  {
3739
3670
  path: "app/_layout.tsx",
3740
3671
  content: lines(
3672
+ 'import "../global.css";',
3741
3673
  'import { DarkTheme, DefaultTheme, ThemeProvider } from "@react-navigation/native";',
3742
3674
  'import { useFonts } from "expo-font";',
3743
3675
  'import { Stack } from "expo-router";',
3744
3676
  'import * as SplashScreen from "expo-splash-screen";',
3745
3677
  'import { useEffect } from "react";',
3746
3678
  'import { useColorScheme } from "react-native";',
3747
- "",
3748
- 'import { Colors } from "@/constants/Colors";',
3679
+ 'import { PortalHost } from "@rn-primitives/portal";',
3680
+ 'import { NAV_THEME } from "@/lib/theme";',
3749
3681
  "",
3750
3682
  "SplashScreen.preventAutoHideAsync();",
3751
3683
  "",
@@ -3766,12 +3698,13 @@ function generateLoginTabsTemplates(projectName) {
3766
3698
  " }",
3767
3699
  "",
3768
3700
  " return (",
3769
- ' <ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>',
3701
+ ' <ThemeProvider value={colorScheme === "dark" ? NAV_THEME.dark : NAV_THEME.light}>',
3770
3702
  " <Stack>",
3771
3703
  ' <Stack.Screen name="login" options={{ headerShown: false }} />',
3772
3704
  ' <Stack.Screen name="(tabs)" options={{ headerShown: false }} />',
3773
3705
  ' <Stack.Screen name="+not-found" />',
3774
3706
  " </Stack>",
3707
+ " <PortalHost />",
3775
3708
  " </ThemeProvider>",
3776
3709
  " );",
3777
3710
  "}",
@@ -3802,19 +3735,10 @@ function generateLoginTabsTemplates(projectName) {
3802
3735
  'import { Tabs } from "expo-router";',
3803
3736
  'import { Platform } from "react-native";',
3804
3737
  "",
3805
- 'import { Colors } from "@/constants/Colors";',
3806
- 'import { useColorScheme } from "@/hooks/useColorScheme";',
3807
- "",
3808
3738
  "export default function TabLayout() {",
3809
- " const colorScheme = useColorScheme();",
3810
- "",
3811
3739
  " return (",
3812
3740
  " <Tabs",
3813
3741
  " screenOptions={{",
3814
- ' tabBarActiveTintColor: Colors[colorScheme ?? "light"].tint,',
3815
- " headerStyle: {",
3816
- ' backgroundColor: Colors[colorScheme ?? "light"].background,',
3817
- " },",
3818
3742
  " headerShadowVisible: false,",
3819
3743
  " tabBarStyle: Platform.select({",
3820
3744
  " ios: {",
@@ -3825,24 +3749,24 @@ function generateLoginTabsTemplates(projectName) {
3825
3749
  " }}",
3826
3750
  " >",
3827
3751
  " <Tabs.Screen",
3828
- ' name="home"',
3752
+ ' name="index"',
3829
3753
  " options={{",
3830
3754
  ' title: "Home",',
3831
- " tabBarIcon: () => null,",
3755
+ ' tabBarIcon: ({ color }) => <IconSymbol size={28} name="house.fill" color={color} />,',
3832
3756
  " }}",
3833
3757
  " />",
3834
3758
  " <Tabs.Screen",
3835
- ' name="list"',
3759
+ ' name="explore"',
3836
3760
  " options={{",
3837
- ' title: "List",',
3838
- " tabBarIcon: () => null,",
3761
+ ' title: "Explore",',
3762
+ ' tabBarIcon: ({ color }) => <IconSymbol size={28} name="paperplane.fill" color={color} />',
3839
3763
  " }}",
3840
3764
  " />",
3841
3765
  " <Tabs.Screen",
3842
3766
  ' name="mine"',
3843
3767
  " options={{",
3844
3768
  ' title: "Mine",',
3845
- " tabBarIcon: () => null,",
3769
+ ' tabBarIcon: ({ color }) => <IconSymbol size={28} name="chevron.right" color={color} />',
3846
3770
  " }}",
3847
3771
  " />",
3848
3772
  " </Tabs>",
@@ -3851,9 +3775,9 @@ function generateLoginTabsTemplates(projectName) {
3851
3775
  ""
3852
3776
  )
3853
3777
  },
3854
- // ─── app/(tabs)/home.tsx ────────────────────────────────────────────
3778
+ // ─── app/(tabs)/index.tsx ──────────────────────────────────────────
3855
3779
  {
3856
- path: "app/(tabs)/home.tsx",
3780
+ path: "app/(tabs)/index.tsx",
3857
3781
  content: lines(
3858
3782
  'import { Button } from "@/components/ui/button";',
3859
3783
  "import {",
@@ -3934,9 +3858,9 @@ function generateLoginTabsTemplates(projectName) {
3934
3858
  ""
3935
3859
  )
3936
3860
  },
3937
- // ─── app/(tabs)/list.tsx ────────────────────────────────────────────
3861
+ // ─── app/(tabs)/explore.tsx ────────────────────────────────────────
3938
3862
  {
3939
- path: "app/(tabs)/list.tsx",
3863
+ path: "app/(tabs)/explore.tsx",
3940
3864
  content: lines(
3941
3865
  'import { Text } from "@/components/ui/text";',
3942
3866
  'import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";',
@@ -3948,10 +3872,10 @@ function generateLoginTabsTemplates(projectName) {
3948
3872
  " description: `Description for item ${i + 1}`,",
3949
3873
  "}));",
3950
3874
  "",
3951
- "export default function ListScreen() {",
3875
+ "export default function ExploreScreen() {",
3952
3876
  " return (",
3953
3877
  ' <ScrollView className="flex-1 p-4">',
3954
- ' <Text variant="h3" className="mb-4">List</Text>',
3878
+ ' <Text variant="h3" className="mb-4">Explore</Text>',
3955
3879
  ' <View className="gap-3">',
3956
3880
  " {ITEMS.map((item) => (",
3957
3881
  " <Card key={item.id}>",
@@ -4011,7 +3935,7 @@ function generateLoginTabsTemplates(projectName) {
4011
3935
  ""
4012
3936
  )
4013
3937
  },
4014
- // ─── src/components/SignInForm.tsx ───────────────────────────────────
3938
+ // ─── components/SignInForm.tsx ────────────────────────────────────
4015
3939
  {
4016
3940
  path: "components/SignInForm.tsx",
4017
3941
  content: lines(
@@ -4040,7 +3964,7 @@ function generateLoginTabsTemplates(projectName) {
4040
3964
  "",
4041
3965
  " function onSubmit() {",
4042
3966
  " // TODO: Submit form and navigate to protected screen if successful",
4043
- ' router.replace("/(tabs)/home");',
3967
+ ' router.replace("/(tabs)");',
4044
3968
  " }",
4045
3969
  "",
4046
3970
  " return (",
@@ -4200,6 +4124,7 @@ function generateBasePackageJson(projectName) {
4200
4124
  // ─── Styling ──────────────────────────────────────────────────
4201
4125
  nativewind: "^4.1.0",
4202
4126
  tailwindcss: "^3.4.0",
4127
+ "tailwindcss-animate": "^1.0.7",
4203
4128
  "react-native-svg": "15.12.1",
4204
4129
  // ─── Network ─────────────────────────────────────────────────
4205
4130
  "@tanstack/react-query": "^5.60.0",
@@ -4261,8 +4186,7 @@ function generateBasePackageJson(projectName) {
4261
4186
  }
4262
4187
 
4263
4188
  // src/index.ts
4264
- var import_execa = require("execa");
4265
- var CLI_VERSION = "1.6.1";
4189
+ var CLI_VERSION = "1.7.1";
4266
4190
  var CONFIG_FILE = ".expo-bbase.json";
4267
4191
  async function run() {
4268
4192
  const program = new import_commander.Command();
@@ -4309,12 +4233,12 @@ async function createProject(projectName) {
4309
4233
  message: "Choose a UI template",
4310
4234
  choices: [
4311
4235
  {
4312
- title: `${import_chalk.default.bold("Login + Tabs")} \u2014 Login page, Home/List/Mine tabs with rnr components`,
4236
+ title: `${import_chalk.default.bold("Login + Tabs")} \u2014 Login page, Index/Explore/Mine tabs with rnr components`,
4313
4237
  value: "login-tabs",
4314
4238
  description: "Pre-built login form, 3-tab layout with Button & AlertDialog demos"
4315
4239
  },
4316
4240
  {
4317
- title: `${import_chalk.default.bold("Default")} \u2014 Blank tabs (Home + Explore)`,
4241
+ title: `${import_chalk.default.bold("Default")} \u2014 Blank tabs (Index + Explore)`,
4318
4242
  value: "default",
4319
4243
  description: "Minimal starter with basic tab navigation"
4320
4244
  }