@lodev09/react-native-true-sheet 4.0.0-beta.2 → 4.0.0-beta.20

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 (203) hide show
  1. package/README.md +25 -4
  2. package/android/build.gradle +22 -1
  3. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +50 -16
  4. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +302 -184
  5. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentViewManager.kt +5 -1
  6. package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterView.kt +21 -110
  7. package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayView.kt +116 -0
  8. package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayViewManager.kt +45 -0
  9. package/android/src/main/java/com/lodev09/truesheet/TrueSheetPackage.kt +2 -1
  10. package/android/src/main/java/com/lodev09/truesheet/TrueSheetStateUpdater.kt +18 -0
  11. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +119 -50
  12. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +360 -163
  13. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +54 -12
  14. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +22 -9
  15. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +84 -5
  16. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +104 -39
  17. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDimView.kt +3 -0
  18. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetOverlayRootView.kt +137 -0
  19. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +15 -0
  20. package/android/src/main/java/com/lodev09/truesheet/utils/KeyboardUtils.kt +15 -2
  21. package/android/src/main/java/com/lodev09/truesheet/utils/ScreenUtils.kt +0 -12
  22. package/android/src/main/java/com/lodev09/truesheet/utils/ViewUtils.kt +19 -7
  23. package/android/src/main/jni/TrueSheetSpec.h +1 -0
  24. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +1 -9
  25. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +110 -30
  26. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +30 -7
  27. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +2 -2
  28. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +9 -8
  29. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h +3 -5
  30. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp +9 -3
  31. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.h +3 -6
  32. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.cpp +1 -1
  33. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.h +4 -6
  34. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.cpp +1 -1
  35. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.h +1 -1
  36. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetLayoutUtils.h +43 -0
  37. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewComponentDescriptor.h +21 -0
  38. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.cpp +17 -0
  39. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.h +33 -0
  40. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h +3 -5
  41. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +7 -40
  42. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h +3 -7
  43. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.cpp +3 -5
  44. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.h +4 -5
  45. package/ios/TrueSheetContainerView.h +27 -7
  46. package/ios/TrueSheetContainerView.mm +31 -11
  47. package/ios/TrueSheetContentView.h +43 -15
  48. package/ios/TrueSheetContentView.mm +211 -189
  49. package/ios/TrueSheetFooterView.h +6 -0
  50. package/ios/TrueSheetFooterView.mm +93 -17
  51. package/ios/TrueSheetModule.h +2 -7
  52. package/ios/TrueSheetModule.mm +7 -16
  53. package/ios/TrueSheetOverlayView.h +32 -0
  54. package/ios/TrueSheetOverlayView.mm +161 -0
  55. package/ios/TrueSheetView.mm +212 -55
  56. package/ios/TrueSheetViewController.h +31 -3
  57. package/ios/TrueSheetViewController.mm +393 -94
  58. package/ios/core/TrueSheetBlurView.h +0 -2
  59. package/ios/core/TrueSheetBlurView.mm +3 -36
  60. package/ios/core/TrueSheetDetentCalculator.h +7 -1
  61. package/ios/core/TrueSheetDetentCalculator.mm +27 -4
  62. package/ios/core/TrueSheetGrabberView.mm +13 -3
  63. package/ios/core/TrueSheetKeyboardObserver.mm +2 -0
  64. package/ios/core/TrueSheetOverlayContainerView.h +31 -0
  65. package/ios/core/TrueSheetOverlayContainerView.mm +35 -0
  66. package/ios/events/TrueSheetLifecycleEvents.h +2 -0
  67. package/ios/events/TrueSheetLifecycleEvents.mm +8 -0
  68. package/ios/tvos/TrueSheetStubs.mm +12 -0
  69. package/ios/utils/UIView+ScrollEdgeInteraction.h +1 -0
  70. package/ios/utils/UIView+ScrollEdgeInteraction.mm +24 -2
  71. package/lib/module/TrueSheet.js +173 -39
  72. package/lib/module/TrueSheet.js.map +1 -1
  73. package/lib/module/TrueSheet.web.js +218 -243
  74. package/lib/module/TrueSheet.web.js.map +1 -1
  75. package/lib/module/TrueSheetBackground.js +15 -0
  76. package/lib/module/TrueSheetBackground.js.map +1 -0
  77. package/lib/module/TrueSheetOverlay.js +30 -0
  78. package/lib/module/TrueSheetOverlay.js.map +1 -0
  79. package/lib/module/TrueSheetOverlay.web.js +35 -0
  80. package/lib/module/TrueSheetOverlay.web.js.map +1 -0
  81. package/lib/module/TrueSheetPeek.web.js +20 -15
  82. package/lib/module/TrueSheetPeek.web.js.map +1 -1
  83. package/lib/module/detentBackgrounds.js +21 -0
  84. package/lib/module/detentBackgrounds.js.map +1 -0
  85. package/lib/module/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
  86. package/lib/module/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
  87. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +14 -10
  88. package/lib/module/index.js +1 -0
  89. package/lib/module/index.js.map +1 -1
  90. package/lib/module/mocks/index.js +18 -2
  91. package/lib/module/mocks/index.js.map +1 -1
  92. package/lib/module/mocks/navigationExpoRouter.js.map +1 -1
  93. package/lib/module/navigation/base-types.js +2 -0
  94. package/lib/module/navigation/base-types.js.map +1 -0
  95. package/lib/module/navigation/createTrueSheetRouter.js +0 -9
  96. package/lib/module/navigation/createTrueSheetRouter.js.map +1 -1
  97. package/lib/module/navigation/expo-router/base-types.js +2 -0
  98. package/lib/module/navigation/expo-router/base-types.js.map +1 -0
  99. package/lib/module/navigation/expo-router/index.js +10 -7
  100. package/lib/module/navigation/expo-router/index.js.map +1 -1
  101. package/lib/module/navigation/expo-router/types.js +4 -0
  102. package/lib/module/navigation/expo-router/types.js.map +1 -0
  103. package/lib/module/navigation/index.js.map +1 -1
  104. package/lib/module/navigation/screen/useSheetScreenState.js +1 -0
  105. package/lib/module/navigation/screen/useSheetScreenState.js.map +1 -1
  106. package/lib/module/web/constants.js +1 -1
  107. package/lib/module/web/constants.js.map +1 -1
  108. package/lib/module/web/layout.js +168 -0
  109. package/lib/module/web/layout.js.map +1 -0
  110. package/lib/module/web/vaul/constants.js +4 -0
  111. package/lib/module/web/vaul/constants.js.map +1 -1
  112. package/lib/module/web/vaul/context.js.map +1 -1
  113. package/lib/module/web/vaul/helpers.js +1 -0
  114. package/lib/module/web/vaul/helpers.js.map +1 -1
  115. package/lib/module/web/vaul/index.js +44 -6
  116. package/lib/module/web/vaul/index.js.map +1 -1
  117. package/lib/module/web/vaul/use-snap-points.js +6 -8
  118. package/lib/module/web/vaul/use-snap-points.js.map +1 -1
  119. package/lib/typescript/src/TrueSheet.d.ts +6 -0
  120. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  121. package/lib/typescript/src/TrueSheet.types.d.ts +135 -34
  122. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  123. package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -1
  124. package/lib/typescript/src/TrueSheetBackground.d.ts +3 -0
  125. package/lib/typescript/src/TrueSheetBackground.d.ts.map +1 -0
  126. package/lib/typescript/src/TrueSheetOverlay.d.ts +8 -0
  127. package/lib/typescript/src/TrueSheetOverlay.d.ts.map +1 -0
  128. package/lib/typescript/src/TrueSheetOverlay.web.d.ts +8 -0
  129. package/lib/typescript/src/TrueSheetOverlay.web.d.ts.map +1 -0
  130. package/lib/typescript/src/TrueSheetPeek.web.d.ts +8 -4
  131. package/lib/typescript/src/TrueSheetPeek.web.d.ts.map +1 -1
  132. package/lib/typescript/src/detentBackgrounds.d.ts +10 -0
  133. package/lib/typescript/src/detentBackgrounds.d.ts.map +1 -0
  134. package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts +6 -0
  135. package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts.map +1 -0
  136. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +11 -7
  137. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  138. package/lib/typescript/src/index.d.ts +1 -0
  139. package/lib/typescript/src/index.d.ts.map +1 -1
  140. package/lib/typescript/src/mocks/index.d.ts +4 -0
  141. package/lib/typescript/src/mocks/index.d.ts.map +1 -1
  142. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts +3 -3
  143. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts.map +1 -1
  144. package/lib/typescript/src/navigation/base-types.d.ts +9 -0
  145. package/lib/typescript/src/navigation/base-types.d.ts.map +1 -0
  146. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts +2 -13
  147. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts.map +1 -1
  148. package/lib/typescript/src/navigation/expo-router/base-types.d.ts +8 -0
  149. package/lib/typescript/src/navigation/expo-router/base-types.d.ts.map +1 -0
  150. package/lib/typescript/src/navigation/expo-router/index.d.ts +8 -6
  151. package/lib/typescript/src/navigation/expo-router/index.d.ts.map +1 -1
  152. package/lib/typescript/src/navigation/expo-router/types.d.ts +44 -0
  153. package/lib/typescript/src/navigation/expo-router/types.d.ts.map +1 -0
  154. package/lib/typescript/src/navigation/index.d.ts +3 -4
  155. package/lib/typescript/src/navigation/index.d.ts.map +1 -1
  156. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts +2 -1
  157. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -1
  158. package/lib/typescript/src/navigation/types.d.ts +41 -5
  159. package/lib/typescript/src/navigation/types.d.ts.map +1 -1
  160. package/lib/typescript/src/web/constants.d.ts +1 -1
  161. package/lib/typescript/src/web/constants.d.ts.map +1 -1
  162. package/lib/typescript/src/web/layout.d.ts +19 -0
  163. package/lib/typescript/src/web/layout.d.ts.map +1 -0
  164. package/lib/typescript/src/web/vaul/constants.d.ts +1 -0
  165. package/lib/typescript/src/web/vaul/constants.d.ts.map +1 -1
  166. package/lib/typescript/src/web/vaul/context.d.ts +1 -0
  167. package/lib/typescript/src/web/vaul/context.d.ts.map +1 -1
  168. package/lib/typescript/src/web/vaul/helpers.d.ts +1 -0
  169. package/lib/typescript/src/web/vaul/helpers.d.ts.map +1 -1
  170. package/lib/typescript/src/web/vaul/index.d.ts +7 -1
  171. package/lib/typescript/src/web/vaul/index.d.ts.map +1 -1
  172. package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -1
  173. package/package.json +17 -8
  174. package/react-native.config.js +1 -0
  175. package/src/TrueSheet.tsx +206 -48
  176. package/src/TrueSheet.types.ts +142 -35
  177. package/src/TrueSheet.web.tsx +270 -290
  178. package/src/TrueSheetBackground.tsx +17 -0
  179. package/src/TrueSheetOverlay.tsx +24 -0
  180. package/src/TrueSheetOverlay.web.tsx +33 -0
  181. package/src/TrueSheetPeek.web.tsx +25 -23
  182. package/src/detentBackgrounds.ts +24 -0
  183. package/src/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
  184. package/src/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
  185. package/src/fabric/TrueSheetViewNativeComponent.ts +14 -10
  186. package/src/index.ts +1 -0
  187. package/src/mocks/index.ts +17 -2
  188. package/src/mocks/navigationExpoRouter.ts +6 -5
  189. package/src/navigation/base-types.ts +20 -0
  190. package/src/navigation/createTrueSheetRouter.ts +5 -33
  191. package/src/navigation/expo-router/base-types.ts +18 -0
  192. package/src/navigation/expo-router/index.ts +28 -30
  193. package/src/navigation/expo-router/types.ts +116 -0
  194. package/src/navigation/index.ts +6 -7
  195. package/src/navigation/screen/useSheetScreenState.ts +2 -0
  196. package/src/navigation/types.ts +75 -22
  197. package/src/web/constants.ts +1 -1
  198. package/src/web/layout.ts +196 -0
  199. package/src/web/vaul/constants.ts +4 -0
  200. package/src/web/vaul/context.ts +1 -0
  201. package/src/web/vaul/helpers.ts +5 -0
  202. package/src/web/vaul/index.tsx +67 -5
  203. package/src/web/vaul/use-snap-points.ts +6 -14
@@ -0,0 +1,43 @@
1
+ #pragma once
2
+
3
+ #include <react/renderer/components/view/conversions.h>
4
+ #include <yoga/node/Node.h>
5
+ #include <yoga/style/Style.h>
6
+
7
+ namespace facebook::react {
8
+
9
+ /*
10
+ * Overrides a node's Yoga dimensions with the container size reported from
11
+ * native. A zero dimension leaves that axis to Yoga.
12
+ */
13
+ inline void applyContainerSizeToYogaNode(
14
+ yoga::Node &node, const yoga::Style &baseStyle, float containerWidth, float containerHeight) {
15
+ if (containerWidth <= 0 && containerHeight <= 0) {
16
+ return;
17
+ }
18
+
19
+ yoga::Style adjustedStyle = baseStyle;
20
+ const auto &currentStyle = node.style();
21
+ bool needsUpdate = false;
22
+
23
+ if (containerWidth > 0) {
24
+ adjustedStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(containerWidth));
25
+ if (adjustedStyle.dimension(yoga::Dimension::Width) != currentStyle.dimension(yoga::Dimension::Width)) {
26
+ needsUpdate = true;
27
+ }
28
+ }
29
+
30
+ if (containerHeight > 0) {
31
+ adjustedStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(containerHeight));
32
+ if (adjustedStyle.dimension(yoga::Dimension::Height) != currentStyle.dimension(yoga::Dimension::Height)) {
33
+ needsUpdate = true;
34
+ }
35
+ }
36
+
37
+ if (needsUpdate) {
38
+ node.setStyle(adjustedStyle);
39
+ node.setDirty(true);
40
+ }
41
+ }
42
+
43
+ } // namespace facebook::react
@@ -0,0 +1,21 @@
1
+ #pragma once
2
+
3
+ #include <react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.h>
4
+ #include <react/renderer/core/ConcreteComponentDescriptor.h>
5
+
6
+ namespace facebook::react {
7
+
8
+ /*
9
+ * Descriptor for <TrueSheetOverlayView> component.
10
+ */
11
+ class TrueSheetOverlayViewComponentDescriptor final
12
+ : public ConcreteComponentDescriptor<TrueSheetOverlayViewShadowNode> {
13
+ using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
14
+
15
+ void adopt(ShadowNode &shadowNode) const override {
16
+ static_cast<TrueSheetOverlayViewShadowNode &>(shadowNode).adjustLayoutWithState();
17
+ ConcreteComponentDescriptor::adopt(shadowNode);
18
+ }
19
+ };
20
+
21
+ } // namespace facebook::react
@@ -0,0 +1,17 @@
1
+ #include "TrueSheetOverlayViewShadowNode.h"
2
+
3
+ #include "TrueSheetLayoutUtils.h"
4
+
5
+ namespace facebook::react {
6
+
7
+ extern const char TrueSheetOverlayViewComponentName[] = "TrueSheetOverlayView";
8
+
9
+ void TrueSheetOverlayViewShadowNode::adjustLayoutWithState() {
10
+ ensureUnsealed();
11
+
12
+ const auto &stateData = getStateData();
13
+ applyContainerSizeToYogaNode(
14
+ yogaNode_, getConcreteProps().yogaStyle, stateData.containerWidth, stateData.containerHeight);
15
+ }
16
+
17
+ } // namespace facebook::react
@@ -0,0 +1,33 @@
1
+ #pragma once
2
+
3
+ #include <jsi/jsi.h>
4
+ #include <react/renderer/components/TrueSheetSpec/EventEmitters.h>
5
+ #include <react/renderer/components/TrueSheetSpec/Props.h>
6
+ #include <react/renderer/components/TrueSheetSpec/TrueSheetViewState.h>
7
+ #include <react/renderer/components/view/ConcreteViewShadowNode.h>
8
+
9
+ namespace facebook::react {
10
+
11
+ JSI_EXPORT extern const char TrueSheetOverlayViewComponentName[];
12
+
13
+ /*
14
+ * `ShadowNode` for <TrueSheetOverlayView> component.
15
+ * Sized to the window from native (via TrueSheetViewState) so its children
16
+ * lay out against the full window like the sheet's container.
17
+ */
18
+ class JSI_EXPORT TrueSheetOverlayViewShadowNode final
19
+ : public ConcreteViewShadowNode<TrueSheetOverlayViewComponentName, TrueSheetOverlayViewProps,
20
+ TrueSheetOverlayViewEventEmitter, TrueSheetViewState> {
21
+ using ConcreteViewShadowNode::ConcreteViewShadowNode;
22
+
23
+ public:
24
+ static ShadowNodeTraits BaseTraits() {
25
+ auto traits = ConcreteViewShadowNode::BaseTraits();
26
+ traits.set(ShadowNodeTraits::Trait::RootNodeKind);
27
+ return traits;
28
+ }
29
+
30
+ void adjustLayoutWithState();
31
+ };
32
+
33
+ } // namespace facebook::react
@@ -8,13 +8,11 @@ namespace facebook::react {
8
8
  /*
9
9
  * Descriptor for <TrueSheetView> component.
10
10
  */
11
- class TrueSheetViewComponentDescriptor final
12
- : public ConcreteComponentDescriptor<TrueSheetViewShadowNode> {
11
+ class TrueSheetViewComponentDescriptor final : public ConcreteComponentDescriptor<TrueSheetViewShadowNode> {
13
12
  using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
14
13
 
15
14
  void adopt(ShadowNode &shadowNode) const override {
16
- auto &concreteShadowNode =
17
- static_cast<TrueSheetViewShadowNode &>(shadowNode);
15
+ auto &concreteShadowNode = static_cast<TrueSheetViewShadowNode &>(shadowNode);
18
16
  concreteShadowNode.adjustLayoutWithState();
19
17
 
20
18
  ConcreteComponentDescriptor::adopt(shadowNode);
@@ -25,4 +23,4 @@ class TrueSheetViewComponentDescriptor final
25
23
  }
26
24
  };
27
25
 
28
- } // namespace facebook::react
26
+ } // namespace facebook::react
@@ -1,61 +1,28 @@
1
1
  #include "TrueSheetViewShadowNode.h"
2
2
 
3
- #include <react/renderer/components/view/conversions.h>
3
+ #include "TrueSheetLayoutUtils.h"
4
4
 
5
5
  namespace facebook::react {
6
6
 
7
- using namespace yoga;
8
-
9
7
  extern const char TrueSheetViewComponentName[] = "TrueSheetView";
10
8
 
11
9
  void TrueSheetViewShadowNode::adjustLayoutWithState() {
12
10
  ensureUnsealed();
13
11
 
14
- auto state = std::static_pointer_cast<
15
- const TrueSheetViewShadowNode::ConcreteState>(getState());
16
- auto stateData = state->getData();
17
-
18
- // If container dimensions are set from native, override Yoga's dimensions
19
- if (stateData.containerWidth > 0 || stateData.containerHeight > 0) {
20
- auto &props = getConcreteProps();
21
- yoga::Style adjustedStyle = props.yogaStyle;
22
- auto currentStyle = yogaNode_.style();
23
- bool needsUpdate = false;
24
-
25
- // Set width if provided
26
- if (stateData.containerWidth > 0) {
27
- adjustedStyle.setDimension(yoga::Dimension::Width, StyleSizeLength::points(stateData.containerWidth));
28
- if (adjustedStyle.dimension(yoga::Dimension::Width) != currentStyle.dimension(yoga::Dimension::Width)) {
29
- needsUpdate = true;
30
- }
31
- }
32
-
33
- // Set height if provided
34
- if (stateData.containerHeight > 0) {
35
- adjustedStyle.setDimension(yoga::Dimension::Height, StyleSizeLength::points(stateData.containerHeight));
36
- if (adjustedStyle.dimension(yoga::Dimension::Height) != currentStyle.dimension(yoga::Dimension::Height)) {
37
- needsUpdate = true;
38
- }
39
- }
40
-
41
- if (needsUpdate) {
42
- yogaNode_.setStyle(adjustedStyle);
43
- yogaNode_.setDirty(true);
44
- }
45
- }
12
+ const auto &stateData = getStateData();
13
+ applyContainerSizeToYogaNode(
14
+ yogaNode_, getConcreteProps().yogaStyle, stateData.containerWidth, stateData.containerHeight);
46
15
  }
47
16
 
48
17
  #if !defined(ANDROID)
49
- void TrueSheetViewShadowNode::setEventDispatcher(
50
- std::weak_ptr<const EventDispatcher> dispatcher) {
18
+ void TrueSheetViewShadowNode::setEventDispatcher(std::weak_ptr<const EventDispatcher> dispatcher) {
51
19
  getStateDataMutable().setEventDispatcher(dispatcher);
52
20
  }
53
21
 
54
- TrueSheetViewShadowNode::StateData &
55
- TrueSheetViewShadowNode::getStateDataMutable() {
22
+ TrueSheetViewShadowNode::StateData &TrueSheetViewShadowNode::getStateDataMutable() {
56
23
  ensureUnsealed();
57
24
  return const_cast<TrueSheetViewShadowNode::StateData &>(getStateData());
58
25
  }
59
26
  #endif
60
27
 
61
- } // namespace facebook::react
28
+ } // namespace facebook::react
@@ -15,12 +15,8 @@ JSI_EXPORT extern const char TrueSheetViewComponentName[];
15
15
  /*
16
16
  * `ShadowNode` for <TrueSheetView> component.
17
17
  */
18
- class JSI_EXPORT TrueSheetViewShadowNode final
19
- : public ConcreteViewShadowNode<
20
- TrueSheetViewComponentName,
21
- TrueSheetViewProps,
22
- TrueSheetViewEventEmitter,
23
- TrueSheetViewState> {
18
+ class JSI_EXPORT TrueSheetViewShadowNode final : public ConcreteViewShadowNode<TrueSheetViewComponentName,
19
+ TrueSheetViewProps, TrueSheetViewEventEmitter, TrueSheetViewState> {
24
20
  using ConcreteViewShadowNode::ConcreteViewShadowNode;
25
21
 
26
22
  public:
@@ -42,4 +38,4 @@ class JSI_EXPORT TrueSheetViewShadowNode final
42
38
  #endif
43
39
  };
44
40
 
45
- } // namespace facebook::react
41
+ } // namespace facebook::react
@@ -9,15 +9,13 @@ folly::dynamic TrueSheetViewState::getDynamic() const {
9
9
  #endif
10
10
 
11
11
  #if !defined(ANDROID)
12
- void TrueSheetViewState::setEventDispatcher(
13
- std::weak_ptr<const EventDispatcher> dispatcher) {
12
+ void TrueSheetViewState::setEventDispatcher(std::weak_ptr<const EventDispatcher> dispatcher) {
14
13
  eventDispatcher_ = dispatcher;
15
14
  }
16
15
 
17
- std::weak_ptr<const EventDispatcher> TrueSheetViewState::getEventDispatcher()
18
- const noexcept {
16
+ std::weak_ptr<const EventDispatcher> TrueSheetViewState::getEventDispatcher() const noexcept {
19
17
  return eventDispatcher_;
20
18
  }
21
19
  #endif
22
20
 
23
- } // namespace facebook::react
21
+ } // namespace facebook::react
@@ -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;
@@ -46,20 +54,27 @@ NS_ASSUME_NONNULL_BEGIN
46
54
  @property (nonatomic, weak, nullable) id<TrueSheetContainerViewDelegate> delegate;
47
55
 
48
56
  /**
49
- * Inset adjustment mode for scrollable content
57
+ * Options for scrollable behavior
50
58
  */
51
- @property (nonatomic, assign) facebook::react::TrueSheetViewInsetAdjustment insetAdjustment;
59
+ @property (nonatomic, strong, nullable) ScrollableOptions *scrollableOptions;
52
60
 
53
61
  /**
54
- * Options for scrollable behavior
62
+ * React tag of the user-provided scrollable within the content (see the `scrollableRef` prop)
55
63
  */
56
- @property (nonatomic, strong, nullable) ScrollableOptions *scrollableOptions;
64
+ @property (nonatomic, assign) NSInteger scrollableHandle;
57
65
 
58
66
  /**
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
67
+ * Whether the resolved scrollable gets the bottom safe-area inset (UIKit's
68
+ * `contentInsetAdjustmentBehavior` set to `automatic`) — already gated by the
69
+ * sheet's `insetAdjustment`
61
70
  */
62
- @property (nonatomic, assign) BOOL hasAutoDetent;
71
+ @property (nonatomic, assign) BOOL safeAreaInsetAdjustment;
72
+
73
+ /**
74
+ * Whether the resolved scrollable is padded by the absolute footer's height —
75
+ * already gated by the footer position and a plugged scrollable
76
+ */
77
+ @property (nonatomic, assign) BOOL footerInsetAdjustment;
63
78
 
64
79
  /**
65
80
  * Bottom safe-area inset the footer absorbs as padding — the footer
@@ -82,6 +97,11 @@ NS_ASSUME_NONNULL_BEGIN
82
97
  */
83
98
  - (CGFloat)footerHeight;
84
99
 
100
+ /**
101
+ * Returns the bottom inset currently baked into the footer's height
102
+ */
103
+ - (CGFloat)footerAppliedBottomInset;
104
+
85
105
  /**
86
106
  * Returns the current height of the peek view within the content
87
107
  */
@@ -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,
@@ -118,6 +129,10 @@ using namespace facebook::react;
118
129
  return _footerView ? _footerView.frame.size.height : 0;
119
130
  }
120
131
 
132
+ - (CGFloat)footerAppliedBottomInset {
133
+ return _footerView ? _footerView.appliedBottomInset : 0;
134
+ }
135
+
121
136
  // Distance from the top of the content view to the bottom of the peek view.
122
137
  // Includes the peek view's offset within the content (padding, views above it)
123
138
  // so the peek detent reveals everything down to the peek content's bottom edge.
@@ -145,16 +160,20 @@ using namespace facebook::react;
145
160
  - (void)setScrollableOptions:(ScrollableOptions *)scrollableOptions {
146
161
  _scrollableOptions = scrollableOptions;
147
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;
148
169
  }
149
170
 
150
171
  - (void)setupScrollable {
151
172
  if (_contentView) {
152
- CGFloat bottomInset = 0;
153
- if (_insetAdjustment == TrueSheetViewInsetAdjustment::Automatic) {
154
- bottomInset = [WindowUtil keyWindow].safeAreaInsets.bottom;
155
- }
156
- _contentView.hasAutoDetent = _hasAutoDetent;
157
- [_contentView setupScrollableWithBottomInset:bottomInset];
173
+ _contentView.scrollableHandle = _scrollableHandle;
174
+ _contentView.safeAreaInsetAdjustment = _safeAreaInsetAdjustment;
175
+ _contentView.footerInsetAdjustment = _footerInsetAdjustment;
176
+ [_contentView setupScrollable];
158
177
  [_contentView applyScrollEdgeEffects:_scrollableOptions];
159
178
  if (@available(iOS 26.0, *)) {
160
179
  [self setupEdgeInteractions];
@@ -199,6 +218,7 @@ using namespace facebook::react;
199
218
  _contentView = (TrueSheetContentView *)childComponentView;
200
219
  _contentView.delegate = self;
201
220
  _contentView.footerView = _footerView;
221
+ _contentView.footerInsetAdjustment = _footerInsetAdjustment;
202
222
 
203
223
  // Children mount bottom-up, so the content subtree is complete here.
204
224
  // Late-mounted peek views attach themselves instead (see TrueSheetPeekView).
@@ -280,6 +300,7 @@ using namespace facebook::react;
280
300
 
281
301
  - (void)footerViewDidChangeSize:(CGSize)newSize {
282
302
  [self.delegate containerViewFooterDidChangeSize:newSize];
303
+ [_contentView updateBottomInset];
283
304
  if (@available(iOS 26.0, *)) {
284
305
  [self setupEdgeInteractions];
285
306
  }
@@ -307,10 +328,9 @@ using namespace facebook::react;
307
328
  return;
308
329
  }
309
330
 
310
- if (_peekView != nil) {
311
- RCTLogWarn(@"TrueSheet: Sheet can only have one peek component.");
312
- return;
313
- }
331
+ // Last-attached wins. During a screen transition the incoming peek mounts
332
+ // before the outgoing one detaches, and the outgoing detach is a no-op.
333
+ _peekView.delegate = nil;
314
334
 
315
335
  _peekView = peekView;
316
336
  peekView.delegate = self;
@@ -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>
@@ -28,42 +29,69 @@ NS_ASSUME_NONNULL_BEGIN
28
29
 
29
30
  @end
30
31
 
31
- @interface TrueSheetContentView : RCTViewComponentView <TrueSheetKeyboardObserverDelegate>
32
+ @interface TrueSheetContentView
33
+ : RCTViewComponentView <TrueSheetKeyboardObserverDelegate, RCTMountingTransactionObserving>
32
34
 
33
35
  @property (nonatomic, weak, nullable) id<TrueSheetContentViewDelegate> delegate;
34
36
  @property (nonatomic, assign) CGFloat keyboardScrollOffset;
37
+
38
+ /**
39
+ * Adjustment added to the keyboard bottom inset applied to the detected
40
+ * scrollable — negative values reduce the inset (e.g. to cancel out safe-area
41
+ * padding already baked into the content's paddingBottom).
42
+ */
43
+ @property (nonatomic, assign) CGFloat keyboardOffset;
44
+
35
45
  @property (nonatomic, weak, nullable) TrueSheetKeyboardObserver *keyboardObserver;
36
46
 
37
47
  /**
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.
48
+ * Sibling footer view — a relative footer shields part of the keyboard's
49
+ * overlap from the inset; an absolute footer extends the caret reveal target.
40
50
  */
41
51
  @property (nonatomic, weak, nullable) TrueSheetFooterView *footerView;
42
52
 
43
53
  /**
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.
54
+ * Content height measured unconstrained by the shadow node — the height the
55
+ * content wants regardless of container bounds (see
56
+ * TrueSheetContentViewShadowNode). Falls back to the frame height before the
57
+ * first state update.
47
58
  */
48
- @property (nonatomic, assign) BOOL hasAutoDetent;
59
+ @property (nonatomic, readonly) CGFloat naturalHeight;
49
60
 
50
61
  /**
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.
62
+ * React tag of the user-provided scrollable (see the `scrollableRef` prop).
63
+ * Setting a new handle clears the currently resolved ScrollView.
54
64
  */
55
- @property (nonatomic, readonly) CGFloat naturalHeight;
65
+ @property (nonatomic, assign) NSInteger scrollableHandle;
66
+
67
+ /**
68
+ * Sets the resolved ScrollView's `contentInsetAdjustmentBehavior` to
69
+ * `automatic` while plugged so UIKit applies the bottom safe-area inset to
70
+ * the scroll content. The previous behavior is restored on clear.
71
+ */
72
+ @property (nonatomic, assign) BOOL safeAreaInsetAdjustment;
73
+
74
+ /**
75
+ * Pads the resolved ScrollView's bottom content inset by the absolute
76
+ * footer's height so the last item scrolls into view above it. Stacks with
77
+ * the keyboard inset.
78
+ */
79
+ @property (nonatomic, assign) BOOL footerInsetAdjustment;
56
80
 
57
81
  - (RCTScrollViewComponentView *_Nullable)findScrollView;
58
82
 
59
83
  /**
60
- * Pin the first ScrollView found in the content, wiring insets and keyboard handling
61
- * @param bottomInset Bottom content inset for the scroll view
84
+ * Re-applies the footer and keyboard insets — call when the footer's size changes
85
+ */
86
+ - (void)updateBottomInset;
87
+
88
+ /**
89
+ * Resolve the ScrollView from `scrollableHandle`, wiring keyboard handling
62
90
  */
63
- - (void)setupScrollableWithBottomInset:(CGFloat)bottomInset;
91
+ - (void)setupScrollable;
64
92
 
65
93
  /**
66
- * Apply scroll edge effects to the pinned scroll view (iOS 26+)
94
+ * Apply scroll edge effects to the detected scroll view (iOS 26+)
67
95
  */
68
96
  - (void)applyScrollEdgeEffects:(nullable ScrollableOptions *)options;
69
97