@lodev09/react-native-true-sheet 3.0.0-beta.13 → 3.0.0-beta.15
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/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +20 -20
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +49 -14
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +10 -1
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDialogObserver.kt +17 -43
- package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetDragEvents.kt +71 -0
- package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetFocusEvents.kt +65 -0
- package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +94 -0
- package/android/src/main/java/com/lodev09/truesheet/events/{PositionChangeEvent.kt → TrueSheetStateEvents.kt} +25 -3
- package/ios/TrueSheetView.mm +39 -25
- package/ios/TrueSheetViewController.h +7 -1
- package/ios/TrueSheetViewController.mm +101 -51
- package/ios/core/TrueSheetBlurView.h +24 -0
- package/ios/{utils/ConversionUtil.mm → core/TrueSheetBlurView.mm} +65 -3
- package/ios/events/TrueSheetDragEvents.h +39 -0
- package/ios/events/TrueSheetDragEvents.mm +62 -0
- package/ios/events/{OnPositionChangeEvent.h → TrueSheetFocusEvents.h} +8 -6
- package/ios/events/TrueSheetFocusEvents.mm +49 -0
- package/ios/events/TrueSheetLifecycleEvents.h +40 -0
- package/ios/events/TrueSheetLifecycleEvents.mm +71 -0
- package/ios/events/TrueSheetStateEvents.h +35 -0
- package/ios/events/TrueSheetStateEvents.mm +49 -0
- package/ios/utils/GestureUtil.h +7 -0
- package/ios/utils/GestureUtil.mm +12 -0
- package/lib/module/TrueSheet.js +12 -0
- package/lib/module/TrueSheet.js.map +1 -1
- package/lib/module/fabric/TrueSheetViewNativeComponent.ts +8 -1
- package/lib/module/reanimated/ReanimatedTrueSheet.js +6 -6
- package/lib/module/reanimated/ReanimatedTrueSheet.js.map +1 -1
- package/lib/typescript/src/TrueSheet.d.ts +2 -0
- package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.types.d.ts +37 -3
- package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +6 -1
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/TrueSheet.tsx +16 -0
- package/src/TrueSheet.types.ts +42 -3
- package/src/fabric/TrueSheetViewNativeComponent.ts +8 -1
- package/src/reanimated/ReanimatedTrueSheet.tsx +6 -6
- package/android/src/main/java/com/lodev09/truesheet/events/BlurEvent.kt +0 -20
- package/android/src/main/java/com/lodev09/truesheet/events/DetentChangeEvent.kt +0 -27
- package/android/src/main/java/com/lodev09/truesheet/events/DidDismissEvent.kt +0 -20
- package/android/src/main/java/com/lodev09/truesheet/events/DidPresentEvent.kt +0 -27
- package/android/src/main/java/com/lodev09/truesheet/events/DragBeginEvent.kt +0 -27
- package/android/src/main/java/com/lodev09/truesheet/events/DragChangeEvent.kt +0 -27
- package/android/src/main/java/com/lodev09/truesheet/events/DragEndEvent.kt +0 -27
- package/android/src/main/java/com/lodev09/truesheet/events/FocusEvent.kt +0 -20
- package/android/src/main/java/com/lodev09/truesheet/events/MountEvent.kt +0 -20
- package/android/src/main/java/com/lodev09/truesheet/events/WillDismissEvent.kt +0 -20
- package/android/src/main/java/com/lodev09/truesheet/events/WillPresentEvent.kt +0 -27
- package/ios/events/OnDetentChangeEvent.h +0 -29
- package/ios/events/OnDetentChangeEvent.mm +0 -32
- package/ios/events/OnDidBlurEvent.h +0 -26
- package/ios/events/OnDidBlurEvent.mm +0 -25
- package/ios/events/OnDidDismissEvent.h +0 -26
- package/ios/events/OnDidDismissEvent.mm +0 -25
- package/ios/events/OnDidFocusEvent.h +0 -26
- package/ios/events/OnDidFocusEvent.mm +0 -25
- package/ios/events/OnDidPresentEvent.h +0 -29
- package/ios/events/OnDidPresentEvent.mm +0 -32
- package/ios/events/OnDragBeginEvent.h +0 -29
- package/ios/events/OnDragBeginEvent.mm +0 -32
- package/ios/events/OnDragChangeEvent.h +0 -29
- package/ios/events/OnDragChangeEvent.mm +0 -32
- package/ios/events/OnDragEndEvent.h +0 -29
- package/ios/events/OnDragEndEvent.mm +0 -32
- package/ios/events/OnMountEvent.h +0 -26
- package/ios/events/OnMountEvent.mm +0 -25
- package/ios/events/OnPositionChangeEvent.mm +0 -34
- package/ios/events/OnWillDismissEvent.h +0 -26
- package/ios/events/OnWillDismissEvent.mm +0 -25
- package/ios/events/OnWillPresentEvent.h +0 -29
- package/ios/events/OnWillPresentEvent.mm +0 -32
- package/ios/utils/ConversionUtil.h +0 -24
|
@@ -4,9 +4,31 @@ import com.facebook.react.bridge.Arguments
|
|
|
4
4
|
import com.facebook.react.bridge.WritableMap
|
|
5
5
|
import com.facebook.react.uimanager.events.Event
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Fired when the detent changes
|
|
9
|
+
* Payload: { index: number, position: number, detent: number }
|
|
10
|
+
*/
|
|
11
|
+
class DetentChangeEvent(surfaceId: Int, viewId: Int, private val index: Int, private val position: Float, private val detent: Float) :
|
|
12
|
+
Event<DetentChangeEvent>(surfaceId, viewId) {
|
|
13
|
+
|
|
14
|
+
override fun getEventName(): String = EVENT_NAME
|
|
15
|
+
|
|
16
|
+
override fun getEventData(): WritableMap =
|
|
17
|
+
Arguments.createMap().apply {
|
|
18
|
+
putInt("index", index)
|
|
19
|
+
putDouble("position", position.toDouble())
|
|
20
|
+
putDouble("detent", detent.toDouble())
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
companion object {
|
|
24
|
+
const val EVENT_NAME = "topDetentChange"
|
|
25
|
+
const val REGISTRATION_NAME = "onDetentChange"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
7
29
|
/**
|
|
8
30
|
* Fired continuously for position updates during drag and animation
|
|
9
|
-
* Payload: { index: number, position: number, detent: number,
|
|
31
|
+
* Payload: { index: number, position: number, detent: number, realtime: boolean }
|
|
10
32
|
*/
|
|
11
33
|
class PositionChangeEvent(
|
|
12
34
|
surfaceId: Int,
|
|
@@ -14,7 +36,7 @@ class PositionChangeEvent(
|
|
|
14
36
|
private val index: Float,
|
|
15
37
|
private val position: Float,
|
|
16
38
|
private val detent: Float,
|
|
17
|
-
private val
|
|
39
|
+
private val realtime: Boolean = false
|
|
18
40
|
) : Event<PositionChangeEvent>(surfaceId, viewId) {
|
|
19
41
|
|
|
20
42
|
override fun getEventName(): String = EVENT_NAME
|
|
@@ -24,7 +46,7 @@ class PositionChangeEvent(
|
|
|
24
46
|
putDouble("index", index.toDouble())
|
|
25
47
|
putDouble("position", position.toDouble())
|
|
26
48
|
putDouble("detent", detent.toDouble())
|
|
27
|
-
putBoolean("
|
|
49
|
+
putBoolean("realtime", realtime)
|
|
28
50
|
}
|
|
29
51
|
|
|
30
52
|
companion object {
|
package/ios/TrueSheetView.mm
CHANGED
|
@@ -14,18 +14,10 @@
|
|
|
14
14
|
#import "TrueSheetFooterView.h"
|
|
15
15
|
#import "TrueSheetModule.h"
|
|
16
16
|
#import "TrueSheetViewController.h"
|
|
17
|
-
#import "events/
|
|
18
|
-
#import "events/
|
|
19
|
-
#import "events/
|
|
20
|
-
#import "events/
|
|
21
|
-
#import "events/OnDidPresentEvent.h"
|
|
22
|
-
#import "events/OnDragBeginEvent.h"
|
|
23
|
-
#import "events/OnDragChangeEvent.h"
|
|
24
|
-
#import "events/OnDragEndEvent.h"
|
|
25
|
-
#import "events/OnMountEvent.h"
|
|
26
|
-
#import "events/OnPositionChangeEvent.h"
|
|
27
|
-
#import "events/OnWillDismissEvent.h"
|
|
28
|
-
#import "events/OnWillPresentEvent.h"
|
|
17
|
+
#import "events/TrueSheetDragEvents.h"
|
|
18
|
+
#import "events/TrueSheetFocusEvents.h"
|
|
19
|
+
#import "events/TrueSheetLifecycleEvents.h"
|
|
20
|
+
#import "events/TrueSheetStateEvents.h"
|
|
29
21
|
#import "utils/LayoutUtil.h"
|
|
30
22
|
#import "utils/WindowUtil.h"
|
|
31
23
|
|
|
@@ -129,6 +121,12 @@ using namespace facebook::react;
|
|
|
129
121
|
// Blur tint
|
|
130
122
|
_controller.blurTint = !newProps.blurTint.empty() ? RCTNSStringFromString(newProps.blurTint) : nil;
|
|
131
123
|
|
|
124
|
+
// Blur intensity (-1 means use system default)
|
|
125
|
+
_controller.blurIntensity = newProps.blurIntensity >= 0 ? @(newProps.blurIntensity) : nil;
|
|
126
|
+
|
|
127
|
+
// Blur interaction
|
|
128
|
+
_controller.blurInteraction = newProps.blurInteraction;
|
|
129
|
+
|
|
132
130
|
// Corner radius
|
|
133
131
|
_controller.cornerRadius = newProps.cornerRadius < 0 ? nil : @(newProps.cornerRadius);
|
|
134
132
|
|
|
@@ -140,6 +138,7 @@ using namespace facebook::react;
|
|
|
140
138
|
_controller.grabber = newProps.grabber;
|
|
141
139
|
_controller.pageSizing = newProps.pageSizing;
|
|
142
140
|
_controller.modalInPresentation = !newProps.dismissible;
|
|
141
|
+
_controller.draggable = newProps.draggable;
|
|
143
142
|
_controller.dimmed = newProps.dimmed;
|
|
144
143
|
|
|
145
144
|
if (newProps.dimmedDetentIndex >= 0) {
|
|
@@ -195,6 +194,7 @@ using namespace facebook::react;
|
|
|
195
194
|
[self->_controller setupSheetDetents];
|
|
196
195
|
[self->_controller applyActiveDetent];
|
|
197
196
|
}];
|
|
197
|
+
[_controller updateDraggable];
|
|
198
198
|
} else if (_initialDetentIndex >= 0) {
|
|
199
199
|
[self presentAtIndex:_initialDetentIndex animated:_initialDetentAnimated completion:nil];
|
|
200
200
|
}
|
|
@@ -244,7 +244,7 @@ using namespace facebook::react;
|
|
|
244
244
|
_containerView.scrollViewPinningEnabled = _scrollable;
|
|
245
245
|
[_containerView setupContentScrollViewPinning];
|
|
246
246
|
|
|
247
|
-
[
|
|
247
|
+
[TrueSheetLifecycleEvents emitMount:_eventEmitter];
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
|
|
@@ -372,27 +372,33 @@ using namespace facebook::react;
|
|
|
372
372
|
NSInteger index = [_controller currentDetentIndex];
|
|
373
373
|
_controller.activeDetentIndex = index;
|
|
374
374
|
CGFloat detent = [_controller detentValueForIndex:index];
|
|
375
|
-
[
|
|
375
|
+
[TrueSheetLifecycleEvents emitWillPresent:_eventEmitter
|
|
376
|
+
index:index
|
|
377
|
+
position:_controller.currentPosition
|
|
378
|
+
detent:detent];
|
|
376
379
|
}
|
|
377
380
|
|
|
378
381
|
- (void)viewControllerDidPresent {
|
|
379
382
|
NSInteger index = [_controller currentDetentIndex];
|
|
380
383
|
CGFloat detent = [_controller detentValueForIndex:index];
|
|
381
|
-
[
|
|
384
|
+
[TrueSheetLifecycleEvents emitDidPresent:_eventEmitter
|
|
385
|
+
index:index
|
|
386
|
+
position:_controller.currentPosition
|
|
387
|
+
detent:detent];
|
|
382
388
|
}
|
|
383
389
|
|
|
384
390
|
- (void)viewControllerDidDrag:(UIGestureRecognizerState)state index:(NSInteger)index position:(CGFloat)position {
|
|
385
391
|
CGFloat detent = [_controller detentValueForIndex:index];
|
|
386
392
|
switch (state) {
|
|
387
393
|
case UIGestureRecognizerStateBegan:
|
|
388
|
-
[
|
|
394
|
+
[TrueSheetDragEvents emitDragBegin:_eventEmitter index:index position:position detent:detent];
|
|
389
395
|
break;
|
|
390
396
|
case UIGestureRecognizerStateChanged:
|
|
391
|
-
[
|
|
397
|
+
[TrueSheetDragEvents emitDragChange:_eventEmitter index:index position:position detent:detent];
|
|
392
398
|
break;
|
|
393
399
|
case UIGestureRecognizerStateEnded:
|
|
394
400
|
case UIGestureRecognizerStateCancelled:
|
|
395
|
-
[
|
|
401
|
+
[TrueSheetDragEvents emitDragEnd:_eventEmitter index:index position:position detent:detent];
|
|
396
402
|
break;
|
|
397
403
|
default:
|
|
398
404
|
break;
|
|
@@ -400,12 +406,12 @@ using namespace facebook::react;
|
|
|
400
406
|
}
|
|
401
407
|
|
|
402
408
|
- (void)viewControllerWillDismiss {
|
|
403
|
-
[
|
|
409
|
+
[TrueSheetLifecycleEvents emitWillDismiss:_eventEmitter];
|
|
404
410
|
}
|
|
405
411
|
|
|
406
412
|
- (void)viewControllerDidDismiss {
|
|
407
413
|
_controller.activeDetentIndex = -1;
|
|
408
|
-
[
|
|
414
|
+
[TrueSheetLifecycleEvents emitDidDismiss:_eventEmitter];
|
|
409
415
|
}
|
|
410
416
|
|
|
411
417
|
- (void)viewControllerDidChangeDetent:(NSInteger)index position:(CGFloat)position {
|
|
@@ -413,26 +419,34 @@ using namespace facebook::react;
|
|
|
413
419
|
_controller.activeDetentIndex = index;
|
|
414
420
|
}
|
|
415
421
|
CGFloat detent = [_controller detentValueForIndex:index];
|
|
416
|
-
[
|
|
422
|
+
[TrueSheetStateEvents emitDetentChange:_eventEmitter index:index position:position detent:detent];
|
|
417
423
|
}
|
|
418
424
|
|
|
419
425
|
- (void)viewControllerDidChangePosition:(CGFloat)index
|
|
420
426
|
position:(CGFloat)position
|
|
421
427
|
detent:(CGFloat)detent
|
|
422
|
-
|
|
423
|
-
[
|
|
428
|
+
realtime:(BOOL)realtime {
|
|
429
|
+
[TrueSheetStateEvents emitPositionChange:_eventEmitter index:index position:position detent:detent realtime:realtime];
|
|
424
430
|
}
|
|
425
431
|
|
|
426
432
|
- (void)viewControllerDidChangeSize:(CGSize)size {
|
|
427
433
|
[self updateStateWithSize:size];
|
|
428
434
|
}
|
|
429
435
|
|
|
436
|
+
- (void)viewControllerWillFocus {
|
|
437
|
+
[TrueSheetFocusEvents emitWillFocus:_eventEmitter];
|
|
438
|
+
}
|
|
439
|
+
|
|
430
440
|
- (void)viewControllerDidFocus {
|
|
431
|
-
[
|
|
441
|
+
[TrueSheetFocusEvents emitDidFocus:_eventEmitter];
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
- (void)viewControllerWillBlur {
|
|
445
|
+
[TrueSheetFocusEvents emitWillBlur:_eventEmitter];
|
|
432
446
|
}
|
|
433
447
|
|
|
434
448
|
- (void)viewControllerDidBlur {
|
|
435
|
-
[
|
|
449
|
+
[TrueSheetFocusEvents emitDidBlur:_eventEmitter];
|
|
436
450
|
}
|
|
437
451
|
|
|
438
452
|
#pragma mark - Private Helpers
|
|
@@ -28,9 +28,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
28
28
|
- (void)viewControllerDidChangePosition:(CGFloat)index
|
|
29
29
|
position:(CGFloat)position
|
|
30
30
|
detent:(CGFloat)detent
|
|
31
|
-
|
|
31
|
+
realtime:(BOOL)realtime;
|
|
32
32
|
- (void)viewControllerDidChangeSize:(CGSize)size;
|
|
33
|
+
- (void)viewControllerWillFocus;
|
|
33
34
|
- (void)viewControllerDidFocus;
|
|
35
|
+
- (void)viewControllerWillBlur;
|
|
34
36
|
- (void)viewControllerDidBlur;
|
|
35
37
|
|
|
36
38
|
@end
|
|
@@ -50,9 +52,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
50
52
|
@property (nonatomic, strong, nullable) UIColor *backgroundColor;
|
|
51
53
|
@property (nonatomic, strong, nullable) NSNumber *cornerRadius;
|
|
52
54
|
@property (nonatomic, assign) BOOL grabber;
|
|
55
|
+
@property (nonatomic, assign) BOOL draggable;
|
|
53
56
|
@property (nonatomic, assign) BOOL dimmed;
|
|
54
57
|
@property (nonatomic, strong, nullable) NSNumber *dimmedDetentIndex;
|
|
55
58
|
@property (nonatomic, copy, nullable) NSString *blurTint;
|
|
59
|
+
@property (nonatomic, strong, nullable) NSNumber *blurIntensity;
|
|
60
|
+
@property (nonatomic, assign) BOOL blurInteraction;
|
|
56
61
|
@property (nonatomic, assign) BOOL pageSizing;
|
|
57
62
|
@property (nonatomic, assign) BOOL layoutTransitioning;
|
|
58
63
|
@property (nonatomic, assign) BOOL isPresented;
|
|
@@ -62,6 +67,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
62
67
|
- (void)setupActiveDetentWithIndex:(NSInteger)index;
|
|
63
68
|
- (void)setupSheetDetents;
|
|
64
69
|
- (void)setupSheetProps;
|
|
70
|
+
- (void)updateDraggable;
|
|
65
71
|
- (NSInteger)currentDetentIndex;
|
|
66
72
|
- (CGFloat)currentPosition;
|
|
67
73
|
- (CGFloat)bottomInset;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
#import "TrueSheetViewController.h"
|
|
10
10
|
#import "TrueSheetContentView.h"
|
|
11
|
-
#import "
|
|
11
|
+
#import "core/TrueSheetBlurView.h"
|
|
12
12
|
#import "utils/GestureUtil.h"
|
|
13
13
|
#import "utils/WindowUtil.h"
|
|
14
14
|
|
|
@@ -21,10 +21,8 @@
|
|
|
21
21
|
|
|
22
22
|
@implementation TrueSheetViewController {
|
|
23
23
|
CGFloat _lastPosition;
|
|
24
|
-
CGFloat _lastTransitionPosition;
|
|
25
24
|
BOOL _isTransitioning;
|
|
26
25
|
BOOL _isDragging;
|
|
27
|
-
BOOL _isTrackingPositionFromLayout;
|
|
28
26
|
|
|
29
27
|
// Hidden view used to track position during native transition animations
|
|
30
28
|
UIView *_fakeTransitionView;
|
|
@@ -32,6 +30,9 @@
|
|
|
32
30
|
|
|
33
31
|
// Reference to parent TrueSheetViewController (if presented from another sheet)
|
|
34
32
|
__weak TrueSheetViewController *_parentSheetController;
|
|
33
|
+
|
|
34
|
+
// Blur effect view
|
|
35
|
+
TrueSheetBlurView *_blurView;
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
#pragma mark - Initialization
|
|
@@ -42,14 +43,13 @@
|
|
|
42
43
|
_contentHeight = @(0);
|
|
43
44
|
_headerHeight = @(0);
|
|
44
45
|
_grabber = YES;
|
|
46
|
+
_draggable = YES;
|
|
45
47
|
_dimmed = YES;
|
|
46
48
|
_dimmedDetentIndex = @(0);
|
|
47
49
|
_pageSizing = YES;
|
|
48
50
|
_lastPosition = 0;
|
|
49
|
-
_lastTransitionPosition = 0;
|
|
50
51
|
_isTransitioning = NO;
|
|
51
52
|
_isDragging = NO;
|
|
52
|
-
_isTrackingPositionFromLayout = NO;
|
|
53
53
|
_layoutTransitioning = NO;
|
|
54
54
|
_isPresented = NO;
|
|
55
55
|
_activeDetentIndex = -1;
|
|
@@ -57,6 +57,8 @@
|
|
|
57
57
|
_fakeTransitionView = [[UIView alloc] init];
|
|
58
58
|
_fakeTransitionView.hidden = YES;
|
|
59
59
|
_fakeTransitionView.userInteractionEnabled = NO;
|
|
60
|
+
|
|
61
|
+
_blurInteraction = YES;
|
|
60
62
|
}
|
|
61
63
|
return self;
|
|
62
64
|
}
|
|
@@ -148,9 +150,9 @@
|
|
|
148
150
|
UIViewController *presenter = self.presentingViewController;
|
|
149
151
|
if ([presenter isKindOfClass:[TrueSheetViewController class]]) {
|
|
150
152
|
_parentSheetController = (TrueSheetViewController *)presenter;
|
|
151
|
-
// Notify parent that it
|
|
152
|
-
if ([_parentSheetController.delegate respondsToSelector:@selector(
|
|
153
|
-
[_parentSheetController.delegate
|
|
153
|
+
// Notify parent that it is about to lose focus
|
|
154
|
+
if ([_parentSheetController.delegate respondsToSelector:@selector(viewControllerWillBlur)]) {
|
|
155
|
+
[_parentSheetController.delegate viewControllerWillBlur];
|
|
154
156
|
}
|
|
155
157
|
}
|
|
156
158
|
|
|
@@ -165,6 +167,13 @@
|
|
|
165
167
|
[super viewDidAppear:animated];
|
|
166
168
|
|
|
167
169
|
if (!_isPresented) {
|
|
170
|
+
// Notify parent that it has lost focus (after the child sheet appeared)
|
|
171
|
+
if (_parentSheetController) {
|
|
172
|
+
if ([_parentSheetController.delegate respondsToSelector:@selector(viewControllerDidBlur)]) {
|
|
173
|
+
[_parentSheetController.delegate viewControllerDidBlur];
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
168
177
|
if ([self.delegate respondsToSelector:@selector(viewControllerDidPresent)]) {
|
|
169
178
|
[self.delegate viewControllerDidPresent];
|
|
170
179
|
}
|
|
@@ -176,12 +185,22 @@
|
|
|
176
185
|
- (void)viewWillDisappear:(BOOL)animated {
|
|
177
186
|
[super viewWillDisappear:animated];
|
|
178
187
|
|
|
179
|
-
|
|
180
|
-
|
|
188
|
+
BOOL isActuallyDismissing = self.presentingViewController == nil || self.isBeingDismissed;
|
|
189
|
+
|
|
190
|
+
if (isActuallyDismissing) {
|
|
191
|
+
// Notify the parent sheet (if any) that it is about to regain focus
|
|
192
|
+
if (_parentSheetController) {
|
|
193
|
+
if ([_parentSheetController.delegate respondsToSelector:@selector(viewControllerWillFocus)]) {
|
|
194
|
+
[_parentSheetController.delegate viewControllerWillFocus];
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if ([self.delegate respondsToSelector:@selector(viewControllerWillDismiss)]) {
|
|
199
|
+
[self.delegate viewControllerWillDismiss];
|
|
200
|
+
}
|
|
181
201
|
}
|
|
182
202
|
|
|
183
203
|
[self setupTransitionPositionTracking];
|
|
184
|
-
_isTrackingPositionFromLayout = NO;
|
|
185
204
|
}
|
|
186
205
|
|
|
187
206
|
- (void)viewDidDisappear:(BOOL)animated {
|
|
@@ -204,8 +223,6 @@
|
|
|
204
223
|
}
|
|
205
224
|
}
|
|
206
225
|
|
|
207
|
-
_isTrackingPositionFromLayout = NO;
|
|
208
|
-
|
|
209
226
|
if (isActuallyDismissing) {
|
|
210
227
|
_isPresented = NO;
|
|
211
228
|
_activeDetentIndex = -1;
|
|
@@ -219,12 +236,9 @@
|
|
|
219
236
|
[self.delegate viewControllerDidChangeSize:self.view.frame.size];
|
|
220
237
|
}
|
|
221
238
|
|
|
222
|
-
if (!_isTransitioning && self.isActiveAndVisible) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
// Treat position changes as transitioning when another controller is presented on top
|
|
226
|
-
[self emitChangePositionDelegateWithPosition:self.currentPosition
|
|
227
|
-
transitioning:_layoutTransitioning || !self.isTopmostPresentedController];
|
|
239
|
+
if (!_isTransitioning && !_isDragging && self.isActiveAndVisible) {
|
|
240
|
+
// Not realtime when layout changes (e.g., another controller is presented on top)
|
|
241
|
+
[self emitChangePositionDelegateWithPosition:self.currentPosition realtime:NO];
|
|
228
242
|
|
|
229
243
|
// On iOS 26, this is called twice when we have a ScrollView
|
|
230
244
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
@@ -255,6 +269,21 @@
|
|
|
255
269
|
if (!presentedView)
|
|
256
270
|
return;
|
|
257
271
|
|
|
272
|
+
// Disable pan gestures if draggable is NO
|
|
273
|
+
if (!self.draggable) {
|
|
274
|
+
[GestureUtil setPanGesturesEnabled:NO forView:presentedView];
|
|
275
|
+
|
|
276
|
+
// Also disable ScrollView's pan gesture if present
|
|
277
|
+
TrueSheetContentView *contentView = [self findContentView:presentedView];
|
|
278
|
+
if (contentView) {
|
|
279
|
+
RCTScrollViewComponentView *scrollViewComponent = [contentView findScrollView:nil];
|
|
280
|
+
if (scrollViewComponent && scrollViewComponent.scrollView) {
|
|
281
|
+
[GestureUtil setPanGesturesEnabled:NO forView:scrollViewComponent.scrollView];
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
258
287
|
// Attach to presented view's pan gesture (sheet's drag gesture from UIKit)
|
|
259
288
|
[GestureUtil attachPanGestureHandler:presentedView target:self selector:@selector(handlePanGesture:)];
|
|
260
289
|
|
|
@@ -270,6 +299,23 @@
|
|
|
270
299
|
}
|
|
271
300
|
}
|
|
272
301
|
|
|
302
|
+
- (void)updateDraggable {
|
|
303
|
+
UIView *presentedView = self.presentedView;
|
|
304
|
+
if (!presentedView)
|
|
305
|
+
return;
|
|
306
|
+
|
|
307
|
+
[GestureUtil setPanGesturesEnabled:self.draggable forView:presentedView];
|
|
308
|
+
|
|
309
|
+
// Also update ScrollView's pan gesture if present
|
|
310
|
+
TrueSheetContentView *contentView = [self findContentView:presentedView];
|
|
311
|
+
if (contentView) {
|
|
312
|
+
RCTScrollViewComponentView *scrollViewComponent = [contentView findScrollView:nil];
|
|
313
|
+
if (scrollViewComponent && scrollViewComponent.scrollView) {
|
|
314
|
+
[GestureUtil setPanGesturesEnabled:self.draggable forView:scrollViewComponent.scrollView];
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
273
319
|
- (void)handlePanGesture:(UIPanGestureRecognizer *)gesture {
|
|
274
320
|
NSInteger index = [self currentDetentIndex];
|
|
275
321
|
|
|
@@ -282,14 +328,16 @@
|
|
|
282
328
|
_isDragging = YES;
|
|
283
329
|
break;
|
|
284
330
|
case UIGestureRecognizerStateChanged:
|
|
285
|
-
|
|
286
|
-
[self emitChangePositionDelegateWithPosition:self.currentPosition transitioning:NO];
|
|
287
|
-
}
|
|
331
|
+
[self emitChangePositionDelegateWithPosition:self.currentPosition realtime:YES];
|
|
288
332
|
break;
|
|
289
333
|
case UIGestureRecognizerStateEnded:
|
|
290
|
-
case UIGestureRecognizerStateCancelled:
|
|
291
|
-
|
|
334
|
+
case UIGestureRecognizerStateCancelled: {
|
|
335
|
+
[self emitChangePositionDelegateWithPosition:self.currentPosition realtime:NO];
|
|
336
|
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
337
|
+
self->_isDragging = NO;
|
|
338
|
+
});
|
|
292
339
|
break;
|
|
340
|
+
}
|
|
293
341
|
default:
|
|
294
342
|
break;
|
|
295
343
|
}
|
|
@@ -297,15 +345,16 @@
|
|
|
297
345
|
|
|
298
346
|
#pragma mark - Position Tracking
|
|
299
347
|
|
|
300
|
-
- (void)emitChangePositionDelegateWithPosition:(CGFloat)position
|
|
301
|
-
|
|
348
|
+
- (void)emitChangePositionDelegateWithPosition:(CGFloat)position realtime:(BOOL)realtime {
|
|
349
|
+
// Use epsilon comparison to avoid missing updates due to floating point precision
|
|
350
|
+
if (fabs(_lastPosition - position) > 0.01) {
|
|
302
351
|
_lastPosition = position;
|
|
303
352
|
|
|
304
353
|
CGFloat index = [self interpolatedIndexForPosition:position];
|
|
305
354
|
NSInteger discreteIndex = (NSInteger)round(index);
|
|
306
355
|
CGFloat detent = [self detentValueForIndex:discreteIndex];
|
|
307
|
-
if ([self.delegate respondsToSelector:@selector(viewControllerDidChangePosition:position:detent:
|
|
308
|
-
[self.delegate viewControllerDidChangePosition:index position:position detent:detent
|
|
356
|
+
if ([self.delegate respondsToSelector:@selector(viewControllerDidChangePosition:position:detent:realtime:)]) {
|
|
357
|
+
[self.delegate viewControllerDidChangePosition:index position:position detent:detent realtime:realtime];
|
|
309
358
|
}
|
|
310
359
|
}
|
|
311
360
|
}
|
|
@@ -395,8 +444,6 @@
|
|
|
395
444
|
finalFrame.origin.y = presentedView.frame.origin.y;
|
|
396
445
|
self->_fakeTransitionView.frame = finalFrame;
|
|
397
446
|
|
|
398
|
-
self->_lastTransitionPosition = finalFrame.origin.y;
|
|
399
|
-
|
|
400
447
|
// Track position at screen refresh rate via display link
|
|
401
448
|
self->_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(trackTransitionPosition:)];
|
|
402
449
|
[self->_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
|
@@ -422,18 +469,12 @@
|
|
|
422
469
|
CALayer *presentationLayer = _fakeTransitionView.layer.presentationLayer;
|
|
423
470
|
|
|
424
471
|
if (presentationLayer) {
|
|
425
|
-
|
|
426
|
-
CGFloat
|
|
472
|
+
CGFloat transitioningPosition = presentationLayer.frame.origin.y;
|
|
473
|
+
CGFloat staticPosition = _fakeTransitionView.frame.origin.y;
|
|
427
474
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
transitioning = YES;
|
|
431
|
-
position = presentedView.frame.origin.y;
|
|
432
|
-
} else {
|
|
433
|
-
_lastTransitionPosition = position;
|
|
475
|
+
if (fabs(staticPosition - transitioningPosition) > 0.01) {
|
|
476
|
+
[self emitChangePositionDelegateWithPosition:transitioningPosition realtime:YES];
|
|
434
477
|
}
|
|
435
|
-
|
|
436
|
-
[self emitChangePositionDelegateWithPosition:position transitioning:transitioning];
|
|
437
478
|
}
|
|
438
479
|
}
|
|
439
480
|
|
|
@@ -447,7 +488,7 @@
|
|
|
447
488
|
NSMutableArray<UISheetPresentationControllerDetent *> *detents = [NSMutableArray array];
|
|
448
489
|
|
|
449
490
|
// Subtract bottomInset to prevent iOS from adding extra bottom insets
|
|
450
|
-
CGFloat autoHeight = [self.contentHeight floatValue] + [self.headerHeight floatValue]
|
|
491
|
+
CGFloat autoHeight = [self.contentHeight floatValue] + [self.headerHeight floatValue];
|
|
451
492
|
|
|
452
493
|
for (NSInteger index = 0; index < self.detents.count; index++) {
|
|
453
494
|
id detent = self.detents[index];
|
|
@@ -597,7 +638,7 @@
|
|
|
597
638
|
}
|
|
598
639
|
|
|
599
640
|
sheet.prefersEdgeAttachedInCompactHeight = YES;
|
|
600
|
-
sheet.prefersGrabberVisible = self.grabber;
|
|
641
|
+
sheet.prefersGrabberVisible = self.grabber && self.draggable;
|
|
601
642
|
|
|
602
643
|
if (self.cornerRadius) {
|
|
603
644
|
sheet.preferredCornerRadius = [self.cornerRadius floatValue];
|
|
@@ -609,16 +650,25 @@
|
|
|
609
650
|
|
|
610
651
|
// Setup or remove blur effect
|
|
611
652
|
if (self.blurTint && self.blurTint.length > 0) {
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
653
|
+
// Create blur view if needed
|
|
654
|
+
if (!_blurView) {
|
|
655
|
+
_blurView = [[TrueSheetBlurView alloc] init];
|
|
656
|
+
_blurView.frame = self.view.bounds;
|
|
657
|
+
_blurView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
658
|
+
[self.view insertSubview:_blurView atIndex:0];
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// Update blur properties and apply effect
|
|
662
|
+
_blurView.blurTint = self.blurTint;
|
|
663
|
+
_blurView.blurIntensity = self.blurIntensity;
|
|
664
|
+
_blurView.blurInteraction = self.blurInteraction;
|
|
665
|
+
[_blurView applyBlurEffect];
|
|
617
666
|
} else {
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
667
|
+
// Remove blur effect
|
|
668
|
+
if (_blurView) {
|
|
669
|
+
[_blurView removeBlurEffect];
|
|
670
|
+
[_blurView removeFromSuperview];
|
|
671
|
+
_blurView = nil;
|
|
622
672
|
}
|
|
623
673
|
}
|
|
624
674
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Created by Jovanni Lo (@lodev09)
|
|
3
|
+
// Copyright (c) 2024-present. All rights reserved.
|
|
4
|
+
//
|
|
5
|
+
// This source code is licensed under the MIT license found in the
|
|
6
|
+
// LICENSE file in the root directory of this source tree.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
#import <UIKit/UIKit.h>
|
|
10
|
+
|
|
11
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
12
|
+
|
|
13
|
+
@interface TrueSheetBlurView : UIVisualEffectView
|
|
14
|
+
|
|
15
|
+
@property (nonatomic, copy, nullable) NSString *blurTint;
|
|
16
|
+
@property (nonatomic, strong, nullable) NSNumber *blurIntensity;
|
|
17
|
+
@property (nonatomic, assign) BOOL blurInteraction;
|
|
18
|
+
|
|
19
|
+
- (void)applyBlurEffect;
|
|
20
|
+
- (void)removeBlurEffect;
|
|
21
|
+
|
|
22
|
+
@end
|
|
23
|
+
|
|
24
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -6,9 +6,13 @@
|
|
|
6
6
|
// LICENSE file in the root directory of this source tree.
|
|
7
7
|
//
|
|
8
8
|
|
|
9
|
-
#import "
|
|
9
|
+
#import "TrueSheetBlurView.h"
|
|
10
10
|
|
|
11
|
-
@implementation
|
|
11
|
+
@implementation TrueSheetBlurView {
|
|
12
|
+
UIViewPropertyAnimator *_blurAnimator;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
#pragma mark - Private
|
|
12
16
|
|
|
13
17
|
+ (UIBlurEffectStyle)blurEffectStyleFromString:(NSString *)tintString {
|
|
14
18
|
static NSDictionary<NSString *, NSNumber *> *styleMap = nil;
|
|
@@ -43,8 +47,66 @@
|
|
|
43
47
|
return (UIBlurEffectStyle)[style integerValue];
|
|
44
48
|
}
|
|
45
49
|
|
|
46
|
-
// Default to light if not recognized
|
|
47
50
|
return UIBlurEffectStyleLight;
|
|
48
51
|
}
|
|
49
52
|
|
|
53
|
+
#pragma mark - Initialization
|
|
54
|
+
|
|
55
|
+
- (instancetype)init {
|
|
56
|
+
if (self = [super init]) {
|
|
57
|
+
_blurInteraction = YES;
|
|
58
|
+
}
|
|
59
|
+
return self;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
#pragma mark - Public
|
|
63
|
+
|
|
64
|
+
- (void)applyBlurEffect {
|
|
65
|
+
if (!self.blurTint || self.blurTint.length == 0) {
|
|
66
|
+
[self removeBlurEffect];
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Stop and clear existing animator
|
|
71
|
+
if (_blurAnimator) {
|
|
72
|
+
[_blurAnimator stopAnimation:YES];
|
|
73
|
+
_blurAnimator = nil;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Clear existing effect
|
|
77
|
+
self.effect = nil;
|
|
78
|
+
|
|
79
|
+
UIBlurEffectStyle style = [TrueSheetBlurView blurEffectStyleFromString:self.blurTint];
|
|
80
|
+
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:style];
|
|
81
|
+
|
|
82
|
+
self.userInteractionEnabled = self.blurInteraction;
|
|
83
|
+
|
|
84
|
+
// Use animator to control blur intensity
|
|
85
|
+
__weak typeof(self) weakSelf = self;
|
|
86
|
+
_blurAnimator = [[UIViewPropertyAnimator alloc] initWithDuration:1.0
|
|
87
|
+
curve:UIViewAnimationCurveLinear
|
|
88
|
+
animations:^{
|
|
89
|
+
weakSelf.effect = blurEffect;
|
|
90
|
+
}];
|
|
91
|
+
_blurAnimator.pausesOnCompletion = YES;
|
|
92
|
+
|
|
93
|
+
// Set intensity: nil means system default (100%), otherwise use provided value (0-100)
|
|
94
|
+
CGFloat intensity =
|
|
95
|
+
(self.blurIntensity && [self.blurIntensity floatValue] >= 0) ? [self.blurIntensity floatValue] / 100.0 : 1.0;
|
|
96
|
+
_blurAnimator.fractionComplete = intensity;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
- (void)removeBlurEffect {
|
|
100
|
+
if (_blurAnimator) {
|
|
101
|
+
[_blurAnimator stopAnimation:YES];
|
|
102
|
+
_blurAnimator = nil;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
self.effect = nil;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
- (void)dealloc {
|
|
109
|
+
[self removeBlurEffect];
|
|
110
|
+
}
|
|
111
|
+
|
|
50
112
|
@end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Created by Jovanni Lo (@lodev09)
|
|
3
|
+
// Copyright (c) 2024-present. All rights reserved.
|
|
4
|
+
//
|
|
5
|
+
// This source code is licensed under the MIT license found in the
|
|
6
|
+
// LICENSE file in the root directory of this source tree.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
10
|
+
|
|
11
|
+
#import <Foundation/Foundation.h>
|
|
12
|
+
#import <react/renderer/components/TrueSheetSpec/EventEmitters.h>
|
|
13
|
+
|
|
14
|
+
using namespace facebook::react;
|
|
15
|
+
|
|
16
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
17
|
+
|
|
18
|
+
@interface TrueSheetDragEvents : NSObject
|
|
19
|
+
|
|
20
|
+
+ (void)emitDragBegin:(std::shared_ptr<const facebook::react::EventEmitter>)eventEmitter
|
|
21
|
+
index:(NSInteger)index
|
|
22
|
+
position:(CGFloat)position
|
|
23
|
+
detent:(CGFloat)detent;
|
|
24
|
+
|
|
25
|
+
+ (void)emitDragChange:(std::shared_ptr<const facebook::react::EventEmitter>)eventEmitter
|
|
26
|
+
index:(NSInteger)index
|
|
27
|
+
position:(CGFloat)position
|
|
28
|
+
detent:(CGFloat)detent;
|
|
29
|
+
|
|
30
|
+
+ (void)emitDragEnd:(std::shared_ptr<const facebook::react::EventEmitter>)eventEmitter
|
|
31
|
+
index:(NSInteger)index
|
|
32
|
+
position:(CGFloat)position
|
|
33
|
+
detent:(CGFloat)detent;
|
|
34
|
+
|
|
35
|
+
@end
|
|
36
|
+
|
|
37
|
+
NS_ASSUME_NONNULL_END
|
|
38
|
+
|
|
39
|
+
#endif // RCT_NEW_ARCH_ENABLED
|