From 58a21d3471abc3aea66c538f4d698188b7c8e7bb Mon Sep 17 00:00:00 2001 From: Juozas Petkelis <juozas.petkelis@callstack.com> Date: Fri, 28 Mar 2025 15:09:21 +0200 Subject: [PATCH 01/14] feat: add nitro view template --- .../common/$.github/workflows/ci.yml | 4 +-- .../templates/common/$package.json | 10 +++---- .../templates/common/CONTRIBUTING.md | 4 ++- .../templates/common/README.md | 8 ++++-- .../native-common/android/build.gradle | 16 +++++------ .../native-common/{%- project.name %}.podspec | 2 +- .../nitro-view/android/CMakeLists.txt | 24 ++++++++++++++++ .../android/src/main/cpp/cpp-adapter.cpp | 6 ++++ .../{%- project.name %}.kt | 23 +++++++++++++++ .../{%- project.name %}Package.kt | 28 +++++++++++++++++++ .../nitro-view/ios/{%- project.name %}.swift | 28 +++++++++++++++++++ .../templates/nitro-view/nitro.json | 17 +++++++++++ .../templates/nitro-view/src/index.tsx | 8 ++++++ .../src/{%- project.name %}.nitro.ts | 12 ++++++++ 14 files changed, 171 insertions(+), 19 deletions(-) create mode 100644 packages/create-react-native-library/templates/nitro-view/android/CMakeLists.txt create mode 100644 packages/create-react-native-library/templates/nitro-view/android/src/main/cpp/cpp-adapter.cpp create mode 100644 packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/margelo/nitro/{%- project.package_dir %}/{%- project.name %}.kt create mode 100644 packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt create mode 100644 packages/create-react-native-library/templates/nitro-view/ios/{%- project.name %}.swift create mode 100644 packages/create-react-native-library/templates/nitro-view/nitro.json create mode 100644 packages/create-react-native-library/templates/nitro-view/src/index.tsx create mode 100644 packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts diff --git a/packages/create-react-native-library/templates/common/$.github/workflows/ci.yml b/packages/create-react-native-library/templates/common/$.github/workflows/ci.yml index 3cba52f1..9e791972 100644 --- a/packages/create-react-native-library/templates/common/$.github/workflows/ci.yml +++ b/packages/create-react-native-library/templates/common/$.github/workflows/ci.yml @@ -61,7 +61,7 @@ jobs: - name: Setup uses: ./.github/actions/setup -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> - name: Generate nitrogen code run: yarn nitrogen @@ -122,7 +122,7 @@ jobs: - name: Setup uses: ./.github/actions/setup -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> - name: Generate nitrogen code run: yarn nitrogen diff --git a/packages/create-react-native-library/templates/common/$package.json b/packages/create-react-native-library/templates/common/$package.json index cd773f35..32bfb613 100644 --- a/packages/create-react-native-library/templates/common/$package.json +++ b/packages/create-react-native-library/templates/common/$package.json @@ -52,7 +52,7 @@ "clean": "del-cli lib", <% } -%> "prepare": "bob build", -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> "nitrogen": "nitro-codegen", <% } -%> "release": "release-it" @@ -91,14 +91,14 @@ "eslint-config-prettier": "^9.0.0", "eslint-plugin-prettier": "^5.0.1", "jest": "^29.7.0", -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> "nitro-codegen": "^<%- versions.nitroCodegen %>", <% } -%> "prettier": "^3.0.3", "react": "17.0.2", "react-native": "0.73.0", "react-native-builder-bob": "^<%- versions.bob %>", -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> "react-native-nitro-modules": "^<%- versions.nitroModules %>", <% } -%> "release-it": "^17.10.0", @@ -112,7 +112,7 @@ }, "peerDependencies": { "react": "*", -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> "react-native": "*", "react-native-nitro-modules": "^<%- versions.nitroModules %>" <% } else { -%> @@ -191,7 +191,7 @@ "source": "src", "output": "lib", "targets": [ -<% if (project.moduleConfig === "nitro-modules") { -%> +<% if (project.moduleConfig === "nitro-modules" || project.viewConfig === "nitro-view") { -%> [ "custom", { diff --git a/packages/create-react-native-library/templates/common/CONTRIBUTING.md b/packages/create-react-native-library/templates/common/CONTRIBUTING.md index fa78e872..85cdcf56 100644 --- a/packages/create-react-native-library/templates/common/CONTRIBUTING.md +++ b/packages/create-react-native-library/templates/common/CONTRIBUTING.md @@ -18,13 +18,14 @@ yarn ``` > Since the project relies on Yarn workspaces, you cannot use [`npm`](https://github.com/npm/cli) for development. -<% if (project.moduleConfig === 'nitro-modules') { -%> +> <% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> This project uses Nitro Modules. If you're not familiar with how Nitro works, make sure to check the [Nitro Modules Docs](https://nitro.margelo.com/). You need to run [Nitrogen](https://nitro.margelo.com/docs/nitrogen) to generate the boilerplate code required for this project. The example app will not build without this step. Run **Nitrogen** in following cases: + - When you make changes to any `*.nitro.ts` files. - When running the project for the first time (since the generated files are not committed to the repository). @@ -33,6 +34,7 @@ To invoke **Nitrogen**, use the following command: ```sh yarn nitrogen ``` + <% } -%> The [example app](/example/) demonstrates usage of the library. You need to run it to test any changes you make. diff --git a/packages/create-react-native-library/templates/common/README.md b/packages/create-react-native-library/templates/common/README.md index 5b34c58f..aacb0cf3 100644 --- a/packages/create-react-native-library/templates/common/README.md +++ b/packages/create-react-native-library/templates/common/README.md @@ -4,16 +4,20 @@ ## Installation -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> + ```sh npm install <%- project.slug %> react-native-nitro-modules > `react-native-nitro-modules` is required as this library relies on [Nitro Modules](https://nitro.margelo.com/). ``` + <% } else { -%> + ```sh npm install <%- project.slug %> ``` + <% } -%> ## Usage @@ -28,7 +32,7 @@ import { <%- project.name -%>View } from "<%- project.slug -%>"; <<%- project.name -%>View color="tomato" /> ``` -<% } else if (project.moduleConfig === 'nitro-modules' || project.moduleConfig === 'turbo-modules') { -%> +<% } else if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view' || project.moduleConfig === 'turbo-modules') { -%> ```js import { multiply } from '<%- project.slug -%>'; diff --git a/packages/create-react-native-library/templates/native-common/android/build.gradle b/packages/create-react-native-library/templates/native-common/android/build.gradle index d7925a44..fa3912ca 100644 --- a/packages/create-react-native-library/templates/native-common/android/build.gradle +++ b/packages/create-react-native-library/templates/native-common/android/build.gradle @@ -15,7 +15,7 @@ buildscript { } } -<% if (project.cpp || project.moduleConfig === 'nitro-modules') { -%> +<% if (project.cpp || project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> def reactNativeArchitectures() { def value = rootProject.getProperties().get("reactNativeArchitectures") return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] @@ -24,7 +24,7 @@ def reactNativeArchitectures() { apply plugin: "com.android.library" apply plugin: "kotlin-android" -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> apply from: '../nitrogen/generated/android/<%- project.package_cpp -%>+autolinking.gradle' <% } -%> @@ -47,7 +47,7 @@ def supportsNamespace() { android { if (supportsNamespace()) { -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> namespace "com.margelo.nitro.<%- project.package -%>" <% } else { -%> namespace "com.<%- project.package -%>" @@ -68,7 +68,7 @@ android { defaultConfig { minSdkVersion getExtOrIntegerDefault("minSdkVersion") targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") -<% if (project.cpp || project.moduleConfig === 'nitro-modules') { -%> +<% if (project.cpp || project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> externalNativeBuild { cmake { @@ -88,7 +88,7 @@ android { } <% } -%> } -<% if (project.cpp || project.moduleConfig === 'nitro-modules') { -%> +<% if (project.cpp || project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> externalNativeBuild { cmake { @@ -96,7 +96,7 @@ android { } } <% } -%> -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> packagingOptions { excludes = [ @@ -123,7 +123,7 @@ android { buildFeatures { buildConfig true -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> prefab true <% } -%> } @@ -166,7 +166,7 @@ def kotlin_version = getExtOrDefault("kotlinVersion") dependencies { implementation "com.facebook.react:react-android" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" -<% if (project.moduleConfig === 'nitro-modules') { -%> +<% if (project.moduleConfig === 'nitro-modules' || project.viewConfig === 'nitro-view') { -%> implementation project(":react-native-nitro-modules") <% } -%> } diff --git a/packages/create-react-native-library/templates/native-common/{%- project.name %}.podspec b/packages/create-react-native-library/templates/native-common/{%- project.name %}.podspec index 1c440cfb..5327b690 100644 --- a/packages/create-react-native-library/templates/native-common/{%- project.name %}.podspec +++ b/packages/create-react-native-library/templates/native-common/{%- project.name %}.podspec @@ -23,7 +23,7 @@ Pod::Spec.new do |s| <% } else { -%> s.source_files = "ios/**/*.{h,m,mm}" <% } -%> -<% if (project.moduleConfig === "nitro-modules") { -%> +<% if (project.moduleConfig === "nitro-modules" || project.viewConfig === "nitro-view") { -%> load 'nitrogen/generated/ios/<%- project.name -%>+autolinking.rb' add_nitrogen_files(s) diff --git a/packages/create-react-native-library/templates/nitro-view/android/CMakeLists.txt b/packages/create-react-native-library/templates/nitro-view/android/CMakeLists.txt new file mode 100644 index 00000000..1fa9ed39 --- /dev/null +++ b/packages/create-react-native-library/templates/nitro-view/android/CMakeLists.txt @@ -0,0 +1,24 @@ +project(<%- project.package_cpp -%>) +cmake_minimum_required(VERSION 3.9.0) + +set(PACKAGE_NAME <%- project.package_cpp -%>) +set(CMAKE_VERBOSE_MAKEFILE ON) +set(CMAKE_CXX_STANDARD 20) + +# Define C++ library and add all sources +add_library(${PACKAGE_NAME} SHARED src/main/cpp/cpp-adapter.cpp) + +# Add Nitrogen specs :) +include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/<%- project.package_cpp -%>+autolinking.cmake) + +# Set up local includes +include_directories("src/main/cpp" "../cpp") + +find_library(LOG_LIB log) + +# Link all libraries together +target_link_libraries( + ${PACKAGE_NAME} + ${LOG_LIB} + android # <-- Android core +) diff --git a/packages/create-react-native-library/templates/nitro-view/android/src/main/cpp/cpp-adapter.cpp b/packages/create-react-native-library/templates/nitro-view/android/src/main/cpp/cpp-adapter.cpp new file mode 100644 index 00000000..8e1f6123 --- /dev/null +++ b/packages/create-react-native-library/templates/nitro-view/android/src/main/cpp/cpp-adapter.cpp @@ -0,0 +1,6 @@ +#include <jni.h> +#include "<%- project.package_cpp -%>OnLoad.hpp" + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) { + return margelo::nitro::<%- project.package_cpp -%>::initialize(vm); +} diff --git a/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/margelo/nitro/{%- project.package_dir %}/{%- project.name %}.kt b/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/margelo/nitro/{%- project.package_dir %}/{%- project.name %}.kt new file mode 100644 index 00000000..9634f8d5 --- /dev/null +++ b/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/margelo/nitro/{%- project.package_dir %}/{%- project.name %}.kt @@ -0,0 +1,23 @@ +package com.margelo.nitro.<%- project.package %> + +import android.view.View +import com.facebook.proguard.annotations.DoNotStrip +import com.facebook.react.uimanager.ThemedReactContext +import androidx.core.graphics.toColorInt + +@DoNotStrip +class Hybrid<%- project.name %>(val context: ThemedReactContext) : Hybrid<%- project.name %>Spec() { + + // View + override val view: View = View(context) + + // Props + private var _color = "#000" + override var color: String + get() = _color + set(value) { + _color = value + val color = value.toColorInt() + view.setBackgroundColor(color) + } +} diff --git a/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt b/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt new file mode 100644 index 00000000..c2ceba5a --- /dev/null +++ b/packages/create-react-native-library/templates/nitro-view/android/src/main/java/com/{%- project.package_dir %}/{%- project.name %}Package.kt @@ -0,0 +1,28 @@ +package com.<%- project.package %> + +import com.facebook.react.TurboReactPackage +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.module.model.ReactModuleInfoProvider +import com.facebook.react.uimanager.ViewManager +import com.margelo.nitro.<%- project.package_cpp -%>.views.Hybrid<%- project.name -%>Manager + +class <%- project.name -%>Package : TurboReactPackage() { + override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? { + return null + } + + override fun getReactModuleInfoProvider(): ReactModuleInfoProvider { + return ReactModuleInfoProvider { HashMap() } + } + + override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> { + return listOf(Hybrid<%- project.name -%>Manager()) + } + + companion object { + init { + System.loadLibrary("<%- project.package_cpp -%>") + } + } +} diff --git a/packages/create-react-native-library/templates/nitro-view/ios/{%- project.name %}.swift b/packages/create-react-native-library/templates/nitro-view/ios/{%- project.name %}.swift new file mode 100644 index 00000000..0e4c8ef3 --- /dev/null +++ b/packages/create-react-native-library/templates/nitro-view/ios/{%- project.name %}.swift @@ -0,0 +1,28 @@ +class Hybrid<%- project.name -%> : Hybrid<%- project.name -%>Spec { + + // UIView + var view: UIView = UIView() + + // props + var color: String = "#000" { + didSet { + view.backgroundColor = hexStringToUIColor(hexColor: color) + } + } + + func hexStringToUIColor(hexColor: String) -> UIColor { + let stringScanner = Scanner(string: hexColor) + + if(hexColor.hasPrefix("#")) { + stringScanner.scanLocation = 1 + } + var color: UInt32 = 0 + stringScanner.scanHexInt32(&color) + + let r = CGFloat(Int(color >> 16) & 0x000000FF) + let g = CGFloat(Int(color >> 8) & 0x000000FF) + let b = CGFloat(Int(color) & 0x000000FF) + + return UIColor(red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: 1) + } +} diff --git a/packages/create-react-native-library/templates/nitro-view/nitro.json b/packages/create-react-native-library/templates/nitro-view/nitro.json new file mode 100644 index 00000000..78941a51 --- /dev/null +++ b/packages/create-react-native-library/templates/nitro-view/nitro.json @@ -0,0 +1,17 @@ +{ + "cxxNamespace": ["<%- project.package_cpp -%>"], + "ios": { + "iosModuleName": "<%- project.name -%>" + }, + "android": { + "androidNamespace": <%- JSON.stringify(project.package.split('.')) -%>, + "androidCxxLibName": "<%- project.package_cpp -%>" + }, + "autolinking": { + "<%- project.name -%>": { + "swift": "Hybrid<%- project.name -%>", + "kotlin": "Hybrid<%- project.name -%>" + } + }, + "ignorePaths": ["node_modules"] +} diff --git a/packages/create-react-native-library/templates/nitro-view/src/index.tsx b/packages/create-react-native-library/templates/nitro-view/src/index.tsx new file mode 100644 index 00000000..67a42c92 --- /dev/null +++ b/packages/create-react-native-library/templates/nitro-view/src/index.tsx @@ -0,0 +1,8 @@ +import { getHostComponent } from 'react-native-nitro-modules'; +import <%- project.name %>Config from '../nitrogen/generated/shared/json/<%- project.name %>Config.json'; +import type { <%- project.name %>Methods, <%- project.name %>Props } from './<%- project.name %>.nitro'; + +export const <%- project.name %>View = getHostComponent<<%- project.name %>Props, <%- project.name %>Methods>( + '<%- project.name %>', + () => <%- project.name %>Config +); diff --git a/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts b/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts new file mode 100644 index 00000000..467dcf83 --- /dev/null +++ b/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts @@ -0,0 +1,12 @@ +import type { + HybridView, + HybridViewMethods, + HybridViewProps, +} from 'react-native-nitro-modules'; + +export interface <%- project.name %>Props extends HybridViewProps { + color: string; +} +export interface <%- project.name %>Methods extends HybridViewMethods {} + +export type <%- project.name %> = HybridView<<%- project.name %>Props, <%- project.name %>Methods>; From ce5ed31b70141abd4fed5fcebb02314f8e12513c Mon Sep 17 00:00:00 2001 From: Juozas Petkelis <juozas.petkelis@callstack.com> Date: Fri, 28 Mar 2025 15:30:54 +0200 Subject: [PATCH 02/14] chore: change nitro modules version to 0.25.2 --- packages/create-react-native-library/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/create-react-native-library/src/index.ts b/packages/create-react-native-library/src/index.ts index f109da15..9f01610b 100644 --- a/packages/create-react-native-library/src/index.ts +++ b/packages/create-react-native-library/src/index.ts @@ -21,7 +21,7 @@ import { getDependencyVersionsFromExampleApp } from './exampleApp/dependencies'; import { printErrorHelp, printNextSteps, printUsedRNVersion } from './inform'; const FALLBACK_BOB_VERSION = '0.36.0'; -const FALLBACK_NITRO_MODULES_VERSION = '0.22.1'; +const FALLBACK_NITRO_MODULES_VERSION = '0.25.2'; yargs .command( From ba232d23874cb835713a28389e220b76785a01f0 Mon Sep 17 00:00:00 2001 From: Juozas Petkelis <juozas.petkelis@callstack.com> Date: Fri, 28 Mar 2025 15:31:47 +0200 Subject: [PATCH 03/14] feat: add nitro view to template creation --- .../src/exampleApp/generateExampleApp.ts | 5 ++++- packages/create-react-native-library/src/index.ts | 3 +-- packages/create-react-native-library/src/input.ts | 9 ++++++++- packages/create-react-native-library/src/template.ts | 10 +++++++++- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts b/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts index 457897fb..646a95ce 100644 --- a/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts +++ b/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts @@ -181,7 +181,10 @@ export default async function generateExampleApp({ 'react-native-builder-bob': `^${config.versions.bob}`, }; - if (config.project.moduleConfig === 'nitro-modules') { + if ( + config.project.moduleConfig === 'nitro-modules' || + config.project.viewConfig === 'nitro-view' + ) { const packagesToAddNitro = { 'react-native-nitro-modules': `^${config.versions.nitroModules}`, }; diff --git a/packages/create-react-native-library/src/index.ts b/packages/create-react-native-library/src/index.ts index 9f01610b..4ffbe12c 100644 --- a/packages/create-react-native-library/src/index.ts +++ b/packages/create-react-native-library/src/index.ts @@ -74,9 +74,8 @@ async function create(_argv: yargs.Arguments<Args>) { assertUserInput(questions, answers); const bobVersion = await bobVersionPromise; - const nitroModulesVersion = - answers.type === 'nitro-module' + answers.type === 'nitro-module' || answers.type === 'nitro-view' ? await nitroModulesVersionPromise : undefined; diff --git a/packages/create-react-native-library/src/input.ts b/packages/create-react-native-library/src/input.ts index 3d9c8f88..73b9d3bc 100644 --- a/packages/create-react-native-library/src/input.ts +++ b/packages/create-react-native-library/src/input.ts @@ -26,6 +26,7 @@ export type ProjectType = | 'legacy-module' | 'legacy-view' | 'nitro-module' + | 'nitro-view' | 'library'; const LANGUAGE_CHOICES: { @@ -36,7 +37,7 @@ const LANGUAGE_CHOICES: { { title: 'Kotlin & Swift', value: 'kotlin-swift', - types: ['nitro-module', 'legacy-module', 'legacy-view'], + types: ['nitro-view', 'nitro-module', 'legacy-module', 'legacy-view'], }, { title: 'Kotlin & Objective-C', @@ -96,6 +97,12 @@ const TYPE_CHOICES: { description: 'type-safe, fast integration for native APIs to JS (experimental)', }, + { + title: 'Nitro View', + value: 'nitro-view', + description: + 'integration for native views to JS using nitro for prop parsing (experimental)', + }, { title: 'Fabric view', value: 'fabric-view', diff --git a/packages/create-react-native-library/src/template.ts b/packages/create-react-native-library/src/template.ts index c003891c..b70fd75b 100644 --- a/packages/create-react-native-library/src/template.ts +++ b/packages/create-react-native-library/src/template.ts @@ -20,7 +20,7 @@ export type ModuleConfig = | 'nitro-modules' | null; -export type ViewConfig = 'paper-view' | 'fabric-view' | null; +export type ViewConfig = 'paper-view' | 'fabric-view' | 'nitro-view' | null; // Please think at least 5 times before introducing a new config key // You can just reuse the existing ones most of the time @@ -90,6 +90,7 @@ const NATIVE_FILES = { view_legacy: path.resolve(__dirname, '../templates/native-view-legacy'), view_new: path.resolve(__dirname, '../templates/native-view-new'), module_nitro: path.resolve(__dirname, '../templates/nitro-module'), + view_nitro: path.resolve(__dirname, '../templates/nitro-view'), } as const; const OBJC_FILES = { @@ -195,6 +196,8 @@ function getViewConfig(projectType: ProjectType): ViewConfig { return 'paper-view'; case 'fabric-view': return 'fabric-view'; + case 'nitro-view': + return 'nitro-view'; default: return null; } @@ -241,6 +244,11 @@ export async function applyTemplates( return; } + if (config.project.viewConfig === 'nitro-view') { + await applyTemplate(config, NATIVE_FILES['view_nitro'], folder); + return; + } + if (config.project.moduleConfig !== null) { await applyTemplate( config, From 82fdf09086c4859113668abc67217ee7a9d63708 Mon Sep 17 00:00:00 2001 From: Juozas Petkelis <juozas.petkelis@callstack.com> Date: Fri, 28 Mar 2025 15:35:46 +0200 Subject: [PATCH 04/14] feat: ios16 min deployment for nitro modules example app --- .../src/exampleApp/generateExampleApp.ts | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts b/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts index 646a95ce..b71ff0c3 100644 --- a/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts +++ b/packages/create-react-native-library/src/exampleApp/generateExampleApp.ts @@ -300,6 +300,76 @@ export default async function generateExampleApp({ } } + // nitro modules on xcode 16.2 requires ios 16 version because of the bug https://github.com/swiftlang/swift/issues/77909 + // full thread in https://github.com/mrousavy/nitro/issues/422 + if ( + config.project.viewConfig === 'nitro-view' || + config.project.moduleConfig === 'nitro-modules' + ) { + const newTargetVersion = 16.0; + + const podfile = await fs.readFile( + path.join(directory, 'ios', 'Podfile'), + 'utf8' + ); + + const postInstallLine = 'post_install do |installer|'; + // set pods deployement min version + const podVersionOverride = ` + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '${newTargetVersion}' + end + end + `; + + const insertionIndex = podfile.indexOf(postInstallLine); + + if (insertionIndex !== -1) { + const endOfMarkerLineIndex = podfile.indexOf('\n', insertionIndex); + + if (endOfMarkerLineIndex !== -1) { + const updatedPodfileContent = + podfile.slice(0, endOfMarkerLineIndex) + + podVersionOverride + + podfile.slice(endOfMarkerLineIndex); + + await fs.writeFile( + path.join(directory, 'ios', 'Podfile'), + updatedPodfileContent + ); + } + } + + // set project deployement min version + const project = await fs.readFile( + path.join( + directory, + `ios/${config.project.name}Example.xcodeproj`, + 'project.pbxproj' + ), + 'utf8' + ); + + // match whole IPHONEOS_DEPLOYMENT_TARGET line + const deployementLineRegex = + /^(\s*)IPHONEOS_DEPLOYMENT_TARGET\s*=\s*[^;]+;$/gm; + const replacementPattern = `$1IPHONEOS_DEPLOYMENT_TARGET = ${newTargetVersion};`; + const updatedContent = project.replace( + deployementLineRegex, + replacementPattern + ); + + await fs.writeFile( + path.join( + directory, + `ios/${config.project.name}Example.xcodeproj`, + 'project.pbxproj' + ), + updatedContent + ); + } + await fs.writeFile( path.join(directory, 'android', 'gradle.properties'), gradleProperties From 4595d45004bee5352ff607e2bafe9ecb5310a614 Mon Sep 17 00:00:00 2001 From: Juozas Petkelis <juozas.petkelis@callstack.com> Date: Fri, 28 Mar 2025 16:43:52 +0200 Subject: [PATCH 05/14] chore: remove autospace in readme From f124db5f47a6f79895a636d6528548a1fdfef1ca Mon Sep 17 00:00:00 2001 From: Juozas Petkelis <juozas.petkelis@callstack.com> Date: Fri, 28 Mar 2025 16:45:11 +0200 Subject: [PATCH 06/14] chore: lower case Nitro view in selection --- packages/create-react-native-library/src/input.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/create-react-native-library/src/input.ts b/packages/create-react-native-library/src/input.ts index 73b9d3bc..8311c025 100644 --- a/packages/create-react-native-library/src/input.ts +++ b/packages/create-react-native-library/src/input.ts @@ -98,7 +98,7 @@ const TYPE_CHOICES: { 'type-safe, fast integration for native APIs to JS (experimental)', }, { - title: 'Nitro View', + title: 'Nitro view', value: 'nitro-view', description: 'integration for native views to JS using nitro for prop parsing (experimental)', From 6e003c8e86338ee19458602a9ba17bdc259aae98 Mon Sep 17 00:00:00 2001 From: Juozas Petkelis <juozas.petkelis@callstack.com> Date: Mon, 31 Mar 2025 16:09:30 +0300 Subject: [PATCH 07/14] fix: add nitro view to CI matrix --- .github/workflows/build-templates.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build-templates.yml b/.github/workflows/build-templates.yml index 73d5df0b..cf7a7435 100644 --- a/.github/workflows/build-templates.yml +++ b/.github/workflows/build-templates.yml @@ -35,6 +35,7 @@ jobs: - legacy-module - legacy-view - nitro-module + - nitro-view language: - kotlin-objc - kotlin-swift @@ -52,6 +53,10 @@ jobs: language: kotlin-objc - type: nitro-module language: cpp + - type: nitro-view + language: kotlin-objc + - type: nitro-view + language: cpp include: - os: ubuntu type: library From 46c4f897d01be68f5013c5de76d3b8365a33c29a Mon Sep 17 00:00:00 2001 From: Juozas Petkelis <juozas.petkelis@callstack.com> Date: Mon, 31 Mar 2025 16:18:55 +0300 Subject: [PATCH 08/14] fix: prettier ci error --- .../templates/nitro-view/src/{%- project.name %}.nitro.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts b/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts index 467dcf83..2cbd723b 100644 --- a/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts +++ b/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts @@ -9,4 +9,7 @@ export interface <%- project.name %>Props extends HybridViewProps { } export interface <%- project.name %>Methods extends HybridViewMethods {} -export type <%- project.name %> = HybridView<<%- project.name %>Props, <%- project.name %>Methods>; +export type <%- project.name %> = HybridView< + <%- project.name %>Props, + <%- project.name %>Methods +>; \ No newline at end of file From 14496f07d0e2868bf3985761876a93fe6aa9db58 Mon Sep 17 00:00:00 2001 From: Juozas Petkelis <juozas.petkelis@callstack.com> Date: Mon, 31 Mar 2025 17:28:23 +0300 Subject: [PATCH 09/14] fix: prettier formatting for CI --- .../templates/nitro-view/src/index.tsx | 13 ++++++++----- .../nitro-view/src/{%- project.name %}.nitro.ts | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/create-react-native-library/templates/nitro-view/src/index.tsx b/packages/create-react-native-library/templates/nitro-view/src/index.tsx index 67a42c92..e260bef1 100644 --- a/packages/create-react-native-library/templates/nitro-view/src/index.tsx +++ b/packages/create-react-native-library/templates/nitro-view/src/index.tsx @@ -1,8 +1,11 @@ import { getHostComponent } from 'react-native-nitro-modules'; import <%- project.name %>Config from '../nitrogen/generated/shared/json/<%- project.name %>Config.json'; -import type { <%- project.name %>Methods, <%- project.name %>Props } from './<%- project.name %>.nitro'; +import type { + <%- project.name %>Methods, + <%- project.name %>Props, +} from './<%- project.name %>.nitro'; -export const <%- project.name %>View = getHostComponent<<%- project.name %>Props, <%- project.name %>Methods>( - '<%- project.name %>', - () => <%- project.name %>Config -); +export const <%- project.name %>View = getHostComponent< + <%- project.name %>Props, + <%- project.name %>Methods +>('<%- project.name %>', () => <%- project.name %>Config); diff --git a/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts b/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts index 2cbd723b..194477f9 100644 --- a/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts +++ b/packages/create-react-native-library/templates/nitro-view/src/{%- project.name %}.nitro.ts @@ -12,4 +12,4 @@ export interface <%- project.name %>Methods extends HybridViewMethods {} export type <%- project.name %> = HybridView< <%- project.name %>Props, <%- project.name %>Methods ->; \ No newline at end of file +>; From aa67b12dd6d7597fab06e4fd2b161391927ecafc Mon Sep 17 00:00:00 2001 From: Juozas Petkelis <juozas.petkelis@callstack.com> Date: Tue, 1 Apr 2025 17:18:45 +0300 Subject: [PATCH 10/14] fix: add nitrogen step in CI --- .github/workflows/build-templates.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build-templates.yml b/.github/workflows/build-templates.yml index cf7a7435..41cd2a5b 100644 --- a/.github/workflows/build-templates.yml +++ b/.github/workflows/build-templates.yml @@ -152,6 +152,10 @@ jobs: fi fi + - name: Generate nitrogen code + if: matrix.type == 'nitro-view' || matrix.type == 'nitro-module' + run: yarn nitrogen + - name: Cache turborepo if: env.android_build == 1 || env.ios_build == 1 uses: actions/cache@v4 From 02509386b744ecdaeab82df1f33202f251ccc10a Mon Sep 17 00:00:00 2001 From: Juozas Petkelis <juozas.petkelis@callstack.com> Date: Tue, 1 Apr 2025 17:25:43 +0300 Subject: [PATCH 11/14] fix: add full nitro-codegen command --- .github/workflows/build-templates.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-templates.yml b/.github/workflows/build-templates.yml index 41cd2a5b..ea365c10 100644 --- a/.github/workflows/build-templates.yml +++ b/.github/workflows/build-templates.yml @@ -154,7 +154,7 @@ jobs: - name: Generate nitrogen code if: matrix.type == 'nitro-view' || matrix.type == 'nitro-module' - run: yarn nitrogen + run: yarn nitro-codegen - name: Cache turborepo if: env.android_build == 1 || env.ios_build == 1 From 6ffc282e4eb5ca46ecd46dd5c22232a962a45967 Mon Sep 17 00:00:00 2001 From: Juozas Petkelis <juozas.petkelis@callstack.com> Date: Tue, 1 Apr 2025 17:32:19 +0300 Subject: [PATCH 12/14] fix: add working dir to nitrogen --- .github/workflows/build-templates.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-templates.yml b/.github/workflows/build-templates.yml index ea365c10..53d1e1ce 100644 --- a/.github/workflows/build-templates.yml +++ b/.github/workflows/build-templates.yml @@ -153,8 +153,9 @@ jobs: fi - name: Generate nitrogen code - if: matrix.type == 'nitro-view' || matrix.type == 'nitro-module' - run: yarn nitro-codegen + if: matrix.type == 'nitro-view' || matrix.type == 'nitro-module' + working-directory: ${{ env.work_dir }} + run: yarn nitrogen - name: Cache turborepo if: env.android_build == 1 || env.ios_build == 1 From e545ba33b45ea02338508e20feb11929cf366bed Mon Sep 17 00:00:00 2001 From: Juozas Petkelis <juozas.petkelis@callstack.com> Date: Fri, 4 Apr 2025 09:06:47 +0300 Subject: [PATCH 13/14] fix: change config json import to require --- .../templates/nitro-view/src/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/create-react-native-library/templates/nitro-view/src/index.tsx b/packages/create-react-native-library/templates/nitro-view/src/index.tsx index e260bef1..6d2946c1 100644 --- a/packages/create-react-native-library/templates/nitro-view/src/index.tsx +++ b/packages/create-react-native-library/templates/nitro-view/src/index.tsx @@ -1,5 +1,6 @@ import { getHostComponent } from 'react-native-nitro-modules'; -import <%- project.name %>Config from '../nitrogen/generated/shared/json/<%- project.name %>Config.json'; +// import <%- project.name %>Config from '../nitrogen/generated/shared/json/<%- project.name %>Config.json'; +const <%- project.name %>Config = require('../nitrogen/generated/shared/json/<%- project.name %>Config.json') import type { <%- project.name %>Methods, <%- project.name %>Props, From 1a21f3b115e58c1c0c121ab8c19f9801d7e28f41 Mon Sep 17 00:00:00 2001 From: Juozas Petkelis <juozas.petkelis@callstack.com> Date: Fri, 4 Apr 2025 09:20:36 +0300 Subject: [PATCH 14/14] chore: prettier fix --- .../templates/nitro-view/src/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/create-react-native-library/templates/nitro-view/src/index.tsx b/packages/create-react-native-library/templates/nitro-view/src/index.tsx index 6d2946c1..2f1c9526 100644 --- a/packages/create-react-native-library/templates/nitro-view/src/index.tsx +++ b/packages/create-react-native-library/templates/nitro-view/src/index.tsx @@ -1,6 +1,5 @@ import { getHostComponent } from 'react-native-nitro-modules'; -// import <%- project.name %>Config from '../nitrogen/generated/shared/json/<%- project.name %>Config.json'; -const <%- project.name %>Config = require('../nitrogen/generated/shared/json/<%- project.name %>Config.json') +const <%- project.name %>Config = require('../nitrogen/generated/shared/json/<%- project.name %>Config.json'); import type { <%- project.name %>Methods, <%- project.name %>Props,