@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
@@ -1,7 +1,10 @@
1
1
  import type { ComponentType } from 'react';
2
+ import { DevSettings } from 'react-native';
2
3
  import { setDefaultOptions, setRoot } from '../../engine/commands';
3
4
  import { type AppProvider, enableSlots, withSlots } from '../../engine/slots';
4
5
  import { listenToNativeScreens, startHost } from '../../engine/nativeScreens';
6
+ import { sameValue } from '../../engine/optionsChange';
7
+ import { familyOf, keepStateOf, refreshRuns } from '../../engine/refresh';
5
8
  import { listenToSplitViews } from '../../engine/places';
6
9
  import { hasNativeScreenHooks } from '../../engine/screens';
7
10
  import type { LayoutRoot } from '../../interfaces/Layout';
@@ -24,7 +27,10 @@ import type { ErrorFallbackProps } from '../screens/ScreenBoundary';
24
27
  import { getAppContext, setAppContext } from '../context/appContext';
25
28
  import {
26
29
  type AppOptionsInput,
30
+ getDirection,
31
+ getTheme,
27
32
  initTheme,
33
+ setTheme,
28
34
  type NavigationDirection,
29
35
  type NavigationTheme,
30
36
  themedDefaultOptions,
@@ -43,6 +49,7 @@ import {
43
49
  import { launchState } from '../../engine/launchState';
44
50
  import { watchBackListeners } from '../../engine/backListeners';
45
51
  import { resolveRoot, type RootsMap, type RootTarget, type UsesOfRootValue } from './roots';
52
+ import { listenToDispatchedLinks } from '../linking/dispatchedLinks';
46
53
  import {
47
54
  launchLink,
48
55
  launchRoot,
@@ -50,6 +57,7 @@ import {
50
57
  linksStarted,
51
58
  reportLink,
52
59
  setupLinking,
60
+ updateLinking,
53
61
  } from '../linking/linking';
54
62
  import type { LinkMatch } from '../linking/linkPaths';
55
63
  import type { LinkingConfig } from '../linking/types';
@@ -85,6 +93,9 @@ const starts = new WeakMap<NavigationApp<any, any>, () => Promise<void>>();
85
93
 
86
94
  /** Starts the app, or brings back its root when the native side launches again. */
87
95
  export function startApp(app: NavigationApp<any, any>): Promise<void> {
96
+ // An app made after another launched knows once its module ran whether it is that app's next version.
97
+ const waiting = pending.get(app);
98
+ if (waiting) return waiting.then(() => startApp(app));
88
99
  const start = starts.get(app);
89
100
  if (!start) throw new Error('[navigation] Not an app made by createNavigation');
90
101
  return start();
@@ -150,9 +161,9 @@ interface BaseConfig<
150
161
  /** The look of the navigation: colors of the bars, tabs and backgrounds; `navigation.setTheme` changes it. */
151
162
  theme?: NavigationTheme;
152
163
  /**
153
- * The edges on which every screen keeps its content out of its safe area. Without it: all four on Android; on iOS
154
- * every edge but those where the content goes under a bar that shows. A screen gives its own with `safeArea(...)`
155
- * in its options.
164
+ * The edges on which every screen keeps its content out of its safe area. Without it: the top and the sides, but
165
+ * those where the content goes under a bar (`layout.safeAreaEdges`); the bottom is free and a list keeps clear of it
166
+ * with `useSafeAreaInsets()`. A screen gives its own with `safeArea(...)` in its options.
156
167
  */
157
168
  safeArea?: { edges: SafeAreaEdge[] };
158
169
  /** (iOS) The app's window, behind the screens: seen around a modal as it comes in. */
@@ -239,7 +250,11 @@ type CheckedRoots<Root, Roots, AppScreens> = {
239
250
  };
240
251
 
241
252
  export function isNavigationApp(value: unknown): value is NavigationApp {
242
- return typeof value === 'object' && value !== null && starts.has(value as NavigationApp);
253
+ return (
254
+ typeof value === 'object' &&
255
+ value !== null &&
256
+ (starts.has(value as NavigationApp) || pending.has(value as NavigationApp))
257
+ );
243
258
  }
244
259
 
245
260
  /**
@@ -276,14 +291,18 @@ export function createNavigation<
276
291
  > &
277
292
  NoInfer<CheckedRoots<FirstLayout, Roots, AllScreens<AppScreens, Groups>>>
278
293
  ): NavigationApp<Roots, AllScreens<AppScreens, Groups>> {
294
+ // The app that launched before, when this call may be its module running again after an edit (Fast Refresh): what
295
+ // the call starts waits until that is known.
296
+ const launched = __DEV__ ? hotCandidate() : undefined;
279
297
  // Counted from here: a "back again to leave" listener of the app's entry file comes after this call.
280
- watchBackListeners();
298
+ if (!launched) watchBackListeners();
281
299
  // idle: not started yet, or the last start failed. mounting: the first root is on its way. mounted: it is shown.
282
300
  let phase: 'idle' | 'mounting' | 'mounted' = 'idle';
283
301
  let screensRegistered = false;
284
302
  // The splash shows at the first start of this runtime only: a start that failed and runs again goes without it.
285
303
  let splashChecked = false;
286
304
  let listening = false;
305
+ let removeListeners: (() => void) | undefined;
287
306
  let prepared: Promise<void> | undefined;
288
307
  let markMounted!: () => void;
289
308
  // A new activity came while the first root was on its way (Android): its link is taken once that root is shown.
@@ -324,6 +343,62 @@ export function createNavigation<
324
343
  return buildRoot(typeof root === 'function' ? root(context) : root);
325
344
  }
326
345
 
346
+ // The screens of the app, its groups, the screen of a failed start and the splash, with what wraps each of them.
347
+ function registerAppScreens() {
348
+ const wrapper = {
349
+ errorFallback: config.errorFallback,
350
+ loadingFallback: config.loadingFallback,
351
+ onError:
352
+ config.onError &&
353
+ ((error: unknown, screen: ScreenInfo, componentStack: string | null | undefined) =>
354
+ config.onError?.(error, { type: 'screen', screen, componentStack })),
355
+ };
356
+ registerScreens(
357
+ [
358
+ { source: 'screens', screens: config.screens ?? {} },
359
+ ...Object.entries(config.groups ?? {}).map(([group, { screens, options }]) => ({
360
+ source: `the group '${group}'`,
361
+ screens,
362
+ options,
363
+ })),
364
+ ...(config.errorFallback
365
+ ? [
366
+ {
367
+ source: 'the start',
368
+ screens: { [START_FAILURE_SCREEN]: startFailureScreen(config.errorFallback) },
369
+ },
370
+ ]
371
+ : []),
372
+ ],
373
+ { ...wrapper, provider: config.screenProvider }
374
+ );
375
+ // The splash renders before willMount ends: a root of its own, without the app's providers, which may need what
376
+ // willMount prepares.
377
+ if (config.splash) {
378
+ registerScreens(
379
+ [
380
+ {
381
+ source: 'the splash',
382
+ screens: { [SPLASH_SCREEN]: config.splash.component },
383
+ ownRoot: true,
384
+ },
385
+ ],
386
+ {
387
+ ...wrapper,
388
+ // A splash that failed to render can't call hide(): the start goes on without waiting for it.
389
+ onError: (
390
+ error: unknown,
391
+ screen: ScreenInfo,
392
+ componentStack: string | null | undefined
393
+ ) => {
394
+ releaseSplash();
395
+ wrapper.onError?.(error, screen, componentStack);
396
+ },
397
+ }
398
+ );
399
+ }
400
+ }
401
+
327
402
  async function mount() {
328
403
  phase = 'mounting';
329
404
  // The state before the first root: the links wait for a newer one, which tells the screen they act from.
@@ -332,54 +407,7 @@ export function createNavigation<
332
407
  let linkHandled = false;
333
408
  try {
334
409
  if (!screensRegistered) {
335
- const wrapper = {
336
- errorFallback: config.errorFallback,
337
- loadingFallback: config.loadingFallback,
338
- onError:
339
- config.onError &&
340
- ((error: unknown, screen: ScreenInfo, componentStack: string | null | undefined) =>
341
- config.onError?.(error, { type: 'screen', screen, componentStack })),
342
- };
343
- registerScreens(
344
- [
345
- { source: 'screens', screens: config.screens ?? {} },
346
- ...Object.entries(config.groups ?? {}).map(([group, { screens, options }]) => ({
347
- source: `the group '${group}'`,
348
- screens,
349
- options,
350
- })),
351
- ...(config.errorFallback
352
- ? [
353
- {
354
- source: 'the start',
355
- screens: { [START_FAILURE_SCREEN]: startFailureScreen(config.errorFallback) },
356
- },
357
- ]
358
- : []),
359
- ],
360
- { ...wrapper, provider: config.screenProvider }
361
- );
362
- // The splash renders before willMount ends: a root of its own, without the app's providers, which may need what
363
- // willMount prepares.
364
- if (config.splash) {
365
- registerScreens(
366
- [
367
- {
368
- source: 'the splash',
369
- screens: { [SPLASH_SCREEN]: config.splash.component },
370
- ownRoot: true,
371
- },
372
- ],
373
- {
374
- ...wrapper,
375
- // A splash that failed to render can't call hide(): the start goes on without waiting for it.
376
- onError: (error: unknown, screen: ScreenInfo, componentStack: string | null | undefined) => {
377
- releaseSplash();
378
- wrapper.onError?.(error, screen, componentStack);
379
- },
380
- }
381
- );
382
- }
410
+ registerAppScreens();
383
411
  screensRegistered = true;
384
412
  }
385
413
  // The link that launched the app is asked for first: on iOS the first React content to appear (the host below,
@@ -484,28 +512,22 @@ export function createNavigation<
484
512
  }
485
513
 
486
514
  async function launch() {
515
+ if (__DEV__) launchedApp = app;
487
516
  setActiveApp({ roots: config.roots, presentation: config.presentation, mounted });
488
517
  if (!listening) {
489
518
  listening = true;
490
519
  // The edges of `safeArea` go under the app's options; the window's color goes with them, as the native side
491
520
  // takes it from the default options.
492
- initTheme(
493
- config.theme,
494
- {
495
- under: config.safeArea && { layout: { safeAreaEdges: config.safeArea.edges } },
496
- options: config.options,
497
- over: config.window && { window: config.window },
498
- },
499
- config.direction
500
- );
521
+ initTheme(config.theme, appDefaults(), config.direction);
501
522
  if (config.context !== undefined) setAppContext(config.context);
502
523
  if (config.appProvider) enableSlots(config.appProvider);
503
524
  listenToNavigationState();
525
+ listenToDispatchedLinks();
504
526
  watchSideMenus();
505
527
  listenToNativeScreens();
506
528
  listenToSplitViews();
507
529
  listenToNativeScreenCalls();
508
- if (config.listeners) addNavigationListeners(config.listeners);
530
+ if (config.listeners) removeListeners = addNavigationListeners(config.listeners);
509
531
  }
510
532
  launchState.launch++;
511
533
  // A new activity has no default options: the last ones set come back, else the theme's and the app's.
@@ -526,19 +548,131 @@ export function createNavigation<
526
548
  relaunchWaiters.splice(0).forEach((resume) => resume());
527
549
  }
528
550
 
529
- // The links listen from now on: one that comes before the native side launches waits for the first root.
530
- if (config.linking) {
531
- setupLinking(config.linking, {
551
+ // The routes of the links, the roots they name and where their errors go.
552
+ function linkingOptions() {
553
+ return {
532
554
  roots: config.roots,
533
- onError: config.onError && ((error, url) => config.onError?.(error, { type: 'link', url })),
534
- });
555
+ onError:
556
+ config.onError &&
557
+ ((error: unknown, url: string) => config.onError?.(error, { type: 'link', url })),
558
+ };
559
+ }
560
+
561
+ // Fast Refresh ran the module that makes the app again (development): its new config takes the place of the old.
562
+ // What only the start reads (the first root, willMount, the splash, the context) has done its part; the screens, the
563
+ // default options, the roots, the listeners and the links take the new one. A theme the same as before leaves the one
564
+ // the app set since. The providers and fallbacks are in the families of the ones before (`keepStateOf`): React
565
+ // Refresh puts the new ones in place, with the state of what they wrap.
566
+ function update(next: typeof config) {
567
+ const before = config;
568
+ // The app's one tree is set up at the start, or not: a provider added or taken out starts the app again.
569
+ if (!before.appProvider !== !next.appProvider) {
570
+ DevSettings.reload('[navigation] appProvider was added or taken out');
571
+ return;
572
+ }
573
+ config = next;
574
+ if (screensRegistered) registerAppScreens();
575
+ setActiveApp({ roots: config.roots, presentation: config.presentation, mounted });
576
+ // A direction the app set since stays too, unless the edit changes the config's.
577
+ const defaultsBefore = themedDefaultOptions();
578
+ const direction = sameValue(before.direction, next.direction) ? getDirection() : next.direction;
579
+ initTheme(getTheme(), appDefaults(), direction);
580
+ if (!sameValue(before.theme, next.theme)) {
581
+ setTheme(next.theme ?? {});
582
+ } else {
583
+ const defaults = themedDefaultOptions();
584
+ if (!sameValue(defaultsBefore, defaults)) setDefaultOptions(defaults ?? {});
585
+ }
586
+ if (listening) {
587
+ removeListeners?.();
588
+ removeListeners = config.listeners && addNavigationListeners(config.listeners);
589
+ }
590
+ if (config.linking && linkingStarted) updateLinking(config.linking, linkingOptions());
591
+ else startLinking();
592
+ }
593
+
594
+ // The default options of the app, under and over the theme's.
595
+ function appDefaults() {
596
+ return {
597
+ under: config.safeArea && { layout: { safeAreaEdges: config.safeArea.edges } },
598
+ options: config.options,
599
+ over: config.window && { window: config.window },
600
+ };
601
+ }
602
+
603
+ // The links listen from now on: one that comes before the native side launches waits for the first root.
604
+ let linkingStarted = false;
605
+ function startLinking() {
606
+ if (!config.linking || linkingStarted) return;
607
+ linkingStarted = true;
608
+ setupLinking(config.linking, linkingOptions());
609
+ }
610
+
611
+ // The components of the app keep their state across Fast Refresh, as the screens' do.
612
+ function keepComponentsState() {
613
+ if (!__DEV__) return;
614
+ keepStateOf(app, config.appProvider, 'appProvider');
615
+ keepStateOf(app, config.screenProvider, 'screenProvider');
616
+ keepStateOf(app, config.errorFallback, 'errorFallback');
617
+ keepStateOf(app, config.loadingFallback, 'loadingFallback');
618
+ keepStateOf(app, config.splash?.component, 'splash');
535
619
  }
536
620
 
537
621
  const app: NavigationApp<Roots, AllScreens<AppScreens, Groups>> = { [NAVIGATION_APP]: true };
538
- starts.set(app, () => reportStart(launch));
622
+ keepComponentsState();
623
+ const start = () => {
624
+ startLinking();
625
+ starts.set(app, () => reportStart(launch));
626
+ if (__DEV__) updates.set(app, update as (config: unknown) => void);
627
+ };
628
+ if (!launched) {
629
+ start();
630
+ return app;
631
+ }
632
+ // Once the module ran, Metro has put its exports in the families of the ones of its run before: the same family as
633
+ // the app that launched, or the app's entry registering it under the app's name again (an app it doesn't export),
634
+ // means this is its module again, and the app that runs takes the new config.
635
+ pending.set(
636
+ app,
637
+ Promise.resolve().then(() => {
638
+ pending.delete(app);
639
+ const family = familyOf(app);
640
+ if ((family && family === familyOf(launched)) || replacing.delete(app)) {
641
+ updates.get(launched)?.(config);
642
+ starts.set(app, starts.get(launched)!);
643
+ updates.set(app, updates.get(launched)!);
644
+ return;
645
+ }
646
+ watchBackListeners();
647
+ start();
648
+ })
649
+ );
539
650
  return app;
540
651
  }
541
652
 
653
+ // The app that launched in this runtime, and what takes the config of its module when it runs again (development).
654
+ let launchedApp: NavigationApp<any, any> | undefined;
655
+ const updates = new WeakMap<NavigationApp<any, any>, (config: unknown) => void>();
656
+ // The apps made after the launch until their module ran, and those the app's entry registered again under its name.
657
+ const pending = new WeakMap<NavigationApp<any, any>, Promise<void>>();
658
+ const replacing = new WeakSet<NavigationApp<any, any>>();
659
+
660
+ /**
661
+ * Notes an app the entry file registers under the name of the app that launched: the entry ran again after an edit
662
+ * (development), and the new app is the old one's next version.
663
+ */
664
+ export function noteReplacingApp(app: unknown): void {
665
+ if (__DEV__ && launchedApp && typeof app === 'object' && app !== null && NAVIGATION_APP in app) {
666
+ replacing.add(app as NavigationApp<any, any>);
667
+ }
668
+ }
669
+
670
+ // The app that launched, when React Refresh runs and a new app may be its module running again: one its module
671
+ // exports (Metro gives it a family), or one the entry registers again under the app's name.
672
+ function hotCandidate(): NavigationApp<any, any> | undefined {
673
+ return launchedApp && refreshRuns() ? launchedApp : undefined;
674
+ }
675
+
542
676
  // A willMount that never ends keeps the splash screen for good: in development the app hears of it.
543
677
  function warnIfLong(willMount: Promise<void>) {
544
678
  const timer = setTimeout(
@@ -19,7 +19,7 @@ import { stackChild, type StackEntry } from '../layout/Stack';
19
19
  import { badgeText } from '../layout/Tabs';
20
20
  import { mergeOptions } from '../../engine/mergeOptions';
21
21
  import { buildScreenOptions, type ScreenOptionsInput } from '../screens/defineScreen';
22
- import { coversColumn, placeOf } from '../../engine/places';
22
+ import { coversColumn, firstScreenOf, placeOf, type ScreenPlace } from '../../engine/places';
23
23
  import { command, placeFor } from './errors';
24
24
  import type { ColumnConfig, ModalConfig, OverlayConfig, PushConfig } from './presentation';
25
25
  import { defined, modalAnimations, pushAnimations } from './transitions';
@@ -30,6 +30,10 @@ const CLOSE_BUTTON = 'CloseButton';
30
30
  // The modals shown by `showModal`, for the ids of their first screens.
31
31
  let modals = 0;
32
32
 
33
+ // The stacks of the modals shown with a close button, by id: `setStack` and `replace` there give it to the new first
34
+ // screen. A stack's id is its modal's layer.
35
+ const closeButtonStacks = new Set<string>();
36
+
33
37
  // The settings of a command with the props of the screen it shows.
34
38
  type WithProps<Config> = Config & { props?: object };
35
39
 
@@ -115,7 +119,19 @@ export function popToRoot(fromId: string): Promise<string> {
115
119
  export function setStack(fromId: string, entries: StackEntry[]): Promise<string> {
116
120
  return command('setStack', () => {
117
121
  placeFor('setStack', fromId, { stack: true });
118
- return withSlots(() => engine.setStackRoot(fromId, entries.map(stackChild)));
122
+ const children = entries.map(stackChild);
123
+ const first = children[0]?.component;
124
+ if (!first || !hasCloseButton(placeOf(fromId))) {
125
+ return withSlots(() => engine.setStackRoot(fromId, children));
126
+ }
127
+ return afterLoading([first.name], () => {
128
+ // The screen's own buttons stay after the close button: the options of the layout replace them.
129
+ const id = first.id ?? nextId('Component');
130
+ const own = screenOptions(first.name, first.passProps ?? {});
131
+ const options = withCloseButton(mergeOptions(own, first.options ?? {}), id);
132
+ const withButton = { component: { ...first, id, options } };
133
+ return withSlots(() => engine.setStackRoot(fromId, [withButton, ...children.slice(1)]));
134
+ });
119
135
  });
120
136
  }
121
137
 
@@ -133,11 +149,12 @@ export function replace(
133
149
  return afterLoading([name], () => {
134
150
  const { props } = config;
135
151
  const base = getActiveApp()?.presentation?.push;
136
- const options = showOptions(name, props, AS_PUSH, base?.options, config.options, {
152
+ const id = nextId('Component');
153
+ let options = showOptions(name, props, AS_PUSH, base?.options, config.options, {
137
154
  app: pushAnimations(base?.transition),
138
155
  call: pushAnimations(config.transition),
139
156
  });
140
- const id = nextId('Component');
157
+ if (hasCloseButton(placeOf(fromId))) options = withCloseButton(options, id);
141
158
  return withSlots(() =>
142
159
  engine.setStackRoot(fromId, [screenLayout(name, props, options, id)])
143
160
  ).then(() => id);
@@ -192,16 +209,25 @@ function showModalNow(name: string, config: WithProps<ModalConfig>): Promise<str
192
209
  app: modalAnimations(base.transition),
193
210
  call: modalAnimations(call.transition),
194
211
  });
195
- if (settings.closeButton && settings.stack !== false)
212
+ // The stack gets its id here, so that the commands in it later know the modal had a close button.
213
+ const stackId = nextId('Stack');
214
+ const closeButton = settings.closeButton && settings.stack !== false;
215
+ if (closeButton) {
196
216
  options = withCloseButton(options, screenId);
217
+ closeButtonStacks.add(stackId);
218
+ forgetWithStack(stackId, screenId);
219
+ }
197
220
  if (call.onDismiss) whenScreenUnmounts(screenId, call.onDismiss);
198
221
  const screen = screenLayout(name, props, options, screenId);
199
222
  const presentation = presentationOptions(settings);
200
223
  const layout: Layout =
201
224
  settings.stack === false
202
225
  ? mergeLayoutOptions(screen, presentation)
203
- : { stack: { children: [screen], options: presentation } };
204
- return withSlots(() => engine.showModal(layout));
226
+ : { stack: { id: stackId, children: [screen], options: presentation } };
227
+ const shown = withSlots(() => engine.showModal(layout));
228
+ // A modal that never showed has no stack to remember.
229
+ if (closeButton) shown.catch(() => closeButtonStacks.delete(stackId));
230
+ return shown;
205
231
  }
206
232
 
207
233
  export function dismissModal(modalId: string): Promise<string> {
@@ -340,6 +366,21 @@ export function holdLeave(screenId: string, onAttempt: () => void): () => void {
340
366
  };
341
367
  }
342
368
 
369
+ // Whether a screen is in the stack of a modal shown with a close button: the modal's own stack, not one in it.
370
+ function hasCloseButton(place: ScreenPlace | undefined): boolean {
371
+ return place?.stack != null && place.stack === place.layer && closeButtonStacks.has(place.stack);
372
+ }
373
+
374
+ // The stack of a modal is gone with its last first screen: one that unmounts with no other first screen noted after
375
+ // it (`setStack`, `replace` note theirs before the old one goes).
376
+ function forgetWithStack(stackId: string, screenId: string): void {
377
+ whenScreenUnmounts(screenId, () => {
378
+ const next = firstScreenOf(stackId);
379
+ if (next) forgetWithStack(stackId, next);
380
+ else closeButtonStacks.delete(stackId);
381
+ });
382
+ }
383
+
343
384
  /** The options with a close button first at the leading edge, which dismisses the modal of the screen. */
344
385
  function withCloseButton(options: Options, screenId: string): Options {
345
386
  const close: NavigationButton = {
@@ -43,12 +43,13 @@ export interface ModalConfig {
43
43
  stack?: boolean;
44
44
  /**
45
45
  * A close button at the leading edge of the modal's first screen, which dismisses the modal: the system one on iOS,
46
- * an icon on Android. Its id and testID are `CloseButton`. Needs the stack.
46
+ * an icon on Android. Its id and testID are `CloseButton`. Needs the stack. A new first screen of that stack, from
47
+ * `setStack` or `replace`, gets it too.
47
48
  */
48
49
  closeButton?: boolean;
49
50
  /**
50
- * Called once the modal is gone, whatever dismissed it: a command, a swipe, a new root. `setStack` inside the
51
- * modal replaces its first screen, and calls it too.
51
+ * Called once the modal is gone, whatever dismissed it: a command, a swipe, a new root. `setStack` and `replace`
52
+ * inside the modal replace its first screen, and call it too.
52
53
  */
53
54
  onDismiss?: () => void;
54
55
  /**
@@ -48,7 +48,7 @@ export interface NavigationEvents {
48
48
  searchCancelled: ScreenEventOf<SearchBarCancelPressedEvent>;
49
49
  /** #### (iOS 16+, Android) The user picked a suggestion of `searchBar.suggestions`; the text stays. */
50
50
  searchSuggestionPicked: ScreenEventOf<NativeSearchSuggestionPickedEvent>;
51
- /** #### (iOS specific) */
51
+ /** The user dragged a sheet to another detent. */
52
52
  sheetDetentChanged: ScreenEventOf<NativeSheetDetentChangedEvent>;
53
53
  /** #### (iOS specific) */
54
54
  splitViewDisplayModeChanged: NativeSplitViewDisplayModeChangedEvent;
@@ -166,10 +166,16 @@ export function onNavigationEvent<Name extends NavigationEventName>(
166
166
  return onNativeEvent(nativeName, deliver);
167
167
  }
168
168
 
169
- /** Listens to the events of `listeners`, for as long as the app runs. */
170
- export function addNavigationListeners(listeners: NavigationListeners) {
169
+ /** Listens to the events of `listeners` until the function it gives is called. */
170
+ export function addNavigationListeners(listeners: NavigationListeners): () => void {
171
+ const removers: (() => void)[] = [];
171
172
  for (const name of Object.keys(listeners) as NavigationEventName[]) {
172
173
  const handler = listeners[name];
173
- if (handler) onNavigationEvent(name, handler as (event: NavigationEvents[typeof name]) => void);
174
+ if (handler) {
175
+ removers.push(
176
+ onNavigationEvent(name, handler as (event: NavigationEvents[typeof name]) => void)
177
+ );
178
+ }
174
179
  }
180
+ return () => removers.forEach((remove) => remove());
175
181
  }
@@ -22,7 +22,7 @@ import type { ScreenName, ShowArgs } from '../types';
22
22
  interface ScreenCommands {
23
23
  /** The screen the commands act from. */
24
24
  readonly screen: ScreenInfo;
25
- /** Shows a screen over this one in its stack; resolves with the id of the screen shown. */
25
+ /** Shows a screen over this one in its stack; resolves with the id of the screen shown (for a pair, the pair's id). */
26
26
  push<Name extends ScreenName>(name: Name, ...args: ShowArgs<Name, PushConfig>): Promise<string>;
27
27
  /**
28
28
  * Goes back to the screen before this one in its stack. The first screen of a split view column shown over the list
@@ -177,14 +177,19 @@ function stackCommands(id: string): StackCommands {
177
177
  };
178
178
  }
179
179
 
180
- /** The commands of the center for a menu screen: the menu closes once the center has changed. */
180
+ /**
181
+ * The commands of the center for a menu screen: the menu closes as the center changes, and the command resolves once
182
+ * both are done.
183
+ */
181
184
  function fromCenter(center: string, menuScreen: string): StackCommands {
182
185
  const centerCommands = stackCommands(center);
186
+ // As in the system's apps, the menu starts to close at the pick and the center changes as it goes, so a push is seen
187
+ // sliding in. The command settles after both, so the next one acts from the center; either one's error rejects it.
183
188
  const closing =
184
189
  <Args extends unknown[], Result>(run: (...args: Args) => Promise<Result>) =>
185
190
  async (...args: Args) => {
186
- const result = await run(...args);
187
- await closeMenu(menuScreen);
191
+ const closed = closeMenu(menuScreen);
192
+ const [result] = await Promise.all([run(...args), closed]);
188
193
  return result;
189
194
  };
190
195
  return {
@@ -5,13 +5,14 @@ import { useScreen } from './screenHooks';
5
5
  /**
6
6
  * How much of this screen's content the bars and the system still cover on each side, past what the screen keeps its
7
7
  * content off itself (`layout.safeAreaEdges`): 0 on an edge the screen pads, the whole inset on an edge its content goes
8
- * under — under a top bar, under the vertical bar at the side of iPhone Duo, every edge with `safeAreaEdges: []`. A list
9
- * adds exactly this to its own padding. The native side measures every screen on its own, also the screens of
8
+ * under — the bottom by default (the home indicator, the navigation bar, a tab bar or toolbar the screen goes under),
9
+ * under a top bar, under the vertical bar at the side of iPhone Duo, every edge with `safeAreaEdges: []`. A list adds
10
+ * exactly this to its own padding. The native side measures every screen on its own, also the screens of
10
11
  * `appProvider`.
11
12
  *
12
13
  * @example
13
14
  * const insets = useSafeAreaInsets();
14
- * <ScrollView contentContainerStyle={{ paddingLeft: 16 + insets.left, paddingRight: 16 + insets.right }} />
15
+ * <ScrollView contentContainerStyle={{ paddingBottom: 16 + insets.bottom }} />
15
16
  */
16
17
  export function useSafeAreaInsets(): EdgeInsets {
17
18
  const { id } = useScreen();
package/src/api/index.ts CHANGED
@@ -109,6 +109,7 @@ export type { NativeScreen } from './screens/nativeScreens';
109
109
  export { defineArrangement } from './screens/arrangement';
110
110
  export type { Arrangement, ArrangementDefinition, ScreenArrangement } from './screens/arrangement';
111
111
  export type {
112
+ DefinedScreen,
112
113
  OptionsEnvironment,
113
114
  ScreenDefinition,
114
115
  ScreenOptionsInput,
@@ -0,0 +1,18 @@
1
+ import { DeviceEventEmitter, Platform } from 'react-native';
2
+ import { onNativeEvent } from '../../engine/native';
3
+ import type { DeepLinkDispatchedEvent } from '../../interfaces/Events';
4
+
5
+ let listening = false;
6
+
7
+ /**
8
+ * (iOS) Hands `Linking` the links the app dispatched that it didn't take from the native side: on React Native 0.88
9
+ * and newer, in an app with a scene delegate, it takes only the links a scene opened. `Linking` listens to its `url`
10
+ * events through `DeviceEventEmitter`, so every listener of the app gets them, the navigation's links too.
11
+ */
12
+ export function listenToDispatchedLinks() {
13
+ if (listening || Platform.OS !== 'ios') return;
14
+ listening = true;
15
+ onNativeEvent<DeepLinkDispatchedEvent>('DeepLinkDispatched', ({ url }) => {
16
+ DeviceEventEmitter.emit('url', { url });
17
+ });
18
+ }
@@ -6,7 +6,11 @@ import { commandsStarted, whenCommandsSettle } from '../commands/errors';
6
6
  import { getAppContext, subscribeAppContext } from '../context/appContext';
7
7
  import { buildRoot, type RootLayout } from '../layout/Root';
8
8
  import { navigation } from '../navigation';
9
- import { getNavigationState, whenScreenAfter, type NavigationState } from '../state/navigationState';
9
+ import {
10
+ getNavigationState,
11
+ whenScreenAfter,
12
+ type NavigationState,
13
+ } from '../state/navigationState';
10
14
  import {
11
15
  compileRoutes,
12
16
  matchLink,
@@ -68,6 +72,23 @@ export function setupLinking(
68
72
  setPendingLinkOpener((link) => run(link, routeOf(link), false));
69
73
  }
70
74
 
75
+ /**
76
+ * Takes the routes, the roots and `onError` of an app whose module ran again after an edit (Fast Refresh, development):
77
+ * the links that come from now on find the new routes.
78
+ */
79
+ export function updateLinking(
80
+ linking: Config,
81
+ options: {
82
+ roots: RootsMap | undefined;
83
+ onError: ((error: unknown, url: string) => void) | undefined;
84
+ }
85
+ ): void {
86
+ config = linking;
87
+ roots = options.roots;
88
+ onError = options.onError;
89
+ routes = compileRoutes(Object.keys(linking.routes));
90
+ }
91
+
71
92
  /**
72
93
  * The link that launched the app, matched as the app starts (`unmatched` may run commands then); the same one for
73
94
  * every try of the first start.
@@ -55,7 +55,10 @@ export interface AppNavigation {
55
55
  switchTo<const Layout extends Exclude<RootLayout, string>>(
56
56
  layout: Layout & NoInfer<CheckedScreens<UsesOfRoot<Layout>, RegisteredScreens>>
57
57
  ): Promise<void>;
58
- /** Shows a screen in the stack of the screen the user sees; resolves with the id of the screen shown. */
58
+ /**
59
+ * Shows a screen in the stack of the screen the user sees; resolves with the id of the screen shown (for a pair, the
60
+ * pair's id).
61
+ */
59
62
  push<Name extends ScreenName>(name: Name, ...args: ShowArgs<Name, PushConfig>): Promise<string>;
60
63
  /** Goes back in the stack of the screen the user sees; see `useNavigation().pop`. */
61
64
  pop(): Promise<string>;