@lodev09/react-native-true-sheet 2.0.6 → 4.0.0-beta.0
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 +36 -8
- package/RNTrueSheet.podspec +20 -0
- package/android/build.gradle +26 -14
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +108 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerViewManager.kt +21 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +46 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentViewManager.kt +21 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterView.kt +47 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterViewManager.kt +21 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetModule.kt +165 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetPackage.kt +36 -4
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +257 -303
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +855 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +104 -82
- package/android/src/main/java/com/lodev09/truesheet/events/DetentChangeEvent.kt +26 -0
- package/android/src/main/java/com/lodev09/truesheet/events/DidDismissEvent.kt +20 -0
- package/android/src/main/java/com/lodev09/truesheet/events/DidPresentEvent.kt +26 -0
- package/android/src/main/java/com/lodev09/truesheet/events/DragBeginEvent.kt +26 -0
- package/android/src/main/java/com/lodev09/truesheet/events/DragChangeEvent.kt +26 -0
- package/android/src/main/java/com/lodev09/truesheet/events/DragEndEvent.kt +26 -0
- package/android/src/main/java/com/lodev09/truesheet/events/MountEvent.kt +20 -0
- package/android/src/main/java/com/lodev09/truesheet/events/PositionChangeEvent.kt +32 -0
- package/android/src/main/java/com/lodev09/truesheet/events/SizeChangeEvent.kt +27 -0
- package/android/src/main/java/com/lodev09/truesheet/events/WillDismissEvent.kt +20 -0
- package/android/src/main/java/com/lodev09/truesheet/events/WillPresentEvent.kt +26 -0
- package/android/src/main/java/com/lodev09/truesheet/{core/Utils.kt → utils/ScreenUtils.kt} +47 -17
- package/android/src/main/res/values/styles.xml +8 -0
- package/ios/TrueSheetComponentDescriptor.h +24 -0
- package/ios/TrueSheetContainerView.h +47 -0
- package/ios/TrueSheetContainerView.mm +117 -0
- package/ios/TrueSheetContentView.h +37 -0
- package/ios/TrueSheetContentView.mm +114 -0
- package/ios/TrueSheetFooterView.h +27 -0
- package/ios/TrueSheetFooterView.mm +101 -0
- package/ios/TrueSheetModule.h +44 -0
- package/ios/TrueSheetModule.mm +133 -0
- package/ios/TrueSheetView.h +53 -0
- package/ios/TrueSheetView.mm +433 -0
- package/ios/TrueSheetViewController.h +53 -0
- package/ios/TrueSheetViewController.mm +649 -0
- package/ios/events/OnDetentChangeEvent.h +28 -0
- package/ios/events/OnDetentChangeEvent.mm +30 -0
- package/ios/events/OnDidDismissEvent.h +26 -0
- package/ios/events/OnDidDismissEvent.mm +25 -0
- package/ios/events/OnDidPresentEvent.h +28 -0
- package/ios/events/OnDidPresentEvent.mm +30 -0
- package/ios/events/OnDragBeginEvent.h +28 -0
- package/ios/events/OnDragBeginEvent.mm +30 -0
- package/ios/events/OnDragChangeEvent.h +28 -0
- package/ios/events/OnDragChangeEvent.mm +30 -0
- package/ios/events/OnDragEndEvent.h +28 -0
- package/ios/events/OnDragEndEvent.mm +30 -0
- package/ios/events/OnMountEvent.h +26 -0
- package/ios/events/OnMountEvent.mm +25 -0
- package/ios/events/OnPositionChangeEvent.h +29 -0
- package/ios/events/OnPositionChangeEvent.mm +32 -0
- package/ios/events/OnSizeChangeEvent.h +28 -0
- package/ios/events/OnSizeChangeEvent.mm +30 -0
- package/ios/events/OnWillDismissEvent.h +26 -0
- package/ios/events/OnWillDismissEvent.mm +25 -0
- package/ios/events/OnWillPresentEvent.h +28 -0
- package/ios/events/OnWillPresentEvent.mm +30 -0
- package/ios/utils/GestureUtil.h +25 -0
- package/ios/utils/GestureUtil.mm +26 -0
- package/ios/utils/LayoutUtil.h +44 -0
- package/ios/utils/LayoutUtil.mm +50 -0
- package/ios/utils/WindowUtil.h +27 -0
- package/ios/utils/WindowUtil.mm +42 -0
- package/lib/module/TrueSheet.js +231 -135
- package/lib/module/TrueSheet.js.map +1 -1
- package/lib/module/TrueSheetGrabber.js +16 -14
- package/lib/module/TrueSheetGrabber.js.map +1 -1
- package/lib/module/fabric/TrueSheetContainerViewNativeComponent.ts +8 -0
- package/lib/module/fabric/TrueSheetContentViewNativeComponent.ts +8 -0
- package/lib/module/fabric/TrueSheetFooterViewNativeComponent.ts +8 -0
- package/lib/module/fabric/TrueSheetViewNativeComponent.ts +63 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/reanimated/ReanimatedTrueSheet.js +87 -0
- package/lib/module/reanimated/ReanimatedTrueSheet.js.map +1 -0
- package/lib/module/reanimated/ReanimatedTrueSheetProvider.js +72 -0
- package/lib/module/reanimated/ReanimatedTrueSheetProvider.js.map +1 -0
- package/lib/module/reanimated/index.js +6 -0
- package/lib/module/reanimated/index.js.map +1 -0
- package/lib/module/reanimated/useReanimatedPositionChangeHandler.js +19 -0
- package/lib/module/reanimated/useReanimatedPositionChangeHandler.js.map +1 -0
- package/lib/module/specs/NativeTrueSheetModule.js +12 -0
- package/lib/module/specs/NativeTrueSheetModule.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/TrueSheet.d.ts +79 -0
- package/lib/typescript/src/TrueSheet.d.ts.map +1 -0
- package/lib/typescript/src/TrueSheet.types.d.ts +260 -0
- package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -0
- package/lib/typescript/{commonjs/src → src}/TrueSheetGrabber.d.ts +1 -1
- package/lib/typescript/src/TrueSheetGrabber.d.ts.map +1 -0
- package/lib/typescript/src/fabric/TrueSheetContainerViewNativeComponent.d.ts +6 -0
- package/lib/typescript/src/fabric/TrueSheetContainerViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/fabric/TrueSheetContentViewNativeComponent.d.ts +6 -0
- package/lib/typescript/src/fabric/TrueSheetContentViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts +6 -0
- package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +44 -0
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/{commonjs/src → src}/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/reanimated/ReanimatedTrueSheet.d.ts +43 -0
- package/lib/typescript/src/reanimated/ReanimatedTrueSheet.d.ts.map +1 -0
- package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts +57 -0
- package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts.map +1 -0
- package/lib/typescript/src/reanimated/index.d.ts +4 -0
- package/lib/typescript/src/reanimated/index.d.ts.map +1 -0
- package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.d.ts +6 -0
- package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.d.ts.map +1 -0
- package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts +34 -0
- package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts.map +1 -0
- package/package.json +104 -75
- package/react-native.config.js +17 -0
- package/src/TrueSheet.tsx +285 -188
- package/src/TrueSheet.types.ts +119 -106
- package/src/TrueSheetGrabber.tsx +29 -28
- package/src/__mocks__/index.js +60 -12
- package/src/fabric/TrueSheetContainerViewNativeComponent.ts +8 -0
- package/src/fabric/TrueSheetContentViewNativeComponent.ts +8 -0
- package/src/fabric/TrueSheetFooterViewNativeComponent.ts +8 -0
- package/src/fabric/TrueSheetViewNativeComponent.ts +63 -0
- package/src/index.ts +4 -3
- package/src/reanimated/ReanimatedTrueSheet.tsx +95 -0
- package/src/reanimated/ReanimatedTrueSheetProvider.tsx +92 -0
- package/src/reanimated/index.ts +3 -0
- package/src/reanimated/useReanimatedPositionChangeHandler.ts +26 -0
- package/src/specs/NativeTrueSheetModule.ts +38 -0
- package/TrueSheet.podspec +0 -49
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetDialog.kt +0 -413
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetEvent.kt +0 -22
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewModule.kt +0 -63
- package/android/src/main/java/com/lodev09/truesheet/core/KeyboardManager.kt +0 -58
- package/android/src/main/java/com/lodev09/truesheet/core/RootSheetView.kt +0 -102
- package/ios/Extensions/UIBlurEffect+withTint.swift +0 -62
- package/ios/Extensions/UIView+pinTo.swift +0 -74
- package/ios/Extensions/UIViewController+detentForSize.swift +0 -134
- package/ios/TrueSheet-Bridging-Header.h +0 -14
- package/ios/TrueSheetEvent.swift +0 -48
- package/ios/TrueSheetView.swift +0 -467
- package/ios/TrueSheetViewController.swift +0 -275
- package/ios/TrueSheetViewManager.m +0 -53
- package/ios/TrueSheetViewManager.swift +0 -48
- package/ios/Utils/Logger.swift +0 -39
- package/ios/Utils/Promise.swift +0 -25
- package/lib/commonjs/TrueSheet.js +0 -258
- package/lib/commonjs/TrueSheet.js.map +0 -1
- package/lib/commonjs/TrueSheet.types.js +0 -6
- package/lib/commonjs/TrueSheet.types.js.map +0 -1
- package/lib/commonjs/TrueSheetFooter.js +0 -19
- package/lib/commonjs/TrueSheetFooter.js.map +0 -1
- package/lib/commonjs/TrueSheetGrabber.js +0 -54
- package/lib/commonjs/TrueSheetGrabber.js.map +0 -1
- package/lib/commonjs/TrueSheetModule.js +0 -19
- package/lib/commonjs/TrueSheetModule.js.map +0 -1
- package/lib/commonjs/__mocks__/index.js +0 -52
- package/lib/commonjs/__mocks__/index.js.map +0 -1
- package/lib/commonjs/index.js +0 -39
- package/lib/commonjs/index.js.map +0 -1
- package/lib/module/TrueSheetFooter.js +0 -14
- package/lib/module/TrueSheetFooter.js.map +0 -1
- package/lib/module/TrueSheetModule.js +0 -15
- package/lib/module/TrueSheetModule.js.map +0 -1
- package/lib/module/__mocks__/index.js +0 -21
- package/lib/module/__mocks__/index.js.map +0 -1
- package/lib/typescript/commonjs/package.json +0 -1
- package/lib/typescript/commonjs/src/TrueSheet.d.ts +0 -70
- package/lib/typescript/commonjs/src/TrueSheet.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/TrueSheet.types.d.ts +0 -241
- package/lib/typescript/commonjs/src/TrueSheet.types.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/TrueSheetFooter.d.ts +0 -7
- package/lib/typescript/commonjs/src/TrueSheetFooter.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/TrueSheetGrabber.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/TrueSheetModule.d.ts +0 -2
- package/lib/typescript/commonjs/src/TrueSheetModule.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/index.d.ts.map +0 -1
- package/lib/typescript/module/src/TrueSheet.d.ts +0 -70
- package/lib/typescript/module/src/TrueSheet.d.ts.map +0 -1
- package/lib/typescript/module/src/TrueSheet.types.d.ts +0 -241
- package/lib/typescript/module/src/TrueSheet.types.d.ts.map +0 -1
- package/lib/typescript/module/src/TrueSheetFooter.d.ts +0 -7
- package/lib/typescript/module/src/TrueSheetFooter.d.ts.map +0 -1
- package/lib/typescript/module/src/TrueSheetGrabber.d.ts +0 -39
- package/lib/typescript/module/src/TrueSheetGrabber.d.ts.map +0 -1
- package/lib/typescript/module/src/TrueSheetModule.d.ts +0 -2
- package/lib/typescript/module/src/TrueSheetModule.d.ts.map +0 -1
- package/lib/typescript/module/src/index.d.ts +0 -4
- package/lib/typescript/module/src/index.d.ts.map +0 -1
- package/src/TrueSheetFooter.tsx +0 -17
- package/src/TrueSheetModule.ts +0 -19
- /package/lib/{typescript/module → module}/package.json +0 -0
|
@@ -0,0 +1,649 @@
|
|
|
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 "TrueSheetViewController.h"
|
|
10
|
+
#import "utils/WindowUtil.h"
|
|
11
|
+
|
|
12
|
+
#import <React/RCTLog.h>
|
|
13
|
+
#import <React/RCTScrollViewComponentView.h>
|
|
14
|
+
#import "TrueSheetContentView.h"
|
|
15
|
+
#import "utils/GestureUtil.h"
|
|
16
|
+
|
|
17
|
+
@interface TrueSheetViewController ()
|
|
18
|
+
|
|
19
|
+
@end
|
|
20
|
+
|
|
21
|
+
@implementation TrueSheetViewController {
|
|
22
|
+
CGFloat _lastPosition;
|
|
23
|
+
CGFloat _lastTransitionPosition;
|
|
24
|
+
UIVisualEffectView *_backgroundView;
|
|
25
|
+
CGFloat _bottomInset;
|
|
26
|
+
BOOL _isTransitioning;
|
|
27
|
+
BOOL _isDragging;
|
|
28
|
+
BOOL _isTrackingPositionFromLayout;
|
|
29
|
+
UIView *_fakeTransitionView;
|
|
30
|
+
CADisplayLink *_displayLink;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
- (instancetype)init {
|
|
34
|
+
if (self = [super initWithNibName:nil bundle:nil]) {
|
|
35
|
+
_detents = @[ @0.5, @1 ];
|
|
36
|
+
_contentHeight = @(0);
|
|
37
|
+
_grabber = YES;
|
|
38
|
+
_dimmed = YES;
|
|
39
|
+
_dimmedIndex = @(0);
|
|
40
|
+
_lastPosition = 0;
|
|
41
|
+
_lastTransitionPosition = 0;
|
|
42
|
+
_isTransitioning = NO;
|
|
43
|
+
_isDragging = NO;
|
|
44
|
+
_isTrackingPositionFromLayout = NO;
|
|
45
|
+
_layoutTransitioning = NO;
|
|
46
|
+
_isPresented = NO;
|
|
47
|
+
_activeDetentIndex = -1;
|
|
48
|
+
|
|
49
|
+
_backgroundView = [[UIVisualEffectView alloc] init];
|
|
50
|
+
_backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
51
|
+
|
|
52
|
+
// Initialize fake transition view for tracking position during animations
|
|
53
|
+
_fakeTransitionView = [[UIView alloc] init];
|
|
54
|
+
_fakeTransitionView.hidden = YES;
|
|
55
|
+
_fakeTransitionView.userInteractionEnabled = NO;
|
|
56
|
+
|
|
57
|
+
// Get bottom safe area inset from the window's safe area
|
|
58
|
+
// The sheet's view has smaller insets, so we need the actual device insets
|
|
59
|
+
UIWindow *window = [WindowUtil keyWindow];
|
|
60
|
+
_bottomInset = window ? window.safeAreaInsets.bottom : 0;
|
|
61
|
+
}
|
|
62
|
+
return self;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
- (void)dealloc {
|
|
66
|
+
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
#pragma mark - Presentation State
|
|
70
|
+
|
|
71
|
+
- (BOOL)isTopmostPresentedController {
|
|
72
|
+
// Check if we're in the window hierarchy and visible
|
|
73
|
+
if (!self.isViewLoaded || self.view.window == nil) {
|
|
74
|
+
return NO;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Check if another controller is presented on top of this sheet
|
|
78
|
+
return self.presentedViewController == nil;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
- (BOOL)isActiveAndVisible {
|
|
82
|
+
return self.isViewLoaded && self.view.window != nil && !self.isBeingDismissed;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
- (UIView *)presentedView {
|
|
86
|
+
return self.sheetPresentationController.presentedView;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
- (void)viewDidLoad {
|
|
90
|
+
[super viewDidLoad];
|
|
91
|
+
|
|
92
|
+
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
|
|
93
|
+
_backgroundView.frame = self.view.bounds;
|
|
94
|
+
[self.view insertSubview:self->_backgroundView atIndex:0];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
- (void)viewWillAppear:(BOOL)animated {
|
|
98
|
+
[super viewWillAppear:animated];
|
|
99
|
+
|
|
100
|
+
// Only trigger willPresent on the initial presentation, not on repositioning
|
|
101
|
+
if (!_isPresented) {
|
|
102
|
+
if ([self.delegate respondsToSelector:@selector(viewControllerWillPresent)]) {
|
|
103
|
+
[self.delegate viewControllerWillPresent];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Setup transition position tracking
|
|
107
|
+
[self setupTransitionPositionTracking];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
- (void)viewDidAppear:(BOOL)animated {
|
|
112
|
+
[super viewDidAppear:animated];
|
|
113
|
+
|
|
114
|
+
// Only trigger didPresent on the initial presentation, not on repositioning
|
|
115
|
+
if (!_isPresented) {
|
|
116
|
+
if ([self.delegate respondsToSelector:@selector(viewControllerDidPresent)]) {
|
|
117
|
+
[self.delegate viewControllerDidPresent];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Setup gesture recognizer after view appears and React content is mounted
|
|
121
|
+
[self setupGestureRecognizer];
|
|
122
|
+
|
|
123
|
+
_isPresented = YES;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
- (void)viewWillDisappear:(BOOL)animated {
|
|
128
|
+
[super viewWillDisappear:animated];
|
|
129
|
+
|
|
130
|
+
if ([self.delegate respondsToSelector:@selector(viewControllerWillDismiss)]) {
|
|
131
|
+
[self.delegate viewControllerWillDismiss];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
[self setupTransitionPositionTracking];
|
|
135
|
+
_isTrackingPositionFromLayout = NO;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
- (void)viewDidDisappear:(BOOL)animated {
|
|
139
|
+
[super viewDidDisappear:animated];
|
|
140
|
+
if ([self.delegate respondsToSelector:@selector(viewControllerDidDismiss)]) {
|
|
141
|
+
[self.delegate viewControllerDidDismiss];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
_isTrackingPositionFromLayout = NO;
|
|
145
|
+
_isPresented = NO;
|
|
146
|
+
_activeDetentIndex = -1;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
- (void)viewWillTransitionToSize:(CGSize)size
|
|
150
|
+
withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
|
|
151
|
+
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
|
152
|
+
|
|
153
|
+
// Handle rotation/size change
|
|
154
|
+
[coordinator
|
|
155
|
+
animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
|
|
156
|
+
// Animation block - updates happen here
|
|
157
|
+
}
|
|
158
|
+
completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
|
|
159
|
+
// After rotation completes
|
|
160
|
+
[self setupSheetDetents];
|
|
161
|
+
|
|
162
|
+
// Notify delegate of size changes
|
|
163
|
+
if ([self.delegate respondsToSelector:@selector(viewControllerDidChangeSize:)]) {
|
|
164
|
+
[self.delegate viewControllerDidChangeSize:self.view.frame.size];
|
|
165
|
+
}
|
|
166
|
+
}];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
- (void)viewDidLayoutSubviews {
|
|
170
|
+
[super viewDidLayoutSubviews];
|
|
171
|
+
if (!_isTransitioning && self.isActiveAndVisible) {
|
|
172
|
+
// Flag that we are tracking position from layout
|
|
173
|
+
_isTrackingPositionFromLayout = YES;
|
|
174
|
+
|
|
175
|
+
// If another controller is presented on top, treat position changes as transitioning
|
|
176
|
+
// This prevents incorrect position notifications when overlays adjust our size
|
|
177
|
+
[self emitChangePositionDelegateWithPosition:self.currentPosition
|
|
178
|
+
transitioning:_layoutTransitioning || !self.isTopmostPresentedController];
|
|
179
|
+
|
|
180
|
+
// On IOS 26, this is called twice when we have a ScrollView
|
|
181
|
+
// Schedule flag reset after animation to avoid race condition
|
|
182
|
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
183
|
+
// Reset layout transitioning after sending notification
|
|
184
|
+
self->_layoutTransitioning = NO;
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
#pragma mark - Gesture Handling
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Finds the TrueSheetContentView in the hierarchy.
|
|
193
|
+
*
|
|
194
|
+
* @param view The presentedView to start searching from
|
|
195
|
+
* @return The TrueSheetContentView found, or nil
|
|
196
|
+
*/
|
|
197
|
+
- (TrueSheetContentView *)findContentView:(UIView *)view {
|
|
198
|
+
// Check if this view itself is TrueSheetContentView
|
|
199
|
+
if ([view isKindOfClass:[TrueSheetContentView class]]) {
|
|
200
|
+
return (TrueSheetContentView *)view;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Recursively search all subviews
|
|
204
|
+
for (UIView *subview in view.subviews) {
|
|
205
|
+
TrueSheetContentView *found = [self findContentView:subview];
|
|
206
|
+
if (found) {
|
|
207
|
+
return found;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return nil;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
- (void)setupGestureRecognizer {
|
|
215
|
+
UIView *presentedView = self.presentedView;
|
|
216
|
+
if (!presentedView)
|
|
217
|
+
return;
|
|
218
|
+
|
|
219
|
+
// Attach to presented view's pan gestures (sheet's own drag gesture from UIKit)
|
|
220
|
+
[GestureUtil attachPanGestureHandler:presentedView target:self selector:@selector(handlePanGesture:)];
|
|
221
|
+
|
|
222
|
+
// Find and attach to the first ScrollView's pan gesture in the view hierarchy
|
|
223
|
+
// This handles cases where the sheet content includes a ScrollView
|
|
224
|
+
TrueSheetContentView *contentView = [self findContentView:presentedView];
|
|
225
|
+
if (contentView) {
|
|
226
|
+
RCTScrollViewComponentView *scrollViewComponent = [contentView findScrollView];
|
|
227
|
+
if (scrollViewComponent) {
|
|
228
|
+
// Access the internal UIScrollView via the scrollView property
|
|
229
|
+
UIScrollView *scrollView = scrollViewComponent.scrollView;
|
|
230
|
+
if (scrollView) {
|
|
231
|
+
[GestureUtil attachPanGestureHandler:scrollView target:self selector:@selector(handlePanGesture:)];
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
- (void)handlePanGesture:(UIPanGestureRecognizer *)gesture {
|
|
238
|
+
NSInteger index = [self currentDetentIndex];
|
|
239
|
+
|
|
240
|
+
if ([self.delegate respondsToSelector:@selector(viewControllerDidDrag:index:position:)]) {
|
|
241
|
+
[self.delegate viewControllerDidDrag:gesture.state index:index position:self.currentPosition];
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
switch (gesture.state) {
|
|
245
|
+
case UIGestureRecognizerStateBegan:
|
|
246
|
+
_isDragging = YES;
|
|
247
|
+
break;
|
|
248
|
+
case UIGestureRecognizerStateChanged:
|
|
249
|
+
if (!_isTrackingPositionFromLayout)
|
|
250
|
+
[self emitChangePositionDelegateWithPosition:self.currentPosition transitioning:NO];
|
|
251
|
+
break;
|
|
252
|
+
case UIGestureRecognizerStateEnded:
|
|
253
|
+
case UIGestureRecognizerStateCancelled:
|
|
254
|
+
_isDragging = NO;
|
|
255
|
+
break;
|
|
256
|
+
|
|
257
|
+
default:
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
#pragma mark - Position Tracking
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Emits position change to the delegate if the position has changed.
|
|
266
|
+
* @param transitioning Whether the position change is part of a transition animation
|
|
267
|
+
*/
|
|
268
|
+
- (void)emitChangePositionDelegateWithPosition:(CGFloat)position transitioning:(BOOL)transitioning {
|
|
269
|
+
if (_lastPosition != position) {
|
|
270
|
+
_lastPosition = position;
|
|
271
|
+
|
|
272
|
+
// Emit position change delegate
|
|
273
|
+
NSInteger index = [self currentDetentIndex];
|
|
274
|
+
|
|
275
|
+
if ([self.delegate respondsToSelector:@selector(viewControllerDidChangePosition:position:transitioning:)]) {
|
|
276
|
+
[self.delegate viewControllerDidChangePosition:index position:position transitioning:transitioning];
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Sets up position tracking during view controller transitions using a fake view.
|
|
283
|
+
*
|
|
284
|
+
* This approach uses a hidden "fake" view added to the container that animates
|
|
285
|
+
* alongside the actual presented view. By observing the presentation layer of this
|
|
286
|
+
* fake view's frame, we can track smooth position changes during the native transition
|
|
287
|
+
* animation without manually animating in JavaScript.
|
|
288
|
+
*
|
|
289
|
+
* The display link fires at screen refresh rate, allowing us to emit position updates
|
|
290
|
+
* that match the native animation curve, providing smooth synchronized updates to JS.
|
|
291
|
+
*/
|
|
292
|
+
- (void)setupTransitionPositionTracking {
|
|
293
|
+
if (self.transitionCoordinator != nil) {
|
|
294
|
+
_isTransitioning = YES;
|
|
295
|
+
|
|
296
|
+
// Get the container view to add our fake transition view
|
|
297
|
+
UIView *containerView = self.sheetPresentationController.containerView;
|
|
298
|
+
UIView *presentedView = self.presentedView;
|
|
299
|
+
|
|
300
|
+
if (!containerView || !presentedView)
|
|
301
|
+
return;
|
|
302
|
+
|
|
303
|
+
CGRect frame = presentedView.frame;
|
|
304
|
+
|
|
305
|
+
// Determine if presenting or dismissing to set correct start position
|
|
306
|
+
BOOL isPresenting = self.isBeingPresented;
|
|
307
|
+
|
|
308
|
+
// Set initial position based on transition type:
|
|
309
|
+
// - Presenting: Start from bottom (containerHeight) and animate up to detent
|
|
310
|
+
// - Dismissing: Start from current position and animate down to bottom
|
|
311
|
+
if (isPresenting) {
|
|
312
|
+
frame.origin.y = self.containerHeight;
|
|
313
|
+
} else {
|
|
314
|
+
frame.origin.y = presentedView.frame.origin.y;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Set fake view's initial frame before transition starts
|
|
318
|
+
_fakeTransitionView.frame = frame;
|
|
319
|
+
|
|
320
|
+
auto animation = ^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
|
|
321
|
+
// Add fake view to container so it participates in the transition
|
|
322
|
+
[[context containerView] addSubview:self->_fakeTransitionView];
|
|
323
|
+
|
|
324
|
+
// Animate fake view to the presented view's target position
|
|
325
|
+
// UIKit will animate this with the same timing curve as the sheet
|
|
326
|
+
CGRect finalFrame = presentedView.frame;
|
|
327
|
+
finalFrame.origin.y = presentedView.frame.origin.y;
|
|
328
|
+
self->_fakeTransitionView.frame = finalFrame;
|
|
329
|
+
|
|
330
|
+
// Set our last transition position so we can check if
|
|
331
|
+
// fake view's presentation layer has changed
|
|
332
|
+
// This value will not change if the sheet is being repositioned
|
|
333
|
+
// during a transition after a drag
|
|
334
|
+
self->_lastTransitionPosition = finalFrame.origin.y;
|
|
335
|
+
|
|
336
|
+
// Start display link to track position changes at screen refresh rate
|
|
337
|
+
// This fires at 60-120Hz and reads from the presentation layer
|
|
338
|
+
self->_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(trackTransitionPosition:)];
|
|
339
|
+
[self->_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
[self.transitionCoordinator
|
|
343
|
+
animateAlongsideTransition:animation
|
|
344
|
+
completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
|
|
345
|
+
// Clean up display link
|
|
346
|
+
[self->_displayLink invalidate];
|
|
347
|
+
self->_displayLink = nil;
|
|
348
|
+
|
|
349
|
+
// Remove fake view from hierarchy
|
|
350
|
+
[self->_fakeTransitionView removeFromSuperview];
|
|
351
|
+
self->_isTransitioning = NO;
|
|
352
|
+
}];
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
- (void)trackTransitionPosition:(CADisplayLink *)displayLink {
|
|
357
|
+
UIView *presentedView = self.presentedView;
|
|
358
|
+
|
|
359
|
+
if (_isDragging || !_fakeTransitionView || !presentedView) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Get the presentation layer which contains the in-flight animated values
|
|
364
|
+
// Unlike the model layer (which has the final/target value), the presentation
|
|
365
|
+
// layer reflects the current state during animation
|
|
366
|
+
CALayer *presentationLayer = _fakeTransitionView.layer.presentationLayer;
|
|
367
|
+
|
|
368
|
+
if (presentationLayer) {
|
|
369
|
+
BOOL transitioning = NO;
|
|
370
|
+
CGFloat position = presentationLayer.frame.origin.y;
|
|
371
|
+
|
|
372
|
+
// Our last transition position is nearly the same as fake view's layer position
|
|
373
|
+
// Sheet must've been repositioning after dragging at lowest detent
|
|
374
|
+
if (fabs(_lastTransitionPosition - position) < FLT_EPSILON) {
|
|
375
|
+
// Let's just flag it as transitioning to let JS manually animate
|
|
376
|
+
transitioning = YES;
|
|
377
|
+
|
|
378
|
+
// Use the target presented view's frame position to animate
|
|
379
|
+
position = presentedView.frame.origin.y;
|
|
380
|
+
} else {
|
|
381
|
+
// We are actually getting changes to our fake view's layer position
|
|
382
|
+
// Just update our last transition position
|
|
383
|
+
_lastTransitionPosition = position;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Emit the current animated Y position to JS
|
|
387
|
+
// This provides smooth position updates that match the native animation curve
|
|
388
|
+
[self emitChangePositionDelegateWithPosition:position transitioning:transitioning];
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
#pragma mark - Sheet Configuration (iOS 15+)
|
|
393
|
+
|
|
394
|
+
- (void)setupSheetDetents {
|
|
395
|
+
UISheetPresentationController *sheet = self.sheetPresentationController;
|
|
396
|
+
if (!sheet)
|
|
397
|
+
return;
|
|
398
|
+
|
|
399
|
+
NSMutableArray<UISheetPresentationControllerDetent *> *detents = [NSMutableArray array];
|
|
400
|
+
|
|
401
|
+
// Subtract bottomInset from content height to account for safe area
|
|
402
|
+
// This prevents iOS from adding extra bottom insets automatically
|
|
403
|
+
CGFloat totalHeight = [self.contentHeight floatValue] - _bottomInset;
|
|
404
|
+
|
|
405
|
+
for (NSInteger index = 0; index < self.detents.count; index++) {
|
|
406
|
+
id detent = self.detents[index];
|
|
407
|
+
UISheetPresentationControllerDetent *sheetDetent = [self detentForValue:detent
|
|
408
|
+
withHeight:totalHeight
|
|
409
|
+
atIndex:index];
|
|
410
|
+
[detents addObject:sheetDetent];
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
sheet.detents = detents;
|
|
414
|
+
|
|
415
|
+
// Setup dimmed background
|
|
416
|
+
if (self.dimmed && [self.dimmedIndex integerValue] == 0) {
|
|
417
|
+
sheet.largestUndimmedDetentIdentifier = nil;
|
|
418
|
+
} else {
|
|
419
|
+
sheet.largestUndimmedDetentIdentifier = UISheetPresentationControllerDetentIdentifierLarge;
|
|
420
|
+
|
|
421
|
+
if (@available(iOS 16.0, *)) {
|
|
422
|
+
if (self.dimmed && self.dimmedIndex) {
|
|
423
|
+
NSInteger dimmedIdx = [self.dimmedIndex integerValue];
|
|
424
|
+
if (dimmedIdx > 0 && dimmedIdx - 1 < sheet.detents.count) {
|
|
425
|
+
sheet.largestUndimmedDetentIdentifier = sheet.detents[dimmedIdx - 1].identifier;
|
|
426
|
+
} else if (sheet.detents.lastObject) {
|
|
427
|
+
sheet.largestUndimmedDetentIdentifier = sheet.detents.lastObject.identifier;
|
|
428
|
+
}
|
|
429
|
+
} else if (sheet.detents.lastObject) {
|
|
430
|
+
sheet.largestUndimmedDetentIdentifier = sheet.detents.lastObject.identifier;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
- (UISheetPresentationControllerDetent *)detentForValue:(id)detent withHeight:(CGFloat)height atIndex:(NSInteger)index {
|
|
437
|
+
if (![detent isKindOfClass:[NSNumber class]]) {
|
|
438
|
+
return [UISheetPresentationControllerDetent mediumDetent];
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
CGFloat value = [detent floatValue];
|
|
442
|
+
|
|
443
|
+
// -1 represents "auto"
|
|
444
|
+
if (value == -1) {
|
|
445
|
+
if (@available(iOS 16.0, *)) {
|
|
446
|
+
NSString *detentId = @"custom-auto";
|
|
447
|
+
return [UISheetPresentationControllerDetent
|
|
448
|
+
customDetentWithIdentifier:detentId
|
|
449
|
+
resolver:^CGFloat(id<UISheetPresentationControllerDetentResolutionContext> context) {
|
|
450
|
+
CGFloat maxDetentValue = context.maximumDetentValue;
|
|
451
|
+
CGFloat maxValue =
|
|
452
|
+
self.maxHeight ? MIN(maxDetentValue, [self.maxHeight floatValue]) : maxDetentValue;
|
|
453
|
+
CGFloat resolvedValue = MIN(height, maxValue);
|
|
454
|
+
return resolvedValue;
|
|
455
|
+
}];
|
|
456
|
+
} else {
|
|
457
|
+
return [UISheetPresentationControllerDetent mediumDetent];
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Handle fraction (0-1)
|
|
462
|
+
// Fraction should only be > 0 and <= 1
|
|
463
|
+
if (value <= 0 || value > 1) {
|
|
464
|
+
RCTLogError(@"TrueSheet: detent fraction (%f) must be between 0 and 1", value);
|
|
465
|
+
return [UISheetPresentationControllerDetent mediumDetent];
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
NSString *detentId = [NSString stringWithFormat:@"custom-%f", value];
|
|
469
|
+
|
|
470
|
+
if (@available(iOS 16.0, *)) {
|
|
471
|
+
return [UISheetPresentationControllerDetent
|
|
472
|
+
customDetentWithIdentifier:detentId
|
|
473
|
+
resolver:^CGFloat(id<UISheetPresentationControllerDetentResolutionContext> context) {
|
|
474
|
+
CGFloat maxDetentValue = context.maximumDetentValue;
|
|
475
|
+
CGFloat maxValue =
|
|
476
|
+
self.maxHeight ? MIN(maxDetentValue, [self.maxHeight floatValue]) : maxDetentValue;
|
|
477
|
+
CGFloat resolvedValue = MIN(value * maxDetentValue, maxValue);
|
|
478
|
+
return resolvedValue;
|
|
479
|
+
}];
|
|
480
|
+
} else {
|
|
481
|
+
return [UISheetPresentationControllerDetent mediumDetent];
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
- (UISheetPresentationControllerDetentIdentifier)detentIdentifierForIndex:(NSInteger)index {
|
|
486
|
+
UISheetPresentationController *sheet = self.sheetPresentationController;
|
|
487
|
+
if (!sheet)
|
|
488
|
+
return UISheetPresentationControllerDetentIdentifierMedium;
|
|
489
|
+
|
|
490
|
+
UISheetPresentationControllerDetentIdentifier identifier = UISheetPresentationControllerDetentIdentifierMedium;
|
|
491
|
+
if (index < sheet.detents.count) {
|
|
492
|
+
UISheetPresentationControllerDetent *detent = sheet.detents[index];
|
|
493
|
+
if (@available(iOS 16.0, *)) {
|
|
494
|
+
identifier = detent.identifier;
|
|
495
|
+
} else {
|
|
496
|
+
if (detent == [UISheetPresentationControllerDetent largeDetent]) {
|
|
497
|
+
identifier = UISheetPresentationControllerDetentIdentifierLarge;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
return identifier;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
- (void)applyActiveDetent {
|
|
506
|
+
UISheetPresentationController *sheet = self.sheetPresentationController;
|
|
507
|
+
if (!sheet)
|
|
508
|
+
return;
|
|
509
|
+
|
|
510
|
+
// Validate and clamp activeDetentIndex to detents bounds
|
|
511
|
+
NSInteger detentCount = _detents.count;
|
|
512
|
+
if (detentCount == 0) {
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Clamp index to valid range
|
|
517
|
+
NSInteger clampedIndex = _activeDetentIndex;
|
|
518
|
+
if (clampedIndex < 0) {
|
|
519
|
+
clampedIndex = 0;
|
|
520
|
+
} else if (clampedIndex >= detentCount) {
|
|
521
|
+
clampedIndex = detentCount - 1;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// Update the stored index if it was clamped
|
|
525
|
+
if (clampedIndex != _activeDetentIndex) {
|
|
526
|
+
_activeDetentIndex = clampedIndex;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
UISheetPresentationControllerDetentIdentifier identifier = [self detentIdentifierForIndex:clampedIndex];
|
|
530
|
+
if (identifier) {
|
|
531
|
+
sheet.selectedDetentIdentifier = identifier;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
- (void)setupActiveDetentWithIndex:(NSInteger)index {
|
|
536
|
+
_activeDetentIndex = index;
|
|
537
|
+
[self applyActiveDetent];
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
- (NSInteger)currentDetentIndex {
|
|
541
|
+
UISheetPresentationController *sheet = self.sheetPresentationController;
|
|
542
|
+
if (!sheet)
|
|
543
|
+
return -1;
|
|
544
|
+
|
|
545
|
+
UISheetPresentationControllerDetentIdentifier selectedIdentifier = sheet.selectedDetentIdentifier;
|
|
546
|
+
if (!selectedIdentifier)
|
|
547
|
+
return -1;
|
|
548
|
+
|
|
549
|
+
// Find the index by matching the identifier in the detents array
|
|
550
|
+
NSArray<UISheetPresentationControllerDetent *> *detents = sheet.detents;
|
|
551
|
+
for (NSInteger i = 0; i < detents.count; i++) {
|
|
552
|
+
if (@available(iOS 16.0, *)) {
|
|
553
|
+
if ([detents[i].identifier isEqualToString:selectedIdentifier]) {
|
|
554
|
+
return i;
|
|
555
|
+
}
|
|
556
|
+
} else {
|
|
557
|
+
// For iOS 15, we only support system detents (medium/large)
|
|
558
|
+
// Return the index based on the selected identifier
|
|
559
|
+
if ([selectedIdentifier isEqualToString:UISheetPresentationControllerDetentIdentifierMedium]) {
|
|
560
|
+
return 0;
|
|
561
|
+
} else if ([selectedIdentifier isEqualToString:UISheetPresentationControllerDetentIdentifierLarge]) {
|
|
562
|
+
return detents.count - 1;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
return -1;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
- (CGFloat)currentPosition {
|
|
571
|
+
UIView *presentedView = self.presentedView;
|
|
572
|
+
if (!presentedView)
|
|
573
|
+
return 0.0;
|
|
574
|
+
|
|
575
|
+
return presentedView.frame.origin.y;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
- (CGFloat)currentHeight {
|
|
579
|
+
return self.containerHeight - self.currentPosition - _bottomInset;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
- (CGFloat)containerHeight {
|
|
583
|
+
UIView *containerView = self.sheetPresentationController.containerView;
|
|
584
|
+
if (!containerView)
|
|
585
|
+
return 0.0;
|
|
586
|
+
|
|
587
|
+
return containerView.frame.size.height;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
- (void)setupSheetProps {
|
|
591
|
+
UISheetPresentationController *sheet = self.sheetPresentationController;
|
|
592
|
+
if (!sheet) {
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
sheet.delegate = self;
|
|
597
|
+
sheet.prefersEdgeAttachedInCompactHeight = YES;
|
|
598
|
+
sheet.prefersGrabberVisible = self.grabber;
|
|
599
|
+
// Only set preferredCornerRadius if explicitly provided, otherwise use system default
|
|
600
|
+
if (self.cornerRadius) {
|
|
601
|
+
sheet.preferredCornerRadius = [self.cornerRadius floatValue];
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Setup blur effect if blurTint is provided
|
|
605
|
+
if (self.blurTint && self.blurTint.length > 0) {
|
|
606
|
+
UIBlurEffectStyle style = UIBlurEffectStyleLight;
|
|
607
|
+
|
|
608
|
+
if ([self.blurTint isEqualToString:@"dark"]) {
|
|
609
|
+
style = UIBlurEffectStyleDark;
|
|
610
|
+
} else if ([self.blurTint isEqualToString:@"light"]) {
|
|
611
|
+
style = UIBlurEffectStyleLight;
|
|
612
|
+
} else if ([self.blurTint isEqualToString:@"extraLight"]) {
|
|
613
|
+
style = UIBlurEffectStyleExtraLight;
|
|
614
|
+
} else if ([self.blurTint isEqualToString:@"regular"]) {
|
|
615
|
+
style = UIBlurEffectStyleRegular;
|
|
616
|
+
} else if ([self.blurTint isEqualToString:@"prominent"]) {
|
|
617
|
+
style = UIBlurEffectStyleProminent;
|
|
618
|
+
} else if ([self.blurTint isEqualToString:@"systemThinMaterial"]) {
|
|
619
|
+
style = UIBlurEffectStyleSystemThinMaterial;
|
|
620
|
+
} else if ([self.blurTint isEqualToString:@"systemMaterial"]) {
|
|
621
|
+
style = UIBlurEffectStyleSystemMaterial;
|
|
622
|
+
} else if ([self.blurTint isEqualToString:@"systemThickMaterial"]) {
|
|
623
|
+
style = UIBlurEffectStyleSystemThickMaterial;
|
|
624
|
+
} else if ([self.blurTint isEqualToString:@"systemChromeMaterial"]) {
|
|
625
|
+
style = UIBlurEffectStyleSystemChromeMaterial;
|
|
626
|
+
} else if ([self.blurTint isEqualToString:@"systemUltraThinMaterial"]) {
|
|
627
|
+
style = UIBlurEffectStyleSystemUltraThinMaterial;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
_backgroundView.effect = [UIBlurEffect effectWithStyle:style];
|
|
631
|
+
_backgroundView.backgroundColor = nil;
|
|
632
|
+
} else {
|
|
633
|
+
// No blur effect, use solid background color
|
|
634
|
+
_backgroundView.effect = nil;
|
|
635
|
+
_backgroundView.backgroundColor = self.backgroundColor;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
#pragma mark - UISheetPresentationControllerDelegate
|
|
640
|
+
|
|
641
|
+
- (void)sheetPresentationControllerDidChangeSelectedDetentIdentifier:
|
|
642
|
+
(UISheetPresentationController *)sheetPresentationController {
|
|
643
|
+
NSInteger index = [self currentDetentIndex];
|
|
644
|
+
if (index >= 0 && [self.delegate respondsToSelector:@selector(viewControllerDidChangeDetent:position:)]) {
|
|
645
|
+
[self.delegate viewControllerDidChangeDetent:index position:self.currentPosition];
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
@end
|
|
@@ -0,0 +1,28 @@
|
|
|
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 OnDetentChangeEvent : NSObject
|
|
19
|
+
|
|
20
|
+
+ (void)emit:(std::shared_ptr<const facebook::react::EventEmitter>)eventEmitter
|
|
21
|
+
index:(NSInteger)index
|
|
22
|
+
position:(CGFloat)position;
|
|
23
|
+
|
|
24
|
+
@end
|
|
25
|
+
|
|
26
|
+
NS_ASSUME_NONNULL_END
|
|
27
|
+
|
|
28
|
+
#endif // RCT_NEW_ARCH_ENABLED
|
|
@@ -0,0 +1,30 @@
|
|
|
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 "OnDetentChangeEvent.h"
|
|
12
|
+
|
|
13
|
+
@implementation OnDetentChangeEvent
|
|
14
|
+
|
|
15
|
+
+ (void)emit:(std::shared_ptr<const facebook::react::EventEmitter>)eventEmitter
|
|
16
|
+
index:(NSInteger)index
|
|
17
|
+
position:(CGFloat)position {
|
|
18
|
+
if (!eventEmitter)
|
|
19
|
+
return;
|
|
20
|
+
|
|
21
|
+
auto emitter = std::static_pointer_cast<TrueSheetViewEventEmitter const>(eventEmitter);
|
|
22
|
+
TrueSheetViewEventEmitter::OnDetentChange event;
|
|
23
|
+
event.index = static_cast<int>(index);
|
|
24
|
+
event.position = static_cast<double>(position);
|
|
25
|
+
emitter->onDetentChange(event);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@end
|
|
29
|
+
|
|
30
|
+
#endif // RCT_NEW_ARCH_ENABLED
|