@onekeyfe/react-native-pager-view 6.7.0-1 → 6.7.0-3
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 +9 -0
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerViewManager.kt +2 -2
- package/android/src/main/java/com/reactnativepagerview/NativeScrollerViewManager.kt +2 -2
- package/docs/SPEC.md +77 -4
- package/ios/RNCCollapsiblePagerViewComponentView.mm +84 -21
- package/ios/RNCNativeScrollerComponentView.mm +6 -5
- package/ios/tests/RNCCollapsiblePagerHitTestTests.mm +26 -1
- package/ios/tests/RNCNativeScrollerTests.mm +39 -0
- package/lib/module/CollapsiblePagerView.js +4 -4
- package/lib/module/CollapsiblePagerView.web.js +428 -37
- package/lib/module/CollapsiblePagerViewNativeComponent.ts +1 -1
- package/lib/module/NativeScroller.js +2 -2
- package/lib/module/NativeScroller.web.js +16 -3
- package/lib/module/NativeScrollerNativeComponent.ts +1 -1
- package/lib/module/ScrollEdgeEffect.js +8 -0
- package/lib/module/WebCollapsiblePagerPage.js +182 -0
- package/lib/module/index.js +3 -0
- package/lib/module/index.web.js +3 -0
- package/lib/typescript/src/CollapsiblePagerView.d.ts +4 -3
- package/lib/typescript/src/CollapsiblePagerView.web.d.ts +66 -4
- package/lib/typescript/src/CollapsiblePagerViewNativeComponent.d.ts +1 -1
- package/lib/typescript/src/NativeScroller.d.ts +3 -2
- package/lib/typescript/src/NativeScrollerNativeComponent.d.ts +1 -1
- package/lib/typescript/src/ScrollEdgeEffect.d.ts +5 -0
- package/lib/typescript/src/WebCollapsiblePagerPage.d.ts +42 -0
- package/lib/typescript/src/index.d.ts +5 -0
- package/lib/typescript/src/index.web.d.ts +5 -0
- package/package.json +2 -2
- package/src/CollapsiblePagerView.tsx +12 -7
- package/src/CollapsiblePagerView.web.tsx +640 -50
- package/src/CollapsiblePagerViewNativeComponent.ts +1 -1
- package/src/NativeScroller.tsx +6 -4
- package/src/NativeScroller.web.tsx +24 -2
- package/src/NativeScrollerNativeComponent.ts +1 -1
- package/src/ScrollEdgeEffect.ts +4 -0
- package/src/WebCollapsiblePagerPage.tsx +258 -0
- package/src/index.tsx +6 -0
- package/src/index.web.tsx +6 -0
|
@@ -59,7 +59,7 @@ export interface NativeProps extends ViewProps {
|
|
|
59
59
|
nativeSmoothHeaderScrollEnabled?: WithDefault<boolean, false>;
|
|
60
60
|
headerHeight?: Int32;
|
|
61
61
|
stickyHeaderHeight?: Int32;
|
|
62
|
-
|
|
62
|
+
topScrollEdgeEffect?: WithDefault<"none" | "hard" | "soft", "none">;
|
|
63
63
|
topOverlayColorScheme?: string;
|
|
64
64
|
topOverlayHeight?: WithDefault<Double, 0>;
|
|
65
65
|
externalTopOverlayTag?: WithDefault<Int32, 0>;
|
|
@@ -59,7 +59,7 @@ export const NativeScroller = /*#__PURE__*/React.forwardRef(function NativeScrol
|
|
|
59
59
|
height: 0
|
|
60
60
|
});
|
|
61
61
|
const [topOverlayHeight, setTopOverlayHeight] = React.useState(0);
|
|
62
|
-
const hasTopOverlay = Platform.OS === "ios" && parseInt(String(Platform.Version), 10) >= 26 && topScrollEdgeEffect === "hard" && topOverlay != null;
|
|
62
|
+
const hasTopOverlay = Platform.OS === "ios" && parseInt(String(Platform.Version), 10) >= 26 && (topScrollEdgeEffect === "hard" || topScrollEdgeEffect === "soft") && topOverlay != null;
|
|
63
63
|
const [refreshEpoch, requestRefreshSync] = React.useReducer(value => value + 1, 0);
|
|
64
64
|
const contentSizeRef = React.useRef(contentSize);
|
|
65
65
|
const scrolledSinceGrant = React.useRef(false);
|
|
@@ -114,7 +114,7 @@ export const NativeScroller = /*#__PURE__*/React.forwardRef(function NativeScrol
|
|
|
114
114
|
contentInsetRight: contentInset?.right ?? 0,
|
|
115
115
|
contentInsetBottom: contentInset?.bottom ?? 0,
|
|
116
116
|
contentInsetLeft: contentInset?.left ?? 0,
|
|
117
|
-
|
|
117
|
+
topScrollEdgeEffect: hasTopOverlay ? topScrollEdgeEffect : "none",
|
|
118
118
|
topOverlayHeight: hasTopOverlay ? topOverlayHeight : 0,
|
|
119
119
|
decelerationRate: rate,
|
|
120
120
|
keyboardShouldPersistTaps: persistTaps,
|
|
@@ -6,20 +6,33 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
6
6
|
export const NativeScroller = /*#__PURE__*/React.forwardRef(function NativeScroller(inputProps, ref) {
|
|
7
7
|
const {
|
|
8
8
|
dataSet,
|
|
9
|
-
pagerScrollKey
|
|
9
|
+
pagerScrollKey,
|
|
10
10
|
topOverlay: _topOverlay,
|
|
11
11
|
topScrollEdgeEffect: _topScrollEdgeEffect,
|
|
12
12
|
...props
|
|
13
13
|
} = inputProps;
|
|
14
|
+
const scrollRef = React.useRef(null);
|
|
15
|
+
const setRef = React.useCallback(node => {
|
|
16
|
+
scrollRef.current = node;
|
|
17
|
+
if (typeof ref === "function") ref(node);else if (ref) ref.current = node;
|
|
18
|
+
}, [ref]);
|
|
19
|
+
React.useLayoutEffect(() => {
|
|
20
|
+
const element = scrollRef.current?.getScrollableNode();
|
|
21
|
+
const EventConstructor = element?.ownerDocument?.defaultView?.Event;
|
|
22
|
+
if (EventConstructor) element.dispatchEvent(new EventConstructor("ok-collapsible-pager-scroll-key-changed", {
|
|
23
|
+
bubbles: true
|
|
24
|
+
}));
|
|
25
|
+
}, [pagerScrollKey]);
|
|
14
26
|
const webDataProps = {
|
|
15
27
|
dataSet: {
|
|
16
28
|
...dataSet,
|
|
17
|
-
collapsiblePagerScroll: "true"
|
|
29
|
+
collapsiblePagerScroll: "true",
|
|
30
|
+
collapsiblePagerScrollKey: pagerScrollKey ?? ""
|
|
18
31
|
}
|
|
19
32
|
};
|
|
20
33
|
return /*#__PURE__*/_jsx(ScrollView, {
|
|
21
34
|
...props,
|
|
22
|
-
ref:
|
|
35
|
+
ref: setRef,
|
|
23
36
|
...webDataProps
|
|
24
37
|
});
|
|
25
38
|
});
|
|
@@ -47,7 +47,7 @@ export interface NativeProps extends ViewProps {
|
|
|
47
47
|
contentInsetRight?: WithDefault<Double, 0>;
|
|
48
48
|
contentInsetBottom?: WithDefault<Double, 0>;
|
|
49
49
|
contentInsetLeft?: WithDefault<Double, 0>;
|
|
50
|
-
|
|
50
|
+
topScrollEdgeEffect?: WithDefault<"none" | "hard" | "soft", "none">;
|
|
51
51
|
topOverlayHeight?: WithDefault<Double, 0>;
|
|
52
52
|
refreshEnabled?: WithDefault<boolean, false>;
|
|
53
53
|
refreshing?: WithDefault<boolean, false>;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
|
+
const PageContext = /*#__PURE__*/React.createContext(null);
|
|
6
|
+
export function useWebCollapsiblePagerPage() {
|
|
7
|
+
return React.useContext(PageContext);
|
|
8
|
+
}
|
|
9
|
+
export function WebCollapsiblePagerPage({
|
|
10
|
+
children,
|
|
11
|
+
pageKey,
|
|
12
|
+
isFocused,
|
|
13
|
+
isRouteActive,
|
|
14
|
+
headerHeight,
|
|
15
|
+
stickyHeaderHeight,
|
|
16
|
+
onBridge,
|
|
17
|
+
onGeometryChange,
|
|
18
|
+
onScroll,
|
|
19
|
+
onUserInput
|
|
20
|
+
}) {
|
|
21
|
+
const [owner, setOwner] = React.useState(null);
|
|
22
|
+
const ownerRef = React.useRef(null);
|
|
23
|
+
const [registered, setRegistered] = React.useState(null);
|
|
24
|
+
const registeredRef = React.useRef(registered);
|
|
25
|
+
const observerRef = React.useRef(null);
|
|
26
|
+
const observedContentRef = React.useRef(null);
|
|
27
|
+
const frameRef = React.useRef(null);
|
|
28
|
+
const disposedRef = React.useRef(false);
|
|
29
|
+
const [pendingRouteScrollTop, setPendingRouteScrollTop] = React.useState(null);
|
|
30
|
+
const [metrics, setMetrics] = React.useState({
|
|
31
|
+
width: 0,
|
|
32
|
+
height: 0,
|
|
33
|
+
scrollTop: 0
|
|
34
|
+
});
|
|
35
|
+
const inputsRef = React.useRef({
|
|
36
|
+
pageKey,
|
|
37
|
+
headerHeight,
|
|
38
|
+
stickyHeaderHeight,
|
|
39
|
+
onGeometryChange,
|
|
40
|
+
onScroll,
|
|
41
|
+
onUserInput
|
|
42
|
+
});
|
|
43
|
+
inputsRef.current = {
|
|
44
|
+
pageKey,
|
|
45
|
+
headerHeight,
|
|
46
|
+
stickyHeaderHeight,
|
|
47
|
+
onGeometryChange,
|
|
48
|
+
onScroll,
|
|
49
|
+
onUserInput
|
|
50
|
+
};
|
|
51
|
+
const measure = React.useCallback(() => {
|
|
52
|
+
frameRef.current = null;
|
|
53
|
+
if (disposedRef.current) return;
|
|
54
|
+
const current = ownerRef.current;
|
|
55
|
+
if (!current?.isConnected) return;
|
|
56
|
+
const ownerRect = current.getBoundingClientRect();
|
|
57
|
+
const candidate = registeredRef.current?.element;
|
|
58
|
+
const content = candidate?.isConnected && current.contains(candidate) ? candidate : null;
|
|
59
|
+
const contentRect = (content ?? current.firstElementChild)?.getBoundingClientRect();
|
|
60
|
+
const inputs = inputsRef.current;
|
|
61
|
+
const pinnedBottom = ownerRect.top + Math.max(0, inputs.headerHeight - current.scrollTop) + inputs.stickyHeaderHeight;
|
|
62
|
+
const visibleTop = Math.max(ownerRect.top, pinnedBottom, contentRect?.top ?? 0);
|
|
63
|
+
const next = {
|
|
64
|
+
width: current.clientWidth,
|
|
65
|
+
height: Math.max(0, ownerRect.bottom - visibleTop),
|
|
66
|
+
scrollTop: Math.max(0, pinnedBottom - (contentRect?.top ?? pinnedBottom))
|
|
67
|
+
};
|
|
68
|
+
setMetrics(previous => previous.width === next.width && previous.height === next.height && previous.scrollTop === next.scrollTop ? previous : next);
|
|
69
|
+
inputs.onGeometryChange(inputs.pageKey);
|
|
70
|
+
}, []);
|
|
71
|
+
const requestMeasure = React.useCallback(() => {
|
|
72
|
+
if (!disposedRef.current && frameRef.current === null) frameRef.current = requestAnimationFrame(measure);
|
|
73
|
+
}, [measure]);
|
|
74
|
+
const syncContentObservation = React.useCallback(() => {
|
|
75
|
+
const observer = observerRef.current;
|
|
76
|
+
const current = ownerRef.current;
|
|
77
|
+
if (!observer || !current) return;
|
|
78
|
+
const candidate = registeredRef.current?.element;
|
|
79
|
+
const content = candidate?.isConnected && current.contains(candidate) ? candidate : current.firstElementChild;
|
|
80
|
+
const next = typeof HTMLElement !== "undefined" && content instanceof HTMLElement ? content : null;
|
|
81
|
+
if (observedContentRef.current === next) return;
|
|
82
|
+
if (observedContentRef.current) observer.unobserve(observedContentRef.current);
|
|
83
|
+
observedContentRef.current = next;
|
|
84
|
+
if (next) observer.observe(next);
|
|
85
|
+
}, []);
|
|
86
|
+
const registerContent = React.useCallback((element, height) => {
|
|
87
|
+
const entry = {
|
|
88
|
+
element,
|
|
89
|
+
height: height !== undefined && Number.isFinite(height) && height >= 0 ? height : undefined
|
|
90
|
+
};
|
|
91
|
+
registeredRef.current = entry;
|
|
92
|
+
setRegistered(entry);
|
|
93
|
+
syncContentObservation();
|
|
94
|
+
requestMeasure();
|
|
95
|
+
return () => {
|
|
96
|
+
if (registeredRef.current !== entry) return;
|
|
97
|
+
registeredRef.current = null;
|
|
98
|
+
setRegistered(null);
|
|
99
|
+
syncContentObservation();
|
|
100
|
+
requestMeasure();
|
|
101
|
+
};
|
|
102
|
+
}, [requestMeasure, syncContentObservation]);
|
|
103
|
+
const bridge = React.useMemo(() => ({
|
|
104
|
+
setOwner: next => {
|
|
105
|
+
if (ownerRef.current === next) return;
|
|
106
|
+
ownerRef.current = next;
|
|
107
|
+
setOwner(next);
|
|
108
|
+
requestMeasure();
|
|
109
|
+
},
|
|
110
|
+
requestMeasure,
|
|
111
|
+
setPendingRouteScrollTop
|
|
112
|
+
}), [requestMeasure]);
|
|
113
|
+
React.useLayoutEffect(() => {
|
|
114
|
+
disposedRef.current = false;
|
|
115
|
+
return () => {
|
|
116
|
+
disposedRef.current = true;
|
|
117
|
+
if (frameRef.current !== null) cancelAnimationFrame(frameRef.current);
|
|
118
|
+
frameRef.current = null;
|
|
119
|
+
};
|
|
120
|
+
}, []);
|
|
121
|
+
React.useLayoutEffect(() => {
|
|
122
|
+
onBridge(pageKey, bridge);
|
|
123
|
+
return () => onBridge(pageKey, null);
|
|
124
|
+
}, [bridge, onBridge, pageKey]);
|
|
125
|
+
React.useLayoutEffect(() => {
|
|
126
|
+
if (!owner) return undefined;
|
|
127
|
+
const observer = new ResizeObserver(requestMeasure);
|
|
128
|
+
observerRef.current = observer;
|
|
129
|
+
observer.observe(owner);
|
|
130
|
+
syncContentObservation();
|
|
131
|
+
const handleScroll = () => {
|
|
132
|
+
if (ownerRef.current !== owner) return;
|
|
133
|
+
const inputs = inputsRef.current;
|
|
134
|
+
inputs.onScroll(inputs.pageKey, owner.scrollTop);
|
|
135
|
+
requestMeasure();
|
|
136
|
+
};
|
|
137
|
+
const handleKey = event => {
|
|
138
|
+
if (["ArrowUp", "ArrowDown", "PageUp", "PageDown", "Home", "End", " "].includes(event.key)) inputsRef.current.onUserInput(inputsRef.current.pageKey);
|
|
139
|
+
};
|
|
140
|
+
const handleUserInput = () => inputsRef.current.onUserInput(inputsRef.current.pageKey);
|
|
141
|
+
owner.addEventListener("scroll", handleScroll, {
|
|
142
|
+
passive: true
|
|
143
|
+
});
|
|
144
|
+
owner.addEventListener("touchstart", handleUserInput, {
|
|
145
|
+
passive: true
|
|
146
|
+
});
|
|
147
|
+
owner.addEventListener("pointerdown", handleUserInput);
|
|
148
|
+
owner.addEventListener("keydown", handleKey);
|
|
149
|
+
owner.addEventListener("ok-collapsible-pager-user-scroll", handleUserInput);
|
|
150
|
+
owner.addEventListener("ok-collapsible-pager-insets-changed", requestMeasure);
|
|
151
|
+
requestMeasure();
|
|
152
|
+
return () => {
|
|
153
|
+
observer.disconnect();
|
|
154
|
+
observerRef.current = null;
|
|
155
|
+
observedContentRef.current = null;
|
|
156
|
+
owner.removeEventListener("scroll", handleScroll);
|
|
157
|
+
owner.removeEventListener("touchstart", handleUserInput);
|
|
158
|
+
owner.removeEventListener("pointerdown", handleUserInput);
|
|
159
|
+
owner.removeEventListener("keydown", handleKey);
|
|
160
|
+
owner.removeEventListener("ok-collapsible-pager-user-scroll", handleUserInput);
|
|
161
|
+
owner.removeEventListener("ok-collapsible-pager-insets-changed", requestMeasure);
|
|
162
|
+
if (frameRef.current !== null) cancelAnimationFrame(frameRef.current);
|
|
163
|
+
frameRef.current = null;
|
|
164
|
+
};
|
|
165
|
+
}, [owner, requestMeasure, syncContentObservation]);
|
|
166
|
+
React.useLayoutEffect(requestMeasure, [isFocused, isRouteActive, headerHeight, stickyHeaderHeight, requestMeasure]);
|
|
167
|
+
const value = React.useMemo(() => ({
|
|
168
|
+
isFocused,
|
|
169
|
+
isRouteActive,
|
|
170
|
+
owner,
|
|
171
|
+
content: registered?.element.isConnected && owner?.contains(registered.element) ? registered.element : null,
|
|
172
|
+
contentHeight: registered?.height,
|
|
173
|
+
...metrics,
|
|
174
|
+
pendingRouteScrollTop,
|
|
175
|
+
registerContent
|
|
176
|
+
}), [isFocused, isRouteActive, owner, registered, metrics, pendingRouteScrollTop, registerContent]);
|
|
177
|
+
return /*#__PURE__*/_jsx(PageContext.Provider, {
|
|
178
|
+
value: value,
|
|
179
|
+
children: children
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=WebCollapsiblePagerPage.js.map
|
package/lib/module/index.js
CHANGED
|
@@ -5,4 +5,7 @@ export default PagerView;
|
|
|
5
5
|
export * from "./usePagerView.js";
|
|
6
6
|
export * from './CollapsiblePagerView';
|
|
7
7
|
export * from './NativeScroller';
|
|
8
|
+
export { CollapsiblePagerView as WebCollapsiblePagerView } from "./CollapsiblePagerView.web.js";
|
|
9
|
+
export { useWebCollapsiblePagerPage } from "./WebCollapsiblePagerPage.js";
|
|
10
|
+
export { ScrollEdgeEffect } from "./ScrollEdgeEffect.js";
|
|
8
11
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.web.js
CHANGED
|
@@ -4,4 +4,7 @@ export { PagerView as default, PagerView } from "./PagerView.web.js";
|
|
|
4
4
|
export * from "./usePagerView.js";
|
|
5
5
|
export * from "./CollapsiblePagerView.web.js";
|
|
6
6
|
export * from "./NativeScroller.web.js";
|
|
7
|
+
export { CollapsiblePagerView as WebCollapsiblePagerView } from "./CollapsiblePagerView.web.js";
|
|
8
|
+
export { useWebCollapsiblePagerPage } from "./WebCollapsiblePagerPage.js";
|
|
9
|
+
export { ScrollEdgeEffect } from "./ScrollEdgeEffect.js";
|
|
7
10
|
//# sourceMappingURL=index.web.js.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ScrollEdgeEffect } from "./ScrollEdgeEffect";
|
|
1
2
|
import React from "react";
|
|
2
3
|
import type * as ReactNative from "react-native";
|
|
3
4
|
import { type NativeProps, type OnCollapsibleStateChangedEventData, type OnNativeTabPressEventData } from "./CollapsiblePagerViewNativeComponent";
|
|
@@ -55,7 +56,7 @@ export type CollapsiblePagerNativeSubHeaderConfig = Readonly<{
|
|
|
55
56
|
}>;
|
|
56
57
|
export type CollapsiblePagerViewOnNativeTabPressEvent = ReactNative.NativeSyntheticEvent<OnNativeTabPressEventData>;
|
|
57
58
|
export type CollapsiblePagerViewOnNativeSubHeaderPressEvent = ReactNative.NativeSyntheticEvent<OnNativeTabPressEventData>;
|
|
58
|
-
export interface CollapsiblePagerViewProps extends Omit<NativeProps, "children" | "headerHeight" | "stickyHeaderHeight" | "
|
|
59
|
+
export interface CollapsiblePagerViewProps extends Omit<NativeProps, "children" | "headerHeight" | "stickyHeaderHeight" | "topScrollEdgeEffect" | "topOverlayHeight" | "externalTopOverlayTag" | "pageKeys" | "retainedPages" | "nativeTabBarItems" | "nativeTabBarHeight" | "nativeTabBarContentPaddingHorizontal" | "nativeTabBarItemSpacing" | "nativeTabBarFontSize" | "nativeTabBarFontFamily" | "nativeTabBarBackgroundColor" | "nativeTabBarActiveTextColor" | "nativeTabBarInactiveTextColor" | "nativeTabBarIndicatorColor" | "nativeTabBarIndicatorHeight" | "nativeTabBarIndicatorBottom" | "nativeSubHeaderConfig" | "nativeSubHeaderSelectedBackgroundColor" | "onNativeTabPress" | "onNativeSubHeaderPress" | "layoutDirection"> {
|
|
59
60
|
/** Collapsible content rendered above the sticky bar. */
|
|
60
61
|
header: React.ReactNode;
|
|
61
62
|
/** Bar which remains pinned after the header has collapsed. */
|
|
@@ -68,8 +69,8 @@ export interface CollapsiblePagerViewProps extends Omit<NativeProps, "children"
|
|
|
68
69
|
topOverlay?: React.ReactNode;
|
|
69
70
|
/** Existing fixed header shared with a parent pager on iOS 26 and newer. */
|
|
70
71
|
externalTopOverlayTag?: number;
|
|
71
|
-
/**
|
|
72
|
-
topScrollEdgeEffect?:
|
|
72
|
+
/** Selects UIKit's top scroll-edge effect on iOS 26 and newer. */
|
|
73
|
+
topScrollEdgeEffect?: `${ScrollEdgeEffect}`;
|
|
73
74
|
/** Effective appearance of the fixed overlay or pinned sticky bar. */
|
|
74
75
|
topOverlayColorScheme?: "light" | "dark";
|
|
75
76
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ScrollEdgeEffect } from "./ScrollEdgeEffect";
|
|
1
2
|
import React from "react";
|
|
2
3
|
import type * as ReactNative from "react-native";
|
|
3
4
|
export type OnPageScrollEventData = Readonly<{
|
|
@@ -37,10 +38,11 @@ export type CollapsiblePagerMountState = Readonly<{
|
|
|
37
38
|
export interface CollapsiblePagerViewProps extends Omit<WebCollapsiblePagerNativeProps, "children" | "headerHeight" | "stickyHeaderHeight" | "pageKeys" | "retainedPages" | "layoutDirection"> {
|
|
38
39
|
header: React.ReactNode;
|
|
39
40
|
stickyHeader: React.ReactNode;
|
|
40
|
-
headerHeight
|
|
41
|
-
stickyHeaderHeight
|
|
41
|
+
headerHeight?: number;
|
|
42
|
+
stickyHeaderHeight?: number;
|
|
43
|
+
isActive?: boolean;
|
|
42
44
|
topOverlay?: React.ReactNode;
|
|
43
|
-
topScrollEdgeEffect?:
|
|
45
|
+
topScrollEdgeEffect?: `${ScrollEdgeEffect}`;
|
|
44
46
|
topOverlayColorScheme?: "light" | "dark";
|
|
45
47
|
externalTopOverlayTag?: number;
|
|
46
48
|
pageRetentionDistance?: number;
|
|
@@ -52,16 +54,42 @@ type State = {
|
|
|
52
54
|
selectedPage: number;
|
|
53
55
|
animateTransition: boolean;
|
|
54
56
|
};
|
|
57
|
+
type WebRouteTarget = Readonly<{
|
|
58
|
+
key: string;
|
|
59
|
+
identity: string;
|
|
60
|
+
owner: HTMLElement;
|
|
61
|
+
generation: number;
|
|
62
|
+
top: number;
|
|
63
|
+
}>;
|
|
55
64
|
/** Web counterpart of the native collapsible pager contract. */
|
|
56
65
|
export declare class CollapsiblePagerView extends React.PureComponent<CollapsiblePagerViewProps, State> {
|
|
57
66
|
state: State;
|
|
58
67
|
private root;
|
|
59
68
|
private track;
|
|
69
|
+
private headerSlot;
|
|
70
|
+
private stickySlot;
|
|
71
|
+
private cssTimelineSupported;
|
|
72
|
+
private overlayTouch;
|
|
60
73
|
private touchStartX;
|
|
61
74
|
private touchStartY;
|
|
62
75
|
private horizontalTouch;
|
|
63
76
|
private pageOffsets;
|
|
64
77
|
private pageHosts;
|
|
78
|
+
private pageScrollIdentities;
|
|
79
|
+
private pageBridges;
|
|
80
|
+
private ownerRecords;
|
|
81
|
+
private ownerGeneration;
|
|
82
|
+
private lastRawTops;
|
|
83
|
+
private routeTarget;
|
|
84
|
+
private measuredHeaderHeight;
|
|
85
|
+
private measuredStickyHeight;
|
|
86
|
+
private headerMeasured;
|
|
87
|
+
private stickyMeasured;
|
|
88
|
+
private headerContent;
|
|
89
|
+
private stickyContent;
|
|
90
|
+
private chromeObserver;
|
|
91
|
+
private chromeMeasureFrame;
|
|
92
|
+
private disposed;
|
|
65
93
|
private sharedHeaderOffset;
|
|
66
94
|
private selectionRestoreToken;
|
|
67
95
|
private bodyAlignment;
|
|
@@ -73,9 +101,32 @@ export declare class CollapsiblePagerView extends React.PureComponent<Collapsibl
|
|
|
73
101
|
private pageScrollState;
|
|
74
102
|
private configuredScrollElement;
|
|
75
103
|
private readonly timelineName;
|
|
104
|
+
private get headerHeight();
|
|
105
|
+
private get hasExplicitHeaderHeight();
|
|
106
|
+
private get stickyHeaderHeight();
|
|
107
|
+
private get hasExplicitStickyHeaderHeight();
|
|
108
|
+
getSnapshotBeforeUpdate(previousProps: CollapsiblePagerViewProps): Readonly<{
|
|
109
|
+
key: string;
|
|
110
|
+
identity: string;
|
|
111
|
+
owner: HTMLElement;
|
|
112
|
+
generation: number;
|
|
113
|
+
top: number;
|
|
114
|
+
}> | null;
|
|
76
115
|
componentDidMount(): void;
|
|
77
|
-
componentDidUpdate(previousProps: CollapsiblePagerViewProps): void;
|
|
116
|
+
componentDidUpdate(previousProps: CollapsiblePagerViewProps, _previousState: State, routeSnapshot: WebRouteTarget | null): void;
|
|
78
117
|
componentWillUnmount(): void;
|
|
118
|
+
private setHeaderContent;
|
|
119
|
+
private setStickyContent;
|
|
120
|
+
private observeChrome;
|
|
121
|
+
private scheduleChromeMeasurement;
|
|
122
|
+
private onPageBridge;
|
|
123
|
+
private setRouteTarget;
|
|
124
|
+
private syncPageOwner;
|
|
125
|
+
private captureRouteTarget;
|
|
126
|
+
restoreScrollPosition: () => boolean;
|
|
127
|
+
private onPageScroll;
|
|
128
|
+
private onPageGeometryChange;
|
|
129
|
+
private onPageUserInput;
|
|
79
130
|
setPage: (selectedPage: number) => void;
|
|
80
131
|
setPageWithoutAnimation: (selectedPage: number) => void;
|
|
81
132
|
scrollToPageTop: (options?: Readonly<{
|
|
@@ -100,9 +151,20 @@ export declare class CollapsiblePagerView extends React.PureComponent<Collapsibl
|
|
|
100
151
|
private onTrackTransitionEnd;
|
|
101
152
|
private setTrack;
|
|
102
153
|
private pageScrollElement;
|
|
154
|
+
private setRoot;
|
|
155
|
+
private overlayTarget;
|
|
156
|
+
private nestedScrollConsumes;
|
|
157
|
+
private scrollOverlayOwner;
|
|
158
|
+
private onOverlayWheel;
|
|
159
|
+
private onOverlayTouchStart;
|
|
160
|
+
private onOverlayTouchMove;
|
|
161
|
+
private onOverlayTouchEnd;
|
|
162
|
+
private synchronizeScrollOwnerIdentity;
|
|
163
|
+
private onScrollOwnerIdentityChanged;
|
|
103
164
|
private notifyInsetsChanged;
|
|
104
165
|
private restoreConfiguredScrollElement;
|
|
105
166
|
private configureActiveScrollElement;
|
|
167
|
+
private syncFallbackHeader;
|
|
106
168
|
private scheduleScrollConfiguration;
|
|
107
169
|
private takeOverVerticalScroll;
|
|
108
170
|
private onListScrollCommandAccepted;
|
|
@@ -42,7 +42,7 @@ export interface NativeProps extends ViewProps {
|
|
|
42
42
|
nativeSmoothHeaderScrollEnabled?: WithDefault<boolean, false>;
|
|
43
43
|
headerHeight?: Int32;
|
|
44
44
|
stickyHeaderHeight?: Int32;
|
|
45
|
-
|
|
45
|
+
topScrollEdgeEffect?: WithDefault<"none" | "hard" | "soft", "none">;
|
|
46
46
|
topOverlayColorScheme?: string;
|
|
47
47
|
topOverlayHeight?: WithDefault<Double, 0>;
|
|
48
48
|
externalTopOverlayTag?: WithDefault<Int32, 0>;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type NativeMethods, type RefreshControlProps, type ScrollView, type ScrollViewProps, type ViewProps } from "react-native";
|
|
3
3
|
import NativeScrollerHost from "./NativeScrollerNativeComponent";
|
|
4
|
+
import type { ScrollEdgeEffect } from "./ScrollEdgeEffect";
|
|
4
5
|
export declare const NATIVE_SCROLLER_NATIVE_ID_PREFIX = "rnc-collapsible-pager-native-scroller";
|
|
5
6
|
/** Supported vertical subset; horizontal, snapping, zoom and sticky rows are not supported. */
|
|
6
7
|
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
8
|
pagerScrollKey?: string;
|
|
8
9
|
/** Fixed overlay above scrolling content on iOS 26 and newer. */
|
|
9
10
|
topOverlay?: React.ReactNode;
|
|
10
|
-
/**
|
|
11
|
-
topScrollEdgeEffect?:
|
|
11
|
+
/** Selects UIKit's top scroll-edge effect on iOS 26 and newer. */
|
|
12
|
+
topScrollEdgeEffect?: `${ScrollEdgeEffect}`;
|
|
12
13
|
/** iOS only. Android retains AndroidX's native fling physics. */
|
|
13
14
|
decelerationRate?: ScrollViewProps["decelerationRate"];
|
|
14
15
|
/** Standard RefreshControl props are mapped to the independently owned native controller. */
|
|
@@ -47,7 +47,7 @@ export interface NativeProps extends ViewProps {
|
|
|
47
47
|
contentInsetRight?: WithDefault<Double, 0>;
|
|
48
48
|
contentInsetBottom?: WithDefault<Double, 0>;
|
|
49
49
|
contentInsetLeft?: WithDefault<Double, 0>;
|
|
50
|
-
|
|
50
|
+
topScrollEdgeEffect?: WithDefault<"none" | "hard" | "soft", "none">;
|
|
51
51
|
topOverlayHeight?: WithDefault<Double, 0>;
|
|
52
52
|
refreshEnabled?: WithDefault<boolean, false>;
|
|
53
53
|
refreshing?: WithDefault<boolean, false>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export type WebCollapsiblePagerPageState = Readonly<{
|
|
3
|
+
isFocused: boolean;
|
|
4
|
+
isRouteActive: boolean;
|
|
5
|
+
owner: HTMLElement | null;
|
|
6
|
+
content: HTMLElement | null;
|
|
7
|
+
contentHeight?: number;
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
scrollTop: number;
|
|
11
|
+
pendingRouteScrollTop: number | null;
|
|
12
|
+
registerContent: (element: HTMLElement, explicitHeight?: number) => () => void;
|
|
13
|
+
}>;
|
|
14
|
+
export type WebCollapsiblePagerPageBridge = Readonly<{
|
|
15
|
+
setOwner: (owner: HTMLElement | null) => void;
|
|
16
|
+
requestMeasure: () => void;
|
|
17
|
+
setPendingRouteScrollTop: (top: number | null) => void;
|
|
18
|
+
}>;
|
|
19
|
+
export declare function useWebCollapsiblePagerPage(): Readonly<{
|
|
20
|
+
isFocused: boolean;
|
|
21
|
+
isRouteActive: boolean;
|
|
22
|
+
owner: HTMLElement | null;
|
|
23
|
+
content: HTMLElement | null;
|
|
24
|
+
contentHeight?: number;
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
scrollTop: number;
|
|
28
|
+
pendingRouteScrollTop: number | null;
|
|
29
|
+
registerContent: (element: HTMLElement, explicitHeight?: number) => () => void;
|
|
30
|
+
}> | null;
|
|
31
|
+
export declare function WebCollapsiblePagerPage({ children, pageKey, isFocused, isRouteActive, headerHeight, stickyHeaderHeight, onBridge, onGeometryChange, onScroll, onUserInput, }: React.PropsWithChildren<{
|
|
32
|
+
pageKey: string;
|
|
33
|
+
isFocused: boolean;
|
|
34
|
+
isRouteActive: boolean;
|
|
35
|
+
headerHeight: number;
|
|
36
|
+
stickyHeaderHeight: number;
|
|
37
|
+
onBridge: (key: string, bridge: WebCollapsiblePagerPageBridge | null) => void;
|
|
38
|
+
onGeometryChange: (key: string) => void;
|
|
39
|
+
onScroll: (key: string, top: number) => void;
|
|
40
|
+
onUserInput: (key: string) => void;
|
|
41
|
+
}>): import("react/jsx-runtime").JSX.Element;
|
|
42
|
+
//# sourceMappingURL=WebCollapsiblePagerPage.d.ts.map
|
|
@@ -4,9 +4,14 @@ export default PagerView;
|
|
|
4
4
|
export * from './usePagerView';
|
|
5
5
|
export * from './CollapsiblePagerView';
|
|
6
6
|
export * from './NativeScroller';
|
|
7
|
+
export { CollapsiblePagerView as WebCollapsiblePagerView } from './CollapsiblePagerView.web';
|
|
8
|
+
export type { CollapsiblePagerViewProps as WebCollapsiblePagerViewProps } from './CollapsiblePagerView.web';
|
|
9
|
+
export { useWebCollapsiblePagerPage } from './WebCollapsiblePagerPage';
|
|
10
|
+
export type { WebCollapsiblePagerPageState } from './WebCollapsiblePagerPage';
|
|
7
11
|
import type { OnPageScrollEventData as PagerViewOnPageScrollEventData, OnPageSelectedEventData as PagerViewOnPageSelectedEventData, OnPageScrollStateChangedEventData as PageScrollStateChangedNativeEventData, NativeProps } from './PagerViewNativeComponent';
|
|
8
12
|
export type { PagerViewOnPageScrollEventData, PagerViewOnPageSelectedEventData, PageScrollStateChangedNativeEventData, NativeProps as PagerViewProps, };
|
|
9
13
|
export type PagerViewOnPageScrollEvent = ReactNative.NativeSyntheticEvent<PagerViewOnPageScrollEventData>;
|
|
10
14
|
export type PagerViewOnPageSelectedEvent = ReactNative.NativeSyntheticEvent<PagerViewOnPageSelectedEventData>;
|
|
11
15
|
export type PageScrollStateChangedNativeEvent = ReactNative.NativeSyntheticEvent<PageScrollStateChangedNativeEventData>;
|
|
16
|
+
export { ScrollEdgeEffect } from './ScrollEdgeEffect';
|
|
12
17
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -3,4 +3,9 @@ export type { PagerViewProps, PagerViewOnPageScrollEvent, PagerViewOnPageScrollE
|
|
|
3
3
|
export * from "./usePagerView";
|
|
4
4
|
export * from "./CollapsiblePagerView.web";
|
|
5
5
|
export * from "./NativeScroller.web";
|
|
6
|
+
export { CollapsiblePagerView as WebCollapsiblePagerView } from "./CollapsiblePagerView.web";
|
|
7
|
+
export type { CollapsiblePagerViewProps as WebCollapsiblePagerViewProps } from "./CollapsiblePagerView.web";
|
|
8
|
+
export { useWebCollapsiblePagerPage } from "./WebCollapsiblePagerPage";
|
|
9
|
+
export type { WebCollapsiblePagerPageState } from "./WebCollapsiblePagerPage";
|
|
10
|
+
export { ScrollEdgeEffect } from "./ScrollEdgeEffect";
|
|
6
11
|
//# sourceMappingURL=index.web.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/react-native-pager-view",
|
|
3
|
-
"version": "6.7.0-
|
|
3
|
+
"version": "6.7.0-3",
|
|
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": "6.7.0-
|
|
75
|
+
"@onekeyfe/react-native-native-logger": "6.7.0-3",
|
|
76
76
|
"react": "*",
|
|
77
77
|
"react-native": "*"
|
|
78
78
|
},
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ScrollEdgeEffect } from "./ScrollEdgeEffect";
|
|
1
2
|
import React from "react";
|
|
2
3
|
import { I18nManager, Platform, StyleSheet, View } from "react-native";
|
|
3
4
|
import type * as ReactNative from "react-native";
|
|
@@ -86,7 +87,7 @@ export interface CollapsiblePagerViewProps
|
|
|
86
87
|
| "children"
|
|
87
88
|
| "headerHeight"
|
|
88
89
|
| "stickyHeaderHeight"
|
|
89
|
-
| "
|
|
90
|
+
| "topScrollEdgeEffect"
|
|
90
91
|
| "topOverlayHeight"
|
|
91
92
|
| "externalTopOverlayTag"
|
|
92
93
|
| "pageKeys"
|
|
@@ -121,8 +122,8 @@ export interface CollapsiblePagerViewProps
|
|
|
121
122
|
topOverlay?: React.ReactNode;
|
|
122
123
|
/** Existing fixed header shared with a parent pager on iOS 26 and newer. */
|
|
123
124
|
externalTopOverlayTag?: number;
|
|
124
|
-
/**
|
|
125
|
-
topScrollEdgeEffect?:
|
|
125
|
+
/** Selects UIKit's top scroll-edge effect on iOS 26 and newer. */
|
|
126
|
+
topScrollEdgeEffect?: `${ScrollEdgeEffect}`;
|
|
126
127
|
/** Effective appearance of the fixed overlay or pinned sticky bar. */
|
|
127
128
|
topOverlayColorScheme?: "light" | "dark";
|
|
128
129
|
/**
|
|
@@ -493,8 +494,10 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
493
494
|
const pages = this.pages();
|
|
494
495
|
const supportsTopScrollEdge =
|
|
495
496
|
Platform.OS === "ios" && parseInt(String(Platform.Version), 10) >= 26;
|
|
496
|
-
const
|
|
497
|
-
|
|
497
|
+
const scrollEdgeEnabled =
|
|
498
|
+
supportsTopScrollEdge &&
|
|
499
|
+
(topScrollEdgeEffect === "hard" || topScrollEdgeEffect === "soft");
|
|
500
|
+
const hasTopOverlay = scrollEdgeEnabled && topOverlay != null;
|
|
498
501
|
const pageKeys = pages.map(pageKey);
|
|
499
502
|
const retained = new Set(this.mountedPages(pages.length));
|
|
500
503
|
const deducedLayoutDirection =
|
|
@@ -535,8 +538,10 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
535
538
|
offscreenPageLimit={Math.max(1, offscreenPageLimit ?? 1)}
|
|
536
539
|
headerHeight={Math.max(0, Math.round(headerHeight))}
|
|
537
540
|
stickyHeaderHeight={Math.max(0, Math.round(stickyHeaderHeight))}
|
|
538
|
-
|
|
539
|
-
topOverlayColorScheme={
|
|
541
|
+
topScrollEdgeEffect={scrollEdgeEnabled ? topScrollEdgeEffect : "none"}
|
|
542
|
+
topOverlayColorScheme={
|
|
543
|
+
scrollEdgeEnabled ? topOverlayColorScheme : undefined
|
|
544
|
+
}
|
|
540
545
|
topOverlayHeight={hasTopOverlay ? this.state.topOverlayHeight : 0}
|
|
541
546
|
externalTopOverlayTag={
|
|
542
547
|
supportsTopScrollEdge && !hasTopOverlay
|