@apexnative/navigation 1.0.0-alpha.0 → 1.0.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (574) hide show
  1. package/ApexNavigation.podspec +2 -1
  2. package/CHANGELOG.md +128 -0
  3. package/README.md +147 -51
  4. package/android/CLAUDE.md +78 -25
  5. package/android/CORE.md +49 -25
  6. package/android/RECIPES.md +13 -6
  7. package/android/consumer-rules.pro +6 -0
  8. package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +85 -10
  9. package/android/src/main/java/dev/apexnative/navigation/NavigationApplication.kt +34 -13
  10. package/android/src/main/java/dev/apexnative/navigation/layout/LayoutChecks.kt +5 -1
  11. package/android/src/main/java/dev/apexnative/navigation/layout/LayoutNode.kt +6 -2
  12. package/android/src/main/java/dev/apexnative/navigation/nativescreen/NativeScreenContext.kt +2 -2
  13. package/android/src/main/java/dev/apexnative/navigation/options/AnimationsOptions.kt +2 -2
  14. package/android/src/main/java/dev/apexnative/navigation/options/BottomTabOptions.kt +1 -1
  15. package/android/src/main/java/dev/apexnative/navigation/options/BottomTabsOptions.kt +13 -8
  16. package/android/src/main/java/dev/apexnative/navigation/options/ButtonMenuOptions.kt +2 -2
  17. package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +3 -3
  18. package/android/src/main/java/dev/apexnative/navigation/options/HardwareBackButtonOptions.kt +9 -1
  19. package/android/src/main/java/dev/apexnative/navigation/options/LargeTitleOptions.kt +1 -1
  20. package/android/src/main/java/dev/apexnative/navigation/options/LayoutAnimation.kt +1 -1
  21. package/android/src/main/java/dev/apexnative/navigation/options/OptionKey.kt +18 -0
  22. package/android/src/main/java/dev/apexnative/navigation/options/OptionPaths.kt +91 -0
  23. package/android/src/main/java/dev/apexnative/navigation/options/OptionsCache.kt +8 -4
  24. package/android/src/main/java/dev/apexnative/navigation/options/SheetOptions.kt +7 -4
  25. package/android/src/main/java/dev/apexnative/navigation/options/SideMenuOptions.kt +6 -1
  26. package/android/src/main/java/dev/apexnative/navigation/options/StackAnimationOptions.kt +40 -2
  27. package/android/src/main/java/dev/apexnative/navigation/options/StatusBarOptions.kt +7 -3
  28. package/android/src/main/java/dev/apexnative/navigation/options/TitleOptions.kt +2 -2
  29. package/android/src/main/java/dev/apexnative/navigation/options/TopBarAppearanceOptions.kt +1 -1
  30. package/android/src/main/java/dev/apexnative/navigation/options/TopBarOptions.kt +16 -7
  31. package/android/src/main/java/dev/apexnative/navigation/options/UserChoices.kt +159 -0
  32. package/android/src/main/java/dev/apexnative/navigation/react/CommandAnswer.kt +29 -36
  33. package/android/src/main/java/dev/apexnative/navigation/react/CommandContract.kt +59 -0
  34. package/android/src/main/java/dev/apexnative/navigation/react/ContentHeights.kt +95 -0
  35. package/android/src/main/java/dev/apexnative/navigation/react/ContentMounts.kt +66 -0
  36. package/android/src/main/java/dev/apexnative/navigation/react/ErrorTexts.kt +75 -60
  37. package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +35 -23
  38. package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +12 -7
  39. package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +42 -4
  40. package/android/src/main/java/dev/apexnative/navigation/react/PendingCalls.kt +48 -0
  41. package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +54 -20
  42. package/android/src/main/java/dev/apexnative/navigation/react/ReloadCoordinator.kt +7 -6
  43. package/android/src/main/java/dev/apexnative/navigation/react/ScreenEnvironment.kt +177 -0
  44. package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +19 -50
  45. package/android/src/main/java/dev/apexnative/navigation/react/ScrollEvents.kt +49 -128
  46. package/android/src/main/java/dev/apexnative/navigation/react/events/AppearanceDispatcher.kt +50 -81
  47. package/android/src/main/java/dev/apexnative/navigation/react/events/EventContract.kt +226 -0
  48. package/android/src/main/java/dev/apexnative/navigation/react/events/EventEmitter.kt +135 -94
  49. package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationState.kt +154 -0
  50. package/android/src/main/java/dev/apexnative/navigation/react/events/ScreenAppearance.kt +0 -6
  51. package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +12 -10
  52. package/android/src/main/java/dev/apexnative/navigation/slots/SlotContainers.kt +10 -7
  53. package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +39 -19
  54. package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +16 -4
  55. package/android/src/main/java/dev/apexnative/navigation/slots/SlotViews.kt +40 -0
  56. package/android/src/main/java/dev/apexnative/navigation/utils/ImageKey.kt +66 -0
  57. package/android/src/main/java/dev/apexnative/navigation/utils/ImageLoader.kt +7 -89
  58. package/android/src/main/java/dev/apexnative/navigation/utils/ImageRequests.kt +76 -0
  59. package/android/src/main/java/dev/apexnative/navigation/utils/MaterialTheme.kt +5 -6
  60. package/android/src/main/java/dev/apexnative/navigation/utils/OptionImages.kt +262 -0
  61. package/android/src/main/java/dev/apexnative/navigation/utils/SystemAnimations.kt +36 -0
  62. package/android/src/main/java/dev/apexnative/navigation/utils/UiUtils.kt +3 -3
  63. package/android/src/main/java/dev/apexnative/navigation/utils/ViewController.kt +3 -1
  64. package/android/src/main/java/dev/apexnative/navigation/utils/ViewExtensions.kt +0 -13
  65. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementController.kt +10 -7
  66. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/SecondaryScreenPresenter.kt +13 -5
  67. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/AppliedTabCalls.kt +49 -0
  68. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsCollapseBehavior.kt +5 -3
  69. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +108 -34
  70. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsPresenter.kt +25 -24
  71. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowGeometry.kt +22 -0
  72. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabItems.kt +3 -3
  73. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabsRoom.kt +0 -5
  74. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentPresenter.kt +28 -7
  75. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +12 -9
  76. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ContentReadiness.kt +2 -2
  77. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/RenderWait.kt +27 -7
  78. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenFrame.kt +1 -1
  79. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenReadiness.kt +103 -56
  80. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenSafeArea.kt +29 -11
  81. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/externalcomponent/ExternalComponentViewController.kt +2 -6
  82. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalAnimations.kt +22 -24
  83. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +109 -21
  84. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalRecord.kt +21 -6
  85. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +476 -73
  86. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +57 -25
  87. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetBack.kt +42 -0
  88. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +83 -0
  89. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackCheck.kt +50 -0
  90. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackState.kt +49 -14
  91. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +71 -12
  92. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +37 -11
  93. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/overlay/OverlayCoordinator.kt +10 -8
  94. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/Capabilities.kt +11 -4
  95. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ContainerBackground.kt +3 -3
  96. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +6 -6
  97. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +42 -9
  98. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +19 -8
  99. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuPresenter.kt +16 -7
  100. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuRules.kt +43 -4
  101. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitPanes.kt +23 -0
  102. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +77 -17
  103. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +315 -0
  104. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/PreparedFrame.kt +3 -3
  105. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +30 -20
  106. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +216 -18
  107. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackDisplay.kt +26 -1
  108. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +149 -41
  109. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackTransitions.kt +26 -8
  110. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +115 -6
  111. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabMotion.kt +142 -0
  112. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +222 -48
  113. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/ScreenSearch.kt +3 -5
  114. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +30 -34
  115. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarComponents.kt +5 -51
  116. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarRowTransition.kt +3 -2
  117. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/ButtonPlaces.kt +11 -5
  118. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/MenuChecks.kt +13 -56
  119. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +219 -54
  120. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarVisibility.kt +9 -2
  121. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ScrollEventListener.kt +6 -9
  122. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ViewController.kt +75 -21
  123. package/android/src/main/java/dev/apexnative/navigation/views/animations/AnimationLayer.kt +73 -0
  124. package/android/src/main/java/dev/apexnative/navigation/views/animations/Curves.kt +29 -11
  125. package/android/src/main/java/dev/apexnative/navigation/views/animations/ValueInterpolation.kt +14 -0
  126. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +9 -7
  127. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabsLayout.kt +61 -2
  128. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomBottomTabItemView.kt +0 -5
  129. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomTabRow.kt +72 -10
  130. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStep.kt +31 -0
  131. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +143 -135
  132. package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +13 -5
  133. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
  134. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionTargets.kt +9 -6
  135. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionViews.kt +100 -0
  136. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +112 -4
  137. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +346 -36
  138. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMorph.kt +199 -0
  139. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +56 -41
  140. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextMorph.kt +176 -0
  141. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewMorph.kt +108 -0
  142. package/android/src/main/java/dev/apexnative/navigation/views/sidemenu/SideMenuView.kt +12 -3
  143. package/android/src/main/java/dev/apexnative/navigation/views/stack/ScreenEdge.kt +45 -0
  144. package/android/src/main/java/dev/apexnative/navigation/views/stack/StackLayout.kt +140 -1
  145. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/Fab.kt +14 -10
  146. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabCopy.kt +85 -0
  147. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabMenu.kt +13 -0
  148. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +5 -17
  149. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +73 -34
  150. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonComponentCell.kt +6 -6
  151. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonView.kt +113 -0
  152. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarMenu.kt +219 -0
  153. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +125 -178
  154. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonMenus.kt +34 -64
  155. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonRow.kt +216 -0
  156. package/android/src/main/jni/ANNContentHeights.cpp +82 -0
  157. package/android/src/main/res/drawable/apex_navigation_ic_arrow_right.xml +14 -0
  158. package/android/src/main/res/layout/apex_navigation_menu_header.xml +19 -0
  159. package/android/src/main/res/layout/apex_navigation_menu_item.xml +68 -0
  160. package/android/src/main/res/values/styles.xml +1 -1
  161. package/android/src/main/res/values-night/styles.xml +1 -1
  162. package/cli/app.js +1 -1
  163. package/cli/doctor/checks/app.js +77 -14
  164. package/cli/doctor/checks/splash.js +4 -22
  165. package/cli/migrate/native.js +18 -0
  166. package/cli/project.js +10 -2
  167. package/cli/setup/index.js +18 -0
  168. package/cli/setup/source.js +2 -1
  169. package/cli/setup/steps/appDelegate.js +66 -11
  170. package/cli/setup/steps/mainApplication.js +134 -19
  171. package/cli/setup/steps/metro.js +46 -0
  172. package/cli/setup/steps/sceneDelegate.js +108 -0
  173. package/cli/splash/index.js +3 -1
  174. package/cli/upgrade/changelog.js +2 -2
  175. package/docs-md/architecture/native-screens.md +4 -0
  176. package/docs-md/architecture/theme-and-context.md +131 -12
  177. package/docs-md/architecture/transitions.md +58 -12
  178. package/docs-md/containers/modals.md +8 -4
  179. package/docs-md/containers/overlays.md +3 -1
  180. package/docs-md/containers/side-menu.md +19 -2
  181. package/docs-md/containers/tabs.md +5 -1
  182. package/docs-md/flows/bottom-sheets.md +4 -2
  183. package/docs-md/flows/forms-in-a-modal.md +1 -1
  184. package/docs-md/fundamentals/screens-and-props.md +9 -1
  185. package/docs-md/fundamentals/starting-the-app.md +1 -1
  186. package/docs-md/guides/cli.md +4 -3
  187. package/docs-md/guides/deep-links.md +15 -33
  188. package/docs-md/help/glossary.md +4 -4
  189. package/docs-md/help/troubleshooting.md +44 -6
  190. package/docs-md/index.json +57 -1
  191. package/docs-md/migration/from-expo-router.md +1 -1
  192. package/docs-md/migration/from-react-native-navigation.md +9 -3
  193. package/docs-md/migration/from-react-navigation.md +2 -2
  194. package/docs-md/screen-ui/back-and-gestures.md +46 -2
  195. package/docs-md/screen-ui/bar-buttons.md +5 -5
  196. package/docs-md/screen-ui/search.md +1 -1
  197. package/docs-md/screen-ui/system-ui.md +17 -12
  198. package/docs-md/screen-ui/toolbar-and-fab.md +4 -2
  199. package/docs-md/screen-ui/top-bar.md +8 -4
  200. package/docs-md/start/installation.md +21 -3
  201. package/ios/Animations/ANNFrameDriver.h +55 -15
  202. package/ios/Animations/ANNFrameDriver.mm +216 -60
  203. package/ios/Animations/ANNTransitionAnimator.h +26 -5
  204. package/ios/Animations/ANNTransitionAnimator.mm +61 -13
  205. package/ios/Animations/ANNTransitionPlan.h +2 -2
  206. package/ios/Animations/ANNTransitionPlan.mm +10 -0
  207. package/ios/Animations/ANNTransitionWait.mm +6 -7
  208. package/ios/Animations/Elements/ANNElementFinder.h +57 -0
  209. package/ios/Animations/Elements/ANNElementFinder.mm +174 -2
  210. package/ios/Animations/Elements/ANNElementTransition.h +10 -8
  211. package/ios/Animations/Elements/ANNElementTransition.mm +19 -21
  212. package/ios/Animations/Elements/ANNSharedElementFlight.h +16 -11
  213. package/ios/Animations/Elements/ANNSharedElementFlight.mm +308 -69
  214. package/ios/Animations/Interpolators/ANNInterpolate.h +2 -30
  215. package/ios/Animations/Interpolators/ANNTransformParts.h +48 -0
  216. package/ios/Animations/Interpolators/ANNTransformParts.mm +507 -0
  217. package/ios/Animations/Interpolators/ANNViewTracks.h +9 -6
  218. package/ios/Animations/Interpolators/ANNViewTracks.mm +100 -30
  219. package/ios/CLAUDE.md +60 -24
  220. package/ios/CORE.md +44 -34
  221. package/ios/Contract/ANNCommandAnswer.h +13 -5
  222. package/ios/Contract/ANNCommandAnswer.mm +40 -32
  223. package/ios/Contract/ANNCommandContract.h +15 -0
  224. package/ios/Contract/ANNCommandContract.mm +78 -0
  225. package/ios/Contract/ANNCommandRunner.h +10 -9
  226. package/ios/Contract/ANNCommandRunner.mm +22 -28
  227. package/ios/Contract/ANNErrorTexts.h +6 -2
  228. package/ios/Contract/ANNErrorTexts.mm +18 -10
  229. package/ios/Contract/ANNLayoutNode.h +3 -3
  230. package/ios/Contract/ANNLayoutReader.h +3 -3
  231. package/ios/Core/ANNAppDelegate.mm +0 -2
  232. package/ios/Core/ANNAppearanceDispatcher.h +5 -4
  233. package/ios/Core/ANNAppearanceDispatcher.mm +12 -1
  234. package/ios/Core/ANNDeepLinkQueue.h +22 -2
  235. package/ios/Core/ANNDeepLinkQueue.mm +121 -14
  236. package/ios/Core/ANNErrorHandler.h +9 -4
  237. package/ios/Core/ANNErrorHandler.mm +20 -2
  238. package/ios/Core/ANNEventContract.h +246 -0
  239. package/ios/Core/ANNEventContract.mm +225 -0
  240. package/ios/Core/ANNEventEmitter.h +6 -2
  241. package/ios/Core/ANNEventEmitter.mm +117 -80
  242. package/ios/Core/ANNHinge.h +6 -0
  243. package/ios/Core/ANNHinge.mm +15 -4
  244. package/ios/Core/ANNJavaScriptCalls.h +33 -0
  245. package/ios/Core/ANNJavaScriptCalls.mm +52 -0
  246. package/ios/Core/ANNLayoutProtocol.h +5 -5
  247. package/ios/Core/ANNNavigationState.h +7 -5
  248. package/ios/Core/ANNNavigationState.mm +8 -7
  249. package/ios/Core/ANNNodeHelper.h +32 -12
  250. package/ios/Core/ANNNodeHelper.mm +100 -3
  251. package/ios/Core/ANNParking.h +5 -4
  252. package/ios/Core/ANNReloadCoordinator.mm +5 -12
  253. package/ios/Core/ANNRenderWait.h +20 -6
  254. package/ios/Core/ANNRenderWait.mm +143 -56
  255. package/ios/Core/ANNSceneDelegate.mm +25 -15
  256. package/ios/Core/ANNSystemUI.h +3 -2
  257. package/ios/Core/ANNSystemUI.mm +7 -0
  258. package/ios/Core/ANNUtils.h +7 -0
  259. package/ios/Core/ANNUtils.mm +10 -0
  260. package/ios/Core/ApexNavigation+Internal.h +1 -1
  261. package/ios/Core/ApexNavigation.mm +7 -6
  262. package/ios/Core/UIViewController+LayoutProtocol.h +9 -2
  263. package/ios/Core/UIViewController+LayoutProtocol.mm +8 -0
  264. package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
  265. package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
  266. package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +10 -8
  267. package/ios/Layouts/Modal/ANNModalCoordinator.h +1 -1
  268. package/ios/Layouts/Modal/ANNModalCoordinator.mm +57 -16
  269. package/ios/Layouts/Modal/ANNModalPresentation.h +8 -5
  270. package/ios/Layouts/Modal/ANNModalPresentation.mm +12 -12
  271. package/ios/Layouts/Modal/ANNSheetPresenter.mm +83 -1
  272. package/ios/Layouts/Overlay/ANNOverlayCoordinator.mm +2 -8
  273. package/ios/Layouts/Root/ANNRootCoordinator.mm +58 -19
  274. package/ios/Layouts/Root/ANNSplashViewController.h +5 -3
  275. package/ios/Layouts/Root/ANNSplashViewController.mm +147 -0
  276. package/ios/Layouts/Screen/ANNComponentPresenter.h +11 -3
  277. package/ios/Layouts/Screen/ANNComponentPresenter.mm +34 -6
  278. package/ios/Layouts/Screen/ANNComponentViewController.h +15 -13
  279. package/ios/Layouts/Screen/ANNComponentViewController.mm +130 -75
  280. package/ios/Layouts/Screen/ANNNativeScreenContext.mm +7 -5
  281. package/ios/Layouts/Screen/ANNPreviewInteraction.h +7 -4
  282. package/ios/Layouts/Screen/ANNPreviewInteraction.mm +72 -10
  283. package/ios/Layouts/Screen/ANNScreenEnvironment.h +63 -0
  284. package/ios/Layouts/Screen/ANNScreenEnvironment.mm +181 -0
  285. package/ios/Layouts/Screen/ANNScreenPlace.h +53 -0
  286. package/ios/Layouts/Screen/ANNScreenPlace.mm +205 -0
  287. package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
  288. package/ios/Layouts/Screen/ANNScreenRegions.mm +9 -44
  289. package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
  290. package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
  291. package/ios/Layouts/Screen/ANNScreenSettling.h +32 -0
  292. package/ios/Layouts/Screen/ANNScreenSettling.mm +137 -0
  293. package/ios/Layouts/SideMenu/ANNSideMenuTypes.h +8 -0
  294. package/ios/Layouts/SideMenu/ANNSideMenuViewController.mm +83 -14
  295. package/ios/Layouts/SplitView/ANNSplitViewCommands.h +3 -2
  296. package/ios/Layouts/SplitView/ANNSplitViewCommands.mm +105 -39
  297. package/ios/Layouts/SplitView/ANNSplitViewController.mm +7 -8
  298. package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
  299. package/ios/Layouts/Stack/ANNPreviewPush.mm +142 -27
  300. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
  301. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
  302. package/ios/Layouts/Stack/ANNStackCommands.mm +1 -0
  303. package/ios/Layouts/Stack/ANNStackController.h +8 -0
  304. package/ios/Layouts/Stack/ANNStackController.mm +184 -16
  305. package/ios/Layouts/Stack/ANNStackQueue.h +5 -2
  306. package/ios/Layouts/Stack/ANNStackQueue.mm +56 -43
  307. package/ios/Layouts/Stack/ANNSwipePopInteraction.h +26 -0
  308. package/ios/Layouts/Stack/ANNSwipePopInteraction.mm +185 -0
  309. package/ios/Layouts/Stack/InteractivePopGestureDelegate.mm +28 -4
  310. package/ios/Layouts/Stack/UINavigationController+ANNCommands.h +4 -2
  311. package/ios/Layouts/Stack/UINavigationController+ANNCommands.mm +2 -3
  312. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.h +4 -0
  313. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.mm +11 -0
  314. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
  315. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
  316. package/ios/Layouts/Tabs/ANNBottomTabsController.h +3 -0
  317. package/ios/Layouts/Tabs/ANNBottomTabsController.mm +237 -57
  318. package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
  319. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +6 -2
  320. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +232 -43
  321. package/ios/Layouts/Tabs/ANNTabsDesign.h +6 -5
  322. package/ios/Layouts/Tabs/ANNTabsDesign.mm +9 -1
  323. package/ios/Layouts/Tabs/UITabBar+utils.h +5 -5
  324. package/ios/Layouts/Tabs/UITabBar+utils.mm +32 -13
  325. package/ios/Options/ANNAnimationOptions.h +2 -1
  326. package/ios/Options/ANNAnimationOptions.mm +1 -1
  327. package/ios/Options/ANNBottomTabsOptions.h +2 -0
  328. package/ios/Options/ANNBottomTabsOptions.mm +1 -0
  329. package/ios/Options/ANNOptions.h +25 -0
  330. package/ios/Options/ANNOptions.mm +157 -1
  331. package/ios/Options/ANNOptionsCache.h +7 -6
  332. package/ios/Options/ANNOptionsReader.mm +108 -0
  333. package/ios/Options/ANNSearchBarOptions.h +4 -3
  334. package/ios/Options/ANNSheetOptions.h +4 -1
  335. package/ios/Options/ANNSideMenuOptions.h +2 -0
  336. package/ios/Options/ANNSideMenuOptions.mm +2 -0
  337. package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
  338. package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
  339. package/ios/Options/ANNUserChoice.h +57 -0
  340. package/ios/Options/ANNUserChoice.mm +44 -0
  341. package/ios/Options/Params/ANNImageSource.h +61 -0
  342. package/ios/Options/Params/ANNImageSource.mm +101 -0
  343. package/ios/Options/Params/ANNOptionImages.h +37 -0
  344. package/ios/Options/Params/ANNOptionImages.mm +284 -0
  345. package/ios/Options/Params/ANNParam.h +15 -0
  346. package/ios/Options/Params/ANNParam.mm +61 -0
  347. package/ios/Options/Params/Color.h +3 -0
  348. package/ios/Options/Params/Color.mm +21 -0
  349. package/ios/Options/Params/ColorParser.h +4 -3
  350. package/ios/Options/Params/ColorParser.mm +22 -4
  351. package/ios/Options/Params/Image.h +15 -2
  352. package/ios/Options/Params/Image.mm +35 -2
  353. package/ios/Options/Params/ImageParser.h +5 -5
  354. package/ios/Options/Params/ImageParser.mm +28 -46
  355. package/ios/Public/ApexNavigation/ANNSceneDelegate.h +3 -0
  356. package/ios/Public/ApexNavigation/ApexNavigation.h +1 -1
  357. package/ios/RECIPES.md +13 -6
  358. package/ios/React/ANNReactView.mm +6 -25
  359. package/ios/React/ANNSafeAreaViewComponentView.mm +28 -17
  360. package/ios/React/ANNSurfaceHostingView.h +14 -0
  361. package/ios/React/ANNSurfaceHostingView.mm +144 -1
  362. package/ios/React/Slots/ANNSlotComponentView.mm +24 -17
  363. package/ios/React/Slots/ANNSlotContainers.h +14 -6
  364. package/ios/React/Slots/ANNSlotContainers.mm +75 -2
  365. package/ios/React/Slots/ANNSlotHost.mm +1 -3
  366. package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
  367. package/ios/TopBar/ANNBackButtonPresenter.mm +6 -5
  368. package/ios/TopBar/ANNBarAppearance.h +2 -1
  369. package/ios/TopBar/ANNBarAppearance.mm +111 -30
  370. package/ios/TopBar/ANNBarBackgroundComponent.mm +16 -0
  371. package/ios/TopBar/ANNBarButtonComponentView.h +4 -4
  372. package/ios/TopBar/ANNBarButtonComponentView.mm +1 -1
  373. package/ios/TopBar/ANNBarButtons.h +14 -8
  374. package/ios/TopBar/ANNBarButtons.mm +397 -80
  375. package/ios/TopBar/ANNIconButtonImage.h +1 -0
  376. package/ios/TopBar/ANNIconButtonImage.mm +34 -1
  377. package/ios/TopBar/ANNLargeTitlePresenter.h +13 -0
  378. package/ios/TopBar/ANNLargeTitlePresenter.mm +50 -7
  379. package/ios/TopBar/ANNMainList.h +3 -0
  380. package/ios/TopBar/ANNMainList.mm +4 -0
  381. package/ios/TopBar/ANNScrollEdgeEffects.h +22 -6
  382. package/ios/TopBar/ANNScrollEdgeEffects.mm +123 -16
  383. package/ios/TopBar/ANNSearchPresenter.mm +172 -21
  384. package/ios/TopBar/ANNSearchResultsViewController.mm +29 -6
  385. package/ios/TopBar/ANNTopBarPresenter.h +8 -2
  386. package/ios/TopBar/ANNTopBarPresenter.mm +155 -33
  387. package/ios/TurboModules/ANNTurboEventEmitter.mm +4 -35
  388. package/ios/TurboModules/ANNTurboModule.mm +104 -33
  389. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.cpp +20 -0
  390. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.h +5 -14
  391. package/lib/module/ARCHITECTURE.md +40 -27
  392. package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
  393. package/lib/module/api/app/AppRegistry.js +14 -2
  394. package/lib/module/api/app/AppRegistry.js.map +1 -1
  395. package/lib/module/api/app/createNavigation.js +190 -66
  396. package/lib/module/api/app/createNavigation.js.map +1 -1
  397. package/lib/module/api/commands/commands.js +54 -6
  398. package/lib/module/api/commands/commands.js.map +1 -1
  399. package/lib/module/api/events/navigationEvents.js +6 -2
  400. package/lib/module/api/events/navigationEvents.js.map +1 -1
  401. package/lib/module/api/hooks/useNavigation.js +8 -3
  402. package/lib/module/api/hooks/useNavigation.js.map +1 -1
  403. package/lib/module/api/hooks/useSafeAreaInsets.js +4 -3
  404. package/lib/module/api/hooks/useSafeAreaInsets.js.map +1 -1
  405. package/lib/module/api/linking/dispatchedLinks.js +23 -0
  406. package/lib/module/api/linking/dispatchedLinks.js.map +1 -0
  407. package/lib/module/api/linking/linking.js +11 -0
  408. package/lib/module/api/linking/linking.js.map +1 -1
  409. package/lib/module/api/navigation.js.map +1 -1
  410. package/lib/module/api/options/OptionsChain.js +2 -2
  411. package/lib/module/api/screens/defineScreen.js +45 -3
  412. package/lib/module/api/screens/defineScreen.js.map +1 -1
  413. package/lib/module/api/screens/nativeScreens.js +31 -6
  414. package/lib/module/api/screens/nativeScreens.js.map +1 -1
  415. package/lib/module/api/screens/registerScreens.js +193 -35
  416. package/lib/module/api/screens/registerScreens.js.map +1 -1
  417. package/lib/module/api/theme/theme.js +5 -0
  418. package/lib/module/api/theme/theme.js.map +1 -1
  419. package/lib/module/engine/commands.js +51 -9
  420. package/lib/module/engine/commands.js.map +1 -1
  421. package/lib/module/engine/layout.js +20 -11
  422. package/lib/module/engine/layout.js.map +1 -1
  423. package/lib/module/engine/nativeScreens.js +9 -0
  424. package/lib/module/engine/nativeScreens.js.map +1 -1
  425. package/lib/module/engine/options.js +49 -15
  426. package/lib/module/engine/options.js.map +1 -1
  427. package/lib/module/engine/optionsChange.js +102 -0
  428. package/lib/module/engine/optionsChange.js.map +1 -0
  429. package/lib/module/engine/places.js +52 -7
  430. package/lib/module/engine/places.js.map +1 -1
  431. package/lib/module/engine/props.js +30 -1
  432. package/lib/module/engine/props.js.map +1 -1
  433. package/lib/module/engine/refresh.js +85 -0
  434. package/lib/module/engine/refresh.js.map +1 -0
  435. package/lib/module/engine/rememberedOptions.js +61 -1
  436. package/lib/module/engine/rememberedOptions.js.map +1 -1
  437. package/lib/module/engine/screens.js +77 -16
  438. package/lib/module/engine/screens.js.map +1 -1
  439. package/lib/module/interfaces/contract/commands.json +101 -0
  440. package/lib/module/interfaces/contract/errors.json +275 -0
  441. package/lib/typescript/adapters/NativeANNTurboModule.d.ts +12 -2
  442. package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
  443. package/lib/typescript/api/app/AppRegistry.d.ts.map +1 -1
  444. package/lib/typescript/api/app/createNavigation.d.ts +8 -3
  445. package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
  446. package/lib/typescript/api/commands/commands.d.ts.map +1 -1
  447. package/lib/typescript/api/commands/presentation.d.ts +4 -3
  448. package/lib/typescript/api/commands/presentation.d.ts.map +1 -1
  449. package/lib/typescript/api/events/navigationEvents.d.ts +3 -3
  450. package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
  451. package/lib/typescript/api/hooks/useNavigation.d.ts +1 -1
  452. package/lib/typescript/api/hooks/useNavigation.d.ts.map +1 -1
  453. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts +4 -3
  454. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
  455. package/lib/typescript/api/index.d.ts +1 -1
  456. package/lib/typescript/api/index.d.ts.map +1 -1
  457. package/lib/typescript/api/linking/dispatchedLinks.d.ts +7 -0
  458. package/lib/typescript/api/linking/dispatchedLinks.d.ts.map +1 -0
  459. package/lib/typescript/api/linking/linking.d.ts +8 -0
  460. package/lib/typescript/api/linking/linking.d.ts.map +1 -1
  461. package/lib/typescript/api/navigation.d.ts +4 -1
  462. package/lib/typescript/api/navigation.d.ts.map +1 -1
  463. package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
  464. package/lib/typescript/api/screens/defineScreen.d.ts +23 -4
  465. package/lib/typescript/api/screens/defineScreen.d.ts.map +1 -1
  466. package/lib/typescript/api/screens/nativeScreens.d.ts +8 -1
  467. package/lib/typescript/api/screens/nativeScreens.d.ts.map +1 -1
  468. package/lib/typescript/api/screens/registerScreens.d.ts.map +1 -1
  469. package/lib/typescript/api/theme/theme.d.ts +2 -0
  470. package/lib/typescript/api/theme/theme.d.ts.map +1 -1
  471. package/lib/typescript/engine/commands.d.ts +5 -0
  472. package/lib/typescript/engine/commands.d.ts.map +1 -1
  473. package/lib/typescript/engine/layout.d.ts.map +1 -1
  474. package/lib/typescript/engine/nativeScreens.d.ts +5 -0
  475. package/lib/typescript/engine/nativeScreens.d.ts.map +1 -1
  476. package/lib/typescript/engine/options.d.ts +5 -2
  477. package/lib/typescript/engine/options.d.ts.map +1 -1
  478. package/lib/typescript/engine/optionsChange.d.ts +28 -0
  479. package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
  480. package/lib/typescript/engine/places.d.ts +7 -2
  481. package/lib/typescript/engine/places.d.ts.map +1 -1
  482. package/lib/typescript/engine/props.d.ts +8 -1
  483. package/lib/typescript/engine/props.d.ts.map +1 -1
  484. package/lib/typescript/engine/refresh.d.ts +35 -0
  485. package/lib/typescript/engine/refresh.d.ts.map +1 -0
  486. package/lib/typescript/engine/rememberedOptions.d.ts +13 -0
  487. package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
  488. package/lib/typescript/engine/screens.d.ts +27 -6
  489. package/lib/typescript/engine/screens.d.ts.map +1 -1
  490. package/lib/typescript/interfaces/ComponentEvents.d.ts +4 -4
  491. package/lib/typescript/interfaces/ComponentEvents.d.ts.map +1 -1
  492. package/lib/typescript/interfaces/Events.d.ts +28 -10
  493. package/lib/typescript/interfaces/Events.d.ts.map +1 -1
  494. package/lib/typescript/interfaces/Options.d.ts +1 -1
  495. package/lib/typescript/interfaces/Options.d.ts.map +1 -1
  496. package/lib/typescript/interfaces/options/animations.d.ts +80 -22
  497. package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
  498. package/lib/typescript/interfaces/options/bottomTabs.d.ts +21 -7
  499. package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
  500. package/lib/typescript/interfaces/options/buttons.d.ts +23 -15
  501. package/lib/typescript/interfaces/options/buttons.d.ts.map +1 -1
  502. package/lib/typescript/interfaces/options/modals.d.ts +34 -26
  503. package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
  504. package/lib/typescript/interfaces/options/sideMenu.d.ts +23 -6
  505. package/lib/typescript/interfaces/options/sideMenu.d.ts.map +1 -1
  506. package/lib/typescript/interfaces/options/stack.d.ts +17 -3
  507. package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
  508. package/lib/typescript/interfaces/options/system.d.ts +18 -11
  509. package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
  510. package/lib/typescript/interfaces/options/toolbar.d.ts +2 -2
  511. package/lib/typescript/interfaces/options/topBar.d.ts +68 -38
  512. package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
  513. package/metro/acceptPlugin.js +57 -0
  514. package/metro/babelTransformer.js +45 -0
  515. package/metro/index.js +36 -0
  516. package/package.json +4 -25
  517. package/src/ARCHITECTURE.md +40 -27
  518. package/src/adapters/NativeANNTurboModule.ts +12 -2
  519. package/src/api/app/AppRegistry.ts +16 -2
  520. package/src/api/app/createNavigation.ts +203 -69
  521. package/src/api/commands/commands.ts +48 -7
  522. package/src/api/commands/presentation.ts +4 -3
  523. package/src/api/events/navigationEvents.ts +10 -4
  524. package/src/api/hooks/useNavigation.ts +9 -4
  525. package/src/api/hooks/useSafeAreaInsets.ts +4 -3
  526. package/src/api/index.ts +1 -0
  527. package/src/api/linking/dispatchedLinks.ts +18 -0
  528. package/src/api/linking/linking.ts +22 -1
  529. package/src/api/navigation.ts +4 -1
  530. package/src/api/options/OptionsChain.ts +2 -2
  531. package/src/api/screens/defineScreen.ts +49 -5
  532. package/src/api/screens/nativeScreens.ts +40 -4
  533. package/src/api/screens/registerScreens.tsx +185 -42
  534. package/src/api/theme/theme.ts +5 -0
  535. package/src/engine/commands.ts +70 -13
  536. package/src/engine/layout.ts +27 -11
  537. package/src/engine/nativeScreens.ts +10 -1
  538. package/src/engine/options.ts +45 -19
  539. package/src/engine/optionsChange.ts +107 -0
  540. package/src/engine/places.ts +65 -7
  541. package/src/engine/props.ts +30 -1
  542. package/src/engine/refresh.ts +97 -0
  543. package/src/engine/rememberedOptions.ts +74 -1
  544. package/src/engine/screens.tsx +76 -21
  545. package/src/interfaces/ComponentEvents.ts +4 -4
  546. package/src/interfaces/Events.ts +29 -10
  547. package/src/interfaces/Options.ts +1 -0
  548. package/src/interfaces/contract/commands.json +101 -0
  549. package/src/interfaces/contract/errors.json +275 -0
  550. package/src/interfaces/options/animations.ts +81 -22
  551. package/src/interfaces/options/bottomTabs.ts +21 -7
  552. package/src/interfaces/options/buttons.ts +23 -15
  553. package/src/interfaces/options/modals.ts +34 -26
  554. package/src/interfaces/options/sideMenu.ts +24 -6
  555. package/src/interfaces/options/stack.ts +17 -3
  556. package/src/interfaces/options/system.ts +18 -11
  557. package/src/interfaces/options/toolbar.ts +2 -2
  558. package/src/interfaces/options/topBar.ts +68 -38
  559. package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -41
  560. package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -69
  561. package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationStateReporter.kt +0 -62
  562. package/android/src/main/java/dev/apexnative/navigation/react/events/StateHold.kt +0 -62
  563. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowPlacer.kt +0 -223
  564. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStub.kt +0 -31
  565. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +0 -138
  566. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -88
  567. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PropertyAnimatorCreator.kt +0 -33
  568. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +0 -66
  569. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +0 -179
  570. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -139
  571. package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
  572. package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -68
  573. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.h +0 -27
  574. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.mm +0 -55
package/android/CORE.md CHANGED
@@ -10,7 +10,7 @@ otherwise.
10
10
  ```
11
11
  JS ─ ANNTurboModule (codegen NativeANNTurboModuleSpec)
12
12
  │ sync getters answer on the JS thread from stores the main thread fills
13
- │ (ScreenInsets, ScreenRegions, ArrangementStates, Hinge, StartInfo)
13
+ │ (ScreenEnvironment, Hinge, StartInfo)
14
14
  ▼ module thread
15
15
  react/NavigationTurboModule one override per method
16
16
  │ layout/LayoutReader ► options/OptionsReader the whole layout read and checked, its options read
@@ -31,7 +31,7 @@ coordinators: RootCoordinator · StackQueue (one per stack) · ModalCoordinator
31
31
  presenters: ComponentPresenter · StackPresenter + TopBarPresenter · BottomTabsPresenter · SideMenuPresenter ·
32
32
  SplitViewPresenter · system/SystemUiOwner (status bar, navigation bar, orientation, keyboard)
33
33
  ▼
34
- react/events/AppearanceDispatcher ─► NavigationStateReporter ─► EventEmitter ─► ANN.* events ─► JS
34
+ react/events/AppearanceDispatcher ─► NavigationState ─► EventEmitter ─► ANN.* events ─► JS
35
35
  ```
36
36
 
37
37
  - **Way in.** `NavigationTurboModule` only turns a method into a `CommandRunner` call; it holds no navigation logic. It
@@ -72,18 +72,24 @@ react/events/AppearanceDispatcher ─► NavigationStateReporter ─► EventEmi
72
72
  5. **Make and join.** `LayoutFactory.create` makes Profile (a `ComponentViewController`, registered in the
73
73
  `ChildControllersRegistry`); `StackController.join` adds it; `StackQueue.push` accepts it as an entry.
74
74
  6. **`StackQueue`** is the only way to change a stack's children. `drain` starts the operation when nothing blocks it.
75
- `startPush` decides the wait: none, `waitForRender`, or a prepared push. A wait is a `RenderWait` on Profile, and the
76
- queue's `deliver` posts readiness signals to the next turn of the loop.
75
+ `startPush` decides the wait: a prepared push; `waitForRender: true` (as long as it takes); unset, for a screen with
76
+ React content, Profile's first mount, 0.5 s at most (`PUSH_WAIT_MILLIS`); none for `false`, a native screen or a
77
+ stack off screen. A wait is a `RenderWait` on Profile. Its mount reaches the push through the queue's `afterCalls`
78
+ (`PendingCalls`: once through the JavaScript thread, the module's thread and the main thread, the way of a
79
+ `mergeOptions`), so the `mergeOptions` of the commit that mounted it (`useScreenOptions`) has applied when the
80
+ transition starts, content mounted before the push too; the prepared push starts the same way after its slot
81
+ mounted. Unset, the targets of elements take what is left of the 0.5 s.
77
82
  7. **Begin.** `beginPush` raises Profile's view (`StackViews`), moves the bar and the tab bar
78
83
  (`StackQueue.Host.barTransition`, `tabBarTransition`), calls `StackController` through `currentChildChanged`, then
79
84
  `AppearanceDispatcher.beginTransition`: **`ComponentWillAppear`** of Profile. The transition runs
80
85
  (`StackTransitions`, `SystemTransition`, or the screens' own animation, `AnimationRules.stackIsOwn`).
81
86
  8. **End.** `finishPush` calls `AppearanceDispatcher.endTransition`: **`ComponentDidDisappear`** of Home, then
82
- **`ComponentDidAppear`** of Profile, then `reportState` (**`NavigationStateChanged`**, only if it changed), then the
83
- transition's own events (none for a push), then `CommandAnswer.resolve` with Profile's id.
84
- 9. **Answer.** `resolve` sends the state once more if it changed (`AnswerEvents.beforeAnswer`), resolves the promise,
85
- then sends **`CommandCompleted`** (`COMPLETED_COMMANDS`). After the task, `BackCallbackState.update` recomputes what
86
- back does.
87
+ **`ComponentDidAppear`** of Profile, then the answer's one state step (`CommandAnswer.reportStateNow`:
88
+ **`NavigationStateChanged`**, only if it changed), then the transition's own events (none for a push), then
89
+ `CommandAnswer.resolve` with Profile's id.
90
+ 9. **Answer.** `resolve` sends the state only when no transition sent it (`reportStateNow` runs once per answer: a
91
+ `setRoot` with layout modals sends it here), resolves the promise, then sends **`CommandCompleted`**
92
+ (`CommandContract.COMPLETED`). After the task, `BackCallbackState.update` recomputes what back does.
87
93
 
88
94
  The events go from the main thread, synchronously, through `EventEmitter.current()`; the promise is answered once.
89
95
 
@@ -91,7 +97,9 @@ The events go from the main thread, synchronously, through `EventEmitter.current
91
97
  current root in the root layer, transparent (`RootLayerViews.place`), so its React roots start while the old root keeps
92
98
  the touches. It waits (`RenderWait`, by `animations.setRoot.enter.waitForRender`), then fades through or plays its own
93
99
  animation, the old root is destroyed with its `ComponentDidDisappear`, `NativeScreenReleased` and `SlotDestroyed`, and
94
- the end steps and answer are the same. The layout's modals and overlays show after it, one by one, before the answer.
100
+ the end steps and answer are the same. The layout's modals and overlays show after it, one by one, before the answer;
101
+ its modals are made with the root and render unseen in the modals layer, held (`ModalCoordinator.hold`), so each
102
+ shows in its turn without a wait of its own.
95
103
  The last `setRoot` wins: an older one is rejected (`ErrorTexts.setRootReplaced`) or finished at once.
96
104
  - **`showModal`** (`Navigator.showModal`, `ModalCoordinator.show`). One `ModalRecord` per modal; it joins the modals
97
105
  layer unseen (`ModalViews`), waits with its own `RenderWait`, then slides in (or opens as a `ModalSheet`). It shows
@@ -120,13 +128,16 @@ Each rule has one owner. Change the owner, not a caller; if a new feature needs
120
128
  `beginTransition` starts the appearances; `endTransition` runs what left, then what came, then the state, then the
121
129
  transition's events, then the answer. Events asked before a screen's content is ready are held in its
122
130
  `ScreenAppearance` (until the content mounts or `HOLD_LIMIT_MILLIS`).
123
- - **Navigation state.** `AppearanceDispatcher.state` (`StateUpdates`) is the one way to ask for it: `StateHold`
124
- coalesces the asks to one posted update per pass of the main loop and keeps it while held; the update calls
125
- `NavigationStateReporter.updateNow`. `updateNow` also runs before every answer of a command that changes what shows
126
- (`CommandAnswer`) and is never held. It reads the navigator through `Navigators.current()`, and `stateOf` finds the
131
+ - **Navigation state.** `NavigationState` owns it: the last state sent, the walk (`stateOf`), the posted update and its
132
+ holds (`NavigationState.Updates`). `AppearanceDispatcher.state` (`StateUpdates`) is the one way to ask for it:
133
+ `setNeedsUpdate` coalesces the asks to one posted update per pass of the main loop and keeps it while held; the
134
+ update calls `updateNow`. A command's answer sends it once, at once and never held (`CommandAnswer.reportStateNow`):
135
+ at the end of its transition, else right before its promise for the commands that change what shows; nothing for a
136
+ JavaScript that went. It reads the navigator through `Navigators.current()`, and `stateOf` finds the
127
137
  `tab` as the nearest tabs of the visible screen (the last tabs met walking down from the visible layout). A `setRoot`
128
138
  with layout modals or overlays takes `AppearanceDispatcher.StateUpdates.hold()` and releases it right before its
129
- answer, so JavaScript hears one state; every hold has one `release()`.
139
+ answer, so JavaScript hears one state; every hold has one `release()`. The holds go when the JavaScript goes
140
+ (`NavigationState.javaScriptWent`), so one left by its `setRoot` never holds the next JavaScript's updates.
130
141
  - **Answer.** `CommandAnswer`: resolves or rejects once, and nothing once the JavaScript went. The id a stack entry
131
142
  answers with is one rule, `StackController.answerIdOf` (the queue asks it through `StackQueue.Host.answerIdOf` with
132
143
  an `AnswerKind`): `push` answers the entry's own id (a pair's), every other command the screen it stands for (a
@@ -134,7 +145,11 @@ Each rule has one owner. Change the owner, not a caller; if a new feature needs
134
145
  - **Stack queue.** `StackQueue`: every command, back and return of a container goes through it; it keeps `entries`
135
146
  (what JavaScript sees) and `shown` (what the container shows) and answers once.
136
147
  - **Screen readiness.** `ScreenReadiness` (by id; written by `SafeAreaView`) and `ContentReadiness` (the `Readiness`
137
- the waits ask, through `IReactView.isReady`).
148
+ the waits ask, through `IReactView.isReady`). As on iOS, the signals are kept (a listener that comes later hears them
149
+ at once), an id has a listener per key (several roots of one bar component), and each signal carries the React
150
+ surface it came from: a `ReactView` takes only its own surface's, so an old root with the same id never makes a new
151
+ one ready. An id renders at once while a root marks it (`ReactView`'s `rendersAtOnce`); the last one takes the id's
152
+ signals with it. A screen's id is cleared as the screen is made and destroyed, everything on reload.
138
153
  - **Render wait.** `RenderWait`: the one wait for screens to render, used by `RootCoordinator`, `ModalCoordinator`,
139
154
  `OverlayCoordinator` and `StackQueue`; `RenderWait.waitedScreens` walks `ParentController.waitedChildren()` at every
140
155
  level. What differs between users are values (limit, bar phase, unknown-content rule), never steps.
@@ -164,12 +179,16 @@ Each rule has one owner. Change the owner, not a caller; if a new feature needs
164
179
  - **Back.** `NavigationActivity.passBack` → `ReactGateway.onBackPressed` (JavaScript's `BackHandler`) →
165
180
  `invokeDefaultOnBackPressed` → `Navigator.handleBack` → `ModalCoordinator.handleBack` → the root's
166
181
  `ParentController.handleBack` → `StackController.handleBack` → `StackQueue.cut`. `BackCallbackState` keeps the
167
- system callback enabled only while back has something to do.
168
- - **Error texts.** `ErrorTexts`: one function per text, the same words as iOS. JavaScript adds `[navigation] <command>:`.
182
+ system callback enabled only while back has something to do, computed again on the events that change it (its KDoc
183
+ lists them), never before each frame; debug builds check it (`BackCallbackCheck`).
184
+ - **Error texts.** `ErrorTexts`: one function per text, the same words as iOS, made with iOS's from
185
+ `src/interfaces/contract/errors.json` (`scripts/contract.mjs`). JavaScript adds `[navigation] <command>:`.
186
+ - **Event names and keys.** `EventContract`, made from the event types of `src/interfaces/`; `EventEmitter` and the
187
+ builders of payloads use it, never a string.
169
188
  - **Room for the bars.** A screen's room at the top and bottom is `ScreenFrame` with `ScreenSafeArea` and the
170
189
  `ParentController` room hooks (`getTopInset`, `keepsStatusBarRoomOf`, …). A screen in a pair forwards its room to
171
190
  the pair (`ScreenFrame.applyRoom`), and the pair's `getTopInset` uses the screens' rule (`ScreenFrame.topRoomOf`)
172
- with the options it shows with. A view's place in the window for the safe area (the React root, the stack's header
191
+ with the options it shows with. The bottom edge is not padded by default (only `'bottom'` in the edges pads it); `roomPadding` still shrinks the view for an opaque navigation bar and the keyboard. A view's place in the window for the safe area (the React root, the stack's header
173
192
  bottom in `headerBottomOf`, the tabs' top in `tabsTopOf`) is `RestPlace`: from layout, without translations, a sheet
174
193
  at rest.
175
194
  - **A container's own move.** A container that moves children in or out of the window without a command (the split
@@ -188,11 +207,12 @@ Modules are the feature classes that plug into the core through its contract (th
188
207
  custom row (`BottomTabsCustomRowOptions`).
189
208
  - **Views and helpers:** tabs bar (`BottomTabs`, `BottomTabItem`, `BottomTabsCollapseBehavior`, `scrollToTop`), slots
190
209
  (`SlotHost`, `SlotView`, `SlotContainers`), safe area (`SafeAreaView`), native screens (`nativescreen/`), splash
191
- (`splash/`), animations (`FadeThrough`, `SystemTransition`, `TransitionTargets`, three element animators), utils
192
- (`MaterialTheme`, `NavigationLog`, `awaitBarComponents`, `whenDrawn`).
193
- - **Stores and singletons:** regions (`Hinge`, `ScreenInsets`, `ScreenRegions`, `WindowFolds`), pair state
194
- (`ArrangementStates`), links (`LaunchLink`, `StartInfo`), events (`NavigationStateReporter`), commands
195
- (`BackCallbackState`), stack (`PreparedFrame`).
210
+ (`splash/`), animations (`FadeThrough`, `SystemTransition`, `TransitionTargets`, the copies of shared elements:
211
+ `TextMorph`, `ViewMorph`, `ImageMorph`), utils (`MaterialTheme`, `NavigationLog`, `awaitBarComponents`,
212
+ `whenDrawn`).
213
+ - **Stores and singletons:** a screen's environment (`ScreenEnvironment`: its insets and padding, its regions as
214
+ `ScreenRegions` measures them, its pair state), the window (`Hinge`, `WindowFolds`), links (`LaunchLink`,
215
+ `StartInfo`), events (`NavigationState`), commands (`BackCallbackState`), stack (`PreparedFrame`).
196
216
 
197
217
  How they plug in:
198
218
 
@@ -216,4 +236,8 @@ How they plug in:
216
236
  - **Core code in a module's folder:** `viewcontrollers/splitview/SplitViewPresenter.kt`, `slots/SlotScreenView.kt`,
217
237
  and in `views/animations/` and `views/element/` everything except the files named above.
218
238
  - **Stores** are written on the main thread by the core and read from any thread; they are cleared with their nodes and on
219
- reload.
239
+ reload. A screen's environment is one immutable record per id in `ScreenEnvironment` (insets for JavaScript, padding,
240
+ regions, pair state), replaced at once; the screen's node clears it with one `remove` when it is destroyed, unless a
241
+ later node has its id; the padding listeners of its safe area views stay until the views stop. Their events, and
242
+ the search's, go through the emitter of the JavaScript the screen was made for
243
+ (`EventEmitter.of(node.jsGeneration)`); the hinge keeps the `EventEmitter.current()` of the call that turned it on.
@@ -14,7 +14,11 @@ The steps for adding an option and for adding a command to the Android core; rea
14
14
  (a repaint after a light/dark switch or `setDefaultOptions`); a system-bar option goes through `SystemUiRules`.
15
15
  Read colors with `ThemeColour.get` at apply so they follow the theme.
16
16
  4. The cache needs nothing: own options are written only through `ViewController.options`, `changeOptions` and
17
- `mergeOptions`, defaults only through `DefaultOptions.set`. Never change a resolved result.
17
+ `mergeOptions` (`mergeOwnOptions`), defaults only through `DefaultOptions.set`. Never change a resolved result.
18
+ What the user chooses in the native UI (a menu's check, a search scope) is not written into own options: it goes
19
+ into the node's user layer through `ViewController.changeChoices` (`options/UserChoices.kt`), which applies it by
20
+ id over the resolved options and lets it go when a merge changes that field. A new kind of choice is a field of
21
+ `UserChoices` with its `applyTo` and `yieldTo`; `changeOptions` stays for the library's own bookkeeping of a merge.
18
22
  5. Tests: add the field to `OptionsFixture.full()`. `WholeTreeTest` walks the tree by reflection and fails when a field
19
23
  is not read, copied, merged or defaulted. Add cases to `ReadersTest`, `MergeRuleTest` and the area's rules test.
20
24
  6. The docs page and a Showcase control; one meaning on both platforms, and where Android can't do it the JSDoc says so
@@ -29,11 +33,14 @@ The steps for adding an option and for adding a command to the Android core; rea
29
33
  3. The body goes to the owner of the area: `Navigator` (root, modals, overlays), `StackCommands` (stacks), a
30
34
  coordinator. A stack operation is a `StackQueue` operation.
31
35
  4. New layout fields are read and checked in `LayoutReader`; checks against what shows are in `LayoutChecks` or in the
32
- command, before any node is made. Every rejection text is a function in `ErrorTexts` (same words as iOS).
33
- 5. The answer goes through `CommandAnswer`: add the name to `COMPLETED_COMMANDS` when the command changes what shows
34
- (then the state, the promise and `CommandCompleted` follow in that order). A transition ends through
36
+ command, before any node is made. Every rejection text is a function in `ErrorTexts` (same words as iOS),
37
+ made by `node scripts/contract.mjs` from `src/interfaces/contract/errors.json`: a new text goes there.
38
+ 5. The answer goes through `CommandAnswer`: give the command its entry in `src/interfaces/contract/commands.json`
39
+ (what it resolves with, `state` when it may change what shows, `completed` when it shows or dismisses) and run
40
+ `node scripts/contract.mjs`, which makes `CommandContract` (then the state, the promise and `CommandCompleted` follow
41
+ in that order). A transition ends through
35
42
  `AppearanceDispatcher.endTransition`.
36
43
  6. Tests: `CommandRunnerTest`, `CommandAnswerTest`, `ErrorTextsTest`, `LayoutReaderTest`; a stack operation also needs a
37
44
  case in the queue tests (`StackQueueHarness`).
38
- 7. A new event: `EventEmitter` (`emit…`), the payload type in `src/interfaces`, and for an appearance event the
39
- `AppearanceDispatcher.Sender`.
45
+ 7. A new event: the payload type in `src/interfaces`, then `node scripts/contract.mjs` for its name and keys in
46
+ `EventContract`; `EventEmitter` (`emit…`) with those, and for an appearance event the `AppearanceDispatcher.Sender`.
@@ -1,2 +1,8 @@
1
1
  # The native screens `npx apex-navigation codegen` lists in the app: the navigation finds the list by its name.
2
2
  -keep class dev.apexnative.navigation.generated.ApexNavigationGeneratedScreens { *; }
3
+
4
+ # The library's C++ measures a React root's content through the surface's handler, which it reads by this getter's
5
+ # name (`android/src/main/jni/ANNContentHeights.cpp`).
6
+ -keepclassmembers class com.facebook.react.runtime.ReactSurfaceImpl {
7
+ com.facebook.react.fabric.SurfaceHandlerBinding getSurfaceHandler();
8
+ }
@@ -11,6 +11,7 @@ import android.view.View
11
11
  import android.view.ViewGroup
12
12
  import android.view.ViewTreeObserver
13
13
  import android.widget.EditText
14
+ import androidx.activity.BackEventCompat
14
15
  import androidx.activity.OnBackPressedCallback
15
16
  import androidx.activity.SystemBarStyle
16
17
  import androidx.activity.enableEdgeToEdge as enableActivityEdgeToEdge
@@ -34,9 +35,12 @@ import dev.apexnative.navigation.splash.SplashTheme
34
35
  import dev.apexnative.navigation.splash.SplashView
35
36
  import dev.apexnative.navigation.system.SystemUiWindow
36
37
  import dev.apexnative.navigation.utils.MaterialTheme
38
+ import dev.apexnative.navigation.viewcontrollers.modal.SheetBack
39
+ import dev.apexnative.navigation.viewcontrollers.navigator.BackCallbackCheck
37
40
  import dev.apexnative.navigation.viewcontrollers.navigator.BackCallbackState
38
41
  import dev.apexnative.navigation.viewcontrollers.navigator.Navigator
39
42
  import dev.apexnative.navigation.viewcontrollers.navigator.Navigators
43
+ import dev.apexnative.navigation.viewcontrollers.stack.StackController
40
44
 
41
45
  /**
42
46
  * The activity of an app with the navigation: its content holds, bottom to top, the copy of the splash and the layers
@@ -67,14 +71,75 @@ open class NavigationActivity : AppCompatActivity(), DefaultHardwareBackBtnHandl
67
71
  private val reloadBroadcast = ReloadBroadcast(this) { reloadFromDeveloperTools() }
68
72
 
69
73
  // Enabled while back has something to do in the app (BackCallbackState); otherwise the system does its own back.
74
+ // From Android 14, where the app hears the progress of the back gesture, a gesture that would pop a stack with the
75
+ // default transition previews the pop as the system previews back between activities (`StackController
76
+ // .BackGesture`), and one that would dismiss a sheet previews its hide as Material's sheets do (`SheetBack`), its
77
+ // release closing it as a drag down does; JavaScript's listeners hear back first, so with them there is no preview.
70
78
  private val backCallback = object : OnBackPressedCallback(false) {
71
- override fun handleOnBackPressed() = passBack()
79
+ override fun handleOnBackStarted(backEvent: BackEventCompat) {
80
+ backGesture = null
81
+ sheetGesture = null
82
+ val navigator = navigator ?: return
83
+ backCheck?.atBack(navigator)
84
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE || BackCallbackState.hasJsListeners) return
85
+ val stack = navigator.stackPoppedByBack()
86
+ if (stack != null) {
87
+ backGesture = stack.startBackGesture(backEvent.swipeEdge == BackEventCompat.EDGE_LEFT, backEvent.touchY)
88
+ return
89
+ }
90
+ sheetGesture = navigator.sheetDismissedByBack()?.startBackPreview(backEvent)
91
+ }
92
+
93
+ override fun handleOnBackProgressed(backEvent: BackEventCompat) {
94
+ backGesture?.progress(backEvent.progress, backEvent.touchY)
95
+ sheetGesture?.progress(backEvent)
96
+ }
97
+
98
+ override fun handleOnBackCancelled() {
99
+ backGesture?.cancel()
100
+ backGesture = null
101
+ sheetGesture?.cancel()
102
+ sheetGesture = null
103
+ navigator?.let(BackCallbackState::update)
104
+ }
105
+
106
+ override fun handleOnBackPressed() {
107
+ navigator?.let { backCheck?.atBack(it) }
108
+ val gesture = backGesture
109
+ backGesture = null
110
+ val sheet = sheetGesture
111
+ sheetGesture = null
112
+ when {
113
+ gesture?.commit() == true -> BackCallbackState.update()
114
+ sheet != null && commitSheet(sheet) -> BackCallbackState.update()
115
+ else -> passBack()
116
+ }
117
+ }
72
118
  }
73
119
 
74
- // Before each frame of the window: what back does may have changed, and the system decides at the start of a
75
- // gesture whether the app takes it.
76
- private val backBeforeFrame = ViewTreeObserver.OnPreDrawListener {
77
- navigator?.let(BackCallbackState::update)
120
+ // The back gesture that previews a pop now; none.
121
+ private var backGesture: StackController.BackGesture? = null
122
+
123
+ // The back gesture that previews a sheet's hide now; none.
124
+ private var sheetGesture: SheetBack.Gesture? = null
125
+
126
+ // A sheet's preview released: the sheet goes as the user's drag down closes it, and back doesn't go on (no
127
+ // `passBack`, which would dismiss it a second time). A command that changed what back does since the gesture
128
+ // started (a push in the sheet, a modal over it, a hold) leaves it to the usual back, the sheet back in place.
129
+ private fun commitSheet(gesture: SheetBack.Gesture): Boolean {
130
+ if (navigator?.sheetDismissedByBack() !== gesture.sheet) {
131
+ gesture.cancel()
132
+ return false
133
+ }
134
+ return gesture.commit()
135
+ }
136
+
137
+ // Debug builds only: the check that what back does never changes without its trigger (BackCallbackState), sampled
138
+ // before frames and at back events. It only logs; release builds have neither the check nor the listener.
139
+ private val backCheck = if (BuildConfig.DEBUG) BackCallbackCheck() else null
140
+ private val backCheckBeforeFrame = ViewTreeObserver.OnPreDrawListener {
141
+ val navigator = navigator
142
+ if (navigator != null) backCheck?.sample(navigator, SystemClock.uptimeMillis())
78
143
  true
79
144
  }
80
145
  private var frameObserver: ViewTreeObserver? = null
@@ -115,7 +180,9 @@ open class NavigationActivity : AppCompatActivity(), DefaultHardwareBackBtnHandl
115
180
  SlotHost.attachIfStarted(this)
116
181
  reactGateway.onActivityCreated(this)
117
182
  onBackPressedDispatcher.addCallback(this, backCallback)
118
- frameObserver = window.decorView.viewTreeObserver.also { it.addOnPreDrawListener(backBeforeFrame) }
183
+ if (backCheck != null) {
184
+ frameObserver = window.decorView.viewTreeObserver.also { it.addOnPreDrawListener(backCheckBeforeFrame) }
185
+ }
119
186
  // The activity's system UI: its owner remembers the theme's colors and the manifest's orientation now, before
120
187
  // anything changes them.
121
188
  navigator.systemUi.start(SystemUiWindow.of(this))
@@ -190,6 +257,8 @@ open class NavigationActivity : AppCompatActivity(), DefaultHardwareBackBtnHandl
190
257
  isNavigationResumed = true
191
258
  // The root, the modals and the overlays lay out again; nothing is sent.
192
259
  navigator?.onResume()
260
+ // A safety net: what back does changes on its own triggers, and the system asks the callback from here on.
261
+ navigator?.let(BackCallbackState::update)
193
262
  if (developerSupport() != null) reloadBroadcast.register()
194
263
  ReloadCoordinator.launchIfDue(this)
195
264
  }
@@ -211,6 +280,8 @@ open class NavigationActivity : AppCompatActivity(), DefaultHardwareBackBtnHandl
211
280
  override fun onWindowFocusChanged(hasFocus: Boolean) {
212
281
  super.onWindowFocusChanged(hasFocus)
213
282
  if (reactGateway.currentReactContext != null) reactGateway.host.onWindowFocusChange(hasFocus)
283
+ // A safety net, as at onResume: back after a dialog or another window over the activity.
284
+ if (hasFocus) navigator?.let(BackCallbackState::update)
214
285
  }
215
286
 
216
287
  override fun onUserLeaveHint() {
@@ -274,9 +345,11 @@ open class NavigationActivity : AppCompatActivity(), DefaultHardwareBackBtnHandl
274
345
  splashHold = null
275
346
  reloadBroadcast.release()
276
347
  navigator?.let(BackCallbackState::detach)
277
- // The window's observer now, and the one the listener was added to, if they differ.
278
- val observers = listOfNotNull(frameObserver, window?.peekDecorView()?.viewTreeObserver).distinct()
279
- observers.forEach { if (it.isAlive) it.removeOnPreDrawListener(backBeforeFrame) }
348
+ // The debug check's listener: from the window's observer now, and the one it was added to, if they differ.
349
+ if (backCheck != null) {
350
+ val observers = listOfNotNull(frameObserver, window?.peekDecorView()?.viewTreeObserver).distinct()
351
+ observers.forEach { if (it.isAlive) it.removeOnPreDrawListener(backCheckBeforeFrame) }
352
+ }
280
353
  frameObserver = null
281
354
  SlotHost.detach(this)
282
355
  navigator?.destroyWithActivity()
@@ -289,7 +362,9 @@ open class NavigationActivity : AppCompatActivity(), DefaultHardwareBackBtnHandl
289
362
  /**
290
363
  * Back that JavaScript's listeners didn't take: the navigation does its step first — a stack's top leaves or holds,
291
364
  * a pane closes —; with nothing to do there, the activity's own back, as without the navigation. An app may
292
- * override it (e.g. `moveTaskToBack(true)`).
365
+ * override it (e.g. `moveTaskToBack(true)`). The callback is off for that back only: the dispatcher's own back is
366
+ * the activity's, not [onBackPressed]; then it is computed again, and `hardwareBackButton.systemAnimation: false`
367
+ * turns it on again.
293
368
  */
294
369
  override fun invokeDefaultOnBackPressed() {
295
370
  val handled = navigator?.handleBack(CommandListenerAdapter()) == true
@@ -3,32 +3,49 @@ package dev.apexnative.navigation
3
3
  import android.app.Application
4
4
  import android.util.Log
5
5
  import com.facebook.react.ReactApplication
6
- import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint
7
- import com.facebook.react.soloader.OpenSourceMergedSoMapping
8
6
  import com.facebook.soloader.SoLoader
9
7
  import dev.apexnative.navigation.nativescreen.NativeScreenCreator
10
8
  import dev.apexnative.navigation.react.ReactGateway
11
9
  import dev.apexnative.navigation.utils.NavigationLog
12
10
 
13
11
  /**
14
- * The application class of an app with the navigation: it loads React Native itself (the app doesn't call
15
- * `loadReactNative`), keeps one React host for every screen ([reactGateway]) and the native screens by name. The app
16
- * gives the host (`reactHost`) and registers its native screens in its `onCreate`, after this one.
12
+ * The application class of an app with the navigation: it keeps one React host for every screen ([reactGateway]) and
13
+ * the native screens by name. The app gives the host (`reactHost`) and loads React Native in its `onCreate` as the
14
+ * React Native template does, so the load follows the app's Gradle settings (the New Architecture, edge-to-edge):
15
+ *
16
+ * ```kotlin
17
+ * override fun onCreate() {
18
+ * super.onCreate()
19
+ * loadReactNative(this)
20
+ * registerNativeScreen("Profile") { activity, context -> ProfileView(activity, context) }
21
+ * }
22
+ * ```
23
+ *
24
+ * The gateway, and with it the host, is made the first time something needs it (the first activity), after the app's
25
+ * `onCreate` loaded React Native.
17
26
  */
18
27
  abstract class NavigationApplication : Application(), ReactApplication {
19
28
  // Written on the main thread as the app registers, read on the module thread by the layout checks: under its lock.
20
29
  private val nativeScreens = LinkedHashMap<String, NativeScreenCreator>()
21
30
 
22
- /** The app's React host as the navigation runs it. */
23
- lateinit var reactGateway: ReactGateway
24
- private set
31
+ // Made once, by the first activity ([reactGateway]); [reactGatewayOrNull] only reads it.
32
+ private val gateway: Lazy<ReactGateway> = lazy {
33
+ check(SoLoader.isInitialized()) {
34
+ "NavigationApplication needs React Native loaded first: call loadReactNative(this) in onCreate, " +
35
+ "as the React Native template does"
36
+ }
37
+ createReactGateway()
38
+ }
39
+
40
+ /**
41
+ * The app's React host as the navigation runs it, made when it is first asked for (the first activity's
42
+ * `onCreate`). React Native must be loaded by then: the app calls `loadReactNative(this)` in its `onCreate`.
43
+ */
44
+ val reactGateway: ReactGateway by gateway
25
45
 
26
46
  override fun onCreate() {
27
47
  super.onCreate()
28
48
  instance = this
29
- SoLoader.init(this, OpenSourceMergedSoMapping)
30
- DefaultNewArchitectureEntryPoint.load()
31
- reactGateway = createReactGateway()
32
49
  registerGeneratedScreens()
33
50
  }
34
51
 
@@ -57,9 +74,13 @@ abstract class NavigationApplication : Application(), ReactApplication {
57
74
  internal fun isNativeScreenRegistered(name: String): Boolean =
58
75
  synchronized(nativeScreens) { nativeScreens.containsKey(name) }
59
76
 
60
- /** [reactGateway] once `onCreate` made it. */
77
+ /**
78
+ * [reactGateway] once the first activity made it; none before. It never makes it: its callers (the log, the
79
+ * events, a React root) may run first, also off the main thread, and the app's `reactHost` isn't theirs to make.
80
+ * Any thread.
81
+ */
61
82
  internal val reactGatewayOrNull: ReactGateway?
62
- get() = if (::reactGateway.isInitialized) reactGateway else null
83
+ get() = if (gateway.isInitialized()) gateway.value else null
63
84
 
64
85
  // The list of `npx apex-navigation codegen`, found by its name: an app without native screens has none.
65
86
  private fun registerGeneratedScreens() {
@@ -47,5 +47,9 @@ internal object LayoutChecks {
47
47
  */
48
48
  @JvmStatic
49
49
  fun checkStackChild(node: LayoutNode, stackId: String): String? =
50
- if (node.type in stackChildren) null else ErrorTexts.stackTakesScreens(stackId, node.type.jsName)
50
+ if (isStackChild(node)) null else ErrorTexts.stackTakesScreens(stackId, node.type.jsName)
51
+
52
+ /** Whether a stack takes [node]: a screen, a native screen or a pair, not a container. */
53
+ @JvmStatic
54
+ fun isStackChild(node: LayoutNode): Boolean = node.type in stackChildren
51
55
  }
@@ -82,10 +82,14 @@ internal data class LayoutNode(
82
82
  private val COLUMN_NAMES = setOf(PRIMARY, SECONDARY, SUPPLEMENTARY, COMPACT, INSPECTOR)
83
83
  private val COLUMNS_WITHOUT_NAMES = listOf(PRIMARY, SECONDARY)
84
84
 
85
- /** The column of the child at [index] of a split view with [columns]; none for a child without one. */
85
+ /**
86
+ * The column of the child at [index] of a split view with [columns]; none for a child without one, and none
87
+ * for a repeat of a name an earlier child has (the first takes the column), as on iOS.
88
+ */
86
89
  internal fun columnName(columns: List<String>, index: Int): String? {
87
90
  val names = columns.ifEmpty { COLUMNS_WITHOUT_NAMES }
88
- return names.getOrNull(index)?.takeIf { it in COLUMN_NAMES }
91
+ val name = names.getOrNull(index)?.takeIf { it in COLUMN_NAMES } ?: return null
92
+ return name.takeIf { names.indexOf(it) == index }
89
93
  }
90
94
  }
91
95
  }
@@ -44,8 +44,8 @@ class NativeScreenContext @RestrictTo(RestrictTo.Scope.LIBRARY) constructor(
44
44
 
45
45
  /**
46
46
  * Runs a command of the navigation from this screen in JS, as `useNavigation()` of a React screen does: push, pop,
47
- * popTo, popToRoot, showInColumn, showModal, dismiss, showOverlay, dismissOverlay, setOptions, selectTab,
48
- * setTabBadge. [arguments] are those of the JS command; [result] gets what it resolved with.
47
+ * popTo, popToRoot, showInColumn, showModal, dismiss, showOverlay, setOptions, selectTab, setTabBadge.
48
+ * [arguments] are those of the JS command; [result] gets what it resolved with.
49
49
  */
50
50
  @JvmOverloads
51
51
  fun navigate(command: String, arguments: JSONArray = JSONArray(), result: ((Result<Any?>) -> Unit)? = null) =
@@ -8,7 +8,7 @@ import com.facebook.react.bridge.ReadableMap
8
8
  */
9
9
  class AnimationsOptions {
10
10
  @JvmField var push = StackPushAnimationOptions()
11
- @JvmField var pop = StackAnimationOptions()
11
+ @JvmField var pop = StackPopAnimationOptions()
12
12
  @JvmField var setStackRoot = SetStackRootAnimationOptions()
13
13
  @JvmField var setRoot = EnterExitAnimationOptions()
14
14
  @JvmField var showModal = ModalAnimationOptions()
@@ -43,7 +43,7 @@ class AnimationsOptions {
43
43
  val options = AnimationsOptions()
44
44
  if (map == null) return options
45
45
  options.push = map.group("push") { StackPushAnimationOptions.parse(it) }
46
- options.pop = map.group("pop") { StackAnimationOptions.parse(it) }
46
+ options.pop = map.group("pop") { StackPopAnimationOptions.parse(it) }
47
47
  options.setStackRoot = map.group("setStackRoot") { SetStackRootAnimationOptions.parse(it) }
48
48
  options.setRoot = map.group("setRoot") { EnterExitAnimationOptions.parse(it) }
49
49
  options.showModal = map.group("showModal") { ModalAnimationOptions.parse(it) }
@@ -105,7 +105,7 @@ class BottomTabOptions {
105
105
  @JvmField var textColor: ThemeColour = NullThemeColour()
106
106
  @JvmField var selectedIconColor: ThemeColour = NullThemeColour()
107
107
  @JvmField var selectedTextColor: ThemeColour = NullThemeColour()
108
- @JvmField var font = FontOptions()
108
+ @ReadFromParent @JvmField var font = FontOptions()
109
109
  @JvmField var fontSize: Fraction = NullFraction()
110
110
  @JvmField var selectedFontSize: Fraction = NullFraction()
111
111
  @JvmField var iconInsets = IconInsetsOptions()
@@ -95,6 +95,7 @@ class BottomTabsAccessoryOptions {
95
95
  class BottomTabsOptions {
96
96
  @JvmField var visible: Bool = NullBool()
97
97
  @JvmField var animate: Bool = NullBool()
98
+ @JvmField var switchAnimation: Text = NullText()
98
99
  /** Selects a tab once; a whole number, truncated where it is read. */
99
100
  @JvmField var currentTabIndex: Fraction = NullFraction()
100
101
  /** Selects a tab once. */
@@ -124,18 +125,19 @@ class BottomTabsOptions {
124
125
  @JvmField var minimizeBehavior: Text = NullText()
125
126
  @JvmField var bottomAccessory = BottomTabsAccessoryOptions()
126
127
 
127
- fun hasValue(): Boolean = visible.hasValue() || animate.hasValue() || currentTabIndex.hasValue() ||
128
- currentTabId.hasValue() || testID.hasValue() || accessibilityLabel.hasValue() || moreTestID.hasValue() ||
129
- drawBehind.hasValue() || backgroundColor.hasValue() || tabsAttachMode.hasValue() || barStyle.hasValue() ||
130
- layoutStyle.hasValue() || cornerRadius.hasValue() || bottomMargin.hasValue() || translucent.hasValue() ||
131
- hideShadow.hasValue() || titleDisplayMode.hasValue() || elevation.hasValue() || hideOnScroll.hasValue() ||
132
- borderColor.hasValue() || borderWidth.hasValue() || shadow.hasValue() || customRow.hasValue() ||
133
- sidebar.hasValue() || sidebarLayout.hasValue() || customizationId.hasValue() || minimizeBehavior.hasValue() ||
134
- bottomAccessory.hasValue()
128
+ fun hasValue(): Boolean = visible.hasValue() || animate.hasValue() || switchAnimation.hasValue() ||
129
+ currentTabIndex.hasValue() || currentTabId.hasValue() || testID.hasValue() || accessibilityLabel.hasValue() ||
130
+ moreTestID.hasValue() || drawBehind.hasValue() || backgroundColor.hasValue() || tabsAttachMode.hasValue() ||
131
+ barStyle.hasValue() || layoutStyle.hasValue() || cornerRadius.hasValue() || bottomMargin.hasValue() ||
132
+ translucent.hasValue() || hideShadow.hasValue() || titleDisplayMode.hasValue() || elevation.hasValue() ||
133
+ hideOnScroll.hasValue() || borderColor.hasValue() || borderWidth.hasValue() || shadow.hasValue() ||
134
+ customRow.hasValue() || sidebar.hasValue() || sidebarLayout.hasValue() || customizationId.hasValue() ||
135
+ minimizeBehavior.hasValue() || bottomAccessory.hasValue()
135
136
 
136
137
  fun mergeWith(other: BottomTabsOptions) {
137
138
  if (other.visible.hasValue()) visible = other.visible
138
139
  if (other.animate.hasValue()) animate = other.animate
140
+ if (other.switchAnimation.hasValue()) switchAnimation = other.switchAnimation
139
141
  if (other.currentTabIndex.hasValue()) currentTabIndex = other.currentTabIndex
140
142
  if (other.currentTabId.hasValue()) currentTabId = other.currentTabId
141
143
  if (other.testID.hasValue()) testID = other.testID
@@ -167,6 +169,7 @@ class BottomTabsOptions {
167
169
  fun mergeWithDefault(defaults: BottomTabsOptions) {
168
170
  if (!visible.hasValue()) visible = defaults.visible
169
171
  if (!animate.hasValue()) animate = defaults.animate
172
+ if (!switchAnimation.hasValue()) switchAnimation = defaults.switchAnimation
170
173
  if (!currentTabIndex.hasValue()) currentTabIndex = defaults.currentTabIndex
171
174
  if (!currentTabId.hasValue()) currentTabId = defaults.currentTabId
172
175
  if (!testID.hasValue()) testID = defaults.testID
@@ -198,6 +201,7 @@ class BottomTabsOptions {
198
201
  fun copy() = BottomTabsOptions().also { it.mergeWith(this) }
199
202
 
200
203
  companion object {
204
+ private val SWITCH_ANIMATIONS = setOf("platform", "none")
201
205
  private val TABS_ATTACH_MODES = setOf("together", "afterInitialTab", "onSwitchToTab")
202
206
  private val BAR_STYLES = setOf("default", "black")
203
207
  private val LAYOUT_STYLES = setOf("stretch", "compact")
@@ -212,6 +216,7 @@ class BottomTabsOptions {
212
216
  if (map == null) return options
213
217
  options.visible = BoolParser.parse(map, "visible")
214
218
  options.animate = BoolParser.parse(map, "animate")
219
+ options.switchAnimation = TextParser.parse(map, "switchAnimation", SWITCH_ANIMATIONS)
215
220
  options.currentTabIndex = FractionParser.parse(map, "currentTabIndex")
216
221
  options.currentTabId = TextParser.parse(map, "currentTabId")
217
222
  options.testID = TextParser.parse(map, "testID")
@@ -8,8 +8,8 @@ import dev.apexnative.navigation.options.parsers.IconParser
8
8
  * A menu of the bar: `topBar.overflowMenu`, or the `menu` of a button. Its items, and submenus among them; with
9
9
  * `singleSelection` one item of a level has a checkmark at a time.
10
10
  *
11
- * Copied options share it, so the checkmark a pick moves stays with the screen when it appears again, until new
12
- * options give the menu again.
11
+ * Copied options share it, so nobody changes a menu in place but in a copy of its own: the check a user's pick moves
12
+ * lives in the screen's user layer (`UserChoices`), which goes into a copy as the screen's options resolve.
13
13
  */
14
14
  class ButtonMenuOptions(
15
15
  @JvmField val singleSelection: Boolean,
@@ -31,7 +31,7 @@ class ButtonOptions(@JvmField var id: Text = NullText()) {
31
31
  @JvmField var systemItem: Text = NullText()
32
32
  @JvmField var text: Text = NullText()
33
33
  @JvmField var accessibilityLabel: Text = NullText()
34
- @JvmField var font = FontOptions()
34
+ @ReadFromParent @JvmField var font = FontOptions()
35
35
  @JvmField var fontSize: Fraction = NullFraction()
36
36
  @JvmField var enabled: Bool = NullBool()
37
37
  @JvmField var disableIconTint: Bool = NullBool()
@@ -197,8 +197,8 @@ class ButtonOptions(@JvmField var id: Text = NullText()) {
197
197
 
198
198
  /**
199
199
  * A copy of the menu with new items and submenus and the same values. A menu taken from the default options is copied
200
- * first, so that the module's in-place `checked` never writes into [DefaultOptions.current]; copies between a node's
201
- * own and resolved options share the menu on purpose.
200
+ * first, so that nothing written into a resolved result reaches [DefaultOptions.current]; the user layer writes its
201
+ * checks into a copy too (`UserChoices`), and copies between a node's own and resolved options share the menu.
202
202
  */
203
203
  internal fun ButtonMenuOptions.copyMenu(): ButtonMenuOptions =
204
204
  ButtonMenuOptions(singleSelection, items.map(::copyElement), testID)