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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (574) hide show
  1. package/ApexNavigation.podspec +2 -1
  2. package/CHANGELOG.md +128 -0
  3. package/README.md +147 -51
  4. package/android/CLAUDE.md +78 -25
  5. package/android/CORE.md +49 -25
  6. package/android/RECIPES.md +13 -6
  7. package/android/consumer-rules.pro +6 -0
  8. package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +85 -10
  9. package/android/src/main/java/dev/apexnative/navigation/NavigationApplication.kt +34 -13
  10. package/android/src/main/java/dev/apexnative/navigation/layout/LayoutChecks.kt +5 -1
  11. package/android/src/main/java/dev/apexnative/navigation/layout/LayoutNode.kt +6 -2
  12. package/android/src/main/java/dev/apexnative/navigation/nativescreen/NativeScreenContext.kt +2 -2
  13. package/android/src/main/java/dev/apexnative/navigation/options/AnimationsOptions.kt +2 -2
  14. package/android/src/main/java/dev/apexnative/navigation/options/BottomTabOptions.kt +1 -1
  15. package/android/src/main/java/dev/apexnative/navigation/options/BottomTabsOptions.kt +13 -8
  16. package/android/src/main/java/dev/apexnative/navigation/options/ButtonMenuOptions.kt +2 -2
  17. package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +3 -3
  18. package/android/src/main/java/dev/apexnative/navigation/options/HardwareBackButtonOptions.kt +9 -1
  19. package/android/src/main/java/dev/apexnative/navigation/options/LargeTitleOptions.kt +1 -1
  20. package/android/src/main/java/dev/apexnative/navigation/options/LayoutAnimation.kt +1 -1
  21. package/android/src/main/java/dev/apexnative/navigation/options/OptionKey.kt +18 -0
  22. package/android/src/main/java/dev/apexnative/navigation/options/OptionPaths.kt +91 -0
  23. package/android/src/main/java/dev/apexnative/navigation/options/OptionsCache.kt +8 -4
  24. package/android/src/main/java/dev/apexnative/navigation/options/SheetOptions.kt +7 -4
  25. package/android/src/main/java/dev/apexnative/navigation/options/SideMenuOptions.kt +6 -1
  26. package/android/src/main/java/dev/apexnative/navigation/options/StackAnimationOptions.kt +40 -2
  27. package/android/src/main/java/dev/apexnative/navigation/options/StatusBarOptions.kt +7 -3
  28. package/android/src/main/java/dev/apexnative/navigation/options/TitleOptions.kt +2 -2
  29. package/android/src/main/java/dev/apexnative/navigation/options/TopBarAppearanceOptions.kt +1 -1
  30. package/android/src/main/java/dev/apexnative/navigation/options/TopBarOptions.kt +16 -7
  31. package/android/src/main/java/dev/apexnative/navigation/options/UserChoices.kt +159 -0
  32. package/android/src/main/java/dev/apexnative/navigation/react/CommandAnswer.kt +29 -36
  33. package/android/src/main/java/dev/apexnative/navigation/react/CommandContract.kt +59 -0
  34. package/android/src/main/java/dev/apexnative/navigation/react/ContentHeights.kt +95 -0
  35. package/android/src/main/java/dev/apexnative/navigation/react/ContentMounts.kt +66 -0
  36. package/android/src/main/java/dev/apexnative/navigation/react/ErrorTexts.kt +75 -60
  37. package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +35 -23
  38. package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +12 -7
  39. package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +42 -4
  40. package/android/src/main/java/dev/apexnative/navigation/react/PendingCalls.kt +48 -0
  41. package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +54 -20
  42. package/android/src/main/java/dev/apexnative/navigation/react/ReloadCoordinator.kt +7 -6
  43. package/android/src/main/java/dev/apexnative/navigation/react/ScreenEnvironment.kt +177 -0
  44. package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +19 -50
  45. package/android/src/main/java/dev/apexnative/navigation/react/ScrollEvents.kt +49 -128
  46. package/android/src/main/java/dev/apexnative/navigation/react/events/AppearanceDispatcher.kt +50 -81
  47. package/android/src/main/java/dev/apexnative/navigation/react/events/EventContract.kt +226 -0
  48. package/android/src/main/java/dev/apexnative/navigation/react/events/EventEmitter.kt +135 -94
  49. package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationState.kt +154 -0
  50. package/android/src/main/java/dev/apexnative/navigation/react/events/ScreenAppearance.kt +0 -6
  51. package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +12 -10
  52. package/android/src/main/java/dev/apexnative/navigation/slots/SlotContainers.kt +10 -7
  53. package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +39 -19
  54. package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +16 -4
  55. package/android/src/main/java/dev/apexnative/navigation/slots/SlotViews.kt +40 -0
  56. package/android/src/main/java/dev/apexnative/navigation/utils/ImageKey.kt +66 -0
  57. package/android/src/main/java/dev/apexnative/navigation/utils/ImageLoader.kt +7 -89
  58. package/android/src/main/java/dev/apexnative/navigation/utils/ImageRequests.kt +76 -0
  59. package/android/src/main/java/dev/apexnative/navigation/utils/MaterialTheme.kt +5 -6
  60. package/android/src/main/java/dev/apexnative/navigation/utils/OptionImages.kt +262 -0
  61. package/android/src/main/java/dev/apexnative/navigation/utils/SystemAnimations.kt +36 -0
  62. package/android/src/main/java/dev/apexnative/navigation/utils/UiUtils.kt +3 -3
  63. package/android/src/main/java/dev/apexnative/navigation/utils/ViewController.kt +3 -1
  64. package/android/src/main/java/dev/apexnative/navigation/utils/ViewExtensions.kt +0 -13
  65. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementController.kt +10 -7
  66. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/SecondaryScreenPresenter.kt +13 -5
  67. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/AppliedTabCalls.kt +49 -0
  68. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsCollapseBehavior.kt +5 -3
  69. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +108 -34
  70. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsPresenter.kt +25 -24
  71. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowGeometry.kt +22 -0
  72. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabItems.kt +3 -3
  73. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabsRoom.kt +0 -5
  74. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentPresenter.kt +28 -7
  75. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +12 -9
  76. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ContentReadiness.kt +2 -2
  77. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/RenderWait.kt +27 -7
  78. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenFrame.kt +1 -1
  79. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenReadiness.kt +103 -56
  80. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenSafeArea.kt +29 -11
  81. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/externalcomponent/ExternalComponentViewController.kt +2 -6
  82. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalAnimations.kt +22 -24
  83. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +109 -21
  84. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalRecord.kt +21 -6
  85. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +476 -73
  86. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +57 -25
  87. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetBack.kt +42 -0
  88. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +83 -0
  89. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackCheck.kt +50 -0
  90. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackState.kt +49 -14
  91. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +71 -12
  92. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +37 -11
  93. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/overlay/OverlayCoordinator.kt +10 -8
  94. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/Capabilities.kt +11 -4
  95. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ContainerBackground.kt +3 -3
  96. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +6 -6
  97. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +42 -9
  98. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +19 -8
  99. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuPresenter.kt +16 -7
  100. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuRules.kt +43 -4
  101. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitPanes.kt +23 -0
  102. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +77 -17
  103. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +315 -0
  104. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/PreparedFrame.kt +3 -3
  105. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +30 -20
  106. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +216 -18
  107. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackDisplay.kt +26 -1
  108. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +149 -41
  109. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackTransitions.kt +26 -8
  110. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +115 -6
  111. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabMotion.kt +142 -0
  112. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +222 -48
  113. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/ScreenSearch.kt +3 -5
  114. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +30 -34
  115. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarComponents.kt +5 -51
  116. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarRowTransition.kt +3 -2
  117. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/ButtonPlaces.kt +11 -5
  118. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/MenuChecks.kt +13 -56
  119. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +219 -54
  120. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarVisibility.kt +9 -2
  121. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ScrollEventListener.kt +6 -9
  122. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ViewController.kt +75 -21
  123. package/android/src/main/java/dev/apexnative/navigation/views/animations/AnimationLayer.kt +73 -0
  124. package/android/src/main/java/dev/apexnative/navigation/views/animations/Curves.kt +29 -11
  125. package/android/src/main/java/dev/apexnative/navigation/views/animations/ValueInterpolation.kt +14 -0
  126. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +9 -7
  127. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabsLayout.kt +61 -2
  128. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomBottomTabItemView.kt +0 -5
  129. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomTabRow.kt +72 -10
  130. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStep.kt +31 -0
  131. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +143 -135
  132. package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +13 -5
  133. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
  134. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionTargets.kt +9 -6
  135. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionViews.kt +100 -0
  136. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +112 -4
  137. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +346 -36
  138. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMorph.kt +199 -0
  139. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +56 -41
  140. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextMorph.kt +176 -0
  141. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewMorph.kt +108 -0
  142. package/android/src/main/java/dev/apexnative/navigation/views/sidemenu/SideMenuView.kt +12 -3
  143. package/android/src/main/java/dev/apexnative/navigation/views/stack/ScreenEdge.kt +45 -0
  144. package/android/src/main/java/dev/apexnative/navigation/views/stack/StackLayout.kt +140 -1
  145. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/Fab.kt +14 -10
  146. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabCopy.kt +85 -0
  147. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabMenu.kt +13 -0
  148. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +5 -17
  149. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +73 -34
  150. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonComponentCell.kt +6 -6
  151. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonView.kt +113 -0
  152. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarMenu.kt +219 -0
  153. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +125 -178
  154. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonMenus.kt +34 -64
  155. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonRow.kt +216 -0
  156. package/android/src/main/jni/ANNContentHeights.cpp +82 -0
  157. package/android/src/main/res/drawable/apex_navigation_ic_arrow_right.xml +14 -0
  158. package/android/src/main/res/layout/apex_navigation_menu_header.xml +19 -0
  159. package/android/src/main/res/layout/apex_navigation_menu_item.xml +68 -0
  160. package/android/src/main/res/values/styles.xml +1 -1
  161. package/android/src/main/res/values-night/styles.xml +1 -1
  162. package/cli/app.js +1 -1
  163. package/cli/doctor/checks/app.js +77 -14
  164. package/cli/doctor/checks/splash.js +4 -22
  165. package/cli/migrate/native.js +18 -0
  166. package/cli/project.js +10 -2
  167. package/cli/setup/index.js +18 -0
  168. package/cli/setup/source.js +2 -1
  169. package/cli/setup/steps/appDelegate.js +66 -11
  170. package/cli/setup/steps/mainApplication.js +134 -19
  171. package/cli/setup/steps/metro.js +46 -0
  172. package/cli/setup/steps/sceneDelegate.js +108 -0
  173. package/cli/splash/index.js +3 -1
  174. package/cli/upgrade/changelog.js +2 -2
  175. package/docs-md/architecture/native-screens.md +4 -0
  176. package/docs-md/architecture/theme-and-context.md +131 -12
  177. package/docs-md/architecture/transitions.md +58 -12
  178. package/docs-md/containers/modals.md +8 -4
  179. package/docs-md/containers/overlays.md +3 -1
  180. package/docs-md/containers/side-menu.md +19 -2
  181. package/docs-md/containers/tabs.md +5 -1
  182. package/docs-md/flows/bottom-sheets.md +4 -2
  183. package/docs-md/flows/forms-in-a-modal.md +1 -1
  184. package/docs-md/fundamentals/screens-and-props.md +9 -1
  185. package/docs-md/fundamentals/starting-the-app.md +1 -1
  186. package/docs-md/guides/cli.md +4 -3
  187. package/docs-md/guides/deep-links.md +15 -33
  188. package/docs-md/help/glossary.md +4 -4
  189. package/docs-md/help/troubleshooting.md +44 -6
  190. package/docs-md/index.json +57 -1
  191. package/docs-md/migration/from-expo-router.md +1 -1
  192. package/docs-md/migration/from-react-native-navigation.md +9 -3
  193. package/docs-md/migration/from-react-navigation.md +2 -2
  194. package/docs-md/screen-ui/back-and-gestures.md +46 -2
  195. package/docs-md/screen-ui/bar-buttons.md +5 -5
  196. package/docs-md/screen-ui/search.md +1 -1
  197. package/docs-md/screen-ui/system-ui.md +17 -12
  198. package/docs-md/screen-ui/toolbar-and-fab.md +4 -2
  199. package/docs-md/screen-ui/top-bar.md +8 -4
  200. package/docs-md/start/installation.md +21 -3
  201. package/ios/Animations/ANNFrameDriver.h +55 -15
  202. package/ios/Animations/ANNFrameDriver.mm +216 -60
  203. package/ios/Animations/ANNTransitionAnimator.h +26 -5
  204. package/ios/Animations/ANNTransitionAnimator.mm +61 -13
  205. package/ios/Animations/ANNTransitionPlan.h +2 -2
  206. package/ios/Animations/ANNTransitionPlan.mm +10 -0
  207. package/ios/Animations/ANNTransitionWait.mm +6 -7
  208. package/ios/Animations/Elements/ANNElementFinder.h +57 -0
  209. package/ios/Animations/Elements/ANNElementFinder.mm +174 -2
  210. package/ios/Animations/Elements/ANNElementTransition.h +10 -8
  211. package/ios/Animations/Elements/ANNElementTransition.mm +19 -21
  212. package/ios/Animations/Elements/ANNSharedElementFlight.h +16 -11
  213. package/ios/Animations/Elements/ANNSharedElementFlight.mm +308 -69
  214. package/ios/Animations/Interpolators/ANNInterpolate.h +2 -30
  215. package/ios/Animations/Interpolators/ANNTransformParts.h +48 -0
  216. package/ios/Animations/Interpolators/ANNTransformParts.mm +507 -0
  217. package/ios/Animations/Interpolators/ANNViewTracks.h +9 -6
  218. package/ios/Animations/Interpolators/ANNViewTracks.mm +100 -30
  219. package/ios/CLAUDE.md +60 -24
  220. package/ios/CORE.md +44 -34
  221. package/ios/Contract/ANNCommandAnswer.h +13 -5
  222. package/ios/Contract/ANNCommandAnswer.mm +40 -32
  223. package/ios/Contract/ANNCommandContract.h +15 -0
  224. package/ios/Contract/ANNCommandContract.mm +78 -0
  225. package/ios/Contract/ANNCommandRunner.h +10 -9
  226. package/ios/Contract/ANNCommandRunner.mm +22 -28
  227. package/ios/Contract/ANNErrorTexts.h +6 -2
  228. package/ios/Contract/ANNErrorTexts.mm +18 -10
  229. package/ios/Contract/ANNLayoutNode.h +3 -3
  230. package/ios/Contract/ANNLayoutReader.h +3 -3
  231. package/ios/Core/ANNAppDelegate.mm +0 -2
  232. package/ios/Core/ANNAppearanceDispatcher.h +5 -4
  233. package/ios/Core/ANNAppearanceDispatcher.mm +12 -1
  234. package/ios/Core/ANNDeepLinkQueue.h +22 -2
  235. package/ios/Core/ANNDeepLinkQueue.mm +121 -14
  236. package/ios/Core/ANNErrorHandler.h +9 -4
  237. package/ios/Core/ANNErrorHandler.mm +20 -2
  238. package/ios/Core/ANNEventContract.h +246 -0
  239. package/ios/Core/ANNEventContract.mm +225 -0
  240. package/ios/Core/ANNEventEmitter.h +6 -2
  241. package/ios/Core/ANNEventEmitter.mm +117 -80
  242. package/ios/Core/ANNHinge.h +6 -0
  243. package/ios/Core/ANNHinge.mm +15 -4
  244. package/ios/Core/ANNJavaScriptCalls.h +33 -0
  245. package/ios/Core/ANNJavaScriptCalls.mm +52 -0
  246. package/ios/Core/ANNLayoutProtocol.h +5 -5
  247. package/ios/Core/ANNNavigationState.h +7 -5
  248. package/ios/Core/ANNNavigationState.mm +8 -7
  249. package/ios/Core/ANNNodeHelper.h +32 -12
  250. package/ios/Core/ANNNodeHelper.mm +100 -3
  251. package/ios/Core/ANNParking.h +5 -4
  252. package/ios/Core/ANNReloadCoordinator.mm +5 -12
  253. package/ios/Core/ANNRenderWait.h +20 -6
  254. package/ios/Core/ANNRenderWait.mm +143 -56
  255. package/ios/Core/ANNSceneDelegate.mm +25 -15
  256. package/ios/Core/ANNSystemUI.h +3 -2
  257. package/ios/Core/ANNSystemUI.mm +7 -0
  258. package/ios/Core/ANNUtils.h +7 -0
  259. package/ios/Core/ANNUtils.mm +10 -0
  260. package/ios/Core/ApexNavigation+Internal.h +1 -1
  261. package/ios/Core/ApexNavigation.mm +7 -6
  262. package/ios/Core/UIViewController+LayoutProtocol.h +9 -2
  263. package/ios/Core/UIViewController+LayoutProtocol.mm +8 -0
  264. package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
  265. package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
  266. package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +10 -8
  267. package/ios/Layouts/Modal/ANNModalCoordinator.h +1 -1
  268. package/ios/Layouts/Modal/ANNModalCoordinator.mm +57 -16
  269. package/ios/Layouts/Modal/ANNModalPresentation.h +8 -5
  270. package/ios/Layouts/Modal/ANNModalPresentation.mm +12 -12
  271. package/ios/Layouts/Modal/ANNSheetPresenter.mm +83 -1
  272. package/ios/Layouts/Overlay/ANNOverlayCoordinator.mm +2 -8
  273. package/ios/Layouts/Root/ANNRootCoordinator.mm +58 -19
  274. package/ios/Layouts/Root/ANNSplashViewController.h +5 -3
  275. package/ios/Layouts/Root/ANNSplashViewController.mm +147 -0
  276. package/ios/Layouts/Screen/ANNComponentPresenter.h +11 -3
  277. package/ios/Layouts/Screen/ANNComponentPresenter.mm +34 -6
  278. package/ios/Layouts/Screen/ANNComponentViewController.h +15 -13
  279. package/ios/Layouts/Screen/ANNComponentViewController.mm +130 -75
  280. package/ios/Layouts/Screen/ANNNativeScreenContext.mm +7 -5
  281. package/ios/Layouts/Screen/ANNPreviewInteraction.h +7 -4
  282. package/ios/Layouts/Screen/ANNPreviewInteraction.mm +72 -10
  283. package/ios/Layouts/Screen/ANNScreenEnvironment.h +63 -0
  284. package/ios/Layouts/Screen/ANNScreenEnvironment.mm +181 -0
  285. package/ios/Layouts/Screen/ANNScreenPlace.h +53 -0
  286. package/ios/Layouts/Screen/ANNScreenPlace.mm +205 -0
  287. package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
  288. package/ios/Layouts/Screen/ANNScreenRegions.mm +9 -44
  289. package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
  290. package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
  291. package/ios/Layouts/Screen/ANNScreenSettling.h +32 -0
  292. package/ios/Layouts/Screen/ANNScreenSettling.mm +137 -0
  293. package/ios/Layouts/SideMenu/ANNSideMenuTypes.h +8 -0
  294. package/ios/Layouts/SideMenu/ANNSideMenuViewController.mm +83 -14
  295. package/ios/Layouts/SplitView/ANNSplitViewCommands.h +3 -2
  296. package/ios/Layouts/SplitView/ANNSplitViewCommands.mm +105 -39
  297. package/ios/Layouts/SplitView/ANNSplitViewController.mm +7 -8
  298. package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
  299. package/ios/Layouts/Stack/ANNPreviewPush.mm +142 -27
  300. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
  301. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
  302. package/ios/Layouts/Stack/ANNStackCommands.mm +1 -0
  303. package/ios/Layouts/Stack/ANNStackController.h +8 -0
  304. package/ios/Layouts/Stack/ANNStackController.mm +184 -16
  305. package/ios/Layouts/Stack/ANNStackQueue.h +5 -2
  306. package/ios/Layouts/Stack/ANNStackQueue.mm +56 -43
  307. package/ios/Layouts/Stack/ANNSwipePopInteraction.h +26 -0
  308. package/ios/Layouts/Stack/ANNSwipePopInteraction.mm +185 -0
  309. package/ios/Layouts/Stack/InteractivePopGestureDelegate.mm +28 -4
  310. package/ios/Layouts/Stack/UINavigationController+ANNCommands.h +4 -2
  311. package/ios/Layouts/Stack/UINavigationController+ANNCommands.mm +2 -3
  312. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.h +4 -0
  313. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.mm +11 -0
  314. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
  315. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
  316. package/ios/Layouts/Tabs/ANNBottomTabsController.h +3 -0
  317. package/ios/Layouts/Tabs/ANNBottomTabsController.mm +237 -57
  318. package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
  319. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +6 -2
  320. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +232 -43
  321. package/ios/Layouts/Tabs/ANNTabsDesign.h +6 -5
  322. package/ios/Layouts/Tabs/ANNTabsDesign.mm +9 -1
  323. package/ios/Layouts/Tabs/UITabBar+utils.h +5 -5
  324. package/ios/Layouts/Tabs/UITabBar+utils.mm +32 -13
  325. package/ios/Options/ANNAnimationOptions.h +2 -1
  326. package/ios/Options/ANNAnimationOptions.mm +1 -1
  327. package/ios/Options/ANNBottomTabsOptions.h +2 -0
  328. package/ios/Options/ANNBottomTabsOptions.mm +1 -0
  329. package/ios/Options/ANNOptions.h +25 -0
  330. package/ios/Options/ANNOptions.mm +157 -1
  331. package/ios/Options/ANNOptionsCache.h +7 -6
  332. package/ios/Options/ANNOptionsReader.mm +108 -0
  333. package/ios/Options/ANNSearchBarOptions.h +4 -3
  334. package/ios/Options/ANNSheetOptions.h +4 -1
  335. package/ios/Options/ANNSideMenuOptions.h +2 -0
  336. package/ios/Options/ANNSideMenuOptions.mm +2 -0
  337. package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
  338. package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
  339. package/ios/Options/ANNUserChoice.h +57 -0
  340. package/ios/Options/ANNUserChoice.mm +44 -0
  341. package/ios/Options/Params/ANNImageSource.h +61 -0
  342. package/ios/Options/Params/ANNImageSource.mm +101 -0
  343. package/ios/Options/Params/ANNOptionImages.h +37 -0
  344. package/ios/Options/Params/ANNOptionImages.mm +284 -0
  345. package/ios/Options/Params/ANNParam.h +15 -0
  346. package/ios/Options/Params/ANNParam.mm +61 -0
  347. package/ios/Options/Params/Color.h +3 -0
  348. package/ios/Options/Params/Color.mm +21 -0
  349. package/ios/Options/Params/ColorParser.h +4 -3
  350. package/ios/Options/Params/ColorParser.mm +22 -4
  351. package/ios/Options/Params/Image.h +15 -2
  352. package/ios/Options/Params/Image.mm +35 -2
  353. package/ios/Options/Params/ImageParser.h +5 -5
  354. package/ios/Options/Params/ImageParser.mm +28 -46
  355. package/ios/Public/ApexNavigation/ANNSceneDelegate.h +3 -0
  356. package/ios/Public/ApexNavigation/ApexNavigation.h +1 -1
  357. package/ios/RECIPES.md +13 -6
  358. package/ios/React/ANNReactView.mm +6 -25
  359. package/ios/React/ANNSafeAreaViewComponentView.mm +28 -17
  360. package/ios/React/ANNSurfaceHostingView.h +14 -0
  361. package/ios/React/ANNSurfaceHostingView.mm +144 -1
  362. package/ios/React/Slots/ANNSlotComponentView.mm +24 -17
  363. package/ios/React/Slots/ANNSlotContainers.h +14 -6
  364. package/ios/React/Slots/ANNSlotContainers.mm +75 -2
  365. package/ios/React/Slots/ANNSlotHost.mm +1 -3
  366. package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
  367. package/ios/TopBar/ANNBackButtonPresenter.mm +6 -5
  368. package/ios/TopBar/ANNBarAppearance.h +2 -1
  369. package/ios/TopBar/ANNBarAppearance.mm +111 -30
  370. package/ios/TopBar/ANNBarBackgroundComponent.mm +16 -0
  371. package/ios/TopBar/ANNBarButtonComponentView.h +4 -4
  372. package/ios/TopBar/ANNBarButtonComponentView.mm +1 -1
  373. package/ios/TopBar/ANNBarButtons.h +14 -8
  374. package/ios/TopBar/ANNBarButtons.mm +397 -80
  375. package/ios/TopBar/ANNIconButtonImage.h +1 -0
  376. package/ios/TopBar/ANNIconButtonImage.mm +34 -1
  377. package/ios/TopBar/ANNLargeTitlePresenter.h +13 -0
  378. package/ios/TopBar/ANNLargeTitlePresenter.mm +50 -7
  379. package/ios/TopBar/ANNMainList.h +3 -0
  380. package/ios/TopBar/ANNMainList.mm +4 -0
  381. package/ios/TopBar/ANNScrollEdgeEffects.h +22 -6
  382. package/ios/TopBar/ANNScrollEdgeEffects.mm +123 -16
  383. package/ios/TopBar/ANNSearchPresenter.mm +172 -21
  384. package/ios/TopBar/ANNSearchResultsViewController.mm +29 -6
  385. package/ios/TopBar/ANNTopBarPresenter.h +8 -2
  386. package/ios/TopBar/ANNTopBarPresenter.mm +155 -33
  387. package/ios/TurboModules/ANNTurboEventEmitter.mm +4 -35
  388. package/ios/TurboModules/ANNTurboModule.mm +104 -33
  389. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.cpp +20 -0
  390. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.h +5 -14
  391. package/lib/module/ARCHITECTURE.md +40 -27
  392. package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
  393. package/lib/module/api/app/AppRegistry.js +14 -2
  394. package/lib/module/api/app/AppRegistry.js.map +1 -1
  395. package/lib/module/api/app/createNavigation.js +190 -66
  396. package/lib/module/api/app/createNavigation.js.map +1 -1
  397. package/lib/module/api/commands/commands.js +54 -6
  398. package/lib/module/api/commands/commands.js.map +1 -1
  399. package/lib/module/api/events/navigationEvents.js +6 -2
  400. package/lib/module/api/events/navigationEvents.js.map +1 -1
  401. package/lib/module/api/hooks/useNavigation.js +8 -3
  402. package/lib/module/api/hooks/useNavigation.js.map +1 -1
  403. package/lib/module/api/hooks/useSafeAreaInsets.js +4 -3
  404. package/lib/module/api/hooks/useSafeAreaInsets.js.map +1 -1
  405. package/lib/module/api/linking/dispatchedLinks.js +23 -0
  406. package/lib/module/api/linking/dispatchedLinks.js.map +1 -0
  407. package/lib/module/api/linking/linking.js +11 -0
  408. package/lib/module/api/linking/linking.js.map +1 -1
  409. package/lib/module/api/navigation.js.map +1 -1
  410. package/lib/module/api/options/OptionsChain.js +2 -2
  411. package/lib/module/api/screens/defineScreen.js +45 -3
  412. package/lib/module/api/screens/defineScreen.js.map +1 -1
  413. package/lib/module/api/screens/nativeScreens.js +31 -6
  414. package/lib/module/api/screens/nativeScreens.js.map +1 -1
  415. package/lib/module/api/screens/registerScreens.js +193 -35
  416. package/lib/module/api/screens/registerScreens.js.map +1 -1
  417. package/lib/module/api/theme/theme.js +5 -0
  418. package/lib/module/api/theme/theme.js.map +1 -1
  419. package/lib/module/engine/commands.js +51 -9
  420. package/lib/module/engine/commands.js.map +1 -1
  421. package/lib/module/engine/layout.js +20 -11
  422. package/lib/module/engine/layout.js.map +1 -1
  423. package/lib/module/engine/nativeScreens.js +9 -0
  424. package/lib/module/engine/nativeScreens.js.map +1 -1
  425. package/lib/module/engine/options.js +49 -15
  426. package/lib/module/engine/options.js.map +1 -1
  427. package/lib/module/engine/optionsChange.js +102 -0
  428. package/lib/module/engine/optionsChange.js.map +1 -0
  429. package/lib/module/engine/places.js +52 -7
  430. package/lib/module/engine/places.js.map +1 -1
  431. package/lib/module/engine/props.js +30 -1
  432. package/lib/module/engine/props.js.map +1 -1
  433. package/lib/module/engine/refresh.js +85 -0
  434. package/lib/module/engine/refresh.js.map +1 -0
  435. package/lib/module/engine/rememberedOptions.js +61 -1
  436. package/lib/module/engine/rememberedOptions.js.map +1 -1
  437. package/lib/module/engine/screens.js +77 -16
  438. package/lib/module/engine/screens.js.map +1 -1
  439. package/lib/module/interfaces/contract/commands.json +101 -0
  440. package/lib/module/interfaces/contract/errors.json +275 -0
  441. package/lib/typescript/adapters/NativeANNTurboModule.d.ts +12 -2
  442. package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
  443. package/lib/typescript/api/app/AppRegistry.d.ts.map +1 -1
  444. package/lib/typescript/api/app/createNavigation.d.ts +8 -3
  445. package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
  446. package/lib/typescript/api/commands/commands.d.ts.map +1 -1
  447. package/lib/typescript/api/commands/presentation.d.ts +4 -3
  448. package/lib/typescript/api/commands/presentation.d.ts.map +1 -1
  449. package/lib/typescript/api/events/navigationEvents.d.ts +3 -3
  450. package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
  451. package/lib/typescript/api/hooks/useNavigation.d.ts +1 -1
  452. package/lib/typescript/api/hooks/useNavigation.d.ts.map +1 -1
  453. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts +4 -3
  454. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
  455. package/lib/typescript/api/index.d.ts +1 -1
  456. package/lib/typescript/api/index.d.ts.map +1 -1
  457. package/lib/typescript/api/linking/dispatchedLinks.d.ts +7 -0
  458. package/lib/typescript/api/linking/dispatchedLinks.d.ts.map +1 -0
  459. package/lib/typescript/api/linking/linking.d.ts +8 -0
  460. package/lib/typescript/api/linking/linking.d.ts.map +1 -1
  461. package/lib/typescript/api/navigation.d.ts +4 -1
  462. package/lib/typescript/api/navigation.d.ts.map +1 -1
  463. package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
  464. package/lib/typescript/api/screens/defineScreen.d.ts +23 -4
  465. package/lib/typescript/api/screens/defineScreen.d.ts.map +1 -1
  466. package/lib/typescript/api/screens/nativeScreens.d.ts +8 -1
  467. package/lib/typescript/api/screens/nativeScreens.d.ts.map +1 -1
  468. package/lib/typescript/api/screens/registerScreens.d.ts.map +1 -1
  469. package/lib/typescript/api/theme/theme.d.ts +2 -0
  470. package/lib/typescript/api/theme/theme.d.ts.map +1 -1
  471. package/lib/typescript/engine/commands.d.ts +5 -0
  472. package/lib/typescript/engine/commands.d.ts.map +1 -1
  473. package/lib/typescript/engine/layout.d.ts.map +1 -1
  474. package/lib/typescript/engine/nativeScreens.d.ts +5 -0
  475. package/lib/typescript/engine/nativeScreens.d.ts.map +1 -1
  476. package/lib/typescript/engine/options.d.ts +5 -2
  477. package/lib/typescript/engine/options.d.ts.map +1 -1
  478. package/lib/typescript/engine/optionsChange.d.ts +28 -0
  479. package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
  480. package/lib/typescript/engine/places.d.ts +7 -2
  481. package/lib/typescript/engine/places.d.ts.map +1 -1
  482. package/lib/typescript/engine/props.d.ts +8 -1
  483. package/lib/typescript/engine/props.d.ts.map +1 -1
  484. package/lib/typescript/engine/refresh.d.ts +35 -0
  485. package/lib/typescript/engine/refresh.d.ts.map +1 -0
  486. package/lib/typescript/engine/rememberedOptions.d.ts +13 -0
  487. package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
  488. package/lib/typescript/engine/screens.d.ts +27 -6
  489. package/lib/typescript/engine/screens.d.ts.map +1 -1
  490. package/lib/typescript/interfaces/ComponentEvents.d.ts +4 -4
  491. package/lib/typescript/interfaces/ComponentEvents.d.ts.map +1 -1
  492. package/lib/typescript/interfaces/Events.d.ts +28 -10
  493. package/lib/typescript/interfaces/Events.d.ts.map +1 -1
  494. package/lib/typescript/interfaces/Options.d.ts +1 -1
  495. package/lib/typescript/interfaces/Options.d.ts.map +1 -1
  496. package/lib/typescript/interfaces/options/animations.d.ts +80 -22
  497. package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
  498. package/lib/typescript/interfaces/options/bottomTabs.d.ts +21 -7
  499. package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
  500. package/lib/typescript/interfaces/options/buttons.d.ts +23 -15
  501. package/lib/typescript/interfaces/options/buttons.d.ts.map +1 -1
  502. package/lib/typescript/interfaces/options/modals.d.ts +34 -26
  503. package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
  504. package/lib/typescript/interfaces/options/sideMenu.d.ts +23 -6
  505. package/lib/typescript/interfaces/options/sideMenu.d.ts.map +1 -1
  506. package/lib/typescript/interfaces/options/stack.d.ts +17 -3
  507. package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
  508. package/lib/typescript/interfaces/options/system.d.ts +18 -11
  509. package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
  510. package/lib/typescript/interfaces/options/toolbar.d.ts +2 -2
  511. package/lib/typescript/interfaces/options/topBar.d.ts +68 -38
  512. package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
  513. package/metro/acceptPlugin.js +57 -0
  514. package/metro/babelTransformer.js +45 -0
  515. package/metro/index.js +36 -0
  516. package/package.json +4 -25
  517. package/src/ARCHITECTURE.md +40 -27
  518. package/src/adapters/NativeANNTurboModule.ts +12 -2
  519. package/src/api/app/AppRegistry.ts +16 -2
  520. package/src/api/app/createNavigation.ts +203 -69
  521. package/src/api/commands/commands.ts +48 -7
  522. package/src/api/commands/presentation.ts +4 -3
  523. package/src/api/events/navigationEvents.ts +10 -4
  524. package/src/api/hooks/useNavigation.ts +9 -4
  525. package/src/api/hooks/useSafeAreaInsets.ts +4 -3
  526. package/src/api/index.ts +1 -0
  527. package/src/api/linking/dispatchedLinks.ts +18 -0
  528. package/src/api/linking/linking.ts +22 -1
  529. package/src/api/navigation.ts +4 -1
  530. package/src/api/options/OptionsChain.ts +2 -2
  531. package/src/api/screens/defineScreen.ts +49 -5
  532. package/src/api/screens/nativeScreens.ts +40 -4
  533. package/src/api/screens/registerScreens.tsx +185 -42
  534. package/src/api/theme/theme.ts +5 -0
  535. package/src/engine/commands.ts +70 -13
  536. package/src/engine/layout.ts +27 -11
  537. package/src/engine/nativeScreens.ts +10 -1
  538. package/src/engine/options.ts +45 -19
  539. package/src/engine/optionsChange.ts +107 -0
  540. package/src/engine/places.ts +65 -7
  541. package/src/engine/props.ts +30 -1
  542. package/src/engine/refresh.ts +97 -0
  543. package/src/engine/rememberedOptions.ts +74 -1
  544. package/src/engine/screens.tsx +76 -21
  545. package/src/interfaces/ComponentEvents.ts +4 -4
  546. package/src/interfaces/Events.ts +29 -10
  547. package/src/interfaces/Options.ts +1 -0
  548. package/src/interfaces/contract/commands.json +101 -0
  549. package/src/interfaces/contract/errors.json +275 -0
  550. package/src/interfaces/options/animations.ts +81 -22
  551. package/src/interfaces/options/bottomTabs.ts +21 -7
  552. package/src/interfaces/options/buttons.ts +23 -15
  553. package/src/interfaces/options/modals.ts +34 -26
  554. package/src/interfaces/options/sideMenu.ts +24 -6
  555. package/src/interfaces/options/stack.ts +17 -3
  556. package/src/interfaces/options/system.ts +18 -11
  557. package/src/interfaces/options/toolbar.ts +2 -2
  558. package/src/interfaces/options/topBar.ts +68 -38
  559. package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -41
  560. package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -69
  561. package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationStateReporter.kt +0 -62
  562. package/android/src/main/java/dev/apexnative/navigation/react/events/StateHold.kt +0 -62
  563. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowPlacer.kt +0 -223
  564. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStub.kt +0 -31
  565. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +0 -138
  566. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -88
  567. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PropertyAnimatorCreator.kt +0 -33
  568. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +0 -66
  569. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +0 -179
  570. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -139
  571. package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
  572. package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -68
  573. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.h +0 -27
  574. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.mm +0 -55
@@ -36,7 +36,8 @@ import dev.apexnative.navigation.views.animations.AnimationRules
36
36
  * The modals over the old root ([ModalsOverRoot]): taken as the `setRoot` is accepted (commands don't find them), given
37
37
  * back when it ends without replacing the root, carried with the old root into its transition and destroyed with it,
38
38
  * without `ANN.ModalDismissed`. The modals and the overlays of the layout ([LayerStep]) show after the root, one by
39
- * one, before the answer: a newer `setRoot` stops them.
39
+ * one, before the answer: a newer `setRoot` stops them. Its modals are made with the root ([LayerStep.prepare]) and
40
+ * render unseen while it waits and comes in, so each shows in its turn without a wait of its own.
40
41
  *
41
42
  * The steps that come later (the wait's timers and readiness signals, the end of the transition, the end of a layer,
42
43
  * a stack of the waiting root that changed its top) run under no runner: each goes through one guard, and a failure
@@ -128,11 +129,20 @@ internal class RootCoordinator(
128
129
  }
129
130
 
130
131
  /**
131
- * A modal or an overlay of the layout of a `setRoot`, shown after its root: [show] makes it and shows it, and calls
132
- * its argument once it showed or went (a failure is logged and skipped); what it returns stops it while it waits —
133
- * a newer `setRoot`: it goes without a word.
132
+ * A modal or an overlay of the layout of a `setRoot`, shown after its root: [show] shows it (made then, unless
133
+ * [prepare] made it), and calls its argument once it showed or went (a failure is logged and skipped); what it
134
+ * returns stops it while it waits — a newer `setRoot`: it goes without a word.
134
135
  */
135
136
  fun interface LayerStep {
137
+ /**
138
+ * Right after the root is placed, before its wait: a step may make its layer now, so that it renders unseen
139
+ * while the root waits and comes in, and shows without a wait of its own in its turn.
140
+ */
141
+ fun prepare() = Unit
142
+
143
+ /** The `setRoot` ended before this step's turn: what [prepare] made goes without a word. */
144
+ fun discard() = Unit
145
+
136
146
  fun show(done: () -> Unit): () -> Unit
137
147
  }
138
148
 
@@ -221,6 +231,7 @@ internal class RootCoordinator(
221
231
  modals.rootAccepted()
222
232
  val waitForRender = animationsOf(root).enter.waitForRender
223
233
  this.pending = pending
234
+ layers.forEach { it.prepare() }
224
235
  firstRoot.rootSet(waitForRender)
225
236
  await(pending, waitForRender)
226
237
  }
@@ -229,8 +240,9 @@ internal class RootCoordinator(
229
240
  /**
230
241
  * The activity's layers go: the `setRoot` on its way ends, then the root it replaced, the current root and its root
231
242
  * are destroyed, as at any destroy (their events reach only their own JavaScript). [answerPending]: the activity
232
- * went, the waiting `setRoot` resolves with `''` (JavaScript sets the root again in the next activity); otherwise
233
- * (a reload) it gets no answer.
243
+ * went; a `setRoot` whose root still waited resolves with `''` (JavaScript sets the root again in the next
244
+ * activity), one whose root showed (its transition ran, or the modals and overlays of its layout were showing)
245
+ * resolves with the root's id. Otherwise (a reload) it gets no answer.
234
246
  */
235
247
  fun destroyAll(answerPending: Boolean) {
236
248
  val pending = pending
@@ -245,7 +257,9 @@ internal class RootCoordinator(
245
257
  modals.replacedRootGone()
246
258
  pending?.let(::releaseState)
247
259
  if (pending != null && pending.phase == Phase.Waiting) firstRoot.rootDestroyed()
248
- if (answerPending) pending?.answer?.resolve("")
260
+ if (!answerPending || pending == null) return
261
+ // An empty id tells JavaScript the root didn't show: its start waits for the next activity and sets it there.
262
+ pending.answer.resolve(if (pending.phase == Phase.Waiting) "" else pending.root.id)
249
263
  }
250
264
 
251
265
  // Waits for the screens that show when the root shows, then runs its transition. Without `waitForRender` one limit
@@ -367,6 +381,14 @@ internal class RootCoordinator(
367
381
  if (!done) pending.stopLayer = stop
368
382
  }
369
383
 
384
+ // The layers of [pending] not shown yet go: what they made ahead goes unseen, the others aren't made. Each on its
385
+ // own: one that fails doesn't keep the others.
386
+ private fun discardLayers(pending: Pending) {
387
+ val rest = pending.layers.drop(pending.nextLayer)
388
+ pending.nextLayer = pending.layers.size
389
+ rest.forEach { attempt { it.discard() } }
390
+ }
391
+
370
392
  // A new `setRoot` came while this one was on its way.
371
393
  private fun supersede() {
372
394
  val pending = pending ?: return
@@ -389,14 +411,15 @@ internal class RootCoordinator(
389
411
  pending.replaced = null
390
412
  modals.replacedRootGone()
391
413
  }
392
- // Its root is the current root: the modal or the overlay that waits now goes without a word, the others
393
- // aren't made; those shown stay over its root, and go with it when the new root replaces it.
414
+ // Its root is the current root: the modal or the overlay that waits now goes without a word, the others go
415
+ // unseen or aren't made; those shown stay over its root, and go with it when the new root replaces it.
394
416
  Phase.Layers -> {
395
417
  pending.stopLayer?.invoke()
396
418
  pending.stopLayer = null
397
419
  releaseState(pending)
398
420
  }
399
421
  }
422
+ discardLayers(pending)
400
423
  pending.answer.reject(ErrorTexts.setRootReplaced(pending.root.id))
401
424
  }
402
425
 
@@ -426,6 +449,7 @@ internal class RootCoordinator(
426
449
  pending.wait = null
427
450
  when (pending.phase) {
428
451
  Phase.Waiting -> {
452
+ discardLayers(pending)
429
453
  attempt { takeAway(pending.root) }
430
454
  attempt { modals.rootKept() }
431
455
  attempt { firstRoot.rootDestroyed() }
@@ -451,6 +475,7 @@ internal class RootCoordinator(
451
475
  pending.stopLayer = null
452
476
  }
453
477
  }
478
+ discardLayers(pending)
454
479
  // A root that is up takes the splash away, as at its show.
455
480
  if (pending.phase != Phase.Waiting) attempt { onRootShown() }
456
481
  attempt { releaseState(pending) }
@@ -463,8 +488,8 @@ internal class RootCoordinator(
463
488
  }
464
489
 
465
490
  // The navigation state goes once, when the root is in place and its layers have shown, right before the answer:
466
- // what the old root's destroy, the root's appearance and each layer ask for meanwhile waits (StateHold). Taken once
467
- // per `setRoot`, before the old root goes.
491
+ // what the old root's destroy, the root's appearance and each layer ask for meanwhile waits (the hold of
492
+ // NavigationState). Taken once per `setRoot`, before the old root goes.
468
493
  private fun holdState(pending: Pending) {
469
494
  if (pending.holdsState) return
470
495
  pending.holdsState = true
@@ -482,6 +507,7 @@ internal class RootCoordinator(
482
507
  // The root was destroyed while it waited, by something other than a newer `setRoot` or the activity going.
483
508
  private fun rootGone(pending: Pending) {
484
509
  this.pending = null
510
+ discardLayers(pending)
485
511
  releaseState(pending)
486
512
  layer.remove(pending.root)
487
513
  modals.rootKept()
@@ -124,18 +124,18 @@ internal class OverlayCoordinator(
124
124
  }
125
125
 
126
126
  /**
127
- * `dismissOverlay`: the overlays with the root id [componentId] go — one that waits is cancelled, one that shows
128
- * goes with its events (both, when a replacement of a shown one waits) — and [answer] resolves with the id. An id
129
- * no node has: `not shown`; a node that is no overlay's root (Android takes only the root's id): `not in an
130
- * overlay`.
127
+ * `dismissOverlay`: the overlay [componentId] is in — its root or any screen inside it — goes with every overlay of
128
+ * the same root id: one that waits is cancelled, one that shows goes with its events (both, when a replacement of
129
+ * a shown one waits). [answer] resolves with the overlay's root id, as on iOS. An id no node has: `not shown`; a
130
+ * node in no overlay: `not in an overlay`.
131
131
  */
132
132
  fun dismiss(componentId: String, answer: CommandAnswer) {
133
- if (host.find(componentId) == null) return answer.reject(ErrorTexts.screenNotShown(componentId))
134
- val matches = records.filter { it.rootId == componentId }
135
- if (matches.isEmpty()) return answer.reject(ErrorTexts.notInOverlay(componentId))
133
+ val node = host.find(componentId) ?: return answer.reject(ErrorTexts.screenNotShown(componentId))
134
+ val rootId = recordOf(node)?.rootId ?: return answer.reject(ErrorTexts.notInOverlay(componentId))
135
+ val matches = records.filter { it.rootId == rootId }
136
136
  matches.filter { it.state == OverlayRecord.State.Waiting }.forEach(::cancel)
137
137
  val shown = matches.filter { it.state == OverlayRecord.State.Shown }
138
- if (shown.isEmpty()) return answer.resolve(componentId)
138
+ if (shown.isEmpty()) return answer.resolve(rootId)
139
139
  shown.dropLast(1).forEach { remove(it, null) }
140
140
  remove(shown.last(), answer)
141
141
  }
@@ -185,6 +185,8 @@ internal class OverlayCoordinator(
185
185
 
186
186
  private fun start(make: () -> ViewController<*>, answer: CommandAnswer?, chainDone: (() -> Unit)?): OverlayRecord {
187
187
  val root = make()
188
+ // Before the root's view is made: its screens are drawn under the status bar from their first layout.
189
+ root.shownAsOverlay = true
188
190
  val record = OverlayRecord(root)
189
191
  // A waiting layer before its views join the window: what is in it isn't on screen from its first layout.
190
192
  record.screensChanged = { screensChanged(record) }
@@ -41,11 +41,18 @@ interface KeepsStatusBarRoom
41
41
  /** A node that shows screens in its columns (the split view): `showInColumn` and `setColumnShown` go to it. */
42
42
  interface ShowsColumns {
43
43
  /**
44
- * Shows [screen] in the column after the first one, in place of what it shows; [listener] once it shows, or with
45
- * the error reason, which names [from], the screen the command comes from. False when the node doesn't take it now
46
- * (its compact layout shows): the core pushes the screen over [from] instead.
44
+ * Shows [screen] in [column], in place of what it shows; [listener] once it shows, or with the error reason, which
45
+ * names [from], the screen the command comes from. [goesInStack] says whether [screen]'s layout is what a stack
46
+ * takes (a screen, a native screen, a pair), not a container. False when the node doesn't take it now (its compact
47
+ * layout shows): the core pushes the screen over [from] instead.
47
48
  */
48
- fun showScreen(screen: ViewController<*>, from: ViewController<*>, listener: CommandListener): Boolean
49
+ fun showScreen(
50
+ screen: ViewController<*>,
51
+ column: String,
52
+ goesInStack: Boolean,
53
+ from: ViewController<*>,
54
+ listener: CommandListener,
55
+ ): Boolean
49
56
 
50
57
  /** Shows or hides [column]; [done] once the columns have stopped moving. */
51
58
  fun setColumnShown(column: String, shown: Boolean, done: Runnable)
@@ -31,9 +31,9 @@ internal object ContainerBackground {
31
31
  if (!colour.hasValue()) return null
32
32
  val color = colour.get(node.activity, Color.TRANSPARENT) ?: Color.TRANSPARENT
33
33
  // The screens' band rule (`ScreenSafeArea.backgroundBand`) for a layout, which keeps no room at its top: the
34
- // status bar's height, but none when it is hidden or the layout is drawn under it, in a side menu, a sheet or
35
- // a pair.
36
- val full = options.statusBar.isHiddenOrDrawBehind || node.isInSideMenu || node.isInSheet ||
34
+ // status bar's height, but none when it is hidden or the layout is drawn under it (in an overlay by default),
35
+ // in a side menu, a sheet or a pair.
36
+ val full = options.statusBar.isHiddenOrDrawBehind(node.isInOverlay) || node.isInSideMenu || node.isInSheet ||
37
37
  node.parentController is KeepsStatusBarRoom
38
38
  val band = if (full) 0 else SystemUiUtils.getStatusBarHeight(node.activity)
39
39
  if (band <= 0) return ColorDrawable(color)
@@ -8,6 +8,7 @@ import dev.apexnative.navigation.react.CommandListener
8
8
  import dev.apexnative.navigation.viewcontrollers.bottomtabs.TabBarMotion
9
9
  import dev.apexnative.navigation.viewcontrollers.child.ChildController
10
10
  import dev.apexnative.navigation.viewcontrollers.child.ChildControllersRegistry
11
+ import dev.apexnative.navigation.viewcontrollers.stack.StackController
11
12
  import dev.apexnative.navigation.viewcontrollers.stack.fab.FabPlacement
12
13
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.Presenter
13
14
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
@@ -128,12 +129,9 @@ abstract class ParentController<V : ViewGroup>(
128
129
  open fun leavesTopEdgeFree(child: ViewController<*>): Boolean =
129
130
  parentController?.leavesTopEdgeFree(this) ?: false
130
131
 
131
- /**
132
- * Whether the safe area of [child] leaves its bottom edge free by default: the tabs show with
133
- * `bottomTabs.hideOnScroll` of [screen], the screen that asks.
134
- */
135
- open fun leavesBottomEdgeFree(child: ViewController<*>, screen: ViewController<*> = child): Boolean =
136
- parentController?.leavesBottomEdgeFree(this, screen) ?: false
132
+ /** Whether a large title shows over [child]: its stack shows the bar with one. No by default. */
133
+ open fun showsLargeTitleOver(child: ViewController<*>): Boolean =
134
+ parentController?.showsLargeTitleOver(this) ?: false
137
135
 
138
136
  /**
139
137
  * The tab bar at rest under [child]: where a stack's FAB keeps clear of it, by the options of [screen], the stack's
@@ -210,6 +208,8 @@ abstract class ParentController<V : ViewGroup>(
210
208
 
211
209
  override fun canHandleBack(): Boolean = getCurrentChild()?.canHandleBack() == true
212
210
 
211
+ override fun stackPoppedByBack(): StackController? = getCurrentChild()?.stackPoppedByBack()
212
+
213
213
  override fun destroy() {
214
214
  if (isDestroyed) return
215
215
  getChildControllers().forEach { it.destroy() }
@@ -16,6 +16,7 @@ import dev.apexnative.navigation.viewcontrollers.navigator.Navigator
16
16
  import dev.apexnative.navigation.viewcontrollers.parent.ChildOffsetFromRest
17
17
  import dev.apexnative.navigation.viewcontrollers.parent.ParentController
18
18
  import dev.apexnative.navigation.viewcontrollers.sidemenu.SideMenuMotion.Side
19
+ import dev.apexnative.navigation.viewcontrollers.stack.StackController
19
20
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.Presenter
20
21
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
21
22
  import dev.apexnative.navigation.views.sidemenu.SideMenuView
@@ -28,7 +29,8 @@ import dev.apexnative.navigation.views.sidemenu.SideMenuView
28
29
  * - The current child is the open menu's node, else the center ([SideMenuMotion.openSide]: from the end of the
29
30
  * opening to the end of the closing); the state, the options and back follow it.
30
31
  * - The center and the open menu show with the side menu ([visibleChildren]); a wait for the side menu to render
31
- * waits for the center ([waitedChildren]); the menus' views are made with the side menu's.
32
+ * waits for the center ([waitedChildren]); the menus' views join the drawer as `sideMenu.menusAttachMode` says
33
+ * ([attached]): with the side menu's view, once it first appeared, or each as it first starts to show.
32
34
  * - Its options ([SideMenuPresenter]): from the resolution of [resolveShownOptions] at creation, at every appearance
33
35
  * of a screen inside, and for the fields a merge names; `sideMenu.<side>.visible` acts once, from a merge or from the
34
36
  * layout at the first show. What goes on up goes without `sideMenu`: the nearest side menu acts.
@@ -63,6 +65,12 @@ internal class SideMenuController(
63
65
  // From the end of its appearance's start until it disappears: the drawer's motion tells the menu screens then.
64
66
  private var appeared = false
65
67
  private var firstShown = false
68
+ private var firstAppeared = false
69
+
70
+ private val attachMode = SideMenuRules.attachModeOf(initialOptions.sideMenu, DefaultOptions.current.sideMenu)
71
+
72
+ /** The menus whose nodes' views are in the drawer, or join it as it is made. */
73
+ internal val attached = HashSet<Side>(2)
66
74
  // Its children go first as it is destroyed: nothing reacts to them, nor to the drawer, from the start.
67
75
  private var destroying = false
68
76
 
@@ -71,6 +79,7 @@ internal class SideMenuController(
71
79
 
72
80
  init {
73
81
  getChildControllers().forEach { it.parentController = this }
82
+ SideMenuRules.attachedAtCreation(attachMode).filter { childOf(it) != null }.forEach { attached += it }
74
83
  }
75
84
 
76
85
  override fun getChildControllers(): List<ViewController<*>> = listOfNotNull(center, left, right)
@@ -87,13 +96,16 @@ internal class SideMenuController(
87
96
 
88
97
  private fun childOf(side: Side): ViewController<*>? = if (side == Side.Left) left else right
89
98
 
90
- // The drawer and its parts, each node's view in its part; the creation's options. An open menu recorded before the
91
- // view existed is open in it from the start; the drawer is silent before its first layout.
99
+ // The drawer and its parts, the view of each node attached so far in its part; the creation's options. An open menu
100
+ // recorded before the view existed is open in it from the start; the drawer is silent before its first layout.
92
101
  override fun createView(): SideMenuView {
93
102
  val view = SideMenuView(activity)
94
103
  view.setCenter(center.view)
95
- left?.let { view.addPart(Side.Left, it.view) }
96
- right?.let { view.addPart(Side.Right, it.view) }
104
+ for (side in Side.entries) {
105
+ val child = childOf(side) ?: continue
106
+ view.addPart(side)
107
+ if (side in attached) view.fillPart(side, child.view)
108
+ }
97
109
  menus.applyOnCreation(view, resolveShownOptions(DefaultOptions.current))
98
110
  motion.openSide?.let { view.open(it, false) }
99
111
  view.follow(motion)
@@ -130,7 +142,7 @@ internal class SideMenuController(
130
142
 
131
143
  // `mergeOptions` with the side menu's id: its own options, then what a merge does, then the layouts around.
132
144
  override fun mergeOptions(options: Options) {
133
- this.options = this.options.copy().mergeWith(options)
145
+ mergeOwnOptions(options)
134
146
  applyMerge(options)
135
147
  performOnParentController { it.mergeChildOptions(SideMenuRules.withoutSideMenu(options), this) }
136
148
  }
@@ -171,6 +183,14 @@ internal class SideMenuController(
171
183
  motion.containerAppeared()
172
184
  }
173
185
 
186
+ // `afterCenter`: the menus join once the side menu first appeared with its center.
187
+ override fun onViewDidAppear() {
188
+ super.onViewDidAppear()
189
+ if (firstAppeared || destroying || isDestroyed) return
190
+ firstAppeared = true
191
+ SideMenuRules.attachedAfterAppearance(attachMode).forEach(::attach)
192
+ }
193
+
174
194
  override fun onViewDisappear() {
175
195
  appeared = false
176
196
  motion.containerDisappeared()
@@ -183,6 +203,9 @@ internal class SideMenuController(
183
203
 
184
204
  override fun canHandleBack(): Boolean = motion.canGoBack || center.canHandleBack()
185
205
 
206
+ // An open menu closes first: no preview of a pop then.
207
+ override fun stackPoppedByBack(): StackController? = if (motion.canGoBack) null else center.stackPoppedByBack()
208
+
186
209
  // A button's press addressed to the side menu goes to the center.
187
210
  override fun sendOnNavigationButtonPressed(buttonId: String) = center.sendOnNavigationButtonPressed(buttonId)
188
211
 
@@ -218,6 +241,16 @@ internal class SideMenuController(
218
241
  if (child === currentChild) super.tabBarSettled(child)
219
242
  }
220
243
 
244
+ // The view of the menu on [side] joins its part, once, before its screens hear that they appear: a stack lays out
245
+ // its bar as it appears in the window. The drawer's first movement may come while it draws (a peek settles in
246
+ // `computeScroll`, before the drawer draws its children): the view joins the part then, measured and laid out at the
247
+ // next frame.
248
+ private fun attach(side: Side) {
249
+ val child = childOf(side) ?: return
250
+ if (destroying || isDestroyed || !attached.add(side)) return
251
+ peekView()?.fillPart(side, child.view)
252
+ }
253
+
221
254
  /** Destroys the side menu once: the drawer's callbacks stop first, then the children go. */
222
255
  override fun destroy() {
223
256
  if (isDestroyed) return
@@ -234,6 +267,8 @@ internal class SideMenuController(
234
267
 
235
268
  override fun child(side: Side): ViewController<*>? = childOf(side)
236
269
 
270
+ override fun starts(side: Side) = attach(side)
271
+
237
272
  override fun isEnabled(side: Side): Boolean =
238
273
  SideMenuRules.isEnabled(resolveShownOptions(DefaultOptions.current).sideMenu, side)
239
274
 
@@ -255,9 +290,7 @@ internal class SideMenuController(
255
290
  }
256
291
 
257
292
  // The system UI follows the screen the user sees now, at rest: the open menu's, the center's once a close
258
- // ends. The owner reads it before the next frame, when a menu that closed is hidden already. An open without
259
- // animation runs this inside `AppearanceDispatcher.withoutWillAppear`: what starts to appear from here would
260
- // send no WillAppear.
293
+ // ends. The owner reads it before the next frame, when a menu that closed is hidden already.
261
294
  override fun shownChanged() {
262
295
  navigator?.shownScreensChanged(this@SideMenuController)
263
296
  navigator?.systemUi?.invalidate()
@@ -1,6 +1,7 @@
1
1
  package dev.apexnative.navigation.viewcontrollers.sidemenu
2
2
 
3
3
  import dev.apexnative.navigation.react.events.AppearanceDispatcher
4
+ import dev.apexnative.navigation.utils.SystemAnimations
4
5
  import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
5
6
 
6
7
  /**
@@ -16,8 +17,8 @@ import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
16
17
  * the drawer calls `onDrawerClosed` only for a drawer that had opened.
17
18
  * - The menu screen's events: WillAppear at the side's first movement, DidAppear when it opened, DidDisappear when it
18
19
  * rests closed; only while the side menu has appeared ([Host.appeared]) — otherwise they come with the side menu's
19
- * own appearance (its visible children). An open without animation sends DidAppear without WillAppear
20
- * (`AppearanceDispatcher.withoutWillAppear`).
20
+ * own appearance (its visible children). An open without animation sends both too, WillAppear first, as on iOS:
21
+ * the drawer jumps to its open offset before it calls the open.
21
22
  * - At each rest: one state update after the menu's events, the back callback, and the layers that follow the shown
22
23
  * screen.
23
24
  * - A drawer that doesn't call back (not laid out since it joined the window, or not in one: `DrawerLayout` only
@@ -26,6 +27,8 @@ import dev.apexnative.navigation.viewcontrollers.viewcontroller.ViewController
26
27
  internal class SideMenuMotion(
27
28
  private val drawer: () -> Drawer,
28
29
  private val host: Host,
30
+ /** The system's animations are off ([SystemAnimations]): a command or back moves the drawer at once. */
31
+ private val animationsOff: () -> Boolean = { SystemAnimations.areOff() },
29
32
  ) {
30
33
  /** A side of the side menu: physical, `left` stays on the left in RTL too. */
31
34
  enum class Side(
@@ -79,6 +82,12 @@ internal class SideMenuMotion(
79
82
  /** `sideMenu.<side>.enabled` of the side menu's options now. */
80
83
  fun isEnabled(side: Side): Boolean
81
84
 
85
+ /**
86
+ * The menu on [side] starts to show: the drawer's first movement, or a command that opens it. Before its
87
+ * screen hears that it appears.
88
+ */
89
+ fun starts(side: Side)
90
+
82
91
  /** `visible: true` for a side the layout doesn't have: a warning, nothing else. */
83
92
  fun missingSide(side: Side)
84
93
 
@@ -119,6 +128,7 @@ internal class SideMenuMotion(
119
128
  fun slid(side: Side, offset: Float) {
120
129
  // Not more than 0 also takes a NaN: `DrawerLayout` divides by the drawer's width, which may be 0.
121
130
  if (destroyed || !(offset > 0f)) return
131
+ if (!isOnScreen(side)) host.starts(side)
122
132
  onScreen += side
123
133
  if (side in appearing || !host.appeared) return
124
134
  appearing += side
@@ -204,6 +214,7 @@ internal class SideMenuMotion(
204
214
  }
205
215
  // Never decided by where the other menu is: a side asked to open in the same merge hasn't moved yet.
206
216
  if (drawer.has(side.other)) move(side.other, open = false, animate = animated)
217
+ if (!isOnScreen(side)) host.starts(side)
207
218
  onScreen += side
208
219
  // A locked menu opened from code can be dragged closed while it is open.
209
220
  drawer.lock(side, locked = false)
@@ -242,15 +253,15 @@ internal class SideMenuMotion(
242
253
  drawer.lock(side, locked = !isOnScreen(side) && !host.isEnabled(side))
243
254
  }
244
255
 
245
- // The drawer opens or closes [side]; one that doesn't call back has its result recorded here.
256
+ // The drawer opens or closes [side]; one that doesn't call back has its result recorded here. With the system's
257
+ // animations off it jumps, unless it moves: the drag and the settle aren't animators, and it can't jump while it
258
+ // settles.
246
259
  private fun move(side: Side, open: Boolean, animate: Boolean) {
247
260
  val drawer = drawer()
261
+ val animated = animate && (moving || !animationsOff())
248
262
  val silent = !drawer.callsBack
249
- val run = {
250
- if (open) drawer.open(side, animate) else drawer.close(side, animate)
251
- if (silent) record(side, open)
252
- }
253
- if (open && !animate && host.appeared) AppearanceDispatcher.withoutWillAppear(run) else run()
263
+ if (open) drawer.open(side, animated) else drawer.close(side, animated)
264
+ if (silent) record(side, open)
254
265
  }
255
266
 
256
267
  private fun record(side: Side, open: Boolean) {
@@ -18,15 +18,14 @@ import dev.apexnative.navigation.views.sidemenu.SideMenuView
18
18
  * `testID`s. Each moment applies its part, from the side menu's resolved options
19
19
  * (`SideMenuController.resolveShownOptions`: the current part's chain, the center's `sideMenu` over an open menu's) —
20
20
  * at creation everything with the heights, at every appearance of a screen inside everything but the heights, at a
21
- * merge the fields it names, at a repaint the background and the `testID`s. The locks of `enabled` and the command
21
+ * merge the fields it names (a width or a height at once, an open menu too), at a repaint the background and the
22
+ * `testID`s. The locks of `enabled` and the command
22
23
  * `visible` are the node's ([SideMenuMotion]). Main thread only.
23
24
  */
24
25
  internal class SideMenuPresenter(activity: Activity) : Presenter(activity, Options()) {
25
- /** The side menu's [view] is made, with [options], resolved: the heights, read only now. */
26
+ /** The side menu's [view] is made, with [options], resolved: the heights too, which only a merge changes after. */
26
27
  fun applyOnCreation(view: SideMenuView, options: Options) {
27
- for (side in Side.entries) {
28
- view.setPartHeight(side, SideMenuRules.height(SideMenuRules.sideOf(options.sideMenu, side), ::toPixels))
29
- }
28
+ applyHeights(view, options.sideMenu)
30
29
  applyWidths(view, options.sideMenu)
31
30
  applyBackground(view, options)
32
31
  applyTestIds(view, options.sideMenu)
@@ -46,14 +45,18 @@ internal class SideMenuPresenter(activity: Activity) : Presenter(activity, Optio
46
45
  /**
47
46
  * A merge reached the side menu, its own or through a screen inside (`mergeOptions` step 3): the fields [options]
48
47
  * name, with the values of the side menu's resolution now, so a screen off what shows changes nothing until it
49
- * appears. A width waits for the next appearance, a height for nothing.
48
+ * appears. A width or a height resizes its menu at once, open or closed, as on iOS.
50
49
  */
51
50
  override fun mergeOptions(viewController: ViewController<*>, options: Options) {
52
51
  val layout = viewController.peekView() as? SideMenuView ?: return
53
52
  val touchesBackground = SideMenuRules.touchesBackground(options)
54
53
  val touchesTestIds = SideMenuRules.touchesTestIds(options.sideMenu)
55
- if (!touchesBackground && !touchesTestIds) return
54
+ val touchesWidths = SideMenuRules.touchesWidths(options.sideMenu)
55
+ val touchesHeights = SideMenuRules.touchesHeights(options.sideMenu)
56
+ if (!touchesBackground && !touchesTestIds && !touchesWidths && !touchesHeights) return
56
57
  val shown = viewController.resolveShownOptions(DefaultOptions.current)
58
+ if (touchesWidths) applyWidths(layout, shown.sideMenu)
59
+ if (touchesHeights) applyHeights(layout, shown.sideMenu)
57
60
  if (touchesBackground) applyBackground(layout, shown)
58
61
  if (touchesTestIds) applyTestIds(layout, shown.sideMenu)
59
62
  }
@@ -71,6 +74,12 @@ internal class SideMenuPresenter(activity: Activity) : Presenter(activity, Optio
71
74
  }
72
75
  }
73
76
 
77
+ private fun applyHeights(view: SideMenuView, options: SideMenuOptions) {
78
+ for (side in Side.entries) {
79
+ view.setPartHeight(side, SideMenuRules.height(SideMenuRules.sideOf(options, side), ::toPixels))
80
+ }
81
+ }
82
+
74
83
  // `layout.backgroundColor` on the drawer, its whole height, under the status bar; unset leaves the view as it is,
75
84
  // `'NoColor'` clears it.
76
85
  private fun applyBackground(view: View, options: Options) {
@@ -11,11 +11,23 @@ import kotlin.math.min
11
11
 
12
12
  /**
13
13
  * What the options of a side menu do on Android (`sideMenu.*`), without views: the values of each moment, `visible` as
14
- * a command, the sizes, the `testID`s. Android reads `enabled`, `width`, `height`, `visible`, `animate` and the
15
- * `testID`s of `sideMenu`; `openGestureMode`, `animationType`, `openMode`, `shouldStretchDrawer`, `animationVelocity`
16
- * and `glass` are iOS's.
14
+ * a command, the sizes, the `testID`s, when the menus join the drawer. Android reads `enabled`, `width`, `height`,
15
+ * `visible`, `animate`, `menusAttachMode` and the `testID`s of `sideMenu`; `openGestureMode`, `animationType`,
16
+ * `openMode`, `shouldStretchDrawer`, `animationVelocity` and `glass` are iOS's.
17
17
  */
18
18
  internal object SideMenuRules {
19
+ /** When the views of the menus' nodes join the drawer (`sideMenu.menusAttachMode`): their content renders then. */
20
+ enum class AttachMode {
21
+ /** With the side menu's view. */
22
+ Together,
23
+
24
+ /** Once the side menu first appeared, with its center. */
25
+ AfterCenter,
26
+
27
+ /** Each as it first starts to show: the drawer's first movement, or a command that opens it. */
28
+ OnOpen,
29
+ }
30
+
19
31
  /** A side's `visible` of one merge: open or close it, with its `animate`. */
20
32
  data class Command(val side: Side, val visible: Boolean, val animate: Boolean)
21
33
 
@@ -43,6 +55,26 @@ internal object SideMenuRules {
43
55
  */
44
56
  fun firstShow(layout: SideMenuOptions): List<Side> = Side.entries.filter { sideOf(layout, it).visible.isTrue }
45
57
 
58
+ /**
59
+ * The mode of `sideMenu.menusAttachMode`: the side menu's [own] options, else the [defaults]; `together` without
60
+ * either. Read once, as the side menu is made.
61
+ */
62
+ fun attachModeOf(own: SideMenuOptions, defaults: SideMenuOptions): AttachMode {
63
+ val value = own.menusAttachMode.takeIf { it.hasValue() } ?: defaults.menusAttachMode
64
+ return when (value.get(null)) {
65
+ "afterCenter" -> AttachMode.AfterCenter
66
+ "onOpen" -> AttachMode.OnOpen
67
+ else -> AttachMode.Together
68
+ }
69
+ }
70
+
71
+ /** The menus that join as the side menu is made: both with `together`. */
72
+ fun attachedAtCreation(mode: AttachMode): List<Side> = if (mode == AttachMode.Together) Side.entries else emptyList()
73
+
74
+ /** The menus that join once the side menu first appeared: both with `afterCenter`. */
75
+ fun attachedAfterAppearance(mode: AttachMode): List<Side> =
76
+ if (mode == AttachMode.AfterCenter) Side.entries else emptyList()
77
+
46
78
  /** `enabled` of [side]: true unless `false`, from the side menu's resolved options. */
47
79
  fun isEnabled(options: SideMenuOptions, side: Side): Boolean = !sideOf(options, side).enabled.isFalse
48
80
 
@@ -54,6 +86,13 @@ internal object SideMenuRules {
54
86
  fun touchesTestIds(merge: SideMenuOptions): Boolean =
55
87
  merge.testID.hasValue() || merge.left.testID.hasValue() || merge.right.testID.hasValue()
56
88
 
89
+ /** A merge names `width` of a side: the menus take their widths again. */
90
+ fun touchesWidths(merge: SideMenuOptions): Boolean = merge.left.width.hasValue() || merge.right.width.hasValue()
91
+
92
+ /** A merge names `height` of a side: the menus take their heights again. */
93
+ fun touchesHeights(merge: SideMenuOptions): Boolean =
94
+ merge.left.height.hasValue() || merge.right.height.hasValue()
95
+
57
96
  /** A merge names the background of the side menu (`layout.backgroundColor`). */
58
97
  fun touchesBackground(merge: Options): Boolean = merge.layout.backgroundColor.hasValue()
59
98
 
@@ -64,7 +103,7 @@ internal object SideMenuRules {
64
103
  fun wantedWidth(options: SideMenuSideOptions, toPixels: (Double) -> Int): Int? =
65
104
  options.width.get(null)?.let { max(0, toPixels(it)) }
66
105
 
67
- /** The height of a side, in pixels: `height` (dp) by [toPixels], read at creation only; none: the whole height. */
106
+ /** The height of a side, in pixels: `height` (dp) by [toPixels]; none: the whole height. */
68
107
  fun height(options: SideMenuSideOptions, toPixels: (Double) -> Int): Int? =
69
108
  options.height.get(null)?.let { max(0, toPixels(it)) }
70
109
 
@@ -1,6 +1,8 @@
1
1
  package dev.apexnative.navigation.viewcontrollers.splitview
2
2
 
3
3
  import android.content.Context
4
+ import android.view.View
5
+ import android.view.ViewGroup
4
6
  import android.view.WindowInsets
5
7
  import androidx.core.graphics.Insets
6
8
  import androidx.core.view.WindowInsetsCompat
@@ -14,6 +16,27 @@ class SplitPanes(context: Context) : SlidingPaneLayout(context) {
14
16
  /** The panes are side by side. */
15
17
  var isSideBySide = false
16
18
 
19
+ /**
20
+ * Puts [next] in the place of the pane [old], with the structure and the params [old] had. The library wraps the
21
+ * second view it is given in a view of its own that holds back touches (`addView` with one child there), and its
22
+ * `removeView` takes that wrapper away: a plain remove and add would wrap a new primary pane, or give a new
23
+ * secondary one the wrapper's params, and lose its width and weight. So the secondary pane's content changes
24
+ * inside the wrapper, and a new primary pane goes in before the old one leaves, while two children are there.
25
+ */
26
+ internal fun replacePane(old: View, next: View) {
27
+ val holder = old.parent as? ViewGroup ?: return
28
+ val params = old.layoutParams
29
+ if (holder === this) {
30
+ // A copy: the width that `splitView.width` changes later is the new pane's own.
31
+ addView(next, indexOfChild(old), if (params is LayoutParams) LayoutParams(params) else params)
32
+ removeView(old)
33
+ } else {
34
+ val index = holder.indexOfChild(old)
35
+ holder.removeView(old)
36
+ holder.addView(next, index, params)
37
+ }
38
+ }
39
+
17
40
  override fun dispatchApplyWindowInsets(insets: WindowInsets): WindowInsets {
18
41
  if (!isSideBySide) return super.dispatchApplyWindowInsets(insets)
19
42
  val own = onApplyWindowInsets(insets)