@lodev09/react-native-true-sheet 3.0.0-beta.4 → 3.0.0-beta.6

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 (41) hide show
  1. package/README.md +0 -1
  2. package/RNTrueSheet.podspec +5 -1
  3. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +50 -0
  4. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerViewManager.kt +7 -0
  5. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +0 -9
  6. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +33 -7
  7. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +12 -4
  8. package/android/src/main/jni/CMakeLists.txt +87 -0
  9. package/android/src/main/jni/TrueSheetSpec.h +17 -0
  10. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContainerViewComponentDescriptor.h +24 -0
  11. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContainerViewShadowNode.cpp +46 -0
  12. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContainerViewShadowNode.h +28 -0
  13. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContainerViewState.cpp +11 -0
  14. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContainerViewState.h +42 -0
  15. package/ios/TrueSheetContainerView.mm +61 -5
  16. package/ios/TrueSheetContentView.mm +0 -11
  17. package/ios/TrueSheetView.h +0 -16
  18. package/ios/TrueSheetView.mm +10 -8
  19. package/ios/TrueSheetViewController.h +0 -1
  20. package/ios/TrueSheetViewController.mm +9 -26
  21. package/ios/utils/ConversionUtil.mm +30 -40
  22. package/lib/module/TrueSheet.js +1 -23
  23. package/lib/module/TrueSheet.js.map +1 -1
  24. package/lib/module/fabric/TrueSheetContainerViewNativeComponent.ts +3 -1
  25. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +0 -6
  26. package/lib/typescript/src/TrueSheet.d.ts +0 -3
  27. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  28. package/lib/typescript/src/TrueSheet.types.d.ts +0 -13
  29. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  30. package/lib/typescript/src/fabric/TrueSheetContainerViewNativeComponent.d.ts.map +1 -1
  31. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +0 -5
  32. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  33. package/package.json +2 -2
  34. package/react-native.config.js +5 -2
  35. package/src/TrueSheet.tsx +1 -27
  36. package/src/TrueSheet.types.ts +0 -15
  37. package/src/fabric/TrueSheetContainerViewNativeComponent.ts +3 -1
  38. package/src/fabric/TrueSheetViewNativeComponent.ts +0 -6
  39. package/android/src/main/java/com/lodev09/truesheet/events/SizeChangeEvent.kt +0 -27
  40. package/ios/events/OnSizeChangeEvent.h +0 -28
  41. package/ios/events/OnSizeChangeEvent.mm +0 -30
package/README.md CHANGED
@@ -67,7 +67,6 @@ export const App = () => {
67
67
  <TrueSheet
68
68
  ref={sheet}
69
69
  detents={['auto', 1]}
70
- cornerRadius={24}
71
70
  >
72
71
  <Button onPress={dismiss} title="Dismiss" />
73
72
  </TrueSheet>
@@ -13,8 +13,12 @@ Pod::Spec.new do |s|
13
13
  s.platforms = { :ios => min_ios_version_supported }
14
14
  s.source = { :git => "https://github.com/lodev09/react-native-true-sheet.git", :tag => "#{s.version}" }
15
15
 
16
- s.source_files = "ios/**/*.{h,m,mm,swift,cpp}"
16
+ s.source_files = "ios/**/*.{h,m,mm,swift,cpp}", "common/cpp/**/*.{cpp,h}"
17
17
  s.private_header_files = "ios/**/*.h"
18
18
 
19
+ s.pod_target_xcconfig = {
20
+ "HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/common/cpp\""
21
+ }
22
+
19
23
  install_modules_dependencies(s)
20
24
  end
@@ -3,6 +3,9 @@ package com.lodev09.truesheet
3
3
  import android.annotation.SuppressLint
4
4
  import android.view.View
5
5
  import androidx.core.view.isNotEmpty
6
+ import com.facebook.react.bridge.WritableNativeMap
7
+ import com.facebook.react.uimanager.PixelUtil.pxToDp
8
+ import com.facebook.react.uimanager.StateWrapper
6
9
  import com.facebook.react.uimanager.ThemedReactContext
7
10
  import com.facebook.react.views.view.ReactViewGroup
8
11
 
@@ -26,6 +29,53 @@ class TrueSheetContainerView(private val reactContext: ThemedReactContext) :
26
29
 
27
30
  var delegate: TrueSheetContainerViewDelegate? = null
28
31
 
32
+ private var stateWrapper: StateWrapper? = null
33
+
34
+ // Pending dimensions to update when stateWrapper becomes available
35
+ private var pendingWidth: Int = 0
36
+ private var pendingHeight: Int = 0
37
+
38
+ fun setStateWrapper(wrapper: StateWrapper?) {
39
+ stateWrapper = wrapper
40
+
41
+ if (wrapper == null) return
42
+
43
+ // Get dimensions from parent controller and update state if we haven't yet
44
+ val controller = parent as? TrueSheetViewController
45
+ if (controller != null && pendingWidth == 0) {
46
+ val w = controller.width
47
+ val h = controller.height
48
+ if (w > 0 && h > 0) {
49
+ updateState(w, h)
50
+ }
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Update state with container dimensions.
56
+ * Called by the controller when the dialog size changes.
57
+ */
58
+ fun updateState(width: Int, height: Int) {
59
+ // Skip if dimensions haven't changed
60
+ if (width == pendingWidth && height == pendingHeight && stateWrapper != null) {
61
+ return
62
+ }
63
+
64
+ // Store dimensions
65
+ pendingWidth = width
66
+ pendingHeight = height
67
+
68
+ val sw = stateWrapper ?: return
69
+
70
+ val realWidth = width.toFloat().pxToDp()
71
+ val realHeight = height.toFloat().pxToDp()
72
+
73
+ val newStateData = WritableNativeMap()
74
+ newStateData.putDouble("containerWidth", realWidth.toDouble())
75
+ newStateData.putDouble("containerHeight", realHeight.toDouble())
76
+ sw.updateState(newStateData)
77
+ }
78
+
29
79
  /**
30
80
  * Reference to content view (first child)
31
81
  */
@@ -1,6 +1,8 @@
1
1
  package com.lodev09.truesheet
2
2
 
3
3
  import com.facebook.react.module.annotations.ReactModule
4
+ import com.facebook.react.uimanager.ReactStylesDiffMap
5
+ import com.facebook.react.uimanager.StateWrapper
4
6
  import com.facebook.react.uimanager.ThemedReactContext
5
7
  import com.facebook.react.uimanager.ViewGroupManager
6
8
 
@@ -15,6 +17,11 @@ class TrueSheetContainerViewManager : ViewGroupManager<TrueSheetContainerView>()
15
17
 
16
18
  override fun createViewInstance(reactContext: ThemedReactContext): TrueSheetContainerView = TrueSheetContainerView(reactContext)
17
19
 
20
+ override fun updateState(view: TrueSheetContainerView, props: ReactStylesDiffMap?, stateWrapper: StateWrapper?): Any? {
21
+ view.setStateWrapper(stateWrapper)
22
+ return null
23
+ }
24
+
18
25
  companion object {
19
26
  const val REACT_CLASS = "TrueSheetContainerView"
20
27
  }
@@ -18,7 +18,6 @@ import com.lodev09.truesheet.events.DragChangeEvent
18
18
  import com.lodev09.truesheet.events.DragEndEvent
19
19
  import com.lodev09.truesheet.events.MountEvent
20
20
  import com.lodev09.truesheet.events.PositionChangeEvent
21
- import com.lodev09.truesheet.events.SizeChangeEvent
22
21
  import com.lodev09.truesheet.events.WillDismissEvent
23
22
  import com.lodev09.truesheet.events.WillPresentEvent
24
23
 
@@ -350,14 +349,6 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
350
349
  viewController.dismiss()
351
350
  }
352
351
 
353
- override fun viewControllerDidChangeSize(width: Int, height: Int) {
354
- // Dispatch size change event to JS
355
- val surfaceId = UIManagerHelper.getSurfaceId(this)
356
- eventDispatcher?.dispatchEvent(
357
- SizeChangeEvent(surfaceId, id, width, height)
358
- )
359
- }
360
-
361
352
  // ==================== TrueSheetContainerViewDelegate Implementation ====================
362
353
 
363
354
  override fun containerViewContentDidChangeSize(width: Int, height: Int) {
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
4
4
  import android.graphics.Color
5
5
  import android.graphics.drawable.ShapeDrawable
6
6
  import android.graphics.drawable.shapes.RoundRectShape
7
+ import android.util.TypedValue
7
8
  import android.view.MotionEvent
8
9
  import android.view.View
9
10
  import android.view.WindowManager
@@ -40,7 +41,6 @@ interface TrueSheetViewControllerDelegate {
40
41
  fun viewControllerDidDragChange(index: Int, position: Float)
41
42
  fun viewControllerDidDragEnd(index: Int, position: Float)
42
43
  fun viewControllerDidChangePosition(index: Int, position: Float, transitioning: Boolean)
43
- fun viewControllerDidChangeSize(width: Int, height: Int)
44
44
  }
45
45
 
46
46
  /**
@@ -65,6 +65,9 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
65
65
  private val jSTouchDispatcher = JSTouchDispatcher(this)
66
66
  private var jSPointerDispatcher: JSPointerDispatcher? = null
67
67
 
68
+ private var viewWidth = 0
69
+ private var viewHeight = 0
70
+
68
71
  /**
69
72
  * Delegate for handling view controller events
70
73
  */
@@ -192,8 +195,8 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
192
195
  }
193
196
  }
194
197
 
195
- var cornerRadius: Float = 0f
196
- var sheetBackgroundColor: Int = Color.WHITE
198
+ var cornerRadius: Float = 28f.dpToPx()
199
+ var sheetBackgroundColor: Int = 0
197
200
  var detents = mutableListOf(0.5, 1.0)
198
201
 
199
202
  private var windowAnimation: Int = 0
@@ -203,6 +206,24 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
203
206
  jSPointerDispatcher = JSPointerDispatcher(this)
204
207
  }
205
208
 
209
+ /**
210
+ * Get the default background color from Material Design 3 theme.
211
+ * Uses colorSurfaceContainerLow which adapts to light/dark mode.
212
+ */
213
+ fun getDefaultBackgroundColor(): Int {
214
+ val typedValue = TypedValue()
215
+ return if (reactContext.theme.resolveAttribute(
216
+ com.google.android.material.R.attr.colorSurfaceContainerLow,
217
+ typedValue,
218
+ true
219
+ )
220
+ ) {
221
+ typedValue.data
222
+ } else {
223
+ Color.WHITE
224
+ }
225
+ }
226
+
206
227
  // ==================== Lifecycle ====================
207
228
 
208
229
  /**
@@ -495,8 +516,11 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
495
516
  0f
496
517
  )
497
518
 
519
+ // 0 (transparent) is used as sentinel for "use system default"
520
+ val backgroundColor = if (sheetBackgroundColor != 0) sheetBackgroundColor else getDefaultBackgroundColor()
521
+
498
522
  val background = ShapeDrawable(RoundRectShape(outerRadii, null, null))
499
- background.paint.color = sheetBackgroundColor
523
+ background.paint.color = backgroundColor
500
524
 
501
525
  this.background = background
502
526
  this.clipToOutline = true
@@ -774,6 +798,11 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
774
798
 
775
799
  override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
776
800
  super.onSizeChanged(w, h, oldw, oldh)
801
+ viewWidth = w
802
+ viewHeight = h
803
+
804
+ // Update container state with new dimensions
805
+ containerView?.updateState(viewWidth, viewHeight)
777
806
 
778
807
  // Only proceed if size actually changed
779
808
  if (w == oldw && h == oldh) return
@@ -796,9 +825,6 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
796
825
  delegate?.viewControllerDidChangePosition(detentInfo.index, detentInfo.position, transitioning = true)
797
826
  }
798
827
  }
799
-
800
- // Notify delegate about size change
801
- delegate?.viewControllerDidChangeSize(w, h)
802
828
  }
803
829
 
804
830
  override fun handleException(t: Throwable) {
@@ -1,6 +1,5 @@
1
1
  package com.lodev09.truesheet
2
2
 
3
- import android.graphics.Color
4
3
  import android.view.WindowManager
5
4
  import com.facebook.react.bridge.ReadableArray
6
5
  import com.facebook.react.module.annotations.ReactModule
@@ -61,8 +60,7 @@ class TrueSheetViewManager :
61
60
  DragBeginEvent.EVENT_NAME to hashMapOf("registrationName" to DragBeginEvent.REGISTRATION_NAME),
62
61
  DragChangeEvent.EVENT_NAME to hashMapOf("registrationName" to DragChangeEvent.REGISTRATION_NAME),
63
62
  DragEndEvent.EVENT_NAME to hashMapOf("registrationName" to DragEndEvent.REGISTRATION_NAME),
64
- PositionChangeEvent.EVENT_NAME to hashMapOf("registrationName" to PositionChangeEvent.REGISTRATION_NAME),
65
- SizeChangeEvent.EVENT_NAME to hashMapOf("registrationName" to SizeChangeEvent.REGISTRATION_NAME)
63
+ PositionChangeEvent.EVENT_NAME to hashMapOf("registrationName" to PositionChangeEvent.REGISTRATION_NAME)
66
64
  )
67
65
 
68
66
  // ==================== Props ====================
@@ -85,7 +83,7 @@ class TrueSheetViewManager :
85
83
  view.setDetents(detents)
86
84
  }
87
85
 
88
- @ReactProp(name = "background", defaultInt = Color.WHITE)
86
+ @ReactProp(name = "background", defaultInt = 0)
89
87
  override fun setBackground(view: TrueSheetView, color: Int) {
90
88
  view.setSheetBackgroundColor(color)
91
89
  }
@@ -154,6 +152,16 @@ class TrueSheetViewManager :
154
152
  view.setEdgeToEdgeFullScreen(edgeToEdgeFullScreen)
155
153
  }
156
154
 
155
+ @ReactProp(name = "fitScrollView", defaultBoolean = false)
156
+ override fun setFitScrollView(view: TrueSheetView, value: Boolean) {
157
+ // iOS-specific prop - no-op on Android
158
+ }
159
+
160
+ @ReactProp(name = "pageSizing", defaultBoolean = true)
161
+ override fun setPageSizing(view: TrueSheetView, value: Boolean) {
162
+ // iOS-specific prop - no-op on Android
163
+ }
164
+
157
165
  companion object {
158
166
  const val REACT_CLASS = "TrueSheetView"
159
167
  const val TAG_NAME = "TrueSheet"
@@ -0,0 +1,87 @@
1
+ cmake_minimum_required(VERSION 3.13)
2
+ set(CMAKE_VERBOSE_MAKEFILE ON)
3
+
4
+ set(LIB_LITERAL TrueSheetSpec)
5
+ set(LIB_TARGET_NAME react_codegen_${LIB_LITERAL})
6
+
7
+ set(LIB_ANDROID_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
8
+ set(LIB_COMMON_DIR ${LIB_ANDROID_DIR}/../common/cpp)
9
+ set(LIB_ANDROID_GENERATED_JNI_DIR ${LIB_ANDROID_DIR}/build/generated/source/codegen/jni)
10
+ set(LIB_ANDROID_GENERATED_COMPONENTS_DIR ${LIB_ANDROID_GENERATED_JNI_DIR}/react/renderer/components/${LIB_LITERAL})
11
+
12
+ file(GLOB LIB_CUSTOM_SRCS CONFIGURE_DEPENDS *.cpp ${LIB_COMMON_DIR}/react/renderer/components/${LIB_LITERAL}/*.cpp)
13
+ file(GLOB LIB_CODEGEN_SRCS CONFIGURE_DEPENDS ${LIB_ANDROID_GENERATED_JNI_DIR}/*.cpp ${LIB_ANDROID_GENERATED_COMPONENTS_DIR}/*.cpp)
14
+
15
+ add_library(
16
+ ${LIB_TARGET_NAME}
17
+ SHARED
18
+ ${LIB_CUSTOM_SRCS}
19
+ ${LIB_CODEGEN_SRCS}
20
+ )
21
+
22
+ target_include_directories(
23
+ ${LIB_TARGET_NAME}
24
+ PUBLIC
25
+ .
26
+ ${LIB_COMMON_DIR}
27
+ ${LIB_ANDROID_GENERATED_JNI_DIR}
28
+ ${LIB_ANDROID_GENERATED_COMPONENTS_DIR}
29
+ )
30
+
31
+ if (REACTNATIVE_MERGED_SO)
32
+ target_link_libraries(
33
+ ${LIB_TARGET_NAME}
34
+ fbjni
35
+ jsi
36
+ reactnative
37
+ log
38
+ )
39
+ else()
40
+ target_link_libraries(
41
+ ${LIB_TARGET_NAME}
42
+ fbjni
43
+ folly_runtime
44
+ glog
45
+ jsi
46
+ react_codegen_rncore
47
+ react_debug
48
+ react_nativemodule_core
49
+ react_render_core
50
+ react_render_debug
51
+ react_render_graphics
52
+ react_render_mapbuffer
53
+ react_render_componentregistry
54
+ react_utils
55
+ rrc_view
56
+ turbomodulejsijni
57
+ yoga
58
+ log
59
+ )
60
+ endif()
61
+
62
+ target_include_directories(
63
+ ${CMAKE_PROJECT_NAME}
64
+ PUBLIC
65
+ ${CMAKE_CURRENT_SOURCE_DIR}
66
+ )
67
+
68
+ if(ReactAndroid_VERSION_MINOR GREATER_EQUAL 80)
69
+ target_compile_reactnative_options(${LIB_TARGET_NAME} PUBLIC)
70
+ else()
71
+ target_compile_options(
72
+ ${LIB_TARGET_NAME}
73
+ PRIVATE
74
+ -fexceptions
75
+ -frtti
76
+ -std=c++20
77
+ -Wall
78
+ )
79
+ endif()
80
+
81
+ target_compile_options(
82
+ ${LIB_TARGET_NAME}
83
+ PRIVATE
84
+ -Wpedantic
85
+ -Wno-gnu-zero-variadic-macro-arguments
86
+ -Wno-dollar-in-identifier-extension
87
+ )
@@ -0,0 +1,17 @@
1
+ #pragma once
2
+
3
+ #include <ReactCommon/JavaTurboModule.h>
4
+ #include <ReactCommon/TurboModule.h>
5
+ #include <jsi/jsi.h>
6
+ #include <react/renderer/components/TrueSheetSpec/TrueSheetContainerViewComponentDescriptor.h>
7
+
8
+ namespace facebook {
9
+ namespace react {
10
+
11
+ JSI_EXPORT
12
+ std::shared_ptr<TurboModule> TrueSheetSpec_ModuleProvider(
13
+ const std::string &moduleName,
14
+ const JavaTurboModule::InitParams &params);
15
+
16
+ } // namespace react
17
+ } // namespace facebook
@@ -0,0 +1,24 @@
1
+ #pragma once
2
+
3
+ #include <react/renderer/components/TrueSheetSpec/TrueSheetContainerViewShadowNode.h>
4
+ #include <react/renderer/core/ConcreteComponentDescriptor.h>
5
+
6
+ namespace facebook::react {
7
+
8
+ /*
9
+ * Descriptor for <TrueSheetContainerView> component.
10
+ */
11
+ class TrueSheetContainerViewComponentDescriptor final
12
+ : public ConcreteComponentDescriptor<TrueSheetContainerViewShadowNode> {
13
+ using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
14
+
15
+ void adopt(ShadowNode &shadowNode) const override {
16
+ auto &concreteShadowNode =
17
+ static_cast<TrueSheetContainerViewShadowNode &>(shadowNode);
18
+ concreteShadowNode.adjustLayoutWithState();
19
+
20
+ ConcreteComponentDescriptor::adopt(shadowNode);
21
+ }
22
+ };
23
+
24
+ } // namespace facebook::react
@@ -0,0 +1,46 @@
1
+ #include "TrueSheetContainerViewShadowNode.h"
2
+
3
+ #include <yoga/style/StyleSizeLength.h>
4
+
5
+ namespace facebook::react {
6
+
7
+ extern const char TrueSheetContainerViewComponentName[] = "TrueSheetContainerView";
8
+
9
+ void TrueSheetContainerViewShadowNode::adjustLayoutWithState() {
10
+ ensureUnsealed();
11
+
12
+ auto state = std::static_pointer_cast<
13
+ const TrueSheetContainerViewShadowNode::ConcreteState>(getState());
14
+ auto stateData = state->getData();
15
+
16
+ // If container dimensions are set from native, override Yoga's dimensions
17
+ if (stateData.containerWidth > 0 || stateData.containerHeight > 0) {
18
+ auto &props = getConcreteProps();
19
+ yoga::Style adjustedStyle = props.yogaStyle;
20
+ auto currentStyle = yogaNode_.style();
21
+ bool needsUpdate = false;
22
+
23
+ // Set width if provided
24
+ if (stateData.containerWidth > 0) {
25
+ adjustedStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(stateData.containerWidth));
26
+ if (adjustedStyle.dimension(yoga::Dimension::Width) != currentStyle.dimension(yoga::Dimension::Width)) {
27
+ needsUpdate = true;
28
+ }
29
+ }
30
+
31
+ // Set height if provided
32
+ if (stateData.containerHeight > 0) {
33
+ adjustedStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(stateData.containerHeight));
34
+ if (adjustedStyle.dimension(yoga::Dimension::Height) != currentStyle.dimension(yoga::Dimension::Height)) {
35
+ needsUpdate = true;
36
+ }
37
+ }
38
+
39
+ if (needsUpdate) {
40
+ yogaNode_.setStyle(adjustedStyle);
41
+ yogaNode_.setDirty(true);
42
+ }
43
+ }
44
+ }
45
+
46
+ } // namespace facebook::react
@@ -0,0 +1,28 @@
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/TrueSheetContainerViewState.h>
7
+ #include <react/renderer/components/view/ConcreteViewShadowNode.h>
8
+
9
+ namespace facebook::react {
10
+
11
+ JSI_EXPORT extern const char TrueSheetContainerViewComponentName[];
12
+
13
+ /*
14
+ * `ShadowNode` for <TrueSheetContainerView> component.
15
+ */
16
+ class JSI_EXPORT TrueSheetContainerViewShadowNode final
17
+ : public ConcreteViewShadowNode<
18
+ TrueSheetContainerViewComponentName,
19
+ TrueSheetContainerViewProps,
20
+ TrueSheetContainerViewEventEmitter,
21
+ TrueSheetContainerViewState> {
22
+ using ConcreteViewShadowNode::ConcreteViewShadowNode;
23
+
24
+ public:
25
+ void adjustLayoutWithState();
26
+ };
27
+
28
+ } // namespace facebook::react
@@ -0,0 +1,11 @@
1
+ #include "TrueSheetContainerViewState.h"
2
+
3
+ namespace facebook::react {
4
+
5
+ #ifdef ANDROID
6
+ folly::dynamic TrueSheetContainerViewState::getDynamic() const {
7
+ return folly::dynamic::object("containerWidth", containerWidth)("containerHeight", containerHeight);
8
+ }
9
+ #endif
10
+
11
+ } // namespace facebook::react
@@ -0,0 +1,42 @@
1
+ #pragma once
2
+
3
+ #include <memory>
4
+
5
+ #ifdef ANDROID
6
+ #include <folly/dynamic.h>
7
+ #include <react/renderer/mapbuffer/MapBuffer.h>
8
+ #include <react/renderer/mapbuffer/MapBufferBuilder.h>
9
+ #endif
10
+
11
+ namespace facebook::react {
12
+
13
+ /*
14
+ * State for <TrueSheetContainerView> component.
15
+ * Contains the container dimensions from native.
16
+ */
17
+ class TrueSheetContainerViewState final {
18
+ public:
19
+ using Shared = std::shared_ptr<const TrueSheetContainerViewState>;
20
+
21
+ TrueSheetContainerViewState() = default;
22
+
23
+ #ifdef ANDROID
24
+ TrueSheetContainerViewState(
25
+ TrueSheetContainerViewState const &previousState,
26
+ folly::dynamic data)
27
+ : containerWidth(static_cast<float>(data["containerWidth"].getDouble())),
28
+ containerHeight(static_cast<float>(data["containerHeight"].getDouble())) {}
29
+ #endif
30
+
31
+ float containerWidth{0};
32
+ float containerHeight{0};
33
+
34
+ #ifdef ANDROID
35
+ folly::dynamic getDynamic() const;
36
+ MapBuffer getMapBuffer() const {
37
+ return MapBufferBuilder::EMPTY();
38
+ }
39
+ #endif
40
+ };
41
+
42
+ } // namespace facebook::react
@@ -9,14 +9,18 @@
9
9
  #ifdef RCT_NEW_ARCH_ENABLED
10
10
 
11
11
  #import "TrueSheetContainerView.h"
12
- #import <react/renderer/components/TrueSheetSpec/ComponentDescriptors.h>
13
12
  #import <react/renderer/components/TrueSheetSpec/EventEmitters.h>
14
13
  #import <react/renderer/components/TrueSheetSpec/Props.h>
15
14
  #import <react/renderer/components/TrueSheetSpec/RCTComponentViewHelpers.h>
15
+ #import <react/renderer/components/TrueSheetSpec/TrueSheetContainerViewComponentDescriptor.h>
16
+ #import <react/renderer/components/TrueSheetSpec/TrueSheetContainerViewShadowNode.h>
17
+ #import <react/renderer/components/TrueSheetSpec/TrueSheetContainerViewState.h>
16
18
  #import "TrueSheetContentView.h"
17
19
  #import "TrueSheetFooterView.h"
18
20
 
19
21
  #import <React/RCTConversions.h>
22
+ #import <React/RCTLog.h>
23
+ #import <react/renderer/core/State.h>
20
24
 
21
25
  using namespace facebook::react;
22
26
 
@@ -26,6 +30,8 @@ using namespace facebook::react;
26
30
  @implementation TrueSheetContainerView {
27
31
  TrueSheetContentView *_contentView;
28
32
  TrueSheetFooterView *_footerView;
33
+ TrueSheetContainerViewShadowNode::ConcreteState::Shared _state;
34
+ CGFloat _lastContainerWidth;
29
35
  }
30
36
 
31
37
  + (ComponentDescriptorProvider)componentDescriptorProvider {
@@ -41,11 +47,49 @@ using namespace facebook::react;
41
47
 
42
48
  _contentView = nil;
43
49
  _footerView = nil;
50
+ _lastContainerWidth = 0;
44
51
  }
45
52
  return self;
46
53
  }
47
54
 
48
- - (void)dealloc {
55
+ - (void)layoutSubviews {
56
+ [super layoutSubviews];
57
+
58
+ // Override Yoga layout - fill the entire parent (controller's view)
59
+ if (self.superview) {
60
+ CGRect parentBounds = self.superview.bounds;
61
+ if (!CGRectEqualToRect(self.frame, parentBounds)) {
62
+ self.frame = parentBounds;
63
+ }
64
+
65
+ // Update state with container width so Yoga can use it for children layout
66
+ [self updateStateIfNeeded];
67
+ }
68
+ }
69
+
70
+ - (void)updateStateIfNeeded {
71
+ if (!self.superview) {
72
+ return;
73
+ }
74
+
75
+ CGFloat containerWidth = self.superview.bounds.size.width;
76
+ if (containerWidth > 0 && fabs(containerWidth - _lastContainerWidth) > 0.5) {
77
+ _lastContainerWidth = containerWidth;
78
+ [self updateState];
79
+ }
80
+ }
81
+
82
+ - (void)updateState {
83
+ if (!_state) {
84
+ return;
85
+ }
86
+
87
+ _state->updateState([=](TrueSheetContainerViewShadowNode::ConcreteState::Data const &oldData)
88
+ -> TrueSheetContainerViewShadowNode::ConcreteState::SharedData {
89
+ auto newData = oldData;
90
+ newData.containerWidth = static_cast<float>(_lastContainerWidth);
91
+ return std::make_shared<TrueSheetContainerViewShadowNode::ConcreteState::Data const>(newData);
92
+ });
49
93
  }
50
94
 
51
95
  - (CGFloat)contentHeight {
@@ -64,7 +108,6 @@ using namespace facebook::react;
64
108
 
65
109
  - (void)setupContentScrollViewPinning:(BOOL)pinned {
66
110
  if (_contentView) {
67
- NSLog(@"setting up scrollview pinning: %i", pinned);
68
111
  [_contentView setupScrollViewPinning:pinned];
69
112
  }
70
113
  }
@@ -75,7 +118,7 @@ using namespace facebook::react;
75
118
  // Handle content view mounting
76
119
  if ([childComponentView isKindOfClass:[TrueSheetContentView class]]) {
77
120
  if (_contentView != nil) {
78
- NSLog(@"TrueSheet: Container can only have one content component.");
121
+ RCTLogWarn(@"TrueSheet: Container can only have one content component.");
79
122
  return;
80
123
  }
81
124
 
@@ -86,7 +129,7 @@ using namespace facebook::react;
86
129
  // Handle footer view mounting
87
130
  if ([childComponentView isKindOfClass:[TrueSheetFooterView class]]) {
88
131
  if (_footerView != nil) {
89
- NSLog(@"TrueSheet: Container can only have one footer component.");
132
+ RCTLogWarn(@"TrueSheet: Container can only have one footer component.");
90
133
  return;
91
134
  }
92
135
 
@@ -110,6 +153,19 @@ using namespace facebook::react;
110
153
  [super updateProps:props oldProps:oldProps];
111
154
  }
112
155
 
156
+ - (void)updateState:(const State::Shared &)state oldState:(const State::Shared &)oldState {
157
+ _state = std::static_pointer_cast<TrueSheetContainerViewShadowNode::ConcreteState const>(state);
158
+
159
+ // Reset last width when state is updated to ensure we push the correct width
160
+ // This handles re-presentation of the sheet where state is recreated
161
+ _lastContainerWidth = 0;
162
+ }
163
+
164
+ - (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask {
165
+ [super finalizeUpdates:updateMask];
166
+ [self updateStateIfNeeded];
167
+ }
168
+
113
169
  #pragma mark - TrueSheetContentViewDelegate
114
170
 
115
171
  - (void)contentViewDidChangeSize:(CGSize)newSize {
@@ -53,17 +53,6 @@ using namespace facebook::react;
53
53
  }
54
54
  }
55
55
 
56
- //- (void)didMoveToSuperview {
57
- // [super didMoveToSuperview];
58
- //
59
- // // Setup scroll view pinning after Fabric mounts the view in container
60
- // // Ensures proper view hierarchy for scroll detection and pinning
61
- // if (self.superview) {
62
- // NSLog(@"content has attached");
63
- //// [self setupScrollViewPinning];
64
- // }
65
- //}
66
-
67
56
  - (void)unpinScrollView {
68
57
  // Unpin previous scroll view if exists
69
58
  if (_pinnedScrollView) {