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

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 (205) 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 +303 -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 +124 -50
  12. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +369 -163
  13. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +59 -12
  14. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetBehavior.kt +126 -0
  15. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +22 -9
  16. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +84 -5
  17. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +104 -39
  18. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDimView.kt +3 -0
  19. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetOverlayRootView.kt +137 -0
  20. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +15 -0
  21. package/android/src/main/java/com/lodev09/truesheet/utils/KeyboardUtils.kt +15 -2
  22. package/android/src/main/java/com/lodev09/truesheet/utils/ScreenUtils.kt +0 -12
  23. package/android/src/main/java/com/lodev09/truesheet/utils/ViewUtils.kt +19 -7
  24. package/android/src/main/jni/TrueSheetSpec.h +1 -0
  25. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +1 -9
  26. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +110 -30
  27. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +30 -7
  28. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +2 -2
  29. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +9 -8
  30. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h +3 -5
  31. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp +9 -3
  32. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.h +3 -6
  33. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.cpp +1 -1
  34. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.h +4 -6
  35. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.cpp +1 -1
  36. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.h +1 -1
  37. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetLayoutUtils.h +43 -0
  38. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewComponentDescriptor.h +21 -0
  39. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.cpp +17 -0
  40. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.h +33 -0
  41. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h +3 -5
  42. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +7 -40
  43. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h +3 -7
  44. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.cpp +3 -5
  45. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.h +4 -5
  46. package/ios/TrueSheetContainerView.h +27 -7
  47. package/ios/TrueSheetContainerView.mm +31 -11
  48. package/ios/TrueSheetContentView.h +43 -15
  49. package/ios/TrueSheetContentView.mm +211 -189
  50. package/ios/TrueSheetFooterView.h +6 -0
  51. package/ios/TrueSheetFooterView.mm +93 -17
  52. package/ios/TrueSheetModule.h +2 -7
  53. package/ios/TrueSheetModule.mm +7 -16
  54. package/ios/TrueSheetOverlayView.h +32 -0
  55. package/ios/TrueSheetOverlayView.mm +161 -0
  56. package/ios/TrueSheetView.mm +275 -56
  57. package/ios/TrueSheetViewController.h +31 -3
  58. package/ios/TrueSheetViewController.mm +393 -94
  59. package/ios/core/TrueSheetBlurView.h +0 -2
  60. package/ios/core/TrueSheetBlurView.mm +3 -36
  61. package/ios/core/TrueSheetDetentCalculator.h +7 -1
  62. package/ios/core/TrueSheetDetentCalculator.mm +27 -4
  63. package/ios/core/TrueSheetGrabberView.mm +13 -3
  64. package/ios/core/TrueSheetKeyboardObserver.mm +2 -0
  65. package/ios/core/TrueSheetOverlayContainerView.h +31 -0
  66. package/ios/core/TrueSheetOverlayContainerView.mm +35 -0
  67. package/ios/events/TrueSheetLifecycleEvents.h +2 -0
  68. package/ios/events/TrueSheetLifecycleEvents.mm +8 -0
  69. package/ios/tvos/TrueSheetStubs.mm +12 -0
  70. package/ios/utils/UIView+ScrollEdgeInteraction.h +1 -0
  71. package/ios/utils/UIView+ScrollEdgeInteraction.mm +24 -2
  72. package/lib/module/TrueSheet.js +175 -39
  73. package/lib/module/TrueSheet.js.map +1 -1
  74. package/lib/module/TrueSheet.web.js +220 -243
  75. package/lib/module/TrueSheet.web.js.map +1 -1
  76. package/lib/module/TrueSheetBackground.js +15 -0
  77. package/lib/module/TrueSheetBackground.js.map +1 -0
  78. package/lib/module/TrueSheetOverlay.js +30 -0
  79. package/lib/module/TrueSheetOverlay.js.map +1 -0
  80. package/lib/module/TrueSheetOverlay.web.js +35 -0
  81. package/lib/module/TrueSheetOverlay.web.js.map +1 -0
  82. package/lib/module/TrueSheetPeek.web.js +20 -15
  83. package/lib/module/TrueSheetPeek.web.js.map +1 -1
  84. package/lib/module/detentBackgrounds.js +21 -0
  85. package/lib/module/detentBackgrounds.js.map +1 -0
  86. package/lib/module/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
  87. package/lib/module/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
  88. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +15 -10
  89. package/lib/module/index.js +1 -0
  90. package/lib/module/index.js.map +1 -1
  91. package/lib/module/mocks/index.js +18 -2
  92. package/lib/module/mocks/index.js.map +1 -1
  93. package/lib/module/mocks/navigationExpoRouter.js.map +1 -1
  94. package/lib/module/navigation/base-types.js +2 -0
  95. package/lib/module/navigation/base-types.js.map +1 -0
  96. package/lib/module/navigation/createTrueSheetRouter.js +0 -9
  97. package/lib/module/navigation/createTrueSheetRouter.js.map +1 -1
  98. package/lib/module/navigation/expo-router/base-types.js +2 -0
  99. package/lib/module/navigation/expo-router/base-types.js.map +1 -0
  100. package/lib/module/navigation/expo-router/index.js +10 -7
  101. package/lib/module/navigation/expo-router/index.js.map +1 -1
  102. package/lib/module/navigation/expo-router/types.js +4 -0
  103. package/lib/module/navigation/expo-router/types.js.map +1 -0
  104. package/lib/module/navigation/index.js.map +1 -1
  105. package/lib/module/navigation/screen/useSheetScreenState.js +1 -0
  106. package/lib/module/navigation/screen/useSheetScreenState.js.map +1 -1
  107. package/lib/module/web/constants.js +1 -1
  108. package/lib/module/web/constants.js.map +1 -1
  109. package/lib/module/web/layout.js +168 -0
  110. package/lib/module/web/layout.js.map +1 -0
  111. package/lib/module/web/vaul/constants.js +9 -0
  112. package/lib/module/web/vaul/constants.js.map +1 -1
  113. package/lib/module/web/vaul/context.js.map +1 -1
  114. package/lib/module/web/vaul/helpers.js +1 -0
  115. package/lib/module/web/vaul/helpers.js.map +1 -1
  116. package/lib/module/web/vaul/index.js +47 -7
  117. package/lib/module/web/vaul/index.js.map +1 -1
  118. package/lib/module/web/vaul/use-snap-points.js +21 -10
  119. package/lib/module/web/vaul/use-snap-points.js.map +1 -1
  120. package/lib/typescript/src/TrueSheet.d.ts +6 -0
  121. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  122. package/lib/typescript/src/TrueSheet.types.d.ts +157 -34
  123. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  124. package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -1
  125. package/lib/typescript/src/TrueSheetBackground.d.ts +3 -0
  126. package/lib/typescript/src/TrueSheetBackground.d.ts.map +1 -0
  127. package/lib/typescript/src/TrueSheetOverlay.d.ts +8 -0
  128. package/lib/typescript/src/TrueSheetOverlay.d.ts.map +1 -0
  129. package/lib/typescript/src/TrueSheetOverlay.web.d.ts +8 -0
  130. package/lib/typescript/src/TrueSheetOverlay.web.d.ts.map +1 -0
  131. package/lib/typescript/src/TrueSheetPeek.web.d.ts +8 -4
  132. package/lib/typescript/src/TrueSheetPeek.web.d.ts.map +1 -1
  133. package/lib/typescript/src/detentBackgrounds.d.ts +10 -0
  134. package/lib/typescript/src/detentBackgrounds.d.ts.map +1 -0
  135. package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts +6 -0
  136. package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts.map +1 -0
  137. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +12 -7
  138. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  139. package/lib/typescript/src/index.d.ts +1 -0
  140. package/lib/typescript/src/index.d.ts.map +1 -1
  141. package/lib/typescript/src/mocks/index.d.ts +4 -0
  142. package/lib/typescript/src/mocks/index.d.ts.map +1 -1
  143. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts +3 -3
  144. package/lib/typescript/src/mocks/navigationExpoRouter.d.ts.map +1 -1
  145. package/lib/typescript/src/navigation/base-types.d.ts +9 -0
  146. package/lib/typescript/src/navigation/base-types.d.ts.map +1 -0
  147. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts +2 -13
  148. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts.map +1 -1
  149. package/lib/typescript/src/navigation/expo-router/base-types.d.ts +8 -0
  150. package/lib/typescript/src/navigation/expo-router/base-types.d.ts.map +1 -0
  151. package/lib/typescript/src/navigation/expo-router/index.d.ts +8 -6
  152. package/lib/typescript/src/navigation/expo-router/index.d.ts.map +1 -1
  153. package/lib/typescript/src/navigation/expo-router/types.d.ts +44 -0
  154. package/lib/typescript/src/navigation/expo-router/types.d.ts.map +1 -0
  155. package/lib/typescript/src/navigation/index.d.ts +3 -4
  156. package/lib/typescript/src/navigation/index.d.ts.map +1 -1
  157. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts +2 -1
  158. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -1
  159. package/lib/typescript/src/navigation/types.d.ts +41 -5
  160. package/lib/typescript/src/navigation/types.d.ts.map +1 -1
  161. package/lib/typescript/src/web/constants.d.ts +1 -1
  162. package/lib/typescript/src/web/constants.d.ts.map +1 -1
  163. package/lib/typescript/src/web/layout.d.ts +19 -0
  164. package/lib/typescript/src/web/layout.d.ts.map +1 -0
  165. package/lib/typescript/src/web/vaul/constants.d.ts +3 -0
  166. package/lib/typescript/src/web/vaul/constants.d.ts.map +1 -1
  167. package/lib/typescript/src/web/vaul/context.d.ts +1 -0
  168. package/lib/typescript/src/web/vaul/context.d.ts.map +1 -1
  169. package/lib/typescript/src/web/vaul/helpers.d.ts +1 -0
  170. package/lib/typescript/src/web/vaul/helpers.d.ts.map +1 -1
  171. package/lib/typescript/src/web/vaul/index.d.ts +13 -1
  172. package/lib/typescript/src/web/vaul/index.d.ts.map +1 -1
  173. package/lib/typescript/src/web/vaul/use-snap-points.d.ts +2 -1
  174. package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -1
  175. package/package.json +17 -8
  176. package/react-native.config.js +1 -0
  177. package/src/TrueSheet.tsx +208 -48
  178. package/src/TrueSheet.types.ts +166 -35
  179. package/src/TrueSheet.web.tsx +272 -290
  180. package/src/TrueSheetBackground.tsx +17 -0
  181. package/src/TrueSheetOverlay.tsx +24 -0
  182. package/src/TrueSheetOverlay.web.tsx +33 -0
  183. package/src/TrueSheetPeek.web.tsx +25 -23
  184. package/src/detentBackgrounds.ts +24 -0
  185. package/src/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
  186. package/src/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
  187. package/src/fabric/TrueSheetViewNativeComponent.ts +15 -10
  188. package/src/index.ts +1 -0
  189. package/src/mocks/index.ts +17 -2
  190. package/src/mocks/navigationExpoRouter.ts +6 -5
  191. package/src/navigation/base-types.ts +20 -0
  192. package/src/navigation/createTrueSheetRouter.ts +5 -33
  193. package/src/navigation/expo-router/base-types.ts +18 -0
  194. package/src/navigation/expo-router/index.ts +28 -30
  195. package/src/navigation/expo-router/types.ts +116 -0
  196. package/src/navigation/index.ts +6 -7
  197. package/src/navigation/screen/useSheetScreenState.ts +2 -0
  198. package/src/navigation/types.ts +75 -22
  199. package/src/web/constants.ts +1 -1
  200. package/src/web/layout.ts +196 -0
  201. package/src/web/vaul/constants.ts +9 -0
  202. package/src/web/vaul/context.ts +1 -0
  203. package/src/web/vaul/helpers.ts +5 -0
  204. package/src/web/vaul/index.tsx +75 -5
  205. package/src/web/vaul/use-snap-points.ts +32 -15
@@ -1,6 +1,12 @@
1
1
  #include "TrueSheetContentViewShadowNode.h"
2
2
 
3
+ #include <folly/ScopeGuard.h>
3
4
  #include <react/renderer/components/view/conversions.h>
5
+ #include <react/renderer/core/ComponentDescriptor.h>
6
+ #include <react/renderer/core/LayoutConstraints.h>
7
+ #include <react/renderer/core/LayoutContext.h>
8
+
9
+ #include <limits>
4
10
 
5
11
  namespace facebook::react {
6
12
 
@@ -8,36 +14,110 @@ using namespace yoga;
8
14
 
9
15
  extern const char TrueSheetContentViewComponentName[] = "TrueSheetContentView";
10
16
 
11
- void TrueSheetContentViewShadowNode::adjustLayoutWithState() {
12
- ensureUnsealed();
13
-
14
- auto state = std::static_pointer_cast<
15
- const TrueSheetContentViewShadowNode::ConcreteState>(getState());
16
- auto stateData = state->getData();
17
-
18
- auto &props = getConcreteProps();
19
-
20
- // When a ScrollView is pinned under an auto detent, fill the container so
21
- // descendant flex layouts (flex:1 wrappers, the ScrollView itself) resolve
22
- // against a definite height and the viewport is bounded — natural layout is
23
- // circular there since the sheet height derives from the ScrollView's content
24
- // size instead (see ContentView's naturalHeight on each platform). For fixed
25
- // detents, content lays out naturally like a regular view.
26
- auto flexGrow = stateData.scrollableBounded
27
- ? FloatOptional{1.0f}
28
- : props.yogaStyle.flexGrow();
29
- auto flexShrink = stateData.scrollableBounded
30
- ? FloatOptional{1.0f}
31
- : props.yogaStyle.flexShrink();
32
-
33
- if (yogaNode_.style().flexGrow() != flexGrow ||
34
- yogaNode_.style().flexShrink() != flexShrink) {
35
- yoga::Style adjustedStyle = props.yogaStyle;
36
- adjustedStyle.setFlexGrow(flexGrow);
37
- adjustedStyle.setFlexShrink(flexShrink);
38
- yogaNode_.setStyle(adjustedStyle);
39
- yogaNode_.setDirty(true);
17
+ // The measurement pass re-enters layout() on a clone — guard so it doesn't
18
+ // measure again recursively.
19
+ static thread_local bool gIsMeasuringNaturalHeight = false;
20
+
21
+ TrueSheetContentViewShadowNode::TrueSheetContentViewShadowNode(
22
+ const ShadowNode &sourceShadowNode, const ShadowNodeFragment &fragment)
23
+ : ConcreteViewShadowNode(sourceShadowNode, fragment),
24
+ measurement_(static_cast<const TrueSheetContentViewShadowNode &>(sourceShadowNode).measurement_),
25
+ measurementSourceChildren_(
26
+ static_cast<const TrueSheetContentViewShadowNode &>(sourceShadowNode).measurementSourceChildren_),
27
+ contentChanged_(static_cast<const TrueSheetContentViewShadowNode &>(sourceShadowNode).contentChanged_ ||
28
+ fragment.props || fragment.children) {
29
+ }
30
+
31
+ void TrueSheetContentViewShadowNode::layout(LayoutContext layoutContext) {
32
+ // The sizing tree needs Yoga's result, not Fabric state updates or events.
33
+ if (gIsMeasuringNaturalHeight) {
34
+ return;
35
+ }
36
+ ConcreteViewShadowNode::layout(layoutContext);
37
+ updateNaturalHeightIfNeeded(layoutContext);
38
+ }
39
+
40
+ // Every descendant must be detached from React's runtime references before
41
+ // Yoga clones it during measurement. Disabling transfer only on the root
42
+ // still lets descendant clones replace React's live nodes. Reuse unchanged
43
+ // measurement subtrees; Yoga owns copy-on-write when their layout changes.
44
+ std::shared_ptr<ShadowNode> TrueSheetContentViewShadowNode::cloneForMeasurement(
45
+ const ShadowNode &node, const Children &previousSourceChildren, const Children &previousMeasurementChildren) {
46
+ auto children = std::make_shared<Children>();
47
+ children->reserve(node.getChildren().size());
48
+ for (size_t index = 0; index < node.getChildren().size(); index++) {
49
+ const auto &child = node.getChildren()[index];
50
+ if (index < previousSourceChildren.size() && ShadowNode::sameFamily(*child, *previousSourceChildren[index])) {
51
+ const auto &previousSource = previousSourceChildren[index];
52
+ const auto &previousMeasurement = previousMeasurementChildren[index];
53
+ children->push_back(child == previousSource ? previousMeasurement
54
+ : cloneForMeasurement(*child, previousSource->getChildren(),
55
+ previousMeasurement->getChildren()));
56
+ } else {
57
+ children->push_back(cloneForMeasurement(*child, {}, {}));
58
+ }
59
+ }
60
+
61
+ auto clone = node.getComponentDescriptor().cloneShadowNode(
62
+ node, {.children = children, .state = node.getState(), .runtimeShadowNodeReference = false});
63
+ if (auto content = dynamic_cast<TrueSheetContentViewShadowNode *>(clone.get())) {
64
+ content->measurement_.reset();
65
+ content->measurementSourceChildren_.reset();
66
+ }
67
+ return clone;
68
+ }
69
+
70
+ // The natural height is the height the content wants when unbounded — the
71
+ // source for the auto detent. When the content's height derives from the
72
+ // container, the committed layout doesn't reflect it — lay out a clone of the
73
+ // subtree with an unconstrained height instead. Yoga respects the user's
74
+ // styles: an explicit-height ScrollView keeps its height while a flexible one
75
+ // expands to its content — no ScrollView discovery involved.
76
+ void TrueSheetContentViewShadowNode::updateNaturalHeightIfNeeded(const LayoutContext &layoutContext) {
77
+ auto stateData = getStateData();
78
+ auto size = getLayoutMetrics().frame.size;
79
+
80
+ Float naturalHeight = size.height;
81
+ // Auto-height content can also be capped by a shrinking ScrollView. Only
82
+ // a fixed, non-flexible height can be taken from the viewport layout.
83
+ if (yogaNode_.isNodeFlexible() || !getConcreteProps().yogaStyle.dimension(Dimension::Height).isPoints()) {
84
+ auto constraints = LayoutConstraints{};
85
+ constraints.minimumSize = {size.width, 0};
86
+ constraints.maximumSize = {size.width, std::numeric_limits<Float>::infinity()};
87
+ constraints.layoutDirection = getLayoutMetrics().layoutDirection;
88
+
89
+ auto measurementContext = layoutContext;
90
+ measurementContext.affectedNodes = nullptr;
91
+ auto errata = YGConfigGetErrata(&yogaConfig_);
92
+
93
+ // Yoga's viewport-only clones carry no new props or children. Reuse the
94
+ // intrinsic height across those layouts instead of measuring each drag frame.
95
+ if (contentChanged_ || !measurement_ || !(measurement_->constraints == constraints) ||
96
+ !(measurement_->context == measurementContext) || measurement_->errata != errata) {
97
+ gIsMeasuringNaturalHeight = true;
98
+ auto restoreMeasurement = folly::makeGuard([] { gIsMeasuringNaturalHeight = false; });
99
+ auto measurementNode =
100
+ measurement_ ? cloneForMeasurement(*this, *measurementSourceChildren_, measurement_->root->getChildren())
101
+ : cloneForMeasurement(*this, {}, {});
102
+ auto &measurement = static_cast<LayoutableShadowNode &>(*measurementNode);
103
+ measurement.layoutTree(measurementContext, constraints);
104
+ measurement_ = std::make_shared<const Measurement>(Measurement{.root = measurementNode,
105
+ .constraints = constraints,
106
+ .context = measurementContext,
107
+ .errata = errata,
108
+ .height = measurement.getLayoutMetrics().frame.size.height});
109
+ }
110
+ naturalHeight = measurement_->height;
111
+ } else {
112
+ measurement_.reset();
113
+ }
114
+ measurementSourceChildren_ = children_;
115
+ contentChanged_ = false;
116
+
117
+ if (stateData.naturalHeight != naturalHeight) {
118
+ stateData.naturalHeight = naturalHeight;
119
+ setStateData(std::move(stateData));
40
120
  }
41
121
  }
42
122
 
43
- } // namespace facebook::react
123
+ } // namespace facebook::react
@@ -5,6 +5,8 @@
5
5
  #include <react/renderer/components/TrueSheetSpec/Props.h>
6
6
  #include <react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h>
7
7
  #include <react/renderer/components/view/ConcreteViewShadowNode.h>
8
+ #include <react/renderer/core/LayoutConstraints.h>
9
+ #include <react/renderer/core/LayoutContext.h>
8
10
 
9
11
  namespace facebook::react {
10
12
 
@@ -14,15 +16,36 @@ JSI_EXPORT extern const char TrueSheetContentViewComponentName[];
14
16
  * `ShadowNode` for <TrueSheetContentView> component.
15
17
  */
16
18
  class JSI_EXPORT TrueSheetContentViewShadowNode final
17
- : public ConcreteViewShadowNode<
18
- TrueSheetContentViewComponentName,
19
- TrueSheetContentViewProps,
20
- TrueSheetContentViewEventEmitter,
21
- TrueSheetContentViewState> {
19
+ : public ConcreteViewShadowNode<TrueSheetContentViewComponentName, TrueSheetContentViewProps,
20
+ TrueSheetContentViewEventEmitter, TrueSheetContentViewState> {
22
21
  using ConcreteViewShadowNode::ConcreteViewShadowNode;
23
22
 
24
23
  public:
25
- void adjustLayoutWithState();
24
+ TrueSheetContentViewShadowNode(const ShadowNode &sourceShadowNode, const ShadowNodeFragment &fragment);
25
+
26
+ #pragma mark - LayoutableShadowNode
27
+
28
+ void layout(LayoutContext layoutContext) override;
29
+
30
+ private:
31
+ using Children = std::vector<std::shared_ptr<const ShadowNode>>;
32
+
33
+ struct Measurement {
34
+ std::shared_ptr<const ShadowNode> root;
35
+ LayoutConstraints constraints;
36
+ LayoutContext context;
37
+ YGErrata errata;
38
+ Float height;
39
+ };
40
+
41
+ std::shared_ptr<const Measurement> measurement_;
42
+ std::shared_ptr<const Children> measurementSourceChildren_;
43
+ bool contentChanged_{true};
44
+
45
+ static std::shared_ptr<ShadowNode> cloneForMeasurement(
46
+ const ShadowNode &node, const Children &previousSourceChildren, const Children &previousMeasurementChildren);
47
+
48
+ void updateNaturalHeightIfNeeded(const LayoutContext &layoutContext);
26
49
  };
27
50
 
28
- } // namespace facebook::react
51
+ } // namespace facebook::react
@@ -4,8 +4,8 @@ namespace facebook::react {
4
4
 
5
5
  #ifdef ANDROID
6
6
  folly::dynamic TrueSheetContentViewState::getDynamic() const {
7
- return folly::dynamic::object("scrollableBounded", scrollableBounded);
7
+ return folly::dynamic::object("naturalHeight", naturalHeight);
8
8
  }
9
9
  #endif
10
10
 
11
- } // namespace facebook::react
11
+ } // namespace facebook::react
@@ -1,5 +1,7 @@
1
1
  #pragma once
2
2
 
3
+ #include <react/renderer/graphics/Float.h>
4
+
3
5
  #ifdef ANDROID
4
6
  #include <folly/dynamic.h>
5
7
  #include <react/renderer/mapbuffer/MapBuffer.h>
@@ -10,21 +12,20 @@ namespace facebook::react {
10
12
 
11
13
  /*
12
14
  * State for <TrueSheetContentView> component.
13
- * Set from native when a ScrollView is pinned so the shadow node bounds the
14
- * content to the container via flexShrink (see TrueSheetContentViewShadowNode).
15
+ * `naturalHeight` is measured by the shadow node during layout — the height
16
+ * the content wants when unbounded (see TrueSheetContentViewShadowNode).
15
17
  */
16
18
  class TrueSheetContentViewState final {
17
19
  public:
18
20
  TrueSheetContentViewState() = default;
19
21
 
20
22
  #ifdef ANDROID
21
- TrueSheetContentViewState(
22
- TrueSheetContentViewState const &previousState,
23
- folly::dynamic data)
24
- : scrollableBounded(data["scrollableBounded"].getBool()) {}
23
+ TrueSheetContentViewState(TrueSheetContentViewState const &previousState, folly::dynamic data)
24
+ : naturalHeight(previousState.naturalHeight) {
25
+ }
25
26
  #endif
26
27
 
27
- bool scrollableBounded{false};
28
+ Float naturalHeight{0};
28
29
 
29
30
  #ifdef ANDROID
30
31
  folly::dynamic getDynamic() const;
@@ -34,4 +35,4 @@ class TrueSheetContentViewState final {
34
35
  #endif
35
36
  };
36
37
 
37
- } // namespace facebook::react
38
+ } // namespace facebook::react
@@ -8,17 +8,15 @@ namespace facebook::react {
8
8
  /*
9
9
  * Descriptor for <TrueSheetFooterView> component.
10
10
  */
11
- class TrueSheetFooterViewComponentDescriptor final
12
- : public ConcreteComponentDescriptor<TrueSheetFooterViewShadowNode> {
11
+ class TrueSheetFooterViewComponentDescriptor final : public ConcreteComponentDescriptor<TrueSheetFooterViewShadowNode> {
13
12
  using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
14
13
 
15
14
  void adopt(ShadowNode &shadowNode) const override {
16
- auto &concreteShadowNode =
17
- static_cast<TrueSheetFooterViewShadowNode &>(shadowNode);
15
+ auto &concreteShadowNode = static_cast<TrueSheetFooterViewShadowNode &>(shadowNode);
18
16
  concreteShadowNode.adjustLayoutWithState();
19
17
 
20
18
  ConcreteComponentDescriptor::adopt(shadowNode);
21
19
  }
22
20
  };
23
21
 
24
- } // namespace facebook::react
22
+ } // namespace facebook::react
@@ -13,8 +13,7 @@ extern const char TrueSheetFooterViewComponentName[] = "TrueSheetFooterView";
13
13
  void TrueSheetFooterViewShadowNode::adjustLayoutWithState() {
14
14
  ensureUnsealed();
15
15
 
16
- auto state = std::static_pointer_cast<
17
- const TrueSheetFooterViewShadowNode::ConcreteState>(getState());
16
+ auto state = std::static_pointer_cast<const TrueSheetFooterViewShadowNode::ConcreteState>(getState());
18
17
  auto stateData = state->getData();
19
18
 
20
19
  auto &props = getConcreteProps();
@@ -25,6 +24,13 @@ void TrueSheetFooterViewShadowNode::adjustLayoutWithState() {
25
24
  float bottomInset = stateData.bottomInset;
26
25
  if (!stateData.initialized && props.autoBottomInset) {
27
26
  bottomInset = TrueSheetInsets::bottomSafeArea();
27
+ if (bottomInset != stateData.bottomInset) {
28
+ // Record the seeded value so the mounted view reads exactly the inset
29
+ // baked into this layout — the global may change before mount.
30
+ auto seededData = stateData;
31
+ seededData.bottomInset = bottomInset;
32
+ setStateData(std::move(seededData));
33
+ }
28
34
  }
29
35
 
30
36
  // A footer pinned to the sheet's bottom edge owns the bottom safe-area
@@ -53,4 +59,4 @@ void TrueSheetFooterViewShadowNode::adjustLayoutWithState() {
53
59
  }
54
60
  }
55
61
 
56
- } // namespace facebook::react
62
+ } // namespace facebook::react
@@ -14,15 +14,12 @@ JSI_EXPORT extern const char TrueSheetFooterViewComponentName[];
14
14
  * `ShadowNode` for <TrueSheetFooterView> component.
15
15
  */
16
16
  class JSI_EXPORT TrueSheetFooterViewShadowNode final
17
- : public ConcreteViewShadowNode<
18
- TrueSheetFooterViewComponentName,
19
- TrueSheetFooterViewProps,
20
- TrueSheetFooterViewEventEmitter,
21
- TrueSheetFooterViewState> {
17
+ : public ConcreteViewShadowNode<TrueSheetFooterViewComponentName, TrueSheetFooterViewProps,
18
+ TrueSheetFooterViewEventEmitter, TrueSheetFooterViewState> {
22
19
  using ConcreteViewShadowNode::ConcreteViewShadowNode;
23
20
 
24
21
  public:
25
22
  void adjustLayoutWithState();
26
23
  };
27
24
 
28
- } // namespace facebook::react
25
+ } // namespace facebook::react
@@ -8,4 +8,4 @@ folly::dynamic TrueSheetFooterViewState::getDynamic() const {
8
8
  }
9
9
  #endif
10
10
 
11
- } // namespace facebook::react
11
+ } // namespace facebook::react
@@ -18,11 +18,9 @@ class TrueSheetFooterViewState final {
18
18
  TrueSheetFooterViewState() = default;
19
19
 
20
20
  #ifdef ANDROID
21
- TrueSheetFooterViewState(
22
- TrueSheetFooterViewState const &previousState,
23
- folly::dynamic data)
24
- : bottomInset(static_cast<float>(data["bottomInset"].getDouble())),
25
- initialized(true) {}
21
+ TrueSheetFooterViewState(TrueSheetFooterViewState const &previousState, folly::dynamic data)
22
+ : bottomInset(static_cast<float>(data["bottomInset"].getDouble())), initialized(true) {
23
+ }
26
24
  #endif
27
25
 
28
26
  float bottomInset{0};
@@ -38,4 +36,4 @@ class TrueSheetFooterViewState final {
38
36
  #endif
39
37
  };
40
38
 
41
- } // namespace facebook::react
39
+ } // namespace facebook::react
@@ -15,4 +15,4 @@ float TrueSheetInsets::bottomSafeArea() {
15
15
  return gBottomSafeArea.load(std::memory_order_relaxed);
16
16
  }
17
17
 
18
- } // namespace facebook::react
18
+ } // namespace facebook::react
@@ -13,4 +13,4 @@ class TrueSheetInsets {
13
13
  static float bottomSafeArea();
14
14
  };
15
15
 
16
- } // namespace facebook::react
16
+ } // namespace facebook::react
@@ -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