@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
@@ -3,37 +3,33 @@ package dev.apexnative.navigation.react
3
3
  import android.app.Activity
4
4
  import android.graphics.Rect
5
5
  import androidx.core.view.WindowInsetsCompat
6
- import com.facebook.react.ReactApplication
7
- import com.facebook.react.bridge.Arguments
8
- import com.facebook.react.bridge.WritableArray
9
- import com.facebook.react.bridge.WritableMap
6
+ import dev.apexnative.navigation.react.ScreenEnvironment.Region
7
+ import dev.apexnative.navigation.react.ScreenEnvironment.Regions
10
8
  import dev.apexnative.navigation.react.events.EventEmitter
11
9
  import dev.apexnative.navigation.utils.WindowFolds
12
- import java.util.concurrent.ConcurrentHashMap
13
10
 
14
11
  /**
15
- * The reserved regions of each screen (`useReservedRegions`), in dp from the top left of its content: where it divides
16
- * (a fold the window is divided at, `division`) and where hardware covers it (a fold that hides what is under it, the
17
- * camera cutout: `occlusion`). Only those on the screen, cut to it: a fold at the edge of a screen of a pair is not on
18
- * it. Measured on the main thread as each screen lays out, and again after a change of the window's folds (which lays
19
- * the window out); JavaScript reads them from its own thread for a screen's first render, and gets every change as
20
- * `ANN.ScreenRegionsChanged`.
12
+ * Measures the reserved regions of each screen (`useReservedRegions`), in dp from the top left of its content: where
13
+ * it divides (a fold the window is divided at, `division`) and where hardware covers it (a fold that hides what is
14
+ * under it, the camera cutout: `occlusion`). Only those on the screen, cut to it: a fold at the edge of a screen of a
15
+ * pair is not on it. Measured on the main thread as each screen lays out, and again after a change of the window's
16
+ * folds (which lays the window out); [ScreenEnvironment] keeps them, answers JavaScript's reads and tells it of every
17
+ * change as `ANN.ScreenRegionsChanged`.
21
18
  */
22
19
  internal object ScreenRegions {
23
- data class Region(val x: Double, val y: Double, val width: Double, val height: Double)
24
-
25
- data class Regions(val division: List<Region>, val occlusion: List<Region>) {
26
- val isEmpty: Boolean get() = division.isEmpty() && occlusion.isEmpty()
27
- }
28
-
29
- private val NONE = Regions(emptyList(), emptyList())
30
- private val regions = ConcurrentHashMap<String, Regions>()
31
-
32
20
  /**
33
21
  * Measures the regions of the screen whose content the layout puts at [content] in the window (pixels), with the
34
- * window's [insets] (the camera cutout), and tells JavaScript when they changed. Main thread only.
22
+ * window's [insets] (the camera cutout), and keeps them in [ScreenEnvironment], which tells JavaScript when they
23
+ * changed through [emitter], the one of the JavaScript the screen was made for: silent once it went. Main thread
24
+ * only.
35
25
  */
36
- fun update(activity: Activity, screenId: String, content: Rect, insets: WindowInsetsCompat?) {
26
+ fun update(
27
+ activity: Activity,
28
+ screenId: String,
29
+ content: Rect,
30
+ insets: WindowInsetsCompat?,
31
+ emitter: EventEmitter,
32
+ ) {
37
33
  val folds = WindowFolds.of(activity)?.folds.orEmpty()
38
34
  val cutouts = insets?.displayCutout?.boundingRects.orEmpty()
39
35
  val density = activity.resources.displayMetrics.density
@@ -42,18 +38,7 @@ internal object ScreenRegions {
42
38
  occlusion = (folds.filter { it.occludes }.map { it.bounds } + cutouts)
43
39
  .mapNotNull { onScreen(it, content, density) },
44
40
  )
45
- val previous = regions.put(screenId, value)
46
- // None at first is what JavaScript reads before the first layout.
47
- if (previous == value || (previous == null && value.isEmpty)) return
48
- val reactContext = (activity.application as? ReactApplication)?.reactHost?.currentReactContext ?: return
49
- EventEmitter(reactContext).emitScreenRegionsChanged(screenId, toMap(value))
50
- }
51
-
52
- /** `{ division, occlusion }`, empty lists for an unknown screen and before its first layout. Any thread. */
53
- fun get(screenId: String): WritableMap = toMap(regions[screenId] ?: NONE)
54
-
55
- fun remove(screenId: String) {
56
- regions.remove(screenId)
41
+ ScreenEnvironment.setRegions(screenId, value, ScreenEnvironment.changesOf(emitter))
57
42
  }
58
43
 
59
44
  // The part of [bounds] (window pixels) on the screen, in dp from its top left; null off it. A fold without width
@@ -68,20 +53,4 @@ internal object ScreenRegions {
68
53
  height = part.height() / density.toDouble(),
69
54
  )
70
55
  }
71
-
72
- private fun toMap(value: Regions): WritableMap = Arguments.createMap().apply {
73
- putArray("division", toArray(value.division))
74
- putArray("occlusion", toArray(value.occlusion))
75
- }
76
-
77
- private fun toArray(regions: List<Region>): WritableArray = Arguments.createArray().apply {
78
- for (region in regions) {
79
- pushMap(Arguments.createMap().apply {
80
- putDouble("x", region.x)
81
- putDouble("y", region.y)
82
- putDouble("width", region.width)
83
- putDouble("height", region.height)
84
- })
85
- }
86
- }
87
56
  }
@@ -1,25 +1,17 @@
1
1
  package dev.apexnative.navigation.react
2
2
 
3
- import android.content.Context
4
- import android.util.Log
5
- import com.facebook.react.ReactApplication
6
- import com.facebook.react.uimanager.UIManagerHelper
7
- import com.facebook.react.uimanager.events.Event
8
- import com.facebook.react.uimanager.events.EventDispatcherListener
9
- import com.facebook.react.views.scroll.ScrollEvent
3
+ import android.view.ViewGroup
4
+ import android.widget.HorizontalScrollView
5
+ import com.facebook.react.views.scroll.ReactScrollViewHelper
10
6
  import com.facebook.react.views.scroll.ScrollEventType
11
- import dev.apexnative.navigation.utils.NavigationLog
12
- import dev.apexnative.navigation.utils.UiThread
13
- import dev.apexnative.navigation.viewcontrollers.viewcontroller.ScrollEventListener
14
- import java.lang.reflect.Field
15
- import java.util.Collections
16
- import java.util.WeakHashMap
17
7
 
18
8
  /**
19
- * The scroll events of React Native's lists, as the screens' scroll listeners hear them: from the event dispatcher of
20
- * the running React Native, every list of the app. React Native keeps the offset, the speed and the kind of a scroll
21
- * event in private fields: they are looked up once, with their types; if React Native renames them, one warning goes to
22
- * the log and the screens hear no scroll, with no error at each event.
9
+ * The scroll events of React Native's scroll views, as the screens' scroll listeners hear them: through React Native's
10
+ * public scroll listener ([ReactScrollViewHelper.addScrollListener]), which every `ReactScrollView`,
11
+ * `ReactHorizontalScrollView` and `ReactNestedScrollView` of the process calls on the main thread just before it
12
+ * dispatches the same event to JavaScript, after the same throttle. One listener serves every screen and every React
13
+ * context; it is added while a screen listens and removed when the last one stops. Horizontal scroll views are left
14
+ * out: a pager or a carousel doesn't move the bars. Main thread only.
23
15
  */
24
16
  internal object ScrollEvents {
25
17
  /** What a scroll event is. */
@@ -28,133 +20,62 @@ internal object ScrollEvents {
28
20
  /** One scroll event: the list's tag (its view's id), its kind, its vertical offset and speed, in pixels. */
29
21
  class Reading(val viewTag: Int, val kind: Kind, val offsetY: Float, val velocityY: Float)
30
22
 
31
- private class Fields(val type: Field, val offsetY: Field, val velocityY: Field)
23
+ // One screen's listening: its own object, so that a stop takes away that listening and no other.
24
+ private class Listening(val handler: (Reading) -> Unit)
32
25
 
33
- private var fields: Fields? = null
34
- private var lookedUp = false
26
+ // The screens' listenings, in the order they came.
27
+ private val listenings = mutableListOf<Listening>()
35
28
 
36
- // The screens' listeners that found no event dispatcher, held weakly until React Native has one. Main thread.
37
- private val waiting: MutableSet<ScrollEventListener> = Collections.newSetFromMap(WeakHashMap())
29
+ // React Native holds its scroll listeners weakly: this object keeps the one it added for as long as it is added.
30
+ private val listener = object : ReactScrollViewHelper.ScrollListener {
31
+ override fun onScroll(
32
+ scrollView: ViewGroup?,
33
+ scrollEventType: ScrollEventType?,
34
+ xVelocity: Float,
35
+ yVelocity: Float,
36
+ ) = hear(scrollView, scrollEventType, yVelocity)
38
37
 
39
- /** [listener] found no event dispatcher: it is asked to listen again once React Native has one. */
40
- fun waitForDispatcher(listener: ScrollEventListener) {
41
- waiting += listener
42
- }
43
-
44
- /** A React context is ready (`ReloadCoordinator`): the listeners waiting for an event dispatcher listen now. */
45
- fun dispatcherReady() {
46
- val listeners = waiting.toList()
47
- waiting.clear()
48
- listeners.forEach(ScrollEventListener::attachIfNeeded)
38
+ override fun onLayout(scrollView: ViewGroup?) = Unit
49
39
  }
50
40
 
51
41
  /**
52
- * Calls [handler] on the main thread with each scroll event of the app's React Native, until the function returned
53
- * is called. None when React Native has no event dispatcher now (around a reload, the caller asks again later) or
54
- * its scroll events can't be read.
42
+ * Calls [handler] with each scroll event of a vertical scroll view of the app, until the function returned is
43
+ * called.
55
44
  */
56
- fun listen(context: Context, handler: (Reading) -> Unit): (() -> Unit)? {
57
- if (fields() == null) return null
58
- val reactContext = (context.applicationContext as? ReactApplication)?.reactHost?.currentReactContext
59
- ?: return null
60
- val dispatcher = try {
61
- UIManagerHelper.getEventDispatcher(reactContext)
62
- } catch (e: RuntimeException) {
63
- null
64
- } ?: return null
65
- val listener = EventDispatcherListener { event ->
66
- // The event goes back to its pool after the dispatch: it is read now, on the thread that dispatches.
67
- val reading = read(event) ?: return@EventDispatcherListener
68
- if (UiThread.isMainThread()) handler(reading) else UiThread.post { handler(reading) }
45
+ fun listen(handler: (Reading) -> Unit): () -> Unit {
46
+ val listening = Listening(handler)
47
+ if (listenings.isEmpty()) ReactScrollViewHelper.addScrollListener(listener)
48
+ listenings += listening
49
+ return {
50
+ // By identity: the second call of a stop finds nothing to take away.
51
+ if (listenings.removeAll { it === listening } && listenings.isEmpty()) {
52
+ ReactScrollViewHelper.removeScrollListener(listener)
53
+ }
69
54
  }
70
- dispatcher.addListener(listener)
71
- return { dispatcher.removeListener(listener) }
72
55
  }
73
56
 
74
- private fun read(event: Event<*>): Reading? {
75
- if (event !is ScrollEvent) return null
76
- val fields = fields() ?: return null
77
- return try {
78
- val type = fields.type.get(event) as? ScrollEventType ?: return null
79
- val offsetY = readFloat(fields.offsetY, event) ?: return null
80
- val velocityY = readFloat(fields.velocityY, event) ?: return null
81
- Reading(event.viewTag, kindOf(type), offsetY, velocityY)
82
- } catch (e: ReflectiveOperationException) {
83
- null
84
- } catch (e: IllegalArgumentException) {
85
- null
86
- }
57
+ /** One call of React Native's listener: the handlers listening now hear its reading, if it has one. */
58
+ fun hear(scrollView: ViewGroup?, type: ScrollEventType?, velocityY: Float) {
59
+ val reading = read(scrollView, type, velocityY) ?: return
60
+ listenings.toList().forEach { it.handler(reading) }
87
61
  }
88
62
 
89
- private fun kindOf(type: ScrollEventType): Kind = when (type) {
63
+ /**
64
+ * The reading of one call of React Native's listener: none for a horizontal scroll view, or when React Native gives
65
+ * no view or no kind. The offset is the view's `scrollY` and the speed React Native's own, in pixels, as the event
66
+ * sent to JavaScript carries them before it converts them to dp.
67
+ */
68
+ fun read(scrollView: ViewGroup?, type: ScrollEventType?, velocityY: Float): Reading? {
69
+ if (scrollView == null || type == null || scrollView is HorizontalScrollView) return null
70
+ return Reading(scrollView.id, kindOf(type), scrollView.scrollY.toFloat(), velocityY)
71
+ }
72
+
73
+ /** The kind of a reading for React Native's [type]. */
74
+ fun kindOf(type: ScrollEventType): Kind = when (type) {
90
75
  ScrollEventType.BEGIN_DRAG -> Kind.BeginDrag
91
76
  ScrollEventType.END_DRAG -> Kind.EndDrag
92
77
  ScrollEventType.SCROLL -> Kind.Scroll
93
78
  ScrollEventType.MOMENTUM_BEGIN -> Kind.MomentumBegin
94
79
  ScrollEventType.MOMENTUM_END -> Kind.MomentumEnd
95
80
  }
96
-
97
- @Synchronized
98
- private fun fields(): Fields? {
99
- if (lookedUp) return fields
100
- lookedUp = true
101
- fields = try {
102
- val owner = ScrollEvent::class.java
103
- val type = declaredField(owner, TYPE_NAMES) { ScrollEventType::class.java.isAssignableFrom(it) }
104
- val offsetY = declaredField(owner, OFFSET_NAMES, ::isNumeric)
105
- val velocityY = declaredField(owner, VELOCITY_NAMES, ::isNumeric)
106
- if (type != null && offsetY != null && velocityY != null) Fields(type, offsetY, velocityY) else null
107
- } catch (e: ReflectiveOperationException) {
108
- null
109
- } catch (e: SecurityException) {
110
- null
111
- }
112
- if (fields == null) {
113
- Log.w(
114
- NavigationLog.TAG,
115
- "[ApexNavigation] React Native's scroll events changed: hideOnScroll and the large title " +
116
- "don't follow the scroll",
117
- )
118
- }
119
- return fields
120
- }
121
-
122
- // The names of the fields: React Native 0.87 first, then the earlier ones with the `m` prefix.
123
- private val TYPE_NAMES = listOf("scrollEventType", "mScrollEventType")
124
- private val OFFSET_NAMES = listOf("scrollY", "mScrollY")
125
- private val VELOCITY_NAMES = listOf("yVelocity", "mYVelocity")
126
-
127
- /**
128
- * The first of the fields [names] that [owner] declares with a type [accepted] takes, made readable; none when no
129
- * name fits. React Native renamed them and changed their types between versions.
130
- */
131
- fun declaredField(owner: Class<*>, names: List<String>, accepted: (Class<*>) -> Boolean): Field? {
132
- for (name in names) {
133
- val field = try {
134
- owner.getDeclaredField(name)
135
- } catch (e: NoSuchFieldException) {
136
- continue
137
- }
138
- if (!accepted(field.type)) continue
139
- field.isAccessible = true
140
- return field
141
- }
142
- return null
143
- }
144
-
145
- /** A number of any kind: a primitive one (`int`, `float`, `double`, …) or a boxed one. */
146
- fun isNumeric(type: Class<*>): Boolean =
147
- type in PRIMITIVE_NUMBERS || Number::class.java.isAssignableFrom(type)
148
-
149
- /** [field] of [target] as a float, whatever numeric type it has; none when it holds no number. */
150
- fun readFloat(field: Field, target: Any): Float? = (field.get(target) as? Number)?.toFloat()
151
-
152
- private val PRIMITIVE_NUMBERS = setOf<Class<*>?>(
153
- Byte::class.javaPrimitiveType,
154
- Short::class.javaPrimitiveType,
155
- Int::class.javaPrimitiveType,
156
- Long::class.javaPrimitiveType,
157
- Float::class.javaPrimitiveType,
158
- Double::class.javaPrimitiveType,
159
- )
160
81
  }
@@ -90,7 +90,7 @@ internal object AppearanceDispatcher {
90
90
  val appearanceRecord: ScreenAppearance?
91
91
  }
92
92
 
93
- /** The navigation state (`NavigationStateReporter`): one update in this pass of the main loop, or one now. */
93
+ /** The navigation state ([NavigationState]): one update in this pass of the main loop, or one now. */
94
94
  interface StateUpdates {
95
95
  /**
96
96
  * Asks for one update in this pass of the main loop: the calls of one pass make one, after a DidAppear or a
@@ -98,7 +98,10 @@ internal object AppearanceDispatcher {
98
98
  */
99
99
  fun setNeedsUpdate()
100
100
 
101
- /** Computes the state now and sends it when it changed: before an answer, at the end of a transition. */
101
+ /**
102
+ * Computes the state now and sends it when it changed: a command's answer, once
103
+ * (`CommandAnswer.reportStateNow`), the end of a user's transition, a tab chosen from code.
104
+ */
102
105
  fun updateNow()
103
106
 
104
107
  /**
@@ -157,33 +160,6 @@ internal object AppearanceDispatcher {
157
160
  EventEmitter.current().emitSheetDetentChanged(componentId, detent)
158
161
  }
159
162
 
160
- /** The state of `NavigationStateReporter`, sent through the JavaScript that runs now, when it can be. */
161
- object ReporterState : StateUpdates {
162
- private val handler by lazy { Handler(Looper.getMainLooper()) }
163
-
164
- // The one posted update of a pass of the main loop, which checks the hold when it runs.
165
- private val held = StateHold(
166
- post = { task -> handler.post(task) },
167
- generation = { ReloadCoordinator.generation },
168
- ) {
169
- val emitter = EventEmitter.current()
170
- if (emitter.canSend) NavigationStateReporter.updateNow(emitter)
171
- }
172
-
173
- override fun setNeedsUpdate() {
174
- if (EventEmitter.current().canSend) held.setNeedsUpdate()
175
- }
176
-
177
- override fun hold() = held.hold()
178
-
179
- override fun release() = held.release()
180
-
181
- override fun updateNow() {
182
- val emitter = EventEmitter.current()
183
- if (emitter.canSend) NavigationStateReporter.updateNow(emitter)
184
- }
185
- }
186
-
187
163
  /** The main thread's loop. */
188
164
  object MainScheduler : Scheduler {
189
165
  private val handler by lazy { Handler(Looper.getMainLooper()) }
@@ -198,8 +174,8 @@ internal object AppearanceDispatcher {
198
174
  /** Where the events go: [EmitterSender]; the tests put a journal here. */
199
175
  var sender: Sender = EmitterSender
200
176
 
201
- /** The navigation state the sent appearance events and transitions update: [ReporterState]; a journal in tests. */
202
- var state: StateUpdates = ReporterState
177
+ /** The navigation state the appearance events and transitions update: [NavigationState]; a journal in tests. */
178
+ var state: StateUpdates = NavigationState
203
179
 
204
180
  /** The clock of the hold limit: [MainScheduler]; the tests put a clock that moves when they say. */
205
181
  var scheduler: Scheduler = MainScheduler
@@ -210,43 +186,18 @@ internal object AppearanceDispatcher {
210
186
  // A transition whose caller sends the state itself ends: the DidDisappears it sends ask for no update.
211
187
  private var holdsState = false
212
188
 
213
- // A side menu's drawer jumps open: the appearances that start in it send no WillAppear.
214
- private var skipsWillAppear = false
215
-
216
189
  // The native screens that told JavaScript they went: once per node.
217
190
  private val released: MutableSet<ViewController<*>> = Collections.newSetFromMap(WeakHashMap())
218
191
 
219
192
  // Appearance of a record.
220
193
 
221
- /**
222
- * The record starts to appear: WillAppear, now when it is ready, else held. Only once per appearance; none inside
223
- * [withoutWillAppear].
224
- */
194
+ /** The record starts to appear: WillAppear, now when it is ready, else held. Only once per appearance. */
225
195
  fun willAppear(record: ScreenAppearance) {
226
196
  if (record.phase != Phase.Hidden) return
227
197
  record.phase = Phase.Appearing
228
- if (skipsWillAppear) {
229
- record.skippedWill = true
230
- return
231
- }
232
198
  if (record.isReady) send(record, Event.WillAppear) else hold(record, Event.WillAppear)
233
199
  }
234
200
 
235
- /**
236
- * Runs [block], in which the appearances that start send no WillAppear: their DidAppear is their first event, and
237
- * their DidDisappear goes only once that DidAppear went. A side menu's drawer that opens without animation does so
238
- * on Android; the screens' options and the components of their bars go as at any appearance.
239
- */
240
- fun withoutWillAppear(block: () -> Unit) {
241
- val outer = skipsWillAppear
242
- skipsWillAppear = true
243
- try {
244
- block()
245
- } finally {
246
- skipsWillAppear = outer
247
- }
248
- }
249
-
250
201
  /**
251
202
  * The record has appeared: DidAppear, after a WillAppear (asked now when it wasn't), now when nothing is held and
252
203
  * it is ready, else held behind what is held. Only once per appearance.
@@ -261,19 +212,12 @@ internal object AppearanceDispatcher {
261
212
  /**
262
213
  * The record has disappeared. Nothing when it didn't appear. When its WillAppear is still held, JavaScript never
263
214
  * heard it appear: what is held goes away and nothing is sent. Otherwise a held DidAppear goes away and
264
- * DidDisappear is sent: a swipe that was cancelled gives WillAppear, then DidDisappear. An appearance without its
265
- * WillAppear ([withoutWillAppear]) appeared once its DidAppear went.
215
+ * DidDisappear is sent: a swipe that was cancelled gives WillAppear, then DidDisappear.
266
216
  */
267
217
  fun didDisappear(record: ScreenAppearance) {
268
218
  if (record.phase == Phase.Hidden) return
269
- val wasShown = record.phase == Phase.Shown
270
219
  record.phase = Phase.Hidden
271
- val appeared = if (record.skippedWill) {
272
- wasShown && Event.DidAppear !in record.held
273
- } else {
274
- Event.WillAppear !in record.held
275
- }
276
- record.skippedWill = false
220
+ val appeared = Event.WillAppear !in record.held
277
221
  record.held.clear()
278
222
  cancelLimit(record)
279
223
  // What waited for its DidAppear goes now: none will be sent for this appearance.
@@ -369,12 +313,15 @@ internal object AppearanceDispatcher {
369
313
  }
370
314
 
371
315
  /**
372
- * A transition ended,: what went disappears ([hiding]), what stands appears ([showing], with its WillAppear first
316
+ * A transition ended: what went disappears ([hiding]), what stands appears ([showing], with its WillAppear first
373
317
  * where it wasn't asked), the navigation state goes when it changed, then [events] (the transition's own:
374
318
  * `ANN.ScreenPopped`, `ANN.ModalDismissed`, and what must follow them, like stopping the content of what went),
375
- * then [answer] resolves with [value] (the promise, then `ANN.CommandCompleted`). A user's action has no answer. A
376
- * state that fails is logged ([log]) and the transition goes on: [events] and the answer always come. Without
377
- * [reportsState] the caller sends the state itself, later (a tab switch: after `ANN.BottomTabSelected`).
319
+ * then [answer] resolves with [value] (the promise, then `ANN.CommandCompleted`; no second state). The state is the
320
+ * answer's one state step (`CommandAnswer.reportStateNow`), which sends nothing for a JavaScript that went; a
321
+ * user's action has no answer, and a command answered before its transition ended had its state then: the state
322
+ * of the end goes all the same, unless its JavaScript went. A state that fails is logged and the transition goes
323
+ * on: [events] and the answer always come. Without [reportsState] the caller sends the state itself, later (a tab
324
+ * switch: after `ANN.BottomTabSelected`; a `setRoot` with layers: from its answer).
378
325
  */
379
326
  fun endTransition(
380
327
  hiding: List<ViewController<*>>,
@@ -392,18 +339,30 @@ internal object AppearanceDispatcher {
392
339
  holdsState = false
393
340
  }
394
341
  showing.forEach { it.onViewDidAppear() }
395
- if (reportsState) reportState(answer?.commandName)
342
+ if (reportsState) {
343
+ // The state before the transition's events, once per answer: the answer's own step before its promise
344
+ // finds it sent. Without an answer to wait for, the dispatcher sends it; nothing for a JavaScript that
345
+ // went.
346
+ when {
347
+ answer == null -> reportState()
348
+ answer.isAnswered -> if (ReloadCoordinator.isCurrent(answer.generation)) reportState()
349
+ else -> answer.reportStateNow()
350
+ }
351
+ }
396
352
  events?.invoke()
397
353
  answer?.resolve(value)
398
354
  }
399
355
 
400
- /** The navigation state now, when it changed; a failure is logged ([log]), nothing else stops for it. */
401
- fun reportState(commandName: String? = null) {
356
+ /**
357
+ * The navigation state now, when it changed, without a command's answer (a command's goes through its answer,
358
+ * `CommandAnswer.reportStateNow`); a failure is logged ([log]), nothing else stops for it.
359
+ */
360
+ fun reportState() {
402
361
  try {
403
362
  state.updateNow()
404
363
  } catch (e: Throwable) {
405
364
  val reason = ErrorTexts.couldNot("report the navigation state", ErrorTexts.reasonOf(e))
406
- log("[ApexNavigation] ${commandName ?: "transition"}: $reason")
365
+ log("[ApexNavigation] transition: $reason")
407
366
  }
408
367
  }
409
368
 
@@ -423,12 +382,14 @@ internal object AppearanceDispatcher {
423
382
 
424
383
  /**
425
384
  * [modal] went with [count] modals (EVT-ModalDismissed): `ANN.ModalDismissed` with the id and the name of the
426
- * screen the modal shows, down its current children.
385
+ * screen the modal shows, down its current children ([modalScreen]); a modal that shows no screen gives its own id
386
+ * and no name.
427
387
  */
428
388
  fun modalDismissed(modal: ViewController<*>, count: Int) {
429
389
  if (!ReloadCoordinator.isCurrent(modal.jsGeneration)) return
430
- val screen = visibleNode(modal)
431
- sender.modalDismissed(screen.id, screen.currentComponentName.orEmpty(), count)
390
+ val named = modalScreen(modal)
391
+ val name = if (named is ParentController<*>) "" else named.currentComponentName.orEmpty()
392
+ sender.modalDismissed(named.id, name, count)
432
393
  }
433
394
 
434
395
  /**
@@ -481,7 +442,7 @@ internal object AppearanceDispatcher {
481
442
  * modal shows. Nothing for a JavaScript that went.
482
443
  */
483
444
  fun modalAttemptedToDismiss(modal: ViewController<*>) {
484
- val screen = visibleNode(modal)
445
+ val screen = modalScreen(modal)
485
446
  if (ReloadCoordinator.isCurrent(screen.jsGeneration)) sender.modalAttemptedToDismiss(screen.id)
486
447
  }
487
448
 
@@ -490,18 +451,26 @@ internal object AppearanceDispatcher {
490
451
  * Nothing for a JavaScript that went.
491
452
  */
492
453
  fun sheetDetentChanged(modal: ViewController<*>, detent: Any) {
493
- val screen = visibleNode(modal)
454
+ val screen = modalScreen(modal)
494
455
  if (ReloadCoordinator.isCurrent(screen.jsGeneration)) sender.sheetDetentChanged(screen.id, detent)
495
456
  }
496
457
 
497
458
  /**
498
459
  * The screen [node] shows: the node at the end of its current children (the one "visible screen" of the core): what
499
- * `ANN.ModalDismissed`, `ANN.ModalAttemptedToDismiss`, `ANN.SheetDetentChanged` and back's
500
- * `ANN.NavigationButtonPressed` of a modal name. A layout without a child answers itself.
460
+ * back's `ANN.NavigationButtonPressed` of a modal names, and, through [modalScreen], its `ANN.ModalDismissed`,
461
+ * `ANN.ModalAttemptedToDismiss` and `ANN.SheetDetentChanged`. A layout without a child answers itself.
501
462
  */
502
463
  fun visibleNode(node: ViewController<*>): ViewController<*> {
503
464
  var current = node
504
465
  while (current is ParentController<*>) current = current.currentChild ?: break
505
466
  return current
506
467
  }
468
+
469
+ /**
470
+ * The node the events of the modal [modal] (its root) name: its [visibleNode] when that is a screen; the root
471
+ * itself when the chain ends in a layout without a child, as on iOS. Asked again of what it gave, it gives the
472
+ * same.
473
+ */
474
+ fun modalScreen(modal: ViewController<*>): ViewController<*> =
475
+ visibleNode(modal).takeUnless { it is ParentController<*> } ?: modal
507
476
  }