@onekeyfe/react-native-pager-view 6.7.0-alpha.436 → 6.7.0-alpha.449

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 (25) hide show
  1. package/README.md +16 -0
  2. package/android/build.gradle +1 -0
  3. package/android/src/androidTest/java/com/reactnativepagerview/CollapsiblePagerTabReservationTest.kt +135 -0
  4. package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerHost.kt +88 -12
  5. package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerNativeHeaders.kt +442 -15
  6. package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerViewManager.kt +11 -1
  7. package/android/src/main/java/com/reactnativepagerview/event/NativeHeaderPressEvent.kt +8 -0
  8. package/docs/SPEC.md +298 -3
  9. package/ios/RNCCollapsiblePagerViewComponentView.mm +834 -20
  10. package/ios/tests/RNCCollapsiblePagerFirstFrameTests.mm +61 -0
  11. package/ios/tests/RNCCollapsiblePagerHitTestTests.mm +22 -0
  12. package/lib/module/CollapsiblePagerView.js +37 -5
  13. package/lib/module/CollapsiblePagerView.web.js +519 -6
  14. package/lib/module/CollapsiblePagerViewNativeComponent.ts +6 -0
  15. package/lib/module/NativeScrollerNativeComponent.ts +0 -1
  16. package/lib/typescript/src/CollapsiblePagerView.d.ts +31 -2
  17. package/lib/typescript/src/CollapsiblePagerView.web.d.ts +44 -1
  18. package/lib/typescript/src/CollapsiblePagerViewNativeComponent.d.ts +11 -0
  19. package/lib/typescript/src/NativeScroller.d.ts +2 -2
  20. package/package.json +3 -2
  21. package/src/CollapsiblePagerView.tsx +68 -5
  22. package/src/CollapsiblePagerView.web.tsx +464 -5
  23. package/src/CollapsiblePagerViewNativeComponent.ts +6 -0
  24. package/src/NativeScroller.tsx +2 -3
  25. package/src/NativeScrollerNativeComponent.ts +0 -1
@@ -36,6 +36,13 @@ using namespace facebook::react;
36
36
  - (void)scrollToEnd:(BOOL)animated;
37
37
  @end
38
38
 
39
+ @interface RNCCollapsiblePagerNativeTabBarView : UIView
40
+ - (void)updateItemsJSON:(NSString *)json;
41
+ - (void)updateConfigJSON:(NSString *)json;
42
+ - (void)updateToolbarPagerIndex:(NSInteger)index busy:(BOOL)busy;
43
+ - (BOOL)toolbarCanCommit;
44
+ @end
45
+
39
46
  @interface RNCCollapsiblePagerFirstFrameTests : XCTestCase
40
47
  @end
41
48
 
@@ -903,4 +910,58 @@ using namespace facebook::react;
903
910
  XCTAssertEqual([outer verticalScrollViewForPageAtIndex:0], scroller.scrollView);
904
911
  }
905
912
 
913
+ - (void)testControlledToolbarRetainsSnapshotAndRestoresLegacyHitAndAccessibility
914
+ {
915
+ RNCCollapsiblePagerNativeTabBarView *bar = [NSClassFromString(@"RNCCollapsiblePagerNativeTabBarView") new];
916
+ bar.frame = CGRectMake(0, 0, 320, 44);
917
+ UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 600)];
918
+ UIViewController *root = [UIViewController new];
919
+ window.rootViewController = root;
920
+ [root.view addSubview:bar];
921
+ window.hidden = NO;
922
+ [self addTeardownBlock:^{ [bar removeFromSuperview]; window.hidden = YES; window.rootViewController = nil; }];
923
+ [bar updateItemsJSON:@"[{\"key\":\"a\",\"title\":\"A\"},{\"key\":\"b\",\"title\":\"B\"}]"];
924
+ UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:CGSizeMake(1, 1)];
925
+ UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext *context) {
926
+ [UIColor.blackColor setFill]; UIRectFill(CGRectMake(0, 0, 1, 1));
927
+ }];
928
+ NSString *identity = [NSString stringWithFormat:@"SliderHorOutline|#000000|%g|24", window.screen.scale];
929
+ [bar setValue:image forKey:@"loadedToolbarImage"];
930
+ [bar setValue:identity forKey:@"loadedIconIdentity"];
931
+ NSString *owned = @"{\"controlled\":true,\"selectedKey\":\"a\",\"pageKeys\":[\"a\",\"b\"],\"toolbar\":{\"a\":{\"iconName\":\"SliderHorOutline\",\"accessibilityLabel\":\"A action\"}}}";
932
+ [bar updateConfigJSON:owned];
933
+ [bar updateToolbarPagerIndex:0 busy:NO];
934
+ UIButton *button = [bar valueForKey:@"toolbarButton"];
935
+ XCTAssertTrue(button.enabled);
936
+ XCTAssertTrue(button.isAccessibilityElement);
937
+ XCTAssertFalse(button.adjustsImageWhenDisabled);
938
+ [bar updateToolbarPagerIndex:-1 busy:YES];
939
+ XCTAssertFalse(button.enabled);
940
+ XCTAssertFalse(button.isAccessibilityElement);
941
+ XCTAssertEqual([button imageForState:UIControlStateNormal], image);
942
+ XCTAssertEqualObjects(button.accessibilityLabel, @"A action");
943
+ XCTAssertFalse([bar toolbarCanCommit]);
944
+ [bar updateConfigJSON:@"{\"controlled\":false,\"toolbar\":{\"a\":{\"iconName\":\"SliderHorOutline\",\"accessibilityLabel\":\"A action\"}}}"];
945
+ XCTAssertTrue(button.enabled);
946
+ XCTAssertTrue(button.userInteractionEnabled);
947
+ XCTAssertTrue(button.isAccessibilityElement);
948
+ XCTAssertFalse(button.accessibilityElementsHidden);
949
+ XCTAssertTrue(button.adjustsImageWhenDisabled);
950
+ [bar updateConfigJSON:owned];
951
+ [bar updateToolbarPagerIndex:0 busy:NO];
952
+ [bar updateConfigJSON:[owned stringByReplacingOccurrencesOfString:@"\"selectedKey\":\"a\"" withString:@"\"selectedKey\":\"b\""]];
953
+ XCTAssertFalse(button.enabled);
954
+ XCTAssertEqualObjects(button.accessibilityLabel, @"A action");
955
+ XCTAssertFalse([bar toolbarCanCommit]);
956
+ [bar updateToolbarPagerIndex:1 busy:NO];
957
+ XCTAssertTrue([bar toolbarCanCommit]);
958
+ XCTAssertFalse(button.enabled); // B has no action; the fixed slot remains.
959
+ [bar removeFromSuperview];
960
+ [root.view addSubview:bar];
961
+ XCTAssertFalse([bar toolbarCanCommit]);
962
+ [bar updateToolbarPagerIndex:1 busy:NO];
963
+ XCTAssertTrue([bar toolbarCanCommit]);
964
+ XCTAssertFalse(button.enabled);
965
+ }
966
+
906
967
  @end
@@ -1013,6 +1013,20 @@ using namespace facebook::react;
1013
1013
  for (id owner in owners) {
1014
1014
  XCTAssertNotNil([owner valueForKey:@"topInteraction"]);
1015
1015
  XCTAssertNotNil([[owner valueForKey:@"topInteraction"] scrollView]);
1016
+ if (owner == sourceOwner) continue;
1017
+ XCTAssertTrue([[owner valueForKey:@"ownsTransitionHosts"] boolValue]);
1018
+ UIView *page = [owner valueForKey:@"page"];
1019
+ UIScrollView *list = [owner valueForKey:@"scrollView"];
1020
+ UIView *incomingTop = [owner valueForKey:@"ownedTopHost"];
1021
+ UIView *incomingSticky = [owner valueForKey:@"ownedStickyHost"];
1022
+ XCTAssertEqual(incomingTop.superview, page);
1023
+ XCTAssertEqual(incomingSticky.superview, page);
1024
+ XCTAssertNotEqual(incomingTop, topHost);
1025
+ XCTAssertNotEqual(incomingSticky, pinnedHost);
1026
+ XCTAssertFalse(incomingTop.userInteractionEnabled);
1027
+ XCTAssertFalse(incomingSticky.userInteractionEnabled);
1028
+ XCTAssertEqualWithAccuracy(incomingTop.frame.origin.x,
1029
+ CGRectGetMinX([list convertRect:list.bounds toView:page]), 0.001);
1016
1030
  }
1017
1031
  } else {
1018
1032
  XCTSkip(@"Direct local Hard drag handoff requires iOS 27 or newer");
@@ -1046,11 +1060,19 @@ using namespace facebook::react;
1046
1060
  XCTAssertEqual([[self.pager valueForKey:@"programmaticScrollEdgeOwners"] count], 3);
1047
1061
  [self.pager scrollViewDidEndDragging:horizontal willDecelerate:YES];
1048
1062
  XCTAssertEqual([[self.pager valueForKey:@"programmaticScrollEdgeOwners"] count], 3);
1063
+ NSMutableArray<UIView *> *incomingHosts = [NSMutableArray new];
1064
+ for (id owner in [self.pager valueForKey:@"programmaticScrollEdgeOwners"]) {
1065
+ if (![[owner valueForKey:@"ownsTransitionHosts"] boolValue]) continue;
1066
+ [incomingHosts addObject:[owner valueForKey:@"ownedTopHost"]];
1067
+ [incomingHosts addObject:[owner valueForKey:@"ownedStickyHost"]];
1068
+ }
1049
1069
  [self.pager scrollViewDidEndDecelerating:horizontal];
1050
1070
  XCTestExpectation *settled = [self expectationWithDescription:@"drag settled"];
1051
1071
  dispatch_async(dispatch_get_main_queue(), ^{ [settled fulfill]; });
1052
1072
  [self waitForExpectations:@[settled] timeout:2];
1053
1073
  XCTAssertEqual([[self.pager valueForKey:@"programmaticScrollEdgeOwners"] count], 0);
1074
+ XCTAssertEqual(incomingHosts.count, 4);
1075
+ for (UIView *host in incomingHosts) XCTAssertNil(host.superview);
1054
1076
  XCTAssertFalse([topHost.interactions containsObject:top]);
1055
1077
  XCTAssertNil(top.scrollView);
1056
1078
  XCTAssertEqual([[self.pager valueForKey:@"currentIndex"] integerValue], 1);
@@ -1,9 +1,23 @@
1
1
  "use strict";
2
2
 
3
3
  import React from "react";
4
- import { I18nManager, Platform, StyleSheet, View } from "react-native";
4
+ import { I18nManager, Platform, StyleSheet, View, processColor } from "react-native";
5
5
  import CollapsiblePagerViewNativeComponent, { Commands as CollapsiblePagerViewNativeCommands } from "./CollapsiblePagerViewNativeComponent";
6
6
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
+ const nativeToolbar = toolbar => {
8
+ if (!toolbar) return undefined;
9
+ return Object.fromEntries(Object.entries(toolbar).map(([key, item]) => {
10
+ const color = processColor(item.iconColor ?? "#000000");
11
+ const argb = typeof color === "number" ? color >>> 0 : 0xff000000;
12
+ return [key, {
13
+ ...item,
14
+ iconColor: `rgba(${argb >>> 16 & 255},${argb >>> 8 & 255},${argb & 255},${Math.round((argb >>> 24) / 255 * 1000000) / 1000000})`,
15
+ selectedBackgroundColor: processColor(item.selectedBackgroundColor ?? "transparent"),
16
+ hoverBackgroundColor: processColor(item.hoverBackgroundColor ?? "transparent"),
17
+ pressedBackgroundColor: processColor(item.pressedBackgroundColor ?? "transparent")
18
+ }];
19
+ }));
20
+ };
7
21
  const pageIndex = value => {
8
22
  const index = Math.trunc(value);
9
23
  return Number.isFinite(index) ? index : null;
@@ -62,7 +76,7 @@ export class CollapsiblePagerView extends React.PureComponent {
62
76
  setPage = selectedPage => {
63
77
  const position = pageIndex(selectedPage);
64
78
  if (this.nativeRef && position !== null && position >= 0 && position < this.pages().length) {
65
- if (this.nativeTabBarEnabled()) {
79
+ if (this.nativeTabBarEnabled() && !this.props.nativeTabBar?.controlled) {
66
80
  this.dispatchNativeTabPageCommand(position, true);
67
81
  } else {
68
82
  CollapsiblePagerViewNativeCommands.setPage(this.nativeRef, position);
@@ -72,7 +86,7 @@ export class CollapsiblePagerView extends React.PureComponent {
72
86
  setPageWithoutAnimation = selectedPage => {
73
87
  const position = pageIndex(selectedPage);
74
88
  if (this.nativeRef && position !== null && position >= 0 && position < this.pages().length) {
75
- if (this.nativeTabBarEnabled()) {
89
+ if (this.nativeTabBarEnabled() && !this.props.nativeTabBar?.controlled) {
76
90
  this.dispatchNativeTabPageCommand(position, false);
77
91
  } else {
78
92
  CollapsiblePagerViewNativeCommands.setPageWithoutAnimation(this.nativeRef, position);
@@ -195,13 +209,17 @@ export class CollapsiblePagerView extends React.PureComponent {
195
209
  if (!this.nativeTabBarEnabled() || position === null || this.props.nativeTabBar?.items[position]?.key !== event.nativeEvent.key) {
196
210
  return;
197
211
  }
198
- if (position >= 0 && position < this.pages().length && (position !== this.state.selectedPage || this.latestNativeTabTarget !== null)) {
212
+ if (!this.props.nativeTabBar?.controlled && position >= 0 && position < this.pages().length && (position !== this.state.selectedPage || this.latestNativeTabTarget !== null)) {
199
213
  // Selection state lags an in-flight transition until native reports it.
200
214
  const currentPage = this.dispatchedNativeTabTarget ?? this.state.selectedPage;
201
215
  this.dispatchNativeTabPageCommand(position, this.props.nativeTabPressAnimationEnabled ?? Math.abs(position - currentPage) <= 1, event.nativeEvent.key);
202
216
  }
203
217
  this.props.onNativeTabPress?.(event);
204
218
  };
219
+ onNativeToolbarPress = event => {
220
+ if (!this.props.nativeTabBar?.toolbar?.[event.nativeEvent.key]?.iconName) return;
221
+ this.props.onNativeToolbarPress?.(event);
222
+ };
205
223
  onNativeSubHeaderPress = event => {
206
224
  this.props.onNativeSubHeaderPress?.(event);
207
225
  };
@@ -274,6 +292,20 @@ export class CollapsiblePagerView extends React.PureComponent {
274
292
  retainedPages: JSON.stringify([...retained]),
275
293
  onPageSelected: this.onPageSelected,
276
294
  onPageScrollStateChanged: this.onPageScrollStateChanged,
295
+ nativeTabBarConfig: nativeTabBarEnabled ? JSON.stringify({
296
+ controlled: nativeTabBar.controlled,
297
+ selectedKey: nativeTabBar.selectedKey,
298
+ pageKeys: (() => {
299
+ const keys = [];
300
+ React.Children.forEach(this.props.children, child => {
301
+ if (child !== null && child !== undefined && typeof child !== "boolean") keys.push(pageKey(child, keys.length));
302
+ });
303
+ return keys;
304
+ })(),
305
+ toolbar: nativeToolbar(nativeTabBar.toolbar),
306
+ activeFontFamily: nativeTabBar.style?.activeFontFamily
307
+ }) : undefined,
308
+ onNativeToolbarPress: this.onNativeToolbarPress,
277
309
  nativeTabBarItems: nativeTabBarEnabled ? JSON.stringify(nativeTabBar.items) : undefined,
278
310
  nativeTabBarHeight: nativeTabBarEnabled ? nativeTabBarStyle?.height ?? 44 : undefined,
279
311
  nativeTabBarVariant: nativeTabBarEnabled ? nativeTabBarStyle?.variant ?? "underline" : undefined,
@@ -281,7 +313,7 @@ export class CollapsiblePagerView extends React.PureComponent {
281
313
  nativeTabBarContentPaddingHorizontal: nativeTabBarEnabled ? nativeTabBarStyle?.contentPaddingHorizontal ?? 20 : undefined,
282
314
  nativeTabBarContentPaddingVertical: nativeTabBarEnabled ? nativeTabBarContentPaddingVertical : undefined,
283
315
  nativeTabBarItemSpacing: nativeTabBarEnabled ? nativeTabBarStyle?.itemSpacing ?? 8 : undefined,
284
- nativeTabBarFontSize: nativeTabBarEnabled ? nativeTabBarStyle?.fontSize ?? 16 : undefined,
316
+ nativeTabBarFontSize: nativeTabBarEnabled ? nativeTabBarStyle?.fontSize ?? (nativeTabBarStyle?.variant === "text" ? 18 : 16) : undefined,
285
317
  nativeTabBarFontFamily: nativeTabBarEnabled ? nativeTabBarStyle?.fontFamily : undefined,
286
318
  nativeTabBarBackgroundColor: nativeTabBarEnabled ? nativeTabBarStyle?.backgroundColor : undefined,
287
319
  nativeTabBarActiveTextColor: nativeTabBarEnabled ? nativeTabBarStyle?.activeTextColor : undefined,