@apexnative/navigation 1.0.0-alpha.1 → 1.0.0-alpha.11

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 (581) hide show
  1. package/ApexNavigation.podspec +2 -1
  2. package/CHANGELOG.md +132 -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/ArrangementDefinition.kt +9 -3
  67. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementPlanner.kt +20 -15
  68. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/SecondaryScreenPresenter.kt +13 -5
  69. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/AppliedTabCalls.kt +49 -0
  70. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsCollapseBehavior.kt +5 -3
  71. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +108 -34
  72. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsPresenter.kt +25 -24
  73. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowGeometry.kt +22 -0
  74. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabItems.kt +3 -3
  75. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabsRoom.kt +0 -5
  76. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentPresenter.kt +28 -7
  77. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +12 -9
  78. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ContentReadiness.kt +2 -2
  79. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/RenderWait.kt +27 -7
  80. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenFrame.kt +1 -1
  81. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenReadiness.kt +103 -56
  82. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenSafeArea.kt +29 -11
  83. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/externalcomponent/ExternalComponentViewController.kt +2 -6
  84. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalAnimations.kt +22 -24
  85. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +109 -21
  86. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalRecord.kt +21 -6
  87. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +476 -73
  88. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +57 -25
  89. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetBack.kt +42 -0
  90. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +83 -0
  91. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackCheck.kt +50 -0
  92. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackState.kt +49 -14
  93. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +71 -12
  94. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +37 -11
  95. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/overlay/OverlayCoordinator.kt +10 -8
  96. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/Capabilities.kt +11 -4
  97. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ContainerBackground.kt +3 -3
  98. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +6 -6
  99. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +42 -9
  100. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +19 -8
  101. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuPresenter.kt +16 -7
  102. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuRules.kt +43 -4
  103. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitPanes.kt +23 -0
  104. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +77 -17
  105. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +315 -0
  106. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/PreparedFrame.kt +3 -3
  107. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +30 -20
  108. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +216 -18
  109. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackDisplay.kt +26 -1
  110. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +149 -41
  111. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackTransitions.kt +26 -8
  112. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +115 -6
  113. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabMotion.kt +142 -0
  114. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +222 -48
  115. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/ScreenSearch.kt +3 -5
  116. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +30 -34
  117. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarComponents.kt +5 -51
  118. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarRowTransition.kt +3 -2
  119. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/ButtonPlaces.kt +11 -5
  120. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/MenuChecks.kt +13 -56
  121. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +219 -54
  122. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarVisibility.kt +9 -2
  123. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ScrollEventListener.kt +6 -9
  124. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ViewController.kt +75 -21
  125. package/android/src/main/java/dev/apexnative/navigation/views/animations/AnimationLayer.kt +73 -0
  126. package/android/src/main/java/dev/apexnative/navigation/views/animations/Curves.kt +29 -11
  127. package/android/src/main/java/dev/apexnative/navigation/views/animations/ValueInterpolation.kt +14 -0
  128. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +9 -7
  129. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabsLayout.kt +61 -2
  130. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomBottomTabItemView.kt +0 -5
  131. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomTabRow.kt +72 -10
  132. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStep.kt +31 -0
  133. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +143 -135
  134. package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +13 -5
  135. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
  136. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionTargets.kt +9 -6
  137. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionViews.kt +100 -0
  138. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +112 -4
  139. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +346 -36
  140. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMorph.kt +199 -0
  141. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +56 -41
  142. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextMorph.kt +176 -0
  143. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewMorph.kt +108 -0
  144. package/android/src/main/java/dev/apexnative/navigation/views/sidemenu/SideMenuView.kt +12 -3
  145. package/android/src/main/java/dev/apexnative/navigation/views/stack/ScreenEdge.kt +45 -0
  146. package/android/src/main/java/dev/apexnative/navigation/views/stack/StackLayout.kt +140 -1
  147. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/Fab.kt +14 -10
  148. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabCopy.kt +85 -0
  149. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabMenu.kt +13 -0
  150. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +5 -17
  151. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +73 -34
  152. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonComponentCell.kt +6 -6
  153. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonView.kt +113 -0
  154. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarMenu.kt +219 -0
  155. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +125 -178
  156. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonMenus.kt +34 -64
  157. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonRow.kt +216 -0
  158. package/android/src/main/jni/ANNContentHeights.cpp +82 -0
  159. package/android/src/main/res/drawable/apex_navigation_ic_arrow_right.xml +14 -0
  160. package/android/src/main/res/layout/apex_navigation_menu_header.xml +19 -0
  161. package/android/src/main/res/layout/apex_navigation_menu_item.xml +68 -0
  162. package/android/src/main/res/values/styles.xml +1 -1
  163. package/android/src/main/res/values-night/styles.xml +1 -1
  164. package/cli/app.js +1 -1
  165. package/cli/doctor/checks/app.js +77 -14
  166. package/cli/doctor/checks/splash.js +4 -22
  167. package/cli/migrate/native.js +18 -0
  168. package/cli/project.js +10 -2
  169. package/cli/setup/index.js +18 -0
  170. package/cli/setup/source.js +2 -1
  171. package/cli/setup/steps/appDelegate.js +66 -11
  172. package/cli/setup/steps/mainApplication.js +134 -19
  173. package/cli/setup/steps/metro.js +46 -0
  174. package/cli/setup/steps/sceneDelegate.js +108 -0
  175. package/cli/splash/index.js +3 -1
  176. package/docs-md/architecture/native-screens.md +4 -0
  177. package/docs-md/architecture/theme-and-context.md +131 -12
  178. package/docs-md/architecture/transitions.md +58 -12
  179. package/docs-md/containers/arrangement.md +17 -1
  180. package/docs-md/containers/modals.md +8 -4
  181. package/docs-md/containers/overlays.md +3 -1
  182. package/docs-md/containers/side-menu.md +19 -2
  183. package/docs-md/containers/tabs.md +5 -1
  184. package/docs-md/flows/bottom-sheets.md +4 -2
  185. package/docs-md/flows/forms-in-a-modal.md +1 -1
  186. package/docs-md/fundamentals/screens-and-props.md +9 -1
  187. package/docs-md/fundamentals/starting-the-app.md +1 -1
  188. package/docs-md/guides/cli.md +4 -3
  189. package/docs-md/guides/deep-links.md +15 -33
  190. package/docs-md/help/glossary.md +4 -4
  191. package/docs-md/help/troubleshooting.md +44 -6
  192. package/docs-md/index.json +61 -1
  193. package/docs-md/migration/from-expo-router.md +1 -1
  194. package/docs-md/migration/from-react-native-navigation.md +9 -3
  195. package/docs-md/migration/from-react-navigation.md +2 -2
  196. package/docs-md/screen-ui/back-and-gestures.md +46 -2
  197. package/docs-md/screen-ui/bar-buttons.md +5 -5
  198. package/docs-md/screen-ui/search.md +1 -1
  199. package/docs-md/screen-ui/system-ui.md +17 -12
  200. package/docs-md/screen-ui/toolbar-and-fab.md +4 -2
  201. package/docs-md/screen-ui/top-bar.md +8 -4
  202. package/docs-md/start/installation.md +21 -3
  203. package/ios/Animations/ANNFrameDriver.h +55 -15
  204. package/ios/Animations/ANNFrameDriver.mm +216 -60
  205. package/ios/Animations/ANNTransitionAnimator.h +26 -5
  206. package/ios/Animations/ANNTransitionAnimator.mm +61 -13
  207. package/ios/Animations/ANNTransitionPlan.h +2 -2
  208. package/ios/Animations/ANNTransitionPlan.mm +10 -0
  209. package/ios/Animations/ANNTransitionWait.mm +6 -7
  210. package/ios/Animations/Elements/ANNElementFinder.h +57 -0
  211. package/ios/Animations/Elements/ANNElementFinder.mm +174 -2
  212. package/ios/Animations/Elements/ANNElementTransition.h +10 -8
  213. package/ios/Animations/Elements/ANNElementTransition.mm +19 -21
  214. package/ios/Animations/Elements/ANNSharedElementFlight.h +16 -11
  215. package/ios/Animations/Elements/ANNSharedElementFlight.mm +308 -69
  216. package/ios/Animations/Interpolators/ANNInterpolate.h +2 -30
  217. package/ios/Animations/Interpolators/ANNTransformParts.h +48 -0
  218. package/ios/Animations/Interpolators/ANNTransformParts.mm +507 -0
  219. package/ios/Animations/Interpolators/ANNViewTracks.h +9 -6
  220. package/ios/Animations/Interpolators/ANNViewTracks.mm +100 -30
  221. package/ios/CLAUDE.md +60 -24
  222. package/ios/CORE.md +44 -34
  223. package/ios/Contract/ANNCommandAnswer.h +13 -5
  224. package/ios/Contract/ANNCommandAnswer.mm +40 -32
  225. package/ios/Contract/ANNCommandContract.h +15 -0
  226. package/ios/Contract/ANNCommandContract.mm +78 -0
  227. package/ios/Contract/ANNCommandRunner.h +10 -9
  228. package/ios/Contract/ANNCommandRunner.mm +22 -28
  229. package/ios/Contract/ANNErrorTexts.h +6 -2
  230. package/ios/Contract/ANNErrorTexts.mm +18 -10
  231. package/ios/Contract/ANNLayoutNode.h +3 -3
  232. package/ios/Contract/ANNLayoutReader.h +3 -3
  233. package/ios/Core/ANNAppDelegate.mm +0 -2
  234. package/ios/Core/ANNAppearanceDispatcher.h +5 -4
  235. package/ios/Core/ANNAppearanceDispatcher.mm +12 -1
  236. package/ios/Core/ANNDeepLinkQueue.h +22 -2
  237. package/ios/Core/ANNDeepLinkQueue.mm +121 -14
  238. package/ios/Core/ANNErrorHandler.h +9 -4
  239. package/ios/Core/ANNErrorHandler.mm +20 -2
  240. package/ios/Core/ANNEventContract.h +246 -0
  241. package/ios/Core/ANNEventContract.mm +225 -0
  242. package/ios/Core/ANNEventEmitter.h +6 -2
  243. package/ios/Core/ANNEventEmitter.mm +117 -80
  244. package/ios/Core/ANNHinge.h +6 -0
  245. package/ios/Core/ANNHinge.mm +15 -4
  246. package/ios/Core/ANNJavaScriptCalls.h +33 -0
  247. package/ios/Core/ANNJavaScriptCalls.mm +52 -0
  248. package/ios/Core/ANNLayoutProtocol.h +5 -5
  249. package/ios/Core/ANNNavigationState.h +7 -5
  250. package/ios/Core/ANNNavigationState.mm +8 -7
  251. package/ios/Core/ANNNodeHelper.h +32 -12
  252. package/ios/Core/ANNNodeHelper.mm +100 -3
  253. package/ios/Core/ANNParking.h +5 -4
  254. package/ios/Core/ANNReloadCoordinator.mm +5 -12
  255. package/ios/Core/ANNRenderWait.h +20 -6
  256. package/ios/Core/ANNRenderWait.mm +143 -56
  257. package/ios/Core/ANNSceneDelegate.mm +25 -15
  258. package/ios/Core/ANNSystemUI.h +3 -2
  259. package/ios/Core/ANNSystemUI.mm +7 -0
  260. package/ios/Core/ANNUtils.h +7 -0
  261. package/ios/Core/ANNUtils.mm +10 -0
  262. package/ios/Core/ApexNavigation+Internal.h +1 -1
  263. package/ios/Core/ApexNavigation.mm +7 -6
  264. package/ios/Core/UIViewController+LayoutProtocol.h +9 -2
  265. package/ios/Core/UIViewController+LayoutProtocol.mm +8 -0
  266. package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
  267. package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
  268. package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +195 -21
  269. package/ios/Layouts/Modal/ANNModalCoordinator.h +1 -1
  270. package/ios/Layouts/Modal/ANNModalCoordinator.mm +57 -16
  271. package/ios/Layouts/Modal/ANNModalPresentation.h +8 -5
  272. package/ios/Layouts/Modal/ANNModalPresentation.mm +12 -12
  273. package/ios/Layouts/Modal/ANNSheetPresenter.mm +83 -1
  274. package/ios/Layouts/Overlay/ANNOverlayCoordinator.mm +2 -8
  275. package/ios/Layouts/Root/ANNRootCoordinator.mm +58 -19
  276. package/ios/Layouts/Root/ANNSplashViewController.h +5 -3
  277. package/ios/Layouts/Root/ANNSplashViewController.mm +147 -0
  278. package/ios/Layouts/Screen/ANNComponentPresenter.h +11 -3
  279. package/ios/Layouts/Screen/ANNComponentPresenter.mm +34 -6
  280. package/ios/Layouts/Screen/ANNComponentViewController.h +15 -13
  281. package/ios/Layouts/Screen/ANNComponentViewController.mm +130 -75
  282. package/ios/Layouts/Screen/ANNNativeScreenContext.mm +7 -5
  283. package/ios/Layouts/Screen/ANNPreviewInteraction.h +7 -4
  284. package/ios/Layouts/Screen/ANNPreviewInteraction.mm +72 -10
  285. package/ios/Layouts/Screen/ANNScreenEnvironment.h +63 -0
  286. package/ios/Layouts/Screen/ANNScreenEnvironment.mm +181 -0
  287. package/ios/Layouts/Screen/ANNScreenPlace.h +53 -0
  288. package/ios/Layouts/Screen/ANNScreenPlace.mm +205 -0
  289. package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
  290. package/ios/Layouts/Screen/ANNScreenRegions.mm +9 -44
  291. package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
  292. package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
  293. package/ios/Layouts/Screen/ANNScreenSettling.h +34 -0
  294. package/ios/Layouts/Screen/ANNScreenSettling.mm +171 -0
  295. package/ios/Layouts/SideMenu/ANNSideMenuTypes.h +8 -0
  296. package/ios/Layouts/SideMenu/ANNSideMenuViewController.mm +83 -14
  297. package/ios/Layouts/SplitView/ANNSplitViewCommands.h +3 -2
  298. package/ios/Layouts/SplitView/ANNSplitViewCommands.mm +105 -39
  299. package/ios/Layouts/SplitView/ANNSplitViewController.mm +7 -8
  300. package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
  301. package/ios/Layouts/Stack/ANNPreviewPush.mm +142 -27
  302. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
  303. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
  304. package/ios/Layouts/Stack/ANNStackCommands.mm +1 -0
  305. package/ios/Layouts/Stack/ANNStackController.h +8 -0
  306. package/ios/Layouts/Stack/ANNStackController.mm +184 -16
  307. package/ios/Layouts/Stack/ANNStackQueue.h +5 -2
  308. package/ios/Layouts/Stack/ANNStackQueue.mm +56 -43
  309. package/ios/Layouts/Stack/ANNSwipePopInteraction.h +26 -0
  310. package/ios/Layouts/Stack/ANNSwipePopInteraction.mm +185 -0
  311. package/ios/Layouts/Stack/InteractivePopGestureDelegate.mm +28 -4
  312. package/ios/Layouts/Stack/UINavigationController+ANNCommands.h +4 -2
  313. package/ios/Layouts/Stack/UINavigationController+ANNCommands.mm +2 -3
  314. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.h +4 -0
  315. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.mm +11 -0
  316. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
  317. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
  318. package/ios/Layouts/Tabs/ANNBottomTabsController.h +3 -0
  319. package/ios/Layouts/Tabs/ANNBottomTabsController.mm +237 -57
  320. package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
  321. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +6 -2
  322. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +232 -43
  323. package/ios/Layouts/Tabs/ANNTabsDesign.h +6 -5
  324. package/ios/Layouts/Tabs/ANNTabsDesign.mm +9 -1
  325. package/ios/Layouts/Tabs/UITabBar+utils.h +5 -5
  326. package/ios/Layouts/Tabs/UITabBar+utils.mm +32 -13
  327. package/ios/Options/ANNAnimationOptions.h +2 -1
  328. package/ios/Options/ANNAnimationOptions.mm +1 -1
  329. package/ios/Options/ANNBottomTabsOptions.h +2 -0
  330. package/ios/Options/ANNBottomTabsOptions.mm +1 -0
  331. package/ios/Options/ANNOptions.h +25 -0
  332. package/ios/Options/ANNOptions.mm +157 -1
  333. package/ios/Options/ANNOptionsCache.h +7 -6
  334. package/ios/Options/ANNOptionsReader.mm +108 -0
  335. package/ios/Options/ANNSearchBarOptions.h +4 -3
  336. package/ios/Options/ANNSheetOptions.h +4 -1
  337. package/ios/Options/ANNSideMenuOptions.h +2 -0
  338. package/ios/Options/ANNSideMenuOptions.mm +2 -0
  339. package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
  340. package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
  341. package/ios/Options/ANNUserChoice.h +57 -0
  342. package/ios/Options/ANNUserChoice.mm +44 -0
  343. package/ios/Options/Params/ANNImageSource.h +61 -0
  344. package/ios/Options/Params/ANNImageSource.mm +101 -0
  345. package/ios/Options/Params/ANNOptionImages.h +37 -0
  346. package/ios/Options/Params/ANNOptionImages.mm +284 -0
  347. package/ios/Options/Params/ANNParam.h +15 -0
  348. package/ios/Options/Params/ANNParam.mm +61 -0
  349. package/ios/Options/Params/Color.h +3 -0
  350. package/ios/Options/Params/Color.mm +21 -0
  351. package/ios/Options/Params/ColorParser.h +4 -3
  352. package/ios/Options/Params/ColorParser.mm +22 -4
  353. package/ios/Options/Params/Image.h +15 -2
  354. package/ios/Options/Params/Image.mm +35 -2
  355. package/ios/Options/Params/ImageParser.h +5 -5
  356. package/ios/Options/Params/ImageParser.mm +28 -46
  357. package/ios/Public/ApexNavigation/ANNSceneDelegate.h +3 -0
  358. package/ios/Public/ApexNavigation/ApexNavigation.h +1 -1
  359. package/ios/RECIPES.md +13 -6
  360. package/ios/React/ANNReactView.mm +6 -25
  361. package/ios/React/ANNSafeAreaViewComponentView.mm +28 -17
  362. package/ios/React/ANNSurfaceHostingView.h +14 -0
  363. package/ios/React/ANNSurfaceHostingView.mm +144 -1
  364. package/ios/React/Slots/ANNSlotComponentView.mm +24 -17
  365. package/ios/React/Slots/ANNSlotContainers.h +14 -6
  366. package/ios/React/Slots/ANNSlotContainers.mm +75 -2
  367. package/ios/React/Slots/ANNSlotHost.mm +1 -3
  368. package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
  369. package/ios/TopBar/ANNBackButtonPresenter.mm +6 -5
  370. package/ios/TopBar/ANNBarAppearance.h +2 -1
  371. package/ios/TopBar/ANNBarAppearance.mm +111 -30
  372. package/ios/TopBar/ANNBarBackgroundComponent.mm +16 -0
  373. package/ios/TopBar/ANNBarButtonComponentView.h +4 -4
  374. package/ios/TopBar/ANNBarButtonComponentView.mm +1 -1
  375. package/ios/TopBar/ANNBarButtons.h +14 -8
  376. package/ios/TopBar/ANNBarButtons.mm +397 -80
  377. package/ios/TopBar/ANNIconButtonImage.h +1 -0
  378. package/ios/TopBar/ANNIconButtonImage.mm +34 -1
  379. package/ios/TopBar/ANNLargeTitlePresenter.h +13 -0
  380. package/ios/TopBar/ANNLargeTitlePresenter.mm +50 -7
  381. package/ios/TopBar/ANNMainList.h +3 -0
  382. package/ios/TopBar/ANNMainList.mm +4 -0
  383. package/ios/TopBar/ANNScrollEdgeEffects.h +22 -6
  384. package/ios/TopBar/ANNScrollEdgeEffects.mm +123 -16
  385. package/ios/TopBar/ANNSearchPresenter.mm +172 -21
  386. package/ios/TopBar/ANNSearchResultsViewController.mm +29 -6
  387. package/ios/TopBar/ANNTopBarPresenter.h +8 -2
  388. package/ios/TopBar/ANNTopBarPresenter.mm +155 -33
  389. package/ios/TurboModules/ANNTurboEventEmitter.mm +4 -35
  390. package/ios/TurboModules/ANNTurboModule.mm +104 -33
  391. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.cpp +20 -0
  392. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.h +5 -14
  393. package/lib/module/ARCHITECTURE.md +40 -27
  394. package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
  395. package/lib/module/api/app/AppRegistry.js +14 -2
  396. package/lib/module/api/app/AppRegistry.js.map +1 -1
  397. package/lib/module/api/app/createNavigation.js +190 -66
  398. package/lib/module/api/app/createNavigation.js.map +1 -1
  399. package/lib/module/api/commands/commands.js +54 -6
  400. package/lib/module/api/commands/commands.js.map +1 -1
  401. package/lib/module/api/events/navigationEvents.js +6 -2
  402. package/lib/module/api/events/navigationEvents.js.map +1 -1
  403. package/lib/module/api/hooks/useNavigation.js +8 -3
  404. package/lib/module/api/hooks/useNavigation.js.map +1 -1
  405. package/lib/module/api/hooks/useSafeAreaInsets.js +4 -3
  406. package/lib/module/api/hooks/useSafeAreaInsets.js.map +1 -1
  407. package/lib/module/api/linking/dispatchedLinks.js +23 -0
  408. package/lib/module/api/linking/dispatchedLinks.js.map +1 -0
  409. package/lib/module/api/linking/linking.js +11 -0
  410. package/lib/module/api/linking/linking.js.map +1 -1
  411. package/lib/module/api/navigation.js.map +1 -1
  412. package/lib/module/api/options/OptionsChain.js +2 -2
  413. package/lib/module/api/screens/arrangement.js +5 -2
  414. package/lib/module/api/screens/arrangement.js.map +1 -1
  415. package/lib/module/api/screens/defineScreen.js +45 -3
  416. package/lib/module/api/screens/defineScreen.js.map +1 -1
  417. package/lib/module/api/screens/nativeScreens.js +31 -6
  418. package/lib/module/api/screens/nativeScreens.js.map +1 -1
  419. package/lib/module/api/screens/registerScreens.js +193 -35
  420. package/lib/module/api/screens/registerScreens.js.map +1 -1
  421. package/lib/module/api/theme/theme.js +5 -0
  422. package/lib/module/api/theme/theme.js.map +1 -1
  423. package/lib/module/engine/commands.js +51 -9
  424. package/lib/module/engine/commands.js.map +1 -1
  425. package/lib/module/engine/layout.js +20 -11
  426. package/lib/module/engine/layout.js.map +1 -1
  427. package/lib/module/engine/nativeScreens.js +9 -0
  428. package/lib/module/engine/nativeScreens.js.map +1 -1
  429. package/lib/module/engine/options.js +49 -15
  430. package/lib/module/engine/options.js.map +1 -1
  431. package/lib/module/engine/optionsChange.js +102 -0
  432. package/lib/module/engine/optionsChange.js.map +1 -0
  433. package/lib/module/engine/places.js +52 -7
  434. package/lib/module/engine/places.js.map +1 -1
  435. package/lib/module/engine/props.js +30 -1
  436. package/lib/module/engine/props.js.map +1 -1
  437. package/lib/module/engine/refresh.js +85 -0
  438. package/lib/module/engine/refresh.js.map +1 -0
  439. package/lib/module/engine/rememberedOptions.js +61 -1
  440. package/lib/module/engine/rememberedOptions.js.map +1 -1
  441. package/lib/module/engine/screens.js +77 -16
  442. package/lib/module/engine/screens.js.map +1 -1
  443. package/lib/module/interfaces/contract/commands.json +101 -0
  444. package/lib/module/interfaces/contract/errors.json +275 -0
  445. package/lib/typescript/adapters/NativeANNTurboModule.d.ts +12 -2
  446. package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
  447. package/lib/typescript/api/app/AppRegistry.d.ts.map +1 -1
  448. package/lib/typescript/api/app/createNavigation.d.ts +8 -3
  449. package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
  450. package/lib/typescript/api/commands/commands.d.ts.map +1 -1
  451. package/lib/typescript/api/commands/presentation.d.ts +4 -3
  452. package/lib/typescript/api/commands/presentation.d.ts.map +1 -1
  453. package/lib/typescript/api/events/navigationEvents.d.ts +3 -3
  454. package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
  455. package/lib/typescript/api/hooks/useNavigation.d.ts +1 -1
  456. package/lib/typescript/api/hooks/useNavigation.d.ts.map +1 -1
  457. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts +4 -3
  458. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
  459. package/lib/typescript/api/index.d.ts +1 -1
  460. package/lib/typescript/api/index.d.ts.map +1 -1
  461. package/lib/typescript/api/linking/dispatchedLinks.d.ts +7 -0
  462. package/lib/typescript/api/linking/dispatchedLinks.d.ts.map +1 -0
  463. package/lib/typescript/api/linking/linking.d.ts +8 -0
  464. package/lib/typescript/api/linking/linking.d.ts.map +1 -1
  465. package/lib/typescript/api/navigation.d.ts +4 -1
  466. package/lib/typescript/api/navigation.d.ts.map +1 -1
  467. package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
  468. package/lib/typescript/api/screens/arrangement.d.ts +12 -2
  469. package/lib/typescript/api/screens/arrangement.d.ts.map +1 -1
  470. package/lib/typescript/api/screens/defineScreen.d.ts +23 -4
  471. package/lib/typescript/api/screens/defineScreen.d.ts.map +1 -1
  472. package/lib/typescript/api/screens/nativeScreens.d.ts +8 -1
  473. package/lib/typescript/api/screens/nativeScreens.d.ts.map +1 -1
  474. package/lib/typescript/api/screens/registerScreens.d.ts.map +1 -1
  475. package/lib/typescript/api/theme/theme.d.ts +2 -0
  476. package/lib/typescript/api/theme/theme.d.ts.map +1 -1
  477. package/lib/typescript/engine/commands.d.ts +5 -0
  478. package/lib/typescript/engine/commands.d.ts.map +1 -1
  479. package/lib/typescript/engine/layout.d.ts.map +1 -1
  480. package/lib/typescript/engine/nativeScreens.d.ts +5 -0
  481. package/lib/typescript/engine/nativeScreens.d.ts.map +1 -1
  482. package/lib/typescript/engine/options.d.ts +5 -2
  483. package/lib/typescript/engine/options.d.ts.map +1 -1
  484. package/lib/typescript/engine/optionsChange.d.ts +28 -0
  485. package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
  486. package/lib/typescript/engine/places.d.ts +7 -2
  487. package/lib/typescript/engine/places.d.ts.map +1 -1
  488. package/lib/typescript/engine/props.d.ts +8 -1
  489. package/lib/typescript/engine/props.d.ts.map +1 -1
  490. package/lib/typescript/engine/refresh.d.ts +35 -0
  491. package/lib/typescript/engine/refresh.d.ts.map +1 -0
  492. package/lib/typescript/engine/rememberedOptions.d.ts +13 -0
  493. package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
  494. package/lib/typescript/engine/screens.d.ts +27 -6
  495. package/lib/typescript/engine/screens.d.ts.map +1 -1
  496. package/lib/typescript/interfaces/ComponentEvents.d.ts +4 -4
  497. package/lib/typescript/interfaces/ComponentEvents.d.ts.map +1 -1
  498. package/lib/typescript/interfaces/Events.d.ts +28 -10
  499. package/lib/typescript/interfaces/Events.d.ts.map +1 -1
  500. package/lib/typescript/interfaces/Options.d.ts +1 -1
  501. package/lib/typescript/interfaces/Options.d.ts.map +1 -1
  502. package/lib/typescript/interfaces/options/animations.d.ts +80 -22
  503. package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
  504. package/lib/typescript/interfaces/options/bottomTabs.d.ts +21 -7
  505. package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
  506. package/lib/typescript/interfaces/options/buttons.d.ts +23 -15
  507. package/lib/typescript/interfaces/options/buttons.d.ts.map +1 -1
  508. package/lib/typescript/interfaces/options/modals.d.ts +34 -26
  509. package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
  510. package/lib/typescript/interfaces/options/sideMenu.d.ts +23 -6
  511. package/lib/typescript/interfaces/options/sideMenu.d.ts.map +1 -1
  512. package/lib/typescript/interfaces/options/stack.d.ts +17 -3
  513. package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
  514. package/lib/typescript/interfaces/options/system.d.ts +18 -11
  515. package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
  516. package/lib/typescript/interfaces/options/toolbar.d.ts +2 -2
  517. package/lib/typescript/interfaces/options/topBar.d.ts +68 -38
  518. package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
  519. package/metro/acceptPlugin.js +57 -0
  520. package/metro/babelTransformer.js +45 -0
  521. package/metro/index.js +36 -0
  522. package/package.json +3 -1
  523. package/src/ARCHITECTURE.md +40 -27
  524. package/src/adapters/NativeANNTurboModule.ts +12 -2
  525. package/src/api/app/AppRegistry.ts +16 -2
  526. package/src/api/app/createNavigation.ts +203 -69
  527. package/src/api/commands/commands.ts +48 -7
  528. package/src/api/commands/presentation.ts +4 -3
  529. package/src/api/events/navigationEvents.ts +10 -4
  530. package/src/api/hooks/useNavigation.ts +9 -4
  531. package/src/api/hooks/useSafeAreaInsets.ts +4 -3
  532. package/src/api/index.ts +1 -0
  533. package/src/api/linking/dispatchedLinks.ts +18 -0
  534. package/src/api/linking/linking.ts +22 -1
  535. package/src/api/navigation.ts +4 -1
  536. package/src/api/options/OptionsChain.ts +2 -2
  537. package/src/api/screens/arrangement.ts +17 -4
  538. package/src/api/screens/defineScreen.ts +49 -5
  539. package/src/api/screens/nativeScreens.ts +40 -4
  540. package/src/api/screens/registerScreens.tsx +185 -42
  541. package/src/api/theme/theme.ts +5 -0
  542. package/src/engine/commands.ts +70 -13
  543. package/src/engine/layout.ts +27 -11
  544. package/src/engine/nativeScreens.ts +10 -1
  545. package/src/engine/options.ts +45 -19
  546. package/src/engine/optionsChange.ts +107 -0
  547. package/src/engine/places.ts +65 -7
  548. package/src/engine/props.ts +30 -1
  549. package/src/engine/refresh.ts +97 -0
  550. package/src/engine/rememberedOptions.ts +74 -1
  551. package/src/engine/screens.tsx +76 -21
  552. package/src/interfaces/ComponentEvents.ts +4 -4
  553. package/src/interfaces/Events.ts +29 -10
  554. package/src/interfaces/Options.ts +1 -0
  555. package/src/interfaces/contract/commands.json +101 -0
  556. package/src/interfaces/contract/errors.json +275 -0
  557. package/src/interfaces/options/animations.ts +81 -22
  558. package/src/interfaces/options/bottomTabs.ts +21 -7
  559. package/src/interfaces/options/buttons.ts +23 -15
  560. package/src/interfaces/options/modals.ts +34 -26
  561. package/src/interfaces/options/sideMenu.ts +24 -6
  562. package/src/interfaces/options/stack.ts +17 -3
  563. package/src/interfaces/options/system.ts +18 -11
  564. package/src/interfaces/options/toolbar.ts +2 -2
  565. package/src/interfaces/options/topBar.ts +68 -38
  566. package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -41
  567. package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -69
  568. package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationStateReporter.kt +0 -62
  569. package/android/src/main/java/dev/apexnative/navigation/react/events/StateHold.kt +0 -62
  570. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowPlacer.kt +0 -223
  571. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStub.kt +0 -31
  572. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +0 -138
  573. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -88
  574. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PropertyAnimatorCreator.kt +0 -33
  575. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +0 -66
  576. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +0 -179
  577. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -139
  578. package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
  579. package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -68
  580. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.h +0 -27
  581. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.mm +0 -55
@@ -4,9 +4,9 @@ import android.animation.Animator
4
4
  import android.animation.AnimatorListenerAdapter
5
5
  import android.animation.AnimatorSet
6
6
  import android.animation.ObjectAnimator
7
- import android.animation.PropertyValuesHolder
8
7
  import android.animation.TimeInterpolator
9
8
  import android.content.Context
9
+ import android.view.Gravity
10
10
  import android.view.View
11
11
  import android.view.ViewGroup
12
12
  import android.view.animation.LinearInterpolator
@@ -14,10 +14,15 @@ import android.widget.FrameLayout
14
14
  import androidx.coordinatorlayout.widget.CoordinatorLayout
15
15
  import androidx.core.view.ViewCompat
16
16
  import androidx.core.view.WindowInsetsCompat
17
+ import dev.apexnative.navigation.options.DefaultOptions
17
18
  import dev.apexnative.navigation.options.ModalAnimationOptions
18
19
  import dev.apexnative.navigation.options.Options
19
20
  import dev.apexnative.navigation.utils.TestIds
21
+ import dev.apexnative.navigation.utils.dp
22
+ import dev.apexnative.navigation.viewcontrollers.component.ComponentViewController
23
+ import dev.apexnative.navigation.viewcontrollers.parent.ParentController
20
24
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
25
+ import dev.apexnative.navigation.views.animations.AnimationLayer
21
26
  import dev.apexnative.navigation.views.animations.AnimationRules
22
27
  import dev.apexnative.navigation.views.animations.SideAnimator
23
28
  import dev.apexnative.navigation.views.element.ElementTransition
@@ -62,9 +67,15 @@ internal class ModalViews(
62
67
  try {
63
68
  val view = record.root.view
64
69
  (view.parent as? ViewGroup)?.removeView(view)
65
- // A sheet's content waits at the sheet's full height, under the status bar.
70
+ // A sheet's content waits at the sheet's full height, under the status bar, and at its width.
66
71
  val params = CoordinatorLayout.LayoutParams(MATCH, MATCH)
67
- if (record.isSheet) params.topMargin = statusBarTop()
72
+ if (record.isSheet) {
73
+ params.topMargin = statusBarTop()
74
+ params.gravity = Gravity.CENTER_HORIZONTAL
75
+ // The modals layer is hidden while it has no modal: the window's content gives the width.
76
+ val maxWidth = ModalSheet.MAX_WIDTH_DP.dp
77
+ if (((modalsLayer.parent as? View)?.width ?: 0) > maxWidth) params.width = maxWidth
78
+ }
68
79
  container.addView(view, params)
69
80
  modalsLayer.addView(container, FrameLayout.LayoutParams(MATCH, MATCH))
70
81
  } catch (e: Throwable) {
@@ -88,7 +99,7 @@ internal class ModalViews(
88
99
  val container = parts.container
89
100
  container.isWaiting = false
90
101
  container.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
91
- if (record.isSheet) return presentSheet(record, parts, options, seen, events, onEnd)
102
+ if (record.isSheet) return presentSheet(record, parts, options, animated, seen, events, onEnd)
92
103
  applyTestIds(record, parts, options)
93
104
  if (!animated || !seen) {
94
105
  SideAnimator.rest(container)
@@ -100,22 +111,23 @@ internal class ModalViews(
100
111
  container.translationY = 0f
101
112
  return playOwn(record, parts, motion, showing = true, onEnd)
102
113
  }
114
+ // The system's slide over the window below: the modal comes up whole, without a fade.
103
115
  val distance = distanceOf(container)
104
- val animator = ObjectAnimator.ofPropertyValuesHolder(
105
- container,
106
- PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, distance, 0f),
107
- PropertyValuesHolder.ofFloat(View.ALPHA, 0f, 1f),
108
- )
109
- animator.interpolator = TimeInterpolator { ModalAnimations.decelerate(it) }
110
- return play(parts, animator, onEnd)
116
+ container.alpha = 1f
117
+ container.translationY = distance
118
+ val animator = ObjectAnimator.ofFloat(container, View.TRANSLATION_Y, distance, 0f)
119
+ animator.interpolator = TimeInterpolator { ModalAnimations.linearOutSlowIn(it) }
120
+ return play(parts, animator, ModalAnimations.SHOW_DURATION, onEnd)
111
121
  }
112
122
 
113
123
  // The root's view leaves the container and goes into the sheet's, in one turn; the sheet slides to its first
114
- // detent. Nobody sees the activity: the show counts as done now, the sheet's later end does nothing.
124
+ // detent, or stands there at once when not [animated]. Nobody sees the activity: the show counts as done now, the
125
+ // sheet's later end does nothing.
115
126
  private fun presentSheet(
116
127
  record: ModalRecord,
117
128
  parts: Parts,
118
129
  options: Options,
130
+ animated: Boolean,
119
131
  seen: Boolean,
120
132
  events: ModalSheet.Events,
121
133
  onEnd: () -> Unit,
@@ -123,7 +135,16 @@ internal class ModalViews(
123
135
  val container = parts.container
124
136
  val view = record.root.view
125
137
  container.removeView(view)
126
- val sheet = ModalSheet(container, view, events)
138
+ val sheet = ModalSheet(
139
+ container,
140
+ view,
141
+ events,
142
+ shownContent = { (shownScreen(record.root) as? ComponentViewController)?.content },
143
+ adjustsForKeyboard = {
144
+ val screen = shownScreen(record.root)
145
+ screen == null || !screen.resolveCurrentOptions(DefaultOptions.current).layout.adjustResize.isFalse
146
+ },
147
+ )
127
148
  parts.sheet = sheet
128
149
  container.alpha = 1f
129
150
  applyTestIds(record, parts, options)
@@ -134,11 +155,18 @@ internal class ModalViews(
134
155
  onEnd()
135
156
  }
136
157
  }
137
- sheet.show(options.modal.sheet, swipeToDismissOf(options)) { shown() }
158
+ sheet.show(options.modal.sheet, swipeToDismissOf(options), animated) { shown() }
138
159
  if (!seen) shown()
139
160
  return { told = true }
140
161
  }
141
162
 
163
+ // The screen a layout shows now: down through the child each parent shows.
164
+ private fun shownScreen(root: ViewController<*>): ViewController<*>? {
165
+ var node = root
166
+ while (node is ParentController<*>) node = node.currentChild ?: return null
167
+ return node
168
+ }
169
+
142
170
  override fun dismiss(
143
171
  record: ModalRecord,
144
172
  animated: Boolean,
@@ -152,7 +180,7 @@ internal class ModalViews(
152
180
  if (sheet != null) {
153
181
  if (!seen) return none(onEnd)
154
182
  var told = false
155
- sheet.close {
183
+ sheet.close(animated) {
156
184
  if (!told) {
157
185
  told = true
158
186
  onEnd()
@@ -163,13 +191,11 @@ internal class ModalViews(
163
191
  if (!animated || !seen) return none(onEnd)
164
192
  if (motion != null) return playOwn(record, parts, motion, showing = false, onEnd)
165
193
  val container = parts.container
166
- val animator = ObjectAnimator.ofPropertyValuesHolder(
167
- container,
168
- PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, container.translationY, distanceOf(container)),
169
- PropertyValuesHolder.ofFloat(View.ALPHA, container.alpha, 0f),
194
+ val animator = ObjectAnimator.ofFloat(
195
+ container, View.TRANSLATION_Y, container.translationY, distanceOf(container),
170
196
  )
171
- animator.interpolator = TimeInterpolator { ModalAnimations.accelerateDecelerate(it) }
172
- return play(parts, animator, onEnd)
197
+ animator.interpolator = TimeInterpolator { ModalAnimations.accelerate(it) }
198
+ return play(parts, animator, ModalAnimations.DISMISS_DURATION, onEnd)
173
199
  }
174
200
 
175
201
  override fun awaitTargets(
@@ -245,10 +271,10 @@ internal class ModalViews(
245
271
  hideEmptyLayer()
246
272
  }
247
273
 
248
- override fun update(record: ModalRecord, options: Options, move: Boolean) {
274
+ override fun update(record: ModalRecord, options: Options, merge: Options?) {
249
275
  val parts = parts[record] ?: return
250
276
  applyTestIds(record, parts, options)
251
- parts.sheet?.update(options.modal.sheet, swipeToDismissOf(options), move)
277
+ parts.sheet?.update(options.modal.sheet, swipeToDismissOf(options), merge?.modal?.sheet)
252
278
  }
253
279
 
254
280
  override fun repaint(record: ModalRecord) {
@@ -259,6 +285,8 @@ internal class ModalViews(
259
285
  parts[record]?.container?.requestLayout()
260
286
  }
261
287
 
288
+ override fun sheetBack(record: ModalRecord): SheetBack? = parts[record]?.sheet
289
+
262
290
  // `modal.testID` on the modal's view; a sheet's on the sheet's container, `modal.sheet.testID` first, and its
263
291
  // grabber and scrim after it.
264
292
  private fun applyTestIds(record: ModalRecord, parts: Parts, options: Options) {
@@ -289,7 +317,11 @@ internal class ModalViews(
289
317
  val under = motion.underSide?.let { side -> underView?.let { SideAnimator.build(it, side, underBase) } }
290
318
  if (under != null && underView != null) {
291
319
  if (showing) moved[underView] = record else moved.remove(underView)
320
+ AnimationLayer.during(underView, under)
292
321
  }
322
+ // A fade of the modal or of the layer under it draws it through a hardware layer, given back at its end and at
323
+ // any stop (the set's cancel cancels it).
324
+ for (animator in listOfNotNull(side, fade)) AnimationLayer.during(container, animator)
293
325
  val fadeLength = motion.side?.takeIf(AnimationRules::isSingleAlpha)?.let(AnimationRules::lengthOf)
294
326
  val elements = motion.elements?.let { animation ->
295
327
  val content = modalsLayer.parent as? ViewGroup ?: return@let null
@@ -355,8 +387,8 @@ internal class ModalViews(
355
387
  private fun viewOf(node: ViewController<*>): View? =
356
388
  parts.entries.firstOrNull { it.key.root === node }?.value?.container ?: node.peekView()
357
389
 
358
- private fun play(parts: Parts, animator: Animator, onEnd: () -> Unit): () -> Unit {
359
- animator.duration = ModalAnimations.DURATION
390
+ private fun play(parts: Parts, animator: Animator, duration: Long, onEnd: () -> Unit): () -> Unit {
391
+ animator.duration = duration
360
392
  animator.addListener(object : AnimatorListenerAdapter() {
361
393
  override fun onAnimationEnd(animation: Animator) {
362
394
  if (parts.animator === animation) parts.animator = null
@@ -0,0 +1,42 @@
1
+ package dev.apexnative.navigation.viewcontrollers.modal
2
+
3
+ import androidx.activity.BackEventCompat
4
+
5
+ /**
6
+ * A modal's sheet as back sees it ([ModalSheet]): whether a release of back would hide it, and the preview of that
7
+ * hide during the back gesture (Android 14+). [ModalCoordinator.backTargetSheet] gives the one back would dismiss now.
8
+ * Main thread only.
9
+ */
10
+ internal interface SheetBack {
11
+ /**
12
+ * Back's release would hide the sheet, as a drag down does: it stands at a detent from which it goes down (its
13
+ * smallest, while it lets the user close it), laid out, and it isn't closing already. False at a larger detent:
14
+ * the Material behavior would only collapse it there.
15
+ */
16
+ val hidesOnBack: Boolean
17
+
18
+ /**
19
+ * Starts the preview of back on the sheet with the gesture's first [event]: the sheet shrinks a little toward the
20
+ * bottom with the progress, the scrim following it. None when [hidesOnBack] doesn't hold or a preview runs.
21
+ */
22
+ fun startBackPreview(event: BackEventCompat): Gesture?
23
+
24
+ /** A back gesture over the sheet ([startBackPreview]). */
25
+ interface Gesture {
26
+ /** The sheet the gesture previews. */
27
+ val sheet: SheetBack
28
+
29
+ /** The gesture moved. */
30
+ fun progress(event: BackEventCompat)
31
+
32
+ /** Cancelled, or back went elsewhere: the sheet grows back to where it stood, the scrim with it. */
33
+ fun cancel()
34
+
35
+ /**
36
+ * Released: the sheet slides down from where the preview left it and goes as one the user dragged down (its
37
+ * events, its dismissal). False when the preview stopped since it started (a command closed or moved the
38
+ * sheet): back goes the usual way.
39
+ */
40
+ fun commit(): Boolean
41
+ }
42
+ }
@@ -0,0 +1,83 @@
1
+ package dev.apexnative.navigation.viewcontrollers.modal
2
+
3
+ import dev.apexnative.navigation.options.SheetDetent
4
+
5
+ /**
6
+ * Where a sheet rests: the stops it keeps of its detents, how the Material behavior stands at them, and where a shown
7
+ * sheet goes at new options, as on iOS: the sheet keeps the stop it stands at (the user's last drag included) until a
8
+ * `selectedDetent` arrives in a `mergeOptions`, or until its stop is no longer among the detents.
9
+ */
10
+ internal object SheetStops {
11
+ /** The Material behavior has three resting states: collapsed, half expanded and expanded. */
12
+ const val MAX_STOPS = 3
13
+
14
+ /**
15
+ * The stops of the sheet, from the lowest: [detents] by their height ([heightOf]), one of each height (the first
16
+ * the options give), and at most [MAX_STOPS] of them: the lowest, the highest, and between them [selected] when
17
+ * it stands there, else the lowest of the rest.
18
+ */
19
+ fun stops(detents: List<SheetDetent>, heightOf: (SheetDetent) -> Int, selected: SheetDetent?): List<SheetDetent> {
20
+ val sorted = detents.sortedBy(heightOf).distinctBy(heightOf)
21
+ if (sorted.size <= MAX_STOPS) return sorted
22
+ val between = sorted.subList(1, sorted.size - 1)
23
+ val middle = selected?.takeIf { it in between } ?: between.first()
24
+ return listOf(sorted.first(), middle, sorted.last())
25
+ }
26
+
27
+ /**
28
+ * How the Material behavior stands at the stops: [fitToContents] with one or two (collapsed and expanded, the
29
+ * sheet as tall as the highest, [maxHeight]), else half expanded between them at [halfExpandedRatio] of the
30
+ * layout, and expanded [expandedOffset] below its top. [skipCollapsed] with one stop: the sheet has only that.
31
+ * The heights are in pixels, as is the rest.
32
+ */
33
+ data class Material(
34
+ val fitToContents: Boolean,
35
+ val skipCollapsed: Boolean,
36
+ val peekHeight: Int,
37
+ val halfExpandedRatio: Float?,
38
+ val expandedOffset: Int,
39
+ val maxHeight: Int,
40
+ )
41
+
42
+ /**
43
+ * The behavior's settings for stops [heights] tall (from the lowest, each higher than the one before) in a layout
44
+ * [parentHeight] tall.
45
+ */
46
+ fun material(heights: List<Int>, parentHeight: Int): Material {
47
+ val lowest = heights.first()
48
+ val highest = heights.last()
49
+ val three = heights.size == MAX_STOPS && parentHeight > 0
50
+ return Material(
51
+ fitToContents = !three,
52
+ skipCollapsed = heights.size == 1,
53
+ peekHeight = lowest,
54
+ halfExpandedRatio = if (three) heights[1].toFloat() / parentHeight else null,
55
+ expandedOffset = (parentHeight - highest).coerceAtLeast(0),
56
+ maxHeight = highest,
57
+ )
58
+ }
59
+
60
+ /**
61
+ * The heights of stops [heights] tall (from the lowest, each higher) lifted by [lift] pixels, the part of the
62
+ * keyboard over the navigation bar: the sheet stands on the keyboard as it stood on the bottom. At most [full]
63
+ * each, and each still higher than the one below, so the behavior keeps all of its states.
64
+ */
65
+ fun lifted(heights: List<Int>, lift: Int, full: Int): List<Int> =
66
+ heights.mapIndexed { i, height -> (height + lift).coerceAtMost(full - (heights.lastIndex - i)) }
67
+
68
+ /**
69
+ * The stop to move to, or null to stay: [arrived] (the `selectedDetent` the merge names) when it is among
70
+ * [detents]; else, when [settled] (the stop the sheet rests at) is no longer one of them, [selected] (the resolved
71
+ * `selectedDetent`) when it is, or the lowest.
72
+ */
73
+ fun target(
74
+ settled: SheetDetent?,
75
+ detents: List<SheetDetent>,
76
+ arrived: SheetDetent?,
77
+ selected: SheetDetent?,
78
+ ): SheetDetent? = when {
79
+ arrived != null && arrived in detents -> arrived
80
+ settled != null && settled !in detents -> selected?.takeIf { it in detents } ?: detents.first()
81
+ else -> null
82
+ }
83
+ }
@@ -0,0 +1,50 @@
1
+ package dev.apexnative.navigation.viewcontrollers.navigator
2
+
3
+ import android.util.Log
4
+ import dev.apexnative.navigation.utils.NavigationLog
5
+
6
+ /**
7
+ * The check of [BackCallbackState]'s triggers in debug builds (`NavigationActivity` makes it only when
8
+ * `BuildConfig.DEBUG`): it compares an activity's back callback with what back does now
9
+ * ([BackCallbackState.mismatchOf]) and writes a mismatch to the log once per state, with the screen on top. It never
10
+ * changes the callback, so a missing trigger behaves as in a release build. A [sample] before a frame runs at most
11
+ * every [SAMPLE_MILLIS] and reports a mismatch only when the sample before saw the same one: a change whose trigger
12
+ * comes at the end of its motion (a pane that slides, a menu dragged open) isn't reported while it moves. A back event
13
+ * ([atBack]) reports at once. Main thread only.
14
+ */
15
+ internal class BackCallbackCheck(
16
+ private val log: (String) -> Unit = { Log.w(NavigationLog.TAG, it) },
17
+ ) {
18
+ private var lastSample: Long? = null
19
+ private var previous: String? = null
20
+ private val logged = HashSet<String>()
21
+
22
+ /** Before a frame of the activity of [navigator], at [now] (`SystemClock.uptimeMillis`). */
23
+ fun sample(navigator: Navigator, now: Long) {
24
+ val last = lastSample
25
+ if (last != null && now - last < SAMPLE_MILLIS) return
26
+ lastSample = now
27
+ val mismatch = BackCallbackState.mismatchOf(navigator)
28
+ if (mismatch != null && mismatch == previous) report(mismatch)
29
+ previous = mismatch
30
+ }
31
+
32
+ /** A back event reached the callback of the activity of [navigator], before it acts. */
33
+ fun atBack(navigator: Navigator) {
34
+ BackCallbackState.mismatchOf(navigator)?.let(::report)
35
+ }
36
+
37
+ // Once per state, and not without end.
38
+ private fun report(mismatch: String) {
39
+ if (logged.size >= MAX_LOGGED || !logged.add(mismatch)) return
40
+ log("[ApexNavigation] $mismatch: a change of what back does came without its trigger")
41
+ }
42
+
43
+ companion object {
44
+ /** The least time between two samples. */
45
+ const val SAMPLE_MILLIS = 500L
46
+
47
+ // The states logged at most: a debug check, not a second log.
48
+ private const val MAX_LOGGED = 32
49
+ }
50
+ }
@@ -2,21 +2,38 @@ package dev.apexnative.navigation.viewcontrollers.navigator
2
2
 
3
3
  import android.util.Log
4
4
  import androidx.activity.OnBackPressedCallback
5
+ import dev.apexnative.navigation.react.events.AppearanceDispatcher
5
6
  import dev.apexnative.navigation.utils.NavigationLog
6
7
  import java.lang.ref.WeakReference
7
8
 
8
9
  /**
9
10
  * Keeps the back callback of each navigation activity enabled only while back has something to do in the app: its
10
- * navigation can go back ([Navigator.canHandleBack]), or JavaScript listens to it (`BackHandler`). Otherwise the
11
- * callback is disabled and the system does its own back. The system plays its back animation (to the home screen, to
12
- * another task) only when no callback of the app is enabled as the gesture starts, and it decides that before the app
13
- * hears of the gesture.
11
+ * navigation can go back ([Navigator.canHandleBack]), the screen back acts on keeps it from the system
12
+ * (`hardwareBackButton.systemAnimation: false`, [Navigator.keepsBackFromSystem]), or JavaScript listens to it
13
+ * (`BackHandler`). Otherwise the callback is disabled and the system does its own back. The system plays its back
14
+ * animation (to the home screen, to another task) only when no callback of the app is enabled as the gesture starts,
15
+ * and it decides that before the app hears of the gesture.
14
16
  *
15
17
  * A stale "enabled" only loses that animation; a stale "disabled" would leave the app where back has to go back. So
16
- * the value is computed again whenever what back does can have changed: before each frame of the activity's window,
17
- * when a command is done, when JavaScript reports its listeners, and when a side menu, the panes of a split view or a
18
- * search open or close (the first two after their last frame). Each activity has its own navigator and callback; the
19
- * listeners of JavaScript count for all of them. Main thread only.
18
+ * the value is computed again on every event that can change what back does, never by walking the layouts before
19
+ * each frame:
20
+ * - the end of each command's main-thread task, `setDefaultOptions` and `mergeOptions` too (`CommandRunner`);
21
+ * - a stack's operation accepted, its current child changed, and the operation ended or rejected
22
+ * (`StackController`'s queue host), which covers a push or a `setStackRoot` that waited for its screen, a prepared
23
+ * push, back of the user and the back arrow;
24
+ * - a layout that changed the screens it shows (`Navigator.shownScreensChanged`: the tabs, a side menu, a split view,
25
+ * a pair) and the end of a tab's switch;
26
+ * - every change of the modals (`ModalCoordinator.Host.backChanged`): a show, a dismissal by a command, by back or by
27
+ * the user (a sheet dragged down, its scrim), a failure, a `setRoot` that takes them;
28
+ * - a root that changed or showed, and the layers that went (a reload: `Navigator.destroy`);
29
+ * - a side menu, the panes of a split view or a search that opened or closed (the first two after their last frame),
30
+ * and a split view's width that changed;
31
+ * - the release and the cancel of a back gesture, and each back press;
32
+ * - JavaScript's listeners ([setJsListeners]), and the activity resumed or focused, as a safety net.
33
+ *
34
+ * Overlays don't count: back never goes to them. Each activity has its own navigator and callback; the listeners of
35
+ * JavaScript count for all of them. Debug builds check the triggers ([mismatchOf], `BackCallbackCheck`). Main thread
36
+ * only.
20
37
  */
21
38
  internal object BackCallbackState {
22
39
  private class Entry(navigator: Navigator, callback: OnBackPressedCallback) {
@@ -41,6 +58,10 @@ internal object BackCallbackState {
41
58
  entries.removeAll { it.navigator.get().let { attached -> attached == null || attached === navigator } }
42
59
  }
43
60
 
61
+ /** JavaScript listens to back (`BackHandler`): it hears a press before the navigation does. */
62
+ val hasJsListeners: Boolean
63
+ get() = jsListeners
64
+
44
65
  /** `setBackListeners` of JavaScript; false again when its JavaScript goes. */
45
66
  fun setJsListeners(active: Boolean) {
46
67
  jsListeners = active
@@ -52,22 +73,36 @@ internal object BackCallbackState {
52
73
  for (entry in entries.toList()) update(entry)
53
74
  }
54
75
 
55
- /** The callback of the activity of [navigator]: before its frames and at its back presses. */
76
+ /** The callback of the activity of [navigator]: after a change in its navigation. */
56
77
  fun update(navigator: Navigator) {
57
78
  entries.firstOrNull { it.navigator.get() === navigator }?.let(::update)
58
79
  }
59
80
 
81
+ /**
82
+ * Debug builds only: a callback of [navigator]'s activity that differs from what back does now — a change without
83
+ * its trigger —, described with the screen on top; null when it is right or not attached. It changes nothing.
84
+ */
85
+ fun mismatchOf(navigator: Navigator): String? {
86
+ val callback = entries.firstOrNull { it.navigator.get() === navigator }?.callback?.get() ?: return null
87
+ val expected = jsListeners || takesBack(navigator)
88
+ if (callback.isEnabled == expected) return null
89
+ val top = navigator.visibleLayout?.let { AppearanceDispatcher.visibleNode(it).id } ?: "none"
90
+ val state = if (callback.isEnabled) "enabled" else "disabled"
91
+ val back = if (expected) "back stays in the app" else "back leaves the app"
92
+ return "the back callback is $state where $back (on top: '$top')"
93
+ }
94
+
60
95
  // Enables or disables the callback when what back does changed.
61
96
  private fun update(entry: Entry) {
62
97
  val callback = entry.callback.get() ?: return
63
- val enabled = jsListeners || canHandleBack(entry.navigator.get())
98
+ val enabled = jsListeners || takesBack(entry.navigator.get())
64
99
  if (callback.isEnabled != enabled) callback.isEnabled = enabled
65
100
  }
66
101
 
67
- // A layout that fails to answer leaves back to the navigation, as before: this runs before each frame, and an
68
- // exception here would end the app.
69
- private fun canHandleBack(navigator: Navigator?): Boolean = try {
70
- navigator?.canHandleBack() == true
102
+ // A layout that fails to answer leaves back to the navigation, as before: this runs from the triggers of layouts
103
+ // and animators, and an exception here would end the app.
104
+ private fun takesBack(navigator: Navigator?): Boolean = try {
105
+ navigator != null && (navigator.canHandleBack() || navigator.keepsBackFromSystem())
71
106
  } catch (e: RuntimeException) {
72
107
  if (!failureLogged) {
73
108
  failureLogged = true
@@ -31,14 +31,16 @@ import dev.apexnative.navigation.viewcontrollers.component.ContentReadiness
31
31
  import dev.apexnative.navigation.viewcontrollers.component.ScreenReadiness
32
32
  import dev.apexnative.navigation.viewcontrollers.externalcomponent.ExternalComponentViewController
33
33
  import dev.apexnative.navigation.viewcontrollers.modal.ModalCoordinator
34
+ import dev.apexnative.navigation.viewcontrollers.modal.ModalRecord
34
35
  import dev.apexnative.navigation.viewcontrollers.modal.ModalViews
36
+ import dev.apexnative.navigation.viewcontrollers.modal.SheetBack
35
37
  import dev.apexnative.navigation.viewcontrollers.overlay.OverlayCoordinator
36
38
  import dev.apexnative.navigation.viewcontrollers.overlay.OverlayRecord
37
39
  import dev.apexnative.navigation.viewcontrollers.overlay.OverlayViews
38
40
  import dev.apexnative.navigation.viewcontrollers.parent.ParentController
39
41
  import dev.apexnative.navigation.viewcontrollers.stack.PreparedPushes
40
42
  import dev.apexnative.navigation.viewcontrollers.stack.StackCommands
41
- import dev.apexnative.navigation.viewcontrollers.stack.topbar.BarComponents
43
+ import dev.apexnative.navigation.viewcontrollers.stack.StackController
42
44
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
43
45
  import dev.apexnative.navigation.views.animations.FadeThrough
44
46
  import dev.apexnative.navigation.views.animations.SideAnimator
@@ -103,7 +105,10 @@ class Navigator(
103
105
  readiness = ContentReadiness,
104
106
  scheduler = scheduler,
105
107
  firstRoot = firstRootDraw,
106
- onRootChanged = { root = it },
108
+ onRootChanged = {
109
+ root = it
110
+ BackCallbackState.update(this)
111
+ },
107
112
  onRootShown = {
108
113
  onRootShown?.invoke()
109
114
  BackCallbackState.update(this)
@@ -140,10 +145,21 @@ class Navigator(
140
145
 
141
146
  /**
142
147
  * Whether back has something to do in the navigation: the mirror of [handleBack], without acting — the top modal
143
- * first, then the root. The back callback asks it before each frame (`BackCallbackState`).
148
+ * first, then the root. The back callback asks it whenever what back does can have changed (`BackCallbackState`).
144
149
  */
145
150
  fun canHandleBack(): Boolean = modals.canHandleBack() ?: (root?.canHandleBack() == true)
146
151
 
152
+ /**
153
+ * Whether back stays in the app also when the navigation has nothing to do: the layout back acts on — the top
154
+ * modal's, else the root — shows a screen with `hardwareBackButton.systemAnimation: false`. The system then doesn't
155
+ * play its animation of going home, and the press does the activity's own back ([handleBack] is false). The back
156
+ * callback asks it with [canHandleBack] (`BackCallbackState`).
157
+ */
158
+ fun keepsBackFromSystem(): Boolean {
159
+ val layout = modals.backTargetRoot() ?: root ?: return false
160
+ return layout.resolveShownOptions(DefaultOptions.current).hardwareBackButton.systemAnimation.isFalse
161
+ }
162
+
147
163
  /**
148
164
  * The navigation's step of back, after JavaScript's listeners didn't take it: the top modal first (its content,
149
165
  * else it closes or holds), else the root does the first thing it can (a stack's top leaves or holds, an open side
@@ -153,6 +169,18 @@ class Navigator(
153
169
  fun handleBack(listener: CommandListener): Boolean =
154
170
  modals.handleBack(listener) ?: (root?.handleBack(listener) == true)
155
171
 
172
+ /**
173
+ * The stack whose top [handleBack] would take away with the default pop: in the top modal, else in the root; none
174
+ * when back would do anything else.
175
+ */
176
+ internal fun stackPoppedByBack(): StackController? {
177
+ val modalRoot = modals.backTargetRoot()
178
+ return if (modalRoot != null) modalRoot.stackPoppedByBack() else root?.stackPoppedByBack()
179
+ }
180
+
181
+ /** The sheet [handleBack] would dismiss, as a drag down of the user would; none when back would do anything else. */
182
+ internal fun sheetDismissedByBack(): SheetBack? = modals.backTargetSheet()
183
+
156
184
  /**
157
185
  * [layer] may wait to show from now on ([WaitingLayer]): the nodes in it ask it through [isInWaitingLayer] and
158
186
  * [shownScreensChanged]. The root's layer is there from the start.
@@ -176,12 +204,14 @@ class Navigator(
176
204
  * A layout of [node] (a stack, the tabs, a side menu, a split view, a pair) changed the screens it shows: when it
177
205
  * is in a layer that still waits, the layer waits for the screens it shows now, and no longer for one that went
178
206
  * ([WaitingLayer.shownScreensChanged]); so does the operation of its stack that waits for [node] as its entry (a
179
- * pushed pair); a modal's sheet takes the hold of the screen it shows now.
207
+ * pushed pair); a modal's sheet takes the hold of the screen it shows now; what back does is computed again (the
208
+ * tab, the pane or the menu back goes to, and the options of the screen it shows).
180
209
  */
181
210
  internal fun shownScreensChanged(node: ViewController<*>) {
182
211
  waitingLayerOf(node)?.shownScreensChanged()
183
212
  node.findParentStack()?.queue?.shownScreensChanged(node)
184
213
  modals.visibleScreenChanged(node)
214
+ BackCallbackState.update(this)
185
215
  }
186
216
 
187
217
  // The waiting layer [node] is in, up through the layouts around it; none.
@@ -214,7 +244,7 @@ class Navigator(
214
244
  * it itself, `ComponentPresenter`); the system UI follows (only what changed is written).
215
245
  */
216
246
  internal fun optionsMerged(node: ViewController<*>, options: Options = Options()) {
217
- modals.optionsMergedInto(node)
247
+ modals.optionsMergedInto(node, options)
218
248
  overlays.optionsMergedInto(node)
219
249
  val navigationBar = options.navigationBar
220
250
  val padding = navigationBar.drawBehind.hasValue() || navigationBar.backgroundColor.hasValue()
@@ -264,9 +294,7 @@ class Navigator(
264
294
  if (!made) return answer.reject(ErrorTexts.notDoneYet("setRoot"))
265
295
  val steps = layout.modals.mapIndexed { index, node ->
266
296
  val last = index == layout.modals.lastIndex
267
- RootCoordinator.LayerStep { done ->
268
- modals.showInChain(node.id, { makeLayer(node, isOverlay = false) }, last, done)
269
- }
297
+ ModalLayerStep(node, last)
270
298
  } + layout.overlays.map { node ->
271
299
  RootCoordinator.LayerStep { done ->
272
300
  overlays.showInChain(node.id, { makeLayer(node, isOverlay = true) }, done)
@@ -275,6 +303,35 @@ class Navigator(
275
303
  roots.setRoot({ factory.create(layout.root) }, answer, steps)
276
304
  }
277
305
 
306
+ // A modal of a `setRoot`'s layout: made with the root and held until its turn, so it renders while the root waits
307
+ // and comes in; made in its turn instead while an id of it still shows (a modal of the old root with that id goes
308
+ // with the old root). A modal that couldn't be made is skipped in its turn.
309
+ private inner class ModalLayerStep(private val node: LayoutNode, private val animated: Boolean) :
310
+ RootCoordinator.LayerStep {
311
+ private var prepared = false
312
+ private var held: ModalRecord? = null
313
+
314
+ override fun prepare() {
315
+ if (LayoutChecks.firstShownId(listOf(node), ::isShownNow) { false } != null) return
316
+ prepared = true
317
+ held = modals.hold(node.id, { factory.create(node) }, animated)
318
+ }
319
+
320
+ override fun discard() {
321
+ held?.let(modals::drop)
322
+ held = null
323
+ }
324
+
325
+ override fun show(done: () -> Unit): () -> Unit {
326
+ val record = held
327
+ held = null
328
+ if (record != null) return modals.release(record, done)
329
+ if (!prepared) return modals.showInChain(node.id, { makeLayer(node, isOverlay = false) }, animated, done)
330
+ done()
331
+ return {}
332
+ }
333
+ }
334
+
278
335
  // A modal or an overlay of a `setRoot`'s layout, made as its turn comes: an id that shows by then fails it.
279
336
  private fun makeLayer(node: LayoutNode, isOverlay: Boolean): ViewController<*> {
280
337
  val shown = LayoutChecks.firstShownId(listOf(node), ::isShownNow) { isOverlay && isReplacedOverlay(node, it) }
@@ -397,13 +454,15 @@ class Navigator(
397
454
  destroyLayers(answerPending = false)
398
455
  // Nothing the old screens told of their readiness holds for the screens of the new JavaScript.
399
456
  ScreenReadiness.reset()
400
- BarComponents.reset()
457
+ // Without layers back leaves the app until the new JavaScript sets its root.
458
+ BackCallbackState.update(this)
401
459
  }
402
460
 
403
461
  /**
404
- * The activity is destroyed: every layer goes, with the events of a destroy; a `setRoot` on its way resolves with
405
- * `''` (JavaScript sets its root again in the next activity), a modal's or an overlay's show and the commands that
406
- * wait for a modal with their roots' ids. Main thread only.
462
+ * The activity is destroyed: every layer goes, with the events of a destroy; a `setRoot` whose root still waited
463
+ * resolves with `''` (JavaScript sets its root again in the next activity), one whose root showed resolves with
464
+ * its id, and a modal's or an overlay's show and the commands that wait for a modal resolve with their roots' ids.
465
+ * Main thread only.
407
466
  */
408
467
  internal fun destroyWithActivity() {
409
468
  destroyLayers(answerPending = true)