@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
@@ -24,15 +24,23 @@ static NSMutableSet *ANNPreviews(void) {
24
24
  @implementation ANNPreviewInteraction {
25
25
  UIViewController *_preview;
26
26
  NSInteger _reactTag;
27
+ __weak UIViewController *_source;
28
+ BOOL (^_prepare)(void);
27
29
  BOOL (^_commit)(void);
28
30
  void (^_dismissed)(void);
29
31
  UIContextMenuInteraction *_interaction;
32
+ // The snapshots of the view that the menu of this press lifts and puts back, over the view until
33
+ // the menu is gone. Each press has its own list: a new press may start while the last menu goes.
34
+ NSMutableArray<UIView *> *_snapshots;
35
+ // The list of the menu that goes now: its end removes them.
36
+ __weak NSMutableArray<UIView *> *_endingSnapshots;
30
37
  }
31
38
 
32
39
  + (void)attachPreview:(UIViewController *)preview
33
40
  toView:(UIView *)view
34
41
  reactTag:(NSInteger)reactTag
35
42
  source:(UIViewController *)source
43
+ prepare:(BOOL (^)(void))prepare
36
44
  commit:(BOOL (^)(void))commit
37
45
  dismissed:(void (^)(void))dismissed {
38
46
  if (!view || !preview) {
@@ -45,6 +53,8 @@ static NSMutableSet *ANNPreviews(void) {
45
53
  ANNPreviewInteraction *previewInteraction = [ANNPreviewInteraction new];
46
54
  previewInteraction->_preview = preview;
47
55
  previewInteraction->_reactTag = reactTag;
56
+ previewInteraction->_source = source;
57
+ previewInteraction->_prepare = [prepare copy];
48
58
  previewInteraction->_commit = [commit copy];
49
59
  previewInteraction->_dismissed = [dismissed copy];
50
60
  previewInteraction->_interaction =
@@ -91,7 +101,9 @@ static NSMutableSet *ANNPreviews(void) {
91
101
  [view removeInteraction:_interaction];
92
102
  // A tap's commit animation may still run: a preview that went, its screen destroyed and its push failed, is not
93
103
  // pushed when the animation ends.
104
+ _prepare = nil;
94
105
  _commit = nil;
106
+ [ANNPreviewInteraction removeSnapshots:_snapshots];
95
107
  void (^dismissed)(void) = _dismissed;
96
108
  _dismissed = nil;
97
109
  if (dismissed) {
@@ -116,6 +128,18 @@ static NSMutableSet *ANNPreviews(void) {
116
128
  [self detach];
117
129
  return nil;
118
130
  }
131
+ // UIKit ends a lift that never became a menu too (the touch ended before the long press); should
132
+ // it not, the snapshot of that press goes now.
133
+ if (_snapshots != _endingSnapshots) {
134
+ [ANNPreviewInteraction removeSnapshots:_snapshots];
135
+ }
136
+ _snapshots = [NSMutableArray new];
137
+ // UIKit asks for the configuration as the press starts, about half a second before it shows the preview: the
138
+ // screen renders now, so that its content is there by then.
139
+ if (_prepare && !_prepare()) {
140
+ [self detach];
141
+ return nil;
142
+ }
119
143
  UIViewController *preview = _preview;
120
144
  NSArray *actions = preview.resolveOptions.preview.actions;
121
145
  return [UIContextMenuConfiguration
@@ -129,6 +153,23 @@ static NSMutableSet *ANNPreviews(void) {
129
153
  }];
130
154
  }
131
155
 
156
+ // The menu goes: the snapshots of its press go once it is gone. UIKit asks for the one
157
+ // it goes back to after this call, so the list is read at the end, not now.
158
+ - (void)contextMenuInteraction:(UIContextMenuInteraction *)interaction
159
+ willEndForConfiguration:(UIContextMenuConfiguration *)configuration
160
+ animator:(id<UIContextMenuInteractionAnimating>)animator {
161
+ NSMutableArray<UIView *> *snapshots = _snapshots;
162
+ _endingSnapshots = snapshots;
163
+ void (^remove)(void) = ^{
164
+ [ANNPreviewInteraction removeSnapshots:snapshots];
165
+ };
166
+ if (animator) {
167
+ [animator addCompletion:remove];
168
+ } else {
169
+ dispatch_async(dispatch_get_main_queue(), remove);
170
+ }
171
+ }
172
+
132
173
  - (void)contextMenuInteraction:(UIContextMenuInteraction *)interaction
133
174
  willPerformPreviewActionForMenuWithConfiguration:(UIContextMenuConfiguration *)configuration
134
175
  animator:(id<UIContextMenuInteractionCommitAnimating>)
@@ -148,24 +189,45 @@ static NSMutableSet *ANNPreviews(void) {
148
189
 
149
190
  #pragma mark - Targeted previews
150
191
 
151
- // The view the menu lifts from and goes back to: a snapshot of the source view in its window. With
152
- // the source view itself UIKit adds its views next to it, among the React views of its parent, and
153
- // Fabric then mounts and unmounts at the wrong places.
192
+ // The view the menu lifts from and goes back to: a snapshot of the source view, laid over it in the
193
+ // view of its screen, the core's own (in its window when the view is elsewhere), so that it goes with
194
+ // the screen (a pop right after the menu). With the source view itself UIKit adds its views next to
195
+ // it, among the React views of its parent, and Fabric then mounts and unmounts at the wrong places.
196
+ // A snapshot out of the window, with only a target there, iOS 27 doesn't lift: it dims it in place.
154
197
  - (UITargetedPreview *)snapshotPreviewOf:(UIView *)view {
155
- UIWindow *window = view.window;
198
+ UIView *container = _source.viewIfLoaded;
199
+ if (!container || ![view isDescendantOfView:container]) {
200
+ container = view.window;
201
+ }
202
+ // A screen out of its window (a command took it away while the menu showed) has no place for it:
203
+ // UIKit needs the view in a window.
204
+ if (!container.window) {
205
+ return nil;
206
+ }
156
207
  UIView *snapshot = [view snapshotViewAfterScreenUpdates:NO];
157
- if (!window || !snapshot) {
208
+ if (!snapshot) {
158
209
  return nil;
159
210
  }
211
+ snapshot.frame = [view convertRect:view.bounds toView:container];
212
+ snapshot.userInteractionEnabled = NO;
213
+ snapshot.accessibilityElementsHidden = YES;
214
+ [container addSubview:snapshot];
215
+ if (!_snapshots) {
216
+ _snapshots = [NSMutableArray new];
217
+ }
218
+ [_snapshots addObject:snapshot];
160
219
  UIPreviewParameters *parameters = [UIPreviewParameters new];
161
220
  parameters.backgroundColor = UIColor.clearColor;
162
221
  parameters.visiblePath = [UIBezierPath bezierPathWithRoundedRect:view.bounds
163
222
  cornerRadius:view.layer.cornerRadius];
164
- CGPoint center = [view convertPoint:CGPointMake(CGRectGetMidX(view.bounds),
165
- CGRectGetMidY(view.bounds))
166
- toView:window];
167
- UIPreviewTarget *target = [[UIPreviewTarget alloc] initWithContainer:window center:center];
168
- return [[UITargetedPreview alloc] initWithView:snapshot parameters:parameters target:target];
223
+ return [[UITargetedPreview alloc] initWithView:snapshot parameters:parameters];
224
+ }
225
+
226
+ + (void)removeSnapshots:(NSMutableArray<UIView *> *)snapshots {
227
+ for (UIView *snapshot in snapshots) {
228
+ [snapshot removeFromSuperview];
229
+ }
230
+ [snapshots removeAllObjects];
169
231
  }
170
232
 
171
233
  - (UITargetedPreview *)contextMenuInteraction:(UIContextMenuInteraction *)interaction
@@ -0,0 +1,63 @@
1
+ #import "ANNEventEmitter.h"
2
+ #import <UIKit/UIKit.h>
3
+
4
+ NS_ASSUME_NONNULL_BEGIN
5
+
6
+ /// A view that keeps a screen's content out of its padding (the screen's safe area view).
7
+ @protocol ANNScreenPaddingListener <NSObject>
8
+ /// The padding of its screen changed. Main queue.
9
+ - (void)screenPaddingDidChange;
10
+ @end
11
+
12
+ /// What JavaScript knows of each screen's place, by the screen's id, in one record: its safe area (the insets
13
+ /// JavaScript gets, `useSafeAreaInsets`, and the padding of its safe area view), its reserved regions
14
+ /// (`useReservedRegions`) and, in a pair, its arrangement (`useArrangement`). The core measures them
15
+ /// (`ANNScreenSafeArea`, `ANNScreenRegions`, the pair's layout) on the main queue and keeps them here; JavaScript reads
16
+ /// them from its own thread for a screen's first render, under one lock, and gets every change as an event. When the
17
+ /// screen goes, `removeScreenId:` clears all of it. As on Android (`ScreenEnvironment`).
18
+ @interface ANNScreenEnvironment : NSObject
19
+
20
+ /// Keeps the screen's insets and the padding of its safe area view. The padding is the part of the insets the safe
21
+ /// area view keeps the content out of (the edges the screen's options give); JavaScript gets the rest, what still
22
+ /// covers the content (0 on a padded edge). Tells the padding's listeners of that screen when the padding changed, then
23
+ /// JavaScript (`ANN.ScreenInsetsChanged`) when its insets did. Main queue.
24
+ + (void)setInsets:(UIEdgeInsets)insets
25
+ padding:(UIEdgeInsets)padding
26
+ forScreenId:(NSString *)screenId
27
+ eventEmitter:(ANNEventEmitter *)eventEmitter;
28
+ /// The padding of the screen's safe area view; none before the screen was laid out. Any thread.
29
+ + (UIEdgeInsets)paddingForScreenId:(NSString *)screenId;
30
+ /// `{ top, right, bottom, left }`, or nil before the screen was laid out. Any thread.
31
+ + (nullable NSDictionary<NSString *, NSNumber *> *)insetsForScreenId:(NSString *)screenId;
32
+
33
+ /// Keeps the screen's regions (`{ division, occlusion }`) and tells JavaScript (`ANN.ScreenRegionsChanged`) when they
34
+ /// changed. None at first is what JavaScript reads before the first layout: it is neither kept nor told. Main queue.
35
+ + (void)setRegions:(NSDictionary<NSString *, NSArray *> *)regions
36
+ forScreenId:(NSString *)screenId
37
+ eventEmitter:(ANNEventEmitter *)eventEmitter;
38
+ /// `{ division, occlusion }`, or nil before the screen's regions were first kept. Any thread.
39
+ + (nullable NSDictionary<NSString *, NSArray *> *)regionsForScreenId:(NSString *)screenId;
40
+
41
+ /// Keeps the screen's arrangement (`{ placement, layout, front, hidden }`) and tells JavaScript
42
+ /// (`ANN.ArrangementChanged`) when it changed; nothing goes without an emitter. Main queue.
43
+ + (void)setArrangement:(NSDictionary<NSString *, id> *)arrangement
44
+ forScreenId:(NSString *)screenId
45
+ eventEmitter:(nullable ANNEventEmitter *)eventEmitter;
46
+ /// The screen's arrangement, or nil for a screen outside a pair. Any thread.
47
+ + (nullable NSDictionary<NSString *, id> *)arrangementForScreenId:(NSString *)screenId;
48
+
49
+ /// Tells `listener` of each change of the screen's padding, until it is removed or goes (held weakly). Several
50
+ /// listeners may listen to one screen. Main queue.
51
+ + (void)addPaddingListener:(id<ANNScreenPaddingListener>)listener forScreenId:(NSString *)screenId;
52
+ + (void)removePaddingListener:(id<ANNScreenPaddingListener>)listener
53
+ forScreenId:(NSString *)screenId;
54
+
55
+ /// Forgets everything kept for the screen. Its padding listeners stay: a live safe area view keeps listening while it
56
+ /// keeps the id, and stops itself. Main queue.
57
+ + (void)removeScreenId:(NSString *)screenId;
58
+ /// Forgets every screen: after a reload the new JavaScript counts its ids anew. Main queue.
59
+ + (void)removeAll;
60
+
61
+ @end
62
+
63
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,181 @@
1
+ #import "ANNScreenEnvironment.h"
2
+ #import "ANNEventContract.h"
3
+
4
+ // One screen's record; nil for a fact not known yet (not laid out, no regions, outside a pair). Changed and read only
5
+ // under the lock of `ANNEnvironmentById`; the values are immutable, so a reader keeps what it took.
6
+ @interface ANNScreenEnvironmentRecord : NSObject
7
+ @property(nonatomic, copy, nullable) NSDictionary<NSString *, NSNumber *> *insets;
8
+ @property(nonatomic, strong, nullable) NSValue *padding;
9
+ @property(nonatomic, copy, nullable) NSDictionary<NSString *, NSArray *> *regions;
10
+ @property(nonatomic, copy, nullable) NSDictionary<NSString *, id> *arrangement;
11
+ @end
12
+
13
+ @implementation ANNScreenEnvironmentRecord
14
+ @end
15
+
16
+ // Written on the main queue, read from any thread: every access holds its lock.
17
+ static NSMutableDictionary<NSString *, ANNScreenEnvironmentRecord *> *ANNEnvironmentById;
18
+ // The safe area views of each screen, by its id (the id's value: the view's id and the core's are other strings), held
19
+ // weakly. Main queue only.
20
+ static NSMutableDictionary<NSString *, NSHashTable<id<ANNScreenPaddingListener>> *>
21
+ *ANNPaddingListenersById;
22
+
23
+ @implementation ANNScreenEnvironment
24
+
25
+ + (void)initialize {
26
+ if (self == ANNScreenEnvironment.class) {
27
+ ANNEnvironmentById = [NSMutableDictionary new];
28
+ ANNPaddingListenersById = [NSMutableDictionary new];
29
+ }
30
+ }
31
+
32
+ // The screen's record, a new one for a screen not kept yet. Under the lock.
33
+ + (ANNScreenEnvironmentRecord *)recordOf:(NSString *)screenId {
34
+ ANNScreenEnvironmentRecord *record = ANNEnvironmentById[screenId];
35
+ if (!record) {
36
+ record = [ANNScreenEnvironmentRecord new];
37
+ ANNEnvironmentById[screenId] = record;
38
+ }
39
+ return record;
40
+ }
41
+
42
+ #pragma mark - Insets and padding
43
+
44
+ + (void)setInsets:(UIEdgeInsets)insets
45
+ padding:(UIEdgeInsets)padding
46
+ forScreenId:(NSString *)screenId
47
+ eventEmitter:(ANNEventEmitter *)eventEmitter {
48
+ NSValue *paddingValue = [NSValue valueWithUIEdgeInsets:padding];
49
+ // JavaScript gets what still covers the content: the edges the safe area view keeps it off are 0.
50
+ const auto &keys = ANNEventContract.ScreenInsetsChanged;
51
+ NSDictionary<NSString *, NSNumber *> *value = @{
52
+ keys.top : @(MAX(insets.top - padding.top, 0)),
53
+ keys.right : @(MAX(insets.right - padding.right, 0)),
54
+ keys.bottom : @(MAX(insets.bottom - padding.bottom, 0)),
55
+ keys.left : @(MAX(insets.left - padding.left, 0)),
56
+ };
57
+ BOOL paddingChanged;
58
+ BOOL insetsChanged;
59
+ @synchronized(ANNEnvironmentById) {
60
+ ANNScreenEnvironmentRecord *record = [self recordOf:screenId];
61
+ paddingChanged = ![record.padding isEqualToValue:paddingValue];
62
+ insetsChanged = ![record.insets isEqualToDictionary:value];
63
+ record.padding = paddingValue;
64
+ record.insets = value;
65
+ }
66
+ // The listeners read the padding back, so it is kept before they are told. A copy: a listener may stop or start
67
+ // listening while it is told.
68
+ if (paddingChanged) {
69
+ NSHashTable<id<ANNScreenPaddingListener>> *listeners = ANNPaddingListenersById[screenId];
70
+ for (id<ANNScreenPaddingListener> listener in listeners.allObjects) {
71
+ [listener screenPaddingDidChange];
72
+ }
73
+ }
74
+ if (insetsChanged) {
75
+ [eventEmitter sendScreenInsetsChanged:screenId insets:value];
76
+ }
77
+ }
78
+
79
+ + (UIEdgeInsets)paddingForScreenId:(NSString *)screenId {
80
+ @synchronized(ANNEnvironmentById) {
81
+ return ANNEnvironmentById[screenId].padding.UIEdgeInsetsValue;
82
+ }
83
+ }
84
+
85
+ + (NSDictionary<NSString *, NSNumber *> *)insetsForScreenId:(NSString *)screenId {
86
+ @synchronized(ANNEnvironmentById) {
87
+ return ANNEnvironmentById[screenId].insets;
88
+ }
89
+ }
90
+
91
+ #pragma mark - Regions
92
+
93
+ + (void)setRegions:(NSDictionary<NSString *, NSArray *> *)regions
94
+ forScreenId:(NSString *)screenId
95
+ eventEmitter:(ANNEventEmitter *)eventEmitter {
96
+ const auto &keys = ANNEventContract.ScreenRegionsChanged;
97
+ BOOL empty = [regions[keys.division] count] == 0 && [regions[keys.occlusion] count] == 0;
98
+ @synchronized(ANNEnvironmentById) {
99
+ NSDictionary<NSString *, NSArray *> *before = ANNEnvironmentById[screenId].regions;
100
+ if ((!before && empty) || [before isEqualToDictionary:regions]) {
101
+ return;
102
+ }
103
+ [self recordOf:screenId].regions = regions;
104
+ }
105
+ [eventEmitter sendScreenRegionsChanged:screenId regions:regions];
106
+ }
107
+
108
+ + (NSDictionary<NSString *, NSArray *> *)regionsForScreenId:(NSString *)screenId {
109
+ @synchronized(ANNEnvironmentById) {
110
+ return ANNEnvironmentById[screenId].regions;
111
+ }
112
+ }
113
+
114
+ #pragma mark - Arrangement
115
+
116
+ + (void)setArrangement:(NSDictionary<NSString *, id> *)arrangement
117
+ forScreenId:(NSString *)screenId
118
+ eventEmitter:(ANNEventEmitter *)eventEmitter {
119
+ @synchronized(ANNEnvironmentById) {
120
+ ANNScreenEnvironmentRecord *record = [self recordOf:screenId];
121
+ if ([record.arrangement isEqualToDictionary:arrangement]) {
122
+ return;
123
+ }
124
+ record.arrangement = arrangement;
125
+ }
126
+ [eventEmitter sendArrangementChanged:screenId state:arrangement];
127
+ }
128
+
129
+ + (NSDictionary<NSString *, id> *)arrangementForScreenId:(NSString *)screenId {
130
+ @synchronized(ANNEnvironmentById) {
131
+ return ANNEnvironmentById[screenId].arrangement;
132
+ }
133
+ }
134
+
135
+ #pragma mark - Padding listeners
136
+
137
+ + (void)addPaddingListener:(id<ANNScreenPaddingListener>)listener
138
+ forScreenId:(NSString *)screenId {
139
+ NSHashTable<id<ANNScreenPaddingListener>> *listeners = ANNPaddingListenersById[screenId];
140
+ if (!listeners) {
141
+ listeners = [NSHashTable weakObjectsHashTable];
142
+ ANNPaddingListenersById[screenId] = listeners;
143
+ }
144
+ [listeners addObject:listener];
145
+ }
146
+
147
+ + (void)removePaddingListener:(id<ANNScreenPaddingListener>)listener
148
+ forScreenId:(NSString *)screenId {
149
+ NSHashTable<id<ANNScreenPaddingListener>> *listeners = ANNPaddingListenersById[screenId];
150
+ [listeners removeObject:listener];
151
+ [self forgetListenersOfScreenIdIfNone:screenId];
152
+ }
153
+
154
+ // A view that went (it doesn't remove itself in its `dealloc`) leaves no entry in the weak table: `allObjects` counts
155
+ // only the live ones. The table of a screen nobody listens to goes with the last one, or with the screen's record.
156
+ + (void)forgetListenersOfScreenIdIfNone:(NSString *)screenId {
157
+ NSHashTable<id<ANNScreenPaddingListener>> *listeners = ANNPaddingListenersById[screenId];
158
+ if (listeners && listeners.allObjects.count == 0) {
159
+ [ANNPaddingListenersById removeObjectForKey:screenId];
160
+ }
161
+ }
162
+
163
+ #pragma mark - Removal
164
+
165
+ + (void)removeScreenId:(NSString *)screenId {
166
+ @synchronized(ANNEnvironmentById) {
167
+ [ANNEnvironmentById removeObjectForKey:screenId];
168
+ }
169
+ [self forgetListenersOfScreenIdIfNone:screenId];
170
+ }
171
+
172
+ + (void)removeAll {
173
+ @synchronized(ANNEnvironmentById) {
174
+ [ANNEnvironmentById removeAllObjects];
175
+ }
176
+ for (NSString *screenId in ANNPaddingListenersById.allKeys) {
177
+ [self forgetListenersOfScreenIdIfNone:screenId];
178
+ }
179
+ }
180
+
181
+ @end
@@ -1,12 +1,10 @@
1
- #import "ANNEventEmitter.h"
2
1
  #import <UIKit/UIKit.h>
3
2
 
4
3
  NS_ASSUME_NONNULL_BEGIN
5
4
 
6
- /// The reserved regions of each screen (`useReservedRegions`), iOS 27.1: `division`, where the screen divides (the fold
7
- /// of a partly folded device), and `occlusion`, where hardware covers it (a camera); each a list of
8
- /// `{ x, y, width, height }`. The native side keeps them on the main queue; JavaScript reads them from its own thread
9
- /// for a screen's first render, and gets every change as `ANN.ScreenRegionsChanged`.
5
+ /// The reserved regions of a screen (`useReservedRegions`), iOS 27.1: `division`, where the screen divides (the fold of
6
+ /// a partly folded device), and `occlusion`, where hardware covers it (a camera); each a list of
7
+ /// `{ x, y, width, height }`. Measured here; kept for JavaScript by `ANNScreenEnvironment`.
10
8
  @interface ANNScreenRegions : NSObject
11
9
 
12
10
  /// The active regions UIKit reserves in `view`, without the margins it adds around them for interactive content, in
@@ -15,19 +13,6 @@ NS_ASSUME_NONNULL_BEGIN
15
13
  + (nullable NSDictionary<NSString *, NSArray *> *)regionsOfView:(UIView *)view
16
14
  inCoordinatesOf:(UIView *)coordinateView;
17
15
 
18
- /// Keeps the screen's regions and tells when they changed. Main queue.
19
- + (void)setRegions:(NSDictionary<NSString *, NSArray *> *)regions
20
- forScreenId:(NSString *)screenId
21
- eventEmitter:(ANNEventEmitter *)eventEmitter;
22
-
23
- /// `{ division, occlusion }`, or nil before the screen was laid out. Any thread.
24
- + (nullable NSDictionary<NSString *, NSArray *> *)regionsForScreenId:(NSString *)screenId;
25
-
26
- + (void)removeScreenId:(NSString *)screenId;
27
-
28
- /// Forgets every screen: after a reload the new JavaScript counts its ids anew. Main queue.
29
- + (void)removeAll;
30
-
31
16
  @end
32
17
 
33
18
  NS_ASSUME_NONNULL_END
@@ -1,8 +1,6 @@
1
1
  #import "ANNScreenRegions.h"
2
2
  #import "ANNEventContract.h"
3
3
 
4
- static NSMutableDictionary<NSString *, NSDictionary<NSString *, NSArray *> *> *ANNScreenRegionsById;
5
-
6
4
  #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 270100
7
5
  // The part of a region inside the screen, CGRectNull for a region outside it (the fold beside a screen of a pair, the
8
6
  // camera above a screen under the bar). A fold is 0 wide or 0 high: it is inside where its line crosses the screen,
@@ -51,12 +49,6 @@ ANNRegionRects(NSArray<UIViewReservedRegion *> *regions, UIView *view, UIView *c
51
49
 
52
50
  @implementation ANNScreenRegions
53
51
 
54
- + (void)initialize {
55
- if (self == ANNScreenRegions.class) {
56
- ANNScreenRegionsById = [NSMutableDictionary new];
57
- }
58
- }
59
-
60
52
  + (NSDictionary<NSString *, NSArray *> *)regionsOfView:(UIView *)view
61
53
  inCoordinatesOf:(UIView *)coordinateView {
62
54
  #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 270100
@@ -75,34 +67,4 @@ ANNRegionRects(NSArray<UIViewReservedRegion *> *regions, UIView *view, UIView *c
75
67
  return nil;
76
68
  }
77
69
 
78
- + (void)setRegions:(NSDictionary<NSString *, NSArray *> *)regions
79
- forScreenId:(NSString *)screenId
80
- eventEmitter:(ANNEventEmitter *)eventEmitter {
81
- @synchronized(ANNScreenRegionsById) {
82
- if ([ANNScreenRegionsById[screenId] isEqualToDictionary:regions]) {
83
- return;
84
- }
85
- ANNScreenRegionsById[screenId] = regions;
86
- }
87
- [eventEmitter sendScreenRegionsChanged:screenId regions:regions];
88
- }
89
-
90
- + (NSDictionary<NSString *, NSArray *> *)regionsForScreenId:(NSString *)screenId {
91
- @synchronized(ANNScreenRegionsById) {
92
- return ANNScreenRegionsById[screenId];
93
- }
94
- }
95
-
96
- + (void)removeScreenId:(NSString *)screenId {
97
- @synchronized(ANNScreenRegionsById) {
98
- [ANNScreenRegionsById removeObjectForKey:screenId];
99
- }
100
- }
101
-
102
- + (void)removeAll {
103
- @synchronized(ANNScreenRegionsById) {
104
- [ANNScreenRegionsById removeAllObjects];
105
- }
106
- }
107
-
108
70
  @end
@@ -7,10 +7,6 @@ NS_ASSUME_NONNULL_BEGIN
7
7
  typedef struct {
8
8
  /// The screen is in a stack.
9
9
  BOOL inStack;
10
- /// The screen's stack shows its toolbar.
11
- BOOL stackShowsToolbar;
12
- /// The bottom of the window's safe area: the home indicator.
13
- CGFloat windowBottomSafeArea;
14
10
  /// The physical side of the iPhone Duo vertical bar (iOS 27.1): `UIRectEdgeLeft`, `UIRectEdgeRight`, or
15
11
  /// `UIRectEdgeNone` without one.
16
12
  UIRectEdge verticalBarSide;
@@ -27,11 +23,10 @@ FOUNDATION_EXPORT UIEdgeInsets ANNScreenInsetsOverRoot(CGRect rootFrame, CGSize
27
23
  UIEdgeInsets safeArea);
28
24
 
29
25
  /// The padding the screen's safe area view keeps (`layout.safeAreaEdges`): the insets on the padded edges, 0 on the
30
- /// others. With `layout.safeAreaEdges` exactly those edges (an explicit `'top'` keeps the top under a large title too);
31
- /// without it every edge but: the top under a shown top bar (in a stack, under the top bar, `topBar.visible` not
32
- /// `false`) or with a large title that can show; the bottom when the bottom inset covers more than the window's home
33
- /// indicator (by over 0.5 pt), or in a stack with a toolbar and `topBar.hideOnScroll`; the side of the vertical bar
34
- /// unless `layout.drawBehindVerticalBar` or `layout.verticalBars` is `false`.
26
+ /// others. With `layout.safeAreaEdges` exactly those edges, but the top under a large title that can show (in a stack,
27
+ /// `topBar.visible` not `false`); without it every edge but: the top under a shown top bar (in a stack, under the top
28
+ /// bar, `topBar.visible` not `false`) or with a large title that can show; the bottom, always; the side of the
29
+ /// vertical bar unless `layout.drawBehindVerticalBar` or `layout.verticalBars` is `false`.
35
30
  FOUNDATION_EXPORT UIEdgeInsets ANNScreenPadding(UIEdgeInsets insets, ANNNavigationOptions *options,
36
31
  ANNScreenPaddingContext context);
37
32
 
@@ -1,9 +1,6 @@
1
1
  #import "ANNScreenSafeArea.h"
2
2
  #import "ANNScreenBars.h"
3
3
 
4
- // A bar at the bottom covers more than the home indicator when the bottom inset passes it by more than this.
5
- static const CGFloat ANNBottomBarThreshold = 0.5;
6
-
7
4
  CGRect ANNScreenRootFrame(CGRect bounds, UIEdgeInsets safeArea, BOOL fromTop, BOOL toBottom) {
8
5
  CGFloat top = fromTop ? 0 : safeArea.top;
9
6
  CGFloat bottom = toBottom ? CGRectGetHeight(bounds) : CGRectGetHeight(bounds) - safeArea.bottom;
@@ -20,31 +17,32 @@ UIEdgeInsets ANNScreenInsetsOverRoot(CGRect rootFrame, CGSize viewSize, UIEdgeIn
20
17
 
21
18
  UIEdgeInsets ANNScreenPadding(UIEdgeInsets insets, ANNNavigationOptions *options,
22
19
  ANNScreenPaddingContext context) {
20
+ ANNTopBarOptions *topBar = options.topBar;
21
+ BOOL topBarShown = [topBar.visible withDefault:YES];
22
+ // Under a large title the list keeps its first rows clear of the bar itself. A padded top would follow the bar as
23
+ // it collapses and move the list with it, and UIKit, which collapses the title by the list's offset, would keep
24
+ // the small title hidden.
25
+ BOOL largeTitleShown = topBarShown && context.inStack && ANNLargeTitleCanShow(options);
23
26
  NSArray<NSString *> *edges = options.layout.safeAreaEdges;
24
27
  if (edges) {
25
- // Exactly the edges given; unknown names count for nothing (`layout.safeAreaEdges`).
26
- return UIEdgeInsetsMake([edges containsObject:@"top"] ? insets.top : 0,
28
+ // Exactly the edges given, but the top under a large title; unknown names count for nothing
29
+ // (`layout.safeAreaEdges`).
30
+ BOOL top = [edges containsObject:@"top"] && !largeTitleShown;
31
+ return UIEdgeInsetsMake(top ? insets.top : 0,
27
32
  [edges containsObject:@"left"] ? insets.left : 0,
28
33
  [edges containsObject:@"bottom"] ? insets.bottom : 0,
29
34
  [edges containsObject:@"right"] ? insets.right : 0);
30
35
  }
31
36
  UIEdgeInsets padding = insets;
32
- ANNTopBarOptions *topBar = options.topBar;
33
- BOOL topBarShown = [topBar.visible withDefault:YES];
34
37
  // A bar hidden for a while (`hideOnScroll`, `hideOnTap`, `hideOnKeyboard`) still counts as shown: only
35
38
  // `topBar.visible: false` gives the content its top back. A large title that can show takes the top too: the list
36
39
  // goes under the bar that collapses it.
37
- if (topBarShown && context.inStack &&
38
- (ANNScreenIsUnderTopBar(options) || ANNLargeTitleCanShow(options))) {
40
+ if (largeTitleShown || (topBarShown && context.inStack && ANNScreenIsUnderTopBar(options))) {
39
41
  padding.top = 0;
40
42
  }
41
- // A bar at the bottom over the home indicator (a tab bar, a toolbar, the bottom search field of iOS 26): the list
42
- // goes under it. A tab bar at the top on iPad adds nothing to the bottom. A toolbar that hides on scroll counts as
43
- // there.
44
- if (insets.bottom > context.windowBottomSafeArea + ANNBottomBarThreshold ||
45
- (context.inStack && context.stackShowsToolbar && [topBar.hideOnScroll withDefault:NO])) {
46
- padding.bottom = 0;
47
- }
43
+ // The bottom is free: the content goes down to the bottom of the screen, under the home indicator and under a bar
44
+ // at the bottom, and a list keeps its last rows clear with `useSafeAreaInsets()`.
45
+ padding.bottom = 0;
48
46
  BOOL behindVerticalBar = [options.layout.drawBehindVerticalBar withDefault:YES] &&
49
47
  [options.layout.verticalBars withDefault:YES];
50
48
  if (behindVerticalBar) {
@@ -5,12 +5,13 @@
5
5
 
6
6
  NS_ASSUME_NONNULL_BEGIN
7
7
 
8
- /// The preview of a push (`usePreview`): a push that waits for a tap on its preview. Its screen is made and renders
9
- /// unseen, out of the stack, its key kept; the view with `preview.nativeID` is looked for on the source screen at once,
10
- /// then at each mount of the source's content (on each frame for a slot screen), for at most 0.5 s; found, the preview module (`ANNPreviewInteraction`)
11
- /// shows the screen from it on a long press. A tap that commits pushes the screen without an animation and without a
12
- /// wait, or goes back to the entry with its key; a preview that goes without being opened destroys its screen and
13
- /// rejects the push. Main queue.
8
+ /// The preview of a push (`usePreview`): a push that waits for a tap on its preview. Its screen is made at once, out of
9
+ /// the stack, its key kept, and renders unseen: a React screen with a root of its own as a press on the view starts, a
10
+ /// native screen or one of the app's one tree at once. The view with `preview.nativeID` is looked for on the source
11
+ /// screen at once, then at each mount of the source's content (on each frame for a slot screen), for at most 0.5 s;
12
+ /// found, the preview module (`ANNPreviewInteraction`) shows the screen from it on a long press. A tap that commits
13
+ /// pushes the screen without an animation (and without a wait once its content is there), or goes back to the entry
14
+ /// with its key; a preview that goes without being opened destroys its screen and rejects the push. Main queue.
14
15
  @interface ANNPreviewPush : NSObject
15
16
 
16
17
  - (instancetype)init NS_UNAVAILABLE;