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
@@ -21,7 +21,9 @@ import com.swmansion.rnscreens.stack.header.config.StackHeaderConfigurationObser
21
21
  import com.swmansion.rnscreens.stack.header.config.StackHeaderConfigurationProviding
22
22
  import com.swmansion.rnscreens.stack.header.config.StackHeaderDelegate
23
23
  import com.swmansion.rnscreens.stack.header.config.StackHeaderInvalidationFlags
24
+ import com.swmansion.rnscreens.stack.host.StackUpdateBatchStateProviding
24
25
  import com.swmansion.rnscreens.stack.screen.StackScreen
26
+ import java.lang.ref.WeakReference
25
27
 
26
28
  /**
27
29
  * Root CoordinatorLayout for a screen's header: hosts the app bar and the
@@ -33,6 +35,8 @@ internal class StackHeaderCoordinatorLayout(
33
35
  context: Context,
34
36
  internal val stackScreen: StackScreen,
35
37
  private val canNavigateBack: Boolean,
38
+ private val updateBatchStateProvider: WeakReference<StackUpdateBatchStateProviding>,
39
+ parentColorSchemeProvider: WeakReference<ColorSchemeProviding>,
36
40
  private val backPressHandler: StackHeaderBackPressHandler,
37
41
  ) : CoordinatorLayout(context),
38
42
  ColorSchemeProviding {
@@ -63,8 +67,13 @@ internal class StackHeaderCoordinatorLayout(
63
67
 
64
68
  if (provider != null) {
65
69
  provider.setConfigurationObserver(configObserver)
66
- processUpdate(provider)
70
+ // A freshly adopted config is fully dirty by construction: this
71
+ // coordinator has applied nothing of it yet, regardless of what a
72
+ // previous (destroyed) coordinator consumed.
73
+ invalidate(StackHeaderInvalidationFlags.ALL)
74
+ flushPendingUpdates()
67
75
  } else {
76
+ pendingFlags = StackHeaderInvalidationFlags.NONE
68
77
  removeHeader()
69
78
  }
70
79
  }
@@ -74,8 +83,9 @@ internal class StackHeaderCoordinatorLayout(
74
83
  // region Configuration observer
75
84
 
76
85
  private val configObserver =
77
- object : StackHeaderConfigurationObserver {
78
- override fun onConfigChanged(config: StackHeaderConfigurationProviding) = processUpdate(config)
86
+ StackHeaderConfigurationObserver { flags ->
87
+ invalidate(flags)
88
+ flushPendingUpdates()
79
89
  }
80
90
 
81
91
  // endregion
@@ -110,11 +120,12 @@ internal class StackHeaderCoordinatorLayout(
110
120
  StackHeaderFrameSynchronizer.sync(appBar, provider, delegate)
111
121
  }
112
122
 
113
- // Tracks whether the app bar is currently scrolled to its fully collapsed offset. Used to work
114
- // around a Material offset bug when the title/subtitle changes at runtime — see
115
- // StackHeaderApplicator.applyTitleAndSubtitle. This should be equivalent to Material's
116
- // `collapsingTitleHelper.getExpansionFraction() == 1f` condition.
117
- private var isAppBarFullyCollapsed = false
123
+ // Tracks whether the app bar is currently scrolled to its fully collapsed offset, so
124
+ // processUpdate can preserve the collapsed resting state across header updates (rebuilds and
125
+ // re-measures start expanded). This should be equivalent to Material's
126
+ // `collapsingTitleHelper.getExpansionFraction() == 1f` condition. `null` means unknown: no
127
+ // offset has been observed since the header was last removed.
128
+ private var isAppBarFullyCollapsed: Boolean? = null
118
129
 
119
130
  private fun evaluateCollapseState(
120
131
  appBar: AppBarLayout,
@@ -126,6 +137,26 @@ internal class StackHeaderCoordinatorLayout(
126
137
 
127
138
  // endregion
128
139
 
140
+ // region Layout direction
141
+
142
+ // Direction the header was last built against. In order to ensure correct
143
+ // layout and appearance (e.g. back button arrow direction), we rebuild the
144
+ // header on layout direction change.
145
+ private var builtLayoutDirection: Int? = null
146
+
147
+ override fun onRtlPropertiesChanged(layoutDirection: Int) {
148
+ super.onRtlPropertiesChanged(layoutDirection)
149
+
150
+ if (builtLayoutDirection == null || builtLayoutDirection == layoutDirection) {
151
+ return
152
+ }
153
+
154
+ invalidate(StackHeaderInvalidationFlags.STRUCTURE)
155
+ flushPendingUpdates()
156
+ }
157
+
158
+ // endregion
159
+
129
160
  // region Header updates
130
161
 
131
162
  private val wrappedContext =
@@ -142,69 +173,75 @@ internal class StackHeaderCoordinatorLayout(
142
173
  backPressHandler.handleHeaderBackButtonPress(stackScreen)
143
174
  }
144
175
 
145
- private fun processUpdate(
146
- provider: StackHeaderConfigurationProviding,
147
- forcedFlags: StackHeaderInvalidationFlags = StackHeaderInvalidationFlags.NONE,
148
- ) {
149
- val effectiveFlags = provider.invalidationFlags or forcedFlags
150
- val needsRebuild = effectiveFlags.needsRebuild
176
+ private var pendingFlags = StackHeaderInvalidationFlags.NONE
177
+
178
+ private fun invalidate(flags: StackHeaderInvalidationFlags) {
179
+ pendingFlags = pendingFlags or flags
180
+ }
181
+
182
+ internal fun flushPendingUpdates() {
183
+ val provider = currentProvider ?: return
184
+ if (pendingFlags.isEmpty) return
185
+ // Hold the flush while more updates may arrive in the current batch; the container
186
+ // flushes when the batch ends.
187
+ if (updateBatchStateProvider.get()?.isUpdatePending == true) return
188
+ // While detached from window, only accumulate: onAttachedToWindow flushes once, after the
189
+ // color scheme is resolved, so the header is built under the right theme.
190
+ if (!isAttachedToWindow) return
191
+ processUpdate(provider)
192
+ }
193
+
194
+ private fun processUpdate(provider: StackHeaderConfigurationProviding) {
195
+ val flags = pendingFlags
196
+ pendingFlags = StackHeaderInvalidationFlags.NONE
197
+
198
+ val needsRebuild = flags.needsRebuild
199
+ val wasFullyCollapsed = isAppBarFullyCollapsed
200
+
151
201
  if (needsRebuild) {
152
- resetHeader()
153
202
  if (provider.hidden) {
154
- removeContentBehavior()
155
- requestLayout()
156
- provider.clearInvalidationFlags(StackHeaderInvalidationFlags.ALL)
203
+ removeHeader()
157
204
  return
158
205
  }
159
206
 
207
+ resetHeader()
160
208
  val appBar = applicator.rebuild(this, provider)
161
209
  appBarLayout = appBar
210
+ builtLayoutDirection = layoutDirection
162
211
  attachAppBarListeners(appBar)
163
-
164
- // If config needs to be rebuilt, all other flags must be invalidated as well.
165
- provider.clearInvalidationFlags(
166
- StackHeaderInvalidationFlags.STRUCTURE or StackHeaderInvalidationFlags.SUBVIEWS,
167
- )
168
212
  }
169
213
 
170
214
  val appBar = appBarLayout
171
215
  if (appBar != null) {
172
- if (needsRebuild || effectiveFlags.containsAny(StackHeaderInvalidationFlags.TITLE)) {
173
- applicator.applyTitleAndSubtitle(appBar, provider, isAppBarFullyCollapsed)
174
- provider.clearInvalidationFlags(StackHeaderInvalidationFlags.TITLE)
216
+ if (needsRebuild || flags.containsAny(StackHeaderInvalidationFlags.TITLE)) {
217
+ applicator.applyTitleAndSubtitle(appBar, provider)
175
218
  }
176
219
 
177
- if (needsRebuild || effectiveFlags.containsAny(StackHeaderInvalidationFlags.TITLE_APPEARANCE)) {
220
+ if (needsRebuild || flags.containsAny(StackHeaderInvalidationFlags.TITLE_APPEARANCE)) {
178
221
  applicator.applyTitleAndSubtitleAppearance(appBar, provider)
179
- provider.clearInvalidationFlags(StackHeaderInvalidationFlags.TITLE_APPEARANCE)
180
222
  }
181
223
 
182
- if (needsRebuild || effectiveFlags.containsAny(StackHeaderInvalidationFlags.TITLE_POSITIONING)) {
224
+ if (needsRebuild || flags.containsAny(StackHeaderInvalidationFlags.TITLE_POSITIONING)) {
183
225
  applicator.applyTitlePositioning(appBar, provider)
184
- provider.clearInvalidationFlags(StackHeaderInvalidationFlags.TITLE_POSITIONING)
185
226
  }
186
227
 
187
- if (needsRebuild || effectiveFlags.containsAny(StackHeaderInvalidationFlags.CONTENT_INSETS)) {
228
+ if (needsRebuild || flags.containsAny(StackHeaderInvalidationFlags.CONTENT_INSETS)) {
188
229
  applicator.applyContentInsets(appBar, provider)
189
- provider.clearInvalidationFlags(StackHeaderInvalidationFlags.CONTENT_INSETS)
190
230
  }
191
231
 
192
- if (needsRebuild || effectiveFlags.containsAny(StackHeaderInvalidationFlags.BACK_BUTTON)) {
232
+ if (needsRebuild || flags.containsAny(StackHeaderInvalidationFlags.BACK_BUTTON)) {
193
233
  applicator.applyBackButton(appBar.toolbar, provider, canNavigateBack, onNavigationIconClick)
194
- provider.clearInvalidationFlags(StackHeaderInvalidationFlags.BACK_BUTTON)
195
234
  }
196
235
 
197
- if (needsRebuild || effectiveFlags.containsAny(StackHeaderInvalidationFlags.SCROLL_FLAGS)) {
236
+ if (needsRebuild || flags.containsAny(StackHeaderInvalidationFlags.SCROLL_FLAGS)) {
198
237
  applicator.applyScrollFlags(appBar, provider)
199
- provider.clearInvalidationFlags(StackHeaderInvalidationFlags.SCROLL_FLAGS)
200
238
  }
201
239
 
202
- if (needsRebuild || effectiveFlags.containsAny(StackHeaderInvalidationFlags.BACKGROUND_COLORS)) {
240
+ if (needsRebuild || flags.containsAny(StackHeaderInvalidationFlags.BACKGROUND_COLORS)) {
203
241
  applicator.applyBackgroundColors(appBar, provider)
204
- provider.clearInvalidationFlags(StackHeaderInvalidationFlags.BACKGROUND_COLORS)
205
242
  }
206
243
 
207
- if (needsRebuild || effectiveFlags.containsAny(StackHeaderInvalidationFlags.LIFT_ON_SCROLL)) {
244
+ if (needsRebuild || flags.containsAny(StackHeaderInvalidationFlags.LIFT_ON_SCROLL)) {
208
245
  // Lift-on-scroll is disabled in transparent mode: there is no content
209
246
  // scrolling behavior installed and the app bar overlays the content.
210
247
  applicator.applyLiftOnScroll(
@@ -212,28 +249,43 @@ internal class StackHeaderCoordinatorLayout(
212
249
  enabled = provider.liftOnScroll && !provider.transparent,
213
250
  targetScrollView = stackScreen.findContentScrollView(),
214
251
  )
215
- provider.clearInvalidationFlags(StackHeaderInvalidationFlags.LIFT_ON_SCROLL)
216
252
  }
217
253
 
218
- if (needsRebuild || effectiveFlags.containsAny(StackHeaderInvalidationFlags.TOOLBAR_MENU)) {
254
+ if (needsRebuild || flags.containsAny(StackHeaderInvalidationFlags.TOOLBAR_MENU)) {
219
255
  provider.toolbarMenuController.attach(appBar.toolbar)
220
- provider.clearInvalidationFlags(StackHeaderInvalidationFlags.TOOLBAR_MENU)
221
256
  }
222
257
 
223
- if (needsRebuild || effectiveFlags.containsAny(StackHeaderInvalidationFlags.OVERFLOW_ICON)) {
258
+ if (needsRebuild || flags.containsAny(StackHeaderInvalidationFlags.OVERFLOW_ICON)) {
224
259
  applicator.applyOverflowIcon(appBar.toolbar, provider)
225
- provider.clearInvalidationFlags(StackHeaderInvalidationFlags.OVERFLOW_ICON)
260
+ }
261
+
262
+ // A rebuilt or re-measured app bar starts expanded; re-assert the fully-collapsed
263
+ // resting state so a scrolled-down screen doesn't jump. When the state is unknown
264
+ // (the header was removed — hidden, config detach), infer it from the content:
265
+ // scrolled content implies the bar was collapsed. A pending action, so it wins
266
+ // over applyScrollFlags' expand snap, and it resolves against the new configuration —
267
+ // degrading to expanded when the header can no longer collapse. Fractional offsets
268
+ // reset to expanded.
269
+ if (wasFullyCollapsed ?: isContentScrolled()) {
270
+ appBar.setExpanded(false, false)
226
271
  }
227
272
  }
228
273
 
229
274
  onMaybeHeaderLayoutChanged()
230
275
  }
231
276
 
277
+ // If the scroll view hasn't reached the top, we consider it scrolled.
278
+ private fun isContentScrolled() = stackScreen.findContentScrollView()?.canScrollVertically(-1) == true
279
+
232
280
  // endregion
233
281
 
234
282
  // region Color scheme
235
283
 
236
- private val colorSchemeCoordinator = ColorSchemeCoordinator()
284
+ // As the fragment's root view, this layout gets reparented into the container's
285
+ // ViewGroupOverlay for exit transitions, where a parent walk finds no provider -
286
+ // hence the ownership-injected one.
287
+ private val colorSchemeCoordinator =
288
+ ColorSchemeCoordinator().apply { explicitParentProvider = parentColorSchemeProvider }
237
289
 
238
290
  // Night mode the header visuals were last applied against. Unlike the coordinator's
239
291
  // internal dedupe (reset on every setup()), this survives detach/reattach, skipping
@@ -252,7 +304,14 @@ internal class StackHeaderCoordinatorLayout(
252
304
 
253
305
  override fun onAttachedToWindow() {
254
306
  super.onAttachedToWindow()
307
+ // Resolve the color scheme before flushing, so a deferred first build happens under the
308
+ // pinned theme (a scheme change inside setup() flushes by itself; the trailing flush then
309
+ // no-ops).
255
310
  colorSchemeCoordinator.setup(this) { applyUiNightMode(it) }
311
+ // AppBarLayout clears its liftOnScrollTargetView on window detach and never re-resolves
312
+ // it; re-apply on every attach.
313
+ invalidate(StackHeaderInvalidationFlags.LIFT_ON_SCROLL)
314
+ flushPendingUpdates()
256
315
  }
257
316
 
258
317
  override fun onDetachedFromWindow() {
@@ -274,18 +333,11 @@ internal class StackHeaderCoordinatorLayout(
274
333
  }
275
334
 
276
335
  appliedUiNightMode = uiNightMode
277
- currentProvider?.let {
278
- // A rebuild is forced because MaterialToolbar snapshots its theme at construction:
279
- // ripples, the overflow popup and menu item views resolve from that frozen copy, so
280
- // only view recreation refreshes them.
281
- val wasFullyCollapsed = isAppBarFullyCollapsed
282
- processUpdate(it, forcedFlags = StackHeaderInvalidationFlags.STRUCTURE)
283
- // The rebuilt app bar starts expanded; restore the fully-collapsed resting state
284
- // so a scrolled-down screen doesn't jump. Fractional offsets reset.
285
- if (wasFullyCollapsed) {
286
- appBarLayout?.setExpanded(false, false)
287
- }
288
- }
336
+ // A rebuild is needed because MaterialToolbar snapshots its theme at construction:
337
+ // ripples, the overflow popup and menu item views resolve from that frozen copy, so
338
+ // only view recreation refreshes them.
339
+ invalidate(StackHeaderInvalidationFlags.STRUCTURE)
340
+ flushPendingUpdates()
289
341
  }
290
342
 
291
343
  // endregion
@@ -298,13 +350,13 @@ internal class StackHeaderCoordinatorLayout(
298
350
  removeView(it)
299
351
  }
300
352
  appBarLayout = null
301
- // A rebuilt header starts fully expanded; drop any stale collapsed state from the old one.
302
- isAppBarFullyCollapsed = false
303
353
  currentProvider?.toolbarMenuController?.detach()
304
354
  }
305
355
 
306
356
  private fun removeHeader() {
307
357
  resetHeader()
358
+ isAppBarFullyCollapsed = null
359
+ builtLayoutDirection = null
308
360
  removeContentBehavior()
309
361
  requestLayout()
310
362
  }
@@ -383,6 +435,7 @@ internal class StackHeaderCoordinatorLayout(
383
435
  internal fun tearDown() {
384
436
  colorSchemeCoordinator.teardown()
385
437
 
438
+ pendingFlags = StackHeaderInvalidationFlags.NONE
386
439
  removeHeader()
387
440
 
388
441
  stackScreenWrapper.removeView(stackScreen)
@@ -117,7 +117,7 @@ internal sealed class StackHeaderAppBarLayout(
117
117
  collapsedTitleGravityMode: StackHeaderCollapsedTitleGravityMode,
118
118
  ) : StackHeaderAppBarLayout(context) {
119
119
  override val toolbar =
120
- MaterialToolbar(context).apply {
120
+ StackHeaderToolbar(context).apply {
121
121
  elevation = 0f
122
122
  layoutParams =
123
123
  CollapsingToolbarLayout
@@ -0,0 +1,74 @@
1
+ package com.swmansion.rnscreens.stack.header.appbar
2
+
3
+ import android.content.Context
4
+ import android.view.Gravity
5
+ import android.view.View
6
+ import android.view.ViewGroup.LayoutParams.MATCH_PARENT
7
+ import com.google.android.material.appbar.MaterialToolbar
8
+ import com.swmansion.rnscreens.stack.header.subview.StackHeaderSubview
9
+
10
+ /**
11
+ * Toolbar of a collapsing header. It exists to change the gravity of the
12
+ * placeholder view that CollapsingToolbarLayout adds to the toolbar, so that
13
+ * custom subview layout under RTL is correct.
14
+ *
15
+ * CollapsingToolbarLayout tracks the area the collapsed title is drawn in by
16
+ * adding a placeholder view with MATCH_PARENT layout params to the toolbar -
17
+ * the view itself doesn't draw the title, it is only measured. The placeholder
18
+ * inherits the toolbar's default START gravity, which is the same layout group
19
+ * our leading subview goes into. The toolbar walks that group in reverse child
20
+ * order under RTL, so the placeholder is positioned first and takes over the
21
+ * whole layout cursor, leaving the collapsed title drawn over the trailing
22
+ * subview and the toolbar menu. CENTER_HORIZONTAL moves it to the group the
23
+ * toolbar positions last, clamped into what the other children left over, which
24
+ * is the correct rect in both directions.
25
+ *
26
+ * See https://github.com/material-components/material-components-android/issues/1867.
27
+ */
28
+ internal class StackHeaderToolbar(
29
+ context: Context,
30
+ ) : MaterialToolbar(context) {
31
+ private var hasCollapsedTitlePlaceholder = false
32
+
33
+ override fun onViewAdded(child: View) {
34
+ super.onViewAdded(child)
35
+
36
+ val params = child.layoutParams as LayoutParams
37
+ if (!isCollapsedTitlePlaceholder(child, params)) {
38
+ return
39
+ }
40
+
41
+ params.gravity = Gravity.CENTER_HORIZONTAL or Gravity.CENTER_VERTICAL
42
+ hasCollapsedTitlePlaceholder = true
43
+ }
44
+
45
+ /**
46
+ * The placeholder is not identifiable by type - it is a plain [View] - so it is recognized by
47
+ * its size instead. Every view the toolbar builds for itself (navigation & collapse buttons,
48
+ * menu, logo, expanded action view) is WRAP_CONTENT, and so are the subviews we add, which
49
+ * leaves a MATCH_PARENT child of a foreign type as the placeholder and nothing else.
50
+ */
51
+ private fun isCollapsedTitlePlaceholder(
52
+ child: View,
53
+ params: LayoutParams,
54
+ ): Boolean =
55
+ child !is StackHeaderSubview &&
56
+ params.width == MATCH_PARENT &&
57
+ params.height == MATCH_PARENT
58
+
59
+ override fun onLayout(
60
+ changed: Boolean,
61
+ l: Int,
62
+ t: Int,
63
+ r: Int,
64
+ b: Int,
65
+ ) {
66
+ // The placeholder is added from CollapsingToolbarLayout.onMeasure, which always precedes
67
+ // our layout. Holds as long as the collapsing layout keeps its title enabled.
68
+ check(hasCollapsedTitlePlaceholder) {
69
+ "[RNScreens] CollapsingToolbarLayout did not add its collapsed title placeholder."
70
+ }
71
+
72
+ super.onLayout(changed, l, t, r, b)
73
+ }
74
+ }
@@ -2,19 +2,13 @@ package com.swmansion.rnscreens.stack.header.config
2
2
 
3
3
  import android.annotation.SuppressLint
4
4
  import android.graphics.drawable.Drawable
5
- import android.util.LayoutDirection
6
5
  import android.view.Gravity
7
- import com.facebook.react.bridge.UIManager
8
- import com.facebook.react.bridge.UIManagerListener
9
- import com.facebook.react.common.annotations.UnstableReactNativeAPI
10
6
  import com.facebook.react.uimanager.ThemedReactContext
11
- import com.facebook.react.uimanager.UIManagerHelper
12
7
  import com.facebook.react.views.view.ReactViewGroup
13
8
  import com.swmansion.rnscreens.common.ShadowStateProxy
14
9
  import com.swmansion.rnscreens.common.text.ReactTextAppearance
15
10
  import com.swmansion.rnscreens.helpers.IconResolution
16
11
  import com.swmansion.rnscreens.helpers.PropIconResolver
17
- import com.swmansion.rnscreens.helpers.getFabricUIManagerNotNull
18
12
  import com.swmansion.rnscreens.helpers.resolveImage
19
13
  import com.swmansion.rnscreens.stack.header.subview.OnStackHeaderSubviewChangeListener
20
14
  import com.swmansion.rnscreens.stack.header.subview.StackHeaderSubview
@@ -27,7 +21,6 @@ import com.swmansion.rnscreens.stack.header.toolbar.update.StackHeaderToolbarMen
27
21
  import java.lang.ref.WeakReference
28
22
  import kotlin.properties.Delegates
29
23
 
30
- @OptIn(UnstableReactNativeAPI::class)
31
24
  @SuppressLint("ViewConstructor")
32
25
  internal class StackHeaderConfig(
33
26
  val reactContext: ThemedReactContext,
@@ -35,14 +28,7 @@ internal class StackHeaderConfig(
35
28
  StackHeaderConfigurationProviding,
36
29
  StackHeaderDelegate,
37
30
  StackHeaderToolbarMenuDelegate,
38
- OnStackHeaderSubviewChangeListener,
39
- UIManagerListener {
40
- init {
41
- UIManagerHelper
42
- .getFabricUIManagerNotNull(reactContext)
43
- .addUIManagerEventListener(this)
44
- }
45
-
31
+ OnStackHeaderSubviewChangeListener {
46
32
  // region Handling configuration changes
47
33
 
48
34
  private var configObserver: StackHeaderConfigurationObserver? = null
@@ -51,22 +37,8 @@ internal class StackHeaderConfig(
51
37
  configObserver = observer
52
38
  }
53
39
 
54
- override var invalidationFlags = StackHeaderInvalidationFlags.ALL
55
-
56
- override fun clearInvalidationFlags(flags: StackHeaderInvalidationFlags) {
57
- invalidationFlags = invalidationFlags.clearing(flags)
58
- }
59
-
60
40
  private fun invalidate(flags: StackHeaderInvalidationFlags) {
61
- invalidationFlags = invalidationFlags or flags
62
- }
63
-
64
- private fun flushUpdates() {
65
- if (configObserver == null || invalidationFlags.isEmpty) {
66
- return
67
- }
68
-
69
- configObserver?.onConfigChanged(this)
41
+ configObserver?.onInvalidated(flags)
70
42
  }
71
43
 
72
44
  // endregion
@@ -188,9 +160,6 @@ internal class StackHeaderConfig(
188
160
 
189
161
  private fun invalidateTextAppearance() = invalidate(StackHeaderInvalidationFlags.TITLE_APPEARANCE)
190
162
 
191
- override val isRTL: Boolean
192
- get() = layoutDirection == LayoutDirection.RTL
193
-
194
163
  // endregion
195
164
 
196
165
  // region Content scroll view
@@ -203,9 +172,6 @@ internal class StackHeaderConfig(
203
172
  */
204
173
  internal fun onContentScrollViewChanged() {
205
174
  invalidate(StackHeaderInvalidationFlags.LIFT_ON_SCROLL)
206
- if (!isInsideMountTransaction) {
207
- flushUpdates()
208
- }
209
175
  }
210
176
 
211
177
  // endregion
@@ -226,12 +192,7 @@ internal class StackHeaderConfig(
226
192
  ) { result ->
227
193
  when (result) {
228
194
  IconResolution.Unchanged -> Unit
229
- is IconResolution.Resolved -> {
230
- backButtonIcon = result.drawable
231
- if (!isInsideMountTransaction) {
232
- flushUpdates()
233
- }
234
- }
195
+ is IconResolution.Resolved -> backButtonIcon = result.drawable
235
196
  }
236
197
  }
237
198
  }
@@ -253,12 +214,7 @@ internal class StackHeaderConfig(
253
214
  ) { result ->
254
215
  when (result) {
255
216
  IconResolution.Unchanged -> Unit
256
- is IconResolution.Resolved -> {
257
- overflowIcon = result.drawable
258
- if (!isInsideMountTransaction) {
259
- flushUpdates()
260
- }
261
- }
217
+ is IconResolution.Resolved -> overflowIcon = result.drawable
262
218
  }
263
219
  }
264
220
  }
@@ -407,35 +363,10 @@ internal class StackHeaderConfig(
407
363
 
408
364
  // endregion
409
365
 
410
- // region UIManagerListener
411
-
412
- private var isInsideMountTransaction = false
413
-
414
- override fun willMountItems(uiManager: UIManager) {
415
- isInsideMountTransaction = true
416
- }
417
-
418
- override fun didMountItems(uiManager: UIManager) {
419
- isInsideMountTransaction = false
420
- flushUpdates()
421
- }
422
-
423
- override fun willDispatchViewUpdates(uiManager: UIManager) = Unit
424
-
425
- override fun didDispatchMountItems(uiManager: UIManager) = Unit
426
-
427
- override fun didScheduleMountItems(uiManager: UIManager) = Unit
428
-
429
- // endregion
430
-
431
366
  // region Teardown
432
367
 
433
368
  internal fun tearDown() {
434
- UIManagerHelper
435
- .getFabricUIManagerNotNull(reactContext)
436
- .removeUIManagerEventListener(this)
437
369
  toolbarMenuController.tearDown()
438
- invalidationFlags = StackHeaderInvalidationFlags.NONE
439
370
  configObserver = null
440
371
  }
441
372
 
@@ -1,5 +1,8 @@
1
1
  package com.swmansion.rnscreens.stack.header.config
2
2
 
3
- internal interface StackHeaderConfigurationObserver {
4
- fun onConfigChanged(config: StackHeaderConfigurationProviding)
3
+ internal fun interface StackHeaderConfigurationObserver {
4
+ /**
5
+ * Reports that the parts of the configuration described by [flags] changed.
6
+ */
7
+ fun onInvalidated(flags: StackHeaderInvalidationFlags)
5
8
  }
@@ -55,11 +55,5 @@ internal interface StackHeaderConfigurationProviding {
55
55
  val expandedSubtitleAppearance: TextAppearance
56
56
  val collapsedSubtitleAppearance: TextAppearance
57
57
 
58
- val isRTL: Boolean
59
-
60
- val invalidationFlags: StackHeaderInvalidationFlags
61
-
62
- fun clearInvalidationFlags(flags: StackHeaderInvalidationFlags)
63
-
64
58
  fun setConfigurationObserver(observer: StackHeaderConfigurationObserver?)
65
59
  }
@@ -18,19 +18,15 @@ internal value class StackHeaderInvalidationFlags(
18
18
  val TITLE_APPEARANCE = StackHeaderInvalidationFlags(1 shl 9)
19
19
  val CONTENT_INSETS = StackHeaderInvalidationFlags(1 shl 10)
20
20
  val BACKGROUND_COLORS = StackHeaderInvalidationFlags(1 shl 11)
21
- val APPEARANCE =
22
- TITLE or BACK_BUTTON or OVERFLOW_ICON or TITLE_POSITIONING or TITLE_APPEARANCE or CONTENT_INSETS or BACKGROUND_COLORS
23
- val ALL = STRUCTURE or SUBVIEWS or APPEARANCE or SCROLL_FLAGS or TOOLBAR_MENU or LIFT_ON_SCROLL
21
+ val ALL =
22
+ STRUCTURE or SUBVIEWS or TITLE or BACK_BUTTON or SCROLL_FLAGS or TOOLBAR_MENU or LIFT_ON_SCROLL or
23
+ OVERFLOW_ICON or TITLE_POSITIONING or TITLE_APPEARANCE or CONTENT_INSETS or BACKGROUND_COLORS
24
24
  }
25
25
 
26
26
  infix fun or(other: StackHeaderInvalidationFlags) = StackHeaderInvalidationFlags(raw or other.raw)
27
27
 
28
28
  fun containsAny(flags: StackHeaderInvalidationFlags) = flags.raw != 0 && (raw and flags.raw) != 0
29
29
 
30
- fun clearing(flags: StackHeaderInvalidationFlags) = StackHeaderInvalidationFlags(raw and flags.raw.inv())
31
-
32
- val isNotEmpty get() = raw != 0
33
-
34
30
  val isEmpty get() = raw == 0
35
31
 
36
32
  val needsRebuild get() = containsAny(STRUCTURE or SUBVIEWS)
@@ -14,6 +14,7 @@ internal class AddAndSetAsPrimaryOp(
14
14
  val fragment: StackScreenFragment,
15
15
  val containerViewId: Int,
16
16
  val addToBackStack: Boolean,
17
+ val coveredFragment: StackScreenFragment?,
17
18
  val allowStateLoss: Boolean = true,
18
19
  ) : FragmentOperation() {
19
20
  override fun execute(
@@ -2,7 +2,7 @@ package com.swmansion.rnscreens.stack.host
2
2
 
3
3
  import androidx.fragment.app.FragmentManager
4
4
  import androidx.fragment.app.FragmentTransaction
5
- import com.swmansion.rnscreens.helpers.createTransactionWithReordering
5
+ import com.swmansion.rnscreens.ext.createTransactionWithReordering
6
6
 
7
7
  internal class FragmentOperationExecutor {
8
8
  internal fun executeOperations(
@@ -26,6 +26,7 @@ internal class FragmentOperationExecutor {
26
26
  tx.addToBackStack(op.fragment.stackScreen.screenKey)
27
27
  }
28
28
  tx.add(op.containerViewId, op.fragment)
29
+ op.coveredFragment?.let { tx.detach(it) }
29
30
  tx.setPrimaryNavigationFragment(op.fragment)
30
31
  commitTransaction(tx, op.allowStateLoss)
31
32
  }