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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (358) hide show
  1. package/ApexNavigation.podspec +2 -1
  2. package/CHANGELOG.md +32 -0
  3. package/README.md +1 -1
  4. package/android/CLAUDE.md +31 -20
  5. package/android/CORE.md +12 -8
  6. package/android/consumer-rules.pro +6 -0
  7. package/android/src/main/java/dev/apexnative/navigation/NavigationActivity.kt +36 -5
  8. package/android/src/main/java/dev/apexnative/navigation/options/BottomTabOptions.kt +1 -1
  9. package/android/src/main/java/dev/apexnative/navigation/options/BottomTabsOptions.kt +13 -8
  10. package/android/src/main/java/dev/apexnative/navigation/options/ButtonOptions.kt +1 -1
  11. package/android/src/main/java/dev/apexnative/navigation/options/LargeTitleOptions.kt +1 -1
  12. package/android/src/main/java/dev/apexnative/navigation/options/LayoutAnimation.kt +1 -1
  13. package/android/src/main/java/dev/apexnative/navigation/options/OptionKey.kt +18 -0
  14. package/android/src/main/java/dev/apexnative/navigation/options/OptionPaths.kt +91 -0
  15. package/android/src/main/java/dev/apexnative/navigation/options/SheetOptions.kt +7 -4
  16. package/android/src/main/java/dev/apexnative/navigation/options/TitleOptions.kt +2 -2
  17. package/android/src/main/java/dev/apexnative/navigation/options/TopBarAppearanceOptions.kt +1 -1
  18. package/android/src/main/java/dev/apexnative/navigation/options/TopBarOptions.kt +16 -7
  19. package/android/src/main/java/dev/apexnative/navigation/react/ContentHeights.kt +95 -0
  20. package/android/src/main/java/dev/apexnative/navigation/react/ContentMounts.kt +66 -0
  21. package/android/src/main/java/dev/apexnative/navigation/react/NavigationTurboModule.kt +7 -3
  22. package/android/src/main/java/dev/apexnative/navigation/react/OptionsCommands.kt +41 -3
  23. package/android/src/main/java/dev/apexnative/navigation/react/ReactView.kt +16 -1
  24. package/android/src/main/java/dev/apexnative/navigation/react/ReloadCoordinator.kt +0 -2
  25. package/android/src/main/java/dev/apexnative/navigation/react/ScreenEnvironment.kt +177 -0
  26. package/android/src/main/java/dev/apexnative/navigation/react/ScreenRegions.kt +12 -49
  27. package/android/src/main/java/dev/apexnative/navigation/react/ScrollEvents.kt +49 -128
  28. package/android/src/main/java/dev/apexnative/navigation/safearea/SafeAreaView.kt +6 -6
  29. package/android/src/main/java/dev/apexnative/navigation/slots/SlotScreenView.kt +27 -7
  30. package/android/src/main/java/dev/apexnative/navigation/slots/SlotView.kt +12 -1
  31. package/android/src/main/java/dev/apexnative/navigation/utils/MaterialTheme.kt +5 -6
  32. package/android/src/main/java/dev/apexnative/navigation/utils/SystemAnimations.kt +36 -0
  33. package/android/src/main/java/dev/apexnative/navigation/utils/ViewExtensions.kt +0 -13
  34. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/arrangement/ArrangementController.kt +9 -7
  35. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsCollapseBehavior.kt +5 -3
  36. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/BottomTabsController.kt +13 -10
  37. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowGeometry.kt +22 -0
  38. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/TabsRoom.kt +0 -5
  39. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ComponentViewController.kt +7 -8
  40. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/component/ScreenSafeArea.kt +29 -11
  41. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/externalcomponent/ExternalComponentViewController.kt +2 -6
  42. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalCoordinator.kt +20 -2
  43. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalSheet.kt +443 -58
  44. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/ModalViews.kt +33 -5
  45. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetBack.kt +42 -0
  46. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/modal/SheetStops.kt +60 -2
  47. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/navigator/Navigator.kt +4 -0
  48. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/parent/ParentController.kt +3 -6
  49. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/sidemenu/SideMenuMotion.kt +8 -2
  50. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/BackPreview.kt +32 -4
  51. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/PreparedFrame.kt +3 -3
  52. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackCommands.kt +2 -2
  53. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackController.kt +50 -7
  54. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackQueue.kt +15 -3
  55. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/StackViews.kt +10 -4
  56. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabMotion.kt +142 -0
  57. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/fab/FabPresenter.kt +215 -43
  58. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/search/StackSearchPresenter.kt +25 -26
  59. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/BarRowTransition.kt +3 -2
  60. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/ButtonPlaces.kt +11 -5
  61. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/stack/topbar/TopBarPresenter.kt +36 -38
  62. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/viewcontroller/ScrollEventListener.kt +6 -9
  63. package/android/src/main/java/dev/apexnative/navigation/views/animations/AnimationLayer.kt +73 -0
  64. package/android/src/main/java/dev/apexnative/navigation/views/animations/ValueInterpolation.kt +14 -0
  65. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/BottomTabsLayout.kt +61 -2
  66. package/android/src/main/java/dev/apexnative/navigation/views/bottomtabs/CustomTabRow.kt +72 -10
  67. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementTransitions.kt +129 -179
  68. package/android/src/main/java/dev/apexnative/navigation/views/element/TargetsWait.kt +8 -1
  69. package/android/src/main/java/dev/apexnative/navigation/views/element/TransitionLayer.kt +37 -112
  70. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ElementPictures.kt +67 -3
  71. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/FlightGeometry.kt +346 -36
  72. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMorph.kt +199 -0
  73. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/SharedAnimatorFactory.kt +55 -42
  74. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextMorph.kt +176 -0
  75. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewMorph.kt +108 -0
  76. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabCopy.kt +85 -0
  77. package/android/src/main/java/dev/apexnative/navigation/views/stack/fab/FabMenu.kt +13 -0
  78. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TitleBar.kt +5 -24
  79. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/TopBar.kt +51 -34
  80. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonComponentCell.kt +6 -6
  81. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarButtonView.kt +113 -0
  82. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/BarMenu.kt +219 -0
  83. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonBar.kt +121 -175
  84. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonMenus.kt +34 -64
  85. package/android/src/main/java/dev/apexnative/navigation/views/stack/topbar/titlebar/ButtonRow.kt +216 -0
  86. package/android/src/main/jni/ANNContentHeights.cpp +82 -0
  87. package/android/src/main/res/drawable/apex_navigation_ic_arrow_right.xml +14 -0
  88. package/android/src/main/res/layout/apex_navigation_menu_header.xml +19 -0
  89. package/android/src/main/res/layout/apex_navigation_menu_item.xml +68 -0
  90. package/android/src/main/res/values/styles.xml +1 -1
  91. package/android/src/main/res/values-night/styles.xml +1 -1
  92. package/cli/doctor/checks/app.js +16 -1
  93. package/cli/project.js +4 -0
  94. package/cli/setup/index.js +5 -0
  95. package/cli/setup/steps/metro.js +46 -0
  96. package/docs-md/architecture/native-screens.md +4 -0
  97. package/docs-md/architecture/theme-and-context.md +131 -12
  98. package/docs-md/architecture/transitions.md +46 -5
  99. package/docs-md/containers/modals.md +2 -0
  100. package/docs-md/containers/overlays.md +1 -1
  101. package/docs-md/containers/side-menu.md +1 -1
  102. package/docs-md/containers/tabs.md +2 -0
  103. package/docs-md/flows/bottom-sheets.md +4 -2
  104. package/docs-md/fundamentals/screens-and-props.md +9 -1
  105. package/docs-md/fundamentals/starting-the-app.md +1 -1
  106. package/docs-md/guides/cli.md +3 -1
  107. package/docs-md/help/glossary.md +2 -2
  108. package/docs-md/help/troubleshooting.md +22 -1
  109. package/docs-md/index.json +41 -1
  110. package/docs-md/migration/from-expo-router.md +1 -1
  111. package/docs-md/migration/from-react-native-navigation.md +1 -1
  112. package/docs-md/migration/from-react-navigation.md +2 -2
  113. package/docs-md/screen-ui/back-and-gestures.md +17 -1
  114. package/docs-md/screen-ui/bar-buttons.md +5 -5
  115. package/docs-md/screen-ui/search.md +1 -1
  116. package/docs-md/screen-ui/system-ui.md +16 -11
  117. package/docs-md/screen-ui/toolbar-and-fab.md +4 -2
  118. package/docs-md/screen-ui/top-bar.md +8 -4
  119. package/docs-md/start/installation.md +16 -1
  120. package/ios/Animations/ANNFrameDriver.h +55 -15
  121. package/ios/Animations/ANNFrameDriver.mm +216 -60
  122. package/ios/Animations/ANNTransitionAnimator.h +26 -5
  123. package/ios/Animations/ANNTransitionAnimator.mm +49 -3
  124. package/ios/Animations/ANNTransitionPlan.h +2 -2
  125. package/ios/Animations/ANNTransitionPlan.mm +10 -0
  126. package/ios/Animations/Elements/ANNElementFinder.h +2 -2
  127. package/ios/Animations/Elements/ANNElementFinder.mm +2 -2
  128. package/ios/Animations/Elements/ANNElementTransition.h +3 -3
  129. package/ios/Animations/Elements/ANNElementTransition.mm +2 -2
  130. package/ios/Animations/Elements/ANNSharedElementFlight.h +3 -3
  131. package/ios/Animations/Elements/ANNSharedElementFlight.mm +249 -45
  132. package/ios/Animations/Interpolators/ANNInterpolate.h +2 -30
  133. package/ios/Animations/Interpolators/ANNTransformParts.h +48 -0
  134. package/ios/Animations/Interpolators/ANNTransformParts.mm +507 -0
  135. package/ios/Animations/Interpolators/ANNViewTracks.h +9 -6
  136. package/ios/Animations/Interpolators/ANNViewTracks.mm +100 -30
  137. package/ios/CLAUDE.md +32 -22
  138. package/ios/CORE.md +25 -21
  139. package/ios/Contract/ANNCommandRunner.h +8 -7
  140. package/ios/Contract/ANNCommandRunner.mm +21 -27
  141. package/ios/Contract/ANNLayoutNode.h +3 -3
  142. package/ios/Contract/ANNLayoutReader.h +3 -3
  143. package/ios/Core/ANNAppDelegate.mm +0 -2
  144. package/ios/Core/ANNDeepLinkQueue.h +6 -5
  145. package/ios/Core/ANNDeepLinkQueue.mm +22 -10
  146. package/ios/Core/ANNJavaScriptCalls.h +11 -12
  147. package/ios/Core/ANNJavaScriptCalls.mm +7 -16
  148. package/ios/Core/ANNReloadCoordinator.mm +4 -8
  149. package/ios/Core/ANNSceneDelegate.mm +2 -2
  150. package/ios/Core/ApexNavigation+Internal.h +1 -1
  151. package/ios/Core/ApexNavigation.mm +6 -2
  152. package/ios/Layouts/Arrangement/ANNArrangementState.h +2 -17
  153. package/ios/Layouts/Arrangement/ANNArrangementState.mm +0 -38
  154. package/ios/Layouts/Arrangement/ANNArrangementViewController.mm +4 -4
  155. package/ios/Layouts/Root/ANNRootCoordinator.mm +45 -15
  156. package/ios/Layouts/Screen/ANNComponentViewController.h +2 -2
  157. package/ios/Layouts/Screen/ANNComponentViewController.mm +13 -23
  158. package/ios/Layouts/Screen/ANNPreviewInteraction.h +7 -4
  159. package/ios/Layouts/Screen/ANNPreviewInteraction.mm +72 -10
  160. package/ios/Layouts/Screen/ANNScreenEnvironment.h +63 -0
  161. package/ios/Layouts/Screen/ANNScreenEnvironment.mm +181 -0
  162. package/ios/Layouts/Screen/ANNScreenRegions.h +3 -18
  163. package/ios/Layouts/Screen/ANNScreenRegions.mm +0 -38
  164. package/ios/Layouts/Screen/ANNScreenSafeArea.h +4 -9
  165. package/ios/Layouts/Screen/ANNScreenSafeArea.mm +14 -16
  166. package/ios/Layouts/Stack/ANNPreviewPush.h +7 -6
  167. package/ios/Layouts/Stack/ANNPreviewPush.mm +57 -5
  168. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.h +11 -2
  169. package/ios/Layouts/Stack/ANNStackAnimatingDelegate.mm +14 -7
  170. package/ios/Layouts/Stack/ANNStackController.h +8 -0
  171. package/ios/Layouts/Stack/ANNStackController.mm +153 -11
  172. package/ios/Layouts/Stack/ANNSwipePopInteraction.h +26 -0
  173. package/ios/Layouts/Stack/ANNSwipePopInteraction.mm +185 -0
  174. package/ios/Layouts/Stack/InteractivePopGestureDelegate.mm +28 -4
  175. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.h +12 -1
  176. package/ios/Layouts/Tabs/ANNBottomTabsAccessoryView.mm +23 -0
  177. package/ios/Layouts/Tabs/ANNBottomTabsController.mm +2 -1
  178. package/ios/Layouts/Tabs/ANNBottomTabsCustomRow.mm +8 -3
  179. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.h +4 -0
  180. package/ios/Layouts/Tabs/ANNBottomTabsPresenter.mm +123 -36
  181. package/ios/Layouts/Tabs/ANNTabsDesign.h +6 -5
  182. package/ios/Layouts/Tabs/ANNTabsDesign.mm +9 -1
  183. package/ios/Layouts/Tabs/UITabBar+utils.h +5 -5
  184. package/ios/Layouts/Tabs/UITabBar+utils.mm +32 -13
  185. package/ios/Options/ANNAnimationOptions.h +2 -1
  186. package/ios/Options/ANNAnimationOptions.mm +1 -1
  187. package/ios/Options/ANNBottomTabsOptions.h +2 -0
  188. package/ios/Options/ANNBottomTabsOptions.mm +1 -0
  189. package/ios/Options/ANNOptions.h +25 -0
  190. package/ios/Options/ANNOptions.mm +157 -1
  191. package/ios/Options/ANNOptionsReader.mm +108 -0
  192. package/ios/Options/ANNStackPopAnimationOptions.h +13 -0
  193. package/ios/Options/ANNStackPopAnimationOptions.mm +11 -0
  194. package/ios/Options/Params/ANNParam.h +15 -0
  195. package/ios/Options/Params/ANNParam.mm +61 -0
  196. package/ios/Options/Params/Color.h +3 -0
  197. package/ios/Options/Params/Color.mm +21 -0
  198. package/ios/Options/Params/ColorParser.h +4 -3
  199. package/ios/Options/Params/ColorParser.mm +22 -4
  200. package/ios/Options/Params/Image.h +4 -0
  201. package/ios/Options/Params/Image.mm +20 -0
  202. package/ios/React/ANNReactView.mm +6 -25
  203. package/ios/React/ANNSafeAreaViewComponentView.mm +26 -15
  204. package/ios/React/ANNSurfaceHostingView.h +14 -0
  205. package/ios/React/ANNSurfaceHostingView.mm +144 -1
  206. package/ios/React/Slots/ANNSlotScreenView.mm +8 -2
  207. package/ios/TopBar/ANNBackButtonPresenter.mm +6 -5
  208. package/ios/TopBar/ANNBarAppearance.h +2 -1
  209. package/ios/TopBar/ANNBarAppearance.mm +111 -30
  210. package/ios/TopBar/ANNBarBackgroundComponent.mm +16 -0
  211. package/ios/TopBar/ANNBarButtonComponentView.h +4 -4
  212. package/ios/TopBar/ANNBarButtonComponentView.mm +1 -1
  213. package/ios/TopBar/ANNBarButtons.h +5 -3
  214. package/ios/TopBar/ANNBarButtons.mm +186 -17
  215. package/ios/TopBar/ANNLargeTitlePresenter.mm +24 -4
  216. package/ios/TopBar/ANNMainList.h +3 -0
  217. package/ios/TopBar/ANNMainList.mm +4 -0
  218. package/ios/TopBar/ANNScrollEdgeEffects.h +22 -6
  219. package/ios/TopBar/ANNScrollEdgeEffects.mm +123 -16
  220. package/ios/TopBar/ANNSearchPresenter.mm +2 -2
  221. package/ios/TopBar/ANNSearchResultsViewController.mm +5 -5
  222. package/ios/TopBar/ANNTopBarPresenter.h +3 -2
  223. package/ios/TopBar/ANNTopBarPresenter.mm +95 -22
  224. package/ios/TurboModules/ANNTurboModule.mm +66 -16
  225. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.cpp +20 -0
  226. package/ios/cpp/react/renderer/components/ApexNavigationSpec/ANNSlotState.h +5 -14
  227. package/lib/module/ARCHITECTURE.md +17 -7
  228. package/lib/module/adapters/NativeANNTurboModule.js.map +1 -1
  229. package/lib/module/api/app/AppRegistry.js +14 -2
  230. package/lib/module/api/app/AppRegistry.js.map +1 -1
  231. package/lib/module/api/app/createNavigation.js +188 -66
  232. package/lib/module/api/app/createNavigation.js.map +1 -1
  233. package/lib/module/api/events/navigationEvents.js +6 -2
  234. package/lib/module/api/events/navigationEvents.js.map +1 -1
  235. package/lib/module/api/hooks/useSafeAreaInsets.js +4 -3
  236. package/lib/module/api/hooks/useSafeAreaInsets.js.map +1 -1
  237. package/lib/module/api/linking/linking.js +11 -0
  238. package/lib/module/api/linking/linking.js.map +1 -1
  239. package/lib/module/api/options/OptionsChain.js +2 -2
  240. package/lib/module/api/screens/defineScreen.js +45 -3
  241. package/lib/module/api/screens/defineScreen.js.map +1 -1
  242. package/lib/module/api/screens/nativeScreens.js +31 -6
  243. package/lib/module/api/screens/nativeScreens.js.map +1 -1
  244. package/lib/module/api/screens/registerScreens.js +172 -35
  245. package/lib/module/api/screens/registerScreens.js.map +1 -1
  246. package/lib/module/api/theme/theme.js +5 -0
  247. package/lib/module/api/theme/theme.js.map +1 -1
  248. package/lib/module/engine/commands.js +42 -2
  249. package/lib/module/engine/commands.js.map +1 -1
  250. package/lib/module/engine/layout.js +7 -2
  251. package/lib/module/engine/layout.js.map +1 -1
  252. package/lib/module/engine/nativeScreens.js +9 -0
  253. package/lib/module/engine/nativeScreens.js.map +1 -1
  254. package/lib/module/engine/options.js +5 -4
  255. package/lib/module/engine/options.js.map +1 -1
  256. package/lib/module/engine/optionsChange.js +102 -0
  257. package/lib/module/engine/optionsChange.js.map +1 -0
  258. package/lib/module/engine/refresh.js +85 -0
  259. package/lib/module/engine/refresh.js.map +1 -0
  260. package/lib/module/engine/rememberedOptions.js +60 -0
  261. package/lib/module/engine/rememberedOptions.js.map +1 -1
  262. package/lib/module/engine/screens.js +55 -4
  263. package/lib/module/engine/screens.js.map +1 -1
  264. package/lib/typescript/adapters/NativeANNTurboModule.d.ts +7 -0
  265. package/lib/typescript/adapters/NativeANNTurboModule.d.ts.map +1 -1
  266. package/lib/typescript/api/app/AppRegistry.d.ts.map +1 -1
  267. package/lib/typescript/api/app/createNavigation.d.ts +8 -3
  268. package/lib/typescript/api/app/createNavigation.d.ts.map +1 -1
  269. package/lib/typescript/api/events/navigationEvents.d.ts +2 -2
  270. package/lib/typescript/api/events/navigationEvents.d.ts.map +1 -1
  271. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts +4 -3
  272. package/lib/typescript/api/hooks/useSafeAreaInsets.d.ts.map +1 -1
  273. package/lib/typescript/api/index.d.ts +1 -1
  274. package/lib/typescript/api/index.d.ts.map +1 -1
  275. package/lib/typescript/api/linking/linking.d.ts +8 -0
  276. package/lib/typescript/api/linking/linking.d.ts.map +1 -1
  277. package/lib/typescript/api/options/OptionsChain.d.ts +2 -2
  278. package/lib/typescript/api/screens/defineScreen.d.ts +23 -4
  279. package/lib/typescript/api/screens/defineScreen.d.ts.map +1 -1
  280. package/lib/typescript/api/screens/nativeScreens.d.ts +8 -1
  281. package/lib/typescript/api/screens/nativeScreens.d.ts.map +1 -1
  282. package/lib/typescript/api/screens/registerScreens.d.ts.map +1 -1
  283. package/lib/typescript/api/theme/theme.d.ts +2 -0
  284. package/lib/typescript/api/theme/theme.d.ts.map +1 -1
  285. package/lib/typescript/engine/commands.d.ts +5 -0
  286. package/lib/typescript/engine/commands.d.ts.map +1 -1
  287. package/lib/typescript/engine/layout.d.ts.map +1 -1
  288. package/lib/typescript/engine/nativeScreens.d.ts +5 -0
  289. package/lib/typescript/engine/nativeScreens.d.ts.map +1 -1
  290. package/lib/typescript/engine/optionsChange.d.ts +28 -0
  291. package/lib/typescript/engine/optionsChange.d.ts.map +1 -0
  292. package/lib/typescript/engine/refresh.d.ts +35 -0
  293. package/lib/typescript/engine/refresh.d.ts.map +1 -0
  294. package/lib/typescript/engine/rememberedOptions.d.ts +13 -0
  295. package/lib/typescript/engine/rememberedOptions.d.ts.map +1 -1
  296. package/lib/typescript/engine/screens.d.ts +27 -6
  297. package/lib/typescript/engine/screens.d.ts.map +1 -1
  298. package/lib/typescript/interfaces/ComponentEvents.d.ts +2 -2
  299. package/lib/typescript/interfaces/options/animations.d.ts +44 -14
  300. package/lib/typescript/interfaces/options/animations.d.ts.map +1 -1
  301. package/lib/typescript/interfaces/options/bottomTabs.d.ts +19 -6
  302. package/lib/typescript/interfaces/options/bottomTabs.d.ts.map +1 -1
  303. package/lib/typescript/interfaces/options/buttons.d.ts +10 -10
  304. package/lib/typescript/interfaces/options/modals.d.ts +6 -7
  305. package/lib/typescript/interfaces/options/modals.d.ts.map +1 -1
  306. package/lib/typescript/interfaces/options/stack.d.ts +8 -3
  307. package/lib/typescript/interfaces/options/stack.d.ts.map +1 -1
  308. package/lib/typescript/interfaces/options/system.d.ts +8 -5
  309. package/lib/typescript/interfaces/options/system.d.ts.map +1 -1
  310. package/lib/typescript/interfaces/options/toolbar.d.ts +2 -2
  311. package/lib/typescript/interfaces/options/topBar.d.ts +46 -29
  312. package/lib/typescript/interfaces/options/topBar.d.ts.map +1 -1
  313. package/metro/acceptPlugin.js +57 -0
  314. package/metro/babelTransformer.js +45 -0
  315. package/metro/index.js +36 -0
  316. package/package.json +3 -1
  317. package/src/ARCHITECTURE.md +17 -7
  318. package/src/adapters/NativeANNTurboModule.ts +7 -0
  319. package/src/api/app/AppRegistry.ts +16 -2
  320. package/src/api/app/createNavigation.ts +201 -69
  321. package/src/api/events/navigationEvents.ts +9 -3
  322. package/src/api/hooks/useSafeAreaInsets.ts +4 -3
  323. package/src/api/index.ts +1 -0
  324. package/src/api/linking/linking.ts +22 -1
  325. package/src/api/options/OptionsChain.ts +2 -2
  326. package/src/api/screens/defineScreen.ts +49 -5
  327. package/src/api/screens/nativeScreens.ts +40 -4
  328. package/src/api/screens/registerScreens.tsx +170 -42
  329. package/src/api/theme/theme.ts +5 -0
  330. package/src/engine/commands.ts +51 -6
  331. package/src/engine/layout.ts +11 -2
  332. package/src/engine/nativeScreens.ts +10 -1
  333. package/src/engine/options.ts +6 -8
  334. package/src/engine/optionsChange.ts +107 -0
  335. package/src/engine/refresh.ts +97 -0
  336. package/src/engine/rememberedOptions.ts +70 -0
  337. package/src/engine/screens.tsx +53 -8
  338. package/src/interfaces/ComponentEvents.ts +2 -2
  339. package/src/interfaces/options/animations.ts +44 -14
  340. package/src/interfaces/options/bottomTabs.ts +19 -6
  341. package/src/interfaces/options/buttons.ts +10 -10
  342. package/src/interfaces/options/modals.ts +6 -7
  343. package/src/interfaces/options/stack.ts +8 -3
  344. package/src/interfaces/options/system.ts +8 -5
  345. package/src/interfaces/options/toolbar.ts +2 -2
  346. package/src/interfaces/options/topBar.ts +46 -29
  347. package/android/src/main/java/dev/apexnative/navigation/react/ArrangementStates.kt +0 -42
  348. package/android/src/main/java/dev/apexnative/navigation/react/ScreenInsets.kt +0 -70
  349. package/android/src/main/java/dev/apexnative/navigation/viewcontrollers/bottomtabs/CustomTabRowPlacer.kt +0 -223
  350. package/android/src/main/java/dev/apexnative/navigation/views/element/ElementStub.kt +0 -31
  351. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ImageMatrixAnimator.kt +0 -136
  352. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PlainViewAnimator.kt +0 -86
  353. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/PropertyAnimatorCreator.kt +0 -33
  354. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ReactImageAnimator.kt +0 -64
  355. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/TextChangeAnimator.kt +0 -177
  356. package/android/src/main/java/dev/apexnative/navigation/views/element/animators/ViewChangeAnimator.kt +0 -137
  357. package/ios/Layouts/Screen/ANNScreenInsets.h +0 -30
  358. package/ios/Layouts/Screen/ANNScreenInsets.mm +0 -70
@@ -1,136 +0,0 @@
1
- package dev.apexnative.navigation.views.element.animators
2
-
3
- import android.animation.Animator
4
- import android.graphics.Matrix
5
- import android.view.View
6
- import android.view.ViewOutlineProvider
7
- import android.widget.ImageView
8
- import com.facebook.react.views.view.ReactViewGroup
9
- import dev.apexnative.navigation.utils.borderRadius
10
- import dev.apexnative.navigation.views.animations.ValueInterpolation
11
- import dev.apexnative.navigation.views.element.TransitionLayer
12
- import kotlin.math.max
13
- import kotlin.math.min
14
- import kotlin.math.roundToInt
15
-
16
- /**
17
- * A shared image of another kind (an `ImageView` that isn't React Native's): its place by a translation; its image
18
- * matrix from `from`'s fit (`centerCrop`, `fitXY`, `fitCenter`, `centerInside`) to its own, the part seen from `from`'s
19
- * size to its own, the corner radius of the parent that clips it (`borderRadius` with `overflow: hidden`) by its
20
- * outline. Another fit: the pair moves without the change of its matrix, and a line goes to the log. Everything goes
21
- * back as it was at the end. Main thread only.
22
- */
23
- internal class ImageMatrixAnimator(
24
- private val from: ImageView,
25
- private val to: ImageView,
26
- private val layer: TransitionLayer,
27
- /** The parents the views are clipped by in their screens: [to]'s is the one it had before the layer. */
28
- private val fromParent: View?,
29
- private val toParent: View?,
30
- private val id: String,
31
- private val log: (String) -> Unit,
32
- ) {
33
- /** The animator; none when [to] has no place in the layer. */
34
- fun create(): Animator? {
35
- val geometry = FlightGeometry.of(from, to, layer) ?: return null
36
- val toRect = geometry.to
37
- val fromFit = from.scaleType
38
- val toFit = to.scaleType
39
- // The image whose matrix changes; none when a fit isn't one of the four or there is no image to fit.
40
- val image = to.drawable?.takeIf {
41
- fromFit in FITS && toFit in FITS && it.intrinsicWidth > 0 && it.intrinsicHeight > 0
42
- }
43
- val fits = image != null
44
- if (!fits) log("The image '$id' fits by ${fromFit.name} and ${toFit.name}: it moves without a change of fit")
45
- val fromRadius = clipRadius(fromParent) * geometry.fromScale
46
- val toRadius = clipRadius(toParent)
47
- val outline = FlightOutline()
48
- var savedProvider: ViewOutlineProvider? = null
49
- var savedClip = false
50
- val savedMatrix = Matrix(to.imageMatrix)
51
- val start = FloatArray(MATRIX)
52
- val end = FloatArray(MATRIX)
53
- val values = FloatArray(MATRIX)
54
- val matrix = Matrix()
55
- return MoveAnimator().apply {
56
- fun frame(time: Float) {
57
- val f = curve.getInterpolation(time)
58
- val left = ValueInterpolation.number(geometry.from.left, toRect.left, f, time)
59
- val top = ValueInterpolation.number(geometry.from.top, toRect.top, f, time)
60
- val width = ValueInterpolation.number(geometry.from.width(), toRect.width(), f, time).roundToInt()
61
- val height = ValueInterpolation.number(geometry.from.height(), toRect.height(), f, time).roundToInt()
62
- layer.place(to, toRect.left.toInt(), toRect.top.toInt(), width, height)
63
- to.translationX = left - toRect.left
64
- to.translationY = top - toRect.top
65
- outline.width = width
66
- outline.height = height
67
- outline.radius = ValueInterpolation.number(fromRadius, toRadius, f, time)
68
- to.invalidateOutline()
69
- if (image != null) {
70
- val imageWidth = image.intrinsicWidth
71
- val imageHeight = image.intrinsicHeight
72
- fitMatrix(fromFit, imageWidth, imageHeight, width, height).getValues(start)
73
- fitMatrix(toFit, imageWidth, imageHeight, width, height).getValues(end)
74
- for (i in 0 until MATRIX) values[i] = ValueInterpolation.number(start[i], end[i], f, time)
75
- matrix.setValues(values)
76
- to.imageMatrix = matrix
77
- }
78
- }
79
- onStart {
80
- savedProvider = to.outlineProvider
81
- savedClip = to.clipToOutline
82
- to.outlineProvider = outline
83
- to.clipToOutline = true
84
- if (fits) to.scaleType = ImageView.ScaleType.MATRIX
85
- frame(0f)
86
- }
87
- onFrame { frame(it) }
88
- onEnd {
89
- if (fits) {
90
- to.scaleType = toFit
91
- to.imageMatrix = savedMatrix
92
- }
93
- to.outlineProvider = savedProvider
94
- to.clipToOutline = savedClip
95
- to.translationX = 0f
96
- to.translationY = 0f
97
- layer.place(to, toRect.left.toInt(), toRect.top.toInt(), toRect.width().toInt(),
98
- toRect.height().toInt())
99
- }
100
- }
101
- }
102
-
103
- // The radius of a React parent that clips what is in it; 0 for another.
104
- private fun clipRadius(parent: View?): Float =
105
- (parent as? ReactViewGroup)?.takeIf { it.overflow == HIDDEN }?.borderRadius ?: 0f
106
-
107
- private companion object {
108
- const val MATRIX = 9
109
- const val HIDDEN = "hidden"
110
- val FITS = setOf(
111
- ImageView.ScaleType.CENTER_CROP,
112
- ImageView.ScaleType.FIT_XY,
113
- ImageView.ScaleType.FIT_CENTER,
114
- ImageView.ScaleType.CENTER_INSIDE,
115
- )
116
-
117
- // The matrix of a fit of an image of [imageWidth] × [imageHeight] into [width] × [height].
118
- fun fitMatrix(fit: ImageView.ScaleType, imageWidth: Int, imageHeight: Int, width: Int, height: Int): Matrix {
119
- val sx = width.toFloat() / imageWidth
120
- val sy = height.toFloat() / imageHeight
121
- val matrix = Matrix()
122
- if (fit == ImageView.ScaleType.FIT_XY) {
123
- matrix.setScale(sx, sy)
124
- return matrix
125
- }
126
- val scale = when (fit) {
127
- ImageView.ScaleType.CENTER_CROP -> max(sx, sy)
128
- ImageView.ScaleType.CENTER_INSIDE -> min(1f, min(sx, sy))
129
- else -> min(sx, sy)
130
- }
131
- matrix.setScale(scale, scale)
132
- matrix.postTranslate((width - imageWidth * scale) / 2f, (height - imageHeight * scale) / 2f)
133
- return matrix
134
- }
135
- }
136
- }
@@ -1,86 +0,0 @@
1
- package dev.apexnative.navigation.views.element.animators
2
-
3
- import android.animation.Animator
4
- import android.view.View
5
- import android.view.ViewOutlineProvider
6
- import com.facebook.react.uimanager.BackgroundStyleApplicator
7
- import com.facebook.react.uimanager.style.BorderRadiusProp
8
- import dev.apexnative.navigation.utils.borderRadius
9
- import dev.apexnative.navigation.views.animations.ValueInterpolation
10
- import dev.apexnative.navigation.views.element.TransitionLayer
11
- import kotlin.math.roundToInt
12
-
13
- /**
14
- * A shared React view without children moves itself: from `from`'s place on the screen to its own by a translation; its
15
- * size and corner radius by an outline that grows from `from`'s (at the scale of its parents) to its own while it is
16
- * laid out at the larger of the two sizes; its own radius taken off meanwhile and put back as it was; its background
17
- * color from `from`'s to its own in Lab, ending exactly on its own (`BackgroundStyleApplicator`); its rotation from
18
- * `from`'s to its own. Main thread only.
19
- */
20
- internal class PlainViewAnimator(
21
- private val from: View,
22
- private val to: View,
23
- private val layer: TransitionLayer,
24
- ) {
25
- /** The animator; none when [to] has no place in the layer. */
26
- fun create(): Animator? {
27
- val geometry = FlightGeometry.of(from, to, layer) ?: return null
28
- val fromRadius = from.borderRadius * geometry.fromScale
29
- val toRadius = to.borderRadius
30
- val fromColor = BackgroundStyleApplicator.getBackgroundColor(from)
31
- val toColor = BackgroundStyleApplicator.getBackgroundColor(to)
32
- val fromRotation = from.rotation
33
- val toRotation = to.rotation
34
- val ownRadius = BackgroundStyleApplicator.getBorderRadius(to, RADIUS)
35
- val outline = FlightOutline()
36
- var savedProvider: ViewOutlineProvider? = null
37
- var savedClip = false
38
- val (width, height) = geometry.largest
39
- val toRect = geometry.to
40
- return MoveAnimator().apply {
41
- fun frame(time: Float) {
42
- val f = curve.getInterpolation(time)
43
- val left = ValueInterpolation.number(geometry.from.left, toRect.left, f, time)
44
- val top = ValueInterpolation.number(geometry.from.top, toRect.top, f, time)
45
- to.translationX = left - toRect.left
46
- to.translationY = top - toRect.top
47
- val from = geometry.from
48
- outline.width = ValueInterpolation.number(from.width(), toRect.width(), f, time).roundToInt()
49
- outline.height = ValueInterpolation.number(from.height(), toRect.height(), f, time).roundToInt()
50
- outline.radius = ValueInterpolation.number(fromRadius, toRadius, f, time)
51
- to.invalidateOutline()
52
- if (fromColor != toColor) {
53
- val color = ValueInterpolation.color(fromColor, toColor, f, time)
54
- BackgroundStyleApplicator.setBackgroundColor(to, color)
55
- }
56
- to.rotation = ValueInterpolation.number(fromRotation, toRotation, f, time)
57
- }
58
- onStart {
59
- savedProvider = to.outlineProvider
60
- savedClip = to.clipToOutline
61
- if (ownRadius != null) BackgroundStyleApplicator.setBorderRadius(to, RADIUS, null)
62
- to.outlineProvider = outline
63
- to.clipToOutline = true
64
- layer.place(to, toRect.left.toInt(), toRect.top.toInt(), width, height)
65
- frame(0f)
66
- }
67
- onFrame { frame(it) }
68
- // A cancelled flight ends too: the view goes back whole.
69
- onEnd {
70
- to.translationX = 0f
71
- to.translationY = 0f
72
- to.rotation = toRotation
73
- if (fromColor != toColor) BackgroundStyleApplicator.setBackgroundColor(to, toColor)
74
- if (ownRadius != null) BackgroundStyleApplicator.setBorderRadius(to, RADIUS, ownRadius)
75
- to.outlineProvider = savedProvider
76
- to.clipToOutline = savedClip
77
- layer.place(to, toRect.left.toInt(), toRect.top.toInt(), toRect.width().toInt(),
78
- toRect.height().toInt())
79
- }
80
- }
81
- }
82
-
83
- private companion object {
84
- val RADIUS = BorderRadiusProp.BORDER_RADIUS
85
- }
86
- }
@@ -1,33 +0,0 @@
1
- package dev.apexnative.navigation.views.element.animators
2
-
3
- import android.animation.Animator
4
- import android.view.View
5
- import dev.apexnative.navigation.options.SharedElementTransitionOptions
6
-
7
- /**
8
- * One animator of a shared element: how [from], on the screen that goes, becomes [to], on the screen that comes, when
9
- * both are of [type]. The core picks one by the views' classes (`SharedAnimatorFactory`) and runs it in the
10
- * transition's layer.
11
- */
12
- abstract class PropertyAnimatorCreator<T : View>(
13
- protected val from: View,
14
- protected val to: View,
15
- private val type: Class<T>,
16
- ) {
17
- /** Whether this animator takes part: both views are of its type and differ in what it animates. */
18
- fun shouldAnimate(): Boolean {
19
- if (!type.isInstance(from) || !type.isInstance(to)) return false
20
- val fromChild = type.cast(from) ?: return false
21
- val toChild = type.cast(to) ?: return false
22
- return shouldAnimateProperty(fromChild, toChild)
23
- }
24
-
25
- /** Whether [fromChild] and [toChild] differ in what this animator animates. */
26
- abstract fun shouldAnimateProperty(fromChild: T, toChild: T): Boolean
27
-
28
- /**
29
- * The animator of the pair for [options]; the core gives it the pair's duration, delay and curve (each animator
30
- * its own, never through a set around it).
31
- */
32
- abstract fun create(options: SharedElementTransitionOptions): Animator
33
- }
@@ -1,64 +0,0 @@
1
- package dev.apexnative.navigation.views.element.animators
2
-
3
- import android.animation.Animator
4
- import com.facebook.drawee.drawable.ScalingUtils
5
- import com.facebook.react.views.image.ReactImageView
6
- import dev.apexnative.navigation.views.animations.ValueInterpolation
7
- import dev.apexnative.navigation.views.element.TransitionLayer
8
- import kotlin.math.roundToInt
9
-
10
- /**
11
- * A shared React image: its place by a translation from `from`'s on the screen; its content by Fresco's scale type
12
- * going from `from`'s fit to its own (`ScalingUtils.InterpolatingScaleType`); the part seen from `from`'s size to its
13
- * own (it is laid out at the size of each frame); its rotation from `from`'s to its own; Fresco's own fade off
14
- * meanwhile. Everything goes back as it was at the end. Main thread only.
15
- */
16
- internal class ReactImageAnimator(
17
- private val from: ReactImageView,
18
- private val to: ReactImageView,
19
- private val layer: TransitionLayer,
20
- ) {
21
- /** The animator; none when [to] has no place in the layer or no hierarchy. */
22
- fun create(): Animator? {
23
- if (!from.hasHierarchy() || !to.hasHierarchy()) return null
24
- val geometry = FlightGeometry.of(from, to, layer) ?: return null
25
- val toRect = geometry.to
26
- val toType = to.hierarchy.actualImageScaleType ?: ScalingUtils.ScaleType.CENTER_CROP
27
- val fromType = from.hierarchy.actualImageScaleType ?: ScalingUtils.ScaleType.CENTER_CROP
28
- val scale = ScalingUtils.InterpolatingScaleType(fromType, toType)
29
- val fromRotation = from.rotation
30
- val toRotation = to.rotation
31
- var savedFade = 0
32
- return MoveAnimator().apply {
33
- fun frame(time: Float) {
34
- val f = curve.getInterpolation(time)
35
- val left = ValueInterpolation.number(geometry.from.left, toRect.left, f, time)
36
- val top = ValueInterpolation.number(geometry.from.top, toRect.top, f, time)
37
- val width = ValueInterpolation.number(geometry.from.width(), toRect.width(), f, time).roundToInt()
38
- val height = ValueInterpolation.number(geometry.from.height(), toRect.height(), f, time).roundToInt()
39
- layer.place(to, toRect.left.toInt(), toRect.top.toInt(), width, height)
40
- to.translationX = left - toRect.left
41
- to.translationY = top - toRect.top
42
- scale.setValue(if (time >= 1f) 1f else f)
43
- to.rotation = ValueInterpolation.number(fromRotation, toRotation, f, time)
44
- to.invalidate()
45
- }
46
- onStart {
47
- savedFade = to.hierarchy.fadeDuration
48
- to.hierarchy.fadeDuration = 0
49
- to.hierarchy.setActualImageScaleType(scale)
50
- frame(0f)
51
- }
52
- onFrame { frame(it) }
53
- onEnd {
54
- to.hierarchy.setActualImageScaleType(toType)
55
- to.hierarchy.fadeDuration = savedFade
56
- to.translationX = 0f
57
- to.translationY = 0f
58
- to.rotation = toRotation
59
- layer.place(to, toRect.left.toInt(), toRect.top.toInt(), toRect.width().toInt(),
60
- toRect.height().toInt())
61
- }
62
- }
63
- }
64
- }
@@ -1,177 +0,0 @@
1
- package dev.apexnative.navigation.views.element.animators
2
-
3
- import android.animation.Animator
4
- import android.graphics.Canvas
5
- import android.graphics.ColorFilter
6
- import android.graphics.Picture
7
- import android.graphics.PixelFormat
8
- import android.graphics.PointF
9
- import android.graphics.drawable.Drawable
10
- import android.text.Layout
11
- import android.view.View
12
- import android.view.ViewGroup
13
- import android.widget.TextView
14
- import com.facebook.react.views.text.ReactTextView
15
- import dev.apexnative.navigation.options.SharedElementTransitionOptions
16
- import dev.apexnative.navigation.utils.TextViewUtils
17
- import dev.apexnative.navigation.utils.ViewUtils
18
- import kotlin.math.roundToInt
19
-
20
- // The text moves as two pictures of itself, of the text that goes away and of the text that comes, the same text or
21
- // another. Both keep their proportions, scaled by the font size from a point of the first line, and one turns into the
22
- // other in a quarter of the move: at its start when the text grows, at its end when it shrinks, so the larger picture
23
- // shows most of the way (as on iOS). The pictures are drawing commands, not pixels: they stay sharp at any scale and
24
- // keep the colors, emoji and background of the text. They are drawn in the overlay of the transition layer while `to`
25
- // is hidden.
26
- class TextChangeAnimator(from: View, to: View) : PropertyAnimatorCreator<ReactTextView>(from, to, ReactTextView::class.java) {
27
- private val pictures by lazy { pictures() }
28
-
29
- override fun shouldAnimateProperty(fromChild: ReactTextView, toChild: ReactTextView): Boolean {
30
- val fromPlace = ViewUtils.getLocationOnScreen(from)
31
- val toPlace = ViewUtils.getLocationOnScreen(to)
32
- return (fromChild.text.toString() != toChild.text.toString() ||
33
- TextViewUtils.getTextSize(fromChild) != TextViewUtils.getTextSize(toChild) || fromPlace != toPlace
34
- ) && pictures != null
35
- }
36
-
37
- override fun create(options: SharedElementTransitionOptions): Animator {
38
- val (start, end) = checkNotNull(pictures)
39
- val layer = to.parent as ViewGroup
40
- val drawable = TextMorphDrawable(start, end)
41
- // Everything changes between the start and the end of the animation: a cancelled one ends too.
42
- return MoveAnimator().apply {
43
- onStart {
44
- drawable.setBounds(0, 0, layer.width, layer.height)
45
- layer.overlay.add(drawable)
46
- to.alpha = 0f
47
- }
48
- onFrame {
49
- drawable.update(it, curve.getInterpolation(it))
50
- layer.invalidate()
51
- }
52
- onEnd {
53
- layer.overlay.remove(drawable)
54
- layer.invalidate()
55
- to.alpha = end.alpha
56
- }
57
- }
58
- }
59
-
60
- // `to` is in the transition layer already, at its margins (the coordinates of the other animators); `from` is where
61
- // it is on the screen. Texts that line up the same way go from that point of their first lines (the same text lies
62
- // over itself); others from the start of the line, as on iOS: a centered text no longer sticks out of a text at the
63
- // start.
64
- private fun pictures(): Pair<TextPicture, TextPicture>? {
65
- if (to.parent !is ViewGroup) return null
66
- val toPlace = to.layoutParams as? ViewGroup.MarginLayoutParams ?: return null
67
- val fromLayout = (from as TextView).layout ?: return null
68
- val toLayout = (to as TextView).layout ?: return null
69
- val edge = lineEdge(fromLayout).takeIf { it == lineEdge(toLayout) } ?: LineEdge.START
70
- val fromPlace = ViewUtils.getLocationOnScreen(from)
71
- .apply { ViewUtils.getLocationOnScreen(to.parent as View).let { offset(-it.x, -it.y) } }
72
- val start = TextPicture.of(from, fromPlace.x, fromPlace.y, edge) ?: return null
73
- val end = TextPicture.of(to, toPlace.leftMargin, toPlace.topMargin, edge) ?: return null
74
- return start to end
75
- }
76
- }
77
-
78
- // A text's picture, the point of its first line it is scaled from (in the view) and where that point is in the
79
- // transition layer, its font size and opacity.
80
- private class TextPicture(
81
- val picture: Picture,
82
- val anchor: PointF,
83
- val position: PointF,
84
- val fontSize: Float,
85
- val alpha: Float
86
- ) {
87
- companion object {
88
- fun of(view: TextView, left: Int, top: Int, edge: LineEdge): TextPicture? {
89
- val layout = view.layout ?: return null
90
- val fontSize = TextViewUtils.getTextSize(view).takeIf { it > 0 } ?: view.textSize
91
- if (view.width <= 0 || view.height <= 0 || layout.lineCount == 0 || fontSize <= 0) return null
92
- // Without a picture (recording failed) the text goes to its place at once, as a different text does.
93
- val picture = recordPicture(view) ?: return null
94
- val anchor = PointF(
95
- view.totalPaddingLeft + edgeX(layout, edge),
96
- view.totalPaddingTop + layout.getLineBaseline(0).toFloat()
97
- )
98
- return TextPicture(picture, anchor, PointF(left + anchor.x, top + anchor.y), fontSize, view.alpha)
99
- }
100
-
101
- // That point of the first line, in the direction of the text.
102
- private fun edgeX(layout: Layout, edge: LineEdge): Float {
103
- val left = layout.getLineLeft(0)
104
- val right = layout.getLineRight(0)
105
- val rightToLeft = layout.getParagraphDirection(0) == Layout.DIR_RIGHT_TO_LEFT
106
- return when (edge) {
107
- LineEdge.CENTER -> (left + right) / 2
108
- LineEdge.START -> if (rightToLeft) right else left
109
- LineEdge.END -> if (rightToLeft) left else right
110
- }
111
- }
112
- }
113
- }
114
-
115
- // Where the lines of a text line up: their start, center or end, in the direction of the text.
116
- private enum class LineEdge { START, CENTER, END }
117
-
118
- // ALIGN_LEFT and ALIGN_RIGHT are hidden constants, for Gravity.LEFT and RIGHT.
119
- private fun lineEdge(layout: Layout): LineEdge {
120
- val rightToLeft = layout.getParagraphDirection(0) == Layout.DIR_RIGHT_TO_LEFT
121
- return when (layout.getParagraphAlignment(0).name) {
122
- "ALIGN_CENTER" -> LineEdge.CENTER
123
- "ALIGN_OPPOSITE" -> LineEdge.END
124
- "ALIGN_LEFT" -> if (rightToLeft) LineEdge.END else LineEdge.START
125
- "ALIGN_RIGHT" -> if (rightToLeft) LineEdge.START else LineEdge.END
126
- else -> LineEdge.START
127
- }
128
- }
129
-
130
- // Both pictures where the move has brought the text: the font size and the point of the first line go from the start
131
- // to the end along the transition's curve, the pictures change over by the clock.
132
- private class TextMorphDrawable(private val start: TextPicture, private val end: TextPicture) : Drawable() {
133
- private val grows = end.fontSize >= start.fontSize
134
- private var progress = 0f
135
- private var changeOver = 0f
136
-
137
- fun update(time: Float, progress: Float) {
138
- this.progress = progress
139
- val changeOverStart = if (grows) 0f else 1f - CHANGE_OVER
140
- changeOver = ((time - changeOverStart) / CHANGE_OVER).coerceIn(0f, 1f)
141
- }
142
-
143
- override fun draw(canvas: Canvas) {
144
- val x = start.position.x + (end.position.x - start.position.x) * progress
145
- val y = start.position.y + (end.position.y - start.position.y) * progress
146
- val fontSize = start.fontSize + (end.fontSize - start.fontSize) * progress
147
- draw(canvas, start, x, y, fontSize, 1f - changeOver)
148
- draw(canvas, end, x, y, fontSize, changeOver)
149
- }
150
-
151
- private fun draw(canvas: Canvas, text: TextPicture, x: Float, y: Float, fontSize: Float, shown: Float) {
152
- val alpha = (shown * text.alpha * 255).roundToInt().coerceIn(0, 255)
153
- if (alpha == 0) return
154
- val scale = fontSize / text.fontSize
155
- val count = canvas.save()
156
- canvas.translate(x, y)
157
- canvas.scale(scale, scale)
158
- canvas.translate(-text.anchor.x, -text.anchor.y)
159
- // The picture fades as a whole: its letters and background don't show through each other.
160
- if (alpha < 255) {
161
- canvas.saveLayerAlpha(0f, 0f, text.picture.width.toFloat(), text.picture.height.toFloat(), alpha)
162
- }
163
- canvas.drawPicture(text.picture)
164
- canvas.restoreToCount(count)
165
- }
166
-
167
- override fun setAlpha(alpha: Int) = Unit
168
-
169
- override fun setColorFilter(colorFilter: ColorFilter?) = Unit
170
-
171
- @Deprecated("Deprecated in Java")
172
- override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
173
-
174
- private companion object {
175
- const val CHANGE_OVER = 0.25f
176
- }
177
- }
@@ -1,137 +0,0 @@
1
- package dev.apexnative.navigation.views.element.animators
2
-
3
- import android.animation.Animator
4
- import android.graphics.Canvas
5
- import android.graphics.ColorFilter
6
- import android.graphics.Paint
7
- import android.graphics.Picture
8
- import android.graphics.PixelFormat
9
- import android.graphics.PorterDuff
10
- import android.graphics.PorterDuffXfermode
11
- import android.graphics.RectF
12
- import android.graphics.drawable.Drawable
13
- import android.view.View
14
- import android.view.ViewGroup
15
- import com.facebook.react.views.view.ReactViewGroup
16
- import dev.apexnative.navigation.options.SharedElementTransitionOptions
17
- import dev.apexnative.navigation.utils.ViewUtils
18
- import dev.apexnative.navigation.utils.borderRadius
19
- import dev.apexnative.navigation.utils.computeInheritedScale
20
- import kotlin.math.roundToInt
21
-
22
- // A view with children moves as two pictures of itself, as on iOS: of the view that goes away and of the one that
23
- // comes, each with its children. The copy goes from the place, size and corner radius of the one to those of the other,
24
- // both pictures fill it, and the picture of the destination shows over the other on the way. The pictures are drawing
25
- // commands: an avatar's letter grows sharp. They are drawn in the overlay of the transition layer while `to` is hidden,
26
- // and nothing else moves the pair. A view without children moves itself, its outline growing, as before.
27
- class ViewChangeAnimator(from: View, to: View) : PropertyAnimatorCreator<ReactViewGroup>(from, to, ReactViewGroup::class.java) {
28
- private val pictures by lazy { pictures() }
29
-
30
- override fun shouldAnimateProperty(fromChild: ReactViewGroup, toChild: ReactViewGroup): Boolean =
31
- (fromChild.childCount > 0 || toChild.childCount > 0) && pictures != null
32
-
33
- override fun create(options: SharedElementTransitionOptions): Animator {
34
- val (start, end) = checkNotNull(pictures)
35
- val layer = to.parent as ViewGroup
36
- val drawable = ViewMorphDrawable(start, end)
37
- // Everything changes between the start and the end of the animation: a cancelled one ends too.
38
- return MoveAnimator().apply {
39
- onStart {
40
- drawable.setBounds(0, 0, layer.width, layer.height)
41
- layer.overlay.add(drawable)
42
- to.alpha = 0f
43
- }
44
- onFrame {
45
- drawable.progress = curve.getInterpolation(it)
46
- layer.invalidate()
47
- }
48
- onEnd {
49
- layer.overlay.remove(drawable)
50
- layer.invalidate()
51
- to.alpha = end.alpha
52
- }
53
- }
54
- }
55
-
56
- // `to` is in the transition layer already, at its margins (the coordinates of the other animators); `from` is where
57
- // it is on the screen, at the scale of its parents.
58
- private fun pictures(): Pair<ViewPicture, ViewPicture>? {
59
- if (to.parent !is ViewGroup) return null
60
- val toPlace = to.layoutParams as? ViewGroup.MarginLayoutParams ?: return null
61
- val fromPlace = ViewUtils.getLocationOnScreen(from)
62
- .apply { ViewUtils.getLocationOnScreen(to.parent as View).let { offset(-it.x, -it.y) } }
63
- val (scaleX, scaleY) = computeInheritedScale(from)
64
- val fromRect = RectF(0f, 0f, from.width * scaleX, from.height * scaleY).apply {
65
- offset(fromPlace.x.toFloat(), fromPlace.y.toFloat())
66
- }
67
- val toRect = RectF(0f, 0f, to.width.toFloat(), to.height.toFloat()).apply {
68
- offset(toPlace.leftMargin.toFloat(), toPlace.topMargin.toFloat())
69
- }
70
- val start = ViewPicture.of(from as ReactViewGroup, fromRect, scaleX) ?: return null
71
- val end = ViewPicture.of(to as ReactViewGroup, toRect, 1f) ?: return null
72
- return start to end
73
- }
74
- }
75
-
76
- // A view's picture, its place in the transition layer, its corner radius there and its opacity.
77
- private class ViewPicture(val picture: Picture, val rect: RectF, val radius: Float, val alpha: Float) {
78
- companion object {
79
- fun of(view: ReactViewGroup, rect: RectF, scale: Float): ViewPicture? {
80
- if (view.width <= 0 || view.height <= 0) return null
81
- val picture = recordPicture(view) ?: return null
82
- return ViewPicture(picture, rect, view.borderRadius * scale, view.alpha)
83
- }
84
- }
85
- }
86
-
87
- // The copy where the move has brought it: its place, size and corner radius go from the start to the end along the
88
- // transition's curve, and so does the picture of the end over the picture of the start.
89
- private class ViewMorphDrawable(private val start: ViewPicture, private val end: ViewPicture) : Drawable() {
90
- var progress = 0f
91
- private val rect = RectF()
92
- private val maskPaint = Paint(Paint.ANTI_ALIAS_FLAG)
93
- // What is drawn over the mask keeps only the mask's pixels: the corners stay smooth (a clip path on the hardware
94
- // canvas is not anti-aliased).
95
- private val contentPaint = Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) }
96
-
97
- override fun draw(canvas: Canvas) {
98
- rect.set(
99
- lerp(start.rect.left, end.rect.left),
100
- lerp(start.rect.top, end.rect.top),
101
- lerp(start.rect.right, end.rect.right),
102
- lerp(start.rect.bottom, end.rect.bottom)
103
- )
104
- if (rect.isEmpty) return
105
- val radius = lerp(start.radius, end.radius)
106
- val count = canvas.saveLayer(rect, null)
107
- canvas.drawRoundRect(rect, radius, radius, maskPaint)
108
- canvas.saveLayer(rect, contentPaint)
109
- draw(canvas, start, start.alpha)
110
- draw(canvas, end, end.alpha * progress)
111
- canvas.restoreToCount(count)
112
- }
113
-
114
- // A picture fills the copy, as on iOS.
115
- private fun draw(canvas: Canvas, view: ViewPicture, shown: Float) {
116
- val alpha = (shown * 255).roundToInt().coerceIn(0, 255)
117
- if (alpha == 0) return
118
- val width = view.picture.width.toFloat()
119
- val height = view.picture.height.toFloat()
120
- val count = canvas.save()
121
- canvas.translate(rect.left, rect.top)
122
- canvas.scale(rect.width() / width, rect.height() / height)
123
- // The picture fades as a whole: its children and background don't show through each other.
124
- if (alpha < 255) canvas.saveLayerAlpha(0f, 0f, width, height, alpha)
125
- canvas.drawPicture(view.picture)
126
- canvas.restoreToCount(count)
127
- }
128
-
129
- private fun lerp(from: Float, to: Float) = from + (to - from) * progress
130
-
131
- override fun setAlpha(alpha: Int) = Unit
132
-
133
- override fun setColorFilter(colorFilter: ColorFilter?) = Unit
134
-
135
- @Deprecated("Deprecated in Java")
136
- override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
137
- }
@@ -1,30 +0,0 @@
1
- #import "ANNEventEmitter.h"
2
- #import <UIKit/UIKit.h>
3
-
4
- NS_ASSUME_NONNULL_BEGIN
5
-
6
- /// Posted on the main queue when the padding of a screen's safe area view changed; the object is the screen id.
7
- extern NSNotificationName const ANNScreenSafeAreaPaddingDidChangeNotification;
8
-
9
- /// The safe area of each screen: how much of its content the bars and the system cover on each side. The padding is
10
- /// the part of it the screen's safe area view keeps its content out of: the insets on the edges the screen's options
11
- /// give. JavaScript gets the rest, what still covers the content (0 on a padded edge): it reads it from its own thread
12
- /// for a screen's first render, and gets every change as `ANN.ScreenInsetsChanged`. Main queue, but the reads.
13
- @interface ANNScreenInsets : NSObject
14
-
15
- /// Keeps the screen's insets and padding, and tells when they changed.
16
- + (void)setInsets:(UIEdgeInsets)insets
17
- padding:(UIEdgeInsets)padding
18
- forScreenId:(NSString *)screenId
19
- eventEmitter:(ANNEventEmitter *)eventEmitter;
20
- /// The padding of the screen's safe area view; none before the screen was laid out. Main queue.
21
- + (UIEdgeInsets)paddingForScreenId:(NSString *)screenId;
22
- /// `{ top, right, bottom, left }`, or nil before the screen was laid out. Any thread.
23
- + (nullable NSDictionary<NSString *, NSNumber *> *)insetsForScreenId:(NSString *)screenId;
24
- + (void)removeScreenId:(NSString *)screenId;
25
- /// Forgets every screen: after a reload the new JavaScript counts its ids anew. Main queue.
26
- + (void)removeAll;
27
-
28
- @end
29
-
30
- NS_ASSUME_NONNULL_END