@sdcx/bottom-sheet 0.1.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/LICENSE +21 -0
- package/README.md +78 -0
- package/RNBottomSheet.podspec +18 -0
- package/android/build.gradle +35 -0
- package/android/proguard-rules.pro +0 -0
- package/android/src/main/AndroidManifest.xml +4 -0
- package/android/src/main/java/com/reactnative/bottomsheet/BottomSheet.java +599 -0
- package/android/src/main/java/com/reactnative/bottomsheet/BottomSheetManager.java +45 -0
- package/android/src/main/java/com/reactnative/bottomsheet/BottomSheetPackage.java +25 -0
- package/android/src/main/java/com/reactnative/bottomsheet/BottomSheetState.java +5 -0
- package/android/src/main/java/com/reactnative/bottomsheet/OffsetChangedEvent.java +40 -0
- package/android/src/main/java/com/reactnative/bottomsheet/StateChangedEvent.java +31 -0
- package/ios/BottomSheet/RNBottomSheet.h +15 -0
- package/ios/BottomSheet/RNBottomSheet.m +321 -0
- package/ios/BottomSheet/RNBottomSheetManager.h +9 -0
- package/ios/BottomSheet/RNBottomSheetManager.m +18 -0
- package/ios/BottomSheet.xcodeproj/project.pbxproj +283 -0
- package/lib/index.d.ts +21 -0
- package/lib/index.js +31 -0
- package/lib/splitLayoutProps.d.ts +15 -0
- package/lib/splitLayoutProps.js +41 -0
- package/package.json +65 -0
- package/src/index.tsx +74 -0
- package/src/splitLayoutProps.ts +47 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
package com.reactnative.bottomsheet;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.Nullable;
|
|
4
|
+
|
|
5
|
+
import com.facebook.react.bridge.Arguments;
|
|
6
|
+
import com.facebook.react.bridge.WritableMap;
|
|
7
|
+
import com.facebook.react.uimanager.PixelUtil;
|
|
8
|
+
import com.facebook.react.uimanager.events.Event;
|
|
9
|
+
|
|
10
|
+
public class OffsetChangedEvent extends Event<OffsetChangedEvent> {
|
|
11
|
+
public static final String Name = "offsetEvent";
|
|
12
|
+
public static final String JSEventName = "onSlide";
|
|
13
|
+
|
|
14
|
+
private final int offset;
|
|
15
|
+
private final int minOffset;
|
|
16
|
+
private final int maxOffset;
|
|
17
|
+
|
|
18
|
+
public OffsetChangedEvent(int surfaceId, int viewTag, int offset, int minOffset, int maxOffset) {
|
|
19
|
+
super(surfaceId, viewTag);
|
|
20
|
+
this.offset = offset;
|
|
21
|
+
this.maxOffset = maxOffset;
|
|
22
|
+
this.minOffset = minOffset;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@Override
|
|
26
|
+
public String getEventName() {
|
|
27
|
+
return Name;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@Nullable
|
|
31
|
+
protected WritableMap getEventData() {
|
|
32
|
+
double progress = Math.min((offset - minOffset) * 1.0f / (maxOffset - minOffset), 1);
|
|
33
|
+
WritableMap data = Arguments.createMap();
|
|
34
|
+
data.putDouble("progress", progress);
|
|
35
|
+
data.putDouble("offset", PixelUtil.toDIPFromPixel(offset));
|
|
36
|
+
data.putDouble("expandedOffset", PixelUtil.toDIPFromPixel(minOffset));
|
|
37
|
+
data.putDouble("collapsedOffset", PixelUtil.toDIPFromPixel(maxOffset));
|
|
38
|
+
return data;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
package com.reactnative.bottomsheet;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.Nullable;
|
|
4
|
+
|
|
5
|
+
import com.facebook.react.bridge.Arguments;
|
|
6
|
+
import com.facebook.react.bridge.WritableMap;
|
|
7
|
+
import com.facebook.react.uimanager.events.Event;
|
|
8
|
+
|
|
9
|
+
public class StateChangedEvent extends Event<StateChangedEvent> {
|
|
10
|
+
public static final String Name = "stateEvent";
|
|
11
|
+
public static final String JSEventName = "onStateChanged";
|
|
12
|
+
|
|
13
|
+
private final String state;
|
|
14
|
+
|
|
15
|
+
public StateChangedEvent(int surfaceId, int viewTag, String state) {
|
|
16
|
+
super(surfaceId, viewTag);
|
|
17
|
+
this.state = state;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@Override
|
|
21
|
+
public String getEventName() {
|
|
22
|
+
return Name;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@Nullable
|
|
26
|
+
protected WritableMap getEventData() {
|
|
27
|
+
WritableMap data = Arguments.createMap();
|
|
28
|
+
data.putString("state", state);
|
|
29
|
+
return data;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#import <UIKit/UIKit.h>
|
|
2
|
+
#import <React/RCTComponent.h>
|
|
3
|
+
|
|
4
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
5
|
+
|
|
6
|
+
@interface RNBottomSheet : UIView
|
|
7
|
+
|
|
8
|
+
@property(nonatomic, copy) RCTDirectEventBlock onSlide;
|
|
9
|
+
@property(nonatomic, copy) RCTDirectEventBlock onStateChanged;
|
|
10
|
+
@property(nonatomic, assign) CGFloat peekHeight;
|
|
11
|
+
@property(nonatomic, copy) NSString *state;
|
|
12
|
+
|
|
13
|
+
@end
|
|
14
|
+
|
|
15
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
#import "RNBottomSheet.h"
|
|
2
|
+
|
|
3
|
+
#import <React/UIView+React.h>
|
|
4
|
+
#import <React/RCTLog.h>
|
|
5
|
+
|
|
6
|
+
@interface RNBottomSheet () <UIGestureRecognizerDelegate>
|
|
7
|
+
|
|
8
|
+
@property(nonatomic, strong) UIScrollView *target;
|
|
9
|
+
@property(nonatomic, strong) UIPanGestureRecognizer *panGestureRecognizer;
|
|
10
|
+
|
|
11
|
+
@property(nonatomic, assign) CGFloat minY;
|
|
12
|
+
@property(nonatomic, assign) CGFloat maxY;
|
|
13
|
+
|
|
14
|
+
@property(nonatomic, assign) BOOL nextReturn;
|
|
15
|
+
@property(nonatomic, assign) CGFloat lastDragDistance;
|
|
16
|
+
|
|
17
|
+
@property(nonatomic, strong) CADisplayLink *displayLink;
|
|
18
|
+
|
|
19
|
+
@end
|
|
20
|
+
|
|
21
|
+
@implementation RNBottomSheet
|
|
22
|
+
|
|
23
|
+
- (instancetype)init {
|
|
24
|
+
if (self = [super init]) {
|
|
25
|
+
_panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
|
|
26
|
+
_panGestureRecognizer.delegate = self;
|
|
27
|
+
_state = @"collapsed";
|
|
28
|
+
[self addGestureRecognizer:_panGestureRecognizer];
|
|
29
|
+
}
|
|
30
|
+
return self;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
|
|
34
|
+
if (gestureRecognizer == self.panGestureRecognizer && otherGestureRecognizer == self.target.panGestureRecognizer) {
|
|
35
|
+
return YES;
|
|
36
|
+
}
|
|
37
|
+
return NO;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
|
|
41
|
+
if (gestureRecognizer != self.panGestureRecognizer) {
|
|
42
|
+
return YES;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (self.target) {
|
|
46
|
+
[self.target removeObserver:self forKeyPath:@"contentOffset"];
|
|
47
|
+
}
|
|
48
|
+
self.target = nil;
|
|
49
|
+
|
|
50
|
+
UIView *touchView = touch.view;
|
|
51
|
+
|
|
52
|
+
while (touchView != nil && [touchView isDescendantOfView:self]) {
|
|
53
|
+
if ([touchView isKindOfClass:[UIScrollView class]]) {
|
|
54
|
+
UIScrollView *scrollView = (UIScrollView *)touchView;
|
|
55
|
+
if (![self isHorizontal:scrollView]) {
|
|
56
|
+
self.target = scrollView;
|
|
57
|
+
[self.target addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
touchView = touchView.superview;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return YES;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
- (void)willMoveToSuperview:(UIView *)superview {
|
|
68
|
+
[super willMoveToSuperview:superview];
|
|
69
|
+
if (superview == nil && self.target) {
|
|
70
|
+
[self.target removeObserver:self forKeyPath:@"contentOffset"];
|
|
71
|
+
self.target = nil;
|
|
72
|
+
}
|
|
73
|
+
if (superview == nil) {
|
|
74
|
+
[self stopWatchBottomSheetTransition];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
- (void)willMoveToWindow:(UIWindow *)newWindow {
|
|
79
|
+
[super willMoveToWindow:newWindow];
|
|
80
|
+
if (newWindow == nil) {
|
|
81
|
+
[self stopWatchBottomSheetTransition];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
- (BOOL)isHorizontal:(UIScrollView *)scrollView {
|
|
86
|
+
return scrollView.contentSize.width > self.frame.size.width;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
- (void)reactSetFrame:(CGRect)frame {
|
|
91
|
+
[super reactSetFrame:frame];
|
|
92
|
+
if (!CGRectEqualToRect(self.frame, CGRectZero)) {
|
|
93
|
+
[self calculateOffset];
|
|
94
|
+
if ([self.state isEqualToString:@"collapsed"]) {
|
|
95
|
+
self.frame = CGRectOffset(self.frame, 0, self.frame.size.height - self.peekHeight);
|
|
96
|
+
[self dispatchOnSlide:self.frame.origin.y];
|
|
97
|
+
} else if ([self.state isEqualToString:@"hidden"]) {
|
|
98
|
+
self.frame = CGRectOffset(self.frame, 0, self.frame.size.height);
|
|
99
|
+
[self dispatchOnSlide:self.frame.origin.y];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
- (void)layoutSubviews {
|
|
105
|
+
[super layoutSubviews];
|
|
106
|
+
[self calculateOffset];
|
|
107
|
+
[self dispatchOnSlide:self.frame.origin.y];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
- (void)calculateOffset {
|
|
111
|
+
CGFloat parentHeight = self.superview.frame.size.height;
|
|
112
|
+
self.minY = fmax(0, parentHeight - self.frame.size.height);
|
|
113
|
+
self.maxY = fmax(self.minY, parentHeight - self.peekHeight);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
- (void)handlePan:(UIPanGestureRecognizer *)pan {
|
|
117
|
+
|
|
118
|
+
CGFloat translationY = [pan translationInView:self].y;
|
|
119
|
+
[pan setTranslation:CGPointZero inView:self];
|
|
120
|
+
|
|
121
|
+
CGFloat top = self.frame.origin.y;
|
|
122
|
+
|
|
123
|
+
if (pan.state == UIGestureRecognizerStateChanged) {
|
|
124
|
+
[self setStateInternal:@"dragging"];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 如果有嵌套滚动
|
|
128
|
+
if (self.target) {
|
|
129
|
+
if(translationY > 0 && top < self.maxY && self.target.contentOffset.y <= 0) {
|
|
130
|
+
//向下拖
|
|
131
|
+
CGFloat y = fmin(top + translationY, self.maxY);
|
|
132
|
+
self.frame = CGRectOffset(self.frame, 0, y - top);
|
|
133
|
+
[self dispatchOnSlide:self.frame.origin.y];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (translationY < 0 && top > self.minY) {
|
|
137
|
+
//向上拖
|
|
138
|
+
CGFloat y = fmax(top + translationY, self.minY);
|
|
139
|
+
self.frame = CGRectOffset(self.frame, 0, y - top);
|
|
140
|
+
[self dispatchOnSlide:self.frame.origin.y];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// 没有嵌套滚动
|
|
145
|
+
if (!self.target) {
|
|
146
|
+
if(translationY > 0 && top < self.maxY) {
|
|
147
|
+
//向下拖
|
|
148
|
+
CGFloat y = fmin(top + translationY, self.maxY);
|
|
149
|
+
self.frame = CGRectOffset(self.frame, 0, y - top);
|
|
150
|
+
[self dispatchOnSlide:self.frame.origin.y];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (translationY < 0 && top > self.minY) {
|
|
154
|
+
//向上拖
|
|
155
|
+
CGFloat y = fmax(top + translationY, self.minY);
|
|
156
|
+
self.frame = CGRectOffset(self.frame, 0, y - top);
|
|
157
|
+
[self dispatchOnSlide:self.frame.origin.y];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (pan.state == UIGestureRecognizerStateEnded) {
|
|
162
|
+
if (self.lastDragDistance > 10) {
|
|
163
|
+
if (self.target && self.target.contentOffset.y <= 0) {
|
|
164
|
+
//如果是类似轻扫的那种
|
|
165
|
+
[self settleToState:@"collapsed"];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (!self.target) {
|
|
169
|
+
//如果是类似轻扫的那种
|
|
170
|
+
[self settleToState:@"collapsed"];
|
|
171
|
+
}
|
|
172
|
+
} else if (self.lastDragDistance < -10) {
|
|
173
|
+
//如果是类似轻扫的那种
|
|
174
|
+
[self settleToState:@"expanded"];
|
|
175
|
+
} else {
|
|
176
|
+
//如果是普通拖拽
|
|
177
|
+
if(fabs(self.frame.origin.y - self.minY) > fabs(self.frame.origin.y - self.maxY)) {
|
|
178
|
+
[self settleToState:@"collapsed"];
|
|
179
|
+
} else {
|
|
180
|
+
[self settleToState:@"expanded"];
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
self.lastDragDistance = translationY;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(UIScrollView *)target change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
|
|
189
|
+
if (_nextReturn) {
|
|
190
|
+
_nextReturn = false;
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (![keyPath isEqualToString:@"contentOffset"]) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
CGFloat new = [change[@"new"] CGPointValue].y;
|
|
199
|
+
CGFloat old = [change[@"old"] CGPointValue].y;
|
|
200
|
+
|
|
201
|
+
if (new == old) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
CGFloat dy = old - new;
|
|
206
|
+
|
|
207
|
+
if (dy > 0) {
|
|
208
|
+
//向下
|
|
209
|
+
if(target.contentOffset.y < 0){
|
|
210
|
+
_nextReturn = true;
|
|
211
|
+
target.contentOffset = CGPointMake(0, 0);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (dy < 0) {
|
|
216
|
+
//向上
|
|
217
|
+
if (self.frame.origin.y > self.minY) {
|
|
218
|
+
_nextReturn = true;
|
|
219
|
+
target.contentOffset = CGPointMake(0, old);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
- (void)setPeekHeight:(CGFloat)peekHeight {
|
|
225
|
+
_peekHeight = peekHeight;
|
|
226
|
+
if (!CGRectEqualToRect(self.frame, CGRectZero)) {
|
|
227
|
+
[self calculateOffset];
|
|
228
|
+
if ([self.state isEqualToString:@"collapsed"]) {
|
|
229
|
+
[self settleToState:@"collapsed"];
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
- (void)setState:(NSString *)state {
|
|
235
|
+
if ([_state isEqualToString:@"state"]) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (CGRectEqualToRect(self.frame, CGRectZero)) {
|
|
240
|
+
[self setStateInternal:state];
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
[self settleToState:state];
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
- (void)settleToState:(NSString *)state {
|
|
248
|
+
if ([state isEqualToString:@"collapsed"]) {
|
|
249
|
+
[self startSettlingToState:state top:self.maxY];
|
|
250
|
+
} else if ([state isEqualToString:@"expanded"]) {
|
|
251
|
+
[self startSettlingToState:state top:self.minY];
|
|
252
|
+
} else if ([state isEqualToString:@"hidden"]) {
|
|
253
|
+
[self startSettlingToState:@"hidden" top:self.superview.frame.size.height];
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
- (void)startSettlingToState:(NSString *)state top:(CGFloat)top {
|
|
258
|
+
self.target.pagingEnabled = YES;
|
|
259
|
+
[self setStateInternal:@"settling"];
|
|
260
|
+
[self startWatchBottomSheetTransition];
|
|
261
|
+
[self.layer removeAllAnimations];
|
|
262
|
+
CGFloat duration = fmin(fabs(self.frame.origin.y - top) / (self.maxY - self.minY) * 0.3, 0.3);
|
|
263
|
+
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionBeginFromCurrentState animations:^{
|
|
264
|
+
self.frame = CGRectOffset(self.frame, 0, top - self.frame.origin.y);
|
|
265
|
+
} completion:^(BOOL finished) {
|
|
266
|
+
self.target.pagingEnabled = NO;
|
|
267
|
+
[self stopWatchBottomSheetTransition];
|
|
268
|
+
[self setStateInternal:state];
|
|
269
|
+
}];
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
- (void)setStateInternal:(NSString *)state {
|
|
273
|
+
if ([_state isEqualToString:state]) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
_state = state;
|
|
277
|
+
|
|
278
|
+
if (self.onStateChanged) {
|
|
279
|
+
if ([state isEqualToString:@"collapsed"] || [state isEqualToString:@"expanded"] || [state isEqualToString:@"hidden"]) {
|
|
280
|
+
self.onStateChanged(@{
|
|
281
|
+
@"state": state,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
- (void)dispatchOnSlide:(CGFloat)top {
|
|
288
|
+
if (top < 0 || self.maxY == 0) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
if (self.onSlide) {
|
|
292
|
+
CGFloat progress = fmin((top - self.minY) * 1.0f / (self.maxY - self.minY), 1);
|
|
293
|
+
self.onSlide(@{
|
|
294
|
+
@"progress": @(progress),
|
|
295
|
+
@"offset": @(top),
|
|
296
|
+
@"collapsedOffset": @(self.maxY),
|
|
297
|
+
@"expandedOffset": @(self.minY)
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
- (void)startWatchBottomSheetTransition {
|
|
303
|
+
[self stopWatchBottomSheetTransition];
|
|
304
|
+
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(watchBottomSheetTransition)];
|
|
305
|
+
_displayLink.preferredFramesPerSecond = 120;
|
|
306
|
+
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
- (void)stopWatchBottomSheetTransition {
|
|
310
|
+
if(_displayLink){
|
|
311
|
+
[_displayLink invalidate];
|
|
312
|
+
_displayLink = nil;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
- (void)watchBottomSheetTransition {
|
|
317
|
+
CGFloat top = [self.layer presentationLayer].frame.origin.y;
|
|
318
|
+
[self dispatchOnSlide:top];
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
@end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#import "RNBottomSheetManager.h"
|
|
2
|
+
#import "RNBottomSheet.h"
|
|
3
|
+
|
|
4
|
+
@implementation RNBottomSheetManager
|
|
5
|
+
|
|
6
|
+
RCT_EXPORT_MODULE(BottomSheet)
|
|
7
|
+
|
|
8
|
+
- (UIView *)view {
|
|
9
|
+
return [RNBottomSheet new];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
RCT_EXPORT_VIEW_PROPERTY(onSlide, RCTDirectEventBlock)
|
|
13
|
+
RCT_EXPORT_VIEW_PROPERTY(onStateChanged, RCTDirectEventBlock)
|
|
14
|
+
|
|
15
|
+
RCT_EXPORT_VIEW_PROPERTY(peekHeight, CGFloat)
|
|
16
|
+
RCT_EXPORT_VIEW_PROPERTY(state, NSString)
|
|
17
|
+
|
|
18
|
+
@end
|