react-native-screens 5.0.0-alpha.3 → 5.0.0-alpha.4

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 (337) hide show
  1. package/README.md +0 -4
  2. package/android/build.gradle +1 -0
  3. package/android/consumer-rules.pro +3 -0
  4. package/android/src/fabric/java/com/swmansion/rnscreens/legacy/FabricEnabledHeaderConfigViewGroup.kt +2 -0
  5. package/android/src/fabric/java/com/swmansion/rnscreens/legacy/FabricEnabledHeaderSubviewViewGroup.kt +2 -0
  6. package/android/src/fabric/java/com/swmansion/rnscreens/legacy/FabricEnabledViewGroup.kt +18 -3
  7. package/android/src/main/java/com/swmansion/rnscreens/RNScreensPackage.kt +2 -2
  8. package/android/src/main/java/com/swmansion/rnscreens/ScreensModule.kt +7 -3
  9. package/android/src/main/java/com/swmansion/rnscreens/common/colorscheme/ColorSchemeCoordinator.kt +11 -1
  10. package/android/src/main/java/com/swmansion/rnscreens/common/container/Container.kt +9 -0
  11. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native → core/modals/formsheet}/coordinator/FormSheetAppearanceCoordinator.kt +2 -2
  12. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native → core/modals/formsheet}/coordinator/FormSheetBehaviorController.kt +2 -2
  13. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native → core/modals/formsheet}/coordinator/FormSheetDimensionsCoordinator.kt +6 -6
  14. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native → core/modals/formsheet}/coordinator/FormSheetKeyboardCoordinator.kt +1 -1
  15. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native → core/modals/formsheet}/coordinator/FormSheetNativeDismissCoordinator.kt +2 -2
  16. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native/core → core/modals/formsheet/dialog}/FormSheetAvailableHeightProvider.kt +1 -1
  17. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native/core → core/modals/formsheet/dialog}/FormSheetContainer.kt +1 -1
  18. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native/core → core/modals/formsheet/dialog}/FormSheetDialog.kt +1 -1
  19. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native/core → core/modals/formsheet/dialog}/FormSheetDialogManager.kt +26 -8
  20. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native → core/modals/formsheet}/interfaces/FormSheetContentSizeChangeDelegate.kt +1 -1
  21. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native → core/modals/formsheet}/interfaces/FormSheetContentSizeChangeProvider.kt +1 -1
  22. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native → core/modals/formsheet}/interfaces/FormSheetDialogEventEmitter.kt +1 -1
  23. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native → core/modals/formsheet}/model/FormSheetConfig.kt +1 -1
  24. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native → core/modals/formsheet}/model/FormSheetDetents.kt +1 -1
  25. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native → core/modals/formsheet}/presentation/FormSheetAnimatorFactory.kt +1 -1
  26. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native → core/modals/formsheet}/presentation/FormSheetDimmingManager.kt +6 -18
  27. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native → core/modals/formsheet}/presentation/FormSheetDismissalOrigin.kt +1 -1
  28. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native → core/modals/formsheet}/presentation/FormSheetPresentation.kt +10 -10
  29. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native → core/modals/formsheet}/presentation/FormSheetPresentationManager.kt +1 -1
  30. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native → core/modals/formsheet}/presentation/FormSheetPresentationState.kt +1 -1
  31. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/native → core/modals/formsheet}/presentation/FormSheetStackRegistry.kt +1 -1
  32. package/android/src/main/java/com/swmansion/rnscreens/ext/FragmentManagerExt.kt +6 -0
  33. package/android/src/main/java/com/swmansion/rnscreens/helpers/FragmentManagerHelper.kt +0 -3
  34. package/android/src/main/java/com/swmansion/rnscreens/helpers/NoTintDrawable.kt +31 -0
  35. package/android/src/main/java/com/swmansion/rnscreens/helpers/ViewFinder.kt +0 -17
  36. package/android/src/main/java/com/swmansion/rnscreens/legacy/Screen.kt +29 -2
  37. package/android/src/main/java/com/swmansion/rnscreens/legacy/ScreenContainer.kt +35 -3
  38. package/android/src/main/java/com/swmansion/rnscreens/legacy/ScreenStack.kt +13 -0
  39. package/android/src/main/java/com/swmansion/rnscreens/legacy/ScreenStackHeaderConfig.kt +7 -1
  40. package/android/src/main/java/com/swmansion/rnscreens/legacy/ScreenStackHeaderSubviewManager.kt +7 -0
  41. package/android/src/main/java/com/swmansion/rnscreens/legacy/ScreenStackViewManager.kt +6 -0
  42. package/android/src/main/java/com/swmansion/rnscreens/legacy/bottomsheet/DimmingView.kt +2 -0
  43. package/android/src/main/java/com/swmansion/rnscreens/legacy/stack/views/ScreensCoordinatorLayout.kt +2 -0
  44. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/react → react/modals/formsheet}/contentwrapper/FormSheetContentWrapper.kt +3 -3
  45. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/react → react/modals/formsheet}/contentwrapper/FormSheetContentWrapperViewManager.kt +1 -1
  46. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/react → react/modals/formsheet}/event/FormSheetDetentChangedEvent.kt +1 -1
  47. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/react → react/modals/formsheet}/event/FormSheetDidAppearEvent.kt +1 -1
  48. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/react → react/modals/formsheet}/event/FormSheetDidDisappearEvent.kt +1 -1
  49. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/react → react/modals/formsheet}/event/FormSheetDismissEvent.kt +1 -1
  50. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/react → react/modals/formsheet}/event/FormSheetNativeDismissEvent.kt +1 -1
  51. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/react → react/modals/formsheet}/event/FormSheetNativeDismissPreventedEvent.kt +1 -1
  52. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/react → react/modals/formsheet}/event/FormSheetSyncFlushEvent.kt +1 -1
  53. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/react → react/modals/formsheet}/event/FormSheetWillAppearEvent.kt +1 -1
  54. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/react → react/modals/formsheet}/event/FormSheetWillDisappearEvent.kt +1 -1
  55. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/react → react/modals/formsheet}/host/FormSheetContentView.kt +3 -3
  56. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/react → react/modals/formsheet}/host/FormSheetHost.kt +5 -3
  57. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/react → react/modals/formsheet}/host/FormSheetHostEventEmitter.kt +11 -11
  58. package/android/src/main/java/com/swmansion/rnscreens/{modals/formsheet/react → react/modals/formsheet}/host/FormSheetHostViewManager.kt +10 -10
  59. package/android/src/main/java/com/swmansion/rnscreens/safearea/OnInterfaceInsetsChangeListener.kt +15 -0
  60. package/android/src/main/java/com/swmansion/rnscreens/safearea/SafeAreaProvider.kt +8 -8
  61. package/android/src/main/java/com/swmansion/rnscreens/safearea/SafeAreaView.kt +3 -2
  62. package/android/src/main/java/com/swmansion/rnscreens/stack/header/StackHeaderApplicator.kt +0 -52
  63. package/android/src/main/java/com/swmansion/rnscreens/stack/header/StackHeaderCoordinatorLayout.kt +112 -59
  64. package/android/src/main/java/com/swmansion/rnscreens/stack/header/appbar/StackHeaderAppBarLayout.kt +1 -1
  65. package/android/src/main/java/com/swmansion/rnscreens/stack/header/appbar/StackHeaderToolbar.kt +74 -0
  66. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderConfig.kt +4 -73
  67. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderConfigurationObserver.kt +5 -2
  68. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderConfigurationProviding.kt +0 -6
  69. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderInvalidationFlags.kt +3 -7
  70. package/android/src/main/java/com/swmansion/rnscreens/stack/host/FragmentOperation.kt +1 -0
  71. package/android/src/main/java/com/swmansion/rnscreens/stack/host/FragmentOperationExecutor.kt +2 -1
  72. package/android/src/main/java/com/swmansion/rnscreens/stack/host/StackContainer.kt +57 -19
  73. package/android/src/main/java/com/swmansion/rnscreens/stack/host/StackContainerDelegate.kt +7 -0
  74. package/android/src/main/java/com/swmansion/rnscreens/stack/host/StackContainerUpdateCoordinator.kt +5 -3
  75. package/android/src/main/java/com/swmansion/rnscreens/stack/host/StackHost.kt +14 -5
  76. package/android/src/main/java/com/swmansion/rnscreens/stack/host/StackUpdateBatchStateProviding.kt +10 -0
  77. package/android/src/main/java/com/swmansion/rnscreens/stack/screen/PreventNativeDismissCallback.kt +2 -2
  78. package/android/src/main/java/com/swmansion/rnscreens/stack/screen/StackScreenFragment.kt +33 -12
  79. package/android/src/main/java/com/swmansion/rnscreens/tabs/appearance/TabsAppearanceApplicator.kt +106 -10
  80. package/android/src/main/java/com/swmansion/rnscreens/tabs/appearance/TabsAppearanceCoordinator.kt +44 -3
  81. package/android/src/main/java/com/swmansion/rnscreens/tabs/appearance/TabsAppearanceModel.kt +3 -0
  82. package/android/src/main/java/com/swmansion/rnscreens/tabs/container/CustomBottomNavigationView.kt +21 -1
  83. package/android/src/main/java/com/swmansion/rnscreens/tabs/container/TabsContainer.kt +28 -13
  84. package/android/src/main/java/com/swmansion/rnscreens/tabs/container/TabsContainerDelegate.kt +11 -0
  85. package/android/src/main/java/com/swmansion/rnscreens/tabs/host/TabsHost.kt +12 -2
  86. package/android/src/main/java/com/swmansion/rnscreens/tabs/screen/TabsScreen.kt +41 -17
  87. package/android/src/main/java/com/swmansion/rnscreens/tabs/screen/TabsScreenDelegate.kt +6 -0
  88. package/android/src/main/java/com/swmansion/rnscreens/tabs/screen/TabsScreenIcon.kt +82 -0
  89. package/android/src/main/java/com/swmansion/rnscreens/tabs/screen/TabsScreenIconTinting.kt +17 -0
  90. package/android/src/main/java/com/swmansion/rnscreens/tabs/screen/TabsScreenViewManager.kt +26 -19
  91. package/android/src/main/java/com/swmansion/rnscreens/utils/DimensionUtils.kt +14 -7
  92. package/android/src/main/java/com/swmansion/rnscreens/utils/RNSLog.kt +22 -6
  93. package/ios/RNSEnums.h +14 -1
  94. package/ios/helpers/image/RNSImageLoadingHelper.h +7 -0
  95. package/ios/helpers/image/RNSImageLoadingHelper.mm +9 -0
  96. package/ios/legacy/RNSBarButtonItem.mm +15 -0
  97. package/ios/legacy/RNSConvert.h +6 -0
  98. package/ios/legacy/RNSConvert.mm +17 -0
  99. package/ios/legacy/RNSNavigationBar.h +31 -0
  100. package/ios/legacy/RNSNavigationBar.mm +15 -0
  101. package/ios/legacy/RNSScreen.mm +122 -12
  102. package/ios/legacy/RNSScreenContentWrapper.mm +4 -1
  103. package/ios/legacy/RNSScreenStack.mm +202 -15
  104. package/ios/legacy/RNSScreenStackHeaderConfig.h +30 -0
  105. package/ios/legacy/RNSScreenStackHeaderConfig.mm +70 -17
  106. package/ios/legacy/RNSScreenStackHeaderSubview.mm +33 -0
  107. package/ios/safe-area/RNSSafeAreaViewComponentView.mm +1 -12
  108. package/ios/stack/conversion/RNSConversions-Stack.h +30 -0
  109. package/ios/stack/conversion/RNSConversions-Stack.mm +79 -0
  110. package/ios/stack/header/RNSHeaderItemVisibilityPriority.h +9 -0
  111. package/ios/stack/header/RNSStackHeaderConfigComponentView.h +4 -0
  112. package/ios/stack/header/RNSStackHeaderConfigComponentView.mm +40 -6
  113. package/ios/stack/header/RNSStackHeaderConfigDataProviding.h +5 -0
  114. package/ios/stack/header/RNSStackHeaderContentFactory.mm +3 -0
  115. package/ios/stack/header/RNSStackHeaderItemComponentView.h +9 -2
  116. package/ios/stack/header/RNSStackHeaderItemComponentView.mm +57 -3
  117. package/ios/stack/header/RNSStackHeaderItemDataProviding.h +5 -0
  118. package/ios/stack/header/RNSStackHeaderMenuCoordinator.h +13 -0
  119. package/ios/stack/header/RNSStackHeaderMenuCoordinator.mm +24 -0
  120. package/ios/stack/header/RNSStackHeaderMenuFinder.h +8 -1
  121. package/ios/stack/header/RNSStackHeaderMenuFinder.mm +26 -9
  122. package/ios/stack/screen/RNSStackScreenComponentView.h +2 -1
  123. package/ios/stack/screen/RNSStackScreenComponentView.mm +23 -0
  124. package/ios/stack/screen/RNSStackScreenHeaderCoordinator.mm +81 -8
  125. package/ios/tabs/RNSTabBarAppearanceCoordinator.mm +79 -16
  126. package/ios/tabs/RNSTabBarItemCoordinator.h +16 -0
  127. package/ios/tabs/RNSTabBarItemCoordinator.mm +143 -0
  128. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryWrapperView.h +24 -0
  129. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryWrapperView.mm +22 -0
  130. package/ios/tabs/conversion/RNSConversions-Tabs.h +22 -0
  131. package/ios/tabs/conversion/RNSConversions-Tabs.mm +97 -3
  132. package/ios/tabs/host/RNSTabBarController.h +16 -0
  133. package/ios/tabs/host/RNSTabBarController.mm +516 -107
  134. package/ios/tabs/host/RNSTabsHostComponentView.h +2 -0
  135. package/ios/tabs/host/RNSTabsHostComponentView.mm +32 -2
  136. package/ios/tabs/screen/RNSTabsScreenComponentView.h +21 -0
  137. package/ios/tabs/screen/RNSTabsScreenComponentView.mm +54 -69
  138. package/ios/tabs/screen/RNSTabsScreenViewController.mm +1 -0
  139. package/ios/utils/RNSDefines.h +12 -7
  140. package/lib/commonjs/components/stack/header/StackHeaderConfig.android.js +3 -2
  141. package/lib/commonjs/components/stack/header/StackHeaderConfig.android.js.map +1 -1
  142. package/lib/commonjs/components/stack/header/StackHeaderConfig.ios.js +8 -3
  143. package/lib/commonjs/components/stack/header/StackHeaderConfig.ios.js.map +1 -1
  144. package/lib/commonjs/components/stack/header/StackHeaderConfig.js +17 -0
  145. package/lib/commonjs/components/stack/header/StackHeaderConfig.js.map +1 -0
  146. package/lib/commonjs/components/stack/header/ios/StackHeaderItem.ios.js +4 -1
  147. package/lib/commonjs/components/stack/header/ios/StackHeaderItem.ios.js.map +1 -1
  148. package/lib/commonjs/components/stack/host/StackHost.js +8 -1
  149. package/lib/commonjs/components/stack/host/StackHost.js.map +1 -1
  150. package/lib/commonjs/components/stack/host/StackHost.web.js +0 -2
  151. package/lib/commonjs/components/stack/host/StackHost.web.js.map +1 -1
  152. package/lib/commonjs/components/stack/index.js.map +1 -1
  153. package/lib/commonjs/components/tabs/host/TabsHost.ios.js +2 -0
  154. package/lib/commonjs/components/tabs/host/TabsHost.ios.js.map +1 -1
  155. package/lib/commonjs/components/tabs/host/{TabsHost.web.js → TabsHost.js} +1 -1
  156. package/lib/commonjs/components/tabs/host/TabsHost.js.map +1 -0
  157. package/lib/commonjs/components/tabs/index.js.map +1 -1
  158. package/lib/commonjs/components/tabs/screen/TabsScreen.android.js +3 -1
  159. package/lib/commonjs/components/tabs/screen/TabsScreen.android.js.map +1 -1
  160. package/lib/commonjs/components/tabs/screen/TabsScreen.ios.js +10 -1
  161. package/lib/commonjs/components/tabs/screen/TabsScreen.ios.js.map +1 -1
  162. package/lib/commonjs/components/tabs/screen/{TabsScreen.web.js → TabsScreen.js} +1 -1
  163. package/lib/commonjs/components/tabs/screen/TabsScreen.js.map +1 -0
  164. package/lib/commonjs/components/{stack/header/StackHeaderConfig.d.js → tabs/screen/TabsScreenIcon.types.js} +1 -1
  165. package/lib/commonjs/components/{stack/header/StackHeaderConfig.d.js.map → tabs/screen/TabsScreenIcon.types.js.map} +1 -1
  166. package/lib/commonjs/fabric/legacy/ScreenStackHeaderSubviewNativeComponent.js.map +1 -1
  167. package/lib/commonjs/fabric/legacy/ScreenStackNativeComponent.js.map +1 -1
  168. package/lib/commonjs/fabric/stack/StackHeaderConfigIOSNativeComponent.js.map +1 -1
  169. package/lib/commonjs/fabric/stack/StackHeaderItemIOSNativeComponent.js.map +1 -1
  170. package/lib/commonjs/fabric/tabs/TabsHostIOSNativeComponent.js.map +1 -1
  171. package/lib/commonjs/fabric/tabs/TabsScreenAndroidNativeComponent.js.map +1 -1
  172. package/lib/commonjs/fabric/tabs/TabsScreenIOSNativeComponent.js +1 -1
  173. package/lib/commonjs/fabric/tabs/TabsScreenIOSNativeComponent.js.map +1 -1
  174. package/lib/commonjs/legacy/components/ScreenStackItem.js +31 -11
  175. package/lib/commonjs/legacy/components/ScreenStackItem.js.map +1 -1
  176. package/lib/module/components/stack/header/StackHeaderConfig.android.js +4 -3
  177. package/lib/module/components/stack/header/StackHeaderConfig.android.js.map +1 -1
  178. package/lib/module/components/stack/header/StackHeaderConfig.ios.js +9 -4
  179. package/lib/module/components/stack/header/StackHeaderConfig.ios.js.map +1 -1
  180. package/lib/module/components/stack/header/StackHeaderConfig.js +10 -0
  181. package/lib/module/components/stack/header/StackHeaderConfig.js.map +1 -0
  182. package/lib/module/components/stack/header/ios/StackHeaderItem.ios.js +4 -1
  183. package/lib/module/components/stack/header/ios/StackHeaderItem.ios.js.map +1 -1
  184. package/lib/module/components/stack/host/StackHost.js +9 -2
  185. package/lib/module/components/stack/host/StackHost.js.map +1 -1
  186. package/lib/module/components/stack/host/StackHost.web.js +0 -3
  187. package/lib/module/components/stack/host/StackHost.web.js.map +1 -1
  188. package/lib/module/components/stack/index.js.map +1 -1
  189. package/lib/module/components/tabs/host/TabsHost.ios.js +2 -0
  190. package/lib/module/components/tabs/host/TabsHost.ios.js.map +1 -1
  191. package/{src/components/tabs/host/TabsHost.web.tsx → lib/module/components/tabs/host/TabsHost.js} +1 -2
  192. package/lib/module/components/tabs/host/TabsHost.js.map +1 -0
  193. package/lib/module/components/tabs/index.js.map +1 -1
  194. package/lib/module/components/tabs/screen/TabsScreen.android.js +3 -1
  195. package/lib/module/components/tabs/screen/TabsScreen.android.js.map +1 -1
  196. package/lib/module/components/tabs/screen/TabsScreen.ios.js +10 -1
  197. package/lib/module/components/tabs/screen/TabsScreen.ios.js.map +1 -1
  198. package/{src/components/tabs/screen/TabsScreen.web.tsx → lib/module/components/tabs/screen/TabsScreen.js} +1 -2
  199. package/lib/module/components/tabs/screen/TabsScreen.js.map +1 -0
  200. package/lib/module/components/tabs/screen/TabsScreenIcon.types.js +2 -0
  201. package/lib/module/components/{stack/header/StackHeaderConfig.d.js.map → tabs/screen/TabsScreenIcon.types.js.map} +1 -1
  202. package/lib/module/fabric/legacy/ScreenStackHeaderSubviewNativeComponent.js.map +1 -1
  203. package/lib/module/fabric/legacy/ScreenStackNativeComponent.js.map +1 -1
  204. package/lib/module/fabric/stack/StackHeaderConfigIOSNativeComponent.js.map +1 -1
  205. package/lib/module/fabric/stack/StackHeaderItemIOSNativeComponent.js.map +1 -1
  206. package/lib/module/fabric/tabs/TabsHostIOSNativeComponent.js.map +1 -1
  207. package/lib/module/fabric/tabs/TabsScreenAndroidNativeComponent.js.map +1 -1
  208. package/lib/module/fabric/tabs/TabsScreenIOSNativeComponent.js +1 -1
  209. package/lib/module/fabric/tabs/TabsScreenIOSNativeComponent.js.map +1 -1
  210. package/lib/module/legacy/components/ScreenStackItem.js +31 -11
  211. package/lib/module/legacy/components/ScreenStackItem.js.map +1 -1
  212. package/lib/typescript/components/stack/header/StackHeaderConfig.android.d.ts +6 -3
  213. package/lib/typescript/components/stack/header/StackHeaderConfig.android.d.ts.map +1 -1
  214. package/lib/typescript/components/stack/header/StackHeaderConfig.android.types.d.ts +4 -3
  215. package/lib/typescript/components/stack/header/StackHeaderConfig.android.types.d.ts.map +1 -1
  216. package/lib/typescript/components/stack/header/StackHeaderConfig.d.ts +8 -0
  217. package/lib/typescript/components/stack/header/StackHeaderConfig.d.ts.map +1 -0
  218. package/lib/typescript/components/stack/header/StackHeaderConfig.ios.d.ts +6 -3
  219. package/lib/typescript/components/stack/header/StackHeaderConfig.ios.d.ts.map +1 -1
  220. package/lib/typescript/components/stack/header/StackHeaderConfig.ios.types.d.ts +137 -2
  221. package/lib/typescript/components/stack/header/StackHeaderConfig.ios.types.d.ts.map +1 -1
  222. package/lib/typescript/components/stack/header/StackHeaderConfig.types.d.ts +2 -0
  223. package/lib/typescript/components/stack/header/StackHeaderConfig.types.d.ts.map +1 -1
  224. package/lib/typescript/components/stack/header/ios/StackHeaderItem.ios.d.ts.map +1 -1
  225. package/lib/typescript/components/stack/header/ios/StackHeaderItem.ios.types.d.ts +5 -0
  226. package/lib/typescript/components/stack/header/ios/StackHeaderItem.ios.types.d.ts.map +1 -1
  227. package/lib/typescript/components/stack/host/StackHost.d.ts.map +1 -1
  228. package/lib/typescript/components/stack/host/StackHost.types.d.ts +24 -1
  229. package/lib/typescript/components/stack/host/StackHost.types.d.ts.map +1 -1
  230. package/lib/typescript/components/stack/host/StackHost.web.d.ts +1 -3
  231. package/lib/typescript/components/stack/host/StackHost.web.d.ts.map +1 -1
  232. package/lib/typescript/components/stack/index.d.ts +4 -3
  233. package/lib/typescript/components/stack/index.d.ts.map +1 -1
  234. package/lib/typescript/components/tabs/host/TabsHost.d.ts +5 -0
  235. package/lib/typescript/components/tabs/host/TabsHost.d.ts.map +1 -0
  236. package/lib/typescript/components/tabs/host/TabsHost.ios.d.ts.map +1 -1
  237. package/lib/typescript/components/tabs/host/TabsHost.ios.types.d.ts +56 -0
  238. package/lib/typescript/components/tabs/host/TabsHost.ios.types.d.ts.map +1 -1
  239. package/lib/typescript/components/tabs/index.d.ts +4 -6
  240. package/lib/typescript/components/tabs/index.d.ts.map +1 -1
  241. package/lib/typescript/components/tabs/screen/TabsScreen.android.d.ts.map +1 -1
  242. package/lib/typescript/components/tabs/screen/TabsScreen.android.types.d.ts +42 -7
  243. package/lib/typescript/components/tabs/screen/TabsScreen.android.types.d.ts.map +1 -1
  244. package/lib/typescript/components/tabs/screen/TabsScreen.d.ts +5 -0
  245. package/lib/typescript/components/tabs/screen/TabsScreen.d.ts.map +1 -0
  246. package/lib/typescript/components/tabs/screen/TabsScreen.ios.d.ts.map +1 -1
  247. package/lib/typescript/components/tabs/screen/TabsScreen.ios.types.d.ts +78 -13
  248. package/lib/typescript/components/tabs/screen/TabsScreen.ios.types.d.ts.map +1 -1
  249. package/lib/typescript/components/tabs/screen/TabsScreenIcon.types.d.ts +91 -0
  250. package/lib/typescript/components/tabs/screen/TabsScreenIcon.types.d.ts.map +1 -0
  251. package/lib/typescript/components/tabs/screen/index.d.ts +1 -0
  252. package/lib/typescript/components/tabs/screen/index.d.ts.map +1 -1
  253. package/lib/typescript/fabric/legacy/ScreenStackHeaderSubviewNativeComponent.d.ts +2 -0
  254. package/lib/typescript/fabric/legacy/ScreenStackHeaderSubviewNativeComponent.d.ts.map +1 -1
  255. package/lib/typescript/fabric/legacy/ScreenStackNativeComponent.d.ts +1 -0
  256. package/lib/typescript/fabric/legacy/ScreenStackNativeComponent.d.ts.map +1 -1
  257. package/lib/typescript/fabric/stack/StackHeaderConfigIOSNativeComponent.d.ts +4 -0
  258. package/lib/typescript/fabric/stack/StackHeaderConfigIOSNativeComponent.d.ts.map +1 -1
  259. package/lib/typescript/fabric/stack/StackHeaderItemIOSNativeComponent.d.ts +6 -0
  260. package/lib/typescript/fabric/stack/StackHeaderItemIOSNativeComponent.d.ts.map +1 -1
  261. package/lib/typescript/fabric/tabs/TabsHostIOSNativeComponent.d.ts +3 -0
  262. package/lib/typescript/fabric/tabs/TabsHostIOSNativeComponent.d.ts.map +1 -1
  263. package/lib/typescript/fabric/tabs/TabsScreenAndroidNativeComponent.d.ts +6 -0
  264. package/lib/typescript/fabric/tabs/TabsScreenAndroidNativeComponent.d.ts.map +1 -1
  265. package/lib/typescript/fabric/tabs/TabsScreenIOSNativeComponent.d.ts +10 -1
  266. package/lib/typescript/fabric/tabs/TabsScreenIOSNativeComponent.d.ts.map +1 -1
  267. package/lib/typescript/legacy/components/ScreenStackItem.d.ts +25 -0
  268. package/lib/typescript/legacy/components/ScreenStackItem.d.ts.map +1 -1
  269. package/lib/typescript/legacy/components/helpers/prepareHeaderBarButtonItems.d.ts +4 -0
  270. package/lib/typescript/legacy/components/helpers/prepareHeaderBarButtonItems.d.ts.map +1 -1
  271. package/lib/typescript/legacy/types.d.ts +30 -0
  272. package/lib/typescript/legacy/types.d.ts.map +1 -1
  273. package/package.json +4 -2
  274. package/src/components/stack/header/StackHeaderConfig.android.tsx +6 -20
  275. package/src/components/stack/header/StackHeaderConfig.android.types.ts +4 -3
  276. package/src/components/stack/header/StackHeaderConfig.ios.tsx +10 -16
  277. package/src/components/stack/header/StackHeaderConfig.ios.types.ts +148 -2
  278. package/src/components/stack/header/StackHeaderConfig.tsx +12 -0
  279. package/src/components/stack/header/StackHeaderConfig.types.ts +2 -0
  280. package/src/components/stack/header/ios/StackHeaderItem.ios.tsx +9 -1
  281. package/src/components/stack/header/ios/StackHeaderItem.ios.types.ts +5 -0
  282. package/src/components/stack/host/StackHost.tsx +10 -3
  283. package/src/components/stack/host/StackHost.types.ts +25 -1
  284. package/src/components/stack/host/StackHost.web.tsx +1 -4
  285. package/src/components/stack/index.ts +9 -1
  286. package/src/components/tabs/host/TabsHost.ios.tsx +2 -0
  287. package/src/components/tabs/host/TabsHost.ios.types.ts +60 -0
  288. package/src/components/tabs/host/TabsHost.tsx +7 -0
  289. package/src/components/tabs/index.ts +9 -0
  290. package/src/components/tabs/screen/TabsScreen.android.tsx +8 -3
  291. package/src/components/tabs/screen/TabsScreen.android.types.ts +42 -7
  292. package/src/components/tabs/screen/TabsScreen.ios.tsx +22 -5
  293. package/src/components/tabs/screen/TabsScreen.ios.types.ts +79 -17
  294. package/src/components/tabs/screen/TabsScreen.tsx +7 -0
  295. package/src/components/tabs/screen/TabsScreenIcon.types.ts +117 -0
  296. package/src/components/tabs/screen/index.ts +1 -0
  297. package/src/fabric/legacy/ScreenStackHeaderSubviewNativeComponent.ts +6 -0
  298. package/src/fabric/legacy/ScreenStackNativeComponent.ts +2 -0
  299. package/src/fabric/stack/StackHeaderConfigIOSNativeComponent.ts +11 -0
  300. package/src/fabric/stack/StackHeaderItemIOSNativeComponent.ts +11 -0
  301. package/src/fabric/tabs/TabsHostIOSNativeComponent.ts +7 -0
  302. package/src/fabric/tabs/TabsScreenAndroidNativeComponent.ts +9 -0
  303. package/src/fabric/tabs/TabsScreenIOSNativeComponent.ts +20 -2
  304. package/src/legacy/components/ScreenStackItem.tsx +59 -12
  305. package/src/legacy/types.ts +31 -0
  306. package/android/src/main/java/com/swmansion/rnscreens/legacy/ScreenModalFragment.kt +0 -281
  307. package/android/src/main/java/com/swmansion/rnscreens/legacy/bottomsheet/BottomSheetDialogRootView.kt +0 -104
  308. package/android/src/main/java/com/swmansion/rnscreens/legacy/bottomsheet/BottomSheetDialogScreen.kt +0 -26
  309. package/lib/commonjs/components/stack/header/StackHeaderConfig.web.js +0 -10
  310. package/lib/commonjs/components/stack/header/StackHeaderConfig.web.js.map +0 -1
  311. package/lib/commonjs/components/tabs/host/TabsHost.d.js +0 -2
  312. package/lib/commonjs/components/tabs/host/TabsHost.d.js.map +0 -1
  313. package/lib/commonjs/components/tabs/host/TabsHost.web.js.map +0 -1
  314. package/lib/commonjs/components/tabs/screen/TabsScreen.d.js +0 -2
  315. package/lib/commonjs/components/tabs/screen/TabsScreen.d.js.map +0 -1
  316. package/lib/commonjs/components/tabs/screen/TabsScreen.web.js.map +0 -1
  317. package/lib/module/components/stack/header/StackHeaderConfig.d.js +0 -2
  318. package/lib/module/components/stack/header/StackHeaderConfig.web.js +0 -4
  319. package/lib/module/components/stack/header/StackHeaderConfig.web.js.map +0 -1
  320. package/lib/module/components/tabs/host/TabsHost.d.js +0 -2
  321. package/lib/module/components/tabs/host/TabsHost.d.js.map +0 -1
  322. package/lib/module/components/tabs/host/TabsHost.web.js +0 -4
  323. package/lib/module/components/tabs/host/TabsHost.web.js.map +0 -1
  324. package/lib/module/components/tabs/screen/TabsScreen.d.js +0 -2
  325. package/lib/module/components/tabs/screen/TabsScreen.d.js.map +0 -1
  326. package/lib/module/components/tabs/screen/TabsScreen.web.js +0 -4
  327. package/lib/module/components/tabs/screen/TabsScreen.web.js.map +0 -1
  328. package/lib/typescript/components/stack/header/StackHeaderConfig.web.d.ts +0 -7
  329. package/lib/typescript/components/stack/header/StackHeaderConfig.web.d.ts.map +0 -1
  330. package/lib/typescript/components/tabs/host/TabsHost.web.d.ts +0 -7
  331. package/lib/typescript/components/tabs/host/TabsHost.web.d.ts.map +0 -1
  332. package/lib/typescript/components/tabs/screen/TabsScreen.web.d.ts +0 -7
  333. package/lib/typescript/components/tabs/screen/TabsScreen.web.d.ts.map +0 -1
  334. package/src/components/stack/header/StackHeaderConfig.d.ts +0 -22
  335. package/src/components/stack/header/StackHeaderConfig.web.tsx +0 -5
  336. package/src/components/tabs/host/TabsHost.d.ts +0 -12
  337. package/src/components/tabs/screen/TabsScreen.d.ts +0 -12
@@ -16,7 +16,6 @@ import com.swmansion.rnscreens.common.container.Container
16
16
  import com.swmansion.rnscreens.common.container.ContainerItem
17
17
  import com.swmansion.rnscreens.common.container.ParentContainerItemRegistry
18
18
  import com.swmansion.rnscreens.ext.isMeasured
19
- import com.swmansion.rnscreens.helpers.FragmentManagerHelper
20
19
  import com.swmansion.rnscreens.helpers.ViewIdGenerator
21
20
  import com.swmansion.rnscreens.stack.header.StackHeaderBackPressHandler
22
21
  import com.swmansion.rnscreens.stack.screen.StackScreen
@@ -34,7 +33,8 @@ internal class StackContainer(
34
33
  FragmentManager.OnBackStackChangedListener,
35
34
  ColorSchemeProviding,
36
35
  StackHeaderBackPressHandler,
37
- StackScreenFragmentDelegate {
36
+ StackScreenFragmentDelegate,
37
+ StackUpdateBatchStateProviding {
38
38
  private var fragmentManager: FragmentManager? = null
39
39
 
40
40
  private fun requireFragmentManager(): FragmentManager =
@@ -85,7 +85,7 @@ internal class StackContainer(
85
85
  super.onAttachedToWindow()
86
86
 
87
87
  parentContainerRegistry.attach(this)
88
- setupFragmentManger()
88
+ setupFragmentManager()
89
89
 
90
90
  // StackContainer only provides container-level color scheme configuration for its screens
91
91
  // but doesn't use any color scheme-dependent views, so we don't need the callback.
@@ -120,25 +120,50 @@ internal class StackContainer(
120
120
 
121
121
  override fun onFragmentConfigurationChanged(config: Configuration) = onConfigurationChanged(config)
122
122
 
123
- internal fun setupFragmentManger() {
123
+ internal fun setupFragmentManager() {
124
124
  fragmentManager =
125
- checkNotNull(FragmentManagerHelper.findFragmentManagerForView(this)) {
126
- "[RNScreens] Nullish fragment manager - can't run container operations"
127
- }.also {
125
+ checkNotNull(delegate.get()) {
126
+ "[RNScreens] StackContainer has no delegate to resolve the fragment manager from"
127
+ }.resolveFragmentManager().also {
128
128
  it.addOnBackStackChangedListener(this)
129
129
  }
130
130
  }
131
131
 
132
+ // region Update batch
133
+
134
+ override var isUpdatePending: Boolean = false
135
+ private set
136
+
137
+ /**
138
+ * Announces that more updates are coming. Header updates raised until [endUpdateBatch]
139
+ * are held and applied together with the navigation operations of the batch.
140
+ */
141
+ internal fun beginUpdateBatch() {
142
+ isUpdatePending = true
143
+ }
144
+
145
+ internal fun endUpdateBatch() {
146
+ isUpdatePending = false
147
+ performContainerUpdateIfNeeded()
148
+ }
149
+
150
+ // endregion
151
+
132
152
  /**
133
- * Call this function to trigger container update
153
+ * Applies pending navigation operations and then pending header updates of the screens
154
+ * remaining in the stack.
134
155
  */
135
156
  internal fun performContainerUpdateIfNeeded() {
136
157
  // If container update is requested before container is attached to window, we ignore
137
158
  // the call because we don't have valid fragmentManager yet.
138
159
  // Update will be eventually executed in onAttachedToWindow().
139
- if (hasPendingOperations && isAttachedToWindow) {
160
+ if (!isAttachedToWindow) {
161
+ return
162
+ }
163
+ if (hasPendingOperations) {
140
164
  performOperations(requireFragmentManager())
141
165
  }
166
+ stackModel.forEach { it.flushPendingHeaderUpdates() }
142
167
  }
143
168
 
144
169
  internal fun enqueuePushOperation(stackScreen: StackScreen) {
@@ -209,6 +234,7 @@ internal class StackContainer(
209
234
  newFragment,
210
235
  containerViewId = this.id,
211
236
  addToBackStack = stackModel.isNotEmpty(),
237
+ coveredFragment = stackModel.lastOrNull(),
212
238
  ),
213
239
  )
214
240
  stackModel.add(newFragment)
@@ -233,9 +259,9 @@ internal class StackContainer(
233
259
  }
234
260
 
235
261
  private fun dumpStackModel() {
236
- Log.d(TAG, "StackContainer [$id] MODEL BEGIN")
262
+ RNSLog.d(TAG, "StackContainer [$id] MODEL BEGIN")
237
263
  stackModel.forEach {
238
- Log.d(TAG, "${it.stackScreen.screenKey}")
264
+ RNSLog.d(TAG, "${it.stackScreen.screenKey}")
239
265
  }
240
266
  }
241
267
 
@@ -248,21 +274,22 @@ internal class StackContainer(
248
274
  canNavigateBack,
249
275
  WeakReference(this),
250
276
  backPressHandler = WeakReference(this),
277
+ updateBatchStateProvider = WeakReference(this),
278
+ colorSchemeProvider = WeakReference(this),
251
279
  ).also {
252
- Log.d(TAG, "Created Fragment $it for screen ${screen.screenKey}")
280
+ RNSLog.d(TAG, "Created Fragment $it for screen ${screen.screenKey}")
253
281
  }
254
282
 
255
283
  private fun updateTopFragment() {
256
- // We try to handle situation where other fragments might be present.
257
- val fragmentManager = requireFragmentManager()
258
- val fragments = fragmentManager.fragments.filterIsInstance<StackScreenFragment>()
259
- check(fragments.isNotEmpty()) { "[RNScreens] Empty fragment manager while attempting to update top fragment" }
260
- fragments.forEach { it.onResignTopFragment() }
261
- fragments.last().onBecomeTopFragment()
284
+ // Covered fragments are detached, so FragmentManager's added list holds only the top
285
+ // fragment - the model is the only place all of them can be resigned from.
286
+ check(stackModel.isNotEmpty()) { "[RNScreens] Empty stack model while attempting to update top fragment" }
287
+ stackModel.forEach { it.onResignTopFragment() }
288
+ stackModel.last().onBecomeTopFragment()
262
289
 
263
290
  // This assumes that the updateTopFragment is called already after primary nav frag. is updated.
264
291
  // If this needs to be changed in the future, just remove this assertion.
265
- check(fragmentManager.primaryNavigationFragment === fragments.last()) {
292
+ check(requireFragmentManager().primaryNavigationFragment === stackModel.last()) {
266
293
  "[RNScreens] Top fragment different from primary navigation fragment"
267
294
  }
268
295
  }
@@ -341,6 +368,17 @@ internal class StackContainer(
341
368
  .asReversed()
342
369
  .firstNotNullOfOrNull { it.stackScreen.wantsToPreventStackNativeDismiss() }
343
370
 
371
+ // Pop-to-root is not implemented for the v5 stack yet - the request is forwarded to the top screen's
372
+ // nested container.
373
+ override fun requestPopToRoot(): Boolean {
374
+ RNSLog.w(TAG, "[RNScreens] Pop-to-root special effect is not implemented for v5 stack yet")
375
+ return stackModel
376
+ .lastOrNull()
377
+ ?.stackScreen
378
+ ?.resolveNestedContainer()
379
+ ?.requestPopToRoot() == true
380
+ }
381
+
344
382
  // endregion
345
383
 
346
384
  // region Header back button
@@ -1,7 +1,14 @@
1
1
  package com.swmansion.rnscreens.stack.host
2
2
 
3
+ import androidx.fragment.app.FragmentManager
3
4
  import com.swmansion.rnscreens.stack.screen.StackScreen
4
5
 
5
6
  internal interface StackContainerDelegate {
6
7
  fun onScreenDismissCommitted(stackScreen: StackScreen)
8
+
9
+ /**
10
+ * Resolves the fragment manager the container should run its operations on. Called every time the container
11
+ * is attached to a window, as the result may differ between attachments.
12
+ */
13
+ fun resolveFragmentManager(): FragmentManager
7
14
  }
@@ -16,7 +16,11 @@ internal class StackContainerUpdateCoordinator {
16
16
  pendingPopOperations.add(PopOperation(stackScreen))
17
17
  }
18
18
 
19
- internal fun executePendingOperationsIfNeeded(
19
+ /**
20
+ * Hands the pending operations to the container in stack order. The container applies
21
+ * them on its next update.
22
+ */
23
+ internal fun enqueuePendingOperations(
20
24
  container: StackContainer,
21
25
  renderedScreens: List<StackScreen>,
22
26
  ) {
@@ -35,8 +39,6 @@ internal class StackContainerUpdateCoordinator {
35
39
  .sortedBy { it.first }
36
40
  .forEach { (_, operation) -> container.enqueuePushOperation(operation.screen) }
37
41
 
38
- container.performContainerUpdateIfNeeded()
39
-
40
42
  pendingPopOperations.clear()
41
43
  pendingPushOperations.clear()
42
44
  }
@@ -1,14 +1,15 @@
1
1
  package com.swmansion.rnscreens.stack.host
2
2
 
3
3
  import android.annotation.SuppressLint
4
- import android.util.Log
5
4
  import android.view.ViewGroup
5
+ import androidx.fragment.app.FragmentManager
6
6
  import com.facebook.react.bridge.UIManager
7
7
  import com.facebook.react.bridge.UIManagerListener
8
8
  import com.facebook.react.common.annotations.UnstableReactNativeAPI
9
9
  import com.facebook.react.uimanager.ThemedReactContext
10
10
  import com.facebook.react.uimanager.UIManagerHelper
11
11
  import com.swmansion.rnscreens.common.colorscheme.ColorScheme
12
+ import com.swmansion.rnscreens.helpers.FragmentManagerHelper
12
13
  import com.swmansion.rnscreens.helpers.getFabricUIManagerNotNull
13
14
  import com.swmansion.rnscreens.stack.screen.StackScreen
14
15
  import com.swmansion.rnscreens.utils.RNSLog
@@ -80,7 +81,7 @@ class StackHost(
80
81
  // This shouldn't happen in typical scenarios but it can happen with fast-refresh.
81
82
  containerUpdateCoordinator.addPopOperation(stackScreen)
82
83
  } else {
83
- Log.d(TAG, "Ignoring pop operation of ${stackScreen.screenKey}, already not attached or natively dismissed")
84
+ RNSLog.d(TAG, "Ignoring pop operation of ${stackScreen.screenKey}, already not attached or natively dismissed")
84
85
  }
85
86
  }
86
87
 
@@ -97,6 +98,11 @@ class StackHost(
97
98
  }
98
99
  }
99
100
 
101
+ override fun resolveFragmentManager(): FragmentManager =
102
+ checkNotNull(FragmentManagerHelper.findFragmentManagerForView(this)) {
103
+ "[RNScreens] Nullish fragment manager - can't run container operations"
104
+ }
105
+
100
106
  override fun onMeasure(
101
107
  widthMeasureSpec: Int,
102
108
  heightMeasureSpec: Int,
@@ -161,14 +167,17 @@ class StackHost(
161
167
  container.layout(left, top, right, bottom)
162
168
  }
163
169
 
170
+ override fun willMountItems(uiManager: UIManager) {
171
+ container.beginUpdateBatch()
172
+ }
173
+
164
174
  override fun didMountItems(uiManager: UIManager) {
165
- containerUpdateCoordinator.executePendingOperationsIfNeeded(container, renderedScreens)
175
+ containerUpdateCoordinator.enqueuePendingOperations(container, renderedScreens)
176
+ container.endUpdateBatch()
166
177
  }
167
178
 
168
179
  override fun willDispatchViewUpdates(uiManager: UIManager) = Unit
169
180
 
170
- override fun willMountItems(uiManager: UIManager) = Unit
171
-
172
181
  override fun didDispatchMountItems(uiManager: UIManager) = Unit
173
182
 
174
183
  override fun didScheduleMountItems(uiManager: UIManager) = Unit
@@ -0,0 +1,10 @@
1
+ package com.swmansion.rnscreens.stack.host
2
+
3
+ /**
4
+ * Tells whether the owner has begun an update batch that has not ended yet.
5
+ * Consumers hold their pending updates while it is `true`; the owner applies
6
+ * them all in one pass when the batch ends.
7
+ */
8
+ internal interface StackUpdateBatchStateProviding {
9
+ val isUpdatePending: Boolean
10
+ }
@@ -1,10 +1,10 @@
1
1
  package com.swmansion.rnscreens.stack.screen
2
2
 
3
- import android.util.Log
4
3
  import androidx.activity.OnBackPressedCallback
5
4
  import androidx.lifecycle.Lifecycle
6
5
  import androidx.lifecycle.LifecycleEventObserver
7
6
  import androidx.lifecycle.LifecycleOwner
7
+ import com.swmansion.rnscreens.utils.RNSLog
8
8
 
9
9
  internal class PreventNativeDismissCallback(
10
10
  lifecycleOwner: LifecycleOwner,
@@ -31,7 +31,7 @@ internal class PreventNativeDismissCallback(
31
31
  }
32
32
 
33
33
  override fun handleOnBackPressed() {
34
- Log.i("RNScreens", "PreventNativeDismissCallback called for screen ${screen.screenKey}")
34
+ RNSLog.i("RNScreens", "PreventNativeDismissCallback called for screen ${screen.screenKey}")
35
35
  screen.onNativeDismissPrevented()
36
36
  }
37
37
 
@@ -9,8 +9,10 @@ import android.view.View
9
9
  import android.view.ViewGroup
10
10
  import androidx.fragment.app.Fragment
11
11
  import androidx.transition.Slide
12
+ import com.swmansion.rnscreens.common.colorscheme.ColorSchemeProviding
12
13
  import com.swmansion.rnscreens.stack.header.StackHeaderBackPressHandler
13
14
  import com.swmansion.rnscreens.stack.header.StackHeaderCoordinatorLayout
15
+ import com.swmansion.rnscreens.stack.host.StackUpdateBatchStateProviding
14
16
  import java.lang.ref.WeakReference
15
17
 
16
18
  internal class StackScreenFragment(
@@ -18,9 +20,18 @@ internal class StackScreenFragment(
18
20
  private val canNavigateBack: Boolean,
19
21
  private val delegate: WeakReference<StackScreenFragmentDelegate>,
20
22
  private val backPressHandler: WeakReference<StackHeaderBackPressHandler>,
23
+ private val updateBatchStateProvider: WeakReference<StackUpdateBatchStateProviding>,
24
+ private val colorSchemeProvider: WeakReference<ColorSchemeProviding>,
21
25
  ) : Fragment() {
22
26
  private var screenLifecycleEventEmitter: StackScreenAppearanceEventsEmitter? = null
23
27
 
28
+ /**
29
+ * Retained across fragment view destruction (e.g. tab switches detaching the fragment), so that
30
+ * the app bar scroll offset and the built header survive reattachment. FragmentManager removes
31
+ * the view from its container before `onDestroyView`, so `onCreateView` can return it as-is.
32
+ */
33
+ private var headerCoordinatorLayout: StackHeaderCoordinatorLayout? = null
34
+
24
35
  /**
25
36
  * This holds the screen strongly for now. Beware of retain cycle.
26
37
  *
@@ -41,21 +52,34 @@ internal class StackScreenFragment(
41
52
  allowEnterTransitionOverlap = true
42
53
  allowReturnTransitionOverlap = true
43
54
 
44
- enterTransition = Slide(Gravity.RIGHT)
45
- exitTransition = Slide(Gravity.LEFT)
46
- returnTransition = Slide(Gravity.RIGHT)
47
- reenterTransition = Slide(Gravity.LEFT)
55
+ enterTransition = Slide(Gravity.END)
56
+ exitTransition = Slide(Gravity.START)
57
+ returnTransition = Slide(Gravity.END)
58
+ reenterTransition = Slide(Gravity.START)
48
59
  }
49
60
 
50
61
  override fun onCreateView(
51
62
  inflater: LayoutInflater,
52
63
  container: ViewGroup?,
53
64
  savedInstanceState: Bundle?,
54
- ): View =
55
- StackHeaderCoordinatorLayout(requireContext(), stackScreen, canNavigateBack) { pressedScreen ->
65
+ ): View {
66
+ headerCoordinatorLayout?.let { return it }
67
+
68
+ return StackHeaderCoordinatorLayout(
69
+ requireContext(),
70
+ stackScreen,
71
+ canNavigateBack,
72
+ updateBatchStateProvider,
73
+ colorSchemeProvider,
74
+ ) { pressedScreen ->
56
75
  backPressHandler.get()?.handleHeaderBackButtonPress(pressedScreen)
57
76
  ?: Log.w(TAG, "[RNScreens] Header back button press dropped - handler is gone")
58
- }
77
+ }.also { headerCoordinatorLayout = it }
78
+ }
79
+
80
+ internal fun flushPendingHeaderUpdates() {
81
+ headerCoordinatorLayout?.flushPendingUpdates()
82
+ }
59
83
 
60
84
  override fun onViewCreated(
61
85
  view: View,
@@ -66,17 +90,14 @@ internal class StackScreenFragment(
66
90
  }
67
91
 
68
92
  override fun onDestroyView() {
69
- val coordinatorLayout = view
70
- check(coordinatorLayout is StackHeaderCoordinatorLayout) {
71
- "[RNScreens] Unexpected fragment view type: $view"
72
- }
73
- coordinatorLayout.tearDown()
74
93
  super.onDestroyView()
75
94
  screenLifecycleEventEmitter = null
76
95
  }
77
96
 
78
97
  override fun onDestroy() {
79
98
  super.onDestroy()
99
+ headerCoordinatorLayout?.tearDown()
100
+ headerCoordinatorLayout = null
80
101
  stackScreen.onDismiss()
81
102
  teardownPreventNativeDismissCallback()
82
103
  }
@@ -3,6 +3,8 @@ package com.swmansion.rnscreens.tabs.appearance
3
3
  import android.annotation.SuppressLint
4
4
  import android.content.Context
5
5
  import android.content.res.ColorStateList
6
+ import android.graphics.drawable.Drawable
7
+ import android.graphics.drawable.InsetDrawable
6
8
  import android.graphics.drawable.StateListDrawable
7
9
  import android.util.TypedValue
8
10
  import android.view.MenuItem
@@ -14,14 +16,99 @@ import com.facebook.react.common.assets.ReactFontManager
14
16
  import com.facebook.react.uimanager.PixelUtil
15
17
  import com.google.android.material.R
16
18
  import com.google.android.material.bottomnavigation.BottomNavigationView
19
+ import com.google.android.material.navigation.NavigationBarItemView
17
20
  import com.google.android.material.navigation.NavigationBarView
18
21
  import com.swmansion.rnscreens.tabs.screen.TabsScreen
22
+ import com.swmansion.rnscreens.utils.dpToPx
23
+ import com.swmansion.rnscreens.utils.pxToDp
19
24
  import com.swmansion.rnscreens.utils.resolveColorAttr
20
25
 
21
26
  @SuppressLint("PrivateResource") // We want to use variables from material design for default values
22
27
  internal class TabsAppearanceApplicator(
23
28
  private val bottomNavigationView: BottomNavigationView,
24
29
  ) {
30
+ // Resolved on each access: tracks the display density of the current configuration.
31
+ internal val defaultIconSizeDp: Float
32
+ get() =
33
+ bottomNavigationView.pxToDp(
34
+ bottomNavigationView.resources.getDimension(R.dimen.mtrl_navigation_bar_item_default_icon_size),
35
+ )
36
+
37
+ internal fun effectiveIconSizeDp(tabsScreen: TabsScreen): Float =
38
+ tabsScreen.appearance?.tabBarItemIconSize?.takeIf { it > 0f } ?: defaultIconSizeDp
39
+
40
+ // Material allows only one icon size for all items; iconBoxDp is the largest effective per-tab size.
41
+ fun applyIconBox(iconBoxDp: Float) {
42
+ val iconBoxPx = bottomNavigationView.dpToPx(iconBoxDp).toInt()
43
+ if (bottomNavigationView.itemIconSize != iconBoxPx) {
44
+ bottomNavigationView.itemIconSize = iconBoxPx
45
+ }
46
+ }
47
+
48
+ // Resolved on each access: tracks the material library version and the display density.
49
+ private val defaultIndicatorWidthPx: Int
50
+ get() = bottomNavigationView.resources.getDimensionPixelSize(R.dimen.m3_bottom_nav_item_active_indicator_width)
51
+
52
+ private val defaultIndicatorHeightPx: Int
53
+ get() = bottomNavigationView.resources.getDimensionPixelSize(R.dimen.m3_bottom_nav_item_active_indicator_height)
54
+
55
+ // Auto-scale preserves the themed default padding around the icon: default indicator minus default icon size.
56
+ private val autoIndicatorHorizontalPaddingDp: Float
57
+ get() = bottomNavigationView.pxToDp(defaultIndicatorWidthPx.toFloat()) - defaultIconSizeDp
58
+
59
+ private val autoIndicatorVerticalPaddingDp: Float
60
+ get() = bottomNavigationView.pxToDp(defaultIndicatorHeightPx.toFloat()) - defaultIconSizeDp
61
+
62
+ internal fun effectiveIndicatorWidthDp(tabsScreen: TabsScreen): Float =
63
+ tabsScreen.appearance?.tabBarItemActiveIndicatorWidth?.takeIf { it > 0f }
64
+ ?: (effectiveIconSizeDp(tabsScreen) + autoIndicatorHorizontalPaddingDp)
65
+
66
+ internal fun effectiveIndicatorHeightDp(tabsScreen: TabsScreen): Float =
67
+ tabsScreen.appearance?.tabBarItemActiveIndicatorHeight?.takeIf { it > 0f }
68
+ ?: (effectiveIconSizeDp(tabsScreen) + autoIndicatorVerticalPaddingDp)
69
+
70
+ @SuppressLint("RestrictedApi")
71
+ private fun applyActiveIndicatorSize(
72
+ menuItem: MenuItem,
73
+ tabsScreen: TabsScreen,
74
+ ): Boolean {
75
+ val widthPx = bottomNavigationView.dpToPx(effectiveIndicatorWidthDp(tabsScreen)).toInt()
76
+ val heightPx = bottomNavigationView.dpToPx(effectiveIndicatorHeightDp(tabsScreen)).toInt()
77
+ val isAlreadyApplied =
78
+ widthPx == (tabsScreen.appliedActiveIndicatorWidthPx ?: defaultIndicatorWidthPx) &&
79
+ heightPx == (tabsScreen.appliedActiveIndicatorHeightPx ?: defaultIndicatorHeightPx)
80
+ if (isAlreadyApplied) {
81
+ return true
82
+ }
83
+ val itemView =
84
+ bottomNavigationView.menuViewGroup.children.firstOrNull { it.id == menuItem.itemId } as? NavigationBarItemView
85
+ ?: return false
86
+ // NavigationBarItemView is restricted Material API. Without it, Material only offers one active
87
+ // indicator size for the whole tab bar (BottomNavigationView.itemActiveIndicatorWidth/Height).
88
+ itemView.setActiveIndicatorWidth(widthPx)
89
+ itemView.setActiveIndicatorHeight(heightPx)
90
+
91
+ tabsScreen.appliedActiveIndicatorWidthPx = widthPx
92
+ tabsScreen.appliedActiveIndicatorHeightPx = heightPx
93
+
94
+ return true
95
+ }
96
+
97
+ // Inset the icon so it renders at effectiveDp, centered within iconBoxDp.
98
+ // Intrinsic-relative on purpose: Material FIT_CENTER-scales the drawable to the icon box,
99
+ // so the intrinsic factor cancels and the glyph lands at effectiveDp/iconBoxDp of the box.
100
+ private fun sizeIcon(
101
+ icon: Drawable?,
102
+ effectiveDp: Float,
103
+ iconBoxDp: Float,
104
+ ): Drawable? {
105
+ if (icon == null || effectiveDp >= iconBoxDp) return icon
106
+ val larger = maxOf(icon.intrinsicWidth, icon.intrinsicHeight)
107
+ if (larger <= 0) return icon
108
+ val insetPx = (larger * (iconBoxDp - effectiveDp) / (2f * effectiveDp)).toInt()
109
+ return if (insetPx > 0) InsetDrawable(icon, insetPx) else icon
110
+ }
111
+
25
112
  private val states =
26
113
  arrayOf(
27
114
  intArrayOf(-android.R.attr.state_enabled), // disabled
@@ -174,23 +261,32 @@ internal class TabsAppearanceApplicator(
174
261
  fun updateMenuItemAppearance(
175
262
  menuItem: MenuItem,
176
263
  tabsScreen: TabsScreen,
264
+ iconBoxDp: Float,
177
265
  ) {
178
266
  if (menuItem.title != tabsScreen.tabTitle) {
179
267
  menuItem.title = tabsScreen.tabTitle
180
268
  }
181
269
 
182
- val targetIcon =
183
- if (tabsScreen.selectedIcon != null && tabsScreen.icon != null) {
184
- StateListDrawable().apply {
185
- addState(intArrayOf(android.R.attr.state_checked), tabsScreen.selectedIcon?.mutate())
186
- addState(intArrayOf(), tabsScreen.icon?.mutate())
270
+ if (tabsScreen.isMenuItemIconInvalidated) {
271
+ tabsScreen.isMenuItemIconInvalidated = false
272
+ // Sized per slot: a StateListDrawable's intrinsic size follows its current state, so a
273
+ // single inset computed from one child would mis-size the other when their resolutions differ.
274
+ val effectiveDp = effectiveIconSizeDp(tabsScreen)
275
+ val iconDrawable = sizeIcon(tabsScreen.icon.drawable, effectiveDp, iconBoxDp)
276
+ val selectedIconDrawable = sizeIcon(tabsScreen.selectedIcon.drawable, effectiveDp, iconBoxDp)
277
+ menuItem.icon =
278
+ if (selectedIconDrawable != null && iconDrawable != null) {
279
+ StateListDrawable().apply {
280
+ addState(intArrayOf(android.R.attr.state_checked), selectedIconDrawable.mutate())
281
+ addState(intArrayOf(), iconDrawable.mutate())
282
+ }
283
+ } else {
284
+ iconDrawable
187
285
  }
188
- } else {
189
- tabsScreen.icon
190
- }
286
+ }
191
287
 
192
- if (menuItem.icon != targetIcon) {
193
- menuItem.icon = targetIcon
288
+ if (tabsScreen.isMenuItemActiveIndicatorInvalidated && applyActiveIndicatorSize(menuItem, tabsScreen)) {
289
+ tabsScreen.isMenuItemActiveIndicatorInvalidated = false
194
290
  }
195
291
  }
196
292
 
@@ -13,19 +13,59 @@ internal class TabsAppearanceCoordinator(
13
13
  ) {
14
14
  private val appearanceApplicator = TabsAppearanceApplicator(bottomNavigationView)
15
15
 
16
+ private var appliedIconBoxDp: Float? = null
17
+
18
+ // Icon box is bar-wide: the largest effective size across tabs.
19
+ internal fun resolveIconBoxDp(): Float {
20
+ if (tabsScreenFragments.isEmpty()) {
21
+ return appearanceApplicator.defaultIconSizeDp
22
+ }
23
+ var largestIconDp = 0f
24
+ var tallestIndicatorDp = 0f
25
+ var shortestIndicatorDp = Float.MAX_VALUE
26
+ tabsScreenFragments.forEach {
27
+ largestIconDp = maxOf(largestIconDp, appearanceApplicator.effectiveIconSizeDp(it.tabsScreen))
28
+ val indicatorHeightDp = appearanceApplicator.effectiveIndicatorHeightDp(it.tabsScreen)
29
+ tallestIndicatorDp = maxOf(tallestIndicatorDp, indicatorHeightDp)
30
+ shortestIndicatorDp = minOf(shortestIndicatorDp, indicatorHeightDp)
31
+ }
32
+ val unevenIndicatorsOutgrowIcons = tallestIndicatorDp > largestIconDp && tallestIndicatorDp != shortestIndicatorDp
33
+ return if (unevenIndicatorsOutgrowIcons) tallestIndicatorDp else largestIconDp
34
+ }
35
+
36
+ internal fun invalidateMenuItemIcons() {
37
+ tabsScreenFragments.forEach { it.tabsScreen.isMenuItemIconInvalidated = true }
38
+ }
39
+
40
+ internal fun invalidateRebuiltMenuItems() {
41
+ invalidateMenuItemIcons()
42
+ tabsScreenFragments.forEach {
43
+ it.tabsScreen.isMenuItemActiveIndicatorInvalidated = true
44
+ it.tabsScreen.appliedActiveIndicatorWidthPx = null
45
+ it.tabsScreen.appliedActiveIndicatorHeightPx = null
46
+ }
47
+ }
48
+
16
49
  fun updateTabAppearance(
17
50
  context: Context,
18
51
  tabsContainer: TabsContainer,
19
52
  ) {
20
53
  val selectedTabAppearance = tabsContainer.selectedTab.tabsScreen.appearance
54
+ val iconBoxDp = resolveIconBoxDp()
55
+ if (iconBoxDp != appliedIconBoxDp) {
56
+ appliedIconBoxDp = iconBoxDp
57
+ invalidateMenuItemIcons()
58
+ }
59
+ appearanceApplicator.applyIconBox(iconBoxDp)
21
60
  appearanceApplicator.updateSharedAppearance(context, selectedTabAppearance, tabsContainer.tabBarHidden)
22
- updateMenuItems(context, selectedTabAppearance)
61
+ updateMenuItems(context, selectedTabAppearance, iconBoxDp)
23
62
  appearanceApplicator.updateFontStyles(context, selectedTabAppearance) // It needs to be updated after updateMenuItems
24
63
  }
25
64
 
26
65
  private fun updateMenuItems(
27
66
  context: Context,
28
67
  tabsAppearance: TabsAppearance?,
68
+ iconBoxDp: Float,
29
69
  ) {
30
70
  tabsScreenFragments.forEach { fragment ->
31
71
  val menuItemId = fragment.menuItemId
@@ -33,7 +73,7 @@ internal class TabsAppearanceCoordinator(
33
73
  checkNotNull(bottomNavigationView.menu.findItem(menuItemId)) {
34
74
  "[RNScreens] Missing MenuItem for id: $menuItemId"
35
75
  }
36
- updateMenuItemAppearance(context, menuItem, fragment.tabsScreen, tabsAppearance)
76
+ updateMenuItemAppearance(context, menuItem, fragment.tabsScreen, tabsAppearance, iconBoxDp)
37
77
  }
38
78
  }
39
79
 
@@ -42,8 +82,9 @@ internal class TabsAppearanceCoordinator(
42
82
  menuItem: MenuItem,
43
83
  tabsScreen: TabsScreen,
44
84
  appearance: TabsAppearance?,
85
+ iconBoxDp: Float,
45
86
  ) {
46
- appearanceApplicator.updateMenuItemAppearance(menuItem, tabsScreen)
87
+ appearanceApplicator.updateMenuItemAppearance(menuItem, tabsScreen, iconBoxDp)
47
88
  appearanceApplicator.updateBadgeAppearance(context, menuItem, tabsScreen, appearance)
48
89
  }
49
90
  }
@@ -8,8 +8,11 @@ internal data class TabsAppearance(
8
8
  val selected: ItemStateAppearance? = null,
9
9
  val focused: ItemStateAppearance? = null,
10
10
  val disabled: ItemStateAppearance? = null,
11
+ val tabBarItemIconSize: Float? = null,
11
12
  val tabBarItemActiveIndicatorColor: Int? = null,
12
13
  val tabBarItemActiveIndicatorEnabled: Boolean? = null,
14
+ val tabBarItemActiveIndicatorWidth: Float? = null,
15
+ val tabBarItemActiveIndicatorHeight: Float? = null,
13
16
  val tabBarItemTitleFontFamily: String? = null,
14
17
  val tabBarItemTitleSmallLabelFontSize: Float? = null,
15
18
  val tabBarItemTitleLargeLabelFontSize: Float? = null,
@@ -2,15 +2,35 @@ package com.swmansion.rnscreens.tabs.container
2
2
 
3
3
  import android.annotation.SuppressLint
4
4
  import android.content.Context
5
+ import androidx.core.view.isVisible
6
+ import com.facebook.react.uimanager.PointerEvents
7
+ import com.facebook.react.uimanager.ReactPointerEventsView
5
8
  import com.google.android.material.bottomnavigation.BottomNavigationView
6
9
 
7
10
  @SuppressLint("ViewConstructor") // Should not be restored & should only be constructed by us.
8
11
  class CustomBottomNavigationView(
9
12
  context: Context,
10
13
  val container: TabsContainer,
11
- ) : BottomNavigationView(context) {
14
+ ) : BottomNavigationView(context),
15
+ ReactPointerEventsView {
12
16
  private var actionOrigin: TabsActionOrigin? = null
13
17
 
18
+ /**
19
+ * The tab bar is hidden by setting its visibility to `GONE`. A `GONE` view is skipped by its
20
+ * parent's layout pass, so it keeps the bounds it was last laid out with, and Android's own
21
+ * touch dispatch ignores it (`ViewGroup.canViewReceivePointerEvents` requires `VISIBLE`).
22
+ *
23
+ * React Native does not go through Android's dispatch to pick a touch target - it runs its own
24
+ * hit-test over the native view tree in `TouchTargetHelper`, which only checks bounds. The
25
+ * retained bounds of the hidden bar therefore keep capturing every touch aimed at the content
26
+ * laid out underneath it. Declaring [PointerEvents.NONE] while hidden is how a native view opts
27
+ * out of that hit-test, which brings it back in line with Android's dispatch.
28
+ *
29
+ * See https://github.com/software-mansion/react-native-screens/issues/4132.
30
+ */
31
+ override val pointerEvents: PointerEvents
32
+ get() = if (isVisible) PointerEvents.AUTO else PointerEvents.NONE
33
+
14
34
  internal fun setSelectedItemIdWithActionOrigin(
15
35
  itemId: Int,
16
36
  actionOrigin: TabsActionOrigin,