react-native-screens 5.0.0-alpha.2 → 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 (237) hide show
  1. package/Package.swift +87 -0
  2. package/README.md +0 -7
  3. package/android/src/main/cpp/NativeProxy.cpp +30 -6
  4. package/android/src/main/cpp/NativeProxy.h +7 -1
  5. package/android/src/main/java/com/swmansion/rnscreens/common/container/Container.kt +8 -0
  6. package/android/src/main/java/com/swmansion/rnscreens/common/container/ContainerItem.kt +13 -1
  7. package/android/src/main/java/com/swmansion/rnscreens/common/text/ReactTextAppearance.kt +62 -0
  8. package/android/src/main/java/com/swmansion/rnscreens/common/text/TextAppearance.kt +20 -0
  9. package/android/src/main/java/com/swmansion/rnscreens/common/text/TextAppearanceDefaults.kt +65 -0
  10. package/android/src/main/java/com/swmansion/rnscreens/helpers/PropIconResolver.kt +17 -23
  11. package/android/src/main/java/com/swmansion/rnscreens/legacy/Screen.kt +3 -1
  12. package/android/src/main/java/com/swmansion/rnscreens/legacy/ScreenStack.kt +2 -0
  13. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/coordinator/FormSheetBehaviorController.kt +49 -18
  14. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/coordinator/FormSheetDimensionsCoordinator.kt +65 -40
  15. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/coordinator/FormSheetKeyboardCoordinator.kt +101 -0
  16. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/coordinator/FormSheetNativeDismissCoordinator.kt +0 -6
  17. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/core/FormSheetAvailableHeightProvider.kt +44 -0
  18. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/core/FormSheetDialog.kt +35 -3
  19. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/core/FormSheetDialogManager.kt +33 -106
  20. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/interfaces/FormSheetDialogEventEmitter.kt +2 -0
  21. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/model/FormSheetDetents.kt +61 -15
  22. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetAnimatorFactory.kt +8 -9
  23. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetDimmingManager.kt +115 -0
  24. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetDismissalOrigin.kt +22 -0
  25. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetPresentation.kt +173 -0
  26. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetPresentationManager.kt +141 -49
  27. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetPresentationState.kt +1 -1
  28. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/native/presentation/FormSheetStackRegistry.kt +28 -0
  29. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/react/event/FormSheetDismissEvent.kt +29 -0
  30. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/react/host/FormSheetHostEventEmitter.kt +7 -0
  31. package/android/src/main/java/com/swmansion/rnscreens/modals/formsheet/react/host/FormSheetHostViewManager.kt +2 -0
  32. package/android/src/main/java/com/swmansion/rnscreens/stack/header/StackHeaderApplicator.kt +369 -58
  33. package/android/src/main/java/com/swmansion/rnscreens/stack/header/StackHeaderBackPressHandler.kt +11 -0
  34. package/android/src/main/java/com/swmansion/rnscreens/stack/header/StackHeaderCoordinatorLayout.kt +143 -98
  35. package/android/src/main/java/com/swmansion/rnscreens/stack/header/appbar/StackHeaderAppBarLayout.kt +155 -23
  36. package/android/src/main/java/com/swmansion/rnscreens/stack/header/appbar/StackHeaderContentScrimDrawable.kt +36 -0
  37. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderCollapsedTitleGravityMode.kt +6 -0
  38. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderConfig.kt +170 -167
  39. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderConfigViewManager.kt +385 -12
  40. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderConfigurationObserver.kt +0 -4
  41. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderConfigurationProviding.kt +32 -3
  42. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderDelegate.kt +0 -7
  43. package/android/src/main/java/com/swmansion/rnscreens/stack/header/config/StackHeaderInvalidationFlags.kt +7 -2
  44. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/StackHeaderToolbarMenuApplicator.kt +27 -280
  45. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/StackHeaderToolbarMenuController.kt +448 -0
  46. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/StackHeaderToolbarMenuDelegate.kt +10 -0
  47. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/StackHeaderToolbarMenuMapper.kt +28 -20
  48. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/model/StackHeaderToolbarMenuConfig.kt +3 -55
  49. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/model/StackHeaderToolbarMenuGroupMetadata.kt +1 -10
  50. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/model/StackHeaderToolbarMenuItemConfig.kt +1 -3
  51. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/model/StackHeaderToolbarMenuModel.kt +180 -0
  52. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/update/StackHeaderToolbarMenuElementOptions.kt +57 -6
  53. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/update/StackHeaderToolbarMenuElementRawUpdate.kt +3 -1
  54. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/update/StackHeaderToolbarMenuElementUpdate.kt +1 -0
  55. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/update/StackHeaderToolbarMenuIconResolver.kt +4 -3
  56. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/update/StackHeaderToolbarMenuUpdateQueue.kt +23 -9
  57. package/android/src/main/java/com/swmansion/rnscreens/stack/host/StackContainer.kt +103 -3
  58. package/android/src/main/java/com/swmansion/rnscreens/stack/host/StackHost.kt +13 -0
  59. package/android/src/main/java/com/swmansion/rnscreens/stack/host/StackHostViewManager.kt +14 -0
  60. package/android/src/main/java/com/swmansion/rnscreens/stack/screen/StackScreen.kt +4 -0
  61. package/android/src/main/java/com/swmansion/rnscreens/stack/screen/StackScreenFragment.kt +20 -1
  62. package/android/src/main/java/com/swmansion/rnscreens/stack/screen/StackScreenFragmentDelegate.kt +12 -0
  63. package/android/src/main/java/com/swmansion/rnscreens/tabs/appearance/TabsAppearanceCoordinator.kt +2 -4
  64. package/android/src/main/java/com/swmansion/rnscreens/tabs/container/MenuHelpers.kt +5 -23
  65. package/android/src/main/java/com/swmansion/rnscreens/tabs/container/TabsContainer.kt +46 -25
  66. package/android/src/main/java/com/swmansion/rnscreens/tabs/host/TabsHost.kt +10 -0
  67. package/android/src/main/java/com/swmansion/rnscreens/tabs/host/TabsHostA11yCoordinator.kt +23 -2
  68. package/android/src/main/java/com/swmansion/rnscreens/tabs/screen/TabsScreen.kt +17 -0
  69. package/android/src/main/java/com/swmansion/rnscreens/tabs/screen/TabsScreenFragment.kt +3 -0
  70. package/android/src/main/java/com/swmansion/rnscreens/utils/DimensionUtils.kt +7 -0
  71. package/android/src/main/java/com/swmansion/rnscreens/utils/StyleUtils.kt +22 -0
  72. package/android/src/main/res/base/layout/rns_collapsing_toolbar_large_available_space.xml +8 -0
  73. package/android/src/main/res/base/layout/rns_collapsing_toolbar_large_entire_space.xml +8 -0
  74. package/android/src/main/res/base/layout/rns_collapsing_toolbar_medium_available_space.xml +8 -0
  75. package/android/src/main/res/base/layout/rns_collapsing_toolbar_medium_entire_space.xml +8 -0
  76. package/cpp/legacy/RNSScreenRemovalListener.cpp +31 -1
  77. package/cpp/legacy/RNSScreenRemovalListener.h +18 -3
  78. package/ios/RNSEnums.h +2 -0
  79. package/ios/conversion/RNSConversions.h +7 -108
  80. package/ios/legacy/RNSFullWindowOverlay.mm +1 -1
  81. package/ios/legacy/RNSModalScreen.mm +1 -1
  82. package/ios/legacy/RNSScreen.mm +8 -19
  83. package/ios/legacy/RNSScreenStackHeaderConfig.mm +3 -1
  84. package/ios/legacy/RNSScreenStackHeaderSubview.mm +1 -1
  85. package/ios/legacy/RNSScreenWindowTraits.mm +5 -13
  86. package/ios/modals/form-sheet/RNSFormSheetConfigurationApplicator.h +1 -3
  87. package/ios/modals/form-sheet/RNSFormSheetConfigurationApplicator.mm +11 -22
  88. package/ios/modals/form-sheet/RNSFormSheetContentController.h +1 -1
  89. package/ios/modals/form-sheet/RNSFormSheetContentController.mm +7 -18
  90. package/ios/modals/form-sheet/RNSFormSheetHostComponentView.mm +4 -4
  91. package/ios/modals/form-sheet/RNSFormSheetHostShadowStateProxy.mm +2 -2
  92. package/ios/modals/form-sheet/RNSFormSheetUpdateFlags.h +3 -0
  93. package/ios/safe-area/RNSSafeAreaViewComponentView.mm +2 -2
  94. package/ios/{conversion → scroll-view-marker/conversion}/RNSConversions-ScrollViewMarker.mm +2 -3
  95. package/ios/split/RNSSplitAppearanceApplicator.h +4 -4
  96. package/ios/split/RNSSplitAppearanceApplicator.mm +53 -56
  97. package/ios/split/RNSSplitHostComponentEventEmitter.h +1 -0
  98. package/ios/split/RNSSplitHostComponentEventEmitter.mm +1 -1
  99. package/ios/split/RNSSplitHostComponentView.h +5 -15
  100. package/ios/split/RNSSplitHostComponentView.mm +55 -6
  101. package/ios/split/RNSSplitHostController.h +25 -6
  102. package/ios/split/RNSSplitHostController.mm +24 -92
  103. package/ios/split/RNSSplitHostProviders.h +67 -0
  104. package/ios/split/RNSSplitScreenComponentView.h +0 -39
  105. package/ios/split/RNSSplitScreenComponentView.mm +27 -10
  106. package/ios/split/RNSSplitScreenController.h +26 -3
  107. package/ios/split/RNSSplitScreenController.mm +13 -30
  108. package/ios/split/RNSSplitScreenShadowStateProxy.h +1 -40
  109. package/ios/split/RNSSplitScreenShadowStateProxy.mm +1 -26
  110. package/ios/split/conversion/RNSConversions-SplitView.h +56 -0
  111. package/ios/{conversion → split/conversion}/RNSConversions-SplitView.mm +4 -1
  112. package/ios/stack/conversion/RNSConversions-Stack.h +32 -0
  113. package/ios/stack/conversion/RNSConversions-Stack.mm +55 -0
  114. package/ios/stack/header/RNSStackHeaderAppearanceMapper.h +26 -0
  115. package/ios/stack/header/RNSStackHeaderAppearanceMapper.mm +88 -0
  116. package/ios/stack/header/RNSStackHeaderConfigComponentView.h +10 -1
  117. package/ios/stack/header/RNSStackHeaderConfigComponentView.mm +67 -35
  118. package/ios/stack/header/RNSStackHeaderConfigDataProviding.h +6 -0
  119. package/ios/stack/header/RNSStackHeaderConfigShadowStateProxy.mm +1 -1
  120. package/ios/stack/header/RNSStackHeaderIconResolver.mm +7 -0
  121. package/ios/stack/header/RNSStackHeaderItemComponentView.h +3 -1
  122. package/ios/stack/header/RNSStackHeaderItemComponentView.mm +15 -2
  123. package/ios/stack/header/RNSStackHeaderItemDataProviding.h +2 -0
  124. package/ios/stack/header/RNSStackHeaderItemShadowStateProxy.mm +1 -1
  125. package/ios/stack/header/RNSStackHeaderItemSpacerComponentView.mm +2 -1
  126. package/ios/stack/header/RNSStackHeaderMenuMapper.mm +4 -0
  127. package/ios/stack/host/RNSStackNavigationBar.h +25 -0
  128. package/ios/stack/host/RNSStackNavigationBar.mm +80 -0
  129. package/ios/stack/host/RNSStackNavigationBarCoordinator.h +8 -0
  130. package/ios/stack/host/RNSStackNavigationBarCoordinator.mm +11 -0
  131. package/ios/stack/host/RNSStackNavigationController.mm +13 -5
  132. package/ios/stack/host/RNSStackOperation.h +0 -2
  133. package/ios/stack/screen/RNSStackScreenComponentView.mm +9 -2
  134. package/ios/stack/screen/RNSStackScreenController.mm +12 -0
  135. package/ios/stack/screen/RNSStackScreenHeaderCoordinator.h +8 -0
  136. package/ios/stack/screen/RNSStackScreenHeaderCoordinator.mm +98 -16
  137. package/ios/tabs/RNSTabBarAppearanceCoordinator.mm +40 -9
  138. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryComponentView.h +1 -1
  139. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryComponentView.mm +1 -1
  140. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryContentComponentView.mm +1 -1
  141. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryEventEmitter.mm +1 -1
  142. package/ios/tabs/bottom-accessory/RNSTabsBottomAccessoryShadowStateProxy.mm +1 -1
  143. package/ios/tabs/conversion/RNSConversions-Tabs.h +78 -0
  144. package/ios/{conversion → tabs/conversion}/RNSConversions-Tabs.mm +8 -71
  145. package/ios/tabs/extensions/RNSTabsHostComponentView+RNSImageLoader.h +1 -1
  146. package/ios/tabs/host/RNSTabsHostComponentView.h +2 -0
  147. package/ios/tabs/host/RNSTabsHostComponentView.mm +10 -3
  148. package/ios/tabs/host/RNSTabsHostEventEmitter.mm +1 -1
  149. package/ios/tabs/screen/RNSTabsScreenComponentView.mm +20 -5
  150. package/ios/utils/RNSDefines.h +3 -0
  151. package/lib/commonjs/components/stack/header/StackHeaderConfig.android.js +34 -19
  152. package/lib/commonjs/components/stack/header/StackHeaderConfig.android.js.map +1 -1
  153. package/lib/commonjs/components/stack/header/StackHeaderConfig.ios.js +33 -1
  154. package/lib/commonjs/components/stack/header/StackHeaderConfig.ios.js.map +1 -1
  155. package/lib/commonjs/components/stack/host/StackHost.js +9 -6
  156. package/lib/commonjs/components/stack/host/StackHost.js.map +1 -1
  157. package/lib/commonjs/components/stack/index.js.map +1 -1
  158. package/lib/commonjs/components/tabs/host/TabsHost.ios.js +1 -0
  159. package/lib/commonjs/components/tabs/host/TabsHost.ios.js.map +1 -1
  160. package/lib/commonjs/fabric/stack/StackHeaderConfigAndroidNativeComponent.js.map +1 -1
  161. package/lib/commonjs/fabric/stack/StackHeaderConfigIOSNativeComponent.js.map +1 -1
  162. package/lib/commonjs/fabric/stack/StackHeaderItemIOSNativeComponent.js.map +1 -1
  163. package/lib/commonjs/fabric/stack/StackHostNativeComponent.js.map +1 -1
  164. package/lib/commonjs/fabric/tabs/TabsHostIOSNativeComponent.js.map +1 -1
  165. package/lib/module/components/stack/header/StackHeaderConfig.android.js +35 -20
  166. package/lib/module/components/stack/header/StackHeaderConfig.android.js.map +1 -1
  167. package/lib/module/components/stack/header/StackHeaderConfig.ios.js +34 -2
  168. package/lib/module/components/stack/header/StackHeaderConfig.ios.js.map +1 -1
  169. package/lib/module/components/stack/host/StackHost.js +9 -6
  170. package/lib/module/components/stack/host/StackHost.js.map +1 -1
  171. package/lib/module/components/stack/index.js.map +1 -1
  172. package/lib/module/components/tabs/host/TabsHost.ios.js +1 -0
  173. package/lib/module/components/tabs/host/TabsHost.ios.js.map +1 -1
  174. package/lib/module/fabric/stack/StackHeaderConfigAndroidNativeComponent.js.map +1 -1
  175. package/lib/module/fabric/stack/StackHeaderConfigIOSNativeComponent.js.map +1 -1
  176. package/lib/module/fabric/stack/StackHeaderItemIOSNativeComponent.js.map +1 -1
  177. package/lib/module/fabric/stack/StackHostNativeComponent.js.map +1 -1
  178. package/lib/module/fabric/tabs/TabsHostIOSNativeComponent.js.map +1 -1
  179. package/lib/typescript/components/modals/form-sheet/FormSheet.types.d.ts +1 -1
  180. package/lib/typescript/components/stack/header/StackHeaderConfig.android.d.ts.map +1 -1
  181. package/lib/typescript/components/stack/header/StackHeaderConfig.android.types.d.ts +616 -21
  182. package/lib/typescript/components/stack/header/StackHeaderConfig.android.types.d.ts.map +1 -1
  183. package/lib/typescript/components/stack/header/StackHeaderConfig.ios.d.ts.map +1 -1
  184. package/lib/typescript/components/stack/header/StackHeaderConfig.ios.types.d.ts +226 -2
  185. package/lib/typescript/components/stack/header/StackHeaderConfig.ios.types.d.ts.map +1 -1
  186. package/lib/typescript/components/stack/header/StackHeaderConfig.types.d.ts +2 -2
  187. package/lib/typescript/components/stack/header/ios/StackHeaderItem.ios.types.d.ts +2 -0
  188. package/lib/typescript/components/stack/header/ios/StackHeaderItem.ios.types.d.ts.map +1 -1
  189. package/lib/typescript/components/stack/host/StackHost.d.ts +1 -1
  190. package/lib/typescript/components/stack/host/StackHost.d.ts.map +1 -1
  191. package/lib/typescript/components/stack/host/StackHost.types.d.ts +24 -0
  192. package/lib/typescript/components/stack/host/StackHost.types.d.ts.map +1 -1
  193. package/lib/typescript/components/stack/index.d.ts +2 -2
  194. package/lib/typescript/components/stack/index.d.ts.map +1 -1
  195. package/lib/typescript/components/tabs/host/TabsHost.ios.d.ts.map +1 -1
  196. package/lib/typescript/components/tabs/host/TabsHost.ios.types.d.ts +16 -0
  197. package/lib/typescript/components/tabs/host/TabsHost.ios.types.d.ts.map +1 -1
  198. package/lib/typescript/components/tabs/host/TabsHost.types.d.ts +3 -0
  199. package/lib/typescript/components/tabs/host/TabsHost.types.d.ts.map +1 -1
  200. package/lib/typescript/fabric/stack/StackHeaderConfigAndroidNativeComponent.d.ts +52 -0
  201. package/lib/typescript/fabric/stack/StackHeaderConfigAndroidNativeComponent.d.ts.map +1 -1
  202. package/lib/typescript/fabric/stack/StackHeaderConfigIOSNativeComponent.d.ts +25 -1
  203. package/lib/typescript/fabric/stack/StackHeaderConfigIOSNativeComponent.d.ts.map +1 -1
  204. package/lib/typescript/fabric/stack/StackHeaderItemIOSNativeComponent.d.ts +2 -0
  205. package/lib/typescript/fabric/stack/StackHeaderItemIOSNativeComponent.d.ts.map +1 -1
  206. package/lib/typescript/fabric/stack/StackHostNativeComponent.d.ts +3 -1
  207. package/lib/typescript/fabric/stack/StackHostNativeComponent.d.ts.map +1 -1
  208. package/lib/typescript/fabric/tabs/TabsHostIOSNativeComponent.d.ts +1 -0
  209. package/lib/typescript/fabric/tabs/TabsHostIOSNativeComponent.d.ts.map +1 -1
  210. package/package.json +8 -7
  211. package/react-native.config.js +3 -0
  212. package/src/components/modals/form-sheet/FormSheet.types.ts +1 -1
  213. package/src/components/stack/header/StackHeaderConfig.android.tsx +48 -23
  214. package/src/components/stack/header/StackHeaderConfig.android.types.ts +637 -21
  215. package/src/components/stack/header/StackHeaderConfig.ios.tsx +45 -1
  216. package/src/components/stack/header/StackHeaderConfig.ios.types.ts +238 -2
  217. package/src/components/stack/header/StackHeaderConfig.types.ts +2 -2
  218. package/src/components/stack/header/ios/StackHeaderItem.ios.types.ts +2 -0
  219. package/src/components/stack/host/StackHost.tsx +4 -2
  220. package/src/components/stack/host/StackHost.types.ts +26 -0
  221. package/src/components/stack/index.ts +6 -1
  222. package/src/components/tabs/host/TabsHost.ios.tsx +1 -0
  223. package/src/components/tabs/host/TabsHost.ios.types.ts +16 -0
  224. package/src/components/tabs/host/TabsHost.types.ts +3 -0
  225. package/src/fabric/stack/StackHeaderConfigAndroidNativeComponent.ts +78 -0
  226. package/src/fabric/stack/StackHeaderConfigIOSNativeComponent.ts +32 -0
  227. package/src/fabric/stack/StackHeaderItemIOSNativeComponent.ts +2 -0
  228. package/src/fabric/stack/StackHostNativeComponent.ts +11 -2
  229. package/src/fabric/tabs/TabsHostIOSNativeComponent.ts +1 -0
  230. package/android/src/main/java/com/swmansion/rnscreens/modals/dimmingview/DimmingView.kt +0 -83
  231. package/android/src/main/java/com/swmansion/rnscreens/modals/dimmingview/DimmingViewManager.kt +0 -89
  232. package/android/src/main/java/com/swmansion/rnscreens/modals/dimmingview/DimmingViewPointerEvents.kt +0 -18
  233. package/android/src/main/java/com/swmansion/rnscreens/stack/header/toolbar/StackHeaderToolbarMenuSelectionController.kt +0 -83
  234. package/ios/conversion/RNSConversions-Stack.h +0 -32
  235. package/ios/conversion/RNSConversions-Stack.mm +0 -41
  236. package/ios/conversion/always_false.h +0 -31
  237. /package/ios/{conversion → scroll-view-marker/conversion}/RNSConversions-ScrollViewMarker.h +0 -0
package/Package.swift ADDED
@@ -0,0 +1,87 @@
1
+ // swift-tools-version: 6.0
2
+ import PackageDescription
3
+
4
+ // Header search paths for quoted cross-directory imports (SPM has no CocoaPods header maps).
5
+ // Keep in sync when adding new ios/ subdirectories that contain headers.
6
+ let headerSearchPaths: [String] = [
7
+ "ios",
8
+ "ios/bridging",
9
+ "ios/conversion",
10
+ "ios/helpers/container",
11
+ "ios/helpers/image",
12
+ "ios/helpers/scroll-view",
13
+ "ios/legacy",
14
+ "ios/legacy/events",
15
+ "ios/legacy/integrations",
16
+ "ios/legacy/utils",
17
+ "ios/modals/form-sheet",
18
+ "ios/modals/utils",
19
+ "ios/safe-area",
20
+ "ios/scroll-to-top-guard",
21
+ "ios/scroll-view-marker",
22
+ "ios/scroll-view-marker/conversion",
23
+ "ios/split",
24
+ "ios/split/conversion",
25
+ "ios/stack",
26
+ "ios/stack/conversion",
27
+ "ios/stack/header",
28
+ "ios/stack/host",
29
+ "ios/stack/screen",
30
+ "ios/tabs",
31
+ "ios/tabs/bottom-accessory",
32
+ "ios/tabs/conversion",
33
+ "ios/tabs/extensions",
34
+ "ios/tabs/host",
35
+ "ios/tabs/screen",
36
+ "ios/utils",
37
+ "ios/utils/extensions",
38
+ "common/cpp",
39
+ "cpp/legacy",
40
+ ]
41
+
42
+ let cSettings: [CSetting] = headerSearchPaths.map { .headerSearchPath($0) }
43
+
44
+ let cxxSettings: [CXXSetting] = [
45
+ .define("DEBUG", .when(configuration: .debug)),
46
+ .define("NDEBUG", .when(configuration: .release)),
47
+ ] + headerSearchPaths.map { .headerSearchPath($0) }
48
+
49
+ let package = Package(
50
+ name: "RNScreens",
51
+ platforms: [.iOS(.v15)],
52
+ products: [
53
+ .library(name: "RNScreens", targets: ["RNScreens"]),
54
+ ],
55
+ dependencies: [
56
+ // Resolved from the autolinker symlink `<app>/ios/build/generated/autolinking/libs/RNScreens`,
57
+ // not from node_modules: `../../../../xcframeworks` -> `<app>/ios/build/xcframeworks`,
58
+ // `../../../ios` -> `<app>/ios/build/generated/ios`. Same layout `npx react-native spm scaffold` emits.
59
+ // Making this self-contained (remote RN package URL + shipping our own codegen output) is blocked
60
+ // on RN publishing a remote SPM package and would require `codegenConfig.includesGeneratedCode`, see:
61
+ // https://github.com/react/react-native/blob/v0.87.1/packages/react-native/scripts/spm/__docs__/spm-header-paths-contract.md#hand-authored-community-library-contract
62
+ .package(name: "ReactNative", path: "../../../../xcframeworks"),
63
+ .package(name: "React-GeneratedCode", path: "../../../ios"),
64
+ ],
65
+ targets: [
66
+ .target(
67
+ name: "RNScreens",
68
+ dependencies: [
69
+ .product(name: "ReactHeaders", package: "ReactNative"),
70
+ .product(name: "ReactNativeHeaders", package: "ReactNative"),
71
+ .product(name: "ReactNativeDependenciesHeaders", package: "ReactNative"),
72
+ .product(name: "ReactAppHeaders", package: "React-GeneratedCode"),
73
+ ],
74
+ path: ".",
75
+ exclude: ["ios/RNScreens.xcodeproj"],
76
+ sources: ["ios", "common/cpp", "cpp"],
77
+ publicHeadersPath: "ios",
78
+ cSettings: cSettings,
79
+ cxxSettings: cxxSettings,
80
+ linkerSettings: [
81
+ .linkedFramework("UIKit"),
82
+ .linkedFramework("Foundation"),
83
+ ]
84
+ ),
85
+ ],
86
+ cxxLanguageStandard: .cxx20
87
+ )
package/README.md CHANGED
@@ -254,13 +254,6 @@ There are many ways to contribute to this project. See [CONTRIBUTING](https://gi
254
254
 
255
255
  React native screens library is licensed under [The MIT License](LICENSE).
256
256
 
257
- ## Credits
258
-
259
- This project has been built and is maintained thanks to the support from [Expo.io](https://expo.io) and [Software Mansion](https://swmansion.com).
260
-
261
- [![expo](https://avatars2.githubusercontent.com/u/12504344?v=3&s=100 'Expo.io')](https://expo.io)
262
- [![swm](https://logo.swmansion.com/logo?color=white&variant=desktop&width=150&tag=react-native-reanimated-github 'Software Mansion')](https://swmansion.com)
263
-
264
257
  ## React Native Screens is created by Software Mansion
265
258
 
266
259
  Since 2012 [Software Mansion](https://swmansion.com) is a software agency with experience in building web and mobile apps. We are Core React Native Contributors and experts in dealing with all kinds of React Native issues. We can help you build your next dream product – [Hire us](https://swmansion.com/contact/projects?utm_source=screens&utm_medium=readme).
@@ -2,6 +2,7 @@
2
2
  #include <react/fabric/Binding.h>
3
3
  #include <react/renderer/scheduler/Scheduler.h>
4
4
 
5
+ #include <memory>
5
6
  #include <string>
6
7
 
7
8
  #include "NativeProxy.h"
@@ -11,6 +12,19 @@ using namespace react;
11
12
 
12
13
  namespace rnscreens {
13
14
 
15
+ namespace {
16
+ // Keep this listener process-lifetime to avoid races during initialization,
17
+ // when nativeAddMutationsListener() can be called concurrently from different
18
+ // threads. A function-local static initializes thread-safely, and an immortal
19
+ // instance suits core's delegate list, which is append-only. For more details:
20
+ // https://github.com/software-mansion/react-native-screens/pull/4413
21
+ const std::shared_ptr<RNSScreenRemovalListener> &removalListener() {
22
+ static const std::shared_ptr<RNSScreenRemovalListener> instance =
23
+ std::make_shared<RNSScreenRemovalListener>();
24
+ return instance;
25
+ }
26
+ } // namespace
27
+
14
28
  NativeProxy::NativeProxy(jni::alias_ref<NativeProxy::javaobject> jThis)
15
29
  : javaPart_(jni::make_global(jThis)) {}
16
30
 
@@ -32,13 +46,18 @@ void NativeProxy::nativeAddMutationsListener(
32
46
  auto uiManager =
33
47
  fabricUIManager->getBinding()->getScheduler()->getUIManager();
34
48
 
35
- if (!screenRemovalListener_) {
36
- screenRemovalListener_ =
37
- std::make_shared<RNSScreenRemovalListener>([this](int tag) {
49
+ {
50
+ // Capture a copy of the global ref, never `this`: the listener outlives
51
+ // this NativeProxy, and the old live read of javaPart_ at call time raced
52
+ // invalidateNative(). installMutex_ keeps the copy from racing the
53
+ // invalidation write and keeps the stored token matching the last install.
54
+ std::lock_guard<std::mutex> lock(installMutex_);
55
+ removalListenerToken_ =
56
+ removalListener()->setListener([javaPart = javaPart_](int tag) {
38
57
  static const auto method =
39
- javaPart_->getClass()->getMethod<void(jint)>(
58
+ javaPart->getClass()->getMethod<void(jint)>(
40
59
  "notifyScreenRemoved");
41
- method(javaPart_, tag);
60
+ method(javaPart, tag);
42
61
  });
43
62
  }
44
63
 
@@ -79,7 +98,7 @@ void NativeProxy::addMountingCoordinatorIfNeeded(
79
98
  });
80
99
 
81
100
  if (!wasRegistered) {
82
- coordinator->setMountingOverrideDelegate(screenRemovalListener_);
101
+ coordinator->setMountingOverrideDelegate(removalListener());
83
102
  coordinatorsWithMountingOverrides_.push_back(coordinator);
84
103
  }
85
104
  }
@@ -90,6 +109,11 @@ jni::local_ref<NativeProxy::jhybriddata> NativeProxy::initHybrid(
90
109
  }
91
110
 
92
111
  void NativeProxy::invalidateNative() {
112
+ // Disarm before the hybrid is collected; also releases the captured global
113
+ // ref so the Java NativeProxy stays collectable. Serialized with the install
114
+ // path so the token is never stale and javaPart_ is not nulled mid-capture.
115
+ std::lock_guard<std::mutex> lock(installMutex_);
116
+ removalListener()->clearListener(removalListenerToken_);
93
117
  javaPart_ = nullptr;
94
118
  }
95
119
 
@@ -4,6 +4,7 @@
4
4
  #include <react/fabric/JFabricUIManager.h>
5
5
  #include "RNSScreenRemovalListener.h"
6
6
 
7
+ #include <cstdint>
7
8
  #include <mutex>
8
9
  #include <string>
9
10
 
@@ -13,7 +14,6 @@ using namespace facebook::jni;
13
14
 
14
15
  class NativeProxy : public jni::HybridClass<NativeProxy> {
15
16
  public:
16
- std::shared_ptr<RNSScreenRemovalListener> screenRemovalListener_;
17
17
  std::vector<std::weak_ptr<const facebook::react::MountingCoordinator>>
18
18
  coordinatorsWithMountingOverrides_;
19
19
  static auto constexpr kJavaDescriptor =
@@ -28,6 +28,12 @@ class NativeProxy : public jni::HybridClass<NativeProxy> {
28
28
 
29
29
  std::mutex coordinatorsMutex_;
30
30
 
31
+ // Serializes callback install (nativeAddMutationsListener) with
32
+ // invalidateNative: the install-time copy of javaPart_ must not race the
33
+ // invalidation write, and the stored token must match the last install.
34
+ std::mutex installMutex_;
35
+ uint64_t removalListenerToken_{0};
36
+
31
37
  explicit NativeProxy(jni::alias_ref<NativeProxy::javaobject> jThis);
32
38
 
33
39
  void nativeAddMutationsListener(
@@ -9,4 +9,12 @@ interface Container {
9
9
  * (if any).
10
10
  */
11
11
  fun resolveCurrentContentScrollView(): ViewGroup?
12
+
13
+ /**
14
+ * Asked when this container's whole subtree is about to be natively dismissed,
15
+ * e.g. the screen hosting this container is popped. Returns the item that
16
+ * vetoes the dismissal via `preventNativeDismiss`, or null when nothing
17
+ * in the subtree does.
18
+ */
19
+ fun wantsToPreventStackNativeDismiss(): ContainerItem?
12
20
  }
@@ -2,7 +2,7 @@ package com.swmansion.rnscreens.common.container
2
2
 
3
3
  import android.view.ViewGroup
4
4
 
5
- internal interface ContainerItem {
5
+ interface ContainerItem {
6
6
  // region Nested Container handling
7
7
 
8
8
  /**
@@ -27,4 +27,16 @@ internal interface ContainerItem {
27
27
  fun findContentScrollView(): ViewGroup?
28
28
 
29
29
  // endregion
30
+
31
+ // region Native dismissal
32
+
33
+ /**
34
+ * Asked when this item (screen) is about to be natively dismissed together
35
+ * with its subtree. The nested container (if any) is consulted first; its
36
+ * non-null answer wins, otherwise the item answers for itself, returning
37
+ * itself when it vetoes the dismissal or null otherwise.
38
+ */
39
+ fun wantsToPreventStackNativeDismiss(): ContainerItem?
40
+
41
+ // endregion
30
42
  }
@@ -0,0 +1,62 @@
1
+ package com.swmansion.rnscreens.common.text
2
+
3
+ import android.content.res.AssetManager
4
+ import android.graphics.Typeface
5
+ import android.os.Build
6
+ import com.facebook.react.common.ReactConstants
7
+ import com.facebook.react.common.assets.ReactFontManager.TypefaceStyle
8
+ import com.facebook.react.views.text.ReactTypefaceUtils
9
+ import kotlin.properties.Delegates
10
+ import kotlin.properties.ReadWriteProperty
11
+
12
+ /**
13
+ * [TextAppearance] driven by React props. Font family, weight and style are kept as the raw
14
+ * React values and turned into a [Typeface]. [onChanged] is invoked whenever a property
15
+ * actually changes value.
16
+ */
17
+ internal class ReactTextAppearance(
18
+ private val assets: AssetManager,
19
+ onChanged: () -> Unit,
20
+ ) : TextAppearance {
21
+ override var color: Int? by changeNotifying(onChanged)
22
+ override var fontSize: Float? by changeNotifying(onChanged)
23
+ internal var fontFamily: String? by changeNotifying(onChanged)
24
+ internal var fontWeight: String? by changeNotifying(onChanged)
25
+ internal var fontStyle: String? by changeNotifying(onChanged)
26
+
27
+ override fun resolveTypeface(base: Typeface): Typeface {
28
+ val weight = ReactTypefaceUtils.parseFontWeight(fontWeight)
29
+ val style = ReactTypefaceUtils.parseFontStyle(fontStyle)
30
+
31
+ if (fontFamily == null && weight == ReactConstants.UNSET && style == ReactConstants.UNSET) {
32
+ return base
33
+ }
34
+
35
+ // ReactFontManager.TypefaceStyle turns an unset weight into 400 and an unset style into
36
+ // "not italic" rather than deriving them from the base. This would drop default styling
37
+ // from base typeface. Resolve both up front so it never receives UNSET style or weight.
38
+ return ReactTypefaceUtils.applyStyles(
39
+ base,
40
+ if (style != ReactConstants.UNSET) style else base.resolveStyle(),
41
+ if (weight != ReactConstants.UNSET) weight else base.resolveWeight(),
42
+ fontFamily,
43
+ assets,
44
+ )
45
+ }
46
+ }
47
+
48
+ private fun <T> changeNotifying(onChanged: () -> Unit): ReadWriteProperty<Any?, T?> =
49
+ Delegates.observable(null) { _, old, new -> if (old != new) onChanged() }
50
+
51
+ /**
52
+ * Numeric weight of this typeface. [Typeface.getWeight] requires API 28; below it only bold
53
+ * can be told apart from regular.
54
+ */
55
+ private fun Typeface.resolveWeight(): Int =
56
+ when {
57
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.P -> weight
58
+ isBold -> TypefaceStyle.BOLD
59
+ else -> TypefaceStyle.NORMAL
60
+ }
61
+
62
+ private fun Typeface.resolveStyle(): Int = if (isItalic) Typeface.ITALIC else Typeface.NORMAL
@@ -0,0 +1,20 @@
1
+ package com.swmansion.rnscreens.common.text
2
+
3
+ import android.graphics.Typeface
4
+
5
+ /**
6
+ * Provides text styling for some given part of the interface. Interface is React-agnostic. A `null`
7
+ * value means "keep the default".
8
+ */
9
+ internal interface TextAppearance {
10
+ val color: Int?
11
+
12
+ /** Font size in SP. */
13
+ val fontSize: Float?
14
+
15
+ /**
16
+ * Returns the modified typeface based on [base] typeface. Properties that are not overridden
17
+ * are inherited from [base], which is returned unchanged when there are no overrides at all.
18
+ */
19
+ fun resolveTypeface(base: Typeface): Typeface
20
+ }
@@ -0,0 +1,65 @@
1
+ package com.swmansion.rnscreens.common.text
2
+
3
+ import android.content.Context
4
+ import android.graphics.Typeface
5
+ import androidx.annotation.AttrRes
6
+ import com.swmansion.rnscreens.utils.resolveColorAttr
7
+ import com.swmansion.rnscreens.utils.resolveStyleResAttr
8
+
9
+ /**
10
+ * Default text styling of a single title/subtitle slot, resolved from the M3 type-scale
11
+ * style behind [textAppearanceAttr] and the color behind [textColorAttr].
12
+ *
13
+ * Resolved from the style rather than read back from the widget: Material resolves a slot's
14
+ * default typeface asynchronously, so until that lands the widget reports [Typeface.DEFAULT].
15
+ */
16
+ internal class TextAppearanceDefaults(
17
+ val color: Int,
18
+ val textSizePx: Float,
19
+ val typeface: Typeface,
20
+ ) {
21
+ companion object {
22
+ fun resolve(
23
+ context: Context,
24
+ @AttrRes textAppearanceAttr: Int,
25
+ @AttrRes textColorAttr: Int,
26
+ ): TextAppearanceDefaults {
27
+ val appearanceRes = resolveStyleResAttr(context, textAppearanceAttr)
28
+ val attrs = context.obtainStyledAttributes(appearanceRes, APPEARANCE_ATTRS)
29
+ try {
30
+ val textSizePx = attrs.getDimension(IDX_TEXT_SIZE, 0f)
31
+ require(textSizePx > 0f) { "[RNScreens] Text appearance defines no text size." }
32
+
33
+ // android:fontFamily is either a font resource (@font/…, resolvable only
34
+ // asynchronously) or a family name. The M3 type scale always declares a family
35
+ // name (@string/m3_ref_typeface_* — "sans-serif" / "sans-serif-medium"),
36
+ // so we can unconditionally take the synchronous path (Material's own fallback and
37
+ // AppCompatTextHelper do the same).
38
+ val textStyle = attrs.getInt(IDX_TEXT_STYLE, Typeface.NORMAL)
39
+ val typeface =
40
+ attrs.getString(IDX_FONT_FAMILY)?.let { Typeface.create(it, textStyle) }
41
+ ?: Typeface.defaultFromStyle(textStyle)
42
+
43
+ return TextAppearanceDefaults(
44
+ resolveColorAttr(context, textColorAttr),
45
+ textSizePx,
46
+ typeface,
47
+ )
48
+ } finally {
49
+ attrs.recycle()
50
+ }
51
+ }
52
+
53
+ // Framework attr ids are compile-time constants; the array must stay sorted
54
+ // ascending (obtainStyledAttributes requirement).
55
+ private val APPEARANCE_ATTRS =
56
+ intArrayOf(
57
+ android.R.attr.textSize,
58
+ android.R.attr.textStyle,
59
+ android.R.attr.fontFamily,
60
+ )
61
+ private const val IDX_TEXT_SIZE = 0
62
+ private const val IDX_TEXT_STYLE = 1
63
+ private const val IDX_FONT_FAMILY = 2
64
+ }
65
+ }
@@ -1,6 +1,5 @@
1
1
  package com.swmansion.rnscreens.helpers
2
2
 
3
- import android.content.Context
4
3
  import android.graphics.drawable.Drawable
5
4
 
6
5
  /**
@@ -21,27 +20,28 @@ internal sealed interface IconResolution {
21
20
 
22
21
  /**
23
22
  * Stateful, latest-wins icon resolver for a single declaratively-driven icon slot — a `toolbarMenu`
24
- * prop menu item, or the back button — that is re-evaluated on every prop transaction. It
25
- * deduplicates unchanged sources ([IconResolution.Unchanged]) to avoid needless reloads/flicker,
26
- * and drops stale async results so a slow load cannot clobber a newer source.
23
+ * prop menu item, or the back button — that is re-evaluated on every source change. It deduplicates
24
+ * unchanged sources ([IconResolution.Unchanged]) to avoid needless reloads/flicker, and drops stale
25
+ * async results so a slow load cannot clobber a newer source.
26
+ *
27
+ * [load] must invoke its completion callback exactly once — synchronously or asynchronously,
28
+ * always on the main thread — with the loaded drawable, or `null` when the source resolves to
29
+ * no icon or fails to load (see e.g. [resolveImage]).
27
30
  */
28
- internal class PropIconResolver {
31
+ internal class PropIconResolver(
32
+ private val load: (drawableIconResourceName: String?, imageIconUri: String?, onComplete: (Drawable?) -> Unit) -> Unit,
33
+ ) {
29
34
  private var lastDrawableName: String? = null
30
35
  private var lastImageUri: String? = null
31
36
  private var lastEmittedDrawableName: String? = null
32
37
  private var lastEmittedImageUri: String? = null
33
38
 
34
39
  /**
35
- * Resolves an icon from a drawable resource name or an image uri.
36
- *
37
- * The result is delivered to [onResult] synchronously for drawable resources and empty sources,
38
- * and asynchronously for image uris. For image uris, the callback is only invoked if the
39
- * resolved uri is still the latest requested source (stale requests are dropped). On a failed
40
- * image load the latest request still emits [IconResolution.Resolved] with a `null` drawable, so
41
- * the icon is cleared rather than left stale.
40
+ * Resolves an icon from a drawable resource name or an image uri. The result is delivered
41
+ * to [onResult] only if the requested source is still the latest one (stale async results
42
+ * are dropped).
42
43
  */
43
44
  fun resolve(
44
- context: Context,
45
45
  drawableIconResourceName: String?,
46
46
  imageIconUri: String?,
47
47
  onResult: (IconResolution) -> Unit,
@@ -56,16 +56,10 @@ internal class PropIconResolver {
56
56
  }
57
57
  lastEmittedDrawableName = drawableIconResourceName
58
58
  lastEmittedImageUri = imageIconUri
59
- when {
60
- drawableIconResourceName != null ->
61
- onResult(IconResolution.Resolved(getSystemDrawableResource(context, drawableIconResourceName)))
62
- imageIconUri != null ->
63
- loadImage(context, imageIconUri) { drawable ->
64
- if (imageIconUri == lastImageUri && lastDrawableName == null) {
65
- onResult(IconResolution.Resolved(drawable))
66
- }
67
- }
68
- else -> onResult(IconResolution.Resolved(null))
59
+ load(drawableIconResourceName, imageIconUri) { drawable ->
60
+ if (drawableIconResourceName == lastDrawableName && imageIconUri == lastImageUri) {
61
+ onResult(IconResolution.Resolved(drawable))
62
+ }
69
63
  }
70
64
  }
71
65
  }
@@ -495,8 +495,10 @@ class Screen(
495
495
  // It has a custom `getChildDrawingOrder` method which returns
496
496
  // wrong index if we called `startViewTransition` on the views on new arch.
497
497
  // We add a simple View to bump the number of children to make it work.
498
+ // Appended, not inserted at `i`: a filler before the circle inflates the
499
+ // index `onMeasure` caches for it, which then outlives the child it points at.
498
500
  // TODO: find a better way to handle this scenario
499
- it.addView(View(context), i)
501
+ it.addView(View(context))
500
502
  } else {
501
503
  child?.let { view -> it.startViewTransition(view) }
502
504
  }
@@ -282,6 +282,8 @@ class ScreenStack(
282
282
  screenWrappers
283
283
  .asSequence()
284
284
  .dropWhile { it !== visibleBottom } // ignore all screens beneath the visible bottom
285
+ // dismissed screens are already removed above & preloaded ones must stay detached
286
+ .filter { !dismissedWrappers.contains(it) && it.screen.activityState !== Screen.ActivityState.INACTIVE }
285
287
  .forEach { wrapper ->
286
288
  // TODO: It should be enough to dispatch this on commit action once.
287
289
  transaction.add(id, wrapper.fragment).runOnCommit {
@@ -69,6 +69,9 @@ internal class FormSheetBehaviorController(
69
69
  }
70
70
 
71
71
  /**
72
+ * Expected to be called from the measure pass, before the sheet is measured (see
73
+ * `FormSheetAvailableHeightProvider`), so the metrics below are consumed by the ongoing traversal.
74
+ *
72
75
  * @param detents - parsed detents configuration.
73
76
  * @param sheetAvailableSpace - the full window height that detent fractions are measured against.
74
77
  * Using the full height lets a BottomSheet with large detent configured to slide
@@ -77,7 +80,11 @@ internal class FormSheetBehaviorController(
77
80
  * Used exclusively when the sheet is in `fitToContents` mode.
78
81
  * @param nativeContainerPaddingBottom - the bottom system inset. In `fitToContents` mode, this is added to the
79
82
  * BottomSheet's height to extend its background behind the system bars, while the inner content remains within
80
- * the safe area.
83
+ * the safe area. For fractional detents it is subtracted from the collapsed peek height, which Material resolves
84
+ * above the inset, so the lowest detent lands at its fraction of [sheetAvailableSpace] like the other ones.
85
+ * @param keyboardLift - the part of the keyboard inset above [nativeContainerPaddingBottom]. Every resting position
86
+ * is extended by it so the sheet is pushed above the keyboard as far as [sheetAvailableSpace] allows,
87
+ * see [FormSheetDetents].
81
88
  * @param initialDetentIndex - the index of the detent the sheet should snap to while opening.
82
89
  * @param applyInitialDetent - whether the sheet should forcefully snap to the initial detent state.
83
90
  * This should typically be `true` only when the sheet transitions from closed to open.
@@ -87,6 +94,7 @@ internal class FormSheetBehaviorController(
87
94
  sheetAvailableSpace: Int,
88
95
  contentHeightForFitToContents: Int = 0,
89
96
  nativeContainerPaddingBottom: Int = 0,
97
+ keyboardLift: Int = 0,
90
98
  initialDetentIndex: Int = 0,
91
99
  applyInitialDetent: Boolean = false,
92
100
  ) {
@@ -97,22 +105,39 @@ internal class FormSheetBehaviorController(
97
105
  }
98
106
 
99
107
  if (detents.isFitToContents) {
100
- configureFitToContents(detents, sheetAvailableSpace, contentHeightForFitToContents, nativeContainerPaddingBottom)
108
+ configureFitToContents(
109
+ detents,
110
+ sheetAvailableSpace,
111
+ contentHeightForFitToContents,
112
+ nativeContainerPaddingBottom,
113
+ keyboardLift,
114
+ )
101
115
  } else {
102
116
  when (detents.count) {
103
- 1 -> configureSingleDetent(detents, sheetAvailableSpace)
104
- 2 -> configureTwoDetents(detents, sheetAvailableSpace, initialDetentIndex, applyInitialDetent)
105
- 3 -> configureThreeDetents(detents, sheetAvailableSpace, initialDetentIndex, applyInitialDetent)
117
+ 1 -> configureSingleDetent(detents, sheetAvailableSpace, keyboardLift)
118
+ 2 ->
119
+ configureTwoDetents(
120
+ detents,
121
+ sheetAvailableSpace,
122
+ nativeContainerPaddingBottom,
123
+ keyboardLift,
124
+ initialDetentIndex,
125
+ applyInitialDetent,
126
+ )
127
+ 3 ->
128
+ configureThreeDetents(
129
+ detents,
130
+ sheetAvailableSpace,
131
+ nativeContainerPaddingBottom,
132
+ keyboardLift,
133
+ initialDetentIndex,
134
+ applyInitialDetent,
135
+ )
106
136
  else -> throw IllegalStateException(
107
137
  "[RNScreens] Unsupported detent count ${detents.count}.",
108
138
  )
109
139
  }
110
140
  }
111
-
112
- // Metrics were mutated on an already-measured sheet; force a fresh layout
113
- // pass so the behavior re-settles to the new detent instead of keeping its
114
- // stale height.
115
- sheetView.requestLayout()
116
141
  }
117
142
 
118
143
  private fun configureFitToContents(
@@ -120,33 +145,37 @@ internal class FormSheetBehaviorController(
120
145
  sheetAvailableSpace: Int,
121
146
  contentHeight: Int,
122
147
  bottomInset: Int,
148
+ keyboardLift: Int,
123
149
  ) = behavior.apply {
124
150
  skipCollapsed = true
125
151
  isFitToContents = true
126
- maxHeight = detents.maxAllowedHeightForFitToContents(sheetAvailableSpace, contentHeight, bottomInset)
152
+ maxHeight = detents.maxAllowedHeightForFitToContents(sheetAvailableSpace, contentHeight, bottomInset, keyboardLift)
127
153
  state = BottomSheetBehavior.STATE_EXPANDED
128
154
  }
129
155
 
130
156
  private fun configureSingleDetent(
131
157
  detents: FormSheetDetents,
132
158
  sheetAvailableSpace: Int,
159
+ keyboardLift: Int,
133
160
  ) = behavior.apply {
134
161
  skipCollapsed = true
135
162
  isFitToContents = true
136
- maxHeight = detents.maxAllowedHeight(sheetAvailableSpace)
163
+ maxHeight = detents.maxAllowedHeight(sheetAvailableSpace, keyboardLift)
137
164
  state = BottomSheetBehavior.STATE_EXPANDED
138
165
  }
139
166
 
140
167
  private fun configureTwoDetents(
141
168
  detents: FormSheetDetents,
142
169
  sheetAvailableSpace: Int,
170
+ bottomInset: Int,
171
+ keyboardLift: Int,
143
172
  initialDetentIndex: Int,
144
173
  applyInitialDetent: Boolean,
145
174
  ) = behavior.apply {
146
175
  skipCollapsed = false
147
176
  isFitToContents = true
148
- peekHeight = detents.firstHeight(sheetAvailableSpace)
149
- maxHeight = detents.maxAllowedHeight(sheetAvailableSpace)
177
+ peekHeight = detents.peekHeight(sheetAvailableSpace, bottomInset, keyboardLift)
178
+ maxHeight = detents.maxAllowedHeight(sheetAvailableSpace, keyboardLift)
150
179
  if (applyInitialDetent) {
151
180
  state = resolveStateFromIndex(initialDetentIndex, detents.count)
152
181
  }
@@ -155,15 +184,17 @@ internal class FormSheetBehaviorController(
155
184
  private fun configureThreeDetents(
156
185
  detents: FormSheetDetents,
157
186
  sheetAvailableSpace: Int,
187
+ bottomInset: Int,
188
+ keyboardLift: Int,
158
189
  initialDetentIndex: Int,
159
190
  applyInitialDetent: Boolean,
160
191
  ) = behavior.apply {
161
192
  skipCollapsed = false
162
193
  isFitToContents = false
163
- peekHeight = detents.firstHeight(sheetAvailableSpace)
164
- halfExpandedRatio = detents.halfExpandedRatio()
165
- expandedOffset = detents.expandedOffsetFromTop(sheetAvailableSpace)
166
- maxHeight = detents.maxAllowedHeight(sheetAvailableSpace)
194
+ peekHeight = detents.peekHeight(sheetAvailableSpace, bottomInset, keyboardLift)
195
+ halfExpandedRatio = detents.halfExpandedRatio(sheetAvailableSpace, keyboardLift)
196
+ expandedOffset = detents.expandedOffsetFromTop(sheetAvailableSpace, keyboardLift = keyboardLift)
197
+ maxHeight = detents.maxAllowedHeight(sheetAvailableSpace, keyboardLift)
167
198
  if (applyInitialDetent) {
168
199
  state = resolveStateFromIndex(initialDetentIndex, detents.count)
169
200
  }