{"owner":"wix","repo":"react-native-navigation","hasSkills":true,"totalSkillsCount":11,"totalTokensCount":32827,"categories":["anthropic-skill","project-spec","cursor-rule"],"hasMcp":false,"mcpConfig":null,"found":[".claude/skills/rnn-codebase/SKILL.md",".cursor/skills/ios26-navigation/SKILL.md",".cursor/skills/rnn-codebase/SKILL.md","ARCHITECTURE.md","ios/ARCHITECTURE.md","src/ARCHITECTURE.md","android/ARCHITECTURE.md",".claude/skills/rn-version-upgrade.md",".cursor/rules/github-descriptions.mdc",".cursor/skills/engine-e2e/SKILL.md",".github/skills/rnn-codebase/SKILL.md"],"skills":{".claude/skills/rnn-codebase/SKILL.md":"---\nname: rnn-codebase\ndescription: Navigate and work with the react-native-navigation (RNN) codebase. Use when fixing bugs, adding features, tracing command flows, understanding options resolution, or working across JS/iOS/Android layers in this repo.\n---\n\n# React Native Navigation Codebase\n\n## Architecture Overview\n\nRNN has three layers that mirror each other:\n\n```\nJS/TS (src/)  →  TurboModule bridge  →  iOS native (ios/)\n                                     →  Android native (android/)\n```\n\nA navigation command (e.g. `push`) flows:\n1. `Navigation.push()` → `Commands.ts` → processing pipeline → `NativeCommandsSender.ts`\n2. TurboModule: `RNNTurboModule` (iOS) / `NavigationTurboModule.kt` (Android)\n3. iOS: `RNNCommandsHandler` → `RNNViewControllerFactory` → UIKit controllers\n4. Android: `Navigator` → `LayoutFactory` → View-based controllers (no Fragments)\n\nRead [ARCHITECTURE.md](../../ARCHITECTURE.md) for the full overview.\n\n## Key Cross-Layer Mappings\n\n### Layout Types → Native Controllers\n\n| JS Layout Type | iOS Controller | Android Controller |\n|----------------|---------------|-------------------|\n| `component` | `RNNComponentViewController` | `ComponentViewController` |\n| `stack` | `RNNStackController` (UINavigationController) | `StackController` |\n| `bottomTabs` | `RNNBottomTabsController` (UITabBarController) | `BottomTabsController` |\n| `sideMenu` | `RNNSideMenuViewController` (MMDrawerController) | `SideMenuController` (DrawerLayout) |\n| `topTabs` | `RNNTopTabsViewController` | `TopTabsController` (ViewPager) |\n| `splitView` | `RNNSplitViewController` | N/A (iOS only) |\n| `externalComponent` | `RNNExternalViewController` | `ExternalComponentViewController` |\n\n### Options → Presenters\n\nEach controller type has a Presenter that applies options to views:\n\n| iOS Controller | iOS Presenter | Android Presenter |\n|----------------|--------------|-------------------|\n| `RNNComponentViewController` | `RNNComponentPresenter` | `ComponentPresenter` |\n| `RNNStackController` | `RNNStackPresenter` + `TopBarPresenter` | `StackPresenter` |\n| `RNNBottomTabsController` | `RNNBottomTabsPresenter` | `BottomTabsPresenter` |\n| `RNNSideMenuViewController` | `RNNSideMenuPresenter` | `SideMenuPresenter` |\n\n### Events (same names both platforms)\n\n| Event | Trigger |\n|-------|---------|\n| `RNN.ComponentDidAppear` | Screen becomes visible |\n| `RNN.ComponentDidDisappear` | Screen hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tap |\n| `RNN.BottomTabSelected` | Tab changed |\n| `RNN.ModalDismissed` | Modal dismissed |\n| `RNN.ScreenPopped` | Screen popped from stack |\n| `RNN.CommandCompleted` | Any command finished |\n\n## Where to Find Things\n\n### By task: \"I need to fix/change X\"\n\n| Task | JS File(s) | iOS File(s) | Android File(s) |\n|------|-----------|------------|----------------|\n| Command execution | `src/commands/Commands.ts` | `ios/RNNCommandsHandler.mm` | `react/NavigationTurboModule.kt` |\n| Layout creation | `src/commands/LayoutTreeParser.ts` | `ios/RNNViewControllerFactory.mm` | `options/LayoutFactory.java` |\n| Options processing | `src/commands/OptionsProcessor.ts` | `ios/RNNNavigationOptions.mm` | `options/Options.java` |\n| Options application | — | `ios/*Presenter.mm` | `viewcontrollers/*Presenter.java` |\n| TopBar | `src/interfaces/Options.ts` (TopBarOptions) | `ios/TopBarPresenter.mm`, `ios/RNNUIBarButtonItem.mm` | `views/stack/topbar/` |\n| Bottom tabs | `src/interfaces/Options.ts` (BottomTabsOptions) | `ios/RNNBottomTabsPresenter.mm` | `viewcontrollers/bottomtabs/` |\n| Modals | `src/commands/Commands.ts` | `ios/RNNModalManager.mm` | `viewcontrollers/modal/ModalStack.java` |\n| Overlays | `src/commands/Commands.ts` | `ios/RNNOverlayManager.mm` | `viewcontrollers/overlay/OverlayManager.kt` |\n| Animations | `src/interfaces/Options.ts` (AnimationOptions) | `ios/ScreenAnimationController.mm` | `viewcontrollers/stack/StackAnimator.kt` |\n| React view rendering | — | `ios/RNNReactView.mm` | `react/ReactView.java` |\n| Events to JS | `src/adapters/NativeEventsReceiver.ts` | `ios/RNNEventEmitter.mm` | `react/events/EventEmitter.java` |\n| Component registration | `src/components/ComponentRegistry.ts` | — | — |\n| Deep linking (URL → screen) | `src/linking/` (`LinkingHandler`, `URLParser`, `RouteMatcher`, `DeferredLinkQueue`, `ModalLayoutBuilder`) | `ios/RNNAppDelegate.mm` (`dispatchDeepLinkURL:`, cold-start queue, `RCTContentDidAppearNotification`) | `NavigationActivity.onNewIntent` → `ReactGateway` |\n\n### By directory\n\n- **`src/`** — JS public API, commands, processing pipeline. See [src/ARCHITECTURE.md](../../src/ARCHITECTURE.md)\n- **`ios/`** — All Obj-C/C++ native code. See [ios/ARCHITECTURE.md](../../ios/ARCHITECTURE.md)\n- **`ios/TurboModules/`** — New architecture entry points (`RNNTurboModule`, `RNNTurboManager`, `RNNTurboCommandsHandler`)\n- **`android/src/main/java/com/reactnativenavigation/`** — All Java/Kotlin native code. See [android/ARCHITECTURE.md](../../android/ARCHITECTURE.md)\n- **`playground/`** — Demo app for development and E2E tests\n- **`playground/src/screens/`** — Test screens exercising every feature\n- **`playground/e2e/`** — Detox E2E tests\n\n## Options Resolution Order\n\nOptions are applied in ascending priority:\n1. Default options (from `Navigation.setDefaultOptions()`) — lowest priority\n2. Static options (from component class or `Navigation.registerComponent`)\n3. Options passed in the layout call (e.g. `push`, `setRoot`)\n4. `mergeOptions()` — runtime override, highest priority\n\n## JS Processing Pipeline (exact order)\n\n```\nAPI layout → OptionsCrawler.crawl() → LayoutProcessor.process()\n  → LayoutTreeParser.parse() → LayoutTreeCrawler.crawl()\n  → OptionsProcessor (colors, assets, custom) → NativeCommandsSender\n```\n\n## iOS Patterns\n\n- All controllers conform to `RNNLayoutProtocol`\n- `RNNBasePresenter` subclasses apply options — `applyOptionsOnInit:`, `applyOptions:`, `mergeOptions:resolvedOptions:`\n- Commands run on main thread (`RCTExecuteOnMainQueue`)\n- React views: `RNNReactView` wraps `RCTSurfaceHostingView` (new arch)\n- Overlays use separate `UIWindow` instances (`RNNOverlayWindow`)\n- `RNNReactComponentRegistry` caches React component instances\n\n## Android Patterns\n\n- View-based, NOT Fragment-based\n- All commands dispatched via `UiThread.post()`\n- `ViewController<T extends ViewGroup>` is the base — `createView()` is abstract\n- `ParentController` extends `ChildController` extends `ViewController`\n- Bottom tabs use `AHBottomNavigation` library\n- Three root layouts in `NavigationActivity`: rootLayout, modalsLayout, overlaysLayout\n- Tab attachment modes: `Together`, `OnSwitchToTab`, `AfterInitialTab`\n\n## Development Workflow\n\n### Playground app\n- `yarn start` — Metro bundler\n- `yarn xcode` — Open iOS project\n- `yarn studio` — Open Android project\n- `yarn pod-install` — Install iOS pods\n\n### Testing\n- `yarn test-js` — Jest unit tests\n- `yarn test-unit-ios` — iOS native unit tests (XCTest)\n- `yarn test-unit-android` — Android native unit tests (JUnit + Robolectric)\n- `yarn test-e2e-ios-ci` / `yarn test-e2e-android-ci` — Detox E2E tests\n\n### Building\n- `yarn prepare` — Builds `src/` → `lib/` (ESM + types)\n- Codegen config: `rnnavigation` in `package.json`\n\n## Common Gotchas\n\n- iOS uses UIKit subclasses (UINavigationController, UITabBarController); Android uses custom View hierarchy\n- `splitView` is iOS-only\n- Side menu: iOS uses MMDrawerController (3rd party); Android uses DrawerLayout (native)\n- Options that exist in JS types may not be implemented on both platforms — check the presenter\n- `passProps` are stored in JS `Store`, not sent to native (cleared before bridge crossing)\n- The `lib/` folder is generated — never edit it, edit `src/` instead\n- Deep links are processed only after the first `setRoot()` resolves; pre-bridge URLs on iOS are queued natively in `RNNAppDelegate` and flushed on `RCTContentDidAppearNotification` (bridgeless mode — `RCTJavaScriptDidLoadNotification` does NOT fire)\n- `ModalLayoutBuilder` strips React-reserved keys (`ref`, `key`) from URL query params before they reach `passProps`, to avoid React 19 ref-validation crashes\n",".cursor/skills/ios26-navigation/SKILL.md":"---\nname: ios26-navigation\ndescription: Reference for iOS 26 navigation bar, tab bar, toolbar, and Liquid Glass building blocks (UITab, scroll-edge effects, search placement, shared-background platter, UIButton glass configurations, UIGlassEffect / UIGlassContainerEffect, UINavigationItem.style navigator/browser/editor, UICornerConfiguration / concentric corners, UISheetPresentationController, SF Symbols 7) plus the internal view hierarchy of UIBarButtonItem and UIToolbar, and how react-native-navigation maps to all of it. Use when adding or fixing iOS 26 behavior in RNN's top bar, bottom tabs, bar buttons, toolbar, modals, or any glass-styled custom chrome; when investigating iOS 26-only regressions; or when deciding how to expose a new iOS 26 capability through RNN options.\n---\n\n# iOS 26 Navigation in RNN\n\n## When this applies\n\nUse this skill any time work touches:\n- Top bar / navigation bar appearance, buttons, titles, or search\n- Bottom tab bar appearance, items, badges, or layout\n- Toolbar items or bar button styling\n- Any `@available(iOS 26.0, *)` branch\n- iOS 26-only bugs (Liquid Glass clipping, tab bar floating, button platter, scroll-edge effects)\n\nPair this with `rnn-codebase` (repo navigation) and `rnn-e2e-runner` (validation).\n\n## Build configuration\n\n- **Always Release** for verification — see workspace rule `rnn-build-release.mdc`. Debug masks iOS 26 layout/transition issues.\n- Xcode 26.1 toolchain: `DEVELOPER_DIR=/Applications/Xcode_26.1.app/Contents/Developer`\n- Simulator: `iPhone 17 Pro Max` (iOS 26 default)\n- Do **not** disable Fabric / New Architecture (user rule).\n- Compatibility opt-out flag: `UIDesignRequiresCompatibility` in `Info.plist`. RNN reads it in `RNNReactButtonView.designRequiresCompatibility` to fall back to pre-iOS-26 layout. Always honor it in new iOS 26 code paths.\n\n---\n\n## Apple iOS 26 API map\n\n### 1. Liquid Glass material\nThe system bar material on `UINavigationBar`, `UITabBar`, `UIToolbar` is **always translucent / glass** by default. `configureWithOpaqueBackground` is silently overlaid with glass unless you also nil out `backgroundEffect`.\n\n- `UIBarAppearance.backgroundEffect = nil` — required to actually get an opaque/transparent fill on iOS 26.\n- `UITabBarAppearance` / `UINavigationBarAppearance` / `UIToolbarAppearance` — same `backgroundEffect` rule.\n- Apple HIG: [Adopt Liquid Glass](https://developer.apple.com/design/human-interface-guidelines/materials)\n- WWDC25: \"What's new in UIKit\", \"Build a UIKit app with the new design\"\n\n**RNN handling:**\n- `ios/BottomTabsAppearancePresenter.mm`: branches on iOS 26 — uses `configureWithTransparentBackground` + `backgroundEffect=nil` + sets `tabBar.backgroundColor`. Pre-26 uses `configureWithOpaqueBackground`.\n- `ios/TopBarAppearancePresenter.mm`: same pattern for the navigation bar.\n\n### 2. Floating tab bar + drawBehind default\nThe tab bar floats above content on iOS 26 instead of pushing it up. Content underneath needs to extend.\n\n- Tab bar no longer occupies layout space the same way; `safeAreaInsets.bottom` increases for content.\n- Default `drawBehind` should be `YES` on iOS 26.\n\n**RNN handling:**\n- `ios/RNNBottomTabsOptions.mm` (`-shouldDrawBehind`): defaults `drawBehind` to `YES` on iOS 26, `NO` otherwise.\n- `ios/RNNBottomTabsController.mm`: `rnn_cycleAllTabsThenRestoreInitialSelection` — iOS 26 first-layout bug where tab item titles get misplaced; cycle selection in `viewDidAppear` to force a correct layout. Gated by `_rnnDidApplyInitialTabBarSelectionFix`.\n\n### 3. UITab / UITabBarController.tabs (iOS 18+, expanded in 26)\nModern tab API replaces `viewControllers` with `tabs: [UITab]`. Supports `UITabGroup`, `UISearchTab`, and `UITabBarController.mode = .tabSidebar`.\n\n- `UITab(title:image:identifier:viewControllerProvider:)` — lazy VC creation per tab.\n- `UITabBarController.tabs` — array of `UITab`, can mix `UITab` and `UITabGroup`.\n- `UITabBarController.mode` — `.tabBar` (default) vs `.tabSidebar` (iPad sidebar).\n- `UISearchTab` — first-class search tab, integrates with `UINavigationItem` search.\n- `UITabBarController.sidebarLayoutPreferences` — iPad sidebar customization.\n- `UITabBarController.tabBarPlacement` — `.automatic`, `.bottom`, `.top` (iPadOS 26 can pin the tab bar at the top of the window).\n- Programmatic transitions between sidebar and tab bar layouts via animating `mode` changes inside `UIView.animate`.\n- Apple: [UITabBarController.tabs](https://developer.apple.com/documentation/uikit/uitabbarcontroller/tabs), [UITab](https://developer.apple.com/documentation/uikit/uitab), [UITabGroup](https://developer.apple.com/documentation/uikit/uitabgroup)\n\n**RNN handling:** RNN currently uses the legacy `viewControllers` API. There is **no** `UITab` / `tabs` adoption yet. New iOS 26 tab features (sidebar mode, search tab, groups, top placement) would need a new code path in `RNNBottomTabsController` and corresponding `Options.ts` surface.\n\n### 4. UITabBarController.bottomAccessory\nPersistent floating mini-control attached above the tab bar (e.g., Apple Music's now-playing bar).\n\n- `UITabBarController.bottomAccessory: UITabAccessory?`\n- `UITabAccessory(contentView:)` — wraps a UIView.\n- Apple: [UITabAccessory](https://developer.apple.com/documentation/uikit/uitabaccessory)\n\n**RNN handling:** Not yet exposed. Would need a new option (e.g., `bottomTabs.accessory: { component: { name, ... } }`) and a presenter to mount a React view inside a `UITabAccessory`.\n\n### 5. Scroll-edge appearance and effects\niOS 26 makes `scrollEdgeAppearance` matter more (the bar fades to transparent when scrolled to the top). New `scrollEdgeEffect` on `UINavigationItem` controls the effect.\n\n- `UINavigationItem.scrollEdgeEffect` — controls the fading/glass effect at scroll edges.\n- `UINavigationBar.scrollEdgeAppearance` — appearance when at the scroll edge.\n- `UITabBar.scrollEdgeAppearance` — same for tab bar.\n- Apple: [UIScrollEdgeEffect](https://developer.apple.com/documentation/uikit/uiscrolledgeeffect) (iOS 26)\n\n**RNN handling:**\n- `scrollEdgeAppearance` exposed via top bar options — see `website/docs/api/options-scrollEdgeAppearance.mdx`.\n- iOS 26 `scrollEdgeEffect` added in PR #8281 (`Add scrollEdgeEffect option`).\n- Title customization on scroll edge: PRs #8207, #8239.\n\n### 6. Search bar placement (UINavigationItemSearchBarPlacement)\niOS 26 introduces three placements:\n\n- `UINavigationItemSearchBarPlacementStacked` — under the title, classic.\n- `UINavigationItemSearchBarPlacementIntegrated` — inline with the title bar, expanded.\n- `UINavigationItemSearchBarPlacementIntegratedButton` — collapsed to a button until tapped.\n\nProperty: `UINavigationItem.preferredSearchBarPlacement`. Availability-gated, not present pre-iOS-26.\n\n**RNN handling:**\n- `ios/RNNSearchBarPlacement.mm` / `.h` — JS-facing enum.\n- `ios/UIViewController+RNNOptions.mm` (`setSearchBar...`): maps RNN's `SearchBarPlacementIntegrated` to integrated or integrated-button depending on `focus`. Falls through to stacked otherwise.\n- PR #8211 — skip integrated placement when not available (pre-26 safety).\n\n### 7. Shared background (\"Platter\") on bar button items\niOS 26 wraps every `UIBarButtonItem` in a shared Liquid Glass platter. Custom views and pre-styled `UIButton`s get double-decorated.\n\n- `UIBarButtonItem.hidesSharedBackground: Bool` — opt out of the platter.\n- Custom views need a fixed bar-item size (44pt) so the navbar reserves the slot before React mounts the content; otherwise the navbar relayouts after mount and the custom view snaps into place.\n\n**RNN handling:**\n- `ios/RNNUIBarButtonItem.mm`: defaults `hidesSharedBackground = YES` on iOS 26 for both icon buttons and custom (React) view buttons. Pins custom view to 44x44.\n- `ios/RNNReactButtonView.mm`: width/height constraints + center translation post-mount to keep the React view aligned inside the reserved 44pt slot.\n- New option: `RNNButtonOptions.hideSharedBackground` (also on `RNNBackButtonOptions`) — see `src/interfaces/Options.ts`.\n- PR #8300 — centering fix.\n\n### 7a. `UIBarButtonItemGroup` factory APIs and prominent style (iOS 26)\n\niOS 26 added direct factories on `UIBarButtonItem` that build groups inline. These are the cleanest way to make the shared platter intentional rather than relying on UIKit's implicit clustering.\n\n```\nUIBarButtonItem.creatingFixedGroup() -> UIBarButtonItemGroup\nUIBarButtonItem.creatingMovableGroup(customizationIdentifier:) -> UIBarButtonItemGroup\nUIBarButtonItem.creatingOptionalGroup(customizationIdentifier:isInDefaultCustomization:) -> UIBarButtonItemGroup\n```\n\nPlus a new style:\n\n- `UIBarButtonItem.style = .prominent` — primary-action styling, tints the platter with the bar's `tintColor` at full saturation. Use sparingly (one prominent item per bar).\n\nWhen grouping is intentional, UIKit renders the group under a single `_UIBarItemGroupPlatter` (see §7b/§9) instead of one platter per item. `hidesSharedBackground` still applies per item, so you can mix glassed and bare items inside one group.\n\n**RNN handling:** Not exposed today. If a future option models a logical action cluster, build it as a `UIBarButtonItemGroup` rather than a sequence of items so the platter coalesces correctly.\n\nReferences:\n- [`UIBarButtonItemGroup`](https://developer.apple.com/documentation/uikit/uibarbuttonitemgroup)\n- [`UIBarButtonItem.Style`](https://developer.apple.com/documentation/uikit/uibarbuttonitem/style)\n\n### 7b. Internal view hierarchy: `UIBarButtonItem` on iOS 26\n\n`UIBarButtonItem` is **not a `UIView`** — it's a model object. UIKit materializes it into a private view hierarchy inside the parent `UINavigationBar` or `UIToolbar`. The exact class names are private and can change; the **layering and ordering are stable** and worth knowing for layout debugging.\n\nApproximate structure for a single bar button item (Liquid Glass, iOS 26):\n\n```\nUINavigationBar / UIToolbar\n└── _UIBarBackground               (bar-wide background, Liquid Glass material)\n└── _UIButtonBarStackView          (horizontal stack of items, leading or trailing group)\n    └── _UIModernBarButton         (host view per item; one per UIBarButtonItem)\n        ├── _UIBarItemPlatter      (shared Liquid Glass background; the \"platter\")\n        │   └── CAFilter / glass layers (UIGlassEffect-backed)\n        └── content view           (image, title label, OR customView)\n```\n\nKey facts that affect RNN code:\n\n- **The platter is per-item by default**, but adjacent items inside the same `UIBarButtonItemGroup` (or implicit leading/trailing cluster) can be coalesced into a **single shared platter** spanning several items. This is the \"shared background\" that `hidesSharedBackground` opts out of.\n- **`hidesSharedBackground = YES`** removes the `_UIBarItemPlatter` from the host view; the content view becomes the direct child of `_UIModernBarButton`. The host view is **still 44pt minimum**.\n- **The host view (`_UIModernBarButton`) reserves the slot**, not the customView. UIKit sizes the host using:\n  - System images: intrinsic size of the symbol + padding.\n  - Title-only items: text width + padding.\n  - **Custom views: the customView's intrinsic content size at the time the bar performs layout.** This is why RNN pins the custom React view to 44×44 in `RNNUIBarButtonItem.mm` — without explicit constraints, React mounts asynchronously, the customView's intrinsic size starts at zero, the host reserves zero width, the bar lays out, then React reports its real size and the host has to relayout. The visible artifact is the button \"popping in\" or being misplaced after the push transition's snapshot already captured the wrong frame.\n- **Transitions snapshot the bar.** During push/pop, UIKit takes a snapshot of the navigation bar for the cross-fade between the from/to nav items. If the customView hasn't laid out before the snapshot, the snapshot shows the wrong state. This is also why a React customView can appear blank during a transition while being fine on the destination screen.\n- **Tinting flows through the platter, not the customView.** `tintColor` set on the bar item or bar applies to the system image inside the host view; it does not propagate into a React customView. Color the React content explicitly.\n\nPractical debugging:\n\n- Inspect the live hierarchy with `po [self.navigationItem.rightBarButtonItems.firstObject valueForKey:@\"_view\"]` in lldb, or with View Debugger → uncheck \"Show layers only\" to see the private classes.\n- A button that's \"there but invisible\" usually means the host view has 0×0 frame (sizing race) or `hidesSharedBackground = NO` with a customView that paints its own chrome (double-decoration clips/overlaps).\n- A button that \"snaps into place\" after the screen appears means the host view's intrinsic size changed after the bar's first layout pass.\n\nReferences (public API only — internals are observed, not documented):\n- [`UIBarButtonItem`](https://developer.apple.com/documentation/uikit/uibarbuttonitem)\n- [`UIBarButtonItem.hidesSharedBackground`](https://developer.apple.com/documentation/uikit/uibarbuttonitem/hidessharedbackground)\n- [`UIBarButtonItemGroup`](https://developer.apple.com/documentation/uikit/uibarbuttonitemgroup)\n\n### 8. Tab bar minimize behavior (iOS 26)\nThe tab bar can auto-minimize during scroll.\n\n- `UITabBarController.tabBarMinimizeBehavior` — `.automatic`, `.never`, `.onScrollDown`, `.onScrollUp`.\n- `setNeedsUpdateOfTabBarMinimizeBehavior()` — re-evaluate.\n- Apple: [UITabBarController](https://developer.apple.com/documentation/uikit/uitabbarcontroller)\n\n**RNN handling:** Not yet exposed. Would be a new option on `bottomTabs`.\n\n### 9. `UIToolbar` on iOS 26\n\n`UIToolbar` is a real `UIView` (unlike `UIBarButtonItem`). Approximate internal hierarchy on iOS 26:\n\n```\nUIToolbar\n├── _UIBarBackground                  (bar-wide Liquid Glass material;\n│                                      configured via UIToolbarAppearance)\n│   └── _UIBackdropView / glass layers\n│   └── _UIBarBackgroundShadowView    (1pt hairline; controlled by shadowImage / shadowColor)\n└── _UIToolbarContentView\n    └── _UIButtonBarStackView         (horizontal stack of toolbar items)\n        ├── _UIModernBarButton        (item host — see 7b for layer breakdown)\n        ├── _UIModernBarButton\n        ├── ... fixed/flexible spaces become layout gaps in the stack ...\n        └── (optional) _UIBarItemGroupPlatter\n              └── two or more _UIModernBarButton sharing one platter\n                  (only when items are in the same UIBarButtonItemGroup)\n```\n\nWhat's actually public and load-bearing on iOS 26:\n\n- **Appearance objects are the only safe way to style.** `UIToolbarAppearance` (standard / compact / scrollEdge) drives `_UIBarBackground`. Setting `barTintColor` / `backgroundImage` on `UIToolbar` directly is **silently overridden** by Liquid Glass unless `appearance.backgroundEffect = nil`.\n- **Translucency is the default.** `configureWithDefaultBackground` on iOS 26 produces glass. To get an opaque fill: `configureWithOpaqueBackground` **plus** `backgroundEffect = nil` **plus** explicit `backgroundColor`. This mirrors what `BottomTabsAppearancePresenter.mm` does for the tab bar.\n- **Items follow the same Platter rules as nav bar buttons.** A custom view in a toolbar item gets wrapped in a platter unless `hidesSharedBackground = YES`. The 44pt host-view sizing race applies identically.\n- **Grouping with `UIBarButtonItemGroup`** lets adjacent items render under one shared platter (visually grouped pill). `customizationIdentifier` opts the toolbar into the user-customization sheet (iPadOS).\n- **`scrollEdgeAppearance` matters here too.** When a scroll view is attached, the toolbar fades to transparent at the scroll edge using `UIToolbar.scrollEdgeAppearance`. Pre-iOS-26 this was iPad-only for many cases; iOS 26 applies it consistently.\n\nDisplay mode and customization (iOS 26 / iPadOS 26):\n\n- `UIToolbar.displayMode` — `.automatic`, `.expanded`, `.compact`. Drives whether items spread out or collapse into an overflow menu.\n- `UIBarButtonItem.menuRepresentation` — the menu UIKit shows when the item is hoisted into the overflow control under `.compact`.\n- `UIToolbar.beginCustomizingItems(...)` / `endCustomizingItems` — programmatic entry into the user-customization sheet for movable/optional groups.\n\nRNN handling:\n\nRNN does not expose `UIToolbar` as a first-class options surface today. Toolbar-shaped behavior in this repo comes from the navigation controller's bottom bar via `RNNStackController` and is configured indirectly through stack options. Any new toolbar feature should:\n\n1. Add a presenter (e.g. `ToolbarPresenter`) mirroring `TopBarPresenter`'s appearance pattern.\n2. Configure via `UIToolbarAppearance` only — never direct `barTintColor` / `backgroundImage`.\n3. Use `UIBarButtonItemGroup` when the option models a logical cluster (e.g. \"primary actions\") so the platter coalesces correctly.\n4. Apply `hidesSharedBackground` defaults for React custom views, same as `RNNUIBarButtonItem.mm` does today.\n\nReferences:\n- [`UIToolbar`](https://developer.apple.com/documentation/uikit/uitoolbar)\n- [`UIToolbarAppearance`](https://developer.apple.com/documentation/uikit/uitoolbarappearance)\n- [`UIBarButtonItemGroup`](https://developer.apple.com/documentation/uikit/uibarbuttonitemgroup)\n- WWDC25: \"What's new in UIKit\" (toolbar/group section), \"Build a UIKit app with the new design\"\n\n### 10. Preferred transition\n- `UINavigationController.preferredTransition` — control push/pop animation style (iOS 26 expansion).\n- `UIViewController.preferredTransition` — zoom transitions.\n\n**RNN handling:** Not exposed. Stack push/pop currently uses defaults.\n\n### 11. SF Symbols 7\niOS 26 ships SF Symbols 7. Bar buttons that use system images get the new variants automatically. Custom symbol configurations should re-test on iOS 26.\n\nAnimated symbols are part of the iOS 26 bar story:\n\n- `NSSymbolEffect` family — `.bounce`, `.pulse`, `.variableColor`, `.replace`, `.breathe`, `.scale`, `.appear`, `.disappear`, `.wiggle` (iOS 18+; new variants in 26).\n- Apply via the bar item's image: configure `UIImageView` produced by UIKit, or use `UIView.addSymbolEffect(_:options:animated:)` on the host view returned by `UIBarButtonItem.value(forKey: \"_view\")` (private — prefer using `UIButton` with a configured image inside a custom bar item).\n- WWDC25: \"What's new in SF Symbols 7\".\n\n### 12. `UIButton` glass configurations\n`UIButton.Configuration` got first-class glass factories in iOS 26. Anything RNN renders that's *not* a bar button (custom views inside a screen, overlays, modal headers, bottom accessories) should adopt these instead of hand-rolling chrome.\n\n```\nUIButton.Configuration.glass()           — translucent Liquid Glass pill\nUIButton.Configuration.prominentGlass()  — tinted, more saturated variant\nUIButton.Configuration.plain()\nUIButton.Configuration.gray()\nUIButton.Configuration.tinted()\nUIButton.Configuration.filled()\nUIButton.Configuration.borderless()\n```\n\nOn iOS 26 the legacy configurations (`plain` / `gray` / `tinted` / `filled` / `borderless`) automatically repaint with the Liquid Glass material — you don't opt in, you opt *out* via `UIDesignRequiresCompatibility`.\n\nConfiguration knobs that affect build-up:\n- `cornerStyle` — `.fixed` / `.dynamic` / `.capsule` / `.small` / `.medium` / `.large`. `.dynamic` adopts concentric corners (see §15).\n- `buttonSize` — `.mini` / `.small` / `.medium` / `.large`.\n- `baseBackgroundColor` / `baseForegroundColor` — tint multiplier on glass.\n\nApproximate internal hierarchy for a configuration-based button on iOS 26:\n\n```\nUIButton (configuration-based)\n├── _UIButtonBackgroundView         (the platter / glass body)\n│   ├── UIVisualEffectView          (UIGlassEffect — see §13)\n│   └── tint overlay (CALayer)\n└── _UIButtonContentStackView\n    ├── UIImageView                 (leading or trailing image)\n    ├── UILabel                     (title)\n    └── UILabel                     (subtitle, when set)\n```\n\n**RNN handling:** Not exposed as an option today. RNN doesn't render its own button chrome inside screens — that's the React side's job — but if RNN ever needs a system-styled control (e.g. a \"Done\" button on a custom modal header it builds natively), use `UIButton.Configuration.glass()` rather than custom drawing.\n\nReferences:\n- [`UIButton.Configuration`](https://developer.apple.com/documentation/uikit/uibutton/configuration)\n- [`UIButton.Configuration.glass()`](https://developer.apple.com/documentation/uikit/uibutton/configuration/glass())\n\n### 13. `UIGlassEffect` and `UIGlassContainerEffect` (public Liquid Glass API)\n\nThe entire Liquid Glass material is exposed publicly. This is the API to use whenever RNN needs custom glass chrome — floating overlays, bottom accessories, custom navigation extensions, modal grabbers.\n\n```\nUIGlassEffect                        — UIVisualEffect subclass\nUIGlassEffect.Style.regular          — default frosted glass\nUIGlassEffect.Style.clear            — thinner, more transparent variant\nUIGlassEffect.tintColor              — multiplied tint\nUIGlassContainerEffect               — wraps multiple glass views; they morph/merge when adjacent\nUIVisualEffectView(effect: UIGlassEffect())  — host\n```\n\nBehavioral rules:\n- Glass **refracts and blurs** content behind it; opacity is content-derived, not a static color.\n- Two `UIVisualEffectView`s with `UIGlassEffect` placed inside the same `UIGlassContainerEffect` will **visually merge** into a single platter when they touch or overlap. This is what produces the \"morphing\" you see when a search bar collapses into a button, or when tabs minimize into a single pill.\n- `tintColor` is **multiplied**, not painted — fully saturated colors look pastel. Use bold colors only when you want a noticeably tinted glass.\n- Glass adapts to dark / light mode automatically; do not hand-set background colors on the visual effect view.\n\nBuild-up:\n\n```\nUIVisualEffectView (effect: UIGlassEffect)\n├── _UIVisualEffectBackdropView      (CAFilter blur + refraction)\n├── _UIVisualEffectSubview           (tint overlay)\n└── contentView                      (your content; goes here, not on the effect view directly)\n```\n\n**RNN handling:** Not used yet. Any future custom chrome (e.g. a `bottomAccessory` host, a custom modal grabber, a floating action overlay) should be a `UIVisualEffectView` with `UIGlassEffect`, **not** a `UIView` with a manually configured `UIBlurEffect`. Pre-iOS-26 RNN can fall back to `UIBlurEffectStyle.systemMaterial` via the existing availability pattern.\n\nReferences:\n- [`UIGlassEffect`](https://developer.apple.com/documentation/uikit/uiglasseffect)\n- [`UIGlassContainerEffect`](https://developer.apple.com/documentation/uikit/uiglasscontainereffect)\n- [`UIVisualEffectView`](https://developer.apple.com/documentation/uikit/uivisualeffectview)\n- WWDC25: \"Meet Liquid Glass\"\n\n### 14. `UINavigationItem.style` — navigator / browser / editor\n\niOS 26 introduces three navigation item styles that reshape the entire navigation bar's internal layout. This is one of the bigger build-up changes in 26.\n\n```\nUINavigationItem.Style.navigator     — default; classic nav title + leading/trailing items\nUINavigationItem.Style.browser       — URL-bar-like layout with a centered integrated field\nUINavigationItem.Style.editor        — document editor; renamable title + subtitle + badge\n```\n\nRelated properties (only meaningful when `style` ≠ `.navigator`):\n\n- `UINavigationItem.documentProperties: UIDocumentProperties?` — file URL, subtitle, badge displayed in editor style.\n- `UINavigationItem.renameDelegate` — inline rename UI for editor style.\n- `UINavigationItem.titleMenuProvider` — context menu when tapping the title (iOS 16+, but actually visible by default in browser/editor styles on 26).\n\nHow the build-up changes:\n\n- `.navigator` — standard `_UINavigationBarContentView` with title label centered.\n- `.browser` — `_UINavigationBarContentView` swaps the title slot for an integrated URL field (`UISearchTextField`-shaped), with leading and trailing item clusters under shared platters.\n- `.editor` — adds a vertical stack: title (renamable) + subtitle (file path) + badge, plus a primary action slot at the trailing edge.\n\n**RNN handling:** Not exposed. A future RNN option could surface `topBar.style: 'navigator' | 'browser' | 'editor'`. Editor style is the more interesting one for document-shaped apps; browser style fits Wix preview-style flows.\n\nReferences:\n- [`UINavigationItem.Style`](https://developer.apple.com/documentation/uikit/uinavigationitem/style)\n- [`UIDocumentProperties`](https://developer.apple.com/documentation/uikit/uidocumentproperties)\n- WWDC25: \"Build a UIKit app with the new design\"\n\n### 15. `UICornerConfiguration` and concentric corners\n\nConcentric corners are a foundational iOS 26 design rule: a child element's corner radius should equal its parent's radius minus the inset, so curves stay visually parallel. Apple's own bar items, sheets, and buttons obey this; mixing fixed `cornerRadius` with a concentric container looks visibly wrong on 26.\n\n```\nUICornerConfiguration.uniformCornerRadius(_:)            // fixed radius\nUICornerConfiguration.uniformCornerConfiguration(_:)     // with corner style (capsule, etc.)\nUICornerConfiguration.concentric(minimum:)               // matches parent's curvature, floored at minimum\nUIView.cornerConfiguration: UICornerConfiguration?       // applies to the view's layer\n```\n\nRule of thumb: anything painted **inside** a glass element should be `.concentric(minimum: small)` rather than `.uniformCornerRadius(N)`. The system already uses concentric corners for bar item platters, sheet corners that morph with the device screen radius, and tab bar item shapes.\n\n**RNN handling:** Not exposed. Any future RNN-native custom chrome that nests inside a glass element (e.g. a React custom view sitting inside an iOS 26 platter that RNN draws) should apply `.cornerConfiguration = .concentric(...)` on the wrapping UIView so it inherits the platter's curvature.\n\nReferences:\n- [`UICornerConfiguration`](https://developer.apple.com/documentation/uikit/uicornerconfiguration)\n- [`UIView.cornerConfiguration`](https://developer.apple.com/documentation/uikit/uiview/cornerconfiguration)\n\n### 16. `UISheetPresentationController` iOS 26 changes\n\nRNN modals route through `UISheetPresentationController` when configured. iOS 26 changes its presentation in three meaningful ways:\n\n- **`cornerConfiguration`** replaces `preferredCornerRadius` for finer control. Sheets can now have asymmetric corners and use `.concentric(minimum:)` to match the device's screen radius — the result is the visible \"corner morph\" when the sheet animates from the small detent to medium/large.\n- **Default detents changed.** The small detent now overlaps the safe area more gracefully because the corner configuration animates with the detent height. Custom detents (`UISheetPresentationController.Detent.custom`) need to play nicely with this.\n- **Sheets slide *under* the floating tab bar by default.** Pre-iOS-26 the tab bar pushed the sheet up; on 26 the sheet's small detent extends behind the tab bar. If a sheet must avoid covering the tab bar, opt out by configuring the detent height explicitly or by presenting from a context that excludes the tab bar.\n\nRelated: `UISheetPresentationController.prefersGrabberVisible` still controls the grabber; the grabber now uses Liquid Glass material.\n\n**RNN handling:** RNN exposes modal presentation through stack options. iOS 26 sheet behavior surfaces automatically through UIKit defaults — but the \"sheet over tab bar\" change can visually regress apps that expected the pre-26 layout. If users report it, the fix is to adjust the detent or presentation context, not to fight UIKit.\n\nReferences:\n- [`UISheetPresentationController`](https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller)\n- WWDC25: \"What's new in UIKit\" (sheet section)\n\n---\n\n## Workflow: adding iOS 26 support for a new API\n\n1. **Confirm the Apple API surface.** Read the relevant `developer.apple.com` page; check WWDC25 sessions for sample patterns.\n2. **Pick the RNN seam.** Use the mapping above. Top bar → `TopBarPresenter` + `RNNTopBarOptions`. Bottom tab → `BottomTabsAppearancePresenter` / `RNNBottomTabsController` + `RNNBottomTabsOptions`. Bar buttons → `RNNUIBarButtonItem` + `RNNButtonOptions`.\n3. **Add the JS option** in `lib/src/interfaces/Options.ts`. Document semantics, iOS-only marker, iOS 26 minimum.\n4. **Parse it** in the matching `*Options.mm` (use the existing `[XParser parse:dict key:@\"...\"]` pattern). Add to `mergeOptions:`.\n5. **Apply it** in the presenter, **always guarded** by `if (@available(iOS 26.0, *)) { ... }`. Honor `UIDesignRequiresCompatibility` if behavior would diverge for legacy-design apps.\n6. **Add a playground screen** in `playground/src/screens/` exercising the option, both visible and toggle states.\n7. **Add an e2e** in `playground/e2e/` using `device.getPlatform() === 'ios'` and an iOS version check. Follow existing baseline-then-action screenshot patterns.\n8. **Update docs** in `website/docs/api/options-*.mdx`.\n9. **Build Release** with Xcode 26.1, run on iPhone 17 Pro Max simulator, then **also** verify on an iOS 18 simulator for regression.\n\n## Workflow: investigating an iOS 26 regression\n\n1. Reproduce in Release on iOS 26 sim. Reproduce on iOS 18/17 — confirm it's 26-only.\n2. Grep `if (@available(iOS 26.0, *))` and the property name (e.g. `backgroundEffect`, `hidesSharedBackground`, `preferredSearchBarPlacement`) — see if RNN already has a branch.\n3. Check recent PRs touching the same file (`git log --oneline -- ios/<file>.mm | head -20`) — most iOS 26 regressions cluster.\n4. Check `UIDesignRequiresCompatibility`: if the bug only happens with the new design, the fix must not break compatibility mode.\n5. Confirm Fabric / New Architecture is still on (don't disable it to \"fix\" something).\n6. Before changing code, summarize the hypothesis and proposed fix to the user (per user rule \"show me first\").\n\n---\n\n## Known iOS 26 trouble spots in this repo\n\n| Area | File(s) | Last touched PR(s) |\n|------|---------|-------------------|\n| Custom React bar buttons (Platter, centering, lifecycle) | `RNNUIBarButtonItem.mm`, `RNNReactButtonView.mm` | #8300 |\n| Tab item title misplaced on first layout | `RNNBottomTabsController.mm` (`rnn_cycleAllTabsThenRestoreInitialSelection`) | #8245, #8254, #8255 |\n| Tab bar background color / glass | `BottomTabsAppearancePresenter.mm` | #8263, #8288 |\n| Search bar placement | `UIViewController+RNNOptions.mm`, `RNNSearchBarPlacement.mm` | #8183, #8211 |\n| Scroll edge effect on top bar | top bar options | #8281, #8239, #8207 |\n| iPad back navigation (iOS 26) | nav controller | #8277 |\n| `drawBehind` default on floating tab bar | `RNNBottomTabsOptions.mm` (`-shouldDrawBehind`) | — |\n\n---\n\n## Authoritative references\n\n- HIG: [Designing for iOS 26](https://developer.apple.com/design/human-interface-guidelines/designing-for-ios), [Materials (Liquid Glass)](https://developer.apple.com/design/human-interface-guidelines/materials), [Tab bars](https://developer.apple.com/design/human-interface-guidelines/tab-bars), [Navigation bars](https://developer.apple.com/design/human-interface-guidelines/navigation-bars), [Toolbars](https://developer.apple.com/design/human-interface-guidelines/toolbars)\n- API (bars and tabs): [UITabBarController](https://developer.apple.com/documentation/uikit/uitabbarcontroller), [UITab](https://developer.apple.com/documentation/uikit/uitab), [UITabAccessory](https://developer.apple.com/documentation/uikit/uitabaccessory), [UINavigationItem](https://developer.apple.com/documentation/uikit/uinavigationitem), [UINavigationItem.Style](https://developer.apple.com/documentation/uikit/uinavigationitem/style), [UIBarButtonItem.hidesSharedBackground](https://developer.apple.com/documentation/uikit/uibarbuttonitem/hidessharedbackground), [UIBarButtonItemGroup](https://developer.apple.com/documentation/uikit/uibarbuttonitemgroup), [UIScrollEdgeEffect](https://developer.apple.com/documentation/uikit/uiscrolledgeeffect), [UIBarAppearance](https://developer.apple.com/documentation/uikit/uibarappearance), [UIToolbar](https://developer.apple.com/documentation/uikit/uitoolbar)\n- API (glass and shapes): [UIGlassEffect](https://developer.apple.com/documentation/uikit/uiglasseffect), [UIGlassContainerEffect](https://developer.apple.com/documentation/uikit/uiglasscontainereffect), [UICornerConfiguration](https://developer.apple.com/documentation/uikit/uicornerconfiguration), [UIButton.Configuration](https://developer.apple.com/documentation/uikit/uibutton/configuration), [UIButton.Configuration.glass()](https://developer.apple.com/documentation/uikit/uibutton/configuration/glass())\n- API (presentation): [UISheetPresentationController](https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller), [UIDocumentProperties](https://developer.apple.com/documentation/uikit/uidocumentproperties)\n- WWDC25: \"Meet Liquid Glass\", \"Get to know the new design system\", \"What's new in UIKit\", \"Build a UIKit app with the new design\", \"Elevate your tab and sidebar experience\", \"Make your UIKit app more flexible\", \"What's new in SF Symbols 7\"\n- Compatibility: [UIDesignRequiresCompatibility](https://developer.apple.com/documentation/bundleresources/information-property-list/uidesignrequirescompatibility)\n",".cursor/skills/rnn-codebase/SKILL.md":"---\nname: rnn-codebase\ndescription: Navigate and work with the react-native-navigation (RNN) codebase. Use when fixing bugs, adding features, tracing command flows, understanding options resolution, or working across JS/iOS/Android layers in this repo.\n---\n\n# React Native Navigation Codebase\n\n## Architecture Overview\n\nRNN has three layers that mirror each other:\n\n```\nJS/TS (src/)  →  TurboModule bridge  →  iOS native (ios/)\n                                     →  Android native (android/)\n```\n\nA navigation command (e.g. `push`) flows:\n1. `Navigation.push()` → `Commands.ts` → processing pipeline → `NativeCommandsSender.ts`\n2. TurboModule: `RNNTurboModule` (iOS) / `NavigationTurboModule.kt` (Android)\n3. iOS: `RNNCommandsHandler` → `RNNViewControllerFactory` → UIKit controllers\n4. Android: `Navigator` → `LayoutFactory` → View-based controllers (no Fragments)\n\nRead [ARCHITECTURE.md](../../ARCHITECTURE.md) for the full overview.\n\n## Key Cross-Layer Mappings\n\n### Layout Types → Native Controllers\n\n| JS Layout Type | iOS Controller | Android Controller |\n|----------------|---------------|-------------------|\n| `component` | `RNNComponentViewController` | `ComponentViewController` |\n| `stack` | `RNNStackController` (UINavigationController) | `StackController` |\n| `bottomTabs` | `RNNBottomTabsController` (UITabBarController) | `BottomTabsController` |\n| `sideMenu` | `RNNSideMenuViewController` (MMDrawerController) | `SideMenuController` (DrawerLayout) |\n| `topTabs` | `RNNTopTabsViewController` | `TopTabsController` (ViewPager) |\n| `splitView` | `RNNSplitViewController` | N/A (iOS only) |\n| `externalComponent` | `RNNExternalViewController` | `ExternalComponentViewController` |\n\n### Options → Presenters\n\nEach controller type has a Presenter that applies options to views:\n\n| iOS Controller | iOS Presenter | Android Presenter |\n|----------------|--------------|-------------------|\n| `RNNComponentViewController` | `RNNComponentPresenter` | `ComponentPresenter` |\n| `RNNStackController` | `RNNStackPresenter` + `TopBarPresenter` | `StackPresenter` |\n| `RNNBottomTabsController` | `RNNBottomTabsPresenter` | `BottomTabsPresenter` |\n| `RNNSideMenuViewController` | `RNNSideMenuPresenter` | `SideMenuPresenter` |\n\n### Events (same names both platforms)\n\n| Event | Trigger |\n|-------|---------|\n| `RNN.ComponentDidAppear` | Screen becomes visible |\n| `RNN.ComponentDidDisappear` | Screen hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tap |\n| `RNN.BottomTabSelected` | Tab changed |\n| `RNN.ModalDismissed` | Modal dismissed |\n| `RNN.ScreenPopped` | Screen popped from stack |\n| `RNN.CommandCompleted` | Any command finished |\n\n## Where to Find Things\n\n### By task: \"I need to fix/change X\"\n\n| Task | JS File(s) | iOS File(s) | Android File(s) |\n|------|-----------|------------|----------------|\n| Command execution | `src/commands/Commands.ts` | `ios/RNNCommandsHandler.mm` | `react/NavigationTurboModule.kt` |\n| Layout creation | `src/commands/LayoutTreeParser.ts` | `ios/RNNViewControllerFactory.mm` | `options/LayoutFactory.java` |\n| Options processing | `src/commands/OptionsProcessor.ts` | `ios/RNNNavigationOptions.mm` | `options/Options.java` |\n| Options application | — | `ios/*Presenter.mm` | `viewcontrollers/*Presenter.java` |\n| TopBar | `src/interfaces/Options.ts` (TopBarOptions) | `ios/TopBarPresenter.mm`, `ios/RNNUIBarButtonItem.mm` | `views/stack/topbar/` |\n| Bottom tabs | `src/interfaces/Options.ts` (BottomTabsOptions) | `ios/RNNBottomTabsPresenter.mm` | `viewcontrollers/bottomtabs/` |\n| Modals | `src/commands/Commands.ts` | `ios/RNNModalManager.mm` | `viewcontrollers/modal/ModalStack.java` |\n| Overlays | `src/commands/Commands.ts` | `ios/RNNOverlayManager.mm` | `viewcontrollers/overlay/OverlayManager.kt` |\n| Animations | `src/interfaces/Options.ts` (AnimationOptions) | `ios/ScreenAnimationController.mm` | `viewcontrollers/stack/StackAnimator.kt` |\n| React view rendering | — | `ios/RNNReactView.mm` | `react/ReactView.java` |\n| Events to JS | `src/adapters/NativeEventsReceiver.ts` | `ios/RNNEventEmitter.mm` | `react/events/EventEmitter.java` |\n| Component registration | `src/components/ComponentRegistry.ts` | — | — |\n\n### By directory\n\n- **`src/`** — JS public API, commands, processing pipeline. See [src/ARCHITECTURE.md](../../src/ARCHITECTURE.md)\n- **`ios/`** — All Obj-C/C++ native code. See [ios/ARCHITECTURE.md](../../ios/ARCHITECTURE.md)\n- **`ios/TurboModules/`** — New architecture entry points (`RNNTurboModule`, `RNNTurboManager`, `RNNTurboCommandsHandler`)\n- **`android/src/main/java/com/reactnativenavigation/`** — All Java/Kotlin native code. See [android/ARCHITECTURE.md](../../android/ARCHITECTURE.md)\n- **`playground/`** — Demo app for development and E2E tests\n- **`playground/src/screens/`** — Test screens exercising every feature\n- **`playground/e2e/`** — Detox E2E tests\n\n## Options Resolution Order\n\nOptions are applied in ascending priority:\n1. Default options (from `Navigation.setDefaultOptions()`) — lowest priority\n2. Static options (from component class or `Navigation.registerComponent`)\n3. Options passed in the layout call (e.g. `push`, `setRoot`)\n4. `mergeOptions()` — runtime override, highest priority\n\n## JS Processing Pipeline (exact order)\n\n```\nAPI layout → OptionsCrawler.crawl() → LayoutProcessor.process()\n  → LayoutTreeParser.parse() → LayoutTreeCrawler.crawl()\n  → OptionsProcessor (colors, assets, custom) → NativeCommandsSender\n```\n\n## iOS Patterns\n\n- All controllers conform to `RNNLayoutProtocol`\n- `RNNBasePresenter` subclasses apply options — `applyOptionsOnInit:`, `applyOptions:`, `mergeOptions:resolvedOptions:`\n- Commands run on main thread (`RCTExecuteOnMainQueue`)\n- React views: `RNNReactView` wraps `RCTSurfaceHostingView` (new arch)\n- Overlays use separate `UIWindow` instances (`RNNOverlayWindow`)\n- `RNNReactComponentRegistry` caches React component instances\n\n## Android Patterns\n\n- View-based, NOT Fragment-based\n- All commands dispatched via `UiThread.post()`\n- `ViewController<T extends ViewGroup>` is the base — `createView()` is abstract\n- `ParentController` extends `ChildController` extends `ViewController`\n- Bottom tabs use `AHBottomNavigation` library\n- Three root layouts in `NavigationActivity`: rootLayout, modalsLayout, overlaysLayout\n- Tab attachment modes: `Together`, `OnSwitchToTab`, `AfterInitialTab`\n\n## Development Workflow\n\n### Playground app\n- `yarn start` — Metro bundler\n- `yarn xcode` — Open iOS project\n- `yarn studio` — Open Android project\n- `yarn pod-install` — Install iOS pods\n\n### Testing\n- `yarn test-js` — Jest unit tests\n- `yarn test-unit-ios` — iOS native unit tests (XCTest)\n- `yarn test-unit-android` — Android native unit tests (JUnit + Robolectric)\n- `yarn test-e2e-ios-ci` / `yarn test-e2e-android-ci` — Detox E2E tests\n\n### Building\n- `yarn prepare` — Builds `src/` → `lib/` (ESM + types)\n- Codegen config: `rnnavigation` in `package.json`\n\n## Engine Integration (Wix One App)\n\nRNN is a standalone library but also a core dependency of `mobile-apps-engine` (the Wix One App platform). Changes to RNN's public API surface can break engine.\n\n### Version Management\n\n- Version pinned in two files (must match):\n  - `packages/native/mobile-apps-engine-native/package.json`\n  - `packages/wix-one-app-storage/package.json`\n- `yarn.config.cjs` has a constraint that reads the version from `mobile-apps-engine-native` and validates all workspaces use the same version. It's a validation rule — bumping the native package.json is sufficient.\n\n### iOS Integration\n\n- Engine's `AppDelegate` subclasses `RNNAppDelegate` — breaking changes to that class will break engine.\n- Podfile resolves `ReactNativeNavigation` pod from node_modules.\n- Xcode project has header search paths pointing into `node_modules/react-native-navigation/ios/**`.\n\n### Android Integration\n\n- Engine's `EngineRN.kt` extends `NavigationApplication` and uses `NavigationPackage` / `NavigationReactNativeHost`.\n- `missingDimensionStrategy \"RNN.reactNativeVersion\"` is set in `app/build.gradle` — may need updating if RNN changes its flavor dimensions.\n- Build variables `RNNKotlinVersion`, `RNNKotlinStdlib`, `RNNKotlinCoroutinesCore` are forwarded from engine's Kotlin config.\n\n### Active Patches (in engine's setup)\n\n- **OptionsProcessor.js** — engine replaces RNN's `OptionsProcessor.js` at setup time via `patchRNNOptionsProcessor()` in `packages/cli/mobile-apps-engine-setup/src/index.js`. The patched copy lives at `packages/cli/mobile-apps-engine-setup/etc/OptionsProcessor.js`. It adds:\n  - Custom iOS color processing with `DynamicColorIOS` (dark/light/dynamic object shapes)\n  - Custom Android color processing wrapping colors in `{dark, light}` objects with `semantic`/`resource_paths` support\n  - Component ID uses `value.name` instead of `uniqueIdProvider.generate()`\n- Any changes to `src/commands/OptionsProcessor.ts` require checking if the engine patch needs updating.\n\n### JS Wrappers\n\nEngine wraps RNN's `Navigation` API in several services:\n- `Navigator.ts` — root layout, overlays, error screens, tab navigation\n- `BottomTabsBackHandler.ts` — back handling on bottom tabs via `Navigation.events()`\n- `TabsManager.ts` — tab management using RNN `Layout` types\n- Various other services import `Layout`, `LayoutRoot`, `LayoutSideMenu`, `OptionsSideMenu` from RNN\n\n### Upgrade Checklist\n\n1. Bump version in both `package.json` files\n2. Verify `OptionsProcessor.js` patch still applies (diff upstream changes)\n3. Check `RNNAppDelegate` API compatibility (iOS)\n4. Check `NavigationApplication` / `NavigationPackage` / `NavigationReactNativeHost` API compatibility (Android)\n5. Verify `missingDimensionStrategy` value is still valid\n6. Check `react-native-navigation-hooks` and `rnn-copilot` compatibility\n7. Run `yarn install` to update lockfile\n8. Verify test mocks (`react-native-navigation/Mock`) still work\n\n## Common Gotchas\n\n- iOS uses UIKit subclasses (UINavigationController, UITabBarController); Android uses custom View hierarchy\n- `splitView` is iOS-only\n- Side menu: iOS uses MMDrawerController (3rd party); Android uses DrawerLayout (native)\n- Options that exist in JS types may not be implemented on both platforms — check the presenter\n- `passProps` are stored in JS `Store`, not sent to native (cleared before bridge crossing)\n- The `lib/` folder is generated — never edit it, edit `src/` instead\n","ARCHITECTURE.md":"# React Native Navigation Architecture\n\nReact 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.\n\n## Project Overview\n\n- **Package**: `react-native-navigation` (v8.7.0)\n- **Platforms**: iOS 11+, Android 7.0+ (API 24)\n- **React Native**: 0.77+ (developed against 0.83; see package.json for current version)\n- **License**: MIT (maintained by Wix)\n\n## Directory Structure\n\n```\nreact-native-navigation/\n├── src/                    # TypeScript source code (JS API layer)\n├── lib/                    # Compiled output (generated by bob build - do not edit)\n├── android/                # Android native implementation (Java/Kotlin)\n├── ios/                    # iOS native implementation (Obj-C/C++)\n├── playground/             # Demo app and E2E test target\n├── autolink/               # Post-install linking scripts\n├── scripts/                # Build, test, and release scripts\n├── website/                # Docusaurus documentation site\n├── integration/            # Integration tests (Redux, Remx)\n├── Mock/                   # Mock implementations for testing\n└── .buildkite/             # CI/CD pipeline configuration\n```\n\n## High-Level Architecture\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│                     JavaScript API Layer                         │\n│  Navigation.setRoot() / push() / pop() / showModal() / etc.     │\n└─────────────────────────────┬────────────────────────────────────┘\n                              │\n┌─────────────────────────────▼────────────────────────────────────┐\n│                    Processing Pipeline                            │\n│  OptionsCrawler → LayoutProcessor → LayoutTreeParser → OptionsProcessor │\n└─────────────────────────────┬────────────────────────────────────┘\n                              │\n┌─────────────────────────────▼────────────────────────────────────┐\n│                   TurboModule Bridge                              │\n│  NativeCommandsSender ←→ RNNTurboModule (iOS) / NavigationTurboModule (Android) │\n└──────────┬─────────────────────────────────────┬─────────────────┘\n           │                                     │\n┌──────────▼──────────┐               ┌─────────▼──────────┐\n│   iOS Native Layer  │               │ Android Native Layer│\n│  UINavigationController             │   ViewControllers   │\n│  UITabBarController │               │   CoordinatorLayout │\n│  UIViewController   │               │   BottomNavigation  │\n└─────────────────────┘               └────────────────────┘\n```\n\n## Core Concepts\n\n### Layout Types\nAll navigation structures are composed from these layout primitives:\n\n| Layout Type | Description | iOS Implementation | Android Implementation |\n|-------------|-------------|-------------------|----------------------|\n| `component` | React component screen | RNNComponentViewController | ComponentViewController |\n| `stack` | Push/pop navigation | UINavigationController (RNNStackController) | StackController |\n| `bottomTabs` | Tab bar navigation | UITabBarController (RNNBottomTabsController) | BottomTabsController |\n| `topTabs` | Horizontal scrollable tabs | RNNTopTabsViewController | TopTabsController |\n| `sideMenu` | Drawer navigation (with center, left, right) | MMDrawerController (RNNSideMenuViewController) | SideMenuController |\n| `splitView` | Master-detail (iPad only) | UISplitViewController (RNNSplitViewController) | — |\n| `externalComponent` | Native (non-React) screen | RNNExternalViewController | ExternalComponentViewController |\n\n### Navigation Commands\nCore commands available through the Navigation API:\n\n- **Root**: `setRoot()` - Replace entire navigation hierarchy\n- **Stack**: `push()`, `pop()`, `popTo()`, `popToRoot()`, `setStackRoot()`\n- **Modal**: `showModal()`, `dismissModal()`, `dismissAllModals()`\n- **Overlay**: `showOverlay()`, `dismissOverlay()`, `dismissAllOverlays()`\n- **Options**: `setDefaultOptions()`, `mergeOptions()`, `updateProps()`\n- **Linking**: `setLinking()`, `handleDeepLink()`, `setLinkingReady()` - URL-to-screen routing\n\n### Deep Linking\nURL-driven navigation is implemented entirely in the JS layer (`src/linking/`) and feeds into the standard command pipeline. Configure with `Navigation.setLinking({ prefixes, config: { screens } })`; matched URLs are presented as modals by default (preserving the user's current navigation state). Customize via `getModal`/`onLink` hooks; gate processing on auth via `isReady`/`setLinkingReady`. Native plumbing — `application:openURL:`, `application:continueUserActivity:`, cold-start URL queueing — lives in `RNNAppDelegate` (iOS) and `NavigationActivity.onNewIntent` (Android), so subclassing the base classes is sufficient. See [Deep Linking docs](https://wix.github.io/react-native-navigation/docs/deep-linking).\n\n### Options System\nStyling and behavior is controlled via a hierarchical options object:\n\n```typescript\n{\n  statusBar: {...},      // Status bar appearance\n  topBar: {...},         // Navigation bar styling\n  bottomTabs: {...},     // Tab bar configuration\n  bottomTab: {...},      // Individual tab styling\n  sideMenu: {...},       // Drawer configuration\n  layout: {...},         // Screen layout options\n  animations: {...},     // Transition animations\n  modal: {...},          // Modal presentation style\n  overlay: {...}         // Overlay behavior\n}\n```\n\nOptions merge in order: **Default Options → Parent Options → Component Options**\n\n## Data Flow\n\n### Command Execution Flow\n```\n1. JS: Navigation.push(componentId, layout)\n2. Commands.ts validates and begins processing\n3. OptionsCrawler extracts static options from component classes\n4. LayoutProcessor applies registered layout processors\n5. LayoutTreeParser converts to internal LayoutNode tree\n6. LayoutTreeCrawler processes tree, saves props to Store\n7. OptionsProcessor resolves colors, images, fonts\n8. NativeCommandsSender sends to TurboModule\n9. Native layer creates/updates view hierarchy\n10. EventEmitter sends completion event to JS\n```\n\n**Note**: The JS layer exports a single `Navigation` object (from `NavigationDelegate`). The TurboModule names differ per platform: `RNNTurboModule` on iOS, `NavigationTurboModule` on Android.\n\n### Event Flow (Native → JS)\n```\n1. Native lifecycle event (viewDidAppear, etc.)\n2. RNNEventEmitter (iOS) / EventEmitter (Android)\n3. NativeEventsReceiver receives via NativeEventEmitter\n4. EventsRegistry dispatches to registered listeners\n5. ComponentEventsObserver calls component instance methods\n```\n\n## Key Architecture Patterns\n\n1. **Facade Pattern**: `NavigationDelegate` provides clean public API\n2. **Bridge Pattern**: Adapters isolate JS from native implementation details\n3. **Presenter Pattern**: Separates view styling from controller logic\n4. **Observer Pattern**: Event system for lifecycle and command notifications\n5. **Factory Pattern**: `LayoutFactory` creates controllers from layout nodes\n6. **Plugin Pattern**: Processors allow extending layout/options handling\n\n## Component Lifecycle\n\nReact components receive navigation lifecycle events:\n\n```typescript\nclass MyScreen extends NavigationComponent {\n  componentWillAppear(event) {}      // About to become visible\n  componentDidAppear(event) {}       // Now visible\n  componentDidDisappear(event) {}    // No longer visible\n  navigationButtonPressed(event) {}  // TopBar button tapped\n  screenPopped(event) {}             // Screen removed from stack\n  searchBarUpdated(event) {}         // Search text changed\n  searchBarCancelPressed(event) {}   // Search cancelled\n  previewCompleted(event) {}         // 3D Touch preview completed\n}\n```\n\n## Testing Architecture\n\n- **Unit Tests**: Jest + ts-mockito for TypeScript source\n- **Integration Tests**: Redux/Remx integration verification\n- **E2E Tests**: Detox framework with playground app\n- **Snapshot Tests**: iOS visual regression testing\n- **Native Unit Tests**: XCTest (iOS) and JUnit (Android)\n\n## Related Documentation\n\n- [JavaScript/TypeScript Architecture](./src/ARCHITECTURE.md)\n- [iOS Native Architecture](./ios/ARCHITECTURE.md)\n- [Android Native Architecture](./android/ARCHITECTURE.md)\n- [API Documentation](https://wix.github.io/react-native-navigation/)\n","ios/ARCHITECTURE.md":"# iOS Native Architecture\n\nThe iOS implementation provides native navigation using UIKit view controllers, coordinated through a bridge module that receives commands from JavaScript.\n\n## App Integration\n\n### RNNAppDelegate\n**Files**: `RNNAppDelegate.h/mm`\n\nBase class that user's AppDelegate must extend. Handles React Native and navigation initialization:\n\n```objc\n// AppDelegate.h - User extends RNNAppDelegate\n#import \"RNNAppDelegate.h\"\n@interface AppDelegate : RNNAppDelegate\n@end\n\n// AppDelegate.m - User implements sourceURLForBridge\n@implementation AppDelegate\n- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {\n  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@\"index\"];\n}\n@end\n```\n\n**What RNNAppDelegate does:**\n- Sets up React Native feature flags (Fabric, TurboModules, Bridgeless)\n- Creates `RCTRootViewFactory` and `ReactHost`\n- Calls `[ReactNativeNavigation bootstrapWithHost:]` to initialize navigation\n- Handles RN version differences (0.77, 0.78, 0.79+) via compile-time macros\n- **Deep linking plumbing**:\n  - Implements `application:openURL:options:` and `application:continueUserActivity:restorationHandler:`; both call `-dispatchDeepLinkURL:`.\n  - `-dispatchDeepLinkURL:` posts `RCTOpenURLNotification` directly if the React runtime is ready, otherwise enqueues the URL.\n  - Observes `RCTContentDidAppearNotification` (the Fabric/bridgeless signal) to flush the queue. This solves the cold-start race where URLs (push notifications, OS link launches) arrive before `RCTLinkingManager` is listening.\n  - Subclasses can call `-dispatchDeepLinkURL:` manually from notification delegates or any other URL source; the queueing behavior is reused automatically.\n\n### ReactNativeNavigation Bootstrap\n**File**: `ReactNativeNavigation.h/mm`\n\nPublic API for native initialization:\n\n```objc\n// New architecture (0.77+)\n[ReactNativeNavigation bootstrapWithHost:reactHost];\n\n// Legacy bridge\n[ReactNativeNavigation bootstrapWithBridge:bridge];\n\n// Register native screens\n[ReactNativeNavigation registerExternalComponent:@\"NativeScreen\"\n                                        callback:^(NSDictionary *props, RCTBridge *bridge) {\n    return [[MyNativeVC alloc] init];\n}];\n```\n\n### Autolink Script (`npx rnn-link`)\n\nThe `autolink/postlink/postLinkIOS.js` script automates setup:\n\n| Linker | What it does |\n|--------|--------------|\n| `AppDelegateLinker` | Changes AppDelegate to extend `RNNAppDelegate`, imports ReactNativeNavigation, removes RCTRootView setup |\n| `PodfileLinker` | Adds required pods configuration |\n| `PlistLinker` | Updates Info.plist if needed |\n\n**AppDelegateLinker transformations:**\n- Swift: `class AppDelegate: RCTAppDelegate` → `class AppDelegate: RNNAppDelegate`\n- Obj-C header: `@interface AppDelegate : RCTAppDelegate` → `@interface AppDelegate : RNNAppDelegate`\n- Imports `<ReactNativeNavigation/ReactNativeNavigation.h>`\n- Removes manual RCTRootView/window setup (navigation manages the window)\n\n## Directory Structure\n\n```\nios/\n├── RNNBridgeModule.h/mm         # Bridge entry point (legacy architecture)\n├── RNNBridgeManager.h/mm        # Bridge initialization\n├── RNNCommandsHandler.h/mm      # Command dispatcher\n├── RNNEventEmitter.h/mm         # Event emission to JS\n├── RNNLayoutManager.h/mm        # View controller tracking\n├── RNNLayoutNode.h/mm           # Layout tree parsing\n├── RNNNavigationOptions.h/mm    # Options model\n├── RNNComponentViewController.h/mm  # React component screen\n├── RNNStackController.h/mm      # Stack navigation\n├── RNNBottomTabsController.h/mm # Tab navigation\n├── RNNSideMenuViewController.h/mm   # Side menu\n├── RNNTopTabsViewController.h/mm    # Top tabs\n├── RNNSplitViewController.h/mm  # Split view (iPad)\n├── RNNModalManager.h/mm         # Modal presentation\n├── RNNOverlayManager.h/mm       # Overlay management\n├── TurboModules/                # New architecture entry points\n│   ├── RNNTurboModule.h/mm      # TurboModule spec implementation\n│   ├── RNNTurboManager.h/mm     # Manager for host, window, external components\n│   ├── RNNTurboCommandsHandler.h/mm  # TurboModule command routing\n│   └── RNNTurboEventEmitter.h/mm     # Event emission for new arch\n├── Utils/                       # Utility classes\n├── RNNSideMenu/                 # MMDrawerController integration\n└── ReactNativeNavigation.xcodeproj/\n```\n\n## Bridge Architecture\n\nThe library supports both the legacy bridge and new TurboModule architecture:\n- **Legacy (Bridge)**: `RNNBridgeModule` receives commands via `RCT_EXPORT_METHOD`\n- **New Architecture**: `RNNTurboModule` (in `TurboModules/`) receives commands directly\n\nBoth entry points delegate to `RNNCommandsHandler` for command execution.\n\n```\n┌────────────────────────────────────────────────────────────┐\n│                 JavaScript (TurboModule)                   │\n└─────────────────────────┬──────────────────────────────────┘\n                          │\n┌─────────────────────────▼──────────────────────────────────┐\n│  RNNBridgeModule (bridge) / RNNTurboModule (new arch)      │\n│  - setRoot, push, pop, showModal, dismissModal, etc.       │\n└─────────────────────────┬──────────────────────────────────┘\n                          │\n┌─────────────────────────▼──────────────────────────────────┐\n│  RNNCommandsHandler                                         │\n│  - Validates commands, manages layout lifecycle            │\n│  - Coordinates with managers                               │\n└──────┬──────────────┬──────────────┬──────────────┬────────┘\n       │              │              │              │\n┌──────▼─────┐ ┌──────▼─────┐ ┌──────▼─────┐ ┌─────▼──────┐\n│RNNLayout   │ │RNNModal    │ │RNNOverlay  │ │RNNViewController│\n│Manager     │ │Manager     │ │Manager     │ │Factory     │\n└────────────┘ └────────────┘ └────────────┘ └────────────┘\n```\n\n## View Controller Hierarchy\n\nAll navigation view controllers conform to `RNNLayoutProtocol`:\n\n```\nUIViewController\n├── RNNComponentViewController    # React component screen\n├── RNNExternalViewController     # Native screen wrapper\n└── RNNSplashScreenViewController # Launch screen\n\nUINavigationController\n└── RNNStackController           # Stack navigation\n\nUITabBarController\n└── RNNBottomTabsController      # Bottom tabs\n\nUIViewController (custom)\n├── RNNTopTabsViewController     # Horizontal top tabs\n└── RNNSideMenuChildViewController  # Drawer child\n\nMMDrawerController\n└── RNNSideMenuViewController    # Side menu/drawer\n\nUISplitViewController\n└── RNNSplitViewController       # Master-detail (iPad)\n```\n\n## Core Classes\n\n### RNNBridgeModule\nEntry point for JavaScript commands (legacy architecture). Exports methods via `RCT_EXPORT_METHOD`:\n\n```objc\nRCT_EXPORT_METHOD(setRoot:(NSString*)commandId layout:(NSDictionary*)layout\n                  resolver:(RCTPromiseResolveBlock)resolve\n                  rejecter:(RCTPromiseRejectBlock)reject);\n```\n\n`RNNBridgeModule` returns the main queue as its `methodQueue`; `RNNTurboModule` uses `RCTExecuteOnMainQueue` for each command to ensure UI operations run on the main thread.\n\n### RNNBridgeManager\nInitializes bridge infrastructure:\n- Creates RNNLayoutManager, RNNModalManager, RNNOverlayManager\n- Creates RNNViewControllerFactory, RNNCommandsHandler\n- Provides extra modules to React bridge\n- Handles JavaScript reload events\n\n### RNNCommandsHandler\nCentral command dispatcher implementing all navigation operations:\n- `setRoot:` - Replace root view controller\n- `push:componentId:layout:` - Push to stack\n- `pop:componentId:` - Pop from stack\n- `showModal:` - Present modal\n- `dismissModal:` - Dismiss modal\n- `showOverlay:` - Show overlay window\n- `dismissOverlay:` - Hide overlay\n\n### RNNLayoutManager\nTracks active view controllers:\n- `addPendingViewController:` - Register during creation\n- `removePendingViewController:` - Cleanup after presentation\n- `findComponentForId:` - Lookup by componentId\n\n### RNNLayoutNode\nParses JSON layout from JavaScript:\n- Determines type via predicates: `isComponent`, `isStack`, `isTabs`, etc.\n- Holds `type`, `nodeId`, `data` (options), `children`\n\n### RNNViewControllerFactory\nCreates view controllers from RNNLayoutNode:\n- `createStack:` → RNNStackController\n- `createBottomTabs:` → RNNBottomTabsController\n- `createComponent:` → RNNComponentViewController\n- `createSideMenu:` → RNNSideMenuViewController\n\n## RNNLayoutProtocol\n\nProtocol all navigation controllers implement:\n\n```objc\n@protocol RNNLayoutProtocol\n- (instancetype)initWithLayoutInfo:(RNNLayoutInfo*)layoutInfo\n                           creator:(id<RNNComponentViewCreator>)creator\n                           options:(RNNNavigationOptions*)options\n                    defaultOptions:(RNNNavigationOptions*)defaultOptions\n                         presenter:(RNNBasePresenter*)presenter\n                      eventEmitter:(RNNEventEmitter*)eventEmitter\n              childViewControllers:(NSArray*)childViewControllers;\n\n- (void)render;\n- (UIViewController*)getCurrentChild;\n- (void)mergeOptions:(RNNNavigationOptions*)options;\n- (RNNNavigationOptions*)resolveOptions;\n- (void)setDefaultOptions:(RNNNavigationOptions*)defaultOptions;\n- (void)onChildWillAppear;\n- (void)readyForPresentation;\n- (CGFloat)getTopBarHeight;\n- (CGFloat)getBottomTabsHeight;\n@end\n```\n\nAdditional methods provided via `UIViewController+LayoutProtocol` category:\n- `destroy`, `topMostViewController`, `stack`\n- `componentWillAppear`, `componentDidAppear`, `componentDidDisappear`\n- `screenPopped`, `prepareForTransition`\n- `resolveOptionsWithDefault`, `mergeChildOptions:child:`\n\n## Presenter Pattern\n\nEach view controller type has a corresponding presenter that applies options:\n\n| Controller | Presenter |\n|------------|-----------|\n| RNNComponentViewController | RNNComponentPresenter |\n| RNNStackController | RNNStackPresenter + TopBarPresenter |\n| RNNBottomTabsController | RNNBottomTabsPresenter + BottomTabPresenter |\n| RNNSideMenuViewController | RNNSideMenuPresenter |\n| RNNSplitViewController | RNNSplitViewControllerPresenter |\n\n### RNNBasePresenter\nBase class with lifecycle methods:\n- `applyOptionsOnInit:` - Initial setup\n- `applyOptions:` - Apply current options\n- `mergeOptions:resolvedOptions:` - Runtime updates\n- `componentWillAppear`, `componentDidAppear`, `componentDidDisappear`\n\n## React View Integration\n\n### RNNReactView\nWraps RCTRootView (legacy) or RCTSurfaceHostingView (new architecture):\n- Implements `RNNComponentProtocol`\n- Manages `componentId`, `componentType`, `moduleName`\n- Lifecycle: `componentWillAppear`, `componentDidAppear`, `componentDidDisappear`\n\n### RNNReactRootViewCreator\nCreates RNNReactView instances:\n- Supports component types: Component, TopBarTitle, TopBarButton, TopBarBackground\n- Handles size flexibility for flexible layouts\n\n### RNNReactComponentRegistry\nCaches created React component instances:\n- `createComponentIfNotExists:parentComponentId:componentType:reactViewReadyBlock:`\n- `removeComponent:`, `clearComponentsForParentId:`\n\n## Options System\n\n### RNNNavigationOptions\nMaster options object containing all configuration:\n\n```objc\n@interface RNNNavigationOptions : RNNOptions\n@property RNNTopBarOptions* topBar;\n@property RNNBottomTabsOptions* bottomTabs;\n@property RNNBottomTabOptions* bottomTab;\n@property RNNTopTabsOptions* topTabs;\n@property RNNSideMenuOptions* sideMenu;\n@property RNNOverlayOptions* overlay;\n@property RNNAnimationsOptions* animations;\n@property RNNStatusBarOptions* statusBar;\n@property RNNLayoutOptions* layout;\n@property RNNModalOptions* modal;\n@property RNNPreviewOptions* preview;\n@property RNNSplitViewOptions* splitView;\n@end\n```\n\n### Options Resolution\nOptions merge in hierarchy:\n1. Component's own options\n2. Parent controller options (loop through chain)\n3. Default options (from `setDefaultOptions`)\n\n## Event Emission\n\n### RNNEventEmitter\nSends events to JavaScript via RCTEventEmitter:\n\n| Event | Method |\n|-------|--------|\n| Component lifecycle | `sendComponentWillAppear:`, `sendComponentDidAppear:`, `sendComponentDidDisappear:` |\n| Button press | `sendOnNavigationButtonPressed:buttonId:` |\n| Command completion | `sendOnNavigationCommandCompletion:commandId:` |\n| Tab events | `sendBottomTabSelected:unselected:`, `sendBottomTabLongPressed:`, `sendBottomTabPressed:` |\n| Modal events | `sendModalsDismissedEvent:numberOfModalsDismissed:`, `sendModalAttemptedToDismissEvent:` |\n| Screen events | `sendScreenPoppedEvent:` |\n| Search | `sendOnSearchBarUpdated:text:isFocused:`, `sendOnSearchBarCancelPressed:` |\n| Preview | `sendOnPreviewCompleted:previewComponentId:` |\n\n### RNNBridgeEventEmitter\nConcrete implementation that sends `onAppLaunched` on initialization.\n\n## Modal & Overlay Management\n\n### RNNModalManager\n- Tracks presented modals array\n- Supports custom transition animations via ScreenAnimationController\n- Handles presentationController delegate for adaptive presentation\n\n### RNNOverlayManager\n- Manages UIWindow instances for overlays\n- Each overlay gets its own RNNOverlayWindow\n- Maintains previous window reference for restoration\n- Controls window level and accessibility\n\n## Animation System\n\n### ScreenAnimationController\nImplements `UIViewControllerAnimatedTransitioning`:\n- Custom push/pop/modal transitions\n- Content transitions (RNNEnterExitAnimation)\n- Element transitions (ElementTransitionOptions)\n- Shared element transitions (SharedElementTransitionOptions)\n\n### Element Animators\n- `ElementAnimator` - Individual element animations\n- `SharedElementAnimator` - Cross-screen shared elements\n- Transition types: Alpha, Scale, Translation, Frame, Bounds, Color, CornerRadius\n\n### RNNSetRootAnimator\nAnimates window root replacement using CABasicAnimation.\n\n## Navigation Types\n\n### Stack Navigation (RNNStackController)\n- Subclass of UINavigationController\n- Push/pop with custom animations\n- Back button customization\n- Uses StackControllerDelegate for bar delegate handling\n\n```objc\n// Extension methods\n@interface UINavigationController (RNNCommands)\n- (void)push:(UIViewController*)vc onTop:(UIViewController*)onTopVC\n     animated:(BOOL)animated completion:(void(^)(void))completion rejection:(RCTPromiseRejectBlock)rejection;\n- (void)popAnimated:(BOOL)animated completion:(void(^)(NSString*))completion rejection:(RCTPromiseRejectBlock)rejection;\n@end\n```\n\n### Bottom Tabs (RNNBottomTabsController)\n- Subclass of UITabBarController\n- Tab attachment modes: Together, OnSwitchToTab, AfterInitialTab\n- Long-press gesture support\n- Badge and dot indicator support\n\n### Side Menu (RNNSideMenuViewController)\n- Uses MMDrawerController (third-party)\n- Center, left, right child containers\n- Configurable open modes and widths\n\n### Top Tabs (RNNTopTabsViewController)\n- Custom horizontal tab implementation\n- Not based on UITabBarController\n- Manual content switching\n\n### Split View (RNNSplitViewController)\n- UISplitViewController subclass\n- Master-detail for iPad\n\n## External Components\n\n### RNNExternalComponentStore\nRegistry for native (non-React) view controllers.\n\n### RNNExternalViewController\nWraps native UIViewController for integration:\n\n```objc\n[ReactNativeNavigation registerExternalComponent:@\"NativeScreen\"\n                                       callback:^(NSDictionary *props, RCTBridge *bridge) {\n    return [[MyNativeViewController alloc] init];\n}];\n```\n\n## Key Files Reference\n\n| File | Purpose |\n|------|---------|\n| `RNNBridgeModule.h/mm` | Bridge entry point (legacy) |\n| `TurboModules/RNNTurboModule.mm` | TurboModule entry point (new arch) |\n| `TurboModules/RNNTurboCommandsHandler.mm` | TurboModule command routing |\n| `RNNCommandsHandler.h/mm` | Command execution |\n| `RNNLayoutManager.h/mm` | Controller tracking |\n| `RNNViewControllerFactory.h/mm` | Controller creation |\n| `RNNComponentViewController.h/mm` | React screen |\n| `RNNStackController.h/mm` | Stack navigation |\n| `RNNBottomTabsController.h/mm` | Tab navigation |\n| `RNNNavigationOptions.h/mm` | Options model |\n| `RNNBasePresenter.h/mm` | Presenter base |\n| `TopBarPresenter.h/mm` | Top bar styling |\n| `RNNReactView.h/mm` | React view wrapper |\n| `ScreenAnimationController.h/mm` | Custom transitions |\n","src/ARCHITECTURE.md":"# JavaScript/TypeScript Architecture\n\nThe JavaScript layer provides the public API and orchestrates communication between React components and native navigation implementations.\n\n## Entry Point\n\n`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.\n\n## Module Structure\n\n```\nsrc/\n├── index.ts                 # Main entry point, exports Navigation singleton\n├── Navigation.ts            # NavigationRoot - core orchestrator\n├── NavigationDelegate.ts    # Public API facade\n├── adapters/                # Native bridge layer\n├── commands/                # Command processing\n├── components/              # React component management\n├── events/                  # Event system\n├── interfaces/              # TypeScript type definitions\n├── linking/                 # Deep-linking framework (URL → command)\n└── processors/              # Extensibility hooks\n```\n\n## Core Classes\n\n### NavigationDelegate (Public API)\n**File**: `NavigationDelegate.ts`\n\nFacade providing the public `Navigation` API. All methods proxy to `NavigationRoot`.\n\n```typescript\n// Usage\nimport { Navigation } from 'react-native-navigation';\nNavigation.setRoot({ root: { stack: { children: [...] } } });\n```\n\n### NavigationRoot (Core Orchestrator)\n**File**: `Navigation.ts`\n\nCoordinates all subsystems. Constructed with dependencies:\n- `NativeCommandsSender` - sends commands to native\n- `NativeEventsReceiver` - receives events from native\n- `AppRegistryService` - manages React Native component registry\n\nInitializes and coordinates:\n- `Store` - component instance & props storage\n- `ComponentRegistry` - component registration\n- `LayoutTreeParser` - converts layouts to internal nodes\n- `LayoutTreeCrawler` - processes layout trees\n- `Commands` - command execution\n- `EventsRegistry` - event subscriptions\n- `OptionsProcessor` - option processing\n- `LayoutProcessor` - layout transformations\n\n## Adapters Layer\n\nBridge between JavaScript and native/React Native APIs.\n\n| Adapter | Purpose |\n|---------|---------|\n| `NativeCommandsSender` | Wraps TurboModule for command dispatch |\n| `NativeEventsReceiver` | Wraps NativeEventEmitter for events |\n| `NativeRNNTurboModule` | TurboModule spec interface |\n| `NativeRNNTurboEventEmitter` | TurboModule event emitter spec |\n| `UniqueIdProvider` | Generates unique component/command IDs |\n| `ColorService` | Converts colors to native format |\n| `AssetResolver` | Resolves require() image assets (class: AssetService) |\n| `AppRegistryService` | Registers components with React Native |\n| `Constants` | Platform dimension constants |\n| `TouchablePreview` | 3D Touch / Haptic preview handling |\n\n## Commands Layer\n\n### Commands Class\n**File**: `commands/Commands.ts`\n\nCentral command dispatcher. Each navigation command:\n1. Validates input\n2. Processes layout through pipeline\n3. Sends to native via adapter\n4. Returns promise with result\n\n### Processing Pipeline\n\nThe pipeline executes in this exact order:\n\n```\nInput Layout (from API)\n       ↓\n1. OptionsCrawler.crawl()         # Extract static options from component classes\n       ↓\n2. LayoutProcessor.process()      # Apply registered layout processors\n       ↓\n3. LayoutTreeParser.parse()       # Convert to internal LayoutNode tree\n       ↓\n4. LayoutTreeCrawler.crawl()      # Process options, save props to Store\n       ↓\n5. OptionsProcessor (during crawl) # Resolve colors, assets, custom processors\n       ↓\n6. NativeCommandsSender           # Send to native module\n```\n\n### LayoutNode (Internal Tree)\n```typescript\ninterface LayoutNode {\n  id: string;           // Unique identifier\n  type: LayoutType;     // Component|Stack|BottomTabs|etc\n  data: {\n    name?: string;      // Component name\n    options?: any;      // Processed options\n    passProps?: any;    // Component props (cleared before native)\n  };\n  children: LayoutNode[];\n}\n```\n\n### LayoutType Enum\n```typescript\nenum LayoutType {\n  Component = 'Component',\n  Stack = 'Stack',\n  BottomTabs = 'BottomTabs',\n  SideMenuRoot = 'SideMenuRoot',\n  SideMenuCenter = 'SideMenuCenter',\n  SideMenuLeft = 'SideMenuLeft',\n  SideMenuRight = 'SideMenuRight',\n  TopTabs = 'TopTabs',\n  ExternalComponent = 'ExternalComponent',\n  SplitView = 'SplitView',\n}\n```\n\n## Components Layer\n\n### ComponentRegistry\n**File**: `components/ComponentRegistry.ts`\n\nManages React component registration and wrapping.\n\n```typescript\nNavigation.registerComponent('ScreenName', () => MyComponent);\n```\n\n### ComponentWrapper\n**File**: `components/ComponentWrapper.tsx`\n\nHigher-order component that:\n- Wraps original component with lifecycle management\n- Stores instance in `Store` for event dispatch\n- Injects `componentId` and `componentName` props\n\n### Store\n**File**: `components/Store.ts`\n\nCentralized storage for:\n- `componentsByName` - registered component providers\n- `componentsInstancesById` - mounted component instances\n- `propsById` - static props by component ID\n- `pendingPropsById` - props awaiting component mount\n- `wrappedComponents` - cached wrapped components\n- `lazyRegistratorFn` - function for lazy component registration\n\n## Events Layer\n\n### EventsRegistry\n**File**: `events/EventsRegistry.ts`\n\nPublic API for event subscriptions:\n\n```typescript\nNavigation.events().registerComponentDidAppearListener(({ componentId }) => {});\nNavigation.events().registerCommandCompletedListener(({ commandId }) => {});\n```\n\n### ComponentEventsObserver\n**File**: `events/ComponentEventsObserver.ts`\n\nDispatches events to component instance methods:\n- `componentWillAppear()`\n- `componentDidAppear()`\n- `componentDidDisappear()`\n- `navigationButtonPressed()`\n- `screenPopped()`\n\n### CommandsObserver\n**File**: `events/CommandsObserver.ts`\n\nNotifies listeners of command lifecycle (start, complete).\n\n## Events (Native → JS)\n\n| Event | Description |\n|-------|-------------|\n| `RNN.AppLaunched` | App initialization complete |\n| `RNN.ComponentWillAppear` | Component about to appear |\n| `RNN.ComponentDidAppear` | Component now visible |\n| `RNN.ComponentDidDisappear` | Component hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tapped |\n| `RNN.BottomTabPressed` | Tab pressed (even if selected) |\n| `RNN.BottomTabSelected` | Tab selection changed |\n| `RNN.BottomTabLongPressed` | Tab long-pressed |\n| `RNN.ModalDismissed` | Modal was dismissed |\n| `RNN.ModalAttemptedToDismiss` | Swipe-to-dismiss attempted |\n| `RNN.ScreenPopped` | Screen removed from stack |\n| `RNN.SearchBarUpdated` | Search text changed |\n| `RNN.SearchBarCancelPressed` | Search cancelled |\n| `RNN.PreviewCompleted` | 3D Touch preview completed |\n| `RNN.CommandCompleted` | Navigation command finished |\n\n## Linking Layer\n\nImplements URL-to-screen routing on top of the standard command pipeline. The whole feature is JS-only; it consumes URLs from RN's `Linking` module and dispatches `showModal` (or a user-supplied command) when a match is found.\n\n**Public surface** (proxied through `NavigationDelegate`):\n- `Navigation.setLinking(config)` — configure prefixes, screen map, and customization hooks\n- `Navigation.handleDeepLink(url)` — manually feed a URL (push notifications, branch.io, App Clips)\n- `Navigation.setLinkingReady(ready)` — user-controlled gate for deferred deep links\n\n**Internal modules** (`src/linking/`):\n\n| File | Purpose |\n|------|---------|\n| `LinkingHandler.ts` | Orchestrator. Subscribes to `Linking.url`/`getInitialURL`, drives the queue, dispatches matches. Instantiated by `NavigationRoot`. |\n| `URLParser.ts` | Strips prefix (longest match), removes fragment, decodes path segments + query params. |\n| `RouteMatcher.ts` | Compiles `ScreensConfig` into a `RouteNode` tree; matches paths to screen chains with parameter extraction. |\n| `DeferredLinkQueue.ts` | FIFO queue. Holds URLs until both gates open (root-ready + user-ready). |\n| `ModalLayoutBuilder.ts` | Default presentation: wraps the matched chain in a `stack`, merges params into `passProps`, filters React-reserved keys (`ref`, `key`). |\n| `types.ts` | Public types: `LinkingConfig`, `RouteMatch`, `ScreensConfig`, etc. (re-exported via `src/index.ts`). |\n\n**Readiness gates** — a URL is dispatched only when both are true:\n1. **Root-ready** (automatic): the first `Navigation.setRoot()` has resolved. `NavigationRoot.setRoot` calls `linkingHandler.setRootReady()` after the promise resolves.\n2. **User-ready** (optional): `config.isReady()` returns `true`, or `setLinkingReady(true)` was called.\n\n**Resolution priority** when a match is found:\n1. `config.onLink(match)` — full escape hatch, RNN does nothing else\n2. `config.getModal(match)` — custom modal layout\n3. Default `ModalLayoutBuilder` output\n\n## Processors Layer\n\n### OptionProcessorsStore\n**File**: `processors/OptionProcessorsStore.ts`\n\nRegisters custom option processors:\n\n```typescript\nNavigation.addOptionProcessor('topBar.title.text', (value, commandName) => {\n  return value.toUpperCase(); // Transform all titles\n});\n```\n\n### LayoutProcessorsStore\n**File**: `processors/LayoutProcessorsStore.ts`\n\nRegisters layout transformers:\n\n```typescript\nNavigation.addLayoutProcessor((layout, commandName) => {\n  // Add default options to all components\n  return layout;\n});\n```\n\n## Interfaces\n\n### Layout Types\n**File**: `interfaces/Layout.ts`\n\n```typescript\ninterface LayoutRoot {\n  root: Layout;\n  modals?: any[];\n  overlays?: any[];\n}\n\ntype Layout = {\n  component?: LayoutComponent;\n  stack?: LayoutStack;\n  bottomTabs?: LayoutBottomTabs;\n  sideMenu?: LayoutSideMenu;\n  splitView?: LayoutSplitView;\n  topTabs?: LayoutTopTabs;\n  externalComponent?: ExternalComponent;\n}\n```\n\n### Options Interface\n**File**: `interfaces/Options.ts` (comprehensive)\n\nContains all configuration options for:\n- Status bar, navigation bars\n- Top bar (buttons, title, search)\n- Bottom tabs\n- Side menus\n- Modals, overlays\n- Animations\n- Layout parameters\n\n### NavigationComponent\n**File**: `interfaces/NavigationComponent.ts`\n\nBase class for navigation-aware components:\n\n```typescript\nclass MyScreen extends NavigationComponent<Props> {\n  static options: Options = { ... };\n\n  componentDidAppear(event) { }\n  navigationButtonPressed(event) { }\n}\n```\n\n## Dependencies\n\n**Production**:\n- `lodash` - utility functions\n- `hoist-non-react-statics` - HOC support\n- `react-lifecycles-compat` - lifecycle polyfill\n- `tslib` - TypeScript helpers\n\n**Peer**:\n- `react`, `react-native` (required)\n- `remx` (optional state management)\n\n## Build Output\n\nUses `react-native-builder-bob`:\n- **Source**: `src/`\n- **Output**: `lib/`\n- **Targets**: ESM modules + TypeScript declarations\n","android/ARCHITECTURE.md":"# Android Native Architecture\n\nThe Android implementation provides native navigation using Views and ViewGroups (not Fragments), coordinated through a TurboModule that receives commands from JavaScript.\n\n## App Integration\n\n### NavigationApplication\n**File**: `NavigationApplication.java`\n\nAbstract Application class that user's MainApplication must extend:\n\n```kotlin\n// MainApplication.kt - User extends NavigationApplication\nclass MainApplication : NavigationApplication() {\n    override val reactNativeHost: ReactNativeHost\n        get() = NavigationReactNativeHost(this) // Must use NavigationReactNativeHost\n}\n```\n\n**What NavigationApplication does:**\n- Initializes SoLoader\n- Provides `ReactGateway` singleton for React lifecycle\n- Offers `registerExternalComponent()` for native screens\n\n### NavigationActivity\n**File**: `NavigationActivity.java`\n\nBase Activity that user's MainActivity must extend:\n\n```kotlin\n// MainActivity.kt - User extends NavigationActivity\nclass MainActivity : NavigationActivity() {\n    // No getMainComponentName() needed - navigation handles root\n}\n```\n\n**What NavigationActivity does:**\n- Creates `Navigator` with root, modal, and overlay layouts\n- Manages back press via `OnBackPressedCallback`\n- Coordinates React lifecycle with activity lifecycle\n\n### NavigationReactNativeHost\n**File**: `react/NavigationReactNativeHost.kt`\n\nCustom ReactNativeHost that integrates with navigation:\n- Used instead of `DefaultReactNativeHost`\n- Provides proper module registration for navigation\n\n### Autolink Script (`npx rnn-link`)\n\nThe `autolink/postlink/postLinkAndroid.js` script automates setup:\n\n| Linker | What it does |\n|--------|--------------|\n| `ApplicationLinker` | Changes MainApplication to extend `NavigationApplication`, uses `NavigationReactNativeHost`, removes SoLoader.init() |\n| `ActivityLinker` | Changes MainActivity to extend `NavigationActivity`, removes `getMainComponentName()` |\n| `GradleLinker` | Updates build.gradle if needed |\n\n**ApplicationLinker transformations:**\n- `class MainApplication : Application(), ReactApplication` → `class MainApplication : NavigationApplication()`\n- `DefaultReactNativeHost(this)` → `NavigationReactNativeHost(this)`\n- Removes `SoLoader.init()` (NavigationApplication handles it)\n- Removes new architecture entry point load block\n\n**ActivityLinker transformations:**\n- `class MainActivity : ReactActivity()` → `class MainActivity : NavigationActivity()`\n- Removes `getMainComponentName()` override\n- Removes `createReactActivityDelegate()` override\n\n## Directory Structure\n\n```\nandroid/src/main/java/com/reactnativenavigation/\n├── NavigationActivity.java       # Main Activity entry point\n├── NavigationApplication.java    # Application class\n├── NavigationPackage.kt          # React package registration\n├── react/                        # React bridge layer\n│   ├── NavigationTurboModule.kt  # TurboModule implementation\n│   ├── ReactGateway.java         # React lifecycle management\n│   └── events/\n│       └── EventEmitter.java     # Event emission to JS\n├── options/                      # Options parsing and factories\n│   ├── LayoutFactory.java        # Creates ViewControllers from layout nodes\n│   └── Options.java              # Options model\n├── viewcontrollers/              # ViewController hierarchy\n│   ├── ViewController.java       # Base class\n│   ├── ChildController.java      # With presenter support\n│   ├── ParentController.java     # Container controllers\n│   ├── stack/                    # Stack navigation\n│   ├── bottomtabs/               # Bottom tabs\n│   ├── toptabs/                  # Top tabs (lowercase)\n│   ├── sidemenu/                 # Side menu/drawer\n│   ├── modal/                    # Modal management\n│   └── externalcomponent/        # Native component support\n├── views/                        # UI View implementations\n├── utils/                        # Utilities\n└── hierarchy/                    # Root layout management\n```\n\n## Bridge Architecture\n\n```\n┌────────────────────────────────────────────────────────────┐\n│                 JavaScript (TurboModule)                   │\n└─────────────────────────┬──────────────────────────────────┘\n                          │\n┌─────────────────────────▼──────────────────────────────────┐\n│  NavigationTurboModule.kt                                   │\n│  - setRoot, push, pop, showModal, dismissModal, etc.       │\n└─────────────────────────┬──────────────────────────────────┘\n                          │\n┌─────────────────────────▼──────────────────────────────────┐\n│  Navigator (Root ViewController)                           │\n│  - Manages root, modals, overlays                          │\n│  - Coordinates LayoutFactory                               │\n└──────┬──────────────┬──────────────┬──────────────┬────────┘\n       │              │              │              │\n┌──────▼─────┐ ┌──────▼─────┐ ┌──────▼─────┐ ┌─────▼──────┐\n│ModalStack  │ │OverlayMgr  │ │LayoutFactory│ │EventEmitter│\n└────────────┘ └────────────┘ └────────────┘ └────────────┘\n```\n\n## Entry Points\n\n### NavigationApplication\nAbstract Application class that apps extend:\n- Manages `ReactGateway` singleton\n- Initializes SoLoader\n- Provides `registerExternalComponent()` for native screens\n\n### NavigationActivity\nMain Activity containing all navigation:\n- Creates `Navigator` with three CoordinatorLayouts:\n  - `rootLayout` - Main navigation content\n  - `modalsLayout` - Modal stack\n  - `overlaysLayout` - Overlays (highest z-order)\n- Handles back press via `OnBackPressedCallback`\n- Coordinates activity lifecycle with React\n\n### NavigationTurboModule\nTurboModule implementation (Kotlin, ~300 lines):\n\n```kotlin\n@ReactMethod\nfun setRoot(commandId: String, layout: ReadableMap, promise: Promise)\n\n@ReactMethod\nfun push(commandId: String, componentId: String, layout: ReadableMap, promise: Promise)\n\n@ReactMethod\nfun showModal(commandId: String, layout: ReadableMap, promise: Promise)\n```\n\nAll commands execute on UI thread via `UiThread.post()`.\n\n## ViewController Hierarchy\n\n**Note**: Android implementation does NOT use Fragments - it's purely View-based.\n\n```\nViewController (abstract)\n│   - Base for all navigation controllers\n│   - Manages view creation and lifecycle\n│   - Handles options and back press\n│\n├── ChildController\n│   │   - Adds Presenter support\n│   │\n│   ├── ComponentViewController\n│   │       - Renders React components via ReactView\n│   │\n│   └── ExternalComponentViewController\n│           - Wraps native Android views\n│\n└── ParentController (extends ChildController)\n        - Container for child controllers\n        │\n        ├── StackController\n        │       - Push/pop navigation\n        │       - Uses IdStack<ViewController>\n        │\n        ├── BottomTabsController\n        │       - UITabBarController equivalent\n        │       - Uses AHBottomNavigation\n        │\n        ├── TopTabsController\n        │       - Horizontal ViewPager tabs\n        │\n        ├── SideMenuController\n        │       - DrawerLayout-based drawer\n        │\n        └── Navigator\n                - Root controller\n                - Manages modals and overlays\n```\n\n## Core Classes\n\n### ViewController (Base)\n**File**: `viewcontrollers/viewcontroller/ViewController.java` (~500 lines)\n\nAbstract base for all navigation controllers:\n\n```java\npublic abstract class ViewController<T extends ViewGroup> {\n    protected abstract T createView();  // Subclasses create views\n\n    public void onViewWillAppear() { }\n    public void onViewDidAppear() { }\n    public void onViewDisappear() { }\n\n    public void mergeOptions(Options options) { }\n    public void applyOptions(Options options) { }\n    public boolean handleBack(CommandListener listener) { }\n    public void destroy() { }\n}\n```\n\n### Navigator (Root)\n**File**: `viewcontrollers/navigator/Navigator.java`\n\nRoot ViewController managing:\n- Root content hierarchy\n- Modal stack (`ModalStack`)\n- Overlay manager (`OverlayManager`)\n- Component lookup by ID\n\n### LayoutFactory\n**File**: `options/LayoutFactory.java`\n\nFactory creating ViewControllers from LayoutNode. Owned by `NavigationTurboModule` and used to build the view controller hierarchy when commands are received from JavaScript.\n\n```java\npublic ViewController create(LayoutNode node) {\n    switch (node.type) {\n        case Component: return createComponent(node);\n        case Stack: return createStack(node);\n        case BottomTabs: return createBottomTabs(node);\n        case SideMenuRoot: return createSideMenuRoot(node);\n        case SideMenuCenter: return createSideMenuContent(node);\n        case SideMenuLeft: return createSideMenuLeft(node);\n        case SideMenuRight: return createSideMenuRight(node);\n        case TopTabs: return createTopTabs(node);\n        // Note: SplitView is iOS-only, not implemented on Android\n    }\n}\n```\n\n## Navigation Types\n\n### Stack Navigation (StackController)\n**Files**: `viewcontrollers/stack/`\n\n- View: `StackLayout` (CoordinatorLayout with TopBar)\n- Internal stack: `IdStack<ViewController<?>>`\n- Components: `TopBarController`, `StackAnimator`, `StackPresenter`, `FabPresenter`\n\nOperations:\n- `push(viewController, listener)`\n- `pop(options, listener)`\n- `popTo(target, options, listener)`\n- `popToRoot(options, listener)`\n- `setRoot(children, listener)`\n\n### Bottom Tabs (BottomTabsController)\n**Files**: `viewcontrollers/bottomtabs/`\n\n- View: `BottomTabsLayout` (CoordinatorLayout with BottomTabs)\n- Uses `AHBottomNavigation` library\n- Components: `BottomTabsPresenter`, `BottomTabPresenter`, `BottomTabsAnimator`\n\nAttachment Modes:\n- `TogetherAttacher` - Load all tabs immediately\n- `OnSwitchToTabAttacher` - Lazy load on selection\n- `AfterInitialTabAttacher` - Load initial + others in background\n\n### Side Menu (SideMenuController)\n**Files**: `viewcontrollers/sidemenu/`\n\n- View: `SideMenuRoot` (DrawerLayout-based)\n- Children: Center, Left, Right controllers\n- `SideMenuPresenter` for styling\n\n### Top Tabs (TopTabsController)\n**Files**: `viewcontrollers/toptabs/`\n\n- View: `TopTabsViewPager` (ViewPager-based)\n- `TopTabsLayoutCreator` for view creation\n\n### Modals (ModalStack)\n**Files**: `viewcontrollers/modal/`\n\nNot a ViewController - manages modal presentation:\n- `ModalPresenter` - Show/dismiss with animations\n- `ModalAnimator` (Kotlin) - Animation handling\n- Stack of modals with lifecycle management\n\n### Overlays (OverlayManager)\n**File**: `viewcontrollers/overlay/OverlayManager.kt`\n\nRegistry of active overlays:\n- Show/dismiss by component ID\n- Configuration change handling\n- Host pause/resume lifecycle\n\n## React Component Rendering\n\n### ComponentViewController\nManages React component lifecycle:\n- Creates `ComponentLayout` view\n- Initializes `ReactView` with ReactSurface\n- Emits lifecycle events to JS\n- Handles scroll events and status bar\n\n### ReactView\n**File**: `react/ReactView.java`\n\nExtends FrameLayout, wraps `ReactSurface`:\n- `start()` - Attach surface to React instance\n- `destroy()` - Clean up React surface\n- `sendComponentWillStart()` - Emit event to JS\n- `isReady()` - Check surface attachment\n\n## Event Emission\n\n### EventEmitter\n**File**: `react/events/EventEmitter.java`\n\nEvents sent to JavaScript:\n\n| Event | Description |\n|-------|-------------|\n| `RNN.AppLaunched` | App initialization complete |\n| `RNN.ComponentDidAppear` | Component visible |\n| `RNN.ComponentWillAppear` | About to become visible |\n| `RNN.ComponentDidDisappear` | Component hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tapped |\n| `RNN.BottomTabSelected` | Tab selection changed |\n| `RNN.BottomTabPressed` | Tab pressed (even if selected) |\n| `RNN.ModalDismissed` | Modal was dismissed |\n| `RNN.ScreenPopped` | Screen removed from stack |\n| `RNN.CommandCompleted` | Navigation command finished |\n\n## Options System\n\n### Options Class\n**File**: `options/Options.java`\n\n```java\npublic class Options {\n    public TopBarOptions topBar;\n    public TopTabsOptions topTabs;\n    public BottomTabsOptions bottomTabsOptions;\n    public BottomTabOptions bottomTabOptions;\n    public OverlayOptions overlayOptions;\n    public FabOptions fabOptions;\n    public AnimationsOptions animations;\n    public SideMenuRootOptions sideMenuRootOptions;\n    public ModalOptions modal;\n    public StatusBarOptions statusBar;\n    public NavigationBarOptions navigationBar;\n    public LayoutOptions layout;\n    public HardwareBackButtonOptions hardwareBack;\n}\n```\n\n### Options Flow\n1. **Parse**: JSON from JS → Options object via JSONParser\n2. **Merge**: Default → Screen → Component options\n3. **Apply**: Presenter applies to views\n\n## Presenter Pattern\n\nEach ViewController has a Presenter:\n\n| ViewController | Presenter |\n|---------------|-----------|\n| StackController | StackPresenter |\n| BottomTabsController | BottomTabsPresenter + BottomTabPresenter |\n| ComponentViewController | ComponentPresenter |\n| SideMenuController | SideMenuPresenter |\n| Navigator | RootPresenter |\n\n### Presenter Base\n**File**: `viewcontrollers/viewcontroller/Presenter.java`\n\nHandles:\n- Orientation changes\n- Status bar styling\n- Navigation bar styling\n- Layout parameters\n\n## Animation System\n\n### Animators (Kotlin)\n- `StackAnimator.kt` - Push, pop, setRoot animations\n- `ModalAnimator.kt` - Modal show/dismiss\n- `BottomTabsAnimator.kt` - Tab transitions\n- `TopBarAppearanceAnimator.kt` - Top bar changes\n\n### Element Transitions\nVia `TransitionAnimatorCreator.kt`:\n- Position, scale, rotation animations\n- Color transitions\n- Corner radius animations\n- Shared element support\n\n## Activity Lifecycle\n\n```java\nonCreate()      // Create Navigator, initialize React\nonPostCreate()  // Set content layout\nonResume()      // React host resume, event emitter setup\nonPause()       // React host pause\nonDestroy()     // Clean up Navigator\nonConfigurationChanged()  // Handle orientation, locale\nonNewIntent()   // Process deep links\nonActivityResult()  // Handle permissions\n```\n\n## ViewController Lifecycle\n\n```\nView creation\n    ↓\nonViewWillAppear()   // Register with registry\n    ↓\nonViewDidAppear()    // Emit event to JS\n    ↓\n[visible]\n    ↓\nonViewWillDisappear()\n    ↓\nonViewDisappear()    // Unregister from registry\n    ↓\ndestroy()            // Complete cleanup\n```\n\n## Key Files Reference\n\nAll paths relative to `android/src/main/java/com/reactnativenavigation/`:\n\n| File | Path | Purpose |\n|------|------|---------|\n| NavigationActivity.java | `.` | Main Activity |\n| NavigationApplication.java | `.` | Application class |\n| NavigationTurboModule.kt | `react/` | JS bridge |\n| Navigator.java | `viewcontrollers/navigator/` | Root controller |\n| ViewController.java | `viewcontrollers/viewcontroller/` | Base class |\n| StackController.java | `viewcontrollers/stack/` | Stack navigation |\n| BottomTabsController.java | `viewcontrollers/bottomtabs/` | Tab navigation |\n| LayoutFactory.java | `options/` | Controller factory |\n| Options.java | `options/` | Options model |\n| Presenter.java | `viewcontrollers/viewcontroller/` | Base presenter |\n| EventEmitter.java | `react/events/` | JS events |\n| ReactView.java | `react/` | React component wrapper |\n| StackAnimator.kt | `viewcontrollers/stack/` | Stack animations |\n| ModalStack.java | `viewcontrollers/modal/` | Modal management |\n",".claude/skills/rn-version-upgrade.md":"# Skill: Add Support for a New React Native Version\n\nThis skill guides the process of adding support for a new React Native version to react-native-navigation (RNN). It covers CI setup, dependency analysis, native code fixes, playground validation, and the version-switch infrastructure.\n\n## Prerequisites\n\nBefore starting, gather:\n- The target RN version number (e.g., `0.84.0`)\n- The previous highest supported RN version (check `package.json` and `.buildkite/pipeline.sh`)\n\n## Phase 1: Research Breaking Changes\n\n**This phase is critical and prevents most downstream failures. Do it thoroughly before writing any code.**\n\n### 1a. Read the RN Release Blog & Changelog\n\nFetch the release blog post and changelog for the target version:\n- Blog: `https://reactnative.dev/blog` (search for the version)\n- Changelog: `https://github.com/facebook/react-native/blob/main/CHANGELOG.md`\n\nFocus on:\n- **Removed APIs/classes** (iOS and Android) -- these cause compile errors\n- **Changed method signatures** (Android) -- parameters becoming non-nullable, new required params, etc. (e.g., `ColorPropConverter.getColor()` changed in 0.80)\n- **Deprecated APIs now removed** -- check if RNN uses any deprecated APIs from prior versions\n- **Architecture changes** (e.g., New Architecture enforcement, legacy arch removal)\n- **Build system changes** -- Gradle version, Android SDK levels, Kotlin version, CocoaPods/podspec changes, Xcode requirements\n- **Header/import changes** -- headers moved, renamed, or removed from precompiled binaries\n- **CocoaPods / podspec changes** -- Check if RN changed how native modules declare dependencies (e.g., the shift to `install_modules_dependencies` in 0.80). Review `ReactNativeNavigation.podspec` for hardcoded dependency lists, header search paths, or compiler flags that may need updating.\n- **Kotlin version requirements** -- Newer RN versions may require newer Kotlin versions (e.g., RN 0.79+ requires Kotlin 2.x). Check if the version needs bumping.\n\n### 1b. Check RNN's Usage of Known Risk Areas\n\nSearch the RNN codebase for any classes/headers mentioned as removed or changed:\n\n```bash\n# Search iOS for legacy RCT headers (common removal targets)\ngrep -rn \"#import <React/RCT\" ios/ --include=\"*.h\" --include=\"*.mm\" --include=\"*.m\"\n\n# Search Android for deprecated classes\ngrep -rn \"CSSBackgroundDrawable\\|onCatalystInstanceDestroy\\|ReactInstanceManager\" android/ --include=\"*.java\" --include=\"*.kt\"\n\n# Check Android test infrastructure for classes extending RN framework classes\ngrep -rn \"extends.*React\\|: React\" android/ --include=\"*.java\" --include=\"*.kt\" | grep -i \"test\\|mock\\|simple\"\n```\n\n**If the new RN version strips legacy headers from the xcframework** (look for `RCT_REMOVE_LEGACY_ARCH` changes in the RN release), identify ALL iOS files importing legacy-only headers and plan to guard them in batch. Do NOT rely on iterative build failures to find them one by one. Cross-reference each `#import <React/RCT...>` against the headers actually available in the new RN version's xcframework.\n\n### 1c. Check Third-Party Dependency Compatibility\n\nFor each playground dependency that wraps native code, verify compatibility with the target RN version:\n\n1. **react-native-reanimated** -- Check https://docs.swmansion.com/react-native-reanimated/docs/guides/compatibility/ for the compatibility table. This is the most frequent source of build failures.\n2. **react-native-gesture-handler** -- Check release notes for RN version support.\n3. **react-native-fast-image** (or `@d11/react-native-fast-image`) -- Check for Fabric/new arch support.\n4. **react-native-worklets** -- Must be compatible with the reanimated version you chose.\n5. **Other native deps** -- Check each one's GitHub releases/issues for RN version support.\n\nAlso check the full peer dependency tree: `npm info react-native@<version> peerDependencies` for all peer deps, not just `react`.\n\n**Key lesson from RN 0.84**: Reanimated 4.2.0 did NOT support RN 0.84 (needed 4.2.2+). The `react-native-worklets` package also needed bumping (0.7.1 -> 0.7.4). Not catching this early means the build will fail late in the process.\n\n**Key lesson from RN 0.83**: The original `react-native-fast-image` package was abandoned and had no Fabric support. The `@d11/react-native-fast-image` fork was needed as a replacement. When replacing a package, check ALL references: package.json (root AND playground), TypeScript imports, Android `build.gradle` manual `implementation project()` lines, and iOS pod references.\n\n## Phase 2: CI Infrastructure Setup\n\n### 2a. Maintain Buildkite CI Jobs\n\nCopy an existing job file and update the version:\n\n```bash\n# Copy from the latest supported RN lane (adjust source/target versions)\ncp .buildkite/jobs/pipeline.android_rn_84.yml .buildkite/jobs/pipeline.android_rn_85.yml\ncp .buildkite/jobs/pipeline.ios_rn_84.yml .buildkite/jobs/pipeline.ios_rn_85.yml\n```\n\nEdit both files:\n- Update the label: `\":android: Android (RN 0.84.0)\"`\n- Update `REACT_NATIVE_VERSION: 0.84.0`\n- Update the key: `\"android_rn_84\"` / `\"ios_rn_84\"`\n- Keep `JAVA_HOME` on Android jobs (check if JDK version needs bumping)\n\n### 2b. Register Jobs in Pipeline Script\n\nAdd the new jobs to `.buildkite/pipeline.sh`:\n\n```bash\ncat .buildkite/jobs/pipeline.android_rn_84.yml\ncat .buildkite/jobs/pipeline.ios_rn_84.yml\n```\n\nInsert them in version order alongside the other platform jobs. Release publishing is dispatched separately through the GitHub Actions release workflow.\n\n### 2c. Optionally Drop Old Versions\n\nIf the project drops support for an old version, remove its pipeline files and entries from `pipeline.sh`. RN 0.82 PR dropped RN 0.80 and 0.81 pipelines.\n\n## Phase 3: Update Default Versions and Build Configuration\n\n### 3a. Update `package.json` (Root and Playground)\n\nUpdate in both `/package.json` and `/playground/package.json`:\n- `react-native` to the target version\n- `react` to the matching peer dependency version (check `npm info react-native@0.84.0 peerDependencies.react`)\n- `react-test-renderer` to match react\n- `@react-native/babel-preset`, `@react-native/eslint-config`, `@react-native/metro-config`, `@react-native/typescript-config` to `0.<minor>.0`\n- `@react-native-community/cli`, `cli-platform-android`, `cli-platform-ios` to matching CLI version\n- Any third-party deps identified in Phase 1c as needing version bumps\n\n### 3b. Update Android SDK, NDK, and Kotlin Versions\n\nCheck the target RN version's requirements and update in **both** `android/build.gradle` (the library defaults) and `playground/android/build.gradle`:\n- `compileSdkVersion` / `compileSdk`\n- `targetSdkVersion` / `targetSdk`\n- `buildToolsVersion`\n- `ndkVersion`\n- Kotlin version (`kotlinVersion` / `RNNKotlinVersion`)\n\nCross-reference with the RN template app's `build.gradle` for the target version (`npx @react-native-community/cli init` or check the RN GitHub repo).\n\nAlso update `autolink/fixtures/rn79/build.gradle.template` if SDK or Kotlin versions changed there.\n\n### 3c. Update Gradle Wrapper\n\nIf the target RN requires a newer Gradle version, update `playground/android/gradle/wrapper/gradle-wrapper.properties`.\n\n### 3d. Update Version-Switch Infrastructure\n\nUpdate `scripts/versionMapping.js`:\n- Add the new minor version to `CLI_VERSION_MAP`\n- Update `getGradleVersion()` if the Gradle version requirement changed\n- Update `getReanimatedOverride()` / `shouldRemoveWorklets()` if compatibility ranges changed\n\nUpdate `playground/android/rninfo.gradle` if new version-conditional logic is needed:\n- Add new boolean flags (e.g., `isRN84OrHigher`) if Gradle build logic needs to branch on the new version\n- Used for things like Kotlin version branching and conditional dependency resolution\n\n### 3e. Review and Update Podspec and Podfile\n\n**`ReactNativeNavigation.podspec`** may need changes if RN altered how native modules declare dependencies:\n- Manual `s.dependency` lists for React submodules may be replaced by `install_modules_dependencies(s)` (happened in 0.80)\n- Hardcoded `HEADER_SEARCH_PATHS`, folly compiler flags, or per-arch dependency lists may become unnecessary\n- Compare against the new RN version's recommended podspec pattern\n\n**`playground/ios/Podfile`** may need restructuring if RN changed `use_react_native!`, new arch configuration, or post-install hooks. Compare against the RN template app's Podfile for the target version.\n\n### 3f. Install Dependencies\n\nAfter updating package.json and build configs:\n\n```bash\ncd playground && yarn install && cd ios && pod deintegrate && pod install && cd ../..\n```\n\n### 3g. Clean Stale Xcode Build Settings\n\n**Do this BEFORE the first build** -- stale settings cause mysterious \"module not found\" errors.\n\nThe `playground/ios/playground.xcodeproj/project.pbxproj` may contain hardcoded build settings from previous RN versions (e.g., `REACT_NATIVE_MINOR_VERSION=72`, stale modulemap paths in `OTHER_CFLAGS`). Search for and remove/fix these:\n\n```bash\ngrep -n \"REACT_NATIVE_MINOR_VERSION\\|REANIMATED_VERSION\\|modulemap\" playground/ios/playground.xcodeproj/project.pbxproj\n```\n\nReplace hardcoded values with `\"$(inherited)\"` where appropriate.\n\n## Phase 4: Fix Native Compilation Errors\n\n### Strategy\n\nFor **systematic, known patterns** identified in Phase 1 (like legacy import guarding across many files), fix all instances in batch before building. This avoids slow iterative build cycles.\n\nFor **unexpected errors**, use an iterative build-fix approach: build, fix the first error, rebuild, repeat.\n\n```bash\n# iOS build\nxcodebuild build -workspace playground/ios/playground.xcworkspace \\\n  -scheme playground -configuration Debug -sdk iphonesimulator \\\n  -destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' -quiet\n\n# Android build\ncd playground/android && ./gradlew assembleDebug\n```\n\n### 4a. Batch-Fix: Guard Legacy iOS Imports\n\nIf the new RN version removes legacy headers from precompiled binaries, guard ALL identified imports at once.\n\n**Preferred approach: `__has_include` (compile-time header check)**\n\nThe best way to guard optional headers is `#if __has_include(...)`. This is forward-compatible — if a future RN version removes more headers, the code adapts automatically without needing new flags:\n\n```objc\n#if __has_include(<React/RCTScrollView.h>)\n#import <React/RCTScrollView.h>\n#endif\n\n#if __has_include(<React/RCTCxxBridgeDelegate.h>)\n#import <React/RCTCxxBridgeDelegate.h>\n#endif\n```\n\nUse `__has_include` for **imports** where the header may or may not exist. Then use `NSClassFromString` (see Pattern 3 below) for runtime references to classes from those headers.\n\n**Alternative: `#ifndef RCT_REMOVE_LEGACY_ARCH`**\n\nStarting with RN 0.84, React Native defines `RCT_REMOVE_LEGACY_ARCH=1` when legacy/bridge APIs are fully removed. This is more precise than `RCT_NEW_ARCH_ENABLED` (which has been true since RN 0.76 even though legacy APIs were still available). Use this for guarding **code blocks** that use legacy APIs:\n\n```objc\n#ifndef RCT_REMOVE_LEGACY_ARCH\n#import <React/RCTModalHostViewManager.h>\n#endif\n\n// In implementation:\n#ifndef RCT_REMOVE_LEGACY_ARCH\n- (void)connectModalHostViewManager:(RCTModalHostViewManager *)manager {\n    // old-arch-only code\n}\n#endif\n```\n\n**When to use which:**\n- `__has_include(...)` — for **imports** of headers that may not exist. Most robust, no flag dependency.\n- `#ifndef RCT_REMOVE_LEGACY_ARCH` — for **code blocks** using legacy APIs (method declarations, implementations, protocol conformances). Semantically correct: \"this code requires the legacy arch.\"\n- `#ifdef RCT_NEW_ARCH_ENABLED` — only for code that differs **between architectures** (e.g., `RCTHost` vs `RCTBridge` parameters). NOT for \"is legacy available?\" checks.\n\n**Steps:**\n\n1. List all files importing legacy headers:\n   ```bash\n   grep -rn \"#import <React/RCTRootView\\|#import <React/RCTRootViewDelegate\\|#import <React/RCTBridge+Private\\|#import <React/RCTModalHostView\\|#import <React/RCTScrollView\\|#import <React/RCTRootContentView\\|#import <React/RCTSurfacePresenterStub\\|#import <React/RCTBridgeProxy\" ios/ --include=\"*.h\" --include=\"*.mm\"\n   ```\n\n2. For each file, apply the appropriate guard (prefer `__has_include` for imports, `#ifndef RCT_REMOVE_LEGACY_ARCH` for code blocks).\n\n3. **Guard the full chain**: import -> type usage -> method declarations -> protocol conformances -> method implementations. Guarding just the import without guarding the code that uses the type causes \"undeclared identifier\" errors.\n\n4. **Check for dead code in `#ifdef` blocks**: After guarding imports, search for old-arch symbols referenced in new-arch code paths:\n   ```bash\n   # Find potential dead references to bridge in new-arch blocks\n   grep -n \"getBridge\\|bridgeManager\\|RCTBridge\" ios/ --include=\"*.mm\" -r\n   ```\n   Cross-reference hits with their surrounding `#ifdef` context. Remove any new-arch code that calls old-arch-only methods.\n\n### 4b. Common iOS Fix Patterns\n\n**Pattern 1: Guard optional imports with `__has_include`** -- Preferred for headers that may not exist:\n```objc\n#if __has_include(<React/RCTSurfacePresenterBridgeAdapter.h>)\n#import <React/RCTSurfacePresenterBridgeAdapter.h>\n#endif\n```\n\n**Pattern 2: Guard legacy code blocks with `RCT_REMOVE_LEGACY_ARCH`** -- For methods/classes that only exist on old arch:\n```objc\n#ifndef RCT_REMOVE_LEGACY_ARCH\n- (void)connectModalHostViewManager:(RCTModalHostViewManager *)manager { ... }\n#endif\n```\n\n**Pattern 3: Guard entire files** -- If a file is only used on old arch (e.g., `RNNBridgeManager.h/.mm`), wrap the entire content in `#ifndef RCT_REMOVE_LEGACY_ARCH`.\n\n**Pattern 4: Runtime class lookup** -- When you need to reference a class that may not exist at compile time (e.g., in `hitTest:withEvent:` or `isKindOfClass:` checks), use `NSClassFromString` instead of direct class references. This pairs well with `__has_include` — the import is conditional, and the runtime check handles the case where the class doesn't exist:\n\n```objc\n// Instead of: [view isKindOfClass:[RCTModalHostView class]]\n[view isKindOfClass:NSClassFromString(@\"RCTModalHostView\")]\n```\n\nCache the result with `dispatch_once` if it's in a hot path:\n```objc\nstatic Class myClass;\nstatic dispatch_once_t onceToken;\ndispatch_once(&onceToken, ^{\n    myClass = NSClassFromString(@\"RCTModalHostView\");\n});\n```\n\n**Pattern 5: Remove dead code paths** -- A `#ifdef RCT_NEW_ARCH_ENABLED` block that calls `getBridge` (old-arch only) is dead code -- remove it.\n\n**Pattern 6: Protocol conformance guards** -- If a protocol (e.g., `RCTRootViewDelegate`) only exists on old arch, guard the conformance declaration AND the delegate method implementations:\n\n```objc\n@interface MyView : UIView\n#ifndef RCT_NEW_ARCH_ENABLED\n                    <RCTRootViewDelegate>\n#endif\n```\n\n### 4c. Common Android Fix Patterns\n\n**Pattern 1: Deprecated method migration** -- When RN deprecates methods with `forRemoval = true`, rename to the replacement (e.g., `onCatalystInstanceDestroy()` -> `invalidate()`). Note: only rename the RN framework override, not internal RNN methods with the same name.\n\n**Pattern 2: Removed classes** -- When Android classes are removed (e.g., `CSSBackgroundDrawable` in RN 0.83), replace with standard Android equivalents (e.g., `ColorDrawable`).\n\n**Pattern 3: Test infrastructure** -- Test/mock classes that extend RN framework classes (e.g., `SimpleView extends ReactView`) may need refactoring if the parent class behavior changed. Also check Robolectric version compatibility -- newer Android SDK levels may require bumping Robolectric, and if the new Robolectric version requires a higher Java version than CI provides, add a `robolectric.properties` file to pin the SDK level (e.g., `sdk=35` when SDK 36 requires Java 21 but CI uses Java 17).\n\n**Pattern 4: Changed method signatures** -- RN may change method signatures without deprecation (e.g., nullable parameters becoming non-nullable, or new required parameters). These cause compile errors that aren't caught by searching for removed/deprecated APIs. Check the RN changelog for API changes in utility classes like `ColorPropConverter`, `ColorParser`, etc.\n\n### 4d. Research Before Fixing: Don't Just Pattern-Match\n\n**When you hit a new compilation error, resist the urge to immediately copy the fix pattern from nearby code.** Instead:\n\n1. **Check what the target RN version introduces.** Read the RN changelog/blog for new preprocessor flags, build system features, or recommended migration patterns. For example, RN 0.84 introduced `RCT_REMOVE_LEGACY_ARCH` — a flag specifically designed for the exact guarding problem we need to solve. Using it is better than repurposing `RCT_NEW_ARCH_ENABLED`.\n\n2. **Search for how other RN libraries solved it.** Check how major community libraries (react-native-screens, react-native-reanimated, react-native-gesture-handler) handle the same compatibility issue. They often discover better patterns first.\n\n3. **Evaluate the existing codebase pattern critically.** The pattern used in the current code may predate better alternatives. Ask: is there a more forward-compatible approach? Would `__has_include` be more robust than a flag check? Would `NSClassFromString` be cleaner than a compile-time guard?\n\n4. **Prefer compile-time safety over runtime safety, and standard compiler features over framework-specific flags.** `__has_include` is a C/ObjC compiler feature that works regardless of RN version. Framework flags like `RCT_REMOVE_LEGACY_ARCH` are next best. `NSClassFromString` is a runtime fallback for when compile-time checks aren't sufficient.\n\n### 4e. Compile Error Triage\n\nWhen you get a compile error:\n1. Identify the missing symbol (header, class, method)\n2. **Research** the best available guard mechanism (see 4d above)\n3. Check if it's used only in old-arch or new-arch code paths\n4. If old-arch only: guard with `__has_include` (imports) or `#ifndef RCT_REMOVE_LEGACY_ARCH` (code)\n5. If new-arch only: this shouldn't happen -- investigate the API replacement\n6. If used in both: find the new-arch equivalent and branch with `#ifdef RCT_NEW_ARCH_ENABLED`\n\n### 4e. Fix Test Files\n\n**Test files are easily overlooked.** They often reference arch-specific APIs (like `RCTBridge` vs `RCTHost`, or methods that only exist under `#ifdef RCT_NEW_ARCH_ENABLED`). Check all test files for arch-specific calls:\n\n```bash\n# Find test files referencing RCTBridge (old-arch only in new-arch builds)\ngrep -rn \"RCTBridge\\|registerExternalComponent\" playground/ios/NavigationTests/ --include=\"*.mm\"\n\n# Check that test method calls match the current header signatures\n# e.g., RNNExternalComponentStore exposes different methods under #ifdef RCT_NEW_ARCH_ENABLED\n```\n\nGuard test code the same way as production code — use `#ifndef RCT_REMOVE_LEGACY_ARCH` for tests that only apply to legacy arch:\n\n```objc\n#ifndef RCT_REMOVE_LEGACY_ARCH\n\n@interface RNNModalHostViewManagerHandlerTest : XCTestCase\n@end\n// ... entire test class ...\n@end\n\n#endif\n```\n\n**Key lesson from RN 0.84**: All 4 iOS CI jobs failed because a single test file (`RNNViewControllerFactoryTest.mm`) called an old-arch method on `RNNExternalComponentStore` without a guard. The fix was trivial but blocked the entire build.\n\n### 4f. clang-format\n\nRNN uses clang-format on iOS files via a pre-commit hook. After editing `.h`/`.mm` files, verify formatting:\n\n```bash\n./node_modules/.bin/git-clang-format --diff -- ios/MyFile.mm\n```\n\nThe formatter has opinions about `#ifdef` indentation that may require unusual formatting (e.g., protocol conformance on a continuation line after `#ifndef`).\n\n## Phase 5: Validate Playground Dependencies\n\n### 5a. Check for Stale References\n\nAfter replacing any dependency (like fast-image -> @d11/fast-image), search for ALL references:\n\n```bash\n# TypeScript imports\ngrep -r \"react-native-fast-image\" playground/src/ --include=\"*.ts\" --include=\"*.tsx\"\n\n# Android gradle -- look for manual implementation project() lines\ngrep -r \"fast-image\\|fast_image\" playground/android/ --include=\"*.gradle\"\n\n# iOS podfile\ngrep -r \"fast-image\\|FastImage\" playground/ios/Podfile\n```\n\nNote: `autolinkLibrariesWithApp()` in the playground's `build.gradle` handles most deps automatically. Manual `implementation project(':...')` lines are often stale and should be removed when the package is autolinked.\n\n## Phase 6: Full Build Verification\n\nRun both platform builds to confirm everything compiles:\n\n```bash\n# iOS\nxcodebuild build -workspace playground/ios/playground.xcworkspace \\\n  -scheme playground -configuration Debug -sdk iphonesimulator \\\n  -destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' -quiet\n\n# Android\ncd playground/android && ./gradlew assembleDebug\n\n# JS tests\nyarn test-js\n```\n\n## Phase 7: Backward Compatibility\n\nVerify that the version-switch script works for older supported versions:\n\n```bash\nREACT_NATIVE_VERSION=0.83.0 node scripts/changeReactNativeVersion.js\n# Then rebuild to verify\n```\n\n## Phase 8: Documentation\n\nUpdate `website/docs/docs/docs-Installing.mdx`:\n- Update the supported RN version range\n- Note any breaking changes users need to be aware of\n\n## Common Pitfalls (Lessons Learned)\n\n1. **Don't assume deps are compatible** -- Always check third-party native dep compatibility tables BEFORE starting the build. Reanimated is the most common offender.\n\n2. **Search for ALL references when replacing a package** -- TypeScript imports, Android gradle `implementation project()` lines, iOS pod references, root AND playground package.json. Missing one causes CI failures.\n\n3. **Legacy headers in precompiled binaries** -- When RN enforces new arch by default (like 0.84 with `RCT_REMOVE_LEGACY_ARCH=1`), headers for old-arch classes are stripped from the xcframework. Use `__has_include` for conditional imports and `#ifndef RCT_REMOVE_LEGACY_ARCH` for code blocks. Batch-fix all legacy imports identified in Phase 1b rather than finding them one build at a time.\n\n4. **Guard code, not just imports** -- Guarding an import without guarding the code that uses the imported types leads to \"undeclared identifier\" errors. Always guard the full chain: import -> type usage -> method declarations -> method implementations.\n\n5. **Dead code in `#ifdef` blocks** -- When splitting code paths between old/new arch, check that each path only references symbols available in that architecture. A common bug is new-arch code calling old-arch-only methods (like `getBridge` in a `#ifdef RCT_NEW_ARCH_ENABLED` block).\n\n6. **Stale Xcode project settings** -- The `.pbxproj` file can accumulate hardcoded build flags from old versions. These cause mysterious \"module not found\" errors. Check for stale `OTHER_CFLAGS` BEFORE the first build (Phase 3g).\n\n7. **clang-format surprises** -- The formatter enforces specific indentation around preprocessor directives. Run the check before committing to avoid hook failures.\n\n8. **Batch-fix systematic patterns, iterate on surprises** -- When you identify a pattern that affects many files (like legacy import guarding), fix all instances at once. Use iterative build-fix only for unexpected or one-off errors.\n\n9. **Android SDK level cascading effects** -- Bumping `compileSdkVersion`/`targetSdkVersion` can require bumping Robolectric, which may require a higher Java version than CI provides. Solution: pin the Robolectric SDK via `robolectric.properties` (e.g., `sdk=35` when SDK 36 needs Java 21).\n\n10. **Podspec can be a major effort** -- Don't underestimate podspec changes. RN 0.80 required replacing the entire dependency declaration strategy. Compare your podspec against the RN template's pattern for the target version.\n\n11. **Don't forget test files** -- Test files (`NavigationTests/*.mm`) often call arch-specific APIs directly. When guarding production code, search test files for the same APIs and guard them too. A single unguarded test call can fail the entire CI build across all RN versions.\n\n12. **Don't just follow existing patterns — research better ones** -- When fixing a compilation error, don't blindly copy the guarding pattern already used in the codebase. The existing pattern may predate better alternatives introduced in newer RN versions. For example, RN 0.84 introduced `RCT_REMOVE_LEGACY_ARCH` and the codebase already supported `__has_include`, but initial fixes used the older `#ifdef RCT_NEW_ARCH_ENABLED` pattern because that's what the existing code used. Always check: what new preprocessor flags or build-system features does the target RN version introduce? Is there a more robust/forward-compatible way to solve this?\n",".cursor/rules/github-descriptions.mdc":"---\ndescription: When the user asks for a GitHub description or PR description\nglobs:\nalwaysApply: false\n---\n\nWhen generating GitHub descriptions (PR descriptions, issue descriptions, commit descriptions), always use GitHub-flavored Markdown formatting: **bold** for emphasis, `backticks` for code/class/file references, bullet lists with `-`, and `##` headers where appropriate.\n",".cursor/skills/engine-e2e/SKILL.md":"---\nname: engine-e2e\ndescription: Run Wix Engine (mobile-apps-engine) iOS E2E tests locally to validate RNN changes. Use when you need to test RNN fixes against the Engine's Detox test suite.\n---\n\n# Running Engine E2E Tests Against Local RNN Changes\n\nThe Engine app (`@wix/wix-one-app-engine`) in `~/Documents/mobile-apps-engine` consumes RNN\nfrom `node_modules/react-native-navigation`. To test RNN changes against the Engine's E2E\nsuite, you patch the Engine's copy of RNN, rebuild the native binary, and run the tests.\n\n## Prerequisites\n\n- Node via nvm (`nvm use default`)\n- The `CI` env var must be **unset** (not `0`, fully unset) to avoid CI-specific codepaths.\n  Use `env -u CI` before every command.\n- The Engine repo at `~/Documents/mobile-apps-engine` with `yarn install` already done.\n\n## Step 1: Patch RNN in Engine's node_modules\n\nApply your RNN source changes to the corresponding files under:\n```\n~/Documents/mobile-apps-engine/node_modules/react-native-navigation/ios/\n```\nThe directory structure mirrors the RNN repo's `ios/` folder exactly.\n\n## Step 2: Rebuild the iOS Native Binary\n\n```bash\ncd ~/Documents/mobile-apps-engine\nunset PREFIX && . ~/.nvm/nvm.sh > /dev/null && nvm use default > /dev/null\nenv -u CI yarn workspace @wix/mobile-apps-engine-native-builds build-local-ios\n```\n\nThis runs `xcodebuild` with `-quiet` flag — expect no output until it finishes.\nTakes ~10-15 minutes on M-series Macs.\n\nThe build output (`.app` bundle) lands in:\n```\npackages/native/mobile-apps-engine-native-builds/dist/binaries.json\n```\n\n### Troubleshooting Build\n\n- **Keychain error** (`SecKeychainUnlock`): The `CI` env var is set. Use `env -u CI`.\n- **Signing errors**: Expected for local builds — the script handles ad-hoc signing.\n\n## Step 3: Build JS Bundles (first time only)\n\nThese are needed once per checkout. Skip if already built.\n\n```bash\nenv -u CI yarn workspace @wix/mobile-apps-engine-extra-bundle local:build\nenv -u CI yarn workspace @wix/mobile-apps-dependencies local:build\n```\n\n## Step 4: Run E2E Tests\n\n```bash\ncd ~/Documents/mobile-apps-engine\nunset PREFIX && . ~/.nvm/nvm.sh > /dev/null && nvm use default > /dev/null\nenv -u CI yarn workspace @wix/wix-one-app-engine test:e2e:ios -w d <suite_files...>\n```\n\nThe `-w d` flag selects the Detox worker count.\n\n### Specific suites relevant to RNN\n\n| Suite file | What it tests |\n|-----------|---------------|\n| `e2e/suites/ExternalLinks.test.js` | Deep link navigation, back button |\n| `e2e/suites/ExternalLinksModes.test.js` | Deep link modes (pop to root, tab switch) |\n| `e2e/suites/ExternalLinksPushNotifications.test.js` | Push notification deep links |\n| `e2e/suites/ExtenalLinksWithSiteSelect.test.js` | Deep links with site selection |\n| `e2e/suites/EngineUIComponents.test.js` | Error screen, UI components |\n| `e2e/suites/LaunchArgs.test.js` | Launch arguments |\n| `e2e/suites/LazyModules.test.js` | Lazy-loaded modules |\n\n### Example: Run the deep-link suites\n\n```bash\nenv -u CI yarn workspace @wix/wix-one-app-engine test:e2e:ios -w d \\\n  e2e/suites/ExternalLinks.test.js \\\n  e2e/suites/ExternalLinksModes.test.js \\\n  e2e/suites/ExternalLinksPushNotifications.test.js\n```\n\n### Troubleshooting Tests\n\n- **`Error: No dist version found`**: The native build hasn't run or failed.\n  Run step 2 again.\n- **`Cannot find module .../mobile-apps-engine-extra-bundle/index.js`**:\n  Run step 3 (`local:build` for extra-bundle).\n- **`ENOENT .../metadata.json`**: Run step 3 (`local:build` for mobile-apps-dependencies).\n- **`Unable to resolve module @rozenite/...`**: The Rozenite plugin import is broken.\n  Patch `packages/wix-one-app-engine/src/rozenitePlugin/helper/rozenite-network-inspector.ts`\n  to make the import optional with a no-op fallback.\n- **Tests time out on `navigateBack()`**: The `navigateBack()` helper taps\n  `element(by.id('pop'))` on iOS. This relies on RNN's `setBackButtonTestID` working\n  correctly. If the back button's view hierarchy changed (e.g., iOS 26 Liquid Glass),\n  the testID isn't applied and the element can't be found.\n\n## Key Engine Files\n\n| File | Purpose |\n|------|---------|\n| `packages/wix-one-app-engine/e2e/helpers/utils.js` | Test helpers including `navigateBack()` |\n| `packages/wix-one-app-engine/demo-modules/deep-links/module.js` | Deep link route definitions |\n| `packages/wix-one-app-engine/demo-modules/deep-links/Screens.js` | Deep link screen components |\n| `packages/wix-one-app-engine/internalScripts/test-e2e.js` | E2E test runner script |\n| `packages/native/mobile-apps-engine-native-builds/local_build_scripts/build_ios.js` | Local iOS build script |\n\n",".github/skills/rnn-codebase/SKILL.md":"---\nname: rnn-codebase\ndescription: Navigate and work with the react-native-navigation (RNN) codebase. Use when fixing bugs, adding features, tracing command flows, understanding options resolution, or working across JS/iOS/Android layers in this repo.\n---\n\n# React Native Navigation Codebase\n\n## Architecture Overview\n\nRNN has three layers that mirror each other:\n\n```\nJS/TS (src/)  →  TurboModule bridge  →  iOS native (ios/)\n                                     →  Android native (android/)\n```\n\nA navigation command (e.g. `push`) flows:\n1. `Navigation.push()` → `Commands.ts` → processing pipeline → `NativeCommandsSender.ts`\n2. TurboModule: `RNNTurboModule` (iOS) / `NavigationTurboModule.kt` (Android)\n3. iOS: `RNNCommandsHandler` → `RNNViewControllerFactory` → UIKit controllers\n4. Android: `Navigator` → `LayoutFactory` → View-based controllers (no Fragments)\n\nRead [ARCHITECTURE.md](../../../ARCHITECTURE.md) for the full overview.\n\n## Key Cross-Layer Mappings\n\n### Layout Types → Native Controllers\n\n| JS Layout Type | iOS Controller | Android Controller |\n|----------------|---------------|-------------------|\n| `component` | `RNNComponentViewController` | `ComponentViewController` |\n| `stack` | `RNNStackController` (UINavigationController) | `StackController` |\n| `bottomTabs` | `RNNBottomTabsController` (UITabBarController) | `BottomTabsController` |\n| `sideMenu` | `RNNSideMenuViewController` (MMDrawerController) | `SideMenuController` (DrawerLayout) |\n| `topTabs` | `RNNTopTabsViewController` | `TopTabsController` (ViewPager) |\n| `splitView` | `RNNSplitViewController` | N/A (iOS only) |\n| `externalComponent` | `RNNExternalViewController` | `ExternalComponentViewController` |\n\n### Options → Presenters\n\nEach controller type has a Presenter that applies options to views:\n\n| iOS Controller | iOS Presenter | Android Presenter |\n|----------------|--------------|-------------------|\n| `RNNComponentViewController` | `RNNComponentPresenter` | `ComponentPresenter` |\n| `RNNStackController` | `RNNStackPresenter` + `TopBarPresenter` | `StackPresenter` |\n| `RNNBottomTabsController` | `RNNBottomTabsPresenter` | `BottomTabsPresenter` |\n| `RNNSideMenuViewController` | `RNNSideMenuPresenter` | `SideMenuPresenter` |\n\n### Events (same names both platforms)\n\n| Event | Trigger |\n|-------|---------|\n| `RNN.ComponentDidAppear` | Screen becomes visible |\n| `RNN.ComponentDidDisappear` | Screen hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tap |\n| `RNN.BottomTabSelected` | Tab changed |\n| `RNN.ModalDismissed` | Modal dismissed |\n| `RNN.ScreenPopped` | Screen popped from stack |\n| `RNN.CommandCompleted` | Any command finished |\n\n## Where to Find Things\n\n### By task: \"I need to fix/change X\"\n\n| Task | JS File(s) | iOS File(s) | Android File(s) |\n|------|-----------|------------|----------------|\n| Command execution | `src/commands/Commands.ts` | `ios/RNNCommandsHandler.mm` | `react/NavigationTurboModule.kt` |\n| Layout creation | `src/commands/LayoutTreeParser.ts` | `ios/RNNViewControllerFactory.mm` | `options/LayoutFactory.java` |\n| Options processing | `src/commands/OptionsProcessor.ts` | `ios/RNNNavigationOptions.mm` | `options/Options.java` |\n| Options application | — | `ios/*Presenter.mm` | `viewcontrollers/*Presenter.java` |\n| TopBar | `src/interfaces/Options.ts` (TopBarOptions) | `ios/TopBarPresenter.mm`, `ios/RNNUIBarButtonItem.mm` | `views/stack/topbar/` |\n| Bottom tabs | `src/interfaces/Options.ts` (BottomTabsOptions) | `ios/RNNBottomTabsPresenter.mm` | `viewcontrollers/bottomtabs/` |\n| Modals | `src/commands/Commands.ts` | `ios/RNNModalManager.mm` | `viewcontrollers/modal/ModalStack.java` |\n| Overlays | `src/commands/Commands.ts` | `ios/RNNOverlayManager.mm` | `viewcontrollers/overlay/OverlayManager.kt` |\n| Animations | `src/interfaces/Options.ts` (AnimationOptions) | `ios/ScreenAnimationController.mm` | `viewcontrollers/stack/StackAnimator.kt` |\n| React view rendering | — | `ios/RNNReactView.mm` | `react/ReactView.java` |\n| Events to JS | `src/adapters/NativeEventsReceiver.ts` | `ios/RNNEventEmitter.mm` | `react/events/EventEmitter.java` |\n| Component registration | `src/components/ComponentRegistry.ts` | — | — |\n\n### By directory\n\n- **`src/`** — JS public API, commands, processing pipeline. See [src/ARCHITECTURE.md](../../../src/ARCHITECTURE.md)\n- **`ios/`** — All Obj-C/C++ native code. See [ios/ARCHITECTURE.md](../../../ios/ARCHITECTURE.md)\n- **`ios/TurboModules/`** — New architecture entry points (`RNNTurboModule`, `RNNTurboManager`, `RNNTurboCommandsHandler`)\n- **`android/src/main/java/com/reactnativenavigation/`** — All Java/Kotlin native code. See [android/ARCHITECTURE.md](../../../android/ARCHITECTURE.md)\n- **`playground/`** — Demo app for development and E2E tests\n- **`playground/src/screens/`** — Test screens exercising every feature\n- **`playground/e2e/`** — Detox E2E tests\n\n## Options Resolution Order\n\nOptions are applied in ascending priority:\n1. Default options (from `Navigation.setDefaultOptions()`) — lowest priority\n2. Static options (from component class or `Navigation.registerComponent`)\n3. Options passed in the layout call (e.g. `push`, `setRoot`)\n4. `mergeOptions()` — runtime override, highest priority\n\n## JS Processing Pipeline (exact order)\n\n```\nAPI layout → OptionsCrawler.crawl() → LayoutProcessor.process()\n  → LayoutTreeParser.parse() → LayoutTreeCrawler.crawl()\n  → OptionsProcessor (colors, assets, custom) → NativeCommandsSender\n```\n\n## iOS Patterns\n\n- All controllers conform to `RNNLayoutProtocol`\n- `RNNBasePresenter` subclasses apply options — `applyOptionsOnInit:`, `applyOptions:`, `mergeOptions:resolvedOptions:`\n- Commands run on main thread (`RCTExecuteOnMainQueue`)\n- React views: `RNNReactView` wraps `RCTSurfaceHostingView` (new arch)\n- Overlays use separate `UIWindow` instances (`RNNOverlayWindow`)\n- `RNNReactComponentRegistry` caches React component instances\n\n## Android Patterns\n\n- View-based, NOT Fragment-based\n- All commands dispatched via `UiThread.post()`\n- `ViewController<T extends ViewGroup>` is the base — `createView()` is abstract\n- `ParentController` extends `ChildController` extends `ViewController`\n- Bottom tabs use `AHBottomNavigation` library\n- Three root layouts in `NavigationActivity`: rootLayout, modalsLayout, overlaysLayout\n- Tab attachment modes: `Together`, `OnSwitchToTab`, `AfterInitialTab`\n\n## Development Workflow\n\n### Playground app\n- `yarn start` — Metro bundler\n- `yarn xcode` — Open iOS project\n- `yarn studio` — Open Android project\n- `yarn pod-install` — Install iOS pods\n\n### Testing\n- `yarn test-js` — Jest unit tests\n- `yarn test-unit-ios` — iOS native unit tests (XCTest)\n- `yarn test-unit-android` — Android native unit tests (JUnit + Robolectric)\n- `yarn test-e2e-ios-ci` / `yarn test-e2e-android-ci` — Detox E2E tests\n\n### Building\n- `yarn prepare` — Builds `src/` → `lib/` (ESM + types)\n- Codegen config: `rnnavigation` in `package.json`\n\n## Common Gotchas\n\n- iOS uses UIKit subclasses (UINavigationController, UITabBarController); Android uses custom View hierarchy\n- `splitView` is iOS-only\n- Side menu: iOS uses MMDrawerController (3rd party); Android uses DrawerLayout (native)\n- Options that exist in JS types may not be implemented on both platforms — check the presenter\n- `passProps` are stored in JS `Store`, not sent to native (cleared before bridge crossing)\n- The `lib/` folder is generated — never edit it, edit `src/` instead\n"},"files":{".claude/skills/rnn-codebase/SKILL.md":"---\nname: rnn-codebase\ndescription: Navigate and work with the react-native-navigation (RNN) codebase. Use when fixing bugs, adding features, tracing command flows, understanding options resolution, or working across JS/iOS/Android layers in this repo.\n---\n\n# React Native Navigation Codebase\n\n## Architecture Overview\n\nRNN has three layers that mirror each other:\n\n```\nJS/TS (src/)  →  TurboModule bridge  →  iOS native (ios/)\n                                     →  Android native (android/)\n```\n\nA navigation command (e.g. `push`) flows:\n1. `Navigation.push()` → `Commands.ts` → processing pipeline → `NativeCommandsSender.ts`\n2. TurboModule: `RNNTurboModule` (iOS) / `NavigationTurboModule.kt` (Android)\n3. iOS: `RNNCommandsHandler` → `RNNViewControllerFactory` → UIKit controllers\n4. Android: `Navigator` → `LayoutFactory` → View-based controllers (no Fragments)\n\nRead [ARCHITECTURE.md](../../ARCHITECTURE.md) for the full overview.\n\n## Key Cross-Layer Mappings\n\n### Layout Types → Native Controllers\n\n| JS Layout Type | iOS Controller | Android Controller |\n|----------------|---------------|-------------------|\n| `component` | `RNNComponentViewController` | `ComponentViewController` |\n| `stack` | `RNNStackController` (UINavigationController) | `StackController` |\n| `bottomTabs` | `RNNBottomTabsController` (UITabBarController) | `BottomTabsController` |\n| `sideMenu` | `RNNSideMenuViewController` (MMDrawerController) | `SideMenuController` (DrawerLayout) |\n| `topTabs` | `RNNTopTabsViewController` | `TopTabsController` (ViewPager) |\n| `splitView` | `RNNSplitViewController` | N/A (iOS only) |\n| `externalComponent` | `RNNExternalViewController` | `ExternalComponentViewController` |\n\n### Options → Presenters\n\nEach controller type has a Presenter that applies options to views:\n\n| iOS Controller | iOS Presenter | Android Presenter |\n|----------------|--------------|-------------------|\n| `RNNComponentViewController` | `RNNComponentPresenter` | `ComponentPresenter` |\n| `RNNStackController` | `RNNStackPresenter` + `TopBarPresenter` | `StackPresenter` |\n| `RNNBottomTabsController` | `RNNBottomTabsPresenter` | `BottomTabsPresenter` |\n| `RNNSideMenuViewController` | `RNNSideMenuPresenter` | `SideMenuPresenter` |\n\n### Events (same names both platforms)\n\n| Event | Trigger |\n|-------|---------|\n| `RNN.ComponentDidAppear` | Screen becomes visible |\n| `RNN.ComponentDidDisappear` | Screen hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tap |\n| `RNN.BottomTabSelected` | Tab changed |\n| `RNN.ModalDismissed` | Modal dismissed |\n| `RNN.ScreenPopped` | Screen popped from stack |\n| `RNN.CommandCompleted` | Any command finished |\n\n## Where to Find Things\n\n### By task: \"I need to fix/change X\"\n\n| Task | JS File(s) | iOS File(s) | Android File(s) |\n|------|-----------|------------|----------------|\n| Command execution | `src/commands/Commands.ts` | `ios/RNNCommandsHandler.mm` | `react/NavigationTurboModule.kt` |\n| Layout creation | `src/commands/LayoutTreeParser.ts` | `ios/RNNViewControllerFactory.mm` | `options/LayoutFactory.java` |\n| Options processing | `src/commands/OptionsProcessor.ts` | `ios/RNNNavigationOptions.mm` | `options/Options.java` |\n| Options application | — | `ios/*Presenter.mm` | `viewcontrollers/*Presenter.java` |\n| TopBar | `src/interfaces/Options.ts` (TopBarOptions) | `ios/TopBarPresenter.mm`, `ios/RNNUIBarButtonItem.mm` | `views/stack/topbar/` |\n| Bottom tabs | `src/interfaces/Options.ts` (BottomTabsOptions) | `ios/RNNBottomTabsPresenter.mm` | `viewcontrollers/bottomtabs/` |\n| Modals | `src/commands/Commands.ts` | `ios/RNNModalManager.mm` | `viewcontrollers/modal/ModalStack.java` |\n| Overlays | `src/commands/Commands.ts` | `ios/RNNOverlayManager.mm` | `viewcontrollers/overlay/OverlayManager.kt` |\n| Animations | `src/interfaces/Options.ts` (AnimationOptions) | `ios/ScreenAnimationController.mm` | `viewcontrollers/stack/StackAnimator.kt` |\n| React view rendering | — | `ios/RNNReactView.mm` | `react/ReactView.java` |\n| Events to JS | `src/adapters/NativeEventsReceiver.ts` | `ios/RNNEventEmitter.mm` | `react/events/EventEmitter.java` |\n| Component registration | `src/components/ComponentRegistry.ts` | — | — |\n| Deep linking (URL → screen) | `src/linking/` (`LinkingHandler`, `URLParser`, `RouteMatcher`, `DeferredLinkQueue`, `ModalLayoutBuilder`) | `ios/RNNAppDelegate.mm` (`dispatchDeepLinkURL:`, cold-start queue, `RCTContentDidAppearNotification`) | `NavigationActivity.onNewIntent` → `ReactGateway` |\n\n### By directory\n\n- **`src/`** — JS public API, commands, processing pipeline. See [src/ARCHITECTURE.md](../../src/ARCHITECTURE.md)\n- **`ios/`** — All Obj-C/C++ native code. See [ios/ARCHITECTURE.md](../../ios/ARCHITECTURE.md)\n- **`ios/TurboModules/`** — New architecture entry points (`RNNTurboModule`, `RNNTurboManager`, `RNNTurboCommandsHandler`)\n- **`android/src/main/java/com/reactnativenavigation/`** — All Java/Kotlin native code. See [android/ARCHITECTURE.md](../../android/ARCHITECTURE.md)\n- **`playground/`** — Demo app for development and E2E tests\n- **`playground/src/screens/`** — Test screens exercising every feature\n- **`playground/e2e/`** — Detox E2E tests\n\n## Options Resolution Order\n\nOptions are applied in ascending priority:\n1. Default options (from `Navigation.setDefaultOptions()`) — lowest priority\n2. Static options (from component class or `Navigation.registerComponent`)\n3. Options passed in the layout call (e.g. `push`, `setRoot`)\n4. `mergeOptions()` — runtime override, highest priority\n\n## JS Processing Pipeline (exact order)\n\n```\nAPI layout → OptionsCrawler.crawl() → LayoutProcessor.process()\n  → LayoutTreeParser.parse() → LayoutTreeCrawler.crawl()\n  → OptionsProcessor (colors, assets, custom) → NativeCommandsSender\n```\n\n## iOS Patterns\n\n- All controllers conform to `RNNLayoutProtocol`\n- `RNNBasePresenter` subclasses apply options — `applyOptionsOnInit:`, `applyOptions:`, `mergeOptions:resolvedOptions:`\n- Commands run on main thread (`RCTExecuteOnMainQueue`)\n- React views: `RNNReactView` wraps `RCTSurfaceHostingView` (new arch)\n- Overlays use separate `UIWindow` instances (`RNNOverlayWindow`)\n- `RNNReactComponentRegistry` caches React component instances\n\n## Android Patterns\n\n- View-based, NOT Fragment-based\n- All commands dispatched via `UiThread.post()`\n- `ViewController<T extends ViewGroup>` is the base — `createView()` is abstract\n- `ParentController` extends `ChildController` extends `ViewController`\n- Bottom tabs use `AHBottomNavigation` library\n- Three root layouts in `NavigationActivity`: rootLayout, modalsLayout, overlaysLayout\n- Tab attachment modes: `Together`, `OnSwitchToTab`, `AfterInitialTab`\n\n## Development Workflow\n\n### Playground app\n- `yarn start` — Metro bundler\n- `yarn xcode` — Open iOS project\n- `yarn studio` — Open Android project\n- `yarn pod-install` — Install iOS pods\n\n### Testing\n- `yarn test-js` — Jest unit tests\n- `yarn test-unit-ios` — iOS native unit tests (XCTest)\n- `yarn test-unit-android` — Android native unit tests (JUnit + Robolectric)\n- `yarn test-e2e-ios-ci` / `yarn test-e2e-android-ci` — Detox E2E tests\n\n### Building\n- `yarn prepare` — Builds `src/` → `lib/` (ESM + types)\n- Codegen config: `rnnavigation` in `package.json`\n\n## Common Gotchas\n\n- iOS uses UIKit subclasses (UINavigationController, UITabBarController); Android uses custom View hierarchy\n- `splitView` is iOS-only\n- Side menu: iOS uses MMDrawerController (3rd party); Android uses DrawerLayout (native)\n- Options that exist in JS types may not be implemented on both platforms — check the presenter\n- `passProps` are stored in JS `Store`, not sent to native (cleared before bridge crossing)\n- The `lib/` folder is generated — never edit it, edit `src/` instead\n- Deep links are processed only after the first `setRoot()` resolves; pre-bridge URLs on iOS are queued natively in `RNNAppDelegate` and flushed on `RCTContentDidAppearNotification` (bridgeless mode — `RCTJavaScriptDidLoadNotification` does NOT fire)\n- `ModalLayoutBuilder` strips React-reserved keys (`ref`, `key`) from URL query params before they reach `passProps`, to avoid React 19 ref-validation crashes\n",".cursor/skills/ios26-navigation/SKILL.md":"---\nname: ios26-navigation\ndescription: Reference for iOS 26 navigation bar, tab bar, toolbar, and Liquid Glass building blocks (UITab, scroll-edge effects, search placement, shared-background platter, UIButton glass configurations, UIGlassEffect / UIGlassContainerEffect, UINavigationItem.style navigator/browser/editor, UICornerConfiguration / concentric corners, UISheetPresentationController, SF Symbols 7) plus the internal view hierarchy of UIBarButtonItem and UIToolbar, and how react-native-navigation maps to all of it. Use when adding or fixing iOS 26 behavior in RNN's top bar, bottom tabs, bar buttons, toolbar, modals, or any glass-styled custom chrome; when investigating iOS 26-only regressions; or when deciding how to expose a new iOS 26 capability through RNN options.\n---\n\n# iOS 26 Navigation in RNN\n\n## When this applies\n\nUse this skill any time work touches:\n- Top bar / navigation bar appearance, buttons, titles, or search\n- Bottom tab bar appearance, items, badges, or layout\n- Toolbar items or bar button styling\n- Any `@available(iOS 26.0, *)` branch\n- iOS 26-only bugs (Liquid Glass clipping, tab bar floating, button platter, scroll-edge effects)\n\nPair this with `rnn-codebase` (repo navigation) and `rnn-e2e-runner` (validation).\n\n## Build configuration\n\n- **Always Release** for verification — see workspace rule `rnn-build-release.mdc`. Debug masks iOS 26 layout/transition issues.\n- Xcode 26.1 toolchain: `DEVELOPER_DIR=/Applications/Xcode_26.1.app/Contents/Developer`\n- Simulator: `iPhone 17 Pro Max` (iOS 26 default)\n- Do **not** disable Fabric / New Architecture (user rule).\n- Compatibility opt-out flag: `UIDesignRequiresCompatibility` in `Info.plist`. RNN reads it in `RNNReactButtonView.designRequiresCompatibility` to fall back to pre-iOS-26 layout. Always honor it in new iOS 26 code paths.\n\n---\n\n## Apple iOS 26 API map\n\n### 1. Liquid Glass material\nThe system bar material on `UINavigationBar`, `UITabBar`, `UIToolbar` is **always translucent / glass** by default. `configureWithOpaqueBackground` is silently overlaid with glass unless you also nil out `backgroundEffect`.\n\n- `UIBarAppearance.backgroundEffect = nil` — required to actually get an opaque/transparent fill on iOS 26.\n- `UITabBarAppearance` / `UINavigationBarAppearance` / `UIToolbarAppearance` — same `backgroundEffect` rule.\n- Apple HIG: [Adopt Liquid Glass](https://developer.apple.com/design/human-interface-guidelines/materials)\n- WWDC25: \"What's new in UIKit\", \"Build a UIKit app with the new design\"\n\n**RNN handling:**\n- `ios/BottomTabsAppearancePresenter.mm`: branches on iOS 26 — uses `configureWithTransparentBackground` + `backgroundEffect=nil` + sets `tabBar.backgroundColor`. Pre-26 uses `configureWithOpaqueBackground`.\n- `ios/TopBarAppearancePresenter.mm`: same pattern for the navigation bar.\n\n### 2. Floating tab bar + drawBehind default\nThe tab bar floats above content on iOS 26 instead of pushing it up. Content underneath needs to extend.\n\n- Tab bar no longer occupies layout space the same way; `safeAreaInsets.bottom` increases for content.\n- Default `drawBehind` should be `YES` on iOS 26.\n\n**RNN handling:**\n- `ios/RNNBottomTabsOptions.mm` (`-shouldDrawBehind`): defaults `drawBehind` to `YES` on iOS 26, `NO` otherwise.\n- `ios/RNNBottomTabsController.mm`: `rnn_cycleAllTabsThenRestoreInitialSelection` — iOS 26 first-layout bug where tab item titles get misplaced; cycle selection in `viewDidAppear` to force a correct layout. Gated by `_rnnDidApplyInitialTabBarSelectionFix`.\n\n### 3. UITab / UITabBarController.tabs (iOS 18+, expanded in 26)\nModern tab API replaces `viewControllers` with `tabs: [UITab]`. Supports `UITabGroup`, `UISearchTab`, and `UITabBarController.mode = .tabSidebar`.\n\n- `UITab(title:image:identifier:viewControllerProvider:)` — lazy VC creation per tab.\n- `UITabBarController.tabs` — array of `UITab`, can mix `UITab` and `UITabGroup`.\n- `UITabBarController.mode` — `.tabBar` (default) vs `.tabSidebar` (iPad sidebar).\n- `UISearchTab` — first-class search tab, integrates with `UINavigationItem` search.\n- `UITabBarController.sidebarLayoutPreferences` — iPad sidebar customization.\n- `UITabBarController.tabBarPlacement` — `.automatic`, `.bottom`, `.top` (iPadOS 26 can pin the tab bar at the top of the window).\n- Programmatic transitions between sidebar and tab bar layouts via animating `mode` changes inside `UIView.animate`.\n- Apple: [UITabBarController.tabs](https://developer.apple.com/documentation/uikit/uitabbarcontroller/tabs), [UITab](https://developer.apple.com/documentation/uikit/uitab), [UITabGroup](https://developer.apple.com/documentation/uikit/uitabgroup)\n\n**RNN handling:** RNN currently uses the legacy `viewControllers` API. There is **no** `UITab` / `tabs` adoption yet. New iOS 26 tab features (sidebar mode, search tab, groups, top placement) would need a new code path in `RNNBottomTabsController` and corresponding `Options.ts` surface.\n\n### 4. UITabBarController.bottomAccessory\nPersistent floating mini-control attached above the tab bar (e.g., Apple Music's now-playing bar).\n\n- `UITabBarController.bottomAccessory: UITabAccessory?`\n- `UITabAccessory(contentView:)` — wraps a UIView.\n- Apple: [UITabAccessory](https://developer.apple.com/documentation/uikit/uitabaccessory)\n\n**RNN handling:** Not yet exposed. Would need a new option (e.g., `bottomTabs.accessory: { component: { name, ... } }`) and a presenter to mount a React view inside a `UITabAccessory`.\n\n### 5. Scroll-edge appearance and effects\niOS 26 makes `scrollEdgeAppearance` matter more (the bar fades to transparent when scrolled to the top). New `scrollEdgeEffect` on `UINavigationItem` controls the effect.\n\n- `UINavigationItem.scrollEdgeEffect` — controls the fading/glass effect at scroll edges.\n- `UINavigationBar.scrollEdgeAppearance` — appearance when at the scroll edge.\n- `UITabBar.scrollEdgeAppearance` — same for tab bar.\n- Apple: [UIScrollEdgeEffect](https://developer.apple.com/documentation/uikit/uiscrolledgeeffect) (iOS 26)\n\n**RNN handling:**\n- `scrollEdgeAppearance` exposed via top bar options — see `website/docs/api/options-scrollEdgeAppearance.mdx`.\n- iOS 26 `scrollEdgeEffect` added in PR #8281 (`Add scrollEdgeEffect option`).\n- Title customization on scroll edge: PRs #8207, #8239.\n\n### 6. Search bar placement (UINavigationItemSearchBarPlacement)\niOS 26 introduces three placements:\n\n- `UINavigationItemSearchBarPlacementStacked` — under the title, classic.\n- `UINavigationItemSearchBarPlacementIntegrated` — inline with the title bar, expanded.\n- `UINavigationItemSearchBarPlacementIntegratedButton` — collapsed to a button until tapped.\n\nProperty: `UINavigationItem.preferredSearchBarPlacement`. Availability-gated, not present pre-iOS-26.\n\n**RNN handling:**\n- `ios/RNNSearchBarPlacement.mm` / `.h` — JS-facing enum.\n- `ios/UIViewController+RNNOptions.mm` (`setSearchBar...`): maps RNN's `SearchBarPlacementIntegrated` to integrated or integrated-button depending on `focus`. Falls through to stacked otherwise.\n- PR #8211 — skip integrated placement when not available (pre-26 safety).\n\n### 7. Shared background (\"Platter\") on bar button items\niOS 26 wraps every `UIBarButtonItem` in a shared Liquid Glass platter. Custom views and pre-styled `UIButton`s get double-decorated.\n\n- `UIBarButtonItem.hidesSharedBackground: Bool` — opt out of the platter.\n- Custom views need a fixed bar-item size (44pt) so the navbar reserves the slot before React mounts the content; otherwise the navbar relayouts after mount and the custom view snaps into place.\n\n**RNN handling:**\n- `ios/RNNUIBarButtonItem.mm`: defaults `hidesSharedBackground = YES` on iOS 26 for both icon buttons and custom (React) view buttons. Pins custom view to 44x44.\n- `ios/RNNReactButtonView.mm`: width/height constraints + center translation post-mount to keep the React view aligned inside the reserved 44pt slot.\n- New option: `RNNButtonOptions.hideSharedBackground` (also on `RNNBackButtonOptions`) — see `src/interfaces/Options.ts`.\n- PR #8300 — centering fix.\n\n### 7a. `UIBarButtonItemGroup` factory APIs and prominent style (iOS 26)\n\niOS 26 added direct factories on `UIBarButtonItem` that build groups inline. These are the cleanest way to make the shared platter intentional rather than relying on UIKit's implicit clustering.\n\n```\nUIBarButtonItem.creatingFixedGroup() -> UIBarButtonItemGroup\nUIBarButtonItem.creatingMovableGroup(customizationIdentifier:) -> UIBarButtonItemGroup\nUIBarButtonItem.creatingOptionalGroup(customizationIdentifier:isInDefaultCustomization:) -> UIBarButtonItemGroup\n```\n\nPlus a new style:\n\n- `UIBarButtonItem.style = .prominent` — primary-action styling, tints the platter with the bar's `tintColor` at full saturation. Use sparingly (one prominent item per bar).\n\nWhen grouping is intentional, UIKit renders the group under a single `_UIBarItemGroupPlatter` (see §7b/§9) instead of one platter per item. `hidesSharedBackground` still applies per item, so you can mix glassed and bare items inside one group.\n\n**RNN handling:** Not exposed today. If a future option models a logical action cluster, build it as a `UIBarButtonItemGroup` rather than a sequence of items so the platter coalesces correctly.\n\nReferences:\n- [`UIBarButtonItemGroup`](https://developer.apple.com/documentation/uikit/uibarbuttonitemgroup)\n- [`UIBarButtonItem.Style`](https://developer.apple.com/documentation/uikit/uibarbuttonitem/style)\n\n### 7b. Internal view hierarchy: `UIBarButtonItem` on iOS 26\n\n`UIBarButtonItem` is **not a `UIView`** — it's a model object. UIKit materializes it into a private view hierarchy inside the parent `UINavigationBar` or `UIToolbar`. The exact class names are private and can change; the **layering and ordering are stable** and worth knowing for layout debugging.\n\nApproximate structure for a single bar button item (Liquid Glass, iOS 26):\n\n```\nUINavigationBar / UIToolbar\n└── _UIBarBackground               (bar-wide background, Liquid Glass material)\n└── _UIButtonBarStackView          (horizontal stack of items, leading or trailing group)\n    └── _UIModernBarButton         (host view per item; one per UIBarButtonItem)\n        ├── _UIBarItemPlatter      (shared Liquid Glass background; the \"platter\")\n        │   └── CAFilter / glass layers (UIGlassEffect-backed)\n        └── content view           (image, title label, OR customView)\n```\n\nKey facts that affect RNN code:\n\n- **The platter is per-item by default**, but adjacent items inside the same `UIBarButtonItemGroup` (or implicit leading/trailing cluster) can be coalesced into a **single shared platter** spanning several items. This is the \"shared background\" that `hidesSharedBackground` opts out of.\n- **`hidesSharedBackground = YES`** removes the `_UIBarItemPlatter` from the host view; the content view becomes the direct child of `_UIModernBarButton`. The host view is **still 44pt minimum**.\n- **The host view (`_UIModernBarButton`) reserves the slot**, not the customView. UIKit sizes the host using:\n  - System images: intrinsic size of the symbol + padding.\n  - Title-only items: text width + padding.\n  - **Custom views: the customView's intrinsic content size at the time the bar performs layout.** This is why RNN pins the custom React view to 44×44 in `RNNUIBarButtonItem.mm` — without explicit constraints, React mounts asynchronously, the customView's intrinsic size starts at zero, the host reserves zero width, the bar lays out, then React reports its real size and the host has to relayout. The visible artifact is the button \"popping in\" or being misplaced after the push transition's snapshot already captured the wrong frame.\n- **Transitions snapshot the bar.** During push/pop, UIKit takes a snapshot of the navigation bar for the cross-fade between the from/to nav items. If the customView hasn't laid out before the snapshot, the snapshot shows the wrong state. This is also why a React customView can appear blank during a transition while being fine on the destination screen.\n- **Tinting flows through the platter, not the customView.** `tintColor` set on the bar item or bar applies to the system image inside the host view; it does not propagate into a React customView. Color the React content explicitly.\n\nPractical debugging:\n\n- Inspect the live hierarchy with `po [self.navigationItem.rightBarButtonItems.firstObject valueForKey:@\"_view\"]` in lldb, or with View Debugger → uncheck \"Show layers only\" to see the private classes.\n- A button that's \"there but invisible\" usually means the host view has 0×0 frame (sizing race) or `hidesSharedBackground = NO` with a customView that paints its own chrome (double-decoration clips/overlaps).\n- A button that \"snaps into place\" after the screen appears means the host view's intrinsic size changed after the bar's first layout pass.\n\nReferences (public API only — internals are observed, not documented):\n- [`UIBarButtonItem`](https://developer.apple.com/documentation/uikit/uibarbuttonitem)\n- [`UIBarButtonItem.hidesSharedBackground`](https://developer.apple.com/documentation/uikit/uibarbuttonitem/hidessharedbackground)\n- [`UIBarButtonItemGroup`](https://developer.apple.com/documentation/uikit/uibarbuttonitemgroup)\n\n### 8. Tab bar minimize behavior (iOS 26)\nThe tab bar can auto-minimize during scroll.\n\n- `UITabBarController.tabBarMinimizeBehavior` — `.automatic`, `.never`, `.onScrollDown`, `.onScrollUp`.\n- `setNeedsUpdateOfTabBarMinimizeBehavior()` — re-evaluate.\n- Apple: [UITabBarController](https://developer.apple.com/documentation/uikit/uitabbarcontroller)\n\n**RNN handling:** Not yet exposed. Would be a new option on `bottomTabs`.\n\n### 9. `UIToolbar` on iOS 26\n\n`UIToolbar` is a real `UIView` (unlike `UIBarButtonItem`). Approximate internal hierarchy on iOS 26:\n\n```\nUIToolbar\n├── _UIBarBackground                  (bar-wide Liquid Glass material;\n│                                      configured via UIToolbarAppearance)\n│   └── _UIBackdropView / glass layers\n│   └── _UIBarBackgroundShadowView    (1pt hairline; controlled by shadowImage / shadowColor)\n└── _UIToolbarContentView\n    └── _UIButtonBarStackView         (horizontal stack of toolbar items)\n        ├── _UIModernBarButton        (item host — see 7b for layer breakdown)\n        ├── _UIModernBarButton\n        ├── ... fixed/flexible spaces become layout gaps in the stack ...\n        └── (optional) _UIBarItemGroupPlatter\n              └── two or more _UIModernBarButton sharing one platter\n                  (only when items are in the same UIBarButtonItemGroup)\n```\n\nWhat's actually public and load-bearing on iOS 26:\n\n- **Appearance objects are the only safe way to style.** `UIToolbarAppearance` (standard / compact / scrollEdge) drives `_UIBarBackground`. Setting `barTintColor` / `backgroundImage` on `UIToolbar` directly is **silently overridden** by Liquid Glass unless `appearance.backgroundEffect = nil`.\n- **Translucency is the default.** `configureWithDefaultBackground` on iOS 26 produces glass. To get an opaque fill: `configureWithOpaqueBackground` **plus** `backgroundEffect = nil` **plus** explicit `backgroundColor`. This mirrors what `BottomTabsAppearancePresenter.mm` does for the tab bar.\n- **Items follow the same Platter rules as nav bar buttons.** A custom view in a toolbar item gets wrapped in a platter unless `hidesSharedBackground = YES`. The 44pt host-view sizing race applies identically.\n- **Grouping with `UIBarButtonItemGroup`** lets adjacent items render under one shared platter (visually grouped pill). `customizationIdentifier` opts the toolbar into the user-customization sheet (iPadOS).\n- **`scrollEdgeAppearance` matters here too.** When a scroll view is attached, the toolbar fades to transparent at the scroll edge using `UIToolbar.scrollEdgeAppearance`. Pre-iOS-26 this was iPad-only for many cases; iOS 26 applies it consistently.\n\nDisplay mode and customization (iOS 26 / iPadOS 26):\n\n- `UIToolbar.displayMode` — `.automatic`, `.expanded`, `.compact`. Drives whether items spread out or collapse into an overflow menu.\n- `UIBarButtonItem.menuRepresentation` — the menu UIKit shows when the item is hoisted into the overflow control under `.compact`.\n- `UIToolbar.beginCustomizingItems(...)` / `endCustomizingItems` — programmatic entry into the user-customization sheet for movable/optional groups.\n\nRNN handling:\n\nRNN does not expose `UIToolbar` as a first-class options surface today. Toolbar-shaped behavior in this repo comes from the navigation controller's bottom bar via `RNNStackController` and is configured indirectly through stack options. Any new toolbar feature should:\n\n1. Add a presenter (e.g. `ToolbarPresenter`) mirroring `TopBarPresenter`'s appearance pattern.\n2. Configure via `UIToolbarAppearance` only — never direct `barTintColor` / `backgroundImage`.\n3. Use `UIBarButtonItemGroup` when the option models a logical cluster (e.g. \"primary actions\") so the platter coalesces correctly.\n4. Apply `hidesSharedBackground` defaults for React custom views, same as `RNNUIBarButtonItem.mm` does today.\n\nReferences:\n- [`UIToolbar`](https://developer.apple.com/documentation/uikit/uitoolbar)\n- [`UIToolbarAppearance`](https://developer.apple.com/documentation/uikit/uitoolbarappearance)\n- [`UIBarButtonItemGroup`](https://developer.apple.com/documentation/uikit/uibarbuttonitemgroup)\n- WWDC25: \"What's new in UIKit\" (toolbar/group section), \"Build a UIKit app with the new design\"\n\n### 10. Preferred transition\n- `UINavigationController.preferredTransition` — control push/pop animation style (iOS 26 expansion).\n- `UIViewController.preferredTransition` — zoom transitions.\n\n**RNN handling:** Not exposed. Stack push/pop currently uses defaults.\n\n### 11. SF Symbols 7\niOS 26 ships SF Symbols 7. Bar buttons that use system images get the new variants automatically. Custom symbol configurations should re-test on iOS 26.\n\nAnimated symbols are part of the iOS 26 bar story:\n\n- `NSSymbolEffect` family — `.bounce`, `.pulse`, `.variableColor`, `.replace`, `.breathe`, `.scale`, `.appear`, `.disappear`, `.wiggle` (iOS 18+; new variants in 26).\n- Apply via the bar item's image: configure `UIImageView` produced by UIKit, or use `UIView.addSymbolEffect(_:options:animated:)` on the host view returned by `UIBarButtonItem.value(forKey: \"_view\")` (private — prefer using `UIButton` with a configured image inside a custom bar item).\n- WWDC25: \"What's new in SF Symbols 7\".\n\n### 12. `UIButton` glass configurations\n`UIButton.Configuration` got first-class glass factories in iOS 26. Anything RNN renders that's *not* a bar button (custom views inside a screen, overlays, modal headers, bottom accessories) should adopt these instead of hand-rolling chrome.\n\n```\nUIButton.Configuration.glass()           — translucent Liquid Glass pill\nUIButton.Configuration.prominentGlass()  — tinted, more saturated variant\nUIButton.Configuration.plain()\nUIButton.Configuration.gray()\nUIButton.Configuration.tinted()\nUIButton.Configuration.filled()\nUIButton.Configuration.borderless()\n```\n\nOn iOS 26 the legacy configurations (`plain` / `gray` / `tinted` / `filled` / `borderless`) automatically repaint with the Liquid Glass material — you don't opt in, you opt *out* via `UIDesignRequiresCompatibility`.\n\nConfiguration knobs that affect build-up:\n- `cornerStyle` — `.fixed` / `.dynamic` / `.capsule` / `.small` / `.medium` / `.large`. `.dynamic` adopts concentric corners (see §15).\n- `buttonSize` — `.mini` / `.small` / `.medium` / `.large`.\n- `baseBackgroundColor` / `baseForegroundColor` — tint multiplier on glass.\n\nApproximate internal hierarchy for a configuration-based button on iOS 26:\n\n```\nUIButton (configuration-based)\n├── _UIButtonBackgroundView         (the platter / glass body)\n│   ├── UIVisualEffectView          (UIGlassEffect — see §13)\n│   └── tint overlay (CALayer)\n└── _UIButtonContentStackView\n    ├── UIImageView                 (leading or trailing image)\n    ├── UILabel                     (title)\n    └── UILabel                     (subtitle, when set)\n```\n\n**RNN handling:** Not exposed as an option today. RNN doesn't render its own button chrome inside screens — that's the React side's job — but if RNN ever needs a system-styled control (e.g. a \"Done\" button on a custom modal header it builds natively), use `UIButton.Configuration.glass()` rather than custom drawing.\n\nReferences:\n- [`UIButton.Configuration`](https://developer.apple.com/documentation/uikit/uibutton/configuration)\n- [`UIButton.Configuration.glass()`](https://developer.apple.com/documentation/uikit/uibutton/configuration/glass())\n\n### 13. `UIGlassEffect` and `UIGlassContainerEffect` (public Liquid Glass API)\n\nThe entire Liquid Glass material is exposed publicly. This is the API to use whenever RNN needs custom glass chrome — floating overlays, bottom accessories, custom navigation extensions, modal grabbers.\n\n```\nUIGlassEffect                        — UIVisualEffect subclass\nUIGlassEffect.Style.regular          — default frosted glass\nUIGlassEffect.Style.clear            — thinner, more transparent variant\nUIGlassEffect.tintColor              — multiplied tint\nUIGlassContainerEffect               — wraps multiple glass views; they morph/merge when adjacent\nUIVisualEffectView(effect: UIGlassEffect())  — host\n```\n\nBehavioral rules:\n- Glass **refracts and blurs** content behind it; opacity is content-derived, not a static color.\n- Two `UIVisualEffectView`s with `UIGlassEffect` placed inside the same `UIGlassContainerEffect` will **visually merge** into a single platter when they touch or overlap. This is what produces the \"morphing\" you see when a search bar collapses into a button, or when tabs minimize into a single pill.\n- `tintColor` is **multiplied**, not painted — fully saturated colors look pastel. Use bold colors only when you want a noticeably tinted glass.\n- Glass adapts to dark / light mode automatically; do not hand-set background colors on the visual effect view.\n\nBuild-up:\n\n```\nUIVisualEffectView (effect: UIGlassEffect)\n├── _UIVisualEffectBackdropView      (CAFilter blur + refraction)\n├── _UIVisualEffectSubview           (tint overlay)\n└── contentView                      (your content; goes here, not on the effect view directly)\n```\n\n**RNN handling:** Not used yet. Any future custom chrome (e.g. a `bottomAccessory` host, a custom modal grabber, a floating action overlay) should be a `UIVisualEffectView` with `UIGlassEffect`, **not** a `UIView` with a manually configured `UIBlurEffect`. Pre-iOS-26 RNN can fall back to `UIBlurEffectStyle.systemMaterial` via the existing availability pattern.\n\nReferences:\n- [`UIGlassEffect`](https://developer.apple.com/documentation/uikit/uiglasseffect)\n- [`UIGlassContainerEffect`](https://developer.apple.com/documentation/uikit/uiglasscontainereffect)\n- [`UIVisualEffectView`](https://developer.apple.com/documentation/uikit/uivisualeffectview)\n- WWDC25: \"Meet Liquid Glass\"\n\n### 14. `UINavigationItem.style` — navigator / browser / editor\n\niOS 26 introduces three navigation item styles that reshape the entire navigation bar's internal layout. This is one of the bigger build-up changes in 26.\n\n```\nUINavigationItem.Style.navigator     — default; classic nav title + leading/trailing items\nUINavigationItem.Style.browser       — URL-bar-like layout with a centered integrated field\nUINavigationItem.Style.editor        — document editor; renamable title + subtitle + badge\n```\n\nRelated properties (only meaningful when `style` ≠ `.navigator`):\n\n- `UINavigationItem.documentProperties: UIDocumentProperties?` — file URL, subtitle, badge displayed in editor style.\n- `UINavigationItem.renameDelegate` — inline rename UI for editor style.\n- `UINavigationItem.titleMenuProvider` — context menu when tapping the title (iOS 16+, but actually visible by default in browser/editor styles on 26).\n\nHow the build-up changes:\n\n- `.navigator` — standard `_UINavigationBarContentView` with title label centered.\n- `.browser` — `_UINavigationBarContentView` swaps the title slot for an integrated URL field (`UISearchTextField`-shaped), with leading and trailing item clusters under shared platters.\n- `.editor` — adds a vertical stack: title (renamable) + subtitle (file path) + badge, plus a primary action slot at the trailing edge.\n\n**RNN handling:** Not exposed. A future RNN option could surface `topBar.style: 'navigator' | 'browser' | 'editor'`. Editor style is the more interesting one for document-shaped apps; browser style fits Wix preview-style flows.\n\nReferences:\n- [`UINavigationItem.Style`](https://developer.apple.com/documentation/uikit/uinavigationitem/style)\n- [`UIDocumentProperties`](https://developer.apple.com/documentation/uikit/uidocumentproperties)\n- WWDC25: \"Build a UIKit app with the new design\"\n\n### 15. `UICornerConfiguration` and concentric corners\n\nConcentric corners are a foundational iOS 26 design rule: a child element's corner radius should equal its parent's radius minus the inset, so curves stay visually parallel. Apple's own bar items, sheets, and buttons obey this; mixing fixed `cornerRadius` with a concentric container looks visibly wrong on 26.\n\n```\nUICornerConfiguration.uniformCornerRadius(_:)            // fixed radius\nUICornerConfiguration.uniformCornerConfiguration(_:)     // with corner style (capsule, etc.)\nUICornerConfiguration.concentric(minimum:)               // matches parent's curvature, floored at minimum\nUIView.cornerConfiguration: UICornerConfiguration?       // applies to the view's layer\n```\n\nRule of thumb: anything painted **inside** a glass element should be `.concentric(minimum: small)` rather than `.uniformCornerRadius(N)`. The system already uses concentric corners for bar item platters, sheet corners that morph with the device screen radius, and tab bar item shapes.\n\n**RNN handling:** Not exposed. Any future RNN-native custom chrome that nests inside a glass element (e.g. a React custom view sitting inside an iOS 26 platter that RNN draws) should apply `.cornerConfiguration = .concentric(...)` on the wrapping UIView so it inherits the platter's curvature.\n\nReferences:\n- [`UICornerConfiguration`](https://developer.apple.com/documentation/uikit/uicornerconfiguration)\n- [`UIView.cornerConfiguration`](https://developer.apple.com/documentation/uikit/uiview/cornerconfiguration)\n\n### 16. `UISheetPresentationController` iOS 26 changes\n\nRNN modals route through `UISheetPresentationController` when configured. iOS 26 changes its presentation in three meaningful ways:\n\n- **`cornerConfiguration`** replaces `preferredCornerRadius` for finer control. Sheets can now have asymmetric corners and use `.concentric(minimum:)` to match the device's screen radius — the result is the visible \"corner morph\" when the sheet animates from the small detent to medium/large.\n- **Default detents changed.** The small detent now overlaps the safe area more gracefully because the corner configuration animates with the detent height. Custom detents (`UISheetPresentationController.Detent.custom`) need to play nicely with this.\n- **Sheets slide *under* the floating tab bar by default.** Pre-iOS-26 the tab bar pushed the sheet up; on 26 the sheet's small detent extends behind the tab bar. If a sheet must avoid covering the tab bar, opt out by configuring the detent height explicitly or by presenting from a context that excludes the tab bar.\n\nRelated: `UISheetPresentationController.prefersGrabberVisible` still controls the grabber; the grabber now uses Liquid Glass material.\n\n**RNN handling:** RNN exposes modal presentation through stack options. iOS 26 sheet behavior surfaces automatically through UIKit defaults — but the \"sheet over tab bar\" change can visually regress apps that expected the pre-26 layout. If users report it, the fix is to adjust the detent or presentation context, not to fight UIKit.\n\nReferences:\n- [`UISheetPresentationController`](https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller)\n- WWDC25: \"What's new in UIKit\" (sheet section)\n\n---\n\n## Workflow: adding iOS 26 support for a new API\n\n1. **Confirm the Apple API surface.** Read the relevant `developer.apple.com` page; check WWDC25 sessions for sample patterns.\n2. **Pick the RNN seam.** Use the mapping above. Top bar → `TopBarPresenter` + `RNNTopBarOptions`. Bottom tab → `BottomTabsAppearancePresenter` / `RNNBottomTabsController` + `RNNBottomTabsOptions`. Bar buttons → `RNNUIBarButtonItem` + `RNNButtonOptions`.\n3. **Add the JS option** in `lib/src/interfaces/Options.ts`. Document semantics, iOS-only marker, iOS 26 minimum.\n4. **Parse it** in the matching `*Options.mm` (use the existing `[XParser parse:dict key:@\"...\"]` pattern). Add to `mergeOptions:`.\n5. **Apply it** in the presenter, **always guarded** by `if (@available(iOS 26.0, *)) { ... }`. Honor `UIDesignRequiresCompatibility` if behavior would diverge for legacy-design apps.\n6. **Add a playground screen** in `playground/src/screens/` exercising the option, both visible and toggle states.\n7. **Add an e2e** in `playground/e2e/` using `device.getPlatform() === 'ios'` and an iOS version check. Follow existing baseline-then-action screenshot patterns.\n8. **Update docs** in `website/docs/api/options-*.mdx`.\n9. **Build Release** with Xcode 26.1, run on iPhone 17 Pro Max simulator, then **also** verify on an iOS 18 simulator for regression.\n\n## Workflow: investigating an iOS 26 regression\n\n1. Reproduce in Release on iOS 26 sim. Reproduce on iOS 18/17 — confirm it's 26-only.\n2. Grep `if (@available(iOS 26.0, *))` and the property name (e.g. `backgroundEffect`, `hidesSharedBackground`, `preferredSearchBarPlacement`) — see if RNN already has a branch.\n3. Check recent PRs touching the same file (`git log --oneline -- ios/<file>.mm | head -20`) — most iOS 26 regressions cluster.\n4. Check `UIDesignRequiresCompatibility`: if the bug only happens with the new design, the fix must not break compatibility mode.\n5. Confirm Fabric / New Architecture is still on (don't disable it to \"fix\" something).\n6. Before changing code, summarize the hypothesis and proposed fix to the user (per user rule \"show me first\").\n\n---\n\n## Known iOS 26 trouble spots in this repo\n\n| Area | File(s) | Last touched PR(s) |\n|------|---------|-------------------|\n| Custom React bar buttons (Platter, centering, lifecycle) | `RNNUIBarButtonItem.mm`, `RNNReactButtonView.mm` | #8300 |\n| Tab item title misplaced on first layout | `RNNBottomTabsController.mm` (`rnn_cycleAllTabsThenRestoreInitialSelection`) | #8245, #8254, #8255 |\n| Tab bar background color / glass | `BottomTabsAppearancePresenter.mm` | #8263, #8288 |\n| Search bar placement | `UIViewController+RNNOptions.mm`, `RNNSearchBarPlacement.mm` | #8183, #8211 |\n| Scroll edge effect on top bar | top bar options | #8281, #8239, #8207 |\n| iPad back navigation (iOS 26) | nav controller | #8277 |\n| `drawBehind` default on floating tab bar | `RNNBottomTabsOptions.mm` (`-shouldDrawBehind`) | — |\n\n---\n\n## Authoritative references\n\n- HIG: [Designing for iOS 26](https://developer.apple.com/design/human-interface-guidelines/designing-for-ios), [Materials (Liquid Glass)](https://developer.apple.com/design/human-interface-guidelines/materials), [Tab bars](https://developer.apple.com/design/human-interface-guidelines/tab-bars), [Navigation bars](https://developer.apple.com/design/human-interface-guidelines/navigation-bars), [Toolbars](https://developer.apple.com/design/human-interface-guidelines/toolbars)\n- API (bars and tabs): [UITabBarController](https://developer.apple.com/documentation/uikit/uitabbarcontroller), [UITab](https://developer.apple.com/documentation/uikit/uitab), [UITabAccessory](https://developer.apple.com/documentation/uikit/uitabaccessory), [UINavigationItem](https://developer.apple.com/documentation/uikit/uinavigationitem), [UINavigationItem.Style](https://developer.apple.com/documentation/uikit/uinavigationitem/style), [UIBarButtonItem.hidesSharedBackground](https://developer.apple.com/documentation/uikit/uibarbuttonitem/hidessharedbackground), [UIBarButtonItemGroup](https://developer.apple.com/documentation/uikit/uibarbuttonitemgroup), [UIScrollEdgeEffect](https://developer.apple.com/documentation/uikit/uiscrolledgeeffect), [UIBarAppearance](https://developer.apple.com/documentation/uikit/uibarappearance), [UIToolbar](https://developer.apple.com/documentation/uikit/uitoolbar)\n- API (glass and shapes): [UIGlassEffect](https://developer.apple.com/documentation/uikit/uiglasseffect), [UIGlassContainerEffect](https://developer.apple.com/documentation/uikit/uiglasscontainereffect), [UICornerConfiguration](https://developer.apple.com/documentation/uikit/uicornerconfiguration), [UIButton.Configuration](https://developer.apple.com/documentation/uikit/uibutton/configuration), [UIButton.Configuration.glass()](https://developer.apple.com/documentation/uikit/uibutton/configuration/glass())\n- API (presentation): [UISheetPresentationController](https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller), [UIDocumentProperties](https://developer.apple.com/documentation/uikit/uidocumentproperties)\n- WWDC25: \"Meet Liquid Glass\", \"Get to know the new design system\", \"What's new in UIKit\", \"Build a UIKit app with the new design\", \"Elevate your tab and sidebar experience\", \"Make your UIKit app more flexible\", \"What's new in SF Symbols 7\"\n- Compatibility: [UIDesignRequiresCompatibility](https://developer.apple.com/documentation/bundleresources/information-property-list/uidesignrequirescompatibility)\n",".cursor/skills/rnn-codebase/SKILL.md":"---\nname: rnn-codebase\ndescription: Navigate and work with the react-native-navigation (RNN) codebase. Use when fixing bugs, adding features, tracing command flows, understanding options resolution, or working across JS/iOS/Android layers in this repo.\n---\n\n# React Native Navigation Codebase\n\n## Architecture Overview\n\nRNN has three layers that mirror each other:\n\n```\nJS/TS (src/)  →  TurboModule bridge  →  iOS native (ios/)\n                                     →  Android native (android/)\n```\n\nA navigation command (e.g. `push`) flows:\n1. `Navigation.push()` → `Commands.ts` → processing pipeline → `NativeCommandsSender.ts`\n2. TurboModule: `RNNTurboModule` (iOS) / `NavigationTurboModule.kt` (Android)\n3. iOS: `RNNCommandsHandler` → `RNNViewControllerFactory` → UIKit controllers\n4. Android: `Navigator` → `LayoutFactory` → View-based controllers (no Fragments)\n\nRead [ARCHITECTURE.md](../../ARCHITECTURE.md) for the full overview.\n\n## Key Cross-Layer Mappings\n\n### Layout Types → Native Controllers\n\n| JS Layout Type | iOS Controller | Android Controller |\n|----------------|---------------|-------------------|\n| `component` | `RNNComponentViewController` | `ComponentViewController` |\n| `stack` | `RNNStackController` (UINavigationController) | `StackController` |\n| `bottomTabs` | `RNNBottomTabsController` (UITabBarController) | `BottomTabsController` |\n| `sideMenu` | `RNNSideMenuViewController` (MMDrawerController) | `SideMenuController` (DrawerLayout) |\n| `topTabs` | `RNNTopTabsViewController` | `TopTabsController` (ViewPager) |\n| `splitView` | `RNNSplitViewController` | N/A (iOS only) |\n| `externalComponent` | `RNNExternalViewController` | `ExternalComponentViewController` |\n\n### Options → Presenters\n\nEach controller type has a Presenter that applies options to views:\n\n| iOS Controller | iOS Presenter | Android Presenter |\n|----------------|--------------|-------------------|\n| `RNNComponentViewController` | `RNNComponentPresenter` | `ComponentPresenter` |\n| `RNNStackController` | `RNNStackPresenter` + `TopBarPresenter` | `StackPresenter` |\n| `RNNBottomTabsController` | `RNNBottomTabsPresenter` | `BottomTabsPresenter` |\n| `RNNSideMenuViewController` | `RNNSideMenuPresenter` | `SideMenuPresenter` |\n\n### Events (same names both platforms)\n\n| Event | Trigger |\n|-------|---------|\n| `RNN.ComponentDidAppear` | Screen becomes visible |\n| `RNN.ComponentDidDisappear` | Screen hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tap |\n| `RNN.BottomTabSelected` | Tab changed |\n| `RNN.ModalDismissed` | Modal dismissed |\n| `RNN.ScreenPopped` | Screen popped from stack |\n| `RNN.CommandCompleted` | Any command finished |\n\n## Where to Find Things\n\n### By task: \"I need to fix/change X\"\n\n| Task | JS File(s) | iOS File(s) | Android File(s) |\n|------|-----------|------------|----------------|\n| Command execution | `src/commands/Commands.ts` | `ios/RNNCommandsHandler.mm` | `react/NavigationTurboModule.kt` |\n| Layout creation | `src/commands/LayoutTreeParser.ts` | `ios/RNNViewControllerFactory.mm` | `options/LayoutFactory.java` |\n| Options processing | `src/commands/OptionsProcessor.ts` | `ios/RNNNavigationOptions.mm` | `options/Options.java` |\n| Options application | — | `ios/*Presenter.mm` | `viewcontrollers/*Presenter.java` |\n| TopBar | `src/interfaces/Options.ts` (TopBarOptions) | `ios/TopBarPresenter.mm`, `ios/RNNUIBarButtonItem.mm` | `views/stack/topbar/` |\n| Bottom tabs | `src/interfaces/Options.ts` (BottomTabsOptions) | `ios/RNNBottomTabsPresenter.mm` | `viewcontrollers/bottomtabs/` |\n| Modals | `src/commands/Commands.ts` | `ios/RNNModalManager.mm` | `viewcontrollers/modal/ModalStack.java` |\n| Overlays | `src/commands/Commands.ts` | `ios/RNNOverlayManager.mm` | `viewcontrollers/overlay/OverlayManager.kt` |\n| Animations | `src/interfaces/Options.ts` (AnimationOptions) | `ios/ScreenAnimationController.mm` | `viewcontrollers/stack/StackAnimator.kt` |\n| React view rendering | — | `ios/RNNReactView.mm` | `react/ReactView.java` |\n| Events to JS | `src/adapters/NativeEventsReceiver.ts` | `ios/RNNEventEmitter.mm` | `react/events/EventEmitter.java` |\n| Component registration | `src/components/ComponentRegistry.ts` | — | — |\n\n### By directory\n\n- **`src/`** — JS public API, commands, processing pipeline. See [src/ARCHITECTURE.md](../../src/ARCHITECTURE.md)\n- **`ios/`** — All Obj-C/C++ native code. See [ios/ARCHITECTURE.md](../../ios/ARCHITECTURE.md)\n- **`ios/TurboModules/`** — New architecture entry points (`RNNTurboModule`, `RNNTurboManager`, `RNNTurboCommandsHandler`)\n- **`android/src/main/java/com/reactnativenavigation/`** — All Java/Kotlin native code. See [android/ARCHITECTURE.md](../../android/ARCHITECTURE.md)\n- **`playground/`** — Demo app for development and E2E tests\n- **`playground/src/screens/`** — Test screens exercising every feature\n- **`playground/e2e/`** — Detox E2E tests\n\n## Options Resolution Order\n\nOptions are applied in ascending priority:\n1. Default options (from `Navigation.setDefaultOptions()`) — lowest priority\n2. Static options (from component class or `Navigation.registerComponent`)\n3. Options passed in the layout call (e.g. `push`, `setRoot`)\n4. `mergeOptions()` — runtime override, highest priority\n\n## JS Processing Pipeline (exact order)\n\n```\nAPI layout → OptionsCrawler.crawl() → LayoutProcessor.process()\n  → LayoutTreeParser.parse() → LayoutTreeCrawler.crawl()\n  → OptionsProcessor (colors, assets, custom) → NativeCommandsSender\n```\n\n## iOS Patterns\n\n- All controllers conform to `RNNLayoutProtocol`\n- `RNNBasePresenter` subclasses apply options — `applyOptionsOnInit:`, `applyOptions:`, `mergeOptions:resolvedOptions:`\n- Commands run on main thread (`RCTExecuteOnMainQueue`)\n- React views: `RNNReactView` wraps `RCTSurfaceHostingView` (new arch)\n- Overlays use separate `UIWindow` instances (`RNNOverlayWindow`)\n- `RNNReactComponentRegistry` caches React component instances\n\n## Android Patterns\n\n- View-based, NOT Fragment-based\n- All commands dispatched via `UiThread.post()`\n- `ViewController<T extends ViewGroup>` is the base — `createView()` is abstract\n- `ParentController` extends `ChildController` extends `ViewController`\n- Bottom tabs use `AHBottomNavigation` library\n- Three root layouts in `NavigationActivity`: rootLayout, modalsLayout, overlaysLayout\n- Tab attachment modes: `Together`, `OnSwitchToTab`, `AfterInitialTab`\n\n## Development Workflow\n\n### Playground app\n- `yarn start` — Metro bundler\n- `yarn xcode` — Open iOS project\n- `yarn studio` — Open Android project\n- `yarn pod-install` — Install iOS pods\n\n### Testing\n- `yarn test-js` — Jest unit tests\n- `yarn test-unit-ios` — iOS native unit tests (XCTest)\n- `yarn test-unit-android` — Android native unit tests (JUnit + Robolectric)\n- `yarn test-e2e-ios-ci` / `yarn test-e2e-android-ci` — Detox E2E tests\n\n### Building\n- `yarn prepare` — Builds `src/` → `lib/` (ESM + types)\n- Codegen config: `rnnavigation` in `package.json`\n\n## Engine Integration (Wix One App)\n\nRNN is a standalone library but also a core dependency of `mobile-apps-engine` (the Wix One App platform). Changes to RNN's public API surface can break engine.\n\n### Version Management\n\n- Version pinned in two files (must match):\n  - `packages/native/mobile-apps-engine-native/package.json`\n  - `packages/wix-one-app-storage/package.json`\n- `yarn.config.cjs` has a constraint that reads the version from `mobile-apps-engine-native` and validates all workspaces use the same version. It's a validation rule — bumping the native package.json is sufficient.\n\n### iOS Integration\n\n- Engine's `AppDelegate` subclasses `RNNAppDelegate` — breaking changes to that class will break engine.\n- Podfile resolves `ReactNativeNavigation` pod from node_modules.\n- Xcode project has header search paths pointing into `node_modules/react-native-navigation/ios/**`.\n\n### Android Integration\n\n- Engine's `EngineRN.kt` extends `NavigationApplication` and uses `NavigationPackage` / `NavigationReactNativeHost`.\n- `missingDimensionStrategy \"RNN.reactNativeVersion\"` is set in `app/build.gradle` — may need updating if RNN changes its flavor dimensions.\n- Build variables `RNNKotlinVersion`, `RNNKotlinStdlib`, `RNNKotlinCoroutinesCore` are forwarded from engine's Kotlin config.\n\n### Active Patches (in engine's setup)\n\n- **OptionsProcessor.js** — engine replaces RNN's `OptionsProcessor.js` at setup time via `patchRNNOptionsProcessor()` in `packages/cli/mobile-apps-engine-setup/src/index.js`. The patched copy lives at `packages/cli/mobile-apps-engine-setup/etc/OptionsProcessor.js`. It adds:\n  - Custom iOS color processing with `DynamicColorIOS` (dark/light/dynamic object shapes)\n  - Custom Android color processing wrapping colors in `{dark, light}` objects with `semantic`/`resource_paths` support\n  - Component ID uses `value.name` instead of `uniqueIdProvider.generate()`\n- Any changes to `src/commands/OptionsProcessor.ts` require checking if the engine patch needs updating.\n\n### JS Wrappers\n\nEngine wraps RNN's `Navigation` API in several services:\n- `Navigator.ts` — root layout, overlays, error screens, tab navigation\n- `BottomTabsBackHandler.ts` — back handling on bottom tabs via `Navigation.events()`\n- `TabsManager.ts` — tab management using RNN `Layout` types\n- Various other services import `Layout`, `LayoutRoot`, `LayoutSideMenu`, `OptionsSideMenu` from RNN\n\n### Upgrade Checklist\n\n1. Bump version in both `package.json` files\n2. Verify `OptionsProcessor.js` patch still applies (diff upstream changes)\n3. Check `RNNAppDelegate` API compatibility (iOS)\n4. Check `NavigationApplication` / `NavigationPackage` / `NavigationReactNativeHost` API compatibility (Android)\n5. Verify `missingDimensionStrategy` value is still valid\n6. Check `react-native-navigation-hooks` and `rnn-copilot` compatibility\n7. Run `yarn install` to update lockfile\n8. Verify test mocks (`react-native-navigation/Mock`) still work\n\n## Common Gotchas\n\n- iOS uses UIKit subclasses (UINavigationController, UITabBarController); Android uses custom View hierarchy\n- `splitView` is iOS-only\n- Side menu: iOS uses MMDrawerController (3rd party); Android uses DrawerLayout (native)\n- Options that exist in JS types may not be implemented on both platforms — check the presenter\n- `passProps` are stored in JS `Store`, not sent to native (cleared before bridge crossing)\n- The `lib/` folder is generated — never edit it, edit `src/` instead\n","ARCHITECTURE.md":"# React Native Navigation Architecture\n\nReact 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.\n\n## Project Overview\n\n- **Package**: `react-native-navigation` (v8.7.0)\n- **Platforms**: iOS 11+, Android 7.0+ (API 24)\n- **React Native**: 0.77+ (developed against 0.83; see package.json for current version)\n- **License**: MIT (maintained by Wix)\n\n## Directory Structure\n\n```\nreact-native-navigation/\n├── src/                    # TypeScript source code (JS API layer)\n├── lib/                    # Compiled output (generated by bob build - do not edit)\n├── android/                # Android native implementation (Java/Kotlin)\n├── ios/                    # iOS native implementation (Obj-C/C++)\n├── playground/             # Demo app and E2E test target\n├── autolink/               # Post-install linking scripts\n├── scripts/                # Build, test, and release scripts\n├── website/                # Docusaurus documentation site\n├── integration/            # Integration tests (Redux, Remx)\n├── Mock/                   # Mock implementations for testing\n└── .buildkite/             # CI/CD pipeline configuration\n```\n\n## High-Level Architecture\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│                     JavaScript API Layer                         │\n│  Navigation.setRoot() / push() / pop() / showModal() / etc.     │\n└─────────────────────────────┬────────────────────────────────────┘\n                              │\n┌─────────────────────────────▼────────────────────────────────────┐\n│                    Processing Pipeline                            │\n│  OptionsCrawler → LayoutProcessor → LayoutTreeParser → OptionsProcessor │\n└─────────────────────────────┬────────────────────────────────────┘\n                              │\n┌─────────────────────────────▼────────────────────────────────────┐\n│                   TurboModule Bridge                              │\n│  NativeCommandsSender ←→ RNNTurboModule (iOS) / NavigationTurboModule (Android) │\n└──────────┬─────────────────────────────────────┬─────────────────┘\n           │                                     │\n┌──────────▼──────────┐               ┌─────────▼──────────┐\n│   iOS Native Layer  │               │ Android Native Layer│\n│  UINavigationController             │   ViewControllers   │\n│  UITabBarController │               │   CoordinatorLayout │\n│  UIViewController   │               │   BottomNavigation  │\n└─────────────────────┘               └────────────────────┘\n```\n\n## Core Concepts\n\n### Layout Types\nAll navigation structures are composed from these layout primitives:\n\n| Layout Type | Description | iOS Implementation | Android Implementation |\n|-------------|-------------|-------------------|----------------------|\n| `component` | React component screen | RNNComponentViewController | ComponentViewController |\n| `stack` | Push/pop navigation | UINavigationController (RNNStackController) | StackController |\n| `bottomTabs` | Tab bar navigation | UITabBarController (RNNBottomTabsController) | BottomTabsController |\n| `topTabs` | Horizontal scrollable tabs | RNNTopTabsViewController | TopTabsController |\n| `sideMenu` | Drawer navigation (with center, left, right) | MMDrawerController (RNNSideMenuViewController) | SideMenuController |\n| `splitView` | Master-detail (iPad only) | UISplitViewController (RNNSplitViewController) | — |\n| `externalComponent` | Native (non-React) screen | RNNExternalViewController | ExternalComponentViewController |\n\n### Navigation Commands\nCore commands available through the Navigation API:\n\n- **Root**: `setRoot()` - Replace entire navigation hierarchy\n- **Stack**: `push()`, `pop()`, `popTo()`, `popToRoot()`, `setStackRoot()`\n- **Modal**: `showModal()`, `dismissModal()`, `dismissAllModals()`\n- **Overlay**: `showOverlay()`, `dismissOverlay()`, `dismissAllOverlays()`\n- **Options**: `setDefaultOptions()`, `mergeOptions()`, `updateProps()`\n- **Linking**: `setLinking()`, `handleDeepLink()`, `setLinkingReady()` - URL-to-screen routing\n\n### Deep Linking\nURL-driven navigation is implemented entirely in the JS layer (`src/linking/`) and feeds into the standard command pipeline. Configure with `Navigation.setLinking({ prefixes, config: { screens } })`; matched URLs are presented as modals by default (preserving the user's current navigation state). Customize via `getModal`/`onLink` hooks; gate processing on auth via `isReady`/`setLinkingReady`. Native plumbing — `application:openURL:`, `application:continueUserActivity:`, cold-start URL queueing — lives in `RNNAppDelegate` (iOS) and `NavigationActivity.onNewIntent` (Android), so subclassing the base classes is sufficient. See [Deep Linking docs](https://wix.github.io/react-native-navigation/docs/deep-linking).\n\n### Options System\nStyling and behavior is controlled via a hierarchical options object:\n\n```typescript\n{\n  statusBar: {...},      // Status bar appearance\n  topBar: {...},         // Navigation bar styling\n  bottomTabs: {...},     // Tab bar configuration\n  bottomTab: {...},      // Individual tab styling\n  sideMenu: {...},       // Drawer configuration\n  layout: {...},         // Screen layout options\n  animations: {...},     // Transition animations\n  modal: {...},          // Modal presentation style\n  overlay: {...}         // Overlay behavior\n}\n```\n\nOptions merge in order: **Default Options → Parent Options → Component Options**\n\n## Data Flow\n\n### Command Execution Flow\n```\n1. JS: Navigation.push(componentId, layout)\n2. Commands.ts validates and begins processing\n3. OptionsCrawler extracts static options from component classes\n4. LayoutProcessor applies registered layout processors\n5. LayoutTreeParser converts to internal LayoutNode tree\n6. LayoutTreeCrawler processes tree, saves props to Store\n7. OptionsProcessor resolves colors, images, fonts\n8. NativeCommandsSender sends to TurboModule\n9. Native layer creates/updates view hierarchy\n10. EventEmitter sends completion event to JS\n```\n\n**Note**: The JS layer exports a single `Navigation` object (from `NavigationDelegate`). The TurboModule names differ per platform: `RNNTurboModule` on iOS, `NavigationTurboModule` on Android.\n\n### Event Flow (Native → JS)\n```\n1. Native lifecycle event (viewDidAppear, etc.)\n2. RNNEventEmitter (iOS) / EventEmitter (Android)\n3. NativeEventsReceiver receives via NativeEventEmitter\n4. EventsRegistry dispatches to registered listeners\n5. ComponentEventsObserver calls component instance methods\n```\n\n## Key Architecture Patterns\n\n1. **Facade Pattern**: `NavigationDelegate` provides clean public API\n2. **Bridge Pattern**: Adapters isolate JS from native implementation details\n3. **Presenter Pattern**: Separates view styling from controller logic\n4. **Observer Pattern**: Event system for lifecycle and command notifications\n5. **Factory Pattern**: `LayoutFactory` creates controllers from layout nodes\n6. **Plugin Pattern**: Processors allow extending layout/options handling\n\n## Component Lifecycle\n\nReact components receive navigation lifecycle events:\n\n```typescript\nclass MyScreen extends NavigationComponent {\n  componentWillAppear(event) {}      // About to become visible\n  componentDidAppear(event) {}       // Now visible\n  componentDidDisappear(event) {}    // No longer visible\n  navigationButtonPressed(event) {}  // TopBar button tapped\n  screenPopped(event) {}             // Screen removed from stack\n  searchBarUpdated(event) {}         // Search text changed\n  searchBarCancelPressed(event) {}   // Search cancelled\n  previewCompleted(event) {}         // 3D Touch preview completed\n}\n```\n\n## Testing Architecture\n\n- **Unit Tests**: Jest + ts-mockito for TypeScript source\n- **Integration Tests**: Redux/Remx integration verification\n- **E2E Tests**: Detox framework with playground app\n- **Snapshot Tests**: iOS visual regression testing\n- **Native Unit Tests**: XCTest (iOS) and JUnit (Android)\n\n## Related Documentation\n\n- [JavaScript/TypeScript Architecture](./src/ARCHITECTURE.md)\n- [iOS Native Architecture](./ios/ARCHITECTURE.md)\n- [Android Native Architecture](./android/ARCHITECTURE.md)\n- [API Documentation](https://wix.github.io/react-native-navigation/)\n","ios/ARCHITECTURE.md":"# iOS Native Architecture\n\nThe iOS implementation provides native navigation using UIKit view controllers, coordinated through a bridge module that receives commands from JavaScript.\n\n## App Integration\n\n### RNNAppDelegate\n**Files**: `RNNAppDelegate.h/mm`\n\nBase class that user's AppDelegate must extend. Handles React Native and navigation initialization:\n\n```objc\n// AppDelegate.h - User extends RNNAppDelegate\n#import \"RNNAppDelegate.h\"\n@interface AppDelegate : RNNAppDelegate\n@end\n\n// AppDelegate.m - User implements sourceURLForBridge\n@implementation AppDelegate\n- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {\n  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@\"index\"];\n}\n@end\n```\n\n**What RNNAppDelegate does:**\n- Sets up React Native feature flags (Fabric, TurboModules, Bridgeless)\n- Creates `RCTRootViewFactory` and `ReactHost`\n- Calls `[ReactNativeNavigation bootstrapWithHost:]` to initialize navigation\n- Handles RN version differences (0.77, 0.78, 0.79+) via compile-time macros\n- **Deep linking plumbing**:\n  - Implements `application:openURL:options:` and `application:continueUserActivity:restorationHandler:`; both call `-dispatchDeepLinkURL:`.\n  - `-dispatchDeepLinkURL:` posts `RCTOpenURLNotification` directly if the React runtime is ready, otherwise enqueues the URL.\n  - Observes `RCTContentDidAppearNotification` (the Fabric/bridgeless signal) to flush the queue. This solves the cold-start race where URLs (push notifications, OS link launches) arrive before `RCTLinkingManager` is listening.\n  - Subclasses can call `-dispatchDeepLinkURL:` manually from notification delegates or any other URL source; the queueing behavior is reused automatically.\n\n### ReactNativeNavigation Bootstrap\n**File**: `ReactNativeNavigation.h/mm`\n\nPublic API for native initialization:\n\n```objc\n// New architecture (0.77+)\n[ReactNativeNavigation bootstrapWithHost:reactHost];\n\n// Legacy bridge\n[ReactNativeNavigation bootstrapWithBridge:bridge];\n\n// Register native screens\n[ReactNativeNavigation registerExternalComponent:@\"NativeScreen\"\n                                        callback:^(NSDictionary *props, RCTBridge *bridge) {\n    return [[MyNativeVC alloc] init];\n}];\n```\n\n### Autolink Script (`npx rnn-link`)\n\nThe `autolink/postlink/postLinkIOS.js` script automates setup:\n\n| Linker | What it does |\n|--------|--------------|\n| `AppDelegateLinker` | Changes AppDelegate to extend `RNNAppDelegate`, imports ReactNativeNavigation, removes RCTRootView setup |\n| `PodfileLinker` | Adds required pods configuration |\n| `PlistLinker` | Updates Info.plist if needed |\n\n**AppDelegateLinker transformations:**\n- Swift: `class AppDelegate: RCTAppDelegate` → `class AppDelegate: RNNAppDelegate`\n- Obj-C header: `@interface AppDelegate : RCTAppDelegate` → `@interface AppDelegate : RNNAppDelegate`\n- Imports `<ReactNativeNavigation/ReactNativeNavigation.h>`\n- Removes manual RCTRootView/window setup (navigation manages the window)\n\n## Directory Structure\n\n```\nios/\n├── RNNBridgeModule.h/mm         # Bridge entry point (legacy architecture)\n├── RNNBridgeManager.h/mm        # Bridge initialization\n├── RNNCommandsHandler.h/mm      # Command dispatcher\n├── RNNEventEmitter.h/mm         # Event emission to JS\n├── RNNLayoutManager.h/mm        # View controller tracking\n├── RNNLayoutNode.h/mm           # Layout tree parsing\n├── RNNNavigationOptions.h/mm    # Options model\n├── RNNComponentViewController.h/mm  # React component screen\n├── RNNStackController.h/mm      # Stack navigation\n├── RNNBottomTabsController.h/mm # Tab navigation\n├── RNNSideMenuViewController.h/mm   # Side menu\n├── RNNTopTabsViewController.h/mm    # Top tabs\n├── RNNSplitViewController.h/mm  # Split view (iPad)\n├── RNNModalManager.h/mm         # Modal presentation\n├── RNNOverlayManager.h/mm       # Overlay management\n├── TurboModules/                # New architecture entry points\n│   ├── RNNTurboModule.h/mm      # TurboModule spec implementation\n│   ├── RNNTurboManager.h/mm     # Manager for host, window, external components\n│   ├── RNNTurboCommandsHandler.h/mm  # TurboModule command routing\n│   └── RNNTurboEventEmitter.h/mm     # Event emission for new arch\n├── Utils/                       # Utility classes\n├── RNNSideMenu/                 # MMDrawerController integration\n└── ReactNativeNavigation.xcodeproj/\n```\n\n## Bridge Architecture\n\nThe library supports both the legacy bridge and new TurboModule architecture:\n- **Legacy (Bridge)**: `RNNBridgeModule` receives commands via `RCT_EXPORT_METHOD`\n- **New Architecture**: `RNNTurboModule` (in `TurboModules/`) receives commands directly\n\nBoth entry points delegate to `RNNCommandsHandler` for command execution.\n\n```\n┌────────────────────────────────────────────────────────────┐\n│                 JavaScript (TurboModule)                   │\n└─────────────────────────┬──────────────────────────────────┘\n                          │\n┌─────────────────────────▼──────────────────────────────────┐\n│  RNNBridgeModule (bridge) / RNNTurboModule (new arch)      │\n│  - setRoot, push, pop, showModal, dismissModal, etc.       │\n└─────────────────────────┬──────────────────────────────────┘\n                          │\n┌─────────────────────────▼──────────────────────────────────┐\n│  RNNCommandsHandler                                         │\n│  - Validates commands, manages layout lifecycle            │\n│  - Coordinates with managers                               │\n└──────┬──────────────┬──────────────┬──────────────┬────────┘\n       │              │              │              │\n┌──────▼─────┐ ┌──────▼─────┐ ┌──────▼─────┐ ┌─────▼──────┐\n│RNNLayout   │ │RNNModal    │ │RNNOverlay  │ │RNNViewController│\n│Manager     │ │Manager     │ │Manager     │ │Factory     │\n└────────────┘ └────────────┘ └────────────┘ └────────────┘\n```\n\n## View Controller Hierarchy\n\nAll navigation view controllers conform to `RNNLayoutProtocol`:\n\n```\nUIViewController\n├── RNNComponentViewController    # React component screen\n├── RNNExternalViewController     # Native screen wrapper\n└── RNNSplashScreenViewController # Launch screen\n\nUINavigationController\n└── RNNStackController           # Stack navigation\n\nUITabBarController\n└── RNNBottomTabsController      # Bottom tabs\n\nUIViewController (custom)\n├── RNNTopTabsViewController     # Horizontal top tabs\n└── RNNSideMenuChildViewController  # Drawer child\n\nMMDrawerController\n└── RNNSideMenuViewController    # Side menu/drawer\n\nUISplitViewController\n└── RNNSplitViewController       # Master-detail (iPad)\n```\n\n## Core Classes\n\n### RNNBridgeModule\nEntry point for JavaScript commands (legacy architecture). Exports methods via `RCT_EXPORT_METHOD`:\n\n```objc\nRCT_EXPORT_METHOD(setRoot:(NSString*)commandId layout:(NSDictionary*)layout\n                  resolver:(RCTPromiseResolveBlock)resolve\n                  rejecter:(RCTPromiseRejectBlock)reject);\n```\n\n`RNNBridgeModule` returns the main queue as its `methodQueue`; `RNNTurboModule` uses `RCTExecuteOnMainQueue` for each command to ensure UI operations run on the main thread.\n\n### RNNBridgeManager\nInitializes bridge infrastructure:\n- Creates RNNLayoutManager, RNNModalManager, RNNOverlayManager\n- Creates RNNViewControllerFactory, RNNCommandsHandler\n- Provides extra modules to React bridge\n- Handles JavaScript reload events\n\n### RNNCommandsHandler\nCentral command dispatcher implementing all navigation operations:\n- `setRoot:` - Replace root view controller\n- `push:componentId:layout:` - Push to stack\n- `pop:componentId:` - Pop from stack\n- `showModal:` - Present modal\n- `dismissModal:` - Dismiss modal\n- `showOverlay:` - Show overlay window\n- `dismissOverlay:` - Hide overlay\n\n### RNNLayoutManager\nTracks active view controllers:\n- `addPendingViewController:` - Register during creation\n- `removePendingViewController:` - Cleanup after presentation\n- `findComponentForId:` - Lookup by componentId\n\n### RNNLayoutNode\nParses JSON layout from JavaScript:\n- Determines type via predicates: `isComponent`, `isStack`, `isTabs`, etc.\n- Holds `type`, `nodeId`, `data` (options), `children`\n\n### RNNViewControllerFactory\nCreates view controllers from RNNLayoutNode:\n- `createStack:` → RNNStackController\n- `createBottomTabs:` → RNNBottomTabsController\n- `createComponent:` → RNNComponentViewController\n- `createSideMenu:` → RNNSideMenuViewController\n\n## RNNLayoutProtocol\n\nProtocol all navigation controllers implement:\n\n```objc\n@protocol RNNLayoutProtocol\n- (instancetype)initWithLayoutInfo:(RNNLayoutInfo*)layoutInfo\n                           creator:(id<RNNComponentViewCreator>)creator\n                           options:(RNNNavigationOptions*)options\n                    defaultOptions:(RNNNavigationOptions*)defaultOptions\n                         presenter:(RNNBasePresenter*)presenter\n                      eventEmitter:(RNNEventEmitter*)eventEmitter\n              childViewControllers:(NSArray*)childViewControllers;\n\n- (void)render;\n- (UIViewController*)getCurrentChild;\n- (void)mergeOptions:(RNNNavigationOptions*)options;\n- (RNNNavigationOptions*)resolveOptions;\n- (void)setDefaultOptions:(RNNNavigationOptions*)defaultOptions;\n- (void)onChildWillAppear;\n- (void)readyForPresentation;\n- (CGFloat)getTopBarHeight;\n- (CGFloat)getBottomTabsHeight;\n@end\n```\n\nAdditional methods provided via `UIViewController+LayoutProtocol` category:\n- `destroy`, `topMostViewController`, `stack`\n- `componentWillAppear`, `componentDidAppear`, `componentDidDisappear`\n- `screenPopped`, `prepareForTransition`\n- `resolveOptionsWithDefault`, `mergeChildOptions:child:`\n\n## Presenter Pattern\n\nEach view controller type has a corresponding presenter that applies options:\n\n| Controller | Presenter |\n|------------|-----------|\n| RNNComponentViewController | RNNComponentPresenter |\n| RNNStackController | RNNStackPresenter + TopBarPresenter |\n| RNNBottomTabsController | RNNBottomTabsPresenter + BottomTabPresenter |\n| RNNSideMenuViewController | RNNSideMenuPresenter |\n| RNNSplitViewController | RNNSplitViewControllerPresenter |\n\n### RNNBasePresenter\nBase class with lifecycle methods:\n- `applyOptionsOnInit:` - Initial setup\n- `applyOptions:` - Apply current options\n- `mergeOptions:resolvedOptions:` - Runtime updates\n- `componentWillAppear`, `componentDidAppear`, `componentDidDisappear`\n\n## React View Integration\n\n### RNNReactView\nWraps RCTRootView (legacy) or RCTSurfaceHostingView (new architecture):\n- Implements `RNNComponentProtocol`\n- Manages `componentId`, `componentType`, `moduleName`\n- Lifecycle: `componentWillAppear`, `componentDidAppear`, `componentDidDisappear`\n\n### RNNReactRootViewCreator\nCreates RNNReactView instances:\n- Supports component types: Component, TopBarTitle, TopBarButton, TopBarBackground\n- Handles size flexibility for flexible layouts\n\n### RNNReactComponentRegistry\nCaches created React component instances:\n- `createComponentIfNotExists:parentComponentId:componentType:reactViewReadyBlock:`\n- `removeComponent:`, `clearComponentsForParentId:`\n\n## Options System\n\n### RNNNavigationOptions\nMaster options object containing all configuration:\n\n```objc\n@interface RNNNavigationOptions : RNNOptions\n@property RNNTopBarOptions* topBar;\n@property RNNBottomTabsOptions* bottomTabs;\n@property RNNBottomTabOptions* bottomTab;\n@property RNNTopTabsOptions* topTabs;\n@property RNNSideMenuOptions* sideMenu;\n@property RNNOverlayOptions* overlay;\n@property RNNAnimationsOptions* animations;\n@property RNNStatusBarOptions* statusBar;\n@property RNNLayoutOptions* layout;\n@property RNNModalOptions* modal;\n@property RNNPreviewOptions* preview;\n@property RNNSplitViewOptions* splitView;\n@end\n```\n\n### Options Resolution\nOptions merge in hierarchy:\n1. Component's own options\n2. Parent controller options (loop through chain)\n3. Default options (from `setDefaultOptions`)\n\n## Event Emission\n\n### RNNEventEmitter\nSends events to JavaScript via RCTEventEmitter:\n\n| Event | Method |\n|-------|--------|\n| Component lifecycle | `sendComponentWillAppear:`, `sendComponentDidAppear:`, `sendComponentDidDisappear:` |\n| Button press | `sendOnNavigationButtonPressed:buttonId:` |\n| Command completion | `sendOnNavigationCommandCompletion:commandId:` |\n| Tab events | `sendBottomTabSelected:unselected:`, `sendBottomTabLongPressed:`, `sendBottomTabPressed:` |\n| Modal events | `sendModalsDismissedEvent:numberOfModalsDismissed:`, `sendModalAttemptedToDismissEvent:` |\n| Screen events | `sendScreenPoppedEvent:` |\n| Search | `sendOnSearchBarUpdated:text:isFocused:`, `sendOnSearchBarCancelPressed:` |\n| Preview | `sendOnPreviewCompleted:previewComponentId:` |\n\n### RNNBridgeEventEmitter\nConcrete implementation that sends `onAppLaunched` on initialization.\n\n## Modal & Overlay Management\n\n### RNNModalManager\n- Tracks presented modals array\n- Supports custom transition animations via ScreenAnimationController\n- Handles presentationController delegate for adaptive presentation\n\n### RNNOverlayManager\n- Manages UIWindow instances for overlays\n- Each overlay gets its own RNNOverlayWindow\n- Maintains previous window reference for restoration\n- Controls window level and accessibility\n\n## Animation System\n\n### ScreenAnimationController\nImplements `UIViewControllerAnimatedTransitioning`:\n- Custom push/pop/modal transitions\n- Content transitions (RNNEnterExitAnimation)\n- Element transitions (ElementTransitionOptions)\n- Shared element transitions (SharedElementTransitionOptions)\n\n### Element Animators\n- `ElementAnimator` - Individual element animations\n- `SharedElementAnimator` - Cross-screen shared elements\n- Transition types: Alpha, Scale, Translation, Frame, Bounds, Color, CornerRadius\n\n### RNNSetRootAnimator\nAnimates window root replacement using CABasicAnimation.\n\n## Navigation Types\n\n### Stack Navigation (RNNStackController)\n- Subclass of UINavigationController\n- Push/pop with custom animations\n- Back button customization\n- Uses StackControllerDelegate for bar delegate handling\n\n```objc\n// Extension methods\n@interface UINavigationController (RNNCommands)\n- (void)push:(UIViewController*)vc onTop:(UIViewController*)onTopVC\n     animated:(BOOL)animated completion:(void(^)(void))completion rejection:(RCTPromiseRejectBlock)rejection;\n- (void)popAnimated:(BOOL)animated completion:(void(^)(NSString*))completion rejection:(RCTPromiseRejectBlock)rejection;\n@end\n```\n\n### Bottom Tabs (RNNBottomTabsController)\n- Subclass of UITabBarController\n- Tab attachment modes: Together, OnSwitchToTab, AfterInitialTab\n- Long-press gesture support\n- Badge and dot indicator support\n\n### Side Menu (RNNSideMenuViewController)\n- Uses MMDrawerController (third-party)\n- Center, left, right child containers\n- Configurable open modes and widths\n\n### Top Tabs (RNNTopTabsViewController)\n- Custom horizontal tab implementation\n- Not based on UITabBarController\n- Manual content switching\n\n### Split View (RNNSplitViewController)\n- UISplitViewController subclass\n- Master-detail for iPad\n\n## External Components\n\n### RNNExternalComponentStore\nRegistry for native (non-React) view controllers.\n\n### RNNExternalViewController\nWraps native UIViewController for integration:\n\n```objc\n[ReactNativeNavigation registerExternalComponent:@\"NativeScreen\"\n                                       callback:^(NSDictionary *props, RCTBridge *bridge) {\n    return [[MyNativeViewController alloc] init];\n}];\n```\n\n## Key Files Reference\n\n| File | Purpose |\n|------|---------|\n| `RNNBridgeModule.h/mm` | Bridge entry point (legacy) |\n| `TurboModules/RNNTurboModule.mm` | TurboModule entry point (new arch) |\n| `TurboModules/RNNTurboCommandsHandler.mm` | TurboModule command routing |\n| `RNNCommandsHandler.h/mm` | Command execution |\n| `RNNLayoutManager.h/mm` | Controller tracking |\n| `RNNViewControllerFactory.h/mm` | Controller creation |\n| `RNNComponentViewController.h/mm` | React screen |\n| `RNNStackController.h/mm` | Stack navigation |\n| `RNNBottomTabsController.h/mm` | Tab navigation |\n| `RNNNavigationOptions.h/mm` | Options model |\n| `RNNBasePresenter.h/mm` | Presenter base |\n| `TopBarPresenter.h/mm` | Top bar styling |\n| `RNNReactView.h/mm` | React view wrapper |\n| `ScreenAnimationController.h/mm` | Custom transitions |\n","src/ARCHITECTURE.md":"# JavaScript/TypeScript Architecture\n\nThe JavaScript layer provides the public API and orchestrates communication between React components and native navigation implementations.\n\n## Entry Point\n\n`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.\n\n## Module Structure\n\n```\nsrc/\n├── index.ts                 # Main entry point, exports Navigation singleton\n├── Navigation.ts            # NavigationRoot - core orchestrator\n├── NavigationDelegate.ts    # Public API facade\n├── adapters/                # Native bridge layer\n├── commands/                # Command processing\n├── components/              # React component management\n├── events/                  # Event system\n├── interfaces/              # TypeScript type definitions\n├── linking/                 # Deep-linking framework (URL → command)\n└── processors/              # Extensibility hooks\n```\n\n## Core Classes\n\n### NavigationDelegate (Public API)\n**File**: `NavigationDelegate.ts`\n\nFacade providing the public `Navigation` API. All methods proxy to `NavigationRoot`.\n\n```typescript\n// Usage\nimport { Navigation } from 'react-native-navigation';\nNavigation.setRoot({ root: { stack: { children: [...] } } });\n```\n\n### NavigationRoot (Core Orchestrator)\n**File**: `Navigation.ts`\n\nCoordinates all subsystems. Constructed with dependencies:\n- `NativeCommandsSender` - sends commands to native\n- `NativeEventsReceiver` - receives events from native\n- `AppRegistryService` - manages React Native component registry\n\nInitializes and coordinates:\n- `Store` - component instance & props storage\n- `ComponentRegistry` - component registration\n- `LayoutTreeParser` - converts layouts to internal nodes\n- `LayoutTreeCrawler` - processes layout trees\n- `Commands` - command execution\n- `EventsRegistry` - event subscriptions\n- `OptionsProcessor` - option processing\n- `LayoutProcessor` - layout transformations\n\n## Adapters Layer\n\nBridge between JavaScript and native/React Native APIs.\n\n| Adapter | Purpose |\n|---------|---------|\n| `NativeCommandsSender` | Wraps TurboModule for command dispatch |\n| `NativeEventsReceiver` | Wraps NativeEventEmitter for events |\n| `NativeRNNTurboModule` | TurboModule spec interface |\n| `NativeRNNTurboEventEmitter` | TurboModule event emitter spec |\n| `UniqueIdProvider` | Generates unique component/command IDs |\n| `ColorService` | Converts colors to native format |\n| `AssetResolver` | Resolves require() image assets (class: AssetService) |\n| `AppRegistryService` | Registers components with React Native |\n| `Constants` | Platform dimension constants |\n| `TouchablePreview` | 3D Touch / Haptic preview handling |\n\n## Commands Layer\n\n### Commands Class\n**File**: `commands/Commands.ts`\n\nCentral command dispatcher. Each navigation command:\n1. Validates input\n2. Processes layout through pipeline\n3. Sends to native via adapter\n4. Returns promise with result\n\n### Processing Pipeline\n\nThe pipeline executes in this exact order:\n\n```\nInput Layout (from API)\n       ↓\n1. OptionsCrawler.crawl()         # Extract static options from component classes\n       ↓\n2. LayoutProcessor.process()      # Apply registered layout processors\n       ↓\n3. LayoutTreeParser.parse()       # Convert to internal LayoutNode tree\n       ↓\n4. LayoutTreeCrawler.crawl()      # Process options, save props to Store\n       ↓\n5. OptionsProcessor (during crawl) # Resolve colors, assets, custom processors\n       ↓\n6. NativeCommandsSender           # Send to native module\n```\n\n### LayoutNode (Internal Tree)\n```typescript\ninterface LayoutNode {\n  id: string;           // Unique identifier\n  type: LayoutType;     // Component|Stack|BottomTabs|etc\n  data: {\n    name?: string;      // Component name\n    options?: any;      // Processed options\n    passProps?: any;    // Component props (cleared before native)\n  };\n  children: LayoutNode[];\n}\n```\n\n### LayoutType Enum\n```typescript\nenum LayoutType {\n  Component = 'Component',\n  Stack = 'Stack',\n  BottomTabs = 'BottomTabs',\n  SideMenuRoot = 'SideMenuRoot',\n  SideMenuCenter = 'SideMenuCenter',\n  SideMenuLeft = 'SideMenuLeft',\n  SideMenuRight = 'SideMenuRight',\n  TopTabs = 'TopTabs',\n  ExternalComponent = 'ExternalComponent',\n  SplitView = 'SplitView',\n}\n```\n\n## Components Layer\n\n### ComponentRegistry\n**File**: `components/ComponentRegistry.ts`\n\nManages React component registration and wrapping.\n\n```typescript\nNavigation.registerComponent('ScreenName', () => MyComponent);\n```\n\n### ComponentWrapper\n**File**: `components/ComponentWrapper.tsx`\n\nHigher-order component that:\n- Wraps original component with lifecycle management\n- Stores instance in `Store` for event dispatch\n- Injects `componentId` and `componentName` props\n\n### Store\n**File**: `components/Store.ts`\n\nCentralized storage for:\n- `componentsByName` - registered component providers\n- `componentsInstancesById` - mounted component instances\n- `propsById` - static props by component ID\n- `pendingPropsById` - props awaiting component mount\n- `wrappedComponents` - cached wrapped components\n- `lazyRegistratorFn` - function for lazy component registration\n\n## Events Layer\n\n### EventsRegistry\n**File**: `events/EventsRegistry.ts`\n\nPublic API for event subscriptions:\n\n```typescript\nNavigation.events().registerComponentDidAppearListener(({ componentId }) => {});\nNavigation.events().registerCommandCompletedListener(({ commandId }) => {});\n```\n\n### ComponentEventsObserver\n**File**: `events/ComponentEventsObserver.ts`\n\nDispatches events to component instance methods:\n- `componentWillAppear()`\n- `componentDidAppear()`\n- `componentDidDisappear()`\n- `navigationButtonPressed()`\n- `screenPopped()`\n\n### CommandsObserver\n**File**: `events/CommandsObserver.ts`\n\nNotifies listeners of command lifecycle (start, complete).\n\n## Events (Native → JS)\n\n| Event | Description |\n|-------|-------------|\n| `RNN.AppLaunched` | App initialization complete |\n| `RNN.ComponentWillAppear` | Component about to appear |\n| `RNN.ComponentDidAppear` | Component now visible |\n| `RNN.ComponentDidDisappear` | Component hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tapped |\n| `RNN.BottomTabPressed` | Tab pressed (even if selected) |\n| `RNN.BottomTabSelected` | Tab selection changed |\n| `RNN.BottomTabLongPressed` | Tab long-pressed |\n| `RNN.ModalDismissed` | Modal was dismissed |\n| `RNN.ModalAttemptedToDismiss` | Swipe-to-dismiss attempted |\n| `RNN.ScreenPopped` | Screen removed from stack |\n| `RNN.SearchBarUpdated` | Search text changed |\n| `RNN.SearchBarCancelPressed` | Search cancelled |\n| `RNN.PreviewCompleted` | 3D Touch preview completed |\n| `RNN.CommandCompleted` | Navigation command finished |\n\n## Linking Layer\n\nImplements URL-to-screen routing on top of the standard command pipeline. The whole feature is JS-only; it consumes URLs from RN's `Linking` module and dispatches `showModal` (or a user-supplied command) when a match is found.\n\n**Public surface** (proxied through `NavigationDelegate`):\n- `Navigation.setLinking(config)` — configure prefixes, screen map, and customization hooks\n- `Navigation.handleDeepLink(url)` — manually feed a URL (push notifications, branch.io, App Clips)\n- `Navigation.setLinkingReady(ready)` — user-controlled gate for deferred deep links\n\n**Internal modules** (`src/linking/`):\n\n| File | Purpose |\n|------|---------|\n| `LinkingHandler.ts` | Orchestrator. Subscribes to `Linking.url`/`getInitialURL`, drives the queue, dispatches matches. Instantiated by `NavigationRoot`. |\n| `URLParser.ts` | Strips prefix (longest match), removes fragment, decodes path segments + query params. |\n| `RouteMatcher.ts` | Compiles `ScreensConfig` into a `RouteNode` tree; matches paths to screen chains with parameter extraction. |\n| `DeferredLinkQueue.ts` | FIFO queue. Holds URLs until both gates open (root-ready + user-ready). |\n| `ModalLayoutBuilder.ts` | Default presentation: wraps the matched chain in a `stack`, merges params into `passProps`, filters React-reserved keys (`ref`, `key`). |\n| `types.ts` | Public types: `LinkingConfig`, `RouteMatch`, `ScreensConfig`, etc. (re-exported via `src/index.ts`). |\n\n**Readiness gates** — a URL is dispatched only when both are true:\n1. **Root-ready** (automatic): the first `Navigation.setRoot()` has resolved. `NavigationRoot.setRoot` calls `linkingHandler.setRootReady()` after the promise resolves.\n2. **User-ready** (optional): `config.isReady()` returns `true`, or `setLinkingReady(true)` was called.\n\n**Resolution priority** when a match is found:\n1. `config.onLink(match)` — full escape hatch, RNN does nothing else\n2. `config.getModal(match)` — custom modal layout\n3. Default `ModalLayoutBuilder` output\n\n## Processors Layer\n\n### OptionProcessorsStore\n**File**: `processors/OptionProcessorsStore.ts`\n\nRegisters custom option processors:\n\n```typescript\nNavigation.addOptionProcessor('topBar.title.text', (value, commandName) => {\n  return value.toUpperCase(); // Transform all titles\n});\n```\n\n### LayoutProcessorsStore\n**File**: `processors/LayoutProcessorsStore.ts`\n\nRegisters layout transformers:\n\n```typescript\nNavigation.addLayoutProcessor((layout, commandName) => {\n  // Add default options to all components\n  return layout;\n});\n```\n\n## Interfaces\n\n### Layout Types\n**File**: `interfaces/Layout.ts`\n\n```typescript\ninterface LayoutRoot {\n  root: Layout;\n  modals?: any[];\n  overlays?: any[];\n}\n\ntype Layout = {\n  component?: LayoutComponent;\n  stack?: LayoutStack;\n  bottomTabs?: LayoutBottomTabs;\n  sideMenu?: LayoutSideMenu;\n  splitView?: LayoutSplitView;\n  topTabs?: LayoutTopTabs;\n  externalComponent?: ExternalComponent;\n}\n```\n\n### Options Interface\n**File**: `interfaces/Options.ts` (comprehensive)\n\nContains all configuration options for:\n- Status bar, navigation bars\n- Top bar (buttons, title, search)\n- Bottom tabs\n- Side menus\n- Modals, overlays\n- Animations\n- Layout parameters\n\n### NavigationComponent\n**File**: `interfaces/NavigationComponent.ts`\n\nBase class for navigation-aware components:\n\n```typescript\nclass MyScreen extends NavigationComponent<Props> {\n  static options: Options = { ... };\n\n  componentDidAppear(event) { }\n  navigationButtonPressed(event) { }\n}\n```\n\n## Dependencies\n\n**Production**:\n- `lodash` - utility functions\n- `hoist-non-react-statics` - HOC support\n- `react-lifecycles-compat` - lifecycle polyfill\n- `tslib` - TypeScript helpers\n\n**Peer**:\n- `react`, `react-native` (required)\n- `remx` (optional state management)\n\n## Build Output\n\nUses `react-native-builder-bob`:\n- **Source**: `src/`\n- **Output**: `lib/`\n- **Targets**: ESM modules + TypeScript declarations\n","android/ARCHITECTURE.md":"# Android Native Architecture\n\nThe Android implementation provides native navigation using Views and ViewGroups (not Fragments), coordinated through a TurboModule that receives commands from JavaScript.\n\n## App Integration\n\n### NavigationApplication\n**File**: `NavigationApplication.java`\n\nAbstract Application class that user's MainApplication must extend:\n\n```kotlin\n// MainApplication.kt - User extends NavigationApplication\nclass MainApplication : NavigationApplication() {\n    override val reactNativeHost: ReactNativeHost\n        get() = NavigationReactNativeHost(this) // Must use NavigationReactNativeHost\n}\n```\n\n**What NavigationApplication does:**\n- Initializes SoLoader\n- Provides `ReactGateway` singleton for React lifecycle\n- Offers `registerExternalComponent()` for native screens\n\n### NavigationActivity\n**File**: `NavigationActivity.java`\n\nBase Activity that user's MainActivity must extend:\n\n```kotlin\n// MainActivity.kt - User extends NavigationActivity\nclass MainActivity : NavigationActivity() {\n    // No getMainComponentName() needed - navigation handles root\n}\n```\n\n**What NavigationActivity does:**\n- Creates `Navigator` with root, modal, and overlay layouts\n- Manages back press via `OnBackPressedCallback`\n- Coordinates React lifecycle with activity lifecycle\n\n### NavigationReactNativeHost\n**File**: `react/NavigationReactNativeHost.kt`\n\nCustom ReactNativeHost that integrates with navigation:\n- Used instead of `DefaultReactNativeHost`\n- Provides proper module registration for navigation\n\n### Autolink Script (`npx rnn-link`)\n\nThe `autolink/postlink/postLinkAndroid.js` script automates setup:\n\n| Linker | What it does |\n|--------|--------------|\n| `ApplicationLinker` | Changes MainApplication to extend `NavigationApplication`, uses `NavigationReactNativeHost`, removes SoLoader.init() |\n| `ActivityLinker` | Changes MainActivity to extend `NavigationActivity`, removes `getMainComponentName()` |\n| `GradleLinker` | Updates build.gradle if needed |\n\n**ApplicationLinker transformations:**\n- `class MainApplication : Application(), ReactApplication` → `class MainApplication : NavigationApplication()`\n- `DefaultReactNativeHost(this)` → `NavigationReactNativeHost(this)`\n- Removes `SoLoader.init()` (NavigationApplication handles it)\n- Removes new architecture entry point load block\n\n**ActivityLinker transformations:**\n- `class MainActivity : ReactActivity()` → `class MainActivity : NavigationActivity()`\n- Removes `getMainComponentName()` override\n- Removes `createReactActivityDelegate()` override\n\n## Directory Structure\n\n```\nandroid/src/main/java/com/reactnativenavigation/\n├── NavigationActivity.java       # Main Activity entry point\n├── NavigationApplication.java    # Application class\n├── NavigationPackage.kt          # React package registration\n├── react/                        # React bridge layer\n│   ├── NavigationTurboModule.kt  # TurboModule implementation\n│   ├── ReactGateway.java         # React lifecycle management\n│   └── events/\n│       └── EventEmitter.java     # Event emission to JS\n├── options/                      # Options parsing and factories\n│   ├── LayoutFactory.java        # Creates ViewControllers from layout nodes\n│   └── Options.java              # Options model\n├── viewcontrollers/              # ViewController hierarchy\n│   ├── ViewController.java       # Base class\n│   ├── ChildController.java      # With presenter support\n│   ├── ParentController.java     # Container controllers\n│   ├── stack/                    # Stack navigation\n│   ├── bottomtabs/               # Bottom tabs\n│   ├── toptabs/                  # Top tabs (lowercase)\n│   ├── sidemenu/                 # Side menu/drawer\n│   ├── modal/                    # Modal management\n│   └── externalcomponent/        # Native component support\n├── views/                        # UI View implementations\n├── utils/                        # Utilities\n└── hierarchy/                    # Root layout management\n```\n\n## Bridge Architecture\n\n```\n┌────────────────────────────────────────────────────────────┐\n│                 JavaScript (TurboModule)                   │\n└─────────────────────────┬──────────────────────────────────┘\n                          │\n┌─────────────────────────▼──────────────────────────────────┐\n│  NavigationTurboModule.kt                                   │\n│  - setRoot, push, pop, showModal, dismissModal, etc.       │\n└─────────────────────────┬──────────────────────────────────┘\n                          │\n┌─────────────────────────▼──────────────────────────────────┐\n│  Navigator (Root ViewController)                           │\n│  - Manages root, modals, overlays                          │\n│  - Coordinates LayoutFactory                               │\n└──────┬──────────────┬──────────────┬──────────────┬────────┘\n       │              │              │              │\n┌──────▼─────┐ ┌──────▼─────┐ ┌──────▼─────┐ ┌─────▼──────┐\n│ModalStack  │ │OverlayMgr  │ │LayoutFactory│ │EventEmitter│\n└────────────┘ └────────────┘ └────────────┘ └────────────┘\n```\n\n## Entry Points\n\n### NavigationApplication\nAbstract Application class that apps extend:\n- Manages `ReactGateway` singleton\n- Initializes SoLoader\n- Provides `registerExternalComponent()` for native screens\n\n### NavigationActivity\nMain Activity containing all navigation:\n- Creates `Navigator` with three CoordinatorLayouts:\n  - `rootLayout` - Main navigation content\n  - `modalsLayout` - Modal stack\n  - `overlaysLayout` - Overlays (highest z-order)\n- Handles back press via `OnBackPressedCallback`\n- Coordinates activity lifecycle with React\n\n### NavigationTurboModule\nTurboModule implementation (Kotlin, ~300 lines):\n\n```kotlin\n@ReactMethod\nfun setRoot(commandId: String, layout: ReadableMap, promise: Promise)\n\n@ReactMethod\nfun push(commandId: String, componentId: String, layout: ReadableMap, promise: Promise)\n\n@ReactMethod\nfun showModal(commandId: String, layout: ReadableMap, promise: Promise)\n```\n\nAll commands execute on UI thread via `UiThread.post()`.\n\n## ViewController Hierarchy\n\n**Note**: Android implementation does NOT use Fragments - it's purely View-based.\n\n```\nViewController (abstract)\n│   - Base for all navigation controllers\n│   - Manages view creation and lifecycle\n│   - Handles options and back press\n│\n├── ChildController\n│   │   - Adds Presenter support\n│   │\n│   ├── ComponentViewController\n│   │       - Renders React components via ReactView\n│   │\n│   └── ExternalComponentViewController\n│           - Wraps native Android views\n│\n└── ParentController (extends ChildController)\n        - Container for child controllers\n        │\n        ├── StackController\n        │       - Push/pop navigation\n        │       - Uses IdStack<ViewController>\n        │\n        ├── BottomTabsController\n        │       - UITabBarController equivalent\n        │       - Uses AHBottomNavigation\n        │\n        ├── TopTabsController\n        │       - Horizontal ViewPager tabs\n        │\n        ├── SideMenuController\n        │       - DrawerLayout-based drawer\n        │\n        └── Navigator\n                - Root controller\n                - Manages modals and overlays\n```\n\n## Core Classes\n\n### ViewController (Base)\n**File**: `viewcontrollers/viewcontroller/ViewController.java` (~500 lines)\n\nAbstract base for all navigation controllers:\n\n```java\npublic abstract class ViewController<T extends ViewGroup> {\n    protected abstract T createView();  // Subclasses create views\n\n    public void onViewWillAppear() { }\n    public void onViewDidAppear() { }\n    public void onViewDisappear() { }\n\n    public void mergeOptions(Options options) { }\n    public void applyOptions(Options options) { }\n    public boolean handleBack(CommandListener listener) { }\n    public void destroy() { }\n}\n```\n\n### Navigator (Root)\n**File**: `viewcontrollers/navigator/Navigator.java`\n\nRoot ViewController managing:\n- Root content hierarchy\n- Modal stack (`ModalStack`)\n- Overlay manager (`OverlayManager`)\n- Component lookup by ID\n\n### LayoutFactory\n**File**: `options/LayoutFactory.java`\n\nFactory creating ViewControllers from LayoutNode. Owned by `NavigationTurboModule` and used to build the view controller hierarchy when commands are received from JavaScript.\n\n```java\npublic ViewController create(LayoutNode node) {\n    switch (node.type) {\n        case Component: return createComponent(node);\n        case Stack: return createStack(node);\n        case BottomTabs: return createBottomTabs(node);\n        case SideMenuRoot: return createSideMenuRoot(node);\n        case SideMenuCenter: return createSideMenuContent(node);\n        case SideMenuLeft: return createSideMenuLeft(node);\n        case SideMenuRight: return createSideMenuRight(node);\n        case TopTabs: return createTopTabs(node);\n        // Note: SplitView is iOS-only, not implemented on Android\n    }\n}\n```\n\n## Navigation Types\n\n### Stack Navigation (StackController)\n**Files**: `viewcontrollers/stack/`\n\n- View: `StackLayout` (CoordinatorLayout with TopBar)\n- Internal stack: `IdStack<ViewController<?>>`\n- Components: `TopBarController`, `StackAnimator`, `StackPresenter`, `FabPresenter`\n\nOperations:\n- `push(viewController, listener)`\n- `pop(options, listener)`\n- `popTo(target, options, listener)`\n- `popToRoot(options, listener)`\n- `setRoot(children, listener)`\n\n### Bottom Tabs (BottomTabsController)\n**Files**: `viewcontrollers/bottomtabs/`\n\n- View: `BottomTabsLayout` (CoordinatorLayout with BottomTabs)\n- Uses `AHBottomNavigation` library\n- Components: `BottomTabsPresenter`, `BottomTabPresenter`, `BottomTabsAnimator`\n\nAttachment Modes:\n- `TogetherAttacher` - Load all tabs immediately\n- `OnSwitchToTabAttacher` - Lazy load on selection\n- `AfterInitialTabAttacher` - Load initial + others in background\n\n### Side Menu (SideMenuController)\n**Files**: `viewcontrollers/sidemenu/`\n\n- View: `SideMenuRoot` (DrawerLayout-based)\n- Children: Center, Left, Right controllers\n- `SideMenuPresenter` for styling\n\n### Top Tabs (TopTabsController)\n**Files**: `viewcontrollers/toptabs/`\n\n- View: `TopTabsViewPager` (ViewPager-based)\n- `TopTabsLayoutCreator` for view creation\n\n### Modals (ModalStack)\n**Files**: `viewcontrollers/modal/`\n\nNot a ViewController - manages modal presentation:\n- `ModalPresenter` - Show/dismiss with animations\n- `ModalAnimator` (Kotlin) - Animation handling\n- Stack of modals with lifecycle management\n\n### Overlays (OverlayManager)\n**File**: `viewcontrollers/overlay/OverlayManager.kt`\n\nRegistry of active overlays:\n- Show/dismiss by component ID\n- Configuration change handling\n- Host pause/resume lifecycle\n\n## React Component Rendering\n\n### ComponentViewController\nManages React component lifecycle:\n- Creates `ComponentLayout` view\n- Initializes `ReactView` with ReactSurface\n- Emits lifecycle events to JS\n- Handles scroll events and status bar\n\n### ReactView\n**File**: `react/ReactView.java`\n\nExtends FrameLayout, wraps `ReactSurface`:\n- `start()` - Attach surface to React instance\n- `destroy()` - Clean up React surface\n- `sendComponentWillStart()` - Emit event to JS\n- `isReady()` - Check surface attachment\n\n## Event Emission\n\n### EventEmitter\n**File**: `react/events/EventEmitter.java`\n\nEvents sent to JavaScript:\n\n| Event | Description |\n|-------|-------------|\n| `RNN.AppLaunched` | App initialization complete |\n| `RNN.ComponentDidAppear` | Component visible |\n| `RNN.ComponentWillAppear` | About to become visible |\n| `RNN.ComponentDidDisappear` | Component hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tapped |\n| `RNN.BottomTabSelected` | Tab selection changed |\n| `RNN.BottomTabPressed` | Tab pressed (even if selected) |\n| `RNN.ModalDismissed` | Modal was dismissed |\n| `RNN.ScreenPopped` | Screen removed from stack |\n| `RNN.CommandCompleted` | Navigation command finished |\n\n## Options System\n\n### Options Class\n**File**: `options/Options.java`\n\n```java\npublic class Options {\n    public TopBarOptions topBar;\n    public TopTabsOptions topTabs;\n    public BottomTabsOptions bottomTabsOptions;\n    public BottomTabOptions bottomTabOptions;\n    public OverlayOptions overlayOptions;\n    public FabOptions fabOptions;\n    public AnimationsOptions animations;\n    public SideMenuRootOptions sideMenuRootOptions;\n    public ModalOptions modal;\n    public StatusBarOptions statusBar;\n    public NavigationBarOptions navigationBar;\n    public LayoutOptions layout;\n    public HardwareBackButtonOptions hardwareBack;\n}\n```\n\n### Options Flow\n1. **Parse**: JSON from JS → Options object via JSONParser\n2. **Merge**: Default → Screen → Component options\n3. **Apply**: Presenter applies to views\n\n## Presenter Pattern\n\nEach ViewController has a Presenter:\n\n| ViewController | Presenter |\n|---------------|-----------|\n| StackController | StackPresenter |\n| BottomTabsController | BottomTabsPresenter + BottomTabPresenter |\n| ComponentViewController | ComponentPresenter |\n| SideMenuController | SideMenuPresenter |\n| Navigator | RootPresenter |\n\n### Presenter Base\n**File**: `viewcontrollers/viewcontroller/Presenter.java`\n\nHandles:\n- Orientation changes\n- Status bar styling\n- Navigation bar styling\n- Layout parameters\n\n## Animation System\n\n### Animators (Kotlin)\n- `StackAnimator.kt` - Push, pop, setRoot animations\n- `ModalAnimator.kt` - Modal show/dismiss\n- `BottomTabsAnimator.kt` - Tab transitions\n- `TopBarAppearanceAnimator.kt` - Top bar changes\n\n### Element Transitions\nVia `TransitionAnimatorCreator.kt`:\n- Position, scale, rotation animations\n- Color transitions\n- Corner radius animations\n- Shared element support\n\n## Activity Lifecycle\n\n```java\nonCreate()      // Create Navigator, initialize React\nonPostCreate()  // Set content layout\nonResume()      // React host resume, event emitter setup\nonPause()       // React host pause\nonDestroy()     // Clean up Navigator\nonConfigurationChanged()  // Handle orientation, locale\nonNewIntent()   // Process deep links\nonActivityResult()  // Handle permissions\n```\n\n## ViewController Lifecycle\n\n```\nView creation\n    ↓\nonViewWillAppear()   // Register with registry\n    ↓\nonViewDidAppear()    // Emit event to JS\n    ↓\n[visible]\n    ↓\nonViewWillDisappear()\n    ↓\nonViewDisappear()    // Unregister from registry\n    ↓\ndestroy()            // Complete cleanup\n```\n\n## Key Files Reference\n\nAll paths relative to `android/src/main/java/com/reactnativenavigation/`:\n\n| File | Path | Purpose |\n|------|------|---------|\n| NavigationActivity.java | `.` | Main Activity |\n| NavigationApplication.java | `.` | Application class |\n| NavigationTurboModule.kt | `react/` | JS bridge |\n| Navigator.java | `viewcontrollers/navigator/` | Root controller |\n| ViewController.java | `viewcontrollers/viewcontroller/` | Base class |\n| StackController.java | `viewcontrollers/stack/` | Stack navigation |\n| BottomTabsController.java | `viewcontrollers/bottomtabs/` | Tab navigation |\n| LayoutFactory.java | `options/` | Controller factory |\n| Options.java | `options/` | Options model |\n| Presenter.java | `viewcontrollers/viewcontroller/` | Base presenter |\n| EventEmitter.java | `react/events/` | JS events |\n| ReactView.java | `react/` | React component wrapper |\n| StackAnimator.kt | `viewcontrollers/stack/` | Stack animations |\n| ModalStack.java | `viewcontrollers/modal/` | Modal management |\n",".claude/skills/rn-version-upgrade.md":"# Skill: Add Support for a New React Native Version\n\nThis skill guides the process of adding support for a new React Native version to react-native-navigation (RNN). It covers CI setup, dependency analysis, native code fixes, playground validation, and the version-switch infrastructure.\n\n## Prerequisites\n\nBefore starting, gather:\n- The target RN version number (e.g., `0.84.0`)\n- The previous highest supported RN version (check `package.json` and `.buildkite/pipeline.sh`)\n\n## Phase 1: Research Breaking Changes\n\n**This phase is critical and prevents most downstream failures. Do it thoroughly before writing any code.**\n\n### 1a. Read the RN Release Blog & Changelog\n\nFetch the release blog post and changelog for the target version:\n- Blog: `https://reactnative.dev/blog` (search for the version)\n- Changelog: `https://github.com/facebook/react-native/blob/main/CHANGELOG.md`\n\nFocus on:\n- **Removed APIs/classes** (iOS and Android) -- these cause compile errors\n- **Changed method signatures** (Android) -- parameters becoming non-nullable, new required params, etc. (e.g., `ColorPropConverter.getColor()` changed in 0.80)\n- **Deprecated APIs now removed** -- check if RNN uses any deprecated APIs from prior versions\n- **Architecture changes** (e.g., New Architecture enforcement, legacy arch removal)\n- **Build system changes** -- Gradle version, Android SDK levels, Kotlin version, CocoaPods/podspec changes, Xcode requirements\n- **Header/import changes** -- headers moved, renamed, or removed from precompiled binaries\n- **CocoaPods / podspec changes** -- Check if RN changed how native modules declare dependencies (e.g., the shift to `install_modules_dependencies` in 0.80). Review `ReactNativeNavigation.podspec` for hardcoded dependency lists, header search paths, or compiler flags that may need updating.\n- **Kotlin version requirements** -- Newer RN versions may require newer Kotlin versions (e.g., RN 0.79+ requires Kotlin 2.x). Check if the version needs bumping.\n\n### 1b. Check RNN's Usage of Known Risk Areas\n\nSearch the RNN codebase for any classes/headers mentioned as removed or changed:\n\n```bash\n# Search iOS for legacy RCT headers (common removal targets)\ngrep -rn \"#import <React/RCT\" ios/ --include=\"*.h\" --include=\"*.mm\" --include=\"*.m\"\n\n# Search Android for deprecated classes\ngrep -rn \"CSSBackgroundDrawable\\|onCatalystInstanceDestroy\\|ReactInstanceManager\" android/ --include=\"*.java\" --include=\"*.kt\"\n\n# Check Android test infrastructure for classes extending RN framework classes\ngrep -rn \"extends.*React\\|: React\" android/ --include=\"*.java\" --include=\"*.kt\" | grep -i \"test\\|mock\\|simple\"\n```\n\n**If the new RN version strips legacy headers from the xcframework** (look for `RCT_REMOVE_LEGACY_ARCH` changes in the RN release), identify ALL iOS files importing legacy-only headers and plan to guard them in batch. Do NOT rely on iterative build failures to find them one by one. Cross-reference each `#import <React/RCT...>` against the headers actually available in the new RN version's xcframework.\n\n### 1c. Check Third-Party Dependency Compatibility\n\nFor each playground dependency that wraps native code, verify compatibility with the target RN version:\n\n1. **react-native-reanimated** -- Check https://docs.swmansion.com/react-native-reanimated/docs/guides/compatibility/ for the compatibility table. This is the most frequent source of build failures.\n2. **react-native-gesture-handler** -- Check release notes for RN version support.\n3. **react-native-fast-image** (or `@d11/react-native-fast-image`) -- Check for Fabric/new arch support.\n4. **react-native-worklets** -- Must be compatible with the reanimated version you chose.\n5. **Other native deps** -- Check each one's GitHub releases/issues for RN version support.\n\nAlso check the full peer dependency tree: `npm info react-native@<version> peerDependencies` for all peer deps, not just `react`.\n\n**Key lesson from RN 0.84**: Reanimated 4.2.0 did NOT support RN 0.84 (needed 4.2.2+). The `react-native-worklets` package also needed bumping (0.7.1 -> 0.7.4). Not catching this early means the build will fail late in the process.\n\n**Key lesson from RN 0.83**: The original `react-native-fast-image` package was abandoned and had no Fabric support. The `@d11/react-native-fast-image` fork was needed as a replacement. When replacing a package, check ALL references: package.json (root AND playground), TypeScript imports, Android `build.gradle` manual `implementation project()` lines, and iOS pod references.\n\n## Phase 2: CI Infrastructure Setup\n\n### 2a. Maintain Buildkite CI Jobs\n\nCopy an existing job file and update the version:\n\n```bash\n# Copy from the latest supported RN lane (adjust source/target versions)\ncp .buildkite/jobs/pipeline.android_rn_84.yml .buildkite/jobs/pipeline.android_rn_85.yml\ncp .buildkite/jobs/pipeline.ios_rn_84.yml .buildkite/jobs/pipeline.ios_rn_85.yml\n```\n\nEdit both files:\n- Update the label: `\":android: Android (RN 0.84.0)\"`\n- Update `REACT_NATIVE_VERSION: 0.84.0`\n- Update the key: `\"android_rn_84\"` / `\"ios_rn_84\"`\n- Keep `JAVA_HOME` on Android jobs (check if JDK version needs bumping)\n\n### 2b. Register Jobs in Pipeline Script\n\nAdd the new jobs to `.buildkite/pipeline.sh`:\n\n```bash\ncat .buildkite/jobs/pipeline.android_rn_84.yml\ncat .buildkite/jobs/pipeline.ios_rn_84.yml\n```\n\nInsert them in version order alongside the other platform jobs. Release publishing is dispatched separately through the GitHub Actions release workflow.\n\n### 2c. Optionally Drop Old Versions\n\nIf the project drops support for an old version, remove its pipeline files and entries from `pipeline.sh`. RN 0.82 PR dropped RN 0.80 and 0.81 pipelines.\n\n## Phase 3: Update Default Versions and Build Configuration\n\n### 3a. Update `package.json` (Root and Playground)\n\nUpdate in both `/package.json` and `/playground/package.json`:\n- `react-native` to the target version\n- `react` to the matching peer dependency version (check `npm info react-native@0.84.0 peerDependencies.react`)\n- `react-test-renderer` to match react\n- `@react-native/babel-preset`, `@react-native/eslint-config`, `@react-native/metro-config`, `@react-native/typescript-config` to `0.<minor>.0`\n- `@react-native-community/cli`, `cli-platform-android`, `cli-platform-ios` to matching CLI version\n- Any third-party deps identified in Phase 1c as needing version bumps\n\n### 3b. Update Android SDK, NDK, and Kotlin Versions\n\nCheck the target RN version's requirements and update in **both** `android/build.gradle` (the library defaults) and `playground/android/build.gradle`:\n- `compileSdkVersion` / `compileSdk`\n- `targetSdkVersion` / `targetSdk`\n- `buildToolsVersion`\n- `ndkVersion`\n- Kotlin version (`kotlinVersion` / `RNNKotlinVersion`)\n\nCross-reference with the RN template app's `build.gradle` for the target version (`npx @react-native-community/cli init` or check the RN GitHub repo).\n\nAlso update `autolink/fixtures/rn79/build.gradle.template` if SDK or Kotlin versions changed there.\n\n### 3c. Update Gradle Wrapper\n\nIf the target RN requires a newer Gradle version, update `playground/android/gradle/wrapper/gradle-wrapper.properties`.\n\n### 3d. Update Version-Switch Infrastructure\n\nUpdate `scripts/versionMapping.js`:\n- Add the new minor version to `CLI_VERSION_MAP`\n- Update `getGradleVersion()` if the Gradle version requirement changed\n- Update `getReanimatedOverride()` / `shouldRemoveWorklets()` if compatibility ranges changed\n\nUpdate `playground/android/rninfo.gradle` if new version-conditional logic is needed:\n- Add new boolean flags (e.g., `isRN84OrHigher`) if Gradle build logic needs to branch on the new version\n- Used for things like Kotlin version branching and conditional dependency resolution\n\n### 3e. Review and Update Podspec and Podfile\n\n**`ReactNativeNavigation.podspec`** may need changes if RN altered how native modules declare dependencies:\n- Manual `s.dependency` lists for React submodules may be replaced by `install_modules_dependencies(s)` (happened in 0.80)\n- Hardcoded `HEADER_SEARCH_PATHS`, folly compiler flags, or per-arch dependency lists may become unnecessary\n- Compare against the new RN version's recommended podspec pattern\n\n**`playground/ios/Podfile`** may need restructuring if RN changed `use_react_native!`, new arch configuration, or post-install hooks. Compare against the RN template app's Podfile for the target version.\n\n### 3f. Install Dependencies\n\nAfter updating package.json and build configs:\n\n```bash\ncd playground && yarn install && cd ios && pod deintegrate && pod install && cd ../..\n```\n\n### 3g. Clean Stale Xcode Build Settings\n\n**Do this BEFORE the first build** -- stale settings cause mysterious \"module not found\" errors.\n\nThe `playground/ios/playground.xcodeproj/project.pbxproj` may contain hardcoded build settings from previous RN versions (e.g., `REACT_NATIVE_MINOR_VERSION=72`, stale modulemap paths in `OTHER_CFLAGS`). Search for and remove/fix these:\n\n```bash\ngrep -n \"REACT_NATIVE_MINOR_VERSION\\|REANIMATED_VERSION\\|modulemap\" playground/ios/playground.xcodeproj/project.pbxproj\n```\n\nReplace hardcoded values with `\"$(inherited)\"` where appropriate.\n\n## Phase 4: Fix Native Compilation Errors\n\n### Strategy\n\nFor **systematic, known patterns** identified in Phase 1 (like legacy import guarding across many files), fix all instances in batch before building. This avoids slow iterative build cycles.\n\nFor **unexpected errors**, use an iterative build-fix approach: build, fix the first error, rebuild, repeat.\n\n```bash\n# iOS build\nxcodebuild build -workspace playground/ios/playground.xcworkspace \\\n  -scheme playground -configuration Debug -sdk iphonesimulator \\\n  -destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' -quiet\n\n# Android build\ncd playground/android && ./gradlew assembleDebug\n```\n\n### 4a. Batch-Fix: Guard Legacy iOS Imports\n\nIf the new RN version removes legacy headers from precompiled binaries, guard ALL identified imports at once.\n\n**Preferred approach: `__has_include` (compile-time header check)**\n\nThe best way to guard optional headers is `#if __has_include(...)`. This is forward-compatible — if a future RN version removes more headers, the code adapts automatically without needing new flags:\n\n```objc\n#if __has_include(<React/RCTScrollView.h>)\n#import <React/RCTScrollView.h>\n#endif\n\n#if __has_include(<React/RCTCxxBridgeDelegate.h>)\n#import <React/RCTCxxBridgeDelegate.h>\n#endif\n```\n\nUse `__has_include` for **imports** where the header may or may not exist. Then use `NSClassFromString` (see Pattern 3 below) for runtime references to classes from those headers.\n\n**Alternative: `#ifndef RCT_REMOVE_LEGACY_ARCH`**\n\nStarting with RN 0.84, React Native defines `RCT_REMOVE_LEGACY_ARCH=1` when legacy/bridge APIs are fully removed. This is more precise than `RCT_NEW_ARCH_ENABLED` (which has been true since RN 0.76 even though legacy APIs were still available). Use this for guarding **code blocks** that use legacy APIs:\n\n```objc\n#ifndef RCT_REMOVE_LEGACY_ARCH\n#import <React/RCTModalHostViewManager.h>\n#endif\n\n// In implementation:\n#ifndef RCT_REMOVE_LEGACY_ARCH\n- (void)connectModalHostViewManager:(RCTModalHostViewManager *)manager {\n    // old-arch-only code\n}\n#endif\n```\n\n**When to use which:**\n- `__has_include(...)` — for **imports** of headers that may not exist. Most robust, no flag dependency.\n- `#ifndef RCT_REMOVE_LEGACY_ARCH` — for **code blocks** using legacy APIs (method declarations, implementations, protocol conformances). Semantically correct: \"this code requires the legacy arch.\"\n- `#ifdef RCT_NEW_ARCH_ENABLED` — only for code that differs **between architectures** (e.g., `RCTHost` vs `RCTBridge` parameters). NOT for \"is legacy available?\" checks.\n\n**Steps:**\n\n1. List all files importing legacy headers:\n   ```bash\n   grep -rn \"#import <React/RCTRootView\\|#import <React/RCTRootViewDelegate\\|#import <React/RCTBridge+Private\\|#import <React/RCTModalHostView\\|#import <React/RCTScrollView\\|#import <React/RCTRootContentView\\|#import <React/RCTSurfacePresenterStub\\|#import <React/RCTBridgeProxy\" ios/ --include=\"*.h\" --include=\"*.mm\"\n   ```\n\n2. For each file, apply the appropriate guard (prefer `__has_include` for imports, `#ifndef RCT_REMOVE_LEGACY_ARCH` for code blocks).\n\n3. **Guard the full chain**: import -> type usage -> method declarations -> protocol conformances -> method implementations. Guarding just the import without guarding the code that uses the type causes \"undeclared identifier\" errors.\n\n4. **Check for dead code in `#ifdef` blocks**: After guarding imports, search for old-arch symbols referenced in new-arch code paths:\n   ```bash\n   # Find potential dead references to bridge in new-arch blocks\n   grep -n \"getBridge\\|bridgeManager\\|RCTBridge\" ios/ --include=\"*.mm\" -r\n   ```\n   Cross-reference hits with their surrounding `#ifdef` context. Remove any new-arch code that calls old-arch-only methods.\n\n### 4b. Common iOS Fix Patterns\n\n**Pattern 1: Guard optional imports with `__has_include`** -- Preferred for headers that may not exist:\n```objc\n#if __has_include(<React/RCTSurfacePresenterBridgeAdapter.h>)\n#import <React/RCTSurfacePresenterBridgeAdapter.h>\n#endif\n```\n\n**Pattern 2: Guard legacy code blocks with `RCT_REMOVE_LEGACY_ARCH`** -- For methods/classes that only exist on old arch:\n```objc\n#ifndef RCT_REMOVE_LEGACY_ARCH\n- (void)connectModalHostViewManager:(RCTModalHostViewManager *)manager { ... }\n#endif\n```\n\n**Pattern 3: Guard entire files** -- If a file is only used on old arch (e.g., `RNNBridgeManager.h/.mm`), wrap the entire content in `#ifndef RCT_REMOVE_LEGACY_ARCH`.\n\n**Pattern 4: Runtime class lookup** -- When you need to reference a class that may not exist at compile time (e.g., in `hitTest:withEvent:` or `isKindOfClass:` checks), use `NSClassFromString` instead of direct class references. This pairs well with `__has_include` — the import is conditional, and the runtime check handles the case where the class doesn't exist:\n\n```objc\n// Instead of: [view isKindOfClass:[RCTModalHostView class]]\n[view isKindOfClass:NSClassFromString(@\"RCTModalHostView\")]\n```\n\nCache the result with `dispatch_once` if it's in a hot path:\n```objc\nstatic Class myClass;\nstatic dispatch_once_t onceToken;\ndispatch_once(&onceToken, ^{\n    myClass = NSClassFromString(@\"RCTModalHostView\");\n});\n```\n\n**Pattern 5: Remove dead code paths** -- A `#ifdef RCT_NEW_ARCH_ENABLED` block that calls `getBridge` (old-arch only) is dead code -- remove it.\n\n**Pattern 6: Protocol conformance guards** -- If a protocol (e.g., `RCTRootViewDelegate`) only exists on old arch, guard the conformance declaration AND the delegate method implementations:\n\n```objc\n@interface MyView : UIView\n#ifndef RCT_NEW_ARCH_ENABLED\n                    <RCTRootViewDelegate>\n#endif\n```\n\n### 4c. Common Android Fix Patterns\n\n**Pattern 1: Deprecated method migration** -- When RN deprecates methods with `forRemoval = true`, rename to the replacement (e.g., `onCatalystInstanceDestroy()` -> `invalidate()`). Note: only rename the RN framework override, not internal RNN methods with the same name.\n\n**Pattern 2: Removed classes** -- When Android classes are removed (e.g., `CSSBackgroundDrawable` in RN 0.83), replace with standard Android equivalents (e.g., `ColorDrawable`).\n\n**Pattern 3: Test infrastructure** -- Test/mock classes that extend RN framework classes (e.g., `SimpleView extends ReactView`) may need refactoring if the parent class behavior changed. Also check Robolectric version compatibility -- newer Android SDK levels may require bumping Robolectric, and if the new Robolectric version requires a higher Java version than CI provides, add a `robolectric.properties` file to pin the SDK level (e.g., `sdk=35` when SDK 36 requires Java 21 but CI uses Java 17).\n\n**Pattern 4: Changed method signatures** -- RN may change method signatures without deprecation (e.g., nullable parameters becoming non-nullable, or new required parameters). These cause compile errors that aren't caught by searching for removed/deprecated APIs. Check the RN changelog for API changes in utility classes like `ColorPropConverter`, `ColorParser`, etc.\n\n### 4d. Research Before Fixing: Don't Just Pattern-Match\n\n**When you hit a new compilation error, resist the urge to immediately copy the fix pattern from nearby code.** Instead:\n\n1. **Check what the target RN version introduces.** Read the RN changelog/blog for new preprocessor flags, build system features, or recommended migration patterns. For example, RN 0.84 introduced `RCT_REMOVE_LEGACY_ARCH` — a flag specifically designed for the exact guarding problem we need to solve. Using it is better than repurposing `RCT_NEW_ARCH_ENABLED`.\n\n2. **Search for how other RN libraries solved it.** Check how major community libraries (react-native-screens, react-native-reanimated, react-native-gesture-handler) handle the same compatibility issue. They often discover better patterns first.\n\n3. **Evaluate the existing codebase pattern critically.** The pattern used in the current code may predate better alternatives. Ask: is there a more forward-compatible approach? Would `__has_include` be more robust than a flag check? Would `NSClassFromString` be cleaner than a compile-time guard?\n\n4. **Prefer compile-time safety over runtime safety, and standard compiler features over framework-specific flags.** `__has_include` is a C/ObjC compiler feature that works regardless of RN version. Framework flags like `RCT_REMOVE_LEGACY_ARCH` are next best. `NSClassFromString` is a runtime fallback for when compile-time checks aren't sufficient.\n\n### 4e. Compile Error Triage\n\nWhen you get a compile error:\n1. Identify the missing symbol (header, class, method)\n2. **Research** the best available guard mechanism (see 4d above)\n3. Check if it's used only in old-arch or new-arch code paths\n4. If old-arch only: guard with `__has_include` (imports) or `#ifndef RCT_REMOVE_LEGACY_ARCH` (code)\n5. If new-arch only: this shouldn't happen -- investigate the API replacement\n6. If used in both: find the new-arch equivalent and branch with `#ifdef RCT_NEW_ARCH_ENABLED`\n\n### 4e. Fix Test Files\n\n**Test files are easily overlooked.** They often reference arch-specific APIs (like `RCTBridge` vs `RCTHost`, or methods that only exist under `#ifdef RCT_NEW_ARCH_ENABLED`). Check all test files for arch-specific calls:\n\n```bash\n# Find test files referencing RCTBridge (old-arch only in new-arch builds)\ngrep -rn \"RCTBridge\\|registerExternalComponent\" playground/ios/NavigationTests/ --include=\"*.mm\"\n\n# Check that test method calls match the current header signatures\n# e.g., RNNExternalComponentStore exposes different methods under #ifdef RCT_NEW_ARCH_ENABLED\n```\n\nGuard test code the same way as production code — use `#ifndef RCT_REMOVE_LEGACY_ARCH` for tests that only apply to legacy arch:\n\n```objc\n#ifndef RCT_REMOVE_LEGACY_ARCH\n\n@interface RNNModalHostViewManagerHandlerTest : XCTestCase\n@end\n// ... entire test class ...\n@end\n\n#endif\n```\n\n**Key lesson from RN 0.84**: All 4 iOS CI jobs failed because a single test file (`RNNViewControllerFactoryTest.mm`) called an old-arch method on `RNNExternalComponentStore` without a guard. The fix was trivial but blocked the entire build.\n\n### 4f. clang-format\n\nRNN uses clang-format on iOS files via a pre-commit hook. After editing `.h`/`.mm` files, verify formatting:\n\n```bash\n./node_modules/.bin/git-clang-format --diff -- ios/MyFile.mm\n```\n\nThe formatter has opinions about `#ifdef` indentation that may require unusual formatting (e.g., protocol conformance on a continuation line after `#ifndef`).\n\n## Phase 5: Validate Playground Dependencies\n\n### 5a. Check for Stale References\n\nAfter replacing any dependency (like fast-image -> @d11/fast-image), search for ALL references:\n\n```bash\n# TypeScript imports\ngrep -r \"react-native-fast-image\" playground/src/ --include=\"*.ts\" --include=\"*.tsx\"\n\n# Android gradle -- look for manual implementation project() lines\ngrep -r \"fast-image\\|fast_image\" playground/android/ --include=\"*.gradle\"\n\n# iOS podfile\ngrep -r \"fast-image\\|FastImage\" playground/ios/Podfile\n```\n\nNote: `autolinkLibrariesWithApp()` in the playground's `build.gradle` handles most deps automatically. Manual `implementation project(':...')` lines are often stale and should be removed when the package is autolinked.\n\n## Phase 6: Full Build Verification\n\nRun both platform builds to confirm everything compiles:\n\n```bash\n# iOS\nxcodebuild build -workspace playground/ios/playground.xcworkspace \\\n  -scheme playground -configuration Debug -sdk iphonesimulator \\\n  -destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' -quiet\n\n# Android\ncd playground/android && ./gradlew assembleDebug\n\n# JS tests\nyarn test-js\n```\n\n## Phase 7: Backward Compatibility\n\nVerify that the version-switch script works for older supported versions:\n\n```bash\nREACT_NATIVE_VERSION=0.83.0 node scripts/changeReactNativeVersion.js\n# Then rebuild to verify\n```\n\n## Phase 8: Documentation\n\nUpdate `website/docs/docs/docs-Installing.mdx`:\n- Update the supported RN version range\n- Note any breaking changes users need to be aware of\n\n## Common Pitfalls (Lessons Learned)\n\n1. **Don't assume deps are compatible** -- Always check third-party native dep compatibility tables BEFORE starting the build. Reanimated is the most common offender.\n\n2. **Search for ALL references when replacing a package** -- TypeScript imports, Android gradle `implementation project()` lines, iOS pod references, root AND playground package.json. Missing one causes CI failures.\n\n3. **Legacy headers in precompiled binaries** -- When RN enforces new arch by default (like 0.84 with `RCT_REMOVE_LEGACY_ARCH=1`), headers for old-arch classes are stripped from the xcframework. Use `__has_include` for conditional imports and `#ifndef RCT_REMOVE_LEGACY_ARCH` for code blocks. Batch-fix all legacy imports identified in Phase 1b rather than finding them one build at a time.\n\n4. **Guard code, not just imports** -- Guarding an import without guarding the code that uses the imported types leads to \"undeclared identifier\" errors. Always guard the full chain: import -> type usage -> method declarations -> method implementations.\n\n5. **Dead code in `#ifdef` blocks** -- When splitting code paths between old/new arch, check that each path only references symbols available in that architecture. A common bug is new-arch code calling old-arch-only methods (like `getBridge` in a `#ifdef RCT_NEW_ARCH_ENABLED` block).\n\n6. **Stale Xcode project settings** -- The `.pbxproj` file can accumulate hardcoded build flags from old versions. These cause mysterious \"module not found\" errors. Check for stale `OTHER_CFLAGS` BEFORE the first build (Phase 3g).\n\n7. **clang-format surprises** -- The formatter enforces specific indentation around preprocessor directives. Run the check before committing to avoid hook failures.\n\n8. **Batch-fix systematic patterns, iterate on surprises** -- When you identify a pattern that affects many files (like legacy import guarding), fix all instances at once. Use iterative build-fix only for unexpected or one-off errors.\n\n9. **Android SDK level cascading effects** -- Bumping `compileSdkVersion`/`targetSdkVersion` can require bumping Robolectric, which may require a higher Java version than CI provides. Solution: pin the Robolectric SDK via `robolectric.properties` (e.g., `sdk=35` when SDK 36 needs Java 21).\n\n10. **Podspec can be a major effort** -- Don't underestimate podspec changes. RN 0.80 required replacing the entire dependency declaration strategy. Compare your podspec against the RN template's pattern for the target version.\n\n11. **Don't forget test files** -- Test files (`NavigationTests/*.mm`) often call arch-specific APIs directly. When guarding production code, search test files for the same APIs and guard them too. A single unguarded test call can fail the entire CI build across all RN versions.\n\n12. **Don't just follow existing patterns — research better ones** -- When fixing a compilation error, don't blindly copy the guarding pattern already used in the codebase. The existing pattern may predate better alternatives introduced in newer RN versions. For example, RN 0.84 introduced `RCT_REMOVE_LEGACY_ARCH` and the codebase already supported `__has_include`, but initial fixes used the older `#ifdef RCT_NEW_ARCH_ENABLED` pattern because that's what the existing code used. Always check: what new preprocessor flags or build-system features does the target RN version introduce? Is there a more robust/forward-compatible way to solve this?\n",".cursor/rules/github-descriptions.mdc":"---\ndescription: When the user asks for a GitHub description or PR description\nglobs:\nalwaysApply: false\n---\n\nWhen generating GitHub descriptions (PR descriptions, issue descriptions, commit descriptions), always use GitHub-flavored Markdown formatting: **bold** for emphasis, `backticks` for code/class/file references, bullet lists with `-`, and `##` headers where appropriate.\n",".cursor/skills/engine-e2e/SKILL.md":"---\nname: engine-e2e\ndescription: Run Wix Engine (mobile-apps-engine) iOS E2E tests locally to validate RNN changes. Use when you need to test RNN fixes against the Engine's Detox test suite.\n---\n\n# Running Engine E2E Tests Against Local RNN Changes\n\nThe Engine app (`@wix/wix-one-app-engine`) in `~/Documents/mobile-apps-engine` consumes RNN\nfrom `node_modules/react-native-navigation`. To test RNN changes against the Engine's E2E\nsuite, you patch the Engine's copy of RNN, rebuild the native binary, and run the tests.\n\n## Prerequisites\n\n- Node via nvm (`nvm use default`)\n- The `CI` env var must be **unset** (not `0`, fully unset) to avoid CI-specific codepaths.\n  Use `env -u CI` before every command.\n- The Engine repo at `~/Documents/mobile-apps-engine` with `yarn install` already done.\n\n## Step 1: Patch RNN in Engine's node_modules\n\nApply your RNN source changes to the corresponding files under:\n```\n~/Documents/mobile-apps-engine/node_modules/react-native-navigation/ios/\n```\nThe directory structure mirrors the RNN repo's `ios/` folder exactly.\n\n## Step 2: Rebuild the iOS Native Binary\n\n```bash\ncd ~/Documents/mobile-apps-engine\nunset PREFIX && . ~/.nvm/nvm.sh > /dev/null && nvm use default > /dev/null\nenv -u CI yarn workspace @wix/mobile-apps-engine-native-builds build-local-ios\n```\n\nThis runs `xcodebuild` with `-quiet` flag — expect no output until it finishes.\nTakes ~10-15 minutes on M-series Macs.\n\nThe build output (`.app` bundle) lands in:\n```\npackages/native/mobile-apps-engine-native-builds/dist/binaries.json\n```\n\n### Troubleshooting Build\n\n- **Keychain error** (`SecKeychainUnlock`): The `CI` env var is set. Use `env -u CI`.\n- **Signing errors**: Expected for local builds — the script handles ad-hoc signing.\n\n## Step 3: Build JS Bundles (first time only)\n\nThese are needed once per checkout. Skip if already built.\n\n```bash\nenv -u CI yarn workspace @wix/mobile-apps-engine-extra-bundle local:build\nenv -u CI yarn workspace @wix/mobile-apps-dependencies local:build\n```\n\n## Step 4: Run E2E Tests\n\n```bash\ncd ~/Documents/mobile-apps-engine\nunset PREFIX && . ~/.nvm/nvm.sh > /dev/null && nvm use default > /dev/null\nenv -u CI yarn workspace @wix/wix-one-app-engine test:e2e:ios -w d <suite_files...>\n```\n\nThe `-w d` flag selects the Detox worker count.\n\n### Specific suites relevant to RNN\n\n| Suite file | What it tests |\n|-----------|---------------|\n| `e2e/suites/ExternalLinks.test.js` | Deep link navigation, back button |\n| `e2e/suites/ExternalLinksModes.test.js` | Deep link modes (pop to root, tab switch) |\n| `e2e/suites/ExternalLinksPushNotifications.test.js` | Push notification deep links |\n| `e2e/suites/ExtenalLinksWithSiteSelect.test.js` | Deep links with site selection |\n| `e2e/suites/EngineUIComponents.test.js` | Error screen, UI components |\n| `e2e/suites/LaunchArgs.test.js` | Launch arguments |\n| `e2e/suites/LazyModules.test.js` | Lazy-loaded modules |\n\n### Example: Run the deep-link suites\n\n```bash\nenv -u CI yarn workspace @wix/wix-one-app-engine test:e2e:ios -w d \\\n  e2e/suites/ExternalLinks.test.js \\\n  e2e/suites/ExternalLinksModes.test.js \\\n  e2e/suites/ExternalLinksPushNotifications.test.js\n```\n\n### Troubleshooting Tests\n\n- **`Error: No dist version found`**: The native build hasn't run or failed.\n  Run step 2 again.\n- **`Cannot find module .../mobile-apps-engine-extra-bundle/index.js`**:\n  Run step 3 (`local:build` for extra-bundle).\n- **`ENOENT .../metadata.json`**: Run step 3 (`local:build` for mobile-apps-dependencies).\n- **`Unable to resolve module @rozenite/...`**: The Rozenite plugin import is broken.\n  Patch `packages/wix-one-app-engine/src/rozenitePlugin/helper/rozenite-network-inspector.ts`\n  to make the import optional with a no-op fallback.\n- **Tests time out on `navigateBack()`**: The `navigateBack()` helper taps\n  `element(by.id('pop'))` on iOS. This relies on RNN's `setBackButtonTestID` working\n  correctly. If the back button's view hierarchy changed (e.g., iOS 26 Liquid Glass),\n  the testID isn't applied and the element can't be found.\n\n## Key Engine Files\n\n| File | Purpose |\n|------|---------|\n| `packages/wix-one-app-engine/e2e/helpers/utils.js` | Test helpers including `navigateBack()` |\n| `packages/wix-one-app-engine/demo-modules/deep-links/module.js` | Deep link route definitions |\n| `packages/wix-one-app-engine/demo-modules/deep-links/Screens.js` | Deep link screen components |\n| `packages/wix-one-app-engine/internalScripts/test-e2e.js` | E2E test runner script |\n| `packages/native/mobile-apps-engine-native-builds/local_build_scripts/build_ios.js` | Local iOS build script |\n\n",".github/skills/rnn-codebase/SKILL.md":"---\nname: rnn-codebase\ndescription: Navigate and work with the react-native-navigation (RNN) codebase. Use when fixing bugs, adding features, tracing command flows, understanding options resolution, or working across JS/iOS/Android layers in this repo.\n---\n\n# React Native Navigation Codebase\n\n## Architecture Overview\n\nRNN has three layers that mirror each other:\n\n```\nJS/TS (src/)  →  TurboModule bridge  →  iOS native (ios/)\n                                     →  Android native (android/)\n```\n\nA navigation command (e.g. `push`) flows:\n1. `Navigation.push()` → `Commands.ts` → processing pipeline → `NativeCommandsSender.ts`\n2. TurboModule: `RNNTurboModule` (iOS) / `NavigationTurboModule.kt` (Android)\n3. iOS: `RNNCommandsHandler` → `RNNViewControllerFactory` → UIKit controllers\n4. Android: `Navigator` → `LayoutFactory` → View-based controllers (no Fragments)\n\nRead [ARCHITECTURE.md](../../../ARCHITECTURE.md) for the full overview.\n\n## Key Cross-Layer Mappings\n\n### Layout Types → Native Controllers\n\n| JS Layout Type | iOS Controller | Android Controller |\n|----------------|---------------|-------------------|\n| `component` | `RNNComponentViewController` | `ComponentViewController` |\n| `stack` | `RNNStackController` (UINavigationController) | `StackController` |\n| `bottomTabs` | `RNNBottomTabsController` (UITabBarController) | `BottomTabsController` |\n| `sideMenu` | `RNNSideMenuViewController` (MMDrawerController) | `SideMenuController` (DrawerLayout) |\n| `topTabs` | `RNNTopTabsViewController` | `TopTabsController` (ViewPager) |\n| `splitView` | `RNNSplitViewController` | N/A (iOS only) |\n| `externalComponent` | `RNNExternalViewController` | `ExternalComponentViewController` |\n\n### Options → Presenters\n\nEach controller type has a Presenter that applies options to views:\n\n| iOS Controller | iOS Presenter | Android Presenter |\n|----------------|--------------|-------------------|\n| `RNNComponentViewController` | `RNNComponentPresenter` | `ComponentPresenter` |\n| `RNNStackController` | `RNNStackPresenter` + `TopBarPresenter` | `StackPresenter` |\n| `RNNBottomTabsController` | `RNNBottomTabsPresenter` | `BottomTabsPresenter` |\n| `RNNSideMenuViewController` | `RNNSideMenuPresenter` | `SideMenuPresenter` |\n\n### Events (same names both platforms)\n\n| Event | Trigger |\n|-------|---------|\n| `RNN.ComponentDidAppear` | Screen becomes visible |\n| `RNN.ComponentDidDisappear` | Screen hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tap |\n| `RNN.BottomTabSelected` | Tab changed |\n| `RNN.ModalDismissed` | Modal dismissed |\n| `RNN.ScreenPopped` | Screen popped from stack |\n| `RNN.CommandCompleted` | Any command finished |\n\n## Where to Find Things\n\n### By task: \"I need to fix/change X\"\n\n| Task | JS File(s) | iOS File(s) | Android File(s) |\n|------|-----------|------------|----------------|\n| Command execution | `src/commands/Commands.ts` | `ios/RNNCommandsHandler.mm` | `react/NavigationTurboModule.kt` |\n| Layout creation | `src/commands/LayoutTreeParser.ts` | `ios/RNNViewControllerFactory.mm` | `options/LayoutFactory.java` |\n| Options processing | `src/commands/OptionsProcessor.ts` | `ios/RNNNavigationOptions.mm` | `options/Options.java` |\n| Options application | — | `ios/*Presenter.mm` | `viewcontrollers/*Presenter.java` |\n| TopBar | `src/interfaces/Options.ts` (TopBarOptions) | `ios/TopBarPresenter.mm`, `ios/RNNUIBarButtonItem.mm` | `views/stack/topbar/` |\n| Bottom tabs | `src/interfaces/Options.ts` (BottomTabsOptions) | `ios/RNNBottomTabsPresenter.mm` | `viewcontrollers/bottomtabs/` |\n| Modals | `src/commands/Commands.ts` | `ios/RNNModalManager.mm` | `viewcontrollers/modal/ModalStack.java` |\n| Overlays | `src/commands/Commands.ts` | `ios/RNNOverlayManager.mm` | `viewcontrollers/overlay/OverlayManager.kt` |\n| Animations | `src/interfaces/Options.ts` (AnimationOptions) | `ios/ScreenAnimationController.mm` | `viewcontrollers/stack/StackAnimator.kt` |\n| React view rendering | — | `ios/RNNReactView.mm` | `react/ReactView.java` |\n| Events to JS | `src/adapters/NativeEventsReceiver.ts` | `ios/RNNEventEmitter.mm` | `react/events/EventEmitter.java` |\n| Component registration | `src/components/ComponentRegistry.ts` | — | — |\n\n### By directory\n\n- **`src/`** — JS public API, commands, processing pipeline. See [src/ARCHITECTURE.md](../../../src/ARCHITECTURE.md)\n- **`ios/`** — All Obj-C/C++ native code. See [ios/ARCHITECTURE.md](../../../ios/ARCHITECTURE.md)\n- **`ios/TurboModules/`** — New architecture entry points (`RNNTurboModule`, `RNNTurboManager`, `RNNTurboCommandsHandler`)\n- **`android/src/main/java/com/reactnativenavigation/`** — All Java/Kotlin native code. See [android/ARCHITECTURE.md](../../../android/ARCHITECTURE.md)\n- **`playground/`** — Demo app for development and E2E tests\n- **`playground/src/screens/`** — Test screens exercising every feature\n- **`playground/e2e/`** — Detox E2E tests\n\n## Options Resolution Order\n\nOptions are applied in ascending priority:\n1. Default options (from `Navigation.setDefaultOptions()`) — lowest priority\n2. Static options (from component class or `Navigation.registerComponent`)\n3. Options passed in the layout call (e.g. `push`, `setRoot`)\n4. `mergeOptions()` — runtime override, highest priority\n\n## JS Processing Pipeline (exact order)\n\n```\nAPI layout → OptionsCrawler.crawl() → LayoutProcessor.process()\n  → LayoutTreeParser.parse() → LayoutTreeCrawler.crawl()\n  → OptionsProcessor (colors, assets, custom) → NativeCommandsSender\n```\n\n## iOS Patterns\n\n- All controllers conform to `RNNLayoutProtocol`\n- `RNNBasePresenter` subclasses apply options — `applyOptionsOnInit:`, `applyOptions:`, `mergeOptions:resolvedOptions:`\n- Commands run on main thread (`RCTExecuteOnMainQueue`)\n- React views: `RNNReactView` wraps `RCTSurfaceHostingView` (new arch)\n- Overlays use separate `UIWindow` instances (`RNNOverlayWindow`)\n- `RNNReactComponentRegistry` caches React component instances\n\n## Android Patterns\n\n- View-based, NOT Fragment-based\n- All commands dispatched via `UiThread.post()`\n- `ViewController<T extends ViewGroup>` is the base — `createView()` is abstract\n- `ParentController` extends `ChildController` extends `ViewController`\n- Bottom tabs use `AHBottomNavigation` library\n- Three root layouts in `NavigationActivity`: rootLayout, modalsLayout, overlaysLayout\n- Tab attachment modes: `Together`, `OnSwitchToTab`, `AfterInitialTab`\n\n## Development Workflow\n\n### Playground app\n- `yarn start` — Metro bundler\n- `yarn xcode` — Open iOS project\n- `yarn studio` — Open Android project\n- `yarn pod-install` — Install iOS pods\n\n### Testing\n- `yarn test-js` — Jest unit tests\n- `yarn test-unit-ios` — iOS native unit tests (XCTest)\n- `yarn test-unit-android` — Android native unit tests (JUnit + Robolectric)\n- `yarn test-e2e-ios-ci` / `yarn test-e2e-android-ci` — Detox E2E tests\n\n### Building\n- `yarn prepare` — Builds `src/` → `lib/` (ESM + types)\n- Codegen config: `rnnavigation` in `package.json`\n\n## Common Gotchas\n\n- iOS uses UIKit subclasses (UINavigationController, UITabBarController); Android uses custom View hierarchy\n- `splitView` is iOS-only\n- Side menu: iOS uses MMDrawerController (3rd party); Android uses DrawerLayout (native)\n- Options that exist in JS types may not be implemented on both platforms — check the presenter\n- `passProps` are stored in JS `Store`, not sent to native (cleared before bridge crossing)\n- The `lib/` folder is generated — never edit it, edit `src/` instead\n"},"items":[{"name":"ARCHITECTURE.md","path":"android/ARCHITECTURE.md","rawUrl":"https://raw.githubusercontent.com/wix/react-native-navigation/HEAD/android/ARCHITECTURE.md","title":"android - System Architecture & Module Boundaries","category":"project-spec","format":"markdown","content":"# Android Native Architecture\n\nThe Android implementation provides native navigation using Views and ViewGroups (not Fragments), coordinated through a TurboModule that receives commands from JavaScript.\n\n## App Integration\n\n### NavigationApplication\n**File**: `NavigationApplication.java`\n\nAbstract Application class that user's MainApplication must extend:\n\n```kotlin\n// MainApplication.kt - User extends NavigationApplication\nclass MainApplication : NavigationApplication() {\n    override val reactNativeHost: ReactNativeHost\n        get() = NavigationReactNativeHost(this) // Must use NavigationReactNativeHost\n}\n```\n\n**What NavigationApplication does:**\n- Initializes SoLoader\n- Provides `ReactGateway` singleton for React lifecycle\n- Offers `registerExternalComponent()` for native screens\n\n### NavigationActivity\n**File**: `NavigationActivity.java`\n\nBase Activity that user's MainActivity must extend:\n\n```kotlin\n// MainActivity.kt - User extends NavigationActivity\nclass MainActivity : NavigationActivity() {\n    // No getMainComponentName() needed - navigation handles root\n}\n```\n\n**What NavigationActivity does:**\n- Creates `Navigator` with root, modal, and overlay layouts\n- Manages back press via `OnBackPressedCallback`\n- Coordinates React lifecycle with activity lifecycle\n\n### NavigationReactNativeHost\n**File**: `react/NavigationReactNativeHost.kt`\n\nCustom ReactNativeHost that integrates with navigation:\n- Used instead of `DefaultReactNativeHost`\n- Provides proper module registration for navigation\n\n### Autolink Script (`npx rnn-link`)\n\nThe `autolink/postlink/postLinkAndroid.js` script automates setup:\n\n| Linker | What it does |\n|--------|--------------|\n| `ApplicationLinker` | Changes MainApplication to extend `NavigationApplication`, uses `NavigationReactNativeHost`, removes SoLoader.init() |\n| `ActivityLinker` | Changes MainActivity to extend `NavigationActivity`, removes `getMainComponentName()` |\n| `GradleLinker` | Updates build.gradle if needed |\n\n**ApplicationLinker transformations:**\n- `class MainApplication : Application(), ReactApplication` → `class MainApplication : NavigationApplication()`\n- `DefaultReactNativeHost(this)` → `NavigationReactNativeHost(this)`\n- Removes `SoLoader.init()` (NavigationApplication handles it)\n- Removes new architecture entry point load block\n\n**ActivityLinker transformations:**\n- `class MainActivity : ReactActivity()` → `class MainActivity : NavigationActivity()`\n- Removes `getMainComponentName()` override\n- Removes `createReactActivityDelegate()` override\n\n## Directory Structure\n\n```\nandroid/src/main/java/com/reactnativenavigation/\n├── NavigationActivity.java       # Main Activity entry point\n├── NavigationApplication.java    # Application class\n├── NavigationPackage.kt          # React package registration\n├── react/                        # React bridge layer\n│   ├── NavigationTurboModule.kt  # TurboModule implementation\n│   ├── ReactGateway.java         # React lifecycle management\n│   └── events/\n│       └── EventEmitter.java     # Event emission to JS\n├── options/                      # Options parsing and factories\n│   ├── LayoutFactory.java        # Creates ViewControllers from layout nodes\n│   └── Options.java              # Options model\n├── viewcontrollers/              # ViewController hierarchy\n│   ├── ViewController.java       # Base class\n│   ├── ChildController.java      # With presenter support\n│   ├── ParentController.java     # Container controllers\n│   ├── stack/                    # Stack navigation\n│   ├── bottomtabs/               # Bottom tabs\n│   ├── toptabs/                  # Top tabs (lowercase)\n│   ├── sidemenu/                 # Side menu/drawer\n│   ├── modal/                    # Modal management\n│   └── externalcomponent/        # Native component support\n├── views/                        # UI View implementations\n├── utils/                        # Utilities\n└── hierarchy/                    # Root layout management\n```\n\n## Bridge Architecture\n\n```\n┌────────────────────────────────────────────────────────────┐\n│                 JavaScript (TurboModule)                   │\n└─────────────────────────┬──────────────────────────────────┘\n                          │\n┌─────────────────────────▼──────────────────────────────────┐\n│  NavigationTurboModule.kt                                   │\n│  - setRoot, push, pop, showModal, dismissModal, etc.       │\n└─────────────────────────┬──────────────────────────────────┘\n                          │\n┌─────────────────────────▼──────────────────────────────────┐\n│  Navigator (Root ViewController)                           │\n│  - Manages root, modals, overlays                          │\n│  - Coordinates LayoutFactory                               │\n└──────┬──────────────┬──────────────┬──────────────┬────────┘\n       │              │              │              │\n┌──────▼─────┐ ┌──────▼─────┐ ┌──────▼─────┐ ┌─────▼──────┐\n│ModalStack  │ │OverlayMgr  │ │LayoutFactory│ │EventEmitter│\n└────────────┘ └────────────┘ └────────────┘ └────────────┘\n```\n\n## Entry Points\n\n### NavigationApplication\nAbstract Application class that apps extend:\n- Manages `ReactGateway` singleton\n- Initializes SoLoader\n- Provides `registerExternalComponent()` for native screens\n\n### NavigationActivity\nMain Activity containing all navigation:\n- Creates `Navigator` with three CoordinatorLayouts:\n  - `rootLayout` - Main navigation content\n  - `modalsLayout` - Modal stack\n  - `overlaysLayout` - Overlays (highest z-order)\n- Handles back press via `OnBackPressedCallback`\n- Coordinates activity lifecycle with React\n\n### NavigationTurboModule\nTurboModule implementation (Kotlin, ~300 lines):\n\n```kotlin\n@ReactMethod\nfun setRoot(commandId: String, layout: ReadableMap, promise: Promise)\n\n@ReactMethod\nfun push(commandId: String, componentId: String, layout: ReadableMap, promise: Promise)\n\n@ReactMethod\nfun showModal(commandId: String, layout: ReadableMap, promise: Promise)\n```\n\nAll commands execute on UI thread via `UiThread.post()`.\n\n## ViewController Hierarchy\n\n**Note**: Android implementation does NOT use Fragments - it's purely View-based.\n\n```\nViewController (abstract)\n│   - Base for all navigation controllers\n│   - Manages view creation and lifecycle\n│   - Handles options and back press\n│\n├── ChildController\n│   │   - Adds Presenter support\n│   │\n│   ├── ComponentViewController\n│   │       - Renders React components via ReactView\n│   │\n│   └── ExternalComponentViewController\n│           - Wraps native Android views\n│\n└── ParentController (extends ChildController)\n        - Container for child controllers\n        │\n        ├── StackController\n        │       - Push/pop navigation\n        │       - Uses IdStack<ViewController>\n        │\n        ├── BottomTabsController\n        │       - UITabBarController equivalent\n        │       - Uses AHBottomNavigation\n        │\n        ├── TopTabsController\n        │       - Horizontal ViewPager tabs\n        │\n        ├── SideMenuController\n        │       - DrawerLayout-based drawer\n        │\n        └── Navigator\n                - Root controller\n                - Manages modals and overlays\n```\n\n## Core Classes\n\n### ViewController (Base)\n**File**: `viewcontrollers/viewcontroller/ViewController.java` (~500 lines)\n\nAbstract base for all navigation controllers:\n\n```java\npublic abstract class ViewController<T extends ViewGroup> {\n    protected abstract T createView();  // Subclasses create views\n\n    public void onViewWillAppear() { }\n    public void onViewDidAppear() { }\n    public void onViewDisappear() { }\n\n    public void mergeOptions(Options options) { }\n    public void applyOptions(Options options) { }\n    public boolean handleBack(CommandListener listener) { }\n    public void destroy() { }\n}\n```\n\n### Navigator (Root)\n**File**: `viewcontrollers/navigator/Navigator.java`\n\nRoot ViewController managing:\n- Root content hierarchy\n- Modal stack (`ModalStack`)\n- Overlay manager (`OverlayManager`)\n- Component lookup by ID\n\n### LayoutFactory\n**File**: `options/LayoutFactory.java`\n\nFactory creating ViewControllers from LayoutNode. Owned by `NavigationTurboModule` and used to build the view controller hierarchy when commands are received from JavaScript.\n\n```java\npublic ViewController create(LayoutNode node) {\n    switch (node.type) {\n        case Component: return createComponent(node);\n        case Stack: return createStack(node);\n        case BottomTabs: return createBottomTabs(node);\n        case SideMenuRoot: return createSideMenuRoot(node);\n        case SideMenuCenter: return createSideMenuContent(node);\n        case SideMenuLeft: return createSideMenuLeft(node);\n        case SideMenuRight: return createSideMenuRight(node);\n        case TopTabs: return createTopTabs(node);\n        // Note: SplitView is iOS-only, not implemented on Android\n    }\n}\n```\n\n## Navigation Types\n\n### Stack Navigation (StackController)\n**Files**: `viewcontrollers/stack/`\n\n- View: `StackLayout` (CoordinatorLayout with TopBar)\n- Internal stack: `IdStack<ViewController<?>>`\n- Components: `TopBarController`, `StackAnimator`, `StackPresenter`, `FabPresenter`\n\nOperations:\n- `push(viewController, listener)`\n- `pop(options, listener)`\n- `popTo(target, options, listener)`\n- `popToRoot(options, listener)`\n- `setRoot(children, listener)`\n\n### Bottom Tabs (BottomTabsController)\n**Files**: `viewcontrollers/bottomtabs/`\n\n- View: `BottomTabsLayout` (CoordinatorLayout with BottomTabs)\n- Uses `AHBottomNavigation` library\n- Components: `BottomTabsPresenter`, `BottomTabPresenter`, `BottomTabsAnimator`\n\nAttachment Modes:\n- `TogetherAttacher` - Load all tabs immediately\n- `OnSwitchToTabAttacher` - Lazy load on selection\n- `AfterInitialTabAttacher` - Load initial + others in background\n\n### Side Menu (SideMenuController)\n**Files**: `viewcontrollers/sidemenu/`\n\n- View: `SideMenuRoot` (DrawerLayout-based)\n- Children: Center, Left, Right controllers\n- `SideMenuPresenter` for styling\n\n### Top Tabs (TopTabsController)\n**Files**: `viewcontrollers/toptabs/`\n\n- View: `TopTabsViewPager` (ViewPager-based)\n- `TopTabsLayoutCreator` for view creation\n\n### Modals (ModalStack)\n**Files**: `viewcontrollers/modal/`\n\nNot a ViewController - manages modal presentation:\n- `ModalPresenter` - Show/dismiss with animations\n- `ModalAnimator` (Kotlin) - Animation handling\n- Stack of modals with lifecycle management\n\n### Overlays (OverlayManager)\n**File**: `viewcontrollers/overlay/OverlayManager.kt`\n\nRegistry of active overlays:\n- Show/dismiss by component ID\n- Configuration change handling\n- Host pause/resume lifecycle\n\n## React Component Rendering\n\n### ComponentViewController\nManages React component lifecycle:\n- Creates `ComponentLayout` view\n- Initializes `ReactView` with ReactSurface\n- Emits lifecycle events to JS\n- Handles scroll events and status bar\n\n### ReactView\n**File**: `react/ReactView.java`\n\nExtends FrameLayout, wraps `ReactSurface`:\n- `start()` - Attach surface to React instance\n- `destroy()` - Clean up React surface\n- `sendComponentWillStart()` - Emit event to JS\n- `isReady()` - Check surface attachment\n\n## Event Emission\n\n### EventEmitter\n**File**: `react/events/EventEmitter.java`\n\nEvents sent to JavaScript:\n\n| Event | Description |\n|-------|-------------|\n| `RNN.AppLaunched` | App initialization complete |\n| `RNN.ComponentDidAppear` | Component visible |\n| `RNN.ComponentWillAppear` | About to become visible |\n| `RNN.ComponentDidDisappear` | Component hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tapped |\n| `RNN.BottomTabSelected` | Tab selection changed |\n| `RNN.BottomTabPressed` | Tab pressed (even if selected) |\n| `RNN.ModalDismissed` | Modal was dismissed |\n| `RNN.ScreenPopped` | Screen removed from stack |\n| `RNN.CommandCompleted` | Navigation command finished |\n\n## Options System\n\n### Options Class\n**File**: `options/Options.java`\n\n```java\npublic class Options {\n    public TopBarOptions topBar;\n    public TopTabsOptions topTabs;\n    public BottomTabsOptions bottomTabsOptions;\n    public BottomTabOptions bottomTabOptions;\n    public OverlayOptions overlayOptions;\n    public FabOptions fabOptions;\n    public AnimationsOptions animations;\n    public SideMenuRootOptions sideMenuRootOptions;\n    public ModalOptions modal;\n    public StatusBarOptions statusBar;\n    public NavigationBarOptions navigationBar;\n    public LayoutOptions layout;\n    public HardwareBackButtonOptions hardwareBack;\n}\n```\n\n### Options Flow\n1. **Parse**: JSON from JS → Options object via JSONParser\n2. **Merge**: Default → Screen → Component options\n3. **Apply**: Presenter applies to views\n\n## Presenter Pattern\n\nEach ViewController has a Presenter:\n\n| ViewController | Presenter |\n|---------------|-----------|\n| StackController | StackPresenter |\n| BottomTabsController | BottomTabsPresenter + BottomTabPresenter |\n| ComponentViewController | ComponentPresenter |\n| SideMenuController | SideMenuPresenter |\n| Navigator | RootPresenter |\n\n### Presenter Base\n**File**: `viewcontrollers/viewcontroller/Presenter.java`\n\nHandles:\n- Orientation changes\n- Status bar styling\n- Navigation bar styling\n- Layout parameters\n\n## Animation System\n\n### Animators (Kotlin)\n- `StackAnimator.kt` - Push, pop, setRoot animations\n- `ModalAnimator.kt` - Modal show/dismiss\n- `BottomTabsAnimator.kt` - Tab transitions\n- `TopBarAppearanceAnimator.kt` - Top bar changes\n\n### Element Transitions\nVia `TransitionAnimatorCreator.kt`:\n- Position, scale, rotation animations\n- Color transitions\n- Corner radius animations\n- Shared element support\n\n## Activity Lifecycle\n\n```java\nonCreate()      // Create Navigator, initialize React\nonPostCreate()  // Set content layout\nonResume()      // React host resume, event emitter setup\nonPause()       // React host pause\nonDestroy()     // Clean up Navigator\nonConfigurationChanged()  // Handle orientation, locale\nonNewIntent()   // Process deep links\nonActivityResult()  // Handle permissions\n```\n\n## ViewController Lifecycle\n\n```\nView creation\n    ↓\nonViewWillAppear()   // Register with registry\n    ↓\nonViewDidAppear()    // Emit event to JS\n    ↓\n[visible]\n    ↓\nonViewWillDisappear()\n    ↓\nonViewDisappear()    // Unregister from registry\n    ↓\ndestroy()            // Complete cleanup\n```\n\n## Key Files Reference\n\nAll paths relative to `android/src/main/java/com/reactnativenavigation/`:\n\n| File | Path | Purpose |\n|------|------|---------|\n| NavigationActivity.java | `.` | Main Activity |\n| NavigationApplication.java | `.` | Application class |\n| NavigationTurboModule.kt | `react/` | JS bridge |\n| Navigator.java | `viewcontrollers/navigator/` | Root controller |\n| ViewController.java | `viewcontrollers/viewcontroller/` | Base class |\n| StackController.java | `viewcontrollers/stack/` | Stack navigation |\n| BottomTabsController.java | `viewcontrollers/bottomtabs/` | Tab navigation |\n| LayoutFactory.java | `options/` | Controller factory |\n| Options.java | `options/` | Options model |\n| Presenter.java | `viewcontrollers/viewcontroller/` | Base presenter |\n| EventEmitter.java | `react/events/` | JS events |\n| ReactView.java | `react/` | React component wrapper |\n| StackAnimator.kt | `viewcontrollers/stack/` | Stack animations |\n| ModalStack.java | `viewcontrollers/modal/` | Modal management |\n","isInternal":false,"tokens":3383,"sizeBytes":16521},{"name":"ARCHITECTURE.md","path":"ARCHITECTURE.md","rawUrl":"https://raw.githubusercontent.com/wix/react-native-navigation/HEAD/ARCHITECTURE.md","title":"System Architecture & Module Boundaries","category":"project-spec","format":"markdown","content":"# React Native Navigation Architecture\n\nReact 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.\n\n## Project Overview\n\n- **Package**: `react-native-navigation` (v8.7.0)\n- **Platforms**: iOS 11+, Android 7.0+ (API 24)\n- **React Native**: 0.77+ (developed against 0.83; see package.json for current version)\n- **License**: MIT (maintained by Wix)\n\n## Directory Structure\n\n```\nreact-native-navigation/\n├── src/                    # TypeScript source code (JS API layer)\n├── lib/                    # Compiled output (generated by bob build - do not edit)\n├── android/                # Android native implementation (Java/Kotlin)\n├── ios/                    # iOS native implementation (Obj-C/C++)\n├── playground/             # Demo app and E2E test target\n├── autolink/               # Post-install linking scripts\n├── scripts/                # Build, test, and release scripts\n├── website/                # Docusaurus documentation site\n├── integration/            # Integration tests (Redux, Remx)\n├── Mock/                   # Mock implementations for testing\n└── .buildkite/             # CI/CD pipeline configuration\n```\n\n## High-Level Architecture\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│                     JavaScript API Layer                         │\n│  Navigation.setRoot() / push() / pop() / showModal() / etc.     │\n└─────────────────────────────┬────────────────────────────────────┘\n                              │\n┌─────────────────────────────▼────────────────────────────────────┐\n│                    Processing Pipeline                            │\n│  OptionsCrawler → LayoutProcessor → LayoutTreeParser → OptionsProcessor │\n└─────────────────────────────┬────────────────────────────────────┘\n                              │\n┌─────────────────────────────▼────────────────────────────────────┐\n│                   TurboModule Bridge                              │\n│  NativeCommandsSender ←→ RNNTurboModule (iOS) / NavigationTurboModule (Android) │\n└──────────┬─────────────────────────────────────┬─────────────────┘\n           │                                     │\n┌──────────▼──────────┐               ┌─────────▼──────────┐\n│   iOS Native Layer  │               │ Android Native Layer│\n│  UINavigationController             │   ViewControllers   │\n│  UITabBarController │               │   CoordinatorLayout │\n│  UIViewController   │               │   BottomNavigation  │\n└─────────────────────┘               └────────────────────┘\n```\n\n## Core Concepts\n\n### Layout Types\nAll navigation structures are composed from these layout primitives:\n\n| Layout Type | Description | iOS Implementation | Android Implementation |\n|-------------|-------------|-------------------|----------------------|\n| `component` | React component screen | RNNComponentViewController | ComponentViewController |\n| `stack` | Push/pop navigation | UINavigationController (RNNStackController) | StackController |\n| `bottomTabs` | Tab bar navigation | UITabBarController (RNNBottomTabsController) | BottomTabsController |\n| `topTabs` | Horizontal scrollable tabs | RNNTopTabsViewController | TopTabsController |\n| `sideMenu` | Drawer navigation (with center, left, right) | MMDrawerController (RNNSideMenuViewController) | SideMenuController |\n| `splitView` | Master-detail (iPad only) | UISplitViewController (RNNSplitViewController) | — |\n| `externalComponent` | Native (non-React) screen | RNNExternalViewController | ExternalComponentViewController |\n\n### Navigation Commands\nCore commands available through the Navigation API:\n\n- **Root**: `setRoot()` - Replace entire navigation hierarchy\n- **Stack**: `push()`, `pop()`, `popTo()`, `popToRoot()`, `setStackRoot()`\n- **Modal**: `showModal()`, `dismissModal()`, `dismissAllModals()`\n- **Overlay**: `showOverlay()`, `dismissOverlay()`, `dismissAllOverlays()`\n- **Options**: `setDefaultOptions()`, `mergeOptions()`, `updateProps()`\n- **Linking**: `setLinking()`, `handleDeepLink()`, `setLinkingReady()` - URL-to-screen routing\n\n### Deep Linking\nURL-driven navigation is implemented entirely in the JS layer (`src/linking/`) and feeds into the standard command pipeline. Configure with `Navigation.setLinking({ prefixes, config: { screens } })`; matched URLs are presented as modals by default (preserving the user's current navigation state). Customize via `getModal`/`onLink` hooks; gate processing on auth via `isReady`/`setLinkingReady`. Native plumbing — `application:openURL:`, `application:continueUserActivity:`, cold-start URL queueing — lives in `RNNAppDelegate` (iOS) and `NavigationActivity.onNewIntent` (Android), so subclassing the base classes is sufficient. See [Deep Linking docs](https://wix.github.io/react-native-navigation/docs/deep-linking).\n\n### Options System\nStyling and behavior is controlled via a hierarchical options object:\n\n```typescript\n{\n  statusBar: {...},      // Status bar appearance\n  topBar: {...},         // Navigation bar styling\n  bottomTabs: {...},     // Tab bar configuration\n  bottomTab: {...},      // Individual tab styling\n  sideMenu: {...},       // Drawer configuration\n  layout: {...},         // Screen layout options\n  animations: {...},     // Transition animations\n  modal: {...},          // Modal presentation style\n  overlay: {...}         // Overlay behavior\n}\n```\n\nOptions merge in order: **Default Options → Parent Options → Component Options**\n\n## Data Flow\n\n### Command Execution Flow\n```\n1. JS: Navigation.push(componentId, layout)\n2. Commands.ts validates and begins processing\n3. OptionsCrawler extracts static options from component classes\n4. LayoutProcessor applies registered layout processors\n5. LayoutTreeParser converts to internal LayoutNode tree\n6. LayoutTreeCrawler processes tree, saves props to Store\n7. OptionsProcessor resolves colors, images, fonts\n8. NativeCommandsSender sends to TurboModule\n9. Native layer creates/updates view hierarchy\n10. EventEmitter sends completion event to JS\n```\n\n**Note**: The JS layer exports a single `Navigation` object (from `NavigationDelegate`). The TurboModule names differ per platform: `RNNTurboModule` on iOS, `NavigationTurboModule` on Android.\n\n### Event Flow (Native → JS)\n```\n1. Native lifecycle event (viewDidAppear, etc.)\n2. RNNEventEmitter (iOS) / EventEmitter (Android)\n3. NativeEventsReceiver receives via NativeEventEmitter\n4. EventsRegistry dispatches to registered listeners\n5. ComponentEventsObserver calls component instance methods\n```\n\n## Key Architecture Patterns\n\n1. **Facade Pattern**: `NavigationDelegate` provides clean public API\n2. **Bridge Pattern**: Adapters isolate JS from native implementation details\n3. **Presenter Pattern**: Separates view styling from controller logic\n4. **Observer Pattern**: Event system for lifecycle and command notifications\n5. **Factory Pattern**: `LayoutFactory` creates controllers from layout nodes\n6. **Plugin Pattern**: Processors allow extending layout/options handling\n\n## Component Lifecycle\n\nReact components receive navigation lifecycle events:\n\n```typescript\nclass MyScreen extends NavigationComponent {\n  componentWillAppear(event) {}      // About to become visible\n  componentDidAppear(event) {}       // Now visible\n  componentDidDisappear(event) {}    // No longer visible\n  navigationButtonPressed(event) {}  // TopBar button tapped\n  screenPopped(event) {}             // Screen removed from stack\n  searchBarUpdated(event) {}         // Search text changed\n  searchBarCancelPressed(event) {}   // Search cancelled\n  previewCompleted(event) {}         // 3D Touch preview completed\n}\n```\n\n## Testing Architecture\n\n- **Unit Tests**: Jest + ts-mockito for TypeScript source\n- **Integration Tests**: Redux/Remx integration verification\n- **E2E Tests**: Detox framework with playground app\n- **Snapshot Tests**: iOS visual regression testing\n- **Native Unit Tests**: XCTest (iOS) and JUnit (Android)\n\n## Related Documentation\n\n- [JavaScript/TypeScript Architecture](./src/ARCHITECTURE.md)\n- [iOS Native Architecture](./ios/ARCHITECTURE.md)\n- [Android Native Architecture](./android/ARCHITECTURE.md)\n- [API Documentation](https://wix.github.io/react-native-navigation/)\n","isInternal":false,"tokens":1842,"sizeBytes":9413},{"name":"ARCHITECTURE.md","path":"ios/ARCHITECTURE.md","rawUrl":"https://raw.githubusercontent.com/wix/react-native-navigation/HEAD/ios/ARCHITECTURE.md","title":"ios - System Architecture & Module Boundaries","category":"project-spec","format":"markdown","content":"# iOS Native Architecture\n\nThe iOS implementation provides native navigation using UIKit view controllers, coordinated through a bridge module that receives commands from JavaScript.\n\n## App Integration\n\n### RNNAppDelegate\n**Files**: `RNNAppDelegate.h/mm`\n\nBase class that user's AppDelegate must extend. Handles React Native and navigation initialization:\n\n```objc\n// AppDelegate.h - User extends RNNAppDelegate\n#import \"RNNAppDelegate.h\"\n@interface AppDelegate : RNNAppDelegate\n@end\n\n// AppDelegate.m - User implements sourceURLForBridge\n@implementation AppDelegate\n- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {\n  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@\"index\"];\n}\n@end\n```\n\n**What RNNAppDelegate does:**\n- Sets up React Native feature flags (Fabric, TurboModules, Bridgeless)\n- Creates `RCTRootViewFactory` and `ReactHost`\n- Calls `[ReactNativeNavigation bootstrapWithHost:]` to initialize navigation\n- Handles RN version differences (0.77, 0.78, 0.79+) via compile-time macros\n- **Deep linking plumbing**:\n  - Implements `application:openURL:options:` and `application:continueUserActivity:restorationHandler:`; both call `-dispatchDeepLinkURL:`.\n  - `-dispatchDeepLinkURL:` posts `RCTOpenURLNotification` directly if the React runtime is ready, otherwise enqueues the URL.\n  - Observes `RCTContentDidAppearNotification` (the Fabric/bridgeless signal) to flush the queue. This solves the cold-start race where URLs (push notifications, OS link launches) arrive before `RCTLinkingManager` is listening.\n  - Subclasses can call `-dispatchDeepLinkURL:` manually from notification delegates or any other URL source; the queueing behavior is reused automatically.\n\n### ReactNativeNavigation Bootstrap\n**File**: `ReactNativeNavigation.h/mm`\n\nPublic API for native initialization:\n\n```objc\n// New architecture (0.77+)\n[ReactNativeNavigation bootstrapWithHost:reactHost];\n\n// Legacy bridge\n[ReactNativeNavigation bootstrapWithBridge:bridge];\n\n// Register native screens\n[ReactNativeNavigation registerExternalComponent:@\"NativeScreen\"\n                                        callback:^(NSDictionary *props, RCTBridge *bridge) {\n    return [[MyNativeVC alloc] init];\n}];\n```\n\n### Autolink Script (`npx rnn-link`)\n\nThe `autolink/postlink/postLinkIOS.js` script automates setup:\n\n| Linker | What it does |\n|--------|--------------|\n| `AppDelegateLinker` | Changes AppDelegate to extend `RNNAppDelegate`, imports ReactNativeNavigation, removes RCTRootView setup |\n| `PodfileLinker` | Adds required pods configuration |\n| `PlistLinker` | Updates Info.plist if needed |\n\n**AppDelegateLinker transformations:**\n- Swift: `class AppDelegate: RCTAppDelegate` → `class AppDelegate: RNNAppDelegate`\n- Obj-C header: `@interface AppDelegate : RCTAppDelegate` → `@interface AppDelegate : RNNAppDelegate`\n- Imports `<ReactNativeNavigation/ReactNativeNavigation.h>`\n- Removes manual RCTRootView/window setup (navigation manages the window)\n\n## Directory Structure\n\n```\nios/\n├── RNNBridgeModule.h/mm         # Bridge entry point (legacy architecture)\n├── RNNBridgeManager.h/mm        # Bridge initialization\n├── RNNCommandsHandler.h/mm      # Command dispatcher\n├── RNNEventEmitter.h/mm         # Event emission to JS\n├── RNNLayoutManager.h/mm        # View controller tracking\n├── RNNLayoutNode.h/mm           # Layout tree parsing\n├── RNNNavigationOptions.h/mm    # Options model\n├── RNNComponentViewController.h/mm  # React component screen\n├── RNNStackController.h/mm      # Stack navigation\n├── RNNBottomTabsController.h/mm # Tab navigation\n├── RNNSideMenuViewController.h/mm   # Side menu\n├── RNNTopTabsViewController.h/mm    # Top tabs\n├── RNNSplitViewController.h/mm  # Split view (iPad)\n├── RNNModalManager.h/mm         # Modal presentation\n├── RNNOverlayManager.h/mm       # Overlay management\n├── TurboModules/                # New architecture entry points\n│   ├── RNNTurboModule.h/mm      # TurboModule spec implementation\n│   ├── RNNTurboManager.h/mm     # Manager for host, window, external components\n│   ├── RNNTurboCommandsHandler.h/mm  # TurboModule command routing\n│   └── RNNTurboEventEmitter.h/mm     # Event emission for new arch\n├── Utils/                       # Utility classes\n├── RNNSideMenu/                 # MMDrawerController integration\n└── ReactNativeNavigation.xcodeproj/\n```\n\n## Bridge Architecture\n\nThe library supports both the legacy bridge and new TurboModule architecture:\n- **Legacy (Bridge)**: `RNNBridgeModule` receives commands via `RCT_EXPORT_METHOD`\n- **New Architecture**: `RNNTurboModule` (in `TurboModules/`) receives commands directly\n\nBoth entry points delegate to `RNNCommandsHandler` for command execution.\n\n```\n┌────────────────────────────────────────────────────────────┐\n│                 JavaScript (TurboModule)                   │\n└─────────────────────────┬──────────────────────────────────┘\n                          │\n┌─────────────────────────▼──────────────────────────────────┐\n│  RNNBridgeModule (bridge) / RNNTurboModule (new arch)      │\n│  - setRoot, push, pop, showModal, dismissModal, etc.       │\n└─────────────────────────┬──────────────────────────────────┘\n                          │\n┌─────────────────────────▼──────────────────────────────────┐\n│  RNNCommandsHandler                                         │\n│  - Validates commands, manages layout lifecycle            │\n│  - Coordinates with managers                               │\n└──────┬──────────────┬──────────────┬──────────────┬────────┘\n       │              │              │              │\n┌──────▼─────┐ ┌──────▼─────┐ ┌──────▼─────┐ ┌─────▼──────┐\n│RNNLayout   │ │RNNModal    │ │RNNOverlay  │ │RNNViewController│\n│Manager     │ │Manager     │ │Manager     │ │Factory     │\n└────────────┘ └────────────┘ └────────────┘ └────────────┘\n```\n\n## View Controller Hierarchy\n\nAll navigation view controllers conform to `RNNLayoutProtocol`:\n\n```\nUIViewController\n├── RNNComponentViewController    # React component screen\n├── RNNExternalViewController     # Native screen wrapper\n└── RNNSplashScreenViewController # Launch screen\n\nUINavigationController\n└── RNNStackController           # Stack navigation\n\nUITabBarController\n└── RNNBottomTabsController      # Bottom tabs\n\nUIViewController (custom)\n├── RNNTopTabsViewController     # Horizontal top tabs\n└── RNNSideMenuChildViewController  # Drawer child\n\nMMDrawerController\n└── RNNSideMenuViewController    # Side menu/drawer\n\nUISplitViewController\n└── RNNSplitViewController       # Master-detail (iPad)\n```\n\n## Core Classes\n\n### RNNBridgeModule\nEntry point for JavaScript commands (legacy architecture). Exports methods via `RCT_EXPORT_METHOD`:\n\n```objc\nRCT_EXPORT_METHOD(setRoot:(NSString*)commandId layout:(NSDictionary*)layout\n                  resolver:(RCTPromiseResolveBlock)resolve\n                  rejecter:(RCTPromiseRejectBlock)reject);\n```\n\n`RNNBridgeModule` returns the main queue as its `methodQueue`; `RNNTurboModule` uses `RCTExecuteOnMainQueue` for each command to ensure UI operations run on the main thread.\n\n### RNNBridgeManager\nInitializes bridge infrastructure:\n- Creates RNNLayoutManager, RNNModalManager, RNNOverlayManager\n- Creates RNNViewControllerFactory, RNNCommandsHandler\n- Provides extra modules to React bridge\n- Handles JavaScript reload events\n\n### RNNCommandsHandler\nCentral command dispatcher implementing all navigation operations:\n- `setRoot:` - Replace root view controller\n- `push:componentId:layout:` - Push to stack\n- `pop:componentId:` - Pop from stack\n- `showModal:` - Present modal\n- `dismissModal:` - Dismiss modal\n- `showOverlay:` - Show overlay window\n- `dismissOverlay:` - Hide overlay\n\n### RNNLayoutManager\nTracks active view controllers:\n- `addPendingViewController:` - Register during creation\n- `removePendingViewController:` - Cleanup after presentation\n- `findComponentForId:` - Lookup by componentId\n\n### RNNLayoutNode\nParses JSON layout from JavaScript:\n- Determines type via predicates: `isComponent`, `isStack`, `isTabs`, etc.\n- Holds `type`, `nodeId`, `data` (options), `children`\n\n### RNNViewControllerFactory\nCreates view controllers from RNNLayoutNode:\n- `createStack:` → RNNStackController\n- `createBottomTabs:` → RNNBottomTabsController\n- `createComponent:` → RNNComponentViewController\n- `createSideMenu:` → RNNSideMenuViewController\n\n## RNNLayoutProtocol\n\nProtocol all navigation controllers implement:\n\n```objc\n@protocol RNNLayoutProtocol\n- (instancetype)initWithLayoutInfo:(RNNLayoutInfo*)layoutInfo\n                           creator:(id<RNNComponentViewCreator>)creator\n                           options:(RNNNavigationOptions*)options\n                    defaultOptions:(RNNNavigationOptions*)defaultOptions\n                         presenter:(RNNBasePresenter*)presenter\n                      eventEmitter:(RNNEventEmitter*)eventEmitter\n              childViewControllers:(NSArray*)childViewControllers;\n\n- (void)render;\n- (UIViewController*)getCurrentChild;\n- (void)mergeOptions:(RNNNavigationOptions*)options;\n- (RNNNavigationOptions*)resolveOptions;\n- (void)setDefaultOptions:(RNNNavigationOptions*)defaultOptions;\n- (void)onChildWillAppear;\n- (void)readyForPresentation;\n- (CGFloat)getTopBarHeight;\n- (CGFloat)getBottomTabsHeight;\n@end\n```\n\nAdditional methods provided via `UIViewController+LayoutProtocol` category:\n- `destroy`, `topMostViewController`, `stack`\n- `componentWillAppear`, `componentDidAppear`, `componentDidDisappear`\n- `screenPopped`, `prepareForTransition`\n- `resolveOptionsWithDefault`, `mergeChildOptions:child:`\n\n## Presenter Pattern\n\nEach view controller type has a corresponding presenter that applies options:\n\n| Controller | Presenter |\n|------------|-----------|\n| RNNComponentViewController | RNNComponentPresenter |\n| RNNStackController | RNNStackPresenter + TopBarPresenter |\n| RNNBottomTabsController | RNNBottomTabsPresenter + BottomTabPresenter |\n| RNNSideMenuViewController | RNNSideMenuPresenter |\n| RNNSplitViewController | RNNSplitViewControllerPresenter |\n\n### RNNBasePresenter\nBase class with lifecycle methods:\n- `applyOptionsOnInit:` - Initial setup\n- `applyOptions:` - Apply current options\n- `mergeOptions:resolvedOptions:` - Runtime updates\n- `componentWillAppear`, `componentDidAppear`, `componentDidDisappear`\n\n## React View Integration\n\n### RNNReactView\nWraps RCTRootView (legacy) or RCTSurfaceHostingView (new architecture):\n- Implements `RNNComponentProtocol`\n- Manages `componentId`, `componentType`, `moduleName`\n- Lifecycle: `componentWillAppear`, `componentDidAppear`, `componentDidDisappear`\n\n### RNNReactRootViewCreator\nCreates RNNReactView instances:\n- Supports component types: Component, TopBarTitle, TopBarButton, TopBarBackground\n- Handles size flexibility for flexible layouts\n\n### RNNReactComponentRegistry\nCaches created React component instances:\n- `createComponentIfNotExists:parentComponentId:componentType:reactViewReadyBlock:`\n- `removeComponent:`, `clearComponentsForParentId:`\n\n## Options System\n\n### RNNNavigationOptions\nMaster options object containing all configuration:\n\n```objc\n@interface RNNNavigationOptions : RNNOptions\n@property RNNTopBarOptions* topBar;\n@property RNNBottomTabsOptions* bottomTabs;\n@property RNNBottomTabOptions* bottomTab;\n@property RNNTopTabsOptions* topTabs;\n@property RNNSideMenuOptions* sideMenu;\n@property RNNOverlayOptions* overlay;\n@property RNNAnimationsOptions* animations;\n@property RNNStatusBarOptions* statusBar;\n@property RNNLayoutOptions* layout;\n@property RNNModalOptions* modal;\n@property RNNPreviewOptions* preview;\n@property RNNSplitViewOptions* splitView;\n@end\n```\n\n### Options Resolution\nOptions merge in hierarchy:\n1. Component's own options\n2. Parent controller options (loop through chain)\n3. Default options (from `setDefaultOptions`)\n\n## Event Emission\n\n### RNNEventEmitter\nSends events to JavaScript via RCTEventEmitter:\n\n| Event | Method |\n|-------|--------|\n| Component lifecycle | `sendComponentWillAppear:`, `sendComponentDidAppear:`, `sendComponentDidDisappear:` |\n| Button press | `sendOnNavigationButtonPressed:buttonId:` |\n| Command completion | `sendOnNavigationCommandCompletion:commandId:` |\n| Tab events | `sendBottomTabSelected:unselected:`, `sendBottomTabLongPressed:`, `sendBottomTabPressed:` |\n| Modal events | `sendModalsDismissedEvent:numberOfModalsDismissed:`, `sendModalAttemptedToDismissEvent:` |\n| Screen events | `sendScreenPoppedEvent:` |\n| Search | `sendOnSearchBarUpdated:text:isFocused:`, `sendOnSearchBarCancelPressed:` |\n| Preview | `sendOnPreviewCompleted:previewComponentId:` |\n\n### RNNBridgeEventEmitter\nConcrete implementation that sends `onAppLaunched` on initialization.\n\n## Modal & Overlay Management\n\n### RNNModalManager\n- Tracks presented modals array\n- Supports custom transition animations via ScreenAnimationController\n- Handles presentationController delegate for adaptive presentation\n\n### RNNOverlayManager\n- Manages UIWindow instances for overlays\n- Each overlay gets its own RNNOverlayWindow\n- Maintains previous window reference for restoration\n- Controls window level and accessibility\n\n## Animation System\n\n### ScreenAnimationController\nImplements `UIViewControllerAnimatedTransitioning`:\n- Custom push/pop/modal transitions\n- Content transitions (RNNEnterExitAnimation)\n- Element transitions (ElementTransitionOptions)\n- Shared element transitions (SharedElementTransitionOptions)\n\n### Element Animators\n- `ElementAnimator` - Individual element animations\n- `SharedElementAnimator` - Cross-screen shared elements\n- Transition types: Alpha, Scale, Translation, Frame, Bounds, Color, CornerRadius\n\n### RNNSetRootAnimator\nAnimates window root replacement using CABasicAnimation.\n\n## Navigation Types\n\n### Stack Navigation (RNNStackController)\n- Subclass of UINavigationController\n- Push/pop with custom animations\n- Back button customization\n- Uses StackControllerDelegate for bar delegate handling\n\n```objc\n// Extension methods\n@interface UINavigationController (RNNCommands)\n- (void)push:(UIViewController*)vc onTop:(UIViewController*)onTopVC\n     animated:(BOOL)animated completion:(void(^)(void))completion rejection:(RCTPromiseRejectBlock)rejection;\n- (void)popAnimated:(BOOL)animated completion:(void(^)(NSString*))completion rejection:(RCTPromiseRejectBlock)rejection;\n@end\n```\n\n### Bottom Tabs (RNNBottomTabsController)\n- Subclass of UITabBarController\n- Tab attachment modes: Together, OnSwitchToTab, AfterInitialTab\n- Long-press gesture support\n- Badge and dot indicator support\n\n### Side Menu (RNNSideMenuViewController)\n- Uses MMDrawerController (third-party)\n- Center, left, right child containers\n- Configurable open modes and widths\n\n### Top Tabs (RNNTopTabsViewController)\n- Custom horizontal tab implementation\n- Not based on UITabBarController\n- Manual content switching\n\n### Split View (RNNSplitViewController)\n- UISplitViewController subclass\n- Master-detail for iPad\n\n## External Components\n\n### RNNExternalComponentStore\nRegistry for native (non-React) view controllers.\n\n### RNNExternalViewController\nWraps native UIViewController for integration:\n\n```objc\n[ReactNativeNavigation registerExternalComponent:@\"NativeScreen\"\n                                       callback:^(NSDictionary *props, RCTBridge *bridge) {\n    return [[MyNativeViewController alloc] init];\n}];\n```\n\n## Key Files Reference\n\n| File | Purpose |\n|------|---------|\n| `RNNBridgeModule.h/mm` | Bridge entry point (legacy) |\n| `TurboModules/RNNTurboModule.mm` | TurboModule entry point (new arch) |\n| `TurboModules/RNNTurboCommandsHandler.mm` | TurboModule command routing |\n| `RNNCommandsHandler.h/mm` | Command execution |\n| `RNNLayoutManager.h/mm` | Controller tracking |\n| `RNNViewControllerFactory.h/mm` | Controller creation |\n| `RNNComponentViewController.h/mm` | React screen |\n| `RNNStackController.h/mm` | Stack navigation |\n| `RNNBottomTabsController.h/mm` | Tab navigation |\n| `RNNNavigationOptions.h/mm` | Options model |\n| `RNNBasePresenter.h/mm` | Presenter base |\n| `TopBarPresenter.h/mm` | Top bar styling |\n| `RNNReactView.h/mm` | React view wrapper |\n| `ScreenAnimationController.h/mm` | Custom transitions |\n","isInternal":false,"tokens":3681,"sizeBytes":17319},{"name":"ARCHITECTURE.md","path":"src/ARCHITECTURE.md","rawUrl":"https://raw.githubusercontent.com/wix/react-native-navigation/HEAD/src/ARCHITECTURE.md","title":"src - System Architecture & Module Boundaries","category":"project-spec","format":"markdown","content":"# JavaScript/TypeScript Architecture\n\nThe JavaScript layer provides the public API and orchestrates communication between React components and native navigation implementations.\n\n## Entry Point\n\n`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.\n\n## Module Structure\n\n```\nsrc/\n├── index.ts                 # Main entry point, exports Navigation singleton\n├── Navigation.ts            # NavigationRoot - core orchestrator\n├── NavigationDelegate.ts    # Public API facade\n├── adapters/                # Native bridge layer\n├── commands/                # Command processing\n├── components/              # React component management\n├── events/                  # Event system\n├── interfaces/              # TypeScript type definitions\n├── linking/                 # Deep-linking framework (URL → command)\n└── processors/              # Extensibility hooks\n```\n\n## Core Classes\n\n### NavigationDelegate (Public API)\n**File**: `NavigationDelegate.ts`\n\nFacade providing the public `Navigation` API. All methods proxy to `NavigationRoot`.\n\n```typescript\n// Usage\nimport { Navigation } from 'react-native-navigation';\nNavigation.setRoot({ root: { stack: { children: [...] } } });\n```\n\n### NavigationRoot (Core Orchestrator)\n**File**: `Navigation.ts`\n\nCoordinates all subsystems. Constructed with dependencies:\n- `NativeCommandsSender` - sends commands to native\n- `NativeEventsReceiver` - receives events from native\n- `AppRegistryService` - manages React Native component registry\n\nInitializes and coordinates:\n- `Store` - component instance & props storage\n- `ComponentRegistry` - component registration\n- `LayoutTreeParser` - converts layouts to internal nodes\n- `LayoutTreeCrawler` - processes layout trees\n- `Commands` - command execution\n- `EventsRegistry` - event subscriptions\n- `OptionsProcessor` - option processing\n- `LayoutProcessor` - layout transformations\n\n## Adapters Layer\n\nBridge between JavaScript and native/React Native APIs.\n\n| Adapter | Purpose |\n|---------|---------|\n| `NativeCommandsSender` | Wraps TurboModule for command dispatch |\n| `NativeEventsReceiver` | Wraps NativeEventEmitter for events |\n| `NativeRNNTurboModule` | TurboModule spec interface |\n| `NativeRNNTurboEventEmitter` | TurboModule event emitter spec |\n| `UniqueIdProvider` | Generates unique component/command IDs |\n| `ColorService` | Converts colors to native format |\n| `AssetResolver` | Resolves require() image assets (class: AssetService) |\n| `AppRegistryService` | Registers components with React Native |\n| `Constants` | Platform dimension constants |\n| `TouchablePreview` | 3D Touch / Haptic preview handling |\n\n## Commands Layer\n\n### Commands Class\n**File**: `commands/Commands.ts`\n\nCentral command dispatcher. Each navigation command:\n1. Validates input\n2. Processes layout through pipeline\n3. Sends to native via adapter\n4. Returns promise with result\n\n### Processing Pipeline\n\nThe pipeline executes in this exact order:\n\n```\nInput Layout (from API)\n       ↓\n1. OptionsCrawler.crawl()         # Extract static options from component classes\n       ↓\n2. LayoutProcessor.process()      # Apply registered layout processors\n       ↓\n3. LayoutTreeParser.parse()       # Convert to internal LayoutNode tree\n       ↓\n4. LayoutTreeCrawler.crawl()      # Process options, save props to Store\n       ↓\n5. OptionsProcessor (during crawl) # Resolve colors, assets, custom processors\n       ↓\n6. NativeCommandsSender           # Send to native module\n```\n\n### LayoutNode (Internal Tree)\n```typescript\ninterface LayoutNode {\n  id: string;           // Unique identifier\n  type: LayoutType;     // Component|Stack|BottomTabs|etc\n  data: {\n    name?: string;      // Component name\n    options?: any;      // Processed options\n    passProps?: any;    // Component props (cleared before native)\n  };\n  children: LayoutNode[];\n}\n```\n\n### LayoutType Enum\n```typescript\nenum LayoutType {\n  Component = 'Component',\n  Stack = 'Stack',\n  BottomTabs = 'BottomTabs',\n  SideMenuRoot = 'SideMenuRoot',\n  SideMenuCenter = 'SideMenuCenter',\n  SideMenuLeft = 'SideMenuLeft',\n  SideMenuRight = 'SideMenuRight',\n  TopTabs = 'TopTabs',\n  ExternalComponent = 'ExternalComponent',\n  SplitView = 'SplitView',\n}\n```\n\n## Components Layer\n\n### ComponentRegistry\n**File**: `components/ComponentRegistry.ts`\n\nManages React component registration and wrapping.\n\n```typescript\nNavigation.registerComponent('ScreenName', () => MyComponent);\n```\n\n### ComponentWrapper\n**File**: `components/ComponentWrapper.tsx`\n\nHigher-order component that:\n- Wraps original component with lifecycle management\n- Stores instance in `Store` for event dispatch\n- Injects `componentId` and `componentName` props\n\n### Store\n**File**: `components/Store.ts`\n\nCentralized storage for:\n- `componentsByName` - registered component providers\n- `componentsInstancesById` - mounted component instances\n- `propsById` - static props by component ID\n- `pendingPropsById` - props awaiting component mount\n- `wrappedComponents` - cached wrapped components\n- `lazyRegistratorFn` - function for lazy component registration\n\n## Events Layer\n\n### EventsRegistry\n**File**: `events/EventsRegistry.ts`\n\nPublic API for event subscriptions:\n\n```typescript\nNavigation.events().registerComponentDidAppearListener(({ componentId }) => {});\nNavigation.events().registerCommandCompletedListener(({ commandId }) => {});\n```\n\n### ComponentEventsObserver\n**File**: `events/ComponentEventsObserver.ts`\n\nDispatches events to component instance methods:\n- `componentWillAppear()`\n- `componentDidAppear()`\n- `componentDidDisappear()`\n- `navigationButtonPressed()`\n- `screenPopped()`\n\n### CommandsObserver\n**File**: `events/CommandsObserver.ts`\n\nNotifies listeners of command lifecycle (start, complete).\n\n## Events (Native → JS)\n\n| Event | Description |\n|-------|-------------|\n| `RNN.AppLaunched` | App initialization complete |\n| `RNN.ComponentWillAppear` | Component about to appear |\n| `RNN.ComponentDidAppear` | Component now visible |\n| `RNN.ComponentDidDisappear` | Component hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tapped |\n| `RNN.BottomTabPressed` | Tab pressed (even if selected) |\n| `RNN.BottomTabSelected` | Tab selection changed |\n| `RNN.BottomTabLongPressed` | Tab long-pressed |\n| `RNN.ModalDismissed` | Modal was dismissed |\n| `RNN.ModalAttemptedToDismiss` | Swipe-to-dismiss attempted |\n| `RNN.ScreenPopped` | Screen removed from stack |\n| `RNN.SearchBarUpdated` | Search text changed |\n| `RNN.SearchBarCancelPressed` | Search cancelled |\n| `RNN.PreviewCompleted` | 3D Touch preview completed |\n| `RNN.CommandCompleted` | Navigation command finished |\n\n## Linking Layer\n\nImplements URL-to-screen routing on top of the standard command pipeline. The whole feature is JS-only; it consumes URLs from RN's `Linking` module and dispatches `showModal` (or a user-supplied command) when a match is found.\n\n**Public surface** (proxied through `NavigationDelegate`):\n- `Navigation.setLinking(config)` — configure prefixes, screen map, and customization hooks\n- `Navigation.handleDeepLink(url)` — manually feed a URL (push notifications, branch.io, App Clips)\n- `Navigation.setLinkingReady(ready)` — user-controlled gate for deferred deep links\n\n**Internal modules** (`src/linking/`):\n\n| File | Purpose |\n|------|---------|\n| `LinkingHandler.ts` | Orchestrator. Subscribes to `Linking.url`/`getInitialURL`, drives the queue, dispatches matches. Instantiated by `NavigationRoot`. |\n| `URLParser.ts` | Strips prefix (longest match), removes fragment, decodes path segments + query params. |\n| `RouteMatcher.ts` | Compiles `ScreensConfig` into a `RouteNode` tree; matches paths to screen chains with parameter extraction. |\n| `DeferredLinkQueue.ts` | FIFO queue. Holds URLs until both gates open (root-ready + user-ready). |\n| `ModalLayoutBuilder.ts` | Default presentation: wraps the matched chain in a `stack`, merges params into `passProps`, filters React-reserved keys (`ref`, `key`). |\n| `types.ts` | Public types: `LinkingConfig`, `RouteMatch`, `ScreensConfig`, etc. (re-exported via `src/index.ts`). |\n\n**Readiness gates** — a URL is dispatched only when both are true:\n1. **Root-ready** (automatic): the first `Navigation.setRoot()` has resolved. `NavigationRoot.setRoot` calls `linkingHandler.setRootReady()` after the promise resolves.\n2. **User-ready** (optional): `config.isReady()` returns `true`, or `setLinkingReady(true)` was called.\n\n**Resolution priority** when a match is found:\n1. `config.onLink(match)` — full escape hatch, RNN does nothing else\n2. `config.getModal(match)` — custom modal layout\n3. Default `ModalLayoutBuilder` output\n\n## Processors Layer\n\n### OptionProcessorsStore\n**File**: `processors/OptionProcessorsStore.ts`\n\nRegisters custom option processors:\n\n```typescript\nNavigation.addOptionProcessor('topBar.title.text', (value, commandName) => {\n  return value.toUpperCase(); // Transform all titles\n});\n```\n\n### LayoutProcessorsStore\n**File**: `processors/LayoutProcessorsStore.ts`\n\nRegisters layout transformers:\n\n```typescript\nNavigation.addLayoutProcessor((layout, commandName) => {\n  // Add default options to all components\n  return layout;\n});\n```\n\n## Interfaces\n\n### Layout Types\n**File**: `interfaces/Layout.ts`\n\n```typescript\ninterface LayoutRoot {\n  root: Layout;\n  modals?: any[];\n  overlays?: any[];\n}\n\ntype Layout = {\n  component?: LayoutComponent;\n  stack?: LayoutStack;\n  bottomTabs?: LayoutBottomTabs;\n  sideMenu?: LayoutSideMenu;\n  splitView?: LayoutSplitView;\n  topTabs?: LayoutTopTabs;\n  externalComponent?: ExternalComponent;\n}\n```\n\n### Options Interface\n**File**: `interfaces/Options.ts` (comprehensive)\n\nContains all configuration options for:\n- Status bar, navigation bars\n- Top bar (buttons, title, search)\n- Bottom tabs\n- Side menus\n- Modals, overlays\n- Animations\n- Layout parameters\n\n### NavigationComponent\n**File**: `interfaces/NavigationComponent.ts`\n\nBase class for navigation-aware components:\n\n```typescript\nclass MyScreen extends NavigationComponent<Props> {\n  static options: Options = { ... };\n\n  componentDidAppear(event) { }\n  navigationButtonPressed(event) { }\n}\n```\n\n## Dependencies\n\n**Production**:\n- `lodash` - utility functions\n- `hoist-non-react-statics` - HOC support\n- `react-lifecycles-compat` - lifecycle polyfill\n- `tslib` - TypeScript helpers\n\n**Peer**:\n- `react`, `react-native` (required)\n- `remx` (optional state management)\n\n## Build Output\n\nUses `react-native-builder-bob`:\n- **Source**: `src/`\n- **Output**: `lib/`\n- **Targets**: ESM modules + TypeScript declarations\n","isInternal":false,"tokens":2468,"sizeBytes":10783},{"name":"rn-version-upgrade.md","path":".claude/skills/rn-version-upgrade.md","rawUrl":"https://raw.githubusercontent.com/wix/react-native-navigation/HEAD/.claude/skills/rn-version-upgrade.md","title":"Skills Skill","category":"anthropic-skill","format":"markdown","content":"# Skill: Add Support for a New React Native Version\n\nThis skill guides the process of adding support for a new React Native version to react-native-navigation (RNN). It covers CI setup, dependency analysis, native code fixes, playground validation, and the version-switch infrastructure.\n\n## Prerequisites\n\nBefore starting, gather:\n- The target RN version number (e.g., `0.84.0`)\n- The previous highest supported RN version (check `package.json` and `.buildkite/pipeline.sh`)\n\n## Phase 1: Research Breaking Changes\n\n**This phase is critical and prevents most downstream failures. Do it thoroughly before writing any code.**\n\n### 1a. Read the RN Release Blog & Changelog\n\nFetch the release blog post and changelog for the target version:\n- Blog: `https://reactnative.dev/blog` (search for the version)\n- Changelog: `https://github.com/facebook/react-native/blob/main/CHANGELOG.md`\n\nFocus on:\n- **Removed APIs/classes** (iOS and Android) -- these cause compile errors\n- **Changed method signatures** (Android) -- parameters becoming non-nullable, new required params, etc. (e.g., `ColorPropConverter.getColor()` changed in 0.80)\n- **Deprecated APIs now removed** -- check if RNN uses any deprecated APIs from prior versions\n- **Architecture changes** (e.g., New Architecture enforcement, legacy arch removal)\n- **Build system changes** -- Gradle version, Android SDK levels, Kotlin version, CocoaPods/podspec changes, Xcode requirements\n- **Header/import changes** -- headers moved, renamed, or removed from precompiled binaries\n- **CocoaPods / podspec changes** -- Check if RN changed how native modules declare dependencies (e.g., the shift to `install_modules_dependencies` in 0.80). Review `ReactNativeNavigation.podspec` for hardcoded dependency lists, header search paths, or compiler flags that may need updating.\n- **Kotlin version requirements** -- Newer RN versions may require newer Kotlin versions (e.g., RN 0.79+ requires Kotlin 2.x). Check if the version needs bumping.\n\n### 1b. Check RNN's Usage of Known Risk Areas\n\nSearch the RNN codebase for any classes/headers mentioned as removed or changed:\n\n```bash\n# Search iOS for legacy RCT headers (common removal targets)\ngrep -rn \"#import <React/RCT\" ios/ --include=\"*.h\" --include=\"*.mm\" --include=\"*.m\"\n\n# Search Android for deprecated classes\ngrep -rn \"CSSBackgroundDrawable\\|onCatalystInstanceDestroy\\|ReactInstanceManager\" android/ --include=\"*.java\" --include=\"*.kt\"\n\n# Check Android test infrastructure for classes extending RN framework classes\ngrep -rn \"extends.*React\\|: React\" android/ --include=\"*.java\" --include=\"*.kt\" | grep -i \"test\\|mock\\|simple\"\n```\n\n**If the new RN version strips legacy headers from the xcframework** (look for `RCT_REMOVE_LEGACY_ARCH` changes in the RN release), identify ALL iOS files importing legacy-only headers and plan to guard them in batch. Do NOT rely on iterative build failures to find them one by one. Cross-reference each `#import <React/RCT...>` against the headers actually available in the new RN version's xcframework.\n\n### 1c. Check Third-Party Dependency Compatibility\n\nFor each playground dependency that wraps native code, verify compatibility with the target RN version:\n\n1. **react-native-reanimated** -- Check https://docs.swmansion.com/react-native-reanimated/docs/guides/compatibility/ for the compatibility table. This is the most frequent source of build failures.\n2. **react-native-gesture-handler** -- Check release notes for RN version support.\n3. **react-native-fast-image** (or `@d11/react-native-fast-image`) -- Check for Fabric/new arch support.\n4. **react-native-worklets** -- Must be compatible with the reanimated version you chose.\n5. **Other native deps** -- Check each one's GitHub releases/issues for RN version support.\n\nAlso check the full peer dependency tree: `npm info react-native@<version> peerDependencies` for all peer deps, not just `react`.\n\n**Key lesson from RN 0.84**: Reanimated 4.2.0 did NOT support RN 0.84 (needed 4.2.2+). The `react-native-worklets` package also needed bumping (0.7.1 -> 0.7.4). Not catching this early means the build will fail late in the process.\n\n**Key lesson from RN 0.83**: The original `react-native-fast-image` package was abandoned and had no Fabric support. The `@d11/react-native-fast-image` fork was needed as a replacement. When replacing a package, check ALL references: package.json (root AND playground), TypeScript imports, Android `build.gradle` manual `implementation project()` lines, and iOS pod references.\n\n## Phase 2: CI Infrastructure Setup\n\n### 2a. Maintain Buildkite CI Jobs\n\nCopy an existing job file and update the version:\n\n```bash\n# Copy from the latest supported RN lane (adjust source/target versions)\ncp .buildkite/jobs/pipeline.android_rn_84.yml .buildkite/jobs/pipeline.android_rn_85.yml\ncp .buildkite/jobs/pipeline.ios_rn_84.yml .buildkite/jobs/pipeline.ios_rn_85.yml\n```\n\nEdit both files:\n- Update the label: `\":android: Android (RN 0.84.0)\"`\n- Update `REACT_NATIVE_VERSION: 0.84.0`\n- Update the key: `\"android_rn_84\"` / `\"ios_rn_84\"`\n- Keep `JAVA_HOME` on Android jobs (check if JDK version needs bumping)\n\n### 2b. Register Jobs in Pipeline Script\n\nAdd the new jobs to `.buildkite/pipeline.sh`:\n\n```bash\ncat .buildkite/jobs/pipeline.android_rn_84.yml\ncat .buildkite/jobs/pipeline.ios_rn_84.yml\n```\n\nInsert them in version order alongside the other platform jobs. Release publishing is dispatched separately through the GitHub Actions release workflow.\n\n### 2c. Optionally Drop Old Versions\n\nIf the project drops support for an old version, remove its pipeline files and entries from `pipeline.sh`. RN 0.82 PR dropped RN 0.80 and 0.81 pipelines.\n\n## Phase 3: Update Default Versions and Build Configuration\n\n### 3a. Update `package.json` (Root and Playground)\n\nUpdate in both `/package.json` and `/playground/package.json`:\n- `react-native` to the target version\n- `react` to the matching peer dependency version (check `npm info react-native@0.84.0 peerDependencies.react`)\n- `react-test-renderer` to match react\n- `@react-native/babel-preset`, `@react-native/eslint-config`, `@react-native/metro-config`, `@react-native/typescript-config` to `0.<minor>.0`\n- `@react-native-community/cli`, `cli-platform-android`, `cli-platform-ios` to matching CLI version\n- Any third-party deps identified in Phase 1c as needing version bumps\n\n### 3b. Update Android SDK, NDK, and Kotlin Versions\n\nCheck the target RN version's requirements and update in **both** `android/build.gradle` (the library defaults) and `playground/android/build.gradle`:\n- `compileSdkVersion` / `compileSdk`\n- `targetSdkVersion` / `targetSdk`\n- `buildToolsVersion`\n- `ndkVersion`\n- Kotlin version (`kotlinVersion` / `RNNKotlinVersion`)\n\nCross-reference with the RN template app's `build.gradle` for the target version (`npx @react-native-community/cli init` or check the RN GitHub repo).\n\nAlso update `autolink/fixtures/rn79/build.gradle.template` if SDK or Kotlin versions changed there.\n\n### 3c. Update Gradle Wrapper\n\nIf the target RN requires a newer Gradle version, update `playground/android/gradle/wrapper/gradle-wrapper.properties`.\n\n### 3d. Update Version-Switch Infrastructure\n\nUpdate `scripts/versionMapping.js`:\n- Add the new minor version to `CLI_VERSION_MAP`\n- Update `getGradleVersion()` if the Gradle version requirement changed\n- Update `getReanimatedOverride()` / `shouldRemoveWorklets()` if compatibility ranges changed\n\nUpdate `playground/android/rninfo.gradle` if new version-conditional logic is needed:\n- Add new boolean flags (e.g., `isRN84OrHigher`) if Gradle build logic needs to branch on the new version\n- Used for things like Kotlin version branching and conditional dependency resolution\n\n### 3e. Review and Update Podspec and Podfile\n\n**`ReactNativeNavigation.podspec`** may need changes if RN altered how native modules declare dependencies:\n- Manual `s.dependency` lists for React submodules may be replaced by `install_modules_dependencies(s)` (happened in 0.80)\n- Hardcoded `HEADER_SEARCH_PATHS`, folly compiler flags, or per-arch dependency lists may become unnecessary\n- Compare against the new RN version's recommended podspec pattern\n\n**`playground/ios/Podfile`** may need restructuring if RN changed `use_react_native!`, new arch configuration, or post-install hooks. Compare against the RN template app's Podfile for the target version.\n\n### 3f. Install Dependencies\n\nAfter updating package.json and build configs:\n\n```bash\ncd playground && yarn install && cd ios && pod deintegrate && pod install && cd ../..\n```\n\n### 3g. Clean Stale Xcode Build Settings\n\n**Do this BEFORE the first build** -- stale settings cause mysterious \"module not found\" errors.\n\nThe `playground/ios/playground.xcodeproj/project.pbxproj` may contain hardcoded build settings from previous RN versions (e.g., `REACT_NATIVE_MINOR_VERSION=72`, stale modulemap paths in `OTHER_CFLAGS`). Search for and remove/fix these:\n\n```bash\ngrep -n \"REACT_NATIVE_MINOR_VERSION\\|REANIMATED_VERSION\\|modulemap\" playground/ios/playground.xcodeproj/project.pbxproj\n```\n\nReplace hardcoded values with `\"$(inherited)\"` where appropriate.\n\n## Phase 4: Fix Native Compilation Errors\n\n### Strategy\n\nFor **systematic, known patterns** identified in Phase 1 (like legacy import guarding across many files), fix all instances in batch before building. This avoids slow iterative build cycles.\n\nFor **unexpected errors**, use an iterative build-fix approach: build, fix the first error, rebuild, repeat.\n\n```bash\n# iOS build\nxcodebuild build -workspace playground/ios/playground.xcworkspace \\\n  -scheme playground -configuration Debug -sdk iphonesimulator \\\n  -destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' -quiet\n\n# Android build\ncd playground/android && ./gradlew assembleDebug\n```\n\n### 4a. Batch-Fix: Guard Legacy iOS Imports\n\nIf the new RN version removes legacy headers from precompiled binaries, guard ALL identified imports at once.\n\n**Preferred approach: `__has_include` (compile-time header check)**\n\nThe best way to guard optional headers is `#if __has_include(...)`. This is forward-compatible — if a future RN version removes more headers, the code adapts automatically without needing new flags:\n\n```objc\n#if __has_include(<React/RCTScrollView.h>)\n#import <React/RCTScrollView.h>\n#endif\n\n#if __has_include(<React/RCTCxxBridgeDelegate.h>)\n#import <React/RCTCxxBridgeDelegate.h>\n#endif\n```\n\nUse `__has_include` for **imports** where the header may or may not exist. Then use `NSClassFromString` (see Pattern 3 below) for runtime references to classes from those headers.\n\n**Alternative: `#ifndef RCT_REMOVE_LEGACY_ARCH`**\n\nStarting with RN 0.84, React Native defines `RCT_REMOVE_LEGACY_ARCH=1` when legacy/bridge APIs are fully removed. This is more precise than `RCT_NEW_ARCH_ENABLED` (which has been true since RN 0.76 even though legacy APIs were still available). Use this for guarding **code blocks** that use legacy APIs:\n\n```objc\n#ifndef RCT_REMOVE_LEGACY_ARCH\n#import <React/RCTModalHostViewManager.h>\n#endif\n\n// In implementation:\n#ifndef RCT_REMOVE_LEGACY_ARCH\n- (void)connectModalHostViewManager:(RCTModalHostViewManager *)manager {\n    // old-arch-only code\n}\n#endif\n```\n\n**When to use which:**\n- `__has_include(...)` — for **imports** of headers that may not exist. Most robust, no flag dependency.\n- `#ifndef RCT_REMOVE_LEGACY_ARCH` — for **code blocks** using legacy APIs (method declarations, implementations, protocol conformances). Semantically correct: \"this code requires the legacy arch.\"\n- `#ifdef RCT_NEW_ARCH_ENABLED` — only for code that differs **between architectures** (e.g., `RCTHost` vs `RCTBridge` parameters). NOT for \"is legacy available?\" checks.\n\n**Steps:**\n\n1. List all files importing legacy headers:\n   ```bash\n   grep -rn \"#import <React/RCTRootView\\|#import <React/RCTRootViewDelegate\\|#import <React/RCTBridge+Private\\|#import <React/RCTModalHostView\\|#import <React/RCTScrollView\\|#import <React/RCTRootContentView\\|#import <React/RCTSurfacePresenterStub\\|#import <React/RCTBridgeProxy\" ios/ --include=\"*.h\" --include=\"*.mm\"\n   ```\n\n2. For each file, apply the appropriate guard (prefer `__has_include` for imports, `#ifndef RCT_REMOVE_LEGACY_ARCH` for code blocks).\n\n3. **Guard the full chain**: import -> type usage -> method declarations -> protocol conformances -> method implementations. Guarding just the import without guarding the code that uses the type causes \"undeclared identifier\" errors.\n\n4. **Check for dead code in `#ifdef` blocks**: After guarding imports, search for old-arch symbols referenced in new-arch code paths:\n   ```bash\n   # Find potential dead references to bridge in new-arch blocks\n   grep -n \"getBridge\\|bridgeManager\\|RCTBridge\" ios/ --include=\"*.mm\" -r\n   ```\n   Cross-reference hits with their surrounding `#ifdef` context. Remove any new-arch code that calls old-arch-only methods.\n\n### 4b. Common iOS Fix Patterns\n\n**Pattern 1: Guard optional imports with `__has_include`** -- Preferred for headers that may not exist:\n```objc\n#if __has_include(<React/RCTSurfacePresenterBridgeAdapter.h>)\n#import <React/RCTSurfacePresenterBridgeAdapter.h>\n#endif\n```\n\n**Pattern 2: Guard legacy code blocks with `RCT_REMOVE_LEGACY_ARCH`** -- For methods/classes that only exist on old arch:\n```objc\n#ifndef RCT_REMOVE_LEGACY_ARCH\n- (void)connectModalHostViewManager:(RCTModalHostViewManager *)manager { ... }\n#endif\n```\n\n**Pattern 3: Guard entire files** -- If a file is only used on old arch (e.g., `RNNBridgeManager.h/.mm`), wrap the entire content in `#ifndef RCT_REMOVE_LEGACY_ARCH`.\n\n**Pattern 4: Runtime class lookup** -- When you need to reference a class that may not exist at compile time (e.g., in `hitTest:withEvent:` or `isKindOfClass:` checks), use `NSClassFromString` instead of direct class references. This pairs well with `__has_include` — the import is conditional, and the runtime check handles the case where the class doesn't exist:\n\n```objc\n// Instead of: [view isKindOfClass:[RCTModalHostView class]]\n[view isKindOfClass:NSClassFromString(@\"RCTModalHostView\")]\n```\n\nCache the result with `dispatch_once` if it's in a hot path:\n```objc\nstatic Class myClass;\nstatic dispatch_once_t onceToken;\ndispatch_once(&onceToken, ^{\n    myClass = NSClassFromString(@\"RCTModalHostView\");\n});\n```\n\n**Pattern 5: Remove dead code paths** -- A `#ifdef RCT_NEW_ARCH_ENABLED` block that calls `getBridge` (old-arch only) is dead code -- remove it.\n\n**Pattern 6: Protocol conformance guards** -- If a protocol (e.g., `RCTRootViewDelegate`) only exists on old arch, guard the conformance declaration AND the delegate method implementations:\n\n```objc\n@interface MyView : UIView\n#ifndef RCT_NEW_ARCH_ENABLED\n                    <RCTRootViewDelegate>\n#endif\n```\n\n### 4c. Common Android Fix Patterns\n\n**Pattern 1: Deprecated method migration** -- When RN deprecates methods with `forRemoval = true`, rename to the replacement (e.g., `onCatalystInstanceDestroy()` -> `invalidate()`). Note: only rename the RN framework override, not internal RNN methods with the same name.\n\n**Pattern 2: Removed classes** -- When Android classes are removed (e.g., `CSSBackgroundDrawable` in RN 0.83), replace with standard Android equivalents (e.g., `ColorDrawable`).\n\n**Pattern 3: Test infrastructure** -- Test/mock classes that extend RN framework classes (e.g., `SimpleView extends ReactView`) may need refactoring if the parent class behavior changed. Also check Robolectric version compatibility -- newer Android SDK levels may require bumping Robolectric, and if the new Robolectric version requires a higher Java version than CI provides, add a `robolectric.properties` file to pin the SDK level (e.g., `sdk=35` when SDK 36 requires Java 21 but CI uses Java 17).\n\n**Pattern 4: Changed method signatures** -- RN may change method signatures without deprecation (e.g., nullable parameters becoming non-nullable, or new required parameters). These cause compile errors that aren't caught by searching for removed/deprecated APIs. Check the RN changelog for API changes in utility classes like `ColorPropConverter`, `ColorParser`, etc.\n\n### 4d. Research Before Fixing: Don't Just Pattern-Match\n\n**When you hit a new compilation error, resist the urge to immediately copy the fix pattern from nearby code.** Instead:\n\n1. **Check what the target RN version introduces.** Read the RN changelog/blog for new preprocessor flags, build system features, or recommended migration patterns. For example, RN 0.84 introduced `RCT_REMOVE_LEGACY_ARCH` — a flag specifically designed for the exact guarding problem we need to solve. Using it is better than repurposing `RCT_NEW_ARCH_ENABLED`.\n\n2. **Search for how other RN libraries solved it.** Check how major community libraries (react-native-screens, react-native-reanimated, react-native-gesture-handler) handle the same compatibility issue. They often discover better patterns first.\n\n3. **Evaluate the existing codebase pattern critically.** The pattern used in the current code may predate better alternatives. Ask: is there a more forward-compatible approach? Would `__has_include` be more robust than a flag check? Would `NSClassFromString` be cleaner than a compile-time guard?\n\n4. **Prefer compile-time safety over runtime safety, and standard compiler features over framework-specific flags.** `__has_include` is a C/ObjC compiler feature that works regardless of RN version. Framework flags like `RCT_REMOVE_LEGACY_ARCH` are next best. `NSClassFromString` is a runtime fallback for when compile-time checks aren't sufficient.\n\n### 4e. Compile Error Triage\n\nWhen you get a compile error:\n1. Identify the missing symbol (header, class, method)\n2. **Research** the best available guard mechanism (see 4d above)\n3. Check if it's used only in old-arch or new-arch code paths\n4. If old-arch only: guard with `__has_include` (imports) or `#ifndef RCT_REMOVE_LEGACY_ARCH` (code)\n5. If new-arch only: this shouldn't happen -- investigate the API replacement\n6. If used in both: find the new-arch equivalent and branch with `#ifdef RCT_NEW_ARCH_ENABLED`\n\n### 4e. Fix Test Files\n\n**Test files are easily overlooked.** They often reference arch-specific APIs (like `RCTBridge` vs `RCTHost`, or methods that only exist under `#ifdef RCT_NEW_ARCH_ENABLED`). Check all test files for arch-specific calls:\n\n```bash\n# Find test files referencing RCTBridge (old-arch only in new-arch builds)\ngrep -rn \"RCTBridge\\|registerExternalComponent\" playground/ios/NavigationTests/ --include=\"*.mm\"\n\n# Check that test method calls match the current header signatures\n# e.g., RNNExternalComponentStore exposes different methods under #ifdef RCT_NEW_ARCH_ENABLED\n```\n\nGuard test code the same way as production code — use `#ifndef RCT_REMOVE_LEGACY_ARCH` for tests that only apply to legacy arch:\n\n```objc\n#ifndef RCT_REMOVE_LEGACY_ARCH\n\n@interface RNNModalHostViewManagerHandlerTest : XCTestCase\n@end\n// ... entire test class ...\n@end\n\n#endif\n```\n\n**Key lesson from RN 0.84**: All 4 iOS CI jobs failed because a single test file (`RNNViewControllerFactoryTest.mm`) called an old-arch method on `RNNExternalComponentStore` without a guard. The fix was trivial but blocked the entire build.\n\n### 4f. clang-format\n\nRNN uses clang-format on iOS files via a pre-commit hook. After editing `.h`/`.mm` files, verify formatting:\n\n```bash\n./node_modules/.bin/git-clang-format --diff -- ios/MyFile.mm\n```\n\nThe formatter has opinions about `#ifdef` indentation that may require unusual formatting (e.g., protocol conformance on a continuation line after `#ifndef`).\n\n## Phase 5: Validate Playground Dependencies\n\n### 5a. Check for Stale References\n\nAfter replacing any dependency (like fast-image -> @d11/fast-image), search for ALL references:\n\n```bash\n# TypeScript imports\ngrep -r \"react-native-fast-image\" playground/src/ --include=\"*.ts\" --include=\"*.tsx\"\n\n# Android gradle -- look for manual implementation project() lines\ngrep -r \"fast-image\\|fast_image\" playground/android/ --include=\"*.gradle\"\n\n# iOS podfile\ngrep -r \"fast-image\\|FastImage\" playground/ios/Podfile\n```\n\nNote: `autolinkLibrariesWithApp()` in the playground's `build.gradle` handles most deps automatically. Manual `implementation project(':...')` lines are often stale and should be removed when the package is autolinked.\n\n## Phase 6: Full Build Verification\n\nRun both platform builds to confirm everything compiles:\n\n```bash\n# iOS\nxcodebuild build -workspace playground/ios/playground.xcworkspace \\\n  -scheme playground -configuration Debug -sdk iphonesimulator \\\n  -destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' -quiet\n\n# Android\ncd playground/android && ./gradlew assembleDebug\n\n# JS tests\nyarn test-js\n```\n\n## Phase 7: Backward Compatibility\n\nVerify that the version-switch script works for older supported versions:\n\n```bash\nREACT_NATIVE_VERSION=0.83.0 node scripts/changeReactNativeVersion.js\n# Then rebuild to verify\n```\n\n## Phase 8: Documentation\n\nUpdate `website/docs/docs/docs-Installing.mdx`:\n- Update the supported RN version range\n- Note any breaking changes users need to be aware of\n\n## Common Pitfalls (Lessons Learned)\n\n1. **Don't assume deps are compatible** -- Always check third-party native dep compatibility tables BEFORE starting the build. Reanimated is the most common offender.\n\n2. **Search for ALL references when replacing a package** -- TypeScript imports, Android gradle `implementation project()` lines, iOS pod references, root AND playground package.json. Missing one causes CI failures.\n\n3. **Legacy headers in precompiled binaries** -- When RN enforces new arch by default (like 0.84 with `RCT_REMOVE_LEGACY_ARCH=1`), headers for old-arch classes are stripped from the xcframework. Use `__has_include` for conditional imports and `#ifndef RCT_REMOVE_LEGACY_ARCH` for code blocks. Batch-fix all legacy imports identified in Phase 1b rather than finding them one build at a time.\n\n4. **Guard code, not just imports** -- Guarding an import without guarding the code that uses the imported types leads to \"undeclared identifier\" errors. Always guard the full chain: import -> type usage -> method declarations -> method implementations.\n\n5. **Dead code in `#ifdef` blocks** -- When splitting code paths between old/new arch, check that each path only references symbols available in that architecture. A common bug is new-arch code calling old-arch-only methods (like `getBridge` in a `#ifdef RCT_NEW_ARCH_ENABLED` block).\n\n6. **Stale Xcode project settings** -- The `.pbxproj` file can accumulate hardcoded build flags from old versions. These cause mysterious \"module not found\" errors. Check for stale `OTHER_CFLAGS` BEFORE the first build (Phase 3g).\n\n7. **clang-format surprises** -- The formatter enforces specific indentation around preprocessor directives. Run the check before committing to avoid hook failures.\n\n8. **Batch-fix systematic patterns, iterate on surprises** -- When you identify a pattern that affects many files (like legacy import guarding), fix all instances at once. Use iterative build-fix only for unexpected or one-off errors.\n\n9. **Android SDK level cascading effects** -- Bumping `compileSdkVersion`/`targetSdkVersion` can require bumping Robolectric, which may require a higher Java version than CI provides. Solution: pin the Robolectric SDK via `robolectric.properties` (e.g., `sdk=35` when SDK 36 needs Java 21).\n\n10. **Podspec can be a major effort** -- Don't underestimate podspec changes. RN 0.80 required replacing the entire dependency declaration strategy. Compare your podspec against the RN template's pattern for the target version.\n\n11. **Don't forget test files** -- Test files (`NavigationTests/*.mm`) often call arch-specific APIs directly. When guarding production code, search test files for the same APIs and guard them too. A single unguarded test call can fail the entire CI build across all RN versions.\n\n12. **Don't just follow existing patterns — research better ones** -- When fixing a compilation error, don't blindly copy the guarding pattern already used in the codebase. The existing pattern may predate better alternatives introduced in newer RN versions. For example, RN 0.84 introduced `RCT_REMOVE_LEGACY_ARCH` and the codebase already supported `__has_include`, but initial fixes used the older `#ifdef RCT_NEW_ARCH_ENABLED` pattern because that's what the existing code used. Always check: what new preprocessor flags or build-system features does the target RN version introduce? Is there a more robust/forward-compatible way to solve this?\n","isInternal":false,"tokens":5766,"sizeBytes":24493},{"name":"SKILL.md","path":".claude/skills/rnn-codebase/SKILL.md","rawUrl":"https://raw.githubusercontent.com/wix/react-native-navigation/HEAD/.claude/skills/rnn-codebase/SKILL.md","title":"rnn-codebase","category":"anthropic-skill","format":"markdown","content":"---\nname: rnn-codebase\ndescription: Navigate and work with the react-native-navigation (RNN) codebase. Use when fixing bugs, adding features, tracing command flows, understanding options resolution, or working across JS/iOS/Android layers in this repo.\n---\n\n# React Native Navigation Codebase\n\n## Architecture Overview\n\nRNN has three layers that mirror each other:\n\n```\nJS/TS (src/)  →  TurboModule bridge  →  iOS native (ios/)\n                                     →  Android native (android/)\n```\n\nA navigation command (e.g. `push`) flows:\n1. `Navigation.push()` → `Commands.ts` → processing pipeline → `NativeCommandsSender.ts`\n2. TurboModule: `RNNTurboModule` (iOS) / `NavigationTurboModule.kt` (Android)\n3. iOS: `RNNCommandsHandler` → `RNNViewControllerFactory` → UIKit controllers\n4. Android: `Navigator` → `LayoutFactory` → View-based controllers (no Fragments)\n\nRead [ARCHITECTURE.md](../../ARCHITECTURE.md) for the full overview.\n\n## Key Cross-Layer Mappings\n\n### Layout Types → Native Controllers\n\n| JS Layout Type | iOS Controller | Android Controller |\n|----------------|---------------|-------------------|\n| `component` | `RNNComponentViewController` | `ComponentViewController` |\n| `stack` | `RNNStackController` (UINavigationController) | `StackController` |\n| `bottomTabs` | `RNNBottomTabsController` (UITabBarController) | `BottomTabsController` |\n| `sideMenu` | `RNNSideMenuViewController` (MMDrawerController) | `SideMenuController` (DrawerLayout) |\n| `topTabs` | `RNNTopTabsViewController` | `TopTabsController` (ViewPager) |\n| `splitView` | `RNNSplitViewController` | N/A (iOS only) |\n| `externalComponent` | `RNNExternalViewController` | `ExternalComponentViewController` |\n\n### Options → Presenters\n\nEach controller type has a Presenter that applies options to views:\n\n| iOS Controller | iOS Presenter | Android Presenter |\n|----------------|--------------|-------------------|\n| `RNNComponentViewController` | `RNNComponentPresenter` | `ComponentPresenter` |\n| `RNNStackController` | `RNNStackPresenter` + `TopBarPresenter` | `StackPresenter` |\n| `RNNBottomTabsController` | `RNNBottomTabsPresenter` | `BottomTabsPresenter` |\n| `RNNSideMenuViewController` | `RNNSideMenuPresenter` | `SideMenuPresenter` |\n\n### Events (same names both platforms)\n\n| Event | Trigger |\n|-------|---------|\n| `RNN.ComponentDidAppear` | Screen becomes visible |\n| `RNN.ComponentDidDisappear` | Screen hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tap |\n| `RNN.BottomTabSelected` | Tab changed |\n| `RNN.ModalDismissed` | Modal dismissed |\n| `RNN.ScreenPopped` | Screen popped from stack |\n| `RNN.CommandCompleted` | Any command finished |\n\n## Where to Find Things\n\n### By task: \"I need to fix/change X\"\n\n| Task | JS File(s) | iOS File(s) | Android File(s) |\n|------|-----------|------------|----------------|\n| Command execution | `src/commands/Commands.ts` | `ios/RNNCommandsHandler.mm` | `react/NavigationTurboModule.kt` |\n| Layout creation | `src/commands/LayoutTreeParser.ts` | `ios/RNNViewControllerFactory.mm` | `options/LayoutFactory.java` |\n| Options processing | `src/commands/OptionsProcessor.ts` | `ios/RNNNavigationOptions.mm` | `options/Options.java` |\n| Options application | — | `ios/*Presenter.mm` | `viewcontrollers/*Presenter.java` |\n| TopBar | `src/interfaces/Options.ts` (TopBarOptions) | `ios/TopBarPresenter.mm`, `ios/RNNUIBarButtonItem.mm` | `views/stack/topbar/` |\n| Bottom tabs | `src/interfaces/Options.ts` (BottomTabsOptions) | `ios/RNNBottomTabsPresenter.mm` | `viewcontrollers/bottomtabs/` |\n| Modals | `src/commands/Commands.ts` | `ios/RNNModalManager.mm` | `viewcontrollers/modal/ModalStack.java` |\n| Overlays | `src/commands/Commands.ts` | `ios/RNNOverlayManager.mm` | `viewcontrollers/overlay/OverlayManager.kt` |\n| Animations | `src/interfaces/Options.ts` (AnimationOptions) | `ios/ScreenAnimationController.mm` | `viewcontrollers/stack/StackAnimator.kt` |\n| React view rendering | — | `ios/RNNReactView.mm` | `react/ReactView.java` |\n| Events to JS | `src/adapters/NativeEventsReceiver.ts` | `ios/RNNEventEmitter.mm` | `react/events/EventEmitter.java` |\n| Component registration | `src/components/ComponentRegistry.ts` | — | — |\n| Deep linking (URL → screen) | `src/linking/` (`LinkingHandler`, `URLParser`, `RouteMatcher`, `DeferredLinkQueue`, `ModalLayoutBuilder`) | `ios/RNNAppDelegate.mm` (`dispatchDeepLinkURL:`, cold-start queue, `RCTContentDidAppearNotification`) | `NavigationActivity.onNewIntent` → `ReactGateway` |\n\n### By directory\n\n- **`src/`** — JS public API, commands, processing pipeline. See [src/ARCHITECTURE.md](../../src/ARCHITECTURE.md)\n- **`ios/`** — All Obj-C/C++ native code. See [ios/ARCHITECTURE.md](../../ios/ARCHITECTURE.md)\n- **`ios/TurboModules/`** — New architecture entry points (`RNNTurboModule`, `RNNTurboManager`, `RNNTurboCommandsHandler`)\n- **`android/src/main/java/com/reactnativenavigation/`** — All Java/Kotlin native code. See [android/ARCHITECTURE.md](../../android/ARCHITECTURE.md)\n- **`playground/`** — Demo app for development and E2E tests\n- **`playground/src/screens/`** — Test screens exercising every feature\n- **`playground/e2e/`** — Detox E2E tests\n\n## Options Resolution Order\n\nOptions are applied in ascending priority:\n1. Default options (from `Navigation.setDefaultOptions()`) — lowest priority\n2. Static options (from component class or `Navigation.registerComponent`)\n3. Options passed in the layout call (e.g. `push`, `setRoot`)\n4. `mergeOptions()` — runtime override, highest priority\n\n## JS Processing Pipeline (exact order)\n\n```\nAPI layout → OptionsCrawler.crawl() → LayoutProcessor.process()\n  → LayoutTreeParser.parse() → LayoutTreeCrawler.crawl()\n  → OptionsProcessor (colors, assets, custom) → NativeCommandsSender\n```\n\n## iOS Patterns\n\n- All controllers conform to `RNNLayoutProtocol`\n- `RNNBasePresenter` subclasses apply options — `applyOptionsOnInit:`, `applyOptions:`, `mergeOptions:resolvedOptions:`\n- Commands run on main thread (`RCTExecuteOnMainQueue`)\n- React views: `RNNReactView` wraps `RCTSurfaceHostingView` (new arch)\n- Overlays use separate `UIWindow` instances (`RNNOverlayWindow`)\n- `RNNReactComponentRegistry` caches React component instances\n\n## Android Patterns\n\n- View-based, NOT Fragment-based\n- All commands dispatched via `UiThread.post()`\n- `ViewController<T extends ViewGroup>` is the base — `createView()` is abstract\n- `ParentController` extends `ChildController` extends `ViewController`\n- Bottom tabs use `AHBottomNavigation` library\n- Three root layouts in `NavigationActivity`: rootLayout, modalsLayout, overlaysLayout\n- Tab attachment modes: `Together`, `OnSwitchToTab`, `AfterInitialTab`\n\n## Development Workflow\n\n### Playground app\n- `yarn start` — Metro bundler\n- `yarn xcode` — Open iOS project\n- `yarn studio` — Open Android project\n- `yarn pod-install` — Install iOS pods\n\n### Testing\n- `yarn test-js` — Jest unit tests\n- `yarn test-unit-ios` — iOS native unit tests (XCTest)\n- `yarn test-unit-android` — Android native unit tests (JUnit + Robolectric)\n- `yarn test-e2e-ios-ci` / `yarn test-e2e-android-ci` — Detox E2E tests\n\n### Building\n- `yarn prepare` — Builds `src/` → `lib/` (ESM + types)\n- Codegen config: `rnnavigation` in `package.json`\n\n## Common Gotchas\n\n- iOS uses UIKit subclasses (UINavigationController, UITabBarController); Android uses custom View hierarchy\n- `splitView` is iOS-only\n- Side menu: iOS uses MMDrawerController (3rd party); Android uses DrawerLayout (native)\n- Options that exist in JS types may not be implemented on both platforms — check the presenter\n- `passProps` are stored in JS `Store`, not sent to native (cleared before bridge crossing)\n- The `lib/` folder is generated — never edit it, edit `src/` instead\n- Deep links are processed only after the first `setRoot()` resolves; pre-bridge URLs on iOS are queued natively in `RNNAppDelegate` and flushed on `RCTContentDidAppearNotification` (bridgeless mode — `RCTJavaScriptDidLoadNotification` does NOT fire)\n- `ModalLayoutBuilder` strips React-reserved keys (`ref`, `key`) from URL query params before they reach `passProps`, to avoid React 19 ref-validation crashes\n","frontmatter":{"name":"rnn-codebase","description":"Navigate and work with the react-native-navigation (RNN) codebase. Use when fixing bugs, adding features, tracing command flows, understanding options resolution, or working across JS/iOS/Android layers in this repo."},"isInternal":false,"tokens":2083,"sizeBytes":8206},{"name":"SKILL.md","path":".cursor/skills/engine-e2e/SKILL.md","rawUrl":"https://raw.githubusercontent.com/wix/react-native-navigation/HEAD/.cursor/skills/engine-e2e/SKILL.md","title":"engine-e2e","category":"anthropic-skill","format":"markdown","content":"---\nname: engine-e2e\ndescription: Run Wix Engine (mobile-apps-engine) iOS E2E tests locally to validate RNN changes. Use when you need to test RNN fixes against the Engine's Detox test suite.\n---\n\n# Running Engine E2E Tests Against Local RNN Changes\n\nThe Engine app (`@wix/wix-one-app-engine`) in `~/Documents/mobile-apps-engine` consumes RNN\nfrom `node_modules/react-native-navigation`. To test RNN changes against the Engine's E2E\nsuite, you patch the Engine's copy of RNN, rebuild the native binary, and run the tests.\n\n## Prerequisites\n\n- Node via nvm (`nvm use default`)\n- The `CI` env var must be **unset** (not `0`, fully unset) to avoid CI-specific codepaths.\n  Use `env -u CI` before every command.\n- The Engine repo at `~/Documents/mobile-apps-engine` with `yarn install` already done.\n\n## Step 1: Patch RNN in Engine's node_modules\n\nApply your RNN source changes to the corresponding files under:\n```\n~/Documents/mobile-apps-engine/node_modules/react-native-navigation/ios/\n```\nThe directory structure mirrors the RNN repo's `ios/` folder exactly.\n\n## Step 2: Rebuild the iOS Native Binary\n\n```bash\ncd ~/Documents/mobile-apps-engine\nunset PREFIX && . ~/.nvm/nvm.sh > /dev/null && nvm use default > /dev/null\nenv -u CI yarn workspace @wix/mobile-apps-engine-native-builds build-local-ios\n```\n\nThis runs `xcodebuild` with `-quiet` flag — expect no output until it finishes.\nTakes ~10-15 minutes on M-series Macs.\n\nThe build output (`.app` bundle) lands in:\n```\npackages/native/mobile-apps-engine-native-builds/dist/binaries.json\n```\n\n### Troubleshooting Build\n\n- **Keychain error** (`SecKeychainUnlock`): The `CI` env var is set. Use `env -u CI`.\n- **Signing errors**: Expected for local builds — the script handles ad-hoc signing.\n\n## Step 3: Build JS Bundles (first time only)\n\nThese are needed once per checkout. Skip if already built.\n\n```bash\nenv -u CI yarn workspace @wix/mobile-apps-engine-extra-bundle local:build\nenv -u CI yarn workspace @wix/mobile-apps-dependencies local:build\n```\n\n## Step 4: Run E2E Tests\n\n```bash\ncd ~/Documents/mobile-apps-engine\nunset PREFIX && . ~/.nvm/nvm.sh > /dev/null && nvm use default > /dev/null\nenv -u CI yarn workspace @wix/wix-one-app-engine test:e2e:ios -w d <suite_files...>\n```\n\nThe `-w d` flag selects the Detox worker count.\n\n### Specific suites relevant to RNN\n\n| Suite file | What it tests |\n|-----------|---------------|\n| `e2e/suites/ExternalLinks.test.js` | Deep link navigation, back button |\n| `e2e/suites/ExternalLinksModes.test.js` | Deep link modes (pop to root, tab switch) |\n| `e2e/suites/ExternalLinksPushNotifications.test.js` | Push notification deep links |\n| `e2e/suites/ExtenalLinksWithSiteSelect.test.js` | Deep links with site selection |\n| `e2e/suites/EngineUIComponents.test.js` | Error screen, UI components |\n| `e2e/suites/LaunchArgs.test.js` | Launch arguments |\n| `e2e/suites/LazyModules.test.js` | Lazy-loaded modules |\n\n### Example: Run the deep-link suites\n\n```bash\nenv -u CI yarn workspace @wix/wix-one-app-engine test:e2e:ios -w d \\\n  e2e/suites/ExternalLinks.test.js \\\n  e2e/suites/ExternalLinksModes.test.js \\\n  e2e/suites/ExternalLinksPushNotifications.test.js\n```\n\n### Troubleshooting Tests\n\n- **`Error: No dist version found`**: The native build hasn't run or failed.\n  Run step 2 again.\n- **`Cannot find module .../mobile-apps-engine-extra-bundle/index.js`**:\n  Run step 3 (`local:build` for extra-bundle).\n- **`ENOENT .../metadata.json`**: Run step 3 (`local:build` for mobile-apps-dependencies).\n- **`Unable to resolve module @rozenite/...`**: The Rozenite plugin import is broken.\n  Patch `packages/wix-one-app-engine/src/rozenitePlugin/helper/rozenite-network-inspector.ts`\n  to make the import optional with a no-op fallback.\n- **Tests time out on `navigateBack()`**: The `navigateBack()` helper taps\n  `element(by.id('pop'))` on iOS. This relies on RNN's `setBackButtonTestID` working\n  correctly. If the back button's view hierarchy changed (e.g., iOS 26 Liquid Glass),\n  the testID isn't applied and the element can't be found.\n\n## Key Engine Files\n\n| File | Purpose |\n|------|---------|\n| `packages/wix-one-app-engine/e2e/helpers/utils.js` | Test helpers including `navigateBack()` |\n| `packages/wix-one-app-engine/demo-modules/deep-links/module.js` | Deep link route definitions |\n| `packages/wix-one-app-engine/demo-modules/deep-links/Screens.js` | Deep link screen components |\n| `packages/wix-one-app-engine/internalScripts/test-e2e.js` | E2E test runner script |\n| `packages/native/mobile-apps-engine-native-builds/local_build_scripts/build_ios.js` | Local iOS build script |\n\n","frontmatter":{"name":"engine-e2e","description":"Run Wix Engine (mobile-apps-engine) iOS E2E tests locally to validate RNN changes. Use when you need to test RNN fixes against the Engine's Detox test suite."},"isInternal":false,"tokens":1237,"sizeBytes":4590},{"name":"SKILL.md","path":".cursor/skills/ios26-navigation/SKILL.md","rawUrl":"https://raw.githubusercontent.com/wix/react-native-navigation/HEAD/.cursor/skills/ios26-navigation/SKILL.md","title":"ios26-navigation","category":"anthropic-skill","format":"markdown","content":"---\nname: ios26-navigation\ndescription: Reference for iOS 26 navigation bar, tab bar, toolbar, and Liquid Glass building blocks (UITab, scroll-edge effects, search placement, shared-background platter, UIButton glass configurations, UIGlassEffect / UIGlassContainerEffect, UINavigationItem.style navigator/browser/editor, UICornerConfiguration / concentric corners, UISheetPresentationController, SF Symbols 7) plus the internal view hierarchy of UIBarButtonItem and UIToolbar, and how react-native-navigation maps to all of it. Use when adding or fixing iOS 26 behavior in RNN's top bar, bottom tabs, bar buttons, toolbar, modals, or any glass-styled custom chrome; when investigating iOS 26-only regressions; or when deciding how to expose a new iOS 26 capability through RNN options.\n---\n\n# iOS 26 Navigation in RNN\n\n## When this applies\n\nUse this skill any time work touches:\n- Top bar / navigation bar appearance, buttons, titles, or search\n- Bottom tab bar appearance, items, badges, or layout\n- Toolbar items or bar button styling\n- Any `@available(iOS 26.0, *)` branch\n- iOS 26-only bugs (Liquid Glass clipping, tab bar floating, button platter, scroll-edge effects)\n\nPair this with `rnn-codebase` (repo navigation) and `rnn-e2e-runner` (validation).\n\n## Build configuration\n\n- **Always Release** for verification — see workspace rule `rnn-build-release.mdc`. Debug masks iOS 26 layout/transition issues.\n- Xcode 26.1 toolchain: `DEVELOPER_DIR=/Applications/Xcode_26.1.app/Contents/Developer`\n- Simulator: `iPhone 17 Pro Max` (iOS 26 default)\n- Do **not** disable Fabric / New Architecture (user rule).\n- Compatibility opt-out flag: `UIDesignRequiresCompatibility` in `Info.plist`. RNN reads it in `RNNReactButtonView.designRequiresCompatibility` to fall back to pre-iOS-26 layout. Always honor it in new iOS 26 code paths.\n\n---\n\n## Apple iOS 26 API map\n\n### 1. Liquid Glass material\nThe system bar material on `UINavigationBar`, `UITabBar`, `UIToolbar` is **always translucent / glass** by default. `configureWithOpaqueBackground` is silently overlaid with glass unless you also nil out `backgroundEffect`.\n\n- `UIBarAppearance.backgroundEffect = nil` — required to actually get an opaque/transparent fill on iOS 26.\n- `UITabBarAppearance` / `UINavigationBarAppearance` / `UIToolbarAppearance` — same `backgroundEffect` rule.\n- Apple HIG: [Adopt Liquid Glass](https://developer.apple.com/design/human-interface-guidelines/materials)\n- WWDC25: \"What's new in UIKit\", \"Build a UIKit app with the new design\"\n\n**RNN handling:**\n- `ios/BottomTabsAppearancePresenter.mm`: branches on iOS 26 — uses `configureWithTransparentBackground` + `backgroundEffect=nil` + sets `tabBar.backgroundColor`. Pre-26 uses `configureWithOpaqueBackground`.\n- `ios/TopBarAppearancePresenter.mm`: same pattern for the navigation bar.\n\n### 2. Floating tab bar + drawBehind default\nThe tab bar floats above content on iOS 26 instead of pushing it up. Content underneath needs to extend.\n\n- Tab bar no longer occupies layout space the same way; `safeAreaInsets.bottom` increases for content.\n- Default `drawBehind` should be `YES` on iOS 26.\n\n**RNN handling:**\n- `ios/RNNBottomTabsOptions.mm` (`-shouldDrawBehind`): defaults `drawBehind` to `YES` on iOS 26, `NO` otherwise.\n- `ios/RNNBottomTabsController.mm`: `rnn_cycleAllTabsThenRestoreInitialSelection` — iOS 26 first-layout bug where tab item titles get misplaced; cycle selection in `viewDidAppear` to force a correct layout. Gated by `_rnnDidApplyInitialTabBarSelectionFix`.\n\n### 3. UITab / UITabBarController.tabs (iOS 18+, expanded in 26)\nModern tab API replaces `viewControllers` with `tabs: [UITab]`. Supports `UITabGroup`, `UISearchTab`, and `UITabBarController.mode = .tabSidebar`.\n\n- `UITab(title:image:identifier:viewControllerProvider:)` — lazy VC creation per tab.\n- `UITabBarController.tabs` — array of `UITab`, can mix `UITab` and `UITabGroup`.\n- `UITabBarController.mode` — `.tabBar` (default) vs `.tabSidebar` (iPad sidebar).\n- `UISearchTab` — first-class search tab, integrates with `UINavigationItem` search.\n- `UITabBarController.sidebarLayoutPreferences` — iPad sidebar customization.\n- `UITabBarController.tabBarPlacement` — `.automatic`, `.bottom`, `.top` (iPadOS 26 can pin the tab bar at the top of the window).\n- Programmatic transitions between sidebar and tab bar layouts via animating `mode` changes inside `UIView.animate`.\n- Apple: [UITabBarController.tabs](https://developer.apple.com/documentation/uikit/uitabbarcontroller/tabs), [UITab](https://developer.apple.com/documentation/uikit/uitab), [UITabGroup](https://developer.apple.com/documentation/uikit/uitabgroup)\n\n**RNN handling:** RNN currently uses the legacy `viewControllers` API. There is **no** `UITab` / `tabs` adoption yet. New iOS 26 tab features (sidebar mode, search tab, groups, top placement) would need a new code path in `RNNBottomTabsController` and corresponding `Options.ts` surface.\n\n### 4. UITabBarController.bottomAccessory\nPersistent floating mini-control attached above the tab bar (e.g., Apple Music's now-playing bar).\n\n- `UITabBarController.bottomAccessory: UITabAccessory?`\n- `UITabAccessory(contentView:)` — wraps a UIView.\n- Apple: [UITabAccessory](https://developer.apple.com/documentation/uikit/uitabaccessory)\n\n**RNN handling:** Not yet exposed. Would need a new option (e.g., `bottomTabs.accessory: { component: { name, ... } }`) and a presenter to mount a React view inside a `UITabAccessory`.\n\n### 5. Scroll-edge appearance and effects\niOS 26 makes `scrollEdgeAppearance` matter more (the bar fades to transparent when scrolled to the top). New `scrollEdgeEffect` on `UINavigationItem` controls the effect.\n\n- `UINavigationItem.scrollEdgeEffect` — controls the fading/glass effect at scroll edges.\n- `UINavigationBar.scrollEdgeAppearance` — appearance when at the scroll edge.\n- `UITabBar.scrollEdgeAppearance` — same for tab bar.\n- Apple: [UIScrollEdgeEffect](https://developer.apple.com/documentation/uikit/uiscrolledgeeffect) (iOS 26)\n\n**RNN handling:**\n- `scrollEdgeAppearance` exposed via top bar options — see `website/docs/api/options-scrollEdgeAppearance.mdx`.\n- iOS 26 `scrollEdgeEffect` added in PR #8281 (`Add scrollEdgeEffect option`).\n- Title customization on scroll edge: PRs #8207, #8239.\n\n### 6. Search bar placement (UINavigationItemSearchBarPlacement)\niOS 26 introduces three placements:\n\n- `UINavigationItemSearchBarPlacementStacked` — under the title, classic.\n- `UINavigationItemSearchBarPlacementIntegrated` — inline with the title bar, expanded.\n- `UINavigationItemSearchBarPlacementIntegratedButton` — collapsed to a button until tapped.\n\nProperty: `UINavigationItem.preferredSearchBarPlacement`. Availability-gated, not present pre-iOS-26.\n\n**RNN handling:**\n- `ios/RNNSearchBarPlacement.mm` / `.h` — JS-facing enum.\n- `ios/UIViewController+RNNOptions.mm` (`setSearchBar...`): maps RNN's `SearchBarPlacementIntegrated` to integrated or integrated-button depending on `focus`. Falls through to stacked otherwise.\n- PR #8211 — skip integrated placement when not available (pre-26 safety).\n\n### 7. Shared background (\"Platter\") on bar button items\niOS 26 wraps every `UIBarButtonItem` in a shared Liquid Glass platter. Custom views and pre-styled `UIButton`s get double-decorated.\n\n- `UIBarButtonItem.hidesSharedBackground: Bool` — opt out of the platter.\n- Custom views need a fixed bar-item size (44pt) so the navbar reserves the slot before React mounts the content; otherwise the navbar relayouts after mount and the custom view snaps into place.\n\n**RNN handling:**\n- `ios/RNNUIBarButtonItem.mm`: defaults `hidesSharedBackground = YES` on iOS 26 for both icon buttons and custom (React) view buttons. Pins custom view to 44x44.\n- `ios/RNNReactButtonView.mm`: width/height constraints + center translation post-mount to keep the React view aligned inside the reserved 44pt slot.\n- New option: `RNNButtonOptions.hideSharedBackground` (also on `RNNBackButtonOptions`) — see `src/interfaces/Options.ts`.\n- PR #8300 — centering fix.\n\n### 7a. `UIBarButtonItemGroup` factory APIs and prominent style (iOS 26)\n\niOS 26 added direct factories on `UIBarButtonItem` that build groups inline. These are the cleanest way to make the shared platter intentional rather than relying on UIKit's implicit clustering.\n\n```\nUIBarButtonItem.creatingFixedGroup() -> UIBarButtonItemGroup\nUIBarButtonItem.creatingMovableGroup(customizationIdentifier:) -> UIBarButtonItemGroup\nUIBarButtonItem.creatingOptionalGroup(customizationIdentifier:isInDefaultCustomization:) -> UIBarButtonItemGroup\n```\n\nPlus a new style:\n\n- `UIBarButtonItem.style = .prominent` — primary-action styling, tints the platter with the bar's `tintColor` at full saturation. Use sparingly (one prominent item per bar).\n\nWhen grouping is intentional, UIKit renders the group under a single `_UIBarItemGroupPlatter` (see §7b/§9) instead of one platter per item. `hidesSharedBackground` still applies per item, so you can mix glassed and bare items inside one group.\n\n**RNN handling:** Not exposed today. If a future option models a logical action cluster, build it as a `UIBarButtonItemGroup` rather than a sequence of items so the platter coalesces correctly.\n\nReferences:\n- [`UIBarButtonItemGroup`](https://developer.apple.com/documentation/uikit/uibarbuttonitemgroup)\n- [`UIBarButtonItem.Style`](https://developer.apple.com/documentation/uikit/uibarbuttonitem/style)\n\n### 7b. Internal view hierarchy: `UIBarButtonItem` on iOS 26\n\n`UIBarButtonItem` is **not a `UIView`** — it's a model object. UIKit materializes it into a private view hierarchy inside the parent `UINavigationBar` or `UIToolbar`. The exact class names are private and can change; the **layering and ordering are stable** and worth knowing for layout debugging.\n\nApproximate structure for a single bar button item (Liquid Glass, iOS 26):\n\n```\nUINavigationBar / UIToolbar\n└── _UIBarBackground               (bar-wide background, Liquid Glass material)\n└── _UIButtonBarStackView          (horizontal stack of items, leading or trailing group)\n    └── _UIModernBarButton         (host view per item; one per UIBarButtonItem)\n        ├── _UIBarItemPlatter      (shared Liquid Glass background; the \"platter\")\n        │   └── CAFilter / glass layers (UIGlassEffect-backed)\n        └── content view           (image, title label, OR customView)\n```\n\nKey facts that affect RNN code:\n\n- **The platter is per-item by default**, but adjacent items inside the same `UIBarButtonItemGroup` (or implicit leading/trailing cluster) can be coalesced into a **single shared platter** spanning several items. This is the \"shared background\" that `hidesSharedBackground` opts out of.\n- **`hidesSharedBackground = YES`** removes the `_UIBarItemPlatter` from the host view; the content view becomes the direct child of `_UIModernBarButton`. The host view is **still 44pt minimum**.\n- **The host view (`_UIModernBarButton`) reserves the slot**, not the customView. UIKit sizes the host using:\n  - System images: intrinsic size of the symbol + padding.\n  - Title-only items: text width + padding.\n  - **Custom views: the customView's intrinsic content size at the time the bar performs layout.** This is why RNN pins the custom React view to 44×44 in `RNNUIBarButtonItem.mm` — without explicit constraints, React mounts asynchronously, the customView's intrinsic size starts at zero, the host reserves zero width, the bar lays out, then React reports its real size and the host has to relayout. The visible artifact is the button \"popping in\" or being misplaced after the push transition's snapshot already captured the wrong frame.\n- **Transitions snapshot the bar.** During push/pop, UIKit takes a snapshot of the navigation bar for the cross-fade between the from/to nav items. If the customView hasn't laid out before the snapshot, the snapshot shows the wrong state. This is also why a React customView can appear blank during a transition while being fine on the destination screen.\n- **Tinting flows through the platter, not the customView.** `tintColor` set on the bar item or bar applies to the system image inside the host view; it does not propagate into a React customView. Color the React content explicitly.\n\nPractical debugging:\n\n- Inspect the live hierarchy with `po [self.navigationItem.rightBarButtonItems.firstObject valueForKey:@\"_view\"]` in lldb, or with View Debugger → uncheck \"Show layers only\" to see the private classes.\n- A button that's \"there but invisible\" usually means the host view has 0×0 frame (sizing race) or `hidesSharedBackground = NO` with a customView that paints its own chrome (double-decoration clips/overlaps).\n- A button that \"snaps into place\" after the screen appears means the host view's intrinsic size changed after the bar's first layout pass.\n\nReferences (public API only — internals are observed, not documented):\n- [`UIBarButtonItem`](https://developer.apple.com/documentation/uikit/uibarbuttonitem)\n- [`UIBarButtonItem.hidesSharedBackground`](https://developer.apple.com/documentation/uikit/uibarbuttonitem/hidessharedbackground)\n- [`UIBarButtonItemGroup`](https://developer.apple.com/documentation/uikit/uibarbuttonitemgroup)\n\n### 8. Tab bar minimize behavior (iOS 26)\nThe tab bar can auto-minimize during scroll.\n\n- `UITabBarController.tabBarMinimizeBehavior` — `.automatic`, `.never`, `.onScrollDown`, `.onScrollUp`.\n- `setNeedsUpdateOfTabBarMinimizeBehavior()` — re-evaluate.\n- Apple: [UITabBarController](https://developer.apple.com/documentation/uikit/uitabbarcontroller)\n\n**RNN handling:** Not yet exposed. Would be a new option on `bottomTabs`.\n\n### 9. `UIToolbar` on iOS 26\n\n`UIToolbar` is a real `UIView` (unlike `UIBarButtonItem`). Approximate internal hierarchy on iOS 26:\n\n```\nUIToolbar\n├── _UIBarBackground                  (bar-wide Liquid Glass material;\n│                                      configured via UIToolbarAppearance)\n│   └── _UIBackdropView / glass layers\n│   └── _UIBarBackgroundShadowView    (1pt hairline; controlled by shadowImage / shadowColor)\n└── _UIToolbarContentView\n    └── _UIButtonBarStackView         (horizontal stack of toolbar items)\n        ├── _UIModernBarButton        (item host — see 7b for layer breakdown)\n        ├── _UIModernBarButton\n        ├── ... fixed/flexible spaces become layout gaps in the stack ...\n        └── (optional) _UIBarItemGroupPlatter\n              └── two or more _UIModernBarButton sharing one platter\n                  (only when items are in the same UIBarButtonItemGroup)\n```\n\nWhat's actually public and load-bearing on iOS 26:\n\n- **Appearance objects are the only safe way to style.** `UIToolbarAppearance` (standard / compact / scrollEdge) drives `_UIBarBackground`. Setting `barTintColor` / `backgroundImage` on `UIToolbar` directly is **silently overridden** by Liquid Glass unless `appearance.backgroundEffect = nil`.\n- **Translucency is the default.** `configureWithDefaultBackground` on iOS 26 produces glass. To get an opaque fill: `configureWithOpaqueBackground` **plus** `backgroundEffect = nil` **plus** explicit `backgroundColor`. This mirrors what `BottomTabsAppearancePresenter.mm` does for the tab bar.\n- **Items follow the same Platter rules as nav bar buttons.** A custom view in a toolbar item gets wrapped in a platter unless `hidesSharedBackground = YES`. The 44pt host-view sizing race applies identically.\n- **Grouping with `UIBarButtonItemGroup`** lets adjacent items render under one shared platter (visually grouped pill). `customizationIdentifier` opts the toolbar into the user-customization sheet (iPadOS).\n- **`scrollEdgeAppearance` matters here too.** When a scroll view is attached, the toolbar fades to transparent at the scroll edge using `UIToolbar.scrollEdgeAppearance`. Pre-iOS-26 this was iPad-only for many cases; iOS 26 applies it consistently.\n\nDisplay mode and customization (iOS 26 / iPadOS 26):\n\n- `UIToolbar.displayMode` — `.automatic`, `.expanded`, `.compact`. Drives whether items spread out or collapse into an overflow menu.\n- `UIBarButtonItem.menuRepresentation` — the menu UIKit shows when the item is hoisted into the overflow control under `.compact`.\n- `UIToolbar.beginCustomizingItems(...)` / `endCustomizingItems` — programmatic entry into the user-customization sheet for movable/optional groups.\n\nRNN handling:\n\nRNN does not expose `UIToolbar` as a first-class options surface today. Toolbar-shaped behavior in this repo comes from the navigation controller's bottom bar via `RNNStackController` and is configured indirectly through stack options. Any new toolbar feature should:\n\n1. Add a presenter (e.g. `ToolbarPresenter`) mirroring `TopBarPresenter`'s appearance pattern.\n2. Configure via `UIToolbarAppearance` only — never direct `barTintColor` / `backgroundImage`.\n3. Use `UIBarButtonItemGroup` when the option models a logical cluster (e.g. \"primary actions\") so the platter coalesces correctly.\n4. Apply `hidesSharedBackground` defaults for React custom views, same as `RNNUIBarButtonItem.mm` does today.\n\nReferences:\n- [`UIToolbar`](https://developer.apple.com/documentation/uikit/uitoolbar)\n- [`UIToolbarAppearance`](https://developer.apple.com/documentation/uikit/uitoolbarappearance)\n- [`UIBarButtonItemGroup`](https://developer.apple.com/documentation/uikit/uibarbuttonitemgroup)\n- WWDC25: \"What's new in UIKit\" (toolbar/group section), \"Build a UIKit app with the new design\"\n\n### 10. Preferred transition\n- `UINavigationController.preferredTransition` — control push/pop animation style (iOS 26 expansion).\n- `UIViewController.preferredTransition` — zoom transitions.\n\n**RNN handling:** Not exposed. Stack push/pop currently uses defaults.\n\n### 11. SF Symbols 7\niOS 26 ships SF Symbols 7. Bar buttons that use system images get the new variants automatically. Custom symbol configurations should re-test on iOS 26.\n\nAnimated symbols are part of the iOS 26 bar story:\n\n- `NSSymbolEffect` family — `.bounce`, `.pulse`, `.variableColor`, `.replace`, `.breathe`, `.scale`, `.appear`, `.disappear`, `.wiggle` (iOS 18+; new variants in 26).\n- Apply via the bar item's image: configure `UIImageView` produced by UIKit, or use `UIView.addSymbolEffect(_:options:animated:)` on the host view returned by `UIBarButtonItem.value(forKey: \"_view\")` (private — prefer using `UIButton` with a configured image inside a custom bar item).\n- WWDC25: \"What's new in SF Symbols 7\".\n\n### 12. `UIButton` glass configurations\n`UIButton.Configuration` got first-class glass factories in iOS 26. Anything RNN renders that's *not* a bar button (custom views inside a screen, overlays, modal headers, bottom accessories) should adopt these instead of hand-rolling chrome.\n\n```\nUIButton.Configuration.glass()           — translucent Liquid Glass pill\nUIButton.Configuration.prominentGlass()  — tinted, more saturated variant\nUIButton.Configuration.plain()\nUIButton.Configuration.gray()\nUIButton.Configuration.tinted()\nUIButton.Configuration.filled()\nUIButton.Configuration.borderless()\n```\n\nOn iOS 26 the legacy configurations (`plain` / `gray` / `tinted` / `filled` / `borderless`) automatically repaint with the Liquid Glass material — you don't opt in, you opt *out* via `UIDesignRequiresCompatibility`.\n\nConfiguration knobs that affect build-up:\n- `cornerStyle` — `.fixed` / `.dynamic` / `.capsule` / `.small` / `.medium` / `.large`. `.dynamic` adopts concentric corners (see §15).\n- `buttonSize` — `.mini` / `.small` / `.medium` / `.large`.\n- `baseBackgroundColor` / `baseForegroundColor` — tint multiplier on glass.\n\nApproximate internal hierarchy for a configuration-based button on iOS 26:\n\n```\nUIButton (configuration-based)\n├── _UIButtonBackgroundView         (the platter / glass body)\n│   ├── UIVisualEffectView          (UIGlassEffect — see §13)\n│   └── tint overlay (CALayer)\n└── _UIButtonContentStackView\n    ├── UIImageView                 (leading or trailing image)\n    ├── UILabel                     (title)\n    └── UILabel                     (subtitle, when set)\n```\n\n**RNN handling:** Not exposed as an option today. RNN doesn't render its own button chrome inside screens — that's the React side's job — but if RNN ever needs a system-styled control (e.g. a \"Done\" button on a custom modal header it builds natively), use `UIButton.Configuration.glass()` rather than custom drawing.\n\nReferences:\n- [`UIButton.Configuration`](https://developer.apple.com/documentation/uikit/uibutton/configuration)\n- [`UIButton.Configuration.glass()`](https://developer.apple.com/documentation/uikit/uibutton/configuration/glass())\n\n### 13. `UIGlassEffect` and `UIGlassContainerEffect` (public Liquid Glass API)\n\nThe entire Liquid Glass material is exposed publicly. This is the API to use whenever RNN needs custom glass chrome — floating overlays, bottom accessories, custom navigation extensions, modal grabbers.\n\n```\nUIGlassEffect                        — UIVisualEffect subclass\nUIGlassEffect.Style.regular          — default frosted glass\nUIGlassEffect.Style.clear            — thinner, more transparent variant\nUIGlassEffect.tintColor              — multiplied tint\nUIGlassContainerEffect               — wraps multiple glass views; they morph/merge when adjacent\nUIVisualEffectView(effect: UIGlassEffect())  — host\n```\n\nBehavioral rules:\n- Glass **refracts and blurs** content behind it; opacity is content-derived, not a static color.\n- Two `UIVisualEffectView`s with `UIGlassEffect` placed inside the same `UIGlassContainerEffect` will **visually merge** into a single platter when they touch or overlap. This is what produces the \"morphing\" you see when a search bar collapses into a button, or when tabs minimize into a single pill.\n- `tintColor` is **multiplied**, not painted — fully saturated colors look pastel. Use bold colors only when you want a noticeably tinted glass.\n- Glass adapts to dark / light mode automatically; do not hand-set background colors on the visual effect view.\n\nBuild-up:\n\n```\nUIVisualEffectView (effect: UIGlassEffect)\n├── _UIVisualEffectBackdropView      (CAFilter blur + refraction)\n├── _UIVisualEffectSubview           (tint overlay)\n└── contentView                      (your content; goes here, not on the effect view directly)\n```\n\n**RNN handling:** Not used yet. Any future custom chrome (e.g. a `bottomAccessory` host, a custom modal grabber, a floating action overlay) should be a `UIVisualEffectView` with `UIGlassEffect`, **not** a `UIView` with a manually configured `UIBlurEffect`. Pre-iOS-26 RNN can fall back to `UIBlurEffectStyle.systemMaterial` via the existing availability pattern.\n\nReferences:\n- [`UIGlassEffect`](https://developer.apple.com/documentation/uikit/uiglasseffect)\n- [`UIGlassContainerEffect`](https://developer.apple.com/documentation/uikit/uiglasscontainereffect)\n- [`UIVisualEffectView`](https://developer.apple.com/documentation/uikit/uivisualeffectview)\n- WWDC25: \"Meet Liquid Glass\"\n\n### 14. `UINavigationItem.style` — navigator / browser / editor\n\niOS 26 introduces three navigation item styles that reshape the entire navigation bar's internal layout. This is one of the bigger build-up changes in 26.\n\n```\nUINavigationItem.Style.navigator     — default; classic nav title + leading/trailing items\nUINavigationItem.Style.browser       — URL-bar-like layout with a centered integrated field\nUINavigationItem.Style.editor        — document editor; renamable title + subtitle + badge\n```\n\nRelated properties (only meaningful when `style` ≠ `.navigator`):\n\n- `UINavigationItem.documentProperties: UIDocumentProperties?` — file URL, subtitle, badge displayed in editor style.\n- `UINavigationItem.renameDelegate` — inline rename UI for editor style.\n- `UINavigationItem.titleMenuProvider` — context menu when tapping the title (iOS 16+, but actually visible by default in browser/editor styles on 26).\n\nHow the build-up changes:\n\n- `.navigator` — standard `_UINavigationBarContentView` with title label centered.\n- `.browser` — `_UINavigationBarContentView` swaps the title slot for an integrated URL field (`UISearchTextField`-shaped), with leading and trailing item clusters under shared platters.\n- `.editor` — adds a vertical stack: title (renamable) + subtitle (file path) + badge, plus a primary action slot at the trailing edge.\n\n**RNN handling:** Not exposed. A future RNN option could surface `topBar.style: 'navigator' | 'browser' | 'editor'`. Editor style is the more interesting one for document-shaped apps; browser style fits Wix preview-style flows.\n\nReferences:\n- [`UINavigationItem.Style`](https://developer.apple.com/documentation/uikit/uinavigationitem/style)\n- [`UIDocumentProperties`](https://developer.apple.com/documentation/uikit/uidocumentproperties)\n- WWDC25: \"Build a UIKit app with the new design\"\n\n### 15. `UICornerConfiguration` and concentric corners\n\nConcentric corners are a foundational iOS 26 design rule: a child element's corner radius should equal its parent's radius minus the inset, so curves stay visually parallel. Apple's own bar items, sheets, and buttons obey this; mixing fixed `cornerRadius` with a concentric container looks visibly wrong on 26.\n\n```\nUICornerConfiguration.uniformCornerRadius(_:)            // fixed radius\nUICornerConfiguration.uniformCornerConfiguration(_:)     // with corner style (capsule, etc.)\nUICornerConfiguration.concentric(minimum:)               // matches parent's curvature, floored at minimum\nUIView.cornerConfiguration: UICornerConfiguration?       // applies to the view's layer\n```\n\nRule of thumb: anything painted **inside** a glass element should be `.concentric(minimum: small)` rather than `.uniformCornerRadius(N)`. The system already uses concentric corners for bar item platters, sheet corners that morph with the device screen radius, and tab bar item shapes.\n\n**RNN handling:** Not exposed. Any future RNN-native custom chrome that nests inside a glass element (e.g. a React custom view sitting inside an iOS 26 platter that RNN draws) should apply `.cornerConfiguration = .concentric(...)` on the wrapping UIView so it inherits the platter's curvature.\n\nReferences:\n- [`UICornerConfiguration`](https://developer.apple.com/documentation/uikit/uicornerconfiguration)\n- [`UIView.cornerConfiguration`](https://developer.apple.com/documentation/uikit/uiview/cornerconfiguration)\n\n### 16. `UISheetPresentationController` iOS 26 changes\n\nRNN modals route through `UISheetPresentationController` when configured. iOS 26 changes its presentation in three meaningful ways:\n\n- **`cornerConfiguration`** replaces `preferredCornerRadius` for finer control. Sheets can now have asymmetric corners and use `.concentric(minimum:)` to match the device's screen radius — the result is the visible \"corner morph\" when the sheet animates from the small detent to medium/large.\n- **Default detents changed.** The small detent now overlaps the safe area more gracefully because the corner configuration animates with the detent height. Custom detents (`UISheetPresentationController.Detent.custom`) need to play nicely with this.\n- **Sheets slide *under* the floating tab bar by default.** Pre-iOS-26 the tab bar pushed the sheet up; on 26 the sheet's small detent extends behind the tab bar. If a sheet must avoid covering the tab bar, opt out by configuring the detent height explicitly or by presenting from a context that excludes the tab bar.\n\nRelated: `UISheetPresentationController.prefersGrabberVisible` still controls the grabber; the grabber now uses Liquid Glass material.\n\n**RNN handling:** RNN exposes modal presentation through stack options. iOS 26 sheet behavior surfaces automatically through UIKit defaults — but the \"sheet over tab bar\" change can visually regress apps that expected the pre-26 layout. If users report it, the fix is to adjust the detent or presentation context, not to fight UIKit.\n\nReferences:\n- [`UISheetPresentationController`](https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller)\n- WWDC25: \"What's new in UIKit\" (sheet section)\n\n---\n\n## Workflow: adding iOS 26 support for a new API\n\n1. **Confirm the Apple API surface.** Read the relevant `developer.apple.com` page; check WWDC25 sessions for sample patterns.\n2. **Pick the RNN seam.** Use the mapping above. Top bar → `TopBarPresenter` + `RNNTopBarOptions`. Bottom tab → `BottomTabsAppearancePresenter` / `RNNBottomTabsController` + `RNNBottomTabsOptions`. Bar buttons → `RNNUIBarButtonItem` + `RNNButtonOptions`.\n3. **Add the JS option** in `lib/src/interfaces/Options.ts`. Document semantics, iOS-only marker, iOS 26 minimum.\n4. **Parse it** in the matching `*Options.mm` (use the existing `[XParser parse:dict key:@\"...\"]` pattern). Add to `mergeOptions:`.\n5. **Apply it** in the presenter, **always guarded** by `if (@available(iOS 26.0, *)) { ... }`. Honor `UIDesignRequiresCompatibility` if behavior would diverge for legacy-design apps.\n6. **Add a playground screen** in `playground/src/screens/` exercising the option, both visible and toggle states.\n7. **Add an e2e** in `playground/e2e/` using `device.getPlatform() === 'ios'` and an iOS version check. Follow existing baseline-then-action screenshot patterns.\n8. **Update docs** in `website/docs/api/options-*.mdx`.\n9. **Build Release** with Xcode 26.1, run on iPhone 17 Pro Max simulator, then **also** verify on an iOS 18 simulator for regression.\n\n## Workflow: investigating an iOS 26 regression\n\n1. Reproduce in Release on iOS 26 sim. Reproduce on iOS 18/17 — confirm it's 26-only.\n2. Grep `if (@available(iOS 26.0, *))` and the property name (e.g. `backgroundEffect`, `hidesSharedBackground`, `preferredSearchBarPlacement`) — see if RNN already has a branch.\n3. Check recent PRs touching the same file (`git log --oneline -- ios/<file>.mm | head -20`) — most iOS 26 regressions cluster.\n4. Check `UIDesignRequiresCompatibility`: if the bug only happens with the new design, the fix must not break compatibility mode.\n5. Confirm Fabric / New Architecture is still on (don't disable it to \"fix\" something).\n6. Before changing code, summarize the hypothesis and proposed fix to the user (per user rule \"show me first\").\n\n---\n\n## Known iOS 26 trouble spots in this repo\n\n| Area | File(s) | Last touched PR(s) |\n|------|---------|-------------------|\n| Custom React bar buttons (Platter, centering, lifecycle) | `RNNUIBarButtonItem.mm`, `RNNReactButtonView.mm` | #8300 |\n| Tab item title misplaced on first layout | `RNNBottomTabsController.mm` (`rnn_cycleAllTabsThenRestoreInitialSelection`) | #8245, #8254, #8255 |\n| Tab bar background color / glass | `BottomTabsAppearancePresenter.mm` | #8263, #8288 |\n| Search bar placement | `UIViewController+RNNOptions.mm`, `RNNSearchBarPlacement.mm` | #8183, #8211 |\n| Scroll edge effect on top bar | top bar options | #8281, #8239, #8207 |\n| iPad back navigation (iOS 26) | nav controller | #8277 |\n| `drawBehind` default on floating tab bar | `RNNBottomTabsOptions.mm` (`-shouldDrawBehind`) | — |\n\n---\n\n## Authoritative references\n\n- HIG: [Designing for iOS 26](https://developer.apple.com/design/human-interface-guidelines/designing-for-ios), [Materials (Liquid Glass)](https://developer.apple.com/design/human-interface-guidelines/materials), [Tab bars](https://developer.apple.com/design/human-interface-guidelines/tab-bars), [Navigation bars](https://developer.apple.com/design/human-interface-guidelines/navigation-bars), [Toolbars](https://developer.apple.com/design/human-interface-guidelines/toolbars)\n- API (bars and tabs): [UITabBarController](https://developer.apple.com/documentation/uikit/uitabbarcontroller), [UITab](https://developer.apple.com/documentation/uikit/uitab), [UITabAccessory](https://developer.apple.com/documentation/uikit/uitabaccessory), [UINavigationItem](https://developer.apple.com/documentation/uikit/uinavigationitem), [UINavigationItem.Style](https://developer.apple.com/documentation/uikit/uinavigationitem/style), [UIBarButtonItem.hidesSharedBackground](https://developer.apple.com/documentation/uikit/uibarbuttonitem/hidessharedbackground), [UIBarButtonItemGroup](https://developer.apple.com/documentation/uikit/uibarbuttonitemgroup), [UIScrollEdgeEffect](https://developer.apple.com/documentation/uikit/uiscrolledgeeffect), [UIBarAppearance](https://developer.apple.com/documentation/uikit/uibarappearance), [UIToolbar](https://developer.apple.com/documentation/uikit/uitoolbar)\n- API (glass and shapes): [UIGlassEffect](https://developer.apple.com/documentation/uikit/uiglasseffect), [UIGlassContainerEffect](https://developer.apple.com/documentation/uikit/uiglasscontainereffect), [UICornerConfiguration](https://developer.apple.com/documentation/uikit/uicornerconfiguration), [UIButton.Configuration](https://developer.apple.com/documentation/uikit/uibutton/configuration), [UIButton.Configuration.glass()](https://developer.apple.com/documentation/uikit/uibutton/configuration/glass())\n- API (presentation): [UISheetPresentationController](https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller), [UIDocumentProperties](https://developer.apple.com/documentation/uikit/uidocumentproperties)\n- WWDC25: \"Meet Liquid Glass\", \"Get to know the new design system\", \"What's new in UIKit\", \"Build a UIKit app with the new design\", \"Elevate your tab and sidebar experience\", \"Make your UIKit app more flexible\", \"What's new in SF Symbols 7\"\n- Compatibility: [UIDesignRequiresCompatibility](https://developer.apple.com/documentation/bundleresources/information-property-list/uidesignrequirescompatibility)\n","frontmatter":{"name":"ios26-navigation","description":"Reference for iOS 26 navigation bar, tab bar, toolbar, and Liquid Glass building blocks (UITab, scroll-edge effects, search placement, shared-background platter, UIButton glass configurations, UIGlassEffect / UIGlassContainerEffect, UINavigationItem.style navigator/browser/editor, UICornerConfiguration / concentric corners, UISheetPresentationController, SF Symbols 7) plus the internal view hierarchy of UIBarButtonItem and UIToolbar, and how react-native-navigation maps to all of it. Use when adding or fixing iOS 26 behavior in RNN's top bar, bottom tabs, bar buttons, toolbar, modals, or any glass-styled custom chrome; when investigating iOS 26-only regressions; or when deciding how to expose a new iOS 26 capability through RNN options."},"isInternal":false,"tokens":7785,"sizeBytes":33712},{"name":"SKILL.md","path":".cursor/skills/rnn-codebase/SKILL.md","rawUrl":"https://raw.githubusercontent.com/wix/react-native-navigation/HEAD/.cursor/skills/rnn-codebase/SKILL.md","title":"rnn-codebase","category":"anthropic-skill","format":"markdown","content":"---\nname: rnn-codebase\ndescription: Navigate and work with the react-native-navigation (RNN) codebase. Use when fixing bugs, adding features, tracing command flows, understanding options resolution, or working across JS/iOS/Android layers in this repo.\n---\n\n# React Native Navigation Codebase\n\n## Architecture Overview\n\nRNN has three layers that mirror each other:\n\n```\nJS/TS (src/)  →  TurboModule bridge  →  iOS native (ios/)\n                                     →  Android native (android/)\n```\n\nA navigation command (e.g. `push`) flows:\n1. `Navigation.push()` → `Commands.ts` → processing pipeline → `NativeCommandsSender.ts`\n2. TurboModule: `RNNTurboModule` (iOS) / `NavigationTurboModule.kt` (Android)\n3. iOS: `RNNCommandsHandler` → `RNNViewControllerFactory` → UIKit controllers\n4. Android: `Navigator` → `LayoutFactory` → View-based controllers (no Fragments)\n\nRead [ARCHITECTURE.md](../../ARCHITECTURE.md) for the full overview.\n\n## Key Cross-Layer Mappings\n\n### Layout Types → Native Controllers\n\n| JS Layout Type | iOS Controller | Android Controller |\n|----------------|---------------|-------------------|\n| `component` | `RNNComponentViewController` | `ComponentViewController` |\n| `stack` | `RNNStackController` (UINavigationController) | `StackController` |\n| `bottomTabs` | `RNNBottomTabsController` (UITabBarController) | `BottomTabsController` |\n| `sideMenu` | `RNNSideMenuViewController` (MMDrawerController) | `SideMenuController` (DrawerLayout) |\n| `topTabs` | `RNNTopTabsViewController` | `TopTabsController` (ViewPager) |\n| `splitView` | `RNNSplitViewController` | N/A (iOS only) |\n| `externalComponent` | `RNNExternalViewController` | `ExternalComponentViewController` |\n\n### Options → Presenters\n\nEach controller type has a Presenter that applies options to views:\n\n| iOS Controller | iOS Presenter | Android Presenter |\n|----------------|--------------|-------------------|\n| `RNNComponentViewController` | `RNNComponentPresenter` | `ComponentPresenter` |\n| `RNNStackController` | `RNNStackPresenter` + `TopBarPresenter` | `StackPresenter` |\n| `RNNBottomTabsController` | `RNNBottomTabsPresenter` | `BottomTabsPresenter` |\n| `RNNSideMenuViewController` | `RNNSideMenuPresenter` | `SideMenuPresenter` |\n\n### Events (same names both platforms)\n\n| Event | Trigger |\n|-------|---------|\n| `RNN.ComponentDidAppear` | Screen becomes visible |\n| `RNN.ComponentDidDisappear` | Screen hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tap |\n| `RNN.BottomTabSelected` | Tab changed |\n| `RNN.ModalDismissed` | Modal dismissed |\n| `RNN.ScreenPopped` | Screen popped from stack |\n| `RNN.CommandCompleted` | Any command finished |\n\n## Where to Find Things\n\n### By task: \"I need to fix/change X\"\n\n| Task | JS File(s) | iOS File(s) | Android File(s) |\n|------|-----------|------------|----------------|\n| Command execution | `src/commands/Commands.ts` | `ios/RNNCommandsHandler.mm` | `react/NavigationTurboModule.kt` |\n| Layout creation | `src/commands/LayoutTreeParser.ts` | `ios/RNNViewControllerFactory.mm` | `options/LayoutFactory.java` |\n| Options processing | `src/commands/OptionsProcessor.ts` | `ios/RNNNavigationOptions.mm` | `options/Options.java` |\n| Options application | — | `ios/*Presenter.mm` | `viewcontrollers/*Presenter.java` |\n| TopBar | `src/interfaces/Options.ts` (TopBarOptions) | `ios/TopBarPresenter.mm`, `ios/RNNUIBarButtonItem.mm` | `views/stack/topbar/` |\n| Bottom tabs | `src/interfaces/Options.ts` (BottomTabsOptions) | `ios/RNNBottomTabsPresenter.mm` | `viewcontrollers/bottomtabs/` |\n| Modals | `src/commands/Commands.ts` | `ios/RNNModalManager.mm` | `viewcontrollers/modal/ModalStack.java` |\n| Overlays | `src/commands/Commands.ts` | `ios/RNNOverlayManager.mm` | `viewcontrollers/overlay/OverlayManager.kt` |\n| Animations | `src/interfaces/Options.ts` (AnimationOptions) | `ios/ScreenAnimationController.mm` | `viewcontrollers/stack/StackAnimator.kt` |\n| React view rendering | — | `ios/RNNReactView.mm` | `react/ReactView.java` |\n| Events to JS | `src/adapters/NativeEventsReceiver.ts` | `ios/RNNEventEmitter.mm` | `react/events/EventEmitter.java` |\n| Component registration | `src/components/ComponentRegistry.ts` | — | — |\n\n### By directory\n\n- **`src/`** — JS public API, commands, processing pipeline. See [src/ARCHITECTURE.md](../../src/ARCHITECTURE.md)\n- **`ios/`** — All Obj-C/C++ native code. See [ios/ARCHITECTURE.md](../../ios/ARCHITECTURE.md)\n- **`ios/TurboModules/`** — New architecture entry points (`RNNTurboModule`, `RNNTurboManager`, `RNNTurboCommandsHandler`)\n- **`android/src/main/java/com/reactnativenavigation/`** — All Java/Kotlin native code. See [android/ARCHITECTURE.md](../../android/ARCHITECTURE.md)\n- **`playground/`** — Demo app for development and E2E tests\n- **`playground/src/screens/`** — Test screens exercising every feature\n- **`playground/e2e/`** — Detox E2E tests\n\n## Options Resolution Order\n\nOptions are applied in ascending priority:\n1. Default options (from `Navigation.setDefaultOptions()`) — lowest priority\n2. Static options (from component class or `Navigation.registerComponent`)\n3. Options passed in the layout call (e.g. `push`, `setRoot`)\n4. `mergeOptions()` — runtime override, highest priority\n\n## JS Processing Pipeline (exact order)\n\n```\nAPI layout → OptionsCrawler.crawl() → LayoutProcessor.process()\n  → LayoutTreeParser.parse() → LayoutTreeCrawler.crawl()\n  → OptionsProcessor (colors, assets, custom) → NativeCommandsSender\n```\n\n## iOS Patterns\n\n- All controllers conform to `RNNLayoutProtocol`\n- `RNNBasePresenter` subclasses apply options — `applyOptionsOnInit:`, `applyOptions:`, `mergeOptions:resolvedOptions:`\n- Commands run on main thread (`RCTExecuteOnMainQueue`)\n- React views: `RNNReactView` wraps `RCTSurfaceHostingView` (new arch)\n- Overlays use separate `UIWindow` instances (`RNNOverlayWindow`)\n- `RNNReactComponentRegistry` caches React component instances\n\n## Android Patterns\n\n- View-based, NOT Fragment-based\n- All commands dispatched via `UiThread.post()`\n- `ViewController<T extends ViewGroup>` is the base — `createView()` is abstract\n- `ParentController` extends `ChildController` extends `ViewController`\n- Bottom tabs use `AHBottomNavigation` library\n- Three root layouts in `NavigationActivity`: rootLayout, modalsLayout, overlaysLayout\n- Tab attachment modes: `Together`, `OnSwitchToTab`, `AfterInitialTab`\n\n## Development Workflow\n\n### Playground app\n- `yarn start` — Metro bundler\n- `yarn xcode` — Open iOS project\n- `yarn studio` — Open Android project\n- `yarn pod-install` — Install iOS pods\n\n### Testing\n- `yarn test-js` — Jest unit tests\n- `yarn test-unit-ios` — iOS native unit tests (XCTest)\n- `yarn test-unit-android` — Android native unit tests (JUnit + Robolectric)\n- `yarn test-e2e-ios-ci` / `yarn test-e2e-android-ci` — Detox E2E tests\n\n### Building\n- `yarn prepare` — Builds `src/` → `lib/` (ESM + types)\n- Codegen config: `rnnavigation` in `package.json`\n\n## Engine Integration (Wix One App)\n\nRNN is a standalone library but also a core dependency of `mobile-apps-engine` (the Wix One App platform). Changes to RNN's public API surface can break engine.\n\n### Version Management\n\n- Version pinned in two files (must match):\n  - `packages/native/mobile-apps-engine-native/package.json`\n  - `packages/wix-one-app-storage/package.json`\n- `yarn.config.cjs` has a constraint that reads the version from `mobile-apps-engine-native` and validates all workspaces use the same version. It's a validation rule — bumping the native package.json is sufficient.\n\n### iOS Integration\n\n- Engine's `AppDelegate` subclasses `RNNAppDelegate` — breaking changes to that class will break engine.\n- Podfile resolves `ReactNativeNavigation` pod from node_modules.\n- Xcode project has header search paths pointing into `node_modules/react-native-navigation/ios/**`.\n\n### Android Integration\n\n- Engine's `EngineRN.kt` extends `NavigationApplication` and uses `NavigationPackage` / `NavigationReactNativeHost`.\n- `missingDimensionStrategy \"RNN.reactNativeVersion\"` is set in `app/build.gradle` — may need updating if RNN changes its flavor dimensions.\n- Build variables `RNNKotlinVersion`, `RNNKotlinStdlib`, `RNNKotlinCoroutinesCore` are forwarded from engine's Kotlin config.\n\n### Active Patches (in engine's setup)\n\n- **OptionsProcessor.js** — engine replaces RNN's `OptionsProcessor.js` at setup time via `patchRNNOptionsProcessor()` in `packages/cli/mobile-apps-engine-setup/src/index.js`. The patched copy lives at `packages/cli/mobile-apps-engine-setup/etc/OptionsProcessor.js`. It adds:\n  - Custom iOS color processing with `DynamicColorIOS` (dark/light/dynamic object shapes)\n  - Custom Android color processing wrapping colors in `{dark, light}` objects with `semantic`/`resource_paths` support\n  - Component ID uses `value.name` instead of `uniqueIdProvider.generate()`\n- Any changes to `src/commands/OptionsProcessor.ts` require checking if the engine patch needs updating.\n\n### JS Wrappers\n\nEngine wraps RNN's `Navigation` API in several services:\n- `Navigator.ts` — root layout, overlays, error screens, tab navigation\n- `BottomTabsBackHandler.ts` — back handling on bottom tabs via `Navigation.events()`\n- `TabsManager.ts` — tab management using RNN `Layout` types\n- Various other services import `Layout`, `LayoutRoot`, `LayoutSideMenu`, `OptionsSideMenu` from RNN\n\n### Upgrade Checklist\n\n1. Bump version in both `package.json` files\n2. Verify `OptionsProcessor.js` patch still applies (diff upstream changes)\n3. Check `RNNAppDelegate` API compatibility (iOS)\n4. Check `NavigationApplication` / `NavigationPackage` / `NavigationReactNativeHost` API compatibility (Android)\n5. Verify `missingDimensionStrategy` value is still valid\n6. Check `react-native-navigation-hooks` and `rnn-copilot` compatibility\n7. Run `yarn install` to update lockfile\n8. Verify test mocks (`react-native-navigation/Mock`) still work\n\n## Common Gotchas\n\n- iOS uses UIKit subclasses (UINavigationController, UITabBarController); Android uses custom View hierarchy\n- `splitView` is iOS-only\n- Side menu: iOS uses MMDrawerController (3rd party); Android uses DrawerLayout (native)\n- Options that exist in JS types may not be implemented on both platforms — check the presenter\n- `passProps` are stored in JS `Store`, not sent to native (cleared before bridge crossing)\n- The `lib/` folder is generated — never edit it, edit `src/` instead\n","frontmatter":{"name":"rnn-codebase","description":"Navigate and work with the react-native-navigation (RNN) codebase. Use when fixing bugs, adding features, tracing command flows, understanding options resolution, or working across JS/iOS/Android layers in this repo."},"isInternal":false,"tokens":2593,"sizeBytes":10453},{"name":"SKILL.md","path":".github/skills/rnn-codebase/SKILL.md","rawUrl":"https://raw.githubusercontent.com/wix/react-native-navigation/HEAD/.github/skills/rnn-codebase/SKILL.md","title":"rnn-codebase","category":"anthropic-skill","format":"markdown","content":"---\nname: rnn-codebase\ndescription: Navigate and work with the react-native-navigation (RNN) codebase. Use when fixing bugs, adding features, tracing command flows, understanding options resolution, or working across JS/iOS/Android layers in this repo.\n---\n\n# React Native Navigation Codebase\n\n## Architecture Overview\n\nRNN has three layers that mirror each other:\n\n```\nJS/TS (src/)  →  TurboModule bridge  →  iOS native (ios/)\n                                     →  Android native (android/)\n```\n\nA navigation command (e.g. `push`) flows:\n1. `Navigation.push()` → `Commands.ts` → processing pipeline → `NativeCommandsSender.ts`\n2. TurboModule: `RNNTurboModule` (iOS) / `NavigationTurboModule.kt` (Android)\n3. iOS: `RNNCommandsHandler` → `RNNViewControllerFactory` → UIKit controllers\n4. Android: `Navigator` → `LayoutFactory` → View-based controllers (no Fragments)\n\nRead [ARCHITECTURE.md](../../../ARCHITECTURE.md) for the full overview.\n\n## Key Cross-Layer Mappings\n\n### Layout Types → Native Controllers\n\n| JS Layout Type | iOS Controller | Android Controller |\n|----------------|---------------|-------------------|\n| `component` | `RNNComponentViewController` | `ComponentViewController` |\n| `stack` | `RNNStackController` (UINavigationController) | `StackController` |\n| `bottomTabs` | `RNNBottomTabsController` (UITabBarController) | `BottomTabsController` |\n| `sideMenu` | `RNNSideMenuViewController` (MMDrawerController) | `SideMenuController` (DrawerLayout) |\n| `topTabs` | `RNNTopTabsViewController` | `TopTabsController` (ViewPager) |\n| `splitView` | `RNNSplitViewController` | N/A (iOS only) |\n| `externalComponent` | `RNNExternalViewController` | `ExternalComponentViewController` |\n\n### Options → Presenters\n\nEach controller type has a Presenter that applies options to views:\n\n| iOS Controller | iOS Presenter | Android Presenter |\n|----------------|--------------|-------------------|\n| `RNNComponentViewController` | `RNNComponentPresenter` | `ComponentPresenter` |\n| `RNNStackController` | `RNNStackPresenter` + `TopBarPresenter` | `StackPresenter` |\n| `RNNBottomTabsController` | `RNNBottomTabsPresenter` | `BottomTabsPresenter` |\n| `RNNSideMenuViewController` | `RNNSideMenuPresenter` | `SideMenuPresenter` |\n\n### Events (same names both platforms)\n\n| Event | Trigger |\n|-------|---------|\n| `RNN.ComponentDidAppear` | Screen becomes visible |\n| `RNN.ComponentDidDisappear` | Screen hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tap |\n| `RNN.BottomTabSelected` | Tab changed |\n| `RNN.ModalDismissed` | Modal dismissed |\n| `RNN.ScreenPopped` | Screen popped from stack |\n| `RNN.CommandCompleted` | Any command finished |\n\n## Where to Find Things\n\n### By task: \"I need to fix/change X\"\n\n| Task | JS File(s) | iOS File(s) | Android File(s) |\n|------|-----------|------------|----------------|\n| Command execution | `src/commands/Commands.ts` | `ios/RNNCommandsHandler.mm` | `react/NavigationTurboModule.kt` |\n| Layout creation | `src/commands/LayoutTreeParser.ts` | `ios/RNNViewControllerFactory.mm` | `options/LayoutFactory.java` |\n| Options processing | `src/commands/OptionsProcessor.ts` | `ios/RNNNavigationOptions.mm` | `options/Options.java` |\n| Options application | — | `ios/*Presenter.mm` | `viewcontrollers/*Presenter.java` |\n| TopBar | `src/interfaces/Options.ts` (TopBarOptions) | `ios/TopBarPresenter.mm`, `ios/RNNUIBarButtonItem.mm` | `views/stack/topbar/` |\n| Bottom tabs | `src/interfaces/Options.ts` (BottomTabsOptions) | `ios/RNNBottomTabsPresenter.mm` | `viewcontrollers/bottomtabs/` |\n| Modals | `src/commands/Commands.ts` | `ios/RNNModalManager.mm` | `viewcontrollers/modal/ModalStack.java` |\n| Overlays | `src/commands/Commands.ts` | `ios/RNNOverlayManager.mm` | `viewcontrollers/overlay/OverlayManager.kt` |\n| Animations | `src/interfaces/Options.ts` (AnimationOptions) | `ios/ScreenAnimationController.mm` | `viewcontrollers/stack/StackAnimator.kt` |\n| React view rendering | — | `ios/RNNReactView.mm` | `react/ReactView.java` |\n| Events to JS | `src/adapters/NativeEventsReceiver.ts` | `ios/RNNEventEmitter.mm` | `react/events/EventEmitter.java` |\n| Component registration | `src/components/ComponentRegistry.ts` | — | — |\n\n### By directory\n\n- **`src/`** — JS public API, commands, processing pipeline. See [src/ARCHITECTURE.md](../../../src/ARCHITECTURE.md)\n- **`ios/`** — All Obj-C/C++ native code. See [ios/ARCHITECTURE.md](../../../ios/ARCHITECTURE.md)\n- **`ios/TurboModules/`** — New architecture entry points (`RNNTurboModule`, `RNNTurboManager`, `RNNTurboCommandsHandler`)\n- **`android/src/main/java/com/reactnativenavigation/`** — All Java/Kotlin native code. See [android/ARCHITECTURE.md](../../../android/ARCHITECTURE.md)\n- **`playground/`** — Demo app for development and E2E tests\n- **`playground/src/screens/`** — Test screens exercising every feature\n- **`playground/e2e/`** — Detox E2E tests\n\n## Options Resolution Order\n\nOptions are applied in ascending priority:\n1. Default options (from `Navigation.setDefaultOptions()`) — lowest priority\n2. Static options (from component class or `Navigation.registerComponent`)\n3. Options passed in the layout call (e.g. `push`, `setRoot`)\n4. `mergeOptions()` — runtime override, highest priority\n\n## JS Processing Pipeline (exact order)\n\n```\nAPI layout → OptionsCrawler.crawl() → LayoutProcessor.process()\n  → LayoutTreeParser.parse() → LayoutTreeCrawler.crawl()\n  → OptionsProcessor (colors, assets, custom) → NativeCommandsSender\n```\n\n## iOS Patterns\n\n- All controllers conform to `RNNLayoutProtocol`\n- `RNNBasePresenter` subclasses apply options — `applyOptionsOnInit:`, `applyOptions:`, `mergeOptions:resolvedOptions:`\n- Commands run on main thread (`RCTExecuteOnMainQueue`)\n- React views: `RNNReactView` wraps `RCTSurfaceHostingView` (new arch)\n- Overlays use separate `UIWindow` instances (`RNNOverlayWindow`)\n- `RNNReactComponentRegistry` caches React component instances\n\n## Android Patterns\n\n- View-based, NOT Fragment-based\n- All commands dispatched via `UiThread.post()`\n- `ViewController<T extends ViewGroup>` is the base — `createView()` is abstract\n- `ParentController` extends `ChildController` extends `ViewController`\n- Bottom tabs use `AHBottomNavigation` library\n- Three root layouts in `NavigationActivity`: rootLayout, modalsLayout, overlaysLayout\n- Tab attachment modes: `Together`, `OnSwitchToTab`, `AfterInitialTab`\n\n## Development Workflow\n\n### Playground app\n- `yarn start` — Metro bundler\n- `yarn xcode` — Open iOS project\n- `yarn studio` — Open Android project\n- `yarn pod-install` — Install iOS pods\n\n### Testing\n- `yarn test-js` — Jest unit tests\n- `yarn test-unit-ios` — iOS native unit tests (XCTest)\n- `yarn test-unit-android` — Android native unit tests (JUnit + Robolectric)\n- `yarn test-e2e-ios-ci` / `yarn test-e2e-android-ci` — Detox E2E tests\n\n### Building\n- `yarn prepare` — Builds `src/` → `lib/` (ESM + types)\n- Codegen config: `rnnavigation` in `package.json`\n\n## Common Gotchas\n\n- iOS uses UIKit subclasses (UINavigationController, UITabBarController); Android uses custom View hierarchy\n- `splitView` is iOS-only\n- Side menu: iOS uses MMDrawerController (3rd party); Android uses DrawerLayout (native)\n- Options that exist in JS types may not be implemented on both platforms — check the presenter\n- `passProps` are stored in JS `Store`, not sent to native (cleared before bridge crossing)\n- The `lib/` folder is generated — never edit it, edit `src/` instead\n","frontmatter":{"name":"rnn-codebase","description":"Navigate and work with the react-native-navigation (RNN) codebase. Use when fixing bugs, adding features, tracing command flows, understanding options resolution, or working across JS/iOS/Android layers in this repo."},"isInternal":false,"tokens":1914,"sizeBytes":7506},{"name":"github-descriptions.mdc","path":".cursor/rules/github-descriptions.mdc","rawUrl":"https://raw.githubusercontent.com/wix/react-native-navigation/HEAD/.cursor/rules/github-descriptions.mdc","title":"Cursor Rule: github-descriptions","category":"cursor-rule","format":"mdc","content":"---\ndescription: When the user asks for a GitHub description or PR description\nglobs:\nalwaysApply: false\n---\n\nWhen generating GitHub descriptions (PR descriptions, issue descriptions, commit descriptions), always use GitHub-flavored Markdown formatting: **bold** for emphasis, `backticks` for code/class/file references, bullet lists with `-`, and `##` headers where appropriate.\n","frontmatter":{"description":"When the user asks for a GitHub description or PR description","globs":null,"alwaysApply":false},"isInternal":false,"tokens":75,"sizeBytes":380}],"systemPromptSnippet":"<yakaai_skills repo=\"wix/react-native-navigation\">\n<!-- File: android/ARCHITECTURE.md (Tokens: ~3383 | Category: project-spec) -->\n# Android Native Architecture\n\nThe Android implementation provides native navigation using Views and ViewGroups (not Fragments), coordinated through a TurboModule that receives commands from JavaScript.\n\n## App Integration\n\n### NavigationApplication\n**File**: `NavigationApplication.java`\n\nAbstract Application class that user's MainApplication must extend:\n\n```kotlin\n// MainApplication.kt - User extends NavigationApplication\nclass MainApplication : NavigationApplication() {\n    override val reactNativeHost: ReactNativeHost\n        get() = NavigationReactNativeHost(this) // Must use NavigationReactNativeHost\n}\n```\n\n**What NavigationApplication does:**\n- Initializes SoLoader\n- Provides `ReactGateway` singleton for React lifecycle\n- Offers `registerExternalComponent()` for native screens\n\n### NavigationActivity\n**File**: `NavigationActivity.java`\n\nBase Activity that user's MainActivity must extend:\n\n```kotlin\n// MainActivity.kt - User extends NavigationActivity\nclass MainActivity : NavigationActivity() {\n    // No getMainComponentName() needed - navigation handles root\n}\n```\n\n**What NavigationActivity does:**\n- Creates `Navigator` with root, modal, and overlay layouts\n- Manages back press via `OnBackPressedCallback`\n- Coordinates React lifecycle with activity lifecycle\n\n### NavigationReactNativeHost\n**File**: `react/NavigationReactNativeHost.kt`\n\nCustom ReactNativeHost that integrates with navigation:\n- Used instead of `DefaultReactNativeHost`\n- Provides proper module registration for navigation\n\n### Autolink Script (`npx rnn-link`)\n\nThe `autolink/postlink/postLinkAndroid.js` script automates setup:\n\n| Linker | What it does |\n|--------|--------------|\n| `ApplicationLinker` | Changes MainApplication to extend `NavigationApplication`, uses `NavigationReactNativeHost`, removes SoLoader.init() |\n| `ActivityLinker` | Changes MainActivity to extend `NavigationActivity`, removes `getMainComponentName()` |\n| `GradleLinker` | Updates build.gradle if needed |\n\n**ApplicationLinker transformations:**\n- `class MainApplication : Application(), ReactApplication` → `class MainApplication : NavigationApplication()`\n- `DefaultReactNativeHost(this)` → `NavigationReactNativeHost(this)`\n- Removes `SoLoader.init()` (NavigationApplication handles it)\n- Removes new architecture entry point load block\n\n**ActivityLinker transformations:**\n- `class MainActivity : ReactActivity()` → `class MainActivity : NavigationActivity()`\n- Removes `getMainComponentName()` override\n- Removes `createReactActivityDelegate()` override\n\n## Directory Structure\n\n```\nandroid/src/main/java/com/reactnativenavigation/\n├── NavigationActivity.java       # Main Activity entry point\n├── NavigationApplication.java    # Application class\n├── NavigationPackage.kt          # React package registration\n├── react/                        # React bridge layer\n│   ├── NavigationTurboModule.kt  # TurboModule implementation\n│   ├── ReactGateway.java         # React lifecycle management\n│   └── events/\n│       └── EventEmitter.java     # Event emission to JS\n├── options/                      # Options parsing and factories\n│   ├── LayoutFactory.java        # Creates ViewControllers from layout nodes\n│   └── Options.java              # Options model\n├── viewcontrollers/              # ViewController hierarchy\n│   ├── ViewController.java       # Base class\n│   ├── ChildController.java      # With presenter support\n│   ├── ParentController.java     # Container controllers\n│   ├── stack/                    # Stack navigation\n│   ├── bottomtabs/               # Bottom tabs\n│   ├── toptabs/                  # Top tabs (lowercase)\n│   ├── sidemenu/                 # Side menu/drawer\n│   ├── modal/                    # Modal management\n│   └── externalcomponent/        # Native component support\n├── views/                        # UI View implementations\n├── utils/                        # Utilities\n└── hierarchy/                    # Root layout management\n```\n\n## Bridge Architecture\n\n```\n┌────────────────────────────────────────────────────────────┐\n│                 JavaScript (TurboModule)                   │\n└─────────────────────────┬──────────────────────────────────┘\n                          │\n┌─────────────────────────▼──────────────────────────────────┐\n│  NavigationTurboModule.kt                                   │\n│  - setRoot, push, pop, showModal, dismissModal, etc.       │\n└─────────────────────────┬──────────────────────────────────┘\n                          │\n┌─────────────────────────▼──────────────────────────────────┐\n│  Navigator (Root ViewController)                           │\n│  - Manages root, modals, overlays                          │\n│  - Coordinates LayoutFactory                               │\n└──────┬──────────────┬──────────────┬──────────────┬────────┘\n       │              │              │              │\n┌──────▼─────┐ ┌──────▼─────┐ ┌──────▼─────┐ ┌─────▼──────┐\n│ModalStack  │ │OverlayMgr  │ │LayoutFactory│ │EventEmitter│\n└────────────┘ └────────────┘ └────────────┘ └────────────┘\n```\n\n## Entry Points\n\n### NavigationApplication\nAbstract Application class that apps extend:\n- Manages `ReactGateway` singleton\n- Initializes SoLoader\n- Provides `registerExternalComponent()` for native screens\n\n### NavigationActivity\nMain Activity containing all navigation:\n- Creates `Navigator` with three CoordinatorLayouts:\n  - `rootLayout` - Main navigation content\n  - `modalsLayout` - Modal stack\n  - `overlaysLayout` - Overlays (highest z-order)\n- Handles back press via `OnBackPressedCallback`\n- Coordinates activity lifecycle with React\n\n### NavigationTurboModule\nTurboModule implementation (Kotlin, ~300 lines):\n\n```kotlin\n@ReactMethod\nfun setRoot(commandId: String, layout: ReadableMap, promise: Promise)\n\n@ReactMethod\nfun push(commandId: String, componentId: String, layout: ReadableMap, promise: Promise)\n\n@ReactMethod\nfun showModal(commandId: String, layout: ReadableMap, promise: Promise)\n```\n\nAll commands execute on UI thread via `UiThread.post()`.\n\n## ViewController Hierarchy\n\n**Note**: Android implementation does NOT use Fragments - it's purely View-based.\n\n```\nViewController (abstract)\n│   - Base for all navigation controllers\n│   - Manages view creation and lifecycle\n│   - Handles options and back press\n│\n├── ChildController\n│   │   - Adds Presenter support\n│   │\n│   ├── ComponentViewController\n│   │       - Renders React components via ReactView\n│   │\n│   └── ExternalComponentViewController\n│           - Wraps native Android views\n│\n└── ParentController (extends ChildController)\n        - Container for child controllers\n        │\n        ├── StackController\n        │       - Push/pop navigation\n        │       - Uses IdStack<ViewController>\n        │\n        ├── BottomTabsController\n        │       - UITabBarController equivalent\n        │       - Uses AHBottomNavigation\n        │\n        ├── TopTabsController\n        │       - Horizontal ViewPager tabs\n        │\n        ├── SideMenuController\n        │       - DrawerLayout-based drawer\n        │\n        └── Navigator\n                - Root controller\n                - Manages modals and overlays\n```\n\n## Core Classes\n\n### ViewController (Base)\n**File**: `viewcontrollers/viewcontroller/ViewController.java` (~500 lines)\n\nAbstract base for all navigation controllers:\n\n```java\npublic abstract class ViewController<T extends ViewGroup> {\n    protected abstract T createView();  // Subclasses create views\n\n    public void onViewWillAppear() { }\n    public void onViewDidAppear() { }\n    public void onViewDisappear() { }\n\n    public void mergeOptions(Options options) { }\n    public void applyOptions(Options options) { }\n    public boolean handleBack(CommandListener listener) { }\n    public void destroy() { }\n}\n```\n\n### Navigator (Root)\n**File**: `viewcontrollers/navigator/Navigator.java`\n\nRoot ViewController managing:\n- Root content hierarchy\n- Modal stack (`ModalStack`)\n- Overlay manager (`OverlayManager`)\n- Component lookup by ID\n\n### LayoutFactory\n**File**: `options/LayoutFactory.java`\n\nFactory creating ViewControllers from LayoutNode. Owned by `NavigationTurboModule` and used to build the view controller hierarchy when commands are received from JavaScript.\n\n```java\npublic ViewController create(LayoutNode node) {\n    switch (node.type) {\n        case Component: return createComponent(node);\n        case Stack: return createStack(node);\n        case BottomTabs: return createBottomTabs(node);\n        case SideMenuRoot: return createSideMenuRoot(node);\n        case SideMenuCenter: return createSideMenuContent(node);\n        case SideMenuLeft: return createSideMenuLeft(node);\n        case SideMenuRight: return createSideMenuRight(node);\n        case TopTabs: return createTopTabs(node);\n        // Note: SplitView is iOS-only, not implemented on Android\n    }\n}\n```\n\n## Navigation Types\n\n### Stack Navigation (StackController)\n**Files**: `viewcontrollers/stack/`\n\n- View: `StackLayout` (CoordinatorLayout with TopBar)\n- Internal stack: `IdStack<ViewController<?>>`\n- Components: `TopBarController`, `StackAnimator`, `StackPresenter`, `FabPresenter`\n\nOperations:\n- `push(viewController, listener)`\n- `pop(options, listener)`\n- `popTo(target, options, listener)`\n- `popToRoot(options, listener)`\n- `setRoot(children, listener)`\n\n### Bottom Tabs (BottomTabsController)\n**Files**: `viewcontrollers/bottomtabs/`\n\n- View: `BottomTabsLayout` (CoordinatorLayout with BottomTabs)\n- Uses `AHBottomNavigation` library\n- Components: `BottomTabsPresenter`, `BottomTabPresenter`, `BottomTabsAnimator`\n\nAttachment Modes:\n- `TogetherAttacher` - Load all tabs immediately\n- `OnSwitchToTabAttacher` - Lazy load on selection\n- `AfterInitialTabAttacher` - Load initial + others in background\n\n### Side Menu (SideMenuController)\n**Files**: `viewcontrollers/sidemenu/`\n\n- View: `SideMenuRoot` (DrawerLayout-based)\n- Children: Center, Left, Right controllers\n- `SideMenuPresenter` for styling\n\n### Top Tabs (TopTabsController)\n**Files**: `viewcontrollers/toptabs/`\n\n- View: `TopTabsViewPager` (ViewPager-based)\n- `TopTabsLayoutCreator` for view creation\n\n### Modals (ModalStack)\n**Files**: `viewcontrollers/modal/`\n\nNot a ViewController - manages modal presentation:\n- `ModalPresenter` - Show/dismiss with animations\n- `ModalAnimator` (Kotlin) - Animation handling\n- Stack of modals with lifecycle management\n\n### Overlays (OverlayManager)\n**File**: `viewcontrollers/overlay/OverlayManager.kt`\n\nRegistry of active overlays:\n- Show/dismiss by component ID\n- Configuration change handling\n- Host pause/resume lifecycle\n\n## React Component Rendering\n\n### ComponentViewController\nManages React component lifecycle:\n- Creates `ComponentLayout` view\n- Initializes `ReactView` with ReactSurface\n- Emits lifecycle events to JS\n- Handles scroll events and status bar\n\n### ReactView\n**File**: `react/ReactView.java`\n\nExtends FrameLayout, wraps `ReactSurface`:\n- `start()` - Attach surface to React instance\n- `destroy()` - Clean up React surface\n- `sendComponentWillStart()` - Emit event to JS\n- `isReady()` - Check surface attachment\n\n## Event Emission\n\n### EventEmitter\n**File**: `react/events/EventEmitter.java`\n\nEvents sent to JavaScript:\n\n| Event | Description |\n|-------|-------------|\n| `RNN.AppLaunched` | App initialization complete |\n| `RNN.ComponentDidAppear` | Component visible |\n| `RNN.ComponentWillAppear` | About to become visible |\n| `RNN.ComponentDidDisappear` | Component hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tapped |\n| `RNN.BottomTabSelected` | Tab selection changed |\n| `RNN.BottomTabPressed` | Tab pressed (even if selected) |\n| `RNN.ModalDismissed` | Modal was dismissed |\n| `RNN.ScreenPopped` | Screen removed from stack |\n| `RNN.CommandCompleted` | Navigation command finished |\n\n## Options System\n\n### Options Class\n**File**: `options/Options.java`\n\n```java\npublic class Options {\n    public TopBarOptions topBar;\n    public TopTabsOptions topTabs;\n    public BottomTabsOptions bottomTabsOptions;\n    public BottomTabOptions bottomTabOptions;\n    public OverlayOptions overlayOptions;\n    public FabOptions fabOptions;\n    public AnimationsOptions animations;\n    public SideMenuRootOptions sideMenuRootOptions;\n    public ModalOptions modal;\n    public StatusBarOptions statusBar;\n    public NavigationBarOptions navigationBar;\n    public LayoutOptions layout;\n    public HardwareBackButtonOptions hardwareBack;\n}\n```\n\n### Options Flow\n1. **Parse**: JSON from JS → Options object via JSONParser\n2. **Merge**: Default → Screen → Component options\n3. **Apply**: Presenter applies to views\n\n## Presenter Pattern\n\nEach ViewController has a Presenter:\n\n| ViewController | Presenter |\n|---------------|-----------|\n| StackController | StackPresenter |\n| BottomTabsController | BottomTabsPresenter + BottomTabPresenter |\n| ComponentViewController | ComponentPresenter |\n| SideMenuController | SideMenuPresenter |\n| Navigator | RootPresenter |\n\n### Presenter Base\n**File**: `viewcontrollers/viewcontroller/Presenter.java`\n\nHandles:\n- Orientation changes\n- Status bar styling\n- Navigation bar styling\n- Layout parameters\n\n## Animation System\n\n### Animators (Kotlin)\n- `StackAnimator.kt` - Push, pop, setRoot animations\n- `ModalAnimator.kt` - Modal show/dismiss\n- `BottomTabsAnimator.kt` - Tab transitions\n- `TopBarAppearanceAnimator.kt` - Top bar changes\n\n### Element Transitions\nVia `TransitionAnimatorCreator.kt`:\n- Position, scale, rotation animations\n- Color transitions\n- Corner radius animations\n- Shared element support\n\n## Activity Lifecycle\n\n```java\nonCreate()      // Create Navigator, initialize React\nonPostCreate()  // Set content layout\nonResume()      // React host resume, event emitter setup\nonPause()       // React host pause\nonDestroy()     // Clean up Navigator\nonConfigurationChanged()  // Handle orientation, locale\nonNewIntent()   // Process deep links\nonActivityResult()  // Handle permissions\n```\n\n## ViewController Lifecycle\n\n```\nView creation\n    ↓\nonViewWillAppear()   // Register with registry\n    ↓\nonViewDidAppear()    // Emit event to JS\n    ↓\n[visible]\n    ↓\nonViewWillDisappear()\n    ↓\nonViewDisappear()    // Unregister from registry\n    ↓\ndestroy()            // Complete cleanup\n```\n\n## Key Files Reference\n\nAll paths relative to `android/src/main/java/com/reactnativenavigation/`:\n\n| File | Path | Purpose |\n|------|------|---------|\n| NavigationActivity.java | `.` | Main Activity |\n| NavigationApplication.java | `.` | Application class |\n| NavigationTurboModule.kt | `react/` | JS bridge |\n| Navigator.java | `viewcontrollers/navigator/` | Root controller |\n| ViewController.java | `viewcontrollers/viewcontroller/` | Base class |\n| StackController.java | `viewcontrollers/stack/` | Stack navigation |\n| BottomTabsController.java | `viewcontrollers/bottomtabs/` | Tab navigation |\n| LayoutFactory.java | `options/` | Controller factory |\n| Options.java | `options/` | Options model |\n| Presenter.java | `viewcontrollers/viewcontroller/` | Base presenter |\n| EventEmitter.java | `react/events/` | JS events |\n| ReactView.java | `react/` | React component wrapper |\n| StackAnimator.kt | `viewcontrollers/stack/` | Stack animations |\n| ModalStack.java | `viewcontrollers/modal/` | Modal management |\n\n<!-- File: ARCHITECTURE.md (Tokens: ~1842 | Category: project-spec) -->\n# React Native Navigation Architecture\n\nReact 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.\n\n## Project Overview\n\n- **Package**: `react-native-navigation` (v8.7.0)\n- **Platforms**: iOS 11+, Android 7.0+ (API 24)\n- **React Native**: 0.77+ (developed against 0.83; see package.json for current version)\n- **License**: MIT (maintained by Wix)\n\n## Directory Structure\n\n```\nreact-native-navigation/\n├── src/                    # TypeScript source code (JS API layer)\n├── lib/                    # Compiled output (generated by bob build - do not edit)\n├── android/                # Android native implementation (Java/Kotlin)\n├── ios/                    # iOS native implementation (Obj-C/C++)\n├── playground/             # Demo app and E2E test target\n├── autolink/               # Post-install linking scripts\n├── scripts/                # Build, test, and release scripts\n├── website/                # Docusaurus documentation site\n├── integration/            # Integration tests (Redux, Remx)\n├── Mock/                   # Mock implementations for testing\n└── .buildkite/             # CI/CD pipeline configuration\n```\n\n## High-Level Architecture\n\n```\n┌──────────────────────────────────────────────────────────────────┐\n│                     JavaScript API Layer                         │\n│  Navigation.setRoot() / push() / pop() / showModal() / etc.     │\n└─────────────────────────────┬────────────────────────────────────┘\n                              │\n┌─────────────────────────────▼────────────────────────────────────┐\n│                    Processing Pipeline                            │\n│  OptionsCrawler → LayoutProcessor → LayoutTreeParser → OptionsProcessor │\n└─────────────────────────────┬────────────────────────────────────┘\n                              │\n┌─────────────────────────────▼────────────────────────────────────┐\n│                   TurboModule Bridge                              │\n│  NativeCommandsSender ←→ RNNTurboModule (iOS) / NavigationTurboModule (Android) │\n└──────────┬─────────────────────────────────────┬─────────────────┘\n           │                                     │\n┌──────────▼──────────┐               ┌─────────▼──────────┐\n│   iOS Native Layer  │               │ Android Native Layer│\n│  UINavigationController             │   ViewControllers   │\n│  UITabBarController │               │   CoordinatorLayout │\n│  UIViewController   │               │   BottomNavigation  │\n└─────────────────────┘               └────────────────────┘\n```\n\n## Core Concepts\n\n### Layout Types\nAll navigation structures are composed from these layout primitives:\n\n| Layout Type | Description | iOS Implementation | Android Implementation |\n|-------------|-------------|-------------------|----------------------|\n| `component` | React component screen | RNNComponentViewController | ComponentViewController |\n| `stack` | Push/pop navigation | UINavigationController (RNNStackController) | StackController |\n| `bottomTabs` | Tab bar navigation | UITabBarController (RNNBottomTabsController) | BottomTabsController |\n| `topTabs` | Horizontal scrollable tabs | RNNTopTabsViewController | TopTabsController |\n| `sideMenu` | Drawer navigation (with center, left, right) | MMDrawerController (RNNSideMenuViewController) | SideMenuController |\n| `splitView` | Master-detail (iPad only) | UISplitViewController (RNNSplitViewController) | — |\n| `externalComponent` | Native (non-React) screen | RNNExternalViewController | ExternalComponentViewController |\n\n### Navigation Commands\nCore commands available through the Navigation API:\n\n- **Root**: `setRoot()` - Replace entire navigation hierarchy\n- **Stack**: `push()`, `pop()`, `popTo()`, `popToRoot()`, `setStackRoot()`\n- **Modal**: `showModal()`, `dismissModal()`, `dismissAllModals()`\n- **Overlay**: `showOverlay()`, `dismissOverlay()`, `dismissAllOverlays()`\n- **Options**: `setDefaultOptions()`, `mergeOptions()`, `updateProps()`\n- **Linking**: `setLinking()`, `handleDeepLink()`, `setLinkingReady()` - URL-to-screen routing\n\n### Deep Linking\nURL-driven navigation is implemented entirely in the JS layer (`src/linking/`) and feeds into the standard command pipeline. Configure with `Navigation.setLinking({ prefixes, config: { screens } })`; matched URLs are presented as modals by default (preserving the user's current navigation state). Customize via `getModal`/`onLink` hooks; gate processing on auth via `isReady`/`setLinkingReady`. Native plumbing — `application:openURL:`, `application:continueUserActivity:`, cold-start URL queueing — lives in `RNNAppDelegate` (iOS) and `NavigationActivity.onNewIntent` (Android), so subclassing the base classes is sufficient. See [Deep Linking docs](https://wix.github.io/react-native-navigation/docs/deep-linking).\n\n### Options System\nStyling and behavior is controlled via a hierarchical options object:\n\n```typescript\n{\n  statusBar: {...},      // Status bar appearance\n  topBar: {...},         // Navigation bar styling\n  bottomTabs: {...},     // Tab bar configuration\n  bottomTab: {...},      // Individual tab styling\n  sideMenu: {...},       // Drawer configuration\n  layout: {...},         // Screen layout options\n  animations: {...},     // Transition animations\n  modal: {...},          // Modal presentation style\n  overlay: {...}         // Overlay behavior\n}\n```\n\nOptions merge in order: **Default Options → Parent Options → Component Options**\n\n## Data Flow\n\n### Command Execution Flow\n```\n1. JS: Navigation.push(componentId, layout)\n2. Commands.ts validates and begins processing\n3. OptionsCrawler extracts static options from component classes\n4. LayoutProcessor applies registered layout processors\n5. LayoutTreeParser converts to internal LayoutNode tree\n6. LayoutTreeCrawler processes tree, saves props to Store\n7. OptionsProcessor resolves colors, images, fonts\n8. NativeCommandsSender sends to TurboModule\n9. Native layer creates/updates view hierarchy\n10. EventEmitter sends completion event to JS\n```\n\n**Note**: The JS layer exports a single `Navigation` object (from `NavigationDelegate`). The TurboModule names differ per platform: `RNNTurboModule` on iOS, `NavigationTurboModule` on Android.\n\n### Event Flow (Native → JS)\n```\n1. Native lifecycle event (viewDidAppear, etc.)\n2. RNNEventEmitter (iOS) / EventEmitter (Android)\n3. NativeEventsReceiver receives via NativeEventEmitter\n4. EventsRegistry dispatches to registered listeners\n5. ComponentEventsObserver calls component instance methods\n```\n\n## Key Architecture Patterns\n\n1. **Facade Pattern**: `NavigationDelegate` provides clean public API\n2. **Bridge Pattern**: Adapters isolate JS from native implementation details\n3. **Presenter Pattern**: Separates view styling from controller logic\n4. **Observer Pattern**: Event system for lifecycle and command notifications\n5. **Factory Pattern**: `LayoutFactory` creates controllers from layout nodes\n6. **Plugin Pattern**: Processors allow extending layout/options handling\n\n## Component Lifecycle\n\nReact components receive navigation lifecycle events:\n\n```typescript\nclass MyScreen extends NavigationComponent {\n  componentWillAppear(event) {}      // About to become visible\n  componentDidAppear(event) {}       // Now visible\n  componentDidDisappear(event) {}    // No longer visible\n  navigationButtonPressed(event) {}  // TopBar button tapped\n  screenPopped(event) {}             // Screen removed from stack\n  searchBarUpdated(event) {}         // Search text changed\n  searchBarCancelPressed(event) {}   // Search cancelled\n  previewCompleted(event) {}         // 3D Touch preview completed\n}\n```\n\n## Testing Architecture\n\n- **Unit Tests**: Jest + ts-mockito for TypeScript source\n- **Integration Tests**: Redux/Remx integration verification\n- **E2E Tests**: Detox framework with playground app\n- **Snapshot Tests**: iOS visual regression testing\n- **Native Unit Tests**: XCTest (iOS) and JUnit (Android)\n\n## Related Documentation\n\n- [JavaScript/TypeScript Architecture](./src/ARCHITECTURE.md)\n- [iOS Native Architecture](./ios/ARCHITECTURE.md)\n- [Android Native Architecture](./android/ARCHITECTURE.md)\n- [API Documentation](https://wix.github.io/react-native-navigation/)\n\n<!-- File: ios/ARCHITECTURE.md (Tokens: ~3681 | Category: project-spec) -->\n# iOS Native Architecture\n\nThe iOS implementation provides native navigation using UIKit view controllers, coordinated through a bridge module that receives commands from JavaScript.\n\n## App Integration\n\n### RNNAppDelegate\n**Files**: `RNNAppDelegate.h/mm`\n\nBase class that user's AppDelegate must extend. Handles React Native and navigation initialization:\n\n```objc\n// AppDelegate.h - User extends RNNAppDelegate\n#import \"RNNAppDelegate.h\"\n@interface AppDelegate : RNNAppDelegate\n@end\n\n// AppDelegate.m - User implements sourceURLForBridge\n@implementation AppDelegate\n- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {\n  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@\"index\"];\n}\n@end\n```\n\n**What RNNAppDelegate does:**\n- Sets up React Native feature flags (Fabric, TurboModules, Bridgeless)\n- Creates `RCTRootViewFactory` and `ReactHost`\n- Calls `[ReactNativeNavigation bootstrapWithHost:]` to initialize navigation\n- Handles RN version differences (0.77, 0.78, 0.79+) via compile-time macros\n- **Deep linking plumbing**:\n  - Implements `application:openURL:options:` and `application:continueUserActivity:restorationHandler:`; both call `-dispatchDeepLinkURL:`.\n  - `-dispatchDeepLinkURL:` posts `RCTOpenURLNotification` directly if the React runtime is ready, otherwise enqueues the URL.\n  - Observes `RCTContentDidAppearNotification` (the Fabric/bridgeless signal) to flush the queue. This solves the cold-start race where URLs (push notifications, OS link launches) arrive before `RCTLinkingManager` is listening.\n  - Subclasses can call `-dispatchDeepLinkURL:` manually from notification delegates or any other URL source; the queueing behavior is reused automatically.\n\n### ReactNativeNavigation Bootstrap\n**File**: `ReactNativeNavigation.h/mm`\n\nPublic API for native initialization:\n\n```objc\n// New architecture (0.77+)\n[ReactNativeNavigation bootstrapWithHost:reactHost];\n\n// Legacy bridge\n[ReactNativeNavigation bootstrapWithBridge:bridge];\n\n// Register native screens\n[ReactNativeNavigation registerExternalComponent:@\"NativeScreen\"\n                                        callback:^(NSDictionary *props, RCTBridge *bridge) {\n    return [[MyNativeVC alloc] init];\n}];\n```\n\n### Autolink Script (`npx rnn-link`)\n\nThe `autolink/postlink/postLinkIOS.js` script automates setup:\n\n| Linker | What it does |\n|--------|--------------|\n| `AppDelegateLinker` | Changes AppDelegate to extend `RNNAppDelegate`, imports ReactNativeNavigation, removes RCTRootView setup |\n| `PodfileLinker` | Adds required pods configuration |\n| `PlistLinker` | Updates Info.plist if needed |\n\n**AppDelegateLinker transformations:**\n- Swift: `class AppDelegate: RCTAppDelegate` → `class AppDelegate: RNNAppDelegate`\n- Obj-C header: `@interface AppDelegate : RCTAppDelegate` → `@interface AppDelegate : RNNAppDelegate`\n- Imports `<ReactNativeNavigation/ReactNativeNavigation.h>`\n- Removes manual RCTRootView/window setup (navigation manages the window)\n\n## Directory Structure\n\n```\nios/\n├── RNNBridgeModule.h/mm         # Bridge entry point (legacy architecture)\n├── RNNBridgeManager.h/mm        # Bridge initialization\n├── RNNCommandsHandler.h/mm      # Command dispatcher\n├── RNNEventEmitter.h/mm         # Event emission to JS\n├── RNNLayoutManager.h/mm        # View controller tracking\n├── RNNLayoutNode.h/mm           # Layout tree parsing\n├── RNNNavigationOptions.h/mm    # Options model\n├── RNNComponentViewController.h/mm  # React component screen\n├── RNNStackController.h/mm      # Stack navigation\n├── RNNBottomTabsController.h/mm # Tab navigation\n├── RNNSideMenuViewController.h/mm   # Side menu\n├── RNNTopTabsViewController.h/mm    # Top tabs\n├── RNNSplitViewController.h/mm  # Split view (iPad)\n├── RNNModalManager.h/mm         # Modal presentation\n├── RNNOverlayManager.h/mm       # Overlay management\n├── TurboModules/                # New architecture entry points\n│   ├── RNNTurboModule.h/mm      # TurboModule spec implementation\n│   ├── RNNTurboManager.h/mm     # Manager for host, window, external components\n│   ├── RNNTurboCommandsHandler.h/mm  # TurboModule command routing\n│   └── RNNTurboEventEmitter.h/mm     # Event emission for new arch\n├── Utils/                       # Utility classes\n├── RNNSideMenu/                 # MMDrawerController integration\n└── ReactNativeNavigation.xcodeproj/\n```\n\n## Bridge Architecture\n\nThe library supports both the legacy bridge and new TurboModule architecture:\n- **Legacy (Bridge)**: `RNNBridgeModule` receives commands via `RCT_EXPORT_METHOD`\n- **New Architecture**: `RNNTurboModule` (in `TurboModules/`) receives commands directly\n\nBoth entry points delegate to `RNNCommandsHandler` for command execution.\n\n```\n┌────────────────────────────────────────────────────────────┐\n│                 JavaScript (TurboModule)                   │\n└─────────────────────────┬──────────────────────────────────┘\n                          │\n┌─────────────────────────▼──────────────────────────────────┐\n│  RNNBridgeModule (bridge) / RNNTurboModule (new arch)      │\n│  - setRoot, push, pop, showModal, dismissModal, etc.       │\n└─────────────────────────┬──────────────────────────────────┘\n                          │\n┌─────────────────────────▼──────────────────────────────────┐\n│  RNNCommandsHandler                                         │\n│  - Validates commands, manages layout lifecycle            │\n│  - Coordinates with managers                               │\n└──────┬──────────────┬──────────────┬──────────────┬────────┘\n       │              │              │              │\n┌──────▼─────┐ ┌──────▼─────┐ ┌──────▼─────┐ ┌─────▼──────┐\n│RNNLayout   │ │RNNModal    │ │RNNOverlay  │ │RNNViewController│\n│Manager     │ │Manager     │ │Manager     │ │Factory     │\n└────────────┘ └────────────┘ └────────────┘ └────────────┘\n```\n\n## View Controller Hierarchy\n\nAll navigation view controllers conform to `RNNLayoutProtocol`:\n\n```\nUIViewController\n├── RNNComponentViewController    # React component screen\n├── RNNExternalViewController     # Native screen wrapper\n└── RNNSplashScreenViewController # Launch screen\n\nUINavigationController\n└── RNNStackController           # Stack navigation\n\nUITabBarController\n└── RNNBottomTabsController      # Bottom tabs\n\nUIViewController (custom)\n├── RNNTopTabsViewController     # Horizontal top tabs\n└── RNNSideMenuChildViewController  # Drawer child\n\nMMDrawerController\n└── RNNSideMenuViewController    # Side menu/drawer\n\nUISplitViewController\n└── RNNSplitViewController       # Master-detail (iPad)\n```\n\n## Core Classes\n\n### RNNBridgeModule\nEntry point for JavaScript commands (legacy architecture). Exports methods via `RCT_EXPORT_METHOD`:\n\n```objc\nRCT_EXPORT_METHOD(setRoot:(NSString*)commandId layout:(NSDictionary*)layout\n                  resolver:(RCTPromiseResolveBlock)resolve\n                  rejecter:(RCTPromiseRejectBlock)reject);\n```\n\n`RNNBridgeModule` returns the main queue as its `methodQueue`; `RNNTurboModule` uses `RCTExecuteOnMainQueue` for each command to ensure UI operations run on the main thread.\n\n### RNNBridgeManager\nInitializes bridge infrastructure:\n- Creates RNNLayoutManager, RNNModalManager, RNNOverlayManager\n- Creates RNNViewControllerFactory, RNNCommandsHandler\n- Provides extra modules to React bridge\n- Handles JavaScript reload events\n\n### RNNCommandsHandler\nCentral command dispatcher implementing all navigation operations:\n- `setRoot:` - Replace root view controller\n- `push:componentId:layout:` - Push to stack\n- `pop:componentId:` - Pop from stack\n- `showModal:` - Present modal\n- `dismissModal:` - Dismiss modal\n- `showOverlay:` - Show overlay window\n- `dismissOverlay:` - Hide overlay\n\n### RNNLayoutManager\nTracks active view controllers:\n- `addPendingViewController:` - Register during creation\n- `removePendingViewController:` - Cleanup after presentation\n- `findComponentForId:` - Lookup by componentId\n\n### RNNLayoutNode\nParses JSON layout from JavaScript:\n- Determines type via predicates: `isComponent`, `isStack`, `isTabs`, etc.\n- Holds `type`, `nodeId`, `data` (options), `children`\n\n### RNNViewControllerFactory\nCreates view controllers from RNNLayoutNode:\n- `createStack:` → RNNStackController\n- `createBottomTabs:` → RNNBottomTabsController\n- `createComponent:` → RNNComponentViewController\n- `createSideMenu:` → RNNSideMenuViewController\n\n## RNNLayoutProtocol\n\nProtocol all navigation controllers implement:\n\n```objc\n@protocol RNNLayoutProtocol\n- (instancetype)initWithLayoutInfo:(RNNLayoutInfo*)layoutInfo\n                           creator:(id<RNNComponentViewCreator>)creator\n                           options:(RNNNavigationOptions*)options\n                    defaultOptions:(RNNNavigationOptions*)defaultOptions\n                         presenter:(RNNBasePresenter*)presenter\n                      eventEmitter:(RNNEventEmitter*)eventEmitter\n              childViewControllers:(NSArray*)childViewControllers;\n\n- (void)render;\n- (UIViewController*)getCurrentChild;\n- (void)mergeOptions:(RNNNavigationOptions*)options;\n- (RNNNavigationOptions*)resolveOptions;\n- (void)setDefaultOptions:(RNNNavigationOptions*)defaultOptions;\n- (void)onChildWillAppear;\n- (void)readyForPresentation;\n- (CGFloat)getTopBarHeight;\n- (CGFloat)getBottomTabsHeight;\n@end\n```\n\nAdditional methods provided via `UIViewController+LayoutProtocol` category:\n- `destroy`, `topMostViewController`, `stack`\n- `componentWillAppear`, `componentDidAppear`, `componentDidDisappear`\n- `screenPopped`, `prepareForTransition`\n- `resolveOptionsWithDefault`, `mergeChildOptions:child:`\n\n## Presenter Pattern\n\nEach view controller type has a corresponding presenter that applies options:\n\n| Controller | Presenter |\n|------------|-----------|\n| RNNComponentViewController | RNNComponentPresenter |\n| RNNStackController | RNNStackPresenter + TopBarPresenter |\n| RNNBottomTabsController | RNNBottomTabsPresenter + BottomTabPresenter |\n| RNNSideMenuViewController | RNNSideMenuPresenter |\n| RNNSplitViewController | RNNSplitViewControllerPresenter |\n\n### RNNBasePresenter\nBase class with lifecycle methods:\n- `applyOptionsOnInit:` - Initial setup\n- `applyOptions:` - Apply current options\n- `mergeOptions:resolvedOptions:` - Runtime updates\n- `componentWillAppear`, `componentDidAppear`, `componentDidDisappear`\n\n## React View Integration\n\n### RNNReactView\nWraps RCTRootView (legacy) or RCTSurfaceHostingView (new architecture):\n- Implements `RNNComponentProtocol`\n- Manages `componentId`, `componentType`, `moduleName`\n- Lifecycle: `componentWillAppear`, `componentDidAppear`, `componentDidDisappear`\n\n### RNNReactRootViewCreator\nCreates RNNReactView instances:\n- Supports component types: Component, TopBarTitle, TopBarButton, TopBarBackground\n- Handles size flexibility for flexible layouts\n\n### RNNReactComponentRegistry\nCaches created React component instances:\n- `createComponentIfNotExists:parentComponentId:componentType:reactViewReadyBlock:`\n- `removeComponent:`, `clearComponentsForParentId:`\n\n## Options System\n\n### RNNNavigationOptions\nMaster options object containing all configuration:\n\n```objc\n@interface RNNNavigationOptions : RNNOptions\n@property RNNTopBarOptions* topBar;\n@property RNNBottomTabsOptions* bottomTabs;\n@property RNNBottomTabOptions* bottomTab;\n@property RNNTopTabsOptions* topTabs;\n@property RNNSideMenuOptions* sideMenu;\n@property RNNOverlayOptions* overlay;\n@property RNNAnimationsOptions* animations;\n@property RNNStatusBarOptions* statusBar;\n@property RNNLayoutOptions* layout;\n@property RNNModalOptions* modal;\n@property RNNPreviewOptions* preview;\n@property RNNSplitViewOptions* splitView;\n@end\n```\n\n### Options Resolution\nOptions merge in hierarchy:\n1. Component's own options\n2. Parent controller options (loop through chain)\n3. Default options (from `setDefaultOptions`)\n\n## Event Emission\n\n### RNNEventEmitter\nSends events to JavaScript via RCTEventEmitter:\n\n| Event | Method |\n|-------|--------|\n| Component lifecycle | `sendComponentWillAppear:`, `sendComponentDidAppear:`, `sendComponentDidDisappear:` |\n| Button press | `sendOnNavigationButtonPressed:buttonId:` |\n| Command completion | `sendOnNavigationCommandCompletion:commandId:` |\n| Tab events | `sendBottomTabSelected:unselected:`, `sendBottomTabLongPressed:`, `sendBottomTabPressed:` |\n| Modal events | `sendModalsDismissedEvent:numberOfModalsDismissed:`, `sendModalAttemptedToDismissEvent:` |\n| Screen events | `sendScreenPoppedEvent:` |\n| Search | `sendOnSearchBarUpdated:text:isFocused:`, `sendOnSearchBarCancelPressed:` |\n| Preview | `sendOnPreviewCompleted:previewComponentId:` |\n\n### RNNBridgeEventEmitter\nConcrete implementation that sends `onAppLaunched` on initialization.\n\n## Modal & Overlay Management\n\n### RNNModalManager\n- Tracks presented modals array\n- Supports custom transition animations via ScreenAnimationController\n- Handles presentationController delegate for adaptive presentation\n\n### RNNOverlayManager\n- Manages UIWindow instances for overlays\n- Each overlay gets its own RNNOverlayWindow\n- Maintains previous window reference for restoration\n- Controls window level and accessibility\n\n## Animation System\n\n### ScreenAnimationController\nImplements `UIViewControllerAnimatedTransitioning`:\n- Custom push/pop/modal transitions\n- Content transitions (RNNEnterExitAnimation)\n- Element transitions (ElementTransitionOptions)\n- Shared element transitions (SharedElementTransitionOptions)\n\n### Element Animators\n- `ElementAnimator` - Individual element animations\n- `SharedElementAnimator` - Cross-screen shared elements\n- Transition types: Alpha, Scale, Translation, Frame, Bounds, Color, CornerRadius\n\n### RNNSetRootAnimator\nAnimates window root replacement using CABasicAnimation.\n\n## Navigation Types\n\n### Stack Navigation (RNNStackController)\n- Subclass of UINavigationController\n- Push/pop with custom animations\n- Back button customization\n- Uses StackControllerDelegate for bar delegate handling\n\n```objc\n// Extension methods\n@interface UINavigationController (RNNCommands)\n- (void)push:(UIViewController*)vc onTop:(UIViewController*)onTopVC\n     animated:(BOOL)animated completion:(void(^)(void))completion rejection:(RCTPromiseRejectBlock)rejection;\n- (void)popAnimated:(BOOL)animated completion:(void(^)(NSString*))completion rejection:(RCTPromiseRejectBlock)rejection;\n@end\n```\n\n### Bottom Tabs (RNNBottomTabsController)\n- Subclass of UITabBarController\n- Tab attachment modes: Together, OnSwitchToTab, AfterInitialTab\n- Long-press gesture support\n- Badge and dot indicator support\n\n### Side Menu (RNNSideMenuViewController)\n- Uses MMDrawerController (third-party)\n- Center, left, right child containers\n- Configurable open modes and widths\n\n### Top Tabs (RNNTopTabsViewController)\n- Custom horizontal tab implementation\n- Not based on UITabBarController\n- Manual content switching\n\n### Split View (RNNSplitViewController)\n- UISplitViewController subclass\n- Master-detail for iPad\n\n## External Components\n\n### RNNExternalComponentStore\nRegistry for native (non-React) view controllers.\n\n### RNNExternalViewController\nWraps native UIViewController for integration:\n\n```objc\n[ReactNativeNavigation registerExternalComponent:@\"NativeScreen\"\n                                       callback:^(NSDictionary *props, RCTBridge *bridge) {\n    return [[MyNativeViewController alloc] init];\n}];\n```\n\n## Key Files Reference\n\n| File | Purpose |\n|------|---------|\n| `RNNBridgeModule.h/mm` | Bridge entry point (legacy) |\n| `TurboModules/RNNTurboModule.mm` | TurboModule entry point (new arch) |\n| `TurboModules/RNNTurboCommandsHandler.mm` | TurboModule command routing |\n| `RNNCommandsHandler.h/mm` | Command execution |\n| `RNNLayoutManager.h/mm` | Controller tracking |\n| `RNNViewControllerFactory.h/mm` | Controller creation |\n| `RNNComponentViewController.h/mm` | React screen |\n| `RNNStackController.h/mm` | Stack navigation |\n| `RNNBottomTabsController.h/mm` | Tab navigation |\n| `RNNNavigationOptions.h/mm` | Options model |\n| `RNNBasePresenter.h/mm` | Presenter base |\n| `TopBarPresenter.h/mm` | Top bar styling |\n| `RNNReactView.h/mm` | React view wrapper |\n| `ScreenAnimationController.h/mm` | Custom transitions |\n\n<!-- File: src/ARCHITECTURE.md (Tokens: ~2468 | Category: project-spec) -->\n# JavaScript/TypeScript Architecture\n\nThe JavaScript layer provides the public API and orchestrates communication between React components and native navigation implementations.\n\n## Entry Point\n\n`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.\n\n## Module Structure\n\n```\nsrc/\n├── index.ts                 # Main entry point, exports Navigation singleton\n├── Navigation.ts            # NavigationRoot - core orchestrator\n├── NavigationDelegate.ts    # Public API facade\n├── adapters/                # Native bridge layer\n├── commands/                # Command processing\n├── components/              # React component management\n├── events/                  # Event system\n├── interfaces/              # TypeScript type definitions\n├── linking/                 # Deep-linking framework (URL → command)\n└── processors/              # Extensibility hooks\n```\n\n## Core Classes\n\n### NavigationDelegate (Public API)\n**File**: `NavigationDelegate.ts`\n\nFacade providing the public `Navigation` API. All methods proxy to `NavigationRoot`.\n\n```typescript\n// Usage\nimport { Navigation } from 'react-native-navigation';\nNavigation.setRoot({ root: { stack: { children: [...] } } });\n```\n\n### NavigationRoot (Core Orchestrator)\n**File**: `Navigation.ts`\n\nCoordinates all subsystems. Constructed with dependencies:\n- `NativeCommandsSender` - sends commands to native\n- `NativeEventsReceiver` - receives events from native\n- `AppRegistryService` - manages React Native component registry\n\nInitializes and coordinates:\n- `Store` - component instance & props storage\n- `ComponentRegistry` - component registration\n- `LayoutTreeParser` - converts layouts to internal nodes\n- `LayoutTreeCrawler` - processes layout trees\n- `Commands` - command execution\n- `EventsRegistry` - event subscriptions\n- `OptionsProcessor` - option processing\n- `LayoutProcessor` - layout transformations\n\n## Adapters Layer\n\nBridge between JavaScript and native/React Native APIs.\n\n| Adapter | Purpose |\n|---------|---------|\n| `NativeCommandsSender` | Wraps TurboModule for command dispatch |\n| `NativeEventsReceiver` | Wraps NativeEventEmitter for events |\n| `NativeRNNTurboModule` | TurboModule spec interface |\n| `NativeRNNTurboEventEmitter` | TurboModule event emitter spec |\n| `UniqueIdProvider` | Generates unique component/command IDs |\n| `ColorService` | Converts colors to native format |\n| `AssetResolver` | Resolves require() image assets (class: AssetService) |\n| `AppRegistryService` | Registers components with React Native |\n| `Constants` | Platform dimension constants |\n| `TouchablePreview` | 3D Touch / Haptic preview handling |\n\n## Commands Layer\n\n### Commands Class\n**File**: `commands/Commands.ts`\n\nCentral command dispatcher. Each navigation command:\n1. Validates input\n2. Processes layout through pipeline\n3. Sends to native via adapter\n4. Returns promise with result\n\n### Processing Pipeline\n\nThe pipeline executes in this exact order:\n\n```\nInput Layout (from API)\n       ↓\n1. OptionsCrawler.crawl()         # Extract static options from component classes\n       ↓\n2. LayoutProcessor.process()      # Apply registered layout processors\n       ↓\n3. LayoutTreeParser.parse()       # Convert to internal LayoutNode tree\n       ↓\n4. LayoutTreeCrawler.crawl()      # Process options, save props to Store\n       ↓\n5. OptionsProcessor (during crawl) # Resolve colors, assets, custom processors\n       ↓\n6. NativeCommandsSender           # Send to native module\n```\n\n### LayoutNode (Internal Tree)\n```typescript\ninterface LayoutNode {\n  id: string;           // Unique identifier\n  type: LayoutType;     // Component|Stack|BottomTabs|etc\n  data: {\n    name?: string;      // Component name\n    options?: any;      // Processed options\n    passProps?: any;    // Component props (cleared before native)\n  };\n  children: LayoutNode[];\n}\n```\n\n### LayoutType Enum\n```typescript\nenum LayoutType {\n  Component = 'Component',\n  Stack = 'Stack',\n  BottomTabs = 'BottomTabs',\n  SideMenuRoot = 'SideMenuRoot',\n  SideMenuCenter = 'SideMenuCenter',\n  SideMenuLeft = 'SideMenuLeft',\n  SideMenuRight = 'SideMenuRight',\n  TopTabs = 'TopTabs',\n  ExternalComponent = 'ExternalComponent',\n  SplitView = 'SplitView',\n}\n```\n\n## Components Layer\n\n### ComponentRegistry\n**File**: `components/ComponentRegistry.ts`\n\nManages React component registration and wrapping.\n\n```typescript\nNavigation.registerComponent('ScreenName', () => MyComponent);\n```\n\n### ComponentWrapper\n**File**: `components/ComponentWrapper.tsx`\n\nHigher-order component that:\n- Wraps original component with lifecycle management\n- Stores instance in `Store` for event dispatch\n- Injects `componentId` and `componentName` props\n\n### Store\n**File**: `components/Store.ts`\n\nCentralized storage for:\n- `componentsByName` - registered component providers\n- `componentsInstancesById` - mounted component instances\n- `propsById` - static props by component ID\n- `pendingPropsById` - props awaiting component mount\n- `wrappedComponents` - cached wrapped components\n- `lazyRegistratorFn` - function for lazy component registration\n\n## Events Layer\n\n### EventsRegistry\n**File**: `events/EventsRegistry.ts`\n\nPublic API for event subscriptions:\n\n```typescript\nNavigation.events().registerComponentDidAppearListener(({ componentId }) => {});\nNavigation.events().registerCommandCompletedListener(({ commandId }) => {});\n```\n\n### ComponentEventsObserver\n**File**: `events/ComponentEventsObserver.ts`\n\nDispatches events to component instance methods:\n- `componentWillAppear()`\n- `componentDidAppear()`\n- `componentDidDisappear()`\n- `navigationButtonPressed()`\n- `screenPopped()`\n\n### CommandsObserver\n**File**: `events/CommandsObserver.ts`\n\nNotifies listeners of command lifecycle (start, complete).\n\n## Events (Native → JS)\n\n| Event | Description |\n|-------|-------------|\n| `RNN.AppLaunched` | App initialization complete |\n| `RNN.ComponentWillAppear` | Component about to appear |\n| `RNN.ComponentDidAppear` | Component now visible |\n| `RNN.ComponentDidDisappear` | Component hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tapped |\n| `RNN.BottomTabPressed` | Tab pressed (even if selected) |\n| `RNN.BottomTabSelected` | Tab selection changed |\n| `RNN.BottomTabLongPressed` | Tab long-pressed |\n| `RNN.ModalDismissed` | Modal was dismissed |\n| `RNN.ModalAttemptedToDismiss` | Swipe-to-dismiss attempted |\n| `RNN.ScreenPopped` | Screen removed from stack |\n| `RNN.SearchBarUpdated` | Search text changed |\n| `RNN.SearchBarCancelPressed` | Search cancelled |\n| `RNN.PreviewCompleted` | 3D Touch preview completed |\n| `RNN.CommandCompleted` | Navigation command finished |\n\n## Linking Layer\n\nImplements URL-to-screen routing on top of the standard command pipeline. The whole feature is JS-only; it consumes URLs from RN's `Linking` module and dispatches `showModal` (or a user-supplied command) when a match is found.\n\n**Public surface** (proxied through `NavigationDelegate`):\n- `Navigation.setLinking(config)` — configure prefixes, screen map, and customization hooks\n- `Navigation.handleDeepLink(url)` — manually feed a URL (push notifications, branch.io, App Clips)\n- `Navigation.setLinkingReady(ready)` — user-controlled gate for deferred deep links\n\n**Internal modules** (`src/linking/`):\n\n| File | Purpose |\n|------|---------|\n| `LinkingHandler.ts` | Orchestrator. Subscribes to `Linking.url`/`getInitialURL`, drives the queue, dispatches matches. Instantiated by `NavigationRoot`. |\n| `URLParser.ts` | Strips prefix (longest match), removes fragment, decodes path segments + query params. |\n| `RouteMatcher.ts` | Compiles `ScreensConfig` into a `RouteNode` tree; matches paths to screen chains with parameter extraction. |\n| `DeferredLinkQueue.ts` | FIFO queue. Holds URLs until both gates open (root-ready + user-ready). |\n| `ModalLayoutBuilder.ts` | Default presentation: wraps the matched chain in a `stack`, merges params into `passProps`, filters React-reserved keys (`ref`, `key`). |\n| `types.ts` | Public types: `LinkingConfig`, `RouteMatch`, `ScreensConfig`, etc. (re-exported via `src/index.ts`). |\n\n**Readiness gates** — a URL is dispatched only when both are true:\n1. **Root-ready** (automatic): the first `Navigation.setRoot()` has resolved. `NavigationRoot.setRoot` calls `linkingHandler.setRootReady()` after the promise resolves.\n2. **User-ready** (optional): `config.isReady()` returns `true`, or `setLinkingReady(true)` was called.\n\n**Resolution priority** when a match is found:\n1. `config.onLink(match)` — full escape hatch, RNN does nothing else\n2. `config.getModal(match)` — custom modal layout\n3. Default `ModalLayoutBuilder` output\n\n## Processors Layer\n\n### OptionProcessorsStore\n**File**: `processors/OptionProcessorsStore.ts`\n\nRegisters custom option processors:\n\n```typescript\nNavigation.addOptionProcessor('topBar.title.text', (value, commandName) => {\n  return value.toUpperCase(); // Transform all titles\n});\n```\n\n### LayoutProcessorsStore\n**File**: `processors/LayoutProcessorsStore.ts`\n\nRegisters layout transformers:\n\n```typescript\nNavigation.addLayoutProcessor((layout, commandName) => {\n  // Add default options to all components\n  return layout;\n});\n```\n\n## Interfaces\n\n### Layout Types\n**File**: `interfaces/Layout.ts`\n\n```typescript\ninterface LayoutRoot {\n  root: Layout;\n  modals?: any[];\n  overlays?: any[];\n}\n\ntype Layout = {\n  component?: LayoutComponent;\n  stack?: LayoutStack;\n  bottomTabs?: LayoutBottomTabs;\n  sideMenu?: LayoutSideMenu;\n  splitView?: LayoutSplitView;\n  topTabs?: LayoutTopTabs;\n  externalComponent?: ExternalComponent;\n}\n```\n\n### Options Interface\n**File**: `interfaces/Options.ts` (comprehensive)\n\nContains all configuration options for:\n- Status bar, navigation bars\n- Top bar (buttons, title, search)\n- Bottom tabs\n- Side menus\n- Modals, overlays\n- Animations\n- Layout parameters\n\n### NavigationComponent\n**File**: `interfaces/NavigationComponent.ts`\n\nBase class for navigation-aware components:\n\n```typescript\nclass MyScreen extends NavigationComponent<Props> {\n  static options: Options = { ... };\n\n  componentDidAppear(event) { }\n  navigationButtonPressed(event) { }\n}\n```\n\n## Dependencies\n\n**Production**:\n- `lodash` - utility functions\n- `hoist-non-react-statics` - HOC support\n- `react-lifecycles-compat` - lifecycle polyfill\n- `tslib` - TypeScript helpers\n\n**Peer**:\n- `react`, `react-native` (required)\n- `remx` (optional state management)\n\n## Build Output\n\nUses `react-native-builder-bob`:\n- **Source**: `src/`\n- **Output**: `lib/`\n- **Targets**: ESM modules + TypeScript declarations\n\n<!-- File: .claude/skills/rn-version-upgrade.md (Tokens: ~5766 | Category: anthropic-skill) -->\n# Skill: Add Support for a New React Native Version\n\nThis skill guides the process of adding support for a new React Native version to react-native-navigation (RNN). It covers CI setup, dependency analysis, native code fixes, playground validation, and the version-switch infrastructure.\n\n## Prerequisites\n\nBefore starting, gather:\n- The target RN version number (e.g., `0.84.0`)\n- The previous highest supported RN version (check `package.json` and `.buildkite/pipeline.sh`)\n\n## Phase 1: Research Breaking Changes\n\n**This phase is critical and prevents most downstream failures. Do it thoroughly before writing any code.**\n\n### 1a. Read the RN Release Blog & Changelog\n\nFetch the release blog post and changelog for the target version:\n- Blog: `https://reactnative.dev/blog` (search for the version)\n- Changelog: `https://github.com/facebook/react-native/blob/main/CHANGELOG.md`\n\nFocus on:\n- **Removed APIs/classes** (iOS and Android) -- these cause compile errors\n- **Changed method signatures** (Android) -- parameters becoming non-nullable, new required params, etc. (e.g., `ColorPropConverter.getColor()` changed in 0.80)\n- **Deprecated APIs now removed** -- check if RNN uses any deprecated APIs from prior versions\n- **Architecture changes** (e.g., New Architecture enforcement, legacy arch removal)\n- **Build system changes** -- Gradle version, Android SDK levels, Kotlin version, CocoaPods/podspec changes, Xcode requirements\n- **Header/import changes** -- headers moved, renamed, or removed from precompiled binaries\n- **CocoaPods / podspec changes** -- Check if RN changed how native modules declare dependencies (e.g., the shift to `install_modules_dependencies` in 0.80). Review `ReactNativeNavigation.podspec` for hardcoded dependency lists, header search paths, or compiler flags that may need updating.\n- **Kotlin version requirements** -- Newer RN versions may require newer Kotlin versions (e.g., RN 0.79+ requires Kotlin 2.x). Check if the version needs bumping.\n\n### 1b. Check RNN's Usage of Known Risk Areas\n\nSearch the RNN codebase for any classes/headers mentioned as removed or changed:\n\n```bash\n# Search iOS for legacy RCT headers (common removal targets)\ngrep -rn \"#import <React/RCT\" ios/ --include=\"*.h\" --include=\"*.mm\" --include=\"*.m\"\n\n# Search Android for deprecated classes\ngrep -rn \"CSSBackgroundDrawable\\|onCatalystInstanceDestroy\\|ReactInstanceManager\" android/ --include=\"*.java\" --include=\"*.kt\"\n\n# Check Android test infrastructure for classes extending RN framework classes\ngrep -rn \"extends.*React\\|: React\" android/ --include=\"*.java\" --include=\"*.kt\" | grep -i \"test\\|mock\\|simple\"\n```\n\n**If the new RN version strips legacy headers from the xcframework** (look for `RCT_REMOVE_LEGACY_ARCH` changes in the RN release), identify ALL iOS files importing legacy-only headers and plan to guard them in batch. Do NOT rely on iterative build failures to find them one by one. Cross-reference each `#import <React/RCT...>` against the headers actually available in the new RN version's xcframework.\n\n### 1c. Check Third-Party Dependency Compatibility\n\nFor each playground dependency that wraps native code, verify compatibility with the target RN version:\n\n1. **react-native-reanimated** -- Check https://docs.swmansion.com/react-native-reanimated/docs/guides/compatibility/ for the compatibility table. This is the most frequent source of build failures.\n2. **react-native-gesture-handler** -- Check release notes for RN version support.\n3. **react-native-fast-image** (or `@d11/react-native-fast-image`) -- Check for Fabric/new arch support.\n4. **react-native-worklets** -- Must be compatible with the reanimated version you chose.\n5. **Other native deps** -- Check each one's GitHub releases/issues for RN version support.\n\nAlso check the full peer dependency tree: `npm info react-native@<version> peerDependencies` for all peer deps, not just `react`.\n\n**Key lesson from RN 0.84**: Reanimated 4.2.0 did NOT support RN 0.84 (needed 4.2.2+). The `react-native-worklets` package also needed bumping (0.7.1 -> 0.7.4). Not catching this early means the build will fail late in the process.\n\n**Key lesson from RN 0.83**: The original `react-native-fast-image` package was abandoned and had no Fabric support. The `@d11/react-native-fast-image` fork was needed as a replacement. When replacing a package, check ALL references: package.json (root AND playground), TypeScript imports, Android `build.gradle` manual `implementation project()` lines, and iOS pod references.\n\n## Phase 2: CI Infrastructure Setup\n\n### 2a. Maintain Buildkite CI Jobs\n\nCopy an existing job file and update the version:\n\n```bash\n# Copy from the latest supported RN lane (adjust source/target versions)\ncp .buildkite/jobs/pipeline.android_rn_84.yml .buildkite/jobs/pipeline.android_rn_85.yml\ncp .buildkite/jobs/pipeline.ios_rn_84.yml .buildkite/jobs/pipeline.ios_rn_85.yml\n```\n\nEdit both files:\n- Update the label: `\":android: Android (RN 0.84.0)\"`\n- Update `REACT_NATIVE_VERSION: 0.84.0`\n- Update the key: `\"android_rn_84\"` / `\"ios_rn_84\"`\n- Keep `JAVA_HOME` on Android jobs (check if JDK version needs bumping)\n\n### 2b. Register Jobs in Pipeline Script\n\nAdd the new jobs to `.buildkite/pipeline.sh`:\n\n```bash\ncat .buildkite/jobs/pipeline.android_rn_84.yml\ncat .buildkite/jobs/pipeline.ios_rn_84.yml\n```\n\nInsert them in version order alongside the other platform jobs. Release publishing is dispatched separately through the GitHub Actions release workflow.\n\n### 2c. Optionally Drop Old Versions\n\nIf the project drops support for an old version, remove its pipeline files and entries from `pipeline.sh`. RN 0.82 PR dropped RN 0.80 and 0.81 pipelines.\n\n## Phase 3: Update Default Versions and Build Configuration\n\n### 3a. Update `package.json` (Root and Playground)\n\nUpdate in both `/package.json` and `/playground/package.json`:\n- `react-native` to the target version\n- `react` to the matching peer dependency version (check `npm info react-native@0.84.0 peerDependencies.react`)\n- `react-test-renderer` to match react\n- `@react-native/babel-preset`, `@react-native/eslint-config`, `@react-native/metro-config`, `@react-native/typescript-config` to `0.<minor>.0`\n- `@react-native-community/cli`, `cli-platform-android`, `cli-platform-ios` to matching CLI version\n- Any third-party deps identified in Phase 1c as needing version bumps\n\n### 3b. Update Android SDK, NDK, and Kotlin Versions\n\nCheck the target RN version's requirements and update in **both** `android/build.gradle` (the library defaults) and `playground/android/build.gradle`:\n- `compileSdkVersion` / `compileSdk`\n- `targetSdkVersion` / `targetSdk`\n- `buildToolsVersion`\n- `ndkVersion`\n- Kotlin version (`kotlinVersion` / `RNNKotlinVersion`)\n\nCross-reference with the RN template app's `build.gradle` for the target version (`npx @react-native-community/cli init` or check the RN GitHub repo).\n\nAlso update `autolink/fixtures/rn79/build.gradle.template` if SDK or Kotlin versions changed there.\n\n### 3c. Update Gradle Wrapper\n\nIf the target RN requires a newer Gradle version, update `playground/android/gradle/wrapper/gradle-wrapper.properties`.\n\n### 3d. Update Version-Switch Infrastructure\n\nUpdate `scripts/versionMapping.js`:\n- Add the new minor version to `CLI_VERSION_MAP`\n- Update `getGradleVersion()` if the Gradle version requirement changed\n- Update `getReanimatedOverride()` / `shouldRemoveWorklets()` if compatibility ranges changed\n\nUpdate `playground/android/rninfo.gradle` if new version-conditional logic is needed:\n- Add new boolean flags (e.g., `isRN84OrHigher`) if Gradle build logic needs to branch on the new version\n- Used for things like Kotlin version branching and conditional dependency resolution\n\n### 3e. Review and Update Podspec and Podfile\n\n**`ReactNativeNavigation.podspec`** may need changes if RN altered how native modules declare dependencies:\n- Manual `s.dependency` lists for React submodules may be replaced by `install_modules_dependencies(s)` (happened in 0.80)\n- Hardcoded `HEADER_SEARCH_PATHS`, folly compiler flags, or per-arch dependency lists may become unnecessary\n- Compare against the new RN version's recommended podspec pattern\n\n**`playground/ios/Podfile`** may need restructuring if RN changed `use_react_native!`, new arch configuration, or post-install hooks. Compare against the RN template app's Podfile for the target version.\n\n### 3f. Install Dependencies\n\nAfter updating package.json and build configs:\n\n```bash\ncd playground && yarn install && cd ios && pod deintegrate && pod install && cd ../..\n```\n\n### 3g. Clean Stale Xcode Build Settings\n\n**Do this BEFORE the first build** -- stale settings cause mysterious \"module not found\" errors.\n\nThe `playground/ios/playground.xcodeproj/project.pbxproj` may contain hardcoded build settings from previous RN versions (e.g., `REACT_NATIVE_MINOR_VERSION=72`, stale modulemap paths in `OTHER_CFLAGS`). Search for and remove/fix these:\n\n```bash\ngrep -n \"REACT_NATIVE_MINOR_VERSION\\|REANIMATED_VERSION\\|modulemap\" playground/ios/playground.xcodeproj/project.pbxproj\n```\n\nReplace hardcoded values with `\"$(inherited)\"` where appropriate.\n\n## Phase 4: Fix Native Compilation Errors\n\n### Strategy\n\nFor **systematic, known patterns** identified in Phase 1 (like legacy import guarding across many files), fix all instances in batch before building. This avoids slow iterative build cycles.\n\nFor **unexpected errors**, use an iterative build-fix approach: build, fix the first error, rebuild, repeat.\n\n```bash\n# iOS build\nxcodebuild build -workspace playground/ios/playground.xcworkspace \\\n  -scheme playground -configuration Debug -sdk iphonesimulator \\\n  -destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' -quiet\n\n# Android build\ncd playground/android && ./gradlew assembleDebug\n```\n\n### 4a. Batch-Fix: Guard Legacy iOS Imports\n\nIf the new RN version removes legacy headers from precompiled binaries, guard ALL identified imports at once.\n\n**Preferred approach: `__has_include` (compile-time header check)**\n\nThe best way to guard optional headers is `#if __has_include(...)`. This is forward-compatible — if a future RN version removes more headers, the code adapts automatically without needing new flags:\n\n```objc\n#if __has_include(<React/RCTScrollView.h>)\n#import <React/RCTScrollView.h>\n#endif\n\n#if __has_include(<React/RCTCxxBridgeDelegate.h>)\n#import <React/RCTCxxBridgeDelegate.h>\n#endif\n```\n\nUse `__has_include` for **imports** where the header may or may not exist. Then use `NSClassFromString` (see Pattern 3 below) for runtime references to classes from those headers.\n\n**Alternative: `#ifndef RCT_REMOVE_LEGACY_ARCH`**\n\nStarting with RN 0.84, React Native defines `RCT_REMOVE_LEGACY_ARCH=1` when legacy/bridge APIs are fully removed. This is more precise than `RCT_NEW_ARCH_ENABLED` (which has been true since RN 0.76 even though legacy APIs were still available). Use this for guarding **code blocks** that use legacy APIs:\n\n```objc\n#ifndef RCT_REMOVE_LEGACY_ARCH\n#import <React/RCTModalHostViewManager.h>\n#endif\n\n// In implementation:\n#ifndef RCT_REMOVE_LEGACY_ARCH\n- (void)connectModalHostViewManager:(RCTModalHostViewManager *)manager {\n    // old-arch-only code\n}\n#endif\n```\n\n**When to use which:**\n- `__has_include(...)` — for **imports** of headers that may not exist. Most robust, no flag dependency.\n- `#ifndef RCT_REMOVE_LEGACY_ARCH` — for **code blocks** using legacy APIs (method declarations, implementations, protocol conformances). Semantically correct: \"this code requires the legacy arch.\"\n- `#ifdef RCT_NEW_ARCH_ENABLED` — only for code that differs **between architectures** (e.g., `RCTHost` vs `RCTBridge` parameters). NOT for \"is legacy available?\" checks.\n\n**Steps:**\n\n1. List all files importing legacy headers:\n   ```bash\n   grep -rn \"#import <React/RCTRootView\\|#import <React/RCTRootViewDelegate\\|#import <React/RCTBridge+Private\\|#import <React/RCTModalHostView\\|#import <React/RCTScrollView\\|#import <React/RCTRootContentView\\|#import <React/RCTSurfacePresenterStub\\|#import <React/RCTBridgeProxy\" ios/ --include=\"*.h\" --include=\"*.mm\"\n   ```\n\n2. For each file, apply the appropriate guard (prefer `__has_include` for imports, `#ifndef RCT_REMOVE_LEGACY_ARCH` for code blocks).\n\n3. **Guard the full chain**: import -> type usage -> method declarations -> protocol conformances -> method implementations. Guarding just the import without guarding the code that uses the type causes \"undeclared identifier\" errors.\n\n4. **Check for dead code in `#ifdef` blocks**: After guarding imports, search for old-arch symbols referenced in new-arch code paths:\n   ```bash\n   # Find potential dead references to bridge in new-arch blocks\n   grep -n \"getBridge\\|bridgeManager\\|RCTBridge\" ios/ --include=\"*.mm\" -r\n   ```\n   Cross-reference hits with their surrounding `#ifdef` context. Remove any new-arch code that calls old-arch-only methods.\n\n### 4b. Common iOS Fix Patterns\n\n**Pattern 1: Guard optional imports with `__has_include`** -- Preferred for headers that may not exist:\n```objc\n#if __has_include(<React/RCTSurfacePresenterBridgeAdapter.h>)\n#import <React/RCTSurfacePresenterBridgeAdapter.h>\n#endif\n```\n\n**Pattern 2: Guard legacy code blocks with `RCT_REMOVE_LEGACY_ARCH`** -- For methods/classes that only exist on old arch:\n```objc\n#ifndef RCT_REMOVE_LEGACY_ARCH\n- (void)connectModalHostViewManager:(RCTModalHostViewManager *)manager { ... }\n#endif\n```\n\n**Pattern 3: Guard entire files** -- If a file is only used on old arch (e.g., `RNNBridgeManager.h/.mm`), wrap the entire content in `#ifndef RCT_REMOVE_LEGACY_ARCH`.\n\n**Pattern 4: Runtime class lookup** -- When you need to reference a class that may not exist at compile time (e.g., in `hitTest:withEvent:` or `isKindOfClass:` checks), use `NSClassFromString` instead of direct class references. This pairs well with `__has_include` — the import is conditional, and the runtime check handles the case where the class doesn't exist:\n\n```objc\n// Instead of: [view isKindOfClass:[RCTModalHostView class]]\n[view isKindOfClass:NSClassFromString(@\"RCTModalHostView\")]\n```\n\nCache the result with `dispatch_once` if it's in a hot path:\n```objc\nstatic Class myClass;\nstatic dispatch_once_t onceToken;\ndispatch_once(&onceToken, ^{\n    myClass = NSClassFromString(@\"RCTModalHostView\");\n});\n```\n\n**Pattern 5: Remove dead code paths** -- A `#ifdef RCT_NEW_ARCH_ENABLED` block that calls `getBridge` (old-arch only) is dead code -- remove it.\n\n**Pattern 6: Protocol conformance guards** -- If a protocol (e.g., `RCTRootViewDelegate`) only exists on old arch, guard the conformance declaration AND the delegate method implementations:\n\n```objc\n@interface MyView : UIView\n#ifndef RCT_NEW_ARCH_ENABLED\n                    <RCTRootViewDelegate>\n#endif\n```\n\n### 4c. Common Android Fix Patterns\n\n**Pattern 1: Deprecated method migration** -- When RN deprecates methods with `forRemoval = true`, rename to the replacement (e.g., `onCatalystInstanceDestroy()` -> `invalidate()`). Note: only rename the RN framework override, not internal RNN methods with the same name.\n\n**Pattern 2: Removed classes** -- When Android classes are removed (e.g., `CSSBackgroundDrawable` in RN 0.83), replace with standard Android equivalents (e.g., `ColorDrawable`).\n\n**Pattern 3: Test infrastructure** -- Test/mock classes that extend RN framework classes (e.g., `SimpleView extends ReactView`) may need refactoring if the parent class behavior changed. Also check Robolectric version compatibility -- newer Android SDK levels may require bumping Robolectric, and if the new Robolectric version requires a higher Java version than CI provides, add a `robolectric.properties` file to pin the SDK level (e.g., `sdk=35` when SDK 36 requires Java 21 but CI uses Java 17).\n\n**Pattern 4: Changed method signatures** -- RN may change method signatures without deprecation (e.g., nullable parameters becoming non-nullable, or new required parameters). These cause compile errors that aren't caught by searching for removed/deprecated APIs. Check the RN changelog for API changes in utility classes like `ColorPropConverter`, `ColorParser`, etc.\n\n### 4d. Research Before Fixing: Don't Just Pattern-Match\n\n**When you hit a new compilation error, resist the urge to immediately copy the fix pattern from nearby code.** Instead:\n\n1. **Check what the target RN version introduces.** Read the RN changelog/blog for new preprocessor flags, build system features, or recommended migration patterns. For example, RN 0.84 introduced `RCT_REMOVE_LEGACY_ARCH` — a flag specifically designed for the exact guarding problem we need to solve. Using it is better than repurposing `RCT_NEW_ARCH_ENABLED`.\n\n2. **Search for how other RN libraries solved it.** Check how major community libraries (react-native-screens, react-native-reanimated, react-native-gesture-handler) handle the same compatibility issue. They often discover better patterns first.\n\n3. **Evaluate the existing codebase pattern critically.** The pattern used in the current code may predate better alternatives. Ask: is there a more forward-compatible approach? Would `__has_include` be more robust than a flag check? Would `NSClassFromString` be cleaner than a compile-time guard?\n\n4. **Prefer compile-time safety over runtime safety, and standard compiler features over framework-specific flags.** `__has_include` is a C/ObjC compiler feature that works regardless of RN version. Framework flags like `RCT_REMOVE_LEGACY_ARCH` are next best. `NSClassFromString` is a runtime fallback for when compile-time checks aren't sufficient.\n\n### 4e. Compile Error Triage\n\nWhen you get a compile error:\n1. Identify the missing symbol (header, class, method)\n2. **Research** the best available guard mechanism (see 4d above)\n3. Check if it's used only in old-arch or new-arch code paths\n4. If old-arch only: guard with `__has_include` (imports) or `#ifndef RCT_REMOVE_LEGACY_ARCH` (code)\n5. If new-arch only: this shouldn't happen -- investigate the API replacement\n6. If used in both: find the new-arch equivalent and branch with `#ifdef RCT_NEW_ARCH_ENABLED`\n\n### 4e. Fix Test Files\n\n**Test files are easily overlooked.** They often reference arch-specific APIs (like `RCTBridge` vs `RCTHost`, or methods that only exist under `#ifdef RCT_NEW_ARCH_ENABLED`). Check all test files for arch-specific calls:\n\n```bash\n# Find test files referencing RCTBridge (old-arch only in new-arch builds)\ngrep -rn \"RCTBridge\\|registerExternalComponent\" playground/ios/NavigationTests/ --include=\"*.mm\"\n\n# Check that test method calls match the current header signatures\n# e.g., RNNExternalComponentStore exposes different methods under #ifdef RCT_NEW_ARCH_ENABLED\n```\n\nGuard test code the same way as production code — use `#ifndef RCT_REMOVE_LEGACY_ARCH` for tests that only apply to legacy arch:\n\n```objc\n#ifndef RCT_REMOVE_LEGACY_ARCH\n\n@interface RNNModalHostViewManagerHandlerTest : XCTestCase\n@end\n// ... entire test class ...\n@end\n\n#endif\n```\n\n**Key lesson from RN 0.84**: All 4 iOS CI jobs failed because a single test file (`RNNViewControllerFactoryTest.mm`) called an old-arch method on `RNNExternalComponentStore` without a guard. The fix was trivial but blocked the entire build.\n\n### 4f. clang-format\n\nRNN uses clang-format on iOS files via a pre-commit hook. After editing `.h`/`.mm` files, verify formatting:\n\n```bash\n./node_modules/.bin/git-clang-format --diff -- ios/MyFile.mm\n```\n\nThe formatter has opinions about `#ifdef` indentation that may require unusual formatting (e.g., protocol conformance on a continuation line after `#ifndef`).\n\n## Phase 5: Validate Playground Dependencies\n\n### 5a. Check for Stale References\n\nAfter replacing any dependency (like fast-image -> @d11/fast-image), search for ALL references:\n\n```bash\n# TypeScript imports\ngrep -r \"react-native-fast-image\" playground/src/ --include=\"*.ts\" --include=\"*.tsx\"\n\n# Android gradle -- look for manual implementation project() lines\ngrep -r \"fast-image\\|fast_image\" playground/android/ --include=\"*.gradle\"\n\n# iOS podfile\ngrep -r \"fast-image\\|FastImage\" playground/ios/Podfile\n```\n\nNote: `autolinkLibrariesWithApp()` in the playground's `build.gradle` handles most deps automatically. Manual `implementation project(':...')` lines are often stale and should be removed when the package is autolinked.\n\n## Phase 6: Full Build Verification\n\nRun both platform builds to confirm everything compiles:\n\n```bash\n# iOS\nxcodebuild build -workspace playground/ios/playground.xcworkspace \\\n  -scheme playground -configuration Debug -sdk iphonesimulator \\\n  -destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' -quiet\n\n# Android\ncd playground/android && ./gradlew assembleDebug\n\n# JS tests\nyarn test-js\n```\n\n## Phase 7: Backward Compatibility\n\nVerify that the version-switch script works for older supported versions:\n\n```bash\nREACT_NATIVE_VERSION=0.83.0 node scripts/changeReactNativeVersion.js\n# Then rebuild to verify\n```\n\n## Phase 8: Documentation\n\nUpdate `website/docs/docs/docs-Installing.mdx`:\n- Update the supported RN version range\n- Note any breaking changes users need to be aware of\n\n## Common Pitfalls (Lessons Learned)\n\n1. **Don't assume deps are compatible** -- Always check third-party native dep compatibility tables BEFORE starting the build. Reanimated is the most common offender.\n\n2. **Search for ALL references when replacing a package** -- TypeScript imports, Android gradle `implementation project()` lines, iOS pod references, root AND playground package.json. Missing one causes CI failures.\n\n3. **Legacy headers in precompiled binaries** -- When RN enforces new arch by default (like 0.84 with `RCT_REMOVE_LEGACY_ARCH=1`), headers for old-arch classes are stripped from the xcframework. Use `__has_include` for conditional imports and `#ifndef RCT_REMOVE_LEGACY_ARCH` for code blocks. Batch-fix all legacy imports identified in Phase 1b rather than finding them one build at a time.\n\n4. **Guard code, not just imports** -- Guarding an import without guarding the code that uses the imported types leads to \"undeclared identifier\" errors. Always guard the full chain: import -> type usage -> method declarations -> method implementations.\n\n5. **Dead code in `#ifdef` blocks** -- When splitting code paths between old/new arch, check that each path only references symbols available in that architecture. A common bug is new-arch code calling old-arch-only methods (like `getBridge` in a `#ifdef RCT_NEW_ARCH_ENABLED` block).\n\n6. **Stale Xcode project settings** -- The `.pbxproj` file can accumulate hardcoded build flags from old versions. These cause mysterious \"module not found\" errors. Check for stale `OTHER_CFLAGS` BEFORE the first build (Phase 3g).\n\n7. **clang-format surprises** -- The formatter enforces specific indentation around preprocessor directives. Run the check before committing to avoid hook failures.\n\n8. **Batch-fix systematic patterns, iterate on surprises** -- When you identify a pattern that affects many files (like legacy import guarding), fix all instances at once. Use iterative build-fix only for unexpected or one-off errors.\n\n9. **Android SDK level cascading effects** -- Bumping `compileSdkVersion`/`targetSdkVersion` can require bumping Robolectric, which may require a higher Java version than CI provides. Solution: pin the Robolectric SDK via `robolectric.properties` (e.g., `sdk=35` when SDK 36 needs Java 21).\n\n10. **Podspec can be a major effort** -- Don't underestimate podspec changes. RN 0.80 required replacing the entire dependency declaration strategy. Compare your podspec against the RN template's pattern for the target version.\n\n11. **Don't forget test files** -- Test files (`NavigationTests/*.mm`) often call arch-specific APIs directly. When guarding production code, search test files for the same APIs and guard them too. A single unguarded test call can fail the entire CI build across all RN versions.\n\n12. **Don't just follow existing patterns — research better ones** -- When fixing a compilation error, don't blindly copy the guarding pattern already used in the codebase. The existing pattern may predate better alternatives introduced in newer RN versions. For example, RN 0.84 introduced `RCT_REMOVE_LEGACY_ARCH` and the codebase already supported `__has_include`, but initial fixes used the older `#ifdef RCT_NEW_ARCH_ENABLED` pattern because that's what the existing code used. Always check: what new preprocessor flags or build-system features does the target RN version introduce? Is there a more robust/forward-compatible way to solve this?\n\n<!-- File: .claude/skills/rnn-codebase/SKILL.md (Tokens: ~2083 | Category: anthropic-skill) -->\n---\nname: rnn-codebase\ndescription: Navigate and work with the react-native-navigation (RNN) codebase. Use when fixing bugs, adding features, tracing command flows, understanding options resolution, or working across JS/iOS/Android layers in this repo.\n---\n\n# React Native Navigation Codebase\n\n## Architecture Overview\n\nRNN has three layers that mirror each other:\n\n```\nJS/TS (src/)  →  TurboModule bridge  →  iOS native (ios/)\n                                     →  Android native (android/)\n```\n\nA navigation command (e.g. `push`) flows:\n1. `Navigation.push()` → `Commands.ts` → processing pipeline → `NativeCommandsSender.ts`\n2. TurboModule: `RNNTurboModule` (iOS) / `NavigationTurboModule.kt` (Android)\n3. iOS: `RNNCommandsHandler` → `RNNViewControllerFactory` → UIKit controllers\n4. Android: `Navigator` → `LayoutFactory` → View-based controllers (no Fragments)\n\nRead [ARCHITECTURE.md](../../ARCHITECTURE.md) for the full overview.\n\n## Key Cross-Layer Mappings\n\n### Layout Types → Native Controllers\n\n| JS Layout Type | iOS Controller | Android Controller |\n|----------------|---------------|-------------------|\n| `component` | `RNNComponentViewController` | `ComponentViewController` |\n| `stack` | `RNNStackController` (UINavigationController) | `StackController` |\n| `bottomTabs` | `RNNBottomTabsController` (UITabBarController) | `BottomTabsController` |\n| `sideMenu` | `RNNSideMenuViewController` (MMDrawerController) | `SideMenuController` (DrawerLayout) |\n| `topTabs` | `RNNTopTabsViewController` | `TopTabsController` (ViewPager) |\n| `splitView` | `RNNSplitViewController` | N/A (iOS only) |\n| `externalComponent` | `RNNExternalViewController` | `ExternalComponentViewController` |\n\n### Options → Presenters\n\nEach controller type has a Presenter that applies options to views:\n\n| iOS Controller | iOS Presenter | Android Presenter |\n|----------------|--------------|-------------------|\n| `RNNComponentViewController` | `RNNComponentPresenter` | `ComponentPresenter` |\n| `RNNStackController` | `RNNStackPresenter` + `TopBarPresenter` | `StackPresenter` |\n| `RNNBottomTabsController` | `RNNBottomTabsPresenter` | `BottomTabsPresenter` |\n| `RNNSideMenuViewController` | `RNNSideMenuPresenter` | `SideMenuPresenter` |\n\n### Events (same names both platforms)\n\n| Event | Trigger |\n|-------|---------|\n| `RNN.ComponentDidAppear` | Screen becomes visible |\n| `RNN.ComponentDidDisappear` | Screen hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tap |\n| `RNN.BottomTabSelected` | Tab changed |\n| `RNN.ModalDismissed` | Modal dismissed |\n| `RNN.ScreenPopped` | Screen popped from stack |\n| `RNN.CommandCompleted` | Any command finished |\n\n## Where to Find Things\n\n### By task: \"I need to fix/change X\"\n\n| Task | JS File(s) | iOS File(s) | Android File(s) |\n|------|-----------|------------|----------------|\n| Command execution | `src/commands/Commands.ts` | `ios/RNNCommandsHandler.mm` | `react/NavigationTurboModule.kt` |\n| Layout creation | `src/commands/LayoutTreeParser.ts` | `ios/RNNViewControllerFactory.mm` | `options/LayoutFactory.java` |\n| Options processing | `src/commands/OptionsProcessor.ts` | `ios/RNNNavigationOptions.mm` | `options/Options.java` |\n| Options application | — | `ios/*Presenter.mm` | `viewcontrollers/*Presenter.java` |\n| TopBar | `src/interfaces/Options.ts` (TopBarOptions) | `ios/TopBarPresenter.mm`, `ios/RNNUIBarButtonItem.mm` | `views/stack/topbar/` |\n| Bottom tabs | `src/interfaces/Options.ts` (BottomTabsOptions) | `ios/RNNBottomTabsPresenter.mm` | `viewcontrollers/bottomtabs/` |\n| Modals | `src/commands/Commands.ts` | `ios/RNNModalManager.mm` | `viewcontrollers/modal/ModalStack.java` |\n| Overlays | `src/commands/Commands.ts` | `ios/RNNOverlayManager.mm` | `viewcontrollers/overlay/OverlayManager.kt` |\n| Animations | `src/interfaces/Options.ts` (AnimationOptions) | `ios/ScreenAnimationController.mm` | `viewcontrollers/stack/StackAnimator.kt` |\n| React view rendering | — | `ios/RNNReactView.mm` | `react/ReactView.java` |\n| Events to JS | `src/adapters/NativeEventsReceiver.ts` | `ios/RNNEventEmitter.mm` | `react/events/EventEmitter.java` |\n| Component registration | `src/components/ComponentRegistry.ts` | — | — |\n| Deep linking (URL → screen) | `src/linking/` (`LinkingHandler`, `URLParser`, `RouteMatcher`, `DeferredLinkQueue`, `ModalLayoutBuilder`) | `ios/RNNAppDelegate.mm` (`dispatchDeepLinkURL:`, cold-start queue, `RCTContentDidAppearNotification`) | `NavigationActivity.onNewIntent` → `ReactGateway` |\n\n### By directory\n\n- **`src/`** — JS public API, commands, processing pipeline. See [src/ARCHITECTURE.md](../../src/ARCHITECTURE.md)\n- **`ios/`** — All Obj-C/C++ native code. See [ios/ARCHITECTURE.md](../../ios/ARCHITECTURE.md)\n- **`ios/TurboModules/`** — New architecture entry points (`RNNTurboModule`, `RNNTurboManager`, `RNNTurboCommandsHandler`)\n- **`android/src/main/java/com/reactnativenavigation/`** — All Java/Kotlin native code. See [android/ARCHITECTURE.md](../../android/ARCHITECTURE.md)\n- **`playground/`** — Demo app for development and E2E tests\n- **`playground/src/screens/`** — Test screens exercising every feature\n- **`playground/e2e/`** — Detox E2E tests\n\n## Options Resolution Order\n\nOptions are applied in ascending priority:\n1. Default options (from `Navigation.setDefaultOptions()`) — lowest priority\n2. Static options (from component class or `Navigation.registerComponent`)\n3. Options passed in the layout call (e.g. `push`, `setRoot`)\n4. `mergeOptions()` — runtime override, highest priority\n\n## JS Processing Pipeline (exact order)\n\n```\nAPI layout → OptionsCrawler.crawl() → LayoutProcessor.process()\n  → LayoutTreeParser.parse() → LayoutTreeCrawler.crawl()\n  → OptionsProcessor (colors, assets, custom) → NativeCommandsSender\n```\n\n## iOS Patterns\n\n- All controllers conform to `RNNLayoutProtocol`\n- `RNNBasePresenter` subclasses apply options — `applyOptionsOnInit:`, `applyOptions:`, `mergeOptions:resolvedOptions:`\n- Commands run on main thread (`RCTExecuteOnMainQueue`)\n- React views: `RNNReactView` wraps `RCTSurfaceHostingView` (new arch)\n- Overlays use separate `UIWindow` instances (`RNNOverlayWindow`)\n- `RNNReactComponentRegistry` caches React component instances\n\n## Android Patterns\n\n- View-based, NOT Fragment-based\n- All commands dispatched via `UiThread.post()`\n- `ViewController<T extends ViewGroup>` is the base — `createView()` is abstract\n- `ParentController` extends `ChildController` extends `ViewController`\n- Bottom tabs use `AHBottomNavigation` library\n- Three root layouts in `NavigationActivity`: rootLayout, modalsLayout, overlaysLayout\n- Tab attachment modes: `Together`, `OnSwitchToTab`, `AfterInitialTab`\n\n## Development Workflow\n\n### Playground app\n- `yarn start` — Metro bundler\n- `yarn xcode` — Open iOS project\n- `yarn studio` — Open Android project\n- `yarn pod-install` — Install iOS pods\n\n### Testing\n- `yarn test-js` — Jest unit tests\n- `yarn test-unit-ios` — iOS native unit tests (XCTest)\n- `yarn test-unit-android` — Android native unit tests (JUnit + Robolectric)\n- `yarn test-e2e-ios-ci` / `yarn test-e2e-android-ci` — Detox E2E tests\n\n### Building\n- `yarn prepare` — Builds `src/` → `lib/` (ESM + types)\n- Codegen config: `rnnavigation` in `package.json`\n\n## Common Gotchas\n\n- iOS uses UIKit subclasses (UINavigationController, UITabBarController); Android uses custom View hierarchy\n- `splitView` is iOS-only\n- Side menu: iOS uses MMDrawerController (3rd party); Android uses DrawerLayout (native)\n- Options that exist in JS types may not be implemented on both platforms — check the presenter\n- `passProps` are stored in JS `Store`, not sent to native (cleared before bridge crossing)\n- The `lib/` folder is generated — never edit it, edit `src/` instead\n- Deep links are processed only after the first `setRoot()` resolves; pre-bridge URLs on iOS are queued natively in `RNNAppDelegate` and flushed on `RCTContentDidAppearNotification` (bridgeless mode — `RCTJavaScriptDidLoadNotification` does NOT fire)\n- `ModalLayoutBuilder` strips React-reserved keys (`ref`, `key`) from URL query params before they reach `passProps`, to avoid React 19 ref-validation crashes\n\n<!-- File: .cursor/skills/engine-e2e/SKILL.md (Tokens: ~1237 | Category: anthropic-skill) -->\n---\nname: engine-e2e\ndescription: Run Wix Engine (mobile-apps-engine) iOS E2E tests locally to validate RNN changes. Use when you need to test RNN fixes against the Engine's Detox test suite.\n---\n\n# Running Engine E2E Tests Against Local RNN Changes\n\nThe Engine app (`@wix/wix-one-app-engine`) in `~/Documents/mobile-apps-engine` consumes RNN\nfrom `node_modules/react-native-navigation`. To test RNN changes against the Engine's E2E\nsuite, you patch the Engine's copy of RNN, rebuild the native binary, and run the tests.\n\n## Prerequisites\n\n- Node via nvm (`nvm use default`)\n- The `CI` env var must be **unset** (not `0`, fully unset) to avoid CI-specific codepaths.\n  Use `env -u CI` before every command.\n- The Engine repo at `~/Documents/mobile-apps-engine` with `yarn install` already done.\n\n## Step 1: Patch RNN in Engine's node_modules\n\nApply your RNN source changes to the corresponding files under:\n```\n~/Documents/mobile-apps-engine/node_modules/react-native-navigation/ios/\n```\nThe directory structure mirrors the RNN repo's `ios/` folder exactly.\n\n## Step 2: Rebuild the iOS Native Binary\n\n```bash\ncd ~/Documents/mobile-apps-engine\nunset PREFIX && . ~/.nvm/nvm.sh > /dev/null && nvm use default > /dev/null\nenv -u CI yarn workspace @wix/mobile-apps-engine-native-builds build-local-ios\n```\n\nThis runs `xcodebuild` with `-quiet` flag — expect no output until it finishes.\nTakes ~10-15 minutes on M-series Macs.\n\nThe build output (`.app` bundle) lands in:\n```\npackages/native/mobile-apps-engine-native-builds/dist/binaries.json\n```\n\n### Troubleshooting Build\n\n- **Keychain error** (`SecKeychainUnlock`): The `CI` env var is set. Use `env -u CI`.\n- **Signing errors**: Expected for local builds — the script handles ad-hoc signing.\n\n## Step 3: Build JS Bundles (first time only)\n\nThese are needed once per checkout. Skip if already built.\n\n```bash\nenv -u CI yarn workspace @wix/mobile-apps-engine-extra-bundle local:build\nenv -u CI yarn workspace @wix/mobile-apps-dependencies local:build\n```\n\n## Step 4: Run E2E Tests\n\n```bash\ncd ~/Documents/mobile-apps-engine\nunset PREFIX && . ~/.nvm/nvm.sh > /dev/null && nvm use default > /dev/null\nenv -u CI yarn workspace @wix/wix-one-app-engine test:e2e:ios -w d <suite_files...>\n```\n\nThe `-w d` flag selects the Detox worker count.\n\n### Specific suites relevant to RNN\n\n| Suite file | What it tests |\n|-----------|---------------|\n| `e2e/suites/ExternalLinks.test.js` | Deep link navigation, back button |\n| `e2e/suites/ExternalLinksModes.test.js` | Deep link modes (pop to root, tab switch) |\n| `e2e/suites/ExternalLinksPushNotifications.test.js` | Push notification deep links |\n| `e2e/suites/ExtenalLinksWithSiteSelect.test.js` | Deep links with site selection |\n| `e2e/suites/EngineUIComponents.test.js` | Error screen, UI components |\n| `e2e/suites/LaunchArgs.test.js` | Launch arguments |\n| `e2e/suites/LazyModules.test.js` | Lazy-loaded modules |\n\n### Example: Run the deep-link suites\n\n```bash\nenv -u CI yarn workspace @wix/wix-one-app-engine test:e2e:ios -w d \\\n  e2e/suites/ExternalLinks.test.js \\\n  e2e/suites/ExternalLinksModes.test.js \\\n  e2e/suites/ExternalLinksPushNotifications.test.js\n```\n\n### Troubleshooting Tests\n\n- **`Error: No dist version found`**: The native build hasn't run or failed.\n  Run step 2 again.\n- **`Cannot find module .../mobile-apps-engine-extra-bundle/index.js`**:\n  Run step 3 (`local:build` for extra-bundle).\n- **`ENOENT .../metadata.json`**: Run step 3 (`local:build` for mobile-apps-dependencies).\n- **`Unable to resolve module @rozenite/...`**: The Rozenite plugin import is broken.\n  Patch `packages/wix-one-app-engine/src/rozenitePlugin/helper/rozenite-network-inspector.ts`\n  to make the import optional with a no-op fallback.\n- **Tests time out on `navigateBack()`**: The `navigateBack()` helper taps\n  `element(by.id('pop'))` on iOS. This relies on RNN's `setBackButtonTestID` working\n  correctly. If the back button's view hierarchy changed (e.g., iOS 26 Liquid Glass),\n  the testID isn't applied and the element can't be found.\n\n## Key Engine Files\n\n| File | Purpose |\n|------|---------|\n| `packages/wix-one-app-engine/e2e/helpers/utils.js` | Test helpers including `navigateBack()` |\n| `packages/wix-one-app-engine/demo-modules/deep-links/module.js` | Deep link route definitions |\n| `packages/wix-one-app-engine/demo-modules/deep-links/Screens.js` | Deep link screen components |\n| `packages/wix-one-app-engine/internalScripts/test-e2e.js` | E2E test runner script |\n| `packages/native/mobile-apps-engine-native-builds/local_build_scripts/build_ios.js` | Local iOS build script |\n\n<!-- File: .cursor/skills/ios26-navigation/SKILL.md (Tokens: ~7785 | Category: anthropic-skill) -->\n---\nname: ios26-navigation\ndescription: Reference for iOS 26 navigation bar, tab bar, toolbar, and Liquid Glass building blocks (UITab, scroll-edge effects, search placement, shared-background platter, UIButton glass configurations, UIGlassEffect / UIGlassContainerEffect, UINavigationItem.style navigator/browser/editor, UICornerConfiguration / concentric corners, UISheetPresentationController, SF Symbols 7) plus the internal view hierarchy of UIBarButtonItem and UIToolbar, and how react-native-navigation maps to all of it. Use when adding or fixing iOS 26 behavior in RNN's top bar, bottom tabs, bar buttons, toolbar, modals, or any glass-styled custom chrome; when investigating iOS 26-only regressions; or when deciding how to expose a new iOS 26 capability through RNN options.\n---\n\n# iOS 26 Navigation in RNN\n\n## When this applies\n\nUse this skill any time work touches:\n- Top bar / navigation bar appearance, buttons, titles, or search\n- Bottom tab bar appearance, items, badges, or layout\n- Toolbar items or bar button styling\n- Any `@available(iOS 26.0, *)` branch\n- iOS 26-only bugs (Liquid Glass clipping, tab bar floating, button platter, scroll-edge effects)\n\nPair this with `rnn-codebase` (repo navigation) and `rnn-e2e-runner` (validation).\n\n## Build configuration\n\n- **Always Release** for verification — see workspace rule `rnn-build-release.mdc`. Debug masks iOS 26 layout/transition issues.\n- Xcode 26.1 toolchain: `DEVELOPER_DIR=/Applications/Xcode_26.1.app/Contents/Developer`\n- Simulator: `iPhone 17 Pro Max` (iOS 26 default)\n- Do **not** disable Fabric / New Architecture (user rule).\n- Compatibility opt-out flag: `UIDesignRequiresCompatibility` in `Info.plist`. RNN reads it in `RNNReactButtonView.designRequiresCompatibility` to fall back to pre-iOS-26 layout. Always honor it in new iOS 26 code paths.\n\n---\n\n## Apple iOS 26 API map\n\n### 1. Liquid Glass material\nThe system bar material on `UINavigationBar`, `UITabBar`, `UIToolbar` is **always translucent / glass** by default. `configureWithOpaqueBackground` is silently overlaid with glass unless you also nil out `backgroundEffect`.\n\n- `UIBarAppearance.backgroundEffect = nil` — required to actually get an opaque/transparent fill on iOS 26.\n- `UITabBarAppearance` / `UINavigationBarAppearance` / `UIToolbarAppearance` — same `backgroundEffect` rule.\n- Apple HIG: [Adopt Liquid Glass](https://developer.apple.com/design/human-interface-guidelines/materials)\n- WWDC25: \"What's new in UIKit\", \"Build a UIKit app with the new design\"\n\n**RNN handling:**\n- `ios/BottomTabsAppearancePresenter.mm`: branches on iOS 26 — uses `configureWithTransparentBackground` + `backgroundEffect=nil` + sets `tabBar.backgroundColor`. Pre-26 uses `configureWithOpaqueBackground`.\n- `ios/TopBarAppearancePresenter.mm`: same pattern for the navigation bar.\n\n### 2. Floating tab bar + drawBehind default\nThe tab bar floats above content on iOS 26 instead of pushing it up. Content underneath needs to extend.\n\n- Tab bar no longer occupies layout space the same way; `safeAreaInsets.bottom` increases for content.\n- Default `drawBehind` should be `YES` on iOS 26.\n\n**RNN handling:**\n- `ios/RNNBottomTabsOptions.mm` (`-shouldDrawBehind`): defaults `drawBehind` to `YES` on iOS 26, `NO` otherwise.\n- `ios/RNNBottomTabsController.mm`: `rnn_cycleAllTabsThenRestoreInitialSelection` — iOS 26 first-layout bug where tab item titles get misplaced; cycle selection in `viewDidAppear` to force a correct layout. Gated by `_rnnDidApplyInitialTabBarSelectionFix`.\n\n### 3. UITab / UITabBarController.tabs (iOS 18+, expanded in 26)\nModern tab API replaces `viewControllers` with `tabs: [UITab]`. Supports `UITabGroup`, `UISearchTab`, and `UITabBarController.mode = .tabSidebar`.\n\n- `UITab(title:image:identifier:viewControllerProvider:)` — lazy VC creation per tab.\n- `UITabBarController.tabs` — array of `UITab`, can mix `UITab` and `UITabGroup`.\n- `UITabBarController.mode` — `.tabBar` (default) vs `.tabSidebar` (iPad sidebar).\n- `UISearchTab` — first-class search tab, integrates with `UINavigationItem` search.\n- `UITabBarController.sidebarLayoutPreferences` — iPad sidebar customization.\n- `UITabBarController.tabBarPlacement` — `.automatic`, `.bottom`, `.top` (iPadOS 26 can pin the tab bar at the top of the window).\n- Programmatic transitions between sidebar and tab bar layouts via animating `mode` changes inside `UIView.animate`.\n- Apple: [UITabBarController.tabs](https://developer.apple.com/documentation/uikit/uitabbarcontroller/tabs), [UITab](https://developer.apple.com/documentation/uikit/uitab), [UITabGroup](https://developer.apple.com/documentation/uikit/uitabgroup)\n\n**RNN handling:** RNN currently uses the legacy `viewControllers` API. There is **no** `UITab` / `tabs` adoption yet. New iOS 26 tab features (sidebar mode, search tab, groups, top placement) would need a new code path in `RNNBottomTabsController` and corresponding `Options.ts` surface.\n\n### 4. UITabBarController.bottomAccessory\nPersistent floating mini-control attached above the tab bar (e.g., Apple Music's now-playing bar).\n\n- `UITabBarController.bottomAccessory: UITabAccessory?`\n- `UITabAccessory(contentView:)` — wraps a UIView.\n- Apple: [UITabAccessory](https://developer.apple.com/documentation/uikit/uitabaccessory)\n\n**RNN handling:** Not yet exposed. Would need a new option (e.g., `bottomTabs.accessory: { component: { name, ... } }`) and a presenter to mount a React view inside a `UITabAccessory`.\n\n### 5. Scroll-edge appearance and effects\niOS 26 makes `scrollEdgeAppearance` matter more (the bar fades to transparent when scrolled to the top). New `scrollEdgeEffect` on `UINavigationItem` controls the effect.\n\n- `UINavigationItem.scrollEdgeEffect` — controls the fading/glass effect at scroll edges.\n- `UINavigationBar.scrollEdgeAppearance` — appearance when at the scroll edge.\n- `UITabBar.scrollEdgeAppearance` — same for tab bar.\n- Apple: [UIScrollEdgeEffect](https://developer.apple.com/documentation/uikit/uiscrolledgeeffect) (iOS 26)\n\n**RNN handling:**\n- `scrollEdgeAppearance` exposed via top bar options — see `website/docs/api/options-scrollEdgeAppearance.mdx`.\n- iOS 26 `scrollEdgeEffect` added in PR #8281 (`Add scrollEdgeEffect option`).\n- Title customization on scroll edge: PRs #8207, #8239.\n\n### 6. Search bar placement (UINavigationItemSearchBarPlacement)\niOS 26 introduces three placements:\n\n- `UINavigationItemSearchBarPlacementStacked` — under the title, classic.\n- `UINavigationItemSearchBarPlacementIntegrated` — inline with the title bar, expanded.\n- `UINavigationItemSearchBarPlacementIntegratedButton` — collapsed to a button until tapped.\n\nProperty: `UINavigationItem.preferredSearchBarPlacement`. Availability-gated, not present pre-iOS-26.\n\n**RNN handling:**\n- `ios/RNNSearchBarPlacement.mm` / `.h` — JS-facing enum.\n- `ios/UIViewController+RNNOptions.mm` (`setSearchBar...`): maps RNN's `SearchBarPlacementIntegrated` to integrated or integrated-button depending on `focus`. Falls through to stacked otherwise.\n- PR #8211 — skip integrated placement when not available (pre-26 safety).\n\n### 7. Shared background (\"Platter\") on bar button items\niOS 26 wraps every `UIBarButtonItem` in a shared Liquid Glass platter. Custom views and pre-styled `UIButton`s get double-decorated.\n\n- `UIBarButtonItem.hidesSharedBackground: Bool` — opt out of the platter.\n- Custom views need a fixed bar-item size (44pt) so the navbar reserves the slot before React mounts the content; otherwise the navbar relayouts after mount and the custom view snaps into place.\n\n**RNN handling:**\n- `ios/RNNUIBarButtonItem.mm`: defaults `hidesSharedBackground = YES` on iOS 26 for both icon buttons and custom (React) view buttons. Pins custom view to 44x44.\n- `ios/RNNReactButtonView.mm`: width/height constraints + center translation post-mount to keep the React view aligned inside the reserved 44pt slot.\n- New option: `RNNButtonOptions.hideSharedBackground` (also on `RNNBackButtonOptions`) — see `src/interfaces/Options.ts`.\n- PR #8300 — centering fix.\n\n### 7a. `UIBarButtonItemGroup` factory APIs and prominent style (iOS 26)\n\niOS 26 added direct factories on `UIBarButtonItem` that build groups inline. These are the cleanest way to make the shared platter intentional rather than relying on UIKit's implicit clustering.\n\n```\nUIBarButtonItem.creatingFixedGroup() -> UIBarButtonItemGroup\nUIBarButtonItem.creatingMovableGroup(customizationIdentifier:) -> UIBarButtonItemGroup\nUIBarButtonItem.creatingOptionalGroup(customizationIdentifier:isInDefaultCustomization:) -> UIBarButtonItemGroup\n```\n\nPlus a new style:\n\n- `UIBarButtonItem.style = .prominent` — primary-action styling, tints the platter with the bar's `tintColor` at full saturation. Use sparingly (one prominent item per bar).\n\nWhen grouping is intentional, UIKit renders the group under a single `_UIBarItemGroupPlatter` (see §7b/§9) instead of one platter per item. `hidesSharedBackground` still applies per item, so you can mix glassed and bare items inside one group.\n\n**RNN handling:** Not exposed today. If a future option models a logical action cluster, build it as a `UIBarButtonItemGroup` rather than a sequence of items so the platter coalesces correctly.\n\nReferences:\n- [`UIBarButtonItemGroup`](https://developer.apple.com/documentation/uikit/uibarbuttonitemgroup)\n- [`UIBarButtonItem.Style`](https://developer.apple.com/documentation/uikit/uibarbuttonitem/style)\n\n### 7b. Internal view hierarchy: `UIBarButtonItem` on iOS 26\n\n`UIBarButtonItem` is **not a `UIView`** — it's a model object. UIKit materializes it into a private view hierarchy inside the parent `UINavigationBar` or `UIToolbar`. The exact class names are private and can change; the **layering and ordering are stable** and worth knowing for layout debugging.\n\nApproximate structure for a single bar button item (Liquid Glass, iOS 26):\n\n```\nUINavigationBar / UIToolbar\n└── _UIBarBackground               (bar-wide background, Liquid Glass material)\n└── _UIButtonBarStackView          (horizontal stack of items, leading or trailing group)\n    └── _UIModernBarButton         (host view per item; one per UIBarButtonItem)\n        ├── _UIBarItemPlatter      (shared Liquid Glass background; the \"platter\")\n        │   └── CAFilter / glass layers (UIGlassEffect-backed)\n        └── content view           (image, title label, OR customView)\n```\n\nKey facts that affect RNN code:\n\n- **The platter is per-item by default**, but adjacent items inside the same `UIBarButtonItemGroup` (or implicit leading/trailing cluster) can be coalesced into a **single shared platter** spanning several items. This is the \"shared background\" that `hidesSharedBackground` opts out of.\n- **`hidesSharedBackground = YES`** removes the `_UIBarItemPlatter` from the host view; the content view becomes the direct child of `_UIModernBarButton`. The host view is **still 44pt minimum**.\n- **The host view (`_UIModernBarButton`) reserves the slot**, not the customView. UIKit sizes the host using:\n  - System images: intrinsic size of the symbol + padding.\n  - Title-only items: text width + padding.\n  - **Custom views: the customView's intrinsic content size at the time the bar performs layout.** This is why RNN pins the custom React view to 44×44 in `RNNUIBarButtonItem.mm` — without explicit constraints, React mounts asynchronously, the customView's intrinsic size starts at zero, the host reserves zero width, the bar lays out, then React reports its real size and the host has to relayout. The visible artifact is the button \"popping in\" or being misplaced after the push transition's snapshot already captured the wrong frame.\n- **Transitions snapshot the bar.** During push/pop, UIKit takes a snapshot of the navigation bar for the cross-fade between the from/to nav items. If the customView hasn't laid out before the snapshot, the snapshot shows the wrong state. This is also why a React customView can appear blank during a transition while being fine on the destination screen.\n- **Tinting flows through the platter, not the customView.** `tintColor` set on the bar item or bar applies to the system image inside the host view; it does not propagate into a React customView. Color the React content explicitly.\n\nPractical debugging:\n\n- Inspect the live hierarchy with `po [self.navigationItem.rightBarButtonItems.firstObject valueForKey:@\"_view\"]` in lldb, or with View Debugger → uncheck \"Show layers only\" to see the private classes.\n- A button that's \"there but invisible\" usually means the host view has 0×0 frame (sizing race) or `hidesSharedBackground = NO` with a customView that paints its own chrome (double-decoration clips/overlaps).\n- A button that \"snaps into place\" after the screen appears means the host view's intrinsic size changed after the bar's first layout pass.\n\nReferences (public API only — internals are observed, not documented):\n- [`UIBarButtonItem`](https://developer.apple.com/documentation/uikit/uibarbuttonitem)\n- [`UIBarButtonItem.hidesSharedBackground`](https://developer.apple.com/documentation/uikit/uibarbuttonitem/hidessharedbackground)\n- [`UIBarButtonItemGroup`](https://developer.apple.com/documentation/uikit/uibarbuttonitemgroup)\n\n### 8. Tab bar minimize behavior (iOS 26)\nThe tab bar can auto-minimize during scroll.\n\n- `UITabBarController.tabBarMinimizeBehavior` — `.automatic`, `.never`, `.onScrollDown`, `.onScrollUp`.\n- `setNeedsUpdateOfTabBarMinimizeBehavior()` — re-evaluate.\n- Apple: [UITabBarController](https://developer.apple.com/documentation/uikit/uitabbarcontroller)\n\n**RNN handling:** Not yet exposed. Would be a new option on `bottomTabs`.\n\n### 9. `UIToolbar` on iOS 26\n\n`UIToolbar` is a real `UIView` (unlike `UIBarButtonItem`). Approximate internal hierarchy on iOS 26:\n\n```\nUIToolbar\n├── _UIBarBackground                  (bar-wide Liquid Glass material;\n│                                      configured via UIToolbarAppearance)\n│   └── _UIBackdropView / glass layers\n│   └── _UIBarBackgroundShadowView    (1pt hairline; controlled by shadowImage / shadowColor)\n└── _UIToolbarContentView\n    └── _UIButtonBarStackView         (horizontal stack of toolbar items)\n        ├── _UIModernBarButton        (item host — see 7b for layer breakdown)\n        ├── _UIModernBarButton\n        ├── ... fixed/flexible spaces become layout gaps in the stack ...\n        └── (optional) _UIBarItemGroupPlatter\n              └── two or more _UIModernBarButton sharing one platter\n                  (only when items are in the same UIBarButtonItemGroup)\n```\n\nWhat's actually public and load-bearing on iOS 26:\n\n- **Appearance objects are the only safe way to style.** `UIToolbarAppearance` (standard / compact / scrollEdge) drives `_UIBarBackground`. Setting `barTintColor` / `backgroundImage` on `UIToolbar` directly is **silently overridden** by Liquid Glass unless `appearance.backgroundEffect = nil`.\n- **Translucency is the default.** `configureWithDefaultBackground` on iOS 26 produces glass. To get an opaque fill: `configureWithOpaqueBackground` **plus** `backgroundEffect = nil` **plus** explicit `backgroundColor`. This mirrors what `BottomTabsAppearancePresenter.mm` does for the tab bar.\n- **Items follow the same Platter rules as nav bar buttons.** A custom view in a toolbar item gets wrapped in a platter unless `hidesSharedBackground = YES`. The 44pt host-view sizing race applies identically.\n- **Grouping with `UIBarButtonItemGroup`** lets adjacent items render under one shared platter (visually grouped pill). `customizationIdentifier` opts the toolbar into the user-customization sheet (iPadOS).\n- **`scrollEdgeAppearance` matters here too.** When a scroll view is attached, the toolbar fades to transparent at the scroll edge using `UIToolbar.scrollEdgeAppearance`. Pre-iOS-26 this was iPad-only for many cases; iOS 26 applies it consistently.\n\nDisplay mode and customization (iOS 26 / iPadOS 26):\n\n- `UIToolbar.displayMode` — `.automatic`, `.expanded`, `.compact`. Drives whether items spread out or collapse into an overflow menu.\n- `UIBarButtonItem.menuRepresentation` — the menu UIKit shows when the item is hoisted into the overflow control under `.compact`.\n- `UIToolbar.beginCustomizingItems(...)` / `endCustomizingItems` — programmatic entry into the user-customization sheet for movable/optional groups.\n\nRNN handling:\n\nRNN does not expose `UIToolbar` as a first-class options surface today. Toolbar-shaped behavior in this repo comes from the navigation controller's bottom bar via `RNNStackController` and is configured indirectly through stack options. Any new toolbar feature should:\n\n1. Add a presenter (e.g. `ToolbarPresenter`) mirroring `TopBarPresenter`'s appearance pattern.\n2. Configure via `UIToolbarAppearance` only — never direct `barTintColor` / `backgroundImage`.\n3. Use `UIBarButtonItemGroup` when the option models a logical cluster (e.g. \"primary actions\") so the platter coalesces correctly.\n4. Apply `hidesSharedBackground` defaults for React custom views, same as `RNNUIBarButtonItem.mm` does today.\n\nReferences:\n- [`UIToolbar`](https://developer.apple.com/documentation/uikit/uitoolbar)\n- [`UIToolbarAppearance`](https://developer.apple.com/documentation/uikit/uitoolbarappearance)\n- [`UIBarButtonItemGroup`](https://developer.apple.com/documentation/uikit/uibarbuttonitemgroup)\n- WWDC25: \"What's new in UIKit\" (toolbar/group section), \"Build a UIKit app with the new design\"\n\n### 10. Preferred transition\n- `UINavigationController.preferredTransition` — control push/pop animation style (iOS 26 expansion).\n- `UIViewController.preferredTransition` — zoom transitions.\n\n**RNN handling:** Not exposed. Stack push/pop currently uses defaults.\n\n### 11. SF Symbols 7\niOS 26 ships SF Symbols 7. Bar buttons that use system images get the new variants automatically. Custom symbol configurations should re-test on iOS 26.\n\nAnimated symbols are part of the iOS 26 bar story:\n\n- `NSSymbolEffect` family — `.bounce`, `.pulse`, `.variableColor`, `.replace`, `.breathe`, `.scale`, `.appear`, `.disappear`, `.wiggle` (iOS 18+; new variants in 26).\n- Apply via the bar item's image: configure `UIImageView` produced by UIKit, or use `UIView.addSymbolEffect(_:options:animated:)` on the host view returned by `UIBarButtonItem.value(forKey: \"_view\")` (private — prefer using `UIButton` with a configured image inside a custom bar item).\n- WWDC25: \"What's new in SF Symbols 7\".\n\n### 12. `UIButton` glass configurations\n`UIButton.Configuration` got first-class glass factories in iOS 26. Anything RNN renders that's *not* a bar button (custom views inside a screen, overlays, modal headers, bottom accessories) should adopt these instead of hand-rolling chrome.\n\n```\nUIButton.Configuration.glass()           — translucent Liquid Glass pill\nUIButton.Configuration.prominentGlass()  — tinted, more saturated variant\nUIButton.Configuration.plain()\nUIButton.Configuration.gray()\nUIButton.Configuration.tinted()\nUIButton.Configuration.filled()\nUIButton.Configuration.borderless()\n```\n\nOn iOS 26 the legacy configurations (`plain` / `gray` / `tinted` / `filled` / `borderless`) automatically repaint with the Liquid Glass material — you don't opt in, you opt *out* via `UIDesignRequiresCompatibility`.\n\nConfiguration knobs that affect build-up:\n- `cornerStyle` — `.fixed` / `.dynamic` / `.capsule` / `.small` / `.medium` / `.large`. `.dynamic` adopts concentric corners (see §15).\n- `buttonSize` — `.mini` / `.small` / `.medium` / `.large`.\n- `baseBackgroundColor` / `baseForegroundColor` — tint multiplier on glass.\n\nApproximate internal hierarchy for a configuration-based button on iOS 26:\n\n```\nUIButton (configuration-based)\n├── _UIButtonBackgroundView         (the platter / glass body)\n│   ├── UIVisualEffectView          (UIGlassEffect — see §13)\n│   └── tint overlay (CALayer)\n└── _UIButtonContentStackView\n    ├── UIImageView                 (leading or trailing image)\n    ├── UILabel                     (title)\n    └── UILabel                     (subtitle, when set)\n```\n\n**RNN handling:** Not exposed as an option today. RNN doesn't render its own button chrome inside screens — that's the React side's job — but if RNN ever needs a system-styled control (e.g. a \"Done\" button on a custom modal header it builds natively), use `UIButton.Configuration.glass()` rather than custom drawing.\n\nReferences:\n- [`UIButton.Configuration`](https://developer.apple.com/documentation/uikit/uibutton/configuration)\n- [`UIButton.Configuration.glass()`](https://developer.apple.com/documentation/uikit/uibutton/configuration/glass())\n\n### 13. `UIGlassEffect` and `UIGlassContainerEffect` (public Liquid Glass API)\n\nThe entire Liquid Glass material is exposed publicly. This is the API to use whenever RNN needs custom glass chrome — floating overlays, bottom accessories, custom navigation extensions, modal grabbers.\n\n```\nUIGlassEffect                        — UIVisualEffect subclass\nUIGlassEffect.Style.regular          — default frosted glass\nUIGlassEffect.Style.clear            — thinner, more transparent variant\nUIGlassEffect.tintColor              — multiplied tint\nUIGlassContainerEffect               — wraps multiple glass views; they morph/merge when adjacent\nUIVisualEffectView(effect: UIGlassEffect())  — host\n```\n\nBehavioral rules:\n- Glass **refracts and blurs** content behind it; opacity is content-derived, not a static color.\n- Two `UIVisualEffectView`s with `UIGlassEffect` placed inside the same `UIGlassContainerEffect` will **visually merge** into a single platter when they touch or overlap. This is what produces the \"morphing\" you see when a search bar collapses into a button, or when tabs minimize into a single pill.\n- `tintColor` is **multiplied**, not painted — fully saturated colors look pastel. Use bold colors only when you want a noticeably tinted glass.\n- Glass adapts to dark / light mode automatically; do not hand-set background colors on the visual effect view.\n\nBuild-up:\n\n```\nUIVisualEffectView (effect: UIGlassEffect)\n├── _UIVisualEffectBackdropView      (CAFilter blur + refraction)\n├── _UIVisualEffectSubview           (tint overlay)\n└── contentView                      (your content; goes here, not on the effect view directly)\n```\n\n**RNN handling:** Not used yet. Any future custom chrome (e.g. a `bottomAccessory` host, a custom modal grabber, a floating action overlay) should be a `UIVisualEffectView` with `UIGlassEffect`, **not** a `UIView` with a manually configured `UIBlurEffect`. Pre-iOS-26 RNN can fall back to `UIBlurEffectStyle.systemMaterial` via the existing availability pattern.\n\nReferences:\n- [`UIGlassEffect`](https://developer.apple.com/documentation/uikit/uiglasseffect)\n- [`UIGlassContainerEffect`](https://developer.apple.com/documentation/uikit/uiglasscontainereffect)\n- [`UIVisualEffectView`](https://developer.apple.com/documentation/uikit/uivisualeffectview)\n- WWDC25: \"Meet Liquid Glass\"\n\n### 14. `UINavigationItem.style` — navigator / browser / editor\n\niOS 26 introduces three navigation item styles that reshape the entire navigation bar's internal layout. This is one of the bigger build-up changes in 26.\n\n```\nUINavigationItem.Style.navigator     — default; classic nav title + leading/trailing items\nUINavigationItem.Style.browser       — URL-bar-like layout with a centered integrated field\nUINavigationItem.Style.editor        — document editor; renamable title + subtitle + badge\n```\n\nRelated properties (only meaningful when `style` ≠ `.navigator`):\n\n- `UINavigationItem.documentProperties: UIDocumentProperties?` — file URL, subtitle, badge displayed in editor style.\n- `UINavigationItem.renameDelegate` — inline rename UI for editor style.\n- `UINavigationItem.titleMenuProvider` — context menu when tapping the title (iOS 16+, but actually visible by default in browser/editor styles on 26).\n\nHow the build-up changes:\n\n- `.navigator` — standard `_UINavigationBarContentView` with title label centered.\n- `.browser` — `_UINavigationBarContentView` swaps the title slot for an integrated URL field (`UISearchTextField`-shaped), with leading and trailing item clusters under shared platters.\n- `.editor` — adds a vertical stack: title (renamable) + subtitle (file path) + badge, plus a primary action slot at the trailing edge.\n\n**RNN handling:** Not exposed. A future RNN option could surface `topBar.style: 'navigator' | 'browser' | 'editor'`. Editor style is the more interesting one for document-shaped apps; browser style fits Wix preview-style flows.\n\nReferences:\n- [`UINavigationItem.Style`](https://developer.apple.com/documentation/uikit/uinavigationitem/style)\n- [`UIDocumentProperties`](https://developer.apple.com/documentation/uikit/uidocumentproperties)\n- WWDC25: \"Build a UIKit app with the new design\"\n\n### 15. `UICornerConfiguration` and concentric corners\n\nConcentric corners are a foundational iOS 26 design rule: a child element's corner radius should equal its parent's radius minus the inset, so curves stay visually parallel. Apple's own bar items, sheets, and buttons obey this; mixing fixed `cornerRadius` with a concentric container looks visibly wrong on 26.\n\n```\nUICornerConfiguration.uniformCornerRadius(_:)            // fixed radius\nUICornerConfiguration.uniformCornerConfiguration(_:)     // with corner style (capsule, etc.)\nUICornerConfiguration.concentric(minimum:)               // matches parent's curvature, floored at minimum\nUIView.cornerConfiguration: UICornerConfiguration?       // applies to the view's layer\n```\n\nRule of thumb: anything painted **inside** a glass element should be `.concentric(minimum: small)` rather than `.uniformCornerRadius(N)`. The system already uses concentric corners for bar item platters, sheet corners that morph with the device screen radius, and tab bar item shapes.\n\n**RNN handling:** Not exposed. Any future RNN-native custom chrome that nests inside a glass element (e.g. a React custom view sitting inside an iOS 26 platter that RNN draws) should apply `.cornerConfiguration = .concentric(...)` on the wrapping UIView so it inherits the platter's curvature.\n\nReferences:\n- [`UICornerConfiguration`](https://developer.apple.com/documentation/uikit/uicornerconfiguration)\n- [`UIView.cornerConfiguration`](https://developer.apple.com/documentation/uikit/uiview/cornerconfiguration)\n\n### 16. `UISheetPresentationController` iOS 26 changes\n\nRNN modals route through `UISheetPresentationController` when configured. iOS 26 changes its presentation in three meaningful ways:\n\n- **`cornerConfiguration`** replaces `preferredCornerRadius` for finer control. Sheets can now have asymmetric corners and use `.concentric(minimum:)` to match the device's screen radius — the result is the visible \"corner morph\" when the sheet animates from the small detent to medium/large.\n- **Default detents changed.** The small detent now overlaps the safe area more gracefully because the corner configuration animates with the detent height. Custom detents (`UISheetPresentationController.Detent.custom`) need to play nicely with this.\n- **Sheets slide *under* the floating tab bar by default.** Pre-iOS-26 the tab bar pushed the sheet up; on 26 the sheet's small detent extends behind the tab bar. If a sheet must avoid covering the tab bar, opt out by configuring the detent height explicitly or by presenting from a context that excludes the tab bar.\n\nRelated: `UISheetPresentationController.prefersGrabberVisible` still controls the grabber; the grabber now uses Liquid Glass material.\n\n**RNN handling:** RNN exposes modal presentation through stack options. iOS 26 sheet behavior surfaces automatically through UIKit defaults — but the \"sheet over tab bar\" change can visually regress apps that expected the pre-26 layout. If users report it, the fix is to adjust the detent or presentation context, not to fight UIKit.\n\nReferences:\n- [`UISheetPresentationController`](https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller)\n- WWDC25: \"What's new in UIKit\" (sheet section)\n\n---\n\n## Workflow: adding iOS 26 support for a new API\n\n1. **Confirm the Apple API surface.** Read the relevant `developer.apple.com` page; check WWDC25 sessions for sample patterns.\n2. **Pick the RNN seam.** Use the mapping above. Top bar → `TopBarPresenter` + `RNNTopBarOptions`. Bottom tab → `BottomTabsAppearancePresenter` / `RNNBottomTabsController` + `RNNBottomTabsOptions`. Bar buttons → `RNNUIBarButtonItem` + `RNNButtonOptions`.\n3. **Add the JS option** in `lib/src/interfaces/Options.ts`. Document semantics, iOS-only marker, iOS 26 minimum.\n4. **Parse it** in the matching `*Options.mm` (use the existing `[XParser parse:dict key:@\"...\"]` pattern). Add to `mergeOptions:`.\n5. **Apply it** in the presenter, **always guarded** by `if (@available(iOS 26.0, *)) { ... }`. Honor `UIDesignRequiresCompatibility` if behavior would diverge for legacy-design apps.\n6. **Add a playground screen** in `playground/src/screens/` exercising the option, both visible and toggle states.\n7. **Add an e2e** in `playground/e2e/` using `device.getPlatform() === 'ios'` and an iOS version check. Follow existing baseline-then-action screenshot patterns.\n8. **Update docs** in `website/docs/api/options-*.mdx`.\n9. **Build Release** with Xcode 26.1, run on iPhone 17 Pro Max simulator, then **also** verify on an iOS 18 simulator for regression.\n\n## Workflow: investigating an iOS 26 regression\n\n1. Reproduce in Release on iOS 26 sim. Reproduce on iOS 18/17 — confirm it's 26-only.\n2. Grep `if (@available(iOS 26.0, *))` and the property name (e.g. `backgroundEffect`, `hidesSharedBackground`, `preferredSearchBarPlacement`) — see if RNN already has a branch.\n3. Check recent PRs touching the same file (`git log --oneline -- ios/<file>.mm | head -20`) — most iOS 26 regressions cluster.\n4. Check `UIDesignRequiresCompatibility`: if the bug only happens with the new design, the fix must not break compatibility mode.\n5. Confirm Fabric / New Architecture is still on (don't disable it to \"fix\" something).\n6. Before changing code, summarize the hypothesis and proposed fix to the user (per user rule \"show me first\").\n\n---\n\n## Known iOS 26 trouble spots in this repo\n\n| Area | File(s) | Last touched PR(s) |\n|------|---------|-------------------|\n| Custom React bar buttons (Platter, centering, lifecycle) | `RNNUIBarButtonItem.mm`, `RNNReactButtonView.mm` | #8300 |\n| Tab item title misplaced on first layout | `RNNBottomTabsController.mm` (`rnn_cycleAllTabsThenRestoreInitialSelection`) | #8245, #8254, #8255 |\n| Tab bar background color / glass | `BottomTabsAppearancePresenter.mm` | #8263, #8288 |\n| Search bar placement | `UIViewController+RNNOptions.mm`, `RNNSearchBarPlacement.mm` | #8183, #8211 |\n| Scroll edge effect on top bar | top bar options | #8281, #8239, #8207 |\n| iPad back navigation (iOS 26) | nav controller | #8277 |\n| `drawBehind` default on floating tab bar | `RNNBottomTabsOptions.mm` (`-shouldDrawBehind`) | — |\n\n---\n\n## Authoritative references\n\n- HIG: [Designing for iOS 26](https://developer.apple.com/design/human-interface-guidelines/designing-for-ios), [Materials (Liquid Glass)](https://developer.apple.com/design/human-interface-guidelines/materials), [Tab bars](https://developer.apple.com/design/human-interface-guidelines/tab-bars), [Navigation bars](https://developer.apple.com/design/human-interface-guidelines/navigation-bars), [Toolbars](https://developer.apple.com/design/human-interface-guidelines/toolbars)\n- API (bars and tabs): [UITabBarController](https://developer.apple.com/documentation/uikit/uitabbarcontroller), [UITab](https://developer.apple.com/documentation/uikit/uitab), [UITabAccessory](https://developer.apple.com/documentation/uikit/uitabaccessory), [UINavigationItem](https://developer.apple.com/documentation/uikit/uinavigationitem), [UINavigationItem.Style](https://developer.apple.com/documentation/uikit/uinavigationitem/style), [UIBarButtonItem.hidesSharedBackground](https://developer.apple.com/documentation/uikit/uibarbuttonitem/hidessharedbackground), [UIBarButtonItemGroup](https://developer.apple.com/documentation/uikit/uibarbuttonitemgroup), [UIScrollEdgeEffect](https://developer.apple.com/documentation/uikit/uiscrolledgeeffect), [UIBarAppearance](https://developer.apple.com/documentation/uikit/uibarappearance), [UIToolbar](https://developer.apple.com/documentation/uikit/uitoolbar)\n- API (glass and shapes): [UIGlassEffect](https://developer.apple.com/documentation/uikit/uiglasseffect), [UIGlassContainerEffect](https://developer.apple.com/documentation/uikit/uiglasscontainereffect), [UICornerConfiguration](https://developer.apple.com/documentation/uikit/uicornerconfiguration), [UIButton.Configuration](https://developer.apple.com/documentation/uikit/uibutton/configuration), [UIButton.Configuration.glass()](https://developer.apple.com/documentation/uikit/uibutton/configuration/glass())\n- API (presentation): [UISheetPresentationController](https://developer.apple.com/documentation/uikit/uisheetpresentationcontroller), [UIDocumentProperties](https://developer.apple.com/documentation/uikit/uidocumentproperties)\n- WWDC25: \"Meet Liquid Glass\", \"Get to know the new design system\", \"What's new in UIKit\", \"Build a UIKit app with the new design\", \"Elevate your tab and sidebar experience\", \"Make your UIKit app more flexible\", \"What's new in SF Symbols 7\"\n- Compatibility: [UIDesignRequiresCompatibility](https://developer.apple.com/documentation/bundleresources/information-property-list/uidesignrequirescompatibility)\n\n<!-- File: .cursor/skills/rnn-codebase/SKILL.md (Tokens: ~2593 | Category: anthropic-skill) -->\n---\nname: rnn-codebase\ndescription: Navigate and work with the react-native-navigation (RNN) codebase. Use when fixing bugs, adding features, tracing command flows, understanding options resolution, or working across JS/iOS/Android layers in this repo.\n---\n\n# React Native Navigation Codebase\n\n## Architecture Overview\n\nRNN has three layers that mirror each other:\n\n```\nJS/TS (src/)  →  TurboModule bridge  →  iOS native (ios/)\n                                     →  Android native (android/)\n```\n\nA navigation command (e.g. `push`) flows:\n1. `Navigation.push()` → `Commands.ts` → processing pipeline → `NativeCommandsSender.ts`\n2. TurboModule: `RNNTurboModule` (iOS) / `NavigationTurboModule.kt` (Android)\n3. iOS: `RNNCommandsHandler` → `RNNViewControllerFactory` → UIKit controllers\n4. Android: `Navigator` → `LayoutFactory` → View-based controllers (no Fragments)\n\nRead [ARCHITECTURE.md](../../ARCHITECTURE.md) for the full overview.\n\n## Key Cross-Layer Mappings\n\n### Layout Types → Native Controllers\n\n| JS Layout Type | iOS Controller | Android Controller |\n|----------------|---------------|-------------------|\n| `component` | `RNNComponentViewController` | `ComponentViewController` |\n| `stack` | `RNNStackController` (UINavigationController) | `StackController` |\n| `bottomTabs` | `RNNBottomTabsController` (UITabBarController) | `BottomTabsController` |\n| `sideMenu` | `RNNSideMenuViewController` (MMDrawerController) | `SideMenuController` (DrawerLayout) |\n| `topTabs` | `RNNTopTabsViewController` | `TopTabsController` (ViewPager) |\n| `splitView` | `RNNSplitViewController` | N/A (iOS only) |\n| `externalComponent` | `RNNExternalViewController` | `ExternalComponentViewController` |\n\n### Options → Presenters\n\nEach controller type has a Presenter that applies options to views:\n\n| iOS Controller | iOS Presenter | Android Presenter |\n|----------------|--------------|-------------------|\n| `RNNComponentViewController` | `RNNComponentPresenter` | `ComponentPresenter` |\n| `RNNStackController` | `RNNStackPresenter` + `TopBarPresenter` | `StackPresenter` |\n| `RNNBottomTabsController` | `RNNBottomTabsPresenter` | `BottomTabsPresenter` |\n| `RNNSideMenuViewController` | `RNNSideMenuPresenter` | `SideMenuPresenter` |\n\n### Events (same names both platforms)\n\n| Event | Trigger |\n|-------|---------|\n| `RNN.ComponentDidAppear` | Screen becomes visible |\n| `RNN.ComponentDidDisappear` | Screen hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tap |\n| `RNN.BottomTabSelected` | Tab changed |\n| `RNN.ModalDismissed` | Modal dismissed |\n| `RNN.ScreenPopped` | Screen popped from stack |\n| `RNN.CommandCompleted` | Any command finished |\n\n## Where to Find Things\n\n### By task: \"I need to fix/change X\"\n\n| Task | JS File(s) | iOS File(s) | Android File(s) |\n|------|-----------|------------|----------------|\n| Command execution | `src/commands/Commands.ts` | `ios/RNNCommandsHandler.mm` | `react/NavigationTurboModule.kt` |\n| Layout creation | `src/commands/LayoutTreeParser.ts` | `ios/RNNViewControllerFactory.mm` | `options/LayoutFactory.java` |\n| Options processing | `src/commands/OptionsProcessor.ts` | `ios/RNNNavigationOptions.mm` | `options/Options.java` |\n| Options application | — | `ios/*Presenter.mm` | `viewcontrollers/*Presenter.java` |\n| TopBar | `src/interfaces/Options.ts` (TopBarOptions) | `ios/TopBarPresenter.mm`, `ios/RNNUIBarButtonItem.mm` | `views/stack/topbar/` |\n| Bottom tabs | `src/interfaces/Options.ts` (BottomTabsOptions) | `ios/RNNBottomTabsPresenter.mm` | `viewcontrollers/bottomtabs/` |\n| Modals | `src/commands/Commands.ts` | `ios/RNNModalManager.mm` | `viewcontrollers/modal/ModalStack.java` |\n| Overlays | `src/commands/Commands.ts` | `ios/RNNOverlayManager.mm` | `viewcontrollers/overlay/OverlayManager.kt` |\n| Animations | `src/interfaces/Options.ts` (AnimationOptions) | `ios/ScreenAnimationController.mm` | `viewcontrollers/stack/StackAnimator.kt` |\n| React view rendering | — | `ios/RNNReactView.mm` | `react/ReactView.java` |\n| Events to JS | `src/adapters/NativeEventsReceiver.ts` | `ios/RNNEventEmitter.mm` | `react/events/EventEmitter.java` |\n| Component registration | `src/components/ComponentRegistry.ts` | — | — |\n\n### By directory\n\n- **`src/`** — JS public API, commands, processing pipeline. See [src/ARCHITECTURE.md](../../src/ARCHITECTURE.md)\n- **`ios/`** — All Obj-C/C++ native code. See [ios/ARCHITECTURE.md](../../ios/ARCHITECTURE.md)\n- **`ios/TurboModules/`** — New architecture entry points (`RNNTurboModule`, `RNNTurboManager`, `RNNTurboCommandsHandler`)\n- **`android/src/main/java/com/reactnativenavigation/`** — All Java/Kotlin native code. See [android/ARCHITECTURE.md](../../android/ARCHITECTURE.md)\n- **`playground/`** — Demo app for development and E2E tests\n- **`playground/src/screens/`** — Test screens exercising every feature\n- **`playground/e2e/`** — Detox E2E tests\n\n## Options Resolution Order\n\nOptions are applied in ascending priority:\n1. Default options (from `Navigation.setDefaultOptions()`) — lowest priority\n2. Static options (from component class or `Navigation.registerComponent`)\n3. Options passed in the layout call (e.g. `push`, `setRoot`)\n4. `mergeOptions()` — runtime override, highest priority\n\n## JS Processing Pipeline (exact order)\n\n```\nAPI layout → OptionsCrawler.crawl() → LayoutProcessor.process()\n  → LayoutTreeParser.parse() → LayoutTreeCrawler.crawl()\n  → OptionsProcessor (colors, assets, custom) → NativeCommandsSender\n```\n\n## iOS Patterns\n\n- All controllers conform to `RNNLayoutProtocol`\n- `RNNBasePresenter` subclasses apply options — `applyOptionsOnInit:`, `applyOptions:`, `mergeOptions:resolvedOptions:`\n- Commands run on main thread (`RCTExecuteOnMainQueue`)\n- React views: `RNNReactView` wraps `RCTSurfaceHostingView` (new arch)\n- Overlays use separate `UIWindow` instances (`RNNOverlayWindow`)\n- `RNNReactComponentRegistry` caches React component instances\n\n## Android Patterns\n\n- View-based, NOT Fragment-based\n- All commands dispatched via `UiThread.post()`\n- `ViewController<T extends ViewGroup>` is the base — `createView()` is abstract\n- `ParentController` extends `ChildController` extends `ViewController`\n- Bottom tabs use `AHBottomNavigation` library\n- Three root layouts in `NavigationActivity`: rootLayout, modalsLayout, overlaysLayout\n- Tab attachment modes: `Together`, `OnSwitchToTab`, `AfterInitialTab`\n\n## Development Workflow\n\n### Playground app\n- `yarn start` — Metro bundler\n- `yarn xcode` — Open iOS project\n- `yarn studio` — Open Android project\n- `yarn pod-install` — Install iOS pods\n\n### Testing\n- `yarn test-js` — Jest unit tests\n- `yarn test-unit-ios` — iOS native unit tests (XCTest)\n- `yarn test-unit-android` — Android native unit tests (JUnit + Robolectric)\n- `yarn test-e2e-ios-ci` / `yarn test-e2e-android-ci` — Detox E2E tests\n\n### Building\n- `yarn prepare` — Builds `src/` → `lib/` (ESM + types)\n- Codegen config: `rnnavigation` in `package.json`\n\n## Engine Integration (Wix One App)\n\nRNN is a standalone library but also a core dependency of `mobile-apps-engine` (the Wix One App platform). Changes to RNN's public API surface can break engine.\n\n### Version Management\n\n- Version pinned in two files (must match):\n  - `packages/native/mobile-apps-engine-native/package.json`\n  - `packages/wix-one-app-storage/package.json`\n- `yarn.config.cjs` has a constraint that reads the version from `mobile-apps-engine-native` and validates all workspaces use the same version. It's a validation rule — bumping the native package.json is sufficient.\n\n### iOS Integration\n\n- Engine's `AppDelegate` subclasses `RNNAppDelegate` — breaking changes to that class will break engine.\n- Podfile resolves `ReactNativeNavigation` pod from node_modules.\n- Xcode project has header search paths pointing into `node_modules/react-native-navigation/ios/**`.\n\n### Android Integration\n\n- Engine's `EngineRN.kt` extends `NavigationApplication` and uses `NavigationPackage` / `NavigationReactNativeHost`.\n- `missingDimensionStrategy \"RNN.reactNativeVersion\"` is set in `app/build.gradle` — may need updating if RNN changes its flavor dimensions.\n- Build variables `RNNKotlinVersion`, `RNNKotlinStdlib`, `RNNKotlinCoroutinesCore` are forwarded from engine's Kotlin config.\n\n### Active Patches (in engine's setup)\n\n- **OptionsProcessor.js** — engine replaces RNN's `OptionsProcessor.js` at setup time via `patchRNNOptionsProcessor()` in `packages/cli/mobile-apps-engine-setup/src/index.js`. The patched copy lives at `packages/cli/mobile-apps-engine-setup/etc/OptionsProcessor.js`. It adds:\n  - Custom iOS color processing with `DynamicColorIOS` (dark/light/dynamic object shapes)\n  - Custom Android color processing wrapping colors in `{dark, light}` objects with `semantic`/`resource_paths` support\n  - Component ID uses `value.name` instead of `uniqueIdProvider.generate()`\n- Any changes to `src/commands/OptionsProcessor.ts` require checking if the engine patch needs updating.\n\n### JS Wrappers\n\nEngine wraps RNN's `Navigation` API in several services:\n- `Navigator.ts` — root layout, overlays, error screens, tab navigation\n- `BottomTabsBackHandler.ts` — back handling on bottom tabs via `Navigation.events()`\n- `TabsManager.ts` — tab management using RNN `Layout` types\n- Various other services import `Layout`, `LayoutRoot`, `LayoutSideMenu`, `OptionsSideMenu` from RNN\n\n### Upgrade Checklist\n\n1. Bump version in both `package.json` files\n2. Verify `OptionsProcessor.js` patch still applies (diff upstream changes)\n3. Check `RNNAppDelegate` API compatibility (iOS)\n4. Check `NavigationApplication` / `NavigationPackage` / `NavigationReactNativeHost` API compatibility (Android)\n5. Verify `missingDimensionStrategy` value is still valid\n6. Check `react-native-navigation-hooks` and `rnn-copilot` compatibility\n7. Run `yarn install` to update lockfile\n8. Verify test mocks (`react-native-navigation/Mock`) still work\n\n## Common Gotchas\n\n- iOS uses UIKit subclasses (UINavigationController, UITabBarController); Android uses custom View hierarchy\n- `splitView` is iOS-only\n- Side menu: iOS uses MMDrawerController (3rd party); Android uses DrawerLayout (native)\n- Options that exist in JS types may not be implemented on both platforms — check the presenter\n- `passProps` are stored in JS `Store`, not sent to native (cleared before bridge crossing)\n- The `lib/` folder is generated — never edit it, edit `src/` instead\n\n<!-- File: .github/skills/rnn-codebase/SKILL.md (Tokens: ~1914 | Category: anthropic-skill) -->\n---\nname: rnn-codebase\ndescription: Navigate and work with the react-native-navigation (RNN) codebase. Use when fixing bugs, adding features, tracing command flows, understanding options resolution, or working across JS/iOS/Android layers in this repo.\n---\n\n# React Native Navigation Codebase\n\n## Architecture Overview\n\nRNN has three layers that mirror each other:\n\n```\nJS/TS (src/)  →  TurboModule bridge  →  iOS native (ios/)\n                                     →  Android native (android/)\n```\n\nA navigation command (e.g. `push`) flows:\n1. `Navigation.push()` → `Commands.ts` → processing pipeline → `NativeCommandsSender.ts`\n2. TurboModule: `RNNTurboModule` (iOS) / `NavigationTurboModule.kt` (Android)\n3. iOS: `RNNCommandsHandler` → `RNNViewControllerFactory` → UIKit controllers\n4. Android: `Navigator` → `LayoutFactory` → View-based controllers (no Fragments)\n\nRead [ARCHITECTURE.md](../../../ARCHITECTURE.md) for the full overview.\n\n## Key Cross-Layer Mappings\n\n### Layout Types → Native Controllers\n\n| JS Layout Type | iOS Controller | Android Controller |\n|----------------|---------------|-------------------|\n| `component` | `RNNComponentViewController` | `ComponentViewController` |\n| `stack` | `RNNStackController` (UINavigationController) | `StackController` |\n| `bottomTabs` | `RNNBottomTabsController` (UITabBarController) | `BottomTabsController` |\n| `sideMenu` | `RNNSideMenuViewController` (MMDrawerController) | `SideMenuController` (DrawerLayout) |\n| `topTabs` | `RNNTopTabsViewController` | `TopTabsController` (ViewPager) |\n| `splitView` | `RNNSplitViewController` | N/A (iOS only) |\n| `externalComponent` | `RNNExternalViewController` | `ExternalComponentViewController` |\n\n### Options → Presenters\n\nEach controller type has a Presenter that applies options to views:\n\n| iOS Controller | iOS Presenter | Android Presenter |\n|----------------|--------------|-------------------|\n| `RNNComponentViewController` | `RNNComponentPresenter` | `ComponentPresenter` |\n| `RNNStackController` | `RNNStackPresenter` + `TopBarPresenter` | `StackPresenter` |\n| `RNNBottomTabsController` | `RNNBottomTabsPresenter` | `BottomTabsPresenter` |\n| `RNNSideMenuViewController` | `RNNSideMenuPresenter` | `SideMenuPresenter` |\n\n### Events (same names both platforms)\n\n| Event | Trigger |\n|-------|---------|\n| `RNN.ComponentDidAppear` | Screen becomes visible |\n| `RNN.ComponentDidDisappear` | Screen hidden |\n| `RNN.NavigationButtonPressed` | TopBar button tap |\n| `RNN.BottomTabSelected` | Tab changed |\n| `RNN.ModalDismissed` | Modal dismissed |\n| `RNN.ScreenPopped` | Screen popped from stack |\n| `RNN.CommandCompleted` | Any command finished |\n\n## Where to Find Things\n\n### By task: \"I need to fix/change X\"\n\n| Task | JS File(s) | iOS File(s) | Android File(s) |\n|------|-----------|------------|----------------|\n| Command execution | `src/commands/Commands.ts` | `ios/RNNCommandsHandler.mm` | `react/NavigationTurboModule.kt` |\n| Layout creation | `src/commands/LayoutTreeParser.ts` | `ios/RNNViewControllerFactory.mm` | `options/LayoutFactory.java` |\n| Options processing | `src/commands/OptionsProcessor.ts` | `ios/RNNNavigationOptions.mm` | `options/Options.java` |\n| Options application | — | `ios/*Presenter.mm` | `viewcontrollers/*Presenter.java` |\n| TopBar | `src/interfaces/Options.ts` (TopBarOptions) | `ios/TopBarPresenter.mm`, `ios/RNNUIBarButtonItem.mm` | `views/stack/topbar/` |\n| Bottom tabs | `src/interfaces/Options.ts` (BottomTabsOptions) | `ios/RNNBottomTabsPresenter.mm` | `viewcontrollers/bottomtabs/` |\n| Modals | `src/commands/Commands.ts` | `ios/RNNModalManager.mm` | `viewcontrollers/modal/ModalStack.java` |\n| Overlays | `src/commands/Commands.ts` | `ios/RNNOverlayManager.mm` | `viewcontrollers/overlay/OverlayManager.kt` |\n| Animations | `src/interfaces/Options.ts` (AnimationOptions) | `ios/ScreenAnimationController.mm` | `viewcontrollers/stack/StackAnimator.kt` |\n| React view rendering | — | `ios/RNNReactView.mm` | `react/ReactView.java` |\n| Events to JS | `src/adapters/NativeEventsReceiver.ts` | `ios/RNNEventEmitter.mm` | `react/events/EventEmitter.java` |\n| Component registration | `src/components/ComponentRegistry.ts` | — | — |\n\n### By directory\n\n- **`src/`** — JS public API, commands, processing pipeline. See [src/ARCHITECTURE.md](../../../src/ARCHITECTURE.md)\n- **`ios/`** — All Obj-C/C++ native code. See [ios/ARCHITECTURE.md](../../../ios/ARCHITECTURE.md)\n- **`ios/TurboModules/`** — New architecture entry points (`RNNTurboModule`, `RNNTurboManager`, `RNNTurboCommandsHandler`)\n- **`android/src/main/java/com/reactnativenavigation/`** — All Java/Kotlin native code. See [android/ARCHITECTURE.md](../../../android/ARCHITECTURE.md)\n- **`playground/`** — Demo app for development and E2E tests\n- **`playground/src/screens/`** — Test screens exercising every feature\n- **`playground/e2e/`** — Detox E2E tests\n\n## Options Resolution Order\n\nOptions are applied in ascending priority:\n1. Default options (from `Navigation.setDefaultOptions()`) — lowest priority\n2. Static options (from component class or `Navigation.registerComponent`)\n3. Options passed in the layout call (e.g. `push`, `setRoot`)\n4. `mergeOptions()` — runtime override, highest priority\n\n## JS Processing Pipeline (exact order)\n\n```\nAPI layout → OptionsCrawler.crawl() → LayoutProcessor.process()\n  → LayoutTreeParser.parse() → LayoutTreeCrawler.crawl()\n  → OptionsProcessor (colors, assets, custom) → NativeCommandsSender\n```\n\n## iOS Patterns\n\n- All controllers conform to `RNNLayoutProtocol`\n- `RNNBasePresenter` subclasses apply options — `applyOptionsOnInit:`, `applyOptions:`, `mergeOptions:resolvedOptions:`\n- Commands run on main thread (`RCTExecuteOnMainQueue`)\n- React views: `RNNReactView` wraps `RCTSurfaceHostingView` (new arch)\n- Overlays use separate `UIWindow` instances (`RNNOverlayWindow`)\n- `RNNReactComponentRegistry` caches React component instances\n\n## Android Patterns\n\n- View-based, NOT Fragment-based\n- All commands dispatched via `UiThread.post()`\n- `ViewController<T extends ViewGroup>` is the base — `createView()` is abstract\n- `ParentController` extends `ChildController` extends `ViewController`\n- Bottom tabs use `AHBottomNavigation` library\n- Three root layouts in `NavigationActivity`: rootLayout, modalsLayout, overlaysLayout\n- Tab attachment modes: `Together`, `OnSwitchToTab`, `AfterInitialTab`\n\n## Development Workflow\n\n### Playground app\n- `yarn start` — Metro bundler\n- `yarn xcode` — Open iOS project\n- `yarn studio` — Open Android project\n- `yarn pod-install` — Install iOS pods\n\n### Testing\n- `yarn test-js` — Jest unit tests\n- `yarn test-unit-ios` — iOS native unit tests (XCTest)\n- `yarn test-unit-android` — Android native unit tests (JUnit + Robolectric)\n- `yarn test-e2e-ios-ci` / `yarn test-e2e-android-ci` — Detox E2E tests\n\n### Building\n- `yarn prepare` — Builds `src/` → `lib/` (ESM + types)\n- Codegen config: `rnnavigation` in `package.json`\n\n## Common Gotchas\n\n- iOS uses UIKit subclasses (UINavigationController, UITabBarController); Android uses custom View hierarchy\n- `splitView` is iOS-only\n- Side menu: iOS uses MMDrawerController (3rd party); Android uses DrawerLayout (native)\n- Options that exist in JS types may not be implemented on both platforms — check the presenter\n- `passProps` are stored in JS `Store`, not sent to native (cleared before bridge crossing)\n- The `lib/` folder is generated — never edit it, edit `src/` instead\n\n<!-- File: .cursor/rules/github-descriptions.mdc (Tokens: ~75 | Category: cursor-rule) -->\n---\ndescription: When the user asks for a GitHub description or PR description\nglobs:\nalwaysApply: false\n---\n\nWhen generating GitHub descriptions (PR descriptions, issue descriptions, commit descriptions), always use GitHub-flavored Markdown formatting: **bold** for emphasis, `backticks` for code/class/file references, bullet lists with `-`, and `##` headers where appropriate.\n</yakaai_skills>"}