@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
@@ -6,6 +6,7 @@ import android.view.ViewGroup
6
6
  import dev.apexnative.navigation.options.DefaultOptions
7
7
  import dev.apexnative.navigation.options.Options
8
8
  import dev.apexnative.navigation.options.OptionsCache
9
+ import dev.apexnative.navigation.options.UserChoices
9
10
  import dev.apexnative.navigation.options.params.Bool
10
11
  import dev.apexnative.navigation.options.params.NullBool
11
12
  import dev.apexnative.navigation.react.CommandListener
@@ -30,11 +31,11 @@ abstract class ViewController<V : ViewGroup>(
30
31
  var initialOptions: Options,
31
32
  ) {
32
33
  /**
33
- * The node's own options: those it was made with, with every `mergeOptions` and every user's choice over them.
34
- * Writing them is one of the two places the options change ([OptionsCache]): the setter takes away the one-shot
35
- * options, keeps the object (a stripped copy when it has a one-shot option: the caller's object never changes), and
36
- * makes every resolved result stale. Don't change the object in place: [changeOptions] or [mergeOptions] write a
37
- * changed copy.
34
+ * The node's own options: those it was made with, with every `mergeOptions` over them; what the user chose in the
35
+ * native UI is not here but in [choices]. Writing them is one of the places the options change ([OptionsCache]):
36
+ * the setter takes away the one-shot options, keeps the object (a stripped copy when it has a one-shot option: the
37
+ * caller's object never changes), and makes every resolved result stale. Don't change the object in place:
38
+ * [changeOptions] or [mergeOptions] write a changed copy.
38
39
  */
39
40
  var options: Options = initialOptions.copy().also(Options::clearOneShotOptions)
40
41
  set(value) {
@@ -42,6 +43,10 @@ abstract class ViewController<V : ViewGroup>(
42
43
  OptionsCache.optionsChanged()
43
44
  }
44
45
 
46
+ // The user layer: what the user chose in the native UI (a menu's check, a search scope), over the node's own
47
+ // options as they resolve ([changeChoices]).
48
+ private val choices = UserChoices()
49
+
45
50
  /**
46
51
  * The JavaScript the node was made for (`ReloadCoordinator`): the events of the node and its screens reach only
47
52
  * that one.
@@ -94,6 +99,19 @@ abstract class ViewController<V : ViewGroup>(
94
99
  open val isInSheet: Boolean
95
100
  get() = shownAsSheet || parent?.isInSheet == true
96
101
 
102
+ /**
103
+ * The node is the root of an overlay: the overlays set it before the node's view is made, so its screens are drawn
104
+ * under the status bar from their first layout (`StatusBarOptions.isHiddenOrDrawBehind`).
105
+ */
106
+ internal var shownAsOverlay = false
107
+
108
+ /**
109
+ * The node is in an overlay: it covers the whole window, and is drawn under the status bar by default. It holds from
110
+ * the start of the show, while `OverlayCoordinator.isInOverlay` answers only for the overlays it lists.
111
+ */
112
+ open val isInOverlay: Boolean
113
+ get() = shownAsOverlay || parent?.isInOverlay == true
114
+
97
115
  /**
98
116
  * The node is in a side of a side menu (its left or right menu, not its center): the side goes the whole height of
99
117
  * the window, and the node keeps no room for the status bar. The layout around answers for it
@@ -143,9 +161,9 @@ abstract class ViewController<V : ViewGroup>(
143
161
  }
144
162
 
145
163
  /**
146
- * The node's options over those of the layouts around it, without the default options: the parents' resolution,
147
- * then the node's own. A new object at each call, which the caller may change. For a layout of nodes this is not
148
- * what it shows with: that is [resolveShownOptions].
164
+ * The node's options over those of the layouts around it, without the default options and without the user layer
165
+ * ([changeChoices]): the parents' resolution, then the node's own. A new object at each call, which the caller may
166
+ * change. For a layout of nodes this is not what it shows with: that is [resolveShownOptions].
149
167
  */
150
168
  open fun resolveCurrentOptions(): Options {
151
169
  val resolved = parent?.resolveChildOptions(this) ?: Options()
@@ -153,21 +171,21 @@ abstract class ViewController<V : ViewGroup>(
153
171
  }
154
172
 
155
173
  /**
156
- * The node's options over those of the layouts around it and [defaultOptions]: what it shows with. With the app's
157
- * default options ([DefaultOptions.current]) the result is kept and given again while no options changed
158
- * ([OptionsCache]) and the layouts around the node and its current children are the same: it is read-only, whoever
159
- * changes it copies it first. Main thread only.
174
+ * The node's options over those of the layouts around it and [defaultOptions], with the user layer over them
175
+ * ([changeChoices]): what it shows with. With the app's default options ([DefaultOptions.current]) the result is
176
+ * kept and given again while no options changed ([OptionsCache]) and the layouts around the node and its current
177
+ * children are the same: it is read-only, whoever changes it copies it first. Main thread only.
160
178
  *
161
179
  * For a layout of nodes (a stack, tabs, a side menu) it is the layout's own options over those around it, without
162
180
  * any child's: not what the layout shows with, which [resolveShownOptions] gives.
163
181
  */
164
182
  open fun resolveCurrentOptions(defaultOptions: Options): Options {
165
- if (defaultOptions !== DefaultOptions.current) return resolveCurrentOptions().withDefaultOptions(defaultOptions)
183
+ if (defaultOptions !== DefaultOptions.current) return withChoices(defaultOptions)
166
184
  val generation = OptionsCache.generation
167
185
  val along = resolvedAlong()
168
186
  val kept = resolved
169
187
  if (kept != null && resolvedGeneration == generation && sameNodes(along, resolvedAlong)) return kept
170
- val result = resolveCurrentOptions().withDefaultOptions(defaultOptions)
188
+ val result = withChoices(defaultOptions)
171
189
  resolved = result
172
190
  resolvedGeneration = generation
173
191
  resolvedAlong = along.map(::WeakReference)
@@ -183,6 +201,10 @@ abstract class ViewController<V : ViewGroup>(
183
201
  */
184
202
  open fun resolveShownOptions(defaultOptions: Options): Options = resolveCurrentOptions(defaultOptions)
185
203
 
204
+ // The resolution in its order: the defaults, the parents, the node's own options, then the user layer over them.
205
+ private fun withChoices(defaultOptions: Options): Options =
206
+ choices.applyTo(resolveCurrentOptions().withDefaultOptions(defaultOptions))
207
+
186
208
  // The layouts around this node, nearest first, then its current children down the visible chain.
187
209
  private fun resolvedAlong(): List<ViewController<*>> {
188
210
  val nodes = ArrayList<ViewController<*>>()
@@ -203,9 +225,9 @@ abstract class ViewController<V : ViewGroup>(
203
225
  nodes.size == kept.size && nodes.indices.all { nodes[it] === kept[it].get() }
204
226
 
205
227
  /**
206
- * Changes the node's own options: [change] gets a copy, which is stored ([options]). A presenter or a module that
207
- * writes a user's choice into the options (a menu's checkmark, a search scope, tokens, a toggled button) does it
208
- * this way; a button menu keeps its own shared `checked` (`ButtonMenuOptions`).
228
+ * Changes the node's own options: [change] gets a copy, which is stored ([options]). It is for the library's own
229
+ * bookkeeping of a merge (a side color written into the node's buttons, the back button's visibility); what the
230
+ * user chose goes through [changeChoices].
209
231
  */
210
232
  fun changeOptions(change: (Options) -> Unit) {
211
233
  val copy = options.copy()
@@ -213,14 +235,40 @@ abstract class ViewController<V : ViewGroup>(
213
235
  options = copy
214
236
  }
215
237
 
238
+ /**
239
+ * Changes the node's user layer: what the user chose in the native UI (a single-selection menu's check, a search
240
+ * scope). It goes over the node's own options as they resolve, by the ids of the buttons, items and scopes, and
241
+ * stays through an unrelated `mergeOptions`, the same values sent again and `setDefaultOptions`; a merge that
242
+ * changes the chosen field takes it away ([mergeOwnOptions]). Every resolved result is stale after it
243
+ * ([OptionsCache]).
244
+ */
245
+ internal fun changeChoices(change: (UserChoices) -> Unit) {
246
+ change(choices)
247
+ OptionsCache.optionsChanged()
248
+ }
249
+
250
+ /**
251
+ * [delta] of a `mergeOptions` goes over the node's own options ([options]); a choice of the user layer whose field
252
+ * the merge changes, or whose button, item or scope it took away, leaves, so the app's value shows
253
+ * (`UserChoices.yieldTo`). Every `mergeOptions` into a node writes its own options this way.
254
+ */
255
+ protected fun mergeOwnOptions(delta: Options) {
256
+ val own = options
257
+ val before = if (choices.isEmpty) null else resolveCurrentOptions().withDefaultOptions(DefaultOptions.current)
258
+ options = own.copy().mergeWith(delta)
259
+ before ?: return
260
+ val after = resolveCurrentOptions().withDefaultOptions(DefaultOptions.current)
261
+ if (choices.yieldTo(delta, own, before, after)) OptionsCache.optionsChanged()
262
+ }
263
+
216
264
  /**
217
265
  * `mergeOptions` with the node's id (`mergeOptions`): [options] go over its own and stay there (one-shot options
218
- * not kept); what shows applies them ([applyMergedOptions], when the view shows; otherwise as it appears); the
219
- * layouts around it apply their part (`ParentController.mergeChildOptions`, each passes it on). [options] still
220
- * carry the one-shot options to them. Containers that hand the merge to a child override it.
266
+ * not kept, [mergeOwnOptions]); what shows applies them ([applyMergedOptions], when the view shows; otherwise as it
267
+ * appears); the layouts around it apply their part (`ParentController.mergeChildOptions`, each passes it on).
268
+ * [options] still carry the one-shot options to them. Containers that hand the merge to a child override it.
221
269
  */
222
270
  open fun mergeOptions(options: Options) {
223
- this.options = this.options.copy().mergeWith(options)
271
+ mergeOwnOptions(options)
224
272
  if (isViewShown) applyMergedOptions(options)
225
273
  performOnParentController { it.mergeChildOptions(options, this) }
226
274
  }
@@ -265,6 +313,12 @@ abstract class ViewController<V : ViewGroup>(
265
313
  /** Whether [handleBack] would go back. */
266
314
  open fun canHandleBack(): Boolean = false
267
315
 
316
+ /**
317
+ * The stack whose top [handleBack] would take away with the default pop, which a back gesture previews; none when
318
+ * back would do anything else (hold, close a menu or a pane, a pop of its own) or nothing.
319
+ */
320
+ internal open fun stackPoppedByBack(): StackController? = null
321
+
268
322
  /** Starts the node's content (a native screen's view, a React screen's surface). */
269
323
  open fun start() = Unit
270
324
 
@@ -0,0 +1,73 @@
1
+ package dev.apexnative.navigation.views.animations
2
+
3
+ import android.animation.Animator
4
+ import android.animation.AnimatorListenerAdapter
5
+ import android.animation.AnimatorSet
6
+ import android.animation.ObjectAnimator
7
+ import android.view.View
8
+
9
+ /**
10
+ * A hardware layer on a view for the time of an animator that fades it. A view whose `alpha` is below 1 and whose
11
+ * rendering overlaps (any `ViewGroup` by default) is drawn into an offscreen buffer at every frame; through a layer it
12
+ * is drawn once and the GPU only composites it. The layer is taken as the animator starts and only from
13
+ * `LAYER_TYPE_NONE` (a layer someone else set stays theirs), and given back as it ends or is cancelled. A pure
14
+ * translation or scale needs none: RenderThread draws it. The stack's default transition has its own
15
+ * (`StackViews.dress`). Main thread only.
16
+ */
17
+ internal object AnimationLayer {
18
+ private const val ALPHA = "alpha"
19
+
20
+ /**
21
+ * [view] draws through a hardware layer while [animator] plays, when [animator] changes the `alpha` of [view] and
22
+ * the view's rendering overlaps; [animator] itself, for chaining.
23
+ */
24
+ fun during(view: View, animator: Animator): Animator {
25
+ if (!changesAlpha(animator, view)) return animator
26
+ val hold = Hold({ view.layerType }, { view.setLayerType(it, null) })
27
+ animator.addListener(object : AnimatorListenerAdapter() {
28
+ override fun onAnimationStart(animation: Animator) {
29
+ hold.take(changesAlpha = true, overlapping = view.hasOverlappingRendering())
30
+ }
31
+
32
+ override fun onAnimationCancel(animation: Animator) = hold.release()
33
+
34
+ override fun onAnimationEnd(animation: Animator) = hold.release()
35
+ })
36
+ return animator
37
+ }
38
+
39
+ /** Whether an animation takes a layer: it fades, its view's rendering overlaps, and the view has no layer. */
40
+ fun takes(changesAlpha: Boolean, overlapping: Boolean, layerType: Int): Boolean =
41
+ changesAlpha && overlapping && layerType == View.LAYER_TYPE_NONE
42
+
43
+ /**
44
+ * The layer one animation took on one view, through [layerType] and [setLayerType]: taken at most once at a time,
45
+ * given back once, and only while it is still the hardware layer it set.
46
+ */
47
+ class Hold(private val layerType: () -> Int, private val setLayerType: (Int) -> Unit) {
48
+ /** Whether the animation holds the view's layer now. */
49
+ var isTaken = false
50
+ private set
51
+
52
+ /** The animation starts: the layer, when [takes] says so. */
53
+ fun take(changesAlpha: Boolean, overlapping: Boolean) {
54
+ if (isTaken || !takes(changesAlpha, overlapping, layerType())) return
55
+ setLayerType(View.LAYER_TYPE_HARDWARE)
56
+ isTaken = true
57
+ }
58
+
59
+ /** The animation ended or stopped: the layer goes, unless someone changed it meanwhile. */
60
+ fun release() {
61
+ if (!isTaken) return
62
+ isTaken = false
63
+ if (layerType() == View.LAYER_TYPE_HARDWARE) setLayerType(View.LAYER_TYPE_NONE)
64
+ }
65
+ }
66
+
67
+ // Whether [animator], or an animator in it, writes the alpha of [view].
68
+ private fun changesAlpha(animator: Animator, view: View): Boolean = when (animator) {
69
+ is AnimatorSet -> animator.childAnimations.any { changesAlpha(it, view) }
70
+ is ObjectAnimator -> animator.target === view && animator.values.orEmpty().any { it.propertyName == ALPHA }
71
+ else -> false
72
+ }
73
+ }
@@ -96,6 +96,9 @@ internal object Curves {
96
96
  * linear between them — the values of AndroidX's `FastOutSlowInInterpolator`, computed here.
97
97
  */
98
98
  object FastOutSlowIn : Curve() {
99
+ // Before the table, which is made from it.
100
+ private val curve = CubicBezier(0.4, 0.0, 0.2, 1.0)
101
+
99
102
  /** The 201 values. */
100
103
  val table: DoubleArray = DoubleArray(TABLE_STEPS + 1) {
101
104
  round(bezierAt(it.toDouble() / TABLE_STEPS) * DECIMALS) / DECIMALS
@@ -109,7 +112,25 @@ internal object Curves {
109
112
  }
110
113
 
111
114
  /** y of the Bézier at its x = [x], exactly (to 1e-12). */
112
- fun bezierAt(x: Double): Double {
115
+ fun bezierAt(x: Double): Double = curve.yAt(x)
116
+
117
+ private const val DECIMALS = 1e4
118
+ }
119
+
120
+ /**
121
+ * A cubic Bézier from (0, 0) to (1, 1) with the control points ([x1], [y1]) and ([x2], [y2]), as the framework's
122
+ * `PathInterpolator` draws it, computed exactly: the system's curves without a framework class.
123
+ */
124
+ class CubicBezier(
125
+ private val x1: Double,
126
+ private val y1: Double,
127
+ private val x2: Double,
128
+ private val y2: Double,
129
+ ) : Curve() {
130
+ override fun at(p: Double): Double = yAt(p)
131
+
132
+ /** y of the curve at its x = [x], exactly (to 1e-12). */
133
+ fun yAt(x: Double): Double {
113
134
  if (x <= 0.0) return 0.0
114
135
  if (x >= 1.0) return 1.0
115
136
  // x(t) only grows with t: a bisection finds t, then y(t).
@@ -118,23 +139,20 @@ internal object Curves {
118
139
  var t = x
119
140
  repeat(BISECTION_STEPS) {
120
141
  t = (low + high) / 2
121
- if (bezier(t, X1, X2) < x) low = t else high = t
142
+ if (coordinate(t, x1, x2) < x) low = t else high = t
122
143
  }
123
- return bezier(t, Y1, Y2)
144
+ return coordinate(t, y1, y2)
124
145
  }
125
146
 
126
- // One coordinate of the curve from (0, 0) to (1, 1) with the control points' coordinates [c1], [c2].
127
- private fun bezier(t: Double, c1: Double, c2: Double): Double {
147
+ // One coordinate of the curve with the control points' coordinates [c1], [c2].
148
+ private fun coordinate(t: Double, c1: Double, c2: Double): Double {
128
149
  val u = 1 - t
129
150
  return 3 * u * u * t * c1 + 3 * u * t * t * c2 + t * t * t
130
151
  }
131
152
 
132
- private const val X1 = 0.4
133
- private const val Y1 = 0.0
134
- private const val X2 = 0.2
135
- private const val Y2 = 1.0
136
- private const val BISECTION_STEPS = 60
137
- private const val DECIMALS = 1e4
153
+ private companion object {
154
+ const val BISECTION_STEPS = 60
155
+ }
138
156
  }
139
157
 
140
158
  /**
@@ -18,6 +18,18 @@ internal object ValueInterpolation {
18
18
  else -> from + fraction * (to - from)
19
19
  }
20
20
 
21
+ /**
22
+ * An angle in degrees at [fraction] of the way along the shorter arc, as iOS turns a shared element: 0 → 270 turns
23
+ * back by 90, 170 → −170 turns on by 20; half a turn goes on. At the end of the time exactly [to].
24
+ */
25
+ fun angle(from: Float, to: Float, fraction: Float, time: Float = fraction): Float {
26
+ if (time <= 0f) return from
27
+ if (time >= 1f) return to
28
+ val forward = ((to - from) % FULL_TURN + FULL_TURN) % FULL_TURN
29
+ val turn = if (forward > HALF_TURN) forward - FULL_TURN else forward
30
+ return from + fraction * turn
31
+ }
32
+
21
33
  /**
22
34
  * A color (an sRGB color int, as React Native keeps a background; none is transparent) at [fraction] of the way
23
35
  * from [from] to [to]: L, a and b in Lab (D65), the alpha linear, the result rounded; at the end of the time
@@ -90,4 +102,6 @@ internal object ValueInterpolation {
90
102
  private const val WHITE_Z = 108.883
91
103
  private const val EPSILON = 0.008856
92
104
  private const val KAPPA = 903.3
105
+ private const val FULL_TURN = 360f
106
+ private const val HALF_TURN = 180f
93
107
  }
@@ -98,8 +98,8 @@ class BottomTabs(context: Context) : BottomNavigationView(MaterialTheme.context(
98
98
  var iconInactiveColor: Int? = null
99
99
  var titleActiveColor: Int? = null
100
100
  var titleInactiveColor: Int? = null
101
- var iconWidth: Int? = null
102
- var iconHeight: Int? = null
101
+ var iconWidth: Double? = null
102
+ var iconHeight: Double? = null
103
103
  var typeface: Typeface? = null
104
104
  var activeTextSize: Float? = null
105
105
  var inactiveTextSize: Float? = null
@@ -228,13 +228,15 @@ class BottomTabs(context: Context) : BottomNavigationView(MaterialTheme.context(
228
228
  applyLongPressesAgain()
229
229
  }
230
230
 
231
- fun setIcon(index: Int, icon: Drawable) {
231
+ /** Null: the item has no icon. */
232
+ fun setIcon(index: Int, icon: Drawable?) {
232
233
  val item = items.getOrNull(index) ?: return
233
234
  if (item.icon == icon) return
234
235
  updateIcon(index, item.copy(icon = icon))
235
236
  }
236
237
 
237
- fun setSelectedIcon(index: Int, icon: Drawable) {
238
+ /** Null: the item shows its icon when selected too. */
239
+ fun setSelectedIcon(index: Int, icon: Drawable?) {
238
240
  val item = items.getOrNull(index) ?: return
239
241
  if (item.selectedIcon == icon) return
240
242
  updateIcon(index, item.copy(selectedIcon = icon))
@@ -246,9 +248,9 @@ class BottomTabs(context: Context) : BottomNavigationView(MaterialTheme.context(
246
248
 
247
249
  fun setTabTestId(index: Int, testId: String?) = updateStyle(index) { it.testId = testId }
248
250
 
249
- fun setIconWidth(index: Int, width: Int?) = updateStyle(index) { it.iconWidth = width }
251
+ fun setIconWidth(index: Int, width: Double?) = updateStyle(index) { it.iconWidth = width }
250
252
 
251
- fun setIconHeight(index: Int, height: Int?) = updateStyle(index) { it.iconHeight = height }
253
+ fun setIconHeight(index: Int, height: Double?) = updateStyle(index) { it.iconHeight = height }
252
254
 
253
255
  fun setTitleTypeface(index: Int, typeface: Typeface?) = updateStyle(index) { it.typeface = typeface }
254
256
 
@@ -475,7 +477,7 @@ class BottomTabs(context: Context) : BottomNavigationView(MaterialTheme.context(
475
477
  view.setIconTintList(tint(style.iconActiveColor, style.iconInactiveColor, itemIconTintList))
476
478
  view.setTextColor(tint(style.titleActiveColor, style.titleInactiveColor, itemTextColor))
477
479
  val iconSize = style.iconWidth ?: style.iconHeight
478
- view.setIconSize(if (iconSize != null) UiUtils.dpToPx(context, iconSize) else itemIconSize)
480
+ view.setIconSize(if (iconSize != null) UiUtils.dpToPixels(context, iconSize) else itemIconSize)
479
481
  view.findViewById<TextView>(MaterialR.id.navigation_bar_item_small_label_view)?.let {
480
482
  style.typeface?.let { typeface -> it.typeface = typeface }
481
483
  style.inactiveTextSize?.let { size -> it.setTextSize(TypedValue.COMPLEX_UNIT_SP, size) }
@@ -10,13 +10,15 @@ import androidx.annotation.RestrictTo
10
10
  import androidx.core.view.ViewCompat
11
11
  import androidx.core.view.WindowInsetsCompat
12
12
  import dev.apexnative.navigation.utils.MaterialTheme
13
+ import dev.apexnative.navigation.viewcontrollers.bottomtabs.CustomTabRowGeometry
13
14
 
14
15
  /**
15
16
  * The view of bottom tabs: the view of each tab made so far fills it, the selected one visible and the others invisible
16
17
  * but laid out, so a switch shows a tab at once and its screens render; the bar's [container] lies over them at the
17
18
  * bottom, the module's bar ([bar], `R.id.bottomTabs`) in it. The container's distance from the bottom ([barOffset]:
18
19
  * `bottomMargin`, and the navigation bar under a compact bar) is this view's own inset, not a layout parameter a root
19
- * may ignore. The window insets go on to every child as they came. Main thread only.
20
+ * may ignore. The custom [row], when the tabs have one, lies right after the container and over the bar. The window
21
+ * insets go on to every child as they came. Main thread only.
20
22
  */
21
23
  @SuppressLint("ViewConstructor")
22
24
  @RestrictTo(RestrictTo.Scope.LIBRARY)
@@ -34,8 +36,25 @@ class BottomTabsLayout(context: Context) : FrameLayout(context) {
34
36
  /** The window insets reached this view: the bar's room and the screens' room may have changed. */
35
37
  internal var onInsets: (() -> Unit)? = null
36
38
 
37
- /** The custom row of the tabs, when every tab draws its cell (`bottomTab.component`); the placer puts it. */
39
+ /**
40
+ * The custom row of the tabs, when every tab draws its cell (`bottomTab.component`): a child right after the
41
+ * container, laid out over the bar, going with the container.
42
+ */
38
43
  internal var row: CustomTabRow? = null
44
+ set(value) {
45
+ if (field === value) return
46
+ field?.let {
47
+ removeView(it)
48
+ it.container = null
49
+ }
50
+ field = value
51
+ if (value == null) return
52
+ (value.parent as? ViewGroup)?.removeView(value)
53
+ value.container = container
54
+ value.place = null
55
+ // Its frame is absolute: the layout below puts it in its parameters.
56
+ addView(value, indexOfChild(container) + 1, LayoutParams(0, 0, Gravity.TOP or Gravity.LEFT))
57
+ }
39
58
 
40
59
  /** The container's distance from the bottom, in pixels. */
41
60
  internal var barOffset = 0
@@ -59,6 +78,16 @@ class BottomTabsLayout(context: Context) : FrameLayout(context) {
59
78
  }
60
79
  }
61
80
 
81
+ /**
82
+ * How far the container goes down to leave the screen whole: from the top of what the bar shows — the container, or
83
+ * the custom row that rises above it — to this view's bottom, in pixels.
84
+ */
85
+ internal val hideDistance: Int
86
+ get() {
87
+ val rowTop = row?.takeIf { it.visibility != View.GONE }?.top ?: container.top
88
+ return (height - minOf(container.top, rowTop)).coerceAtLeast(0)
89
+ }
90
+
62
91
  /** [view] of a tab joins under the bar, invisible until its tab shows. */
63
92
  internal fun addTab(view: View) {
64
93
  if (view.parent === this) return
@@ -85,5 +114,35 @@ class BottomTabsLayout(context: Context) : FrameLayout(context) {
85
114
  override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
86
115
  super.onLayout(changed, left, top, right, bottom)
87
116
  if (barOffset != 0) container.offsetTopAndBottom(-barOffset)
117
+ row?.let(::placeRow)
118
+ }
119
+
120
+ // The row over the bar where the bar rests (its container's motion the row takes before each frame), when its place
121
+ // changed: laid out there at once, and kept in its parameters, so the next passes measure it and put it there the
122
+ // same way. A hidden bar keeps the row where it was.
123
+ private fun placeRow(row: CustomTabRow) {
124
+ if (container.visibility == View.GONE || bar.width == 0) return
125
+ val barLeft = container.left + bar.left
126
+ val barTop = container.top + bar.top
127
+ val place = row.placeOver(
128
+ barLeft = barLeft,
129
+ barRight = barLeft + bar.width,
130
+ barBottom = barTop + bar.height,
131
+ barHeight = bar.height,
132
+ tabsHeight = height,
133
+ navigationBar = navigationBarInset,
134
+ )
135
+ if (!CustomTabRowGeometry.needsPlacing(row.place, place)) return
136
+ row.place = place
137
+ val params = row.layoutParams as LayoutParams
138
+ params.width = place.right - place.left
139
+ params.height = place.bottom - place.top
140
+ params.leftMargin = place.left
141
+ params.topMargin = place.top
142
+ row.measure(
143
+ MeasureSpec.makeMeasureSpec(params.width, MeasureSpec.EXACTLY),
144
+ MeasureSpec.makeMeasureSpec(params.height, MeasureSpec.EXACTLY),
145
+ )
146
+ row.layout(place.left, place.top, place.right, place.bottom)
88
147
  }
89
148
  }
@@ -22,9 +22,6 @@ open class CustomBottomTabItemView(context: Context) : FrameLayout(context) {
22
22
  private var state: TabCellState? = null
23
23
  private var destroyed = false
24
24
 
25
- /** Runs once as the cell stops: what was kept for its content's id goes. */
26
- internal var onDestroyed: (() -> Unit)? = null
27
-
28
25
  /** The content the cell shows, filling it, made with [state] as its first props. */
29
26
  internal fun show(view: IReactView, state: TabCellState) {
30
27
  content = view
@@ -68,8 +65,6 @@ open class CustomBottomTabItemView(context: Context) : FrameLayout(context) {
68
65
  didDisappear()
69
66
  destroyed = true
70
67
  content?.destroy()
71
- onDestroyed?.invoke()
72
- onDestroyed = null
73
68
  }
74
69
 
75
70
  /** The props of [state] as React Native takes them. */
@@ -11,18 +11,21 @@ import android.view.MotionEvent
11
11
  import android.view.View
12
12
  import android.view.ViewGroup
13
13
  import android.view.ViewOutlineProvider
14
+ import android.view.ViewTreeObserver
14
15
  import android.widget.FrameLayout
15
16
  import android.widget.LinearLayout
16
17
  import dev.apexnative.navigation.customrow.BottomTabsCustomRowOptions
17
18
  import dev.apexnative.navigation.utils.TestIds
19
+ import dev.apexnative.navigation.utils.UiUtils
18
20
  import dev.apexnative.navigation.viewcontrollers.bottomtabs.CustomTabRowGeometry
19
21
 
20
22
  /**
21
- * The custom row of bottom tabs on Android (`bottomTabs.customRow`): a container over the bar, in the window's content,
22
- * that holds the tabs' cells in one row of equal widths in tab order. It owns its place, its look, its visibility and
23
- * the touches: each cell's place takes them, the React elements in the cell don't, and a tap or a long press of a place
24
- * goes to [onPress] or [onLongPress] with the tab's index. Where it lies is the placer's to say (`CustomTabRowPlacer`);
25
- * what it looks like its tabs'. Main thread only.
23
+ * The custom row of bottom tabs on Android (`bottomTabs.customRow`): a container over the bar, a child of the tabs'
24
+ * view right after the bar's container, that holds the tabs' cells in one row of equal widths in tab order. It owns its
25
+ * look, its visibility and the touches: each cell's place takes them, the React elements in the cell don't, and a tap
26
+ * or a long press of a place goes to [onPress] or [onLongPress] with the tab's index. The tabs' view lays it out over
27
+ * the bar ([placeOver]); before each frame it goes with the bar's [container]. What it looks like is its tabs'. Main
28
+ * thread only.
26
29
  */
27
30
  @SuppressLint("ViewConstructor")
28
31
  internal class CustomTabRow(context: Context) : FrameLayout(context) {
@@ -42,11 +45,23 @@ internal class CustomTabRow(context: Context) : FrameLayout(context) {
42
45
  /** A cell's place was long-pressed. */
43
46
  var onLongPress: ((Int) -> Unit)? = null
44
47
 
45
- /** `bottomTabs.customRow` of the tabs, resolved: the placer reads its height and margins. */
48
+ /** `bottomTabs.customRow` of the tabs, resolved: its height and margins say where the row lies. */
46
49
  var options = BottomTabsCustomRowOptions()
47
50
 
48
51
  /**
49
- * Where the placer put the row last, in its parent; none before it did. The frame holds `bottomMargin` below the
52
+ * The bar's container the row goes with: its motion (a ride, a slide, the hide on scroll), its alpha, its height
53
+ * over the screens and whether it shows. The tabs' view sets it as the row joins it.
54
+ */
55
+ var container: View? = null
56
+
57
+ // Before each frame of the window the row is in: it goes with the container.
58
+ private val following = ViewTreeObserver.OnPreDrawListener {
59
+ container?.let(::follow)
60
+ true
61
+ }
62
+
63
+ /**
64
+ * Where the tabs' view put the row last, in it; none before it did. The frame holds `bottomMargin` below the
50
65
  * content: the row draws, clips, casts its shadow, lays its cells and takes touches only over the content, and the
51
66
  * margin below lets the touches through to what is under it.
52
67
  */
@@ -117,10 +132,57 @@ internal class CustomTabRow(context: Context) : FrameLayout(context) {
117
132
  return super.dispatchTouchEvent(event)
118
133
  }
119
134
 
120
- /** Whether the row shows its cells: it hides with the bar. */
121
- fun showWith(bar: View) {
122
- val wanted = if (bar.visibility != View.GONE) View.VISIBLE else View.GONE
135
+ /**
136
+ * Where the row lies over the bar whose edges are [barLeft], [barRight] and [barBottom] and whose height is
137
+ * [barHeight], in the tabs' view of [tabsHeight] with the navigation bar's [navigationBar] at its bottom: its
138
+ * height and margins from [options].
139
+ */
140
+ fun placeOver(barLeft: Int, barRight: Int, barBottom: Int, barHeight: Int, tabsHeight: Int, navigationBar: Int) =
141
+ CustomTabRowGeometry.inTabs(
142
+ barLeft = barLeft,
143
+ barRight = barRight,
144
+ barBottom = barBottom,
145
+ tabsHeight = tabsHeight,
146
+ navigationBar = navigationBar,
147
+ margin = UiUtils.dpToPixels(
148
+ context,
149
+ options.horizontalMargin.get(CustomTabRowGeometry.HORIZONTAL_MARGIN_DP.toDouble()),
150
+ ),
151
+ content = CustomTabRowGeometry.content(
152
+ barHeight = barHeight,
153
+ height = options.height.get(null)?.let { UiUtils.dpToPixels(context, it) },
154
+ extra = UiUtils.dpToPixels(context, CustomTabRowGeometry.EXTRA_HEIGHT_DP.toDouble()),
155
+ ),
156
+ bottomMargin = UiUtils.dpToPixels(context, options.bottomMargin.get(0.0)),
157
+ )
158
+
159
+ override fun onAttachedToWindow() {
160
+ super.onAttachedToWindow()
161
+ viewTreeObserver.addOnPreDrawListener(following)
162
+ }
163
+
164
+ override fun onDetachedFromWindow() {
165
+ viewTreeObserver.removeOnPreDrawListener(following)
166
+ super.onDetachedFromWindow()
167
+ }
168
+
169
+ // The row hides with the bar and takes its motion and its alpha (the tabs' own alpha and motion, and their
170
+ // parents', the row has as their child); it stands as high as the container, and leaves accessibility while its
171
+ // tabs wait to show.
172
+ private fun follow(container: View) {
173
+ val wanted = if (container.visibility != View.GONE) View.VISIBLE else View.GONE
123
174
  if (visibility != wanted) visibility = wanted
175
+ if (alpha != container.alpha) alpha = container.alpha
176
+ if (translationX != container.translationX) translationX = container.translationX
177
+ if (translationY != container.translationY) translationY = container.translationY
178
+ val lift = CustomTabRowGeometry.lift(container.z, elevation)
179
+ if (translationZ != lift) translationZ = lift
180
+ val mode = if (hiddenFromAccessibility()) {
181
+ View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
182
+ } else {
183
+ View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
184
+ }
185
+ if (importantForAccessibility != mode) importantForAccessibility = mode
124
186
  }
125
187
 
126
188
  /** Draws [look]; nothing changes when it is the one drawn. */
@@ -0,0 +1,31 @@
1
+ package dev.apexnative.navigation.views.element
2
+
3
+ import dev.apexnative.navigation.utils.DevelopmentLog
4
+
5
+ /**
6
+ * The isolation of every element of the transitions: [work], a step of the element named [element] (its `nativeID` in
7
+ * quotes, or a pair's two), runs; an exception in it skips that element only — one line in the log
8
+ * ([elementSkipped]), and false — while the rest of the transition plays and its command completes.
9
+ */
10
+ internal inline fun elementStep(
11
+ element: String,
12
+ noinline log: (String) -> Unit = DevelopmentLog::warn,
13
+ work: () -> Unit,
14
+ ): Boolean = try {
15
+ work()
16
+ true
17
+ } catch (e: Exception) {
18
+ elementSkipped(element, e.toString(), log)
19
+ false
20
+ }
21
+
22
+ /** The line in the log for the element named [element], skipped for [reason]: it shows and hides with its screen. */
23
+ internal fun elementSkipped(element: String, reason: String, log: (String) -> Unit = DevelopmentLog::warn) =
24
+ log("[ApexNavigation] the transition's element $element is skipped, it shows and hides with its screen while the " +
25
+ "rest plays: $reason")
26
+
27
+ /** The name of an element in the log. */
28
+ internal fun elementName(nativeId: String) = "'$nativeId'"
29
+
30
+ /** The name of a shared pair in the log. */
31
+ internal fun pairName(fromId: String, toId: String) = "'$fromId' -> '$toId'"