@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.
- package/README.md +16 -0
- package/android/build.gradle +1 -0
- package/android/src/androidTest/java/com/reactnativepagerview/CollapsiblePagerTabReservationTest.kt +135 -0
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerHost.kt +88 -12
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerNativeHeaders.kt +442 -15
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerViewManager.kt +11 -1
- package/android/src/main/java/com/reactnativepagerview/event/NativeHeaderPressEvent.kt +8 -0
- package/docs/SPEC.md +298 -3
- package/ios/RNCCollapsiblePagerViewComponentView.mm +834 -20
- package/ios/tests/RNCCollapsiblePagerFirstFrameTests.mm +61 -0
- package/ios/tests/RNCCollapsiblePagerHitTestTests.mm +22 -0
- package/lib/module/CollapsiblePagerView.js +37 -5
- package/lib/module/CollapsiblePagerView.web.js +519 -6
- package/lib/module/CollapsiblePagerViewNativeComponent.ts +6 -0
- package/lib/module/NativeScrollerNativeComponent.ts +0 -1
- package/lib/typescript/src/CollapsiblePagerView.d.ts +31 -2
- package/lib/typescript/src/CollapsiblePagerView.web.d.ts +44 -1
- package/lib/typescript/src/CollapsiblePagerViewNativeComponent.d.ts +11 -0
- package/lib/typescript/src/NativeScroller.d.ts +2 -2
- package/package.json +3 -2
- package/src/CollapsiblePagerView.tsx +68 -5
- package/src/CollapsiblePagerView.web.tsx +464 -5
- package/src/CollapsiblePagerViewNativeComponent.ts +6 -0
- package/src/NativeScroller.tsx +2 -3
- 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,
|