@onekeyfe/react-native-pager-view 3.0.161 → 3.0.162-alpha.270
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/docs/SPEC.md
CHANGED
|
@@ -165,28 +165,6 @@ warnings were observed. Keyboard, multi-touch, physical-device performance and
|
|
|
165
165
|
the full lifecycle/interaction matrix remain unverified. These are local source
|
|
166
166
|
builds; the currently installed npm version does not yet contain this migration.
|
|
167
167
|
|
|
168
|
-
## iOS vertical-scroll press cancellation
|
|
169
|
-
|
|
170
|
-
Status: implemented in source. A source-identical `node_modules` build was
|
|
171
|
-
runtime verified on a dedicated iOS 26.5 HomePager simulator on 2026-09-30:
|
|
172
|
-
a slow drag from the Show more button did not activate it, a fling from the
|
|
173
|
-
same button scrolled the list, and a stationary tap activated it. The Pager
|
|
174
|
-
XCTest suite passed 47/47 tests on a separate iOS 26.5 simulator with its data
|
|
175
|
-
on the external drive on 2026-09-30.
|
|
176
|
-
|
|
177
|
-
In `CollapsiblePagerView` smooth-header mode, a single-finger
|
|
178
|
-
vertical drag beginning on React page content MUST cancel that Surface's active
|
|
179
|
-
React press before finger-up once vertical displacement reaches 10 points and
|
|
180
|
-
exceeds horizontal displacement. Cancellation MUST leave the native vertical
|
|
181
|
-
scroller's pan and momentum intact. Stationary taps, movement below the threshold,
|
|
182
|
-
horizontal drags, and multi-touch sequences MUST retain their existing behavior.
|
|
183
|
-
The iOS content press bridge owns cancellation on the UI thread; the pager's
|
|
184
|
-
existing horizontal-drag cancellation remains independent. The bridge MUST clear
|
|
185
|
-
per-touch state on end, cancellation, and reuse. Android and Web behavior is
|
|
186
|
-
unchanged. Acceptance requires a real iOS button-origin drag that does not fire
|
|
187
|
-
the button, a button-origin fling that scrolls, an ordinary tap that fires, and
|
|
188
|
-
focused native touch-delivery coverage.
|
|
189
|
-
|
|
190
168
|
## Native tab-press animation default
|
|
191
169
|
|
|
192
170
|
Behavior change: previously an omitted `nativeTabPressAnimationEnabled` animated
|
|
@@ -328,24 +306,6 @@ and refresh completion, caller offset changes, late installation/replacement,
|
|
|
328
306
|
retained-page switching, clipping and nested-owner cleanup. Programmatic UIKit
|
|
329
307
|
unit tests do not substitute for real pull-gesture visibility acceptance.
|
|
330
308
|
|
|
331
|
-
When a smooth shared header is attached to the active iOS scroll view, UIKit's
|
|
332
|
-
temporary refresh top inset MUST keep the header and content aligned. Both are
|
|
333
|
-
children of that scroll view and move together with its content offset; the
|
|
334
|
-
pager MUST NOT apply a separate refresh translation to the header. The scroll
|
|
335
|
-
view's inset and offset, the refresh indicator, and refresh callback ownership
|
|
336
|
-
remain unchanged. Removing the refresh inset or control preserves this alignment
|
|
337
|
-
even without a scroll-offset event. Caller inset changes update the pager
|
|
338
|
-
baseline. The sticky tab row MUST pin against the baseline top inset; the
|
|
339
|
-
refresh control's temporary inset MUST NOT move it below the content, including
|
|
340
|
-
rapid direction reversals while the spinner is active. Detaching the header
|
|
341
|
-
restores its normal transform. This applies to RN NativeScroller and NativeList
|
|
342
|
-
pages; non-smooth and detached headers keep
|
|
343
|
-
their existing positioning. The 2026-09-30 Home Spot simulator checkpoint covers
|
|
344
|
-
shared header/content alignment and inset removal. A separate source-identical
|
|
345
|
-
local package build verified the sticky row during active-refresh vertical
|
|
346
|
-
reversals; published-package, other Home pages and physical-device acceptance
|
|
347
|
-
remain open.
|
|
348
|
-
|
|
349
309
|
## iOS shared-header hit testing
|
|
350
310
|
|
|
351
311
|
Smooth-header hit forwarding is restricted to the pager's own interactive
|
|
@@ -1033,8 +1033,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1033
1033
|
__weak UITouch *_trackedTouch;
|
|
1034
1034
|
UIEvent *_touchEvent;
|
|
1035
1035
|
BOOL _multipleSurfaceTouchesObserved;
|
|
1036
|
-
CGPoint _trackedTouchStartPoint;
|
|
1037
|
-
BOOL _didCancelReactPressForVerticalMovement;
|
|
1038
1036
|
}
|
|
1039
1037
|
|
|
1040
1038
|
- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)other
|
|
@@ -1071,37 +1069,12 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1071
1069
|
return;
|
|
1072
1070
|
}
|
|
1073
1071
|
_trackedTouch = touches.anyObject;
|
|
1074
|
-
_trackedTouchStartPoint = [_trackedTouch locationInView:self.view];
|
|
1075
|
-
_didCancelReactPressForVerticalMovement = NO;
|
|
1076
1072
|
[self recordEvent:event];
|
|
1077
1073
|
}
|
|
1078
1074
|
|
|
1079
1075
|
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
|
1080
1076
|
{
|
|
1081
1077
|
[self recordEvent:event];
|
|
1082
|
-
UITouch *touch = _trackedTouch;
|
|
1083
|
-
UIGestureRecognizer *handler = self.reactTouchHandler;
|
|
1084
|
-
if (touch == nil || ![touches containsObject:touch] ||
|
|
1085
|
-
self.state != UIGestureRecognizerStatePossible ||
|
|
1086
|
-
_didCancelReactPressForVerticalMovement || _multipleSurfaceTouchesObserved ||
|
|
1087
|
-
handler.view == nil || self.view != handler.view.superview ||
|
|
1088
|
-
handler.state == UIGestureRecognizerStateFailed ||
|
|
1089
|
-
handler.state == UIGestureRecognizerStateCancelled ||
|
|
1090
|
-
handler.state == UIGestureRecognizerStateEnded) return;
|
|
1091
|
-
CGPoint point = [touch locationInView:self.view];
|
|
1092
|
-
CGFloat dx = point.x - _trackedTouchStartPoint.x;
|
|
1093
|
-
CGFloat dy = point.y - _trackedTouchStartPoint.y;
|
|
1094
|
-
if (fabs(dy) < 10.0 || fabs(dy) <= fabs(dx)) return;
|
|
1095
|
-
NSUInteger activeTouches = 0;
|
|
1096
|
-
for (UITouch *activeTouch in event.allTouches) {
|
|
1097
|
-
if (activeTouch.phase == UITouchPhaseEnded ||
|
|
1098
|
-
activeTouch.phase == UITouchPhaseCancelled) continue;
|
|
1099
|
-
if ([activeTouch.view isDescendantOfView:handler.view]) ++activeTouches;
|
|
1100
|
-
}
|
|
1101
|
-
if (activeTouches != 1) return;
|
|
1102
|
-
_didCancelReactPressForVerticalMovement = YES;
|
|
1103
|
-
handler.enabled = NO;
|
|
1104
|
-
handler.enabled = YES;
|
|
1105
1078
|
}
|
|
1106
1079
|
|
|
1107
1080
|
- (void)cancelPressForPan:(UIPanGestureRecognizer *)pan
|
|
@@ -1135,7 +1108,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1135
1108
|
? UIGestureRecognizerStateEnded : UIGestureRecognizerStateFailed;
|
|
1136
1109
|
_trackedTouch = nil;
|
|
1137
1110
|
_touchEvent = nil;
|
|
1138
|
-
_didCancelReactPressForVerticalMovement = NO;
|
|
1139
1111
|
}
|
|
1140
1112
|
|
|
1141
1113
|
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
|
|
@@ -1145,7 +1117,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1145
1117
|
? UIGestureRecognizerStateCancelled : UIGestureRecognizerStateFailed;
|
|
1146
1118
|
_trackedTouch = nil;
|
|
1147
1119
|
_touchEvent = nil;
|
|
1148
|
-
_didCancelReactPressForVerticalMovement = NO;
|
|
1149
1120
|
}
|
|
1150
1121
|
|
|
1151
1122
|
- (void)reset
|
|
@@ -1154,7 +1125,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1154
1125
|
_trackedTouch = nil;
|
|
1155
1126
|
_touchEvent = nil;
|
|
1156
1127
|
_multipleSurfaceTouchesObserved = NO;
|
|
1157
|
-
_didCancelReactPressForVerticalMovement = NO;
|
|
1158
1128
|
}
|
|
1159
1129
|
|
|
1160
1130
|
@end
|
|
@@ -2467,10 +2437,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2467
2437
|
forKeyPath:@"contentOffset"
|
|
2468
2438
|
options:NSKeyValueObservingOptionNew
|
|
2469
2439
|
context:RNCCollapsiblePagerContentOffsetContext];
|
|
2470
|
-
[candidate addObserver:self
|
|
2471
|
-
forKeyPath:@"contentInset"
|
|
2472
|
-
options:NSKeyValueObservingOptionNew
|
|
2473
|
-
context:RNCCollapsiblePagerContentOffsetContext];
|
|
2474
2440
|
[candidate addObserver:self
|
|
2475
2441
|
forKeyPath:@"contentSize"
|
|
2476
2442
|
options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
|
|
@@ -2493,9 +2459,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2493
2459
|
[scrollView removeObserver:self
|
|
2494
2460
|
forKeyPath:@"contentOffset"
|
|
2495
2461
|
context:RNCCollapsiblePagerContentOffsetContext];
|
|
2496
|
-
[scrollView removeObserver:self
|
|
2497
|
-
forKeyPath:@"contentInset"
|
|
2498
|
-
context:RNCCollapsiblePagerContentOffsetContext];
|
|
2499
2462
|
[scrollView removeObserver:self
|
|
2500
2463
|
forKeyPath:@"contentSize"
|
|
2501
2464
|
context:RNCCollapsiblePagerContentOffsetContext];
|
|
@@ -2969,7 +2932,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2969
2932
|
if (appliedTop != nil) {
|
|
2970
2933
|
[_appliedTopInsets setObject:@(appliedTop.doubleValue + next.top - previous.top) forKey:scrollView];
|
|
2971
2934
|
}
|
|
2972
|
-
if (scrollView == _observedScrollView) [self updateHeaderForScrollView:scrollView];
|
|
2973
2935
|
}
|
|
2974
2936
|
|
|
2975
2937
|
- (void)reapplyInsetsToObservedScrollView
|
|
@@ -3002,16 +2964,10 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3002
2964
|
context:(void *)context
|
|
3003
2965
|
{
|
|
3004
2966
|
if (context == RNCScrollRefreshControlContext) {
|
|
3005
|
-
|
|
3006
|
-
[self updateRefreshControlForScrollView:scrollView];
|
|
3007
|
-
if (scrollView == _observedScrollView) [self updateHeaderForScrollView:scrollView];
|
|
2967
|
+
[self updateRefreshControlForScrollView:(UIScrollView *)object];
|
|
3008
2968
|
return;
|
|
3009
2969
|
}
|
|
3010
2970
|
if (context == RNCCollapsiblePagerContentOffsetContext && object == _observedScrollView) {
|
|
3011
|
-
if ([keyPath isEqualToString:@"contentInset"]) {
|
|
3012
|
-
[self updateHeaderForScrollView:(UIScrollView *)object];
|
|
3013
|
-
return;
|
|
3014
|
-
}
|
|
3015
2971
|
if ([keyPath isEqualToString:@"contentSize"]) {
|
|
3016
2972
|
NSValue *oldSize = change[NSKeyValueChangeOldKey];
|
|
3017
2973
|
NSValue *newSize = change[NSKeyValueChangeNewKey];
|
|
@@ -3042,15 +2998,9 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3042
2998
|
BOOL attachedToList = _nativeSmoothHeaderScrollEnabled &&
|
|
3043
2999
|
_sharedHeaderScrollView != nil && !_sharedHeadersLiftedForPagerTransition;
|
|
3044
3000
|
if (attachedToList) {
|
|
3045
|
-
// The header and content share this scroll view. UIKit's refresh inset
|
|
3046
|
-
// moves both together, so translating the header would separate them.
|
|
3047
3001
|
_sharedHeaderHostView.transform = CGAffineTransformIdentity;
|
|
3048
3002
|
_headerView.transform = CGAffineTransformIdentity;
|
|
3049
|
-
|
|
3050
|
-
NSNumber *appliedTop = [_appliedTopInsets objectForKey:scrollView];
|
|
3051
|
-
CGFloat refreshInset = scrollView.refreshControl != nil && appliedTop != nil
|
|
3052
|
-
? MAX(0, scrollView.contentInset.top - appliedTop.doubleValue) : 0;
|
|
3053
|
-
CGFloat pinnedTranslation = MAX(0, _currentLogicalOffset - _headerHeight - refreshInset);
|
|
3003
|
+
CGFloat pinnedTranslation = MAX(0, _currentLogicalOffset - _headerHeight);
|
|
3054
3004
|
CGAffineTransform stickyTransform = CGAffineTransformMakeTranslation(0, pinnedTranslation);
|
|
3055
3005
|
_stickyHeaderView.transform = stickyTransform;
|
|
3056
3006
|
_nativeTabBarView.transform = stickyTransform;
|
|
@@ -744,35 +744,6 @@ typedef struct __IOHIDEvent *RNCTestHIDEventRef;
|
|
|
744
744
|
XCTAssertEqual(self.handler.registeredTouches, 0);
|
|
745
745
|
}
|
|
746
746
|
|
|
747
|
-
- (void)testVerticalPageDragCancelsReactPressBeforeFingerLifts
|
|
748
|
-
{
|
|
749
|
-
[self assertFixtureIsReadyForDelivery];
|
|
750
|
-
CGPoint point = [self pressPoint];
|
|
751
|
-
UITouch *touch = [self.driver beginAt:point];
|
|
752
|
-
XCTAssertEqual(self.handler.registeredTouches, 1);
|
|
753
|
-
|
|
754
|
-
[self.driver move:touch to:CGPointMake(point.x, point.y - 12)];
|
|
755
|
-
XCTAssertEqual(self.handler.registeredTouches, 0);
|
|
756
|
-
XCTAssertTrue([self.handler.events containsObject:@"reset-cancelled"] ||
|
|
757
|
-
[self.handler.events containsObject:@"cancelled"],
|
|
758
|
-
@"handler events %@", self.handler.events);
|
|
759
|
-
XCTAssertFalse([self.handler.events containsObject:@"ended"]);
|
|
760
|
-
|
|
761
|
-
[self.driver end:touch];
|
|
762
|
-
XCTAssertFalse([self.handler.events containsObject:@"ended"], @"events %@", self.handler.events);
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
- (void)testSmallVerticalMovementKeepsReactPress
|
|
766
|
-
{
|
|
767
|
-
[self assertFixtureIsReadyForDelivery];
|
|
768
|
-
CGPoint point = [self pressPoint];
|
|
769
|
-
UITouch *touch = [self.driver beginAt:point];
|
|
770
|
-
[self.driver move:touch to:CGPointMake(point.x, point.y - 8)];
|
|
771
|
-
XCTAssertEqual(self.handler.registeredTouches, 1);
|
|
772
|
-
[self.driver end:touch];
|
|
773
|
-
XCTAssertEqualObjects(self.handler.events, (@[@"began", @"moved", @"ended"]));
|
|
774
|
-
}
|
|
775
|
-
|
|
776
747
|
- (void)testSmallMovementBelowPanThresholdKeepsReactPress
|
|
777
748
|
{
|
|
778
749
|
[self assertFixtureIsReadyForDelivery];
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
@interface RNCCollapsiblePagerViewComponentView (RefreshControlTesting)
|
|
5
5
|
- (void)updateRefreshControlForScrollView:(UIScrollView *)scrollView;
|
|
6
6
|
- (void)releaseRefreshControlForScrollView:(UIScrollView *)scrollView;
|
|
7
|
-
- (void)attachScrollObserverForCurrentPage;
|
|
8
7
|
@end
|
|
9
8
|
|
|
10
9
|
@interface RNCCollapsiblePagerRefreshControlTests : XCTestCase
|
|
@@ -178,46 +177,4 @@
|
|
|
178
177
|
XCTAssertTrue(control.layer.masksToBounds);
|
|
179
178
|
}
|
|
180
179
|
|
|
181
|
-
- (void)testRefreshTopInsetDoesNotDisplaceAttachedSharedHeader
|
|
182
|
-
{
|
|
183
|
-
RNCCollapsiblePagerViewComponentView *pager = [self pagerWithHeader:64];
|
|
184
|
-
UIScrollView *scroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 600)];
|
|
185
|
-
scroll.refreshControl = [UIRefreshControl new];
|
|
186
|
-
scroll.contentSize = CGSizeMake(320, 2000);
|
|
187
|
-
scroll.contentInset = UIEdgeInsetsMake(232, 0, 0, 0);
|
|
188
|
-
UIView *content = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 2000)];
|
|
189
|
-
[scroll addSubview:content];
|
|
190
|
-
UIViewController *page = [UIViewController new];
|
|
191
|
-
[page.view addSubview:scroll];
|
|
192
|
-
NSMutableArray<UIViewController *> *pages = [pager valueForKey:@"pageControllers"];
|
|
193
|
-
[pages addObject:page];
|
|
194
|
-
[pager attachScrollObserverForCurrentPage];
|
|
195
|
-
UIView *headerHost = [pager valueForKey:@"sharedHeaderHostView"];
|
|
196
|
-
UIView *stickyHeader = [pager valueForKey:@"stickyHeaderView"];
|
|
197
|
-
XCTAssertEqual(headerHost.superview, scroll);
|
|
198
|
-
XCTAssertEqualWithAccuracy(scroll.contentInset.top, 340, 0.001);
|
|
199
|
-
XCTAssertEqualWithAccuracy(headerHost.transform.ty, 0, 0.001);
|
|
200
|
-
|
|
201
|
-
scroll.contentOffset = CGPointMake(0, 500);
|
|
202
|
-
CGFloat baselineStickyTranslation = stickyHeader.transform.ty;
|
|
203
|
-
CGPoint offset = scroll.contentOffset;
|
|
204
|
-
scroll.contentInset = UIEdgeInsetsMake(400, 0, 0, 0);
|
|
205
|
-
XCTAssertTrue(CGPointEqualToPoint(scroll.contentOffset, offset));
|
|
206
|
-
XCTAssertEqualWithAccuracy(headerHost.transform.ty, 0, 0.001);
|
|
207
|
-
XCTAssertEqualWithAccuracy(stickyHeader.transform.ty, baselineStickyTranslation, 0.001);
|
|
208
|
-
XCTAssertEqualWithAccuracy(CGRectGetMaxY(headerHost.frame), CGRectGetMinY(content.frame), 0.001);
|
|
209
|
-
|
|
210
|
-
scroll.contentInset = UIEdgeInsetsMake(340, 0, 0, 0);
|
|
211
|
-
XCTAssertEqualWithAccuracy(headerHost.transform.ty, 0, 0.001);
|
|
212
|
-
XCTAssertEqualWithAccuracy(stickyHeader.transform.ty, baselineStickyTranslation, 0.001);
|
|
213
|
-
|
|
214
|
-
scroll.contentInset = UIEdgeInsetsMake(400, 0, 0, 0);
|
|
215
|
-
XCTAssertEqualWithAccuracy(headerHost.transform.ty, 0, 0.001);
|
|
216
|
-
XCTAssertEqualWithAccuracy(stickyHeader.transform.ty, baselineStickyTranslation, 0.001);
|
|
217
|
-
XCTAssertEqualWithAccuracy(CGRectGetMaxY(headerHost.frame), CGRectGetMinY(content.frame), 0.001);
|
|
218
|
-
scroll.refreshControl = nil;
|
|
219
|
-
XCTAssertEqualWithAccuracy(headerHost.transform.ty, 0, 0.001);
|
|
220
|
-
[pager prepareForRecycle];
|
|
221
|
-
}
|
|
222
|
-
|
|
223
180
|
@end
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/react-native-pager-view",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.162-alpha.270",
|
|
4
4
|
"description": "React Native wrapper for Android and iOS ViewPager",
|
|
5
5
|
"source": "./src/index.tsx",
|
|
6
6
|
"main": "./lib/module/index.js",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"typescript": "^5.9.2"
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
72
|
-
"@onekeyfe/react-native-native-logger": "3.0.
|
|
72
|
+
"@onekeyfe/react-native-native-logger": "3.0.162-alpha.270",
|
|
73
73
|
"react": "*",
|
|
74
74
|
"react-native": "*"
|
|
75
75
|
},
|