├── .eslintrc.js ├── .gitignore ├── .prettierignore ├── .prettierrc ├── Gemfile ├── LICENSE ├── README.md ├── __tests__ └── init.test.ts ├── android ├── .gitignore ├── app │ ├── build.gradle │ ├── debug.keystore │ ├── proguard-rules.pro │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── teczer │ │ │ └── exponativewindtypescriptboilerplate │ │ │ ├── MainActivity.kt │ │ │ └── MainApplication.kt │ │ └── res │ │ ├── drawable-hdpi │ │ └── splashscreen_logo.png │ │ ├── drawable-mdpi │ │ └── splashscreen_logo.png │ │ ├── drawable-xhdpi │ │ └── splashscreen_logo.png │ │ ├── drawable-xxhdpi │ │ └── splashscreen_logo.png │ │ ├── drawable-xxxhdpi │ │ └── splashscreen_logo.png │ │ ├── drawable │ │ ├── ic_launcher_background.xml │ │ └── rn_edit_text_material.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.webp │ │ ├── ic_launcher_foreground.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.webp │ │ ├── ic_launcher_foreground.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.webp │ │ ├── ic_launcher_foreground.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.webp │ │ ├── ic_launcher_foreground.webp │ │ └── ic_launcher_round.webp │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.webp │ │ ├── ic_launcher_foreground.webp │ │ └── ic_launcher_round.webp │ │ ├── values-night │ │ └── colors.xml │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── app.json ├── app ├── (tabs) │ ├── _layout.tsx │ ├── index.tsx │ └── settings.tsx ├── +html.tsx ├── +not-found.tsx ├── _layout.tsx └── modal.tsx ├── assets ├── fonts │ └── SpaceMono-Regular.ttf └── images │ ├── adaptive-icon.png │ ├── favicon.png │ ├── icon.png │ └── splash.png ├── babel.config.js ├── bun.lock ├── components ├── ExternalLink.tsx └── ToggleTheme.tsx ├── constants └── Colors.ts ├── global.css ├── ios ├── .gitignore ├── .xcode.env ├── Podfile ├── Podfile.lock ├── Podfile.properties.json ├── exponativewindtypescriptboilerplate.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ └── exponativewindtypescriptboilerplate.xcscheme ├── exponativewindtypescriptboilerplate.xcworkspace │ └── contents.xcworkspacedata └── exponativewindtypescriptboilerplate │ ├── AppDelegate.swift │ ├── Images.xcassets │ ├── AppIcon.appiconset │ │ ├── App-Icon-1024x1024@1x.png │ │ └── Contents.json │ ├── Contents.json │ ├── SplashScreenBackground.colorset │ │ └── Contents.json │ └── SplashScreenLogo.imageset │ │ ├── Contents.json │ │ ├── image.png │ │ ├── image@2x.png │ │ └── image@3x.png │ ├── Info.plist │ ├── PrivacyInfo.xcprivacy │ ├── SplashScreen.storyboard │ ├── Supporting │ └── Expo.plist │ ├── exponativewindtypescriptboilerplate-Bridging-Header.h │ └── exponativewindtypescriptboilerplate.entitlements ├── lib ├── mmkv.ts └── utils.ts ├── metro.config.js ├── nativewind-env.d.ts ├── package.json ├── tailwind.config.js └── tsconfig.json /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://docs.expo.dev/guides/using-eslint/ 2 | module.exports = { 3 | extends: ['expo', 'prettier'], 4 | plugins: ['prettier', 'perfectionist', 'unused-imports'], 5 | rules: { 6 | 'perfectionist/sort-imports': ['error'], 7 | 'perfectionist/sort-interfaces': ['error'], 8 | 'perfectionist/sort-objects': [ 9 | 'error', 10 | { 11 | type: 'alphabetical', 12 | }, 13 | ], 14 | 'prettier/prettier': 'error', 15 | 'unused-imports/no-unused-imports': 'error', 16 | 'unused-imports/no-unused-vars': [ 17 | 'warn', 18 | { 19 | args: 'after-used', 20 | argsIgnorePattern: '^_', 21 | vars: 'all', 22 | varsIgnorePattern: '^_', 23 | }, 24 | ], 25 | }, 26 | settings: { 27 | perfectionist: { 28 | partitionByComment: true, 29 | type: 'line-length', 30 | }, 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files 2 | 3 | # dependencies 4 | node_modules/ 5 | 6 | # Expo 7 | .expo/ 8 | dist/ 9 | web-build/ 10 | 11 | # Native 12 | *.orig.* 13 | *.jks 14 | *.p8 15 | *.p12 16 | *.key 17 | *.mobileprovision 18 | 19 | # Metro 20 | .metro-health-check* 21 | 22 | # debug 23 | npm-debug.* 24 | yarn-debug.* 25 | yarn-error.* 26 | 27 | # macOS 28 | .DS_Store 29 | *.pem 30 | 31 | # local env files 32 | .env*.local 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | 37 | # @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb 38 | # The following patterns were generated by expo-cli 39 | 40 | expo-env.d.ts 41 | # @end expo-cli -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | android 3 | ios 4 | web 5 | .expo 6 | .vscode 7 | yarn.lock 8 | package-lock.json -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": true, 7 | "trailingComma": "all", 8 | "no-return-assign": false, 9 | "array-element-newline": false, 10 | "object-curly-newline": false, 11 | "bracketSameLine": false, 12 | "arrowParens": "avoid" 13 | } 14 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # Autogenerated by fastlane 2 | # 3 | # Ensure this file is checked in to source control! 4 | 5 | source "https://rubygems.org" 6 | 7 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 8 | ruby '>= 3.1.4' 9 | 10 | # Cocoapods 1.15 introduced a bug which break the build. We will remove the upper 11 | # bound in the template on Cocoapods with next React Native release. 12 | gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1' 13 | gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0' 14 | 15 | # FIXME for now the version 1.26 turn the flag ENABLE_USER_SCRIPT_SANDBOXING to YES which declench a problem in build 16 | gem 'xcodeproj', '1.25.0' 17 | 18 | gem 'concurrent-ruby', '< 1.3.4' 19 | 20 | plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') 21 | eval_gemfile(plugins_path) if File.exist?(plugins_path) 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Hattou Mehdi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fast Expo App CLI 2 | 3 | [![NPM version][npm-image]][npm-url] 4 | [![Downloads][downloads-image]][npm-url] 5 | 6 |

7 | Get started by running npx fast-expo-app@latest 8 |

9 | 10 | ## Simple & Fast Starter for Expo, Nativewind, and TypeScript 11 | 12 | ![](https://res.cloudinary.com/dw3mwclgk/image/upload/v1748088179/FAST-EXPO-APP.png) 13 |

14 | 15 | This boilerplate provides a fast and modern setup for building React Native applications with Expo, NativeWind, and TypeScript. It's designed to enhance developer experience and streamline your development process.a 16 | 17 |

18 | 19 | ### Features 20 | 21 | Developer experience first: 22 | 23 | - ⚡ [Expo](https://expo.dev) for mobile development 24 | - ⚛️ [React Native](https://reactnative.dev) for building native apps using React 25 | - 🔥 Type checking [TypeScript](https://www.typescriptlang.org) 26 | - 💎 Integrate with [NativeWind](https://www.nativewind.dev), Tailwind CSS for React Native 27 | - 🌜 Light/Dark mode already setup with toggle 28 | - 📊 MMKV (~30x faster than AsyncStorage and not Async usage) 29 | - 📁 File-based routing with Expo Router 30 | - 📏 Linter with [ESLint](https://eslint.org) 31 | - 💖 Code Formatter with [Prettier](https://prettier.io) 32 | - 🤡 Unit Testing with Jest 33 | - 💡 Absolute Imports using `@` prefix 34 | 35 | ### Last Boilerplate Update 36 | 37 | - ⚡ Expo SDK 53 (Including Expo Router 3.5, Expo UI...) + update all libraries 38 | - ⚛️ React Native 0.79 (Including New Arch, Android Edge-to-Edge...) 39 | - 💎 NativeWind 4.0 40 | - 🥟 Bun 41 | 42 | ![](https://res.cloudinary.com/dw3mwclgk/image/upload/v1748011077/UPDATE.png) 43 | 44 | ### Requirements 45 | 46 | - Node.js 22+ (Recommended LTS) 47 | - BUN IS VERY RECOMMENDED 48 | 49 | ### Contributions 50 | 51 | Contributions are welcome! If you find a bug or have suggestions for improvements, please open an issue on the [GitHub repository](https://github.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/issues). You can also submit pull requests with enhancements or fixes. 52 | 53 | ### License 54 | 55 | Licensed under the MIT License, Copyright © 2025 56 | 57 | See [LICENSE](LICENSE) for more information. 58 | 59 | --- 60 | 61 | Made with ♥ by [Teczer](https://mehdihattou.com/) 62 | 63 | [downloads-image]: https://img.shields.io/npm/dm/fast-expo-app?color=364fc7&logoColor=364fc7 64 | [npm-url]: https://www.npmjs.com/package/fast-expo-app 65 | [npm-image]: https://img.shields.io/npm/v/fast-expo-app?color=0b7285&logoColor=0b7285 66 | -------------------------------------------------------------------------------- /__tests__/init.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@jest/globals'; // Import test from Jest 2 | 3 | test('sample test', () => { 4 | // write your test logic here 5 | expect(1 + 2).toBe(3); // Example test logic 6 | }); 7 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Android/IntelliJ 6 | # 7 | build/ 8 | .idea 9 | .gradle 10 | local.properties 11 | *.iml 12 | *.hprof 13 | .cxx/ 14 | 15 | # Bundle artifacts 16 | *.jsbundle 17 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | apply plugin: "org.jetbrains.kotlin.android" 3 | apply plugin: "com.facebook.react" 4 | 5 | def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath() 6 | 7 | /** 8 | * This is the configuration block to customize your React Native Android app. 9 | * By default you don't need to apply any configuration, just uncomment the lines you need. 10 | */ 11 | react { 12 | entryFile = file(["node", "-e", "require('expo/scripts/resolveAppEntry')", projectRoot, "android", "absolute"].execute(null, rootDir).text.trim()) 13 | reactNativeDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile() 14 | hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc" 15 | codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile() 16 | 17 | enableBundleCompression = (findProperty('android.enableBundleCompression') ?: false).toBoolean() 18 | // Use Expo CLI to bundle the app, this ensures the Metro config 19 | // works correctly with Expo projects. 20 | cliFile = new File(["node", "--print", "require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })"].execute(null, rootDir).text.trim()) 21 | bundleCommand = "export:embed" 22 | 23 | /* Folders */ 24 | // The root of your project, i.e. where "package.json" lives. Default is '../..' 25 | // root = file("../../") 26 | // The folder where the react-native NPM package is. Default is ../../node_modules/react-native 27 | // reactNativeDir = file("../../node_modules/react-native") 28 | // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen 29 | // codegenDir = file("../../node_modules/@react-native/codegen") 30 | 31 | /* Variants */ 32 | // The list of variants to that are debuggable. For those we're going to 33 | // skip the bundling of the JS bundle and the assets. By default is just 'debug'. 34 | // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. 35 | // debuggableVariants = ["liteDebug", "prodDebug"] 36 | 37 | /* Bundling */ 38 | // A list containing the node command and its flags. Default is just 'node'. 39 | // nodeExecutableAndArgs = ["node"] 40 | 41 | // 42 | // The path to the CLI configuration file. Default is empty. 43 | // bundleConfig = file(../rn-cli.config.js) 44 | // 45 | // The name of the generated asset file containing your JS bundle 46 | // bundleAssetName = "MyApplication.android.bundle" 47 | // 48 | // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' 49 | // entryFile = file("../js/MyApplication.android.js") 50 | // 51 | // A list of extra flags to pass to the 'bundle' commands. 52 | // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle 53 | // extraPackagerArgs = [] 54 | 55 | /* Hermes Commands */ 56 | // The hermes compiler command to run. By default it is 'hermesc' 57 | // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" 58 | // 59 | // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" 60 | // hermesFlags = ["-O", "-output-source-map"] 61 | 62 | /* Autolinking */ 63 | autolinkLibrariesWithApp() 64 | } 65 | 66 | /** 67 | * Set this to true to Run Proguard on Release builds to minify the Java bytecode. 68 | */ 69 | def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInReleaseBuilds') ?: false).toBoolean() 70 | 71 | /** 72 | * The preferred build flavor of JavaScriptCore (JSC) 73 | * 74 | * For example, to use the international variant, you can use: 75 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` 76 | * 77 | * The international variant includes ICU i18n library and necessary data 78 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that 79 | * give correct results when using with locales other than en-US. Note that 80 | * this variant is about 6MiB larger per architecture than default. 81 | */ 82 | def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+' 83 | 84 | android { 85 | ndkVersion rootProject.ext.ndkVersion 86 | 87 | buildToolsVersion rootProject.ext.buildToolsVersion 88 | compileSdk rootProject.ext.compileSdkVersion 89 | 90 | namespace 'com.teczer.exponativewindtypescriptboilerplate' 91 | defaultConfig { 92 | applicationId 'com.teczer.exponativewindtypescriptboilerplate' 93 | minSdkVersion rootProject.ext.minSdkVersion 94 | targetSdkVersion rootProject.ext.targetSdkVersion 95 | versionCode 1 96 | versionName "1.0.0" 97 | } 98 | signingConfigs { 99 | debug { 100 | storeFile file('debug.keystore') 101 | storePassword 'android' 102 | keyAlias 'androiddebugkey' 103 | keyPassword 'android' 104 | } 105 | } 106 | buildTypes { 107 | debug { 108 | signingConfig signingConfigs.debug 109 | } 110 | release { 111 | // Caution! In production, you need to generate your own keystore file. 112 | // see https://reactnative.dev/docs/signed-apk-android. 113 | signingConfig signingConfigs.debug 114 | shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false) 115 | minifyEnabled enableProguardInReleaseBuilds 116 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 117 | crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true) 118 | } 119 | } 120 | packagingOptions { 121 | jniLibs { 122 | useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false) 123 | } 124 | } 125 | androidResources { 126 | ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~' 127 | } 128 | } 129 | 130 | // Apply static values from `gradle.properties` to the `android.packagingOptions` 131 | // Accepts values in comma delimited lists, example: 132 | // android.packagingOptions.pickFirsts=/LICENSE,**/picasa.ini 133 | ["pickFirsts", "excludes", "merges", "doNotStrip"].each { prop -> 134 | // Split option: 'foo,bar' -> ['foo', 'bar'] 135 | def options = (findProperty("android.packagingOptions.$prop") ?: "").split(","); 136 | // Trim all elements in place. 137 | for (i in 0.. 0) { 142 | println "android.packagingOptions.$prop += $options ($options.length)" 143 | // Ex: android.packagingOptions.pickFirsts += '**/SCCS/**' 144 | options.each { 145 | android.packagingOptions[prop] += it 146 | } 147 | } 148 | } 149 | 150 | dependencies { 151 | // The version of react-native is set by the React Native Gradle Plugin 152 | implementation("com.facebook.react:react-android") 153 | 154 | def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true"; 155 | def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true"; 156 | def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true"; 157 | 158 | if (isGifEnabled) { 159 | // For animated gif support 160 | implementation("com.facebook.fresco:animated-gif:${expoLibs.versions.fresco.get()}") 161 | } 162 | 163 | if (isWebpEnabled) { 164 | // For webp support 165 | implementation("com.facebook.fresco:webpsupport:${expoLibs.versions.fresco.get()}") 166 | if (isWebpAnimatedEnabled) { 167 | // Animated webp support 168 | implementation("com.facebook.fresco:animated-webp:${expoLibs.versions.fresco.get()}") 169 | } 170 | } 171 | 172 | if (hermesEnabled.toBoolean()) { 173 | implementation("com.facebook.react:hermes-android") 174 | } else { 175 | implementation jscFlavor 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/debug.keystore -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # react-native-reanimated 11 | -keep class com.swmansion.reanimated.** { *; } 12 | -keep class com.facebook.react.turbomodule.** { *; } 13 | 14 | # Add any project specific keep options here: 15 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/teczer/exponativewindtypescriptboilerplate/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.teczer.exponativewindtypescriptboilerplate 2 | import expo.modules.splashscreen.SplashScreenManager 3 | 4 | import android.os.Build 5 | import android.os.Bundle 6 | 7 | import com.facebook.react.ReactActivity 8 | import com.facebook.react.ReactActivityDelegate 9 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled 10 | import com.facebook.react.defaults.DefaultReactActivityDelegate 11 | 12 | import expo.modules.ReactActivityDelegateWrapper 13 | 14 | class MainActivity : ReactActivity() { 15 | override fun onCreate(savedInstanceState: Bundle?) { 16 | // Set the theme to AppTheme BEFORE onCreate to support 17 | // coloring the background, status bar, and navigation bar. 18 | // This is required for expo-splash-screen. 19 | // setTheme(R.style.AppTheme); 20 | // @generated begin expo-splashscreen - expo prebuild (DO NOT MODIFY) sync-f3ff59a738c56c9a6119210cb55f0b613eb8b6af 21 | SplashScreenManager.registerOnActivity(this) 22 | // @generated end expo-splashscreen 23 | super.onCreate(null) 24 | } 25 | 26 | /** 27 | * Returns the name of the main component registered from JavaScript. This is used to schedule 28 | * rendering of the component. 29 | */ 30 | override fun getMainComponentName(): String = "main" 31 | 32 | /** 33 | * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] 34 | * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] 35 | */ 36 | override fun createReactActivityDelegate(): ReactActivityDelegate { 37 | return ReactActivityDelegateWrapper( 38 | this, 39 | BuildConfig.IS_NEW_ARCHITECTURE_ENABLED, 40 | object : DefaultReactActivityDelegate( 41 | this, 42 | mainComponentName, 43 | fabricEnabled 44 | ){}) 45 | } 46 | 47 | /** 48 | * Align the back button behavior with Android S 49 | * where moving root activities to background instead of finishing activities. 50 | * @see onBackPressed 51 | */ 52 | override fun invokeDefaultOnBackPressed() { 53 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) { 54 | if (!moveTaskToBack(false)) { 55 | // For non-root activities, use the default implementation to finish them. 56 | super.invokeDefaultOnBackPressed() 57 | } 58 | return 59 | } 60 | 61 | // Use the default back button implementation on Android S 62 | // because it's doing more than [Activity.moveTaskToBack] in fact. 63 | super.invokeDefaultOnBackPressed() 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/teczer/exponativewindtypescriptboilerplate/MainApplication.kt: -------------------------------------------------------------------------------- 1 | package com.teczer.exponativewindtypescriptboilerplate 2 | 3 | import android.app.Application 4 | import android.content.res.Configuration 5 | 6 | import com.facebook.react.PackageList 7 | import com.facebook.react.ReactApplication 8 | import com.facebook.react.ReactNativeHost 9 | import com.facebook.react.ReactPackage 10 | import com.facebook.react.ReactHost 11 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load 12 | import com.facebook.react.defaults.DefaultReactNativeHost 13 | import com.facebook.react.soloader.OpenSourceMergedSoMapping 14 | import com.facebook.soloader.SoLoader 15 | 16 | import expo.modules.ApplicationLifecycleDispatcher 17 | import expo.modules.ReactNativeHostWrapper 18 | 19 | class MainApplication : Application(), ReactApplication { 20 | 21 | override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper( 22 | this, 23 | object : DefaultReactNativeHost(this) { 24 | override fun getPackages(): List { 25 | val packages = PackageList(this).packages 26 | // Packages that cannot be autolinked yet can be added manually here, for example: 27 | // packages.add(MyReactNativePackage()) 28 | return packages 29 | } 30 | 31 | override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry" 32 | 33 | override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG 34 | 35 | override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED 36 | override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED 37 | } 38 | ) 39 | 40 | override val reactHost: ReactHost 41 | get() = ReactNativeHostWrapper.createReactHost(applicationContext, reactNativeHost) 42 | 43 | override fun onCreate() { 44 | super.onCreate() 45 | SoLoader.init(this, OpenSourceMergedSoMapping) 46 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { 47 | // If you opted-in for the New Architecture, we load the native entry point for this app. 48 | load() 49 | } 50 | ApplicationLifecycleDispatcher.onApplicationCreate(this) 51 | } 52 | 53 | override fun onConfigurationChanged(newConfig: Configuration) { 54 | super.onConfigurationChanged(newConfig) 55 | ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/splashscreen_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/drawable-hdpi/splashscreen_logo.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/splashscreen_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/drawable-mdpi/splashscreen_logo.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/rn_edit_text_material.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 22 | 23 | 24 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/colors.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | #ffffff 3 | #ffffff 4 | #023c69 5 | #ffffff 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | expo-nativewind-typescript-boilerplate 3 | contain 4 | false 5 | automatic 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | google() 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath('com.android.tools.build:gradle') 10 | classpath('com.facebook.react:react-native-gradle-plugin') 11 | classpath('org.jetbrains.kotlin:kotlin-gradle-plugin') 12 | } 13 | } 14 | 15 | def reactNativeAndroidDir = new File( 16 | providers.exec { 17 | workingDir(rootDir) 18 | commandLine("node", "--print", "require.resolve('react-native/package.json')") 19 | }.standardOutput.asText.get().trim(), 20 | "../android" 21 | ) 22 | 23 | allprojects { 24 | repositories { 25 | maven { 26 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 27 | url(reactNativeAndroidDir) 28 | } 29 | 30 | google() 31 | mavenCentral() 32 | maven { url 'https://www.jitpack.io' } 33 | } 34 | } 35 | 36 | apply plugin: "expo-root-project" 37 | apply plugin: "com.facebook.react.rootproject" 38 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m 13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | 25 | # Enable AAPT2 PNG crunching 26 | android.enablePngCrunchInReleaseBuilds=true 27 | 28 | # Use this property to specify which architecture you want to build. 29 | # You can also override it from the CLI using 30 | # ./gradlew -PreactNativeArchitectures=x86_64 31 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 32 | 33 | # Use this property to enable support to the new architecture. 34 | # This will allow you to use TurboModules and the Fabric render in 35 | # your application. You should enable this flag either if you want 36 | # to write custom TurboModules/Fabric components OR use libraries that 37 | # are providing them. 38 | newArchEnabled=true 39 | 40 | # Use this property to enable or disable the Hermes JS engine. 41 | # If set to false, you will be using JSC instead. 42 | hermesEnabled=true 43 | 44 | # Enable GIF support in React Native images (~200 B increase) 45 | expo.gif.enabled=true 46 | # Enable webp support in React Native images (~85 KB increase) 47 | expo.webp.enabled=true 48 | # Enable animated webp support (~3.4 MB increase) 49 | # Disabled by default because iOS doesn't support animated webp 50 | expo.webp.animated=false 51 | 52 | # Enable network inspector 53 | EX_DEV_CLIENT_NETWORK_INSPECTOR=true 54 | 55 | # Use legacy packaging to compress native libraries in the resulting APK. 56 | expo.useLegacyPackaging=false 57 | 58 | # Whether the app is configured to use edge-to-edge via the app config or `react-native-edge-to-edge` plugin 59 | expo.edgeToEdgeEnabled=true -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Teczer/expo-react-native-nativewind-typescript-boilerplate/20f755e588a3ace34a242973496a5a3c11bce3af/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | if ! command -v java >/dev/null 2>&1 137 | then 138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 139 | 140 | Please set the JAVA_HOME variable in your environment to match the 141 | location of your Java installation." 142 | fi 143 | fi 144 | 145 | # Increase the maximum file descriptors if we can. 146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 147 | case $MAX_FD in #( 148 | max*) 149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 150 | # shellcheck disable=SC2039,SC3045 151 | MAX_FD=$( ulimit -H -n ) || 152 | warn "Could not query maximum file descriptor limit" 153 | esac 154 | case $MAX_FD in #( 155 | '' | soft) :;; #( 156 | *) 157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 158 | # shellcheck disable=SC2039,SC3045 159 | ulimit -n "$MAX_FD" || 160 | warn "Could not set maximum file descriptor limit to $MAX_FD" 161 | esac 162 | fi 163 | 164 | # Collect all arguments for the java command, stacking in reverse order: 165 | # * args from the command line 166 | # * the main class name 167 | # * -classpath 168 | # * -D...appname settings 169 | # * --module-path (only if needed) 170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 171 | 172 | # For Cygwin or MSYS, switch paths to Windows format before running java 173 | if "$cygwin" || "$msys" ; then 174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 176 | 177 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 178 | 179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 180 | for arg do 181 | if 182 | case $arg in #( 183 | -*) false ;; # don't mess with options #( 184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 185 | [ -e "$t" ] ;; #( 186 | *) false ;; 187 | esac 188 | then 189 | arg=$( cygpath --path --ignore --mixed "$arg" ) 190 | fi 191 | # Roll the args list around exactly as many times as the number of 192 | # args, so each arg winds up back in the position where it started, but 193 | # possibly modified. 194 | # 195 | # NB: a `for` loop captures its iteration list before it begins, so 196 | # changing the positional parameters here affects neither the number of 197 | # iterations, nor the values presented in `arg`. 198 | shift # remove old arg 199 | set -- "$@" "$arg" # push replacement arg 200 | done 201 | fi 202 | 203 | 204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 205 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 206 | 207 | # Collect all arguments for the java command: 208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 209 | # and any embedded shellness will be escaped. 210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 211 | # treated as '${Hostname}' itself on the command line. 212 | 213 | set -- \ 214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 215 | -classpath "$CLASSPATH" \ 216 | org.gradle.wrapper.GradleWrapperMain \ 217 | "$@" 218 | 219 | # Stop when "xargs" is not available. 220 | if ! command -v xargs >/dev/null 2>&1 221 | then 222 | die "xargs is not available" 223 | fi 224 | 225 | # Use "xargs" to parse quoted args. 226 | # 227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 228 | # 229 | # In Bash we could simply go: 230 | # 231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 232 | # set -- "${ARGS[@]}" "$@" 233 | # 234 | # but POSIX shell has neither arrays nor command substitution, so instead we 235 | # post-process each arg (as a line of input to sed) to backslash-escape any 236 | # character that might be a shell metacharacter, then use eval to reverse 237 | # that process (while maintaining the separation between arguments), and wrap 238 | # the whole thing up as a single "set" statement. 239 | # 240 | # This will of course break if any of these variables contains a newline or 241 | # an unmatched quote. 242 | # 243 | 244 | eval "set -- $( 245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 246 | xargs -n1 | 247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 248 | tr '\n' ' ' 249 | )" '"$@"' 250 | 251 | exec "$JAVACMD" "$@" 252 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def reactNativeGradlePlugin = new File( 3 | providers.exec { 4 | workingDir(rootDir) 5 | commandLine("node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })") 6 | }.standardOutput.asText.get().trim() 7 | ).getParentFile().absolutePath 8 | includeBuild(reactNativeGradlePlugin) 9 | 10 | def expoPluginsPath = new File( 11 | providers.exec { 12 | workingDir(rootDir) 13 | commandLine("node", "--print", "require.resolve('expo-modules-autolinking/package.json', { paths: [require.resolve('expo/package.json')] })") 14 | }.standardOutput.asText.get().trim(), 15 | "../android/expo-gradle-plugin" 16 | ).absolutePath 17 | includeBuild(expoPluginsPath) 18 | } 19 | 20 | plugins { 21 | id("com.facebook.react.settings") 22 | id("expo-autolinking-settings") 23 | } 24 | 25 | extensions.configure(com.facebook.react.ReactSettingsExtension) { ex -> 26 | if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') { 27 | ex.autolinkLibrariesFromCommand() 28 | } else { 29 | ex.autolinkLibrariesFromCommand(expoAutolinking.rnConfigCommand) 30 | } 31 | } 32 | expoAutolinking.useExpoModules() 33 | 34 | rootProject.name = 'expo-nativewind-typescript-boilerplate' 35 | 36 | expoAutolinking.useExpoVersionCatalog() 37 | 38 | include ':app' 39 | includeBuild(expoAutolinking.reactNativeGradlePlugin) 40 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "expo-nativewind-typescript-boilerplate", 4 | "slug": "expo-nativewind-typescript-boilerplate", 5 | "version": "1.0.0", 6 | "orientation": "portrait", 7 | "icon": "./assets/images/icon.png", 8 | "scheme": "myapp", 9 | "userInterfaceStyle": "automatic", 10 | "expo": { 11 | "newArchEnabled": false 12 | }, 13 | "splash": { 14 | "image": "./assets/images/splash.png", 15 | "resizeMode": "contain", 16 | "backgroundColor": "#ffffff" 17 | }, 18 | "ios": { 19 | "supportsTablet": true, 20 | "bundleIdentifier": "com.teczer.expo-nativewind-typescript-boilerplate" 21 | }, 22 | "android": { 23 | "edgeToEdgeEnabled": true, 24 | "adaptiveIcon": { 25 | "foregroundImage": "./assets/images/adaptive-icon.png", 26 | "backgroundColor": "#ffffff" 27 | }, 28 | "package": "com.teczer.exponativewindtypescriptboilerplate" 29 | }, 30 | "web": { 31 | "bundler": "metro", 32 | "output": "static", 33 | "favicon": "./assets/images/favicon.png" 34 | }, 35 | "plugins": ["expo-router", "expo-font", "expo-web-browser"], 36 | "experiments": { 37 | "typedRoutes": true, 38 | "tsconfigPaths": true 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/(tabs)/_layout.tsx: -------------------------------------------------------------------------------- 1 | import { Link, Tabs } from 'expo-router'; 2 | import { Pressable } from 'react-native'; 3 | import { useColorScheme } from 'nativewind'; 4 | import FontAwesome from '@expo/vector-icons/FontAwesome'; 5 | 6 | import Colors from '@/constants/Colors'; 7 | 8 | // You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/ 9 | function TabBarIcon(props: { name: React.ComponentProps['name']; color: string }) { 10 | return ; 11 | } 12 | 13 | export default function TabLayout() { 14 | const { colorScheme } = useColorScheme(); 15 | 16 | return ( 17 | 25 | ( 29 | 30 | 31 | {({ pressed }) => ( 32 | 38 | )} 39 | 40 | 41 | ), 42 | tabBarIcon: ({ color }) => , 43 | title: 'Home', 44 | }} 45 | /> 46 | , 50 | title: 'Settings', 51 | }} 52 | /> 53 | 54 | ); 55 | } 56 | -------------------------------------------------------------------------------- /app/(tabs)/index.tsx: -------------------------------------------------------------------------------- 1 | import { View, Text } from 'react-native'; 2 | 3 | import { ExternalLink } from '@/components/ExternalLink'; 4 | 5 | export default function TabOneScreen() { 6 | return ( 7 | 8 | Home 9 | 10 | Text with custom font (SpaceMono x NativeWind) 11 | 12 | 13 | 14 | 15 | 16 | Tap here if your app doesn't automatically update after making changes 17 | 18 | 19 | 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /app/(tabs)/settings.tsx: -------------------------------------------------------------------------------- 1 | import { useColorScheme } from 'nativewind'; 2 | import { StatusBar } from 'expo-status-bar'; 3 | import { Platform, Text, View } from 'react-native'; 4 | import { SafeAreaView } from 'react-native-safe-area-context'; 5 | 6 | import ToggleTheme from '@/components/ToggleTheme'; 7 | 8 | export default function TabTwoScreen() { 9 | const { colorScheme, setColorScheme } = useColorScheme(); 10 | return ( 11 | 12 | Settings 13 | {/* THEME SETTINGS */} 14 | 15 | Theme Settings 16 | 17 | 18 | 19 | 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /app/+html.tsx: -------------------------------------------------------------------------------- 1 | import { ScrollViewStyleReset } from 'expo-router/html'; 2 | 3 | // This file is web-only and used to configure the root HTML for every 4 | // web page during static rendering. 5 | // The contents of this function only run in Node.js environments and 6 | // do not have access to the DOM or browser APIs. 7 | export default function Root({ children }: { children: React.ReactNode }) { 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | 15 | {/* 16 | Disable body scrolling on web. This makes ScrollView components work closer to how they do on native. 17 | However, body scrolling is often nice to have for mobile web. If you want to enable it, remove this line. 18 | */} 19 | 20 | 21 | {/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */} 22 |