@onekeyfe/react-native-pager-view 3.0.162-alpha.272 → 3.0.163

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.
@@ -364,13 +364,14 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
364
364
  fun removeAllReactChildren() {
365
365
  releaseRefreshForeground()
366
366
  detachPrimaryScrollObserver()
367
- for (recycler in originalRecyclerPadding.keys.toList()) {
367
+ // Weak keys may disappear after size is read; Collection.toArray tolerates this.
368
+ for (recycler in originalRecyclerPadding.keys.toTypedArray()) {
368
369
  restoreRecyclerInsets(recycler)
369
370
  }
370
- for (scroller in originalScrollerPadding.keys.toList()) {
371
+ for (scroller in originalScrollerPadding.keys.toTypedArray()) {
371
372
  restoreNativeScrollerInsets(scroller)
372
373
  }
373
- for (scroller in ownedScrollerKeys.keys.toList()) restoreOwnedScrollerInsets(scroller)
374
+ for (scroller in ownedScrollerKeys.keys.toTypedArray()) restoreOwnedScrollerInsets(scroller)
374
375
  headerView?.let { view -> super.removeView(view) }
375
376
  stickyHeaderView?.let { view -> super.removeView(view) }
376
377
  headerView = null
@@ -1504,13 +1505,14 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
1504
1505
  nestedNativeGestureStarted = false
1505
1506
  viewTreeObserver.removeOnPreDrawListener(pageContentLayoutListener)
1506
1507
  detachPrimaryScrollObserver()
1507
- for (recycler in originalRecyclerPadding.keys.toList()) {
1508
+ // Snapshot live keys before restoration removes their padding records.
1509
+ for (recycler in originalRecyclerPadding.keys.toTypedArray()) {
1508
1510
  restoreRecyclerInsets(recycler)
1509
1511
  }
1510
- for (scroller in originalScrollerPadding.keys.toList()) {
1512
+ for (scroller in originalScrollerPadding.keys.toTypedArray()) {
1511
1513
  restoreNativeScrollerInsets(scroller)
1512
1514
  }
1513
- for (scroller in ownedScrollerKeys.keys.toList()) restoreOwnedScrollerInsets(scroller)
1515
+ for (scroller in ownedScrollerKeys.keys.toTypedArray()) restoreOwnedScrollerInsets(scroller)
1514
1516
  log(
1515
1517
  "host-detach generation=$attachmentGeneration inner=$selectedPage " +
1516
1518
  "outer=${outerPagerIndex()} nativePages=${adapter.itemCount}",
package/docs/SPEC.md CHANGED
@@ -165,6 +165,28 @@ 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
+
168
190
  ## Native tab-press animation default
169
191
 
170
192
  Behavior change: previously an omitted `nativeTabPressAnimationEnabled` animated
@@ -306,6 +328,24 @@ and refresh completion, caller offset changes, late installation/replacement,
306
328
  retained-page switching, clipping and nested-owner cleanup. Programmatic UIKit
307
329
  unit tests do not substitute for real pull-gesture visibility acceptance.
308
330
 
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
+
309
349
  ## iOS shared-header hit testing
310
350
 
311
351
  Smooth-header hit forwarding is restricted to the pager's own interactive
@@ -413,3 +453,73 @@ The focused policy regression includes nonzero caller left/right/bottom padding,
413
453
  nonzero prior native insets, explicit caller padding changes/clear, and initial
414
454
  discovery before ownership. Current Home zero-padding behavior is unchanged by
415
455
  this ownership guard.
456
+
457
+ ## Weak padding-record cleanup
458
+
459
+ Status: Implemented. Android detach/reattach acceptance passed on the
460
+ pre-migration host described below. Remove-all and owned NativeScroller cleanup
461
+ have source and focused regression coverage; current-host device acceptance is
462
+ pending.
463
+
464
+ ### Scope and ownership
465
+
466
+ This specification covers restoring child scroll insets when a collapsible pager
467
+ detaches or removes all React children. Other pager behavior remains documented
468
+ in the package README. Navigation animations belong to the consuming app.
469
+
470
+ The native host owns its temporary inset changes and original-padding records.
471
+ Android lifecycle callbacks and restoration run on the UI thread. Garbage
472
+ collection can clear weak child references independently of that thread.
473
+
474
+ ### API, lifecycle, and identity
475
+
476
+ No public props, events, defaults, or serialization formats change. Detaching
477
+ and removing all children must restore the original insets of every still-live
478
+ tracked RecyclerView, native ScrollView, and owned NativeScroller viewport.
479
+ Restoration may remove entries from the tracking maps. Reattaching must remain supported.
480
+
481
+ Padding records are keyed by native child identity using weak references. The
482
+ host must not retain removed scroll children solely for later cleanup. A cleanup
483
+ snapshot temporarily holds surviving children strongly until restoration ends.
484
+
485
+ ### Platforms and failure handling
486
+
487
+ Android uses WeakHashMap padding records. Its snapshot must tolerate keys being
488
+ collected between reading the collection size and enumerating it, including
489
+ single-entry and multiple-entry maps. Collected children require no restoration;
490
+ they must not cause NoSuchElementException. Live children must not be skipped
491
+ because restoration changes the map.
492
+
493
+ iOS uses weak-key NSMapTable records and keyEnumerator.allObjects snapshots in
494
+ restoreDetachedScrollInsets. Its implementation is unchanged. Web has no Android
495
+ native-padding records and is unaffected.
496
+
497
+ ### Resource budget
498
+
499
+ Cleanup performs one snapshot and one restoration per surviving tracked child
500
+ on the UI thread. Temporary storage is proportional to the existing padding
501
+ records; no new persistent cache, retry, background task, or bridge traffic is
502
+ introduced. This change makes no frame-rate claim.
503
+
504
+ ### Conformance and acceptance
505
+
506
+ - Source: android/src/main/java/com/reactnativepagerview/CollapsiblePagerHost.kt,
507
+ removeAllReactChildren and onDetachedFromWindow.
508
+ - Focused JVM regression: tests/kotlin/WeakPaddingSnapshotTest.kt checks a
509
+ shrinking weak-key collection and restoration that removes snapshot entries.
510
+ - The same regression passed seven assertions on Android 36 ART using Kotlin
511
+ 2.1.20. Compile it without additional dependencies, then run its main function.
512
+ - Android acceptance: build the native host, repeatedly navigate from a populated
513
+ Market pager into stock/token details and back, and exercise modal dismissal.
514
+ Check native fatal logs and pager scroll/header state after returning.
515
+ - Runtime evidence on 2026-10-08 against the pre-migration host (1e1809509):
516
+ four NVDA detail visits and gesture returns,
517
+ BTC detail, quick settings Sheet and chart settings modal dismissal, Market
518
+ Perps tab entry/return, and header collapse/expand passed. The app retained its
519
+ PID and produced no app-native fatal crash during this run.
520
+ - Source and JVM checks do not establish native device acceptance or iOS visual
521
+ parity. Update runtime status only after the actual app has been exercised.
522
+
523
+ The newly merged NativeScroller viewport tracking uses the same weak-key
524
+ snapshot rule. Its cleanup has source and focused regression coverage; the
525
+ pre-migration runtime checks above do not establish its device acceptance.
@@ -1033,6 +1033,8 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
1033
1033
  __weak UITouch *_trackedTouch;
1034
1034
  UIEvent *_touchEvent;
1035
1035
  BOOL _multipleSurfaceTouchesObserved;
1036
+ CGPoint _trackedTouchStartPoint;
1037
+ BOOL _didCancelReactPressForVerticalMovement;
1036
1038
  }
1037
1039
 
1038
1040
  - (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)other
@@ -1069,12 +1071,37 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
1069
1071
  return;
1070
1072
  }
1071
1073
  _trackedTouch = touches.anyObject;
1074
+ _trackedTouchStartPoint = [_trackedTouch locationInView:self.view];
1075
+ _didCancelReactPressForVerticalMovement = NO;
1072
1076
  [self recordEvent:event];
1073
1077
  }
1074
1078
 
1075
1079
  - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
1076
1080
  {
1077
1081
  [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;
1078
1105
  }
1079
1106
 
1080
1107
  - (void)cancelPressForPan:(UIPanGestureRecognizer *)pan
@@ -1108,6 +1135,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
1108
1135
  ? UIGestureRecognizerStateEnded : UIGestureRecognizerStateFailed;
1109
1136
  _trackedTouch = nil;
1110
1137
  _touchEvent = nil;
1138
+ _didCancelReactPressForVerticalMovement = NO;
1111
1139
  }
1112
1140
 
1113
1141
  - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
@@ -1117,6 +1145,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
1117
1145
  ? UIGestureRecognizerStateCancelled : UIGestureRecognizerStateFailed;
1118
1146
  _trackedTouch = nil;
1119
1147
  _touchEvent = nil;
1148
+ _didCancelReactPressForVerticalMovement = NO;
1120
1149
  }
1121
1150
 
1122
1151
  - (void)reset
@@ -1125,6 +1154,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
1125
1154
  _trackedTouch = nil;
1126
1155
  _touchEvent = nil;
1127
1156
  _multipleSurfaceTouchesObserved = NO;
1157
+ _didCancelReactPressForVerticalMovement = NO;
1128
1158
  }
1129
1159
 
1130
1160
  @end
@@ -2437,6 +2467,10 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
2437
2467
  forKeyPath:@"contentOffset"
2438
2468
  options:NSKeyValueObservingOptionNew
2439
2469
  context:RNCCollapsiblePagerContentOffsetContext];
2470
+ [candidate addObserver:self
2471
+ forKeyPath:@"contentInset"
2472
+ options:NSKeyValueObservingOptionNew
2473
+ context:RNCCollapsiblePagerContentOffsetContext];
2440
2474
  [candidate addObserver:self
2441
2475
  forKeyPath:@"contentSize"
2442
2476
  options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
@@ -2459,6 +2493,9 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
2459
2493
  [scrollView removeObserver:self
2460
2494
  forKeyPath:@"contentOffset"
2461
2495
  context:RNCCollapsiblePagerContentOffsetContext];
2496
+ [scrollView removeObserver:self
2497
+ forKeyPath:@"contentInset"
2498
+ context:RNCCollapsiblePagerContentOffsetContext];
2462
2499
  [scrollView removeObserver:self
2463
2500
  forKeyPath:@"contentSize"
2464
2501
  context:RNCCollapsiblePagerContentOffsetContext];
@@ -2932,6 +2969,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
2932
2969
  if (appliedTop != nil) {
2933
2970
  [_appliedTopInsets setObject:@(appliedTop.doubleValue + next.top - previous.top) forKey:scrollView];
2934
2971
  }
2972
+ if (scrollView == _observedScrollView) [self updateHeaderForScrollView:scrollView];
2935
2973
  }
2936
2974
 
2937
2975
  - (void)reapplyInsetsToObservedScrollView
@@ -2964,10 +3002,16 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
2964
3002
  context:(void *)context
2965
3003
  {
2966
3004
  if (context == RNCScrollRefreshControlContext) {
2967
- [self updateRefreshControlForScrollView:(UIScrollView *)object];
3005
+ UIScrollView *scrollView = (UIScrollView *)object;
3006
+ [self updateRefreshControlForScrollView:scrollView];
3007
+ if (scrollView == _observedScrollView) [self updateHeaderForScrollView:scrollView];
2968
3008
  return;
2969
3009
  }
2970
3010
  if (context == RNCCollapsiblePagerContentOffsetContext && object == _observedScrollView) {
3011
+ if ([keyPath isEqualToString:@"contentInset"]) {
3012
+ [self updateHeaderForScrollView:(UIScrollView *)object];
3013
+ return;
3014
+ }
2971
3015
  if ([keyPath isEqualToString:@"contentSize"]) {
2972
3016
  NSValue *oldSize = change[NSKeyValueChangeOldKey];
2973
3017
  NSValue *newSize = change[NSKeyValueChangeNewKey];
@@ -2998,9 +3042,15 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
2998
3042
  BOOL attachedToList = _nativeSmoothHeaderScrollEnabled &&
2999
3043
  _sharedHeaderScrollView != nil && !_sharedHeadersLiftedForPagerTransition;
3000
3044
  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.
3001
3047
  _sharedHeaderHostView.transform = CGAffineTransformIdentity;
3002
3048
  _headerView.transform = CGAffineTransformIdentity;
3003
- CGFloat pinnedTranslation = MAX(0, _currentLogicalOffset - _headerHeight);
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);
3004
3054
  CGAffineTransform stickyTransform = CGAffineTransformMakeTranslation(0, pinnedTranslation);
3005
3055
  _stickyHeaderView.transform = stickyTransform;
3006
3056
  _nativeTabBarView.transform = stickyTransform;
@@ -744,6 +744,59 @@ 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)testVerticalSiblingControlDragKeepsReactPress
766
+ {
767
+ [self assertFixtureIsReadyForDelivery];
768
+ UIView *sibling = [RCTViewComponentView new];
769
+ sibling.frame = CGRectMake(160, 540, 80, 100);
770
+ [self.surface addSubview:sibling];
771
+ CGPoint point = [self pressPoint];
772
+ UIScrollView *pagerScrollView = [self.pager valueForKey:@"pagerScrollView"];
773
+ XCTAssertEqual(sibling.superview, self.pager.superview);
774
+ XCTAssertFalse([sibling isDescendantOfView:pagerScrollView]);
775
+ XCTAssertEqual([self.window hitTest:point withEvent:nil], sibling);
776
+
777
+ UITouch *touch = [self.driver beginAt:point];
778
+ XCTAssertEqual(self.handler.registeredTouches, 1);
779
+ [self.driver move:touch to:CGPointMake(point.x, point.y - 12)];
780
+ XCTAssertEqual(self.handler.registeredTouches, 1);
781
+ XCTAssertFalse([self.handler.events containsObject:@"reset-cancelled"]);
782
+ XCTAssertFalse([self.handler.events containsObject:@"cancelled"]);
783
+
784
+ [self.driver end:touch];
785
+ XCTAssertEqualObjects(self.handler.events, (@[@"began", @"moved", @"ended"]));
786
+ XCTAssertEqual(self.handler.registeredTouches, 0);
787
+ }
788
+
789
+ - (void)testSmallVerticalMovementKeepsReactPress
790
+ {
791
+ [self assertFixtureIsReadyForDelivery];
792
+ CGPoint point = [self pressPoint];
793
+ UITouch *touch = [self.driver beginAt:point];
794
+ [self.driver move:touch to:CGPointMake(point.x, point.y - 8)];
795
+ XCTAssertEqual(self.handler.registeredTouches, 1);
796
+ [self.driver end:touch];
797
+ XCTAssertEqualObjects(self.handler.events, (@[@"began", @"moved", @"ended"]));
798
+ }
799
+
747
800
  - (void)testSmallMovementBelowPanThresholdKeepsReactPress
748
801
  {
749
802
  [self assertFixtureIsReadyForDelivery];
@@ -1,9 +1,11 @@
1
1
  #import <XCTest/XCTest.h>
2
+ #import <React/RCTViewComponentView.h>
2
3
  #import "RNCCollapsiblePagerViewComponentView.h"
3
4
 
4
5
  @interface RNCCollapsiblePagerViewComponentView (RefreshControlTesting)
5
6
  - (void)updateRefreshControlForScrollView:(UIScrollView *)scrollView;
6
7
  - (void)releaseRefreshControlForScrollView:(UIScrollView *)scrollView;
8
+ - (void)attachScrollObserverForCurrentPage;
7
9
  @end
8
10
 
9
11
  @interface RNCCollapsiblePagerRefreshControlTests : XCTestCase
@@ -177,4 +179,71 @@
177
179
  XCTAssertTrue(control.layer.masksToBounds);
178
180
  }
179
181
 
182
+ - (void)testRefreshTopInsetDoesNotDisplaceAttachedSharedHeader
183
+ {
184
+ RNCCollapsiblePagerViewComponentView *pager = [self pagerWithHeader:64];
185
+ [pager mountChildComponentView:[RCTViewComponentView new] index:0];
186
+ [pager mountChildComponentView:[RCTViewComponentView new] index:1];
187
+ UIScrollView *scroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 600)];
188
+ scroll.refreshControl = [UIRefreshControl new];
189
+ scroll.contentSize = CGSizeMake(320, 2000);
190
+ scroll.contentInset = UIEdgeInsetsMake(232, 0, 0, 0);
191
+ UIView *content = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 2000)];
192
+ [scroll addSubview:content];
193
+ UIViewController *page = [UIViewController new];
194
+ [page.view addSubview:scroll];
195
+ NSMutableArray<UIViewController *> *pages = [pager valueForKey:@"pageControllers"];
196
+ [pages addObject:page];
197
+ [pager attachScrollObserverForCurrentPage];
198
+ UIView *headerHost = [pager valueForKey:@"sharedHeaderHostView"];
199
+ UIView *stickyHeader = [pager valueForKey:@"stickyHeaderView"];
200
+ UIView *tabBar = [pager valueForKey:@"nativeTabBarView"];
201
+ XCTAssertNotNil(stickyHeader);
202
+ XCTAssertEqual(stickyHeader.superview, headerHost);
203
+ XCTAssertEqual(headerHost.superview, scroll);
204
+ XCTAssertEqualWithAccuracy(scroll.contentInset.top, 340, 0.001);
205
+ XCTAssertEqualWithAccuracy(headerHost.transform.ty, 0, 0.001);
206
+
207
+ scroll.contentOffset = CGPointMake(0, 500);
208
+ CGFloat baselineStickyTranslation = stickyHeader.transform.ty;
209
+ CGFloat baselineTabBarTranslation = tabBar.transform.ty;
210
+ XCTAssertEqualWithAccuracy(baselineStickyTranslation, 776, 0.001);
211
+ XCTAssertEqualWithAccuracy(baselineTabBarTranslation, 776, 0.001);
212
+ CGPoint offset = scroll.contentOffset;
213
+ scroll.contentInset = UIEdgeInsetsMake(400, 0, 0, 0);
214
+ XCTAssertTrue(CGPointEqualToPoint(scroll.contentOffset, offset));
215
+ XCTAssertEqualWithAccuracy(headerHost.transform.ty, 0, 0.001);
216
+ XCTAssertEqualWithAccuracy(stickyHeader.transform.ty, baselineStickyTranslation, 0.001);
217
+ XCTAssertEqualWithAccuracy(tabBar.transform.ty, baselineTabBarTranslation, 0.001);
218
+ XCTAssertEqualWithAccuracy(CGRectGetMaxY(headerHost.frame), CGRectGetMinY(content.frame), 0.001);
219
+
220
+ // Exercise actual scroll notifications while the temporary refresh inset is
221
+ // present, including direction reversals and the sticky/unpinned boundary.
222
+ // The pre-fix formula adds the extra 60 points on these scroll updates.
223
+ for (NSNumber *nextOffset in @[@620, @450, @-300, @-340, @500]) {
224
+ scroll.contentOffset = CGPointMake(0, nextOffset.doubleValue);
225
+ CGFloat expectedTranslation = MAX(0, nextOffset.doubleValue + 340 - 64);
226
+ XCTAssertEqualWithAccuracy(headerHost.transform.ty, 0, 0.001);
227
+ XCTAssertEqualWithAccuracy(stickyHeader.transform.ty, expectedTranslation, 0.001);
228
+ XCTAssertEqualWithAccuracy(tabBar.transform.ty, expectedTranslation, 0.001);
229
+ XCTAssertEqualWithAccuracy(CGRectGetMaxY(headerHost.frame), CGRectGetMinY(content.frame), 0.001);
230
+ }
231
+
232
+ offset = scroll.contentOffset;
233
+ scroll.contentInset = UIEdgeInsetsMake(340, 0, 0, 0);
234
+ XCTAssertTrue(CGPointEqualToPoint(scroll.contentOffset, offset));
235
+ XCTAssertEqualWithAccuracy(headerHost.transform.ty, 0, 0.001);
236
+ XCTAssertEqualWithAccuracy(stickyHeader.transform.ty, baselineStickyTranslation, 0.001);
237
+ XCTAssertEqualWithAccuracy(tabBar.transform.ty, baselineTabBarTranslation, 0.001);
238
+
239
+ scroll.contentInset = UIEdgeInsetsMake(400, 0, 0, 0);
240
+ XCTAssertEqualWithAccuracy(headerHost.transform.ty, 0, 0.001);
241
+ XCTAssertEqualWithAccuracy(stickyHeader.transform.ty, baselineStickyTranslation, 0.001);
242
+ XCTAssertEqualWithAccuracy(tabBar.transform.ty, baselineTabBarTranslation, 0.001);
243
+ XCTAssertEqualWithAccuracy(CGRectGetMaxY(headerHost.frame), CGRectGetMinY(content.frame), 0.001);
244
+ scroll.refreshControl = nil;
245
+ XCTAssertEqualWithAccuracy(headerHost.transform.ty, 0, 0.001);
246
+ [pager prepareForRecycle];
247
+ }
248
+
180
249
  @end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/react-native-pager-view",
3
- "version": "3.0.162-alpha.272",
3
+ "version": "3.0.163",
4
4
  "description": "React Native wrapper for Android and iOS ViewPager",
5
5
  "source": "./src/index.tsx",
6
6
  "main": "./lib/module/index.js",
@@ -51,11 +51,14 @@
51
51
  ],
52
52
  "repository": {
53
53
  "type": "git",
54
- "url": "git+https://github.com/nicholasxuu/app-modules.git",
54
+ "url": "git+https://github.com/OneKeyHQ/app-modules.git",
55
55
  "directory": "native-views/react-native-pager-view"
56
56
  },
57
57
  "author": "OneKey",
58
- "homepage": "https://github.com/nicholasxuu/app-modules#readme",
58
+ "bugs": {
59
+ "url": "https://github.com/OneKeyHQ/app-modules/issues"
60
+ },
61
+ "homepage": "https://github.com/OneKeyHQ/app-modules/tree/main/native-views/react-native-pager-view#readme",
59
62
  "license": "MIT",
60
63
  "publishConfig": {
61
64
  "registry": "https://registry.npmjs.org/",
@@ -69,7 +72,7 @@
69
72
  "typescript": "^5.9.2"
70
73
  },
71
74
  "peerDependencies": {
72
- "@onekeyfe/react-native-native-logger": "3.0.162-alpha.272",
75
+ "@onekeyfe/react-native-native-logger": "3.0.163",
73
76
  "react": "*",
74
77
  "react-native": "*"
75
78
  },