@onekeyfe/react-native-pager-view 3.0.178 → 3.0.179-alpha.20261015

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.
@@ -7,6 +7,8 @@ export const NativeScroller = /*#__PURE__*/React.forwardRef(function NativeScrol
7
7
  const {
8
8
  dataSet,
9
9
  pagerScrollKey: _pagerScrollKey,
10
+ topOverlay: _topOverlay,
11
+ topScrollEdgeEffect: _topScrollEdgeEffect,
10
12
  ...props
11
13
  } = inputProps;
12
14
  const webDataProps = {
@@ -47,6 +47,8 @@ export interface NativeProps extends ViewProps {
47
47
  contentInsetRight?: WithDefault<Double, 0>;
48
48
  contentInsetBottom?: WithDefault<Double, 0>;
49
49
  contentInsetLeft?: WithDefault<Double, 0>;
50
+ topScrollEdgeHard?: WithDefault<boolean, false>;
51
+ topOverlayHeight?: WithDefault<Double, 0>;
50
52
  refreshEnabled?: WithDefault<boolean, false>;
51
53
  refreshing?: WithDefault<boolean, false>;
52
54
  refreshTintColor?: ColorValue;
@@ -55,7 +55,7 @@ export type CollapsiblePagerNativeSubHeaderConfig = Readonly<{
55
55
  }>;
56
56
  export type CollapsiblePagerViewOnNativeTabPressEvent = ReactNative.NativeSyntheticEvent<OnNativeTabPressEventData>;
57
57
  export type CollapsiblePagerViewOnNativeSubHeaderPressEvent = ReactNative.NativeSyntheticEvent<OnNativeTabPressEventData>;
58
- export interface CollapsiblePagerViewProps extends Omit<NativeProps, "children" | "headerHeight" | "stickyHeaderHeight" | "pageKeys" | "retainedPages" | "nativeTabBarItems" | "nativeTabBarHeight" | "nativeTabBarContentPaddingHorizontal" | "nativeTabBarItemSpacing" | "nativeTabBarFontSize" | "nativeTabBarFontFamily" | "nativeTabBarBackgroundColor" | "nativeTabBarActiveTextColor" | "nativeTabBarInactiveTextColor" | "nativeTabBarIndicatorColor" | "nativeTabBarIndicatorHeight" | "nativeTabBarIndicatorBottom" | "nativeSubHeaderConfig" | "nativeSubHeaderSelectedBackgroundColor" | "onNativeTabPress" | "onNativeSubHeaderPress" | "layoutDirection"> {
58
+ export interface CollapsiblePagerViewProps extends Omit<NativeProps, "children" | "headerHeight" | "stickyHeaderHeight" | "topScrollEdgeHard" | "topOverlayHeight" | "externalTopOverlayTag" | "pageKeys" | "retainedPages" | "nativeTabBarItems" | "nativeTabBarHeight" | "nativeTabBarContentPaddingHorizontal" | "nativeTabBarItemSpacing" | "nativeTabBarFontSize" | "nativeTabBarFontFamily" | "nativeTabBarBackgroundColor" | "nativeTabBarActiveTextColor" | "nativeTabBarInactiveTextColor" | "nativeTabBarIndicatorColor" | "nativeTabBarIndicatorHeight" | "nativeTabBarIndicatorBottom" | "nativeSubHeaderConfig" | "nativeSubHeaderSelectedBackgroundColor" | "onNativeTabPress" | "onNativeSubHeaderPress" | "layoutDirection"> {
59
59
  /** Collapsible content rendered above the sticky bar. */
60
60
  header: React.ReactNode;
61
61
  /** Bar which remains pinned after the header has collapsed. */
@@ -64,6 +64,14 @@ export interface CollapsiblePagerViewProps extends Omit<NativeProps, "children"
64
64
  headerHeight: number;
65
65
  /** Measured sticky bar height. */
66
66
  stickyHeaderHeight: number;
67
+ /** Fixed content above the collapsible header on iOS 26 and newer. */
68
+ topOverlay?: React.ReactNode;
69
+ /** Existing fixed header shared with a parent pager on iOS 26 and newer. */
70
+ externalTopOverlayTag?: number;
71
+ /** Enables UIKit's hard top scroll-edge effect on iOS 26 and newer. */
72
+ topScrollEdgeEffect?: "hard";
73
+ /** Effective appearance of the fixed overlay or pinned sticky bar. */
74
+ topOverlayColorScheme?: "light" | "dark";
67
75
  /**
68
76
  * Lets the active native list own vertical gestures that begin on pager headers.
69
77
  * Defaults to false and has no effect on Web.
@@ -93,6 +101,7 @@ export interface CollapsiblePagerViewProps extends Omit<NativeProps, "children"
93
101
  type State = {
94
102
  selectedPage: number;
95
103
  transientRetainedPages: readonly number[];
104
+ topOverlayHeight: number;
96
105
  };
97
106
  /**
98
107
  * Pager variant whose vertical header coordination is performed by the native
@@ -39,6 +39,10 @@ export interface CollapsiblePagerViewProps extends Omit<WebCollapsiblePagerNativ
39
39
  stickyHeader: React.ReactNode;
40
40
  headerHeight: number;
41
41
  stickyHeaderHeight: number;
42
+ topOverlay?: React.ReactNode;
43
+ topScrollEdgeEffect?: "hard";
44
+ topOverlayColorScheme?: "light" | "dark";
45
+ externalTopOverlayTag?: number;
42
46
  pageRetentionDistance?: number;
43
47
  layoutDirection?: "ltr" | "rtl" | "locale";
44
48
  children?: React.ReactNode;
@@ -26,6 +26,9 @@ export type OnNativeTabPressEventData = Readonly<{
26
26
  position: Int32;
27
27
  key: string;
28
28
  }>;
29
+ export type OnScrollEdgeCapabilityEventData = Readonly<{
30
+ available: boolean;
31
+ }>;
29
32
  /**
30
33
  * Internal native props. Consumers should use CollapsiblePagerViewProps from
31
34
  * CollapsiblePagerView instead of mounting this host component directly.
@@ -39,6 +42,10 @@ export interface NativeProps extends ViewProps {
39
42
  nativeSmoothHeaderScrollEnabled?: WithDefault<boolean, false>;
40
43
  headerHeight?: Int32;
41
44
  stickyHeaderHeight?: Int32;
45
+ topScrollEdgeHard?: WithDefault<boolean, false>;
46
+ topOverlayColorScheme?: string;
47
+ topOverlayHeight?: WithDefault<Double, 0>;
48
+ externalTopOverlayTag?: WithDefault<Int32, 0>;
42
49
  pageKeys?: string;
43
50
  retainedPages?: string;
44
51
  nativeTabBarItems?: string;
@@ -61,6 +68,7 @@ export interface NativeProps extends ViewProps {
61
68
  onCollapsibleStateChanged?: DirectEventHandler<OnCollapsibleStateChangedEventData>;
62
69
  onNativeTabPress?: DirectEventHandler<OnNativeTabPressEventData>;
63
70
  onNativeSubHeaderPress?: DirectEventHandler<OnNativeTabPressEventData>;
71
+ onScrollEdgeCapability?: DirectEventHandler<OnScrollEdgeCapabilityEventData>;
64
72
  }
65
73
  type CollapsiblePagerViewNativeType = HostComponent<NativeProps>;
66
74
  export interface NativeCommands {
@@ -5,6 +5,10 @@ export declare const NATIVE_SCROLLER_NATIVE_ID_PREFIX = "rnc-collapsible-pager-n
5
5
  /** Supported vertical subset; horizontal, snapping, zoom and sticky rows are not supported. */
6
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"> {
7
7
  pagerScrollKey?: string;
8
+ /** Fixed overlay above scrolling content on iOS 26 and newer. */
9
+ topOverlay?: React.ReactNode;
10
+ /** Enables UIKit's hard top scroll-edge effect on iOS 26 and newer. */
11
+ topScrollEdgeEffect?: "hard";
8
12
  /** iOS only. Android retains AndroidX's native fling physics. */
9
13
  decelerationRate?: ScrollViewProps["decelerationRate"];
10
14
  /** Standard RefreshControl props are mapped to the independently owned native controller. */
@@ -47,6 +47,8 @@ export interface NativeProps extends ViewProps {
47
47
  contentInsetRight?: WithDefault<Double, 0>;
48
48
  contentInsetBottom?: WithDefault<Double, 0>;
49
49
  contentInsetLeft?: WithDefault<Double, 0>;
50
+ topScrollEdgeHard?: WithDefault<boolean, false>;
51
+ topOverlayHeight?: WithDefault<Double, 0>;
50
52
  refreshEnabled?: WithDefault<boolean, false>;
51
53
  refreshing?: WithDefault<boolean, false>;
52
54
  refreshTintColor?: ColorValue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/react-native-pager-view",
3
- "version": "3.0.178",
3
+ "version": "3.0.179-alpha.20261015",
4
4
  "description": "React Native wrapper for Android and iOS ViewPager",
5
5
  "source": "./src/index.tsx",
6
6
  "main": "./lib/module/index.js",
@@ -72,7 +72,7 @@
72
72
  "typescript": "^5.9.2"
73
73
  },
74
74
  "peerDependencies": {
75
- "@onekeyfe/react-native-native-logger": "3.0.178",
75
+ "@onekeyfe/react-native-native-logger": "3.0.179-alpha.20261015",
76
76
  "react": "*",
77
77
  "react-native": "*"
78
78
  },
@@ -86,6 +86,9 @@ export interface CollapsiblePagerViewProps
86
86
  | "children"
87
87
  | "headerHeight"
88
88
  | "stickyHeaderHeight"
89
+ | "topScrollEdgeHard"
90
+ | "topOverlayHeight"
91
+ | "externalTopOverlayTag"
89
92
  | "pageKeys"
90
93
  | "retainedPages"
91
94
  | "nativeTabBarItems"
@@ -114,6 +117,14 @@ export interface CollapsiblePagerViewProps
114
117
  headerHeight: number;
115
118
  /** Measured sticky bar height. */
116
119
  stickyHeaderHeight: number;
120
+ /** Fixed content above the collapsible header on iOS 26 and newer. */
121
+ topOverlay?: React.ReactNode;
122
+ /** Existing fixed header shared with a parent pager on iOS 26 and newer. */
123
+ externalTopOverlayTag?: number;
124
+ /** Enables UIKit's hard top scroll-edge effect on iOS 26 and newer. */
125
+ topScrollEdgeEffect?: "hard";
126
+ /** Effective appearance of the fixed overlay or pinned sticky bar. */
127
+ topOverlayColorScheme?: "light" | "dark";
117
128
  /**
118
129
  * Lets the active native list own vertical gestures that begin on pager headers.
119
130
  * Defaults to false and has no effect on Web.
@@ -146,6 +157,7 @@ export interface CollapsiblePagerViewProps
146
157
  type State = {
147
158
  selectedPage: number;
148
159
  transientRetainedPages: readonly number[];
160
+ topOverlayHeight: number;
149
161
  };
150
162
 
151
163
  const pageIndex = (value: number) => {
@@ -173,6 +185,7 @@ export class CollapsiblePagerView extends React.PureComponent<
173
185
  State
174
186
  > {
175
187
  state: State = {
188
+ topOverlayHeight: 0,
176
189
  selectedPage: clampedPageIndex(
177
190
  this.props.initialPage ?? 0,
178
191
  React.Children.toArray(this.props.children).length
@@ -458,6 +471,10 @@ export class CollapsiblePagerView extends React.PureComponent<
458
471
  stickyHeader,
459
472
  headerHeight,
460
473
  stickyHeaderHeight,
474
+ topOverlay,
475
+ externalTopOverlayTag,
476
+ topScrollEdgeEffect,
477
+ topOverlayColorScheme,
461
478
  nativeSmoothHeaderScrollEnabled,
462
479
  pageRetentionDistance: _pageRetentionDistance,
463
480
  onMountedPagesChanged: _onMountedPagesChanged,
@@ -474,6 +491,10 @@ export class CollapsiblePagerView extends React.PureComponent<
474
491
  ...nativeProps
475
492
  } = this.props;
476
493
  const pages = this.pages();
494
+ const supportsTopScrollEdge =
495
+ Platform.OS === "ios" && Number(Platform.Version) >= 26;
496
+ const hardScrollEdge = supportsTopScrollEdge && topScrollEdgeEffect === "hard";
497
+ const hasTopOverlay = hardScrollEdge && topOverlay != null;
477
498
  const pageKeys = pages.map(pageKey);
478
499
  const retained = new Set(this.mountedPages(pages.length));
479
500
  const deducedLayoutDirection =
@@ -514,6 +535,14 @@ export class CollapsiblePagerView extends React.PureComponent<
514
535
  offscreenPageLimit={Math.max(1, offscreenPageLimit ?? 1)}
515
536
  headerHeight={Math.max(0, Math.round(headerHeight))}
516
537
  stickyHeaderHeight={Math.max(0, Math.round(stickyHeaderHeight))}
538
+ topScrollEdgeHard={hardScrollEdge}
539
+ topOverlayColorScheme={hardScrollEdge ? topOverlayColorScheme : undefined}
540
+ topOverlayHeight={hasTopOverlay ? this.state.topOverlayHeight : 0}
541
+ externalTopOverlayTag={
542
+ supportsTopScrollEdge && !hasTopOverlay
543
+ ? externalTopOverlayTag ?? 0
544
+ : 0
545
+ }
517
546
  nativeSmoothHeaderScrollEnabled={nativeSmoothHeaderScrollEnabled}
518
547
  pageKeys={JSON.stringify(pageKeys)}
519
548
  retainedPages={JSON.stringify([...retained])}
@@ -603,6 +632,21 @@ export class CollapsiblePagerView extends React.PureComponent<
603
632
  >
604
633
  {stickyHeader}
605
634
  </View>
635
+ {hasTopOverlay ? (
636
+ <View
637
+ key="top-overlay"
638
+ collapsable={false}
639
+ style={[styles.slot, { bottom: undefined }]}
640
+ onLayout={(event) => {
641
+ const height = Math.ceil(event.nativeEvent.layout.height);
642
+ if (this.state.topOverlayHeight !== height) {
643
+ this.setState({ topOverlayHeight: height });
644
+ }
645
+ }}
646
+ >
647
+ {topOverlay}
648
+ </View>
649
+ ) : null}
606
650
  {pages.map((page, index) => (
607
651
  <View
608
652
  key={pageKeys[index]}
@@ -66,6 +66,10 @@ export interface CollapsiblePagerViewProps
66
66
  stickyHeader: React.ReactNode;
67
67
  headerHeight: number;
68
68
  stickyHeaderHeight: number;
69
+ topOverlay?: React.ReactNode;
70
+ topScrollEdgeEffect?: "hard";
71
+ topOverlayColorScheme?: "light" | "dark";
72
+ externalTopOverlayTag?: number;
69
73
  pageRetentionDistance?: number;
70
74
  layoutDirection?: "ltr" | "rtl" | "locale";
71
75
  children?: React.ReactNode;
@@ -759,6 +763,10 @@ export class CollapsiblePagerView extends React.PureComponent<
759
763
  children: _children,
760
764
  header,
761
765
  stickyHeader,
766
+ topOverlay: _topOverlay,
767
+ topScrollEdgeEffect: _topScrollEdgeEffect,
768
+ topOverlayColorScheme: _topOverlayColorScheme,
769
+ externalTopOverlayTag: _externalTopOverlayTag,
762
770
  headerHeight: _headerHeight,
763
771
  stickyHeaderHeight: _stickyHeaderHeight,
764
772
  pageRetentionDistance: _pageRetentionDistance,
@@ -43,6 +43,7 @@ export type OnNativeTabPressEventData = Readonly<{
43
43
  position: Int32;
44
44
  key: string;
45
45
  }>;
46
+ export type OnScrollEdgeCapabilityEventData = Readonly<{ available: boolean }>;
46
47
 
47
48
  /**
48
49
  * Internal native props. Consumers should use CollapsiblePagerViewProps from
@@ -58,6 +59,10 @@ export interface NativeProps extends ViewProps {
58
59
  nativeSmoothHeaderScrollEnabled?: WithDefault<boolean, false>;
59
60
  headerHeight?: Int32;
60
61
  stickyHeaderHeight?: Int32;
62
+ topScrollEdgeHard?: WithDefault<boolean, false>;
63
+ topOverlayColorScheme?: string;
64
+ topOverlayHeight?: WithDefault<Double, 0>;
65
+ externalTopOverlayTag?: WithDefault<Int32, 0>;
61
66
  pageKeys?: string;
62
67
  retainedPages?: string;
63
68
  nativeTabBarItems?: string;
@@ -80,6 +85,7 @@ export interface NativeProps extends ViewProps {
80
85
  onCollapsibleStateChanged?: DirectEventHandler<OnCollapsibleStateChangedEventData>;
81
86
  onNativeTabPress?: DirectEventHandler<OnNativeTabPressEventData>;
82
87
  onNativeSubHeaderPress?: DirectEventHandler<OnNativeTabPressEventData>;
88
+ onScrollEdgeCapability?: DirectEventHandler<OnScrollEdgeCapabilityEventData>;
83
89
  }
84
90
 
85
91
  type CollapsiblePagerViewNativeType = HostComponent<NativeProps>;
@@ -44,6 +44,10 @@ export interface NativeScrollerProps
44
44
  | "onMomentumScrollEnd"
45
45
  > {
46
46
  pagerScrollKey?: string;
47
+ /** Fixed overlay above scrolling content on iOS 26 and newer. */
48
+ topOverlay?: React.ReactNode;
49
+ /** Enables UIKit's hard top scroll-edge effect on iOS 26 and newer. */
50
+ topScrollEdgeEffect?: "hard";
47
51
  /** iOS only. Android retains AndroidX's native fling physics. */
48
52
  decelerationRate?: ScrollViewProps["decelerationRate"];
49
53
  /** Standard RefreshControl props are mapped to the independently owned native controller. */
@@ -81,6 +85,8 @@ export const NativeScroller = React.forwardRef<
81
85
  >(function NativeScroller(
82
86
  {
83
87
  children,
88
+ topOverlay,
89
+ topScrollEdgeEffect,
84
90
  nativeID,
85
91
  pagerScrollKey,
86
92
  style,
@@ -109,6 +115,10 @@ export const NativeScroller = React.forwardRef<
109
115
  const generatedId = React.useId();
110
116
  const [contentViewportHeight, setContentViewportHeight] = React.useState(0);
111
117
  const [contentSize, setContentSize] = React.useState({ width: 0, height: 0 });
118
+ const [topOverlayHeight, setTopOverlayHeight] = React.useState(0);
119
+ const hasTopOverlay =
120
+ Platform.OS === "ios" && Number(Platform.Version) >= 26 &&
121
+ topScrollEdgeEffect === "hard" && topOverlay != null;
112
122
  const [refreshEpoch, requestRefreshSync] = React.useReducer(
113
123
  (value: number) => value + 1,
114
124
  0
@@ -187,13 +197,14 @@ export const NativeScroller = React.forwardRef<
187
197
  );
188
198
 
189
199
  return (
200
+ <View collapsable={false} style={[styles.viewport, style]} onLayout={onLayout}>
190
201
  <NativeScrollerHost
191
202
  {...props}
192
203
  ref={hostRef}
193
204
  nativeID={`${NATIVE_SCROLLER_NATIVE_ID_PREFIX}:${
194
205
  pagerScrollKey ?? nativeID ?? generatedId
195
206
  }`}
196
- style={[styles.viewport, style]}
207
+ style={StyleSheet.absoluteFill}
197
208
  nestedScrollEnabled={nestedScrollEnabled}
198
209
  contentWidth={contentSize.width}
199
210
  contentHeight={contentSize.height}
@@ -201,6 +212,8 @@ export const NativeScroller = React.forwardRef<
201
212
  contentInsetRight={contentInset?.right ?? 0}
202
213
  contentInsetBottom={contentInset?.bottom ?? 0}
203
214
  contentInsetLeft={contentInset?.left ?? 0}
215
+ topScrollEdgeHard={hasTopOverlay}
216
+ topOverlayHeight={hasTopOverlay ? topOverlayHeight : 0}
204
217
  decelerationRate={rate}
205
218
  keyboardShouldPersistTaps={persistTaps}
206
219
  refreshEnabled={Boolean(refresh) && refresh?.enabled !== false}
@@ -219,7 +232,6 @@ export const NativeScroller = React.forwardRef<
219
232
  requestRefreshSync();
220
233
  }
221
234
  }}
222
- onLayout={onLayout}
223
235
  onContentViewportChange={(event) => {
224
236
  const height = event.nativeEvent.height;
225
237
  if (!Number.isFinite(height) || height < 0) return;
@@ -306,6 +318,19 @@ export const NativeScroller = React.forwardRef<
306
318
  {children}
307
319
  </View>
308
320
  </NativeScrollerHost>
321
+ {hasTopOverlay ? (
322
+ <View
323
+ collapsable={false}
324
+ style={{ position: "absolute", top: 0, left: 0, right: 0 }}
325
+ onLayout={(event) => {
326
+ const height = Math.ceil(event.nativeEvent.layout.height);
327
+ setTopOverlayHeight((previous) => previous === height ? previous : height);
328
+ }}
329
+ >
330
+ {topOverlay}
331
+ </View>
332
+ ) : null}
333
+ </View>
309
334
  );
310
335
  });
311
336
 
@@ -14,6 +14,8 @@ export const NativeScroller = React.forwardRef<
14
14
  const {
15
15
  dataSet,
16
16
  pagerScrollKey: _pagerScrollKey,
17
+ topOverlay: _topOverlay,
18
+ topScrollEdgeEffect: _topScrollEdgeEffect,
17
19
  ...props
18
20
  } = inputProps as NativeScrollerWebProps;
19
21
  const webDataProps = {
@@ -47,6 +47,8 @@ export interface NativeProps extends ViewProps {
47
47
  contentInsetRight?: WithDefault<Double, 0>;
48
48
  contentInsetBottom?: WithDefault<Double, 0>;
49
49
  contentInsetLeft?: WithDefault<Double, 0>;
50
+ topScrollEdgeHard?: WithDefault<boolean, false>;
51
+ topOverlayHeight?: WithDefault<Double, 0>;
50
52
  refreshEnabled?: WithDefault<boolean, false>;
51
53
  refreshing?: WithDefault<boolean, false>;
52
54
  refreshTintColor?: ColorValue;