@lodev09/react-native-true-sheet 3.0.0-beta.9 → 3.0.1

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 (101) hide show
  1. package/README.md +16 -6
  2. package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +29 -33
  3. package/android/src/main/java/com/lodev09/truesheet/TrueSheetModule.kt +3 -1
  4. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +53 -43
  5. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +390 -89
  6. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +42 -4
  7. package/android/src/main/java/com/lodev09/truesheet/core/RNScreensFragmentObserver.kt +0 -5
  8. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDialogObserver.kt +67 -0
  9. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetGrabberView.kt +70 -0
  10. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetDragEvents.kt +71 -0
  11. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetFocusEvents.kt +65 -0
  12. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +94 -0
  13. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetStateEvents.kt +56 -0
  14. package/android/src/main/java/com/lodev09/truesheet/utils/ScreenUtils.kt +37 -33
  15. package/android/src/main/res/anim/true_sheet_slide_in.xml +13 -0
  16. package/android/src/main/res/anim/true_sheet_slide_out.xml +13 -0
  17. package/android/src/main/res/values/styles.xml +13 -1
  18. package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +5 -3
  19. package/ios/TrueSheetContainerView.mm +4 -0
  20. package/ios/TrueSheetContentView.h +2 -1
  21. package/ios/TrueSheetContentView.mm +91 -11
  22. package/ios/TrueSheetView.mm +94 -41
  23. package/ios/TrueSheetViewController.h +22 -10
  24. package/ios/TrueSheetViewController.mm +360 -173
  25. package/ios/core/TrueSheetBlurView.h +26 -0
  26. package/ios/{utils/ConversionUtil.mm → core/TrueSheetBlurView.mm} +64 -3
  27. package/ios/core/TrueSheetGrabberView.h +42 -0
  28. package/ios/core/TrueSheetGrabberView.mm +107 -0
  29. package/ios/events/TrueSheetDragEvents.h +39 -0
  30. package/ios/events/TrueSheetDragEvents.mm +62 -0
  31. package/ios/events/{OnPositionChangeEvent.h → TrueSheetFocusEvents.h} +8 -5
  32. package/ios/events/TrueSheetFocusEvents.mm +49 -0
  33. package/ios/events/TrueSheetLifecycleEvents.h +40 -0
  34. package/ios/events/TrueSheetLifecycleEvents.mm +71 -0
  35. package/ios/events/TrueSheetStateEvents.h +35 -0
  36. package/ios/events/TrueSheetStateEvents.mm +49 -0
  37. package/ios/utils/GestureUtil.h +7 -0
  38. package/ios/utils/GestureUtil.mm +12 -0
  39. package/lib/module/TrueSheet.js +72 -12
  40. package/lib/module/TrueSheet.js.map +1 -1
  41. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +28 -5
  42. package/lib/module/index.js +0 -1
  43. package/lib/module/index.js.map +1 -1
  44. package/lib/module/reanimated/ReanimatedTrueSheet.js +13 -7
  45. package/lib/module/reanimated/ReanimatedTrueSheet.js.map +1 -1
  46. package/lib/module/reanimated/ReanimatedTrueSheetProvider.js +4 -2
  47. package/lib/module/reanimated/ReanimatedTrueSheetProvider.js.map +1 -1
  48. package/lib/typescript/src/TrueSheet.d.ts +4 -0
  49. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  50. package/lib/typescript/src/TrueSheet.types.d.ts +105 -6
  51. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  52. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +25 -5
  53. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  54. package/lib/typescript/src/index.d.ts +0 -1
  55. package/lib/typescript/src/index.d.ts.map +1 -1
  56. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.d.ts.map +1 -1
  57. package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts +8 -2
  58. package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts.map +1 -1
  59. package/package.json +8 -2
  60. package/src/TrueSheet.tsx +87 -10
  61. package/src/TrueSheet.types.ts +114 -6
  62. package/src/__mocks__/index.js +0 -5
  63. package/src/fabric/TrueSheetViewNativeComponent.ts +28 -5
  64. package/src/index.ts +0 -1
  65. package/src/reanimated/ReanimatedTrueSheet.tsx +12 -7
  66. package/src/reanimated/ReanimatedTrueSheetProvider.tsx +11 -3
  67. package/android/src/main/java/com/lodev09/truesheet/events/DetentChangeEvent.kt +0 -26
  68. package/android/src/main/java/com/lodev09/truesheet/events/DidDismissEvent.kt +0 -20
  69. package/android/src/main/java/com/lodev09/truesheet/events/DidPresentEvent.kt +0 -26
  70. package/android/src/main/java/com/lodev09/truesheet/events/DragBeginEvent.kt +0 -26
  71. package/android/src/main/java/com/lodev09/truesheet/events/DragChangeEvent.kt +0 -26
  72. package/android/src/main/java/com/lodev09/truesheet/events/DragEndEvent.kt +0 -26
  73. package/android/src/main/java/com/lodev09/truesheet/events/MountEvent.kt +0 -20
  74. package/android/src/main/java/com/lodev09/truesheet/events/PositionChangeEvent.kt +0 -32
  75. package/android/src/main/java/com/lodev09/truesheet/events/WillDismissEvent.kt +0 -20
  76. package/android/src/main/java/com/lodev09/truesheet/events/WillPresentEvent.kt +0 -26
  77. package/ios/events/OnDetentChangeEvent.h +0 -28
  78. package/ios/events/OnDetentChangeEvent.mm +0 -30
  79. package/ios/events/OnDidDismissEvent.h +0 -26
  80. package/ios/events/OnDidDismissEvent.mm +0 -25
  81. package/ios/events/OnDidPresentEvent.h +0 -28
  82. package/ios/events/OnDidPresentEvent.mm +0 -30
  83. package/ios/events/OnDragBeginEvent.h +0 -28
  84. package/ios/events/OnDragBeginEvent.mm +0 -30
  85. package/ios/events/OnDragChangeEvent.h +0 -28
  86. package/ios/events/OnDragChangeEvent.mm +0 -30
  87. package/ios/events/OnDragEndEvent.h +0 -28
  88. package/ios/events/OnDragEndEvent.mm +0 -30
  89. package/ios/events/OnMountEvent.h +0 -26
  90. package/ios/events/OnMountEvent.mm +0 -25
  91. package/ios/events/OnPositionChangeEvent.mm +0 -32
  92. package/ios/events/OnWillDismissEvent.h +0 -26
  93. package/ios/events/OnWillDismissEvent.mm +0 -25
  94. package/ios/events/OnWillPresentEvent.h +0 -28
  95. package/ios/events/OnWillPresentEvent.mm +0 -30
  96. package/ios/utils/ConversionUtil.h +0 -24
  97. package/lib/module/TrueSheetGrabber.js +0 -51
  98. package/lib/module/TrueSheetGrabber.js.map +0 -1
  99. package/lib/typescript/src/TrueSheetGrabber.d.ts +0 -39
  100. package/lib/typescript/src/TrueSheetGrabber.d.ts.map +0 -1
  101. package/src/TrueSheetGrabber.tsx +0 -82
@@ -1,8 +1,20 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
2
  <resources>
3
- <!-- Custom BottomSheetDialog style with edge-to-edge enabled -->
3
+ <!-- Smooth slide animation for BottomSheetDialog -->
4
+ <style name="TrueSheetAnimation" parent="Animation.AppCompat.Dialog">
5
+ <item name="android:windowEnterAnimation">@anim/true_sheet_slide_in</item>
6
+ <item name="android:windowExitAnimation">@anim/true_sheet_slide_out</item>
7
+ </style>
8
+
9
+ <!-- Default BottomSheetDialog style with smooth animations -->
10
+ <style name="TrueSheetDialog" parent="Theme.Design.Light.BottomSheetDialog">
11
+ <item name="android:windowAnimationStyle">@style/TrueSheetAnimation</item>
12
+ </style>
13
+
14
+ <!-- BottomSheetDialog style with edge-to-edge and smooth animations -->
4
15
  <style name="TrueSheetEdgeToEdgeEnabledDialog" parent="Theme.Design.Light.BottomSheetDialog">
5
16
  <item name="android:windowIsFloating">false</item>
6
17
  <item name="enableEdgeToEdge">true</item>
18
+ <item name="android:windowAnimationStyle">@style/TrueSheetAnimation</item>
7
19
  </style>
8
20
  </resources>
@@ -1,9 +1,11 @@
1
1
  #include "TrueSheetViewShadowNode.h"
2
2
 
3
- #include <yoga/style/StyleSizeLength.h>
3
+ #include <react/renderer/components/view/conversions.h>
4
4
 
5
5
  namespace facebook::react {
6
6
 
7
+ using namespace yoga;
8
+
7
9
  extern const char TrueSheetViewComponentName[] = "TrueSheetView";
8
10
 
9
11
  void TrueSheetViewShadowNode::adjustLayoutWithState() {
@@ -22,7 +24,7 @@ void TrueSheetViewShadowNode::adjustLayoutWithState() {
22
24
 
23
25
  // Set width if provided
24
26
  if (stateData.containerWidth > 0) {
25
- adjustedStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(stateData.containerWidth));
27
+ adjustedStyle.setDimension(yoga::Dimension::Width, StyleSizeLength::points(stateData.containerWidth));
26
28
  if (adjustedStyle.dimension(yoga::Dimension::Width) != currentStyle.dimension(yoga::Dimension::Width)) {
27
29
  needsUpdate = true;
28
30
  }
@@ -30,7 +32,7 @@ void TrueSheetViewShadowNode::adjustLayoutWithState() {
30
32
 
31
33
  // Set height if provided
32
34
  if (stateData.containerHeight > 0) {
33
- adjustedStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(stateData.containerHeight));
35
+ adjustedStyle.setDimension(yoga::Dimension::Height, StyleSizeLength::points(stateData.containerHeight));
34
36
  if (adjustedStyle.dimension(yoga::Dimension::Height) != currentStyle.dimension(yoga::Dimension::Height)) {
35
37
  needsUpdate = true;
36
38
  }
@@ -167,6 +167,10 @@ using namespace facebook::react;
167
167
  }
168
168
  }
169
169
 
170
+ - (void)contentViewDidChangeChildren {
171
+ [self setupContentScrollViewPinning];
172
+ }
173
+
170
174
  #pragma mark - TrueSheetHeaderViewDelegate
171
175
 
172
176
  - (void)headerViewDidChangeSize:(CGSize)newSize {
@@ -21,6 +21,7 @@ NS_ASSUME_NONNULL_BEGIN
21
21
  @protocol TrueSheetContentViewDelegate <NSObject>
22
22
 
23
23
  - (void)contentViewDidChangeSize:(CGSize)newSize;
24
+ - (void)contentViewDidChangeChildren;
24
25
 
25
26
  @end
26
27
 
@@ -28,7 +29,7 @@ NS_ASSUME_NONNULL_BEGIN
28
29
 
29
30
  @property (nonatomic, weak, nullable) id<TrueSheetContentViewDelegate> delegate;
30
31
 
31
- - (RCTScrollViewComponentView *_Nullable)findScrollView;
32
+ - (RCTScrollViewComponentView *_Nullable)findScrollView:(UIView *_Nullable *_Nullable)outTopSibling;
32
33
 
33
34
  /**
34
35
  * Setup ScrollView pinning
@@ -21,6 +21,7 @@ using namespace facebook::react;
21
21
 
22
22
  @implementation TrueSheetContentView {
23
23
  RCTScrollViewComponentView *_pinnedScrollView;
24
+ UIView *_pinnedTopView;
24
25
  CGSize _lastSize;
25
26
  }
26
27
 
@@ -34,6 +35,7 @@ using namespace facebook::react;
34
35
  _props = defaultProps;
35
36
 
36
37
  _pinnedScrollView = nil;
38
+ _pinnedTopView = nil;
37
39
  _lastSize = CGSizeZero;
38
40
  }
39
41
  return self;
@@ -53,6 +55,22 @@ using namespace facebook::react;
53
55
  }
54
56
  }
55
57
 
58
+ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
59
+ [super mountChildComponentView:childComponentView index:index];
60
+
61
+ if ([self.delegate respondsToSelector:@selector(contentViewDidChangeChildren)]) {
62
+ [self.delegate contentViewDidChangeChildren];
63
+ }
64
+ }
65
+
66
+ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
67
+ [super unmountChildComponentView:childComponentView index:index];
68
+
69
+ if ([self.delegate respondsToSelector:@selector(contentViewDidChangeChildren)]) {
70
+ [self.delegate contentViewDidChangeChildren];
71
+ }
72
+ }
73
+
56
74
  - (void)unpinScrollViewFromParentView:(UIView *)parentView {
57
75
  // Unpin previous scroll view if exists
58
76
  if (_pinnedScrollView) {
@@ -67,43 +85,104 @@ using namespace facebook::react;
67
85
  if (!pinned) {
68
86
  [self unpinScrollViewFromParentView:containerView];
69
87
  _pinnedScrollView = nil;
88
+ _pinnedTopView = nil;
70
89
  return;
71
90
  }
72
91
 
73
92
  // Auto-detect and pin scroll views for proper sheet scrolling behavior
74
93
  // Pinning ensures ScrollView fills the available area and scrolls correctly with the sheet
75
- RCTScrollViewComponentView *scrollView = [self findScrollView];
94
+ UIView *topSibling = nil;
95
+ RCTScrollViewComponentView *scrollView = [self findScrollView:&topSibling];
96
+
97
+ // Use closest top sibling if found, otherwise fall back to header view
98
+ UIView *topView = topSibling ?: headerView;
76
99
 
77
- if (scrollView && containerView) {
78
- // Always unpin first to remove old constraints
100
+ // Re-pin when scroll view or top view changes
101
+ BOOL scrollViewChanged = scrollView != _pinnedScrollView;
102
+ BOOL topViewChanged = topView != _pinnedTopView;
103
+
104
+ if (scrollView && containerView && (scrollViewChanged || topViewChanged)) {
105
+ // Unpin first to remove old constraints
79
106
  [self unpinScrollViewFromParentView:containerView];
80
107
 
81
- if (headerView) {
82
- // Pin ScrollView below the header view
108
+ if (topView) {
109
+ // Pin ScrollView below the top view
83
110
  [LayoutUtil pinView:scrollView
84
111
  toParentView:containerView
85
- withTopView:headerView
112
+ withTopView:topView
86
113
  edges:UIRectEdgeLeft | UIRectEdgeRight | UIRectEdgeBottom];
87
114
  } else {
88
- // No header, pin to all edges of container
115
+ // No top view, pin to all edges of container
89
116
  [LayoutUtil pinView:scrollView toParentView:containerView edges:UIRectEdgeAll];
90
117
  }
91
118
 
92
119
  _pinnedScrollView = scrollView;
120
+ _pinnedTopView = topView;
121
+ } else if (!scrollView && _pinnedScrollView) {
122
+ // ScrollView was removed, clean up
123
+ [self unpinScrollViewFromParentView:containerView];
124
+ _pinnedScrollView = nil;
125
+ _pinnedTopView = nil;
93
126
  }
94
127
  }
95
128
 
96
- - (RCTScrollViewComponentView *)findScrollView {
97
- // Check first-level children for scroll views (ScrollView or FlatList)
98
- for (UIView *subview in self.subviews) {
129
+ - (RCTScrollViewComponentView *)findScrollViewInSubviews:(NSArray<UIView *> *)subviews {
130
+ for (UIView *subview in subviews) {
99
131
  if ([subview isKindOfClass:RCTScrollViewComponentView.class]) {
100
132
  return (RCTScrollViewComponentView *)subview;
101
133
  }
102
134
  }
103
-
104
135
  return nil;
105
136
  }
106
137
 
138
+ - (RCTScrollViewComponentView *)findScrollView:(UIView **)outTopSibling {
139
+ if (self.subviews.count == 0) {
140
+ return nil;
141
+ }
142
+
143
+ UIView *topSibling = nil;
144
+
145
+ // Check first-level children for scroll views (ScrollView or FlatList)
146
+ RCTScrollViewComponentView *scrollView = [self findScrollViewInSubviews:self.subviews];
147
+
148
+ // If not found, check second level (grandchildren)
149
+ if (!scrollView) {
150
+ for (UIView *subview in self.subviews) {
151
+ scrollView = [self findScrollViewInSubviews:subview.subviews];
152
+ if (scrollView) {
153
+ break;
154
+ }
155
+ }
156
+ }
157
+
158
+ // Find the view positioned directly above the ScrollView (only for first-level)
159
+ if (scrollView && scrollView.superview == self && self.subviews.count > 1) {
160
+ CGFloat scrollViewTop = CGRectGetMinY(scrollView.frame);
161
+ CGFloat closestDistance = CGFLOAT_MAX;
162
+
163
+ for (UIView *sibling in self.subviews) {
164
+ if (sibling == scrollView) {
165
+ continue;
166
+ }
167
+
168
+ CGFloat siblingBottom = CGRectGetMaxY(sibling.frame);
169
+ if (siblingBottom <= scrollViewTop) {
170
+ CGFloat distance = scrollViewTop - siblingBottom;
171
+ if (distance < closestDistance) {
172
+ closestDistance = distance;
173
+ topSibling = sibling;
174
+ }
175
+ }
176
+ }
177
+ }
178
+
179
+ if (outTopSibling) {
180
+ *outTopSibling = topSibling;
181
+ }
182
+
183
+ return scrollView;
184
+ }
185
+
107
186
  - (void)prepareForRecycle {
108
187
  [super prepareForRecycle];
109
188
 
@@ -111,6 +190,7 @@ using namespace facebook::react;
111
190
  if (_pinnedScrollView) {
112
191
  [LayoutUtil unpinView:_pinnedScrollView fromParentView:self.superview];
113
192
  _pinnedScrollView = nil;
193
+ _pinnedTopView = nil;
114
194
  }
115
195
  }
116
196
 
@@ -14,16 +14,10 @@
14
14
  #import "TrueSheetFooterView.h"
15
15
  #import "TrueSheetModule.h"
16
16
  #import "TrueSheetViewController.h"
17
- #import "events/OnDetentChangeEvent.h"
18
- #import "events/OnDidDismissEvent.h"
19
- #import "events/OnDidPresentEvent.h"
20
- #import "events/OnDragBeginEvent.h"
21
- #import "events/OnDragChangeEvent.h"
22
- #import "events/OnDragEndEvent.h"
23
- #import "events/OnMountEvent.h"
24
- #import "events/OnPositionChangeEvent.h"
25
- #import "events/OnWillDismissEvent.h"
26
- #import "events/OnWillPresentEvent.h"
17
+ #import "events/TrueSheetDragEvents.h"
18
+ #import "events/TrueSheetFocusEvents.h"
19
+ #import "events/TrueSheetLifecycleEvents.h"
20
+ #import "events/TrueSheetStateEvents.h"
27
21
  #import "utils/LayoutUtil.h"
28
22
  #import "utils/WindowUtil.h"
29
23
 
@@ -53,7 +47,7 @@ using namespace facebook::react;
53
47
  TrueSheetViewShadowNode::ConcreteState::Shared _state;
54
48
  CGSize _lastStateSize;
55
49
  NSInteger _initialDetentIndex;
56
- BOOL _fitScrollView;
50
+ BOOL _scrollable;
57
51
  BOOL _initialDetentAnimated;
58
52
  BOOL _isSheetUpdatePending;
59
53
  }
@@ -73,7 +67,7 @@ using namespace facebook::react;
73
67
  _lastStateSize = CGSizeZero;
74
68
  _initialDetentIndex = -1;
75
69
  _initialDetentAnimated = YES;
76
- _fitScrollView = NO;
70
+ _scrollable = NO;
77
71
  _isSheetUpdatePending = NO;
78
72
  }
79
73
  return self;
@@ -127,6 +121,11 @@ using namespace facebook::react;
127
121
  // Blur tint
128
122
  _controller.blurTint = !newProps.blurTint.empty() ? RCTNSStringFromString(newProps.blurTint) : nil;
129
123
 
124
+ // Blur options
125
+ const auto &blurOpts = newProps.blurOptions;
126
+ _controller.blurIntensity = blurOpts.intensity >= 0 ? @(blurOpts.intensity) : nil;
127
+ _controller.blurInteraction = blurOpts.interaction;
128
+
130
129
  // Corner radius
131
130
  _controller.cornerRadius = newProps.cornerRadius < 0 ? nil : @(newProps.cornerRadius);
132
131
 
@@ -136,8 +135,39 @@ using namespace facebook::react;
136
135
  }
137
136
 
138
137
  _controller.grabber = newProps.grabber;
138
+
139
+ // Grabber options - check if any non-default values are set
140
+ const auto &grabberOpts = newProps.grabberOptions;
141
+ BOOL hasGrabberOptions = grabberOpts.width > 0 || grabberOpts.height > 0 || grabberOpts.topMargin > 0 ||
142
+ grabberOpts.cornerRadius >= 0 || grabberOpts.color != 0;
143
+
144
+ if (hasGrabberOptions) {
145
+ NSMutableDictionary *options = [NSMutableDictionary dictionary];
146
+
147
+ if (grabberOpts.width > 0) {
148
+ options[@"width"] = @(grabberOpts.width);
149
+ }
150
+ if (grabberOpts.height > 0) {
151
+ options[@"height"] = @(grabberOpts.height);
152
+ }
153
+ if (grabberOpts.topMargin > 0) {
154
+ options[@"topMargin"] = @(grabberOpts.topMargin);
155
+ }
156
+ if (grabberOpts.cornerRadius >= 0) {
157
+ options[@"cornerRadius"] = @(grabberOpts.cornerRadius);
158
+ }
159
+ if (grabberOpts.color != 0) {
160
+ options[@"color"] = RCTUIColorFromSharedColor(SharedColor(grabberOpts.color));
161
+ }
162
+
163
+ _controller.grabberOptions = options;
164
+ } else {
165
+ _controller.grabberOptions = nil;
166
+ }
167
+
139
168
  _controller.pageSizing = newProps.pageSizing;
140
169
  _controller.modalInPresentation = !newProps.dismissible;
170
+ _controller.draggable = newProps.draggable;
141
171
  _controller.dimmed = newProps.dimmed;
142
172
 
143
173
  if (newProps.dimmedDetentIndex >= 0) {
@@ -146,10 +176,10 @@ using namespace facebook::react;
146
176
 
147
177
  _initialDetentIndex = newProps.initialDetentIndex;
148
178
  _initialDetentAnimated = newProps.initialDetentAnimated;
149
- _fitScrollView = newProps.fitScrollView;
179
+ _scrollable = newProps.scrollable;
150
180
 
151
181
  if (_containerView) {
152
- _containerView.scrollViewPinningEnabled = _fitScrollView;
182
+ _containerView.scrollViewPinningEnabled = _scrollable;
153
183
  }
154
184
  }
155
185
 
@@ -193,6 +223,7 @@ using namespace facebook::react;
193
223
  [self->_controller setupSheetDetents];
194
224
  [self->_controller applyActiveDetent];
195
225
  }];
226
+ [_controller updateDraggable];
196
227
  } else if (_initialDetentIndex >= 0) {
197
228
  [self presentAtIndex:_initialDetentIndex animated:_initialDetentAnimated completion:nil];
198
229
  }
@@ -239,10 +270,10 @@ using namespace facebook::react;
239
270
  _controller.headerHeight = @(headerHeight);
240
271
  }
241
272
 
242
- _containerView.scrollViewPinningEnabled = _fitScrollView;
273
+ _containerView.scrollViewPinningEnabled = _scrollable;
243
274
  [_containerView setupContentScrollViewPinning];
244
275
 
245
- [OnMountEvent emit:_eventEmitter];
276
+ [TrueSheetLifecycleEvents emitMount:_eventEmitter];
246
277
  }
247
278
 
248
279
  - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
@@ -265,9 +296,14 @@ using namespace facebook::react;
265
296
  - (void)presentAtIndex:(NSInteger)index
266
297
  animated:(BOOL)animated
267
298
  completion:(nullable TrueSheetCompletionBlock)completion {
299
+ if (_controller.isBeingPresented) {
300
+ RCTLogWarn(@"TrueSheet: sheet is being presented. Wait for it to transition before presenting again.");
301
+ return;
302
+ }
303
+
268
304
  if (_controller.isPresented) {
269
305
  [_controller.sheetPresentationController animateChanges:^{
270
- [self->_controller setupActiveDetentWithIndex:index];
306
+ [self->_controller resizeToDetentIndex:index];
271
307
  }];
272
308
  if (completion) {
273
309
  completion(YES, nil);
@@ -300,6 +336,11 @@ using namespace facebook::react;
300
336
  }
301
337
 
302
338
  - (void)dismissAnimated:(BOOL)animated completion:(nullable TrueSheetCompletionBlock)completion {
339
+ if (_controller.isBeingDismissed) {
340
+ RCTLogWarn(@"TrueSheet: sheet is being dismissed. No need to dismiss it again.");
341
+ return;
342
+ }
343
+
303
344
  if (!_controller.isPresented) {
304
345
  if (completion) {
305
346
  completion(YES, nil);
@@ -315,14 +356,6 @@ using namespace facebook::react;
315
356
  }];
316
357
  }
317
358
 
318
- - (void)resizeToIndex:(NSInteger)index {
319
- if (_controller.isPresented) {
320
- [_controller.sheetPresentationController animateChanges:^{
321
- [self->_controller setupActiveDetentWithIndex:index];
322
- }];
323
- }
324
- }
325
-
326
359
  #pragma mark - TrueSheetContainerViewDelegate
327
360
 
328
361
  /**
@@ -336,7 +369,6 @@ using namespace facebook::react;
336
369
 
337
370
  dispatch_async(dispatch_get_main_queue(), ^{
338
371
  self->_isSheetUpdatePending = NO;
339
- self->_controller.layoutTransitioning = YES;
340
372
 
341
373
  [self->_controller.sheetPresentationController animateChanges:^{
342
374
  [self->_controller setupSheetDetents];
@@ -356,27 +388,29 @@ using namespace facebook::react;
356
388
 
357
389
  #pragma mark - TrueSheetViewControllerDelegate
358
390
 
359
- - (void)viewControllerWillPresent {
360
- NSInteger index = [_controller currentDetentIndex];
391
+ - (void)viewControllerWillPresentAtIndex:(NSInteger)index position:(CGFloat)position detent:(CGFloat)detent {
361
392
  _controller.activeDetentIndex = index;
362
- [OnWillPresentEvent emit:_eventEmitter index:index position:_controller.currentPosition];
393
+ [TrueSheetLifecycleEvents emitWillPresent:_eventEmitter index:index position:position detent:detent];
363
394
  }
364
395
 
365
- - (void)viewControllerDidPresent {
366
- [OnDidPresentEvent emit:_eventEmitter index:[_controller currentDetentIndex] position:_controller.currentPosition];
396
+ - (void)viewControllerDidPresentAtIndex:(NSInteger)index position:(CGFloat)position detent:(CGFloat)detent {
397
+ [TrueSheetLifecycleEvents emitDidPresent:_eventEmitter index:index position:position detent:detent];
367
398
  }
368
399
 
369
- - (void)viewControllerDidDrag:(UIGestureRecognizerState)state index:(NSInteger)index position:(CGFloat)position {
400
+ - (void)viewControllerDidDrag:(UIGestureRecognizerState)state
401
+ index:(NSInteger)index
402
+ position:(CGFloat)position
403
+ detent:(CGFloat)detent {
370
404
  switch (state) {
371
405
  case UIGestureRecognizerStateBegan:
372
- [OnDragBeginEvent emit:_eventEmitter index:index position:position];
406
+ [TrueSheetDragEvents emitDragBegin:_eventEmitter index:index position:position detent:detent];
373
407
  break;
374
408
  case UIGestureRecognizerStateChanged:
375
- [OnDragChangeEvent emit:_eventEmitter index:index position:position];
409
+ [TrueSheetDragEvents emitDragChange:_eventEmitter index:index position:position detent:detent];
376
410
  break;
377
411
  case UIGestureRecognizerStateEnded:
378
412
  case UIGestureRecognizerStateCancelled:
379
- [OnDragEndEvent emit:_eventEmitter index:index position:position];
413
+ [TrueSheetDragEvents emitDragEnd:_eventEmitter index:index position:position detent:detent];
380
414
  break;
381
415
  default:
382
416
  break;
@@ -384,29 +418,48 @@ using namespace facebook::react;
384
418
  }
385
419
 
386
420
  - (void)viewControllerWillDismiss {
387
- [OnWillDismissEvent emit:_eventEmitter];
421
+ [TrueSheetLifecycleEvents emitWillDismiss:_eventEmitter];
388
422
  }
389
423
 
390
424
  - (void)viewControllerDidDismiss {
391
425
  _controller.activeDetentIndex = -1;
392
- [OnDidDismissEvent emit:_eventEmitter];
426
+ [TrueSheetLifecycleEvents emitDidDismiss:_eventEmitter];
393
427
  }
394
428
 
395
- - (void)viewControllerDidChangeDetent:(NSInteger)index position:(CGFloat)position {
429
+ - (void)viewControllerDidChangeDetent:(NSInteger)index position:(CGFloat)position detent:(CGFloat)detent {
396
430
  if (_controller.activeDetentIndex != index) {
397
431
  _controller.activeDetentIndex = index;
398
432
  }
399
- [OnDetentChangeEvent emit:_eventEmitter index:index position:position];
433
+ [TrueSheetStateEvents emitDetentChange:_eventEmitter index:index position:position detent:detent];
400
434
  }
401
435
 
402
- - (void)viewControllerDidChangePosition:(NSInteger)index position:(CGFloat)position transitioning:(BOOL)transitioning {
403
- [OnPositionChangeEvent emit:_eventEmitter index:index position:position transitioning:transitioning];
436
+ - (void)viewControllerDidChangePosition:(CGFloat)index
437
+ position:(CGFloat)position
438
+ detent:(CGFloat)detent
439
+ realtime:(BOOL)realtime {
440
+ [TrueSheetStateEvents emitPositionChange:_eventEmitter index:index position:position detent:detent realtime:realtime];
404
441
  }
405
442
 
406
443
  - (void)viewControllerDidChangeSize:(CGSize)size {
407
444
  [self updateStateWithSize:size];
408
445
  }
409
446
 
447
+ - (void)viewControllerWillFocus {
448
+ [TrueSheetFocusEvents emitWillFocus:_eventEmitter];
449
+ }
450
+
451
+ - (void)viewControllerDidFocus {
452
+ [TrueSheetFocusEvents emitDidFocus:_eventEmitter];
453
+ }
454
+
455
+ - (void)viewControllerWillBlur {
456
+ [TrueSheetFocusEvents emitWillBlur:_eventEmitter];
457
+ }
458
+
459
+ - (void)viewControllerDidBlur {
460
+ [TrueSheetFocusEvents emitDidBlur:_eventEmitter];
461
+ }
462
+
410
463
  #pragma mark - Private Helpers
411
464
 
412
465
  - (UIViewController *)findPresentingViewController {
@@ -19,14 +19,24 @@ NS_ASSUME_NONNULL_BEGIN
19
19
 
20
20
  @protocol TrueSheetViewControllerDelegate <NSObject>
21
21
 
22
- - (void)viewControllerWillPresent;
23
- - (void)viewControllerDidPresent;
22
+ - (void)viewControllerWillPresentAtIndex:(NSInteger)index position:(CGFloat)position detent:(CGFloat)detent;
23
+ - (void)viewControllerDidPresentAtIndex:(NSInteger)index position:(CGFloat)position detent:(CGFloat)detent;
24
24
  - (void)viewControllerWillDismiss;
25
25
  - (void)viewControllerDidDismiss;
26
- - (void)viewControllerDidChangeDetent:(NSInteger)index position:(CGFloat)position;
27
- - (void)viewControllerDidDrag:(UIGestureRecognizerState)state index:(NSInteger)index position:(CGFloat)position;
28
- - (void)viewControllerDidChangePosition:(NSInteger)index position:(CGFloat)position transitioning:(BOOL)transitioning;
26
+ - (void)viewControllerDidChangeDetent:(NSInteger)index position:(CGFloat)position detent:(CGFloat)detent;
27
+ - (void)viewControllerDidDrag:(UIGestureRecognizerState)state
28
+ index:(NSInteger)index
29
+ position:(CGFloat)position
30
+ detent:(CGFloat)detent;
31
+ - (void)viewControllerDidChangePosition:(CGFloat)index
32
+ position:(CGFloat)position
33
+ detent:(CGFloat)detent
34
+ realtime:(BOOL)realtime;
29
35
  - (void)viewControllerDidChangeSize:(CGSize)size;
36
+ - (void)viewControllerWillFocus;
37
+ - (void)viewControllerDidFocus;
38
+ - (void)viewControllerWillBlur;
39
+ - (void)viewControllerDidBlur;
30
40
 
31
41
  @end
32
42
 
@@ -38,28 +48,30 @@ NS_ASSUME_NONNULL_BEGIN
38
48
  >
39
49
 
40
50
  @property (nonatomic, weak, nullable) id<TrueSheetViewControllerDelegate> delegate;
41
- @property (nonatomic, strong) NSArray *detents;
51
+ @property (nonatomic, strong) NSArray<NSNumber *> *detents;
42
52
  @property (nonatomic, strong, nullable) NSNumber *maxHeight;
43
53
  @property (nonatomic, strong, nullable) NSNumber *contentHeight;
44
54
  @property (nonatomic, strong, nullable) NSNumber *headerHeight;
45
55
  @property (nonatomic, strong, nullable) UIColor *backgroundColor;
46
56
  @property (nonatomic, strong, nullable) NSNumber *cornerRadius;
47
57
  @property (nonatomic, assign) BOOL grabber;
58
+ @property (nonatomic, strong, nullable) NSDictionary *grabberOptions;
59
+ @property (nonatomic, assign) BOOL draggable;
48
60
  @property (nonatomic, assign) BOOL dimmed;
49
61
  @property (nonatomic, strong, nullable) NSNumber *dimmedDetentIndex;
50
62
  @property (nonatomic, copy, nullable) NSString *blurTint;
63
+ @property (nonatomic, strong, nullable) NSNumber *blurIntensity;
64
+ @property (nonatomic, assign) BOOL blurInteraction;
51
65
  @property (nonatomic, assign) BOOL pageSizing;
52
- @property (nonatomic, assign) BOOL layoutTransitioning;
53
66
  @property (nonatomic, assign) BOOL isPresented;
54
67
  @property (nonatomic, assign) NSInteger activeDetentIndex;
55
68
 
56
69
  - (void)applyActiveDetent;
57
70
  - (void)setupActiveDetentWithIndex:(NSInteger)index;
71
+ - (void)resizeToDetentIndex:(NSInteger)index;
58
72
  - (void)setupSheetDetents;
59
73
  - (void)setupSheetProps;
60
- - (NSInteger)currentDetentIndex;
61
- - (CGFloat)currentPosition;
62
- - (CGFloat)bottomInset;
74
+ - (void)updateDraggable;
63
75
 
64
76
  @end
65
77