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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (585) hide show
  1. package/Package.swift +87 -0
  2. package/README.md +0 -8
  3. package/RNScreens.podspec +2 -6
  4. package/android/build.gradle +26 -1
  5. package/android/src/fabric/java/com/swmansion/rnscreens/NativeProxy.kt +5 -0
  6. package/android/src/main/cpp/NativeProxy.cpp +30 -6
  7. package/android/src/main/cpp/NativeProxy.h +7 -1
  8. package/android/src/main/java/com/swmansion/rnscreens/RNScreensPackage.kt +2 -2
  9. package/android/src/main/java/com/swmansion/rnscreens/common/container/Container.kt +8 -0
  10. package/android/src/main/java/com/swmansion/rnscreens/common/container/ContainerItem.kt +13 -1
  11. package/android/src/main/java/com/swmansion/rnscreens/common/text/ReactTextAppearance.kt +62 -0
  12. package/android/src/main/java/com/swmansion/rnscreens/common/text/TextAppearance.kt +20 -0
  13. package/android/src/main/java/com/swmansion/rnscreens/common/text/TextAppearanceDefaults.kt +65 -0
  14. package/android/src/main/java/com/swmansion/rnscreens/helpers/PropIconResolver.kt +17 -23
  15. package/android/src/main/java/com/swmansion/rnscreens/legacy/Screen.kt +25 -7
  16. package/android/src/main/java/com/swmansion/rnscreens/legacy/ScreenStack.kt +2 -0
  17. package/android/src/main/java/com/swmansion/rnscreens/legacy/ScreenStackFragment.kt +39 -10
  18. package/android/src/main/java/com/swmansion/rnscreens/legacy/ScreenViewManager.kt +5 -0
  19. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetAppearanceCoordinator.kt → native/coordinator/FormSheetAppearanceCoordinator.kt} +2 -1
  20. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetBehaviorController.kt → native/coordinator/FormSheetBehaviorController.kt} +74 -19
  21. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/coordinator/FormSheetDimensionsCoordinator.kt +159 -0
  22. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/coordinator/FormSheetKeyboardCoordinator.kt +101 -0
  23. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/coordinator/FormSheetNativeDismissCoordinator.kt +44 -0
  24. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/core/FormSheetAvailableHeightProvider.kt +44 -0
  25. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetContainer.kt → native/core/FormSheetContainer.kt} +1 -1
  26. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/core/FormSheetDialog.kt +115 -0
  27. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/core/FormSheetDialogManager.kt +89 -0
  28. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetContentSizeChangeDelegate.kt → native/interfaces/FormSheetContentSizeChangeDelegate.kt} +1 -1
  29. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetContentSizeChangeProvider.kt → native/interfaces/FormSheetContentSizeChangeProvider.kt} +1 -1
  30. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetDialogEventEmitter.kt → native/interfaces/FormSheetDialogEventEmitter.kt} +5 -1
  31. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetConfig.kt → native/model/FormSheetConfig.kt} +5 -1
  32. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/model/FormSheetDetents.kt +152 -0
  33. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetAnimatorFactory.kt → native/presentation/FormSheetAnimatorFactory.kt} +9 -10
  34. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetDimmingManager.kt +115 -0
  35. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetDismissalOrigin.kt +22 -0
  36. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetPresentation.kt +173 -0
  37. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetPresentationManager.kt +290 -0
  38. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetPresentationState.kt → native/presentation/FormSheetPresentationState.kt} +2 -2
  39. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetStackRegistry.kt +28 -0
  40. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetContentWrapper.kt → react/contentwrapper/FormSheetContentWrapper.kt} +3 -1
  41. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetContentWrapperViewManager.kt → react/contentwrapper/FormSheetContentWrapperViewManager.kt} +1 -1
  42. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetDetentChangedEvent.kt → react/event/FormSheetDetentChangedEvent.kt} +1 -1
  43. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetDidAppearEvent.kt → react/event/FormSheetDidAppearEvent.kt} +1 -1
  44. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetDidDisappearEvent.kt → react/event/FormSheetDidDisappearEvent.kt} +1 -1
  45. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/react/event/FormSheetDismissEvent.kt +29 -0
  46. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetNativeDismissEvent.kt → react/event/FormSheetNativeDismissEvent.kt} +1 -1
  47. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/react/event/FormSheetNativeDismissPreventedEvent.kt +29 -0
  48. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetSyncFlushEvent.kt → react/event/FormSheetSyncFlushEvent.kt} +1 -1
  49. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetWillAppearEvent.kt → react/event/FormSheetWillAppearEvent.kt} +1 -1
  50. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetWillDisappearEvent.kt → react/event/FormSheetWillDisappearEvent.kt} +1 -1
  51. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetContentView.kt → react/host/FormSheetContentView.kt} +3 -1
  52. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetHost.kt → react/host/FormSheetHost.kt} +6 -1
  53. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetHostEventEmitter.kt → react/host/FormSheetHostEventEmitter.kt} +23 -1
  54. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/{FormSheetHostViewManager.kt → react/host/FormSheetHostViewManager.kt} +13 -2
  55. package/android/src/main/java/com/swmansion/rnscreens/stack/header/StackHeaderApplicator.kt +380 -457
  56. package/android/src/main/java/com/swmansion/rnscreens/stack/header/StackHeaderBackPressHandler.kt +11 -0
  57. package/android/src/main/java/com/swmansion/rnscreens/stack/header/StackHeaderCoordinatorLayout.kt +150 -182
  58. package/android/src/main/java/com/swmansion/rnscreens/stack/header/StackHeaderFrameSynchronizer.kt +63 -0
  59. package/android/src/main/java/com/swmansion/rnscreens/stack/header/appbar/StackHeaderAppBarLayout.kt +240 -0
  60. package/android/src/main/java/com/swmansion/rnscreens/stack/header/{StackHeaderAppBarLayoutBehavior.kt → appbar/StackHeaderAppBarLayoutBehavior.kt} +1 -1
  61. package/android/src/main/java/com/swmansion/rnscreens/stack/header/appbar/StackHeaderContentScrimDrawable.kt +36 -0
  62. package/android/src/main/java/com/swmansion/rnscreens/stack/header/{StackHeaderScrollingViewBehavior.kt → appbar/StackHeaderScrollingViewBehavior.kt} +1 -1
  63. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderCollapsedTitleGravityMode.kt +6 -0
  64. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderConfig.kt +192 -167
  65. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderConfigViewManager.kt +393 -13
  66. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderConfigurationObserver.kt +0 -4
  67. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderConfigurationProviding.kt +33 -3
  68. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderDelegate.kt +0 -7
  69. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderInvalidationFlags.kt +9 -3
  70. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/StackHeaderToolbarMenuApplicator.kt +195 -0
  71. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/StackHeaderToolbarMenuController.kt +448 -0
  72. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/StackHeaderToolbarMenuDelegate.kt +10 -0
  73. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/StackHeaderToolbarMenuMapper.kt +43 -21
  74. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/model/StackHeaderToolbarMenuConfig.kt +8 -0
  75. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/{StackHeaderToolbarMenuElementConfig.kt → model/StackHeaderToolbarMenuElementConfig.kt} +1 -1
  76. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/{StackHeaderToolbarMenuGroupConfig.kt → model/StackHeaderToolbarMenuGroupConfig.kt} +1 -1
  77. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/model/StackHeaderToolbarMenuGroupMetadata.kt +11 -0
  78. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/{StackHeaderToolbarMenuItemConfig.kt → model/StackHeaderToolbarMenuItemConfig.kt} +2 -4
  79. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/{StackHeaderToolbarMenuItemDefaults.kt → model/StackHeaderToolbarMenuItemDefaults.kt} +1 -1
  80. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/{StackHeaderToolbarMenuItemIconSource.kt → model/StackHeaderToolbarMenuItemIconSource.kt} +1 -1
  81. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/{StackHeaderToolbarMenuItemShowAsAction.kt → model/StackHeaderToolbarMenuItemShowAsAction.kt} +1 -1
  82. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/{StackHeaderToolbarMenuItemType.kt → model/StackHeaderToolbarMenuItemType.kt} +1 -1
  83. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/model/StackHeaderToolbarMenuModel.kt +180 -0
  84. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/{StackHeaderToolbarFieldUpdate.kt → update/StackHeaderToolbarFieldUpdate.kt} +1 -1
  85. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/update/StackHeaderToolbarMenuElementOptions.kt +84 -0
  86. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/update/StackHeaderToolbarMenuElementRawUpdate.kt +15 -0
  87. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/update/StackHeaderToolbarMenuElementUpdate.kt +11 -0
  88. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/update/StackHeaderToolbarMenuIconResolver.kt +18 -0
  89. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/{StackHeaderToolbarMenuUpdateQueue.kt → update/StackHeaderToolbarMenuUpdateQueue.kt} +24 -52
  90. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/update/StackHeaderToolbarMenuUpdateQueueDelegate.kt +9 -0
  91. package/android/src/main/java/com/swmansion/rnscreens/stack/host/StackContainer.kt +103 -3
  92. package/android/src/main/java/com/swmansion/rnscreens/stack/host/StackHost.kt +13 -0
  93. package/android/src/main/java/com/swmansion/rnscreens/stack/host/StackHostViewManager.kt +14 -0
  94. package/android/src/main/java/com/swmansion/rnscreens/stack/screen/StackScreen.kt +5 -0
  95. package/android/src/main/java/com/swmansion/rnscreens/stack/screen/StackScreenFragment.kt +20 -1
  96. package/android/src/main/java/com/swmansion/rnscreens/stack/screen/StackScreenFragmentDelegate.kt +12 -0
  97. package/android/src/main/java/com/swmansion/rnscreens/tabs/appearance/TabsAppearanceCoordinator.kt +2 -4
  98. package/android/src/main/java/com/swmansion/rnscreens/tabs/container/MenuHelpers.kt +5 -23
  99. package/android/src/main/java/com/swmansion/rnscreens/tabs/container/TabsContainer.kt +46 -25
  100. package/android/src/main/java/com/swmansion/rnscreens/tabs/host/TabsHost.kt +10 -0
  101. package/android/src/main/java/com/swmansion/rnscreens/tabs/host/TabsHostA11yCoordinator.kt +23 -2
  102. package/android/src/main/java/com/swmansion/rnscreens/tabs/screen/TabsScreen.kt +17 -0
  103. package/android/src/main/java/com/swmansion/rnscreens/tabs/screen/TabsScreenFragment.kt +3 -0
  104. package/android/src/main/java/com/swmansion/rnscreens/utils/DimensionUtils.kt +7 -0
  105. package/android/src/main/java/com/swmansion/rnscreens/utils/StyleUtils.kt +22 -0
  106. package/android/src/main/res/base/layout/rns_collapsing_toolbar_large_available_space.xml +8 -0
  107. package/android/src/main/res/base/layout/rns_collapsing_toolbar_large_entire_space.xml +8 -0
  108. package/android/src/main/res/base/layout/rns_collapsing_toolbar_medium_available_space.xml +8 -0
  109. package/android/src/main/res/base/layout/rns_collapsing_toolbar_medium_entire_space.xml +8 -0
  110. package/common/cpp/react/renderer/components/rnscreens/legacy/RNSScreenShadowNode.cpp +10 -5
  111. package/cpp/legacy/RNSScreenRemovalListener.cpp +31 -1
  112. package/cpp/legacy/RNSScreenRemovalListener.h +18 -3
  113. package/ios/RNSEnums.h +2 -2
  114. package/ios/RNSOrientationProviding.h +0 -2
  115. package/ios/RNSReactMountingTransactionObserving.h +15 -0
  116. package/ios/conversion/RNSConversions.h +7 -108
  117. package/ios/legacy/RNSBarButtonItem.mm +12 -5
  118. package/ios/legacy/RNSFullWindowOverlay.mm +1 -1
  119. package/ios/legacy/RNSModalScreen.mm +1 -1
  120. package/ios/legacy/RNSScreen.h +8 -1
  121. package/ios/legacy/RNSScreen.mm +47 -36
  122. package/ios/legacy/RNSScreenContentWrapper.mm +9 -0
  123. package/ios/legacy/RNSScreenFooter.mm +2 -0
  124. package/ios/legacy/RNSScreenStack.mm +9 -4
  125. package/ios/legacy/RNSScreenStackHeaderConfig.mm +3 -1
  126. package/ios/legacy/RNSScreenStackHeaderSubview.mm +1 -1
  127. package/ios/legacy/RNSScreenWindowTraits.mm +5 -13
  128. package/ios/modals/form-sheet/RNSFormSheetConfigurationApplicator.h +1 -3
  129. package/ios/modals/form-sheet/RNSFormSheetConfigurationApplicator.mm +11 -22
  130. package/ios/modals/form-sheet/RNSFormSheetContentController.h +1 -1
  131. package/ios/modals/form-sheet/RNSFormSheetContentController.mm +7 -18
  132. package/ios/modals/form-sheet/RNSFormSheetContentWrapperComponentView.mm +9 -0
  133. package/ios/modals/form-sheet/RNSFormSheetHostComponentView.mm +4 -4
  134. package/ios/modals/form-sheet/RNSFormSheetHostShadowStateProxy.mm +2 -2
  135. package/ios/modals/form-sheet/RNSFormSheetUpdateFlags.h +3 -0
  136. package/ios/safe-area/RNSSafeAreaViewComponentView.mm +2 -2
  137. package/ios/scroll-to-top-guard/RNSScrollToTopGuard.h +17 -0
  138. package/ios/scroll-to-top-guard/RNSScrollToTopGuard.mm +57 -0
  139. package/ios/scroll-to-top-guard/RNSScrollToTopGuardGestureRecognizer.h +28 -0
  140. package/ios/scroll-to-top-guard/RNSScrollToTopGuardGestureRecognizer.mm +64 -0
  141. package/ios/{conversion → scroll-view-marker/conversion}/RNSConversions-ScrollViewMarker.mm +2 -3
  142. package/ios/split/RNSSplitAppearanceApplicator.h +36 -0
  143. package/ios/split/RNSSplitAppearanceApplicator.mm +182 -0
  144. package/ios/split/RNSSplitAppearanceCoordinator.h +26 -0
  145. package/ios/split/RNSSplitAppearanceCoordinator.mm +27 -0
  146. package/ios/split/RNSSplitAppearanceUpdateFlags.h +14 -0
  147. package/ios/split/RNSSplitHostComponentEventEmitter.h +1 -0
  148. package/ios/split/RNSSplitHostComponentEventEmitter.mm +1 -1
  149. package/ios/split/RNSSplitHostComponentView.h +5 -15
  150. package/ios/split/RNSSplitHostComponentView.mm +56 -7
  151. package/ios/split/RNSSplitHostController.h +105 -0
  152. package/ios/split/RNSSplitHostController.mm +492 -0
  153. package/ios/split/RNSSplitHostProviders.h +67 -0
  154. package/ios/split/RNSSplitNavigationController.h +31 -0
  155. package/ios/split/RNSSplitNavigationController.mm +44 -0
  156. package/ios/split/RNSSplitNavigationControllerFrameObserver.h +32 -0
  157. package/ios/split/RNSSplitNavigationControllerFrameObserver.mm +80 -0
  158. package/ios/split/RNSSplitNavigationControllerFrameOriginChangeDelegate.h +15 -0
  159. package/ios/split/RNSSplitScreenComponentView.h +0 -39
  160. package/ios/split/RNSSplitScreenComponentView.mm +35 -19
  161. package/ios/split/RNSSplitScreenController.h +68 -0
  162. package/ios/split/RNSSplitScreenController.mm +113 -0
  163. package/ios/split/RNSSplitScreenShadowStateProxy.h +1 -40
  164. package/ios/split/RNSSplitScreenShadowStateProxy.mm +1 -26
  165. package/ios/split/conversion/RNSConversions-SplitView.h +56 -0
  166. package/ios/{conversion → split/conversion}/RNSConversions-SplitView.mm +4 -1
  167. package/ios/stack/conversion/RNSConversions-Stack.h +32 -0
  168. package/ios/stack/conversion/RNSConversions-Stack.mm +55 -0
  169. package/ios/stack/header/RNSStackHeaderAppearanceMapper.h +26 -0
  170. package/ios/stack/header/RNSStackHeaderAppearanceMapper.mm +88 -0
  171. package/ios/stack/header/RNSStackHeaderConfigComponentView.h +11 -1
  172. package/ios/stack/header/RNSStackHeaderConfigComponentView.mm +108 -38
  173. package/ios/stack/header/RNSStackHeaderConfigDataProviding.h +9 -0
  174. package/ios/stack/header/RNSStackHeaderConfigShadowStateProxy.mm +1 -1
  175. package/ios/stack/header/RNSStackHeaderIconResolver.mm +7 -0
  176. package/ios/stack/header/RNSStackHeaderItemComponentView.h +3 -1
  177. package/ios/stack/header/RNSStackHeaderItemComponentView.mm +15 -2
  178. package/ios/stack/header/RNSStackHeaderItemDataProviding.h +2 -0
  179. package/ios/stack/header/RNSStackHeaderItemShadowStateProxy.mm +1 -1
  180. package/ios/stack/header/RNSStackHeaderItemSpacerComponentView.mm +2 -1
  181. package/ios/stack/header/RNSStackHeaderMenuCoordinator.h +9 -0
  182. package/ios/stack/header/RNSStackHeaderMenuCoordinator.mm +15 -0
  183. package/ios/stack/header/RNSStackHeaderMenuFinder.h +18 -3
  184. package/ios/stack/header/RNSStackHeaderMenuFinder.mm +21 -3
  185. package/ios/stack/header/RNSStackHeaderMenuMapper.mm +4 -0
  186. package/ios/stack/host/RNSStackHostComponentView.mm +3 -1
  187. package/ios/stack/host/RNSStackNavigationBar.h +25 -0
  188. package/ios/stack/host/RNSStackNavigationBar.mm +80 -0
  189. package/ios/stack/host/RNSStackNavigationBarCoordinator.h +8 -0
  190. package/ios/stack/host/RNSStackNavigationBarCoordinator.mm +11 -0
  191. package/ios/stack/host/RNSStackNavigationController.mm +14 -6
  192. package/ios/stack/host/RNSStackOperation.h +0 -2
  193. package/ios/stack/screen/RNSStackScreenComponentView.mm +9 -4
  194. package/ios/stack/screen/RNSStackScreenController.mm +12 -0
  195. package/ios/stack/screen/RNSStackScreenHeaderCoordinator.h +14 -1
  196. package/ios/stack/screen/RNSStackScreenHeaderCoordinator.mm +159 -28
  197. package/ios/tabs/RNSTabBarAppearanceCoordinator.mm +40 -9
  198. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryComponentView.h +1 -1
  199. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryComponentView.mm +4 -1
  200. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryContentComponentView.mm +5 -2
  201. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryEventEmitter.mm +1 -1
  202. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryShadowStateProxy.mm +1 -1
  203. package/ios/tabs/conversion/RNSConversions-Tabs.h +78 -0
  204. package/ios/{conversion → tabs/conversion}/RNSConversions-Tabs.mm +8 -71
  205. package/ios/tabs/extensions/RNSTabsHostComponentView+RNSImageLoader.h +1 -1
  206. package/ios/tabs/host/RNSTabBarController.h +5 -12
  207. package/ios/tabs/host/RNSTabBarController.mm +1 -1
  208. package/ios/tabs/host/RNSTabsHostComponentView.h +2 -0
  209. package/ios/tabs/host/RNSTabsHostComponentView.mm +10 -3
  210. package/ios/tabs/host/RNSTabsHostEventEmitter.mm +1 -1
  211. package/ios/tabs/screen/RNSTabsScreenComponentView.mm +20 -5
  212. package/ios/utils/RNSDefines.h +3 -0
  213. package/lib/commonjs/components/scroll-to-top-guard/ScrollToTopGuard.ios.js +25 -0
  214. package/lib/commonjs/components/scroll-to-top-guard/ScrollToTopGuard.ios.js.map +1 -0
  215. package/lib/commonjs/components/scroll-to-top-guard/ScrollToTopGuard.js +24 -0
  216. package/lib/commonjs/components/scroll-to-top-guard/ScrollToTopGuard.js.map +1 -0
  217. package/lib/commonjs/components/scroll-to-top-guard/index.js +13 -0
  218. package/lib/commonjs/components/scroll-to-top-guard/index.js.map +1 -0
  219. package/lib/commonjs/components/stack/header/StackHeaderConfig.android.js +34 -19
  220. package/lib/commonjs/components/stack/header/StackHeaderConfig.android.js.map +1 -1
  221. package/lib/commonjs/components/stack/header/StackHeaderConfig.ios.js +44 -13
  222. package/lib/commonjs/components/stack/header/StackHeaderConfig.ios.js.map +1 -1
  223. package/lib/commonjs/components/stack/header/ios/StackHeaderItem.ios.js +1 -22
  224. package/lib/commonjs/components/stack/header/ios/StackHeaderItem.ios.js.map +1 -1
  225. package/lib/commonjs/components/stack/header/ios/iconUtils.ios.js +33 -2
  226. package/lib/commonjs/components/stack/header/ios/iconUtils.ios.js.map +1 -1
  227. package/lib/commonjs/components/stack/header/utils.js +6 -9
  228. package/lib/commonjs/components/stack/header/utils.js.map +1 -1
  229. package/lib/commonjs/components/stack/host/StackHost.js +9 -6
  230. package/lib/commonjs/components/stack/host/StackHost.js.map +1 -1
  231. package/lib/commonjs/components/stack/index.js.map +1 -1
  232. package/lib/commonjs/components/tabs/host/TabsHost.ios.js +1 -0
  233. package/lib/commonjs/components/tabs/host/TabsHost.ios.js.map +1 -1
  234. package/lib/commonjs/experimental/index.js +11 -0
  235. package/lib/commonjs/experimental/index.js.map +1 -1
  236. package/lib/commonjs/fabric/ScrollViewMarkerNativeComponent.js.map +1 -1
  237. package/lib/commonjs/fabric/legacy/FullWindowOverlayNativeComponent.js.map +1 -1
  238. package/lib/commonjs/fabric/legacy/ModalScreenNativeComponent.js.map +1 -1
  239. package/lib/commonjs/fabric/legacy/ScreenContainerNativeComponent.js.map +1 -1
  240. package/lib/commonjs/fabric/legacy/ScreenFooterNativeComponent.js.map +1 -1
  241. package/lib/commonjs/fabric/legacy/ScreenNativeComponent.js.map +1 -1
  242. package/lib/commonjs/fabric/legacy/ScreenStackHeaderConfigNativeComponent.js.map +1 -1
  243. package/lib/commonjs/fabric/legacy/ScreenStackHeaderSubviewNativeComponent.js.map +1 -1
  244. package/lib/commonjs/fabric/legacy/ScreenStackNativeComponent.js.map +1 -1
  245. package/lib/commonjs/fabric/legacy/SearchBarNativeComponent.js.map +1 -1
  246. package/lib/commonjs/fabric/modals/form-sheet/FormSheetHostNativeComponent.js.map +1 -1
  247. package/lib/commonjs/fabric/safe-area/SafeAreaViewNativeComponent.js.map +1 -1
  248. package/lib/commonjs/fabric/scroll-to-top-guard/ScrollToTopGuardNativeComponent.js +12 -0
  249. package/lib/commonjs/fabric/scroll-to-top-guard/ScrollToTopGuardNativeComponent.js.map +1 -0
  250. package/lib/commonjs/fabric/split/SplitHostNativeComponent.js.map +1 -1
  251. package/lib/commonjs/fabric/split/SplitScreenNativeComponent.js.map +1 -1
  252. package/lib/commonjs/fabric/stack/StackHeaderConfigAndroidNativeComponent.js.map +1 -1
  253. package/lib/commonjs/fabric/stack/StackHeaderConfigIOSNativeComponent.js.map +1 -1
  254. package/lib/commonjs/fabric/stack/StackHeaderItemIOSNativeComponent.js.map +1 -1
  255. package/lib/commonjs/fabric/stack/StackHeaderItemSpacerIOSNativeComponent.js.map +1 -1
  256. package/lib/commonjs/fabric/stack/StackHeaderSubviewAndroidNativeComponent.js.map +1 -1
  257. package/lib/commonjs/fabric/stack/StackHostNativeComponent.js.map +1 -1
  258. package/lib/commonjs/fabric/stack/StackScreenNativeComponent.js.map +1 -1
  259. package/lib/commonjs/fabric/tabs/TabsBottomAccessoryContentNativeComponent.js.map +1 -1
  260. package/lib/commonjs/fabric/tabs/TabsBottomAccessoryNativeComponent.js.map +1 -1
  261. package/lib/commonjs/fabric/tabs/TabsHostAndroidNativeComponent.js.map +1 -1
  262. package/lib/commonjs/fabric/tabs/TabsHostIOSNativeComponent.js.map +1 -1
  263. package/lib/commonjs/fabric/tabs/TabsScreenAndroidNativeComponent.js.map +1 -1
  264. package/lib/commonjs/fabric/tabs/TabsScreenIOSNativeComponent.js.map +1 -1
  265. package/lib/commonjs/flags.js +22 -1
  266. package/lib/commonjs/flags.js.map +1 -1
  267. package/lib/commonjs/legacy/components/Screen.js +6 -1
  268. package/lib/commonjs/legacy/components/Screen.js.map +1 -1
  269. package/lib/commonjs/legacy/components/ScreenStackHeaderConfig.js +5 -0
  270. package/lib/commonjs/legacy/components/ScreenStackHeaderConfig.js.map +1 -1
  271. package/lib/commonjs/legacy/components/ScreenStackItem.js.map +1 -1
  272. package/lib/commonjs/legacy/components/SearchBar.js +16 -16
  273. package/lib/commonjs/legacy/components/SearchBar.js.map +1 -1
  274. package/lib/commonjs/legacy/components/helpers/prepareHeaderBarButtonItems.js +3 -0
  275. package/lib/commonjs/legacy/components/helpers/prepareHeaderBarButtonItems.js.map +1 -1
  276. package/lib/commonjs/legacy/gesture-handler/fabricUtils.js.map +1 -1
  277. package/lib/commonjs/legacy/useTransitionProgress.js.map +1 -1
  278. package/lib/module/components/scroll-to-top-guard/ScrollToTopGuard.ios.js +20 -0
  279. package/lib/module/components/scroll-to-top-guard/ScrollToTopGuard.ios.js.map +1 -0
  280. package/lib/module/components/scroll-to-top-guard/ScrollToTopGuard.js +18 -0
  281. package/lib/module/components/scroll-to-top-guard/ScrollToTopGuard.js.map +1 -0
  282. package/lib/module/components/scroll-to-top-guard/index.js +2 -0
  283. package/lib/module/components/scroll-to-top-guard/index.js.map +1 -0
  284. package/lib/module/components/stack/header/StackHeaderConfig.android.js +35 -20
  285. package/lib/module/components/stack/header/StackHeaderConfig.android.js.map +1 -1
  286. package/lib/module/components/stack/header/StackHeaderConfig.ios.js +48 -17
  287. package/lib/module/components/stack/header/StackHeaderConfig.ios.js.map +1 -1
  288. package/lib/module/components/stack/header/ios/StackHeaderItem.ios.js +1 -22
  289. package/lib/module/components/stack/header/ios/StackHeaderItem.ios.js.map +1 -1
  290. package/lib/module/components/stack/header/ios/iconUtils.ios.js +31 -2
  291. package/lib/module/components/stack/header/ios/iconUtils.ios.js.map +1 -1
  292. package/lib/module/components/stack/header/utils.js +5 -8
  293. package/lib/module/components/stack/header/utils.js.map +1 -1
  294. package/lib/module/components/stack/host/StackHost.js +9 -6
  295. package/lib/module/components/stack/host/StackHost.js.map +1 -1
  296. package/lib/module/components/stack/index.js.map +1 -1
  297. package/lib/module/components/tabs/host/TabsHost.ios.js +1 -0
  298. package/lib/module/components/tabs/host/TabsHost.ios.js.map +1 -1
  299. package/lib/module/experimental/index.js +1 -0
  300. package/lib/module/experimental/index.js.map +1 -1
  301. package/lib/module/fabric/ScrollViewMarkerNativeComponent.js.map +1 -1
  302. package/lib/module/fabric/legacy/FullWindowOverlayNativeComponent.js.map +1 -1
  303. package/lib/module/fabric/legacy/ModalScreenNativeComponent.js.map +1 -1
  304. package/lib/module/fabric/legacy/ScreenContainerNativeComponent.js.map +1 -1
  305. package/lib/module/fabric/legacy/ScreenFooterNativeComponent.js.map +1 -1
  306. package/lib/module/fabric/legacy/ScreenNativeComponent.js.map +1 -1
  307. package/lib/module/fabric/legacy/ScreenStackHeaderConfigNativeComponent.js.map +1 -1
  308. package/lib/module/fabric/legacy/ScreenStackHeaderSubviewNativeComponent.js.map +1 -1
  309. package/lib/module/fabric/legacy/ScreenStackNativeComponent.js.map +1 -1
  310. package/lib/module/fabric/legacy/SearchBarNativeComponent.js.map +1 -1
  311. package/lib/module/fabric/modals/form-sheet/FormSheetHostNativeComponent.js.map +1 -1
  312. package/lib/module/fabric/safe-area/SafeAreaViewNativeComponent.js.map +1 -1
  313. package/lib/module/fabric/scroll-to-top-guard/ScrollToTopGuardNativeComponent.js +7 -0
  314. package/lib/module/fabric/scroll-to-top-guard/ScrollToTopGuardNativeComponent.js.map +1 -0
  315. package/lib/module/fabric/split/SplitHostNativeComponent.js.map +1 -1
  316. package/lib/module/fabric/split/SplitScreenNativeComponent.js.map +1 -1
  317. package/lib/module/fabric/stack/StackHeaderConfigAndroidNativeComponent.js.map +1 -1
  318. package/lib/module/fabric/stack/StackHeaderConfigIOSNativeComponent.js.map +1 -1
  319. package/lib/module/fabric/stack/StackHeaderItemIOSNativeComponent.js.map +1 -1
  320. package/lib/module/fabric/stack/StackHeaderItemSpacerIOSNativeComponent.js.map +1 -1
  321. package/lib/module/fabric/stack/StackHeaderSubviewAndroidNativeComponent.js.map +1 -1
  322. package/lib/module/fabric/stack/StackHostNativeComponent.js.map +1 -1
  323. package/lib/module/fabric/stack/StackScreenNativeComponent.js.map +1 -1
  324. package/lib/module/fabric/tabs/TabsBottomAccessoryContentNativeComponent.js.map +1 -1
  325. package/lib/module/fabric/tabs/TabsBottomAccessoryNativeComponent.js.map +1 -1
  326. package/lib/module/fabric/tabs/TabsHostAndroidNativeComponent.js.map +1 -1
  327. package/lib/module/fabric/tabs/TabsHostIOSNativeComponent.js.map +1 -1
  328. package/lib/module/fabric/tabs/TabsScreenAndroidNativeComponent.js.map +1 -1
  329. package/lib/module/fabric/tabs/TabsScreenIOSNativeComponent.js.map +1 -1
  330. package/lib/module/flags.js +22 -1
  331. package/lib/module/flags.js.map +1 -1
  332. package/lib/module/legacy/components/Screen.js +6 -1
  333. package/lib/module/legacy/components/Screen.js.map +1 -1
  334. package/lib/module/legacy/components/ScreenStackHeaderConfig.js +5 -0
  335. package/lib/module/legacy/components/ScreenStackHeaderConfig.js.map +1 -1
  336. package/lib/module/legacy/components/ScreenStackItem.js.map +1 -1
  337. package/lib/module/legacy/components/SearchBar.js +17 -17
  338. package/lib/module/legacy/components/SearchBar.js.map +1 -1
  339. package/lib/module/legacy/components/helpers/prepareHeaderBarButtonItems.js +4 -0
  340. package/lib/module/legacy/components/helpers/prepareHeaderBarButtonItems.js.map +1 -1
  341. package/lib/module/legacy/gesture-handler/fabricUtils.js.map +1 -1
  342. package/lib/module/legacy/useTransitionProgress.js.map +1 -1
  343. package/lib/module/private/hooks/useRenderDebugInfo.js.map +1 -1
  344. package/lib/typescript/components/modals/form-sheet/FormSheet.types.d.ts +3 -3
  345. package/lib/typescript/components/safe-area/SafeAreaView.web.d.ts +5 -2
  346. package/lib/typescript/components/safe-area/SafeAreaView.web.d.ts.map +1 -1
  347. package/lib/typescript/components/scroll-to-top-guard/ScrollToTopGuard.d.ts +15 -0
  348. package/lib/typescript/components/scroll-to-top-guard/ScrollToTopGuard.d.ts.map +1 -0
  349. package/lib/typescript/components/scroll-to-top-guard/ScrollToTopGuard.ios.d.ts +12 -0
  350. package/lib/typescript/components/scroll-to-top-guard/ScrollToTopGuard.ios.d.ts.map +1 -0
  351. package/lib/typescript/components/scroll-to-top-guard/index.d.ts +2 -0
  352. package/lib/typescript/components/scroll-to-top-guard/index.d.ts.map +1 -0
  353. package/lib/typescript/components/stack/header/StackHeaderConfig.android.d.ts.map +1 -1
  354. package/lib/typescript/components/stack/header/StackHeaderConfig.android.types.d.ts +639 -20
  355. package/lib/typescript/components/stack/header/StackHeaderConfig.android.types.d.ts.map +1 -1
  356. package/lib/typescript/components/stack/header/StackHeaderConfig.ios.d.ts.map +1 -1
  357. package/lib/typescript/components/stack/header/StackHeaderConfig.ios.types.d.ts +239 -2
  358. package/lib/typescript/components/stack/header/StackHeaderConfig.ios.types.d.ts.map +1 -1
  359. package/lib/typescript/components/stack/header/StackHeaderConfig.types.d.ts +2 -2
  360. package/lib/typescript/components/stack/header/StackHeaderConfig.web.d.ts +5 -2
  361. package/lib/typescript/components/stack/header/StackHeaderConfig.web.d.ts.map +1 -1
  362. package/lib/typescript/components/stack/header/ios/StackHeaderItem.ios.d.ts.map +1 -1
  363. package/lib/typescript/components/stack/header/ios/StackHeaderItem.ios.types.d.ts +2 -0
  364. package/lib/typescript/components/stack/header/ios/StackHeaderItem.ios.types.d.ts.map +1 -1
  365. package/lib/typescript/components/stack/header/ios/iconUtils.ios.d.ts +3 -0
  366. package/lib/typescript/components/stack/header/ios/iconUtils.ios.d.ts.map +1 -1
  367. package/lib/typescript/components/stack/header/utils.d.ts +1 -2
  368. package/lib/typescript/components/stack/header/utils.d.ts.map +1 -1
  369. package/lib/typescript/components/stack/host/StackHost.d.ts +1 -1
  370. package/lib/typescript/components/stack/host/StackHost.d.ts.map +1 -1
  371. package/lib/typescript/components/stack/host/StackHost.types.d.ts +26 -2
  372. package/lib/typescript/components/stack/host/StackHost.types.d.ts.map +1 -1
  373. package/lib/typescript/components/stack/host/StackHost.web.d.ts +6 -2
  374. package/lib/typescript/components/stack/host/StackHost.web.d.ts.map +1 -1
  375. package/lib/typescript/components/stack/index.d.ts +2 -2
  376. package/lib/typescript/components/stack/index.d.ts.map +1 -1
  377. package/lib/typescript/components/stack/screen/StackScreen.web.d.ts +5 -2
  378. package/lib/typescript/components/stack/screen/StackScreen.web.d.ts.map +1 -1
  379. package/lib/typescript/components/tabs/host/TabsHost.ios.d.ts.map +1 -1
  380. package/lib/typescript/components/tabs/host/TabsHost.ios.types.d.ts +16 -0
  381. package/lib/typescript/components/tabs/host/TabsHost.ios.types.d.ts.map +1 -1
  382. package/lib/typescript/components/tabs/host/TabsHost.types.d.ts +3 -0
  383. package/lib/typescript/components/tabs/host/TabsHost.types.d.ts.map +1 -1
  384. package/lib/typescript/components/tabs/host/TabsHost.web.d.ts +5 -2
  385. package/lib/typescript/components/tabs/host/TabsHost.web.d.ts.map +1 -1
  386. package/lib/typescript/components/tabs/screen/TabsScreen.types.d.ts +7 -3
  387. package/lib/typescript/components/tabs/screen/TabsScreen.types.d.ts.map +1 -1
  388. package/lib/typescript/components/tabs/screen/TabsScreen.web.d.ts +5 -2
  389. package/lib/typescript/components/tabs/screen/TabsScreen.web.d.ts.map +1 -1
  390. package/lib/typescript/experimental/index.d.ts +1 -0
  391. package/lib/typescript/experimental/index.d.ts.map +1 -1
  392. package/lib/typescript/fabric/NativeScreensModule.d.ts +1 -1
  393. package/lib/typescript/fabric/ScrollViewMarkerNativeComponent.d.ts +2 -2
  394. package/lib/typescript/fabric/ScrollViewMarkerNativeComponent.d.ts.map +1 -1
  395. package/lib/typescript/fabric/legacy/FullWindowOverlayNativeComponent.d.ts +2 -2
  396. package/lib/typescript/fabric/legacy/FullWindowOverlayNativeComponent.d.ts.map +1 -1
  397. package/lib/typescript/fabric/legacy/ModalScreenNativeComponent.d.ts +3 -2
  398. package/lib/typescript/fabric/legacy/ModalScreenNativeComponent.d.ts.map +1 -1
  399. package/lib/typescript/fabric/legacy/ScreenContainerNativeComponent.d.ts +2 -2
  400. package/lib/typescript/fabric/legacy/ScreenContainerNativeComponent.d.ts.map +1 -1
  401. package/lib/typescript/fabric/legacy/ScreenContentWrapperNativeComponent.d.ts +2 -2
  402. package/lib/typescript/fabric/legacy/ScreenContentWrapperNativeComponent.d.ts.map +1 -1
  403. package/lib/typescript/fabric/legacy/ScreenFooterNativeComponent.d.ts +2 -2
  404. package/lib/typescript/fabric/legacy/ScreenFooterNativeComponent.d.ts.map +1 -1
  405. package/lib/typescript/fabric/legacy/ScreenNativeComponent.d.ts +3 -2
  406. package/lib/typescript/fabric/legacy/ScreenNativeComponent.d.ts.map +1 -1
  407. package/lib/typescript/fabric/legacy/ScreenNavigationContainerNativeComponent.d.ts +2 -2
  408. package/lib/typescript/fabric/legacy/ScreenNavigationContainerNativeComponent.d.ts.map +1 -1
  409. package/lib/typescript/fabric/legacy/ScreenStackHeaderConfigNativeComponent.d.ts +3 -3
  410. package/lib/typescript/fabric/legacy/ScreenStackHeaderConfigNativeComponent.d.ts.map +1 -1
  411. package/lib/typescript/fabric/legacy/ScreenStackHeaderSubviewNativeComponent.d.ts +2 -2
  412. package/lib/typescript/fabric/legacy/ScreenStackHeaderSubviewNativeComponent.d.ts.map +1 -1
  413. package/lib/typescript/fabric/legacy/ScreenStackNativeComponent.d.ts +2 -2
  414. package/lib/typescript/fabric/legacy/ScreenStackNativeComponent.d.ts.map +1 -1
  415. package/lib/typescript/fabric/legacy/SearchBarNativeComponent.d.ts +6 -6
  416. package/lib/typescript/fabric/legacy/SearchBarNativeComponent.d.ts.map +1 -1
  417. package/lib/typescript/fabric/modals/form-sheet/FormSheetContentWrapperNativeComponent.d.ts +2 -2
  418. package/lib/typescript/fabric/modals/form-sheet/FormSheetContentWrapperNativeComponent.d.ts.map +1 -1
  419. package/lib/typescript/fabric/modals/form-sheet/FormSheetHostNativeComponent.d.ts +2 -2
  420. package/lib/typescript/fabric/modals/form-sheet/FormSheetHostNativeComponent.d.ts.map +1 -1
  421. package/lib/typescript/fabric/safe-area/SafeAreaViewNativeComponent.d.ts +2 -2
  422. package/lib/typescript/fabric/safe-area/SafeAreaViewNativeComponent.d.ts.map +1 -1
  423. package/lib/typescript/fabric/scroll-to-top-guard/ScrollToTopGuardNativeComponent.d.ts +6 -0
  424. package/lib/typescript/fabric/scroll-to-top-guard/ScrollToTopGuardNativeComponent.d.ts.map +1 -0
  425. package/lib/typescript/fabric/split/SplitHostNativeComponent.d.ts +1 -1
  426. package/lib/typescript/fabric/split/SplitHostNativeComponent.d.ts.map +1 -1
  427. package/lib/typescript/fabric/split/SplitScreenNativeComponent.d.ts +2 -2
  428. package/lib/typescript/fabric/split/SplitScreenNativeComponent.d.ts.map +1 -1
  429. package/lib/typescript/fabric/stack/StackHeaderConfigAndroidNativeComponent.d.ts +53 -0
  430. package/lib/typescript/fabric/stack/StackHeaderConfigAndroidNativeComponent.d.ts.map +1 -1
  431. package/lib/typescript/fabric/stack/StackHeaderConfigIOSNativeComponent.d.ts +27 -2
  432. package/lib/typescript/fabric/stack/StackHeaderConfigIOSNativeComponent.d.ts.map +1 -1
  433. package/lib/typescript/fabric/stack/StackHeaderItemIOSNativeComponent.d.ts +4 -2
  434. package/lib/typescript/fabric/stack/StackHeaderItemIOSNativeComponent.d.ts.map +1 -1
  435. package/lib/typescript/fabric/stack/StackHeaderItemSpacerIOSNativeComponent.d.ts +2 -2
  436. package/lib/typescript/fabric/stack/StackHeaderItemSpacerIOSNativeComponent.d.ts.map +1 -1
  437. package/lib/typescript/fabric/stack/StackHeaderSubviewAndroidNativeComponent.d.ts +2 -2
  438. package/lib/typescript/fabric/stack/StackHeaderSubviewAndroidNativeComponent.d.ts.map +1 -1
  439. package/lib/typescript/fabric/stack/StackHostNativeComponent.d.ts +4 -2
  440. package/lib/typescript/fabric/stack/StackHostNativeComponent.d.ts.map +1 -1
  441. package/lib/typescript/fabric/stack/StackScreenNativeComponent.d.ts +2 -2
  442. package/lib/typescript/fabric/stack/StackScreenNativeComponent.d.ts.map +1 -1
  443. package/lib/typescript/fabric/tabs/TabsBottomAccessoryContentNativeComponent.d.ts +2 -2
  444. package/lib/typescript/fabric/tabs/TabsBottomAccessoryContentNativeComponent.d.ts.map +1 -1
  445. package/lib/typescript/fabric/tabs/TabsBottomAccessoryNativeComponent.d.ts +2 -2
  446. package/lib/typescript/fabric/tabs/TabsBottomAccessoryNativeComponent.d.ts.map +1 -1
  447. package/lib/typescript/fabric/tabs/TabsHostAndroidNativeComponent.d.ts +2 -2
  448. package/lib/typescript/fabric/tabs/TabsHostAndroidNativeComponent.d.ts.map +1 -1
  449. package/lib/typescript/fabric/tabs/TabsHostIOSNativeComponent.d.ts +3 -2
  450. package/lib/typescript/fabric/tabs/TabsHostIOSNativeComponent.d.ts.map +1 -1
  451. package/lib/typescript/fabric/tabs/TabsScreenAndroidNativeComponent.d.ts +2 -2
  452. package/lib/typescript/fabric/tabs/TabsScreenAndroidNativeComponent.d.ts.map +1 -1
  453. package/lib/typescript/fabric/tabs/TabsScreenIOSNativeComponent.d.ts +2 -2
  454. package/lib/typescript/fabric/tabs/TabsScreenIOSNativeComponent.d.ts.map +1 -1
  455. package/lib/typescript/flags.d.ts +13 -0
  456. package/lib/typescript/flags.d.ts.map +1 -1
  457. package/lib/typescript/legacy/TransitionProgressContext.d.ts +1 -1
  458. package/lib/typescript/legacy/TransitionProgressContext.d.ts.map +1 -1
  459. package/lib/typescript/legacy/components/Screen.d.ts +5 -3
  460. package/lib/typescript/legacy/components/Screen.d.ts.map +1 -1
  461. package/lib/typescript/legacy/components/Screen.web.d.ts +10 -2
  462. package/lib/typescript/legacy/components/Screen.web.d.ts.map +1 -1
  463. package/lib/typescript/legacy/components/ScreenContainer.web.d.ts +5 -2
  464. package/lib/typescript/legacy/components/ScreenContainer.web.d.ts.map +1 -1
  465. package/lib/typescript/legacy/components/ScreenContentWrapper.web.d.ts +5 -2
  466. package/lib/typescript/legacy/components/ScreenContentWrapper.web.d.ts.map +1 -1
  467. package/lib/typescript/legacy/components/ScreenContentWrapper.windows.d.ts +5 -2
  468. package/lib/typescript/legacy/components/ScreenContentWrapper.windows.d.ts.map +1 -1
  469. package/lib/typescript/legacy/components/ScreenFooter.web.d.ts +10 -3
  470. package/lib/typescript/legacy/components/ScreenFooter.web.d.ts.map +1 -1
  471. package/lib/typescript/legacy/components/ScreenFooter.windows.d.ts +10 -3
  472. package/lib/typescript/legacy/components/ScreenFooter.windows.d.ts.map +1 -1
  473. package/lib/typescript/legacy/components/ScreenStack.web.d.ts +5 -2
  474. package/lib/typescript/legacy/components/ScreenStack.web.d.ts.map +1 -1
  475. package/lib/typescript/legacy/components/ScreenStackHeaderConfig.d.ts +3 -1
  476. package/lib/typescript/legacy/components/ScreenStackHeaderConfig.d.ts.map +1 -1
  477. package/lib/typescript/legacy/components/ScreenStackItem.d.ts +3 -2
  478. package/lib/typescript/legacy/components/ScreenStackItem.d.ts.map +1 -1
  479. package/lib/typescript/legacy/components/SearchBar.d.ts +3 -3
  480. package/lib/typescript/legacy/components/SearchBar.d.ts.map +1 -1
  481. package/lib/typescript/legacy/components/SearchBar.web.d.ts +5 -2
  482. package/lib/typescript/legacy/components/SearchBar.web.d.ts.map +1 -1
  483. package/lib/typescript/legacy/components/helpers/prepareHeaderBarButtonItems.d.ts +15 -12
  484. package/lib/typescript/legacy/components/helpers/prepareHeaderBarButtonItems.d.ts.map +1 -1
  485. package/lib/typescript/legacy/gesture-handler/fabricUtils.d.ts +3 -2
  486. package/lib/typescript/legacy/gesture-handler/fabricUtils.d.ts.map +1 -1
  487. package/lib/typescript/legacy/types.d.ts +25 -5
  488. package/lib/typescript/legacy/types.d.ts.map +1 -1
  489. package/lib/typescript/legacy/useTransitionProgress.d.ts +2 -5
  490. package/lib/typescript/legacy/useTransitionProgress.d.ts.map +1 -1
  491. package/lib/typescript/private/hooks/useRenderDebugInfo.d.ts +2 -2
  492. package/lib/typescript/private/hooks/useRenderDebugInfo.d.ts.map +1 -1
  493. package/package.json +18 -17
  494. package/react-native.config.js +3 -0
  495. package/src/components/modals/form-sheet/FormSheet.types.ts +3 -3
  496. package/src/components/scroll-to-top-guard/ScrollToTopGuard.ios.tsx +17 -0
  497. package/src/components/scroll-to-top-guard/ScrollToTopGuard.tsx +18 -0
  498. package/src/components/scroll-to-top-guard/index.ts +1 -0
  499. package/src/components/stack/header/StackHeaderConfig.android.tsx +48 -23
  500. package/src/components/stack/header/StackHeaderConfig.android.types.ts +660 -20
  501. package/src/components/stack/header/StackHeaderConfig.ios.tsx +77 -23
  502. package/src/components/stack/header/StackHeaderConfig.ios.types.ts +251 -2
  503. package/src/components/stack/header/StackHeaderConfig.types.ts +2 -2
  504. package/src/components/stack/header/ios/StackHeaderItem.ios.tsx +1 -23
  505. package/src/components/stack/header/ios/StackHeaderItem.ios.types.ts +2 -0
  506. package/src/components/stack/header/ios/iconUtils.ios.ts +38 -2
  507. package/src/components/stack/header/utils.ts +6 -11
  508. package/src/components/stack/host/StackHost.tsx +4 -2
  509. package/src/components/stack/host/StackHost.types.ts +28 -4
  510. package/src/components/stack/index.ts +6 -1
  511. package/src/components/tabs/host/TabsHost.ios.tsx +1 -0
  512. package/src/components/tabs/host/TabsHost.ios.types.ts +16 -0
  513. package/src/components/tabs/host/TabsHost.types.ts +3 -0
  514. package/src/components/tabs/screen/TabsScreen.types.ts +7 -3
  515. package/src/experimental/index.ts +1 -0
  516. package/src/fabric/ScrollViewMarkerNativeComponent.ts +8 -2
  517. package/src/fabric/legacy/FullWindowOverlayNativeComponent.ts +6 -2
  518. package/src/fabric/legacy/ModalScreenNativeComponent.ts +8 -2
  519. package/src/fabric/legacy/ScreenContainerNativeComponent.ts +5 -2
  520. package/src/fabric/legacy/ScreenContentWrapperNativeComponent.ts +2 -2
  521. package/src/fabric/legacy/ScreenFooterNativeComponent.ts +5 -2
  522. package/src/fabric/legacy/ScreenNativeComponent.ts +8 -2
  523. package/src/fabric/legacy/ScreenNavigationContainerNativeComponent.ts +2 -2
  524. package/src/fabric/legacy/ScreenStackHeaderConfigNativeComponent.ts +8 -3
  525. package/src/fabric/legacy/ScreenStackHeaderSubviewNativeComponent.ts +6 -2
  526. package/src/fabric/legacy/ScreenStackNativeComponent.ts +10 -2
  527. package/src/fabric/legacy/SearchBarNativeComponent.ts +10 -7
  528. package/src/fabric/modals/form-sheet/FormSheetContentWrapperNativeComponent.ts +2 -2
  529. package/src/fabric/modals/form-sheet/FormSheetHostNativeComponent.ts +7 -2
  530. package/src/fabric/safe-area/SafeAreaViewNativeComponent.ts +6 -2
  531. package/src/fabric/scroll-to-top-guard/ScrollToTopGuardNativeComponent.ts +10 -0
  532. package/src/fabric/split/SplitHostNativeComponent.ts +5 -2
  533. package/src/fabric/split/SplitScreenNativeComponent.ts +6 -2
  534. package/src/fabric/stack/StackHeaderConfigAndroidNativeComponent.ts +81 -1
  535. package/src/fabric/stack/StackHeaderConfigIOSNativeComponent.ts +39 -2
  536. package/src/fabric/stack/StackHeaderItemIOSNativeComponent.ts +4 -1
  537. package/src/fabric/stack/StackHeaderItemSpacerIOSNativeComponent.ts +6 -2
  538. package/src/fabric/stack/StackHeaderSubviewAndroidNativeComponent.ts +6 -2
  539. package/src/fabric/stack/StackHostNativeComponent.ts +15 -3
  540. package/src/fabric/stack/StackScreenNativeComponent.ts +6 -2
  541. package/src/fabric/tabs/TabsBottomAccessoryContentNativeComponent.ts +6 -2
  542. package/src/fabric/tabs/TabsBottomAccessoryNativeComponent.ts +6 -2
  543. package/src/fabric/tabs/TabsHostAndroidNativeComponent.ts +7 -2
  544. package/src/fabric/tabs/TabsHostIOSNativeComponent.ts +8 -2
  545. package/src/fabric/tabs/TabsScreenAndroidNativeComponent.ts +2 -1
  546. package/src/fabric/tabs/TabsScreenIOSNativeComponent.ts +2 -1
  547. package/src/flags.ts +26 -0
  548. package/src/legacy/TransitionProgressContext.tsx +1 -1
  549. package/src/legacy/components/Screen.tsx +14 -6
  550. package/src/legacy/components/ScreenStackHeaderConfig.tsx +7 -1
  551. package/src/legacy/components/ScreenStackItem.tsx +3 -4
  552. package/src/legacy/components/SearchBar.tsx +34 -44
  553. package/src/legacy/components/helpers/prepareHeaderBarButtonItems.ts +7 -1
  554. package/src/legacy/gesture-handler/fabricUtils.ts +5 -2
  555. package/src/legacy/types.ts +28 -5
  556. package/src/legacy/useTransitionProgress.tsx +4 -2
  557. package/src/private/hooks/useRenderDebugInfo.tsx +2 -2
  558. package/android/src/main/java/com/swmansion/rnscreens/modals/dimmingview/DimmingView.kt +0 -83
  559. package/android/src/main/java/com/swmansion/rnscreens/modals/dimmingview/DimmingViewManager.kt +0 -89
  560. package/android/src/main/java/com/swmansion/rnscreens/modals/dimmingview/DimmingViewPointerEvents.kt +0 -18
  561. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/FormSheetDetents.kt +0 -106
  562. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/FormSheetDialog.kt +0 -60
  563. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/FormSheetDialogManager.kt +0 -138
  564. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/FormSheetDimensionsCoordinator.kt +0 -131
  565. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/FormSheetNativeDismissCoordinator.kt +0 -25
  566. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/FormSheetPresentationManager.kt +0 -207
  567. package/android/src/main/java/com/swmansion/rnscreens/stack/header/StackHeaderAppBarLayout.kt +0 -113
  568. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/StackHeaderToolbarMenuConfig.kt +0 -60
  569. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/StackHeaderToolbarMenuElementOptions.kt +0 -32
  570. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/StackHeaderToolbarMenuGroupMetadata.kt +0 -16
  571. package/ios/ReactMountingTransactionObserving.swift +0 -7
  572. package/ios/bridging/Swift-Bridging.h +0 -7
  573. package/ios/conversion/RNSConversions-Stack.h +0 -32
  574. package/ios/conversion/RNSConversions-Stack.mm +0 -41
  575. package/ios/conversion/always_false.h +0 -31
  576. package/ios/orientation/RNSOrientationProviding.swift +0 -6
  577. package/ios/orientation/RNSOrientationSwift.swift +0 -14
  578. package/ios/split/RNSSplitAppearanceApplicator.swift +0 -199
  579. package/ios/split/RNSSplitAppearanceCoordinator.swift +0 -26
  580. package/ios/split/RNSSplitAppearanceUpdateFlags.swift +0 -11
  581. package/ios/split/RNSSplitHostController.swift +0 -570
  582. package/ios/split/RNSSplitNavigationController.swift +0 -46
  583. package/ios/split/RNSSplitScreenController.swift +0 -133
  584. package/ios/utils/RNSLog.swift +0 -6
  585. /package/ios/{conversion → scroll-view-marker/conversion}/RNSConversions-ScrollViewMarker.h +0 -0
@@ -1,23 +1,22 @@
1
1
  package com.swmansion.rnscreens.stack.header
2
2
 
3
+ import android.annotation.SuppressLint
3
4
  import android.content.res.ColorStateList
5
+ import android.graphics.Color
6
+ import android.graphics.Typeface
4
7
  import android.graphics.drawable.Drawable
5
- import android.os.Build
6
- import android.text.TextUtils
7
8
  import android.util.Log
9
+ import android.util.TypedValue
8
10
  import android.view.Gravity
9
- import android.view.Menu
10
- import android.view.MenuItem
11
11
  import android.view.View
12
+ import android.view.ViewGroup
12
13
  import android.view.ViewGroup.LayoutParams.MATCH_PARENT
13
14
  import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
14
15
  import android.widget.FrameLayout
15
16
  import androidx.appcompat.view.ContextThemeWrapper
16
- import androidx.appcompat.widget.AppCompatTextView
17
+ import androidx.appcompat.widget.AppCompatImageView
17
18
  import androidx.appcompat.widget.Toolbar
18
19
  import androidx.core.graphics.drawable.DrawableCompat
19
- import androidx.core.view.MenuItemCompat
20
- import androidx.core.widget.TextViewCompat
21
20
  import com.google.android.material.R
22
21
  import com.google.android.material.appbar.AppBarLayout
23
22
  import com.google.android.material.appbar.AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS
@@ -27,30 +26,41 @@ import com.google.android.material.appbar.AppBarLayout.LayoutParams.SCROLL_FLAG_
27
26
  import com.google.android.material.appbar.AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP
28
27
  import com.google.android.material.appbar.CollapsingToolbarLayout
29
28
  import com.google.android.material.appbar.MaterialToolbar
29
+ import com.google.android.material.color.MaterialColors
30
+ import com.google.android.material.shape.MaterialShapeDrawable
31
+ import com.swmansion.rnscreens.common.text.TextAppearance
32
+ import com.swmansion.rnscreens.common.text.TextAppearanceDefaults
30
33
  import com.swmansion.rnscreens.ext.detachFromCurrentParent
34
+ import com.swmansion.rnscreens.stack.header.appbar.StackHeaderAppBarLayout
35
+ import com.swmansion.rnscreens.stack.header.appbar.StackHeaderContentScrimDrawable
31
36
  import com.swmansion.rnscreens.stack.header.config.StackHeaderConfigurationProviding
37
+ import com.swmansion.rnscreens.stack.header.config.StackHeaderType
32
38
  import com.swmansion.rnscreens.stack.header.subview.StackHeaderSubview
33
- import com.swmansion.rnscreens.stack.header.toolbar.StackHeaderToolbarFieldUpdate
34
- import com.swmansion.rnscreens.stack.header.toolbar.StackHeaderToolbarMenuConfig
35
- import com.swmansion.rnscreens.stack.header.toolbar.StackHeaderToolbarMenuElementConfig
36
- import com.swmansion.rnscreens.stack.header.toolbar.StackHeaderToolbarMenuElementOptions
37
- import com.swmansion.rnscreens.stack.header.toolbar.StackHeaderToolbarMenuGroupConfig
38
- import com.swmansion.rnscreens.stack.header.toolbar.StackHeaderToolbarMenuGroupMetadata
39
- import com.swmansion.rnscreens.stack.header.toolbar.StackHeaderToolbarMenuItemConfig
40
- import com.swmansion.rnscreens.stack.header.toolbar.StackHeaderToolbarMenuItemType
41
- import com.swmansion.rnscreens.stack.header.toolbar.valueOrNull
39
+ import com.swmansion.rnscreens.utils.dpToPx
40
+ import com.swmansion.rnscreens.utils.resolveColorAttr
42
41
  import com.swmansion.rnscreens.utils.resolveDrawableAttr
42
+ import com.swmansion.rnscreens.utils.spToPx
43
+ import kotlin.math.roundToInt
43
44
 
45
+ /**
46
+ * Builds and applies the Material app bar — type, subviews, title, back button,
47
+ * scroll flags — from the header configuration.
48
+ */
44
49
  internal class StackHeaderApplicator(
45
50
  private val wrappedContext: ContextThemeWrapper,
46
51
  ) {
47
52
  // region Rebuild
48
53
 
49
- fun rebuild(
54
+ internal fun rebuild(
50
55
  coordinatorLayout: StackHeaderCoordinatorLayout,
51
56
  config: StackHeaderConfigurationProviding,
52
57
  ): StackHeaderAppBarLayout {
53
- val appBar = StackHeaderAppBarLayout.create(wrappedContext, config.type)
58
+ val appBar =
59
+ StackHeaderAppBarLayout.create(
60
+ wrappedContext,
61
+ config.type,
62
+ config.collapsedTitleGravityMode,
63
+ )
54
64
 
55
65
  if (config.transparent) {
56
66
  coordinatorLayout.removeContentBehavior()
@@ -91,30 +101,21 @@ internal class StackHeaderApplicator(
91
101
  toolbar.addView(it.view, Toolbar.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, Gravity.END))
92
102
  }
93
103
 
94
- populateTitleOrCenter(appBar, toolbar, config)
104
+ populateCenterSubview(appBar, toolbar, config)
95
105
  populateBackground(appBar, config)
96
106
  }
97
107
 
98
- private fun populateTitleOrCenter(
108
+ private fun populateCenterSubview(
99
109
  appBar: StackHeaderAppBarLayout,
100
110
  toolbar: Toolbar,
101
111
  config: StackHeaderConfigurationProviding,
102
112
  ) {
103
- val centerSubview = config.centerSubview
104
- if (centerSubview != null) {
105
- if (appBar is StackHeaderAppBarLayout.Small) {
106
- centerSubview.view.detachFromCurrentParent()
107
- toolbar.addView(centerSubview.view, Toolbar.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, Gravity.CENTER_HORIZONTAL))
108
- } else {
109
- Log.e(TAG, "[RNScreens] Center subview is supported only for small header type.")
110
- }
111
- } else if (appBar is StackHeaderAppBarLayout.Small) {
112
- // Small header needs a managed title view because we can't use Toolbar's native
113
- // title — it would be laid out to the leading side of leading subview.
114
- val titleView = createManagedTitleView(toolbar)
115
- appBar.managedTitleView = titleView
116
- val index = if (config.isRTL) 0 else -1
117
- toolbar.addView(titleView, index, Toolbar.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, Gravity.START))
113
+ val centerSubview = config.centerSubview ?: return
114
+ if (appBar is StackHeaderAppBarLayout.Small) {
115
+ centerSubview.view.detachFromCurrentParent()
116
+ toolbar.addView(centerSubview.view, Toolbar.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, Gravity.CENTER_HORIZONTAL))
117
+ } else {
118
+ Log.e(TAG, "[RNScreens] Center subview is supported only for small header type.")
118
119
  }
119
120
  }
120
121
 
@@ -151,52 +152,206 @@ internal class StackHeaderApplicator(
151
152
  )
152
153
  }
153
154
 
154
- private fun createManagedTitleView(toolbar: Toolbar): AppCompatTextView =
155
- AppCompatTextView(toolbar.context).apply {
156
- setSingleLine()
157
- ellipsize = TextUtils.TruncateAt.END
158
- TextViewCompat.setTextAppearance(
159
- this,
160
- R.style.TextAppearance_Material3_TitleLarge,
161
- )
162
- layoutParams =
163
- Toolbar
164
- .LayoutParams(
165
- WRAP_CONTENT,
166
- WRAP_CONTENT,
167
- Gravity.START,
168
- ).apply {
169
- // TODO: there seems to be a problem with collapsing margins.
170
- // We will expose customization either way but we should
171
- // have consistent behavior and defaults.
172
- marginStart = toolbar.titleMarginStart + toolbar.contentInsetStart
173
- marginEnd = toolbar.titleMarginEnd
174
- topMargin = toolbar.titleMarginTop
175
- bottomMargin = toolbar.titleMarginBottom
176
- }
177
- }
178
-
179
155
  // endregion
180
156
 
181
157
  // region In-place updates
182
158
 
183
- fun applyTitle(
159
+ // ctl.setMaxLines() is listed in Material docs in the same way as other props but for some
160
+ // reason it's restricted.
161
+ @SuppressLint("RestrictedApi")
162
+ internal fun applyTitleAndSubtitle(
163
+ appBar: StackHeaderAppBarLayout,
164
+ config: StackHeaderConfigurationProviding,
165
+ isAppBarFullyCollapsed: Boolean,
166
+ ) {
167
+ when (appBar) {
168
+ is StackHeaderAppBarLayout.Small -> {
169
+ appBar.toolbar.title = config.title
170
+ appBar.toolbar.subtitle = config.subtitle
171
+ }
172
+
173
+ is StackHeaderAppBarLayout.Collapsing -> {
174
+ val ctl = appBar.collapsingToolbarLayout
175
+
176
+ ctl.maxLines = config.maxLines
177
+
178
+ ctl.title = config.title
179
+ ctl.subtitle = config.subtitle
180
+
181
+ // setText only recomputes draw offsets within the existing bounds; the
182
+ // title/subtitle vertical split is recomputed only in onLayout. Force a layout
183
+ // so toggling the subtitle at runtime reclaims the title space.
184
+ ctl.requestLayout()
185
+
186
+ // Material re-asserts the collapsed offset after a height change itself, but only
187
+ // when maxLines > 1 (CollapsingToolbarLayout.onMeasure). With maxLines == 1 it never
188
+ // does, so toggling the subtitle at runtime while collapsed leaves a stale offset —
189
+ // setExpanded(false, false) is the closest public equivalent of Material's private
190
+ // maybeSetPendingActionCollapsed().
191
+ if (config.maxLines == 1 && isAppBarFullyCollapsed) {
192
+ appBar.setExpanded(false, false)
193
+ }
194
+ }
195
+ }
196
+ }
197
+
198
+ internal fun applyTitlePositioning(
184
199
  appBar: StackHeaderAppBarLayout,
185
200
  config: StackHeaderConfigurationProviding,
186
201
  ) {
187
202
  when (appBar) {
188
203
  is StackHeaderAppBarLayout.Small -> {
189
- appBar.managedTitleView?.text = config.title
190
- appBar.managedTitleView?.requestLayout()
204
+ appBar.toolbar.isTitleCentered = config.titleCentered
205
+ appBar.toolbar.isSubtitleCentered = config.subtitleCentered
191
206
  }
192
207
 
193
208
  is StackHeaderAppBarLayout.Collapsing -> {
194
- appBar.collapsingToolbarLayout.title = config.title
209
+ appBar.collapsingToolbarLayout.expandedTitleGravity =
210
+ config.expandedTitleHorizontalGravity or config.expandedTitleVerticalGravity
211
+ appBar.collapsingToolbarLayout.collapsedTitleGravity =
212
+ config.collapsedTitleHorizontalGravity or config.collapsedTitleVerticalGravity
195
213
  }
196
214
  }
197
215
  }
198
216
 
199
- fun applyBackButton(
217
+ internal fun applyTitleAndSubtitleAppearance(
218
+ appBar: StackHeaderAppBarLayout,
219
+ config: StackHeaderConfigurationProviding,
220
+ ) {
221
+ // Defaults are resolved from wrappedContext, not the widget's own context: MaterialToolbar
222
+ // wraps its context (materialThemeOverlay) in a ContextThemeWrapper whose theme is a
223
+ // one-time copy, so it never sees later setTheme calls on wrappedContext (color scheme
224
+ // changes).
225
+ when (appBar) {
226
+ is StackHeaderAppBarLayout.Small -> {
227
+ val toolbar = appBar.toolbar
228
+
229
+ // Widget.Material3Expressive.Toolbar#{title,subtitle}TextAppearance
230
+ // = @macro/m3_comp_app_bar_small_{title,subtitle}_font. That style sets no text
231
+ // colors, so both come from @macro/m3_comp_app_bar_{title,subtitle}_color.
232
+ applySlot(
233
+ view = toolbar,
234
+ defaults =
235
+ TextAppearanceDefaults.resolve(
236
+ wrappedContext,
237
+ R.attr.textAppearanceTitleLarge,
238
+ R.attr.colorOnSurface,
239
+ ),
240
+ appearance = config.titleAppearance,
241
+ setColor = { toolbar.setTitleTextColor(it) },
242
+ setTypeface = { appBar.titleTextView.typeface = it },
243
+ setTextSizePx = { appBar.titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, it) },
244
+ )
245
+ applySlot(
246
+ view = toolbar,
247
+ defaults =
248
+ TextAppearanceDefaults.resolve(
249
+ wrappedContext,
250
+ R.attr.textAppearanceLabelMedium,
251
+ R.attr.colorOnSurfaceVariant,
252
+ ),
253
+ appearance = config.subtitleAppearance,
254
+ setColor = { toolbar.setSubtitleTextColor(it) },
255
+ setTypeface = { appBar.subtitleTextView.typeface = it },
256
+ setTextSizePx = { appBar.subtitleTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, it) },
257
+ )
258
+ }
259
+
260
+ is StackHeaderAppBarLayout.Collapsing -> {
261
+ val ctl = appBar.collapsingToolbarLayout
262
+ val isLarge = appBar.type == StackHeaderType.LARGE
263
+
264
+ // Widget.Material3Expressive.CollapsingToolbar.{Large,Medium}#expandedTitleTextAppearance
265
+ // = @macro/m3_comp_app_bar_{large,medium}_flexible_title_font
266
+ val expandedTitleAttr =
267
+ if (isLarge) R.attr.textAppearanceDisplaySmall else R.attr.textAppearanceHeadlineMedium
268
+
269
+ // …#expandedSubtitleTextAppearance
270
+ // = @macro/m3_comp_app_bar_{large,medium}_flexible_subtitle_font
271
+ val expandedSubtitleAttr =
272
+ if (isLarge) R.attr.textAppearanceTitleMedium else R.attr.textAppearanceLabelLarge
273
+
274
+ // In the calls below, the collapsed appearances and all four colors come from the base
275
+ // Widget.Material3Expressive.CollapsingToolbar: collapsed{Title,Subtitle}TextAppearance
276
+ // = @macro/m3_comp_app_bar_small_{title,subtitle}_font,
277
+ // {collapsed,expanded}{Title,Subtitle}TextColor
278
+ // = @macro/m3_comp_app_bar_{title,subtitle}_color.
279
+
280
+ applySlot(
281
+ view = ctl,
282
+ defaults =
283
+ TextAppearanceDefaults.resolve(wrappedContext, expandedTitleAttr, R.attr.colorOnSurface),
284
+ appearance = config.expandedTitleAppearance,
285
+ setColor = { ctl.setExpandedTitleTextColor(ColorStateList.valueOf(it)) },
286
+ setTypeface = { ctl.setExpandedTitleTypeface(it) },
287
+ setTextSizePx = { ctl.expandedTitleTextSize = it },
288
+ )
289
+ applySlot(
290
+ view = ctl,
291
+ defaults =
292
+ TextAppearanceDefaults.resolve(wrappedContext, R.attr.textAppearanceTitleLarge, R.attr.colorOnSurface),
293
+ appearance = config.collapsedTitleAppearance,
294
+ setColor = { ctl.setCollapsedTitleTextColor(it) },
295
+ setTypeface = { ctl.setCollapsedTitleTypeface(it) },
296
+ setTextSizePx = { ctl.collapsedTitleTextSize = it },
297
+ )
298
+ applySlot(
299
+ view = ctl,
300
+ defaults =
301
+ TextAppearanceDefaults.resolve(wrappedContext, expandedSubtitleAttr, R.attr.colorOnSurfaceVariant),
302
+ appearance = config.expandedSubtitleAppearance,
303
+ setColor = { ctl.setExpandedSubtitleTextColor(ColorStateList.valueOf(it)) },
304
+ setTypeface = { ctl.setExpandedSubtitleTypeface(it) },
305
+ setTextSizePx = { ctl.expandedSubtitleTextSize = it },
306
+ )
307
+ applySlot(
308
+ view = ctl,
309
+ defaults =
310
+ TextAppearanceDefaults.resolve(wrappedContext, R.attr.textAppearanceLabelMedium, R.attr.colorOnSurfaceVariant),
311
+ appearance = config.collapsedSubtitleAppearance,
312
+ setColor = { ctl.setCollapsedSubtitleTextColor(it) },
313
+ setTypeface = { ctl.setCollapsedSubtitleTypeface(it) },
314
+ setTextSizePx = { ctl.collapsedSubtitleTextSize = it },
315
+ )
316
+
317
+ // Layout is necessary e.g. after changing subtitle text size.
318
+ ctl.requestLayout()
319
+ }
320
+ }
321
+ }
322
+
323
+ /**
324
+ * Applies one title/subtitle slot as absolute values: each property is the prop value when
325
+ * set, the Material default otherwise.
326
+ */
327
+ private fun applySlot(
328
+ view: View,
329
+ defaults: TextAppearanceDefaults,
330
+ appearance: TextAppearance,
331
+ setColor: (Int) -> Unit,
332
+ setTypeface: (Typeface) -> Unit,
333
+ setTextSizePx: (Float) -> Unit,
334
+ ) {
335
+ setColor(appearance.color ?: defaults.color)
336
+ setTypeface(appearance.resolveTypeface(defaults.typeface))
337
+ setTextSizePx(appearance.fontSize?.let { view.spToPx(it) } ?: defaults.textSizePx)
338
+ }
339
+
340
+ internal fun applyContentInsets(
341
+ appBar: StackHeaderAppBarLayout,
342
+ config: StackHeaderConfigurationProviding,
343
+ ) {
344
+ val toolbar = appBar.toolbar
345
+
346
+ toolbar.setContentInsetsRelative(
347
+ config.contentInsetStart?.let { toolbar.dpToPx(it).roundToInt() } ?: appBar.defaultContentInsetStart,
348
+ config.contentInsetEnd?.let { toolbar.dpToPx(it).roundToInt() } ?: appBar.defaultContentInsetEnd,
349
+ )
350
+
351
+ toolbar.requestLayout()
352
+ }
353
+
354
+ internal fun applyBackButton(
200
355
  toolbar: MaterialToolbar,
201
356
  config: StackHeaderConfigurationProviding,
202
357
  canNavigateBack: Boolean,
@@ -215,9 +370,15 @@ internal class StackHeaderApplicator(
215
370
  val baseDrawable =
216
371
  config.backButtonIcon
217
372
  ?.let { getResizedDrawable(toolbar, it) }
218
- ?: resolveDefaultBackButtonIcon()
373
+ ?: resolveDefaultBackButtonIcon(toolbar)
374
+
375
+ val tintList =
376
+ buildTintList(
377
+ config.backButtonTintColorNormal,
378
+ config.backButtonTintColorPressed,
379
+ config.backButtonTintColorFocused,
380
+ )
219
381
 
220
- val tintList = resolveBackButtonTintList(config)
221
382
  toolbar.navigationIcon =
222
383
  if (tintList != null && baseDrawable != null) {
223
384
  DrawableCompat.wrap(baseDrawable.mutate()).also {
@@ -230,7 +391,33 @@ internal class StackHeaderApplicator(
230
391
  toolbar.setNavigationOnClickListener { onNavigationIconClick() }
231
392
  }
232
393
 
233
- fun applyScrollFlags(
394
+ internal fun applyOverflowIcon(
395
+ toolbar: MaterialToolbar,
396
+ config: StackHeaderConfigurationProviding,
397
+ ) {
398
+ val baseDrawable =
399
+ config.overflowIcon
400
+ ?.let { getResizedDrawable(toolbar, it) }
401
+ ?: resolveDefaultOverflowIcon(toolbar)
402
+
403
+ val tintList =
404
+ buildTintList(
405
+ config.overflowIconTintColorNormal,
406
+ config.overflowIconTintColorPressed,
407
+ config.overflowIconTintColorFocused,
408
+ )
409
+
410
+ toolbar.overflowIcon =
411
+ if (tintList != null && baseDrawable != null) {
412
+ DrawableCompat.wrap(baseDrawable.mutate()).also {
413
+ DrawableCompat.setTintList(it, tintList)
414
+ }
415
+ } else {
416
+ baseDrawable
417
+ }
418
+ }
419
+
420
+ internal fun applyScrollFlags(
234
421
  appBar: StackHeaderAppBarLayout,
235
422
  config: StackHeaderConfigurationProviding,
236
423
  ) {
@@ -249,300 +436,137 @@ internal class StackHeaderApplicator(
249
436
  appBar.setExpanded(true, false)
250
437
  }
251
438
 
252
- // endregion
253
-
254
- // region Toolbar menu
255
-
256
- fun generateToolbarMenuItemMappings(menuConfig: StackHeaderToolbarMenuConfig): Pair<Map<String, Int>, Map<Int, String>> {
257
- val forwardIdMap = mutableMapOf<String, Int>()
258
- val reverseIdMap = mutableMapOf<Int, String>()
259
- var counter = 1
260
- assignElementIds(menuConfig.children, forwardIdMap, reverseIdMap) { counter++ }
261
- return Pair(forwardIdMap.toMap(), reverseIdMap.toMap())
262
- }
263
-
264
- fun generateToolbarMenuGroupMappings(menuConfig: StackHeaderToolbarMenuConfig): Map<String, Int> {
265
- val forwardGroupIdMap = mutableMapOf<String, Int>()
266
- var counter = 1
267
- assignGroupIds(menuConfig, forwardGroupIdMap) { counter++ }
268
- return forwardGroupIdMap.toMap()
269
- }
270
-
271
- fun computeGroupMetadata(menuConfig: StackHeaderToolbarMenuConfig): StackHeaderToolbarMenuGroupMetadata {
272
- val itemGroupMap = mutableMapOf<String, String>()
273
- val groupSingleSelection = mutableMapOf<String, Boolean>()
274
- val groupMemberItems = mutableMapOf<String, MutableList<String>>()
275
- collectGroupMetadata(menuConfig, itemGroupMap, groupSingleSelection, groupMemberItems)
276
- return StackHeaderToolbarMenuGroupMetadata(
277
- itemGroupMap,
278
- groupSingleSelection,
279
- groupMemberItems.mapValues { it.value.toList() },
280
- )
281
- }
282
-
283
- fun validateRadioInitialSelection(menuConfig: StackHeaderToolbarMenuConfig) {
284
- for (group in menuConfig.groups) {
285
- if (!group.singleSelection) continue
286
- var count = 0
287
- for (element in menuConfig.children) {
288
- if (element.item.groupId == group.groupId && element.item.initialToggleState) {
289
- count++
290
- }
291
- }
292
- require(count <= 1) {
293
- "[RNScreens] Radio group '${group.groupId}' has $count items with " +
294
- "initialToggleState=true. At most 1 is allowed for single-selection groups."
295
- }
296
- }
297
- for (element in menuConfig.children) {
298
- if (element is StackHeaderToolbarMenuElementConfig.Submenu) {
299
- validateRadioInitialSelection(element.menu)
300
- }
301
- }
302
- }
303
-
304
439
  /**
305
- * Recursively traverses menu elements and maps user-friendly string item IDs to integers
306
- * expected by Android.
440
+ * Applies lift-on-scroll in-place. `setLiftOnScroll` is a plain field
441
+ * setter (re-read on the next layout / nested-scroll pass), so this needs
442
+ * no header rebuild.
307
443
  *
308
- * @param elements List of menu elements.
309
- * @param forwardIdMap Reference to String->Int ID map to which ID entries will be added.
310
- * @param reverseIdMap Reference to Int->String ID map to which ID entries will be added.
311
- * @param nextId Function that returns next ID integer. New unique integer should be returned
312
- * each time the function is called. The function is used to handle recursive
313
- * element traversal.
314
- */
315
- private fun assignElementIds(
316
- elements: List<StackHeaderToolbarMenuElementConfig>,
317
- forwardIdMap: MutableMap<String, Int>,
318
- reverseIdMap: MutableMap<Int, String>,
319
- nextId: () -> Int,
320
- ) {
321
- for (element in elements) {
322
- require(element.item.id !in forwardIdMap) {
323
- "[RNScreens] Duplicate toolbar menu item id: '${element.item.id}'. Item IDs must be unique across the entire menu."
324
- }
325
- val nativeId = nextId()
326
- forwardIdMap[element.item.id] = nativeId
327
- reverseIdMap[nativeId] = element.item.id
328
- if (element is StackHeaderToolbarMenuElementConfig.Submenu) {
329
- assignElementIds(element.menu.children, forwardIdMap, reverseIdMap, nextId)
330
- }
331
- }
332
- }
333
-
334
- /**
335
- * Recursively traverses menu elements and maps user-friendly string group IDs to integers
336
- * expected by Android.
444
+ * Only the small header participates: medium/large (collapsing) headers
445
+ * derive their elevation from the `CollapsingToolbarLayout` content scrim,
446
+ * not from lift-on-scroll, so we leave their app bar untouched.
337
447
  *
338
- * @param elements List of menu elements.
339
- * @param forwardIdMap Reference to String->Int ID map to which ID entries will be added.
340
- * @param reverseIdMap Reference to Int->String ID map to which ID entries will be added.
341
- * @param nextId Function that returns next ID integer. New unique integer should be returned
342
- * each time the function is called. The function is used to handle recursive
343
- * element traversal.
448
+ * [targetScrollView] is the resolved content scroll view (see
449
+ * [com.swmansion.rnscreens.common.container.ContainerItem.findContentScrollView]).
450
+ * Without it, Material's `findFirstScrollingChild` only inspects the
451
+ * CoordinatorLayout's direct children — which is our wrapper `FrameLayout`,
452
+ * not the (deeply nested) scroll view — so the lifted state is miscomputed
453
+ * and the small header flashes while scrolling.
344
454
  */
345
- private fun assignGroupIds(
346
- menuConfig: StackHeaderToolbarMenuConfig,
347
- forwardMap: MutableMap<String, Int>,
348
- nextId: () -> Int,
455
+ internal fun applyLiftOnScroll(
456
+ appBar: StackHeaderAppBarLayout,
457
+ enabled: Boolean,
458
+ targetScrollView: ViewGroup?,
349
459
  ) {
350
- for (group in menuConfig.groups) {
351
- require(group.groupId !in forwardMap) {
352
- "[RNScreens] Duplicate toolbar menu group id: '${group.groupId}'. Group IDs must be unique across the entire menu."
353
- }
354
- forwardMap[group.groupId] = nextId()
355
- }
356
- for (element in menuConfig.children) {
357
- if (element is StackHeaderToolbarMenuElementConfig.Submenu) {
358
- assignGroupIds(element.menu, forwardMap, nextId)
359
- }
360
- }
361
- }
460
+ if (appBar !is StackHeaderAppBarLayout.Small) return
362
461
 
363
- private fun collectGroupMetadata(
364
- config: StackHeaderToolbarMenuConfig,
365
- itemGroupMap: MutableMap<String, String>,
366
- groupSingleSelection: MutableMap<String, Boolean>,
367
- groupMemberItems: MutableMap<String, MutableList<String>>,
368
- ) {
369
- val localGroupIds = config.groups.map { it.groupId }.toSet()
370
- for (group in config.groups) {
371
- groupSingleSelection[group.groupId] = group.singleSelection
372
- groupMemberItems.getOrPut(group.groupId) { mutableListOf() }
373
- }
374
- for (element in config.children) {
375
- element.item.groupId?.let { gid ->
376
- require(gid in localGroupIds) {
377
- "[RNScreens] Menu item '${element.item.id}' references group '$gid' " +
378
- "which is not defined at the same menu level. " +
379
- "Groups cannot span submenus."
380
- }
381
- itemGroupMap[element.item.id] = gid
382
- groupMemberItems[gid]!!.add(element.item.id)
383
- }
384
- if (element is StackHeaderToolbarMenuElementConfig.Submenu) {
385
- collectGroupMetadata(element.menu, itemGroupMap, groupSingleSelection, groupMemberItems)
386
- }
387
- }
462
+ appBar.isLiftOnScroll = enabled
463
+ appBar.setLiftOnScrollTargetView(if (enabled) targetScrollView else null)
464
+ appBar.requestLayout()
388
465
  }
389
466
 
390
- fun rebuildToolbarMenu(
391
- toolbar: MaterialToolbar,
392
- menuConfig: StackHeaderToolbarMenuConfig,
393
- forwardIdMap: Map<String, Int>,
394
- reverseIdMap: Map<Int, String>,
395
- forwardGroupIdMap: Map<String, Int>,
396
- groupDividerEnabled: Boolean,
397
- onItemClicked: (id: String, menuItem: MenuItem) -> Unit,
467
+ internal fun applyBackgroundColors(
468
+ appBar: StackHeaderAppBarLayout,
469
+ config: StackHeaderConfigurationProviding,
398
470
  ) {
399
- toolbar.menu.clear()
400
- addElements(toolbar, toolbar.menu, menuConfig, forwardIdMap, forwardGroupIdMap)
401
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
402
- toolbar.menu.setGroupDividerEnabled(groupDividerEnabled)
403
- }
404
- toolbar.setOnMenuItemClickListener { menuItem ->
405
- val stringId = reverseIdMap[menuItem.itemId]
406
- if (stringId != null) {
407
- onItemClicked(stringId, menuItem)
471
+ // Widget.Material3Expressive.AppBarLayout (an empty alias of Widget.Material3.AppBarLayout)
472
+ // #android:background = @macro/m3_comp_app_bar_container_color.
473
+ val backgroundColor =
474
+ config.backgroundColor ?: resolveColorAttr(appBar.context, R.attr.colorSurface)
475
+
476
+ // Both header kinds default to the same token, from different places:
477
+ // small — ...AppBarLayout#liftOnScrollColor
478
+ // = @macro/m3_comp_app_bar_on_scroll_container_color;
479
+ // collapsing — the M3 CollapsingToolbar styles set no contentScrim, so CTL installs its
480
+ // own default for titleCollapseMode=fade (getDefaultContentScrimColorForTitleCollapseFadeMode).
481
+ val scrolledBackgroundColor =
482
+ config.scrolledBackgroundColor
483
+ ?: resolveColorAttr(appBar.context, R.attr.colorSurfaceContainer)
484
+
485
+ val background =
486
+ MaterialShapeDrawable().apply {
487
+ fillColor = ColorStateList.valueOf(backgroundColor)
408
488
  }
409
- true
410
- }
411
- }
412
489
 
413
- private fun addElements(
414
- toolbar: MaterialToolbar,
415
- menu: Menu,
416
- menuConfig: StackHeaderToolbarMenuConfig,
417
- forwardIdMap: Map<String, Int>,
418
- forwardGroupIdMap: Map<String, Int>,
419
- ) {
420
- menuConfig.children.forEachIndexed { index, element ->
421
- val itemId =
422
- requireNotNull(forwardIdMap[element.item.id]) {
423
- "[RNScreens] Invalid forwardIdMap received. Missing item: ${element.item}."
424
- }
425
- val groupIntId =
426
- element.item.groupId
427
- ?.let { forwardGroupIdMap[it] ?: Menu.NONE }
428
- ?: Menu.NONE
429
- when (element) {
430
- is StackHeaderToolbarMenuElementConfig.MenuItem -> {
431
- val menuItem = menu.add(groupIntId, itemId, index, null)
432
- applyMenuElementOptions(toolbar, menuItem, element.item.toOptions())
433
- applyCheckability(menuItem, element.item)
434
- }
435
- is StackHeaderToolbarMenuElementConfig.Submenu -> {
436
- val subMenu = menu.addSubMenu(groupIntId, itemId, index, null)
437
- applyMenuElementOptions(toolbar, subMenu.item, element.item.toOptions())
438
- element.menuTitle?.let { subMenu.setHeaderTitle(it) }
439
- addElements(toolbar, subMenu, element.menu, forwardIdMap, forwardGroupIdMap)
490
+ when (appBar) {
491
+ is StackHeaderAppBarLayout.Small -> {
492
+ appBar.background = background
493
+ appBar.setLiftOnScrollColor(ColorStateList.valueOf(scrolledBackgroundColor))
494
+
495
+ // The lift animation runs only on lifted-state changes; jump to the end
496
+ // state when colors change while already lifted. The end state is the
497
+ // scrolled color composited over the background (see Material's
498
+ // initializeLiftOnScrollWithColor), not the raw scrolled color — they
499
+ // differ when the scrolled color is not fully opaque.
500
+ if (appBar.isLifted) {
501
+ background.fillColor =
502
+ ColorStateList.valueOf(
503
+ MaterialColors.layer(backgroundColor, scrolledBackgroundColor),
504
+ )
440
505
  }
441
506
  }
442
- }
443
- configureGroupCheckability(menu, menuConfig.groups, forwardGroupIdMap)
444
- }
445
-
446
- private fun configureGroupCheckability(
447
- menu: Menu,
448
- groups: List<StackHeaderToolbarMenuGroupConfig>,
449
- forwardGroupIdMap: Map<String, Int>,
450
- ) {
451
- for (group in groups) {
452
- val groupIntId = forwardGroupIdMap[group.groupId] ?: continue
453
- menu.setGroupCheckable(groupIntId, true, group.singleSelection)
454
- }
455
- }
456
507
 
457
- private fun applyCheckability(
458
- menuItem: MenuItem,
459
- itemConfig: StackHeaderToolbarMenuItemConfig,
460
- ) {
461
- val shouldBeCheckable =
462
- when (itemConfig.itemType) {
463
- StackHeaderToolbarMenuItemType.TOGGLE -> {
464
- require(itemConfig.groupId != null) {
465
- "[RNScreens] Menu item '${itemConfig.id}' has itemType=TOGGLE but no groupId. " +
466
- "Toggle items must belong to a group."
467
- }
468
- true
469
- }
470
- StackHeaderToolbarMenuItemType.AUTOMATIC -> itemConfig.groupId != null
471
- StackHeaderToolbarMenuItemType.ACTION -> {
472
- require(itemConfig.groupId == null) {
473
- "[RNScreens] Menu item '${itemConfig.id}' has itemType=ACTION " +
474
- "and belongs to a group. Action items cannot belong to groups."
475
- }
476
- false
477
- }
508
+ is StackHeaderAppBarLayout.Collapsing -> {
509
+ // Fade collapse mode disables liftOnScroll, but the lift animation only checks the
510
+ // lift color. We set it to null so the fill stays at backgroundColor under the
511
+ // transparent/translucent content scrim.
512
+ appBar.setLiftOnScrollColor(null)
513
+ appBar.background = background
514
+ appBar.collapsingToolbarLayout.contentScrim =
515
+ StackHeaderContentScrimDrawable(scrolledBackgroundColor)
478
516
  }
479
- if (shouldBeCheckable) {
480
- menuItem.isCheckable = true
481
- menuItem.isChecked = itemConfig.initialToggleState
482
517
  }
483
- }
484
518
 
485
- fun updateToolbarMenuElement(
486
- toolbar: MaterialToolbar,
487
- forwardIdMap: Map<String, Int>,
488
- id: String,
489
- options: StackHeaderToolbarMenuElementOptions,
490
- ) {
491
- val item =
492
- forwardIdMap[id]?.let { toolbar.menu.findItem(it) } ?: run {
493
- Log.e(TAG, "[RNScreens] Unable to find menu element.")
494
- return
495
- }
496
- applyMenuElementOptions(toolbar, item, options)
519
+ applyStatusBarScrim(appBar, config, backgroundColor, scrolledBackgroundColor)
497
520
  }
498
521
 
499
- private fun applyMenuElementOptions(
500
- toolbar: MaterialToolbar,
501
- menuItem: MenuItem,
502
- options: StackHeaderToolbarMenuElementOptions,
522
+ private fun applyStatusBarScrim(
523
+ appBar: StackHeaderAppBarLayout,
524
+ config: StackHeaderConfigurationProviding,
525
+ backgroundColor: Int,
526
+ scrolledBackgroundColor: Int,
503
527
  ) {
504
- options.title?.let { menuItem.title = it.valueOrNull() }
505
- options.titleCondensed?.let { menuItem.titleCondensed = it.valueOrNull() }
506
- options.tooltipText?.let { MenuItemCompat.setTooltipText(menuItem, it.valueOrNull()) }
507
- options.accessibilityLabel?.let {
508
- // Setting `null` will restore Android's default (`title` for items
509
- // in toolbar, `null` otherwise).
510
- MenuItemCompat.setContentDescription(menuItem, it.valueOrNull())
511
- }
512
- options.hidden?.let { menuItem.isVisible = !it }
513
- options.disabled?.let { menuItem.isEnabled = !it }
514
- options.showAsAction?.let { menuItem.setShowAsAction(it.toNativeShowAsAction()) }
515
-
516
- // checked is intentionally not handled here. The coordinator layout manages it in
517
- // applyGroupItemStateChange because toggling checked state requires group metadata
518
- // (radio vs checkbox) and may emit onGroupSelectionChanged events.
519
-
520
- options.icon?.let {
521
- when (it) {
522
- StackHeaderToolbarFieldUpdate.Reset -> menuItem.icon = null
523
- is StackHeaderToolbarFieldUpdate.Set<Drawable> ->
524
- menuItem.icon = getResizedDrawable(toolbar, it.value)
528
+ when (appBar) {
529
+ is StackHeaderAppBarLayout.Small -> {
530
+ val scrimColor = resolveStatusBarScrimColor(config, drivingColor = backgroundColor)
531
+ val autoFollow = scrimColor != null && config.statusBarScrimColor == null
532
+ appBar.setStatusBarScrimSyncEnabled(autoFollow)
533
+ appBar.statusBarForeground?.setTint(
534
+ when {
535
+ scrimColor == null -> Color.TRANSPARENT
536
+ // Same lifted jump as the background fill in applyBackgroundColors.
537
+ autoFollow && appBar.isLifted ->
538
+ MaterialColors.layer(backgroundColor, scrolledBackgroundColor)
539
+ else -> scrimColor
540
+ },
541
+ )
525
542
  }
526
- }
527
-
528
- if (options.requiresIconTintColorUpdate || options.icon != null) {
529
- MenuItemCompat.setIconTintList(menuItem, getResolvedIconTintList(menuItem, options))
530
- }
531
543
 
532
- options.menuTitle?.let { update ->
533
- val subMenu = menuItem.subMenu
534
- if (subMenu != null) {
535
- // In order to match native behavior, we need to clear the header first and then use
536
- // regular title if menuTitle is not provided. If title is also null, there will be
537
- // no submenu header at all.
538
- subMenu.clearHeader()
539
- subMenu.setHeaderTitle(update.valueOrNull() ?: menuItem.title)
540
- } else {
541
- Log.w(TAG, "[RNScreens] menuTitle ignored: target is not a submenu.")
544
+ is StackHeaderAppBarLayout.Collapsing -> {
545
+ // Defaulting to the content scrim color masks toolbar content passing
546
+ // through the status-bar area (scroll-only flags) and is a visual
547
+ // no-op in the opaque exitUntilCollapsed case. An invisible scrim is
548
+ // normalized to null so the content scrim exclusion can key on scrim
549
+ // presence alone.
550
+ val scrimColor =
551
+ resolveStatusBarScrimColor(config, drivingColor = scrolledBackgroundColor)
552
+ ?.takeIf { Color.alpha(it) > 0 }
553
+ if (scrimColor != null) {
554
+ appBar.collapsingToolbarLayout.setStatusBarScrimColor(scrimColor)
555
+ } else {
556
+ appBar.collapsingToolbarLayout.statusBarScrim = null
557
+ }
558
+ appBar.updateContentScrimExclusion()
542
559
  }
543
560
  }
544
561
  }
545
562
 
563
+ // The default scrim exists only for an opaque driving color — a translucent
564
+ // scrim would double-composite over the layer it covers.
565
+ private fun resolveStatusBarScrimColor(
566
+ config: StackHeaderConfigurationProviding,
567
+ drivingColor: Int,
568
+ ): Int? = config.statusBarScrimColor ?: drivingColor.takeIf { Color.alpha(it) == 0xFF }
569
+
546
570
  // endregion
547
571
 
548
572
  // region Helpers
@@ -571,7 +595,21 @@ internal class StackHeaderApplicator(
571
595
  }
572
596
  }
573
597
 
574
- private fun resolveDefaultBackButtonIcon(): Drawable? = resolveDrawableAttr(wrappedContext, androidx.appcompat.R.attr.homeAsUpIndicator)
598
+ // Default icon drawables must load through the toolbar's snapshot context, not
599
+ // wrappedContext: on Android 14+ the framework's themed resource cache returns stale
600
+ // entries for a Theme mutated in place by setTheme (ThemeKey dedup + shallow clone),
601
+ // freezing the icon tint after a color scheme change. The toolbar wrapper's theme is
602
+ // created fresh on every rebuild, so its cache entries always match the current palette.
603
+ // Plain attribute resolution (e.g. text appearance defaults) doesn't hit that cache and
604
+ // stays on the live wrappedContext.
605
+ private fun resolveDefaultBackButtonIcon(toolbar: MaterialToolbar): Drawable? =
606
+ resolveDrawableAttr(toolbar.context, androidx.appcompat.R.attr.homeAsUpIndicator)
607
+
608
+ // Mirrors how the toolbar's own overflow button obtains its icon: an AppCompatImageView built
609
+ // with actionOverflowButtonStyle resolves the theme's srcCompat and applies AppCompat's
610
+ // colorControlNormal auto-tint.
611
+ private fun resolveDefaultOverflowIcon(toolbar: MaterialToolbar): Drawable? =
612
+ AppCompatImageView(toolbar.context, null, androidx.appcompat.R.attr.actionOverflowButtonStyle).drawable
575
613
 
576
614
  private fun maybeApplyRTLCollapsingToolbarLayoutWorkaround(
577
615
  coordinatorLayout: StackHeaderCoordinatorLayout,
@@ -613,27 +651,11 @@ internal class StackHeaderApplicator(
613
651
  }
614
652
  }
615
653
 
616
- private fun StackHeaderToolbarMenuItemConfig.toOptions() =
617
- StackHeaderToolbarMenuElementOptions(
618
- title = StackHeaderToolbarFieldUpdate.from(title),
619
- titleCondensed = StackHeaderToolbarFieldUpdate.from(titleCondensed),
620
- tooltipText = StackHeaderToolbarFieldUpdate.from(tooltipText),
621
- accessibilityLabel = StackHeaderToolbarFieldUpdate.from(accessibilityLabel),
622
- hidden = hidden,
623
- disabled = disabled,
624
- showAsAction = showAsAction,
625
- icon = StackHeaderToolbarFieldUpdate.from(icon),
626
- iconTintColorNormal = StackHeaderToolbarFieldUpdate.from(iconTintColorNormal),
627
- iconTintColorPressed = StackHeaderToolbarFieldUpdate.from(iconTintColorPressed),
628
- iconTintColorFocused = StackHeaderToolbarFieldUpdate.from(iconTintColorFocused),
629
- iconTintColorDisabled = StackHeaderToolbarFieldUpdate.from(iconTintColorDisabled),
630
- )
631
-
632
- private fun resolveBackButtonTintList(config: StackHeaderConfigurationProviding): ColorStateList? {
633
- val normal = config.backButtonTintColorNormal
634
- val pressed = config.backButtonTintColorPressed
635
- val focused = config.backButtonTintColorFocused
636
-
654
+ private fun buildTintList(
655
+ normal: Int?,
656
+ pressed: Int?,
657
+ focused: Int?,
658
+ ): ColorStateList? {
637
659
  if (normal == null && pressed == null && focused == null) return null
638
660
 
639
661
  val states = mutableListOf<IntArray>()
@@ -655,108 +677,9 @@ internal class StackHeaderApplicator(
655
677
  return ColorStateList(states.toTypedArray(), colors.toIntArray())
656
678
  }
657
679
 
658
- private fun getResolvedIconTintList(
659
- menuItem: MenuItem,
660
- options: StackHeaderToolbarMenuElementOptions,
661
- ): ColorStateList? {
662
- val currentTintList = MenuItemCompat.getIconTintList(menuItem)
663
- // The currently-applied normal (catch-all) color, if any. Used both as the "leave
664
- // unchanged" value for normal and to dedup read-back overrides: when a normal entry
665
- // exists every override probe also matches it, so an override equal to the current
666
- // normal is the catch-all leaking through rather than an explicit override.
667
- val currentNormal = currentTintList?.resolvedColorOrNull(intArrayOf(android.R.attr.state_enabled))
668
-
669
- val finalNormal =
670
- when (val update = options.iconTintColorNormal) {
671
- StackHeaderToolbarFieldUpdate.Reset -> null
672
- is StackHeaderToolbarFieldUpdate.Set -> update.value
673
- null -> currentNormal
674
- }
675
-
676
- val finalDisabled =
677
- when (val update = options.iconTintColorDisabled) {
678
- StackHeaderToolbarFieldUpdate.Reset -> null
679
- is StackHeaderToolbarFieldUpdate.Set -> update.value
680
- null ->
681
- currentTintList
682
- ?.resolvedColorOrNull(intArrayOf(-android.R.attr.state_enabled))
683
- ?.takeIf { it != currentNormal }
684
- }
685
-
686
- val finalPressed =
687
- when (val update = options.iconTintColorPressed) {
688
- StackHeaderToolbarFieldUpdate.Reset -> null
689
- is StackHeaderToolbarFieldUpdate.Set -> update.value
690
- null ->
691
- currentTintList
692
- ?.resolvedColorOrNull(intArrayOf(android.R.attr.state_enabled, android.R.attr.state_pressed))
693
- ?.takeIf { it != currentNormal }
694
- }
695
-
696
- val finalFocused =
697
- when (val update = options.iconTintColorFocused) {
698
- StackHeaderToolbarFieldUpdate.Reset -> null
699
- is StackHeaderToolbarFieldUpdate.Set -> update.value
700
- null ->
701
- currentTintList
702
- ?.resolvedColorOrNull(intArrayOf(android.R.attr.state_enabled, android.R.attr.state_focused))
703
- ?.takeIf { it != currentNormal }
704
- }
705
-
706
- val states = mutableListOf<IntArray>()
707
- val colors = mutableListOf<Int>()
708
-
709
- finalDisabled?.let {
710
- states.add(intArrayOf(-android.R.attr.state_enabled))
711
- colors.add(it)
712
- }
713
-
714
- finalPressed?.let {
715
- states.add(intArrayOf(android.R.attr.state_pressed))
716
- colors.add(it)
717
- }
718
-
719
- finalFocused?.let {
720
- states.add(intArrayOf(android.R.attr.state_focused))
721
- colors.add(it)
722
- }
723
-
724
- finalNormal?.let {
725
- states.add(intArrayOf())
726
- colors.add(it)
727
- }
728
-
729
- return if (states.isNotEmpty()) {
730
- ColorStateList(states.toTypedArray(), colors.toIntArray())
731
- } else {
732
- null
733
- }
734
- }
735
-
736
- /**
737
- * Resolves the color the receiver applies to [stateSet], or `null` when no state spec
738
- * matches it.
739
- *
740
- * `getColorForState` returns the caller-supplied fallback when nothing matches, so we
741
- * probe twice with two distinct sentinels: equal results mean a real spec matched (the
742
- * actual color), differing results mean the slot is absent. This is robust for any color
743
- * value and keeps the read-back stateless — see [getResolvedIconTintList].
744
- */
745
- private fun ColorStateList.resolvedColorOrNull(stateSet: IntArray): Int? {
746
- val a = getColorForState(stateSet, SENTINEL_A)
747
- val b = getColorForState(stateSet, SENTINEL_B)
748
- return if (a == b) a else null
749
- }
750
-
751
680
  // endregion
752
681
 
753
682
  companion object {
754
683
  private const val TAG = "StackHeaderApplicator"
755
-
756
- // Two distinct sentinel fallbacks used to detect whether a ColorStateList actually
757
- // defines a color for a given state. Their concrete values are irrelevant as long as
758
- // they differ — see resolvedColorOrNull.
759
- private const val SENTINEL_A = 0x00000001
760
- private const val SENTINEL_B = 0x00000002
761
684
  }
762
685
  }