@onekeyfe/react-native-pager-view 3.0.157-alpha.257 → 3.0.157-alpha.258

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +51 -4
  2. package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerHost.kt +237 -43
  3. package/android/src/main/java/com/reactnativepagerview/NativeScrollerScrollAwayInsets.kt +15 -11
  4. package/android/src/main/java/com/reactnativepagerview/NativeScrollerView.kt +573 -0
  5. package/android/src/main/java/com/reactnativepagerview/NativeScrollerViewManager.kt +130 -0
  6. package/android/src/main/java/com/reactnativepagerview/PagerViewViewPackage.kt +1 -1
  7. package/android/src/main/jni/CMakeLists.txt +19 -0
  8. package/android/src/main/jni/pagerview.h +11 -0
  9. package/android/src/main/res/values/native_scroll_coordinator_ids.xml +1 -0
  10. package/android/src/test/java/com/reactnativepagerview/NativeScrollerScrollAwayInsetsTest.kt +32 -52
  11. package/common/cpp/react/renderer/components/pagerview/RNCNativeScrollerComponentDescriptor.h +8 -0
  12. package/common/cpp/react/renderer/components/pagerview/RNCNativeScrollerShadowNode.cpp +15 -0
  13. package/common/cpp/react/renderer/components/pagerview/RNCNativeScrollerShadowNode.h +23 -0
  14. package/common/cpp/react/renderer/components/pagerview/RNCNativeScrollerState.h +33 -0
  15. package/docs/SPEC.md +267 -34
  16. package/ios/RNCCollapsiblePagerViewComponentView.mm +187 -1
  17. package/ios/RNCNativeScrollerComponentView.h +17 -0
  18. package/ios/RNCNativeScrollerComponentView.mm +479 -0
  19. package/ios/tests/RNCCollapsiblePagerPressCancellationTests.mm +346 -0
  20. package/ios/tests/RNCCollapsiblePagerPressCancellationWiringTests.mm +109 -0
  21. package/ios/tests/RNCNativeScrollerTests.mm +252 -0
  22. package/lib/module/CollapsiblePagerView.js +1 -1
  23. package/lib/module/NativeScroller.js +171 -11
  24. package/lib/module/NativeScrollerNativeComponent.ts +101 -0
  25. package/lib/typescript/src/CollapsiblePagerView.d.ts +2 -3
  26. package/lib/typescript/src/NativeScroller.d.ts +15 -7
  27. package/lib/typescript/src/NativeScrollerNativeComponent.d.ts +79 -0
  28. package/package.json +6 -3
  29. package/react-native-pager-view.podspec +2 -1
  30. package/react-native.config.js +15 -0
  31. package/src/CollapsiblePagerView.tsx +4 -4
  32. package/src/NativeScroller.tsx +291 -14
  33. package/src/NativeScrollerNativeComponent.ts +101 -0
@@ -0,0 +1,346 @@
1
+ #import <XCTest/XCTest.h>
2
+ #import <UIKit/UIGestureRecognizerSubclass.h>
3
+ #import <React/RCTSurfaceTouchHandler.h>
4
+
5
+ // Private declarations access the production class compiled into the pod.
6
+ @interface RNCCollapsiblePagerContentPressCancellationGestureRecognizer : UIGestureRecognizer
7
+ @property (nonatomic, weak) UIGestureRecognizer *reactTouchHandler;
8
+ - (void)cancelPressForPan:(UIPanGestureRecognizer *)pan;
9
+ - (void)observeIncomingTouch:(UITouch *)touch;
10
+ @end
11
+
12
+ // UIKit can reset terminal states immediately outside real touch delivery.
13
+ // Observe requests while retaining the production implementation and UIKit setter.
14
+ @interface RNCPressCancellationObservedBridge : RNCCollapsiblePagerContentPressCancellationGestureRecognizer
15
+ @property (nonatomic, strong) NSMutableArray<NSNumber *> *requestedStates;
16
+ @end
17
+ @implementation RNCPressCancellationObservedBridge
18
+ - (void)setState:(UIGestureRecognizerState)state
19
+ {
20
+ if (self.requestedStates == nil) self.requestedStates = [NSMutableArray new];
21
+ [self.requestedStates addObject:@(state)];
22
+ [super setState:state];
23
+ }
24
+ @end
25
+
26
+ // These doubles supply input facts only. The production bridge owns its state
27
+ // transitions; this suite does not claim to synthesize UIKit touch delivery.
28
+ @interface RNCPressCancellationTestTouch : UITouch
29
+ @property (nonatomic, strong) UIView *testView;
30
+ @property (nonatomic, assign) UITouchPhase testPhase;
31
+ @end
32
+ @implementation RNCPressCancellationTestTouch
33
+ - (UIView *)view { return self.testView; }
34
+ - (UITouchPhase)phase { return self.testPhase; }
35
+ @end
36
+
37
+ @interface RNCPressCancellationTestEvent : UIEvent
38
+ @property (nonatomic, copy) NSSet<UITouch *> *testTouches;
39
+ @end
40
+ @implementation RNCPressCancellationTestEvent
41
+ - (NSSet<UITouch *> *)allTouches { return self.testTouches; }
42
+ @end
43
+
44
+ @interface RNCPressCancellationTestPan : UIPanGestureRecognizer
45
+ @property (nonatomic, assign) UIGestureRecognizerState testState;
46
+ @end
47
+ @implementation RNCPressCancellationTestPan
48
+ - (UIGestureRecognizerState)state { return self.testState; }
49
+ @end
50
+
51
+ @interface RNCCollapsiblePagerPressCancellationTests : XCTestCase
52
+ @property (nonatomic, strong) UIView *host;
53
+ @property (nonatomic, strong) UIView *surface;
54
+ @property (nonatomic, strong) UIView *content;
55
+ @property (nonatomic, strong) RCTSurfaceTouchHandler *handler;
56
+ @property (nonatomic, strong) RNCPressCancellationObservedBridge *bridge;
57
+ @property (nonatomic, strong) RNCPressCancellationTestPan *pan;
58
+ @property (nonatomic, strong) RNCPressCancellationTestTouch *touch;
59
+ @end
60
+
61
+ @implementation RNCCollapsiblePagerPressCancellationTests
62
+
63
+ - (void)setUp
64
+ {
65
+ [super setUp];
66
+ self.host = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 600)];
67
+ self.surface = [[UIView alloc] initWithFrame:self.host.bounds];
68
+ self.content = [[UIView alloc] initWithFrame:self.surface.bounds];
69
+ [self.host addSubview:self.surface];
70
+ [self.surface addSubview:self.content];
71
+ self.handler = [RCTSurfaceTouchHandler new];
72
+ [self.handler attachToView:self.surface];
73
+ Class bridgeClass = NSClassFromString(@"RNCCollapsiblePagerContentPressCancellationGestureRecognizer");
74
+ XCTAssertNotNil(bridgeClass);
75
+ self.bridge = [RNCPressCancellationObservedBridge new];
76
+ self.bridge.reactTouchHandler = self.handler;
77
+ [self.host addGestureRecognizer:self.bridge];
78
+ self.pan = [RNCPressCancellationTestPan new];
79
+ self.pan.testState = UIGestureRecognizerStateBegan;
80
+ self.touch = [self touchInView:self.content phase:UITouchPhaseBegan];
81
+ }
82
+
83
+ - (void)tearDown
84
+ {
85
+ [self.host removeGestureRecognizer:self.bridge];
86
+ [self.handler detachFromView:self.surface];
87
+ self.bridge = nil;
88
+ self.handler = nil;
89
+ self.touch = nil;
90
+ self.pan = nil;
91
+ self.content = nil;
92
+ self.surface = nil;
93
+ self.host = nil;
94
+ [super tearDown];
95
+ }
96
+
97
+ - (RNCPressCancellationTestTouch *)touchInView:(UIView *)view phase:(UITouchPhase)phase
98
+ {
99
+ RNCPressCancellationTestTouch *touch = [RNCPressCancellationTestTouch new];
100
+ touch.testView = view;
101
+ touch.testPhase = phase;
102
+ return touch;
103
+ }
104
+
105
+ - (RNCPressCancellationTestEvent *)eventWithTouches:(NSSet<UITouch *> *)touches
106
+ {
107
+ RNCPressCancellationTestEvent *event = [RNCPressCancellationTestEvent new];
108
+ event.testTouches = touches;
109
+ return event;
110
+ }
111
+
112
+ - (void)beginSingleTouch
113
+ {
114
+ [self.bridge touchesBegan:[NSSet setWithObject:self.touch]
115
+ withEvent:[self eventWithTouches:[NSSet setWithObject:self.touch]]];
116
+ }
117
+
118
+ - (void)testPreventionTargetsExactHandlerAndUsesExternalHost
119
+ {
120
+ RCTSurfaceTouchHandler *otherHandler = [RCTSurfaceTouchHandler new];
121
+ UIPanGestureRecognizer *nativePan = [UIPanGestureRecognizer new];
122
+ XCTAssertTrue([self.bridge canPreventGestureRecognizer:self.handler]);
123
+ XCTAssertFalse([self.bridge canPreventGestureRecognizer:otherHandler]);
124
+ XCTAssertFalse([self.bridge canPreventGestureRecognizer:nativePan]);
125
+ XCTAssertTrue([self.handler canBePreventedByGestureRecognizer:self.bridge]);
126
+
127
+ [self.content addGestureRecognizer:nativePan];
128
+ XCTAssertFalse([self.handler canBePreventedByGestureRecognizer:nativePan]);
129
+ }
130
+
131
+ - (void)testOnlyBeganPanWithTrackedLiveTouchActivates
132
+ {
133
+ [self.bridge cancelPressForPan:self.pan];
134
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStatePossible);
135
+ [self beginSingleTouch];
136
+ for (NSNumber *state in @[@(UIGestureRecognizerStatePossible),
137
+ @(UIGestureRecognizerStateChanged),
138
+ @(UIGestureRecognizerStateFailed),
139
+ @(UIGestureRecognizerStateEnded)]) {
140
+ self.pan.testState = (UIGestureRecognizerState)state.integerValue;
141
+ [self.bridge cancelPressForPan:self.pan];
142
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStatePossible);
143
+ }
144
+ self.pan.testState = UIGestureRecognizerStateBegan;
145
+ [self.bridge cancelPressForPan:self.pan];
146
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStateBegan);
147
+ }
148
+
149
+ - (void)testEndedAndCancelledOriginTouchesCannotActivate
150
+ {
151
+ [self beginSingleTouch];
152
+ for (NSNumber *phase in @[@(UITouchPhaseEnded), @(UITouchPhaseCancelled)]) {
153
+ self.touch.testPhase = (UITouchPhase)phase.integerValue;
154
+ [self.bridge cancelPressForPan:self.pan];
155
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStatePossible);
156
+ }
157
+ }
158
+
159
+ - (void)testSecondActiveTouchOutsidePagerButOnSameSurfaceBlocksCancellation
160
+ {
161
+ UIView *sibling = [UIView new];
162
+ [self.surface addSubview:sibling];
163
+ RNCPressCancellationTestTouch *second = [self touchInView:sibling phase:UITouchPhaseStationary];
164
+ [self beginSingleTouch];
165
+ [self.bridge touchesMoved:[NSSet setWithObject:self.touch]
166
+ withEvent:[self eventWithTouches:[NSSet setWithObjects:self.touch, second, nil]]];
167
+ [self.bridge cancelPressForPan:self.pan];
168
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStatePossible);
169
+ }
170
+
171
+ - (void)testOtherSurfaceAndFinishedTouchesDoNotCountAsActiveSurfaceTouches
172
+ {
173
+ UIView *otherSurface = [UIView new];
174
+ [self.host addSubview:otherSurface];
175
+ RNCPressCancellationTestTouch *other = [self touchInView:otherSurface phase:UITouchPhaseMoved];
176
+ RNCPressCancellationTestTouch *ended = [self touchInView:self.surface phase:UITouchPhaseEnded];
177
+ RNCPressCancellationTestTouch *cancelled = [self touchInView:self.content phase:UITouchPhaseCancelled];
178
+ [self.bridge touchesBegan:[NSSet setWithObject:self.touch]
179
+ withEvent:[self eventWithTouches:[NSSet setWithObjects:self.touch, other, ended, cancelled, nil]]];
180
+ [self.bridge cancelPressForPan:self.pan];
181
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStateBegan);
182
+ }
183
+
184
+ - (void)testMultipleOriginTouchesFailWithoutRecognizing
185
+ {
186
+ RNCPressCancellationTestTouch *second = [self touchInView:self.content phase:UITouchPhaseBegan];
187
+ NSSet<UITouch *> *touches = [NSSet setWithObjects:self.touch, second, nil];
188
+ [self.bridge touchesBegan:touches withEvent:[self eventWithTouches:touches]];
189
+ XCTAssertTrue([self.bridge.requestedStates containsObject:@(UIGestureRecognizerStateFailed)]);
190
+ XCTAssertNotEqual(self.bridge.state, UIGestureRecognizerStateBegan);
191
+ [self.bridge cancelPressForPan:self.pan];
192
+ XCTAssertNotEqual(self.bridge.state, UIGestureRecognizerStateBegan);
193
+ }
194
+
195
+ - (void)testSecondTouchAfterRecognitionDoesNotFailOrEndTheTrackedGesture
196
+ {
197
+ [self beginSingleTouch];
198
+ [self.bridge cancelPressForPan:self.pan];
199
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStateBegan);
200
+ RNCPressCancellationTestTouch *second = [self touchInView:self.content phase:UITouchPhaseBegan];
201
+ RNCPressCancellationTestEvent *event =
202
+ [self eventWithTouches:[NSSet setWithObjects:self.touch, second, nil]];
203
+ NSUInteger requestCount = self.bridge.requestedStates.count;
204
+ XCTAssertNoThrow([self.bridge touchesBegan:[NSSet setWithObject:second] withEvent:event]);
205
+ XCTAssertEqual(self.bridge.requestedStates.count, requestCount);
206
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStateBegan);
207
+ second.testPhase = UITouchPhaseEnded;
208
+ [self.bridge touchesEnded:[NSSet setWithObject:second] withEvent:event];
209
+ XCTAssertEqual(self.bridge.requestedStates.count, requestCount);
210
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStateBegan);
211
+ self.touch.testPhase = UITouchPhaseEnded;
212
+ [self.bridge touchesEnded:[NSSet setWithObject:self.touch] withEvent:event];
213
+ XCTAssertTrue([self.bridge.requestedStates containsObject:@(UIGestureRecognizerStateEnded)]);
214
+ XCTAssertNotEqual(self.bridge.state, UIGestureRecognizerStateBegan);
215
+ }
216
+
217
+ - (void)testSecondTouchCancellationDoesNotCancelTheTrackedGesture
218
+ {
219
+ [self beginSingleTouch];
220
+ [self.bridge cancelPressForPan:self.pan];
221
+ RNCPressCancellationTestTouch *second = [self touchInView:self.content phase:UITouchPhaseBegan];
222
+ RNCPressCancellationTestEvent *event =
223
+ [self eventWithTouches:[NSSet setWithObjects:self.touch, second, nil]];
224
+ [self.bridge touchesBegan:[NSSet setWithObject:second] withEvent:event];
225
+ second.testPhase = UITouchPhaseCancelled;
226
+ [self.bridge touchesCancelled:[NSSet setWithObject:second] withEvent:event];
227
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStateBegan);
228
+ self.touch.testPhase = UITouchPhaseCancelled;
229
+ [self.bridge touchesCancelled:[NSSet setWithObject:self.touch] withEvent:event];
230
+ XCTAssertTrue([self.bridge.requestedStates containsObject:@(UIGestureRecognizerStateCancelled)]);
231
+ XCTAssertNotEqual(self.bridge.state, UIGestureRecognizerStateBegan);
232
+ }
233
+
234
+ - (void)testRejectedSameSurfaceTouchRemainsLatchedUntilReset
235
+ {
236
+ UIView *sibling = [UIView new];
237
+ [self.surface addSubview:sibling];
238
+ RNCPressCancellationTestTouch *second = [self touchInView:sibling phase:UITouchPhaseBegan];
239
+ [self beginSingleTouch];
240
+ // The pager delegate observes this touch even when it rejects delivery to the bridge.
241
+ [self.bridge observeIncomingTouch:second];
242
+ second.testPhase = UITouchPhaseEnded;
243
+ [self.bridge touchesMoved:[NSSet setWithObject:self.touch]
244
+ withEvent:[self eventWithTouches:[NSSet setWithObject:self.touch]]];
245
+ [self.bridge cancelPressForPan:self.pan];
246
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStatePossible);
247
+ [self.bridge reset];
248
+ [self beginSingleTouch];
249
+ [self.bridge cancelPressForPan:self.pan];
250
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStateBegan);
251
+ }
252
+
253
+ - (void)testObservedOtherSurfaceTouchDoesNotLatchCurrentSurface
254
+ {
255
+ UIView *otherSurface = [UIView new];
256
+ [self.host addSubview:otherSurface];
257
+ RNCPressCancellationTestTouch *second = [self touchInView:otherSurface phase:UITouchPhaseBegan];
258
+ [self beginSingleTouch];
259
+ [self.bridge observeIncomingTouch:second];
260
+ [self.bridge cancelPressForPan:self.pan];
261
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStateBegan);
262
+ }
263
+
264
+ - (void)testHostMismatchDoesNotCancel
265
+ {
266
+ [self.host removeGestureRecognizer:self.bridge];
267
+ [self.surface addGestureRecognizer:self.bridge];
268
+ [self beginSingleTouch];
269
+ [self.bridge cancelPressForPan:self.pan];
270
+ XCTAssertNotEqual(self.bridge.state, UIGestureRecognizerStateBegan);
271
+ [self.surface removeGestureRecognizer:self.bridge];
272
+ }
273
+
274
+ - (void)testResetDropsPendingTouchAndAllowsANewSequence
275
+ {
276
+ [self beginSingleTouch];
277
+ [self.bridge reset];
278
+ [self.bridge cancelPressForPan:self.pan];
279
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStatePossible);
280
+ [self beginSingleTouch];
281
+ [self.bridge cancelPressForPan:self.pan];
282
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStateBegan);
283
+ }
284
+
285
+ - (void)testRecognizedSequenceEndsAndReleasesEvent
286
+ {
287
+ __weak UIEvent *weakEvent;
288
+ @autoreleasepool {
289
+ RNCPressCancellationTestEvent *event = [self eventWithTouches:[NSSet setWithObject:self.touch]];
290
+ weakEvent = event;
291
+ [self.bridge touchesBegan:[NSSet setWithObject:self.touch] withEvent:event];
292
+ [self.bridge cancelPressForPan:self.pan];
293
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStateBegan);
294
+ self.touch.testPhase = UITouchPhaseEnded;
295
+ [self.bridge touchesEnded:[NSSet setWithObject:self.touch] withEvent:event];
296
+ XCTAssertTrue([self.bridge.requestedStates containsObject:@(UIGestureRecognizerStateEnded)]);
297
+ XCTAssertNotEqual(self.bridge.state, UIGestureRecognizerStateBegan);
298
+ }
299
+ XCTAssertNil(weakEvent);
300
+ }
301
+
302
+ - (void)testUnrecognizedCancellationFailsAndReleasesEvent
303
+ {
304
+ __weak UIEvent *weakEvent;
305
+ @autoreleasepool {
306
+ RNCPressCancellationTestEvent *event = [self eventWithTouches:[NSSet setWithObject:self.touch]];
307
+ weakEvent = event;
308
+ [self.bridge touchesBegan:[NSSet setWithObject:self.touch] withEvent:event];
309
+ self.touch.testPhase = UITouchPhaseCancelled;
310
+ [self.bridge touchesCancelled:[NSSet setWithObject:self.touch] withEvent:event];
311
+ XCTAssertTrue([self.bridge.requestedStates containsObject:@(UIGestureRecognizerStateFailed)]);
312
+ XCTAssertNotEqual(self.bridge.state, UIGestureRecognizerStateBegan);
313
+ }
314
+ XCTAssertNil(weakEvent);
315
+ }
316
+
317
+ - (void)testRecognizedCancellationTerminatesTheBridge
318
+ {
319
+ [self beginSingleTouch];
320
+ [self.bridge cancelPressForPan:self.pan];
321
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStateBegan);
322
+ self.touch.testPhase = UITouchPhaseCancelled;
323
+ [self.bridge touchesCancelled:[NSSet setWithObject:self.touch]
324
+ withEvent:[self eventWithTouches:[NSSet setWithObject:self.touch]]];
325
+ XCTAssertTrue([self.bridge.requestedStates containsObject:@(UIGestureRecognizerStateCancelled)]);
326
+ XCTAssertNotEqual(self.bridge.state, UIGestureRecognizerStateBegan);
327
+ }
328
+
329
+ - (void)testHandlerBindingIsWeak
330
+ {
331
+ __weak UIGestureRecognizer *weakHandler;
332
+ @autoreleasepool {
333
+ UIGestureRecognizer *handler = [UIGestureRecognizer new];
334
+ weakHandler = handler;
335
+ self.bridge.reactTouchHandler = handler;
336
+ XCTAssertTrue([self.bridge canPreventGestureRecognizer:handler]);
337
+ XCTAssertFalse([self.bridge canPreventGestureRecognizer:self.handler]);
338
+ }
339
+ XCTAssertNil(weakHandler);
340
+ XCTAssertNil(self.bridge.reactTouchHandler);
341
+ [self beginSingleTouch];
342
+ [self.bridge cancelPressForPan:self.pan];
343
+ XCTAssertEqual(self.bridge.state, UIGestureRecognizerStatePossible);
344
+ }
345
+
346
+ @end
@@ -0,0 +1,109 @@
1
+ #import <XCTest/XCTest.h>
2
+ #import <React/RCTSurfaceTouchHandler.h>
3
+
4
+ #import "RNCCollapsiblePagerViewComponentView.h"
5
+ #import <react/renderer/components/pagerview/Props.h>
6
+
7
+ using namespace facebook::react;
8
+
9
+ @interface RNCPressWiringTestTouch : UITouch
10
+ @property (nonatomic, strong) UIView *testView;
11
+ @end
12
+ @implementation RNCPressWiringTestTouch
13
+ - (UIView *)view { return self.testView; }
14
+ @end
15
+
16
+ @interface RNCCollapsiblePagerPressCancellationWiringTests : XCTestCase
17
+ @property (nonatomic, strong) UIWindow *window;
18
+ @property (nonatomic, strong) UIView *host;
19
+ @property (nonatomic, strong) UIView *surface;
20
+ @property (nonatomic, strong) RCTSurfaceTouchHandler *handler;
21
+ @property (nonatomic, strong) RNCCollapsiblePagerViewComponentView *pager;
22
+ @end
23
+
24
+ @implementation RNCCollapsiblePagerPressCancellationWiringTests
25
+
26
+ - (void)setUp
27
+ {
28
+ [super setUp];
29
+ // Window membership installs the bridge without presenting or taking focus.
30
+ self.window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 600)];
31
+ self.host = [[UIView alloc] initWithFrame:self.window.bounds];
32
+ self.surface = [[UIView alloc] initWithFrame:self.host.bounds];
33
+ [self.window addSubview:self.host];
34
+ [self.host addSubview:self.surface];
35
+ self.handler = [RCTSurfaceTouchHandler new];
36
+ [self.handler attachToView:self.surface];
37
+ self.pager = [[RNCCollapsiblePagerViewComponentView alloc] init];
38
+ auto props = std::make_shared<RNCCollapsiblePagerViewProps>();
39
+ props->nativeSmoothHeaderScrollEnabled = true;
40
+ [self.pager updateProps:props oldProps:nullptr];
41
+ self.pager.frame = self.surface.bounds;
42
+ [self.surface addSubview:self.pager];
43
+ }
44
+
45
+ - (void)tearDown
46
+ {
47
+ [self.pager removeFromSuperview];
48
+ [self.handler detachFromView:self.surface];
49
+ self.pager = nil;
50
+ self.handler = nil;
51
+ self.surface = nil;
52
+ self.host = nil;
53
+ self.window = nil;
54
+ [super tearDown];
55
+ }
56
+
57
+ - (void)testInstalledBridgeCancelsTouchesAndFiltersItsContentScope
58
+ {
59
+ UIGestureRecognizer *bridge = [self.pager valueForKey:@"contentPressCancellationGesture"];
60
+ XCTAssertNotNil(bridge);
61
+ XCTAssertTrue([bridge isKindOfClass:NSClassFromString(@"RNCCollapsiblePagerContentPressCancellationGestureRecognizer")]);
62
+ XCTAssertEqual(bridge.view, self.host);
63
+ XCTAssertEqual([bridge valueForKey:@"reactTouchHandler"], self.handler);
64
+ XCTAssertTrue(bridge.cancelsTouchesInView);
65
+ XCTAssertFalse(bridge.delaysTouchesBegan);
66
+ XCTAssertFalse(bridge.delaysTouchesEnded);
67
+ XCTAssertTrue([self.handler canBePreventedByGestureRecognizer:bridge]);
68
+
69
+ UIScrollView *scrollView = [self.pager valueForKey:@"pagerScrollView"];
70
+ XCTAssertNotNil(scrollView);
71
+ UIView *content = [UIView new];
72
+ [scrollView addSubview:content];
73
+ UIView *header = [self.pager valueForKey:@"sharedHeaderHostView"];
74
+ // Smooth mode reparents the shared header into the same content subtree.
75
+ [scrollView addSubview:header];
76
+ UIView *headerButton = [UIView new];
77
+ [header addSubview:headerButton];
78
+ RNCPressWiringTestTouch *touch = [RNCPressWiringTestTouch new];
79
+ id<UIGestureRecognizerDelegate> delegate = bridge.delegate;
80
+ XCTAssertEqual((id)delegate, self.pager);
81
+ touch.testView = content;
82
+ XCTAssertTrue([delegate gestureRecognizer:bridge shouldReceiveTouch:touch]);
83
+ touch.testView = headerButton;
84
+ XCTAssertFalse([delegate gestureRecognizer:bridge shouldReceiveTouch:touch]);
85
+ touch.testView = self.surface;
86
+ XCTAssertFalse([delegate gestureRecognizer:bridge shouldReceiveTouch:touch]);
87
+ }
88
+
89
+ - (void)testWindowDetachUnbindsInstalledBridge
90
+ {
91
+ UIGestureRecognizer *bridge = [self.pager valueForKey:@"contentPressCancellationGesture"];
92
+ XCTAssertNotNil(bridge);
93
+ [self.pager removeFromSuperview];
94
+ XCTAssertNil(bridge.view);
95
+ XCTAssertNil([bridge valueForKey:@"reactTouchHandler"]);
96
+ XCTAssertNil([self.pager valueForKey:@"contentPressCancellationGesture"]);
97
+ }
98
+
99
+ - (void)testRecycleUnbindsInstalledBridge
100
+ {
101
+ UIGestureRecognizer *bridge = [self.pager valueForKey:@"contentPressCancellationGesture"];
102
+ XCTAssertNotNil(bridge);
103
+ [self.pager prepareForRecycle];
104
+ XCTAssertNil(bridge.view);
105
+ XCTAssertNil([bridge valueForKey:@"reactTouchHandler"]);
106
+ XCTAssertNil([self.pager valueForKey:@"contentPressCancellationGesture"]);
107
+ }
108
+
109
+ @end