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

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 (163) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +147 -51
  3. package/android/CLAUDE.md +31 -6
  4. package/android/CORE.md +7 -2
  5. package/android/RECIPES.md +4 -3
  6. package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +29 -1
  7. package/android/src/main/java/dev/apexnative/navigation/options/StatusBarOptions.kt +7 -3
  8. package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +5 -4
  9. package/android/src/main/java/dev/apexnative/navigation/react/ErrorTexts.kt +75 -60
  10. package/android/src/main/java/dev/apexnative/navigation/react/Hinge.kt +3 -2
  11. package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +1 -1
  12. package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +5 -4
  13. package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +7 -6
  14. package/android/src/main/java/dev/apexnative/navigation/react/events/AppearanceDispatcher.kt +3 -35
  15. package/android/src/main/java/dev/apexnative/navigation/react/events/EventContract.kt +226 -0
  16. package/android/src/main/java/dev/apexnative/navigation/react/events/EventEmitter.kt +101 -87
  17. package/android/src/main/java/dev/apexnative/navigation/react/events/ScreenAppearance.kt +0 -6
  18. package/android/src/main/java/dev/apexnative/navigation/utils/UiUtils.kt +3 -3
  19. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/SecondaryScreenPresenter.kt +13 -5
  20. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +76 -13
  21. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabItems.kt +3 -3
  22. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentPresenter.kt +28 -7
  23. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenFrame.kt +1 -1
  24. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalAnimations.kt +22 -24
  25. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +86 -16
  26. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalRecord.kt +21 -6
  27. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +41 -23
  28. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +24 -20
  29. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +25 -0
  30. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/BackCallbackState.kt +4 -0
  31. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +42 -4
  32. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/RootCoordinator.kt +29 -6
  33. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/overlay/OverlayCoordinator.kt +2 -0
  34. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ContainerBackground.kt +3 -3
  35. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +3 -0
  36. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuController.kt +5 -3
  37. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +4 -7
  38. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuPresenter.kt +16 -7
  39. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuRules.kt +8 -1
  40. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/splitview/SplitViewController.kt +16 -2
  41. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +287 -0
  42. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +148 -6
  43. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackDisplay.kt +24 -0
  44. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +51 -11
  45. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackTransitions.kt +26 -8
  46. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +105 -2
  47. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +123 -8
  48. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ViewController.kt +19 -0
  49. package/android/src/main/java/dev/apexnative/navigation/views/animations/Curves.kt +29 -11
  50. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabs.kt +5 -5
  51. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStep.kt +31 -0
  52. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +85 -27
  53. package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +5 -4
  54. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionTargets.kt +9 -6
  55. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionViews.kt +100 -0
  56. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +45 -1
  57. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +3 -5
  58. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +3 -5
  59. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +3 -5
  60. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +2 -0
  61. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +4 -6
  62. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +4 -6
  63. package/android/src/main/java/dev/apexnative/navigation/views/stack/ScreenEdge.kt +15 -0
  64. package/android/src/main/java/dev/apexnative/navigation/views/stack/StackLayout.kt +137 -1
  65. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +8 -1
  66. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +26 -4
  67. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +4 -3
  68. package/cli/app.js +1 -1
  69. package/cli/project.js +6 -2
  70. package/cli/setup/index.js +13 -0
  71. package/cli/setup/steps/appDelegate.js +66 -11
  72. package/cli/setup/steps/sceneDelegate.js +108 -0
  73. package/docs-md/architecture/transitions.md +7 -1
  74. package/docs-md/containers/modals.md +4 -2
  75. package/docs-md/containers/overlays.md +3 -1
  76. package/docs-md/containers/side-menu.md +4 -2
  77. package/docs-md/containers/tabs.md +2 -0
  78. package/docs-md/flows/forms-in-a-modal.md +1 -1
  79. package/docs-md/guides/deep-links.md +15 -33
  80. package/docs-md/help/glossary.md +1 -1
  81. package/docs-md/index.json +8 -0
  82. package/docs-md/screen-ui/back-and-gestures.md +6 -0
  83. package/docs-md/screen-ui/system-ui.md +1 -1
  84. package/docs-md/start/installation.md +1 -0
  85. package/ios/Animations/ANNTransitionAnimator.mm +13 -11
  86. package/ios/Animations/ANNTransitionWait.mm +6 -7
  87. package/ios/Animations/Elements/ANNElementFinder.h +57 -0
  88. package/ios/Animations/Elements/ANNElementFinder.mm +174 -2
  89. package/ios/Animations/Elements/ANNElementTransition.h +7 -5
  90. package/ios/Animations/Elements/ANNElementTransition.mm +17 -19
  91. package/ios/Animations/Elements/ANNSharedElementFlight.h +13 -8
  92. package/ios/Animations/Elements/ANNSharedElementFlight.mm +59 -24
  93. package/ios/CLAUDE.md +10 -2
  94. package/ios/CORE.md +3 -2
  95. package/ios/Contract/ANNCommandAnswer.h +4 -3
  96. package/ios/Contract/ANNCommandAnswer.mm +12 -2
  97. package/ios/Contract/ANNCommandRunner.h +2 -2
  98. package/ios/Contract/ANNCommandRunner.mm +1 -1
  99. package/ios/Contract/ANNErrorTexts.h +6 -2
  100. package/ios/Contract/ANNErrorTexts.mm +18 -10
  101. package/ios/Core/ANNDeepLinkQueue.h +20 -1
  102. package/ios/Core/ANNDeepLinkQueue.mm +107 -12
  103. package/ios/Core/ANNErrorHandler.h +8 -3
  104. package/ios/Core/ANNErrorHandler.mm +17 -1
  105. package/ios/Core/ANNEventContract.h +246 -0
  106. package/ios/Core/ANNEventContract.mm +225 -0
  107. package/ios/Core/ANNEventEmitter.h +5 -1
  108. package/ios/Core/ANNEventEmitter.mm +117 -80
  109. package/ios/Core/ANNHinge.mm +6 -4
  110. package/ios/Core/ANNSceneDelegate.mm +25 -15
  111. package/ios/Core/ANNSystemUI.h +3 -2
  112. package/ios/Core/ANNSystemUI.mm +7 -0
  113. package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +6 -4
  114. package/ios/Layouts/Modal/ANNModalCoordinator.mm +1 -1
  115. package/ios/Layouts/Modal/ANNModalPresentation.h +8 -5
  116. package/ios/Layouts/Modal/ANNModalPresentation.mm +12 -12
  117. package/ios/Layouts/Modal/ANNSheetPresenter.mm +83 -1
  118. package/ios/Layouts/Root/ANNRootCoordinator.mm +12 -3
  119. package/ios/Layouts/Screen/ANNComponentPresenter.h +11 -3
  120. package/ios/Layouts/Screen/ANNComponentPresenter.mm +34 -6
  121. package/ios/Layouts/Screen/ANNComponentViewController.mm +28 -7
  122. package/ios/Layouts/Screen/ANNNativeScreenContext.mm +7 -5
  123. package/ios/Layouts/Screen/ANNScreenInsets.mm +6 -4
  124. package/ios/Layouts/Screen/ANNScreenRegions.mm +9 -6
  125. package/ios/Layouts/SplitView/ANNSplitViewController.mm +4 -7
  126. package/ios/Options/ANNSheetOptions.h +4 -1
  127. package/ios/Public/ApexNavigation/ANNSceneDelegate.h +3 -0
  128. package/ios/RECIPES.md +2 -1
  129. package/ios/TurboModules/ANNTurboEventEmitter.mm +4 -35
  130. package/ios/TurboModules/ANNTurboModule.mm +5 -2
  131. package/lib/module/ARCHITECTURE.md +7 -4
  132. package/lib/module/api/app/createNavigation.js +2 -0
  133. package/lib/module/api/app/createNavigation.js.map +1 -1
  134. package/lib/module/api/hooks/useNavigation.js +8 -3
  135. package/lib/module/api/hooks/useNavigation.js.map +1 -1
  136. package/lib/module/api/linking/dispatchedLinks.js +23 -0
  137. package/lib/module/api/linking/dispatchedLinks.js.map +1 -0
  138. package/lib/module/interfaces/contract/errors.json +275 -0
  139. package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
  140. package/lib/typescript/api/hooks/useNavigation.d.ts.map +1 -1
  141. package/lib/typescript/api/linking/dispatchedLinks.d.ts +7 -0
  142. package/lib/typescript/api/linking/dispatchedLinks.d.ts.map +1 -0
  143. package/lib/typescript/interfaces/Events.d.ts +9 -0
  144. package/lib/typescript/interfaces/Events.d.ts.map +1 -1
  145. package/lib/typescript/interfaces/options/animations.d.ts +27 -18
  146. package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
  147. package/lib/typescript/interfaces/options/modals.d.ts +33 -24
  148. package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
  149. package/lib/typescript/interfaces/options/sideMenu.d.ts +7 -6
  150. package/lib/typescript/interfaces/options/sideMenu.d.ts.map +1 -1
  151. package/lib/typescript/interfaces/options/system.d.ts +10 -6
  152. package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
  153. package/package.json +1 -1
  154. package/src/ARCHITECTURE.md +7 -4
  155. package/src/api/app/createNavigation.ts +2 -0
  156. package/src/api/hooks/useNavigation.ts +8 -3
  157. package/src/api/linking/dispatchedLinks.ts +18 -0
  158. package/src/interfaces/Events.ts +10 -0
  159. package/src/interfaces/contract/errors.json +275 -0
  160. package/src/interfaces/options/animations.ts +27 -18
  161. package/src/interfaces/options/modals.ts +33 -24
  162. package/src/interfaces/options/sideMenu.ts +7 -6
  163. package/src/interfaces/options/system.ts +10 -6
package/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.0.0-alpha.3](https://github.com/apexnative/navigation/compare/v1.0.0-alpha.2...v1.0.0-alpha.3) (2026-10-22)
4
+
5
+
6
+ ### Features
7
+
8
+ * **android:** system stack transitions, an opaque default screen background and predictive back ([#26](https://github.com/apexnative/navigation/issues/26)) ([9f28969](https://github.com/apexnative/navigation/commit/9f28969a30a8902c1512cd2a24c3ddf5439f4642))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **android:** center the back button and the bar buttons in the row ([#35](https://github.com/apexnative/navigation/issues/35)) ([c908971](https://github.com/apexnative/navigation/commit/c9089716ea4e3b3f4bcdc42b16e57134018d76c0))
14
+ * **android:** fade through on a tab switch, a new tab's first frame in place ([#29](https://github.com/apexnative/navigation/issues/29)) ([60d69b6](https://github.com/apexnative/navigation/commit/60d69b618a97c8f7da974fbdf6f427461960d672))
15
+ * **android:** let an overlay cover the status bar ([#27](https://github.com/apexnative/navigation/issues/27)) ([2632194](https://github.com/apexnative/navigation/commit/26321945cf0c457780b3eb7bba1f3d988dad4d96))
16
+ * **android:** match each modal presentation style to its Android equivalent ([#31](https://github.com/apexnative/navigation/issues/31)) ([54ab265](https://github.com/apexnative/navigation/commit/54ab2651f3139e869a2d99a43465b33bfb171414))
17
+ * **android:** move the top bar with its screen in transitions of their own ([#34](https://github.com/apexnative/navigation/issues/34)) ([4d12ee6](https://github.com/apexnative/navigation/commit/4d12ee6d6ec26a04e529bdef8b8111d20e5116aa))
18
+ * close the side menu as a pick in it changes the center ([#28](https://github.com/apexnative/navigation/issues/28)) ([c4b3e81](https://github.com/apexnative/navigation/commit/c4b3e81ba44d2edb6d93d3ddc906eca165d46e29))
19
+
20
+
21
+ ### Performance Improvements
22
+
23
+ * **android:** render the modals of a setRoot's layout together with its root ([#32](https://github.com/apexnative/navigation/issues/32)) ([cf3e1d9](https://github.com/apexnative/navigation/commit/cf3e1d98ff7c5d2a05aba6485203e6fe35a3423d))
24
+
25
+ ## [1.0.0-alpha.2](https://github.com/apexnative/navigation/compare/v1.0.0-alpha.1...v1.0.0-alpha.2) (2026-10-22)
26
+
27
+
28
+ ### Bug Fixes
29
+
30
+ * **android:** fractional option sizes, sheet stops, live side menu size and menu appear events ([#18](https://github.com/apexnative/navigation/issues/18)) ([3ed8913](https://github.com/apexnative/navigation/commit/3ed8913126d83f5d75a265d22e3f80e581d329b8))
31
+ * **cli:** set up and make apps on React Native 0.88's template ([#23](https://github.com/apexnative/navigation/issues/23)) ([3c24f04](https://github.com/apexnative/navigation/commit/3c24f042f4d6a6a2660768a7443cc5eeba004235))
32
+ * **ios:** hand sheet detents to UIKit sorted by height and without repeats ([#15](https://github.com/apexnative/navigation/issues/15)) ([d1c1004](https://github.com/apexnative/navigation/commit/d1c10043353f45b452e7200d2c179515b6989737))
33
+ * **ios:** hide the dismissal of the old root's modals when a new root shows without animation ([#14](https://github.com/apexnative/navigation/issues/14)) ([b639232](https://github.com/apexnative/navigation/commit/b639232e8b73c38bf8599b7bac24ecc5c7104ca6))
34
+ * **ios:** keep deep links working on React Native 0.88 in apps with a scene delegate ([#24](https://github.com/apexnative/navigation/issues/24)) ([7f690cd](https://github.com/apexnative/navigation/commit/7f690cdac41be774b55cf7186105faa605249bc2))
35
+ * **ios:** keep the status bar blur in the status bar's frame as it changes ([#17](https://github.com/apexnative/navigation/issues/17)) ([d5051e9](https://github.com/apexnative/navigation/commit/d5051e9c30fc0040e726d12ef352da7cc43f2a8c))
36
+ * **ios:** log instead of calling a command's nil promise block ([#22](https://github.com/apexnative/navigation/issues/22)) ([b2ed4ca](https://github.com/apexnative/navigation/commit/b2ed4ca2cb76207b24747e78bf702ef1ab02146b))
37
+ * **ios:** reject a command whose answer goes away unanswered ([#12](https://github.com/apexnative/navigation/issues/12)) ([0914c03](https://github.com/apexnative/navigation/commit/0914c03ec465ae8273d736d1b12e5faef2ba4a52))
38
+ * **ios:** show a partialCurl modal as coverVertical when it isn't full screen ([#16](https://github.com/apexnative/navigation/issues/16)) ([404b3be](https://github.com/apexnative/navigation/commit/404b3be98beac73069bfc16bb3903f583aa9b844))
39
+ * keep a transition running when one element fails, and find its elements in one walk ([#21](https://github.com/apexnative/navigation/issues/21)) ([5dd1179](https://github.com/apexnative/navigation/commit/5dd1179834211abc985ffffbd2bd9622530be1dc))
40
+
3
41
  ## [1.0.0-alpha.1](https://github.com/apexnative/navigation/compare/v1.0.0-alpha.0...v1.0.0-alpha.1) (2026-10-21)
4
42
 
5
43
 
package/README.md CHANGED
@@ -1,34 +1,131 @@
1
1
  <picture>
2
- <source media="(prefers-color-scheme: dark)" srcset=".github/assets/navigation-banner-dark.png">
3
- <img alt="@apexnative/navigation: native navigation for React Native on iOS, iPadOS and Android" src=".github/assets/navigation-banner-light.png">
2
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/apexnative/navigation/main/.github/assets/navigation-banner-dark.png">
3
+ <img alt="@apexnative/navigation: native navigation for React Native on iOS, iPadOS and Android" src="https://raw.githubusercontent.com/apexnative/navigation/main/.github/assets/navigation-banner-light.png">
4
4
  </picture>
5
5
 
6
+ <p align="center">
7
+ <a href="https://www.npmjs.com/package/@apexnative/navigation"><img alt="npm version" src="https://img.shields.io/npm/v/@apexnative/navigation?label=npm&color=cb3837"></a>
8
+ <a href="https://www.npmjs.com/package/@apexnative/navigation"><img alt="npm downloads" src="https://img.shields.io/npm/dm/@apexnative/navigation"></a>
9
+ <a href="https://github.com/apexnative/navigation/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/apexnative/navigation/ci.yml?branch=main&label=CI"></a>
10
+ <img alt="Platforms: iOS, iPadOS, Android" src="https://img.shields.io/badge/platforms-iOS%20%7C%20iPadOS%20%7C%20Android-informational">
11
+ <img alt="React Native 0.85 or newer, New Architecture" src="https://img.shields.io/badge/React%20Native-0.85%2B%20%C2%B7%20New%20Architecture-61dafb">
12
+ <img alt="TypeScript types included" src="https://img.shields.io/npm/types/@apexnative/navigation">
13
+ <a href="https://github.com/apexnative/navigation/blob/main/LICENSE"><img alt="License: MIT" src="https://img.shields.io/npm/l/@apexnative/navigation"></a>
14
+ </p>
15
+
16
+ <p align="center">
17
+ <a href="https://navigation.apexnative.dev/docs/start/introduction"><b>Documentation</b></a> ·
18
+ <a href="https://navigation.apexnative.dev/docs/start/quick-start">Quick start</a> ·
19
+ <a href="https://navigation.apexnative.dev/api/starting-the-app/createNavigation">API reference</a> ·
20
+ <a href="https://github.com/apexnative/navigation/releases">Releases</a>
21
+ </p>
22
+
6
23
  # @apexnative/navigation
7
24
 
8
- Native navigation for React Native on iOS, iPadOS and Android. Stacks, tabs, modals, side
9
- menus and overlays are real platform containers — `UINavigationController`,
10
- `UITabBarController`, Material components — owned by the native side and driven from JS.
25
+ **The platform owns the navigation. React describes it.**
26
+
27
+ `@apexnative/navigation` gives a React Native app the navigation of the platform itself. Stacks, tabs, modals, side
28
+ menus, split views and overlays are the real containers of iOS and Android: `UINavigationController`,
29
+ `UITabBarController`, sheets with detents, `UISplitViewController`, the Android back stack and the Material components.
30
+ You describe the screens and how they are arranged in TypeScript; the native side shows them and reports back.
11
31
 
12
32
  > **Status:** a pre-release on npm; the API can still change before 1.0. The current version is on the
13
33
  > [releases page](https://github.com/apexnative/navigation/releases).
14
34
 
15
- ## Principles
35
+ ## Why
36
+
37
+ **The platform already knows how to navigate.** iOS and Android hold years of decisions about gestures,
38
+ accessibility, every screen size, memory and multitasking. A router that keeps its own model of the navigation has to
39
+ mirror all of that in JavaScript and catch up with every OS release. This library gives React the platform's own
40
+ containers instead of replacing them, so a new tab bar or toolbar of the OS arrives with its beta, not a year later.
41
+
42
+ **Native behavior, not only a native look.** The swipe back, the back button and dragging a sheet are the system's
43
+ own, with the same transitions, accessibility and memory use as in an app written in Swift or Kotlin. Nothing is
44
+ replayed into a copy of the state in React: JavaScript reads the state of the platform through events and hooks.
45
+
46
+ **Describe, don't command.** Native navigation usually speaks in JSON layouts and string ids, so a wrong screen name
47
+ or a missing prop shows up at run time. Here screens, props and roots are typed, and the same mistake is an error in
48
+ the editor.
49
+
50
+ | | A router in the React tree | Native navigation by commands | This library |
51
+ | ---------------------- | --------------------------------------------- | ----------------------------- | ------------------------------------------------- |
52
+ | **Who owns the state** | an object in the React tree | the OS | the OS |
53
+ | **Gestures** | native or drawn in JS, synced back into React | the system's own | the system's own |
54
+ | **How you navigate** | navigator components or files as URLs | JSON layouts and screen ids | `Stack`, `Tabs`, `SideMenu`; commands without ids |
55
+ | **Types** | typed route params | strings, props unchecked | names, props and roots checked |
56
+
57
+ ## A quick look
58
+
59
+ A screen is a component with its options:
60
+
61
+ ```tsx
62
+ import { Text } from 'react-native';
63
+ import { defineScreen } from '@apexnative/navigation';
64
+
65
+ function Details({ title }: { title?: string }) {
66
+ return <Text>{title ?? 'Details'}</Text>;
67
+ }
16
68
 
17
- - **The platform leads.** Native stacks, tabs, sheets and gestures rather than a web-style
18
- router; a URL is one entry point among push notifications, widgets and shortcuts.
19
- - **Native is the source of truth.** Navigation state, screen lifecycle, safe areas, keyboard
20
- and theme come from the OS.
21
- - **App lifecycle is first-class.** Cold start, splash, session restore, background and
22
- process death are explicit steps.
23
- - **New OS features, fast.** Support for new iOS and Android releases lands with the betas.
24
- - **Customization without losing native behavior.** Options on system components first, your
25
- own native components inside native containers next, custom JS UI only as a last resort.
26
- - **Performance is a requirement.** Transitions and gestures run natively; JS stays off the
27
- critical path, and we measure it in CI.
69
+ export const DetailsScreen = defineScreen({
70
+ component: Details,
71
+ options: (s, props) => s.title(props.title ?? 'Details'),
72
+ });
73
+ ```
74
+
75
+ The navigation names the screens and the root:
76
+
77
+ ```ts
78
+ import { createNavigation } from '@apexnative/navigation';
28
79
 
29
- ## Platforms
80
+ export const Navigation = createNavigation({
81
+ screens: { Home: HomeScreen, Details: DetailsScreen },
82
+ root: 'Home',
83
+ });
84
+ ```
85
+
86
+ Any screen opens another one with the platform's own transition:
30
87
 
31
- iOS, iPadOS and Android, on React Native 0.85 or newer with the New Architecture. The web is not a target.
88
+ ```ts
89
+ const navigation = useNavigation();
90
+ navigation.push('Details', { props: { title: 'Order 42' } });
91
+ // navigation.push('Detail') or a prop Details doesn't take: a TypeScript error
92
+ ```
93
+
94
+ ## What's in it
95
+
96
+ - **Containers:** native stacks, tabs, modals and sheets, side menus, split views on iPad, and overlays, nested in
97
+ each other: tabs of stacks, a stack in a modal, tabs in a side menu.
98
+ - **Screen UI as options:** the top bar, bar buttons, search, the toolbar and the floating action button, the status
99
+ bar and the system bars.
100
+ - **No safe area code:** every screen keeps its content clear of the bars, the cutout and the home indicator by itself.
101
+ - **Native screens:** SwiftUI, UIKit and Compose screens are pushed, presented and put in tabs the same way as React
102
+ screens.
103
+ - **One React tree when you want it:** each screen is its own React root by default; with `appProvider` all screens
104
+ share one tree.
105
+ - **The app's lifecycle:** cold start, the splash screen, deep links, notifications and switching roots on sign-in
106
+ and sign-out.
107
+ - **A CLI**, `apex-navigation`: sets up an app, checks it (`doctor`), adds screens, deep links, icons and the splash
108
+ screen, upgrades the navigation, migrates an app from another navigation library, and serves the commands and the
109
+ docs to AI coding agents (`mcp`).
110
+
111
+ ## When it fits
112
+
113
+ - Apps that should look and behave like the platform, on iPhone, iPad and Android.
114
+ - Apps with native screens, or a team that also writes Swift or Kotlin.
115
+ - Apps where startup, transitions and memory matter.
116
+
117
+ It doesn't fit an app that also ships to the web, or one that draws the same fully custom UI on every platform in
118
+ JavaScript.
119
+
120
+ ## Requirements
121
+
122
+ | | |
123
+ | -------------- | ------------------------------------------------------------- |
124
+ | React Native | 0.85 or newer, with the New Architecture (bridgeless, Fabric) |
125
+ | iOS and iPadOS | 15.1 or newer |
126
+ | Android | 7.0 or newer (minSdk 24) |
127
+ | Expo | not supported by `setup` yet |
128
+ | Web | not a target |
32
129
 
33
130
  ## Installation
34
131
 
@@ -37,41 +134,40 @@ npm install @apexnative/navigation
37
134
  npx apex-navigation setup
38
135
  ```
39
136
 
40
- `setup` shows what it changes in the app and asks before writing, then installs the pods on a Mac:
41
-
42
- - `MainApplication.kt` extends `NavigationApplication`, which loads React Native itself.
43
- - `MainActivity.kt` extends `NavigationActivity`.
44
- - `AndroidManifest.xml`: `android:enableOnBackInvokedCallback="true"`, so on the first screen the system plays its
45
- own back animation to the home screen (Android 16 turns it on for apps targeting SDK 36).
46
- - `AppDelegate.swift` extends `ANNAppDelegate`, which creates the window and starts React Native.
47
- - `Info.plist`: `UIViewControllerBasedStatusBarAppearance` is `true`, so each screen sets the status bar.
48
- - `index.js` starts the app through the navigation; a new `Navigation.ts` shows `App` as the first screen.
49
- - `navigation-env.d.ts` ties the commands to the screens of `Navigation.ts`, so names and props are checked.
50
-
51
- `--dry-run` shows the changes without writing them, `--yes` applies them without asking, `--skip-pods` leaves
52
- the pods for later. A file changed by hand stays as it is, and `setup` prints what to change in it. Expo apps
53
- aren't supported by `setup` yet. A new app starts with `npx @apexnative/navigation init MyApp`.
54
-
55
- `npx apex-navigation doctor` checks what the navigation needs in the app and on the machine: the files `setup`
56
- sets up, the typed commands, React Native loaded twice, the screens and links of the app, JDK 17, the Android
57
- SDK the app builds with, Xcode, CocoaPods, pods of an older navigation, a simulator and adb to run the app on,
58
- another navigation in the app. Each problem comes with its fix; `--fix` makes the ones the CLI has, for errors
59
- and warnings (`setup`, `links`, `icons`, `codegen`, `pod install`), asking before each, and `--json` prints the
60
- checks for CI and tools. It exits with 1 when it finds an error.
61
-
62
- The other commands: `screen` and `codegen` add screens, React or native; `links` declares deep links natively;
63
- `icons` and `splash` make the app icon and the splash screen; `upgrade` upgrades the navigation; `migrate` moves
64
- an app from another navigation library; `info` prints the versions for an issue; `mcp` serves
65
- the commands and the docs to AI coding agents.
66
-
67
- Edge-to-edge on Android follows the platform: always on Android 16+ for apps targeting SDK 36, and on
68
- Android 15 for apps targeting SDK 35. With `edgeToEdgeEnabled=true` in `android/gradle.properties` (the
69
- default of new React Native apps) it's on for every Android version.
137
+ `setup` shows what it changes in the native files and in `index.js`, asks before writing, and installs the pods on a
138
+ Mac. A new app starts with `npx @apexnative/navigation init MyApp`, and `npx apex-navigation doctor` checks an app
139
+ and the machine and fixes what it can. The [installation guide](https://navigation.apexnative.dev/docs/start/installation)
140
+ has the details, and the [quick start](https://navigation.apexnative.dev/docs/start/quick-start) builds a first app
141
+ with two screens.
142
+
143
+ Coming from another library: [React Navigation](https://navigation.apexnative.dev/docs/migration/from-react-navigation),
144
+ [Expo Router](https://navigation.apexnative.dev/docs/migration/from-expo-router),
145
+ [react-native-navigation](https://navigation.apexnative.dev/docs/migration/from-react-native-navigation).
146
+
147
+ ## Principles
148
+
149
+ 1. **The platform leads.** Native stacks, tabs, sheets and gestures, not a web-style router. A URL is one entry point
150
+ among push notifications, widgets and shortcuts.
151
+ 2. **Native is the source of truth.** Navigation state, screen lifecycle, safe areas, keyboard and theme come from the
152
+ OS.
153
+ 3. **App lifecycle is first-class.** Cold start, splash, session restore, background and process death are explicit
154
+ steps.
155
+ 4. **New OS features, fast.** Support for new iOS and Android releases lands with the betas.
156
+ 5. **Customization without losing native behavior.** Options of system components first, your own native components
157
+ inside native containers next, custom JS UI last.
158
+ 6. **Performance is a requirement.** Transitions and gestures run natively; JavaScript stays off the critical path.
159
+ 7. **Rendering and logic apart.** React renders screens. The logic of the app (a socket, a session, services) lives
160
+ outside the render tree: `navigation` works outside React, and `willMount` prepares the app before the first
161
+ screen.
162
+
163
+ When two of them pull apart, the order decides.
70
164
 
71
165
  ## Contributing
72
166
 
73
- See [CONTRIBUTING.md](CONTRIBUTING.md) and the [code of conduct](CODE_OF_CONDUCT.md).
167
+ The [Showcase app](https://github.com/apexnative/navigation/tree/main/example) runs every feature as a scenario.
168
+ See [CONTRIBUTING.md](https://github.com/apexnative/navigation/blob/main/CONTRIBUTING.md) and the
169
+ [code of conduct](https://github.com/apexnative/navigation/blob/main/CODE_OF_CONDUCT.md).
74
170
 
75
171
  ## License
76
172
 
77
- [MIT](LICENSE)
173
+ [MIT](https://github.com/apexnative/navigation/blob/main/LICENSE)
package/android/CLAUDE.md CHANGED
@@ -23,8 +23,8 @@ top-level folder. Main thread only, unless a line says otherwise.
23
23
  - `react/`: the way in and out: `NavigationTurboModule`, `CommandRunner`, `CommandAnswer`, `ErrorTexts`,
24
24
  `OptionsCommands`, `ReloadCoordinator`, `ReactGateway`, `ReactView` (a React root), the stores (`ScreenInsets`,
25
25
  `ScreenRegions`, `ArrangementStates`, `Hinge`, `StartInfo`), `LaunchLink`, `ScrollEvents`.
26
- - `react/events/`: `AppearanceDispatcher`, `ScreenAppearance`, `EventEmitter`, `NavigationStateReporter`,
27
- `ComponentType`.
26
+ - `react/events/`: `AppearanceDispatcher`, `ScreenAppearance`, `EventEmitter`, `EventContract` (made by
27
+ `scripts/contract.mjs`), `NavigationStateReporter`, `ComponentType`.
28
28
  - `viewcontrollers/viewcontroller/`: `ViewController` (the base of every node), `Presenter`, `IReactView` (what a
29
29
  screen shows), `ScrollEventListener`.
30
30
  - `viewcontrollers/child/`, `parent/`: `ChildController` and the registry; `ParentController` (the base of layouts),
@@ -73,8 +73,10 @@ top-level folder. Main thread only, unless a line says otherwise.
73
73
  `ScreenFrame.kt` (bars' room, window insets, keyboard), `ScreenSafeArea.kt`, `ComponentPresenter.kt` (background),
74
74
  `ScreenContentFactory.kt`, `ScreenFocus.kt`; `react/ReactView.kt`; `views/component/ComponentLayout.kt`.
75
75
  - Stack (queue, commands, back): `viewcontrollers/stack/StackQueue.kt`, `StackCommands.kt`, `StackController.kt`,
76
- `StackViews.kt`, `StackTransitions.kt`, `PreparedPushes.kt`; `views/stack/StackLayout.kt`; back:
77
- `NavigationActivity.kt`, `viewcontrollers/navigator/BackCallbackState.kt`.
76
+ `StackViews.kt`, `StackTransitions.kt`, `PreparedPushes.kt`; `views/stack/StackLayout.kt`, `ScreenEdge.kt` (the edge
77
+ a moving screen extends); back: `NavigationActivity.kt`, `viewcontrollers/navigator/BackCallbackState.kt`; the
78
+ preview of a pop during the back gesture (Android 14+): `StackController.BackGesture`, `BackPreview.kt`,
79
+ `stackPoppedByBack` of the layouts.
78
80
  - Stack FAB: `viewcontrollers/stack/fab/FabPresenter.kt`, `FabPlan.kt`, `FabPlacement.kt`; `views/stack/fab/`.
79
81
  - Top bar (title, buttons, menus, large title): `viewcontrollers/stack/topbar/TopBarPresenter.kt`, `TopBarRoom.kt`,
80
82
  `TopBarVisibility.kt`, `BarComponents.kt`, `ButtonPlaces.kt`, `LargeTitleCollapse.kt`, `BarRowTransition.kt`;
@@ -104,7 +106,7 @@ top-level folder. Main thread only, unless a line says otherwise.
104
106
  `NavigationStateReporter.kt`; `react/CommandAnswer.kt`.
105
107
  - Options (parsing, merging): `options/Options.kt`, `OptionsReader.kt`, `OptionsCache.kt`, `DefaultOptions.kt`,
106
108
  `params/`, `parsers/`; `viewcontrollers/viewcontroller/ViewController.kt` (resolution).
107
- - Error texts: `react/ErrorTexts.kt`.
109
+ - Error texts: `react/ErrorTexts.kt`, made by `scripts/contract.mjs` from `src/interfaces/contract/errors.json`.
108
110
  - Links: `react/LaunchLink.kt`, `NavigationActivity.kt` (`onNewIntent`); `react/StartInfo.kt`.
109
111
  - Hinge and regions: `react/Hinge.kt`, `react/ScreenRegions.kt`, `react/ScreenInsets.kt`, `utils/WindowFolds.kt`.
110
112
  - Native screens: `nativescreen/NativeScreenContext.kt`, `NativeScreenCalls.kt`, `NativeScreenCreator.kt`;
@@ -144,7 +146,11 @@ top-level folder. Main thread only, unless a line says otherwise.
144
146
  ## Pitfalls
145
147
 
146
148
  - Native code never touches React Native's views (their children, their layout): Fabric owns and recycles them. Move
147
- content through `SlotContainers` and `SlotView`, and find views by `nativeID` only through React Native's own search.
149
+ content through `SlotContainers` and `SlotView`, and find views by `nativeID` only through React Native's own search
150
+ or its tag (`ReactR.id.view_tag_native_id`); a transition's elements in one walk per screen (`TransitionViews`).
151
+ - Each step of a transition's element (its move into the layer, its animator, a flight's start and frames in
152
+ `MoveAnimator`) runs in `elementStep`: an exception skips that element only. A new step of an element goes there
153
+ too, or one bad element takes the whole transition down.
148
154
  - Every change of a stack's children goes through its `StackQueue`; a direct change of `shown` or of the container
149
155
  skips the table that decides interrupts and answers.
150
156
  - Every event of an appearance goes through `AppearanceDispatcher`. A container with its own loop of
@@ -163,14 +169,33 @@ top-level folder. Main thread only, unless a line says otherwise.
163
169
  `OverlayCoordinator.guarded`), which rejects the open answer and ends the record, or an exception ends the app and
164
170
  the command never answers.
165
171
  - A node makes its view in `createView`, never in its constructor.
172
+ - Whether a node keeps the status bar's room (its margin, its background band) goes through
173
+ `StatusBarOptions.isHiddenOrDrawBehind(node.isInOverlay)`: an overlay covers the whole window, and a rule that reads
174
+ `drawBehind` alone puts a light band over an overlay's dimmed backdrop.
166
175
  - Only `SystemUiWindow` writes to the window. A presenter that changes a bar option calls `SystemUiOwner.invalidate`.
167
176
  - The core names a module container only in `LayoutFactory`; elsewhere use a capability or `visibleChildren()`.
168
177
  - A hidden stack keeps a `mergeOptions` per entry; applying it for the wrong entry paints the wrong screen's bar.
178
+ - A `mergeOptions` moves or resizes only by what the merge names: the resolved options still hold the values of the
179
+ show, and acting on them undoes what the user did since (a dragged sheet snapped back to `selectedDetent`).
169
180
  - A sync getter reads a store, never a node; the store is written on main and cleared with its node.
170
181
  - A re-apply of the large title (a pop back, a light/dark switch, `mergeOptions`) collapses it to the list's last
171
182
  offset that `ScrollEventListener.lastOffset` keeps, never to 0, or it comes back expanded over a scrolled list.
172
183
  - A view's place in the window while a modal slides or a sheet is dragged comes from layout (`RestPlace`), never from
173
184
  `getLocationInWindow`, which counts the translations of the animation.
185
+ - The bar measures to its children: a picture laid into it for a transition that is taller than the bar the incoming
186
+ screen gives holds the bar at that height to the end (the row's picture of a pop from a large title). What doesn't
187
+ stay in the bar rides with the leaving screen (`TopBarPresenter.pictureUnderRow`).
188
+ - A `Toolbar` centers its navigation button and its menu in `min(minimumHeight, height)` (`buttonGravity` is top):
189
+ the row's toolbars take the row's height as their minimum (`TitleBar`); 0 pins the buttons to the row's top.
190
+ - A screen's overlay is clipped to the screen, and a screen without a large title is laid out under the bar (its `top`
191
+ is the bar's height): a picture of the bar in its overlay doesn't show. The bar's picture in a transition of the
192
+ stack's own is drawn by the stack's view with the screen's transform (`StackLayout.barTravels`).
193
+ - A React screen without `layout.backgroundColor` is opaque with the theme's `android:colorBackground`
194
+ (`ComponentPresenter`): a push keeps the covered screen under the new one until it ends, and a transparent screen
195
+ shows it. Only an explicit `'transparent'` / `null` (overlays, see-through modals) lets it through.
196
+ - The back gesture's preview shows the screen under the top outside any operation of the queue: it may only reveal
197
+ it and put it back, and its release goes through `StackQueue.cut(gesture = true)`. A command that comes meanwhile
198
+ stops it through `StackDisplay.stop`, like any transition it takes over.
174
199
  - Without edge to edge the window resizes for the keyboard by the manifest's soft input mode, so
175
200
  `layout.adjustResize: false` goes through the system UI owner's keyboard group (`SystemUiWindow.setKeyboardCovers`),
176
201
  not through the screen's padding.
package/android/CORE.md CHANGED
@@ -91,7 +91,9 @@ The events go from the main thread, synchronously, through `EventEmitter.current
91
91
  current root in the root layer, transparent (`RootLayerViews.place`), so its React roots start while the old root keeps
92
92
  the touches. It waits (`RenderWait`, by `animations.setRoot.enter.waitForRender`), then fades through or plays its own
93
93
  animation, the old root is destroyed with its `ComponentDidDisappear`, `NativeScreenReleased` and `SlotDestroyed`, and
94
- the end steps and answer are the same. The layout's modals and overlays show after it, one by one, before the answer.
94
+ the end steps and answer are the same. The layout's modals and overlays show after it, one by one, before the answer;
95
+ its modals are made with the root and render unseen in the modals layer, held (`ModalCoordinator.hold`), so each
96
+ shows in its turn without a wait of its own.
95
97
  The last `setRoot` wins: an older one is rejected (`ErrorTexts.setRootReplaced`) or finished at once.
96
98
  - **`showModal`** (`Navigator.showModal`, `ModalCoordinator.show`). One `ModalRecord` per modal; it joins the modals
97
99
  layer unseen (`ModalViews`), waits with its own `RenderWait`, then slides in (or opens as a `ModalSheet`). It shows
@@ -165,7 +167,10 @@ Each rule has one owner. Change the owner, not a caller; if a new feature needs
165
167
  `invokeDefaultOnBackPressed` → `Navigator.handleBack` → `ModalCoordinator.handleBack` → the root's
166
168
  `ParentController.handleBack` → `StackController.handleBack` → `StackQueue.cut`. `BackCallbackState` keeps the
167
169
  system callback enabled only while back has something to do.
168
- - **Error texts.** `ErrorTexts`: one function per text, the same words as iOS. JavaScript adds `[navigation] <command>:`.
170
+ - **Error texts.** `ErrorTexts`: one function per text, the same words as iOS, made with iOS's from
171
+ `src/interfaces/contract/errors.json` (`scripts/contract.mjs`). JavaScript adds `[navigation] <command>:`.
172
+ - **Event names and keys.** `EventContract`, made from the event types of `src/interfaces/`; `EventEmitter` and the
173
+ builders of payloads use it, never a string.
169
174
  - **Room for the bars.** A screen's room at the top and bottom is `ScreenFrame` with `ScreenSafeArea` and the
170
175
  `ParentController` room hooks (`getTopInset`, `keepsStatusBarRoomOf`, …). A screen in a pair forwards its room to
171
176
  the pair (`ScreenFrame.applyRoom`), and the pair's `getTopInset` uses the screens' rule (`ScreenFrame.topRoomOf`)
@@ -29,11 +29,12 @@ The steps for adding an option and for adding a command to the Android core; rea
29
29
  3. The body goes to the owner of the area: `Navigator` (root, modals, overlays), `StackCommands` (stacks), a
30
30
  coordinator. A stack operation is a `StackQueue` operation.
31
31
  4. New layout fields are read and checked in `LayoutReader`; checks against what shows are in `LayoutChecks` or in the
32
- command, before any node is made. Every rejection text is a function in `ErrorTexts` (same words as iOS).
32
+ command, before any node is made. Every rejection text is a function in `ErrorTexts` (same words as iOS),
33
+ made by `node scripts/contract.mjs` from `src/interfaces/contract/errors.json`: a new text goes there.
33
34
  5. The answer goes through `CommandAnswer`: add the name to `COMPLETED_COMMANDS` when the command changes what shows
34
35
  (then the state, the promise and `CommandCompleted` follow in that order). A transition ends through
35
36
  `AppearanceDispatcher.endTransition`.
36
37
  6. Tests: `CommandRunnerTest`, `CommandAnswerTest`, `ErrorTextsTest`, `LayoutReaderTest`; a stack operation also needs a
37
38
  case in the queue tests (`StackQueueHarness`).
38
- 7. A new event: `EventEmitter` (`emit…`), the payload type in `src/interfaces`, and for an appearance event the
39
- `AppearanceDispatcher.Sender`.
39
+ 7. A new event: the payload type in `src/interfaces`, then `node scripts/contract.mjs` for its name and keys in
40
+ `EventContract`; `EventEmitter` (`emit…`) with those, and for an appearance event the `AppearanceDispatcher.Sender`.
@@ -11,6 +11,7 @@ import android.view.View
11
11
  import android.view.ViewGroup
12
12
  import android.view.ViewTreeObserver
13
13
  import android.widget.EditText
14
+ import androidx.activity.BackEventCompat
14
15
  import androidx.activity.OnBackPressedCallback
15
16
  import androidx.activity.SystemBarStyle
16
17
  import androidx.activity.enableEdgeToEdge as enableActivityEdgeToEdge
@@ -37,6 +38,7 @@ import dev.apexnative.navigation.utils.MaterialTheme
37
38
  import dev.apexnative.navigation.viewcontrollers.navigator.BackCallbackState
38
39
  import dev.apexnative.navigation.viewcontrollers.navigator.Navigator
39
40
  import dev.apexnative.navigation.viewcontrollers.navigator.Navigators
41
+ import dev.apexnative.navigation.viewcontrollers.stack.StackController
40
42
 
41
43
  /**
42
44
  * The activity of an app with the navigation: its content holds, bottom to top, the copy of the splash and the layers
@@ -67,10 +69,36 @@ open class NavigationActivity : AppCompatActivity(), DefaultHardwareBackBtnHandl
67
69
  private val reloadBroadcast = ReloadBroadcast(this) { reloadFromDeveloperTools() }
68
70
 
69
71
  // Enabled while back has something to do in the app (BackCallbackState); otherwise the system does its own back.
72
+ // From Android 14, where the app hears the progress of the back gesture, a gesture that would pop a stack with the
73
+ // default transition previews the pop as the system previews back between activities (`StackController
74
+ // .BackGesture`); JavaScript's listeners hear back first, so with them there is no preview.
70
75
  private val backCallback = object : OnBackPressedCallback(false) {
71
- override fun handleOnBackPressed() = passBack()
76
+ override fun handleOnBackStarted(backEvent: BackEventCompat) {
77
+ backGesture = null
78
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE || BackCallbackState.hasJsListeners) return
79
+ val stack = navigator?.stackPoppedByBack() ?: return
80
+ backGesture = stack.startBackGesture(backEvent.swipeEdge == BackEventCompat.EDGE_LEFT, backEvent.touchY)
81
+ }
82
+
83
+ override fun handleOnBackProgressed(backEvent: BackEventCompat) {
84
+ backGesture?.progress(backEvent.progress, backEvent.touchY)
85
+ }
86
+
87
+ override fun handleOnBackCancelled() {
88
+ backGesture?.cancel()
89
+ backGesture = null
90
+ }
91
+
92
+ override fun handleOnBackPressed() {
93
+ val gesture = backGesture
94
+ backGesture = null
95
+ if (gesture?.commit() == true) BackCallbackState.update() else passBack()
96
+ }
72
97
  }
73
98
 
99
+ // The back gesture that previews a pop now; none.
100
+ private var backGesture: StackController.BackGesture? = null
101
+
74
102
  // Before each frame of the window: what back does may have changed, and the system decides at the start of a
75
103
  // gesture whether the app takes it.
76
104
  private val backBeforeFrame = ViewTreeObserver.OnPreDrawListener {
@@ -22,9 +22,13 @@ class StatusBarOptions {
22
22
  @JvmField var hideWithTopBar: Bool = NullBool()
23
23
  @JvmField var blur: Bool = NullBool()
24
24
 
25
- /** The status bar is hidden, or the screen is drawn under it: the screen keeps no room for it. */
26
- val isHiddenOrDrawBehind: Boolean
27
- get() = visible.isFalse || drawBehind.isTrue
25
+ /**
26
+ * The status bar is hidden, or the screen is drawn under it: the screen keeps no room for it. Without `drawBehind`, a
27
+ * screen or a layout in an overlay ([inOverlay]) is drawn under it: an overlay covers the whole window, its dimmed
28
+ * backdrop the status bar too.
29
+ */
30
+ fun isHiddenOrDrawBehind(inOverlay: Boolean): Boolean =
31
+ visible.isFalse || if (drawBehind.hasValue()) drawBehind.isTrue else inOverlay
28
32
 
29
33
  fun hasValue(): Boolean = visible.hasValue() || style.hasValue() || backgroundColor.hasValue() ||
30
34
  drawBehind.hasValue() || translucent.hasValue() || animate.hasValue() || hideWithTopBar.hasValue() ||
@@ -4,6 +4,7 @@ import android.content.Context
4
4
  import com.facebook.react.ReactApplication
5
5
  import com.facebook.react.bridge.Arguments
6
6
  import com.facebook.react.bridge.WritableMap
7
+ import dev.apexnative.navigation.react.events.EventContract
7
8
  import dev.apexnative.navigation.react.events.EventEmitter
8
9
  import java.util.concurrent.ConcurrentHashMap
9
10
 
@@ -33,9 +34,9 @@ internal object ArrangementStates {
33
34
  }
34
35
 
35
36
  private fun toMap(state: State): WritableMap = Arguments.createMap().apply {
36
- putString("placement", state.placement)
37
- putString("layout", state.layout)
38
- putBoolean("front", state.front)
39
- putBoolean("hidden", state.hidden)
37
+ putString(EventContract.ArrangementChanged.PLACEMENT, state.placement)
38
+ putString(EventContract.ArrangementChanged.LAYOUT, state.layout)
39
+ putBoolean(EventContract.ArrangementChanged.FRONT, state.front)
40
+ putBoolean(EventContract.ArrangementChanged.HIDDEN, state.hidden)
40
41
  }
41
42
  }