@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
@@ -5,7 +5,7 @@ Two things every screen shares: the theme, the colors of the bars and background
5
5
  Every screen of an app shares a look and a few facts: the colors of the bars, the signed-in user, the language. The navigation keeps both for every screen. The **theme** is the colors of the bars, tabs and backgrounds. The **context** is a small object of the app that every screen reads. This page answers:
6
6
 
7
7
  1. [Why the navigation keeps them](#why), and not a React provider.
8
- 2. [The theme](#theme): its colors, dark mode, changing it, Android's own colors.
8
+ 2. [The theme](#theme): its colors, dark mode, changing it, [Android's theme](#android).
9
9
  3. [The context](#context): filling it, reading it, typing it.
10
10
  4. [What goes in the context](#context-roles), and what goes elsewhere.
11
11
 
@@ -37,7 +37,7 @@ export const Navigation = createNavigation({
37
37
 
38
38
  Every top bar and the tab bar are navy with light titles; the buttons, the back arrow and the selected tab are orange.
39
39
 
40
- A color left out keeps the platform's look. On iOS 26 a theme without `bar` keeps the bars on glass. On Android the bars take the colors of the app's Material 3 theme, neutral grays by default (see [Android's colors](#android)).
40
+ A color left out keeps the platform's look. On iOS 26 a theme without `bar` keeps the bars on glass. On Android the bars take the colors of the app's Material 3 theme, neutral grays by default (see [Android's theme](#android)).
41
41
 
42
42
  The theme is the bottom layer of the options of every screen. A screen that needs its own look sets it in its options, and they go over the theme (see [Where a screen gets them](../fundamentals/screen-options#layers)).
43
43
 
@@ -106,9 +106,9 @@ The options of the app and of a screen can be built from the theme: their functi
106
106
 
107
107
  So a color that follows the theme belongs in the theme itself, or in the app's `options`.
108
108
 
109
- ### Android's colors
109
+ ### Android's theme
110
110
 
111
- (Android) The bars, tabs, search, sheets and menus are Material 3 views. What the theme and the options leave out, they take from the app's Android theme, as every Material view of the app does. On an app made from React Native's template, `setup` makes the app's theme inherit `Theme.ApexNavigation`: Material 3 in neutral grays, light and dark, with no tint of its own.
111
+ (Android) The bars, tabs, search, sheets, menus and the floating action button are Material 3 views. What the theme and the options leave out, they take from the app's Android theme, as every Material view of the app does. On an app made from React Native's template, `setup` makes the app's theme inherit `Theme.ApexNavigation`: Material 3 in neutral grays, light and dark, with no tint of its own.
112
112
 
113
113
  An app changes any of these colors in `styles.xml`. A color that differs in dark mode is a color resource with a second value in `values-night`, so the one style serves both modes:
114
114
 
@@ -130,19 +130,138 @@ The selected tab now sits on a peach pill in light mode, and a brown one in dark
130
130
 
131
131
  | Material 3 color | What takes it |
132
132
  | --- | --- |
133
- | `colorSurface` | The top bar. |
134
- | `colorOnSurface` | The title and the back arrow. |
135
- | `colorOnSurfaceVariant` | The subtitle and the "⋮" of the bar. |
136
- | `colorSurfaceContainer`, `colorSurfaceContainerLow`, `colorSurfaceContainerHigh` | The tab bar and the menus of the bar; a sheet; the search field. |
133
+ | `colorSurface` | The top bar, and the menus of the bar while the bar is opaque. |
134
+ | `colorOnSurface` | The title, the large title, the back arrow, the text of the search. |
135
+ | `colorOnSurfaceVariant` | The subtitle and the "⋮" of the bar; the hint of the search. |
136
+ | `colorSurfaceContainer` | The tab bar; the menus of the bar when the bar lets the screen through. |
137
+ | `colorSurfaceContainerLow` | A sheet. |
138
+ | `colorSurfaceContainerHigh` | The search field and its suggestions. |
137
139
  | `colorSecondaryContainer` | The pill of the selected tab, the selected scope of the search. |
138
140
  | `colorPrimaryContainer` | The floating action button. |
139
- | `colorError` | The badges of the tabs. |
141
+ | `colorError` | The badges of the tabs, the destructive items of the bar's menus. |
142
+ | `android:colorBackground` | Behind a screen without `layout.backgroundColor`. It comes from the activity's own theme, Material 3 or not; a screen in a sheet shows the sheet's color. |
140
143
 
141
- The theme's `colors` and a screen's options go over these: `bar` over the top bar and the tab bar, `text` over the titles, `badge` over the badges.
144
+ The theme's `colors` and a screen's options go over these: `bar` over the top bar and the tab bar, `text` over the titles, `badge` over the badges. The menus of the bar take the bar's color and the title's color while the bar is opaque; `topBar.menuBackgroundColor` and `topBar.menuTextColor` set them apart. These two are Android only: iOS draws its menus in the system's colors.
142
145
 
143
146
  - **An app with a Material 3 theme of its own** keeps it, and the navigation takes its colors.
144
- - **An app with a theme that isn't Material 3** keeps it too. The bars, tabs, search and sheets then take `Theme.ApexNavigation` themselves, and follow the app's light or dark mode.
145
- - **An app that is only light** sets it in code: `AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)`.
147
+ - **An app with a theme that isn't Material 3** keeps it too, and the navigation's views take `Theme.ApexNavigation` (see [the next section](#android-other-themes)).
148
+ - **An app that is only light** sets it in code: `AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)`. `Theme.ApexNavigation` follows dark mode, so without it the navigation's views turn dark with the device.
149
+
150
+ #### An app with an AppCompat or MaterialComponents theme
151
+
152
+ Many apps keep a theme of their own, such as `Theme.AppCompat.Light.NoActionBar` or `Theme.MaterialComponents.DayNight.NoActionBar`. `setup` leaves it as it is: it changes only the template's `Theme.AppCompat.DayNight.NoActionBar`.
153
+
154
+ The navigation tells a Material 3 theme by `colorSurfaceContainerHigh`, a role only Material 3 themes have. When the activity's theme has none, each view of the navigation is made in a copy of the app's theme with `Theme.ApexNavigation` **laid over it**. Over it means it wins: the colors, text appearances and shapes it sets replace the app's, so the app's `colorPrimary` and `colorAccent` don't reach the bars, and the bars are neutral gray next to the app's own colors. The app's own views keep its theme.
155
+
156
+ There are two ways to give the bars the app's colors.
157
+
158
+ **Move the theme to Material 3.** The parent becomes `Theme.ApexNavigation`, or `Theme.Material3.DayNight.NoActionBar` for Material's own palette, and the brand colors go to Material 3's roles, the ones in the table above:
159
+
160
+ ```xml
161
+ <!-- Before: parent="Theme.MaterialComponents.DayNight.NoActionBar" -->
162
+ <style name="AppTheme" parent="Theme.ApexNavigation">
163
+ <item name="colorSecondaryContainer">@color/selected_tab</item>
164
+ <item name="colorPrimaryContainer">@color/brand</item>
165
+ </style>
166
+ ```
167
+
168
+ The selected tab and the floating action button take the brand colors. Attributes Material 3 has no role for, such as `colorAccent`, `colorPrimaryDark` or `colorPrimaryVariant`, do nothing in the navigation. The app's own native views change with the theme too: its AppCompat and Material widgets and dialogs take the Material 3 look.
169
+
170
+ **Keep the theme, and color the navigation from JavaScript.** The colors of the [theme](#theme) are options, not Android theme attributes, so they paint the bars with any Android theme:
171
+
172
+ ```ts
173
+ export const Navigation = createNavigation({
174
+ // … screens and root
175
+ theme: {
176
+ colors: {
177
+ primary: '#E76F51',
178
+ bar: '#1E2A44',
179
+ text: '#F3E9D2',
180
+ badge: '#E63946',
181
+ },
182
+ },
183
+ });
184
+ ```
185
+
186
+ The bars, the titles, the buttons, the selected tab and the badges take the brand colors. The rest stays in `Theme.ApexNavigation`'s grays: the pill of the selected tab, a sheet, the search field, the floating action button. The navigation has **no theme attribute or overlay of its own** for them. Two of them have an option of their color: `fab.backgroundColor` and `topBar.searchBar.backgroundColor`; the pill of the selected tab and a sheet have none.
187
+
188
+ The way to recolor them in resources is to replace `Theme.ApexNavigation` itself: a style of the same name in the app wins over the library's when the build merges the resources. It replaces the whole style, so it has Material 3's parent, and it goes in `values` and again in `values-night`, or dark mode keeps the library's grays:
189
+
190
+ ```xml
191
+ <style name="Theme.ApexNavigation"
192
+ parent="Theme.Material3.DayNight.NoActionBar">
193
+ <item name="colorSecondaryContainer">#FCE4D6</item>
194
+ </style>
195
+ ```
196
+
197
+ ```xml
198
+ <style name="Theme.ApexNavigation"
199
+ parent="Theme.Material3.DayNight.NoActionBar">
200
+ <item name="colorSecondaryContainer">#5C3B2E</item>
201
+ </style>
202
+ ```
203
+
204
+ A role the app's style leaves out takes Material 3's own palette, with its violet tint, and not the navigation's grays.
205
+
206
+ #### Fonts and shapes
207
+
208
+ An app with a font of its own sets it in the options, which work with any Android theme. The app's `options` give it to every screen:
209
+
210
+ ```ts
211
+ export const Navigation = createNavigation({
212
+ // … screens and root
213
+ options: {
214
+ topBar: {
215
+ title: { fontFamily: 'Inter', fontWeight: '600' },
216
+ subtitle: { fontFamily: 'Inter' },
217
+ largeTitle: { fontFamily: 'Inter' },
218
+ },
219
+ bottomTab: { fontFamily: 'Inter' },
220
+ },
221
+ });
222
+ ```
223
+
224
+ The family is the name a `Text` style takes: a font in `assets/fonts/` or a `res/font` resource React Native knows. Without options, each text takes its font from the app's theme, or from Material 3's text appearances:
225
+
226
+ | Text | Without options | Options over it |
227
+ | --- | --- | --- |
228
+ | The title and the subtitle | 22 sp and 14 sp, set in code; the theme's `android:fontFamily`, else the system font. | `topBar.title.fontFamily`, `fontSize`, `fontWeight`, `fontStyle`; the same in `topBar.subtitle`. |
229
+ | The large title | 28 sp, set in code; the font as the title. | The same in `topBar.largeTitle`. |
230
+ | A text button of the bar | The theme's `actionMenuTextAppearance`. | `fontFamily`, `fontSize`, `fontWeight`, `fontStyle` of the button. |
231
+ | The labels of the tabs | `textAppearanceLabelMedium`, through Material 3's style of the tab bar. | `bottomTab.fontFamily`, `fontWeight`, `fontStyle`; `fontSize` and `selectedFontSize`. |
232
+ | The items of the bar's menus | `textAppearanceLargePopupMenu`, which Material 3 points to `textAppearanceBodyLarge`; the title of a submenu `textAppearancePopupMenuHeader`. | None. |
233
+ | The text of the search | 16 sp. The field in the bar takes the font as the title; the pill under the title, Material's `SearchBar`, its own `TextAppearance.Material3.SearchBar`. | None. |
234
+ | The scopes of the search | `textAppearanceLabelLarge`. | None. |
235
+
236
+ The shapes come mostly from code, not from `shapeAppearance…` attributes:
237
+
238
+ | Shape | Without options | Option over it |
239
+ | --- | --- | --- |
240
+ | A sheet | 28 dp, the top corners only, set in code. | `modal.sheet.cornerRadius`. |
241
+ | The menus of the bar | The theme's `popupMenuBackground`, a drawable: 4 dp in Material 3. | None. |
242
+ | The search field | A capsule: set in code in the bar, Material's `SearchBar` style under the title; the suggestions 16 dp, set in code. While the search fills the screen, Material's `SearchView` has no corners. | None. |
243
+ | The scopes of the search | `shapeAppearanceCornerSmall`. | None. |
244
+ | The tab bar | Square. | `bottomTabs.cornerRadius`. |
245
+ | The floating action button | `shapeAppearanceCornerLarge`. | None. |
246
+
247
+ An app with a Material 3 theme changes the theme's part in `styles.xml`. These attributes are the app's own: its other views that use them change too.
248
+
249
+ ```xml
250
+ <style name="AppTheme" parent="Theme.ApexNavigation">
251
+ <item name="android:fontFamily">@font/inter</item>
252
+ <item name="textAppearanceLabelMedium">@style/TabLabel</item>
253
+ <item name="popupMenuBackground">@drawable/menu</item>
254
+ </style>
255
+
256
+ <style name="TabLabel" parent="TextAppearance.Material3.LabelMedium">
257
+ <item name="fontFamily">@font/inter</item>
258
+ <item name="android:fontFamily">@font/inter</item>
259
+ </style>
260
+ ```
261
+
262
+ The title, the large title and the labels of the tabs are in Inter, and so is the search field in the bar from Android 8 on: before it, a plain text field can't load a font resource. The menus of the bar take the shape of `menu.xml`, in the bar's color while the bar is opaque.
263
+
264
+ In an app whose theme isn't Material 3, `Theme.ApexNavigation` lies over the app's theme, so the text appearances, `popupMenuBackground` and the shapes are `Theme.ApexNavigation`'s whatever the app's theme says. `Theme.ApexNavigation` doesn't set `android:fontFamily`, so the app's own still reaches the title, the large title and the search field in the bar. For the rest, the options are the way.
146
265
 
147
266
  ## The context
148
267
 
@@ -82,7 +82,9 @@ navigation.push('Person', {
82
82
 
83
83
  The avatar of the row moves and grows into the photo of the profile, and the name into its larger title. The views can differ in size and style. A pair that isn't found is skipped (the transition waits for it first); one that fails on the way is skipped with a warning in the log. Either way its views show with their screens, and the other pairs move. `type` and `duration` next to `shared` change how the rest of the screen comes, `'fade'` by default.
84
84
 
85
- Both platforms. (Android) The next screen waits until it is drawn, so its views are there to move into; a `type` other than a fade gives way to a fade.
85
+ A view turned or scaled by its own `transform`, or by a parent's, flies from where it shows and lands as the other view shows, turning the shorter way. The angle is the one React Native draws, from −180° to 180°: `rotate: '270deg'` turns back a quarter, and no pair spins a full turn; a spin is an animation of the view's own.
86
+
87
+ What flies is a copy: pictures of the two views, taken as the transition starts, while the views wait hidden in their places. Both platforms. (Android) The next screen waits until it is drawn, so its views are there to take pictures of; an image flies as its own image, from its fit in one view to its fit in the other; a `type` other than a fade gives way to a fade. A skew and a tilt (`skewX`, `rotateX`, …) don't fly: the view flies without them and has them again at the end.
86
88
 
87
89
  ### Zoom
88
90
 
@@ -121,7 +123,7 @@ function Tile({ id, uri }: { id: string; uri: string }) {
121
123
  }
122
124
  ```
123
125
 
124
- The preview goes when the component unmounts. On Android a long press on the view does nothing of the navigation's: the view has no preview.
126
+ The previewed screen renders when the press starts, not when the component mounts ([when the screen renders](/api/transitions/usePreview#time)). The preview goes when the component unmounts. On Android a long press on the view does nothing of the navigation's: the view has no preview.
125
127
 
126
128
  ## Animations of your own
127
129
 
@@ -146,21 +148,60 @@ navigation.push('Details', {
146
148
 
147
149
  Details rises 300 points as it fades in. Each property animates from a value to a value over a time, with a delay and an interpolation if it needs them; the [API](#api) lists every one.
148
150
 
149
- The same goes for `pop`, `showModal`, `dismissModal`, `setStackRoot` and `setRoot`. The swipe back is the exception: (iOS) it always follows the finger with the system's slide, so a custom `pop` plays for the back button and `pop()` only. (Android) A pop with an animation of its own shows no preview under the swipe: the screen pops when the swipe ends.
151
+ (iOS) Once the move starts, the system draws it on its own, as it draws UIKit's animations: work on the main thread, such as a screen that mounts a long list, doesn't stop it.
152
+
153
+ The same goes for `pop`, `showModal`, `dismissModal`, `setStackRoot` and `setRoot`. The swipe back is the exception: (iOS) by default it follows the finger with the system's slide, so a custom `pop` plays for the back button and `pop()` only. (Android) A pop with an animation of its own shows no preview under the swipe: the screen pops when the swipe ends.
154
+
155
+ ### The swipe back with a pop of your own
156
+
157
+ (iOS) A screen that leaves with a move of its own, such as a card that shrinks away, looks wrong when the swipe back slides it out like any other screen. `interactive` on its pop plays its own move under the finger instead:
158
+
159
+ ```ts
160
+ navigation.push('Details', {
161
+ options: {
162
+ animations: {
163
+ pop: {
164
+ interactive: true,
165
+ content: {
166
+ exit: {
167
+ scaleX: { from: 1, to: 0.8, duration: 400 },
168
+ scaleY: { from: 1, to: 0.8, duration: 400 },
169
+ alpha: { from: 1, to: 0, duration: 400 },
170
+ },
171
+ },
172
+ },
173
+ },
174
+ },
175
+ });
176
+ ```
177
+
178
+ The swipe from the edge now shrinks Details as far as the finger has gone across the screen. The user can stop halfway; letting go past half way, or a flick back, finishes the pop, and letting go before half way, or a flick the other way, grows the screen back. After a quick flick the rest plays faster, never slower. The elements and the shared elements of the pop move with it, so a [shared element](#views) flies home under the finger.
179
+
180
+ - It applies only to a pop with an animation of its own, and `transition` presets get it through `options.animations.pop.interactive`.
181
+ - The swipe moves the time of the animation, not a point: a move with an easing doesn't stay exactly under the finger.
182
+ - On iOS 26 the swipe from the content stays off for a screen with a pop of its own; the swipe from the edge works.
183
+ - The top bar shows the screen under from the start of the swipe, as it does in any move of your own, and comes back if the user gives the swipe up.
184
+ - While the finger is down, the system's animations inside the two screens, such as an activity indicator, hold still.
185
+
186
+ (Android) It doesn't apply: a pop with an animation of its own plays when the back gesture ends.
150
187
 
151
188
  ### The top bar
152
189
 
153
190
  The top bar goes its platform's way in a preset or an animation of your own. (Android) It goes with its screen, as if it were part of it: with `slideUp` the new screen comes up with its bar over the old one and its bar, and on the way back it goes down with its bar, uncovering the bar below. With `fade` or `scale` the bar fades or grows with its screen. (iOS) UIKit keeps the bar in place and changes its title and buttons as the transition starts; only the screens under it move.
154
191
 
192
+ ### When the user reduces motion
193
+
194
+ The system's setting to reduce motion wins over a move of your own, with nothing to set. (iOS) With Reduce Motion on, the move becomes a fade of the same length: the screen that comes fades in on a push, a modal's show and `setRoot`, and the screen that goes fades out on a pop and a dismissal. No element moves. (Android) With Remove animations on, every animation of the app ends at once: the move jumps to its end, no element moves and the push doesn't wait for one, a side menu opens and closes without its slide, and a sheet shows and closes without it.
195
+
155
196
  ## Which to pick
156
197
 
157
198
  | The move | Pick | What it costs |
158
199
  | --- | --- | --- |
159
200
  | Most moves | The platform's | Nothing: it follows the finger and the system. |
160
- | A move that means something else, such as a fading modal | A preset | The swipe back on iOS still slides. |
201
+ | A move that means something else, such as a fading modal | A preset | The swipe back on iOS still slides, unless the pop is [`interactive`](#custom-swipe). |
161
202
  | A view that becomes the next screen | Shared elements, or the zoom on iOS 18+ | A `nativeID` on both views. The zoom shows on iOS 18+ only. |
162
203
  | A look at a screen before opening it | The preview | iOS only. |
163
- | A move no preset has | `options.animations` | Every property spelled out; the swipe back on iOS still slides. |
204
+ | A move no preset has | `options.animations` | Every property spelled out; the swipe back on iOS still slides, unless the pop is [`interactive`](#custom-swipe). |
164
205
 
165
206
  ## Waiting for the content
166
207
 
@@ -126,6 +126,8 @@ navigation.setOptions({
126
126
 
127
127
  On (Android) a sheet is the Material bottom sheet. It stops at half (`'medium'`) and full (`'large'`) height and at heights of its own; `'content'` stops at half.
128
128
 
129
+ (Android) 14+ The back gesture over a sheet shows it sliding down before the user lets go: [the preview of a sheet closing](../screen-ui/back-and-gestures#sheet-preview).
130
+
129
131
  Sheets in a real app, step by step: [Bottom sheets](../flows/bottom-sheets).
130
132
 
131
133
  ## How a modal closes
@@ -26,7 +26,7 @@ A push or a modal moves the user somewhere. An overlay doesn't move anyone: it p
26
26
 
27
27
  An overlay is a screen of `screens` like any other: a component, its props, its options. It shows above the tabs, the bars and the modals; on (iOS) it is in a window of its own. Its background is transparent, so the app shows wherever the overlay draws nothing.
28
28
 
29
- An overlay covers the whole window, **the status bar included**: a dialog's dimmed backdrop dims the status bar too, as a system dialog does. Its safe area keeps the content off the bars, so a toast at the top of the overlay sits below the status bar. On (Android) a status bar with a color of its own (`statusBar.backgroundColor`) stays over the backdrop, and `statusBar.drawBehind: false` starts the overlay below the status bar. What overlays are for:
29
+ An overlay covers the whole window, **the status bar included**: a dialog's dimmed backdrop dims the status bar too, as a system dialog does. Its safe area keeps the top and the sides off the bars, so a toast at the top of the overlay sits below the status bar. On (Android) a status bar with a color of its own (`statusBar.backgroundColor`) stays over the backdrop, and `statusBar.drawBehind: false` starts the overlay below the status bar. What overlays are for:
30
30
 
31
31
  ## Showing and closing
32
32
 
@@ -108,7 +108,7 @@ A tap on Settings closes the menu and shows Settings in the center as it goes. W
108
108
  | (iOS) | Over the content, which dims: `openMode: 'aboveContent'` of the side, the default. Or under it, with the content moved aside: `'pushContent'`. Then `animation(…)` says how the menu appears: `'parallax'`, `'slide'`, `'slide-and-scale'` or `'door'`. |
109
109
  | (Android) | The drawer of the platform: over the content, which dims. |
110
110
 
111
- The menu's color is its screen's `layout.backgroundColor`: it fills the whole height of the menu, behind the status bar and the navigation bar, while the menu's content keeps clear of them. A background on the React content stops at the safe area.
111
+ The menu's color is its screen's `layout.backgroundColor`: it fills the whole height of the menu, behind the status bar and the navigation bar, while the menu's content keeps its top and sides clear of them (the bottom goes down to the edge: a list adds `insets.bottom`). A background on the React content stops at the safe area.
112
112
 
113
113
  `.ios()` keeps the settings that only iOS has apart from the others:
114
114
 
@@ -92,6 +92,8 @@ Inbox shows, and Chat comes in over it, in the stack of the Inbox tab.
92
92
 
93
93
  On (Android) the content changes with Material's fade through, as in the system's Phone app: the tab that goes fades out, then the new one fades in and grows to its size, in 300 ms; the tab bar stays. On (iOS) the new tab shows at once, as the system's tab bar does.
94
94
 
95
+ To switch at once on Android too, give `bottomTabs.switchAnimation: 'none'`: to every tabs node in the app's default `options`, to these tabs with `Tabs().options({ switchAnimation: 'none' })`, or to a screen. The tab that is selected decides, by the screen on top of it: a tab whose top screen says `'none'` comes in at once, and leaving it fades as usual. A screen's `setOptions` changes it from the next switch.
96
+
95
97
  ### A press on a tab
96
98
 
97
99
  A second tap on the selected tab is a convention of both platforms: **back to the start of the tab**. The navigation does it without code:
@@ -152,7 +152,7 @@ navigation.showModal('PhotoActions', {
152
152
  });
153
153
  ```
154
154
 
155
- The content is measured after every render, so the sheet follows it when it grows. It needs (iOS) 16; on (Android) the sheet stops at half the height instead, as the Material sheet has no height of its content. A screen that fills its parent (`flex: 1`) has no height of its own, so give the content of this screen its natural height.
155
+ The content is measured after every render, so the sheet follows it when it grows. It needs (iOS) 16. A screen that fills its parent (`flex: 1`) has no height of its own, so give the content of this screen its natural height. The sheet adds the bottom safe area to the height of a `'content'` sheet itself (UIKit on (iOS), the navigation bar on (Android)), so don't add `insets.bottom` to its content: the gap would come twice.
156
156
 
157
157
  ## 8. Close it with a pick
158
158
 
@@ -218,8 +218,10 @@ The sheet is (iOS) UIKit's sheet, and on (Android) the Material bottom sheet. Th
218
218
  | --- | --- | --- |
219
219
  | `'medium'`, `'large'` | Half and full height. | Half height, and full height under the status bar. |
220
220
  | A number | That height, in points. iOS 16+: iOS 15 leaves it out. | That height, in dp. |
221
- | `'content'` | The height of the content. iOS 16+: iOS 15 leaves it out. | Half the height: the Material sheet has no height of its content. |
221
+ | How many stops | Every detent of the list. | Three at most: the lowest, the highest, and one between them (`selectedDetent` when it stands there, else the lowest of the others). |
222
+ | `'content'` | The height of the content. iOS 16+: iOS 15 leaves it out. | The height of the content. |
222
223
  | The screen under it | Shrinks back a little at full height, as UIKit does. | Stays in place. |
224
+ | The keyboard | The sheet rises and stands on it. | The sheet rises and stands on it at every stop, unless the screen in it has `layout.adjustResize: false`. |
223
225
 
224
226
  ## The whole code
225
227
 
@@ -70,7 +70,7 @@ What `screens` takes, from the simplest:
70
70
  | Entry | When |
71
71
  | --- | --- |
72
72
  | A component | A screen without options of its own: `Settings`. |
73
- | `defineScreen({ component, options })` | A screen with its options next to it: see [Options](#options). |
73
+ | `defineScreen({ component, options })` | A screen with its options next to it: see [Options](#options). It returns a component that renders the screen. |
74
74
  | `{ load: () => import('./screens/Settings') }` | A screen whose code runs the first time it shows: see [Loading later](#lazy). |
75
75
  | `nativeScreen('ProfileScreen', …)` | A screen written in SwiftUI, UIKit or Compose: see [Native screens](../architecture/native-screens). |
76
76
  | `defineArrangement({ primary, secondary })` | Two screens shown as one, side by side in a large window: see [Arrangement](../containers/arrangement). |
@@ -172,10 +172,18 @@ export const DetailsScreen = defineScreen({
172
172
  | `props` | The props of this showing, typed from the component. |
173
173
  | `{ theme, context }` | The theme of the navigation and the app's context, as they are when the screen shows. |
174
174
 
175
+ `defineScreen` returns a component of its own, typed `DefinedScreen`, which renders your component and carries the definition; your component stays as it is, for any other use of it. Put the result in `screens` as it is. Rendered alone, in a test, it renders the screen.
176
+
175
177
  The options go to the native side with the command, so they apply **before the screen appears**: the title is there from the first frame, not set after a render.
176
178
 
177
179
  Options come from several places, and the later go over the earlier: the screen's [group](#groups), its `defineScreen`, the `options` of the command, and `setOptions` or `useScreenOptions` from the screen itself. The whole order, with the theme and the defaults of the app: [Screen options](./screen-options).
178
180
 
181
+ ### Fast Refresh
182
+
183
+ An edit of a screen file updates the screen in place, with its state, when the file is a Fast Refresh boundary: it exports only screens and components. A constant or an object exported from it makes it not a boundary. With `withApexNavigation` in `metro.config.js` ([Installation](../start/installation#fast-refresh)) such an edit still doesn't reload the app: it goes up to the module of the app's `createNavigation`, which updates the running app.
184
+
185
+ An edit of `options` reaches the screens of it at once, a tab not rendered yet too. Changed and added options are merged in; an option taken out is cleared. An option the command gave the screen, or one the screen set since (`useScreenOptions`, `mergeOptions`), stays as it is. An edit of `key` or `arrangement` applies from the next show.
186
+
179
187
  ## The life of a screen
180
188
 
181
189
  A screen isn't only mounted or not. Under another screen it is **still mounted but not seen**: its state and scroll stay, and it comes back as it was. So a screen has two lines of life: React's, from mount to unmount, and the user's, each time it appears and disappears.
@@ -176,7 +176,7 @@ More: [Errors and loading](../architecture/errors-and-loading).
176
176
 
177
177
  Keys of the system; the defaults suit most apps.
178
178
 
179
- - `safeArea` — the edges on which every screen keeps its content out of the safe area: `{ edges: ['top', 'bottom'] }`.
179
+ - `safeArea` — the edges on which every screen keeps its content out of the safe area: `{ edges: ['top', 'left', 'right', 'bottom'] }`. Listed edges replace the default, so list every edge the screens keep. Without it the screens keep the top and the sides, and the bottom is free.
180
180
  - `window` — (iOS) the color behind the screens, seen around a modal as it comes in: `{ backgroundColor: '#000000' }`.
181
181
  - `direction` — `'ltr'`, `'rtl'`, or `'locale'` for the language of the app; `navigation.setDirection` changes it.
182
182
 
@@ -107,7 +107,7 @@ A new app doesn't have the package yet, so `init` runs through the package's nam
107
107
 
108
108
  ## setup
109
109
 
110
- Sets the app you have up for the navigation: the native entry points of both platforms, `index.js`, a new `Navigation.ts` with your `App` as the first screen, and `navigation-env.d.ts`, the [typed commands](../start/installation#typed-commands). Each change and why: [What setup changes, and why](../start/installation#why-native).
110
+ Sets the app you have up for the navigation: the native entry points of both platforms, `index.js`, a new `Navigation.ts` with your `App` as the first screen, `navigation-env.d.ts`, the [typed commands](../start/installation#typed-commands). It also wraps `metro.config.js` in `withApexNavigation`, for [Fast Refresh](../start/installation#fast-refresh). Each change and why: [What setup changes, and why](../start/installation#why-native).
111
111
 
112
112
  ```bash
113
113
  npx apex-navigation setup
@@ -169,6 +169,8 @@ npx apex-navigation doctor --fix
169
169
  | `--fix` | Makes the fixes the CLI has, for errors and warnings alike: `setup`, `links`, `icons`, `codegen` and `pod install`, asking before each. It needs a terminal to ask in. |
170
170
  | `--json` | `{ ok, checks: [{ group, title, status, detail, fix }] }`; `status` is `ok`, `warn`, `error` or `info`, and `fix` is `{ label, run }`, where `run` names the command `--fix` runs. Not with `--fix`. |
171
171
 
172
+ It warns under Fast Refresh when the app's `metro.config.js` doesn't use `withApexNavigation`; the fix is `setup`.
173
+
172
174
  It exits with 1 when a check finds an error; warnings leave it at 0.
173
175
 
174
176
  ## info
@@ -194,7 +194,7 @@ A description of what the platform shows: a screen name, or a tree of [builders]
194
194
 
195
195
  ### Liquid Glass
196
196
 
197
- (iOS) 26: the see-through material of the bars, the tab bar and the buttons. A background color in the options takes it away. More: [The background and the border](../screen-ui/top-bar#background).
197
+ (iOS) 26: the see-through material of the bars, the tab bar and the buttons; the app gets this look, "the glass design", unless it is in the compatibility mode (`UIDesignRequiresCompatibility` in Info.plist), which keeps the look of before iOS 26. A background color in the options takes the glass away. More: [The glass design and the compatibility mode](../screen-ui/top-bar#glass-design), [The background and the border](../screen-ui/top-bar#background).
198
198
 
199
199
  ### listeners
200
200
 
@@ -314,7 +314,7 @@ An entry of `linking.routes`: a path pattern, such as `'user/:userId'`, and what
314
314
 
315
315
  ### Safe area
316
316
 
317
- The part of the screen that nothing covers: not the bars, the status bar, the cutout or the home indicator. The navigation keeps every screen in it by default, measured on the native side. More: [The safe area](../screen-ui/system-ui#safe-area).
317
+ The part of the screen that nothing covers: not the bars, the status bar, the cutout or the home indicator. The navigation keeps every screen's top and sides in it by default, and the bottom is free, measured on the native side. More: [The safe area](../screen-ui/system-ui#safe-area).
318
318
 
319
319
  ### Screen
320
320
 
@@ -439,6 +439,27 @@ return (
439
439
 
440
440
  More: [Hiding the bar](../screen-ui/top-bar#hide), [The large title](../screen-ui/top-bar#large-title).
441
441
 
442
+ ### The last rows of a list sit under the home indicator or the tab bar
443
+
444
+ The last row of a list can't be scrolled above the home indicator, the navigation bar or the tab bar.
445
+
446
+ **Why:** the bottom edge of a screen is not padded by default, so the content goes down to the edge, under the system and under the tab bar or toolbar.
447
+
448
+ **Fix:** add the bottom inset to the padding of the list; on (iOS) `contentInsetAdjustmentBehavior="automatic"` does it by itself. Or have the screen pad it: list every edge the screen keeps (`safeArea('top', 'left', 'right', 'bottom')`), since listed edges replace the default. An explicit `'top'` also keeps the top under a large title, so a large-title screen usually pads its list with `insets.bottom` instead:
449
+
450
+ ```tsx
451
+ const insets = useSafeAreaInsets();
452
+ return (
453
+ <FlatList
454
+ data={items}
455
+ contentContainerStyle={{ paddingBottom: 16 + insets.bottom }}
456
+ renderItem={renderItem}
457
+ />
458
+ );
459
+ ```
460
+
461
+ More: [The safe area](../screen-ui/system-ui#safe-area).
462
+
442
463
  ### A pick in the overflow menu does nothing
443
464
 
444
465
  The user picks Export in the overflow menu, and nothing happens.
@@ -543,7 +564,7 @@ More: [Ask before changes are lost](../flows/forms-in-a-modal#prevent).
543
564
 
544
565
  A sheet with the detent `'content'` isn't as tall as what it shows.
545
566
 
546
- **Why:** a screen that fills its parent (`flex: 1`) has no height of its own to measure. On (Android) `'content'` stops at half the height, as the Material sheet has no height of its content.
567
+ **Why:** a screen that fills its parent (`flex: 1`) has no height of its own to measure.
547
568
 
548
569
  **Fix:** give the content of the screen its natural height, without `flex: 1`. More: [A sheet as tall as its content](../flows/bottom-sheets#content).
549
570
 
@@ -87,6 +87,10 @@
87
87
  "heading": "JavaScript files",
88
88
  "anchor": "js-files"
89
89
  },
90
+ {
91
+ "heading": "Fast Refresh",
92
+ "anchor": "fast-refresh"
93
+ },
90
94
  {
91
95
  "heading": "Typed commands",
92
96
  "anchor": "typed-commands"
@@ -276,6 +280,10 @@
276
280
  "heading": "Options",
277
281
  "anchor": "options"
278
282
  },
283
+ {
284
+ "heading": "Fast Refresh",
285
+ "anchor": "fast-refresh"
286
+ },
279
287
  {
280
288
  "heading": "The life of a screen",
281
289
  "anchor": "lifecycle"
@@ -856,6 +864,10 @@
856
864
  "heading": "What the top bar is",
857
865
  "anchor": "what"
858
866
  },
867
+ {
868
+ "heading": "The glass design and the compatibility mode",
869
+ "anchor": "glass-design"
870
+ },
859
871
  {
860
872
  "heading": "The title",
861
873
  "anchor": "title"
@@ -978,6 +990,10 @@
978
990
  "heading": "The preview of a pop",
979
991
  "anchor": "pop-preview"
980
992
  },
993
+ {
994
+ "heading": "The preview of a sheet closing",
995
+ "anchor": "sheet-preview"
996
+ },
981
997
  {
982
998
  "heading": "Back to the home screen",
983
999
  "anchor": "system-animation"
@@ -1175,9 +1191,17 @@
1175
1191
  "anchor": "theme-options"
1176
1192
  },
1177
1193
  {
1178
- "heading": "Android's colors",
1194
+ "heading": "Android's theme",
1179
1195
  "anchor": "android"
1180
1196
  },
1197
+ {
1198
+ "heading": "An app with an AppCompat or MaterialComponents theme",
1199
+ "anchor": "android-other-themes"
1200
+ },
1201
+ {
1202
+ "heading": "Fonts and shapes",
1203
+ "anchor": "android-fonts-shapes"
1204
+ },
1181
1205
  {
1182
1206
  "heading": "The context",
1183
1207
  "anchor": "context"
@@ -1327,10 +1351,18 @@
1327
1351
  "heading": "Animations of your own",
1328
1352
  "anchor": "custom"
1329
1353
  },
1354
+ {
1355
+ "heading": "The swipe back with a pop of your own",
1356
+ "anchor": "custom-swipe"
1357
+ },
1330
1358
  {
1331
1359
  "heading": "The top bar",
1332
1360
  "anchor": "custom-bar"
1333
1361
  },
1362
+ {
1363
+ "heading": "When the user reduces motion",
1364
+ "anchor": "reduce-motion"
1365
+ },
1334
1366
  {
1335
1367
  "heading": "Which to pick",
1336
1368
  "anchor": "which"
@@ -1410,6 +1442,10 @@
1410
1442
  "heading": "Typed commands",
1411
1443
  "anchor": "typed-commands"
1412
1444
  },
1445
+ {
1446
+ "heading": "Fast Refresh",
1447
+ "anchor": "fast-refresh"
1448
+ },
1413
1449
  {
1414
1450
  "heading": "UIKit and Android views",
1415
1451
  "anchor": "imperative"
@@ -4092,6 +4128,10 @@
4092
4128
  "heading": "The first rows of a list hide under the top bar",
4093
4129
  "anchor": "rows-under-bar"
4094
4130
  },
4131
+ {
4132
+ "heading": "The last rows of a list sit under the home indicator or the tab bar",
4133
+ "anchor": "rows-under-bottom"
4134
+ },
4095
4135
  {
4096
4136
  "heading": "A pick in the overflow menu does nothing",
4097
4137
  "anchor": "overflow-pick"
@@ -425,7 +425,7 @@ The route patterns of `linking` are typed too: in `'user/:userId'` the handler g
425
425
  | `useNavigation` | `useNavigation`: the commands of this screen. |
426
426
  | `useIsFocused` | `useIsFocused`. |
427
427
 
428
- Every screen keeps clear of the bars by itself, so a `SafeAreaView` around the content can go; `useSafeAreaInsets` of this package gives what still covers the content, 0 on an edge the screen keeps clear, so padding by it never comes twice. More: [Lifecycle and events](../fundamentals/lifecycle-and-events#hooks), [The safe area](../screen-ui/system-ui#safe-area).
428
+ The bottom edge of a screen is not padded by default, as with `react-native-safe-area-context`: a list adds `useSafeAreaInsets().bottom` to its bottom padding, or the screen lists `'bottom'` in `safeArea(…)`. Every screen keeps its top and sides clear of the bars by itself, so a `SafeAreaView` around the content can go; `useSafeAreaInsets` of this package gives what still covers the content, 0 on an edge the screen keeps clear, so padding by it never comes twice. More: [Lifecycle and events](../fundamentals/lifecycle-and-events#hooks), [The safe area](../screen-ui/system-ui#safe-area).
429
429
 
430
430
  ## What has no direct equivalent
431
431
 
@@ -779,7 +779,7 @@ The whole list of options, with what each does on each platform: [Where each opt
779
779
  | `react-native-navigation` | What to do here |
780
780
  | --- | --- |
781
781
  | `Navigation.updateProps` | Props are given once. What changes goes in the screen's state, or the app's context or store. |
782
- | `Navigation.constants()` | `useSafeAreaInsets()` of a screen: what the bars and the system still cover of its content, measured for that screen; 0 on an edge the screen keeps clear itself. A screen that needs the height of its top bar goes under it (`drawBehind`) and reads the top inset. |
782
+ | `Navigation.constants()` | `useSafeAreaInsets()` of a screen (the bottom is not padded by default: a list adds `insets.bottom` to its bottom padding): what the bars and the system still cover of its content, measured for that screen; 0 on an edge the screen keeps clear itself. A screen that needs the height of its top bar goes under it (`drawBehind`) and reads the top inset. |
783
783
  | `componentId` in a class component | Hooks need a function component: wrap the class in one that passes `useNavigation()` down as a prop. |
784
784
  | `topTabs` | No container for it. A pager component inside one screen does the same. |
785
785
  | `Navigation.handleDeepLink(url)` | Run the command the route would run, such as `navigation.push('Profile', { props })`. |
@@ -64,7 +64,7 @@ The left side renders the navigation. The right side describes it: `createNaviga
64
64
  | **State** | A React object: routes, params, indexes. | The platform's. JavaScript hears events and reads a small state: the screen the user sees and the selected tab. |
65
65
  | **Params** | `route.params`, changed with `setParams`. | Props of the component, given by the command that shows the screen. |
66
66
  | **Options** | Props of a screen, with React elements for the header. | Data the platform reads before the screen shows. A component in a bar is registered in `screens`, as a screen is. |
67
- | **Safe area** | `SafeAreaView` or a safe area library. | Every screen keeps clear of the bars by itself. See [The safe area](../screen-ui/system-ui#safe-area). |
67
+ | **Safe area** | `SafeAreaView` or a safe area library. | Every screen keeps its top and sides clear of the bars by itself; the bottom is yours (`insets.bottom`). See [The safe area](../screen-ui/system-ui#safe-area). |
68
68
 
69
69
  Because options are data, a title is there from the first frame, and because the state is the platform's, a move renders nothing in React by itself. More on the model: [Introduction](../start/introduction#models).
70
70
 
@@ -605,7 +605,7 @@ Once no file imports them, remove `@react-navigation/*`, and `react-native-scree
605
605
  npx apex-navigation doctor
606
606
  ```
607
607
 
608
- Screens wrapped in `SafeAreaView` can drop it, since every screen keeps clear of the bars by itself; `useSafeAreaInsets` of this package gives what still covers the content of the screen. Code such as `paddingTop: insets.top` keeps working with it: on an edge the screen keeps clear the inset is 0, so nothing is padded twice.
608
+ The bottom edge of a screen is not padded by default, as with `react-native-safe-area-context`: a list adds `useSafeAreaInsets().bottom` to its bottom padding, or the screen lists `'bottom'` in `safeArea(…)`. Screens wrapped in `SafeAreaView` can drop it, since every screen keeps its top and sides clear of the bars by itself; `useSafeAreaInsets` of this package gives what still covers the content of the screen. Code such as `paddingTop: insets.top` keeps working with it: on an edge the screen keeps clear the inset is 0, so nothing is padded twice.
609
609
 
610
610
  ## What has no direct equivalent
611
611
 
@@ -85,6 +85,8 @@ export const MapScreen = defineScreen({
85
85
  | `'edge'` | From the edge only: a swipe on the content stays with the content. |
86
86
  | `false` | Off. The back button still works. |
87
87
 
88
+ (iOS) The swipe slides the screen out the system's way, also for a screen that leaves with a move of its own. `animations.pop.interactive` plays that move under the finger instead: [the swipe back with a pop of your own](../architecture/transitions#custom-swipe).
89
+
88
90
  (Android) The swipe is the system's back, from either edge, and `popGesture` doesn't apply to it. On Android 14+ it shows the pop before the user lets go: both screens shrink, the screen under comes in behind a dim, and the screen on top follows the finger. The user can stop halfway and stay, as on iOS. On Android 13 and older the screen pops when the swipe ends. When the preview shows and when it doesn't: [the preview of a pop](#pop-preview).
89
91
 
90
92
  ## The system back of Android
@@ -115,7 +117,21 @@ defineScreen({
115
117
  });
116
118
  ```
117
119
 
118
- iOS ignores it: the swipe back there is UIKit's.
120
+ iOS ignores it: the swipe back there is UIKit's, or the pop's own move under the finger with `animations.pop.interactive`.
121
+
122
+ ### The preview of a sheet closing
123
+
124
+ (Android) 14+ The back gesture over a modal sheet that back would close shows the close before the user lets go: the sheet shrinks a little toward the bottom as the swipe goes on, and the dimming behind it follows. Letting go slides the sheet down and closes it exactly as a swipe down does, with the same events and the same answers (`onDismiss`, `modalDismissed`). Swiping back cancels, and the sheet returns.
125
+
126
+ There is no preview, and the sheet closes when the swipe ends (at once for a button press), when:
127
+
128
+ - the sheet has several detents and is above its lowest one: the sheet can be hidden only at the lowest detent, so back closes it right there, as before;
129
+ - its screen holds back: `hardwareBackButton.dismissModalOnPress: false`, a [`BackHandler` listener](#back-handler), `usePreventLeave`;
130
+ - a screen pushed inside the sheet pops first: that pop keeps [its own preview](#pop-preview);
131
+ - the modal can't be swiped down (`swipeToDismiss: false`);
132
+ - the sheet is the only modal over no root.
133
+
134
+ On Android 13 and older the sheet closes when the swipe ends. iOS keeps UIKit's sheet: nothing changes there.
119
135
 
120
136
  ### Back to the home screen
121
137