@apexnative/navigation 1.0.0-alpha.5 → 1.0.0-alpha.7

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 (358) hide show
  1. package/ApexNavigation.podspec +2 -1
  2. package/CHANGELOG.md +32 -0
  3. package/README.md +1 -1
  4. package/android/CLAUDE.md +31 -20
  5. package/android/CORE.md +12 -8
  6. package/android/consumer-rules.pro +6 -0
  7. package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +36 -5
  8. package/android/src/main/java/dev/apexnative/navigation/options/BottomTabOptions.kt +1 -1
  9. package/android/src/main/java/dev/apexnative/navigation/options/BottomTabsOptions.kt +13 -8
  10. package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +1 -1
  11. package/android/src/main/java/dev/apexnative/navigation/options/LargeTitleOptions.kt +1 -1
  12. package/android/src/main/java/dev/apexnative/navigation/options/LayoutAnimation.kt +1 -1
  13. package/android/src/main/java/dev/apexnative/navigation/options/OptionKey.kt +18 -0
  14. package/android/src/main/java/dev/apexnative/navigation/options/OptionPaths.kt +91 -0
  15. package/android/src/main/java/dev/apexnative/navigation/options/SheetOptions.kt +7 -4
  16. package/android/src/main/java/dev/apexnative/navigation/options/TitleOptions.kt +2 -2
  17. package/android/src/main/java/dev/apexnative/navigation/options/TopBarAppearanceOptions.kt +1 -1
  18. package/android/src/main/java/dev/apexnative/navigation/options/TopBarOptions.kt +16 -7
  19. package/android/src/main/java/dev/apexnative/navigation/react/ContentHeights.kt +95 -0
  20. package/android/src/main/java/dev/apexnative/navigation/react/ContentMounts.kt +66 -0
  21. package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +7 -3
  22. package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +41 -3
  23. package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +16 -1
  24. package/android/src/main/java/dev/apexnative/navigation/react/ReloadCoordinator.kt +0 -2
  25. package/android/src/main/java/dev/apexnative/navigation/react/ScreenEnvironment.kt +177 -0
  26. package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +12 -49
  27. package/android/src/main/java/dev/apexnative/navigation/react/ScrollEvents.kt +49 -128
  28. package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +6 -6
  29. package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +27 -7
  30. package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +12 -1
  31. package/android/src/main/java/dev/apexnative/navigation/utils/MaterialTheme.kt +5 -6
  32. package/android/src/main/java/dev/apexnative/navigation/utils/SystemAnimations.kt +36 -0
  33. package/android/src/main/java/dev/apexnative/navigation/utils/ViewExtensions.kt +0 -13
  34. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementController.kt +9 -7
  35. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsCollapseBehavior.kt +5 -3
  36. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +13 -10
  37. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowGeometry.kt +22 -0
  38. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabsRoom.kt +0 -5
  39. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +7 -8
  40. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenSafeArea.kt +29 -11
  41. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/externalcomponent/ExternalComponentViewController.kt +2 -6
  42. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +20 -2
  43. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +443 -58
  44. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +33 -5
  45. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetBack.kt +42 -0
  46. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +60 -2
  47. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +4 -0
  48. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +3 -6
  49. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +8 -2
  50. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +32 -4
  51. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/PreparedFrame.kt +3 -3
  52. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +2 -2
  53. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +50 -7
  54. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +15 -3
  55. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +10 -4
  56. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabMotion.kt +142 -0
  57. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +215 -43
  58. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +25 -26
  59. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarRowTransition.kt +3 -2
  60. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/ButtonPlaces.kt +11 -5
  61. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +36 -38
  62. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ScrollEventListener.kt +6 -9
  63. package/android/src/main/java/dev/apexnative/navigation/views/animations/AnimationLayer.kt +73 -0
  64. package/android/src/main/java/dev/apexnative/navigation/views/animations/ValueInterpolation.kt +14 -0
  65. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabsLayout.kt +61 -2
  66. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomTabRow.kt +72 -10
  67. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +129 -179
  68. package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +8 -1
  69. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
  70. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +67 -3
  71. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +346 -36
  72. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMorph.kt +199 -0
  73. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +55 -42
  74. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextMorph.kt +176 -0
  75. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewMorph.kt +108 -0
  76. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabCopy.kt +85 -0
  77. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabMenu.kt +13 -0
  78. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +5 -24
  79. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +51 -34
  80. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonComponentCell.kt +6 -6
  81. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonView.kt +113 -0
  82. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarMenu.kt +219 -0
  83. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +121 -175
  84. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonMenus.kt +34 -64
  85. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonRow.kt +216 -0
  86. package/android/src/main/jni/ANNContentHeights.cpp +82 -0
  87. package/android/src/main/res/drawable/apex_navigation_ic_arrow_right.xml +14 -0
  88. package/android/src/main/res/layout/apex_navigation_menu_header.xml +19 -0
  89. package/android/src/main/res/layout/apex_navigation_menu_item.xml +68 -0
  90. package/android/src/main/res/values/styles.xml +1 -1
  91. package/android/src/main/res/values-night/styles.xml +1 -1
  92. package/cli/doctor/checks/app.js +16 -1
  93. package/cli/project.js +4 -0
  94. package/cli/setup/index.js +5 -0
  95. package/cli/setup/steps/metro.js +46 -0
  96. package/docs-md/architecture/native-screens.md +4 -0
  97. package/docs-md/architecture/theme-and-context.md +131 -12
  98. package/docs-md/architecture/transitions.md +46 -5
  99. package/docs-md/containers/modals.md +2 -0
  100. package/docs-md/containers/overlays.md +1 -1
  101. package/docs-md/containers/side-menu.md +1 -1
  102. package/docs-md/containers/tabs.md +2 -0
  103. package/docs-md/flows/bottom-sheets.md +4 -2
  104. package/docs-md/fundamentals/screens-and-props.md +9 -1
  105. package/docs-md/fundamentals/starting-the-app.md +1 -1
  106. package/docs-md/guides/cli.md +3 -1
  107. package/docs-md/help/glossary.md +2 -2
  108. package/docs-md/help/troubleshooting.md +22 -1
  109. package/docs-md/index.json +41 -1
  110. package/docs-md/migration/from-expo-router.md +1 -1
  111. package/docs-md/migration/from-react-native-navigation.md +1 -1
  112. package/docs-md/migration/from-react-navigation.md +2 -2
  113. package/docs-md/screen-ui/back-and-gestures.md +17 -1
  114. package/docs-md/screen-ui/bar-buttons.md +5 -5
  115. package/docs-md/screen-ui/search.md +1 -1
  116. package/docs-md/screen-ui/system-ui.md +16 -11
  117. package/docs-md/screen-ui/toolbar-and-fab.md +4 -2
  118. package/docs-md/screen-ui/top-bar.md +8 -4
  119. package/docs-md/start/installation.md +16 -1
  120. package/ios/Animations/ANNFrameDriver.h +55 -15
  121. package/ios/Animations/ANNFrameDriver.mm +216 -60
  122. package/ios/Animations/ANNTransitionAnimator.h +26 -5
  123. package/ios/Animations/ANNTransitionAnimator.mm +49 -3
  124. package/ios/Animations/ANNTransitionPlan.h +2 -2
  125. package/ios/Animations/ANNTransitionPlan.mm +10 -0
  126. package/ios/Animations/Elements/ANNElementFinder.h +2 -2
  127. package/ios/Animations/Elements/ANNElementFinder.mm +2 -2
  128. package/ios/Animations/Elements/ANNElementTransition.h +3 -3
  129. package/ios/Animations/Elements/ANNElementTransition.mm +2 -2
  130. package/ios/Animations/Elements/ANNSharedElementFlight.h +3 -3
  131. package/ios/Animations/Elements/ANNSharedElementFlight.mm +249 -45
  132. package/ios/Animations/Interpolators/ANNInterpolate.h +2 -30
  133. package/ios/Animations/Interpolators/ANNTransformParts.h +48 -0
  134. package/ios/Animations/Interpolators/ANNTransformParts.mm +507 -0
  135. package/ios/Animations/Interpolators/ANNViewTracks.h +9 -6
  136. package/ios/Animations/Interpolators/ANNViewTracks.mm +100 -30
  137. package/ios/CLAUDE.md +32 -22
  138. package/ios/CORE.md +25 -21
  139. package/ios/Contract/ANNCommandRunner.h +8 -7
  140. package/ios/Contract/ANNCommandRunner.mm +21 -27
  141. package/ios/Contract/ANNLayoutNode.h +3 -3
  142. package/ios/Contract/ANNLayoutReader.h +3 -3
  143. package/ios/Core/ANNAppDelegate.mm +0 -2
  144. package/ios/Core/ANNDeepLinkQueue.h +6 -5
  145. package/ios/Core/ANNDeepLinkQueue.mm +22 -10
  146. package/ios/Core/ANNJavaScriptCalls.h +11 -12
  147. package/ios/Core/ANNJavaScriptCalls.mm +7 -16
  148. package/ios/Core/ANNReloadCoordinator.mm +4 -8
  149. package/ios/Core/ANNSceneDelegate.mm +2 -2
  150. package/ios/Core/ApexNavigation+Internal.h +1 -1
  151. package/ios/Core/ApexNavigation.mm +6 -2
  152. package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
  153. package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
  154. package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +4 -4
  155. package/ios/Layouts/Root/ANNRootCoordinator.mm +45 -15
  156. package/ios/Layouts/Screen/ANNComponentViewController.h +2 -2
  157. package/ios/Layouts/Screen/ANNComponentViewController.mm +13 -23
  158. package/ios/Layouts/Screen/ANNPreviewInteraction.h +7 -4
  159. package/ios/Layouts/Screen/ANNPreviewInteraction.mm +72 -10
  160. package/ios/Layouts/Screen/ANNScreenEnvironment.h +63 -0
  161. package/ios/Layouts/Screen/ANNScreenEnvironment.mm +181 -0
  162. package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
  163. package/ios/Layouts/Screen/ANNScreenRegions.mm +0 -38
  164. package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
  165. package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
  166. package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
  167. package/ios/Layouts/Stack/ANNPreviewPush.mm +57 -5
  168. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
  169. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
  170. package/ios/Layouts/Stack/ANNStackController.h +8 -0
  171. package/ios/Layouts/Stack/ANNStackController.mm +153 -11
  172. package/ios/Layouts/Stack/ANNSwipePopInteraction.h +26 -0
  173. package/ios/Layouts/Stack/ANNSwipePopInteraction.mm +185 -0
  174. package/ios/Layouts/Stack/InteractivePopGestureDelegate.mm +28 -4
  175. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
  176. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
  177. package/ios/Layouts/Tabs/ANNBottomTabsController.mm +2 -1
  178. package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
  179. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +4 -0
  180. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +123 -36
  181. package/ios/Layouts/Tabs/ANNTabsDesign.h +6 -5
  182. package/ios/Layouts/Tabs/ANNTabsDesign.mm +9 -1
  183. package/ios/Layouts/Tabs/UITabBar+utils.h +5 -5
  184. package/ios/Layouts/Tabs/UITabBar+utils.mm +32 -13
  185. package/ios/Options/ANNAnimationOptions.h +2 -1
  186. package/ios/Options/ANNAnimationOptions.mm +1 -1
  187. package/ios/Options/ANNBottomTabsOptions.h +2 -0
  188. package/ios/Options/ANNBottomTabsOptions.mm +1 -0
  189. package/ios/Options/ANNOptions.h +25 -0
  190. package/ios/Options/ANNOptions.mm +157 -1
  191. package/ios/Options/ANNOptionsReader.mm +108 -0
  192. package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
  193. package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
  194. package/ios/Options/Params/ANNParam.h +15 -0
  195. package/ios/Options/Params/ANNParam.mm +61 -0
  196. package/ios/Options/Params/Color.h +3 -0
  197. package/ios/Options/Params/Color.mm +21 -0
  198. package/ios/Options/Params/ColorParser.h +4 -3
  199. package/ios/Options/Params/ColorParser.mm +22 -4
  200. package/ios/Options/Params/Image.h +4 -0
  201. package/ios/Options/Params/Image.mm +20 -0
  202. package/ios/React/ANNReactView.mm +6 -25
  203. package/ios/React/ANNSafeAreaViewComponentView.mm +26 -15
  204. package/ios/React/ANNSurfaceHostingView.h +14 -0
  205. package/ios/React/ANNSurfaceHostingView.mm +144 -1
  206. package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
  207. package/ios/TopBar/ANNBackButtonPresenter.mm +6 -5
  208. package/ios/TopBar/ANNBarAppearance.h +2 -1
  209. package/ios/TopBar/ANNBarAppearance.mm +111 -30
  210. package/ios/TopBar/ANNBarBackgroundComponent.mm +16 -0
  211. package/ios/TopBar/ANNBarButtonComponentView.h +4 -4
  212. package/ios/TopBar/ANNBarButtonComponentView.mm +1 -1
  213. package/ios/TopBar/ANNBarButtons.h +5 -3
  214. package/ios/TopBar/ANNBarButtons.mm +186 -17
  215. package/ios/TopBar/ANNLargeTitlePresenter.mm +24 -4
  216. package/ios/TopBar/ANNMainList.h +3 -0
  217. package/ios/TopBar/ANNMainList.mm +4 -0
  218. package/ios/TopBar/ANNScrollEdgeEffects.h +22 -6
  219. package/ios/TopBar/ANNScrollEdgeEffects.mm +123 -16
  220. package/ios/TopBar/ANNSearchPresenter.mm +2 -2
  221. package/ios/TopBar/ANNSearchResultsViewController.mm +5 -5
  222. package/ios/TopBar/ANNTopBarPresenter.h +3 -2
  223. package/ios/TopBar/ANNTopBarPresenter.mm +95 -22
  224. package/ios/TurboModules/ANNTurboModule.mm +66 -16
  225. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.cpp +20 -0
  226. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.h +5 -14
  227. package/lib/module/ARCHITECTURE.md +17 -7
  228. package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
  229. package/lib/module/api/app/AppRegistry.js +14 -2
  230. package/lib/module/api/app/AppRegistry.js.map +1 -1
  231. package/lib/module/api/app/createNavigation.js +188 -66
  232. package/lib/module/api/app/createNavigation.js.map +1 -1
  233. package/lib/module/api/events/navigationEvents.js +6 -2
  234. package/lib/module/api/events/navigationEvents.js.map +1 -1
  235. package/lib/module/api/hooks/useSafeAreaInsets.js +4 -3
  236. package/lib/module/api/hooks/useSafeAreaInsets.js.map +1 -1
  237. package/lib/module/api/linking/linking.js +11 -0
  238. package/lib/module/api/linking/linking.js.map +1 -1
  239. package/lib/module/api/options/OptionsChain.js +2 -2
  240. package/lib/module/api/screens/defineScreen.js +45 -3
  241. package/lib/module/api/screens/defineScreen.js.map +1 -1
  242. package/lib/module/api/screens/nativeScreens.js +31 -6
  243. package/lib/module/api/screens/nativeScreens.js.map +1 -1
  244. package/lib/module/api/screens/registerScreens.js +172 -35
  245. package/lib/module/api/screens/registerScreens.js.map +1 -1
  246. package/lib/module/api/theme/theme.js +5 -0
  247. package/lib/module/api/theme/theme.js.map +1 -1
  248. package/lib/module/engine/commands.js +42 -2
  249. package/lib/module/engine/commands.js.map +1 -1
  250. package/lib/module/engine/layout.js +7 -2
  251. package/lib/module/engine/layout.js.map +1 -1
  252. package/lib/module/engine/nativeScreens.js +9 -0
  253. package/lib/module/engine/nativeScreens.js.map +1 -1
  254. package/lib/module/engine/options.js +5 -4
  255. package/lib/module/engine/options.js.map +1 -1
  256. package/lib/module/engine/optionsChange.js +102 -0
  257. package/lib/module/engine/optionsChange.js.map +1 -0
  258. package/lib/module/engine/refresh.js +85 -0
  259. package/lib/module/engine/refresh.js.map +1 -0
  260. package/lib/module/engine/rememberedOptions.js +60 -0
  261. package/lib/module/engine/rememberedOptions.js.map +1 -1
  262. package/lib/module/engine/screens.js +55 -4
  263. package/lib/module/engine/screens.js.map +1 -1
  264. package/lib/typescript/adapters/NativeANNTurboModule.d.ts +7 -0
  265. package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
  266. package/lib/typescript/api/app/AppRegistry.d.ts.map +1 -1
  267. package/lib/typescript/api/app/createNavigation.d.ts +8 -3
  268. package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
  269. package/lib/typescript/api/events/navigationEvents.d.ts +2 -2
  270. package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
  271. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts +4 -3
  272. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
  273. package/lib/typescript/api/index.d.ts +1 -1
  274. package/lib/typescript/api/index.d.ts.map +1 -1
  275. package/lib/typescript/api/linking/linking.d.ts +8 -0
  276. package/lib/typescript/api/linking/linking.d.ts.map +1 -1
  277. package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
  278. package/lib/typescript/api/screens/defineScreen.d.ts +23 -4
  279. package/lib/typescript/api/screens/defineScreen.d.ts.map +1 -1
  280. package/lib/typescript/api/screens/nativeScreens.d.ts +8 -1
  281. package/lib/typescript/api/screens/nativeScreens.d.ts.map +1 -1
  282. package/lib/typescript/api/screens/registerScreens.d.ts.map +1 -1
  283. package/lib/typescript/api/theme/theme.d.ts +2 -0
  284. package/lib/typescript/api/theme/theme.d.ts.map +1 -1
  285. package/lib/typescript/engine/commands.d.ts +5 -0
  286. package/lib/typescript/engine/commands.d.ts.map +1 -1
  287. package/lib/typescript/engine/layout.d.ts.map +1 -1
  288. package/lib/typescript/engine/nativeScreens.d.ts +5 -0
  289. package/lib/typescript/engine/nativeScreens.d.ts.map +1 -1
  290. package/lib/typescript/engine/optionsChange.d.ts +28 -0
  291. package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
  292. package/lib/typescript/engine/refresh.d.ts +35 -0
  293. package/lib/typescript/engine/refresh.d.ts.map +1 -0
  294. package/lib/typescript/engine/rememberedOptions.d.ts +13 -0
  295. package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
  296. package/lib/typescript/engine/screens.d.ts +27 -6
  297. package/lib/typescript/engine/screens.d.ts.map +1 -1
  298. package/lib/typescript/interfaces/ComponentEvents.d.ts +2 -2
  299. package/lib/typescript/interfaces/options/animations.d.ts +44 -14
  300. package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
  301. package/lib/typescript/interfaces/options/bottomTabs.d.ts +19 -6
  302. package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
  303. package/lib/typescript/interfaces/options/buttons.d.ts +10 -10
  304. package/lib/typescript/interfaces/options/modals.d.ts +6 -7
  305. package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
  306. package/lib/typescript/interfaces/options/stack.d.ts +8 -3
  307. package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
  308. package/lib/typescript/interfaces/options/system.d.ts +8 -5
  309. package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
  310. package/lib/typescript/interfaces/options/toolbar.d.ts +2 -2
  311. package/lib/typescript/interfaces/options/topBar.d.ts +46 -29
  312. package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
  313. package/metro/acceptPlugin.js +57 -0
  314. package/metro/babelTransformer.js +45 -0
  315. package/metro/index.js +36 -0
  316. package/package.json +3 -1
  317. package/src/ARCHITECTURE.md +17 -7
  318. package/src/adapters/NativeANNTurboModule.ts +7 -0
  319. package/src/api/app/AppRegistry.ts +16 -2
  320. package/src/api/app/createNavigation.ts +201 -69
  321. package/src/api/events/navigationEvents.ts +9 -3
  322. package/src/api/hooks/useSafeAreaInsets.ts +4 -3
  323. package/src/api/index.ts +1 -0
  324. package/src/api/linking/linking.ts +22 -1
  325. package/src/api/options/OptionsChain.ts +2 -2
  326. package/src/api/screens/defineScreen.ts +49 -5
  327. package/src/api/screens/nativeScreens.ts +40 -4
  328. package/src/api/screens/registerScreens.tsx +170 -42
  329. package/src/api/theme/theme.ts +5 -0
  330. package/src/engine/commands.ts +51 -6
  331. package/src/engine/layout.ts +11 -2
  332. package/src/engine/nativeScreens.ts +10 -1
  333. package/src/engine/options.ts +6 -8
  334. package/src/engine/optionsChange.ts +107 -0
  335. package/src/engine/refresh.ts +97 -0
  336. package/src/engine/rememberedOptions.ts +70 -0
  337. package/src/engine/screens.tsx +53 -8
  338. package/src/interfaces/ComponentEvents.ts +2 -2
  339. package/src/interfaces/options/animations.ts +44 -14
  340. package/src/interfaces/options/bottomTabs.ts +19 -6
  341. package/src/interfaces/options/buttons.ts +10 -10
  342. package/src/interfaces/options/modals.ts +6 -7
  343. package/src/interfaces/options/stack.ts +8 -3
  344. package/src/interfaces/options/system.ts +8 -5
  345. package/src/interfaces/options/toolbar.ts +2 -2
  346. package/src/interfaces/options/topBar.ts +46 -29
  347. package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -42
  348. package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -70
  349. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowPlacer.kt +0 -223
  350. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStub.kt +0 -31
  351. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +0 -136
  352. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -86
  353. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PropertyAnimatorCreator.kt +0 -33
  354. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +0 -64
  355. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +0 -177
  356. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -137
  357. package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
  358. package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -70
@@ -1,11 +1,15 @@
1
1
  #import "ANNPreviewPush.h"
2
2
  #import "ANNAssert.h"
3
+ #import "ANNCommandRunner.h"
4
+ #import "ANNComponentViewController.h"
3
5
  #import "ANNErrorTexts.h"
6
+ #import "ANNExternalViewController.h"
4
7
  #import "ANNLayoutFactory.h"
5
8
  #import "ANNParking.h"
6
9
  #import "ANNPopoverPresenter.h"
7
10
  #import "ANNPreviewInteraction.h"
8
11
  #import "ANNReloadCoordinator.h"
12
+ #import "ANNSlotContainers.h"
9
13
  #import "ANNSlotScreenView.h"
10
14
  #import "ANNStackCommands.h"
11
15
  #import "ANNStackController.h"
@@ -34,6 +38,10 @@ static const NSTimeInterval ANNPreviewSearchInterval = 1.0 / 60;
34
38
  @property(nonatomic, weak, nullable) UIView<ANNComponentProtocol> *watched;
35
39
  @property(nonatomic) BOOL attached;
36
40
  @property(nonatomic) BOOL done;
41
+ // The size of the preview, taken at the push.
42
+ @property(nonatomic) CGSize size;
43
+ // The screen rendered: at the push, or at the press for a screen of its own React root.
44
+ @property(nonatomic) BOOL rendered;
37
45
  // The screen's unseen place in the main window, at its preview size, until UIKit takes its view for the menu.
38
46
  @property(nonatomic, strong, nullable) UIView *host;
39
47
  @property(nonatomic, strong, nullable) ANNParking *parking;
@@ -51,6 +59,15 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
51
59
  return records;
52
60
  }
53
61
 
62
+ // A React screen with a root of its own renders at the press: a view with a preview costs no React root, no render and
63
+ // no effects of the screen until the user presses it. A native screen (a kind of component screen) renders as it is
64
+ // made, and a screen of the app's one tree renders in JavaScript as its slot is added: both render at the push.
65
+ static BOOL ANNPreviewRendersAtPress(UIViewController *screen) {
66
+ return [screen isKindOfClass:ANNComponentViewController.class] &&
67
+ ![screen isKindOfClass:ANNExternalViewController.class] &&
68
+ ![screen.layoutInfo.name hasPrefix:ANNSlotPrefix];
69
+ }
70
+
54
71
  @implementation ANNPreviewPush
55
72
 
56
73
  + (void)push:(ANNLayoutNode *)layout
@@ -71,6 +88,7 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
71
88
  ANNPreviewRecord *record = [ANNPreviewRecord new];
72
89
  record.previewId = layout.nodeId;
73
90
  record.screen = screen;
91
+ record.size = size;
74
92
  record.source = source;
75
93
  record.answer = answer;
76
94
  // The key applies only once the tap made the preview a screen of the stack.
@@ -81,7 +99,9 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
81
99
  record.generation = answer.generation;
82
100
  ANNPreviewRecords()[record.previewId] = record;
83
101
  @try {
84
- [self parkAndRender:record size:size];
102
+ if (!ANNPreviewRendersAtPress(screen)) {
103
+ [self parkAndRender:record];
104
+ }
85
105
  } @catch (NSException *exception) {
86
106
  [self finish:record];
87
107
  [screen destroy];
@@ -90,9 +110,11 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
90
110
  [self startSearch:record];
91
111
  }
92
112
 
93
- // The screen renders as now: its view waits unseen in the main window, at the size of the preview, so that its content
113
+ // The screen renders, once: its view waits unseen in the main window, at the size of the preview, so that its content
94
114
  // lays out; nothing waits for it.
95
- + (void)parkAndRender:(ANNPreviewRecord *)record size:(CGSize)size {
115
+ + (void)parkAndRender:(ANNPreviewRecord *)record {
116
+ record.rendered = YES;
117
+ CGSize size = record.size;
96
118
  UIWindow *window = ApexNavigation.mainWindow;
97
119
  if (window) {
98
120
  UIView *host = [[UIView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)];
@@ -207,6 +229,9 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
207
229
  record.attached = YES;
208
230
  [self stopWatching:record];
209
231
  __weak ANNPreviewRecord *weakRecord = record;
232
+ BOOL (^prepare)(void) = ^BOOL {
233
+ return [ANNPreviewPush renderAtPress:weakRecord];
234
+ };
210
235
  BOOL (^commit)(void) = ^BOOL {
211
236
  return [ANNPreviewPush commit:weakRecord];
212
237
  };
@@ -217,10 +242,35 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
217
242
  toView:view
218
243
  reactTag:view.tag
219
244
  source:source
245
+ prepare:prepare
220
246
  commit:commit
221
247
  dismissed:dismissed];
222
248
  }
223
249
 
250
+ #pragma mark - The press
251
+
252
+ // The press starts (UIKit asks for the menu's configuration, about half a second before it shows the preview): the
253
+ // screen renders now if it hasn't yet, so that its content is there when the preview shows. Out of the command's
254
+ // runner, a failure rejects the push with its text and the preview goes. YES when the screen rendered. A preview of the
255
+ // JavaScript before a reload renders nothing: its screen would start in the new one.
256
+ + (BOOL)renderAtPress:(ANNPreviewRecord *)record {
257
+ if (!record || record.done || !record.answer.isCurrent) {
258
+ return NO;
259
+ }
260
+ if (record.rendered) {
261
+ return YES;
262
+ }
263
+ @try {
264
+ [self parkAndRender:record];
265
+ } @catch (NSException *exception) {
266
+ [self finish:record];
267
+ [record.screen destroy];
268
+ [record.answer reject:[ANNCommandRunner rejectionOf:exception what:record.what]];
269
+ return NO;
270
+ }
271
+ return YES;
272
+ }
273
+
224
274
  #pragma mark - The tap
225
275
 
226
276
  // YES once the core took the preview: a key that leads back to an entry, or the push the queue accepted. From then on
@@ -267,7 +317,9 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
267
317
  return YES;
268
318
  }
269
319
  // The preview grows into the screen: a push without an animation, and without a wait, as the screen rendered
270
- // already; its answer at the end of the transaction.
320
+ // already; its answer at the end of the transaction. A screen that rendered only as the menu opened (a pointer's
321
+ // right click, then a quick tap) may have no content yet: its push waits for it as a push does.
322
+ BOOL waits = ANNPreviewRendersAtPress(screen) && !screen.reactView.isReady;
271
323
  [stack setKey:key ofEntry:screen];
272
324
  [stack.queue push:screen
273
325
  answer:record.answer
@@ -275,7 +327,7 @@ static NSMutableDictionary<NSString *, ANNPreviewRecord *> *ANNPreviewRecords(vo
275
327
  componentId:record.componentId
276
328
  source:entry
277
329
  animated:NO
278
- waits:NO];
330
+ waits:waits];
279
331
  return YES;
280
332
  }
281
333
 
@@ -12,13 +12,18 @@ NS_ASSUME_NONNULL_BEGIN
12
12
  from:(UIViewController *)from
13
13
  to:(UIViewController *)to;
14
14
 
15
+ /// The interaction of the swipe back that plays `animator`; nil for any other transition.
16
+ - (nullable id<UIViewControllerInteractiveTransitioning>)interactionForAnimator:
17
+ (id<UIViewControllerAnimatedTransitioning>)animator;
18
+
15
19
  @end
16
20
 
17
21
  /// The stack's delegate while a custom animation may be needed: it answers what the stack answers as its own delegate —
18
22
  /// every method the stack implements goes to the stack — and also the choice of the transition object. A delegate with
19
23
  /// that method turns the iOS 26 content swipe off, so the stack sets this one only while the top's `animations.pop`,
20
- /// the pushed screen's `animations.push` or a running `setStackRoot` is its own, and itself otherwise. Never an
21
- /// interaction controller: the custom transitions aren't interactive, the swipe stays UIKit's.
24
+ /// the pushed screen's `animations.push` or a running `setStackRoot` is its own, and itself otherwise. An interaction
25
+ /// controller only while `answersInteraction`: the stack's own swipe back then plays the top's own pop under the
26
+ /// finger; otherwise UIKit doesn't see the method, and the swipe stays UIKit's.
22
27
  @interface ANNStackAnimatingDelegate : NSObject <UINavigationControllerDelegate>
23
28
 
24
29
  - (instancetype)initWithStack:(UINavigationController<ANNStackAnimating> *)stack
@@ -27,6 +32,10 @@ NS_ASSUME_NONNULL_BEGIN
27
32
  - (instancetype)init NS_UNAVAILABLE;
28
33
  + (instancetype)new NS_UNAVAILABLE;
29
34
 
35
+ /// The top's pop follows the swipe back (`animations.pop.interactive`). UIKit reads the delegate's methods when it is
36
+ /// set: the stack sets the delegate again after a change.
37
+ @property(nonatomic) BOOL answersInteraction;
38
+
30
39
  @end
31
40
 
32
41
  NS_ASSUME_NONNULL_END
@@ -12,16 +12,16 @@
12
12
  return self;
13
13
  }
14
14
 
15
- // The choice of the transition object is this delegate's own; the interaction controller is never answered. The other
16
- // methods of `UINavigationControllerDelegate` are the stack's when the stack has them; nothing outside the protocol is
17
- // forwarded (design 11).
15
+ // The choice of the transition object is this delegate's own; the interaction controller too, answered only while
16
+ // the top's pop follows the swipe. The other methods of `UINavigationControllerDelegate` are the stack's when the
17
+ // stack has them; nothing outside the protocol is forwarded (design 11).
18
18
  static BOOL ANNIsOwnSelector(SEL selector) {
19
19
  SEL animation = @selector(navigationController:
20
20
  animationControllerForOperation:fromViewController:toViewController:);
21
21
  return selector == animation;
22
22
  }
23
23
 
24
- static BOOL ANNIsNeverAnswered(SEL selector) {
24
+ static BOOL ANNIsInteractionSelector(SEL selector) {
25
25
  return selector == @selector(navigationController:interactionControllerForAnimationController:);
26
26
  }
27
27
 
@@ -33,7 +33,7 @@ static BOOL ANNIsDelegateSelector(SEL selector) {
33
33
 
34
34
  // A method of the protocol this delegate passes to the stack.
35
35
  - (BOOL)forwardsToStack:(SEL)selector {
36
- return !ANNIsOwnSelector(selector) && !ANNIsNeverAnswered(selector) &&
36
+ return !ANNIsOwnSelector(selector) && !ANNIsInteractionSelector(selector) &&
37
37
  ANNIsDelegateSelector(selector) && [_stack respondsToSelector:selector];
38
38
  }
39
39
 
@@ -41,8 +41,8 @@ static BOOL ANNIsDelegateSelector(SEL selector) {
41
41
  if (ANNIsOwnSelector(selector)) {
42
42
  return YES;
43
43
  }
44
- if (ANNIsNeverAnswered(selector)) {
45
- return NO;
44
+ if (ANNIsInteractionSelector(selector)) {
45
+ return _answersInteraction;
46
46
  }
47
47
  if ([super respondsToSelector:selector]) {
48
48
  return YES;
@@ -89,4 +89,11 @@ static BOOL ANNIsDelegateSelector(SEL selector) {
89
89
  return [_stack animatorForOperation:operation from:fromVC to:toVC];
90
90
  }
91
91
 
92
+ - (id<UIViewControllerInteractiveTransitioning>)
93
+ navigationController:(UINavigationController *)navigationController
94
+ interactionControllerForAnimationController:
95
+ (id<UIViewControllerAnimatedTransitioning>)animationController {
96
+ return [_stack interactionForAnimator:animationController];
97
+ }
98
+
92
99
  @end
@@ -93,6 +93,14 @@ FOUNDATION_EXPORT NSString *_Nullable ANNStackKeyOfLayout(ANNLayoutNode *node);
93
93
  /// it), or UIKit's More navigation shows the stack's first screen only (its swipe goes back to the More list).
94
94
  - (BOOL)swipeBackIsUIKits:(UIGestureRecognizer *)recognizer;
95
95
 
96
+ /// The swipe of `recognizer` may play the pop: the stack's own swipe (from the leading edge, toward the trailing side)
97
+ /// only while the top's pop follows the finger (`animations.pop.interactive`) and the screen under is in place, UIKit's
98
+ /// swipes of the stack's navigation only while it doesn't. Every other swipe may.
99
+ - (BOOL)swipeBackTakes:(UIGestureRecognizer *)recognizer;
100
+
101
+ /// `recognizer` is the stack's own swipe back, not one of UIKit's.
102
+ - (BOOL)swipeBackIsStacks:(UIGestureRecognizer *)recognizer;
103
+
96
104
  /// The stack has one entry: there is nowhere to go back to.
97
105
  @property(nonatomic, readonly) BOOL hasOneEntry;
98
106
 
@@ -12,7 +12,9 @@
12
12
  #import "ANNSheetPresenter.h"
13
13
  #import "ANNShownScreens.h"
14
14
  #import "ANNStackAnimatingDelegate.h"
15
+ #import "ANNStackPopAnimationOptions.h"
15
16
  #import "ANNStackPresenter.h"
17
+ #import "ANNSwipePopInteraction.h"
16
18
  #import "ANNSystemUI.h"
17
19
  #import "ANNTopBarPresenter.h"
18
20
  #import "ANNTransitionAnimator.h"
@@ -54,6 +56,10 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
54
56
  return state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged;
55
57
  }
56
58
 
59
+ // How far from the leading edge of the stack's view the stack's own swipe back starts, in points: the strip the side
60
+ // menu leaves to the swipe back (`ANNSideMenuEdgeWidth`).
61
+ static const CGFloat ANNOwnSwipeEdgeWidth = 20;
62
+
57
63
  @interface ANNStackController () <ANNStackDisplay, ANNStackAnimating>
58
64
  @end
59
65
 
@@ -90,6 +96,12 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
90
96
  ANNTransitionPlan *_pendingPlan;
91
97
  ANNStackChange _pendingChange;
92
98
  __weak ANNTransitionAnimator *_runningAnimator;
99
+ // The interaction of the swipe back that plays the top's own pop, until UIKit asks for it.
100
+ __weak ANNSwipePopInteraction *_swipeInteraction;
101
+ // The stack's own swipe from the leading edge, on while the top's pop follows the finger: UIKit runs its swipe
102
+ // without asking the delegate for a transition, so that one would only slide.
103
+ UIPanGestureRecognizer *_ownSwipe;
104
+ InteractivePopGestureDelegate *_ownSwipeDelegate;
93
105
  BOOL _gateUpdateScheduled;
94
106
  // The stack is made (its helper set up): its options can be resolved.
95
107
  BOOL _madeUp;
@@ -260,6 +272,16 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
260
272
  content:YES
261
273
  barSwipe:barSwipe];
262
274
  }
275
+ if (!_ownSwipe) {
276
+ _ownSwipe = [[UIPanGestureRecognizer alloc] initWithTarget:self
277
+ action:@selector(ownSwipeBack:)];
278
+ _ownSwipe.enabled = _animatingDelegate.answersInteraction;
279
+ [self.view addGestureRecognizer:_ownSwipe];
280
+ }
281
+ _ownSwipeDelegate = [InteractivePopGestureDelegate installOn:_ownSwipe
282
+ stack:self
283
+ content:NO
284
+ barSwipe:barSwipe];
263
285
  [self updateSwipeBack];
264
286
  }
265
287
 
@@ -520,6 +542,9 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
520
542
 
521
543
  - (BOOL)isSwipingBack {
522
544
  UINavigationController *navigation = self.shownNavigationController;
545
+ if (navigation == self && ANNIsActive(_ownSwipe)) {
546
+ return YES;
547
+ }
523
548
  if (ANNIsActive(navigation.interactivePopGestureRecognizer)) {
524
549
  return YES;
525
550
  }
@@ -813,15 +838,20 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
813
838
  #pragma mark - The custom transitions
814
839
 
815
840
  // UIKit asks while it starts the change the queue asked for: the queue's plan when the operation and the arriving
816
- // entry are the plan's (the back button and the commands go through the queue, so its plan covers them); nil for
817
- // anything else — UIKit's own pops, the interactive swipe (UIKit never asks for it), a zoom alone.
841
+ // entry are the plan's (the back button and the commands go through the queue, so its plan covers them); the swipe
842
+ // back gets the top's own pop only with `animations.pop.interactive` (`swipeAnimatorFrom:to:`); nil for anything
843
+ // else — UIKit's own pops, a zoom alone.
818
844
  - (id<UIViewControllerAnimatedTransitioning>)
819
845
  animatorForOperation:(UINavigationControllerOperation)operation
820
846
  from:(UIViewController *)from
821
847
  to:(UIViewController *)to {
848
+ if ([self isSwipingBack]) {
849
+ return operation == UINavigationControllerOperationPop
850
+ ? [self swipeAnimatorFrom:from to:to]
851
+ : nil;
852
+ }
822
853
  ANNTransitionPlan *plan = _pendingPlan;
823
- if (!plan || operation == UINavigationControllerOperationNone || to != plan.toNode ||
824
- [self isSwipingBack]) {
854
+ if (!plan || operation == UINavigationControllerOperationNone || to != plan.toNode) {
825
855
  return nil;
826
856
  }
827
857
  BOOL matches = _pendingChange == ANNStackChangeReplace ||
@@ -838,16 +868,73 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
838
868
  return animator;
839
869
  }
840
870
 
871
+ // The stack's own swipe back of a top whose pop follows the finger (`animations.pop.interactive`, not
872
+ // `enabled: false`): the pop plays under it. Nil otherwise, also when UIKit won't ask for the interaction (the gate
873
+ // hasn't seen the option yet: a change of the default options) or the screen under hasn't settled
874
+ // (`revealedEntrySettled:`): UIKit asks for the transition before the queue takes the swipe and moves those, and the
875
+ // frames take the views as they are now.
876
+ - (nullable ANNTransitionAnimator *)swipeAnimatorFrom:(UIViewController *)from
877
+ to:(UIViewController *)to {
878
+ if (!ANNIsActive(_ownSwipe) || !_animatingDelegate.answersInteraction ||
879
+ ![self isOwnViewController:from] || ![self revealedEntrySettled:to]) {
880
+ return nil;
881
+ }
882
+ ANNStackPopAnimationOptions *pop = [from resolveOptionsWithDefault].animations.pop;
883
+ if (![ANNStackController popFollowsSwipe:pop]) {
884
+ return nil;
885
+ }
886
+ ANNTransitionPlan *plan = [ANNTransitionPlan stackPlanOfKind:ANNTransitionKindPop
887
+ animation:pop
888
+ waitForRender:nil
889
+ waitLimit:0
890
+ from:from
891
+ to:to];
892
+ if (!plan) {
893
+ return nil;
894
+ }
895
+ ANNTransitionAnimator *animator = [[ANNTransitionAnimator alloc] initWithPlan:plan];
896
+ // The interaction keeps itself while it follows the gesture; UIKit keeps it once it starts it.
897
+ ANNSwipePopInteraction *interaction =
898
+ [[ANNSwipePopInteraction alloc] initWithAnimator:animator recognizer:_ownSwipe view:self.view];
899
+ _swipeInteraction = interaction;
900
+ _runningAnimator = animator;
901
+ return animator;
902
+ }
903
+
904
+ // The screen under is in place for the frames: its view made, not parked, not rendering as a lower screen.
905
+ - (BOOL)revealedEntrySettled:(nullable UIViewController *)revealed {
906
+ return revealed.isViewLoaded && ![_lowerRendering objectForKey:revealed] &&
907
+ ![_lowerToRender containsObject:revealed] &&
908
+ ![[self parkedEntries] containsObject:revealed];
909
+ }
910
+
911
+ + (BOOL)popFollowsSwipe:(nullable ANNStackPopAnimationOptions *)pop {
912
+ return [ANNAnimationRules stackIsOwn:pop] && [pop.interactive withDefault:NO] &&
913
+ [pop.enabled withDefault:YES];
914
+ }
915
+
916
+ - (nullable id<UIViewControllerInteractiveTransitioning>)interactionForAnimator:
917
+ (id<UIViewControllerAnimatedTransitioning>)animator {
918
+ ANNSwipePopInteraction *interaction = _swipeInteraction;
919
+ return interaction && interaction.animator == animator ? interaction : nil;
920
+ }
921
+
841
922
  // The animating delegate while a custom animation may be needed: a change with its own plan now, or a top whose
842
923
  // `animations.pop` is its own; the stack itself otherwise. UIKit reads the delegate's methods when it is set, so it is
843
- // set again at each change.
924
+ // set again at each change, and again when the interaction of the swipe comes or goes with the top's
925
+ // `animations.pop.interactive`.
844
926
  - (void)updateAnimationGateWith:(ANNTransitionPlan *)plan {
845
- BOOL needed = plan != nil;
846
- if (!needed) {
847
- UIViewController *top = [self getCurrentChild];
848
- needed = top && [ANNAnimationRules
849
- stackIsOwn:[top resolveOptionsWithDefault].animations.pop];
927
+ UIViewController *top = [self getCurrentChild];
928
+ ANNStackPopAnimationOptions *pop = top ? [top resolveOptionsWithDefault].animations.pop : nil;
929
+ BOOL needed = plan != nil || [ANNAnimationRules stackIsOwn:pop];
930
+ BOOL interactive = [ANNStackController popFollowsSwipe:pop];
931
+ if (_animatingDelegate.answersInteraction != interactive) {
932
+ _animatingDelegate.answersInteraction = interactive;
933
+ if (self.delegate == _animatingDelegate) {
934
+ self.delegate = self;
935
+ }
850
936
  }
937
+ _ownSwipe.enabled = interactive;
851
938
  id<UINavigationControllerDelegate> delegate =
852
939
  needed ? (id<UINavigationControllerDelegate>)_animatingDelegate : self;
853
940
  if (self.delegate != delegate) {
@@ -934,13 +1021,66 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
934
1021
  if (top != nil && top != [self getCurrentChild]) {
935
1022
  return YES;
936
1023
  }
937
- BOOL own = recognizer == self.interactivePopGestureRecognizer;
1024
+ BOOL own = recognizer == self.interactivePopGestureRecognizer || recognizer == _ownSwipe;
938
1025
  if (@available(iOS 26.0, *)) {
939
1026
  own = own || recognizer == self.interactiveContentPopGestureRecognizer;
940
1027
  }
941
1028
  return !own && _queue.shown.count < 2;
942
1029
  }
943
1030
 
1031
+ - (BOOL)swipeBackIsStacks:(UIGestureRecognizer *)recognizer {
1032
+ return recognizer != nil && recognizer == _ownSwipe;
1033
+ }
1034
+
1035
+ - (BOOL)swipeBackTakes:(UIGestureRecognizer *)recognizer {
1036
+ BOOL uikits = recognizer == self.interactivePopGestureRecognizer;
1037
+ if (@available(iOS 26.0, *)) {
1038
+ uikits = uikits || recognizer == self.interactiveContentPopGestureRecognizer;
1039
+ }
1040
+ if (recognizer != _ownSwipe && !uikits) {
1041
+ return YES;
1042
+ }
1043
+ NSArray<UIViewController *> *shown = _queue.shown;
1044
+ UIViewController *revealed = shown.count >= 2 ? shown[shown.count - 2] : nil;
1045
+ // The options as they are now, as `swipeAnimatorFrom:to:` reads them: the gate may lag a change of the defaults,
1046
+ // and a swipe of ours without the pop would be a pop the finger can't hold.
1047
+ UIViewController *top = self.topViewController;
1048
+ BOOL ownPlays = _ownSwipe.enabled && _animatingDelegate.answersInteraction && top &&
1049
+ top == [self getCurrentChild] && [self isOwnViewController:top] &&
1050
+ [ANNStackController
1051
+ popFollowsSwipe:[top resolveOptionsWithDefault].animations.pop] &&
1052
+ [self revealedEntrySettled:revealed];
1053
+ if (uikits) {
1054
+ return !ownPlays;
1055
+ }
1056
+ return ownPlays && [self panStartsAtLeadingEdge:_ownSwipe];
1057
+ }
1058
+
1059
+ // A pan that starts near the leading edge of the stack's view and moves more across than along, toward the trailing
1060
+ // side: where UIKit's edge swipe starts.
1061
+ - (BOOL)panStartsAtLeadingEdge:(UIPanGestureRecognizer *)pan {
1062
+ UIView *view = self.view;
1063
+ CGPoint at = [pan locationInView:view];
1064
+ CGPoint move = [pan translationInView:view];
1065
+ BOOL rightToLeft =
1066
+ view.effectiveUserInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft;
1067
+ CGFloat start = at.x - move.x;
1068
+ CGFloat fromEdge = rightToLeft ? view.bounds.size.width - start : start;
1069
+ if (move.x == 0 && move.y == 0) {
1070
+ move = [pan velocityInView:view];
1071
+ }
1072
+ CGFloat along = rightToLeft ? -move.x : move.x;
1073
+ return fromEdge <= ANNOwnSwipeEdgeWidth && along > fabs(move.y);
1074
+ }
1075
+
1076
+ // The stack's own swipe began: a pop as UIKit's swipe makes it, which the stack follows as the swipe back
1077
+ // (`followUIKitTransition`); the transition asks for the top's pop and its interaction (`swipeAnimatorFrom:to:`).
1078
+ - (void)ownSwipeBack:(UIPanGestureRecognizer *)recognizer {
1079
+ if (recognizer.state == UIGestureRecognizerStateBegan) {
1080
+ [self popViewControllerAnimated:YES];
1081
+ }
1082
+ }
1083
+
944
1084
  - (BOOL)hasOneEntry {
945
1085
  return _queue.entries.count < 2;
946
1086
  }
@@ -983,6 +1123,7 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
983
1123
  BOOL edge = !(isBool && ![value boolValue]);
984
1124
  BOOL content = !value || (isBool && [value boolValue]);
985
1125
  _edgeSwipeDelegate.enabled = edge;
1126
+ _ownSwipeDelegate.enabled = edge;
986
1127
  _moreEdgeSwipeDelegate.enabled = edge;
987
1128
  _contentSwipeDelegate.enabled = content;
988
1129
  _moreContentSwipeDelegate.enabled = content;
@@ -992,6 +1133,7 @@ static BOOL ANNIsActive(UIGestureRecognizer *recognizer) {
992
1133
  - (void)swipeBackFollowsBar {
993
1134
  BOOL hidden = [ANNSystemUI barHiddenOf:self.shownNavigationController];
994
1135
  _edgeSwipeDelegate.barHidden = hidden;
1136
+ _ownSwipeDelegate.barHidden = hidden;
995
1137
  _contentSwipeDelegate.barHidden = hidden;
996
1138
  _moreEdgeSwipeDelegate.barHidden = hidden;
997
1139
  _moreContentSwipeDelegate.barHidden = hidden;
@@ -0,0 +1,26 @@
1
+ #import <UIKit/UIKit.h>
2
+
3
+ @class ANNTransitionAnimator;
4
+
5
+ NS_ASSUME_NONNULL_BEGIN
6
+
7
+ /// The interaction of a swipe back that plays the screen's own pop (`animations.pop.interactive`). It follows the
8
+ /// stack's own swipe from the leading edge (UIKit runs its swipe without asking the delegate for a transition), and
9
+ /// shows the animator's frames as far as the finger went across `view`, in the direction of the swipe back. Letting go
10
+ /// finishes the pop after a flick back or past half way, and puts the screen back otherwise; the rest plays faster
11
+ /// after a quick flick, never slower, and UIKit ends its part at the same pace. An interaction UIKit never starts goes
12
+ /// with the end of the gesture. Main queue.
13
+ @interface ANNSwipePopInteraction : NSObject <UIViewControllerInteractiveTransitioning>
14
+
15
+ - (instancetype)initWithAnimator:(ANNTransitionAnimator *)animator
16
+ recognizer:(UIPanGestureRecognizer *)recognizer
17
+ view:(UIView *)view NS_DESIGNATED_INITIALIZER;
18
+
19
+ - (instancetype)init NS_UNAVAILABLE;
20
+ + (instancetype)new NS_UNAVAILABLE;
21
+
22
+ @property(nonatomic, weak, readonly, nullable) ANNTransitionAnimator *animator;
23
+
24
+ @end
25
+
26
+ NS_ASSUME_NONNULL_END