@lodev09/react-native-true-sheet 4.0.0-beta.3 → 4.0.0-beta.30

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 (244) hide show
  1. package/README.md +28 -5
  2. package/android/build.gradle +23 -1
  3. package/android/proguard-rules.pro +3 -0
  4. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +50 -16
  5. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +303 -184
  6. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentViewManager.kt +5 -1
  7. package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterView.kt +38 -109
  8. package/android/src/main/java/com/lodev09/truesheet/TrueSheetModule.kt +13 -0
  9. package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayView.kt +127 -0
  10. package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayViewManager.kt +45 -0
  11. package/android/src/main/java/com/lodev09/truesheet/TrueSheetPackage.kt +2 -1
  12. package/android/src/main/java/com/lodev09/truesheet/TrueSheetStateUpdater.kt +29 -3
  13. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +234 -66
  14. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +491 -186
  15. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +64 -10
  16. package/android/src/main/java/com/lodev09/truesheet/core/RNScreensEventObserver.kt +31 -14
  17. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetBehavior.kt +135 -0
  18. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +23 -23
  19. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +130 -6
  20. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +104 -39
  21. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDimView.kt +14 -17
  22. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetGrabberView.kt +2 -4
  23. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetOverlayRootView.kt +148 -0
  24. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetStackManager.kt +33 -40
  25. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +15 -0
  26. package/android/src/main/java/com/lodev09/truesheet/utils/ColorUtils.kt +19 -0
  27. package/android/src/main/java/com/lodev09/truesheet/utils/KeyboardUtils.kt +15 -2
  28. package/android/src/main/java/com/lodev09/truesheet/utils/ScreenUtils.kt +0 -12
  29. package/android/src/main/java/com/lodev09/truesheet/utils/ViewUtils.kt +19 -7
  30. package/android/src/main/jni/TrueSheetSpec.h +1 -0
  31. package/android/src/main/jni/TrueSheetStateUpdater.cpp +37 -6
  32. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +1 -9
  33. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +114 -30
  34. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +30 -7
  35. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +2 -2
  36. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +9 -8
  37. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h +3 -5
  38. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp +14 -3
  39. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.h +5 -6
  40. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.cpp +1 -1
  41. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.h +10 -6
  42. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.cpp +1 -1
  43. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.h +1 -1
  44. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetLayoutUtils.h +43 -0
  45. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewComponentDescriptor.h +21 -0
  46. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.cpp +17 -0
  47. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.h +33 -0
  48. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h +3 -5
  49. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +7 -40
  50. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h +3 -7
  51. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.cpp +3 -5
  52. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.h +4 -5
  53. package/ios/TrueSheetContainerView.h +23 -7
  54. package/ios/TrueSheetContainerView.mm +45 -25
  55. package/ios/TrueSheetContentView.h +44 -15
  56. package/ios/TrueSheetContentView.mm +221 -190
  57. package/ios/TrueSheetFooterView.mm +133 -28
  58. package/ios/TrueSheetModule.h +2 -7
  59. package/ios/TrueSheetModule.mm +18 -18
  60. package/ios/TrueSheetOverlayView.h +42 -0
  61. package/ios/TrueSheetOverlayView.mm +175 -0
  62. package/ios/TrueSheetView.h +2 -0
  63. package/ios/TrueSheetView.mm +268 -52
  64. package/ios/TrueSheetViewController.h +36 -3
  65. package/ios/TrueSheetViewController.mm +797 -102
  66. package/ios/core/RNScreensEventObserver.mm +31 -28
  67. package/ios/core/TrueSheetBlurView.h +0 -2
  68. package/ios/core/TrueSheetBlurView.mm +3 -36
  69. package/ios/core/TrueSheetDetentCalculator.h +18 -1
  70. package/ios/core/TrueSheetDetentCalculator.mm +44 -9
  71. package/ios/core/TrueSheetDimView.h +27 -0
  72. package/ios/core/TrueSheetDimView.mm +41 -0
  73. package/ios/core/TrueSheetGrabberView.mm +13 -3
  74. package/ios/core/TrueSheetKeyboardObserver.h +7 -0
  75. package/ios/core/TrueSheetKeyboardObserver.mm +107 -15
  76. package/ios/core/TrueSheetOverlayContainerView.h +31 -0
  77. package/ios/core/TrueSheetOverlayContainerView.mm +35 -0
  78. package/ios/events/TrueSheetLifecycleEvents.h +2 -0
  79. package/ios/events/TrueSheetLifecycleEvents.mm +8 -0
  80. package/ios/tvos/TrueSheetStubs.mm +12 -0
  81. package/ios/utils/UIView+ScrollEdgeInteraction.h +1 -0
  82. package/ios/utils/UIView+ScrollEdgeInteraction.mm +24 -2
  83. package/lib/module/TrueSheet.js +222 -54
  84. package/lib/module/TrueSheet.js.map +1 -1
  85. package/lib/module/TrueSheet.web.js +364 -275
  86. package/lib/module/TrueSheet.web.js.map +1 -1
  87. package/lib/module/TrueSheetBackground.js +15 -0
  88. package/lib/module/TrueSheetBackground.js.map +1 -0
  89. package/lib/module/TrueSheetOverlay.js +30 -0
  90. package/lib/module/TrueSheetOverlay.js.map +1 -0
  91. package/lib/module/TrueSheetOverlay.web.js +35 -0
  92. package/lib/module/TrueSheetOverlay.web.js.map +1 -0
  93. package/lib/module/TrueSheetPeek.web.js +20 -15
  94. package/lib/module/TrueSheetPeek.web.js.map +1 -1
  95. package/lib/module/TrueSheetProvider.web.js +13 -9
  96. package/lib/module/TrueSheetProvider.web.js.map +1 -1
  97. package/lib/module/detentBackgrounds.js +21 -0
  98. package/lib/module/detentBackgrounds.js.map +1 -0
  99. package/lib/module/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
  100. package/lib/module/fabric/TrueSheetFooterViewNativeComponent.ts +2 -3
  101. package/lib/module/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
  102. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +89 -73
  103. package/lib/module/index.js +1 -0
  104. package/lib/module/index.js.map +1 -1
  105. package/lib/module/mocks/index.js +18 -2
  106. package/lib/module/mocks/index.js.map +1 -1
  107. package/lib/module/mocks/navigationExpoRouter.js.map +1 -1
  108. package/lib/module/navigation/base-types.js +2 -0
  109. package/lib/module/navigation/base-types.js.map +1 -0
  110. package/lib/module/navigation/createTrueSheetRouter.js +158 -100
  111. package/lib/module/navigation/createTrueSheetRouter.js.map +1 -1
  112. package/lib/module/navigation/expo-router/base-types.js +2 -0
  113. package/lib/module/navigation/expo-router/base-types.js.map +1 -0
  114. package/lib/module/navigation/expo-router/extendTrueSheetRouter.js +71 -0
  115. package/lib/module/navigation/expo-router/extendTrueSheetRouter.js.map +1 -0
  116. package/lib/module/navigation/expo-router/index.js +18 -7
  117. package/lib/module/navigation/expo-router/index.js.map +1 -1
  118. package/lib/module/navigation/expo-router/types.js +4 -0
  119. package/lib/module/navigation/expo-router/types.js.map +1 -0
  120. package/lib/module/navigation/index.js.map +1 -1
  121. package/lib/module/navigation/screen/useSheetScreenState.js +1 -0
  122. package/lib/module/navigation/screen/useSheetScreenState.js.map +1 -1
  123. package/lib/module/scrollable.js +28 -0
  124. package/lib/module/scrollable.js.map +1 -0
  125. package/lib/module/web/constants.js +1 -1
  126. package/lib/module/web/constants.js.map +1 -1
  127. package/lib/module/web/keyboard.js +69 -0
  128. package/lib/module/web/keyboard.js.map +1 -0
  129. package/lib/module/web/layout.js +168 -0
  130. package/lib/module/web/layout.js.map +1 -0
  131. package/lib/module/web/vaul/constants.js +9 -0
  132. package/lib/module/web/vaul/constants.js.map +1 -1
  133. package/lib/module/web/vaul/context.js +4 -0
  134. package/lib/module/web/vaul/context.js.map +1 -1
  135. package/lib/module/web/vaul/helpers.js +1 -0
  136. package/lib/module/web/vaul/helpers.js.map +1 -1
  137. package/lib/module/web/vaul/index.js +83 -21
  138. package/lib/module/web/vaul/index.js.map +1 -1
  139. package/lib/module/web/vaul/use-snap-points.js +57 -28
  140. package/lib/module/web/vaul/use-snap-points.js.map +1 -1
  141. package/lib/typescript/src/TrueSheet.d.ts +18 -1
  142. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  143. package/lib/typescript/src/TrueSheet.types.d.ts +209 -35
  144. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  145. package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -1
  146. package/lib/typescript/src/TrueSheetBackground.d.ts +3 -0
  147. package/lib/typescript/src/TrueSheetBackground.d.ts.map +1 -0
  148. package/lib/typescript/src/TrueSheetOverlay.d.ts +8 -0
  149. package/lib/typescript/src/TrueSheetOverlay.d.ts.map +1 -0
  150. package/lib/typescript/src/TrueSheetOverlay.web.d.ts +8 -0
  151. package/lib/typescript/src/TrueSheetOverlay.web.d.ts.map +1 -0
  152. package/lib/typescript/src/TrueSheetPeek.web.d.ts +8 -4
  153. package/lib/typescript/src/TrueSheetPeek.web.d.ts.map +1 -1
  154. package/lib/typescript/src/TrueSheetProvider.web.d.ts +5 -1
  155. package/lib/typescript/src/TrueSheetProvider.web.d.ts.map +1 -1
  156. package/lib/typescript/src/detentBackgrounds.d.ts +10 -0
  157. package/lib/typescript/src/detentBackgrounds.d.ts.map +1 -0
  158. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts +2 -3
  159. package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts.map +1 -1
  160. package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts +6 -0
  161. package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts.map +1 -0
  162. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +76 -65
  163. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  164. package/lib/typescript/src/index.d.ts +1 -0
  165. package/lib/typescript/src/index.d.ts.map +1 -1
  166. package/lib/typescript/src/mocks/index.d.ts +4 -0
  167. package/lib/typescript/src/mocks/index.d.ts.map +1 -1
  168. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts +3 -3
  169. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts.map +1 -1
  170. package/lib/typescript/src/navigation/base-types.d.ts +9 -0
  171. package/lib/typescript/src/navigation/base-types.d.ts.map +1 -0
  172. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts +36 -10
  173. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts.map +1 -1
  174. package/lib/typescript/src/navigation/expo-router/base-types.d.ts +8 -0
  175. package/lib/typescript/src/navigation/expo-router/base-types.d.ts.map +1 -0
  176. package/lib/typescript/src/navigation/expo-router/extendTrueSheetRouter.d.ts +33 -0
  177. package/lib/typescript/src/navigation/expo-router/extendTrueSheetRouter.d.ts.map +1 -0
  178. package/lib/typescript/src/navigation/expo-router/index.d.ts +9 -6
  179. package/lib/typescript/src/navigation/expo-router/index.d.ts.map +1 -1
  180. package/lib/typescript/src/navigation/expo-router/types.d.ts +44 -0
  181. package/lib/typescript/src/navigation/expo-router/types.d.ts.map +1 -0
  182. package/lib/typescript/src/navigation/index.d.ts +3 -4
  183. package/lib/typescript/src/navigation/index.d.ts.map +1 -1
  184. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts +2 -1
  185. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -1
  186. package/lib/typescript/src/navigation/types.d.ts +43 -6
  187. package/lib/typescript/src/navigation/types.d.ts.map +1 -1
  188. package/lib/typescript/src/scrollable.d.ts +2 -0
  189. package/lib/typescript/src/scrollable.d.ts.map +1 -0
  190. package/lib/typescript/src/web/constants.d.ts +1 -1
  191. package/lib/typescript/src/web/constants.d.ts.map +1 -1
  192. package/lib/typescript/src/web/keyboard.d.ts +15 -0
  193. package/lib/typescript/src/web/keyboard.d.ts.map +1 -0
  194. package/lib/typescript/src/web/layout.d.ts +20 -0
  195. package/lib/typescript/src/web/layout.d.ts.map +1 -0
  196. package/lib/typescript/src/web/vaul/constants.d.ts +3 -0
  197. package/lib/typescript/src/web/vaul/constants.d.ts.map +1 -1
  198. package/lib/typescript/src/web/vaul/context.d.ts +5 -1
  199. package/lib/typescript/src/web/vaul/context.d.ts.map +1 -1
  200. package/lib/typescript/src/web/vaul/helpers.d.ts +1 -0
  201. package/lib/typescript/src/web/vaul/helpers.d.ts.map +1 -1
  202. package/lib/typescript/src/web/vaul/index.d.ts +20 -1
  203. package/lib/typescript/src/web/vaul/index.d.ts.map +1 -1
  204. package/lib/typescript/src/web/vaul/types.d.ts +9 -0
  205. package/lib/typescript/src/web/vaul/types.d.ts.map +1 -1
  206. package/lib/typescript/src/web/vaul/use-snap-points.d.ts +6 -4
  207. package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -1
  208. package/package.json +18 -8
  209. package/react-native.config.js +1 -0
  210. package/src/TrueSheet.tsx +257 -62
  211. package/src/TrueSheet.types.ts +225 -35
  212. package/src/TrueSheet.web.tsx +445 -333
  213. package/src/TrueSheetBackground.tsx +17 -0
  214. package/src/TrueSheetOverlay.tsx +24 -0
  215. package/src/TrueSheetOverlay.web.tsx +33 -0
  216. package/src/TrueSheetPeek.web.tsx +25 -23
  217. package/src/TrueSheetProvider.web.tsx +22 -13
  218. package/src/detentBackgrounds.ts +24 -0
  219. package/src/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
  220. package/src/fabric/TrueSheetFooterViewNativeComponent.ts +2 -3
  221. package/src/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
  222. package/src/fabric/TrueSheetViewNativeComponent.ts +89 -73
  223. package/src/index.ts +1 -0
  224. package/src/mocks/index.ts +17 -2
  225. package/src/mocks/navigationExpoRouter.ts +6 -5
  226. package/src/navigation/base-types.ts +20 -0
  227. package/src/navigation/createTrueSheetRouter.ts +220 -144
  228. package/src/navigation/expo-router/base-types.ts +18 -0
  229. package/src/navigation/expo-router/extendTrueSheetRouter.ts +99 -0
  230. package/src/navigation/expo-router/index.ts +41 -30
  231. package/src/navigation/expo-router/types.ts +116 -0
  232. package/src/navigation/index.ts +6 -7
  233. package/src/navigation/screen/useSheetScreenState.ts +2 -0
  234. package/src/navigation/types.ts +81 -23
  235. package/src/scrollable.ts +25 -0
  236. package/src/web/constants.ts +1 -1
  237. package/src/web/keyboard.ts +79 -0
  238. package/src/web/layout.ts +196 -0
  239. package/src/web/vaul/constants.ts +9 -0
  240. package/src/web/vaul/context.ts +7 -1
  241. package/src/web/vaul/helpers.ts +5 -0
  242. package/src/web/vaul/index.tsx +113 -16
  243. package/src/web/vaul/types.ts +10 -0
  244. package/src/web/vaul/use-snap-points.ts +86 -33
@@ -23,11 +23,10 @@ class TrueSheetViewState final {
23
23
  TrueSheetViewState() = default;
24
24
 
25
25
  #ifdef ANDROID
26
- TrueSheetViewState(
27
- TrueSheetViewState const &previousState,
28
- folly::dynamic data)
26
+ TrueSheetViewState(TrueSheetViewState const &previousState, folly::dynamic data)
29
27
  : containerWidth(static_cast<float>(data["containerWidth"].getDouble())),
30
- containerHeight(static_cast<float>(data["containerHeight"].getDouble())) {}
28
+ containerHeight(static_cast<float>(data["containerHeight"].getDouble())) {
29
+ }
31
30
  #endif
32
31
 
33
32
  float containerWidth{0};
@@ -49,4 +48,4 @@ class TrueSheetViewState final {
49
48
  #endif
50
49
  };
51
50
 
52
- } // namespace facebook::react
51
+ } // namespace facebook::react
@@ -16,11 +16,19 @@ NS_ASSUME_NONNULL_BEGIN
16
16
 
17
17
  @interface ScrollableOptions : NSObject
18
18
 
19
+ @property (nonatomic, assign) facebook::react::TrueSheetViewContentInsetAdjustment contentInsetAdjustment;
19
20
  @property (nonatomic, assign) CGFloat keyboardScrollOffset;
21
+ @property (nonatomic, assign) CGFloat keyboardOffset;
20
22
  @property (nonatomic, assign) BOOL scrollingExpandsSheet;
21
23
  @property (nonatomic, assign) facebook::react::TrueSheetViewTopScrollEdgeEffect topScrollEdgeEffect;
22
24
  @property (nonatomic, assign) facebook::react::TrueSheetViewBottomScrollEdgeEffect bottomScrollEdgeEffect;
23
25
 
26
+ /**
27
+ * Derived from `contentInsetAdjustment` — which of the two bottom insets apply
28
+ */
29
+ @property (nonatomic, readonly) BOOL safeAreaInsetAdjustment;
30
+ @property (nonatomic, readonly) BOOL footerInsetAdjustment;
31
+
24
32
  @end
25
33
 
26
34
  @class TrueSheetPeekView;
@@ -29,6 +37,7 @@ NS_ASSUME_NONNULL_BEGIN
29
37
 
30
38
  - (void)containerViewContentDidChangeSize:(CGSize)newSize;
31
39
  - (void)containerViewScrollViewDidChange;
40
+ - (void)containerViewDidMountTransaction;
32
41
 
33
42
  @optional
34
43
 
@@ -46,20 +55,27 @@ NS_ASSUME_NONNULL_BEGIN
46
55
  @property (nonatomic, weak, nullable) id<TrueSheetContainerViewDelegate> delegate;
47
56
 
48
57
  /**
49
- * Inset adjustment mode for scrollable content
58
+ * Options for scrollable behavior
59
+ */
60
+ @property (nonatomic, strong, nullable) ScrollableOptions *scrollableOptions;
61
+
62
+ /**
63
+ * React tag of the user-provided scrollable within the content (see the `scrollableRef` prop)
50
64
  */
51
- @property (nonatomic, assign) facebook::react::TrueSheetViewInsetAdjustment insetAdjustment;
65
+ @property (nonatomic, assign) NSInteger scrollableHandle;
52
66
 
53
67
  /**
54
- * Options for scrollable behavior
68
+ * Whether the resolved scrollable gets the bottom safe-area inset (UIKit's
69
+ * `contentInsetAdjustmentBehavior` set to `automatic`) — already gated by the
70
+ * sheet's `insetAdjustment`
55
71
  */
56
- @property (nonatomic, strong, nullable) ScrollableOptions *scrollableOptions;
72
+ @property (nonatomic, assign) BOOL safeAreaInsetAdjustment;
57
73
 
58
74
  /**
59
- * Whether the sheet has an `auto` detent — bounds the pinned scrollable's
60
- * viewport to the container so the sheet height can derive from its content size
75
+ * Whether the resolved scrollable is padded by the absolute footer's height —
76
+ * already gated by the footer position and a plugged scrollable
61
77
  */
62
- @property (nonatomic, assign) BOOL hasAutoDetent;
78
+ @property (nonatomic, assign) BOOL footerInsetAdjustment;
63
79
 
64
80
  /**
65
81
  * Bottom safe-area inset the footer absorbs as padding — the footer
@@ -17,7 +17,6 @@
17
17
  #import "TrueSheetViewController.h"
18
18
  #import "core/TrueSheetKeyboardObserver.h"
19
19
  #import "utils/UIView+ScrollEdgeInteraction.h"
20
- #import "utils/WindowUtil.h"
21
20
 
22
21
  #import <react/renderer/components/TrueSheetSpec/ComponentDescriptors.h>
23
22
  #import <react/renderer/components/TrueSheetSpec/EventEmitters.h>
@@ -33,7 +32,9 @@ using namespace facebook::react;
33
32
 
34
33
  - (instancetype)init {
35
34
  if (self = [super init]) {
35
+ _contentInsetAdjustment = TrueSheetViewContentInsetAdjustment::Automatic;
36
36
  _keyboardScrollOffset = 0;
37
+ _keyboardOffset = 0;
37
38
  _scrollingExpandsSheet = YES;
38
39
  _topScrollEdgeEffect = TrueSheetViewTopScrollEdgeEffect::Hidden;
39
40
  _bottomScrollEdgeEffect = TrueSheetViewBottomScrollEdgeEffect::Hidden;
@@ -41,6 +42,16 @@ using namespace facebook::react;
41
42
  return self;
42
43
  }
43
44
 
45
+ - (BOOL)safeAreaInsetAdjustment {
46
+ return _contentInsetAdjustment == TrueSheetViewContentInsetAdjustment::Automatic ||
47
+ _contentInsetAdjustment == TrueSheetViewContentInsetAdjustment::SafeArea;
48
+ }
49
+
50
+ - (BOOL)footerInsetAdjustment {
51
+ return _contentInsetAdjustment == TrueSheetViewContentInsetAdjustment::Automatic ||
52
+ _contentInsetAdjustment == TrueSheetViewContentInsetAdjustment::Footer;
53
+ }
54
+
44
55
  @end
45
56
 
46
57
  @interface TrueSheetContainerView () <TrueSheetContentViewDelegate,
@@ -149,16 +160,20 @@ using namespace facebook::react;
149
160
  - (void)setScrollableOptions:(ScrollableOptions *)scrollableOptions {
150
161
  _scrollableOptions = scrollableOptions;
151
162
  _contentView.keyboardScrollOffset = scrollableOptions ? scrollableOptions.keyboardScrollOffset : 0;
163
+ _contentView.keyboardOffset = scrollableOptions ? scrollableOptions.keyboardOffset : 0;
164
+ }
165
+
166
+ - (void)setFooterInsetAdjustment:(BOOL)footerInsetAdjustment {
167
+ _footerInsetAdjustment = footerInsetAdjustment;
168
+ _contentView.footerInsetAdjustment = footerInsetAdjustment;
152
169
  }
153
170
 
154
171
  - (void)setupScrollable {
155
172
  if (_contentView) {
156
- CGFloat bottomInset = 0;
157
- if (_insetAdjustment == TrueSheetViewInsetAdjustment::Automatic) {
158
- bottomInset = [WindowUtil keyWindow].safeAreaInsets.bottom;
159
- }
160
- _contentView.hasAutoDetent = _hasAutoDetent;
161
- [_contentView setupScrollableWithBottomInset:bottomInset];
173
+ _contentView.scrollableHandle = _scrollableHandle;
174
+ _contentView.safeAreaInsetAdjustment = _safeAreaInsetAdjustment;
175
+ _contentView.footerInsetAdjustment = _footerInsetAdjustment;
176
+ [_contentView setupScrollable];
162
177
  [_contentView applyScrollEdgeEffects:_scrollableOptions];
163
178
  if (@available(iOS 26.0, *)) {
164
179
  [self setupEdgeInteractions];
@@ -203,6 +218,7 @@ using namespace facebook::react;
203
218
  _contentView = (TrueSheetContentView *)childComponentView;
204
219
  _contentView.delegate = self;
205
220
  _contentView.footerView = _footerView;
221
+ _contentView.footerInsetAdjustment = _footerInsetAdjustment;
206
222
 
207
223
  // Children mount bottom-up, so the content subtree is complete here.
208
224
  // Late-mounted peek views attach themselves instead (see TrueSheetPeekView).
@@ -232,22 +248,29 @@ using namespace facebook::react;
232
248
  _contentView.footerView = _footerView;
233
249
  [_footerView setBottomInset:_footerBottomInset];
234
250
  [self footerViewDidChangeSize:_footerView.frame.size];
251
+
252
+ // The observer is set up on present — a footer mounted after that (e.g. a
253
+ // conditional one) joins it here and rises above a keyboard that's already open
254
+ _footerView.keyboardObserver = _keyboardObserver;
255
+ [self updateFooterKeyboardOffset];
235
256
  }
236
257
  }
237
258
 
238
259
  - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
239
- if ([childComponentView isKindOfClass:[TrueSheetContentView class]]) {
260
+ if (childComponentView == _contentView) {
261
+ _contentView.keyboardObserver = nil;
240
262
  _contentView.delegate = nil;
241
263
  _contentView = nil;
242
264
  }
243
265
 
244
- if ([childComponentView isKindOfClass:[TrueSheetHeaderView class]]) {
266
+ if (childComponentView == _headerView) {
245
267
  _headerView.delegate = nil;
246
268
  _headerView = nil;
247
269
  [self headerViewDidChangeSize:CGSizeZero];
248
270
  }
249
271
 
250
- if ([childComponentView isKindOfClass:[TrueSheetFooterView class]]) {
272
+ if (childComponentView == _footerView) {
273
+ _footerView.keyboardObserver = nil;
251
274
  _footerView.delegate = nil;
252
275
  _footerView = nil;
253
276
  _contentView.footerView = nil;
@@ -271,6 +294,12 @@ using namespace facebook::react;
271
294
  [self.delegate containerViewScrollViewDidChange];
272
295
  }
273
296
 
297
+ // Footer controls can mount, unmount, or hide deep in its subtree without
298
+ // passing through its own mount hooks or changing its size.
299
+ - (void)contentViewDidMountTransaction {
300
+ [self.delegate containerViewDidMountTransaction];
301
+ }
302
+
274
303
  #pragma mark - TrueSheetHeaderViewDelegate
275
304
 
276
305
  - (void)headerViewDidChangeSize:(CGSize)newSize {
@@ -284,6 +313,7 @@ using namespace facebook::react;
284
313
 
285
314
  - (void)footerViewDidChangeSize:(CGSize)newSize {
286
315
  [self.delegate containerViewFooterDidChangeSize:newSize];
316
+ [_contentView updateBottomInset];
287
317
  if (@available(iOS 26.0, *)) {
288
318
  [self setupEdgeInteractions];
289
319
  }
@@ -311,10 +341,9 @@ using namespace facebook::react;
311
341
  return;
312
342
  }
313
343
 
314
- if (_peekView != nil) {
315
- RCTLogWarn(@"TrueSheet: Sheet can only have one peek component.");
316
- return;
317
- }
344
+ // Last-attached wins. During a screen transition the incoming peek mounts
345
+ // before the outgoing one detaches, and the outgoing detach is a no-op.
346
+ _peekView.delegate = nil;
318
347
 
319
348
  _peekView = peekView;
320
349
  peekView.delegate = self;
@@ -342,17 +371,8 @@ using namespace facebook::react;
342
371
 
343
372
  _keyboardObserver = [[TrueSheetKeyboardObserver alloc] init];
344
373
  _keyboardObserver.viewController = (TrueSheetViewController *)viewController;
345
-
346
- if (_contentView) {
347
- _contentView.keyboardObserver = _keyboardObserver;
348
- [_keyboardObserver addDelegate:_contentView];
349
- }
350
-
351
- if (_footerView) {
352
- _footerView.keyboardObserver = _keyboardObserver;
353
- [_keyboardObserver addDelegate:_footerView];
354
- }
355
-
374
+ _contentView.keyboardObserver = _keyboardObserver;
375
+ _footerView.keyboardObserver = _keyboardObserver;
356
376
  [_keyboardObserver start];
357
377
  }
358
378
 
@@ -8,6 +8,7 @@
8
8
 
9
9
  #ifdef RCT_NEW_ARCH_ENABLED
10
10
 
11
+ #import <React/RCTMountingTransactionObserving.h>
11
12
  #import <React/RCTSurfaceTouchHandler.h>
12
13
  #import <React/RCTViewComponentView.h>
13
14
  #import <UIKit/UIKit.h>
@@ -25,45 +26,73 @@ NS_ASSUME_NONNULL_BEGIN
25
26
 
26
27
  - (void)contentViewDidChangeSize:(CGSize)newSize;
27
28
  - (void)contentViewScrollViewDidChange;
29
+ - (void)contentViewDidMountTransaction;
28
30
 
29
31
  @end
30
32
 
31
- @interface TrueSheetContentView : RCTViewComponentView <TrueSheetKeyboardObserverDelegate>
33
+ @interface TrueSheetContentView
34
+ : RCTViewComponentView <TrueSheetKeyboardObserverDelegate, RCTMountingTransactionObserving>
32
35
 
33
36
  @property (nonatomic, weak, nullable) id<TrueSheetContentViewDelegate> delegate;
34
37
  @property (nonatomic, assign) CGFloat keyboardScrollOffset;
38
+
39
+ /**
40
+ * Adjustment added to the keyboard bottom inset applied to the detected
41
+ * scrollable — negative values reduce the inset (e.g. to cancel out safe-area
42
+ * padding already baked into the content's paddingBottom).
43
+ */
44
+ @property (nonatomic, assign) CGFloat keyboardOffset;
45
+
35
46
  @property (nonatomic, weak, nullable) TrueSheetKeyboardObserver *keyboardObserver;
36
47
 
37
48
  /**
38
- * Sibling footer view — an absolute footer rises above the keyboard and
39
- * occludes the content's bottom edge, so it counts toward the keyboard inset.
49
+ * Sibling footer view — a relative footer shields part of the keyboard's
50
+ * overlap from the inset; an absolute footer extends the caret reveal target.
40
51
  */
41
52
  @property (nonatomic, weak, nullable) TrueSheetFooterView *footerView;
42
53
 
43
54
  /**
44
- * Whether the sheet has an `auto` detent. Deriving the sheet height from the
45
- * scroll content is circular with natural layout, so the pinned ScrollView's
46
- * viewport is force-bounded to the container only in this case.
55
+ * Content height measured unconstrained by the shadow node — the height the
56
+ * content wants regardless of container bounds (see
57
+ * TrueSheetContentViewShadowNode). Falls back to the frame height before the
58
+ * first state update.
47
59
  */
48
- @property (nonatomic, assign) BOOL hasAutoDetent;
60
+ @property (nonatomic, readonly) CGFloat naturalHeight;
49
61
 
50
62
  /**
51
- * Content height with the pinned ScrollView's viewport replaced by its content
52
- * size — the height the content wants regardless of container bounds.
53
- * Falls back to the frame height when no ScrollView is pinned.
63
+ * React tag of the user-provided scrollable (see the `scrollableRef` prop).
64
+ * Setting a new handle clears the currently resolved ScrollView.
54
65
  */
55
- @property (nonatomic, readonly) CGFloat naturalHeight;
66
+ @property (nonatomic, assign) NSInteger scrollableHandle;
67
+
68
+ /**
69
+ * Sets the resolved ScrollView's `contentInsetAdjustmentBehavior` to
70
+ * `automatic` while plugged so UIKit applies the bottom safe-area inset to
71
+ * the scroll content. The previous behavior is restored on clear.
72
+ */
73
+ @property (nonatomic, assign) BOOL safeAreaInsetAdjustment;
74
+
75
+ /**
76
+ * Pads the resolved ScrollView's bottom content inset by the absolute
77
+ * footer's height so the last item scrolls into view above it. Stacks with
78
+ * the keyboard inset.
79
+ */
80
+ @property (nonatomic, assign) BOOL footerInsetAdjustment;
56
81
 
57
82
  - (RCTScrollViewComponentView *_Nullable)findScrollView;
58
83
 
59
84
  /**
60
- * Pin the first ScrollView found in the content, wiring insets and keyboard handling
61
- * @param bottomInset Bottom content inset for the scroll view
85
+ * Re-applies the footer and keyboard insets — call when the footer's size changes
86
+ */
87
+ - (void)updateBottomInset;
88
+
89
+ /**
90
+ * Resolve the ScrollView from `scrollableHandle`, wiring keyboard handling
62
91
  */
63
- - (void)setupScrollableWithBottomInset:(CGFloat)bottomInset;
92
+ - (void)setupScrollable;
64
93
 
65
94
  /**
66
- * Apply scroll edge effects to the pinned scroll view (iOS 26+)
95
+ * Apply scroll edge effects to the detected scroll view (iOS 26+)
67
96
  */
68
97
  - (void)applyScrollEdgeEffects:(nullable ScrollableOptions *)options;
69
98