@onekeyfe/react-native-pager-view 3.0.114 → 3.0.115

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 (29) hide show
  1. package/README.md +40 -0
  2. package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerHost.kt +630 -0
  3. package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerViewManager.kt +222 -0
  4. package/android/src/main/java/com/reactnativepagerview/NestedScrollableHost.kt +3 -1
  5. package/android/src/main/java/com/reactnativepagerview/PagerViewViewPackage.kt +1 -1
  6. package/android/src/main/java/com/reactnativepagerview/event/CollapsibleStateChangedEvent.kt +39 -0
  7. package/ios/RNCCollapsiblePagerViewComponentView.h +9 -0
  8. package/ios/RNCCollapsiblePagerViewComponentView.mm +991 -0
  9. package/ios/RNCPagerViewComponentView.mm +4 -2
  10. package/lib/module/CollapsiblePagerView.js +167 -0
  11. package/lib/module/CollapsiblePagerView.web.js +478 -0
  12. package/lib/module/CollapsiblePagerViewNativeComponent.ts +87 -0
  13. package/lib/module/PagerView.web.js +177 -0
  14. package/lib/module/index.js +2 -1
  15. package/lib/module/index.web.js +6 -0
  16. package/lib/module/usePagerView.js +1 -1
  17. package/lib/typescript/src/CollapsiblePagerView.d.ts +58 -0
  18. package/lib/typescript/src/CollapsiblePagerView.web.d.ts +105 -0
  19. package/lib/typescript/src/CollapsiblePagerViewNativeComponent.d.ts +51 -0
  20. package/lib/typescript/src/PagerView.web.d.ts +55 -0
  21. package/lib/typescript/src/index.d.ts +1 -0
  22. package/lib/typescript/src/index.web.d.ts +5 -0
  23. package/package.json +5 -2
  24. package/src/CollapsiblePagerView.tsx +293 -0
  25. package/src/CollapsiblePagerView.web.tsx +710 -0
  26. package/src/CollapsiblePagerViewNativeComponent.ts +87 -0
  27. package/src/PagerView.web.tsx +280 -0
  28. package/src/index.tsx +1 -0
  29. package/src/index.web.tsx +12 -0
@@ -0,0 +1,87 @@
1
+ import type * as React from "react";
2
+ import {
3
+ codegenNativeCommands,
4
+ codegenNativeComponent,
5
+ type HostComponent,
6
+ type ViewProps,
7
+ } from "react-native";
8
+
9
+ import type {
10
+ DirectEventHandler,
11
+ Double,
12
+ Int32,
13
+ WithDefault,
14
+ } from "react-native/Libraries/Types/CodegenTypes";
15
+
16
+ export type OnPageScrollEventData = Readonly<{
17
+ position: Double;
18
+ offset: Double;
19
+ }>;
20
+
21
+ export type OnPageSelectedEventData = Readonly<{
22
+ position: Double;
23
+ }>;
24
+
25
+ export type OnPageScrollStateChangedEventData = Readonly<{
26
+ pageScrollState: "idle" | "dragging" | "settling";
27
+ }>;
28
+
29
+ export type OnCollapsibleStateChangedEventData = Readonly<{
30
+ position: Int32;
31
+ headerOffset: Double;
32
+ nativePageCount: Int32;
33
+ attachedPageCount: Int32;
34
+ observedScrollableCount: Int32;
35
+ retainedPages: string;
36
+ reason: string;
37
+ }>;
38
+
39
+ /**
40
+ * Internal native props. Consumers should use CollapsiblePagerViewProps from
41
+ * CollapsiblePagerView instead of mounting this host component directly.
42
+ */
43
+ export interface NativeProps extends ViewProps {
44
+ scrollEnabled?: WithDefault<boolean, true>;
45
+ layoutDirection?: WithDefault<"ltr" | "rtl", "ltr">;
46
+ initialPage?: Int32;
47
+ offscreenPageLimit?: Int32;
48
+ // OneKey patch: Preserve nested pager gesture coordination for collapsible pages.
49
+ nestedScrollEnabled?: WithDefault<boolean, false>;
50
+ headerHeight?: Int32;
51
+ stickyHeaderHeight?: Int32;
52
+ pageKeys?: string;
53
+ retainedPages?: string;
54
+ onPageScroll?: DirectEventHandler<OnPageScrollEventData>;
55
+ onPageSelected?: DirectEventHandler<OnPageSelectedEventData>;
56
+ onPageScrollStateChanged?: DirectEventHandler<OnPageScrollStateChangedEventData>;
57
+ onCollapsibleStateChanged?: DirectEventHandler<OnCollapsibleStateChangedEventData>;
58
+ }
59
+
60
+ type CollapsiblePagerViewNativeType = HostComponent<NativeProps>;
61
+
62
+ export interface NativeCommands {
63
+ setPage: (
64
+ viewRef: React.ElementRef<CollapsiblePagerViewNativeType>,
65
+ selectedPage: Int32
66
+ ) => void;
67
+ setPageWithoutAnimation: (
68
+ viewRef: React.ElementRef<CollapsiblePagerViewNativeType>,
69
+ selectedPage: Int32
70
+ ) => void;
71
+ setScrollEnabledImperatively: (
72
+ viewRef: React.ElementRef<CollapsiblePagerViewNativeType>,
73
+ scrollEnabled: boolean
74
+ ) => void;
75
+ }
76
+
77
+ export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
78
+ supportedCommands: [
79
+ "setPage",
80
+ "setPageWithoutAnimation",
81
+ "setScrollEnabledImperatively",
82
+ ],
83
+ });
84
+
85
+ export default codegenNativeComponent<NativeProps>(
86
+ "RNCCollapsiblePagerView"
87
+ ) as HostComponent<NativeProps>;
@@ -0,0 +1,280 @@
1
+ import React from "react";
2
+ import { I18nManager, Keyboard, StyleSheet, View } from "react-native";
3
+ import type * as ReactNative from "react-native";
4
+
5
+ export type PagerViewOnPageScrollEventData = Readonly<{
6
+ position: number;
7
+ offset: number;
8
+ }>;
9
+
10
+ export type PagerViewOnPageSelectedEventData = Readonly<{
11
+ position: number;
12
+ }>;
13
+
14
+ export type PageScrollStateChangedNativeEventData = Readonly<{
15
+ pageScrollState: "idle" | "dragging" | "settling";
16
+ }>;
17
+
18
+ export interface PagerViewProps extends ReactNative.ViewProps {
19
+ scrollEnabled?: boolean;
20
+ layoutDirection?: "ltr" | "rtl" | "locale";
21
+ initialPage?: number;
22
+ orientation?: "horizontal" | "vertical";
23
+ offscreenPageLimit?: number;
24
+ pageMargin?: number;
25
+ overScrollMode?: "auto" | "always" | "never";
26
+ overdrag?: boolean;
27
+ keyboardDismissMode?: "none" | "on-drag";
28
+ scrollSensitivity?: number;
29
+ nestedScrollEnabled?: boolean;
30
+ onPageScroll?: (
31
+ event: ReactNative.NativeSyntheticEvent<PagerViewOnPageScrollEventData>
32
+ ) => void;
33
+ onPageSelected?: (
34
+ event: ReactNative.NativeSyntheticEvent<PagerViewOnPageSelectedEventData>
35
+ ) => void;
36
+ onPageScrollStateChanged?: (
37
+ event: ReactNative.NativeSyntheticEvent<PageScrollStateChangedNativeEventData>
38
+ ) => void;
39
+ }
40
+
41
+ type State = Readonly<{
42
+ selectedPage: number;
43
+ animateTransition: boolean;
44
+ }>;
45
+
46
+ /**
47
+ * Web fallback for the ordinary PagerView API. All pages stay mounted, matching
48
+ * the package's pre-existing PagerView lifetime contract.
49
+ */
50
+ export class PagerView extends React.Component<PagerViewProps, State> {
51
+ state: State = {
52
+ selectedPage: Math.max(0, Math.trunc(this.props.initialPage ?? 0)),
53
+ animateTransition: true,
54
+ };
55
+
56
+ private pointerStart: Readonly<{ x: number; y: number }> | null = null;
57
+ private scrollEnabled = this.props.scrollEnabled ?? true;
58
+
59
+ componentDidUpdate(previousProps: PagerViewProps) {
60
+ if (previousProps.scrollEnabled !== this.props.scrollEnabled) {
61
+ this.scrollEnabled = this.props.scrollEnabled ?? true;
62
+ }
63
+
64
+ const pageCount = React.Children.count(this.props.children);
65
+ if (pageCount > 0 && this.state.selectedPage >= pageCount) {
66
+ this.setState({
67
+ selectedPage: pageCount - 1,
68
+ animateTransition: false,
69
+ });
70
+ }
71
+ }
72
+
73
+ public setPage = (selectedPage: number) => {
74
+ this.selectPage(selectedPage, true);
75
+ };
76
+
77
+ public setPageWithoutAnimation = (selectedPage: number) => {
78
+ this.selectPage(selectedPage, false);
79
+ };
80
+
81
+ public setScrollEnabled = (scrollEnabled: boolean) => {
82
+ this.scrollEnabled = scrollEnabled;
83
+ };
84
+
85
+ private nativeEvent<T>(nativeEvent: T) {
86
+ return { nativeEvent } as ReactNative.NativeSyntheticEvent<T>;
87
+ }
88
+
89
+ private selectPage(selectedPage: number, animated: boolean) {
90
+ const pageCount = React.Children.count(this.props.children);
91
+ const position = Math.trunc(selectedPage);
92
+ if (
93
+ position < 0 ||
94
+ position >= pageCount ||
95
+ position === this.state.selectedPage
96
+ ) {
97
+ return;
98
+ }
99
+
100
+ this.props.onPageScrollStateChanged?.(
101
+ this.nativeEvent<PageScrollStateChangedNativeEventData>({
102
+ pageScrollState: animated ? "settling" : "idle",
103
+ })
104
+ );
105
+ this.setState(
106
+ { selectedPage: position, animateTransition: animated },
107
+ () => {
108
+ this.props.onPageScroll?.(
109
+ this.nativeEvent<PagerViewOnPageScrollEventData>({
110
+ position,
111
+ offset: 0,
112
+ })
113
+ );
114
+ this.props.onPageSelected?.(
115
+ this.nativeEvent<PagerViewOnPageSelectedEventData>({ position })
116
+ );
117
+ if (animated) {
118
+ this.props.onPageScrollStateChanged?.(
119
+ this.nativeEvent<PageScrollStateChangedNativeEventData>({
120
+ pageScrollState: "idle",
121
+ })
122
+ );
123
+ }
124
+ }
125
+ );
126
+ }
127
+
128
+ private onTouchStart = (event: ReactNative.GestureResponderEvent) => {
129
+ if (!this.scrollEnabled) return;
130
+ this.pointerStart = {
131
+ x: event.nativeEvent.pageX,
132
+ y: event.nativeEvent.pageY,
133
+ };
134
+ if (this.props.keyboardDismissMode === "on-drag") Keyboard.dismiss();
135
+ this.props.onPageScrollStateChanged?.(
136
+ this.nativeEvent<PageScrollStateChangedNativeEventData>({
137
+ pageScrollState: "dragging",
138
+ })
139
+ );
140
+ };
141
+
142
+ private onTouchEnd = (event: ReactNative.GestureResponderEvent) => {
143
+ const start = this.pointerStart;
144
+ this.pointerStart = null;
145
+ if (!start || !this.scrollEnabled) return;
146
+
147
+ const vertical = this.props.orientation === "vertical";
148
+ const delta = vertical
149
+ ? event.nativeEvent.pageY - start.y
150
+ : event.nativeEvent.pageX - start.x;
151
+ const isRTL =
152
+ !vertical &&
153
+ (this.props.layoutDirection === "rtl" ||
154
+ ((!this.props.layoutDirection ||
155
+ this.props.layoutDirection === "locale") &&
156
+ I18nManager.isRTL));
157
+ const direction = Math.abs(delta) >= 40 ? (delta < 0 ? 1 : -1) : 0;
158
+ const next = this.state.selectedPage + (isRTL ? -direction : direction);
159
+ if (
160
+ direction === 0 ||
161
+ next < 0 ||
162
+ next >= React.Children.count(this.props.children)
163
+ ) {
164
+ this.props.onPageScrollStateChanged?.(
165
+ this.nativeEvent<PageScrollStateChangedNativeEventData>({
166
+ pageScrollState: "idle",
167
+ })
168
+ );
169
+ return;
170
+ }
171
+ this.selectPage(next, true);
172
+ };
173
+
174
+ render() {
175
+ const {
176
+ children,
177
+ style,
178
+ orientation = "horizontal",
179
+ pageMargin = 0,
180
+ scrollEnabled: _scrollEnabled,
181
+ initialPage: _initialPage,
182
+ layoutDirection: _layoutDirection,
183
+ offscreenPageLimit: _offscreenPageLimit,
184
+ overScrollMode: _overScrollMode,
185
+ overdrag: _overdrag,
186
+ keyboardDismissMode: _keyboardDismissMode,
187
+ scrollSensitivity: _scrollSensitivity,
188
+ nestedScrollEnabled: _nestedScrollEnabled,
189
+ onPageScroll: _onPageScroll,
190
+ onPageSelected: _onPageSelected,
191
+ onPageScrollStateChanged: _onPageScrollStateChanged,
192
+ ...viewProps
193
+ } = this.props;
194
+ const pages = React.Children.toArray(children);
195
+ const vertical = orientation === "vertical";
196
+ const pageExtent = pages.length > 0 ? `${100 / pages.length}%` : "100%";
197
+ const transform = vertical
198
+ ? [
199
+ {
200
+ translateY: `${
201
+ (-this.state.selectedPage * 100) / Math.max(1, pages.length)
202
+ }%`,
203
+ },
204
+ ]
205
+ : [
206
+ {
207
+ translateX: `${
208
+ (-this.state.selectedPage * 100) / Math.max(1, pages.length)
209
+ }%`,
210
+ },
211
+ ];
212
+
213
+ return (
214
+ <View {...viewProps} style={[styles.root, style]}>
215
+ <View
216
+ style={[
217
+ styles.track,
218
+ vertical ? styles.verticalTrack : styles.horizontalTrack,
219
+ vertical
220
+ ? { height: `${Math.max(1, pages.length) * 100}%` }
221
+ : { width: `${Math.max(1, pages.length) * 100}%` },
222
+ {
223
+ transform,
224
+ transitionProperty: "transform",
225
+ transitionDuration: this.state.animateTransition
226
+ ? "240ms"
227
+ : "0ms",
228
+ } as never,
229
+ ]}
230
+ onTouchStart={this.onTouchStart}
231
+ onTouchEnd={this.onTouchEnd}
232
+ >
233
+ {pages.map((page, index) => (
234
+ <View
235
+ key={React.isValidElement(page) ? page.key ?? index : index}
236
+ style={[
237
+ styles.page,
238
+ vertical
239
+ ? { height: pageExtent, paddingVertical: pageMargin / 2 }
240
+ : { width: pageExtent, paddingHorizontal: pageMargin / 2 },
241
+ ]}
242
+ >
243
+ {page}
244
+ </View>
245
+ ))}
246
+ </View>
247
+ </View>
248
+ );
249
+ }
250
+ }
251
+
252
+ const styles = StyleSheet.create({
253
+ root: {
254
+ overflow: "hidden",
255
+ },
256
+ track: {
257
+ flex: 1,
258
+ },
259
+ horizontalTrack: {
260
+ flexDirection: "row",
261
+ height: "100%",
262
+ },
263
+ verticalTrack: {
264
+ flexDirection: "column",
265
+ width: "100%",
266
+ },
267
+ page: {
268
+ flexShrink: 0,
269
+ minWidth: 0,
270
+ minHeight: 0,
271
+ overflow: "hidden",
272
+ },
273
+ });
274
+
275
+ export type PagerViewOnPageScrollEvent =
276
+ ReactNative.NativeSyntheticEvent<PagerViewOnPageScrollEventData>;
277
+ export type PagerViewOnPageSelectedEvent =
278
+ ReactNative.NativeSyntheticEvent<PagerViewOnPageSelectedEventData>;
279
+ export type PageScrollStateChangedNativeEvent =
280
+ ReactNative.NativeSyntheticEvent<PageScrollStateChangedNativeEventData>;
package/src/index.tsx CHANGED
@@ -2,6 +2,7 @@ import type * as ReactNative from 'react-native';
2
2
  import { PagerView } from './PagerView';
3
3
  export default PagerView;
4
4
  export * from './usePagerView';
5
+ export * from './CollapsiblePagerView';
5
6
 
6
7
  import type {
7
8
  OnPageScrollEventData as PagerViewOnPageScrollEventData,
@@ -0,0 +1,12 @@
1
+ export { PagerView as default, PagerView } from "./PagerView.web";
2
+ export type {
3
+ PagerViewProps,
4
+ PagerViewOnPageScrollEvent,
5
+ PagerViewOnPageScrollEventData,
6
+ PagerViewOnPageSelectedEvent,
7
+ PagerViewOnPageSelectedEventData,
8
+ PageScrollStateChangedNativeEvent,
9
+ PageScrollStateChangedNativeEventData,
10
+ } from "./PagerView.web";
11
+ export * from "./usePagerView";
12
+ export * from "./CollapsiblePagerView.web";