@apexnative/navigation 1.0.0-alpha.1 → 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 (573) hide show
  1. package/ApexNavigation.podspec +2 -1
  2. package/CHANGELOG.md +120 -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/docs-md/architecture/native-screens.md +4 -0
  175. package/docs-md/architecture/theme-and-context.md +131 -12
  176. package/docs-md/architecture/transitions.md +58 -12
  177. package/docs-md/containers/modals.md +8 -4
  178. package/docs-md/containers/overlays.md +3 -1
  179. package/docs-md/containers/side-menu.md +19 -2
  180. package/docs-md/containers/tabs.md +5 -1
  181. package/docs-md/flows/bottom-sheets.md +4 -2
  182. package/docs-md/flows/forms-in-a-modal.md +1 -1
  183. package/docs-md/fundamentals/screens-and-props.md +9 -1
  184. package/docs-md/fundamentals/starting-the-app.md +1 -1
  185. package/docs-md/guides/cli.md +4 -3
  186. package/docs-md/guides/deep-links.md +15 -33
  187. package/docs-md/help/glossary.md +4 -4
  188. package/docs-md/help/troubleshooting.md +44 -6
  189. package/docs-md/index.json +57 -1
  190. package/docs-md/migration/from-expo-router.md +1 -1
  191. package/docs-md/migration/from-react-native-navigation.md +9 -3
  192. package/docs-md/migration/from-react-navigation.md +2 -2
  193. package/docs-md/screen-ui/back-and-gestures.md +46 -2
  194. package/docs-md/screen-ui/bar-buttons.md +5 -5
  195. package/docs-md/screen-ui/search.md +1 -1
  196. package/docs-md/screen-ui/system-ui.md +17 -12
  197. package/docs-md/screen-ui/toolbar-and-fab.md +4 -2
  198. package/docs-md/screen-ui/top-bar.md +8 -4
  199. package/docs-md/start/installation.md +21 -3
  200. package/ios/Animations/ANNFrameDriver.h +55 -15
  201. package/ios/Animations/ANNFrameDriver.mm +216 -60
  202. package/ios/Animations/ANNTransitionAnimator.h +26 -5
  203. package/ios/Animations/ANNTransitionAnimator.mm +61 -13
  204. package/ios/Animations/ANNTransitionPlan.h +2 -2
  205. package/ios/Animations/ANNTransitionPlan.mm +10 -0
  206. package/ios/Animations/ANNTransitionWait.mm +6 -7
  207. package/ios/Animations/Elements/ANNElementFinder.h +57 -0
  208. package/ios/Animations/Elements/ANNElementFinder.mm +174 -2
  209. package/ios/Animations/Elements/ANNElementTransition.h +10 -8
  210. package/ios/Animations/Elements/ANNElementTransition.mm +19 -21
  211. package/ios/Animations/Elements/ANNSharedElementFlight.h +16 -11
  212. package/ios/Animations/Elements/ANNSharedElementFlight.mm +308 -69
  213. package/ios/Animations/Interpolators/ANNInterpolate.h +2 -30
  214. package/ios/Animations/Interpolators/ANNTransformParts.h +48 -0
  215. package/ios/Animations/Interpolators/ANNTransformParts.mm +507 -0
  216. package/ios/Animations/Interpolators/ANNViewTracks.h +9 -6
  217. package/ios/Animations/Interpolators/ANNViewTracks.mm +100 -30
  218. package/ios/CLAUDE.md +60 -24
  219. package/ios/CORE.md +44 -34
  220. package/ios/Contract/ANNCommandAnswer.h +13 -5
  221. package/ios/Contract/ANNCommandAnswer.mm +40 -32
  222. package/ios/Contract/ANNCommandContract.h +15 -0
  223. package/ios/Contract/ANNCommandContract.mm +78 -0
  224. package/ios/Contract/ANNCommandRunner.h +10 -9
  225. package/ios/Contract/ANNCommandRunner.mm +22 -28
  226. package/ios/Contract/ANNErrorTexts.h +6 -2
  227. package/ios/Contract/ANNErrorTexts.mm +18 -10
  228. package/ios/Contract/ANNLayoutNode.h +3 -3
  229. package/ios/Contract/ANNLayoutReader.h +3 -3
  230. package/ios/Core/ANNAppDelegate.mm +0 -2
  231. package/ios/Core/ANNAppearanceDispatcher.h +5 -4
  232. package/ios/Core/ANNAppearanceDispatcher.mm +12 -1
  233. package/ios/Core/ANNDeepLinkQueue.h +22 -2
  234. package/ios/Core/ANNDeepLinkQueue.mm +121 -14
  235. package/ios/Core/ANNErrorHandler.h +9 -4
  236. package/ios/Core/ANNErrorHandler.mm +20 -2
  237. package/ios/Core/ANNEventContract.h +246 -0
  238. package/ios/Core/ANNEventContract.mm +225 -0
  239. package/ios/Core/ANNEventEmitter.h +6 -2
  240. package/ios/Core/ANNEventEmitter.mm +117 -80
  241. package/ios/Core/ANNHinge.h +6 -0
  242. package/ios/Core/ANNHinge.mm +15 -4
  243. package/ios/Core/ANNJavaScriptCalls.h +33 -0
  244. package/ios/Core/ANNJavaScriptCalls.mm +52 -0
  245. package/ios/Core/ANNLayoutProtocol.h +5 -5
  246. package/ios/Core/ANNNavigationState.h +7 -5
  247. package/ios/Core/ANNNavigationState.mm +8 -7
  248. package/ios/Core/ANNNodeHelper.h +32 -12
  249. package/ios/Core/ANNNodeHelper.mm +100 -3
  250. package/ios/Core/ANNParking.h +5 -4
  251. package/ios/Core/ANNReloadCoordinator.mm +5 -12
  252. package/ios/Core/ANNRenderWait.h +20 -6
  253. package/ios/Core/ANNRenderWait.mm +143 -56
  254. package/ios/Core/ANNSceneDelegate.mm +25 -15
  255. package/ios/Core/ANNSystemUI.h +3 -2
  256. package/ios/Core/ANNSystemUI.mm +7 -0
  257. package/ios/Core/ANNUtils.h +7 -0
  258. package/ios/Core/ANNUtils.mm +10 -0
  259. package/ios/Core/ApexNavigation+Internal.h +1 -1
  260. package/ios/Core/ApexNavigation.mm +7 -6
  261. package/ios/Core/UIViewController+LayoutProtocol.h +9 -2
  262. package/ios/Core/UIViewController+LayoutProtocol.mm +8 -0
  263. package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
  264. package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
  265. package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +10 -8
  266. package/ios/Layouts/Modal/ANNModalCoordinator.h +1 -1
  267. package/ios/Layouts/Modal/ANNModalCoordinator.mm +57 -16
  268. package/ios/Layouts/Modal/ANNModalPresentation.h +8 -5
  269. package/ios/Layouts/Modal/ANNModalPresentation.mm +12 -12
  270. package/ios/Layouts/Modal/ANNSheetPresenter.mm +83 -1
  271. package/ios/Layouts/Overlay/ANNOverlayCoordinator.mm +2 -8
  272. package/ios/Layouts/Root/ANNRootCoordinator.mm +58 -19
  273. package/ios/Layouts/Root/ANNSplashViewController.h +5 -3
  274. package/ios/Layouts/Root/ANNSplashViewController.mm +147 -0
  275. package/ios/Layouts/Screen/ANNComponentPresenter.h +11 -3
  276. package/ios/Layouts/Screen/ANNComponentPresenter.mm +34 -6
  277. package/ios/Layouts/Screen/ANNComponentViewController.h +15 -13
  278. package/ios/Layouts/Screen/ANNComponentViewController.mm +130 -75
  279. package/ios/Layouts/Screen/ANNNativeScreenContext.mm +7 -5
  280. package/ios/Layouts/Screen/ANNPreviewInteraction.h +7 -4
  281. package/ios/Layouts/Screen/ANNPreviewInteraction.mm +72 -10
  282. package/ios/Layouts/Screen/ANNScreenEnvironment.h +63 -0
  283. package/ios/Layouts/Screen/ANNScreenEnvironment.mm +181 -0
  284. package/ios/Layouts/Screen/ANNScreenPlace.h +53 -0
  285. package/ios/Layouts/Screen/ANNScreenPlace.mm +205 -0
  286. package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
  287. package/ios/Layouts/Screen/ANNScreenRegions.mm +9 -44
  288. package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
  289. package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
  290. package/ios/Layouts/Screen/ANNScreenSettling.h +32 -0
  291. package/ios/Layouts/Screen/ANNScreenSettling.mm +137 -0
  292. package/ios/Layouts/SideMenu/ANNSideMenuTypes.h +8 -0
  293. package/ios/Layouts/SideMenu/ANNSideMenuViewController.mm +83 -14
  294. package/ios/Layouts/SplitView/ANNSplitViewCommands.h +3 -2
  295. package/ios/Layouts/SplitView/ANNSplitViewCommands.mm +105 -39
  296. package/ios/Layouts/SplitView/ANNSplitViewController.mm +7 -8
  297. package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
  298. package/ios/Layouts/Stack/ANNPreviewPush.mm +142 -27
  299. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
  300. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
  301. package/ios/Layouts/Stack/ANNStackCommands.mm +1 -0
  302. package/ios/Layouts/Stack/ANNStackController.h +8 -0
  303. package/ios/Layouts/Stack/ANNStackController.mm +184 -16
  304. package/ios/Layouts/Stack/ANNStackQueue.h +5 -2
  305. package/ios/Layouts/Stack/ANNStackQueue.mm +56 -43
  306. package/ios/Layouts/Stack/ANNSwipePopInteraction.h +26 -0
  307. package/ios/Layouts/Stack/ANNSwipePopInteraction.mm +185 -0
  308. package/ios/Layouts/Stack/InteractivePopGestureDelegate.mm +28 -4
  309. package/ios/Layouts/Stack/UINavigationController+ANNCommands.h +4 -2
  310. package/ios/Layouts/Stack/UINavigationController+ANNCommands.mm +2 -3
  311. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.h +4 -0
  312. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.mm +11 -0
  313. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
  314. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
  315. package/ios/Layouts/Tabs/ANNBottomTabsController.h +3 -0
  316. package/ios/Layouts/Tabs/ANNBottomTabsController.mm +237 -57
  317. package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
  318. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +6 -2
  319. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +232 -43
  320. package/ios/Layouts/Tabs/ANNTabsDesign.h +6 -5
  321. package/ios/Layouts/Tabs/ANNTabsDesign.mm +9 -1
  322. package/ios/Layouts/Tabs/UITabBar+utils.h +5 -5
  323. package/ios/Layouts/Tabs/UITabBar+utils.mm +32 -13
  324. package/ios/Options/ANNAnimationOptions.h +2 -1
  325. package/ios/Options/ANNAnimationOptions.mm +1 -1
  326. package/ios/Options/ANNBottomTabsOptions.h +2 -0
  327. package/ios/Options/ANNBottomTabsOptions.mm +1 -0
  328. package/ios/Options/ANNOptions.h +25 -0
  329. package/ios/Options/ANNOptions.mm +157 -1
  330. package/ios/Options/ANNOptionsCache.h +7 -6
  331. package/ios/Options/ANNOptionsReader.mm +108 -0
  332. package/ios/Options/ANNSearchBarOptions.h +4 -3
  333. package/ios/Options/ANNSheetOptions.h +4 -1
  334. package/ios/Options/ANNSideMenuOptions.h +2 -0
  335. package/ios/Options/ANNSideMenuOptions.mm +2 -0
  336. package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
  337. package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
  338. package/ios/Options/ANNUserChoice.h +57 -0
  339. package/ios/Options/ANNUserChoice.mm +44 -0
  340. package/ios/Options/Params/ANNImageSource.h +61 -0
  341. package/ios/Options/Params/ANNImageSource.mm +101 -0
  342. package/ios/Options/Params/ANNOptionImages.h +37 -0
  343. package/ios/Options/Params/ANNOptionImages.mm +284 -0
  344. package/ios/Options/Params/ANNParam.h +15 -0
  345. package/ios/Options/Params/ANNParam.mm +61 -0
  346. package/ios/Options/Params/Color.h +3 -0
  347. package/ios/Options/Params/Color.mm +21 -0
  348. package/ios/Options/Params/ColorParser.h +4 -3
  349. package/ios/Options/Params/ColorParser.mm +22 -4
  350. package/ios/Options/Params/Image.h +15 -2
  351. package/ios/Options/Params/Image.mm +35 -2
  352. package/ios/Options/Params/ImageParser.h +5 -5
  353. package/ios/Options/Params/ImageParser.mm +28 -46
  354. package/ios/Public/ApexNavigation/ANNSceneDelegate.h +3 -0
  355. package/ios/Public/ApexNavigation/ApexNavigation.h +1 -1
  356. package/ios/RECIPES.md +13 -6
  357. package/ios/React/ANNReactView.mm +6 -25
  358. package/ios/React/ANNSafeAreaViewComponentView.mm +28 -17
  359. package/ios/React/ANNSurfaceHostingView.h +14 -0
  360. package/ios/React/ANNSurfaceHostingView.mm +144 -1
  361. package/ios/React/Slots/ANNSlotComponentView.mm +24 -17
  362. package/ios/React/Slots/ANNSlotContainers.h +14 -6
  363. package/ios/React/Slots/ANNSlotContainers.mm +75 -2
  364. package/ios/React/Slots/ANNSlotHost.mm +1 -3
  365. package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
  366. package/ios/TopBar/ANNBackButtonPresenter.mm +6 -5
  367. package/ios/TopBar/ANNBarAppearance.h +2 -1
  368. package/ios/TopBar/ANNBarAppearance.mm +111 -30
  369. package/ios/TopBar/ANNBarBackgroundComponent.mm +16 -0
  370. package/ios/TopBar/ANNBarButtonComponentView.h +4 -4
  371. package/ios/TopBar/ANNBarButtonComponentView.mm +1 -1
  372. package/ios/TopBar/ANNBarButtons.h +14 -8
  373. package/ios/TopBar/ANNBarButtons.mm +397 -80
  374. package/ios/TopBar/ANNIconButtonImage.h +1 -0
  375. package/ios/TopBar/ANNIconButtonImage.mm +34 -1
  376. package/ios/TopBar/ANNLargeTitlePresenter.h +13 -0
  377. package/ios/TopBar/ANNLargeTitlePresenter.mm +50 -7
  378. package/ios/TopBar/ANNMainList.h +3 -0
  379. package/ios/TopBar/ANNMainList.mm +4 -0
  380. package/ios/TopBar/ANNScrollEdgeEffects.h +22 -6
  381. package/ios/TopBar/ANNScrollEdgeEffects.mm +123 -16
  382. package/ios/TopBar/ANNSearchPresenter.mm +172 -21
  383. package/ios/TopBar/ANNSearchResultsViewController.mm +29 -6
  384. package/ios/TopBar/ANNTopBarPresenter.h +8 -2
  385. package/ios/TopBar/ANNTopBarPresenter.mm +155 -33
  386. package/ios/TurboModules/ANNTurboEventEmitter.mm +4 -35
  387. package/ios/TurboModules/ANNTurboModule.mm +104 -33
  388. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.cpp +20 -0
  389. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.h +5 -14
  390. package/lib/module/ARCHITECTURE.md +40 -27
  391. package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
  392. package/lib/module/api/app/AppRegistry.js +14 -2
  393. package/lib/module/api/app/AppRegistry.js.map +1 -1
  394. package/lib/module/api/app/createNavigation.js +190 -66
  395. package/lib/module/api/app/createNavigation.js.map +1 -1
  396. package/lib/module/api/commands/commands.js +54 -6
  397. package/lib/module/api/commands/commands.js.map +1 -1
  398. package/lib/module/api/events/navigationEvents.js +6 -2
  399. package/lib/module/api/events/navigationEvents.js.map +1 -1
  400. package/lib/module/api/hooks/useNavigation.js +8 -3
  401. package/lib/module/api/hooks/useNavigation.js.map +1 -1
  402. package/lib/module/api/hooks/useSafeAreaInsets.js +4 -3
  403. package/lib/module/api/hooks/useSafeAreaInsets.js.map +1 -1
  404. package/lib/module/api/linking/dispatchedLinks.js +23 -0
  405. package/lib/module/api/linking/dispatchedLinks.js.map +1 -0
  406. package/lib/module/api/linking/linking.js +11 -0
  407. package/lib/module/api/linking/linking.js.map +1 -1
  408. package/lib/module/api/navigation.js.map +1 -1
  409. package/lib/module/api/options/OptionsChain.js +2 -2
  410. package/lib/module/api/screens/defineScreen.js +45 -3
  411. package/lib/module/api/screens/defineScreen.js.map +1 -1
  412. package/lib/module/api/screens/nativeScreens.js +31 -6
  413. package/lib/module/api/screens/nativeScreens.js.map +1 -1
  414. package/lib/module/api/screens/registerScreens.js +193 -35
  415. package/lib/module/api/screens/registerScreens.js.map +1 -1
  416. package/lib/module/api/theme/theme.js +5 -0
  417. package/lib/module/api/theme/theme.js.map +1 -1
  418. package/lib/module/engine/commands.js +51 -9
  419. package/lib/module/engine/commands.js.map +1 -1
  420. package/lib/module/engine/layout.js +20 -11
  421. package/lib/module/engine/layout.js.map +1 -1
  422. package/lib/module/engine/nativeScreens.js +9 -0
  423. package/lib/module/engine/nativeScreens.js.map +1 -1
  424. package/lib/module/engine/options.js +49 -15
  425. package/lib/module/engine/options.js.map +1 -1
  426. package/lib/module/engine/optionsChange.js +102 -0
  427. package/lib/module/engine/optionsChange.js.map +1 -0
  428. package/lib/module/engine/places.js +52 -7
  429. package/lib/module/engine/places.js.map +1 -1
  430. package/lib/module/engine/props.js +30 -1
  431. package/lib/module/engine/props.js.map +1 -1
  432. package/lib/module/engine/refresh.js +85 -0
  433. package/lib/module/engine/refresh.js.map +1 -0
  434. package/lib/module/engine/rememberedOptions.js +61 -1
  435. package/lib/module/engine/rememberedOptions.js.map +1 -1
  436. package/lib/module/engine/screens.js +77 -16
  437. package/lib/module/engine/screens.js.map +1 -1
  438. package/lib/module/interfaces/contract/commands.json +101 -0
  439. package/lib/module/interfaces/contract/errors.json +275 -0
  440. package/lib/typescript/adapters/NativeANNTurboModule.d.ts +12 -2
  441. package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
  442. package/lib/typescript/api/app/AppRegistry.d.ts.map +1 -1
  443. package/lib/typescript/api/app/createNavigation.d.ts +8 -3
  444. package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
  445. package/lib/typescript/api/commands/commands.d.ts.map +1 -1
  446. package/lib/typescript/api/commands/presentation.d.ts +4 -3
  447. package/lib/typescript/api/commands/presentation.d.ts.map +1 -1
  448. package/lib/typescript/api/events/navigationEvents.d.ts +3 -3
  449. package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
  450. package/lib/typescript/api/hooks/useNavigation.d.ts +1 -1
  451. package/lib/typescript/api/hooks/useNavigation.d.ts.map +1 -1
  452. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts +4 -3
  453. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
  454. package/lib/typescript/api/index.d.ts +1 -1
  455. package/lib/typescript/api/index.d.ts.map +1 -1
  456. package/lib/typescript/api/linking/dispatchedLinks.d.ts +7 -0
  457. package/lib/typescript/api/linking/dispatchedLinks.d.ts.map +1 -0
  458. package/lib/typescript/api/linking/linking.d.ts +8 -0
  459. package/lib/typescript/api/linking/linking.d.ts.map +1 -1
  460. package/lib/typescript/api/navigation.d.ts +4 -1
  461. package/lib/typescript/api/navigation.d.ts.map +1 -1
  462. package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
  463. package/lib/typescript/api/screens/defineScreen.d.ts +23 -4
  464. package/lib/typescript/api/screens/defineScreen.d.ts.map +1 -1
  465. package/lib/typescript/api/screens/nativeScreens.d.ts +8 -1
  466. package/lib/typescript/api/screens/nativeScreens.d.ts.map +1 -1
  467. package/lib/typescript/api/screens/registerScreens.d.ts.map +1 -1
  468. package/lib/typescript/api/theme/theme.d.ts +2 -0
  469. package/lib/typescript/api/theme/theme.d.ts.map +1 -1
  470. package/lib/typescript/engine/commands.d.ts +5 -0
  471. package/lib/typescript/engine/commands.d.ts.map +1 -1
  472. package/lib/typescript/engine/layout.d.ts.map +1 -1
  473. package/lib/typescript/engine/nativeScreens.d.ts +5 -0
  474. package/lib/typescript/engine/nativeScreens.d.ts.map +1 -1
  475. package/lib/typescript/engine/options.d.ts +5 -2
  476. package/lib/typescript/engine/options.d.ts.map +1 -1
  477. package/lib/typescript/engine/optionsChange.d.ts +28 -0
  478. package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
  479. package/lib/typescript/engine/places.d.ts +7 -2
  480. package/lib/typescript/engine/places.d.ts.map +1 -1
  481. package/lib/typescript/engine/props.d.ts +8 -1
  482. package/lib/typescript/engine/props.d.ts.map +1 -1
  483. package/lib/typescript/engine/refresh.d.ts +35 -0
  484. package/lib/typescript/engine/refresh.d.ts.map +1 -0
  485. package/lib/typescript/engine/rememberedOptions.d.ts +13 -0
  486. package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
  487. package/lib/typescript/engine/screens.d.ts +27 -6
  488. package/lib/typescript/engine/screens.d.ts.map +1 -1
  489. package/lib/typescript/interfaces/ComponentEvents.d.ts +4 -4
  490. package/lib/typescript/interfaces/ComponentEvents.d.ts.map +1 -1
  491. package/lib/typescript/interfaces/Events.d.ts +28 -10
  492. package/lib/typescript/interfaces/Events.d.ts.map +1 -1
  493. package/lib/typescript/interfaces/Options.d.ts +1 -1
  494. package/lib/typescript/interfaces/Options.d.ts.map +1 -1
  495. package/lib/typescript/interfaces/options/animations.d.ts +80 -22
  496. package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
  497. package/lib/typescript/interfaces/options/bottomTabs.d.ts +21 -7
  498. package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
  499. package/lib/typescript/interfaces/options/buttons.d.ts +23 -15
  500. package/lib/typescript/interfaces/options/buttons.d.ts.map +1 -1
  501. package/lib/typescript/interfaces/options/modals.d.ts +34 -26
  502. package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
  503. package/lib/typescript/interfaces/options/sideMenu.d.ts +23 -6
  504. package/lib/typescript/interfaces/options/sideMenu.d.ts.map +1 -1
  505. package/lib/typescript/interfaces/options/stack.d.ts +17 -3
  506. package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
  507. package/lib/typescript/interfaces/options/system.d.ts +18 -11
  508. package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
  509. package/lib/typescript/interfaces/options/toolbar.d.ts +2 -2
  510. package/lib/typescript/interfaces/options/topBar.d.ts +68 -38
  511. package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
  512. package/metro/acceptPlugin.js +57 -0
  513. package/metro/babelTransformer.js +45 -0
  514. package/metro/index.js +36 -0
  515. package/package.json +3 -1
  516. package/src/ARCHITECTURE.md +40 -27
  517. package/src/adapters/NativeANNTurboModule.ts +12 -2
  518. package/src/api/app/AppRegistry.ts +16 -2
  519. package/src/api/app/createNavigation.ts +203 -69
  520. package/src/api/commands/commands.ts +48 -7
  521. package/src/api/commands/presentation.ts +4 -3
  522. package/src/api/events/navigationEvents.ts +10 -4
  523. package/src/api/hooks/useNavigation.ts +9 -4
  524. package/src/api/hooks/useSafeAreaInsets.ts +4 -3
  525. package/src/api/index.ts +1 -0
  526. package/src/api/linking/dispatchedLinks.ts +18 -0
  527. package/src/api/linking/linking.ts +22 -1
  528. package/src/api/navigation.ts +4 -1
  529. package/src/api/options/OptionsChain.ts +2 -2
  530. package/src/api/screens/defineScreen.ts +49 -5
  531. package/src/api/screens/nativeScreens.ts +40 -4
  532. package/src/api/screens/registerScreens.tsx +185 -42
  533. package/src/api/theme/theme.ts +5 -0
  534. package/src/engine/commands.ts +70 -13
  535. package/src/engine/layout.ts +27 -11
  536. package/src/engine/nativeScreens.ts +10 -1
  537. package/src/engine/options.ts +45 -19
  538. package/src/engine/optionsChange.ts +107 -0
  539. package/src/engine/places.ts +65 -7
  540. package/src/engine/props.ts +30 -1
  541. package/src/engine/refresh.ts +97 -0
  542. package/src/engine/rememberedOptions.ts +74 -1
  543. package/src/engine/screens.tsx +76 -21
  544. package/src/interfaces/ComponentEvents.ts +4 -4
  545. package/src/interfaces/Events.ts +29 -10
  546. package/src/interfaces/Options.ts +1 -0
  547. package/src/interfaces/contract/commands.json +101 -0
  548. package/src/interfaces/contract/errors.json +275 -0
  549. package/src/interfaces/options/animations.ts +81 -22
  550. package/src/interfaces/options/bottomTabs.ts +21 -7
  551. package/src/interfaces/options/buttons.ts +23 -15
  552. package/src/interfaces/options/modals.ts +34 -26
  553. package/src/interfaces/options/sideMenu.ts +24 -6
  554. package/src/interfaces/options/stack.ts +17 -3
  555. package/src/interfaces/options/system.ts +18 -11
  556. package/src/interfaces/options/toolbar.ts +2 -2
  557. package/src/interfaces/options/topBar.ts +68 -38
  558. package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -41
  559. package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -69
  560. package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationStateReporter.kt +0 -62
  561. package/android/src/main/java/dev/apexnative/navigation/react/events/StateHold.kt +0 -62
  562. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowPlacer.kt +0 -223
  563. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStub.kt +0 -31
  564. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +0 -138
  565. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -88
  566. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PropertyAnimatorCreator.kt +0 -33
  567. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +0 -66
  568. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +0 -179
  569. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -139
  570. package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
  571. package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -68
  572. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.h +0 -27
  573. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.mm +0 -55
@@ -11,8 +11,10 @@ const {
11
11
  reactNativeVersion,
12
12
  usesExpo,
13
13
  } = require('../../app');
14
+ const { mainActivity } = require('../../links/native');
14
15
  const { findProject } = require('../../project');
15
16
  const { codeOf } = require('../../setup/source');
17
+ const { loadsReactNativeItself } = require('../../setup/steps/mainApplication');
16
18
  const { planCodegen } = require('../../codegen');
17
19
  const { readConfig } = require('../../config');
18
20
  const { planProject } = require('../../setup');
@@ -27,6 +29,16 @@ const { splashChecks } = require('./splash');
27
29
  const SETUP = { label: 'npx apex-navigation setup', run: /** @type {const} */ ('setup') };
28
30
  const GENERATED = ['ApexNavigation.generated.swift', 'ApexNavigationGenerated.kt'];
29
31
  const CODEGEN = { label: 'npx apex-navigation codegen', run: /** @type {const} */ ('codegen') };
32
+ // The changes the main activity must handle itself; the template's value has them all.
33
+ const CONFIG_CHANGES = [
34
+ 'orientation',
35
+ 'screenSize',
36
+ 'smallestScreenSize',
37
+ 'screenLayout',
38
+ 'uiMode',
39
+ ];
40
+ const TEMPLATE_CONFIG_CHANGES =
41
+ 'keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode';
30
42
 
31
43
  /**
32
44
  * React Native, the navigation, and the files setup sets up.
@@ -88,11 +100,12 @@ function appChecks({ root, run }) {
88
100
  const project = findProject(root, run);
89
101
  const plans = planProject(project);
90
102
  const app = plans.find(({ file }) => file !== undefined && file === project.app);
103
+ const metro = plans.find(({ file }) => file !== undefined && file === project.metroConfig);
91
104
  const manifest = plans.find(({ file }) => file !== undefined && file === project.manifest);
92
105
  const native = plans.filter((plan) => plan.platform !== 'js' && plan !== manifest);
93
106
  const types = plans.filter(({ name }) => name === ENV_FILE || name === 'tsconfig.json');
94
107
  const entry = plans.filter(
95
- (plan) => plan.platform === 'js' && plan !== app && !types.includes(plan)
108
+ (plan) => plan.platform === 'js' && plan !== app && plan !== metro && !types.includes(plan)
96
109
  );
97
110
  checks.push(filesCheck('Native files', native), filesCheck('Entry point', entry));
98
111
  const typed = typesCheck(root, types);
@@ -108,6 +121,20 @@ function appChecks({ root, run }) {
108
121
  });
109
122
  }
110
123
 
124
+ // Without the navigation's Metro setup an edit that isn't a boundary of Fast Refresh reloads the app.
125
+ if (metro && metro.status !== 'done') {
126
+ checks.push({
127
+ group: 'app',
128
+ title: 'Fast Refresh',
129
+ status: 'warn',
130
+ detail: `${metro.name} doesn't use withApexNavigation: some edits reload the app`,
131
+ fix:
132
+ metro.status === 'manual'
133
+ ? { label: 'Wrap the config metro.config.js exports in withApexNavigation' }
134
+ : SETUP,
135
+ });
136
+ }
137
+
111
138
  // Predictive back is optional: without it the navigation works, and Android plays no back animation of its own.
112
139
  if (manifest && manifest.status !== 'done') {
113
140
  checks.push({
@@ -122,28 +149,64 @@ function appChecks({ root, run }) {
122
149
  });
123
150
  }
124
151
 
152
+ const configChanges = configChangesCheck(project.manifest);
153
+ if (configChanges) checks.push(configChanges);
154
+
125
155
  checks.push(...splashChecks(root, project), ...iconChecks(root, project));
126
156
 
127
- // A second load of React Native crashes the app on start: the most common slip of a setup by hand.
157
+ // NavigationApplication leaves the load of React Native to the template's call: without it the app closes on start,
158
+ // and so it does with a second load of the app's own next to it.
128
159
  const application = project.mainApplication && fs.readFileSync(project.mainApplication, 'utf8');
129
- if (
130
- application &&
131
- /:\s*NavigationApplication\(\)/.test(application) &&
132
- /\bloadReactNative\s*\(/.test(codeOf(application))
133
- ) {
134
- checks.push({
135
- group: 'app',
136
- title: 'React Native loads twice',
137
- status: 'error',
138
- detail: 'MainApplication.kt calls loadReactNative(this), NavigationApplication loads it too',
139
- fix: { label: 'Remove loadReactNative(this) from MainApplication.kt' },
140
- });
160
+ if (application && /:\s*NavigationApplication\(/.test(application)) {
161
+ const loads = /\bloadReactNative\s*\(/.test(codeOf(application));
162
+ if (!loads) {
163
+ checks.push({
164
+ group: 'app',
165
+ title: 'React Native not loaded',
166
+ status: 'error',
167
+ detail: "MainApplication.kt doesn't call loadReactNative(this) in onCreate",
168
+ fix: SETUP,
169
+ });
170
+ } else if (loadsReactNativeItself(application)) {
171
+ checks.push({
172
+ group: 'app',
173
+ title: 'React Native loads twice',
174
+ status: 'error',
175
+ detail:
176
+ 'MainApplication.kt loads React Native itself (SoLoader.init or the New Architecture entry point) next to loadReactNative(this)',
177
+ fix: SETUP,
178
+ });
179
+ }
141
180
  }
142
181
  const generated = generatedCheck(root, run);
143
182
  if (generated) checks.push(generated);
144
183
  return checks;
145
184
  }
146
185
 
186
+ /**
187
+ * Whether the main activity handles the changes of its window itself, as the React Native template has it. Without
188
+ * one of them Android recreates the activity on a rotation, a resize, a fold or a light/dark switch: every screen goes
189
+ * with it and the navigation starts again from its root. Nothing without a manifest or a main activity.
190
+ * @param {string | undefined} manifest
191
+ * @returns {Check | undefined}
192
+ */
193
+ function configChangesCheck(manifest) {
194
+ if (!manifest || !fs.existsSync(manifest)) return undefined;
195
+ const activity = mainActivity(fs.readFileSync(manifest, 'utf8'));
196
+ if (!activity) return undefined;
197
+ const value = /android:configChanges\s*=\s*(?:"([^"]*)"|'([^']*)')/.exec(activity.text);
198
+ const declared = (value?.[1] ?? value?.[2] ?? '').split('|').map((change) => change.trim());
199
+ const missing = CONFIG_CHANGES.filter((change) => !declared.includes(change));
200
+ if (missing.length === 0) return undefined;
201
+ return {
202
+ group: 'app',
203
+ title: 'Config changes',
204
+ status: 'warn',
205
+ detail: `the main activity doesn't handle ${missing.join(', ')}: Android recreates it, and every screen with it`,
206
+ fix: { label: `Set android:configChanges="${TEMPLATE_CONFIG_CHANGES}" on the main activity` },
207
+ };
208
+ }
209
+
147
210
  /**
148
211
  * One line for a few files: set up, or which need setup or a change by hand.
149
212
  * @param {string} title
@@ -17,34 +17,16 @@ const CIRCLE = 192;
17
17
  const LOGO_HEIGHT = /<dimen name="apex_navigation_splash_logo_height">([\d.]+)dp<\/dimen>/;
18
18
 
19
19
  /**
20
- * The native splash: made from its settings in package.json on both platforms, its logo whole on Android 12+; without
21
- * settings, a launch screen the navigation can't keep on screen until the first screen draws.
20
+ * The native splash: made from its settings in package.json on both platforms, its logo whole on Android 12+. Without
21
+ * settings there is nothing to check: the navigation keeps a copy of a storyboard and of `UILaunchScreen` alike.
22
22
  * @param {string} root
23
23
  * @param {Project} project
24
24
  * @returns {Check[]}
25
25
  */
26
26
  function splashChecks(root, project) {
27
- const plist = project.infoPlist && fs.readFileSync(project.infoPlist, 'utf8');
28
27
  const saved = readConfig(root).splash;
29
- if (!saved) {
30
- // UILaunchScreen alone: iOS shows it, but the navigation keeps only a storyboard while the first screen renders.
31
- if (
32
- plist?.includes('<key>UILaunchScreen</key>') &&
33
- !plist.includes('<key>UILaunchStoryboardName</key>')
34
- ) {
35
- return [
36
- {
37
- group: 'app',
38
- title: 'Launch screen',
39
- status: 'warn',
40
- detail:
41
- 'UILaunchScreen in Info.plist: an empty window shows between it and the first screen',
42
- fix: SPLASH,
43
- },
44
- ];
45
- }
46
- return [];
47
- }
28
+ if (!saved) return [];
29
+ const plist = project.infoPlist && fs.readFileSync(project.infoPlist, 'utf8');
48
30
  const resolved = resolveSettings(root, {}, saved);
49
31
  if ('errors' in resolved) {
50
32
  return [
@@ -3,6 +3,7 @@
3
3
 
4
4
  const fs = require('node:fs');
5
5
  const path = require('node:path');
6
+ const { withReactNativeLoaded } = require('../setup/steps/mainApplication');
6
7
 
7
8
  /** @typedef {import('../changes').FileChange} FileChange */
8
9
  /** @typedef {import('./report').ReportItem} ReportItem */
@@ -158,6 +159,23 @@ function planNative(project) {
158
159
  const before = fs.readFileSync(file, 'utf8');
159
160
  let next = before;
160
161
  for (const [pattern, replacement] of rewrite.rules) next = next.replace(pattern, replacement);
162
+ // react-native-navigation loaded React Native itself; the navigation's application leaves it to the template's
163
+ // loadReactNative(this), which such an app doesn't have.
164
+ if (file === project.mainApplication && /:\s*NavigationApplication\(/.test(next)) {
165
+ const loaded = withReactNativeLoaded(next);
166
+ if (loaded !== undefined) next = loaded;
167
+ else {
168
+ report.push({
169
+ file: path.relative(root, file),
170
+ line: 1,
171
+ step: 'native',
172
+ before: 'onCreate',
173
+ after: 'super.onCreate() then loadReactNative(this), and no load of its own',
174
+ what: 'React Native loads through loadReactNative(this) in onCreate: add it by hand',
175
+ docs: `${DOCS}#native`,
176
+ });
177
+ }
178
+ }
161
179
  if (next !== before) {
162
180
  changes.push({
163
181
  name: path.basename(file),
package/cli/project.js CHANGED
@@ -8,8 +8,9 @@ const { exec } = require('./exec');
8
8
  /**
9
9
  * The files of the app the CLI sets up, checks and adds to, where the app has them; `undefined` for one it couldn't
10
10
  * find. `styles` is the file of the app's Android theme, `styles.xml` or `themes.xml`; `manifest` its
11
- * `AndroidManifest.xml`. `xcodeProject` is the app's `project.pbxproj`; `androidPackage` the package of its Kotlin code (the `namespace`
12
- * of `android/app/build.gradle`), and `androidSources` the folder it is in.
11
+ * `AndroidManifest.xml`. `sceneDelegate` is the `SceneDelegate.swift` next to `AppDelegate.swift`, which apps made
12
+ * from React Native 0.88's template have. `xcodeProject` is the app's `project.pbxproj`; `androidPackage` the package
13
+ * of its Kotlin code (the `namespace` of `android/app/build.gradle`), and `androidSources` the folder it is in.
13
14
  * @typedef {{
14
15
  * root: string;
15
16
  * mainApplication?: string;
@@ -17,9 +18,11 @@ const { exec } = require('./exec');
17
18
  * styles?: string;
18
19
  * manifest?: string;
19
20
  * appDelegate?: string;
21
+ * sceneDelegate?: string;
20
22
  * infoPlist?: string;
21
23
  * entry?: string;
22
24
  * app?: string;
25
+ * metroConfig?: string;
23
26
  * typescript: boolean;
24
27
  * xcodeProject?: string;
25
28
  * androidPackage?: string;
@@ -64,6 +67,8 @@ function findProject(root, run = exec) {
64
67
  existing(path.join(androidMain, 'res', 'values', 'themes.xml')),
65
68
  manifest: existing(path.join(androidMain, 'AndroidManifest.xml')),
66
69
  appDelegate,
70
+ sceneDelegate:
71
+ appDelegate && existing(path.join(path.dirname(appDelegate), 'SceneDelegate.swift')),
67
72
  infoPlist: appDelegate && existing(path.join(path.dirname(appDelegate), 'Info.plist')),
68
73
  entry: ['index.js', 'index.ts', 'index.tsx']
69
74
  .map((name) => path.join(root, name))
@@ -71,6 +76,9 @@ function findProject(root, run = exec) {
71
76
  app: ['App.tsx', 'App.ts', 'App.jsx', 'App.js']
72
77
  .map((name) => path.join(root, name))
73
78
  .find((file) => fs.existsSync(file)),
79
+ metroConfig: ['metro.config.js', 'metro.config.cjs']
80
+ .map((name) => path.join(root, name))
81
+ .find((file) => fs.existsSync(file)),
74
82
  typescript: ['App.tsx', 'App.ts', 'tsconfig.json'].some((name) =>
75
83
  fs.existsSync(path.join(root, name))
76
84
  ),
@@ -16,6 +16,8 @@ const { planEntry, navigationFile, HOW_TO: ENTRY_HOW_TO } = require('./steps/ent
16
16
  const { planEnv, targetOf } = require('./steps/env');
17
17
  const { planInfoPlist } = require('./steps/infoPlist');
18
18
  const { planMainActivity } = require('./steps/mainActivity');
19
+ const { planMetro } = require('./steps/metro');
20
+ const { planSceneDelegate } = require('./steps/sceneDelegate');
19
21
  const { planMainApplication } = require('./steps/mainApplication');
20
22
  const { planManifest } = require('./steps/manifest');
21
23
  const { planStyles } = require('./steps/styles');
@@ -83,6 +85,18 @@ function planProject(project) {
83
85
  planAppDelegate,
84
86
  notFound('AppDelegate.swift')
85
87
  ),
88
+ // React Native 0.88's template starts React Native in its scene delegate; the earlier templates have none.
89
+ ...(project.sceneDelegate
90
+ ? [
91
+ planFile(
92
+ 'SceneDelegate.swift',
93
+ 'ios',
94
+ project.sceneDelegate,
95
+ planSceneDelegate,
96
+ notFound('SceneDelegate.swift')
97
+ ),
98
+ ]
99
+ : []),
86
100
  planFile('Info.plist', 'ios', project.infoPlist, planInfoPlist, notFound('Info.plist')),
87
101
  planFile('index.js', 'js', project.entry, planEntry, ENTRY_HOW_TO),
88
102
  ];
@@ -121,6 +135,10 @@ function planProject(project) {
121
135
  plans.push(...planEnv(project.root, navigation, ts));
122
136
  // The template's App renders React Native's status bar; one moved elsewhere or written anew has nothing to change.
123
137
  if (project.app) plans.push(planFile('App.tsx', 'js', project.app, planApp, APP_HOW_TO));
138
+ // Fast Refresh for every edit; an app without a Metro config of its own has nothing to change.
139
+ if (project.metroConfig) {
140
+ plans.push(planFile('metro.config.js', 'js', project.metroConfig, planMetro, ''));
141
+ }
124
142
  return plans;
125
143
  }
126
144
 
@@ -35,7 +35,8 @@ function removeUnusedImports(text, names) {
35
35
  for (const name of names) {
36
36
  const line = new RegExp(`^import\\s+${escape(name)}[ \\t]*\\r?\\n`, 'm');
37
37
  const simple = name.slice(name.lastIndexOf('.') + 1);
38
- const code = result.replace(/^import\s.*$/gm, '');
38
+ // A name in a comment is no use of the import.
39
+ const code = codeOf(result).replace(/^import\s.*$/gm, '');
39
40
  if (line.test(result) && !new RegExp(`\\b${escape(simple)}\\b`).test(code))
40
41
  result = result.replace(line, '');
41
42
  }
@@ -19,7 +19,10 @@ its delegate (the bundle URL) before calling super.
19
19
  self.reactNativeDelegate = ReactNativeDelegate()
20
20
  return super.application(application, didFinishLaunchingWithOptions: launchOptions)
21
21
  }
22
- }`;
22
+ }
23
+
24
+ ReactNativeDelegate is the app's RCTDefaultReactNativeFactoryDelegate, which gives the bundle URL (bundleURL()); in
25
+ React Native 0.88's template that method is in SceneDelegate.`;
23
26
 
24
27
  // Lines of the template's launch: ANNAppDelegate does all of it.
25
28
  const TEMPLATE_LINES = [
@@ -42,6 +45,20 @@ const LAUNCH_OVERRIDE =
42
45
  const DELEGATE = /^([ \t]*)let\s+delegate\s*=\s*ReactNativeDelegate\(\)[ \t]*$/m;
43
46
  const RETURN_TRUE = /^([ \t]*)return\s+true[ \t]*$/m;
44
47
 
48
+ // React Native 0.88's template starts React Native in its scene delegate: the app delegate only returns true. The
49
+ // bundle URL moves into a delegate of React Native's factory, as the earlier templates had it.
50
+ const REACT_NATIVE_DELEGATE = `class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate {
51
+ override func bundleURL() -> URL? {
52
+ #if DEBUG
53
+ RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
54
+ #else
55
+ Bundle.main.url(forResource: "main", withExtension: "jsbundle")
56
+ #endif
57
+ }
58
+ }
59
+ `;
60
+ const RETURN_TRUE_OR_TRUE = /^([ \t]*)(?:return\s+)?true[ \t]*$/m;
61
+
45
62
  /**
46
63
  * AppDelegate.swift: the app delegate becomes an ANNAppDelegate.
47
64
  * @param {string} text
@@ -55,13 +72,30 @@ function planAppDelegate(text) {
55
72
  note: 'changed by hand, see below',
56
73
  howTo: HOW_TO,
57
74
  });
58
- if (!HEADER.test(text) || !LAUNCH.test(text) || !DELEGATE.test(text)) return manual;
75
+ if (!HEADER.test(text) || !LAUNCH.test(text)) return manual;
76
+ let next = DELEGATE.test(text) ? fromFactoryLaunch(text) : fromSceneLaunch(text);
77
+ if (next === undefined) return manual;
59
78
 
79
+ // The dependency provider is ANNAppDelegate's now.
80
+ if (!/\bRCTAppDependencyProvider\b/.test(next)) {
81
+ next = next.replace(/^import\s+ReactAppDependencyProvider[ \t]*\n/m, '');
82
+ }
83
+ next = addImport(next, 'import ApexNavigation', { sorted: false });
84
+ return { status: 'change', next, note: 'ANNAppDelegate' };
85
+ }
86
+
87
+ /**
88
+ * The app delegate of the templates before React Native 0.88, which makes React Native's factory and window in its
89
+ * launch; undefined when the launch has code of the app's own that uses them.
90
+ * @param {string} text
91
+ * @returns {string | undefined}
92
+ */
93
+ function fromFactoryLaunch(text) {
60
94
  let next = text
61
95
  .replace(HEADER, 'class $1: ANNAppDelegate {')
62
96
  .replace(LAUNCH, '$1override func$2');
63
97
  for (const line of TEMPLATE_LINES) {
64
- if (!line.test(next)) return manual;
98
+ if (!line.test(next)) return undefined;
65
99
  next = next.replace(line, '');
66
100
  }
67
101
  next = next.replace(DELEGATE, '$1self.reactNativeDelegate = ReactNativeDelegate()');
@@ -69,10 +103,10 @@ function planAppDelegate(text) {
69
103
  // The launch now ends in super's, which starts React Native.
70
104
  const launchAt = next.search(LAUNCH_OVERRIDE);
71
105
  const returnAt = next.slice(launchAt).search(RETURN_TRUE);
72
- if (returnAt < 0) return manual;
106
+ if (returnAt < 0) return undefined;
73
107
  const body = next.slice(launchAt, launchAt + returnAt).replace(/self\.reactNativeDelegate/g, '');
74
108
  // Code of the app's own that used the template's factory, delegate or window: it has to move by hand.
75
- if (/\b(factory|delegate|window)\b/.test(body)) return manual;
109
+ if (/\b(factory|delegate|window)\b/.test(body)) return undefined;
76
110
  const rest = next
77
111
  .slice(launchAt + returnAt)
78
112
  .replace(
@@ -82,17 +116,38 @@ function planAppDelegate(text) {
82
116
  next = next.slice(0, launchAt + returnAt) + rest;
83
117
 
84
118
  // The blank lines the template's launch leaves behind.
85
- next = next
119
+ return next
86
120
  .replace(/(class\s+\w+:\s*ANNAppDelegate\s*\{\n)(?:[ \t]*\n)+/, '$1')
87
121
  .replace(/(self\.reactNativeDelegate = ReactNativeDelegate\(\)\n)(?:[ \t]*\n)+/, '$1')
88
122
  .replace(/\n(?:[ \t]*\n)+([ \t]*return super\.application\()/, '\n$1');
123
+ }
89
124
 
90
- // The dependency provider is ANNAppDelegate's now.
91
- if (!/\bRCTAppDependencyProvider\b/.test(next)) {
92
- next = next.replace(/^import\s+ReactAppDependencyProvider[ \t]*\n/m, '');
125
+ /**
126
+ * The app delegate of React Native 0.88's template, whose launch only returns true; undefined when the app delegate
127
+ * makes React Native or a window of its own.
128
+ * @param {string} text
129
+ * @returns {string | undefined}
130
+ */
131
+ function fromSceneLaunch(text) {
132
+ if (/\b(RCTReactNativeFactory|ReactNativeDelegate|window)\b/.test(text)) return undefined;
133
+ let next = text
134
+ .replace(HEADER, 'class $1: ANNAppDelegate {')
135
+ .replace(LAUNCH, '$1override func$2');
136
+ const launchAt = next.search(LAUNCH_OVERRIDE);
137
+ const returnAt = next.slice(launchAt).search(RETURN_TRUE_OR_TRUE);
138
+ if (returnAt < 0) return undefined;
139
+ const rest = next
140
+ .slice(launchAt + returnAt)
141
+ .replace(
142
+ RETURN_TRUE_OR_TRUE,
143
+ '$1self.reactNativeDelegate = ReactNativeDelegate()\n' +
144
+ '$1return super.application(application, didFinishLaunchingWithOptions: launchOptions)'
145
+ );
146
+ next = `${next.slice(0, launchAt + returnAt)}${rest.trimEnd()}\n\n${REACT_NATIVE_DELEGATE}`;
147
+ for (const module of ['React', 'React_RCTAppDelegate']) {
148
+ next = addImport(next, `import ${module}`, { sorted: false });
93
149
  }
94
- next = addImport(next, 'import ApexNavigation', { sorted: false });
95
- return { status: 'change', next, note: 'ANNAppDelegate' };
150
+ return next;
96
151
  }
97
152
 
98
153
  module.exports = { planAppDelegate };
@@ -5,24 +5,51 @@ const { addImport, codeOf, removeUnusedImports } = require('../source');
5
5
 
6
6
  /** @typedef {import('./types').StepResult} StepResult */
7
7
 
8
- const HOW_TO = `Extend NavigationApplication. It loads React Native itself, so loadReactNative(this) goes:
9
- calling it again crashes the app on start.
8
+ const HOW_TO = `Extend NavigationApplication and keep the template's loadReactNative(this) in onCreate: it loads
9
+ React Native as the app's Gradle files say, and the navigation makes its React host after it.
10
10
 
11
+ import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
11
12
  import dev.apexnative.navigation.NavigationApplication
12
13
 
13
14
  class MainApplication : NavigationApplication() {
14
15
  override val reactHost: ReactHost by lazy { ... } // as it is
16
+
17
+ override fun onCreate() {
18
+ super.onCreate()
19
+ loadReactNative(this)
20
+ }
15
21
  }`;
16
22
 
23
+ const LOAD_IMPORT = 'import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative';
24
+
17
25
  // Imports of the template that the change leaves unused.
18
- const TEMPLATE_IMPORTS = [
19
- 'android.app.Application',
20
- 'com.facebook.react.ReactApplication',
21
- 'com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative',
26
+ const TEMPLATE_IMPORTS = ['android.app.Application', 'com.facebook.react.ReactApplication'];
27
+
28
+ // A load of React Native of the app's own, next to loadReactNative(this) a second one that crashes the app at start:
29
+ // the New Architecture's entry point (react-native-navigation's apps call it in onCreate) and SoLoader.
30
+ // A bare `load()` is the entry point's only where the file imports it. A form these don't take out (`load` with
31
+ // arguments, an `if` without braces) is left to the app's author.
32
+ const OWN_LOAD = [
33
+ /^[ \t]*if\s*\(\s*BuildConfig\.IS_NEW_ARCHITECTURE_ENABLED\s*\)\s*\{(?:\s*\/\/[^\n]*)*\s*DefaultNewArchitectureEntryPoint\.load\(\)\s*\}[ \t]*\r?\n/gm,
34
+ /^[ \t]*DefaultNewArchitectureEntryPoint\.load\(\)[ \t]*\r?\n/gm,
35
+ /^[ \t]*SoLoader\.init\([^\n]*\)[ \t]*\r?\n/gm,
36
+ ];
37
+ const BARE_LOAD = [
38
+ /^[ \t]*if\s*\(\s*BuildConfig\.IS_NEW_ARCHITECTURE_ENABLED\s*\)\s*\{(?:\s*\/\/[^\n]*)*\s*load\(\)\s*\}[ \t]*\r?\n/gm,
39
+ /^[ \t]*load\(\)[ \t]*\r?\n/gm,
40
+ ];
41
+ const BARE_LOAD_IMPORT =
42
+ /^import\s+com\.facebook\.react\.defaults\.DefaultNewArchitectureEntryPoint\.load\b/m;
43
+ const OWN_LOAD_IMPORTS = [
44
+ 'com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load',
45
+ 'com.facebook.react.defaults.DefaultNewArchitectureEntryPoint',
46
+ 'com.facebook.soloader.SoLoader',
47
+ 'com.facebook.react.soloader.OpenSourceMergedSoMapping',
22
48
  ];
23
49
 
24
50
  /**
25
- * MainApplication.kt: the application becomes a NavigationApplication.
51
+ * MainApplication.kt: the application becomes a NavigationApplication, and loads React Native in its onCreate as the
52
+ * template does.
26
53
  * @param {string} text
27
54
  * @returns {StepResult}
28
55
  */
@@ -32,21 +59,20 @@ function planMainApplication(text) {
32
59
  note: 'changed by hand, see below',
33
60
  howTo: HOW_TO,
34
61
  });
35
- if (/:\s*NavigationApplication\(\)/.test(text)) {
36
- return /\bloadReactNative\s*\(/.test(codeOf(text))
62
+ if (/:\s*NavigationApplication\(/.test(text)) {
63
+ if (loadsReactNative(text) && !loadsReactNativeItself(text)) {
64
+ return { status: 'done', note: 'already set up' };
65
+ }
66
+ const next = withReactNativeLoaded(text);
67
+ return next === undefined
37
68
  ? manual
38
- : { status: 'done', note: 'already set up' };
69
+ : { status: 'change', next, note: 'loadReactNative(this) in onCreate' };
39
70
  }
40
71
  const header = /class\s+(\w+)\s*:\s*Application\(\)\s*,\s*ReactApplication\b/;
41
72
  if (!header.test(text)) return manual;
42
- let next = text.replace(header, 'class $1 : NavigationApplication()');
43
- // The template's onCreate only loads React Native, so it goes; another one keeps the rest of its code.
44
- next = next.replace(
45
- /\n\n?[ \t]*override\s+fun\s+onCreate\(\)\s*\{\s*super\.onCreate\(\)\s*loadReactNative\(this\)\s*\}/,
46
- ''
47
- );
48
- next = next.replace(/^[ \t]*loadReactNative\(this\)[ \t]*\r?\n/m, '');
49
- if (/\bloadReactNative\s*\(/.test(codeOf(next))) return manual;
73
+ // The template's onCreate stays: its loadReactNative(this) loads React Native for the navigation too.
74
+ let next = withReactNativeLoaded(text.replace(header, 'class $1 : NavigationApplication()'));
75
+ if (next === undefined) return manual;
50
76
  // Added first: with the template's imports gone the file would have none to sort it among.
51
77
  next = addImport(next, 'import dev.apexnative.navigation.NavigationApplication', {
52
78
  sorted: true,
@@ -55,4 +81,93 @@ function planMainApplication(text) {
55
81
  return { status: 'change', next, note: 'NavigationApplication' };
56
82
  }
57
83
 
58
- module.exports = { planMainApplication };
84
+ /**
85
+ * Whether the code of the file, not a comment, calls loadReactNative.
86
+ * @param {string} text
87
+ */
88
+ function loadsReactNative(text) {
89
+ return /\bloadReactNative\s*\(/.test(codeOf(text));
90
+ }
91
+
92
+ /**
93
+ * Whether the code of the file loads React Native on its own as well: the New Architecture's entry point or SoLoader.
94
+ * @param {string} text
95
+ */
96
+ function loadsReactNativeItself(text) {
97
+ const code = codeOf(text);
98
+ return (
99
+ /\bSoLoader\.init\s*\(/.test(code) ||
100
+ /\bDefaultNewArchitectureEntryPoint\.load\s*\(/.test(code) ||
101
+ (BARE_LOAD_IMPORT.test(text) && /(?<![\w.])load\s*\(/.test(code))
102
+ );
103
+ }
104
+
105
+ /**
106
+ * The application with `loadReactNative(this)` in its onCreate, after `super.onCreate()`: as it is when it has the
107
+ * call, with an onCreate of the template's when it has none. Undefined for an onCreate that doesn't call
108
+ * `super.onCreate()`, whose order only its author knows.
109
+ * @param {string} text
110
+ * @returns {string | undefined}
111
+ */
112
+ function withReactNativeLoaded(text) {
113
+ let without = text;
114
+ const patterns = BARE_LOAD_IMPORT.test(text) ? [...OWN_LOAD, ...BARE_LOAD] : OWN_LOAD;
115
+ for (const pattern of patterns) without = without.replace(pattern, '');
116
+ without = removeUnusedImports(without, OWN_LOAD_IMPORTS);
117
+ if (loadsReactNativeItself(without)) return undefined;
118
+ if (loadsReactNative(without)) return without;
119
+ return withLoadCall(without);
120
+ }
121
+
122
+ /**
123
+ * @param {string} text an application without a load of React Native
124
+ * @returns {string | undefined}
125
+ */
126
+ function withLoadCall(text) {
127
+ let next;
128
+ const superCall = /^([ \t]*)super\.onCreate\(\)[ \t]*\r?\n/m;
129
+ if (/\boverride\s+fun\s+onCreate\s*\(/.test(text)) {
130
+ if (!superCall.test(text)) return undefined;
131
+ next = text.replace(superCall, (line, indent) => `${line}${indent}loadReactNative(this)\n`);
132
+ } else {
133
+ const close = classEnd(text);
134
+ if (close === undefined) return undefined;
135
+ const indent = /^([ \t]+)override\b/m.exec(text)?.[1] ?? ' ';
136
+ const body = text.slice(0, close).replace(/\s*$/, '');
137
+ const onCreate = [
138
+ '',
139
+ `${indent}override fun onCreate() {`,
140
+ `${indent}${indent}super.onCreate()`,
141
+ `${indent}${indent}loadReactNative(this)`,
142
+ `${indent}}`,
143
+ ].join('\n');
144
+ next = `${body}\n${onCreate}\n${text.slice(close)}`;
145
+ }
146
+ return addImport(next, LOAD_IMPORT, { sorted: true });
147
+ }
148
+
149
+ /**
150
+ * The index of the closing brace of the file's application class: its braces counted from the class's own, past any
151
+ * declaration or comment after it. Undefined when the braces don't close.
152
+ * @param {string} text
153
+ * @returns {number | undefined}
154
+ */
155
+ function classEnd(text) {
156
+ // The comments and the string and character literals blanked out, so that an index in it is one in the text and a
157
+ // brace in a literal doesn't count.
158
+ const blank = (/** @type {string} */ part) => part.replace(/[^\n]/g, ' ');
159
+ const code = text
160
+ .replace(/\/\*[\s\S]*?\*\//g, blank)
161
+ .replace(/\/\/.*$/gm, blank)
162
+ .replace(/"(?:[^"\\\n]|\\.)*"|'(?:[^'\\\n]|\\.)*'/g, blank);
163
+ const header = /\bclass\s+\w+\s*:[^{]*\{/.exec(code);
164
+ if (!header) return undefined;
165
+ let depth = 0;
166
+ for (let index = header.index + header[0].length - 1; index < code.length; index++) {
167
+ if (code[index] === '{') depth++;
168
+ else if (code[index] === '}' && --depth === 0) return index;
169
+ }
170
+ return undefined;
171
+ }
172
+
173
+ module.exports = { planMainApplication, withReactNativeLoaded, loadsReactNativeItself };
@@ -0,0 +1,46 @@
1
+ // @ts-check
2
+ 'use strict';
3
+
4
+ /** @typedef {import('./types').StepResult} StepResult */
5
+
6
+ const REQUIRE = "const { withApexNavigation } = require('@apexnative/navigation/metro');";
7
+
8
+ // The config the file exports: `module.exports = …;`, its last statement.
9
+ const EXPORT = /^module\.exports\s*=\s*([\s\S]+?);?\s*$/m;
10
+
11
+ const HOW_TO = `Wrap the config metro.config.js exports, so an edit updates the app by Fast Refresh instead of
12
+ reloading it:
13
+
14
+ ${REQUIRE}
15
+
16
+ module.exports = withApexNavigation(mergeConfig(getDefaultConfig(__dirname), config));`;
17
+
18
+ /**
19
+ * metro.config.js: the config it exports goes through withApexNavigation, which puts the navigation's Babel
20
+ * transformer in front of the app's own.
21
+ * @param {string} text
22
+ * @returns {StepResult}
23
+ */
24
+ function planMetro(text) {
25
+ if (text.includes('withApexNavigation')) return { status: 'done', note: 'already set up' };
26
+ const found = EXPORT.exec(text);
27
+ // Only an export that ends the file: one in the middle may be changed by what comes after it.
28
+ if (!found || text.slice(found.index + found[0].length).trim() !== '') {
29
+ return { status: 'manual', note: 'changed by hand, see below', howTo: HOW_TO };
30
+ }
31
+ const exported = found[1].trim();
32
+ const before = text.slice(0, found.index);
33
+ const requires = [...before.matchAll(/^.*require\(.*\);?$/gm)];
34
+ const last = requires[requires.length - 1];
35
+ const head =
36
+ last === undefined
37
+ ? `${REQUIRE}\n\n${before}`
38
+ : `${before.slice(0, last.index + last[0].length)}\n${REQUIRE}${before.slice(last.index + last[0].length)}`;
39
+ return {
40
+ status: 'change',
41
+ next: `${head}module.exports = withApexNavigation(${exported});\n`,
42
+ note: 'Fast Refresh for every edit',
43
+ };
44
+ }
45
+
46
+ module.exports = { planMetro, HOW_TO };