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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (581) hide show
  1. package/ApexNavigation.podspec +2 -1
  2. package/CHANGELOG.md +132 -0
  3. package/README.md +147 -51
  4. package/android/CLAUDE.md +78 -25
  5. package/android/CORE.md +49 -25
  6. package/android/RECIPES.md +13 -6
  7. package/android/consumer-rules.pro +6 -0
  8. package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +85 -10
  9. package/android/src/main/java/dev/apexnative/navigation/NavigationApplication.kt +34 -13
  10. package/android/src/main/java/dev/apexnative/navigation/layout/LayoutChecks.kt +5 -1
  11. package/android/src/main/java/dev/apexnative/navigation/layout/LayoutNode.kt +6 -2
  12. package/android/src/main/java/dev/apexnative/navigation/nativescreen/NativeScreenContext.kt +2 -2
  13. package/android/src/main/java/dev/apexnative/navigation/options/AnimationsOptions.kt +2 -2
  14. package/android/src/main/java/dev/apexnative/navigation/options/BottomTabOptions.kt +1 -1
  15. package/android/src/main/java/dev/apexnative/navigation/options/BottomTabsOptions.kt +13 -8
  16. package/android/src/main/java/dev/apexnative/navigation/options/ButtonMenuOptions.kt +2 -2
  17. package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +3 -3
  18. package/android/src/main/java/dev/apexnative/navigation/options/HardwareBackButtonOptions.kt +9 -1
  19. package/android/src/main/java/dev/apexnative/navigation/options/LargeTitleOptions.kt +1 -1
  20. package/android/src/main/java/dev/apexnative/navigation/options/LayoutAnimation.kt +1 -1
  21. package/android/src/main/java/dev/apexnative/navigation/options/OptionKey.kt +18 -0
  22. package/android/src/main/java/dev/apexnative/navigation/options/OptionPaths.kt +91 -0
  23. package/android/src/main/java/dev/apexnative/navigation/options/OptionsCache.kt +8 -4
  24. package/android/src/main/java/dev/apexnative/navigation/options/SheetOptions.kt +7 -4
  25. package/android/src/main/java/dev/apexnative/navigation/options/SideMenuOptions.kt +6 -1
  26. package/android/src/main/java/dev/apexnative/navigation/options/StackAnimationOptions.kt +40 -2
  27. package/android/src/main/java/dev/apexnative/navigation/options/StatusBarOptions.kt +7 -3
  28. package/android/src/main/java/dev/apexnative/navigation/options/TitleOptions.kt +2 -2
  29. package/android/src/main/java/dev/apexnative/navigation/options/TopBarAppearanceOptions.kt +1 -1
  30. package/android/src/main/java/dev/apexnative/navigation/options/TopBarOptions.kt +16 -7
  31. package/android/src/main/java/dev/apexnative/navigation/options/UserChoices.kt +159 -0
  32. package/android/src/main/java/dev/apexnative/navigation/react/CommandAnswer.kt +29 -36
  33. package/android/src/main/java/dev/apexnative/navigation/react/CommandContract.kt +59 -0
  34. package/android/src/main/java/dev/apexnative/navigation/react/ContentHeights.kt +95 -0
  35. package/android/src/main/java/dev/apexnative/navigation/react/ContentMounts.kt +66 -0
  36. package/android/src/main/java/dev/apexnative/navigation/react/ErrorTexts.kt +75 -60
  37. package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +35 -23
  38. package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +12 -7
  39. package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +42 -4
  40. package/android/src/main/java/dev/apexnative/navigation/react/PendingCalls.kt +48 -0
  41. package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +54 -20
  42. package/android/src/main/java/dev/apexnative/navigation/react/ReloadCoordinator.kt +7 -6
  43. package/android/src/main/java/dev/apexnative/navigation/react/ScreenEnvironment.kt +177 -0
  44. package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +19 -50
  45. package/android/src/main/java/dev/apexnative/navigation/react/ScrollEvents.kt +49 -128
  46. package/android/src/main/java/dev/apexnative/navigation/react/events/AppearanceDispatcher.kt +50 -81
  47. package/android/src/main/java/dev/apexnative/navigation/react/events/EventContract.kt +226 -0
  48. package/android/src/main/java/dev/apexnative/navigation/react/events/EventEmitter.kt +135 -94
  49. package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationState.kt +154 -0
  50. package/android/src/main/java/dev/apexnative/navigation/react/events/ScreenAppearance.kt +0 -6
  51. package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +12 -10
  52. package/android/src/main/java/dev/apexnative/navigation/slots/SlotContainers.kt +10 -7
  53. package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +39 -19
  54. package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +16 -4
  55. package/android/src/main/java/dev/apexnative/navigation/slots/SlotViews.kt +40 -0
  56. package/android/src/main/java/dev/apexnative/navigation/utils/ImageKey.kt +66 -0
  57. package/android/src/main/java/dev/apexnative/navigation/utils/ImageLoader.kt +7 -89
  58. package/android/src/main/java/dev/apexnative/navigation/utils/ImageRequests.kt +76 -0
  59. package/android/src/main/java/dev/apexnative/navigation/utils/MaterialTheme.kt +5 -6
  60. package/android/src/main/java/dev/apexnative/navigation/utils/OptionImages.kt +262 -0
  61. package/android/src/main/java/dev/apexnative/navigation/utils/SystemAnimations.kt +36 -0
  62. package/android/src/main/java/dev/apexnative/navigation/utils/UiUtils.kt +3 -3
  63. package/android/src/main/java/dev/apexnative/navigation/utils/ViewController.kt +3 -1
  64. package/android/src/main/java/dev/apexnative/navigation/utils/ViewExtensions.kt +0 -13
  65. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementController.kt +10 -7
  66. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementDefinition.kt +9 -3
  67. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementPlanner.kt +20 -15
  68. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/SecondaryScreenPresenter.kt +13 -5
  69. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/AppliedTabCalls.kt +49 -0
  70. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsCollapseBehavior.kt +5 -3
  71. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +108 -34
  72. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsPresenter.kt +25 -24
  73. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowGeometry.kt +22 -0
  74. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabItems.kt +3 -3
  75. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabsRoom.kt +0 -5
  76. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentPresenter.kt +28 -7
  77. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +12 -9
  78. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ContentReadiness.kt +2 -2
  79. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/RenderWait.kt +27 -7
  80. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenFrame.kt +1 -1
  81. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenReadiness.kt +103 -56
  82. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenSafeArea.kt +29 -11
  83. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/externalcomponent/ExternalComponentViewController.kt +2 -6
  84. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalAnimations.kt +22 -24
  85. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +109 -21
  86. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalRecord.kt +21 -6
  87. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +476 -73
  88. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +57 -25
  89. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetBack.kt +42 -0
  90. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +83 -0
  91. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackCheck.kt +50 -0
  92. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackState.kt +49 -14
  93. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +71 -12
  94. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +37 -11
  95. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/overlay/OverlayCoordinator.kt +10 -8
  96. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/Capabilities.kt +11 -4
  97. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ContainerBackground.kt +3 -3
  98. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +6 -6
  99. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +42 -9
  100. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +19 -8
  101. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuPresenter.kt +16 -7
  102. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuRules.kt +43 -4
  103. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitPanes.kt +23 -0
  104. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +77 -17
  105. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +315 -0
  106. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/PreparedFrame.kt +3 -3
  107. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +30 -20
  108. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +216 -18
  109. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackDisplay.kt +26 -1
  110. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +149 -41
  111. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackTransitions.kt +26 -8
  112. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +115 -6
  113. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabMotion.kt +142 -0
  114. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +222 -48
  115. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/ScreenSearch.kt +3 -5
  116. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +30 -34
  117. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarComponents.kt +5 -51
  118. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarRowTransition.kt +3 -2
  119. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/ButtonPlaces.kt +11 -5
  120. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/MenuChecks.kt +13 -56
  121. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +219 -54
  122. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarVisibility.kt +9 -2
  123. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ScrollEventListener.kt +6 -9
  124. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ViewController.kt +75 -21
  125. package/android/src/main/java/dev/apexnative/navigation/views/animations/AnimationLayer.kt +73 -0
  126. package/android/src/main/java/dev/apexnative/navigation/views/animations/Curves.kt +29 -11
  127. package/android/src/main/java/dev/apexnative/navigation/views/animations/ValueInterpolation.kt +14 -0
  128. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +9 -7
  129. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabsLayout.kt +61 -2
  130. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomBottomTabItemView.kt +0 -5
  131. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomTabRow.kt +72 -10
  132. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStep.kt +31 -0
  133. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +143 -135
  134. package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +13 -5
  135. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
  136. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionTargets.kt +9 -6
  137. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionViews.kt +100 -0
  138. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +112 -4
  139. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +346 -36
  140. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMorph.kt +199 -0
  141. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +56 -41
  142. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextMorph.kt +176 -0
  143. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewMorph.kt +108 -0
  144. package/android/src/main/java/dev/apexnative/navigation/views/sidemenu/SideMenuView.kt +12 -3
  145. package/android/src/main/java/dev/apexnative/navigation/views/stack/ScreenEdge.kt +45 -0
  146. package/android/src/main/java/dev/apexnative/navigation/views/stack/StackLayout.kt +140 -1
  147. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/Fab.kt +14 -10
  148. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabCopy.kt +85 -0
  149. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabMenu.kt +13 -0
  150. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +5 -17
  151. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +73 -34
  152. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonComponentCell.kt +6 -6
  153. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonView.kt +113 -0
  154. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarMenu.kt +219 -0
  155. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +125 -178
  156. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonMenus.kt +34 -64
  157. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonRow.kt +216 -0
  158. package/android/src/main/jni/ANNContentHeights.cpp +82 -0
  159. package/android/src/main/res/drawable/apex_navigation_ic_arrow_right.xml +14 -0
  160. package/android/src/main/res/layout/apex_navigation_menu_header.xml +19 -0
  161. package/android/src/main/res/layout/apex_navigation_menu_item.xml +68 -0
  162. package/android/src/main/res/values/styles.xml +1 -1
  163. package/android/src/main/res/values-night/styles.xml +1 -1
  164. package/cli/app.js +1 -1
  165. package/cli/doctor/checks/app.js +77 -14
  166. package/cli/doctor/checks/splash.js +4 -22
  167. package/cli/migrate/native.js +18 -0
  168. package/cli/project.js +10 -2
  169. package/cli/setup/index.js +18 -0
  170. package/cli/setup/source.js +2 -1
  171. package/cli/setup/steps/appDelegate.js +66 -11
  172. package/cli/setup/steps/mainApplication.js +134 -19
  173. package/cli/setup/steps/metro.js +46 -0
  174. package/cli/setup/steps/sceneDelegate.js +108 -0
  175. package/cli/splash/index.js +3 -1
  176. package/docs-md/architecture/native-screens.md +4 -0
  177. package/docs-md/architecture/theme-and-context.md +131 -12
  178. package/docs-md/architecture/transitions.md +58 -12
  179. package/docs-md/containers/arrangement.md +17 -1
  180. package/docs-md/containers/modals.md +8 -4
  181. package/docs-md/containers/overlays.md +3 -1
  182. package/docs-md/containers/side-menu.md +19 -2
  183. package/docs-md/containers/tabs.md +5 -1
  184. package/docs-md/flows/bottom-sheets.md +4 -2
  185. package/docs-md/flows/forms-in-a-modal.md +1 -1
  186. package/docs-md/fundamentals/screens-and-props.md +9 -1
  187. package/docs-md/fundamentals/starting-the-app.md +1 -1
  188. package/docs-md/guides/cli.md +4 -3
  189. package/docs-md/guides/deep-links.md +15 -33
  190. package/docs-md/help/glossary.md +4 -4
  191. package/docs-md/help/troubleshooting.md +44 -6
  192. package/docs-md/index.json +61 -1
  193. package/docs-md/migration/from-expo-router.md +1 -1
  194. package/docs-md/migration/from-react-native-navigation.md +9 -3
  195. package/docs-md/migration/from-react-navigation.md +2 -2
  196. package/docs-md/screen-ui/back-and-gestures.md +46 -2
  197. package/docs-md/screen-ui/bar-buttons.md +5 -5
  198. package/docs-md/screen-ui/search.md +1 -1
  199. package/docs-md/screen-ui/system-ui.md +17 -12
  200. package/docs-md/screen-ui/toolbar-and-fab.md +4 -2
  201. package/docs-md/screen-ui/top-bar.md +8 -4
  202. package/docs-md/start/installation.md +21 -3
  203. package/ios/Animations/ANNFrameDriver.h +55 -15
  204. package/ios/Animations/ANNFrameDriver.mm +216 -60
  205. package/ios/Animations/ANNTransitionAnimator.h +26 -5
  206. package/ios/Animations/ANNTransitionAnimator.mm +61 -13
  207. package/ios/Animations/ANNTransitionPlan.h +2 -2
  208. package/ios/Animations/ANNTransitionPlan.mm +10 -0
  209. package/ios/Animations/ANNTransitionWait.mm +6 -7
  210. package/ios/Animations/Elements/ANNElementFinder.h +57 -0
  211. package/ios/Animations/Elements/ANNElementFinder.mm +174 -2
  212. package/ios/Animations/Elements/ANNElementTransition.h +10 -8
  213. package/ios/Animations/Elements/ANNElementTransition.mm +19 -21
  214. package/ios/Animations/Elements/ANNSharedElementFlight.h +16 -11
  215. package/ios/Animations/Elements/ANNSharedElementFlight.mm +308 -69
  216. package/ios/Animations/Interpolators/ANNInterpolate.h +2 -30
  217. package/ios/Animations/Interpolators/ANNTransformParts.h +48 -0
  218. package/ios/Animations/Interpolators/ANNTransformParts.mm +507 -0
  219. package/ios/Animations/Interpolators/ANNViewTracks.h +9 -6
  220. package/ios/Animations/Interpolators/ANNViewTracks.mm +100 -30
  221. package/ios/CLAUDE.md +60 -24
  222. package/ios/CORE.md +44 -34
  223. package/ios/Contract/ANNCommandAnswer.h +13 -5
  224. package/ios/Contract/ANNCommandAnswer.mm +40 -32
  225. package/ios/Contract/ANNCommandContract.h +15 -0
  226. package/ios/Contract/ANNCommandContract.mm +78 -0
  227. package/ios/Contract/ANNCommandRunner.h +10 -9
  228. package/ios/Contract/ANNCommandRunner.mm +22 -28
  229. package/ios/Contract/ANNErrorTexts.h +6 -2
  230. package/ios/Contract/ANNErrorTexts.mm +18 -10
  231. package/ios/Contract/ANNLayoutNode.h +3 -3
  232. package/ios/Contract/ANNLayoutReader.h +3 -3
  233. package/ios/Core/ANNAppDelegate.mm +0 -2
  234. package/ios/Core/ANNAppearanceDispatcher.h +5 -4
  235. package/ios/Core/ANNAppearanceDispatcher.mm +12 -1
  236. package/ios/Core/ANNDeepLinkQueue.h +22 -2
  237. package/ios/Core/ANNDeepLinkQueue.mm +121 -14
  238. package/ios/Core/ANNErrorHandler.h +9 -4
  239. package/ios/Core/ANNErrorHandler.mm +20 -2
  240. package/ios/Core/ANNEventContract.h +246 -0
  241. package/ios/Core/ANNEventContract.mm +225 -0
  242. package/ios/Core/ANNEventEmitter.h +6 -2
  243. package/ios/Core/ANNEventEmitter.mm +117 -80
  244. package/ios/Core/ANNHinge.h +6 -0
  245. package/ios/Core/ANNHinge.mm +15 -4
  246. package/ios/Core/ANNJavaScriptCalls.h +33 -0
  247. package/ios/Core/ANNJavaScriptCalls.mm +52 -0
  248. package/ios/Core/ANNLayoutProtocol.h +5 -5
  249. package/ios/Core/ANNNavigationState.h +7 -5
  250. package/ios/Core/ANNNavigationState.mm +8 -7
  251. package/ios/Core/ANNNodeHelper.h +32 -12
  252. package/ios/Core/ANNNodeHelper.mm +100 -3
  253. package/ios/Core/ANNParking.h +5 -4
  254. package/ios/Core/ANNReloadCoordinator.mm +5 -12
  255. package/ios/Core/ANNRenderWait.h +20 -6
  256. package/ios/Core/ANNRenderWait.mm +143 -56
  257. package/ios/Core/ANNSceneDelegate.mm +25 -15
  258. package/ios/Core/ANNSystemUI.h +3 -2
  259. package/ios/Core/ANNSystemUI.mm +7 -0
  260. package/ios/Core/ANNUtils.h +7 -0
  261. package/ios/Core/ANNUtils.mm +10 -0
  262. package/ios/Core/ApexNavigation+Internal.h +1 -1
  263. package/ios/Core/ApexNavigation.mm +7 -6
  264. package/ios/Core/UIViewController+LayoutProtocol.h +9 -2
  265. package/ios/Core/UIViewController+LayoutProtocol.mm +8 -0
  266. package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
  267. package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
  268. package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +195 -21
  269. package/ios/Layouts/Modal/ANNModalCoordinator.h +1 -1
  270. package/ios/Layouts/Modal/ANNModalCoordinator.mm +57 -16
  271. package/ios/Layouts/Modal/ANNModalPresentation.h +8 -5
  272. package/ios/Layouts/Modal/ANNModalPresentation.mm +12 -12
  273. package/ios/Layouts/Modal/ANNSheetPresenter.mm +83 -1
  274. package/ios/Layouts/Overlay/ANNOverlayCoordinator.mm +2 -8
  275. package/ios/Layouts/Root/ANNRootCoordinator.mm +58 -19
  276. package/ios/Layouts/Root/ANNSplashViewController.h +5 -3
  277. package/ios/Layouts/Root/ANNSplashViewController.mm +147 -0
  278. package/ios/Layouts/Screen/ANNComponentPresenter.h +11 -3
  279. package/ios/Layouts/Screen/ANNComponentPresenter.mm +34 -6
  280. package/ios/Layouts/Screen/ANNComponentViewController.h +15 -13
  281. package/ios/Layouts/Screen/ANNComponentViewController.mm +130 -75
  282. package/ios/Layouts/Screen/ANNNativeScreenContext.mm +7 -5
  283. package/ios/Layouts/Screen/ANNPreviewInteraction.h +7 -4
  284. package/ios/Layouts/Screen/ANNPreviewInteraction.mm +72 -10
  285. package/ios/Layouts/Screen/ANNScreenEnvironment.h +63 -0
  286. package/ios/Layouts/Screen/ANNScreenEnvironment.mm +181 -0
  287. package/ios/Layouts/Screen/ANNScreenPlace.h +53 -0
  288. package/ios/Layouts/Screen/ANNScreenPlace.mm +205 -0
  289. package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
  290. package/ios/Layouts/Screen/ANNScreenRegions.mm +9 -44
  291. package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
  292. package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
  293. package/ios/Layouts/Screen/ANNScreenSettling.h +34 -0
  294. package/ios/Layouts/Screen/ANNScreenSettling.mm +171 -0
  295. package/ios/Layouts/SideMenu/ANNSideMenuTypes.h +8 -0
  296. package/ios/Layouts/SideMenu/ANNSideMenuViewController.mm +83 -14
  297. package/ios/Layouts/SplitView/ANNSplitViewCommands.h +3 -2
  298. package/ios/Layouts/SplitView/ANNSplitViewCommands.mm +105 -39
  299. package/ios/Layouts/SplitView/ANNSplitViewController.mm +7 -8
  300. package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
  301. package/ios/Layouts/Stack/ANNPreviewPush.mm +142 -27
  302. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
  303. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
  304. package/ios/Layouts/Stack/ANNStackCommands.mm +1 -0
  305. package/ios/Layouts/Stack/ANNStackController.h +8 -0
  306. package/ios/Layouts/Stack/ANNStackController.mm +184 -16
  307. package/ios/Layouts/Stack/ANNStackQueue.h +5 -2
  308. package/ios/Layouts/Stack/ANNStackQueue.mm +56 -43
  309. package/ios/Layouts/Stack/ANNSwipePopInteraction.h +26 -0
  310. package/ios/Layouts/Stack/ANNSwipePopInteraction.mm +185 -0
  311. package/ios/Layouts/Stack/InteractivePopGestureDelegate.mm +28 -4
  312. package/ios/Layouts/Stack/UINavigationController+ANNCommands.h +4 -2
  313. package/ios/Layouts/Stack/UINavigationController+ANNCommands.mm +2 -3
  314. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.h +4 -0
  315. package/ios/Layouts/Tabs/ANNBottomTabItemBuilder.mm +11 -0
  316. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
  317. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
  318. package/ios/Layouts/Tabs/ANNBottomTabsController.h +3 -0
  319. package/ios/Layouts/Tabs/ANNBottomTabsController.mm +237 -57
  320. package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
  321. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +6 -2
  322. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +232 -43
  323. package/ios/Layouts/Tabs/ANNTabsDesign.h +6 -5
  324. package/ios/Layouts/Tabs/ANNTabsDesign.mm +9 -1
  325. package/ios/Layouts/Tabs/UITabBar+utils.h +5 -5
  326. package/ios/Layouts/Tabs/UITabBar+utils.mm +32 -13
  327. package/ios/Options/ANNAnimationOptions.h +2 -1
  328. package/ios/Options/ANNAnimationOptions.mm +1 -1
  329. package/ios/Options/ANNBottomTabsOptions.h +2 -0
  330. package/ios/Options/ANNBottomTabsOptions.mm +1 -0
  331. package/ios/Options/ANNOptions.h +25 -0
  332. package/ios/Options/ANNOptions.mm +157 -1
  333. package/ios/Options/ANNOptionsCache.h +7 -6
  334. package/ios/Options/ANNOptionsReader.mm +108 -0
  335. package/ios/Options/ANNSearchBarOptions.h +4 -3
  336. package/ios/Options/ANNSheetOptions.h +4 -1
  337. package/ios/Options/ANNSideMenuOptions.h +2 -0
  338. package/ios/Options/ANNSideMenuOptions.mm +2 -0
  339. package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
  340. package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
  341. package/ios/Options/ANNUserChoice.h +57 -0
  342. package/ios/Options/ANNUserChoice.mm +44 -0
  343. package/ios/Options/Params/ANNImageSource.h +61 -0
  344. package/ios/Options/Params/ANNImageSource.mm +101 -0
  345. package/ios/Options/Params/ANNOptionImages.h +37 -0
  346. package/ios/Options/Params/ANNOptionImages.mm +284 -0
  347. package/ios/Options/Params/ANNParam.h +15 -0
  348. package/ios/Options/Params/ANNParam.mm +61 -0
  349. package/ios/Options/Params/Color.h +3 -0
  350. package/ios/Options/Params/Color.mm +21 -0
  351. package/ios/Options/Params/ColorParser.h +4 -3
  352. package/ios/Options/Params/ColorParser.mm +22 -4
  353. package/ios/Options/Params/Image.h +15 -2
  354. package/ios/Options/Params/Image.mm +35 -2
  355. package/ios/Options/Params/ImageParser.h +5 -5
  356. package/ios/Options/Params/ImageParser.mm +28 -46
  357. package/ios/Public/ApexNavigation/ANNSceneDelegate.h +3 -0
  358. package/ios/Public/ApexNavigation/ApexNavigation.h +1 -1
  359. package/ios/RECIPES.md +13 -6
  360. package/ios/React/ANNReactView.mm +6 -25
  361. package/ios/React/ANNSafeAreaViewComponentView.mm +28 -17
  362. package/ios/React/ANNSurfaceHostingView.h +14 -0
  363. package/ios/React/ANNSurfaceHostingView.mm +144 -1
  364. package/ios/React/Slots/ANNSlotComponentView.mm +24 -17
  365. package/ios/React/Slots/ANNSlotContainers.h +14 -6
  366. package/ios/React/Slots/ANNSlotContainers.mm +75 -2
  367. package/ios/React/Slots/ANNSlotHost.mm +1 -3
  368. package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
  369. package/ios/TopBar/ANNBackButtonPresenter.mm +6 -5
  370. package/ios/TopBar/ANNBarAppearance.h +2 -1
  371. package/ios/TopBar/ANNBarAppearance.mm +111 -30
  372. package/ios/TopBar/ANNBarBackgroundComponent.mm +16 -0
  373. package/ios/TopBar/ANNBarButtonComponentView.h +4 -4
  374. package/ios/TopBar/ANNBarButtonComponentView.mm +1 -1
  375. package/ios/TopBar/ANNBarButtons.h +14 -8
  376. package/ios/TopBar/ANNBarButtons.mm +397 -80
  377. package/ios/TopBar/ANNIconButtonImage.h +1 -0
  378. package/ios/TopBar/ANNIconButtonImage.mm +34 -1
  379. package/ios/TopBar/ANNLargeTitlePresenter.h +13 -0
  380. package/ios/TopBar/ANNLargeTitlePresenter.mm +50 -7
  381. package/ios/TopBar/ANNMainList.h +3 -0
  382. package/ios/TopBar/ANNMainList.mm +4 -0
  383. package/ios/TopBar/ANNScrollEdgeEffects.h +22 -6
  384. package/ios/TopBar/ANNScrollEdgeEffects.mm +123 -16
  385. package/ios/TopBar/ANNSearchPresenter.mm +172 -21
  386. package/ios/TopBar/ANNSearchResultsViewController.mm +29 -6
  387. package/ios/TopBar/ANNTopBarPresenter.h +8 -2
  388. package/ios/TopBar/ANNTopBarPresenter.mm +155 -33
  389. package/ios/TurboModules/ANNTurboEventEmitter.mm +4 -35
  390. package/ios/TurboModules/ANNTurboModule.mm +104 -33
  391. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.cpp +20 -0
  392. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.h +5 -14
  393. package/lib/module/ARCHITECTURE.md +40 -27
  394. package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
  395. package/lib/module/api/app/AppRegistry.js +14 -2
  396. package/lib/module/api/app/AppRegistry.js.map +1 -1
  397. package/lib/module/api/app/createNavigation.js +190 -66
  398. package/lib/module/api/app/createNavigation.js.map +1 -1
  399. package/lib/module/api/commands/commands.js +54 -6
  400. package/lib/module/api/commands/commands.js.map +1 -1
  401. package/lib/module/api/events/navigationEvents.js +6 -2
  402. package/lib/module/api/events/navigationEvents.js.map +1 -1
  403. package/lib/module/api/hooks/useNavigation.js +8 -3
  404. package/lib/module/api/hooks/useNavigation.js.map +1 -1
  405. package/lib/module/api/hooks/useSafeAreaInsets.js +4 -3
  406. package/lib/module/api/hooks/useSafeAreaInsets.js.map +1 -1
  407. package/lib/module/api/linking/dispatchedLinks.js +23 -0
  408. package/lib/module/api/linking/dispatchedLinks.js.map +1 -0
  409. package/lib/module/api/linking/linking.js +11 -0
  410. package/lib/module/api/linking/linking.js.map +1 -1
  411. package/lib/module/api/navigation.js.map +1 -1
  412. package/lib/module/api/options/OptionsChain.js +2 -2
  413. package/lib/module/api/screens/arrangement.js +5 -2
  414. package/lib/module/api/screens/arrangement.js.map +1 -1
  415. package/lib/module/api/screens/defineScreen.js +45 -3
  416. package/lib/module/api/screens/defineScreen.js.map +1 -1
  417. package/lib/module/api/screens/nativeScreens.js +31 -6
  418. package/lib/module/api/screens/nativeScreens.js.map +1 -1
  419. package/lib/module/api/screens/registerScreens.js +193 -35
  420. package/lib/module/api/screens/registerScreens.js.map +1 -1
  421. package/lib/module/api/theme/theme.js +5 -0
  422. package/lib/module/api/theme/theme.js.map +1 -1
  423. package/lib/module/engine/commands.js +51 -9
  424. package/lib/module/engine/commands.js.map +1 -1
  425. package/lib/module/engine/layout.js +20 -11
  426. package/lib/module/engine/layout.js.map +1 -1
  427. package/lib/module/engine/nativeScreens.js +9 -0
  428. package/lib/module/engine/nativeScreens.js.map +1 -1
  429. package/lib/module/engine/options.js +49 -15
  430. package/lib/module/engine/options.js.map +1 -1
  431. package/lib/module/engine/optionsChange.js +102 -0
  432. package/lib/module/engine/optionsChange.js.map +1 -0
  433. package/lib/module/engine/places.js +52 -7
  434. package/lib/module/engine/places.js.map +1 -1
  435. package/lib/module/engine/props.js +30 -1
  436. package/lib/module/engine/props.js.map +1 -1
  437. package/lib/module/engine/refresh.js +85 -0
  438. package/lib/module/engine/refresh.js.map +1 -0
  439. package/lib/module/engine/rememberedOptions.js +61 -1
  440. package/lib/module/engine/rememberedOptions.js.map +1 -1
  441. package/lib/module/engine/screens.js +77 -16
  442. package/lib/module/engine/screens.js.map +1 -1
  443. package/lib/module/interfaces/contract/commands.json +101 -0
  444. package/lib/module/interfaces/contract/errors.json +275 -0
  445. package/lib/typescript/adapters/NativeANNTurboModule.d.ts +12 -2
  446. package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
  447. package/lib/typescript/api/app/AppRegistry.d.ts.map +1 -1
  448. package/lib/typescript/api/app/createNavigation.d.ts +8 -3
  449. package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
  450. package/lib/typescript/api/commands/commands.d.ts.map +1 -1
  451. package/lib/typescript/api/commands/presentation.d.ts +4 -3
  452. package/lib/typescript/api/commands/presentation.d.ts.map +1 -1
  453. package/lib/typescript/api/events/navigationEvents.d.ts +3 -3
  454. package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
  455. package/lib/typescript/api/hooks/useNavigation.d.ts +1 -1
  456. package/lib/typescript/api/hooks/useNavigation.d.ts.map +1 -1
  457. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts +4 -3
  458. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
  459. package/lib/typescript/api/index.d.ts +1 -1
  460. package/lib/typescript/api/index.d.ts.map +1 -1
  461. package/lib/typescript/api/linking/dispatchedLinks.d.ts +7 -0
  462. package/lib/typescript/api/linking/dispatchedLinks.d.ts.map +1 -0
  463. package/lib/typescript/api/linking/linking.d.ts +8 -0
  464. package/lib/typescript/api/linking/linking.d.ts.map +1 -1
  465. package/lib/typescript/api/navigation.d.ts +4 -1
  466. package/lib/typescript/api/navigation.d.ts.map +1 -1
  467. package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
  468. package/lib/typescript/api/screens/arrangement.d.ts +12 -2
  469. package/lib/typescript/api/screens/arrangement.d.ts.map +1 -1
  470. package/lib/typescript/api/screens/defineScreen.d.ts +23 -4
  471. package/lib/typescript/api/screens/defineScreen.d.ts.map +1 -1
  472. package/lib/typescript/api/screens/nativeScreens.d.ts +8 -1
  473. package/lib/typescript/api/screens/nativeScreens.d.ts.map +1 -1
  474. package/lib/typescript/api/screens/registerScreens.d.ts.map +1 -1
  475. package/lib/typescript/api/theme/theme.d.ts +2 -0
  476. package/lib/typescript/api/theme/theme.d.ts.map +1 -1
  477. package/lib/typescript/engine/commands.d.ts +5 -0
  478. package/lib/typescript/engine/commands.d.ts.map +1 -1
  479. package/lib/typescript/engine/layout.d.ts.map +1 -1
  480. package/lib/typescript/engine/nativeScreens.d.ts +5 -0
  481. package/lib/typescript/engine/nativeScreens.d.ts.map +1 -1
  482. package/lib/typescript/engine/options.d.ts +5 -2
  483. package/lib/typescript/engine/options.d.ts.map +1 -1
  484. package/lib/typescript/engine/optionsChange.d.ts +28 -0
  485. package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
  486. package/lib/typescript/engine/places.d.ts +7 -2
  487. package/lib/typescript/engine/places.d.ts.map +1 -1
  488. package/lib/typescript/engine/props.d.ts +8 -1
  489. package/lib/typescript/engine/props.d.ts.map +1 -1
  490. package/lib/typescript/engine/refresh.d.ts +35 -0
  491. package/lib/typescript/engine/refresh.d.ts.map +1 -0
  492. package/lib/typescript/engine/rememberedOptions.d.ts +13 -0
  493. package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
  494. package/lib/typescript/engine/screens.d.ts +27 -6
  495. package/lib/typescript/engine/screens.d.ts.map +1 -1
  496. package/lib/typescript/interfaces/ComponentEvents.d.ts +4 -4
  497. package/lib/typescript/interfaces/ComponentEvents.d.ts.map +1 -1
  498. package/lib/typescript/interfaces/Events.d.ts +28 -10
  499. package/lib/typescript/interfaces/Events.d.ts.map +1 -1
  500. package/lib/typescript/interfaces/Options.d.ts +1 -1
  501. package/lib/typescript/interfaces/Options.d.ts.map +1 -1
  502. package/lib/typescript/interfaces/options/animations.d.ts +80 -22
  503. package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
  504. package/lib/typescript/interfaces/options/bottomTabs.d.ts +21 -7
  505. package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
  506. package/lib/typescript/interfaces/options/buttons.d.ts +23 -15
  507. package/lib/typescript/interfaces/options/buttons.d.ts.map +1 -1
  508. package/lib/typescript/interfaces/options/modals.d.ts +34 -26
  509. package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
  510. package/lib/typescript/interfaces/options/sideMenu.d.ts +23 -6
  511. package/lib/typescript/interfaces/options/sideMenu.d.ts.map +1 -1
  512. package/lib/typescript/interfaces/options/stack.d.ts +17 -3
  513. package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
  514. package/lib/typescript/interfaces/options/system.d.ts +18 -11
  515. package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
  516. package/lib/typescript/interfaces/options/toolbar.d.ts +2 -2
  517. package/lib/typescript/interfaces/options/topBar.d.ts +68 -38
  518. package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
  519. package/metro/acceptPlugin.js +57 -0
  520. package/metro/babelTransformer.js +45 -0
  521. package/metro/index.js +36 -0
  522. package/package.json +3 -1
  523. package/src/ARCHITECTURE.md +40 -27
  524. package/src/adapters/NativeANNTurboModule.ts +12 -2
  525. package/src/api/app/AppRegistry.ts +16 -2
  526. package/src/api/app/createNavigation.ts +203 -69
  527. package/src/api/commands/commands.ts +48 -7
  528. package/src/api/commands/presentation.ts +4 -3
  529. package/src/api/events/navigationEvents.ts +10 -4
  530. package/src/api/hooks/useNavigation.ts +9 -4
  531. package/src/api/hooks/useSafeAreaInsets.ts +4 -3
  532. package/src/api/index.ts +1 -0
  533. package/src/api/linking/dispatchedLinks.ts +18 -0
  534. package/src/api/linking/linking.ts +22 -1
  535. package/src/api/navigation.ts +4 -1
  536. package/src/api/options/OptionsChain.ts +2 -2
  537. package/src/api/screens/arrangement.ts +17 -4
  538. package/src/api/screens/defineScreen.ts +49 -5
  539. package/src/api/screens/nativeScreens.ts +40 -4
  540. package/src/api/screens/registerScreens.tsx +185 -42
  541. package/src/api/theme/theme.ts +5 -0
  542. package/src/engine/commands.ts +70 -13
  543. package/src/engine/layout.ts +27 -11
  544. package/src/engine/nativeScreens.ts +10 -1
  545. package/src/engine/options.ts +45 -19
  546. package/src/engine/optionsChange.ts +107 -0
  547. package/src/engine/places.ts +65 -7
  548. package/src/engine/props.ts +30 -1
  549. package/src/engine/refresh.ts +97 -0
  550. package/src/engine/rememberedOptions.ts +74 -1
  551. package/src/engine/screens.tsx +76 -21
  552. package/src/interfaces/ComponentEvents.ts +4 -4
  553. package/src/interfaces/Events.ts +29 -10
  554. package/src/interfaces/Options.ts +1 -0
  555. package/src/interfaces/contract/commands.json +101 -0
  556. package/src/interfaces/contract/errors.json +275 -0
  557. package/src/interfaces/options/animations.ts +81 -22
  558. package/src/interfaces/options/bottomTabs.ts +21 -7
  559. package/src/interfaces/options/buttons.ts +23 -15
  560. package/src/interfaces/options/modals.ts +34 -26
  561. package/src/interfaces/options/sideMenu.ts +24 -6
  562. package/src/interfaces/options/stack.ts +17 -3
  563. package/src/interfaces/options/system.ts +18 -11
  564. package/src/interfaces/options/toolbar.ts +2 -2
  565. package/src/interfaces/options/topBar.ts +68 -38
  566. package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -41
  567. package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -69
  568. package/android/src/main/java/dev/apexnative/navigation/react/events/NavigationStateReporter.kt +0 -62
  569. package/android/src/main/java/dev/apexnative/navigation/react/events/StateHold.kt +0 -62
  570. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowPlacer.kt +0 -223
  571. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStub.kt +0 -31
  572. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +0 -138
  573. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -88
  574. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PropertyAnimatorCreator.kt +0 -33
  575. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +0 -66
  576. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +0 -179
  577. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -139
  578. package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
  579. package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -68
  580. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.h +0 -27
  581. package/ios/Layouts/Tabs/ANNTabsPreloadWindow.mm +0 -55
@@ -1,16 +1,8 @@
1
1
  #import "ANNArrangementState.h"
2
2
  #import "ANNArrangementViewController.h"
3
3
 
4
- static NSMutableDictionary<NSString *, NSDictionary<NSString *, id> *> *ANNArrangementStateById;
5
-
6
4
  @implementation ANNArrangementState
7
5
 
8
- + (void)initialize {
9
- if (self == ANNArrangementState.class) {
10
- ANNArrangementStateById = [NSMutableDictionary new];
11
- }
12
- }
13
-
14
6
  + (BOOL)canShowArrangements {
15
7
  #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 270100
16
8
  if (@available(iOS 27.1, *)) {
@@ -20,34 +12,4 @@ static NSMutableDictionary<NSString *, NSDictionary<NSString *, id> *> *ANNArran
20
12
  return NO;
21
13
  }
22
14
 
23
- + (void)setState:(NSDictionary<NSString *, id> *)state
24
- forScreenId:(NSString *)screenId
25
- eventEmitter:(ANNEventEmitter *)eventEmitter {
26
- @synchronized(ANNArrangementStateById) {
27
- if ([ANNArrangementStateById[screenId] isEqualToDictionary:state]) {
28
- return;
29
- }
30
- ANNArrangementStateById[screenId] = state;
31
- }
32
- [eventEmitter sendArrangementChanged:screenId state:state];
33
- }
34
-
35
- + (NSDictionary<NSString *, id> *)stateForScreenId:(NSString *)screenId {
36
- @synchronized(ANNArrangementStateById) {
37
- return ANNArrangementStateById[screenId];
38
- }
39
- }
40
-
41
- + (void)removeScreenId:(NSString *)screenId {
42
- @synchronized(ANNArrangementStateById) {
43
- [ANNArrangementStateById removeObjectForKey:screenId];
44
- }
45
- }
46
-
47
- + (void)removeAll {
48
- @synchronized(ANNArrangementStateById) {
49
- [ANNArrangementStateById removeAllObjects];
50
- }
51
- }
52
-
53
15
  @end
@@ -2,9 +2,10 @@
2
2
 
3
3
  #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 270100
4
4
 
5
- #import "ANNArrangementState.h"
6
5
  #import "ANNComponentViewController.h"
6
+ #import "ANNEventContract.h"
7
7
  #import "ANNExternalViewController.h"
8
+ #import "ANNScreenEnvironment.h"
8
9
  #import "ANNShownScreens.h"
9
10
  #import "ANNUtils.h"
10
11
 
@@ -47,6 +48,14 @@ static NSDirectionalRectEdge ANNOppositeEdge(NSDirectionalRectEdge edge) {
47
48
  }
48
49
  }
49
50
 
51
+ // `primaryEdge` of a split: whether the primary goes second, at the trailing side or at the bottom. A split has no edge
52
+ // of its own: UIKit puts the view of its primary placement first along either axis (measured on iPhone Duo), so the
53
+ // edge decides which screen goes into that placement.
54
+ static BOOL ANNSecondaryFirst(NSDictionary *data) {
55
+ return ![@"overlay" isEqual:data[@"style"]] &&
56
+ ([@"trailing" isEqual:data[@"primaryEdge"]] || [@"bottom" isEqual:data[@"primaryEdge"]]);
57
+ }
58
+
50
59
  // Overlay view properties with the edge a view takes when the pair goes side by side.
51
60
  static UIOverlayArrangementViewProperties *ANNOverlayProperties(UIOverlayArrangement *overlay,
52
61
  NSDirectionalRectEdge edge)
@@ -94,8 +103,11 @@ static UIArrangement *ANNArrangementOfData(NSDictionary *data) API_AVAILABLE(ios
94
103
  height.preferred = dimension;
95
104
  primary.height = height;
96
105
  }
97
- [split setViewProperties:primary
98
- forPlacement:UIArrangementViewControllerViewPlacementPrimary];
106
+ // The share is the primary screen's, in whichever placement it is.
107
+ UIArrangementViewControllerViewPlacement placement =
108
+ ANNSecondaryFirst(data) ? UIArrangementViewControllerViewPlacementSecondary
109
+ : UIArrangementViewControllerViewPlacementPrimary;
110
+ [split setViewProperties:primary forPlacement:placement];
99
111
  }
100
112
  return split;
101
113
  }
@@ -108,6 +120,38 @@ static UIArrangement *ANNPrimaryAloneArrangement(void) API_AVAILABLE(ios(27.1))
108
120
  return split;
109
121
  }
110
122
 
123
+ // A size range from `minimum` to `maximum`, preferring `preferred`.
124
+ static UISplitArrangementDimensionRange *ANNDimensionRange(UISplitArrangementDimension *minimum,
125
+ UISplitArrangementDimension *preferred,
126
+ UISplitArrangementDimension *maximum)
127
+ API_AVAILABLE(ios(27.1)) {
128
+ UISplitArrangementDimensionRange *range = [UISplitArrangementDimensionRange new];
129
+ range.minimum = minimum;
130
+ range.preferred = preferred;
131
+ range.maximum = maximum;
132
+ return range;
133
+ }
134
+
135
+ // The primary alone in the secondary placement, with the primary placement empty. UIKit keeps the empty placement's
136
+ // share of a split (measured on iPhone Duo folded: the primary in the lower half, the upper one blank), so the empty
137
+ // placement gets no room and the primary all of it, along either axis, which no shape of the window leaves out.
138
+ static UIArrangement *ANNSecondPlacementAloneArrangement(void) API_AVAILABLE(ios(27.1)) {
139
+ UISplitArrangement *split = [UISplitArrangement splitArrangement];
140
+ split.axes = UIAxisHorizontal | UIAxisVertical;
141
+ UISplitArrangementDimension *none = [UISplitArrangementDimension absoluteDimension:0];
142
+ UISplitArrangementDimension *all = [UISplitArrangementDimension fractionalDimension:1];
143
+ UISplitArrangementViewProperties *empty = [split.defaultViewProperties copy];
144
+ empty.width = ANNDimensionRange(none, none, none);
145
+ empty.height = ANNDimensionRange(none, none, none);
146
+ [split setViewProperties:empty forPlacement:UIArrangementViewControllerViewPlacementPrimary];
147
+ UISplitArrangementViewProperties *primary = [split.defaultViewProperties copy];
148
+ primary.width = ANNDimensionRange(all, all, all);
149
+ primary.height = ANNDimensionRange(all, all, all);
150
+ [split setViewProperties:primary
151
+ forPlacement:UIArrangementViewControllerViewPlacementSecondary];
152
+ return split;
153
+ }
154
+
111
155
  // Room for a pair: both size classes regular (iPad, iPhone Duo unfolded). Nil without a size class yet: the view
112
156
  // controller is not in a window.
113
157
  static NSNumber *ANNIsLargeWindow(UITraitCollection *traits) {
@@ -130,11 +174,12 @@ static BOOL ANNKeepsState(UIViewController *screen) {
130
174
 
131
175
  static NSDictionary<NSString *, id> *ANNStateOf(NSString *placement, NSString *layout, BOOL front,
132
176
  BOOL hidden) {
177
+ const auto &keys = ANNEventContract.ArrangementChanged;
133
178
  return @{
134
- @"placement" : placement,
135
- @"layout" : layout,
136
- @"front" : @(front),
137
- @"hidden" : @(hidden),
179
+ keys.placement : placement,
180
+ keys.layout : layout,
181
+ keys.front : @(front),
182
+ keys.hidden : @(hidden),
138
183
  };
139
184
  }
140
185
 
@@ -181,9 +226,20 @@ static BOOL ANNIsShown(UIViewController *screen, UIArrangementViewState *state,
181
226
  // (`compact: 'primary'`).
182
227
  UIArrangement *_arrangement;
183
228
  BOOL _primaryAloneWhenSmall;
229
+ // `primaryEdge` of a split at the trailing side or the bottom: the secondary is in UIKit's primary placement, the
230
+ // primary in its secondary one. The primary alone keeps its placement and the secondary leaves its own, so the
231
+ // primary never changes its container at a fold. The axes the pair may use, for the primary alone then.
232
+ BOOL _secondaryFirst;
233
+ UIAxis _axes;
234
+ // The size a running size transition leads to, zero without one: the shape the pair decides its axes by.
235
+ CGSize _transitionSize;
184
236
  // What UIKit has now, once an arrangement went to it.
185
237
  BOOL _arranged;
186
238
  BOOL _primaryAlone;
239
+ // The scene's size classes the pair takes for a size transition, and which transition set them last: only that
240
+ // one's end takes them away.
241
+ BOOL _sceneSizeClasses;
242
+ NSUInteger _sceneSizeClassesTransition;
187
243
  }
188
244
 
189
245
  - (instancetype)initWithLayoutInfo:(ANNLayoutInfo *)layoutInfo
@@ -216,14 +272,16 @@ static BOOL ANNIsShown(UIViewController *screen, UIArrangementViewState *state,
216
272
  ((ANNComponentViewController *)screen).arrangement = self;
217
273
  }
218
274
  }
219
- [self setViewController:primary
275
+ _secondaryFirst = ANNSecondaryFirst(data);
276
+ _axes = ANNArrangementAxes(data[@"axes"]);
277
+ [self setViewController:_secondaryFirst ? secondary : primary
220
278
  forPlacement:UIArrangementViewControllerViewPlacementPrimary];
221
- [self setViewController:secondary
279
+ [self setViewController:_secondaryFirst ? primary : secondary
222
280
  forPlacement:UIArrangementViewControllerViewPlacementSecondary];
223
281
  _arrangement = ANNArrangementOfData(data);
224
282
  _primaryAloneWhenSmall = ![@"pair" isEqual:data[@"compact"]];
225
283
  // Before it is in a window: the window's size classes, which it will most likely have.
226
- [self arrangeForTraits:ANNUtils.mainWindow.traitCollection animated:NO];
284
+ [self arrangeForTraits:ANNUtils.mainWindow.traitCollection];
227
285
  if (!_arranged) {
228
286
  [self updateArrangement:_arrangement animated:NO];
229
287
  }
@@ -237,19 +295,33 @@ static BOOL ANNIsShown(UIViewController *screen, UIArrangementViewState *state,
237
295
  // `compact: 'primary'`: the pair shows only in a large window; in any other (an iPhone, iPhone Duo folded) the primary
238
296
  // shows alone, and the secondary waits out of the window until the window is large (iPhone Duo unfolded). With
239
297
  // `compact: 'pair'` UIKit lays the pair out everywhere.
240
- - (void)arrangeForTraits:(UITraitCollection *)traits animated:(BOOL)animated {
298
+ - (void)arrangeForTraits:(UITraitCollection *)traits {
241
299
  NSNumber *large = ANNIsLargeWindow(traits);
242
300
  if (!large) {
243
301
  return;
244
302
  }
245
- BOOL alone = _primaryAloneWhenSmall && !large.boolValue;
303
+ BOOL alone = (_primaryAloneWhenSmall && !large.boolValue) ||
304
+ (_secondaryFirst && ![self axesAllowSize:[self pairSize]]);
246
305
  if (_arranged && alone == _primaryAlone) {
247
306
  return;
248
307
  }
249
308
  BOOL changed = _arranged;
250
309
  _arranged = YES;
251
310
  _primaryAlone = alone;
252
- [self updateArrangement:alone ? ANNPrimaryAloneArrangement() : _arrangement animated:animated];
311
+ if (_secondaryFirst) {
312
+ // The secondary leaves the window with its placement, as a split with no axis takes it out otherwise.
313
+ UIViewController *first = alone ? nil : _secondary;
314
+ if ([self viewControllerForPlacement:UIArrangementViewControllerViewPlacementPrimary] !=
315
+ first) {
316
+ [self setViewController:first
317
+ forPlacement:UIArrangementViewControllerViewPlacementPrimary
318
+ animated:NO];
319
+ }
320
+ [self updateArrangement:alone ? ANNSecondPlacementAloneArrangement() : _arrangement
321
+ animated:NO];
322
+ } else {
323
+ [self updateArrangement:alone ? ANNPrimaryAloneArrangement() : _arrangement animated:NO];
324
+ }
253
325
  // A secondary that leaves the window renders no content: the pair waits for it no more.
254
326
  if (alone && _secondaryCounted) {
255
327
  _secondaryCounted = NO;
@@ -262,8 +334,103 @@ static BOOL ANNIsShown(UIViewController *screen, UIArrangementViewState *state,
262
334
  }
263
335
  }
264
336
 
337
+ // Where the axes leave the pair no room, UIKit shows its primary placement alone: with the secondary first that would
338
+ // be the secondary, so the pair takes it out itself, by the shape UIKit goes by (side by side in a wide window, one
339
+ // above the other in a tall one, measured on iPhone Duo).
340
+ - (BOOL)axesAllowSize:(CGSize)size {
341
+ if ((_axes & UIAxisHorizontal) && (_axes & UIAxisVertical)) {
342
+ return YES;
343
+ }
344
+ BOOL wide = size.width > size.height;
345
+ return (_axes & (wide ? UIAxisHorizontal : UIAxisVertical)) != 0;
346
+ }
347
+
348
+ // The pair's size: where a size transition leads, its own once laid out, the window's before.
349
+ - (CGSize)pairSize {
350
+ if (!CGSizeEqualToSize(_transitionSize, CGSizeZero)) {
351
+ return _transitionSize;
352
+ }
353
+ CGSize size = self.viewIfLoaded.bounds.size;
354
+ return size.width > 0 && size.height > 0 ? size : ANNUtils.mainWindow.bounds.size;
355
+ }
356
+
357
+ // New size classes come with a new window size, which leads the pair to its new place. UIKit's own animation of the
358
+ // arrangement would aim at a layout it gives only in between (on iPhone Duo, one above the other while the window
359
+ // still has its old size classes) and play on after the pair took its real one: the screens lagged by half a second.
265
360
  - (void)sizeClassesDidChange {
266
- [self arrangeForTraits:self.traitCollection animated:self.viewIfLoaded.window != nil];
361
+ [self arrangeForTraits:self.traitCollection];
362
+ }
363
+
364
+ // On iPhone Duo the scene has its new size classes as the size transition starts, and the pair gets them only after
365
+ // UIKit laid it out in the new size: the primary first filled the whole open window, then gave half of it to the
366
+ // secondary. For the transition the pair takes the scene's size classes, so it lies as it will from its first layout.
367
+ // Only where the pair has the window's size classes: a sheet or a split view's column has its own.
368
+ - (void)viewWillTransitionToSize:(CGSize)size
369
+ withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
370
+ [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
371
+ // A new shape may leave the axes no room, or give it back: the pair takes it before its first layout in the size.
372
+ if (_secondaryFirst) {
373
+ _transitionSize = size;
374
+ [self arrangeForTraits:self.traitCollection];
375
+ __weak ANNArrangementViewController *weakPair = self;
376
+ void (^sized)(id<UIViewControllerTransitionCoordinatorContext>) =
377
+ ^(id<UIViewControllerTransitionCoordinatorContext> context) {
378
+ ANNArrangementViewController *pair = weakPair;
379
+ if (pair && CGSizeEqualToSize(pair->_transitionSize, size)) {
380
+ pair->_transitionSize = CGSizeZero;
381
+ }
382
+ };
383
+ [coordinator animateAlongsideTransition:nil completion:sized];
384
+ }
385
+ UITraitCollection *scene = self.viewIfLoaded.window.windowScene.traitCollection;
386
+ NSNumber *large = ANNIsLargeWindow(self.traitCollection);
387
+ NSNumber *largeScene = scene ? ANNIsLargeWindow(scene) : nil;
388
+ if (!large || !largeScene || ![self hasWindowSizeClasses]) {
389
+ return;
390
+ }
391
+ // The size classes the pair has now are the scene's of an earlier transition, still running: this one keeps them
392
+ // until its own end.
393
+ if ([large isEqual:largeScene] && !_sceneSizeClasses) {
394
+ return;
395
+ }
396
+ _sceneSizeClasses = YES;
397
+ NSUInteger transition = ++_sceneSizeClassesTransition;
398
+ self.traitOverrides.horizontalSizeClass = scene.horizontalSizeClass;
399
+ self.traitOverrides.verticalSizeClass = scene.verticalSizeClass;
400
+ [self updateTraitsIfNeeded];
401
+ __weak ANNArrangementViewController *weakSelf = self;
402
+ void (^ended)(id<UIViewControllerTransitionCoordinatorContext>) =
403
+ ^(id<UIViewControllerTransitionCoordinatorContext> context) {
404
+ [weakSelf dropSceneSizeClassesOfTransition:transition];
405
+ };
406
+ [coordinator animateAlongsideTransition:nil completion:ended];
407
+ }
408
+
409
+ - (void)dropSceneSizeClassesOfTransition:(NSUInteger)transition {
410
+ if (!_sceneSizeClasses || transition != _sceneSizeClassesTransition) {
411
+ return;
412
+ }
413
+ _sceneSizeClasses = NO;
414
+ [self.traitOverrides removeTrait:UITraitHorizontalSizeClass.class];
415
+ [self.traitOverrides removeTrait:UITraitVerticalSizeClass.class];
416
+ }
417
+
418
+ // The pair's size classes are the window's: it stands in the window's root, not in a presented layer, and no split
419
+ // view's column is between them.
420
+ - (BOOL)hasWindowSizeClasses {
421
+ UIWindow *window = self.viewIfLoaded.window;
422
+ if (!window) {
423
+ return NO;
424
+ }
425
+ UIViewController *top = self;
426
+ for (UIViewController *parent = self.parentViewController; parent;
427
+ parent = parent.parentViewController) {
428
+ if ([parent isKindOfClass:UISplitViewController.class]) {
429
+ return NO;
430
+ }
431
+ top = parent;
432
+ }
433
+ return top == window.rootViewController;
267
434
  }
268
435
 
269
436
  // The first state, before the pair is laid out: as UIKit lays it out in the window's shape (measured on iPhone Duo),
@@ -296,9 +463,9 @@ static BOOL ANNIsShown(UIViewController *screen, UIArrangementViewState *state,
296
463
  ofScreen:(UIViewController *)screen
297
464
  eventEmitter:(ANNEventEmitter *)eventEmitter {
298
465
  if (ANNKeepsState(screen)) {
299
- [ANNArrangementState setState:state
300
- forScreenId:screen.layoutInfo.componentId
301
- eventEmitter:eventEmitter];
466
+ [ANNScreenEnvironment setArrangement:state
467
+ forScreenId:screen.layoutInfo.componentId
468
+ eventEmitter:eventEmitter];
302
469
  }
303
470
  }
304
471
 
@@ -431,13 +598,17 @@ static BOOL ANNIsShown(UIViewController *screen, UIArrangementViewState *state,
431
598
 
432
599
  - (void)viewDidLayoutSubviews {
433
600
  [super viewDidLayoutSubviews];
601
+ // A size of its own without a transition (a column of a split view): the axes may allow another shape now.
602
+ if (_secondaryFirst) {
603
+ [self arrangeForTraits:self.traitCollection];
604
+ }
434
605
  [self setNeedsStateUpdate];
435
606
  }
436
607
 
437
608
  // In the window now: its own size classes, which the window's stood in for.
438
609
  - (void)viewWillAppear:(BOOL)animated {
439
610
  [super viewWillAppear:animated];
440
- [self arrangeForTraits:self.traitCollection animated:NO];
611
+ [self arrangeForTraits:self.traitCollection];
441
612
  }
442
613
 
443
614
  - (void)viewDidAppear:(BOOL)animated {
@@ -477,10 +648,12 @@ static BOOL ANNIsShown(UIViewController *screen, UIArrangementViewState *state,
477
648
  if (!self.viewIfLoaded.window || _screensDestroyed) {
478
649
  return;
479
650
  }
651
+ // By the screens' placements: with `primaryEdge` at the trailing side or the bottom they are the other way round,
652
+ // and a secondary out of its placement has none.
480
653
  UIArrangementViewState *primaryState =
481
- [self stateForPlacement:UIArrangementViewControllerViewPlacementPrimary];
654
+ [self stateForPlacement:[self placementForViewController:_primary]];
482
655
  UIArrangementViewState *secondaryState =
483
- [self stateForPlacement:UIArrangementViewControllerViewPlacementSecondary];
656
+ [self stateForPlacement:[self placementForViewController:_secondary]];
484
657
  CGRect primaryFrame = ANNShownFrame(_primary.viewIfLoaded, self.view);
485
658
  CGRect secondaryFrame = ANNShownFrame(_secondary.viewIfLoaded, self.view);
486
659
  BOOL primaryShown = ANNIsShown(_primary, primaryState, primaryFrame);
@@ -496,7 +669,8 @@ static BOOL ANNIsShown(UIViewController *screen, UIArrangementViewState *state,
496
669
  CGRect overlap = CGRectIntersection(primaryFrame, secondaryFrame);
497
670
  if (!CGRectIsNull(overlap) && overlap.size.width > 1 && overlap.size.height > 1) {
498
671
  layout = @"overlay";
499
- // UIKit puts the primary over the secondary (zIndex 1 and 0).
672
+ // UIKit puts the primary over the secondary (zIndex 1 and 0); an overlay keeps the screens in their own
673
+ // placements.
500
674
  primaryFront = primaryState.zIndex >= secondaryState.zIndex;
501
675
  secondaryFront = !primaryFront;
502
676
  } else {
@@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN
25
25
 
26
26
  /// `dismissModal`: the record of `componentId` (its root's id or any id inside, also of a modal closed below or by the
27
27
  /// user), the options merged into its visible screen, the animation from the command's screen, then its state decides.
28
- /// Answers with the root's id.
28
+ /// Answers with the root's id. The last modal over no root rejects `[ANNErrorTexts modalWithoutRoot:]`, as on Android.
29
29
  + (void)dismissModal:(NSString *)componentId
30
30
  options:(nullable NSDictionary *)options
31
31
  answer:(ANNCommandAnswer *)answer;
@@ -233,7 +233,7 @@ static void ANNCollectIds(UIViewController *node, NSMutableSet<NSString *> *ids)
233
233
  limit:contentFirst ? 0 : ANNModalRenderLimit
234
234
  bar:contentFirst ? ANNRenderWaitBarAfterContent : ANNRenderWaitBarWithContent
235
235
  barLimits:contentFirst ? ownPhase : withContent];
236
- wait.mountLimit = ANNModalRenderLimit;
236
+ wait.unseenLimit = ANNModalRenderLimit;
237
237
  wait.protect = ^(dispatch_block_t step) {
238
238
  [ANNModalCoordinator protect:weakModal step:step];
239
239
  };
@@ -277,8 +277,8 @@ static void ANNCollectIds(UIViewController *node, NSMutableSet<NSString *> *ids)
277
277
 
278
278
  // The end steps of a record (its show presented, its dismissal ended, closed by the user) run inside UIKit's
279
279
  // completions and delegate calls, outside the runner's protection, in any state: a failure there is logged in one line,
280
- // rejects what of the record still waits for an answer (its show, a chain step, its dismissals), and its drive stops.
281
- // The gate's `done` ran before the step, as without a failure.
280
+ // answers what of the record still waits for an answer (its show, a chain step, its dismissals:
281
+ // `endFailedOf:showing:exception:`), and its drive stops. The gate's `done` ran before the step, as without a failure.
282
282
  + (void)protectEndOf:(ANNModal *)modal showing:(BOOL)showing step:(dispatch_block_t)step {
283
283
  @try {
284
284
  step();
@@ -288,24 +288,43 @@ static void ANNCollectIds(UIViewController *node, NSMutableSet<NSString *> *ids)
288
288
  : (showing ? @"show a modal" : @"dismiss a modal");
289
289
  NSString *reason = exception.reason.length > 0 ? exception.reason : exception.name;
290
290
  RCTLogWarn(@"[ApexNavigation] %@", [ANNErrorTexts couldNot:what reason:reason]);
291
- [self endFailedOf:modal exception:exception];
291
+ [self endFailedOf:modal showing:showing exception:exception];
292
292
  }
293
293
  }
294
294
 
295
- + (void)endFailedOf:(ANNModal *)modal exception:(NSException *)exception {
295
+ // A failed end step of `modal`: its show rejects. After a failed show the dismissals that wait for it don't fail with
296
+ // it, as on Android: on a modal that shows they run now and resolve once it went (one still `Presenting` shows: UIKit's
297
+ // completion ran); on one that goes another way (a `dismissAllModals`, with the old root) or went already they resolve
298
+ // with its root's id; on one in another transition (a drag, its own dismissal) they wait for that transition's end.
299
+ // A failed dismissal rejects itself and the dismissals behind it.
300
+ + (void)endFailedOf:(ANNModal *)modal showing:(BOOL)showing exception:(NSException *)exception {
296
301
  if (!modal) {
297
302
  return;
298
303
  }
299
304
  [self stopDriving:modal];
300
305
  NSString *show = [NSString stringWithFormat:@"show the screen '%@'", modal.rootId];
301
- NSString *dismiss = [NSString stringWithFormat:@"dismiss the modal '%@'", modal.rootId];
302
306
  [modal.showAnswer reject:[ANNCommandRunner rejectionOf:exception what:show]];
303
- NSString *dismissText = [ANNCommandRunner rejectionOf:exception what:dismiss];
304
- [modal.dismissal.answer reject:dismissText];
305
- NSArray<ANNModalDismissal *> *pending = modal.pending.copy;
306
- [modal.pending removeAllObjects];
307
- for (ANNModalDismissal *waiting in pending) {
308
- [waiting.answer reject:dismissText];
307
+ ANNModalState state = modal.state;
308
+ BOOL goesAnotherWay = (state == ANNModalStateDismissing && modal.batch) ||
309
+ state == ANNModalStateWithOldRoot ||
310
+ state == ANNModalStateClosedBelow || state == ANNModalStateGone;
311
+ if (showing && state == ANNModalStatePresenting) {
312
+ modal.state = ANNModalStateShown;
313
+ }
314
+ if (showing && modal.state == ANNModalStateShown) {
315
+ [self runPendingOf:modal];
316
+ } else if (showing && goesAnotherWay) {
317
+ [modal.dismissal.answer resolve:modal.rootId];
318
+ [self resolvePendingOf:modal];
319
+ } else if (!showing) {
320
+ NSString *dismiss = [NSString stringWithFormat:@"dismiss the modal '%@'", modal.rootId];
321
+ NSString *dismissText = [ANNCommandRunner rejectionOf:exception what:dismiss];
322
+ [modal.dismissal.answer reject:dismissText];
323
+ NSArray<ANNModalDismissal *> *pending = modal.pending.copy;
324
+ [modal.pending removeAllObjects];
325
+ for (ANNModalDismissal *waiting in pending) {
326
+ [waiting.answer reject:dismissText];
327
+ }
309
328
  }
310
329
  // A `setRoot` chain goes on (its own steps are guarded by the root coordinator).
311
330
  void (^chainStep)(BOOL) = modal.chainStep;
@@ -333,7 +352,7 @@ static void ANNCollectIds(UIViewController *node, NSMutableSet<NSString *> *ids)
333
352
  [waiter reject:text];
334
353
  }
335
354
  for (ANNModal *modal in batch.records.copy) {
336
- [self endFailedOf:modal exception:exception];
355
+ [self endFailedOf:modal showing:NO exception:exception];
337
356
  }
338
357
  }
339
358
  }
@@ -407,7 +426,7 @@ static void ANNCollectIds(UIViewController *node, NSMutableSet<NSString *> *ids)
407
426
  ANNNavigationOptions *resolved = [root resolveOptionsWithDefault];
408
427
  ANNModalPresentation *presentation =
409
428
  [[ANNModalPresentation alloc] initWithOptions:resolved animated:modal.animatedOverride];
410
- NSString *problem = [presentation problemPresentingFrom:presenting windowRoot:windowRoot];
429
+ NSString *problem = [presentation fitToPresenting:presenting windowRoot:windowRoot];
411
430
  if (problem) {
412
431
  [self failShowOf:modal reason:problem];
413
432
  done();
@@ -537,7 +556,8 @@ static void ANNCollectIds(UIViewController *node, NSMutableSet<NSString *> *ids)
537
556
  modal.coversUnder = under != nil && under.viewIfLoaded.window == nil;
538
557
  NSArray<UIViewController *> *hidden = modal.coversUnder ? @[ under ] : @[];
539
558
  @try {
540
- // The chain step stays on the record until its events went: a failure there tells the chain (`endFailedOf:`).
559
+ // The chain step stays on the record until its events went: a failure there tells the chain
560
+ // (`endFailedOf:showing:exception:`).
541
561
  void (^chainStep)(BOOL) = modal.chainStep;
542
562
  if (chainStep) {
543
563
  [ANNAppearanceDispatcher endSwitchHiding:hidden showing:@[ root ] events:nil];
@@ -778,6 +798,11 @@ static void ANNCollectIds(UIViewController *node, NSMutableSet<NSString *> *ids)
778
798
  [answer reject:[ANNErrorTexts screenNotShown:componentId]];
779
799
  return;
780
800
  }
801
+ // The last modal over no root (shown before any `setRoot`) stays: nothing would be left to show, as on Android.
802
+ if ([self isLastWithoutRoot:modal]) {
803
+ [answer reject:[ANNErrorTexts modalWithoutRoot:componentId]];
804
+ return;
805
+ }
781
806
  // Step 1: the options, read on the main queue; one that can't be read rejects before anything changes. They merge
782
807
  // into the modal's visible screen as `mergeOptions` would.
783
808
  if (options.count > 0) {
@@ -815,6 +840,22 @@ static void ANNCollectIds(UIViewController *node, NSMutableSet<NSString *> *ids)
815
840
  [self dismiss:modal with:dismissal];
816
841
  }
817
842
 
843
+ // No root in the window (the splash, or nothing yet) and no other modal that shows or comes: `modal` is all a dismissal
844
+ // would take away. One closed below, going with the old root or gone takes nothing away, so it doesn't count.
845
+ + (BOOL)isLastWithoutRoot:(ANNModal *)modal {
846
+ if (modal.state == ANNModalStateClosedBelow || modal.state == ANNModalStateGone ||
847
+ ApexNavigation.mainWindow.rootViewController.isLayoutNode) {
848
+ return NO;
849
+ }
850
+ for (ANNModal *other in ANNModals) {
851
+ if (other != modal && other.state != ANNModalStateClosedBelow &&
852
+ other.state != ANNModalStateWithOldRoot && other.state != ANNModalStateGone) {
853
+ return NO;
854
+ }
855
+ }
856
+ return YES;
857
+ }
858
+
818
859
  // The modal of `node`: the record whose root is the top of `node`'s layout.
819
860
  + (ANNModal *)modalOf:(UIViewController *)node {
820
861
  UIViewController *top = node;
@@ -897,7 +938,7 @@ static void ANNCollectIds(UIViewController *node, NSMutableSet<NSString *> *ids)
897
938
  [ANNErrorTexts couldNot:what reason:exception.reason ?: exception.name]);
898
939
  // The dismissal still open answers, and so do the dismissals waiting behind it (an answer given already
899
940
  // stays as it was).
900
- [self endFailedOf:modal exception:exception];
941
+ [self endFailedOf:modal showing:NO exception:exception];
901
942
  done();
902
943
  }
903
944
  }
@@ -20,7 +20,8 @@ NS_ASSUME_NONNULL_BEGIN
20
20
 
21
21
  /// `modalPresentationStyle`: one to one; unset is UIKit's automatic style; an unknown string full screen.
22
22
  @property(nonatomic, readonly) UIModalPresentationStyle style;
23
- /// `modalTransitionStyle`: `coverVertical` unless one of the others is given.
23
+ /// `modalTransitionStyle`: `coverVertical` unless one of the others is given; `partialCurl` only where UIKit curls
24
+ /// (`fitToPresenting:windowRoot:`).
24
25
  @property(nonatomic, readonly) UIModalTransitionStyle transitionStyle;
25
26
  /// The present is animated: `enter.enabled` is not `false`.
26
27
  @property(nonatomic, readonly) BOOL animated;
@@ -47,10 +48,12 @@ NS_ASSUME_NONNULL_BEGIN
47
48
  animation:(nullable ANNModalAnimationOptions *)animation
48
49
  under:(nullable UIViewController *)under;
49
50
 
50
- /// Why UIKit can't make this show from `presenting` (`partialCurl` only full screen, to and from), as the reason of the
51
- /// rejection; nil when it can. `windowRoot` is the main window's root.
52
- - (nullable NSString *)problemPresentingFrom:(UIViewController *)presenting
53
- windowRoot:(nullable UIViewController *)windowRoot;
51
+ /// Fits the show to `presenting`, before `prepare:…`: `partialCurl` stays only for a full-screen modal over a
52
+ /// controller that fills the screen (`presenting` is `windowRoot`, the main window's root, or a full-screen modal);
53
+ /// otherwise `transitionStyle` becomes `coverVertical`. Returns why UIKit can't make the show (`presenting` was shown
54
+ /// with `partialCurl`), as the reason of the rejection; nil when it can.
55
+ - (nullable NSString *)fitToPresenting:(UIViewController *)presenting
56
+ windowRoot:(nullable UIViewController *)windowRoot;
54
57
 
55
58
  /// Before `presentViewController:`: the style and the transition, the presentation's delegate, the popover kept a
56
59
  /// popover (`adaptive: false`), the sheet, the size, the popover's source on `presentingLayout`, the hold, the
@@ -118,21 +118,21 @@ static NSDictionary<NSString *, NSNumber *> *ANNTransitionStyles(void) {
118
118
  return nil;
119
119
  }
120
120
 
121
- // UIKit takes `partialCurl` only for a full-screen modal over a controller that fills the screen, and a controller
122
- // shown with `partialCurl` presents nothing more: the command rejects before it asks UIKit.
123
- - (NSString *)problemPresentingFrom:(UIViewController *)presenting
124
- windowRoot:(UIViewController *)windowRoot {
121
+ // UIKit curls only a full-screen modal over a controller that fills the screen: elsewhere `partialCurl` is
122
+ // `coverVertical`, so the modal still shows. A controller shown with `partialCurl` presents nothing more: the command
123
+ // rejects before it asks UIKit.
124
+ - (NSString *)fitToPresenting:(UIViewController *)presenting
125
+ windowRoot:(UIViewController *)windowRoot {
125
126
  if (presenting.presentingViewController &&
126
127
  presenting.modalTransitionStyle == UIModalTransitionStylePartialCurl) {
127
- return @"partialCurl needs a full screen modal";
128
+ return @"a modal shown with partialCurl can't show another modal";
128
129
  }
129
- if (_transitionStyle != UIModalTransitionStylePartialCurl) {
130
- return nil;
131
- }
132
- BOOL presentingFills = presenting == windowRoot ||
133
- presenting.modalPresentationStyle == UIModalPresentationFullScreen;
134
- if (_style != UIModalPresentationFullScreen || !presentingFills) {
135
- return @"partialCurl needs a full screen modal";
130
+ if (_transitionStyle == UIModalTransitionStylePartialCurl) {
131
+ BOOL presentingFills = presenting == windowRoot ||
132
+ presenting.modalPresentationStyle == UIModalPresentationFullScreen;
133
+ if (_style != UIModalPresentationFullScreen || !presentingFills) {
134
+ _transitionStyle = UIModalTransitionStyleCoverVertical;
135
+ }
136
136
  }
137
137
  return nil;
138
138
  }