@onekeyfe/react-native-pager-view 3.0.158 → 3.0.160

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 (42) hide show
  1. package/README.md +57 -4
  2. package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerHost.kt +379 -31
  3. package/android/src/main/java/com/reactnativepagerview/NativeScrollCoordinatorContributions.kt +15 -0
  4. package/android/src/main/java/com/reactnativepagerview/NativeScrollerPendingRestore.kt +26 -0
  5. package/android/src/main/java/com/reactnativepagerview/NativeScrollerScrollAwayInsets.kt +41 -0
  6. package/android/src/main/java/com/reactnativepagerview/NativeScrollerView.kt +600 -0
  7. package/android/src/main/java/com/reactnativepagerview/NativeScrollerViewManager.kt +145 -0
  8. package/android/src/main/java/com/reactnativepagerview/PagerViewViewPackage.kt +1 -1
  9. package/android/src/main/jni/CMakeLists.txt +19 -0
  10. package/android/src/main/jni/pagerview.h +11 -0
  11. package/android/src/main/res/values/native_scroll_coordinator_ids.xml +5 -0
  12. package/android/src/test/java/com/reactnativepagerview/NativeScrollCoordinatorContributionsTest.kt +26 -0
  13. package/android/src/test/java/com/reactnativepagerview/NativeScrollerPendingRestoreTest.kt +31 -0
  14. package/android/src/test/java/com/reactnativepagerview/NativeScrollerScrollAwayInsetsTest.kt +75 -0
  15. package/common/cpp/react/renderer/components/pagerview/RNCNativeScrollerComponentDescriptor.h +8 -0
  16. package/common/cpp/react/renderer/components/pagerview/RNCNativeScrollerShadowNode.cpp +15 -0
  17. package/common/cpp/react/renderer/components/pagerview/RNCNativeScrollerShadowNode.h +23 -0
  18. package/common/cpp/react/renderer/components/pagerview/RNCNativeScrollerState.h +33 -0
  19. package/docs/SPEC.md +450 -0
  20. package/ios/RNCCollapsiblePagerReleasedStatePolicy.h +8 -0
  21. package/ios/RNCCollapsiblePagerReleasedStatePolicy.m +13 -0
  22. package/ios/RNCCollapsiblePagerViewComponentView.mm +414 -1
  23. package/ios/RNCNativeScrollerComponentView.h +17 -0
  24. package/ios/RNCNativeScrollerComponentView.mm +479 -0
  25. package/ios/tests/RNCCollapsiblePagerHitTestTests.mm +80 -0
  26. package/ios/tests/RNCCollapsiblePagerPressCancellationTests.mm +788 -0
  27. package/ios/tests/RNCCollapsiblePagerPressCancellationWiringTests.mm +109 -0
  28. package/ios/tests/RNCCollapsiblePagerRefreshControlTests.mm +218 -0
  29. package/ios/tests/RNCCollapsiblePagerReleasedStatePolicyTests.mm +23 -0
  30. package/ios/tests/RNCNativeScrollerTests.mm +252 -0
  31. package/lib/module/CollapsiblePagerView.js +10 -1
  32. package/lib/module/NativeScroller.js +171 -11
  33. package/lib/module/NativeScrollerNativeComponent.ts +101 -0
  34. package/lib/typescript/src/CollapsiblePagerView.d.ts +3 -3
  35. package/lib/typescript/src/NativeScroller.d.ts +15 -7
  36. package/lib/typescript/src/NativeScrollerNativeComponent.d.ts +79 -0
  37. package/package.json +8 -4
  38. package/react-native-pager-view.podspec +2 -1
  39. package/react-native.config.js +15 -0
  40. package/src/CollapsiblePagerView.tsx +14 -4
  41. package/src/NativeScroller.tsx +291 -14
  42. package/src/NativeScrollerNativeComponent.ts +101 -0
@@ -1,25 +1,185 @@
1
1
  "use strict";
2
2
 
3
3
  import * as React from "react";
4
- import { ScrollView } from "react-native";
4
+ import { findNodeHandle, Keyboard, Platform, StyleSheet, TextInput, View } from "react-native";
5
+ import NativeScrollerHost, { Commands } from "./NativeScrollerNativeComponent";
5
6
  import { jsx as _jsx } from "react/jsx-runtime";
6
7
  export const NATIVE_SCROLLER_NATIVE_ID_PREFIX = "rnc-collapsible-pager-native-scroller";
7
- /**
8
- * Primary non-virtualized vertical scroller for a CollapsiblePagerView page.
9
- */
8
+
9
+ /** Supported vertical subset; horizontal, snapping, zoom and sticky rows are not supported. */
10
+
11
+ // The RN 0.86 JS registry distinguishes another input from an unhandled tap.
12
+ // TextInput.State's public facade does not export this query.
13
+ const textInputState = require("react-native/Libraries/Components/TextInput/TextInputState").default;
14
+ const styles = StyleSheet.create({
15
+ viewport: {
16
+ flexGrow: 1,
17
+ flexShrink: 1,
18
+ overflow: "hidden"
19
+ },
20
+ content: {
21
+ position: "absolute",
22
+ top: 0,
23
+ left: 0,
24
+ right: 0,
25
+ flexShrink: 0
26
+ }
27
+ });
10
28
  export const NativeScroller = /*#__PURE__*/React.forwardRef(function NativeScroller({
29
+ children,
11
30
  nativeID,
12
- nestedScrollEnabled = true,
13
31
  pagerScrollKey,
32
+ style,
33
+ contentContainerStyle,
34
+ onLayout,
35
+ onContentSizeChange,
36
+ refreshControl,
37
+ nestedScrollEnabled = true,
38
+ contentInset,
39
+ decelerationRate = "normal",
40
+ keyboardShouldPersistTaps = "never",
41
+ onScroll,
42
+ onScrollBeginDrag,
43
+ onMomentumScrollBegin,
44
+ onMomentumScrollEnd,
45
+ onStartShouldSetResponder,
46
+ onStartShouldSetResponderCapture,
47
+ onResponderGrant,
48
+ onResponderRelease,
49
+ onResponderTerminationRequest,
14
50
  ...props
15
- }, ref) {
51
+ }, forwardedRef) {
52
+ const hostRef = React.useRef(null);
16
53
  const generatedId = React.useId();
17
- const scrollKey = pagerScrollKey ?? nativeID ?? generatedId;
18
- return /*#__PURE__*/_jsx(ScrollView, {
54
+ const [contentViewportHeight, setContentViewportHeight] = React.useState(0);
55
+ const [contentSize, setContentSize] = React.useState({
56
+ width: 0,
57
+ height: 0
58
+ });
59
+ const [refreshEpoch, requestRefreshSync] = React.useReducer(value => value + 1, 0);
60
+ const contentSizeRef = React.useRef(contentSize);
61
+ const scrolledSinceGrant = React.useRef(false);
62
+ const momentum = React.useRef(false);
63
+ const grantedDuringMomentum = React.useRef(false);
64
+ const persistTaps = keyboardShouldPersistTaps === true ? "always" : keyboardShouldPersistTaps === false ? "never" : keyboardShouldPersistTaps;
65
+ const contentStyle = StyleSheet.flatten(contentContainerStyle);
66
+ const refresh = refreshControl?.props;
67
+ const rate = typeof decelerationRate === "number" ? decelerationRate : decelerationRate === "fast" ? Platform.OS === "ios" ? 0.99 : 0.9 : Platform.OS === "ios" ? 0.998 : 0.985;
68
+ React.useEffect(() => {
69
+ if (hostRef.current) Commands.setRefreshState(hostRef.current, refresh?.refreshing ?? false);
70
+ }, [refresh?.refreshing, refreshEpoch]);
71
+ React.useImperativeHandle(forwardedRef, () => ({
72
+ scrollTo(options, x, animated) {
73
+ const host = hostRef.current;
74
+ if (!host) return;
75
+ if (typeof options === "number") {
76
+ Commands.scrollTo(host, x ?? 0, options, animated !== false);
77
+ } else {
78
+ Commands.scrollTo(host, options?.x ?? 0, options?.y ?? 0, options?.animated !== false);
79
+ }
80
+ },
81
+ scrollToEnd(options) {
82
+ if (hostRef.current) Commands.scrollToEnd(hostRef.current, options?.animated !== false);
83
+ },
84
+ flashScrollIndicators() {
85
+ if (hostRef.current) Commands.flashScrollIndicators(hostRef.current);
86
+ },
87
+ getNativeScrollRef: () => hostRef.current,
88
+ getScrollableNode: () => findNodeHandle(hostRef.current) ?? null,
89
+ measure: (...args) => hostRef.current?.measure(...args),
90
+ measureInWindow: (...args) => hostRef.current?.measureInWindow(...args),
91
+ measureLayout: (...args) => hostRef.current?.measureLayout(...args),
92
+ setNativeProps: nativeProps => hostRef.current?.setNativeProps(nativeProps),
93
+ focus: () => hostRef.current?.focus(),
94
+ blur: () => hostRef.current?.blur()
95
+ }), []);
96
+ const keyboardIsDismissible = () => Boolean(TextInput.State.currentlyFocusedInput() && (Keyboard.isVisible() || Platform.OS === "android" && Number(Platform.Version) < 30) && Keyboard.metrics()?.height !== 0);
97
+ return /*#__PURE__*/_jsx(NativeScrollerHost, {
19
98
  ...props,
20
- ref: ref,
21
- nativeID: `${NATIVE_SCROLLER_NATIVE_ID_PREFIX}:${scrollKey}`,
22
- nestedScrollEnabled: nestedScrollEnabled
99
+ ref: hostRef,
100
+ nativeID: `${NATIVE_SCROLLER_NATIVE_ID_PREFIX}:${pagerScrollKey ?? nativeID ?? generatedId}`,
101
+ style: [styles.viewport, style],
102
+ nestedScrollEnabled: nestedScrollEnabled,
103
+ contentWidth: contentSize.width,
104
+ contentHeight: contentSize.height,
105
+ contentInsetTop: contentInset?.top ?? 0,
106
+ contentInsetRight: contentInset?.right ?? 0,
107
+ contentInsetBottom: contentInset?.bottom ?? 0,
108
+ contentInsetLeft: contentInset?.left ?? 0,
109
+ decelerationRate: rate,
110
+ keyboardShouldPersistTaps: persistTaps,
111
+ refreshEnabled: Boolean(refresh) && refresh?.enabled !== false,
112
+ refreshing: refresh?.refreshing ?? false,
113
+ refreshTintColor: refresh?.tintColor,
114
+ refreshColors: refresh?.colors,
115
+ refreshProgressBackgroundColor: refresh?.progressBackgroundColor,
116
+ refreshProgressViewOffset: refresh?.progressViewOffset ?? 0,
117
+ refreshTitle: refresh?.title,
118
+ refreshTitleColor: refresh?.titleColor,
119
+ refreshSize: refresh?.size === "large" ? "large" : "default",
120
+ onRefresh: () => {
121
+ try {
122
+ refresh?.onRefresh?.();
123
+ } finally {
124
+ requestRefreshSync();
125
+ }
126
+ },
127
+ onLayout: onLayout,
128
+ onContentViewportChange: event => {
129
+ const height = event.nativeEvent.height;
130
+ if (!Number.isFinite(height) || height < 0) return;
131
+ setContentViewportHeight(previous => previous === height ? previous : height);
132
+ },
133
+ onScroll: event => {
134
+ scrolledSinceGrant.current = true;
135
+ onScroll?.(event);
136
+ },
137
+ onScrollBeginDrag: event => {
138
+ scrolledSinceGrant.current = true;
139
+ onScrollBeginDrag?.(event);
140
+ },
141
+ onMomentumScrollBegin: event => {
142
+ momentum.current = true;
143
+ onMomentumScrollBegin?.(event);
144
+ },
145
+ onMomentumScrollEnd: event => {
146
+ momentum.current = false;
147
+ onMomentumScrollEnd?.(event);
148
+ },
149
+ onStartShouldSetResponder: event => onStartShouldSetResponder?.(event) ?? (persistTaps === "handled" && keyboardIsDismissible() && event.target !== TextInput.State.currentlyFocusedInput()),
150
+ onStartShouldSetResponderCapture: event => onStartShouldSetResponderCapture?.(event) ?? (momentum.current || persistTaps === "never" && keyboardIsDismissible() && typeof event.target !== "number" && !textInputState.isTextInput(event.target)),
151
+ onResponderGrant: event => {
152
+ scrolledSinceGrant.current = false;
153
+ grantedDuringMomentum.current = momentum.current;
154
+ onResponderGrant?.(event);
155
+ },
156
+ onResponderRelease: event => {
157
+ onResponderRelease?.(event);
158
+ if (persistTaps !== "always" && keyboardIsDismissible() && event.target !== TextInput.State.currentlyFocusedInput() && !scrolledSinceGrant.current && !grantedDuringMomentum.current) Keyboard.dismiss();
159
+ },
160
+ onResponderTerminationRequest: event => onResponderTerminationRequest?.(event) ?? true,
161
+ children: /*#__PURE__*/_jsx(View, {
162
+ collapsable: false,
163
+ style: [contentContainerStyle, (contentStyle?.flexGrow ?? 0) > 0 && (contentStyle?.minHeight === undefined || typeof contentStyle.minHeight === "number") ? {
164
+ minHeight: Math.max(contentViewportHeight, contentStyle?.minHeight ?? 0)
165
+ } : undefined, styles.content],
166
+ onLayout: event => {
167
+ const {
168
+ width,
169
+ height
170
+ } = event.nativeEvent.layout;
171
+ const previous = contentSizeRef.current;
172
+ if (previous.width === width && previous.height === height) return;
173
+ const next = {
174
+ width,
175
+ height
176
+ };
177
+ contentSizeRef.current = next;
178
+ setContentSize(next);
179
+ onContentSizeChange?.(width, height);
180
+ },
181
+ children: children
182
+ })
23
183
  });
24
184
  });
25
185
  NativeScroller.displayName = "NativeScroller";
@@ -0,0 +1,101 @@
1
+ import type * as React from "react";
2
+ import {
3
+ codegenNativeCommands,
4
+ codegenNativeComponent,
5
+ type ColorValue,
6
+ type HostComponent,
7
+ type ViewProps,
8
+ } from "react-native";
9
+ import type {
10
+ DirectEventHandler,
11
+ Double,
12
+ WithDefault,
13
+ } from "react-native/Libraries/Types/CodegenTypes";
14
+
15
+ export type NativeScrollerScrollEvent = Readonly<{
16
+ contentInset: Readonly<{
17
+ top: Double;
18
+ right: Double;
19
+ bottom: Double;
20
+ left: Double;
21
+ }>;
22
+ contentOffset: Readonly<{ x: Double; y: Double }>;
23
+ contentSize: Readonly<{ width: Double; height: Double }>;
24
+ layoutMeasurement: Readonly<{ width: Double; height: Double }>;
25
+ velocity: Readonly<{ x: Double; y: Double }>;
26
+ targetContentOffset: Readonly<{ x: Double; y: Double }>;
27
+ zoomScale: Double;
28
+ }>;
29
+
30
+ export interface NativeProps extends ViewProps {
31
+ contentWidth?: WithDefault<Double, 0>;
32
+ contentHeight?: WithDefault<Double, 0>;
33
+ scrollEnabled?: WithDefault<boolean, true>;
34
+ nestedScrollEnabled?: WithDefault<boolean, true>;
35
+ showsVerticalScrollIndicator?: WithDefault<boolean, true>;
36
+ showsHorizontalScrollIndicator?: WithDefault<boolean, false>;
37
+ bounces?: WithDefault<boolean, true>;
38
+ alwaysBounceVertical?: WithDefault<boolean, true>;
39
+ keyboardDismissMode?: WithDefault<"none" | "on-drag" | "interactive", "none">;
40
+ keyboardShouldPersistTaps?: WithDefault<
41
+ "never" | "always" | "handled",
42
+ "never"
43
+ >;
44
+ scrollEventThrottle?: WithDefault<Double, 0>;
45
+ decelerationRate?: WithDefault<Double, 0.998>;
46
+ contentInsetTop?: WithDefault<Double, 0>;
47
+ contentInsetRight?: WithDefault<Double, 0>;
48
+ contentInsetBottom?: WithDefault<Double, 0>;
49
+ contentInsetLeft?: WithDefault<Double, 0>;
50
+ refreshEnabled?: WithDefault<boolean, false>;
51
+ refreshing?: WithDefault<boolean, false>;
52
+ refreshTintColor?: ColorValue;
53
+ refreshColors?: ReadonlyArray<ColorValue>;
54
+ refreshProgressBackgroundColor?: ColorValue;
55
+ refreshProgressViewOffset?: WithDefault<Double, 0>;
56
+ refreshTitle?: string;
57
+ refreshTitleColor?: ColorValue;
58
+ refreshSize?: WithDefault<"default" | "large", "default">;
59
+ onContentViewportChange?: DirectEventHandler<Readonly<{ height: Double }>>;
60
+ onRefresh?: DirectEventHandler<null>;
61
+ onScroll?: DirectEventHandler<NativeScrollerScrollEvent>;
62
+ onScrollBeginDrag?: DirectEventHandler<NativeScrollerScrollEvent>;
63
+ onScrollEndDrag?: DirectEventHandler<NativeScrollerScrollEvent>;
64
+ onMomentumScrollBegin?: DirectEventHandler<NativeScrollerScrollEvent>;
65
+ onMomentumScrollEnd?: DirectEventHandler<NativeScrollerScrollEvent>;
66
+ }
67
+
68
+ type NativeScrollerHost = HostComponent<NativeProps>;
69
+
70
+ export interface NativeCommands {
71
+ scrollTo: (
72
+ viewRef: React.ElementRef<NativeScrollerHost>,
73
+ x: Double,
74
+ y: Double,
75
+ animated: boolean
76
+ ) => void;
77
+ scrollToEnd: (
78
+ viewRef: React.ElementRef<NativeScrollerHost>,
79
+ animated: boolean
80
+ ) => void;
81
+ flashScrollIndicators: (
82
+ viewRef: React.ElementRef<NativeScrollerHost>
83
+ ) => void;
84
+ setRefreshState: (
85
+ viewRef: React.ElementRef<NativeScrollerHost>,
86
+ refreshing: boolean
87
+ ) => void;
88
+ }
89
+
90
+ export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
91
+ supportedCommands: [
92
+ "scrollTo",
93
+ "scrollToEnd",
94
+ "flashScrollIndicators",
95
+ "setRefreshState",
96
+ ],
97
+ });
98
+
99
+ export default codegenNativeComponent<NativeProps>("RNCNativeScroller", {
100
+ interfaceOnly: true,
101
+ }) as NativeScrollerHost;
@@ -80,9 +80,8 @@ export interface CollapsiblePagerViewProps extends Omit<NativeProps, "children"
80
80
  nativeTabBar?: CollapsiblePagerNativeTabBarConfig;
81
81
  onNativeTabPress?: (event: CollapsiblePagerViewOnNativeTabPressEvent) => void;
82
82
  /**
83
- * Animates the page change started by a native tab press. Defaults to true.
84
- * Set false to jump straight to the pressed page, so a distant tab does not
85
- * scroll through every page in between, including unmounted ones.
83
+ * Defaults to animating adjacent native tab presses and jumping directly to
84
+ * non-adjacent pages. Set true to always animate, or false to always jump.
86
85
  */
87
86
  nativeTabPressAnimationEnabled?: boolean;
88
87
  /** Optional native secondary sticky header for iOS and Android. */
@@ -106,6 +105,7 @@ export declare class CollapsiblePagerView extends React.PureComponent<Collapsibl
106
105
  private lastMountSignature;
107
106
  private nativeTabCommandId;
108
107
  private latestNativeTabTarget;
108
+ private dispatchedNativeTabTarget;
109
109
  private latestNativeSelectedPage;
110
110
  private nativePagerScrollState;
111
111
  private nativeTabCommandQueuedDuringScroll;
@@ -1,12 +1,20 @@
1
1
  import * as React from "react";
2
- import { type ScrollViewProps } from "react-native";
2
+ import { type NativeMethods, type RefreshControlProps, type ScrollView, type ScrollViewProps, type ViewProps } from "react-native";
3
+ import NativeScrollerHost from "./NativeScrollerNativeComponent";
3
4
  export declare const NATIVE_SCROLLER_NATIVE_ID_PREFIX = "rnc-collapsible-pager-native-scroller";
4
- export interface NativeScrollerProps extends ScrollViewProps {
5
- /** Stable identity used when a page replaces or remounts its primary scroller. */
5
+ /** Supported vertical subset; horizontal, snapping, zoom and sticky rows are not supported. */
6
+ export interface NativeScrollerProps extends ViewProps, Pick<ScrollViewProps, "contentContainerStyle" | "onContentSizeChange" | "scrollEnabled" | "nestedScrollEnabled" | "showsVerticalScrollIndicator" | "showsHorizontalScrollIndicator" | "bounces" | "alwaysBounceVertical" | "contentInset" | "keyboardDismissMode" | "keyboardShouldPersistTaps" | "scrollEventThrottle" | "decelerationRate" | "onScroll" | "onScrollBeginDrag" | "onScrollEndDrag" | "onMomentumScrollBegin" | "onMomentumScrollEnd"> {
6
7
  pagerScrollKey?: string;
8
+ /** iOS only. Android retains AndroidX's native fling physics. */
9
+ decelerationRate?: ScrollViewProps["decelerationRate"];
10
+ /** Standard RefreshControl props are mapped to the independently owned native controller. */
11
+ refreshControl?: React.ReactElement<RefreshControlProps>;
7
12
  }
8
- /**
9
- * Primary non-virtualized vertical scroller for a CollapsiblePagerView page.
10
- */
11
- export declare const NativeScroller: React.ForwardRefExoticComponent<NativeScrollerProps & React.RefAttributes<import("react-native/types_generated/Libraries/Components/ScrollView/ScrollView").PublicScrollViewInstance>>;
13
+ type HostRef = React.ElementRef<typeof NativeScrollerHost>;
14
+ export interface NativeScrollerRef extends NativeMethods, Pick<React.ElementRef<typeof ScrollView>, "scrollTo" | "scrollToEnd" | "flashScrollIndicators"> {
15
+ getNativeScrollRef(): HostRef | null;
16
+ getScrollableNode(): number | null;
17
+ }
18
+ export declare const NativeScroller: React.ForwardRefExoticComponent<NativeScrollerProps & React.RefAttributes<NativeScrollerRef>>;
19
+ export {};
12
20
  //# sourceMappingURL=NativeScroller.d.ts.map
@@ -0,0 +1,79 @@
1
+ import type * as React from "react";
2
+ import { type ColorValue, type HostComponent, type ViewProps } from "react-native";
3
+ import type { DirectEventHandler, Double, WithDefault } from "react-native/Libraries/Types/CodegenTypes";
4
+ export type NativeScrollerScrollEvent = Readonly<{
5
+ contentInset: Readonly<{
6
+ top: Double;
7
+ right: Double;
8
+ bottom: Double;
9
+ left: Double;
10
+ }>;
11
+ contentOffset: Readonly<{
12
+ x: Double;
13
+ y: Double;
14
+ }>;
15
+ contentSize: Readonly<{
16
+ width: Double;
17
+ height: Double;
18
+ }>;
19
+ layoutMeasurement: Readonly<{
20
+ width: Double;
21
+ height: Double;
22
+ }>;
23
+ velocity: Readonly<{
24
+ x: Double;
25
+ y: Double;
26
+ }>;
27
+ targetContentOffset: Readonly<{
28
+ x: Double;
29
+ y: Double;
30
+ }>;
31
+ zoomScale: Double;
32
+ }>;
33
+ export interface NativeProps extends ViewProps {
34
+ contentWidth?: WithDefault<Double, 0>;
35
+ contentHeight?: WithDefault<Double, 0>;
36
+ scrollEnabled?: WithDefault<boolean, true>;
37
+ nestedScrollEnabled?: WithDefault<boolean, true>;
38
+ showsVerticalScrollIndicator?: WithDefault<boolean, true>;
39
+ showsHorizontalScrollIndicator?: WithDefault<boolean, false>;
40
+ bounces?: WithDefault<boolean, true>;
41
+ alwaysBounceVertical?: WithDefault<boolean, true>;
42
+ keyboardDismissMode?: WithDefault<"none" | "on-drag" | "interactive", "none">;
43
+ keyboardShouldPersistTaps?: WithDefault<"never" | "always" | "handled", "never">;
44
+ scrollEventThrottle?: WithDefault<Double, 0>;
45
+ decelerationRate?: WithDefault<Double, 0.998>;
46
+ contentInsetTop?: WithDefault<Double, 0>;
47
+ contentInsetRight?: WithDefault<Double, 0>;
48
+ contentInsetBottom?: WithDefault<Double, 0>;
49
+ contentInsetLeft?: WithDefault<Double, 0>;
50
+ refreshEnabled?: WithDefault<boolean, false>;
51
+ refreshing?: WithDefault<boolean, false>;
52
+ refreshTintColor?: ColorValue;
53
+ refreshColors?: ReadonlyArray<ColorValue>;
54
+ refreshProgressBackgroundColor?: ColorValue;
55
+ refreshProgressViewOffset?: WithDefault<Double, 0>;
56
+ refreshTitle?: string;
57
+ refreshTitleColor?: ColorValue;
58
+ refreshSize?: WithDefault<"default" | "large", "default">;
59
+ onContentViewportChange?: DirectEventHandler<Readonly<{
60
+ height: Double;
61
+ }>>;
62
+ onRefresh?: DirectEventHandler<null>;
63
+ onScroll?: DirectEventHandler<NativeScrollerScrollEvent>;
64
+ onScrollBeginDrag?: DirectEventHandler<NativeScrollerScrollEvent>;
65
+ onScrollEndDrag?: DirectEventHandler<NativeScrollerScrollEvent>;
66
+ onMomentumScrollBegin?: DirectEventHandler<NativeScrollerScrollEvent>;
67
+ onMomentumScrollEnd?: DirectEventHandler<NativeScrollerScrollEvent>;
68
+ }
69
+ type NativeScrollerHost = HostComponent<NativeProps>;
70
+ export interface NativeCommands {
71
+ scrollTo: (viewRef: React.ElementRef<NativeScrollerHost>, x: Double, y: Double, animated: boolean) => void;
72
+ scrollToEnd: (viewRef: React.ElementRef<NativeScrollerHost>, animated: boolean) => void;
73
+ flashScrollIndicators: (viewRef: React.ElementRef<NativeScrollerHost>) => void;
74
+ setRefreshState: (viewRef: React.ElementRef<NativeScrollerHost>, refreshing: boolean) => void;
75
+ }
76
+ export declare const Commands: NativeCommands;
77
+ declare const _default: NativeScrollerHost;
78
+ export default _default;
79
+ //# sourceMappingURL=NativeScrollerNativeComponent.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/react-native-pager-view",
3
- "version": "3.0.158",
3
+ "version": "3.0.160",
4
4
  "description": "React Native wrapper for Android and iOS ViewPager",
5
5
  "source": "./src/index.tsx",
6
6
  "main": "./lib/module/index.js",
@@ -21,6 +21,7 @@
21
21
  "lib",
22
22
  "android",
23
23
  "ios",
24
+ "docs",
24
25
  "react-native-pager-view.podspec",
25
26
  "!ios/build",
26
27
  "!android/build",
@@ -32,7 +33,9 @@
32
33
  "!**/__fixtures__",
33
34
  "!**/__mocks__",
34
35
  "!**/.*",
35
- "!**/*.map"
36
+ "!**/*.map",
37
+ "common",
38
+ "react-native.config.js"
36
39
  ],
37
40
  "scripts": {
38
41
  "clean": "del-cli lib",
@@ -66,7 +69,7 @@
66
69
  "typescript": "^5.9.2"
67
70
  },
68
71
  "peerDependencies": {
69
- "@onekeyfe/react-native-native-logger": "3.0.158",
72
+ "@onekeyfe/react-native-native-logger": "3.0.160",
70
73
  "react": "*",
71
74
  "react-native": "*"
72
75
  },
@@ -98,7 +101,8 @@
98
101
  "ios": {
99
102
  "componentProvider": {
100
103
  "RNCViewPager": "RNCPagerViewComponentView",
101
- "RNCCollapsiblePagerView": "RNCCollapsiblePagerViewComponentView"
104
+ "RNCCollapsiblePagerView": "RNCCollapsiblePagerViewComponentView",
105
+ "RNCNativeScroller": "RNCNativeScrollerComponentView"
102
106
  }
103
107
  }
104
108
  }
@@ -13,7 +13,8 @@ Pod::Spec.new do |s|
13
13
  s.ios.deployment_target = "15.1"
14
14
  s.source = { :git => "https://github.com/nicholasxuu/app-modules.git", :tag => "#{s.version}" }
15
15
 
16
- s.source_files = "ios/**/*.{h,m,mm}"
16
+ s.source_files = "ios/**/*.{h,m,mm}", "common/cpp/**/*.{h,cpp}"
17
+ s.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => '"$(PODS_TARGET_SRCROOT)/common/cpp"' }
17
18
  s.exclude_files = "ios/tests/**/*"
18
19
 
19
20
  s.test_spec "Tests" do |test_spec|
@@ -0,0 +1,15 @@
1
+ module.exports = {
2
+ dependency: {
3
+ platforms: {
4
+ android: {
5
+ libraryName: 'pagerview',
6
+ componentDescriptors: [
7
+ 'RNCViewPagerComponentDescriptor',
8
+ 'RNCCollapsiblePagerViewComponentDescriptor',
9
+ 'RNCNativeScrollerComponentDescriptor',
10
+ ],
11
+ cmakeListsPath: 'src/main/jni/CMakeLists.txt',
12
+ },
13
+ },
14
+ },
15
+ };
@@ -130,9 +130,8 @@ export interface CollapsiblePagerViewProps
130
130
  nativeTabBar?: CollapsiblePagerNativeTabBarConfig;
131
131
  onNativeTabPress?: (event: CollapsiblePagerViewOnNativeTabPressEvent) => void;
132
132
  /**
133
- * Animates the page change started by a native tab press. Defaults to true.
134
- * Set false to jump straight to the pressed page, so a distant tab does not
135
- * scroll through every page in between, including unmounted ones.
133
+ * Defaults to animating adjacent native tab presses and jumping directly to
134
+ * non-adjacent pages. Set true to always animate, or false to always jump.
136
135
  */
137
136
  nativeTabPressAnimationEnabled?: boolean;
138
137
  /** Optional native secondary sticky header for iOS and Android. */
@@ -191,6 +190,10 @@ export class CollapsiblePagerView extends React.PureComponent<
191
190
 
192
191
  private latestNativeTabTarget: number | null = null;
193
192
 
193
+ // Target of the last tab command native has received and not yet reported
194
+ // as selected. Commands superseded before their frame never reach native.
195
+ private dispatchedNativeTabTarget: number | null = null;
196
+
194
197
  private latestNativeSelectedPage = this.state.selectedPage;
195
198
 
196
199
  private nativePagerScrollState: OnPageScrollStateChangedEventData["pageScrollState"] =
@@ -283,6 +286,7 @@ export class CollapsiblePagerView extends React.PureComponent<
283
286
  if (commandId !== this.nativeTabCommandId || !this.nativeRef) {
284
287
  return;
285
288
  }
289
+ this.dispatchedNativeTabTarget = position;
286
290
  if (animated) {
287
291
  CollapsiblePagerViewNativeCommands.setPage(
288
292
  this.nativeRef,
@@ -355,6 +359,7 @@ export class CollapsiblePagerView extends React.PureComponent<
355
359
  const transitionComplete = pendingTarget === position;
356
360
  if (transitionComplete) {
357
361
  this.latestNativeTabTarget = null;
362
+ this.dispatchedNativeTabTarget = null;
358
363
  this.nativeTabCommandQueuedDuringScroll = false;
359
364
  }
360
365
  this.setState(
@@ -387,6 +392,7 @@ export class CollapsiblePagerView extends React.PureComponent<
387
392
  ) {
388
393
  ++this.nativeTabCommandId;
389
394
  this.latestNativeTabTarget = null;
395
+ this.dispatchedNativeTabTarget = null;
390
396
  this.setState(
391
397
  { transientRetainedPages: [] },
392
398
  this.notifyMountedPagesChanged
@@ -409,9 +415,13 @@ export class CollapsiblePagerView extends React.PureComponent<
409
415
  (position !== this.state.selectedPage ||
410
416
  this.latestNativeTabTarget !== null)
411
417
  ) {
418
+ // Selection state lags an in-flight transition until native reports it.
419
+ const currentPage =
420
+ this.dispatchedNativeTabTarget ?? this.state.selectedPage;
412
421
  this.dispatchNativeTabPageCommand(
413
422
  position,
414
- this.props.nativeTabPressAnimationEnabled ?? true
423
+ this.props.nativeTabPressAnimationEnabled ??
424
+ Math.abs(position - currentPage) <= 1
415
425
  );
416
426
  }
417
427
  this.props.onNativeTabPress?.(event);