@sdcx/bottom-sheet 0.17.0 → 1.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 (30) hide show
  1. package/README.md +57 -51
  2. package/RNBottomSheet.podspec +5 -4
  3. package/android/build.gradle +42 -19
  4. package/android/src/main/java/com/reactnative/bottomsheet/BottomSheet.java +62 -59
  5. package/android/src/main/java/com/reactnative/bottomsheet/BottomSheetManager.java +12 -6
  6. package/android/src/main/java/com/reactnative/bottomsheet/{BottomSheetState.java → BottomSheetStatus.java} +1 -1
  7. package/android/src/main/java/com/reactnative/bottomsheet/{OffsetChangedEvent.java → OnSlideEvent.java} +5 -3
  8. package/android/src/main/java/com/reactnative/bottomsheet/{StateChangedEvent.java → OnStateChangedEvent.java} +5 -3
  9. package/dist/BottomSheetNativeComponent.d.ts +20 -0
  10. package/dist/BottomSheetNativeComponent.js +2 -0
  11. package/dist/index.d.ts +8 -15
  12. package/dist/index.js +9 -9
  13. package/ios/BottomSheet/{RNBottomSheetOffsetChangedEvent.m → Event/RNBottomSheetOffsetChangedEvent.mm} +3 -1
  14. package/ios/BottomSheet/{RNBottomSheetStateChangedEvent.h → Event/RNBottomSheetStateChangedEvent.h} +1 -3
  15. package/ios/BottomSheet/{RNBottomSheetStateChangedEvent.m → Event/RNBottomSheetStateChangedEvent.mm} +4 -4
  16. package/ios/BottomSheet/RNBottomSheetComponentView.h +10 -0
  17. package/ios/BottomSheet/RNBottomSheetComponentView.mm +559 -0
  18. package/package.json +50 -38
  19. package/src/BottomSheetNativeComponent.ts +26 -0
  20. package/src/index.tsx +51 -70
  21. package/docs/assets/pagerview.gif +0 -0
  22. package/docs/assets/scrollview.gif +0 -0
  23. package/docs/assets/struct.png +0 -0
  24. package/ios/BottomSheet/RNBottomSheet.h +0 -21
  25. package/ios/BottomSheet/RNBottomSheet.m +0 -407
  26. package/ios/BottomSheet/RNBottomSheetManager.h +0 -9
  27. package/ios/BottomSheet/RNBottomSheetManager.m +0 -24
  28. package/ios/BottomSheet/RNBottomSheetState.h +0 -17
  29. package/ios/BottomSheet/RNBottomSheetState.m +0 -38
  30. /package/ios/BottomSheet/{RNBottomSheetOffsetChangedEvent.h → Event/RNBottomSheetOffsetChangedEvent.h} +0 -0
@@ -0,0 +1,559 @@
1
+ #import "RNBottomSheetComponentView.h"
2
+ #import "RNBottomSheetStateChangedEvent.h"
3
+ #import "RNBottomSheetOffsetChangedEvent.h"
4
+
5
+ #import <react/renderer/components/bottomsheet/ComponentDescriptors.h>
6
+ #import <react/renderer/components/bottomsheet/EventEmitters.h>
7
+ #import <react/renderer/components/bottomsheet/Props.h>
8
+ #import <react/renderer/components/bottomsheet/RCTComponentViewHelpers.h>
9
+
10
+ #import <React/RCTConversions.h>
11
+ #import <React/RCTLog.h>
12
+
13
+
14
+ static void
15
+ RCTSendOffsetForNativeAnimations_DEPRECATED(NSInteger tag,
16
+ CGFloat progress,
17
+ CGFloat offset,
18
+ CGFloat minY,
19
+ CGFloat maxY) {
20
+ RNBottomSheetOffsetChangedEvent *event =[[RNBottomSheetOffsetChangedEvent alloc] initWithViewTag:@(tag) progress:progress offset:offset minY:minY maxY:maxY];
21
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:event, @"event", nil];
22
+ [[NSNotificationCenter defaultCenter] postNotificationName:RCTNotifyEventDispatcherObserversOfEvent_DEPRECATED
23
+ object:nil
24
+ userInfo:userInfo];
25
+ }
26
+
27
+ static void
28
+ RCTSendStateForNativeAnimations_DEPRECATED(NSInteger tag, NSString *state) {
29
+ RNBottomSheetStateChangedEvent *event =[[RNBottomSheetStateChangedEvent alloc] initWithViewTag:@(tag) state:state];
30
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:event, @"event", nil];
31
+ [[NSNotificationCenter defaultCenter] postNotificationName:RCTNotifyEventDispatcherObserversOfEvent_DEPRECATED
32
+ object:nil
33
+ userInfo:userInfo];
34
+ }
35
+
36
+
37
+ using namespace facebook::react;
38
+
39
+ @interface RNBottomSheetComponentView () <UIGestureRecognizerDelegate>
40
+
41
+ @property(nonatomic, assign) BottomSheetStatus status;
42
+ @property(nonatomic, assign) BottomSheetStatus finalStatus;
43
+ @property(nonatomic, assign) BOOL draggable;
44
+ @property(nonatomic, assign) CGFloat peekHeight;
45
+ @property(nonatomic, assign) CGFloat minY;
46
+ @property(nonatomic, assign) CGFloat maxY;
47
+ @property(nonatomic, assign) BOOL nextReturn;
48
+
49
+ @property(nonatomic, strong) UIView *child;
50
+ @property(nonatomic, strong) UIScrollView *target;
51
+ @property(nonatomic, strong) UIPanGestureRecognizer *panGestureRecognizer;
52
+ @property(nonatomic, strong) CADisplayLink *displayLink;
53
+ @property(nonatomic, strong) UIViewPropertyAnimator *animator;
54
+
55
+ @end
56
+
57
+ @implementation RNBottomSheetComponentView {
58
+ __weak UIView *_rootView;
59
+ BOOL _isInitialRender;
60
+ __weak UIView *_reactRootView;
61
+ }
62
+
63
+ // Needed because of this: https://github.com/facebook/react-native/pull/37274
64
+ + (void)load {
65
+ [super load];
66
+ }
67
+
68
+ + (ComponentDescriptorProvider)componentDescriptorProvider {
69
+ return concreteComponentDescriptorProvider<BottomSheetComponentDescriptor>();
70
+ }
71
+
72
+ + (BOOL)shouldBeRecycled {
73
+ return NO;
74
+ }
75
+
76
+ - (instancetype)initWithFrame:(CGRect)frame {
77
+ if (self = [super initWithFrame:frame]) {
78
+ static const auto defaultProps = std::make_shared<const BottomSheetProps>();
79
+ _props = defaultProps;
80
+ _panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
81
+ _panGestureRecognizer.delegate = self;
82
+ _draggable = YES;
83
+ _peekHeight = 200;
84
+ _status = BottomSheetStatus::Collapsed;
85
+ _finalStatus = BottomSheetStatus::Collapsed;
86
+ _isInitialRender = YES;
87
+ }
88
+ return self;
89
+ }
90
+
91
+ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
92
+ UIView *hitView = [super hitTest:point withEvent:event];
93
+ if (hitView == self) {
94
+ return nil;
95
+ }
96
+ return hitView;
97
+ }
98
+
99
+ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
100
+ [super mountChildComponentView:childComponentView index:index];
101
+ if ([childComponentView isKindOfClass:[UIView class]] && index == 0) {
102
+ self.child = (UIView *)childComponentView;
103
+ [self.child addGestureRecognizer:_panGestureRecognizer];
104
+ }
105
+ }
106
+
107
+ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
108
+ if (self.child == childComponentView) {
109
+ [self.child removeGestureRecognizer:_panGestureRecognizer];
110
+ }
111
+ [super unmountChildComponentView:childComponentView index:index];
112
+ }
113
+
114
+ - (void)updateProps:(const facebook::react::Props::Shared &)props oldProps:(const facebook::react::Props::Shared &)oldProps {
115
+ const auto &oldViewProps = static_cast<const BottomSheetProps &>(*_props);
116
+ const auto &newViewProps = static_cast<const BottomSheetProps &>(*props);
117
+
118
+ // `draggable`
119
+ if (newViewProps.draggable != oldViewProps.draggable) {
120
+ self.draggable = newViewProps.draggable;
121
+ }
122
+
123
+ // `peekHeight`
124
+ if (newViewProps.peekHeight != oldViewProps.peekHeight) {
125
+ self.peekHeight = newViewProps.peekHeight;
126
+ }
127
+
128
+ // `status`
129
+ if (newViewProps.status != oldViewProps.status) {
130
+ self.status = newViewProps.status;
131
+ }
132
+
133
+ [super updateProps:props oldProps:oldProps];
134
+ }
135
+
136
+ - (const BottomSheetEventEmitter &)eventEmitter {
137
+ return static_cast<const BottomSheetEventEmitter &>(*_eventEmitter);
138
+ }
139
+
140
+ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
141
+ if (gestureRecognizer == self.panGestureRecognizer && otherGestureRecognizer == self.target.panGestureRecognizer) {
142
+ return YES;
143
+ }
144
+ return NO;
145
+ }
146
+
147
+ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
148
+ if (gestureRecognizer == self.panGestureRecognizer) {
149
+ if ([super gestureRecognizerShouldBegin:gestureRecognizer]) {
150
+ [self cancelRootViewTouches];
151
+ return YES;
152
+ }
153
+ return NO;
154
+ }
155
+ return [super gestureRecognizerShouldBegin:gestureRecognizer];
156
+ }
157
+
158
+ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
159
+ if (!self.draggable) {
160
+ return NO;
161
+ }
162
+
163
+ if (gestureRecognizer != self.panGestureRecognizer) {
164
+ return YES;
165
+ }
166
+
167
+ if (self.target) {
168
+ [self.target removeObserver:self forKeyPath:@"contentOffset"];
169
+ }
170
+ self.target = nil;
171
+
172
+ UIView *touchView = touch.view;
173
+
174
+ while (touchView != nil && [touchView isDescendantOfView:self]) {
175
+ if ([touchView isKindOfClass:[UIScrollView class]]) {
176
+ UIScrollView *scrollView = (UIScrollView *)touchView;
177
+ if (![self isHorizontal:scrollView]) {
178
+ self.target = scrollView;
179
+ [self.target addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
180
+ break;
181
+ }
182
+ }
183
+ touchView = touchView.superview;
184
+ }
185
+
186
+ return YES;
187
+ }
188
+
189
+ - (void)willMoveToSuperview:(UIView *)superview {
190
+ [super willMoveToSuperview:superview];
191
+ if (superview == nil) {
192
+ [self stopWatchBottomSheetTransition];
193
+ if (self.target) {
194
+ [self.target removeObserver:self forKeyPath:@"contentOffset"];
195
+ self.target = nil;
196
+ }
197
+ }
198
+ }
199
+
200
+ - (void)willMoveToWindow:(UIWindow *)newWindow {
201
+ [super willMoveToWindow:newWindow];
202
+ if (newWindow == nil) {
203
+ [self stopWatchBottomSheetTransition];
204
+ }
205
+ }
206
+
207
+ - (void)didMoveToWindow {
208
+ [super didMoveToWindow];
209
+ if (self.window) {
210
+ [self cacheRootView];
211
+ } else {
212
+ _reactRootView = nil;
213
+ }
214
+ }
215
+
216
+ - (BOOL)isHorizontal:(UIScrollView *)scrollView {
217
+ return scrollView.contentSize.width > self.frame.size.width;
218
+ }
219
+
220
+ - (void)layoutSubviews {
221
+ [super layoutSubviews];
222
+
223
+ if (!self.child) {
224
+ return;
225
+ }
226
+
227
+ [self layoutChild];
228
+
229
+ dispatch_async(dispatch_get_main_queue(), ^{
230
+ if (self.finalStatus == BottomSheetStatus::Expanded && self->_isInitialRender) {
231
+ [self settleToStatus:self.finalStatus withFling:NO];
232
+ }
233
+
234
+ self->_isInitialRender = NO;
235
+ });
236
+ }
237
+
238
+ - (void)layoutChild {
239
+ if (!CGRectEqualToRect(self.child.frame, CGRectZero) && !CGRectEqualToRect(self.frame, CGRectZero)) {
240
+ [self calculateOffset];
241
+ if (self.status == BottomSheetStatus::Collapsed) {
242
+ self.child.frame = CGRectOffset(self.child.frame, 0, self.maxY - self.child.frame.origin.y);
243
+ } else if (self.status == BottomSheetStatus::Expanded) {
244
+ self.child.frame = CGRectOffset(self.child.frame, 0, self.minY - self.child.frame.origin.y);
245
+ } else if (self.status == BottomSheetStatus::Hidden) {
246
+ self.child.frame = CGRectOffset(self.child.frame, 0, self.frame.size.height - self.child.frame.origin.y);
247
+ }
248
+ [self dispatchOnSlide:self.child.frame.origin.y];
249
+ }
250
+ }
251
+
252
+ - (void)calculateOffset {
253
+ CGFloat parentHeight = self.frame.size.height;
254
+ self.minY = fmax(0, parentHeight - self.child.frame.size.height);
255
+ self.maxY = fmax(self.minY, parentHeight - self.peekHeight);
256
+ }
257
+
258
+ - (void)handlePan:(UIPanGestureRecognizer *)pan {
259
+ if (!self.draggable || self.status == BottomSheetStatus::Settling) {
260
+ return;
261
+ }
262
+
263
+ CGFloat translationY = [pan translationInView:self.child].y;
264
+ [pan setTranslation:CGPointZero inView:self.child];
265
+
266
+ CGFloat top = self.child.frame.origin.y;
267
+
268
+ if (pan.state == UIGestureRecognizerStateChanged) {
269
+ [self setStateInternal:BottomSheetStatus::Dragging];
270
+ }
271
+
272
+ // 如果有嵌套滚动
273
+ if (self.target) {
274
+ if(translationY > 0 && top < self.maxY && self.target.contentOffset.y <= 0) {
275
+ //向下拖
276
+ CGFloat y = fmin(top + translationY, self.maxY);
277
+ self.child.frame = CGRectOffset(self.child.frame, 0, y - top);
278
+ [self dispatchOnSlide:self.child.frame.origin.y];
279
+ }
280
+
281
+ if (translationY < 0 && top > self.minY) {
282
+ //向上拖
283
+ CGFloat y = fmax(top + translationY, self.minY);
284
+ self.child.frame = CGRectOffset(self.child.frame, 0, y - top);
285
+ [self dispatchOnSlide:self.child.frame.origin.y];
286
+ }
287
+ }
288
+
289
+ // 没有嵌套滚动
290
+ if (!self.target) {
291
+ if(translationY > 0 && top < self.maxY) {
292
+ //向下拖
293
+ CGFloat y = fmin(top + translationY, self.maxY);
294
+ self.child.frame = CGRectOffset(self.child.frame, 0, y - top);
295
+ [self dispatchOnSlide:self.child.frame.origin.y];
296
+ }
297
+
298
+ if (translationY < 0 && top > self.minY) {
299
+ //向上拖
300
+ CGFloat y = fmax(top + translationY, self.minY);
301
+ self.child.frame = CGRectOffset(self.child.frame, 0, y - top);
302
+ [self dispatchOnSlide:self.child.frame.origin.y];
303
+ }
304
+ }
305
+
306
+ if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled) {
307
+ // RCTLogInfo(@"velocity:%f", [pan velocityInView:self.child].y);
308
+ CGFloat velocity = [pan velocityInView:self.child].y;
309
+ if (velocity > 400) {
310
+ if (self.target && self.target.contentOffset.y <= 0) {
311
+ //如果是类似轻扫的那种
312
+ [self settleToStatus:BottomSheetStatus::Collapsed withFling:YES];
313
+ }
314
+
315
+ if (!self.target) {
316
+ //如果是类似轻扫的那种
317
+ [self settleToStatus:BottomSheetStatus::Collapsed withFling:YES];
318
+ }
319
+ } else if (velocity < -400) {
320
+ //如果是类似轻扫的那种
321
+ [self settleToStatus:BottomSheetStatus::Expanded withFling:YES];
322
+ } else {
323
+ //如果是普通拖拽
324
+ if(fabs(self.child.frame.origin.y - self.minY) > fabs(self.child.frame.origin.y - self.maxY)) {
325
+ [self settleToStatus:BottomSheetStatus::Collapsed withFling:YES];
326
+ } else {
327
+ [self settleToStatus:BottomSheetStatus::Expanded withFling:YES];
328
+ }
329
+ }
330
+ }
331
+ }
332
+
333
+ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(UIScrollView *)target change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
334
+ if (_nextReturn) {
335
+ _nextReturn = false;
336
+ return;
337
+ }
338
+
339
+ if (![keyPath isEqualToString:@"contentOffset"]) {
340
+ return;
341
+ }
342
+
343
+ CGFloat newY = [change[@"new"] CGPointValue].y;
344
+ CGFloat oldY = [change[@"old"] CGPointValue].y;
345
+
346
+ if (newY == oldY) {
347
+ return;
348
+ }
349
+
350
+ CGFloat dy = oldY - newY;
351
+
352
+ if (dy > 0) {
353
+ //向下
354
+ if(target.contentOffset.y < 0){
355
+ _nextReturn = true;
356
+ target.contentOffset = CGPointMake(0, 0);
357
+ }
358
+ }
359
+
360
+ if (dy < 0) {
361
+ //向上
362
+ if (self.child.frame.origin.y > self.minY) {
363
+ _nextReturn = true;
364
+ target.contentOffset = CGPointMake(0, oldY);
365
+ }
366
+ }
367
+ }
368
+
369
+ - (void)setPeekHeight:(CGFloat)peekHeight {
370
+ _peekHeight = peekHeight;
371
+ if (_isInitialRender) {
372
+ return;
373
+ }
374
+ if (!CGRectEqualToRect(self.child.frame, CGRectZero)) {
375
+ [self calculateOffset];
376
+ if (self.status == BottomSheetStatus::Collapsed) {
377
+ [self settleToStatus:BottomSheetStatus::Collapsed withFling:NO];
378
+ }
379
+ }
380
+ }
381
+
382
+ - (void)setStatus:(BottomSheetStatus)status {
383
+ if (_isInitialRender) {
384
+ self.finalStatus = status;
385
+ return;
386
+ }
387
+
388
+ if (self.finalStatus == status || _status == BottomSheetStatus::Settling) {
389
+ return;
390
+ }
391
+
392
+ self.finalStatus = status;
393
+
394
+ [self settleToStatus:status withFling:YES];
395
+ }
396
+
397
+ - (void)settleToStatus:(BottomSheetStatus)status withFling:(BOOL)fling {
398
+ if (!fling) {
399
+ [self setStateInternal:status];
400
+ [self layoutChild];
401
+ return;
402
+ }
403
+ if (status == BottomSheetStatus::Collapsed) {
404
+ [self settleToStatus:status top:self.maxY withFling:fling];
405
+ } else if (status == BottomSheetStatus::Expanded) {
406
+ [self settleToStatus:status top:self.minY withFling:fling];
407
+ } else if (status == BottomSheetStatus::Hidden) {
408
+ [self settleToStatus:status top:self.frame.size.height withFling:fling];
409
+ }
410
+ }
411
+
412
+ - (void)settleToStatus:(BottomSheetStatus)status top:(CGFloat)top withFling:(BOOL)fling {
413
+ self.target.pagingEnabled = YES;
414
+ [self setStateInternal:BottomSheetStatus::Settling];
415
+ [self startWatchBottomSheetTransition];
416
+
417
+ if (self.animator) {
418
+ [self.animator stopAnimation:YES];
419
+ }
420
+
421
+ UIViewAnimationOptions options = UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseOut;
422
+
423
+ self.animator = [UIViewPropertyAnimator runningPropertyAnimatorWithDuration:0.3 delay:0 options:options animations:^{
424
+ self.child.frame = CGRectOffset(self.child.frame, 0, top - self.child.frame.origin.y);
425
+ } completion:^(UIViewAnimatingPosition finalPosition) {
426
+ self.target.pagingEnabled = NO;
427
+ self.animator = nil;
428
+ [self stopWatchBottomSheetTransition];
429
+ [self setStateInternal:status];
430
+ }];
431
+ }
432
+
433
+ - (void)setStateInternal:(BottomSheetStatus)status {
434
+ if (_status == status) {
435
+ return;
436
+ }
437
+ _status = status;
438
+
439
+ if (status == BottomSheetStatus::Expanded) {
440
+ [self dispatchOnSlide:self.minY];
441
+ }
442
+
443
+ if (status == BottomSheetStatus::Hidden) {
444
+ [self dispatchOnSlide:self.frame.size.height];
445
+ }
446
+
447
+ if (status == BottomSheetStatus::Collapsed) {
448
+ [self dispatchOnSlide:self.maxY];
449
+ }
450
+
451
+ if (status == BottomSheetStatus::Collapsed ||
452
+ status == BottomSheetStatus::Expanded ||
453
+ status == BottomSheetStatus::Hidden) {
454
+
455
+ self.finalStatus = status;
456
+ [self dispatchOnStateChanged:status];
457
+ }
458
+ }
459
+
460
+ - (void)dispatchOnSlide:(CGFloat)top {
461
+ if (top < 0 || self.maxY == 0) {
462
+ return;
463
+ }
464
+
465
+ CGFloat progress = fmin((top - self.minY) * 1.0f / (self.maxY - self.minY), 1);
466
+ BottomSheetEventEmitter::OnSlide payload = BottomSheetEventEmitter::OnSlide{
467
+ .progress = static_cast<Float>(progress),
468
+ .offset = static_cast<Float>(top),
469
+ .expandedOffset = static_cast<Float>(self.minY),
470
+ .collapsedOffset = static_cast<Float>(self.maxY)
471
+ };
472
+ RCTSendOffsetForNativeAnimations_DEPRECATED(self.tag, progress, top, self.minY, self.maxY);
473
+ [self eventEmitter].onSlide(payload);
474
+ }
475
+
476
+ - (void)dispatchOnStateChanged:(BottomSheetStatus)status {
477
+ BottomSheetEventEmitter::OnStateChanged payload = BottomSheetEventEmitter::OnStateChanged{
478
+ .state = [self convertStatus:status]
479
+ };
480
+ RCTSendStateForNativeAnimations_DEPRECATED(self.tag, [self convertStatusToString:status]);
481
+ [self eventEmitter].onStateChanged(payload);
482
+ }
483
+
484
+ - (BottomSheetEventEmitter::OnStateChangedState)convertStatus:(BottomSheetStatus)status {
485
+ if (status == BottomSheetStatus::Expanded) {
486
+ return BottomSheetEventEmitter::OnStateChangedState::Expanded;
487
+ } else if (status == BottomSheetStatus::Hidden) {
488
+ return BottomSheetEventEmitter::OnStateChangedState::Hidden;
489
+ } else {
490
+ return BottomSheetEventEmitter::OnStateChangedState::Collapsed;
491
+ }
492
+ }
493
+
494
+ - (NSString *)convertStatusToString:(BottomSheetStatus)status {
495
+ if (status == BottomSheetStatus::Expanded) {
496
+ return @"expanded";
497
+ } else if (status == BottomSheetStatus::Hidden) {
498
+ return @"hidden";
499
+ } else {
500
+ return @"collapsed";
501
+ }
502
+ }
503
+
504
+ - (void)startWatchBottomSheetTransition {
505
+ [self stopWatchBottomSheetTransition];
506
+ _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(watchBottomSheetTransition)];
507
+ _displayLink.preferredFramesPerSecond = 120;
508
+ [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
509
+ }
510
+
511
+ - (void)stopWatchBottomSheetTransition {
512
+ if(_displayLink){
513
+ [_displayLink invalidate];
514
+ _displayLink = nil;
515
+ }
516
+ }
517
+
518
+ - (void)watchBottomSheetTransition {
519
+ CGFloat top = [self.child.layer presentationLayer].frame.origin.y;
520
+ [self dispatchOnSlide:top];
521
+ }
522
+
523
+ - (void)cacheRootView {
524
+ if (_reactRootView) {
525
+ return;
526
+ }
527
+
528
+ UIView *v = self;
529
+ while (v) {
530
+ if ([NSStringFromClass([v class]) isEqualToString:@"RCTSurfaceView"]) {
531
+ _reactRootView = v;
532
+ return;
533
+ }
534
+ v = v.superview;
535
+ }
536
+ }
537
+
538
+ - (void)cancelRootViewTouches {
539
+ if (!_reactRootView) {
540
+ return;
541
+ }
542
+ [self cancelTouchesInView:_reactRootView];
543
+ }
544
+
545
+ - (void)cancelTouchesInView:(UIView *)view {
546
+ NSArray<UIGestureRecognizer *> *gestureRecognizers = view.gestureRecognizers;
547
+ if (gestureRecognizers.count > 0) {
548
+ for (UIGestureRecognizer *gr in gestureRecognizers) {
549
+ Class surfaceTouchHandlerClass = NSClassFromString(@"RCTSurfaceTouchHandler");
550
+ if (surfaceTouchHandlerClass && [gr isKindOfClass:surfaceTouchHandlerClass]) {
551
+ gr.enabled = NO;
552
+ gr.enabled = YES;
553
+ continue;
554
+ }
555
+ }
556
+ }
557
+ }
558
+
559
+ @end
package/package.json CHANGED
@@ -1,40 +1,52 @@
1
1
  {
2
- "name": "@sdcx/bottom-sheet",
3
- "description": "A react-native BottomSheet component.",
4
- "version": "0.17.0",
5
- "main": "./dist/index.js",
6
- "typings": "./dist/index.d.ts",
7
- "react-native": "src/index",
8
- "nativePackage": true,
9
- "files": [
10
- "src",
11
- "dist",
12
- "android",
13
- "ios",
14
- "docs",
15
- "RNBottomSheet.podspec",
16
- "!android/build",
17
- "!ios/build",
18
- "!**/__tests__"
19
- ],
20
- "repository": "https://github.com/sdcxtech/react-native-troika",
21
- "homepage": "https://github.com/sdcxtech/react-native-troika/tree/master/packages/bottom-sheet/README.md",
22
- "author": "sdcx",
23
- "license": "MIT",
24
- "keywords": [
25
- "react-native",
26
- "bottom-sheet"
27
- ],
28
- "scripts": {
29
- "build": "rm -rf ./dist && tsc -p tsconfig.json",
30
- "prepare": "npm run build",
31
- "tsc": "tsc",
32
- "test": "jest",
33
- "lint": "eslint . --fix --ext .js,.jsx,.ts,.tsx"
34
- },
35
- "peerDependencies": {
36
- "react": ">=16.8",
37
- "react-native": ">=0.60"
38
- },
39
- "devDependencies": {}
2
+ "name": "@sdcx/bottom-sheet",
3
+ "description": "A react-native BottomSheet component.",
4
+ "version": "1.0.1",
5
+ "main": "./dist/index.js",
6
+ "typings": "./dist/index.d.ts",
7
+ "react-native": "src/index",
8
+ "nativePackage": true,
9
+ "files": [
10
+ "src",
11
+ "dist",
12
+ "android",
13
+ "ios",
14
+ "RNBottomSheet.podspec",
15
+ "!android/build",
16
+ "!ios/build",
17
+ "!**/__tests__"
18
+ ],
19
+ "repository": "https://github.com/sdcxtech/react-native-troika",
20
+ "homepage": "https://github.com/sdcxtech/react-native-troika/tree/master/packages/bottom-sheet/README.md",
21
+ "author": "sdcx",
22
+ "license": "MIT",
23
+ "keywords": [
24
+ "react-native",
25
+ "bottom-sheet"
26
+ ],
27
+ "scripts": {
28
+ "build": "rm -rf ./dist && tsc -p tsconfig.json",
29
+ "prepare": "npm run build",
30
+ "tsc": "tsc",
31
+ "test": "jest",
32
+ "lint": "eslint . --fix --ext .js,.jsx,.ts,.tsx"
33
+ },
34
+ "peerDependencies": {
35
+ "react": ">=16.8",
36
+ "react-native": ">=0.60"
37
+ },
38
+ "devDependencies": {},
39
+ "codegenConfig": {
40
+ "name": "bottomsheet",
41
+ "type": "components",
42
+ "jsSrcsDir": "src",
43
+ "android": {
44
+ "javaPackageName": "com.reactnative.bottomsheet"
45
+ },
46
+ "ios": {
47
+ "componentProvider": {
48
+ "BottomSheet": "RNBottomSheetComponentView"
49
+ }
50
+ }
51
+ }
40
52
  }
@@ -0,0 +1,26 @@
1
+ import type { CodegenTypes, HostComponent, ViewProps } from 'react-native';
2
+ import { codegenNativeComponent } from 'react-native';
3
+
4
+ export type BottomSheetStatus = 'collapsed' | 'expanded' | 'hidden' | 'dragging' | 'settling';
5
+
6
+ export type OnStateChangedEventPayload = {
7
+ state: 'collapsed' | 'expanded' | 'hidden';
8
+ };
9
+
10
+ export type OnSlideEventPayload = {
11
+ progress: CodegenTypes.Float;
12
+ offset: CodegenTypes.Float;
13
+ expandedOffset: CodegenTypes.Float;
14
+ collapsedOffset: CodegenTypes.Float;
15
+ };
16
+
17
+ export interface NativeProps extends ViewProps {
18
+ peekHeight?: CodegenTypes.WithDefault<CodegenTypes.Int32, 200>;
19
+ draggable?: CodegenTypes.WithDefault<boolean, true>;
20
+ // 无法使用 state,会生成 BottomSheetState 枚举类型,和原本要生成的 BottomSheetState 结构体冲突
21
+ status?: CodegenTypes.WithDefault<BottomSheetStatus, 'collapsed'>;
22
+ onSlide?: CodegenTypes.DirectEventHandler<OnSlideEventPayload>;
23
+ onStateChanged?: CodegenTypes.DirectEventHandler<OnStateChangedEventPayload>;
24
+ }
25
+
26
+ export default codegenNativeComponent<NativeProps>('BottomSheet') as HostComponent<NativeProps>;