From 060573c27c494bb5740f413c5bb12bad78c95a83 Mon Sep 17 00:00:00 2001 From: Yedidya Kennard Date: Thu, 5 Feb 2026 16:03:36 +0200 Subject: [PATCH 1/3] Add comprehensive architecture documentation Add ARCHITECTURE.md files documenting the project structure and internals: - Root ARCHITECTURE.md: High-level overview, layout types, data flow, patterns - src/ARCHITECTURE.md: JavaScript/TypeScript layer, adapters, commands, events - ios/ARCHITECTURE.md: iOS native implementation, UIKit controllers, presenters - android/ARCHITECTURE.md: Android native implementation, ViewControllers, options These documents provide a complete reference for understanding how the library works, including the processing pipeline, native bridges (TurboModule support), component lifecycle, and platform-specific implementations. Co-Authored-By: Claude Opus 4.5 --- ARCHITECTURE.md | 164 +++++++++++++++++ android/ARCHITECTURE.md | 393 ++++++++++++++++++++++++++++++++++++++++ ios/ARCHITECTURE.md | 354 ++++++++++++++++++++++++++++++++++++ src/ARCHITECTURE.md | 301 ++++++++++++++++++++++++++++++ 4 files changed, 1212 insertions(+) create mode 100644 ARCHITECTURE.md create mode 100644 android/ARCHITECTURE.md create mode 100644 ios/ARCHITECTURE.md create mode 100644 src/ARCHITECTURE.md diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000000..c3b6a8bebd --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,164 @@ +# React Native Navigation Architecture + +React Native Navigation (RNN) is a native navigation library for React Native that provides 100% native platform navigation on both iOS and Android through a unified JavaScript API. + +## Project Overview + +- **Package**: `react-native-navigation` (v8.7.0) +- **Platforms**: iOS 11+, Android 7.0+ (API 24) +- **React Native**: 0.77+ (developed against 0.83; see package.json for current version) +- **License**: MIT (maintained by Wix) + +## Directory Structure + +``` +react-native-navigation/ +├── src/ # TypeScript source code (JS API layer) +├── lib/ # Compiled output (generated by bob build - do not edit) +├── android/ # Android native implementation (Java/Kotlin) +├── ios/ # iOS native implementation (Obj-C/C++) +├── playground/ # Demo app and E2E test target +├── autolink/ # Post-install linking scripts +├── scripts/ # Build, test, and release scripts +├── website/ # Docusaurus documentation site +├── integration/ # Integration tests (Redux, Remx) +├── Mock/ # Mock implementations for testing +└── .buildkite/ # CI/CD pipeline configuration +``` + +## High-Level Architecture + +``` +┌──────────────────────────────────────────────────────────────────┐ +│ JavaScript API Layer │ +│ Navigation.setRoot() / push() / pop() / showModal() / etc. │ +└─────────────────────────────┬────────────────────────────────────┘ + │ +┌─────────────────────────────▼────────────────────────────────────┐ +│ Processing Pipeline │ +│ OptionsCrawler → LayoutProcessor → LayoutTreeParser → OptionsProcessor │ +└─────────────────────────────┬────────────────────────────────────┘ + │ +┌─────────────────────────────▼────────────────────────────────────┐ +│ TurboModule Bridge │ +│ NativeCommandsSender ←→ RNNTurboModule (iOS) / NavigationTurboModule (Android) │ +└──────────┬─────────────────────────────────────┬─────────────────┘ + │ │ +┌──────────▼──────────┐ ┌─────────▼──────────┐ +│ iOS Native Layer │ │ Android Native Layer│ +│ UINavigationController │ ViewControllers │ +│ UITabBarController │ │ CoordinatorLayout │ +│ UIViewController │ │ BottomNavigation │ +└─────────────────────┘ └────────────────────┘ +``` + +## Core Concepts + +### Layout Types +All navigation structures are composed from these layout primitives: + +| Layout Type | Description | iOS Implementation | Android Implementation | +|-------------|-------------|-------------------|----------------------| +| `component` | React component screen | RNNComponentViewController | ComponentViewController | +| `stack` | Push/pop navigation | UINavigationController (RNNStackController) | StackController | +| `bottomTabs` | Tab bar navigation | UITabBarController (RNNBottomTabsController) | BottomTabsController | +| `topTabs` | Horizontal scrollable tabs | RNNTopTabsViewController | TopTabsController | +| `sideMenu` | Drawer navigation (with center, left, right) | MMDrawerController (RNNSideMenuViewController) | SideMenuController | +| `splitView` | Master-detail (iPad only) | UISplitViewController (RNNSplitViewController) | — | +| `externalComponent` | Native (non-React) screen | RNNExternalViewController | ExternalComponentViewController | + +### Navigation Commands +Core commands available through the Navigation API: + +- **Root**: `setRoot()` - Replace entire navigation hierarchy +- **Stack**: `push()`, `pop()`, `popTo()`, `popToRoot()`, `setStackRoot()` +- **Modal**: `showModal()`, `dismissModal()`, `dismissAllModals()` +- **Overlay**: `showOverlay()`, `dismissOverlay()`, `dismissAllOverlays()` +- **Options**: `setDefaultOptions()`, `mergeOptions()`, `updateProps()` + +### Options System +Styling and behavior is controlled via a hierarchical options object: + +```typescript +{ + statusBar: {...}, // Status bar appearance + topBar: {...}, // Navigation bar styling + bottomTabs: {...}, // Tab bar configuration + bottomTab: {...}, // Individual tab styling + sideMenu: {...}, // Drawer configuration + layout: {...}, // Screen layout options + animations: {...}, // Transition animations + modal: {...}, // Modal presentation style + overlay: {...} // Overlay behavior +} +``` + +Options merge in order: **Default Options → Parent Options → Component Options** + +## Data Flow + +### Command Execution Flow +``` +1. JS: Navigation.push(componentId, layout) +2. Commands.ts validates and begins processing +3. OptionsCrawler extracts static options from component classes +4. LayoutProcessor applies registered layout processors +5. LayoutTreeParser converts to internal LayoutNode tree +6. LayoutTreeCrawler processes tree, saves props to Store +7. OptionsProcessor resolves colors, images, fonts +8. NativeCommandsSender sends to TurboModule +9. Native layer creates/updates view hierarchy +10. EventEmitter sends completion event to JS +``` + +**Note**: The JS layer exports a single `Navigation` object (from `NavigationDelegate`). The TurboModule names differ per platform: `RNNTurboModule` on iOS, `NavigationTurboModule` on Android. + +### Event Flow (Native → JS) +``` +1. Native lifecycle event (viewDidAppear, etc.) +2. RNNEventEmitter (iOS) / EventEmitter (Android) +3. NativeEventsReceiver receives via NativeEventEmitter +4. EventsRegistry dispatches to registered listeners +5. ComponentEventsObserver calls component instance methods +``` + +## Key Architecture Patterns + +1. **Facade Pattern**: `NavigationDelegate` provides clean public API +2. **Bridge Pattern**: Adapters isolate JS from native implementation details +3. **Presenter Pattern**: Separates view styling from controller logic +4. **Observer Pattern**: Event system for lifecycle and command notifications +5. **Factory Pattern**: `LayoutFactory` creates controllers from layout nodes +6. **Plugin Pattern**: Processors allow extending layout/options handling + +## Component Lifecycle + +React components receive navigation lifecycle events: + +```typescript +class MyScreen extends NavigationComponent { + componentWillAppear(event) {} // About to become visible + componentDidAppear(event) {} // Now visible + componentDidDisappear(event) {} // No longer visible + navigationButtonPressed(event) {} // TopBar button tapped + screenPopped(event) {} // Screen removed from stack + searchBarUpdated(event) {} // Search text changed + searchBarCancelPressed(event) {} // Search cancelled + previewCompleted(event) {} // 3D Touch preview completed +} +``` + +## Testing Architecture + +- **Unit Tests**: Jest + ts-mockito for TypeScript source +- **Integration Tests**: Redux/Remx integration verification +- **E2E Tests**: Detox framework with playground app +- **Snapshot Tests**: iOS visual regression testing +- **Native Unit Tests**: XCTest (iOS) and JUnit (Android) + +## Related Documentation + +- [JavaScript/TypeScript Architecture](./src/ARCHITECTURE.md) +- [iOS Native Architecture](./ios/ARCHITECTURE.md) +- [Android Native Architecture](./android/ARCHITECTURE.md) +- [API Documentation](https://wix.github.io/react-native-navigation/) diff --git a/android/ARCHITECTURE.md b/android/ARCHITECTURE.md new file mode 100644 index 0000000000..a37b59aa92 --- /dev/null +++ b/android/ARCHITECTURE.md @@ -0,0 +1,393 @@ +# Android Native Architecture + +The Android implementation provides native navigation using Views and ViewGroups (not Fragments), coordinated through a TurboModule that receives commands from JavaScript. + +## Directory Structure + +``` +android/src/main/java/com/reactnativenavigation/ +├── NavigationActivity.java # Main Activity entry point +├── NavigationApplication.java # Application class +├── NavigationPackage.kt # React package registration +├── react/ # React bridge layer +│ ├── NavigationTurboModule.kt # TurboModule implementation +│ ├── ReactGateway.java # React lifecycle management +│ └── events/ +│ └── EventEmitter.java # Event emission to JS +├── options/ # Options parsing and factories +│ ├── LayoutFactory.java # Creates ViewControllers from layout nodes +│ └── Options.java # Options model +├── viewcontrollers/ # ViewController hierarchy +│ ├── ViewController.java # Base class +│ ├── ChildController.java # With presenter support +│ ├── ParentController.java # Container controllers +│ ├── stack/ # Stack navigation +│ ├── bottomtabs/ # Bottom tabs +│ ├── toptabs/ # Top tabs (lowercase) +│ ├── sidemenu/ # Side menu/drawer +│ ├── modal/ # Modal management +│ └── externalcomponent/ # Native component support +├── views/ # UI View implementations +├── utils/ # Utilities +└── hierarchy/ # Root layout management +``` + +## Bridge Architecture + +``` +┌────────────────────────────────────────────────────────────┐ +│ JavaScript (TurboModule) │ +└─────────────────────────┬──────────────────────────────────┘ + │ +┌─────────────────────────▼──────────────────────────────────┐ +│ NavigationTurboModule.kt │ +│ - setRoot, push, pop, showModal, dismissModal, etc. │ +└─────────────────────────┬──────────────────────────────────┘ + │ +┌─────────────────────────▼──────────────────────────────────┐ +│ Navigator (Root ViewController) │ +│ - Manages root, modals, overlays │ +│ - Coordinates LayoutFactory │ +└──────┬──────────────┬──────────────┬──────────────┬────────┘ + │ │ │ │ +┌──────▼─────┐ ┌──────▼─────┐ ┌──────▼─────┐ ┌─────▼──────┐ +│ModalStack │ │OverlayMgr │ │LayoutFactory│ │EventEmitter│ +└────────────┘ └────────────┘ └────────────┘ └────────────┘ +``` + +## Entry Points + +### NavigationApplication +Abstract Application class that apps extend: +- Manages `ReactGateway` singleton +- Initializes SoLoader +- Provides `registerExternalComponent()` for native screens + +### NavigationActivity +Main Activity containing all navigation: +- Creates `Navigator` with three CoordinatorLayouts: + - `rootLayout` - Main navigation content + - `modalsLayout` - Modal stack + - `overlaysLayout` - Overlays (highest z-order) +- Handles back press via `OnBackPressedCallback` +- Coordinates activity lifecycle with React + +### NavigationTurboModule +TurboModule implementation (Kotlin, ~300 lines): + +```kotlin +@ReactMethod +fun setRoot(commandId: String, layout: ReadableMap, promise: Promise) + +@ReactMethod +fun push(commandId: String, componentId: String, layout: ReadableMap, promise: Promise) + +@ReactMethod +fun showModal(commandId: String, layout: ReadableMap, promise: Promise) +``` + +All commands execute on UI thread via `UiThread.post()`. + +## ViewController Hierarchy + +**Note**: Android implementation does NOT use Fragments - it's purely View-based. + +``` +ViewController (abstract) +│ - Base for all navigation controllers +│ - Manages view creation and lifecycle +│ - Handles options and back press +│ +├── ChildController +│ │ - Adds Presenter support +│ │ +│ ├── ComponentViewController +│ │ - Renders React components via ReactView +│ │ +│ └── ExternalComponentViewController +│ - Wraps native Android views +│ +└── ParentController (extends ChildController) + - Container for child controllers + │ + ├── StackController + │ - Push/pop navigation + │ - Uses IdStack + │ + ├── BottomTabsController + │ - UITabBarController equivalent + │ - Uses AHBottomNavigation + │ + ├── TopTabsController + │ - Horizontal ViewPager tabs + │ + ├── SideMenuController + │ - DrawerLayout-based drawer + │ + └── Navigator + - Root controller + - Manages modals and overlays +``` + +## Core Classes + +### ViewController (Base) +**File**: `viewcontrollers/viewcontroller/ViewController.java` (~500 lines) + +Abstract base for all navigation controllers: + +```java +public abstract class ViewController { + protected abstract T createView(); // Subclasses create views + + public void onViewWillAppear() { } + public void onViewDidAppear() { } + public void onViewDisappear() { } + + public void mergeOptions(Options options) { } + public void applyOptions(Options options) { } + public boolean handleBack(CommandListener listener) { } + public void destroy() { } +} +``` + +### Navigator (Root) +**File**: `viewcontrollers/navigator/Navigator.java` + +Root ViewController managing: +- Root content hierarchy +- Modal stack (`ModalStack`) +- Overlay manager (`OverlayManager`) +- Component lookup by ID + +### LayoutFactory +**File**: `options/LayoutFactory.java` + +Factory creating ViewControllers from LayoutNode. Owned by `NavigationTurboModule` and used to build the view controller hierarchy when commands are received from JavaScript. + +```java +public ViewController create(LayoutNode node) { + switch (node.type) { + case Component: return createComponent(node); + case Stack: return createStack(node); + case BottomTabs: return createBottomTabs(node); + case SideMenuRoot: return createSideMenuRoot(node); + case SideMenuCenter: return createSideMenuContent(node); + case SideMenuLeft: return createSideMenuLeft(node); + case SideMenuRight: return createSideMenuRight(node); + case TopTabs: return createTopTabs(node); + // Note: SplitView is iOS-only, not implemented on Android + } +} +``` + +## Navigation Types + +### Stack Navigation (StackController) +**Files**: `viewcontrollers/stack/` + +- View: `StackLayout` (CoordinatorLayout with TopBar) +- Internal stack: `IdStack>` +- Components: `TopBarController`, `StackAnimator`, `StackPresenter`, `FabPresenter` + +Operations: +- `push(viewController, listener)` +- `pop(options, listener)` +- `popTo(target, options, listener)` +- `popToRoot(options, listener)` +- `setRoot(children, listener)` + +### Bottom Tabs (BottomTabsController) +**Files**: `viewcontrollers/bottomtabs/` + +- View: `BottomTabsLayout` (CoordinatorLayout with BottomTabs) +- Uses `AHBottomNavigation` library +- Components: `BottomTabsPresenter`, `BottomTabPresenter`, `BottomTabsAnimator` + +Attachment Modes: +- `TogetherAttacher` - Load all tabs immediately +- `OnSwitchToTabAttacher` - Lazy load on selection +- `AfterInitialTabAttacher` - Load initial + others in background + +### Side Menu (SideMenuController) +**Files**: `viewcontrollers/sidemenu/` + +- View: `SideMenuRoot` (DrawerLayout-based) +- Children: Center, Left, Right controllers +- `SideMenuPresenter` for styling + +### Top Tabs (TopTabsController) +**Files**: `viewcontrollers/toptabs/` + +- View: `TopTabsViewPager` (ViewPager-based) +- `TopTabsLayoutCreator` for view creation + +### Modals (ModalStack) +**Files**: `viewcontrollers/modal/` + +Not a ViewController - manages modal presentation: +- `ModalPresenter` - Show/dismiss with animations +- `ModalAnimator` (Kotlin) - Animation handling +- Stack of modals with lifecycle management + +### Overlays (OverlayManager) +**File**: `viewcontrollers/overlay/OverlayManager.kt` + +Registry of active overlays: +- Show/dismiss by component ID +- Configuration change handling +- Host pause/resume lifecycle + +## React Component Rendering + +### ComponentViewController +Manages React component lifecycle: +- Creates `ComponentLayout` view +- Initializes `ReactView` with ReactSurface +- Emits lifecycle events to JS +- Handles scroll events and status bar + +### ReactView +**File**: `react/ReactView.java` + +Extends FrameLayout, wraps `ReactSurface`: +- `start()` - Attach surface to React instance +- `destroy()` - Clean up React surface +- `sendComponentWillStart()` - Emit event to JS +- `isReady()` - Check surface attachment + +## Event Emission + +### EventEmitter +**File**: `react/events/EventEmitter.java` + +Events sent to JavaScript: + +| Event | Description | +|-------|-------------| +| `RNN.AppLaunched` | App initialization complete | +| `RNN.ComponentDidAppear` | Component visible | +| `RNN.ComponentWillAppear` | About to become visible | +| `RNN.ComponentDidDisappear` | Component hidden | +| `RNN.NavigationButtonPressed` | TopBar button tapped | +| `RNN.BottomTabSelected` | Tab selection changed | +| `RNN.BottomTabPressed` | Tab pressed (even if selected) | +| `RNN.ModalDismissed` | Modal was dismissed | +| `RNN.ScreenPopped` | Screen removed from stack | +| `RNN.CommandCompleted` | Navigation command finished | + +## Options System + +### Options Class +**File**: `options/Options.java` + +```java +public class Options { + public TopBarOptions topBar; + public TopTabsOptions topTabs; + public BottomTabsOptions bottomTabsOptions; + public BottomTabOptions bottomTabOptions; + public OverlayOptions overlayOptions; + public FabOptions fabOptions; + public AnimationsOptions animations; + public SideMenuRootOptions sideMenuRootOptions; + public ModalOptions modal; + public StatusBarOptions statusBar; + public NavigationBarOptions navigationBar; + public LayoutOptions layout; + public HardwareBackButtonOptions hardwareBack; +} +``` + +### Options Flow +1. **Parse**: JSON from JS → Options object via JSONParser +2. **Merge**: Default → Screen → Component options +3. **Apply**: Presenter applies to views + +## Presenter Pattern + +Each ViewController has a Presenter: + +| ViewController | Presenter | +|---------------|-----------| +| StackController | StackPresenter | +| BottomTabsController | BottomTabsPresenter + BottomTabPresenter | +| ComponentViewController | ComponentPresenter | +| SideMenuController | SideMenuPresenter | +| Navigator | RootPresenter | + +### Presenter Base +**File**: `viewcontrollers/viewcontroller/Presenter.java` + +Handles: +- Orientation changes +- Status bar styling +- Navigation bar styling +- Layout parameters + +## Animation System + +### Animators (Kotlin) +- `StackAnimator.kt` - Push, pop, setRoot animations +- `ModalAnimator.kt` - Modal show/dismiss +- `BottomTabsAnimator.kt` - Tab transitions +- `TopBarAppearanceAnimator.kt` - Top bar changes + +### Element Transitions +Via `TransitionAnimatorCreator.kt`: +- Position, scale, rotation animations +- Color transitions +- Corner radius animations +- Shared element support + +## Activity Lifecycle + +```java +onCreate() // Create Navigator, initialize React +onPostCreate() // Set content layout +onResume() // React host resume, event emitter setup +onPause() // React host pause +onDestroy() // Clean up Navigator +onConfigurationChanged() // Handle orientation, locale +onNewIntent() // Process deep links +onActivityResult() // Handle permissions +``` + +## ViewController Lifecycle + +``` +View creation + ↓ +onViewWillAppear() // Register with registry + ↓ +onViewDidAppear() // Emit event to JS + ↓ +[visible] + ↓ +onViewWillDisappear() + ↓ +onViewDisappear() // Unregister from registry + ↓ +destroy() // Complete cleanup +``` + +## Key Files Reference + +All paths relative to `android/src/main/java/com/reactnativenavigation/`: + +| File | Path | Purpose | +|------|------|---------| +| NavigationActivity.java | `.` | Main Activity | +| NavigationApplication.java | `.` | Application class | +| NavigationTurboModule.kt | `react/` | JS bridge | +| Navigator.java | `viewcontrollers/navigator/` | Root controller | +| ViewController.java | `viewcontrollers/viewcontroller/` | Base class | +| StackController.java | `viewcontrollers/stack/` | Stack navigation | +| BottomTabsController.java | `viewcontrollers/bottomtabs/` | Tab navigation | +| LayoutFactory.java | `options/` | Controller factory | +| Options.java | `options/` | Options model | +| Presenter.java | `viewcontrollers/viewcontroller/` | Base presenter | +| EventEmitter.java | `react/events/` | JS events | +| ReactView.java | `react/` | React component wrapper | +| StackAnimator.kt | `viewcontrollers/stack/` | Stack animations | +| ModalStack.java | `viewcontrollers/modal/` | Modal management | diff --git a/ios/ARCHITECTURE.md b/ios/ARCHITECTURE.md new file mode 100644 index 0000000000..483d4aed13 --- /dev/null +++ b/ios/ARCHITECTURE.md @@ -0,0 +1,354 @@ +# iOS Native Architecture + +The iOS implementation provides native navigation using UIKit view controllers, coordinated through a bridge module that receives commands from JavaScript. + +## Directory Structure + +``` +ios/ +├── RNNBridgeModule.h/mm # Bridge entry point (legacy architecture) +├── RNNBridgeManager.h/mm # Bridge initialization +├── RNNCommandsHandler.h/mm # Command dispatcher +├── RNNEventEmitter.h/mm # Event emission to JS +├── RNNLayoutManager.h/mm # View controller tracking +├── RNNLayoutNode.h/mm # Layout tree parsing +├── RNNNavigationOptions.h/mm # Options model +├── RNNComponentViewController.h/mm # React component screen +├── RNNStackController.h/mm # Stack navigation +├── RNNBottomTabsController.h/mm # Tab navigation +├── RNNSideMenuViewController.h/mm # Side menu +├── RNNTopTabsViewController.h/mm # Top tabs +├── RNNSplitViewController.h/mm # Split view (iPad) +├── RNNModalManager.h/mm # Modal presentation +├── RNNOverlayManager.h/mm # Overlay management +├── TurboModules/ # New architecture entry points +│ ├── RNNTurboModule.h/mm # TurboModule spec implementation +│ ├── RNNTurboManager.h/mm # Manager for host, window, external components +│ ├── RNNTurboCommandsHandler.h/mm # TurboModule command routing +│ └── RNNTurboEventEmitter.h/mm # Event emission for new arch +├── Utils/ # Utility classes +├── RNNSideMenu/ # MMDrawerController integration +└── ReactNativeNavigation.xcodeproj/ +``` + +## Bridge Architecture + +The library supports both the legacy bridge and new TurboModule architecture: +- **Legacy (Bridge)**: `RNNBridgeModule` receives commands via `RCT_EXPORT_METHOD` +- **New Architecture**: `RNNTurboModule` (in `TurboModules/`) receives commands directly + +Both entry points delegate to `RNNCommandsHandler` for command execution. + +``` +┌────────────────────────────────────────────────────────────┐ +│ JavaScript (TurboModule) │ +└─────────────────────────┬──────────────────────────────────┘ + │ +┌─────────────────────────▼──────────────────────────────────┐ +│ RNNBridgeModule (bridge) / RNNTurboModule (new arch) │ +│ - setRoot, push, pop, showModal, dismissModal, etc. │ +└─────────────────────────┬──────────────────────────────────┘ + │ +┌─────────────────────────▼──────────────────────────────────┐ +│ RNNCommandsHandler │ +│ - Validates commands, manages layout lifecycle │ +│ - Coordinates with managers │ +└──────┬──────────────┬──────────────┬──────────────┬────────┘ + │ │ │ │ +┌──────▼─────┐ ┌──────▼─────┐ ┌──────▼─────┐ ┌─────▼──────┐ +│RNNLayout │ │RNNModal │ │RNNOverlay │ │RNNViewController│ +│Manager │ │Manager │ │Manager │ │Factory │ +└────────────┘ └────────────┘ └────────────┘ └────────────┘ +``` + +## View Controller Hierarchy + +All navigation view controllers conform to `RNNLayoutProtocol`: + +``` +UIViewController +├── RNNComponentViewController # React component screen +├── RNNExternalViewController # Native screen wrapper +└── RNNSplashScreenViewController # Launch screen + +UINavigationController +└── RNNStackController # Stack navigation + +UITabBarController +└── RNNBottomTabsController # Bottom tabs + +UIViewController (custom) +├── RNNTopTabsViewController # Horizontal top tabs +└── RNNSideMenuChildViewController # Drawer child + +MMDrawerController +└── RNNSideMenuViewController # Side menu/drawer + +UISplitViewController +└── RNNSplitViewController # Master-detail (iPad) +``` + +## Core Classes + +### RNNBridgeModule +Entry point for JavaScript commands (legacy architecture). Exports methods via `RCT_EXPORT_METHOD`: + +```objc +RCT_EXPORT_METHOD(setRoot:(NSString*)commandId layout:(NSDictionary*)layout + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject); +``` + +`RNNBridgeModule` returns the main queue as its `methodQueue`; `RNNTurboModule` uses `RCTExecuteOnMainQueue` for each command to ensure UI operations run on the main thread. + +### RNNBridgeManager +Initializes bridge infrastructure: +- Creates RNNLayoutManager, RNNModalManager, RNNOverlayManager +- Creates RNNViewControllerFactory, RNNCommandsHandler +- Provides extra modules to React bridge +- Handles JavaScript reload events + +### RNNCommandsHandler +Central command dispatcher implementing all navigation operations: +- `setRoot:` - Replace root view controller +- `push:componentId:layout:` - Push to stack +- `pop:componentId:` - Pop from stack +- `showModal:` - Present modal +- `dismissModal:` - Dismiss modal +- `showOverlay:` - Show overlay window +- `dismissOverlay:` - Hide overlay + +### RNNLayoutManager +Tracks active view controllers: +- `addPendingViewController:` - Register during creation +- `removePendingViewController:` - Cleanup after presentation +- `findComponentForId:` - Lookup by componentId + +### RNNLayoutNode +Parses JSON layout from JavaScript: +- Determines type via predicates: `isComponent`, `isStack`, `isTabs`, etc. +- Holds `type`, `nodeId`, `data` (options), `children` + +### RNNViewControllerFactory +Creates view controllers from RNNLayoutNode: +- `createStack:` → RNNStackController +- `createBottomTabs:` → RNNBottomTabsController +- `createComponent:` → RNNComponentViewController +- `createSideMenu:` → RNNSideMenuViewController + +## RNNLayoutProtocol + +Protocol all navigation controllers implement: + +```objc +@protocol RNNLayoutProtocol +- (instancetype)initWithLayoutInfo:(RNNLayoutInfo*)layoutInfo + creator:(id)creator + options:(RNNNavigationOptions*)options + defaultOptions:(RNNNavigationOptions*)defaultOptions + presenter:(RNNBasePresenter*)presenter + eventEmitter:(RNNEventEmitter*)eventEmitter + childViewControllers:(NSArray*)childViewControllers; + +- (void)render; +- (UIViewController*)getCurrentChild; +- (void)mergeOptions:(RNNNavigationOptions*)options; +- (RNNNavigationOptions*)resolveOptions; +- (void)setDefaultOptions:(RNNNavigationOptions*)defaultOptions; +- (void)onChildWillAppear; +- (void)readyForPresentation; +- (CGFloat)getTopBarHeight; +- (CGFloat)getBottomTabsHeight; +@end +``` + +Additional methods provided via `UIViewController+LayoutProtocol` category: +- `destroy`, `topMostViewController`, `stack` +- `componentWillAppear`, `componentDidAppear`, `componentDidDisappear` +- `screenPopped`, `prepareForTransition` +- `resolveOptionsWithDefault`, `mergeChildOptions:child:` + +## Presenter Pattern + +Each view controller type has a corresponding presenter that applies options: + +| Controller | Presenter | +|------------|-----------| +| RNNComponentViewController | RNNComponentPresenter | +| RNNStackController | RNNStackPresenter + TopBarPresenter | +| RNNBottomTabsController | RNNBottomTabsPresenter + BottomTabPresenter | +| RNNSideMenuViewController | RNNSideMenuPresenter | +| RNNSplitViewController | RNNSplitViewControllerPresenter | + +### RNNBasePresenter +Base class with lifecycle methods: +- `applyOptionsOnInit:` - Initial setup +- `applyOptions:` - Apply current options +- `mergeOptions:resolvedOptions:` - Runtime updates +- `componentWillAppear`, `componentDidAppear`, `componentDidDisappear` + +## React View Integration + +### RNNReactView +Wraps RCTRootView (legacy) or RCTSurfaceHostingView (new architecture): +- Implements `RNNComponentProtocol` +- Manages `componentId`, `componentType`, `moduleName` +- Lifecycle: `componentWillAppear`, `componentDidAppear`, `componentDidDisappear` + +### RNNReactRootViewCreator +Creates RNNReactView instances: +- Supports component types: Component, TopBarTitle, TopBarButton, TopBarBackground +- Handles size flexibility for flexible layouts + +### RNNReactComponentRegistry +Caches created React component instances: +- `createComponentIfNotExists:parentComponentId:componentType:reactViewReadyBlock:` +- `removeComponent:`, `clearComponentsForParentId:` + +## Options System + +### RNNNavigationOptions +Master options object containing all configuration: + +```objc +@interface RNNNavigationOptions : RNNOptions +@property RNNTopBarOptions* topBar; +@property RNNBottomTabsOptions* bottomTabs; +@property RNNBottomTabOptions* bottomTab; +@property RNNTopTabsOptions* topTabs; +@property RNNSideMenuOptions* sideMenu; +@property RNNOverlayOptions* overlay; +@property RNNAnimationsOptions* animations; +@property RNNStatusBarOptions* statusBar; +@property RNNLayoutOptions* layout; +@property RNNModalOptions* modal; +@property RNNPreviewOptions* preview; +@property RNNSplitViewOptions* splitView; +@end +``` + +### Options Resolution +Options merge in hierarchy: +1. Component's own options +2. Parent controller options (loop through chain) +3. Default options (from `setDefaultOptions`) + +## Event Emission + +### RNNEventEmitter +Sends events to JavaScript via RCTEventEmitter: + +| Event | Method | +|-------|--------| +| Component lifecycle | `sendComponentWillAppear:`, `sendComponentDidAppear:`, `sendComponentDidDisappear:` | +| Button press | `sendOnNavigationButtonPressed:buttonId:` | +| Command completion | `sendOnNavigationCommandCompletion:commandId:` | +| Tab events | `sendBottomTabSelected:unselected:`, `sendBottomTabLongPressed:`, `sendBottomTabPressed:` | +| Modal events | `sendModalsDismissedEvent:numberOfModalsDismissed:`, `sendModalAttemptedToDismissEvent:` | +| Screen events | `sendScreenPoppedEvent:` | +| Search | `sendOnSearchBarUpdated:text:isFocused:`, `sendOnSearchBarCancelPressed:` | +| Preview | `sendOnPreviewCompleted:previewComponentId:` | + +### RNNBridgeEventEmitter +Concrete implementation that sends `onAppLaunched` on initialization. + +## Modal & Overlay Management + +### RNNModalManager +- Tracks presented modals array +- Supports custom transition animations via ScreenAnimationController +- Handles presentationController delegate for adaptive presentation + +### RNNOverlayManager +- Manages UIWindow instances for overlays +- Each overlay gets its own RNNOverlayWindow +- Maintains previous window reference for restoration +- Controls window level and accessibility + +## Animation System + +### ScreenAnimationController +Implements `UIViewControllerAnimatedTransitioning`: +- Custom push/pop/modal transitions +- Content transitions (RNNEnterExitAnimation) +- Element transitions (ElementTransitionOptions) +- Shared element transitions (SharedElementTransitionOptions) + +### Element Animators +- `ElementAnimator` - Individual element animations +- `SharedElementAnimator` - Cross-screen shared elements +- Transition types: Alpha, Scale, Translation, Frame, Bounds, Color, CornerRadius + +### RNNSetRootAnimator +Animates window root replacement using CABasicAnimation. + +## Navigation Types + +### Stack Navigation (RNNStackController) +- Subclass of UINavigationController +- Push/pop with custom animations +- Back button customization +- Uses StackControllerDelegate for bar delegate handling + +```objc +// Extension methods +@interface UINavigationController (RNNCommands) +- (void)push:(UIViewController*)vc onTop:(UIViewController*)onTopVC + animated:(BOOL)animated completion:(void(^)(void))completion rejection:(RCTPromiseRejectBlock)rejection; +- (void)popAnimated:(BOOL)animated completion:(void(^)(NSString*))completion rejection:(RCTPromiseRejectBlock)rejection; +@end +``` + +### Bottom Tabs (RNNBottomTabsController) +- Subclass of UITabBarController +- Tab attachment modes: Together, OnSwitchToTab, AfterInitialTab +- Long-press gesture support +- Badge and dot indicator support + +### Side Menu (RNNSideMenuViewController) +- Uses MMDrawerController (third-party) +- Center, left, right child containers +- Configurable open modes and widths + +### Top Tabs (RNNTopTabsViewController) +- Custom horizontal tab implementation +- Not based on UITabBarController +- Manual content switching + +### Split View (RNNSplitViewController) +- UISplitViewController subclass +- Master-detail for iPad + +## External Components + +### RNNExternalComponentStore +Registry for native (non-React) view controllers. + +### RNNExternalViewController +Wraps native UIViewController for integration: + +```objc +[ReactNativeNavigation registerExternalComponent:@"NativeScreen" + callback:^(NSDictionary *props, RCTBridge *bridge) { + return [[MyNativeViewController alloc] init]; +}]; +``` + +## Key Files Reference + +| File | Purpose | +|------|---------| +| `RNNBridgeModule.h/mm` | Bridge entry point (legacy) | +| `TurboModules/RNNTurboModule.mm` | TurboModule entry point (new arch) | +| `TurboModules/RNNTurboCommandsHandler.mm` | TurboModule command routing | +| `RNNCommandsHandler.h/mm` | Command execution | +| `RNNLayoutManager.h/mm` | Controller tracking | +| `RNNViewControllerFactory.h/mm` | Controller creation | +| `RNNComponentViewController.h/mm` | React screen | +| `RNNStackController.h/mm` | Stack navigation | +| `RNNBottomTabsController.h/mm` | Tab navigation | +| `RNNNavigationOptions.h/mm` | Options model | +| `RNNBasePresenter.h/mm` | Presenter base | +| `TopBarPresenter.h/mm` | Top bar styling | +| `RNNReactView.h/mm` | React view wrapper | +| `ScreenAnimationController.h/mm` | Custom transitions | diff --git a/src/ARCHITECTURE.md b/src/ARCHITECTURE.md new file mode 100644 index 0000000000..73f804a4b9 --- /dev/null +++ b/src/ARCHITECTURE.md @@ -0,0 +1,301 @@ +# JavaScript/TypeScript Architecture + +The JavaScript layer provides the public API and orchestrates communication between React components and native navigation implementations. + +## Entry Point + +`index.ts` exports the `Navigation` singleton (a `NavigationDelegate` instance) along with re-exports from `Modal`, `EventsRegistry`, `Constants`, and all interfaces. Applications use `Navigation.*` for commands and `Navigation.events().*` for event subscriptions. + +## Module Structure + +``` +src/ +├── index.ts # Main entry point, exports Navigation singleton +├── Navigation.ts # NavigationRoot - core orchestrator +├── NavigationDelegate.ts # Public API facade +├── adapters/ # Native bridge layer +├── commands/ # Command processing +├── components/ # React component management +├── events/ # Event system +├── interfaces/ # TypeScript type definitions +└── processors/ # Extensibility hooks +``` + +## Core Classes + +### NavigationDelegate (Public API) +**File**: `NavigationDelegate.ts` + +Facade providing the public `Navigation` API. All methods proxy to `NavigationRoot`. + +```typescript +// Usage +import { Navigation } from 'react-native-navigation'; +Navigation.setRoot({ root: { stack: { children: [...] } } }); +``` + +### NavigationRoot (Core Orchestrator) +**File**: `Navigation.ts` + +Coordinates all subsystems. Constructed with dependencies: +- `NativeCommandsSender` - sends commands to native +- `NativeEventsReceiver` - receives events from native +- `AppRegistryService` - manages React Native component registry + +Initializes and coordinates: +- `Store` - component instance & props storage +- `ComponentRegistry` - component registration +- `LayoutTreeParser` - converts layouts to internal nodes +- `LayoutTreeCrawler` - processes layout trees +- `Commands` - command execution +- `EventsRegistry` - event subscriptions +- `OptionsProcessor` - option processing +- `LayoutProcessor` - layout transformations + +## Adapters Layer + +Bridge between JavaScript and native/React Native APIs. + +| Adapter | Purpose | +|---------|---------| +| `NativeCommandsSender` | Wraps TurboModule for command dispatch | +| `NativeEventsReceiver` | Wraps NativeEventEmitter for events | +| `NativeRNNTurboModule` | TurboModule spec interface | +| `NativeRNNTurboEventEmitter` | TurboModule event emitter spec | +| `UniqueIdProvider` | Generates unique component/command IDs | +| `ColorService` | Converts colors to native format | +| `AssetResolver` | Resolves require() image assets (class: AssetService) | +| `AppRegistryService` | Registers components with React Native | +| `Constants` | Platform dimension constants | +| `TouchablePreview` | 3D Touch / Haptic preview handling | + +## Commands Layer + +### Commands Class +**File**: `commands/Commands.ts` + +Central command dispatcher. Each navigation command: +1. Validates input +2. Processes layout through pipeline +3. Sends to native via adapter +4. Returns promise with result + +### Processing Pipeline + +The pipeline executes in this exact order: + +``` +Input Layout (from API) + ↓ +1. OptionsCrawler.crawl() # Extract static options from component classes + ↓ +2. LayoutProcessor.process() # Apply registered layout processors + ↓ +3. LayoutTreeParser.parse() # Convert to internal LayoutNode tree + ↓ +4. LayoutTreeCrawler.crawl() # Process options, save props to Store + ↓ +5. OptionsProcessor (during crawl) # Resolve colors, assets, custom processors + ↓ +6. NativeCommandsSender # Send to native module +``` + +### LayoutNode (Internal Tree) +```typescript +interface LayoutNode { + id: string; // Unique identifier + type: LayoutType; // Component|Stack|BottomTabs|etc + data: { + name?: string; // Component name + options?: any; // Processed options + passProps?: any; // Component props (cleared before native) + }; + children: LayoutNode[]; +} +``` + +### LayoutType Enum +```typescript +enum LayoutType { + Component = 'Component', + Stack = 'Stack', + BottomTabs = 'BottomTabs', + SideMenuRoot = 'SideMenuRoot', + SideMenuCenter = 'SideMenuCenter', + SideMenuLeft = 'SideMenuLeft', + SideMenuRight = 'SideMenuRight', + TopTabs = 'TopTabs', + ExternalComponent = 'ExternalComponent', + SplitView = 'SplitView', +} +``` + +## Components Layer + +### ComponentRegistry +**File**: `components/ComponentRegistry.ts` + +Manages React component registration and wrapping. + +```typescript +Navigation.registerComponent('ScreenName', () => MyComponent); +``` + +### ComponentWrapper +**File**: `components/ComponentWrapper.tsx` + +Higher-order component that: +- Wraps original component with lifecycle management +- Stores instance in `Store` for event dispatch +- Injects `componentId` and `componentName` props + +### Store +**File**: `components/Store.ts` + +Centralized storage for: +- `componentsByName` - registered component providers +- `componentsInstancesById` - mounted component instances +- `propsById` - static props by component ID +- `pendingPropsById` - props awaiting component mount +- `wrappedComponents` - cached wrapped components +- `lazyRegistratorFn` - function for lazy component registration + +## Events Layer + +### EventsRegistry +**File**: `events/EventsRegistry.ts` + +Public API for event subscriptions: + +```typescript +Navigation.events().registerComponentDidAppearListener(({ componentId }) => {}); +Navigation.events().registerCommandCompletedListener(({ commandId }) => {}); +``` + +### ComponentEventsObserver +**File**: `events/ComponentEventsObserver.ts` + +Dispatches events to component instance methods: +- `componentWillAppear()` +- `componentDidAppear()` +- `componentDidDisappear()` +- `navigationButtonPressed()` +- `screenPopped()` + +### CommandsObserver +**File**: `events/CommandsObserver.ts` + +Notifies listeners of command lifecycle (start, complete). + +## Events (Native → JS) + +| Event | Description | +|-------|-------------| +| `RNN.AppLaunched` | App initialization complete | +| `RNN.ComponentWillAppear` | Component about to appear | +| `RNN.ComponentDidAppear` | Component now visible | +| `RNN.ComponentDidDisappear` | Component hidden | +| `RNN.NavigationButtonPressed` | TopBar button tapped | +| `RNN.BottomTabPressed` | Tab pressed (even if selected) | +| `RNN.BottomTabSelected` | Tab selection changed | +| `RNN.BottomTabLongPressed` | Tab long-pressed | +| `RNN.ModalDismissed` | Modal was dismissed | +| `RNN.ModalAttemptedToDismiss` | Swipe-to-dismiss attempted | +| `RNN.ScreenPopped` | Screen removed from stack | +| `RNN.SearchBarUpdated` | Search text changed | +| `RNN.SearchBarCancelPressed` | Search cancelled | +| `RNN.PreviewCompleted` | 3D Touch preview completed | +| `RNN.CommandCompleted` | Navigation command finished | + +## Processors Layer + +### OptionProcessorsStore +**File**: `processors/OptionProcessorsStore.ts` + +Registers custom option processors: + +```typescript +Navigation.addOptionProcessor('topBar.title.text', (value, commandName) => { + return value.toUpperCase(); // Transform all titles +}); +``` + +### LayoutProcessorsStore +**File**: `processors/LayoutProcessorsStore.ts` + +Registers layout transformers: + +```typescript +Navigation.addLayoutProcessor((layout, commandName) => { + // Add default options to all components + return layout; +}); +``` + +## Interfaces + +### Layout Types +**File**: `interfaces/Layout.ts` + +```typescript +interface LayoutRoot { + root: Layout; + modals?: any[]; + overlays?: any[]; +} + +type Layout = { + component?: LayoutComponent; + stack?: LayoutStack; + bottomTabs?: LayoutBottomTabs; + sideMenu?: LayoutSideMenu; + splitView?: LayoutSplitView; + topTabs?: LayoutTopTabs; + externalComponent?: ExternalComponent; +} +``` + +### Options Interface +**File**: `interfaces/Options.ts` (comprehensive) + +Contains all configuration options for: +- Status bar, navigation bars +- Top bar (buttons, title, search) +- Bottom tabs +- Side menus +- Modals, overlays +- Animations +- Layout parameters + +### NavigationComponent +**File**: `interfaces/NavigationComponent.ts` + +Base class for navigation-aware components: + +```typescript +class MyScreen extends NavigationComponent { + static options: Options = { ... }; + + componentDidAppear(event) { } + navigationButtonPressed(event) { } +} +``` + +## Dependencies + +**Production**: +- `lodash` - utility functions +- `hoist-non-react-statics` - HOC support +- `react-lifecycles-compat` - lifecycle polyfill +- `tslib` - TypeScript helpers + +**Peer**: +- `react`, `react-native` (required) +- `remx` (optional state management) + +## Build Output + +Uses `react-native-builder-bob`: +- **Source**: `src/` +- **Output**: `lib/` +- **Targets**: ESM modules + TypeScript declarations From e309bf3ae07806f2bd25d0f780ed12e4d0061b4e Mon Sep 17 00:00:00 2001 From: Yedidya Kennard Date: Thu, 5 Feb 2026 16:29:22 +0200 Subject: [PATCH 2/3] Add App Integration sections to iOS and Android architecture docs Document how users integrate the library into their apps: iOS: - RNNAppDelegate base class and what it does - ReactNativeNavigation bootstrap methods - AppDelegateLinker transformations (Swift/Obj-C) Android: - NavigationApplication and NavigationActivity base classes - NavigationReactNativeHost usage - ApplicationLinker and ActivityLinker transformations Also documents what `npx rnn-link` automates for each platform. Co-Authored-By: Claude Opus 4.5 --- android/ARCHITECTURE.md | 65 +++++++++++++++++++++++++++++++++++++++++ ios/ARCHITECTURE.md | 62 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/android/ARCHITECTURE.md b/android/ARCHITECTURE.md index a37b59aa92..5e508f8041 100644 --- a/android/ARCHITECTURE.md +++ b/android/ARCHITECTURE.md @@ -2,6 +2,71 @@ The Android implementation provides native navigation using Views and ViewGroups (not Fragments), coordinated through a TurboModule that receives commands from JavaScript. +## App Integration + +### NavigationApplication +**File**: `NavigationApplication.java` + +Abstract Application class that user's MainApplication must extend: + +```kotlin +// MainApplication.kt - User extends NavigationApplication +class MainApplication : NavigationApplication() { + override val reactNativeHost: ReactNativeHost + get() = NavigationReactNativeHost(this) // Must use NavigationReactNativeHost +} +``` + +**What NavigationApplication does:** +- Initializes SoLoader +- Provides `ReactGateway` singleton for React lifecycle +- Offers `registerExternalComponent()` for native screens + +### NavigationActivity +**File**: `NavigationActivity.java` + +Base Activity that user's MainActivity must extend: + +```kotlin +// MainActivity.kt - User extends NavigationActivity +class MainActivity : NavigationActivity() { + // No getMainComponentName() needed - navigation handles root +} +``` + +**What NavigationActivity does:** +- Creates `Navigator` with root, modal, and overlay layouts +- Manages back press via `OnBackPressedCallback` +- Coordinates React lifecycle with activity lifecycle + +### NavigationReactNativeHost +**File**: `react/NavigationReactNativeHost.kt` + +Custom ReactNativeHost that integrates with navigation: +- Used instead of `DefaultReactNativeHost` +- Provides proper module registration for navigation + +### Autolink Script (`npx rnn-link`) + +The `autolink/postlink/postLinkAndroid.js` script automates setup: + +| Linker | What it does | +|--------|--------------| +| `ApplicationLinker` | Changes MainApplication to extend `NavigationApplication`, uses `NavigationReactNativeHost`, removes SoLoader.init() | +| `ActivityLinker` | Changes MainActivity to extend `NavigationActivity`, removes `getMainComponentName()` | +| `GradleLinker` | Updates build.gradle if needed | + +**ApplicationLinker transformations:** +- `class MainApplication : Application(), ReactApplication` → `class MainApplication : NavigationApplication()` +- `DefaultReactNativeHost(this)` → `NavigationReactNativeHost(this)` +- Removes `SoLoader.init()` (NavigationApplication handles it) +- Removes new architecture entry point load block + +**ActivityLinker transformations:** +- `class MainActivity : ReactActivity()` → `class MainActivity : NavigationActivity()` +- Removes `getMainComponentName()` override +- Removes `createReactActivityDelegate()` override + ## Directory Structure ``` diff --git a/ios/ARCHITECTURE.md b/ios/ARCHITECTURE.md index 483d4aed13..049c6f6580 100644 --- a/ios/ARCHITECTURE.md +++ b/ios/ARCHITECTURE.md @@ -2,6 +2,68 @@ The iOS implementation provides native navigation using UIKit view controllers, coordinated through a bridge module that receives commands from JavaScript. +## App Integration + +### RNNAppDelegate +**Files**: `RNNAppDelegate.h/mm` + +Base class that user's AppDelegate must extend. Handles React Native and navigation initialization: + +```objc +// AppDelegate.h - User extends RNNAppDelegate +#import "RNNAppDelegate.h" +@interface AppDelegate : RNNAppDelegate +@end + +// AppDelegate.m - User implements sourceURLForBridge +@implementation AppDelegate +- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; +} +@end +``` + +**What RNNAppDelegate does:** +- Sets up React Native feature flags (Fabric, TurboModules, Bridgeless) +- Creates `RCTRootViewFactory` and `ReactHost` +- Calls `[ReactNativeNavigation bootstrapWithHost:]` to initialize navigation +- Handles RN version differences (0.77, 0.78, 0.79+) via compile-time macros + +### ReactNativeNavigation Bootstrap +**File**: `ReactNativeNavigation.h/mm` + +Public API for native initialization: + +```objc +// New architecture (0.77+) +[ReactNativeNavigation bootstrapWithHost:reactHost]; + +// Legacy bridge +[ReactNativeNavigation bootstrapWithBridge:bridge]; + +// Register native screens +[ReactNativeNavigation registerExternalComponent:@"NativeScreen" + callback:^(NSDictionary *props, RCTBridge *bridge) { + return [[MyNativeVC alloc] init]; +}]; +``` + +### Autolink Script (`npx rnn-link`) + +The `autolink/postlink/postLinkIOS.js` script automates setup: + +| Linker | What it does | +|--------|--------------| +| `AppDelegateLinker` | Changes AppDelegate to extend `RNNAppDelegate`, imports ReactNativeNavigation, removes RCTRootView setup | +| `PodfileLinker` | Adds required pods configuration | +| `PlistLinker` | Updates Info.plist if needed | + +**AppDelegateLinker transformations:** +- Swift: `class AppDelegate: RCTAppDelegate` → `class AppDelegate: RNNAppDelegate` +- Obj-C header: `@interface AppDelegate : RCTAppDelegate` → `@interface AppDelegate : RNNAppDelegate` +- Imports `` +- Removes manual RCTRootView/window setup (navigation manages the window) + ## Directory Structure ``` From 6b5e11a05af085c841dd20e0608387ccf76df99c Mon Sep 17 00:00:00 2001 From: Yedidya Kennard Date: Thu, 19 Feb 2026 09:47:36 +0200 Subject: [PATCH 3/3] Allow .md files in src/ directory check to fix CI The assertAllTsFilesInSrc check was failing because src/ARCHITECTURE.md is not a .ts or .tsx file, causing all Android CI builds to fail. Co-Authored-By: Claude Opus 4.6 --- scripts/test-js.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test-js.js b/scripts/test-js.js index d98ae0cf8e..aabc93874e 100644 --- a/scripts/test-js.js +++ b/scripts/test-js.js @@ -25,7 +25,7 @@ function run() { function assertAllTsFilesInSrc() { const allFiles = exec.execSyncRead('find ./src -type f'); const lines = split(allFiles, '\n'); - const offenders = filter(lines, (f) => !f.endsWith('.ts') && !f.endsWith('.tsx')); + const offenders = filter(lines, (f) => !f.endsWith('.ts') && !f.endsWith('.tsx') && !f.endsWith('.md')); if (offenders.length) { throw new Error(`\n\nOnly ts/tsx files are allowed:\n${offenders.join('\n')}\n\n\n`); }