@onekeyfe/react-native-pager-view 3.0.161 → 3.0.162-alpha.268

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
- UIScrollView *scrollView = (UIScrollView *)object;
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
- UIScrollView *scrollView = _sharedHeaderScrollView;
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.161",
3
+ "version": "3.0.162-alpha.268",
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.161",
72
+ "@onekeyfe/react-native-native-logger": "3.0.162-alpha.268",
73
73
  "react": "*",
74
74
  "react-native": "*"
75
75
  },