diff --git a/.changeset/all-cars-matter.md b/.changeset/all-cars-matter.md new file mode 100644 index 00000000..e84e71eb --- /dev/null +++ b/.changeset/all-cars-matter.md @@ -0,0 +1,6 @@ +--- +'create-expo-stack': patch +'rn-new': patch +--- + +update tests to include nativewind + expo router diff --git a/.changeset/clean-dingos-film.md b/.changeset/clean-dingos-film.md new file mode 100644 index 00000000..240caf82 --- /dev/null +++ b/.changeset/clean-dingos-film.md @@ -0,0 +1,6 @@ +--- +'create-expo-stack': minor +'rn-new': minor +--- + +add support for nativewind v5 diff --git a/.changeset/nasty-symbols-shop.md b/.changeset/nasty-symbols-shop.md new file mode 100644 index 00000000..f85ba025 --- /dev/null +++ b/.changeset/nasty-symbols-shop.md @@ -0,0 +1,6 @@ +--- +'create-expo-stack': minor +'rn-new': minor +--- + +add support for nativewind v5 and expo router diff --git a/.changeset/shaky-wombats-stand.md b/.changeset/shaky-wombats-stand.md new file mode 100644 index 00000000..f489ee1a --- /dev/null +++ b/.changeset/shaky-wombats-stand.md @@ -0,0 +1,6 @@ +--- +'create-expo-stack': patch +'rn-new': patch +--- + +temporarily disable nativewindui options and expo router options, update tests accordingly diff --git a/.changeset/spicy-steaks-stand.md b/.changeset/spicy-steaks-stand.md new file mode 100644 index 00000000..cee37500 --- /dev/null +++ b/.changeset/spicy-steaks-stand.md @@ -0,0 +1,6 @@ +--- +'create-expo-stack': patch +'rn-new': patch +--- + +add back expo router as an option for the cli diff --git a/README.md b/README.md index b2bef0e7..4e851c50 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,9 @@ Each project is generated based on the results of the CLI, on a per-file basis. | Expo Status Bar | Status Bar Library | v3 | Status bar support | | Expo System UI | System UI Library | v6 | System UI support | | Expo Web Browser | Web Browser Library | v15 | Open links in the browser | -| NativeWind | UI Framework | v4.1 | Tailwind CSS for React Native | +| NativeWind | UI Framework | v5 | Tailwind CSS for React Native | +| Tailwind CSS | CSS Framework | v4.1 | Utility-first CSS framework | +| React Native CSS | CSS Engine | latest | CSS support for React Native | | Unistyles | UI Framework | v3 | Superset of StyleSheet | | Safe Area Context | Safe Area Library | v5.6 | Safe area support | | React Native Web | Web Support | v0.21 | React Native for Web | diff --git a/cli/README.md b/cli/README.md index 576359dc..54be8899 100644 --- a/cli/README.md +++ b/cli/README.md @@ -59,24 +59,24 @@ Each project is generated based on the results of the CLI, on a per-file basis. | Library | Category | Version | Description | | ------------------ | ------------------- | ------- | ---------------------------------------------- | -| React Native | Mobile Framework | v0.79 | The best cross-platform mobile framework | -| React | UI Framework | v19 | The most popular UI framework in the world | -| TypeScript | Language | v5 | Static typechecking | -| React Navigation | Navigation | v7 | Performant and consistent navigation framework | -| Expo | SDK | v53 | Allows (optional) Expo modules | -| Expo Font | Custom Fonts | v13 | Import custom fonts | -| Expo Linking | URL Handling | v7 | Open your app via a URL | -| Expo Router | Navigation | v5 | File-based routing in React-Native | -| Expo Splash Screen | Splash Screen | v0.27 | Custom splash screen | -| Expo Status Bar | Status Bar Library | v2 | Status bar support | -| Expo System UI | System UI Library | v5 | System UI support | -| Expo Web Browser | Web Browser Library | v14 | Open links in the browser | -| NativeWind | UI Framework | v4.1 | Tailwind CSS for React Native | +| React Native | Mobile Framework | v0.81 | The best cross-platform mobile framework | +| React | UI Framework | v19.1 | The most popular UI framework in the world | +| TypeScript | Language | v5.9 | Static typechecking | +| React Navigation | Navigation | v7.1 | Performant and consistent navigation framework | +| Expo | SDK | v54 | Opionated framework for building RN apps | +| Expo Linking | URL Handling | v8 | Open your app via a URL | +| Expo Router | Navigation | v6 | File-based routing in React-Native | +| Expo Status Bar | Status Bar Library | v3 | Status bar support | +| Expo System UI | System UI Library | v6 | System UI support | +| Expo Web Browser | Web Browser Library | v15 | Open links in the browser | +| NativeWind | UI Framework | v5 | Tailwind CSS for React Native | +| Tailwind CSS | CSS Framework | v4.1 | Utility-first CSS framework | +| React Native CSS | CSS Engine | latest | CSS support for React Native | | Unistyles | UI Framework | v3 | Superset of StyleSheet | -| Safe Area Context | Safe Area Library | v5 | Safe area support | -| React Native Web | Web Support | v0.20 | React Native for Web | -| Firebase | Backend and Auth | v10 | Cloud-hosted NoSQL database from Google | -| Supabase | Backend and Auth | v2 | Open source Firebase alternative | +| Safe Area Context | Safe Area Library | v5.6 | Safe area support | +| React Native Web | Web Support | v0.21 | React Native for Web | +| Firebase | Backend and Auth | v10.5 | Cloud-hosted NoSQL database from Google | +| Supabase | Backend and Auth | v2.38 | Open source Firebase alternative | ## Reporting Bugs & Feedback diff --git a/cli/__tests__/__snapshots__/cli-integration.test.ts.snap b/cli/__tests__/__snapshots__/cli-integration.test.ts.snap index a950fad3..82f8d919 100644 --- a/cli/__tests__/__snapshots__/cli-integration.test.ts.snap +++ b/cli/__tests__/__snapshots__/cli-integration.test.ts.snap @@ -568,11 +568,14 @@ exports[`generates a project with --stylesheet --expo-router --no-install --bun exports[`generates a project with --nativewind --bun --overwrite: --nativewind, --bun, --overwrite-package-json 1`] = ` { "dependencies": { + "@tailwindcss/postcss": "", "expo": "", "expo-status-bar": "", "nativewind": "", + "postcss": "", "react": "", "react-native": "", + "react-native-css": "", "react-native-reanimated": "", "react-native-safe-area-context": "", "react-native-worklets": "", @@ -591,6 +594,9 @@ exports[`generates a project with --nativewind --bun --overwrite: --nativewind, "main": "node_modules/expo/AppEntry.js", "name": "myTestProject", "private": true, + "resolutions": { + "lightningcss": "1.30.1", + }, "scripts": { "android": "expo start --android", "format": "eslint "**/*.{js,jsx,ts,tsx}" --fix && prettier "**/*.{js,jsx,ts,tsx,json}" --write", @@ -645,7 +651,6 @@ exports[`generates a project with --nativewind --bun --overwrite: --nativewind, "./myTestProject/bun.lock", "./myTestProject/cesconfig.jsonc", "./myTestProject/components", - "./myTestProject/components/Container.tsx", "./myTestProject/components/EditScreenInfo.tsx", "./myTestProject/components/ScreenContent.tsx", "./myTestProject/eslint.config.js", @@ -653,8 +658,8 @@ exports[`generates a project with --nativewind --bun --overwrite: --nativewind, "./myTestProject/metro.config.js", "./myTestProject/nativewind-env.d.ts", "./myTestProject/package.json", + "./myTestProject/postcss.config.mjs", "./myTestProject/prettier.config.js", - "./myTestProject/tailwind.config.js", "./myTestProject/tsconfig.json", ] `; @@ -662,11 +667,14 @@ exports[`generates a project with --nativewind --bun --overwrite: --nativewind, exports[`generates a project with --nativewind --no-install --bun --overwrite: --nativewind, --no-install, --bun, --overwrite-package-json 1`] = ` { "dependencies": { + "@tailwindcss/postcss": "", "expo": "", "expo-status-bar": "", "nativewind": "", + "postcss": "", "react": "", "react-native": "", + "react-native-css": "", "react-native-reanimated": "", "react-native-safe-area-context": "", "react-native-worklets": "", @@ -685,6 +693,9 @@ exports[`generates a project with --nativewind --no-install --bun --overwrite: - "main": "node_modules/expo/AppEntry.js", "name": "myTestProject", "private": true, + "resolutions": { + "lightningcss": "1.30.1", + }, "scripts": { "android": "expo start --android", "format": "eslint "**/*.{js,jsx,ts,tsx}" --fix && prettier "**/*.{js,jsx,ts,tsx,json}" --write", @@ -738,7 +749,6 @@ exports[`generates a project with --nativewind --no-install --bun --overwrite: - "./myTestProject/babel.config.js", "./myTestProject/cesconfig.jsonc", "./myTestProject/components", - "./myTestProject/components/Container.tsx", "./myTestProject/components/EditScreenInfo.tsx", "./myTestProject/components/ScreenContent.tsx", "./myTestProject/eslint.config.js", @@ -746,8 +756,8 @@ exports[`generates a project with --nativewind --no-install --bun --overwrite: - "./myTestProject/metro.config.js", "./myTestProject/nativewind-env.d.ts", "./myTestProject/package.json", + "./myTestProject/postcss.config.mjs", "./myTestProject/prettier.config.js", - "./myTestProject/tailwind.config.js", "./myTestProject/tsconfig.json", ] `; @@ -757,6 +767,7 @@ exports[`generates a project with --nativewind --expo-router --bun --overwrite: "dependencies": { "@expo/vector-icons": "", "@react-navigation/native": "", + "@tailwindcss/postcss": "", "expo": "", "expo-constants": "", "expo-linking": "", @@ -765,9 +776,11 @@ exports[`generates a project with --nativewind --expo-router --bun --overwrite: "expo-system-ui": "", "expo-web-browser": "", "nativewind": "", + "postcss": "", "react": "", "react-dom": "", "react-native": "", + "react-native-css": "", "react-native-gesture-handler": "", "react-native-reanimated": "", "react-native-safe-area-context": "", @@ -789,6 +802,9 @@ exports[`generates a project with --nativewind --expo-router --bun --overwrite: "main": "expo-router/entry", "name": "myTestProject", "private": true, + "resolutions": { + "lightningcss": "1.30.1", + }, "scripts": { "android": "expo start --android", "format": "eslint "**/*.{js,jsx,ts,tsx}" --fix && prettier "**/*.{js,jsx,ts,tsx,json}" --write", @@ -856,7 +872,6 @@ exports[`generates a project with --nativewind --expo-router --bun --overwrite: "./myTestProject/cesconfig.jsonc", "./myTestProject/components", "./myTestProject/components/Button.tsx", - "./myTestProject/components/Container.tsx", "./myTestProject/components/EditScreenInfo.tsx", "./myTestProject/components/ScreenContent.tsx", "./myTestProject/eslint.config.js", @@ -865,8 +880,8 @@ exports[`generates a project with --nativewind --expo-router --bun --overwrite: "./myTestProject/metro.config.js", "./myTestProject/nativewind-env.d.ts", "./myTestProject/package.json", + "./myTestProject/postcss.config.mjs", "./myTestProject/prettier.config.js", - "./myTestProject/tailwind.config.js", "./myTestProject/tsconfig.json", ] `; @@ -876,6 +891,7 @@ exports[`generates a project with --nativewind --expo-router --no-install --bun "dependencies": { "@expo/vector-icons": "", "@react-navigation/native": "", + "@tailwindcss/postcss": "", "expo": "", "expo-constants": "", "expo-linking": "", @@ -884,9 +900,11 @@ exports[`generates a project with --nativewind --expo-router --no-install --bun "expo-system-ui": "", "expo-web-browser": "", "nativewind": "", + "postcss": "", "react": "", "react-dom": "", "react-native": "", + "react-native-css": "", "react-native-gesture-handler": "", "react-native-reanimated": "", "react-native-safe-area-context": "", @@ -908,6 +926,9 @@ exports[`generates a project with --nativewind --expo-router --no-install --bun "main": "expo-router/entry", "name": "myTestProject", "private": true, + "resolutions": { + "lightningcss": "1.30.1", + }, "scripts": { "android": "expo start --android", "format": "eslint "**/*.{js,jsx,ts,tsx}" --fix && prettier "**/*.{js,jsx,ts,tsx,json}" --write", @@ -974,7 +995,6 @@ exports[`generates a project with --nativewind --expo-router --no-install --bun "./myTestProject/cesconfig.jsonc", "./myTestProject/components", "./myTestProject/components/Button.tsx", - "./myTestProject/components/Container.tsx", "./myTestProject/components/EditScreenInfo.tsx", "./myTestProject/components/ScreenContent.tsx", "./myTestProject/eslint.config.js", @@ -983,8 +1003,8 @@ exports[`generates a project with --nativewind --expo-router --no-install --bun "./myTestProject/metro.config.js", "./myTestProject/nativewind-env.d.ts", "./myTestProject/package.json", + "./myTestProject/postcss.config.mjs", "./myTestProject/prettier.config.js", - "./myTestProject/tailwind.config.js", "./myTestProject/tsconfig.json", ] `; diff --git a/cli/__tests__/cli-integration.test.ts b/cli/__tests__/cli-integration.test.ts index 586ef658..5fae2444 100644 --- a/cli/__tests__/cli-integration.test.ts +++ b/cli/__tests__/cli-integration.test.ts @@ -95,16 +95,16 @@ const nativewindCombinations = [ ['--nativewind', '--expo-router', '--no-install'] ] as const; -const nativewinduiCombinations = [ - ['--nativewindui'], - ['--nativewindui', '--no-install'], - ['--nativewindui', '--blank'], - ['--nativewindui', '--blank', '--no-install'] -] as const; +// const nativewinduiCombinations = [ +// ['--nativewindui'], +// ['--nativewindui', '--no-install'], +// ['--nativewindui', '--blank'], +// ['--nativewindui', '--blank', '--no-install'] +// ] as const; // Combine all combinations based on environment variables // UPDATED - Only using core combinations since React Navigation tests are commented out -const popularCombinations = [...styleSheetCombinations, ...nativewindCombinations, ...nativewinduiCombinations]; +const popularCombinations = [...styleSheetCombinations, ...nativewindCombinations]; const projectName = `myTestProject`; const pathToProject = `./${projectName}`; diff --git a/cli/src/templates/base/babel.config.js.ejs b/cli/src/templates/base/babel.config.js.ejs index cc589bff..ac5de4ac 100644 --- a/cli/src/templates/base/babel.config.js.ejs +++ b/cli/src/templates/base/babel.config.js.ejs @@ -15,14 +15,7 @@ module.exports = function(api) { plugins.push('react-native-worklets/plugin'); return { - <% if (props.stylingPackage?.name === "nativewind" || props.stylingPackage?.name === "nativewindui") { %> - presets: [ - ['babel-preset-expo', { jsxImportSource: 'nativewind' }], - 'nativewind/babel', - ], - <% } else { %> - presets: ['babel-preset-expo'], - <% } %> + presets: ['babel-preset-expo'], plugins, }; }; diff --git a/cli/src/templates/base/package.json.ejs b/cli/src/templates/base/package.json.ejs index e26e7ac4..97bc0c15 100644 --- a/cli/src/templates/base/package.json.ejs +++ b/cli/src/templates/base/package.json.ejs @@ -31,7 +31,10 @@ }, "dependencies": { <% if (props.stylingPackage?.name === "nativewind" || props.stylingPackage?.name === "nativewindui") { %> - "nativewind": "4.1.21", + "nativewind": "preview", + "react-native-css": "latest", + "postcss": "^8.5.6", + "@tailwindcss/postcss": "^4.1.13", <% } %> <% if (props.stylingPackage?.name === "nativewindui") { %> "@shopify/flash-list": "2.0.2", @@ -143,8 +146,8 @@ "eslint-config-prettier": "^10.1.2", "prettier": "^3.2.5", <% if (props.stylingPackage?.name === "nativewind" || props.stylingPackage?.name === "nativewindui") { %> - "tailwindcss": "^3.4.0", - "prettier-plugin-tailwindcss": "^0.5.11", + "tailwindcss": "^4.1.13", + "prettier-plugin-tailwindcss": "^0.6.14", <% } %> "typescript": "~5.9.2" }, @@ -154,5 +157,10 @@ <% if (props.packageManager === "yarn"){ %> "packageManager": "yarn@4.9.4", <% } %> + <% if (props.stylingPackage?.name === "nativewind") { %> + "resolutions": { + "lightningcss": "1.30.1" + }, + <% } %> "private": true } diff --git a/cli/src/templates/packages/expo-router/metro.config.js.ejs b/cli/src/templates/packages/expo-router/metro.config.js.ejs index 4cb318d8..871cde37 100644 --- a/cli/src/templates/packages/expo-router/metro.config.js.ejs +++ b/cli/src/templates/packages/expo-router/metro.config.js.ejs @@ -1,7 +1,7 @@ // Learn more https://docs.expo.io/guides/customizing-metro const { getDefaultConfig } = require('expo/metro-config'); <% if (["nativewind", "nativewindui"].includes(props.stylingPackage?.name)) { %> - const { withNativeWind } = require("nativewind/metro"); + const { withNativewind } = require("nativewind/metro"); <% } %> /** @type {import('expo/metro-config').MetroConfig} */ @@ -9,9 +9,9 @@ const { getDefaultConfig } = require('expo/metro-config'); const config = getDefaultConfig(__dirname); <% if (props.stylingPackage?.name === "nativewind") { %> - module.exports = withNativeWind(config, { input: "./global.css" }); + module.exports = withNativewind(config); <% } else if (props.stylingPackage?.name === "nativewindui") { %> - module.exports = withNativeWind(config, { input: "./global.css", inlineRem: 16 }); + module.exports = withNativewind(config, { inlineRem: 16 }); <% } else { %> module.exports = config; <% } %> \ No newline at end of file diff --git a/cli/src/templates/packages/expo-router/stack/app/+not-found.tsx.ejs b/cli/src/templates/packages/expo-router/stack/app/+not-found.tsx.ejs index 94d44a68..5d94b25c 100644 --- a/cli/src/templates/packages/expo-router/stack/app/+not-found.tsx.ejs +++ b/cli/src/templates/packages/expo-router/stack/app/+not-found.tsx.ejs @@ -2,16 +2,13 @@ import { Link, Stack } from 'expo-router'; <% if (props.stylingPackage?.name === "nativewind") {%> import { Text, View } from 'react-native'; - import { Container } from '@/components/Container'; <% } else if (props.stylingPackage?.name === "unistyles") { %> import { StyleSheet } from 'react-native-unistyles' import { Text, View } from 'react-native'; - import { Container } from '@/components/Container'; <% } else if (props.stylingPackage?.name === "stylesheet") { %> import { StyleSheet, Text, View } from 'react-native'; - import { Container } from '@/components/Container'; <% } %> export default function NotFoundScreen() { @@ -20,22 +17,22 @@ export default function NotFoundScreen() { <% if (props.stylingPackage?.name === "nativewind") { %> - + {"This screen doesn't exist."} Go to home screen! - + <% } else { %> - + {"This screen doesn't exist."} Go to home screen! - + <% } %> ); @@ -44,6 +41,7 @@ export default function NotFoundScreen() { <% if (props.stylingPackage?.name === "nativewind") { %> const styles = { container: `flex flex-1 bg-white`, + contentContainer: `flex flex-1 m-6`, title: `text-xl font-bold`, link: `mt-4 pt-4`, linkText: `text-base text-[#2e78b7]`, @@ -54,6 +52,10 @@ const styles = StyleSheet.create((theme) => ({ flex: 1, backgroundColor: 'white', }, + contentContainer: { + flex: 1, + margin: 24, + }, title: { fontSize: 20, fontWeight: 'bold', @@ -74,6 +76,10 @@ const styles = StyleSheet.create({ flex: 1, backgroundColor: 'white', }, + contentContainer: { + flex: 1, + margin: 24, + }, title: { fontSize: 20, fontWeight: 'bold', diff --git a/cli/src/templates/packages/expo-router/stack/app/_layout.tsx.ejs b/cli/src/templates/packages/expo-router/stack/app/_layout.tsx.ejs index eac81954..68cb918f 100644 --- a/cli/src/templates/packages/expo-router/stack/app/_layout.tsx.ejs +++ b/cli/src/templates/packages/expo-router/stack/app/_layout.tsx.ejs @@ -34,6 +34,11 @@ export default function Layout() { headerTintColor: theme.colors.typography }} /> + <% } else if (props.stylingPackage?.name === "nativewind") { %> + + + + <% } else { %> <% } %> diff --git a/cli/src/templates/packages/expo-router/stack/app/details.tsx.ejs b/cli/src/templates/packages/expo-router/stack/app/details.tsx.ejs index 6db9aa98..46cbacb8 100644 --- a/cli/src/templates/packages/expo-router/stack/app/details.tsx.ejs +++ b/cli/src/templates/packages/expo-router/stack/app/details.tsx.ejs @@ -3,12 +3,12 @@ import { StyleSheet, View } from 'react-native'; <% } else if (props.stylingPackage?.name === "unistyles") { %> import { StyleSheet } from 'react-native-unistyles'; import { View } from 'react-native'; -<% } else { %> -import { View } from 'react-native'; <% } %> import { Stack, useLocalSearchParams } from 'expo-router'; +<% if (props.stylingPackage?.name !== "nativewind") { %> import { Container } from '@/components/Container'; +<% } %> import { ScreenContent } from '@/components/ScreenContent'; export default function Details() { @@ -16,23 +16,22 @@ export default function Details() { return ( <% if (props.stylingPackage?.name === "nativewind") { %> - + <> + + + <% } else { %> + + + + + <% } %> - - - - - ); } -<% if (props.stylingPackage?.name === "nativewind") { %> -const styles = { - container: "flex flex-1 bg-white", -} -<% } else if (props.stylingPackage?.name === "stylesheet") { %> +<% if (props.stylingPackage?.name === "stylesheet") { %> const styles = StyleSheet.create({ container: { flex: 1, diff --git a/cli/src/templates/packages/expo-router/stack/app/index.tsx.ejs b/cli/src/templates/packages/expo-router/stack/app/index.tsx.ejs index 0645cb33..d690780d 100644 --- a/cli/src/templates/packages/expo-router/stack/app/index.tsx.ejs +++ b/cli/src/templates/packages/expo-router/stack/app/index.tsx.ejs @@ -1,15 +1,20 @@ -import { Stack, Link } from 'expo-router'; <% if (props.stylingPackage?.name === "stylesheet") { %> import { StyleSheet, View } from 'react-native'; +import { Stack, Link } from 'expo-router'; <% } else if (props.stylingPackage?.name === "unistyles") { %> import { StyleSheet } from 'react-native-unistyles'; +import { Stack, Link } from 'expo-router'; import { View } from 'react-native'; <% } else { %> import { View } from 'react-native'; +import { router } from 'expo-router'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; <% } %> import { Button } from '@/components/Button'; +<% if (props.stylingPackage?.name !== "nativewind") { %> import { Container } from '@/components/Container'; +<% } %> import { ScreenContent } from '@/components/ScreenContent'; <% if (props.internalizationPackage?.name === "i18next") { %> @@ -17,34 +22,54 @@ import { ScreenContent } from '@/components/ScreenContent'; <% } %> export default function Home() { + <% if (props.stylingPackage?.name === "nativewind") { %> + const insets = useSafeAreaInsets(); + <% } %> return ( <% if (props.stylingPackage?.name === "nativewind") { %> - - <% } else { %> - - <% } %> - - + + <% if (props.internalizationPackage?.name === "i18next") { %> - <% if (props.internalizationPackage?.name === "i18next") { %> - <% } %> - - <% if (props.stylingPackage?.name === "unistyles") { %> -