@lodev09/react-native-true-sheet 3.0.0-beta.1 → 3.0.0-beta.10
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.
- package/README.md +7 -21
- package/RNTrueSheet.podspec +5 -1
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +58 -60
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +10 -18
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterView.kt +76 -20
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetHeaderView.kt +38 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetHeaderViewManager.kt +21 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetPackage.kt +1 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +104 -146
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +315 -403
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +24 -11
- package/android/src/main/java/com/lodev09/truesheet/core/RNScreensFragmentObserver.kt +116 -0
- package/android/src/main/java/com/lodev09/truesheet/utils/ScreenUtils.kt +33 -5
- package/android/src/main/jni/CMakeLists.txt +87 -0
- package/android/src/main/jni/TrueSheetSpec.h +17 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h +24 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +46 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h +28 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.cpp +11 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.h +42 -0
- package/ios/TrueSheetContainerView.h +23 -0
- package/ios/TrueSheetContainerView.mm +80 -13
- package/ios/TrueSheetContentView.h +9 -1
- package/ios/TrueSheetContentView.mm +102 -24
- package/ios/TrueSheetFooterView.mm +2 -2
- package/ios/TrueSheetHeaderView.h +29 -0
- package/ios/TrueSheetHeaderView.mm +60 -0
- package/ios/TrueSheetView.h +0 -16
- package/ios/TrueSheetView.mm +208 -194
- package/ios/TrueSheetViewController.h +4 -3
- package/ios/TrueSheetViewController.mm +180 -272
- package/ios/utils/ConversionUtil.h +24 -0
- package/ios/utils/ConversionUtil.mm +50 -0
- package/ios/utils/LayoutUtil.h +11 -1
- package/ios/utils/LayoutUtil.mm +32 -1
- package/lib/module/TrueSheet.js +30 -33
- package/lib/module/TrueSheet.js.map +1 -1
- package/lib/module/fabric/TrueSheetContainerViewNativeComponent.ts +1 -1
- package/lib/module/fabric/TrueSheetHeaderViewNativeComponent.ts +8 -0
- package/lib/module/fabric/TrueSheetViewNativeComponent.ts +6 -8
- package/lib/typescript/src/TrueSheet.d.ts +0 -3
- package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.types.d.ts +30 -43
- package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
- package/lib/typescript/src/fabric/TrueSheetContainerViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/fabric/TrueSheetHeaderViewNativeComponent.d.ts +6 -0
- package/lib/typescript/src/fabric/TrueSheetHeaderViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +3 -6
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
- package/package.json +9 -5
- package/react-native.config.js +5 -2
- package/src/TrueSheet.tsx +34 -31
- package/src/TrueSheet.types.ts +47 -61
- package/src/fabric/TrueSheetContainerViewNativeComponent.ts +1 -1
- package/src/fabric/TrueSheetHeaderViewNativeComponent.ts +8 -0
- package/src/fabric/TrueSheetViewNativeComponent.ts +6 -8
- package/android/src/main/java/com/lodev09/truesheet/events/SizeChangeEvent.kt +0 -27
- package/ios/events/OnSizeChangeEvent.h +0 -28
- package/ios/events/OnSizeChangeEvent.mm +0 -30
package/ios/TrueSheetView.mm
CHANGED
|
@@ -22,21 +22,24 @@
|
|
|
22
22
|
#import "events/OnDragEndEvent.h"
|
|
23
23
|
#import "events/OnMountEvent.h"
|
|
24
24
|
#import "events/OnPositionChangeEvent.h"
|
|
25
|
-
#import "events/OnSizeChangeEvent.h"
|
|
26
25
|
#import "events/OnWillDismissEvent.h"
|
|
27
26
|
#import "events/OnWillPresentEvent.h"
|
|
28
27
|
#import "utils/LayoutUtil.h"
|
|
29
28
|
#import "utils/WindowUtil.h"
|
|
30
29
|
|
|
31
|
-
#import <react/renderer/components/TrueSheetSpec/ComponentDescriptors.h>
|
|
32
30
|
#import <react/renderer/components/TrueSheetSpec/EventEmitters.h>
|
|
33
31
|
#import <react/renderer/components/TrueSheetSpec/Props.h>
|
|
34
32
|
#import <react/renderer/components/TrueSheetSpec/RCTComponentViewHelpers.h>
|
|
33
|
+
#import <react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h>
|
|
34
|
+
#import <react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h>
|
|
35
|
+
#import <react/renderer/components/TrueSheetSpec/TrueSheetViewState.h>
|
|
35
36
|
|
|
36
37
|
#import <React/RCTConversions.h>
|
|
37
38
|
#import <React/RCTFabricComponentsPlugins.h>
|
|
39
|
+
#import <React/RCTLog.h>
|
|
38
40
|
#import <React/RCTSurfaceTouchHandler.h>
|
|
39
41
|
#import <React/RCTUtils.h>
|
|
42
|
+
#import <react/renderer/core/State.h>
|
|
40
43
|
|
|
41
44
|
using namespace facebook::react;
|
|
42
45
|
|
|
@@ -47,26 +50,31 @@ using namespace facebook::react;
|
|
|
47
50
|
TrueSheetContainerView *_containerView;
|
|
48
51
|
TrueSheetViewController *_controller;
|
|
49
52
|
RCTSurfaceTouchHandler *_touchHandler;
|
|
53
|
+
TrueSheetViewShadowNode::ConcreteState::Shared _state;
|
|
54
|
+
CGSize _lastStateSize;
|
|
50
55
|
NSInteger _initialDetentIndex;
|
|
56
|
+
BOOL _scrollable;
|
|
51
57
|
BOOL _initialDetentAnimated;
|
|
58
|
+
BOOL _isSheetUpdatePending;
|
|
52
59
|
}
|
|
53
60
|
|
|
61
|
+
#pragma mark - Initialization
|
|
62
|
+
|
|
54
63
|
- (instancetype)initWithFrame:(CGRect)frame {
|
|
55
64
|
if (self = [super initWithFrame:frame]) {
|
|
56
65
|
static const auto defaultProps = std::make_shared<const TrueSheetViewProps>();
|
|
57
66
|
_props = defaultProps;
|
|
58
67
|
|
|
59
|
-
// Initialize controller - persists across container lifecycle
|
|
60
68
|
_controller = [[TrueSheetViewController alloc] init];
|
|
61
69
|
_controller.delegate = self;
|
|
62
70
|
|
|
63
|
-
// Initialize touch handler - will be attached to container when mounted
|
|
64
71
|
_touchHandler = [[RCTSurfaceTouchHandler alloc] init];
|
|
65
|
-
|
|
66
72
|
_containerView = nil;
|
|
67
|
-
|
|
73
|
+
_lastStateSize = CGSizeZero;
|
|
68
74
|
_initialDetentIndex = -1;
|
|
69
75
|
_initialDetentAnimated = YES;
|
|
76
|
+
_scrollable = NO;
|
|
77
|
+
_isSheetUpdatePending = NO;
|
|
70
78
|
}
|
|
71
79
|
return self;
|
|
72
80
|
}
|
|
@@ -74,28 +82,23 @@ using namespace facebook::react;
|
|
|
74
82
|
- (void)didMoveToWindow {
|
|
75
83
|
[super didMoveToWindow];
|
|
76
84
|
|
|
77
|
-
if (!self.window)
|
|
85
|
+
if (!self.window)
|
|
78
86
|
return;
|
|
79
|
-
}
|
|
80
87
|
|
|
81
|
-
// Register
|
|
82
|
-
// This ensures the tag is properly set by the framework
|
|
88
|
+
// Register with TurboModule when tag is set
|
|
83
89
|
if (self.tag > 0) {
|
|
84
90
|
[TrueSheetModule registerView:self withTag:@(self.tag)];
|
|
85
91
|
}
|
|
86
92
|
}
|
|
87
93
|
|
|
88
94
|
- (void)dealloc {
|
|
89
|
-
// Dismiss controller if presented
|
|
90
95
|
if (_controller && _controller.presentingViewController) {
|
|
91
96
|
[_controller dismissViewControllerAnimated:NO completion:nil];
|
|
92
97
|
}
|
|
93
98
|
|
|
94
|
-
// Clean up controller
|
|
95
99
|
_controller.delegate = nil;
|
|
96
100
|
_controller = nil;
|
|
97
101
|
|
|
98
|
-
// Unregister this view from the TurboModule
|
|
99
102
|
[TrueSheetModule unregisterViewWithTag:@(self.tag)];
|
|
100
103
|
}
|
|
101
104
|
|
|
@@ -105,16 +108,172 @@ using namespace facebook::react;
|
|
|
105
108
|
return concreteComponentDescriptorProvider<TrueSheetViewComponentDescriptor>();
|
|
106
109
|
}
|
|
107
110
|
|
|
111
|
+
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps {
|
|
112
|
+
[super updateProps:props oldProps:oldProps];
|
|
113
|
+
|
|
114
|
+
const auto &newProps = *std::static_pointer_cast<TrueSheetViewProps const>(props);
|
|
115
|
+
|
|
116
|
+
// Detents (-1 represents "auto")
|
|
117
|
+
NSMutableArray *detents = [NSMutableArray new];
|
|
118
|
+
for (const auto &detent : newProps.detents) {
|
|
119
|
+
[detents addObject:@(detent)];
|
|
120
|
+
}
|
|
121
|
+
_controller.detents = detents;
|
|
122
|
+
|
|
123
|
+
// Background color
|
|
124
|
+
_controller.backgroundColor =
|
|
125
|
+
newProps.background == 0 ? nil : RCTUIColorFromSharedColor(SharedColor(newProps.background));
|
|
126
|
+
|
|
127
|
+
// Blur tint
|
|
128
|
+
_controller.blurTint = !newProps.blurTint.empty() ? RCTNSStringFromString(newProps.blurTint) : nil;
|
|
129
|
+
|
|
130
|
+
// Corner radius
|
|
131
|
+
_controller.cornerRadius = newProps.cornerRadius < 0 ? nil : @(newProps.cornerRadius);
|
|
132
|
+
|
|
133
|
+
// Max height
|
|
134
|
+
if (newProps.maxHeight != 0.0) {
|
|
135
|
+
_controller.maxHeight = @(newProps.maxHeight);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
_controller.grabber = newProps.grabber;
|
|
139
|
+
_controller.pageSizing = newProps.pageSizing;
|
|
140
|
+
_controller.modalInPresentation = !newProps.dismissible;
|
|
141
|
+
_controller.dimmed = newProps.dimmed;
|
|
142
|
+
|
|
143
|
+
if (newProps.dimmedDetentIndex >= 0) {
|
|
144
|
+
_controller.dimmedDetentIndex = @(newProps.dimmedDetentIndex);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
_initialDetentIndex = newProps.initialDetentIndex;
|
|
148
|
+
_initialDetentAnimated = newProps.initialDetentAnimated;
|
|
149
|
+
_scrollable = newProps.scrollable;
|
|
150
|
+
|
|
151
|
+
if (_containerView) {
|
|
152
|
+
_containerView.scrollViewPinningEnabled = _scrollable;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
- (void)updateState:(const State::Shared &)state oldState:(const State::Shared &)oldState {
|
|
157
|
+
_state = std::static_pointer_cast<TrueSheetViewShadowNode::ConcreteState const>(state);
|
|
158
|
+
|
|
159
|
+
if (_controller) {
|
|
160
|
+
[self updateStateWithSize:_controller.view.frame.size];
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Updates Fabric state with container width for Yoga layout.
|
|
166
|
+
*/
|
|
167
|
+
- (void)updateStateWithSize:(CGSize)size {
|
|
168
|
+
if (!_state || size.width <= 0 || size.width == _lastStateSize.width)
|
|
169
|
+
return;
|
|
170
|
+
|
|
171
|
+
_lastStateSize = size;
|
|
172
|
+
_state->updateState([=](TrueSheetViewShadowNode::ConcreteState::Data const &oldData)
|
|
173
|
+
-> TrueSheetViewShadowNode::ConcreteState::SharedData {
|
|
174
|
+
auto newData = oldData;
|
|
175
|
+
newData.containerWidth = static_cast<float>(size.width);
|
|
176
|
+
return std::make_shared<TrueSheetViewShadowNode::ConcreteState::Data const>(newData);
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
- (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask {
|
|
181
|
+
[super finalizeUpdates:updateMask];
|
|
182
|
+
|
|
183
|
+
if (!(updateMask & RNComponentViewUpdateMaskProps) || !_controller)
|
|
184
|
+
return;
|
|
185
|
+
|
|
186
|
+
if (_containerView) {
|
|
187
|
+
[_containerView setupContentScrollViewPinning];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (_controller.isPresented) {
|
|
191
|
+
[_controller.sheetPresentationController animateChanges:^{
|
|
192
|
+
[self->_controller setupSheetProps];
|
|
193
|
+
[self->_controller setupSheetDetents];
|
|
194
|
+
[self->_controller applyActiveDetent];
|
|
195
|
+
}];
|
|
196
|
+
} else if (_initialDetentIndex >= 0) {
|
|
197
|
+
[self presentAtIndex:_initialDetentIndex animated:_initialDetentAnimated completion:nil];
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
- (void)prepareForRecycle {
|
|
202
|
+
[super prepareForRecycle];
|
|
203
|
+
|
|
204
|
+
_lastStateSize = CGSizeZero;
|
|
205
|
+
|
|
206
|
+
if (_controller && _controller.presentingViewController) {
|
|
207
|
+
[_controller dismissViewControllerAnimated:YES completion:nil];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
[TrueSheetModule unregisterViewWithTag:@(self.tag)];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
#pragma mark - Child Component Mounting
|
|
214
|
+
|
|
215
|
+
- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
|
|
216
|
+
if (![childComponentView isKindOfClass:[TrueSheetContainerView class]])
|
|
217
|
+
return;
|
|
218
|
+
|
|
219
|
+
if (_containerView != nil) {
|
|
220
|
+
RCTLogWarn(@"TrueSheet: Sheet can only have one container component.");
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
_containerView = (TrueSheetContainerView *)childComponentView;
|
|
225
|
+
_containerView.delegate = self;
|
|
226
|
+
|
|
227
|
+
[_touchHandler attachToView:_containerView];
|
|
228
|
+
[_controller.view addSubview:_containerView];
|
|
229
|
+
[LayoutUtil pinView:_containerView toParentView:_controller.view edges:UIRectEdgeAll];
|
|
230
|
+
[_controller.view bringSubviewToFront:_containerView];
|
|
231
|
+
|
|
232
|
+
CGFloat contentHeight = [_containerView contentHeight];
|
|
233
|
+
if (contentHeight > 0) {
|
|
234
|
+
_controller.contentHeight = @(contentHeight);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
CGFloat headerHeight = [_containerView headerHeight];
|
|
238
|
+
if (headerHeight > 0) {
|
|
239
|
+
_controller.headerHeight = @(headerHeight);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
_containerView.scrollViewPinningEnabled = _scrollable;
|
|
243
|
+
[_containerView setupContentScrollViewPinning];
|
|
244
|
+
|
|
245
|
+
[OnMountEvent emit:_eventEmitter];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
|
|
249
|
+
if (![childComponentView isKindOfClass:[TrueSheetContainerView class]])
|
|
250
|
+
return;
|
|
251
|
+
|
|
252
|
+
_containerView.delegate = nil;
|
|
253
|
+
|
|
254
|
+
if (_touchHandler) {
|
|
255
|
+
[_touchHandler detachFromView:_containerView];
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
[LayoutUtil unpinView:_containerView fromParentView:nil];
|
|
259
|
+
[_containerView removeFromSuperview];
|
|
260
|
+
_containerView = nil;
|
|
261
|
+
}
|
|
262
|
+
|
|
108
263
|
#pragma mark - TurboModule Methods
|
|
109
264
|
|
|
110
265
|
- (void)presentAtIndex:(NSInteger)index
|
|
111
266
|
animated:(BOOL)animated
|
|
112
267
|
completion:(nullable TrueSheetCompletionBlock)completion {
|
|
268
|
+
if (_controller.isBeingPresented) {
|
|
269
|
+
RCTLogWarn(@"TrueSheet: sheet is being presented. Wait for it to transition before presenting again.");
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
113
273
|
if (_controller.isPresented) {
|
|
114
274
|
[_controller.sheetPresentationController animateChanges:^{
|
|
115
275
|
[self->_controller setupActiveDetentWithIndex:index];
|
|
116
276
|
}];
|
|
117
|
-
|
|
118
277
|
if (completion) {
|
|
119
278
|
completion(YES, nil);
|
|
120
279
|
}
|
|
@@ -122,30 +281,23 @@ using namespace facebook::react;
|
|
|
122
281
|
}
|
|
123
282
|
|
|
124
283
|
UIViewController *presentingViewController = [self findPresentingViewController];
|
|
125
|
-
|
|
126
284
|
if (!presentingViewController) {
|
|
127
285
|
NSError *error = [NSError errorWithDomain:@"com.lodev09.TrueSheet"
|
|
128
286
|
code:1001
|
|
129
287
|
userInfo:@{NSLocalizedDescriptionKey : @"No presenting view controller found"}];
|
|
130
|
-
|
|
131
288
|
if (completion) {
|
|
132
289
|
completion(NO, error);
|
|
133
290
|
}
|
|
134
291
|
return;
|
|
135
292
|
}
|
|
136
293
|
|
|
137
|
-
// Setup our sheet properties
|
|
138
294
|
[_controller setupSheetProps];
|
|
139
295
|
[_controller setupSheetDetents];
|
|
140
|
-
|
|
141
|
-
// Set to the given detent index
|
|
142
296
|
[_controller setupActiveDetentWithIndex:index];
|
|
143
297
|
|
|
144
|
-
|
|
145
|
-
[presentingViewController presentViewController:self->_controller
|
|
298
|
+
[presentingViewController presentViewController:_controller
|
|
146
299
|
animated:animated
|
|
147
300
|
completion:^{
|
|
148
|
-
// Call completion handler
|
|
149
301
|
if (completion) {
|
|
150
302
|
completion(YES, nil);
|
|
151
303
|
}
|
|
@@ -153,6 +305,11 @@ using namespace facebook::react;
|
|
|
153
305
|
}
|
|
154
306
|
|
|
155
307
|
- (void)dismissAnimated:(BOOL)animated completion:(nullable TrueSheetCompletionBlock)completion {
|
|
308
|
+
if (_controller.isBeingDismissed) {
|
|
309
|
+
RCTLogWarn(@"TrueSheet: sheet is being dismissed. No need to dismiss it again.");
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
|
|
156
313
|
if (!_controller.isPresented) {
|
|
157
314
|
if (completion) {
|
|
158
315
|
completion(YES, nil);
|
|
@@ -176,184 +333,47 @@ using namespace facebook::react;
|
|
|
176
333
|
}
|
|
177
334
|
}
|
|
178
335
|
|
|
179
|
-
|
|
180
|
-
[super updateProps:props oldProps:oldProps];
|
|
181
|
-
|
|
182
|
-
const auto &newProps = *std::static_pointer_cast<TrueSheetViewProps const>(props);
|
|
183
|
-
|
|
184
|
-
// Update detents - pass numbers directly (-1 represents "auto")
|
|
185
|
-
NSMutableArray *detents = [NSMutableArray new];
|
|
186
|
-
for (const auto &detent : newProps.detents) {
|
|
187
|
-
[detents addObject:@(detent)];
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
_controller.detents = detents;
|
|
191
|
-
|
|
192
|
-
// Update background color - always set it, even if 0 (which could be a valid color like black)
|
|
193
|
-
UIColor *color = RCTUIColorFromSharedColor(SharedColor(newProps.background));
|
|
194
|
-
_controller.backgroundColor = color;
|
|
195
|
-
|
|
196
|
-
// Update blur tint - always set it to clear when removed
|
|
197
|
-
_controller.blurTint = !newProps.blurTint.empty() ? RCTNSStringFromString(newProps.blurTint) : nil;
|
|
198
|
-
|
|
199
|
-
// Update corner radius
|
|
200
|
-
if (newProps.cornerRadius < 0) {
|
|
201
|
-
_controller.cornerRadius = nil;
|
|
202
|
-
} else {
|
|
203
|
-
_controller.cornerRadius = @(newProps.cornerRadius);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Update max height
|
|
207
|
-
if (newProps.maxHeight != 0.0) {
|
|
208
|
-
_controller.maxHeight = @(newProps.maxHeight);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Update grabber
|
|
212
|
-
_controller.grabber = newProps.grabber;
|
|
213
|
-
|
|
214
|
-
// Update dismissible
|
|
215
|
-
_controller.modalInPresentation = !newProps.dismissible;
|
|
216
|
-
|
|
217
|
-
// Update dimmed
|
|
218
|
-
_controller.dimmed = newProps.dimmed;
|
|
219
|
-
|
|
220
|
-
// Update dimmedIndex
|
|
221
|
-
if (newProps.dimmedIndex >= 0) {
|
|
222
|
-
_controller.dimmedIndex = @(newProps.dimmedIndex);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Store initial presentation settings
|
|
226
|
-
_initialDetentIndex = newProps.initialDetentIndex;
|
|
227
|
-
_initialDetentAnimated = newProps.initialDetentAnimated;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
- (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask {
|
|
231
|
-
[super finalizeUpdates:updateMask];
|
|
232
|
-
|
|
233
|
-
// Apply controller updates after all props and children are updated
|
|
234
|
-
if (updateMask & RNComponentViewUpdateMaskProps) {
|
|
235
|
-
// Apply changes to presented sheet if needed
|
|
236
|
-
if (_controller.isPresented) {
|
|
237
|
-
[_controller.sheetPresentationController animateChanges:^{
|
|
238
|
-
[self->_controller setupSheetDetents];
|
|
239
|
-
[self->_controller applyActiveDetent];
|
|
240
|
-
}];
|
|
241
|
-
} else {
|
|
242
|
-
// Handle initial presentation
|
|
243
|
-
if (_initialDetentIndex >= 0 && !_controller.isPresented) {
|
|
244
|
-
[self presentAtIndex:_initialDetentIndex animated:_initialDetentAnimated completion:nil];
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
|
|
251
|
-
// Check if it's a container view
|
|
252
|
-
if ([childComponentView isKindOfClass:[TrueSheetContainerView class]]) {
|
|
253
|
-
if (_containerView != nil) {
|
|
254
|
-
NSLog(@"TrueSheet: Sheet can only have one container component.");
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
_containerView = (TrueSheetContainerView *)childComponentView;
|
|
259
|
-
|
|
260
|
-
// Set this view as the container's delegate
|
|
261
|
-
_containerView.delegate = self;
|
|
262
|
-
|
|
263
|
-
// Attach touch handler to container for touch event handling
|
|
264
|
-
[_touchHandler attachToView:_containerView];
|
|
265
|
-
|
|
266
|
-
// Add to parent view hierarchy
|
|
267
|
-
[_controller.view addSubview:_containerView];
|
|
268
|
-
|
|
269
|
-
// Pin container to fill the entire parent view
|
|
270
|
-
[LayoutUtil pinView:_containerView toParentView:_controller.view edges:UIRectEdgeAll];
|
|
271
|
-
|
|
272
|
-
// Ensure container is above background view
|
|
273
|
-
[_controller.view bringSubviewToFront:_containerView];
|
|
274
|
-
|
|
275
|
-
// Get initial content height from container
|
|
276
|
-
CGFloat contentHeight = [_containerView contentHeight];
|
|
277
|
-
if (contentHeight > 0) {
|
|
278
|
-
_controller.contentHeight = @(contentHeight);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// Emit onMount event when container is mounted
|
|
282
|
-
[OnMountEvent emit:_eventEmitter];
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
|
|
287
|
-
if ([childComponentView isKindOfClass:[TrueSheetContainerView class]]) {
|
|
288
|
-
_containerView.delegate = nil;
|
|
289
|
-
|
|
290
|
-
// Detach touch handler
|
|
291
|
-
if (_touchHandler) {
|
|
292
|
-
[_touchHandler detachFromView:_containerView];
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// Unpin and remove from view hierarchy
|
|
296
|
-
[LayoutUtil unpinView:_containerView];
|
|
297
|
-
[_containerView removeFromSuperview];
|
|
336
|
+
#pragma mark - TrueSheetContainerViewDelegate
|
|
298
337
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
338
|
+
/**
|
|
339
|
+
* Debounced sheet update to handle rapid content/header size changes.
|
|
340
|
+
*/
|
|
341
|
+
- (void)updateSheetIfNeeded {
|
|
342
|
+
if (!_controller.isPresented || _isSheetUpdatePending)
|
|
343
|
+
return;
|
|
302
344
|
|
|
303
|
-
|
|
304
|
-
[super prepareForRecycle];
|
|
345
|
+
_isSheetUpdatePending = YES;
|
|
305
346
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
347
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
348
|
+
self->_isSheetUpdatePending = NO;
|
|
349
|
+
self->_controller.layoutTransitioning = YES;
|
|
310
350
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
351
|
+
[self->_controller.sheetPresentationController animateChanges:^{
|
|
352
|
+
[self->_controller setupSheetDetents];
|
|
353
|
+
}];
|
|
354
|
+
});
|
|
314
355
|
}
|
|
315
356
|
|
|
316
|
-
#pragma mark - TrueSheetContainerViewDelegate
|
|
317
|
-
|
|
318
357
|
- (void)containerViewContentDidChangeSize:(CGSize)newSize {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
_controller.contentHeight = @(contentHeight);
|
|
324
|
-
|
|
325
|
-
// Update detents if sheet is already presented
|
|
326
|
-
if (_controller.isPresented) {
|
|
327
|
-
// Tell controller that we are transitioning from layout changes.
|
|
328
|
-
// Controller viewDidLayoutSubviews will handle position notification.
|
|
329
|
-
_controller.layoutTransitioning = YES;
|
|
358
|
+
_controller.contentHeight = @(newSize.height);
|
|
359
|
+
[self updateSheetIfNeeded];
|
|
360
|
+
}
|
|
330
361
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
}
|
|
362
|
+
- (void)containerViewHeaderDidChangeSize:(CGSize)newSize {
|
|
363
|
+
_controller.headerHeight = @(newSize.height);
|
|
364
|
+
[self updateSheetIfNeeded];
|
|
335
365
|
}
|
|
336
366
|
|
|
337
367
|
#pragma mark - TrueSheetViewControllerDelegate
|
|
338
368
|
|
|
339
369
|
- (void)viewControllerWillPresent {
|
|
340
370
|
NSInteger index = [_controller currentDetentIndex];
|
|
341
|
-
CGFloat position = _controller.currentPosition;
|
|
342
|
-
|
|
343
371
|
_controller.activeDetentIndex = index;
|
|
344
|
-
|
|
345
|
-
[OnWillPresentEvent emit:_eventEmitter index:index position:position];
|
|
346
|
-
|
|
347
|
-
// Emit onChangeSize event to layout our container on JS
|
|
348
|
-
CGSize controllerSize = _controller.view.frame.size;
|
|
349
|
-
[OnSizeChangeEvent emit:_eventEmitter width:controllerSize.width height:controllerSize.height];
|
|
372
|
+
[OnWillPresentEvent emit:_eventEmitter index:index position:_controller.currentPosition];
|
|
350
373
|
}
|
|
351
374
|
|
|
352
375
|
- (void)viewControllerDidPresent {
|
|
353
|
-
|
|
354
|
-
CGFloat position = _controller.currentPosition;
|
|
355
|
-
|
|
356
|
-
[OnDidPresentEvent emit:_eventEmitter index:index position:position];
|
|
376
|
+
[OnDidPresentEvent emit:_eventEmitter index:[_controller currentDetentIndex] position:_controller.currentPosition];
|
|
357
377
|
}
|
|
358
378
|
|
|
359
379
|
- (void)viewControllerDidDrag:(UIGestureRecognizerState)state index:(NSInteger)index position:(CGFloat)position {
|
|
@@ -361,16 +381,13 @@ using namespace facebook::react;
|
|
|
361
381
|
case UIGestureRecognizerStateBegan:
|
|
362
382
|
[OnDragBeginEvent emit:_eventEmitter index:index position:position];
|
|
363
383
|
break;
|
|
364
|
-
|
|
365
384
|
case UIGestureRecognizerStateChanged:
|
|
366
385
|
[OnDragChangeEvent emit:_eventEmitter index:index position:position];
|
|
367
386
|
break;
|
|
368
|
-
|
|
369
387
|
case UIGestureRecognizerStateEnded:
|
|
370
388
|
case UIGestureRecognizerStateCancelled:
|
|
371
389
|
[OnDragEndEvent emit:_eventEmitter index:index position:position];
|
|
372
390
|
break;
|
|
373
|
-
|
|
374
391
|
default:
|
|
375
392
|
break;
|
|
376
393
|
}
|
|
@@ -382,7 +399,6 @@ using namespace facebook::react;
|
|
|
382
399
|
|
|
383
400
|
- (void)viewControllerDidDismiss {
|
|
384
401
|
_controller.activeDetentIndex = -1;
|
|
385
|
-
|
|
386
402
|
[OnDidDismissEvent emit:_eventEmitter];
|
|
387
403
|
}
|
|
388
404
|
|
|
@@ -390,7 +406,6 @@ using namespace facebook::react;
|
|
|
390
406
|
if (_controller.activeDetentIndex != index) {
|
|
391
407
|
_controller.activeDetentIndex = index;
|
|
392
408
|
}
|
|
393
|
-
|
|
394
409
|
[OnDetentChangeEvent emit:_eventEmitter index:index position:position];
|
|
395
410
|
}
|
|
396
411
|
|
|
@@ -399,29 +414,28 @@ using namespace facebook::react;
|
|
|
399
414
|
}
|
|
400
415
|
|
|
401
416
|
- (void)viewControllerDidChangeSize:(CGSize)size {
|
|
402
|
-
[
|
|
417
|
+
[self updateStateWithSize:size];
|
|
403
418
|
}
|
|
404
419
|
|
|
405
420
|
#pragma mark - Private Helpers
|
|
406
421
|
|
|
407
422
|
- (UIViewController *)findPresentingViewController {
|
|
408
423
|
UIWindow *keyWindow = [WindowUtil keyWindow];
|
|
409
|
-
|
|
410
|
-
if (!keyWindow) {
|
|
424
|
+
if (!keyWindow)
|
|
411
425
|
return nil;
|
|
412
|
-
}
|
|
413
426
|
|
|
414
427
|
UIViewController *rootViewController = keyWindow.rootViewController;
|
|
428
|
+
if (!rootViewController)
|
|
429
|
+
return nil;
|
|
415
430
|
|
|
416
|
-
// Find
|
|
431
|
+
// Find topmost presented view controller
|
|
417
432
|
while (rootViewController.presentedViewController) {
|
|
418
433
|
UIViewController *presented = rootViewController.presentedViewController;
|
|
419
434
|
|
|
420
|
-
// Skip TrueSheetViewController if
|
|
435
|
+
// Skip TrueSheetViewController if being dismissed
|
|
421
436
|
if ([presented isKindOfClass:[TrueSheetViewController class]] && presented.isBeingDismissed) {
|
|
422
437
|
break;
|
|
423
438
|
}
|
|
424
|
-
|
|
425
439
|
rootViewController = presented;
|
|
426
440
|
}
|
|
427
441
|
|
|
@@ -41,12 +41,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
41
41
|
@property (nonatomic, strong) NSArray *detents;
|
|
42
42
|
@property (nonatomic, strong, nullable) NSNumber *maxHeight;
|
|
43
43
|
@property (nonatomic, strong, nullable) NSNumber *contentHeight;
|
|
44
|
+
@property (nonatomic, strong, nullable) NSNumber *headerHeight;
|
|
44
45
|
@property (nonatomic, strong, nullable) UIColor *backgroundColor;
|
|
45
46
|
@property (nonatomic, strong, nullable) NSNumber *cornerRadius;
|
|
46
47
|
@property (nonatomic, assign) BOOL grabber;
|
|
47
48
|
@property (nonatomic, assign) BOOL dimmed;
|
|
48
|
-
@property (nonatomic, strong, nullable) NSNumber *
|
|
49
|
+
@property (nonatomic, strong, nullable) NSNumber *dimmedDetentIndex;
|
|
49
50
|
@property (nonatomic, copy, nullable) NSString *blurTint;
|
|
51
|
+
@property (nonatomic, assign) BOOL pageSizing;
|
|
50
52
|
@property (nonatomic, assign) BOOL layoutTransitioning;
|
|
51
53
|
@property (nonatomic, assign) BOOL isPresented;
|
|
52
54
|
@property (nonatomic, assign) NSInteger activeDetentIndex;
|
|
@@ -57,8 +59,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
57
59
|
- (void)setupSheetProps;
|
|
58
60
|
- (NSInteger)currentDetentIndex;
|
|
59
61
|
- (CGFloat)currentPosition;
|
|
60
|
-
- (CGFloat)
|
|
61
|
-
- (CGFloat)containerHeight;
|
|
62
|
+
- (CGFloat)bottomInset;
|
|
62
63
|
|
|
63
64
|
@end
|
|
64
65
|
|