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