@onekeyfe/react-native-pager-view 3.0.113 → 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.
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerHost.kt +143 -16
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerViewManager.kt +9 -2
- package/android/src/main/java/com/reactnativepagerview/NestedScrollableHost.kt +3 -1
- package/ios/RNCCollapsiblePagerViewComponentView.mm +291 -38
- package/ios/RNCPagerViewComponentView.mm +4 -2
- package/lib/module/CollapsiblePagerView.js +21 -6
- package/lib/module/CollapsiblePagerView.web.js +149 -35
- package/lib/module/CollapsiblePagerViewNativeComponent.ts +2 -0
- package/lib/module/index.js +2 -2
- package/lib/typescript/src/CollapsiblePagerView.web.d.ts +12 -0
- package/lib/typescript/src/CollapsiblePagerViewNativeComponent.d.ts +1 -0
- package/lib/typescript/src/index.d.ts +5 -5
- package/package.json +1 -1
- package/src/CollapsiblePagerView.tsx +41 -6
- package/src/CollapsiblePagerView.web.tsx +198 -47
- package/src/CollapsiblePagerViewNativeComponent.ts +2 -0
- package/src/index.tsx +5 -5
|
@@ -5,7 +5,18 @@ import { I18nManager, StyleSheet, View } from "react-native";
|
|
|
5
5
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
6
6
|
const COLLAPSE_ANIMATION_NAME = "ok-collapsible-pager-collapse";
|
|
7
7
|
const COLLAPSE_STYLE_ID = "ok-collapsible-pager-styles";
|
|
8
|
+
const PAGER_HEADER_INSET = "--ok-collapsible-pager-header-inset";
|
|
9
|
+
const PAGER_STICKY_INSET = "--ok-collapsible-pager-sticky-inset";
|
|
8
10
|
let collapsiblePagerWebInstance = 0;
|
|
11
|
+
const pageIndex = value => {
|
|
12
|
+
const index = Math.trunc(value);
|
|
13
|
+
return Number.isFinite(index) ? index : null;
|
|
14
|
+
};
|
|
15
|
+
const clampedPageIndex = (value, pageCount) => Math.min(Math.max(0, pageIndex(value) ?? 0), Math.max(0, pageCount - 1));
|
|
16
|
+
const webElement = node => {
|
|
17
|
+
const element = node;
|
|
18
|
+
return element && typeof element.querySelector === "function" && typeof element.addEventListener === "function" ? element : null;
|
|
19
|
+
};
|
|
9
20
|
const timelineStyle = element => element.style;
|
|
10
21
|
function ensureCollapseAnimation(document) {
|
|
11
22
|
if (document.getElementById(COLLAPSE_STYLE_ID)) return;
|
|
@@ -22,18 +33,22 @@ const pageKey = (child, index) => {
|
|
|
22
33
|
/** Web counterpart of the native collapsible pager contract. */
|
|
23
34
|
export class CollapsiblePagerView extends React.PureComponent {
|
|
24
35
|
state = {
|
|
25
|
-
selectedPage:
|
|
36
|
+
selectedPage: clampedPageIndex(this.props.initialPage ?? 0, React.Children.toArray(this.props.children).length),
|
|
26
37
|
animateTransition: true
|
|
27
38
|
};
|
|
28
39
|
root = null;
|
|
40
|
+
track = null;
|
|
29
41
|
touchStartX = null;
|
|
30
42
|
touchStartY = null;
|
|
43
|
+
horizontalTouch = false;
|
|
31
44
|
pageOffsets = new Map();
|
|
32
45
|
pageHosts = new Map();
|
|
33
46
|
sharedHeaderOffset = 0;
|
|
34
47
|
scrollEnabled = this.props.scrollEnabled ?? true;
|
|
35
48
|
lastMountSignature = null;
|
|
36
49
|
configureFrame = null;
|
|
50
|
+
transitionTimer = null;
|
|
51
|
+
pageScrollState = "idle";
|
|
37
52
|
configuredScrollElement = null;
|
|
38
53
|
timelineName = `--ok-collapsible-pager-${++collapsiblePagerWebInstance}`;
|
|
39
54
|
componentDidMount() {
|
|
@@ -45,6 +60,22 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
45
60
|
componentDidUpdate(previousProps) {
|
|
46
61
|
if (previousProps.scrollEnabled !== this.props.scrollEnabled) {
|
|
47
62
|
this.scrollEnabled = this.props.scrollEnabled ?? true;
|
|
63
|
+
if (!this.scrollEnabled) {
|
|
64
|
+
this.touchStartX = null;
|
|
65
|
+
this.touchStartY = null;
|
|
66
|
+
this.horizontalTouch = false;
|
|
67
|
+
this.finishPageTransition();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const pageCount = this.pages().length;
|
|
71
|
+
const selectedPage = clampedPageIndex(this.state.selectedPage, pageCount);
|
|
72
|
+
if (selectedPage !== this.state.selectedPage) {
|
|
73
|
+
this.finishPageTransition();
|
|
74
|
+
this.setState({
|
|
75
|
+
selectedPage,
|
|
76
|
+
animateTransition: false
|
|
77
|
+
});
|
|
78
|
+
return;
|
|
48
79
|
}
|
|
49
80
|
this.scheduleScrollConfiguration();
|
|
50
81
|
this.notifyMountedPagesChanged();
|
|
@@ -55,6 +86,11 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
55
86
|
cancelAnimationFrame(this.configureFrame);
|
|
56
87
|
this.configureFrame = null;
|
|
57
88
|
}
|
|
89
|
+
if (this.transitionTimer !== null) {
|
|
90
|
+
clearTimeout(this.transitionTimer);
|
|
91
|
+
this.transitionTimer = null;
|
|
92
|
+
}
|
|
93
|
+
this.setTrack(null);
|
|
58
94
|
this.restoreConfiguredScrollElement();
|
|
59
95
|
}
|
|
60
96
|
setPage = selectedPage => {
|
|
@@ -85,10 +121,47 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
85
121
|
nativeEvent
|
|
86
122
|
};
|
|
87
123
|
}
|
|
124
|
+
emitPageScrollState(pageScrollState) {
|
|
125
|
+
if (pageScrollState === this.pageScrollState) return;
|
|
126
|
+
this.pageScrollState = pageScrollState;
|
|
127
|
+
this.props.onPageScrollStateChanged?.(this.nativeEvent({
|
|
128
|
+
pageScrollState
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
finishPageTransition = () => {
|
|
132
|
+
if (this.transitionTimer !== null) {
|
|
133
|
+
clearTimeout(this.transitionTimer);
|
|
134
|
+
this.transitionTimer = null;
|
|
135
|
+
}
|
|
136
|
+
this.emitPageScrollState("idle");
|
|
137
|
+
};
|
|
138
|
+
beginPageTransition() {
|
|
139
|
+
if (this.transitionTimer !== null) clearTimeout(this.transitionTimer);
|
|
140
|
+
this.emitPageScrollState("settling");
|
|
141
|
+
this.transitionTimer = setTimeout(this.finishPageTransition, 320);
|
|
142
|
+
}
|
|
143
|
+
onTrackTransitionEnd = event => {
|
|
144
|
+
if (event.target === this.track && event.propertyName === "transform") {
|
|
145
|
+
this.finishPageTransition();
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
setTrack = node => {
|
|
149
|
+
const track = webElement(node);
|
|
150
|
+
if (track === this.track) return;
|
|
151
|
+
this.track?.removeEventListener("transitionend", this.onTrackTransitionEnd);
|
|
152
|
+
this.track = track;
|
|
153
|
+
this.track?.addEventListener("transitionend", this.onTrackTransitionEnd);
|
|
154
|
+
};
|
|
88
155
|
pageScrollElement(index) {
|
|
89
156
|
const pageHost = this.pageHosts.get(index);
|
|
90
157
|
return pageHost?.querySelector(".ok-native-list-viewport, [data-collapsible-pager-scroll]") ?? pageHost;
|
|
91
158
|
}
|
|
159
|
+
notifyInsetsChanged(element) {
|
|
160
|
+
const EventConstructor = element.ownerDocument.defaultView?.Event;
|
|
161
|
+
if (EventConstructor) {
|
|
162
|
+
element.dispatchEvent(new EventConstructor("ok-collapsible-pager-insets-changed"));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
92
165
|
restoreConfiguredScrollElement() {
|
|
93
166
|
const configured = this.configuredScrollElement;
|
|
94
167
|
if (!configured) return;
|
|
@@ -98,7 +171,10 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
98
171
|
style.boxSizing = configured.boxSizing;
|
|
99
172
|
style.scrollTimelineName = configured.scrollTimelineName;
|
|
100
173
|
style.scrollTimelineAxis = configured.scrollTimelineAxis;
|
|
174
|
+
style.setProperty(PAGER_HEADER_INSET, configured.pagerHeaderInset);
|
|
175
|
+
style.setProperty(PAGER_STICKY_INSET, configured.pagerStickyInset);
|
|
101
176
|
configured.element.removeAttribute("data-collapsible-pager-active");
|
|
177
|
+
this.notifyInsetsChanged(configured.element);
|
|
102
178
|
this.configuredScrollElement = null;
|
|
103
179
|
}
|
|
104
180
|
configureActiveScrollElement = () => {
|
|
@@ -108,21 +184,35 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
108
184
|
if (this.configuredScrollElement?.element !== element) {
|
|
109
185
|
this.restoreConfiguredScrollElement();
|
|
110
186
|
const style = timelineStyle(element);
|
|
187
|
+
const computedPaddingTop = element.ownerDocument.defaultView?.getComputedStyle(element).paddingTop || style.paddingTop || "0px";
|
|
111
188
|
this.configuredScrollElement = {
|
|
112
189
|
element,
|
|
113
190
|
paddingTop: style.paddingTop,
|
|
191
|
+
basePaddingTop: computedPaddingTop,
|
|
114
192
|
boxSizing: style.boxSizing,
|
|
115
193
|
scrollTimelineName: style.scrollTimelineName,
|
|
116
|
-
scrollTimelineAxis: style.scrollTimelineAxis
|
|
194
|
+
scrollTimelineAxis: style.scrollTimelineAxis,
|
|
195
|
+
pagerHeaderInset: style.getPropertyValue(PAGER_HEADER_INSET),
|
|
196
|
+
pagerStickyInset: style.getPropertyValue(PAGER_STICKY_INSET)
|
|
117
197
|
};
|
|
118
198
|
element.addEventListener("scrollend", this.onVerticalScrollSettled);
|
|
119
199
|
}
|
|
120
200
|
const style = timelineStyle(element);
|
|
121
|
-
|
|
201
|
+
const headerInset = Math.max(0, this.props.headerHeight);
|
|
202
|
+
const stickyInset = Math.max(0, this.props.stickyHeaderHeight);
|
|
203
|
+
const basePaddingTop = this.configuredScrollElement?.basePaddingTop ?? "0px";
|
|
204
|
+
const paddingTop = `calc(${basePaddingTop} + ${headerInset + stickyInset}px)`;
|
|
205
|
+
const headerInsetValue = `${headerInset}px`;
|
|
206
|
+
const stickyInsetValue = `${stickyInset}px`;
|
|
207
|
+
const insetsChanged = style.paddingTop !== paddingTop || style.getPropertyValue(PAGER_HEADER_INSET) !== headerInsetValue || style.getPropertyValue(PAGER_STICKY_INSET) !== stickyInsetValue;
|
|
208
|
+
style.paddingTop = paddingTop;
|
|
122
209
|
style.boxSizing = "border-box";
|
|
123
210
|
style.scrollTimelineName = this.timelineName;
|
|
124
211
|
style.scrollTimelineAxis = "block";
|
|
212
|
+
style.setProperty(PAGER_HEADER_INSET, headerInsetValue);
|
|
213
|
+
style.setProperty(PAGER_STICKY_INSET, stickyInsetValue);
|
|
125
214
|
element.setAttribute("data-collapsible-pager-active", "true");
|
|
215
|
+
if (insetsChanged) this.notifyInsetsChanged(element);
|
|
126
216
|
};
|
|
127
217
|
scheduleScrollConfiguration() {
|
|
128
218
|
if (this.configureFrame !== null) return;
|
|
@@ -152,21 +242,20 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
152
242
|
}
|
|
153
243
|
selectPage(selectedPage, animated) {
|
|
154
244
|
const pages = this.pages();
|
|
155
|
-
|
|
245
|
+
const position = pageIndex(selectedPage);
|
|
246
|
+
if (position === null || position < 0 || position >= pages.length || position === this.state.selectedPage) {
|
|
156
247
|
return;
|
|
157
248
|
}
|
|
158
249
|
this.savePageOffset(this.state.selectedPage);
|
|
159
|
-
this.
|
|
160
|
-
pageScrollState: animated ? "settling" : "idle"
|
|
161
|
-
}));
|
|
250
|
+
if (animated) this.beginPageTransition();else this.finishPageTransition();
|
|
162
251
|
this.setState({
|
|
163
|
-
selectedPage,
|
|
252
|
+
selectedPage: position,
|
|
164
253
|
animateTransition: animated
|
|
165
254
|
}, () => {
|
|
166
255
|
this.scheduleScrollConfiguration();
|
|
167
256
|
const restore = () => {
|
|
168
257
|
this.configureActiveScrollElement();
|
|
169
|
-
this.restorePageOffset(
|
|
258
|
+
this.restorePageOffset(position);
|
|
170
259
|
};
|
|
171
260
|
if (typeof requestAnimationFrame === "function") {
|
|
172
261
|
requestAnimationFrame(restore);
|
|
@@ -174,17 +263,12 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
174
263
|
setTimeout(restore, 0);
|
|
175
264
|
}
|
|
176
265
|
this.props.onPageSelected?.(this.nativeEvent({
|
|
177
|
-
position
|
|
266
|
+
position
|
|
178
267
|
}));
|
|
179
268
|
this.props.onPageScroll?.(this.nativeEvent({
|
|
180
|
-
position
|
|
269
|
+
position,
|
|
181
270
|
offset: 0
|
|
182
271
|
}));
|
|
183
|
-
if (animated) {
|
|
184
|
-
this.props.onPageScrollStateChanged?.(this.nativeEvent({
|
|
185
|
-
pageScrollState: "idle"
|
|
186
|
-
}));
|
|
187
|
-
}
|
|
188
272
|
this.notifyMountedPagesChanged();
|
|
189
273
|
this.emitDiagnostics("page-selected");
|
|
190
274
|
});
|
|
@@ -221,36 +305,68 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
221
305
|
if (!touch) return;
|
|
222
306
|
this.touchStartX = touch.pageX;
|
|
223
307
|
this.touchStartY = touch.pageY;
|
|
224
|
-
this.
|
|
225
|
-
|
|
226
|
-
|
|
308
|
+
this.horizontalTouch = false;
|
|
309
|
+
};
|
|
310
|
+
onTouchMove = event => {
|
|
311
|
+
if (this.touchStartX == null || !this.scrollEnabled || this.horizontalTouch) return;
|
|
312
|
+
const touch = event.nativeEvent.touches[0];
|
|
313
|
+
if (!touch) return;
|
|
314
|
+
const deltaX = touch.pageX - this.touchStartX;
|
|
315
|
+
const deltaY = touch.pageY - (this.touchStartY ?? touch.pageY);
|
|
316
|
+
if (Math.abs(deltaX) >= 8 && Math.abs(deltaX) > Math.abs(deltaY)) {
|
|
317
|
+
this.horizontalTouch = true;
|
|
318
|
+
this.emitPageScrollState("dragging");
|
|
319
|
+
}
|
|
227
320
|
};
|
|
228
321
|
onTouchEnd = event => {
|
|
229
322
|
if (this.touchStartX == null || !this.scrollEnabled) return;
|
|
230
323
|
const touch = event.nativeEvent.changedTouches[0];
|
|
231
|
-
if (!touch)
|
|
324
|
+
if (!touch) {
|
|
325
|
+
this.onTouchCancel();
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
232
328
|
const delta = touch.pageX - this.touchStartX;
|
|
233
329
|
const verticalDelta = touch.pageY - (this.touchStartY ?? touch.pageY);
|
|
234
330
|
this.touchStartX = null;
|
|
235
331
|
this.touchStartY = null;
|
|
236
|
-
const rtl = this.props.layoutDirection === "rtl" || !this.props.layoutDirection && I18nManager.isRTL;
|
|
332
|
+
const rtl = this.props.layoutDirection === "rtl" || (!this.props.layoutDirection || this.props.layoutDirection === "locale") && I18nManager.isRTL;
|
|
237
333
|
const direction = Math.abs(delta) >= 40 && Math.abs(delta) > Math.abs(verticalDelta) ? delta < 0 ? 1 : -1 : 0;
|
|
238
334
|
const next = this.state.selectedPage + (rtl ? -direction : direction);
|
|
239
335
|
if (direction === 0 || next < 0 || next >= this.pages().length) {
|
|
240
|
-
this.
|
|
241
|
-
|
|
242
|
-
|
|
336
|
+
const wasHorizontal = this.horizontalTouch;
|
|
337
|
+
this.horizontalTouch = false;
|
|
338
|
+
if (wasHorizontal) this.finishPageTransition();
|
|
243
339
|
return;
|
|
244
340
|
}
|
|
341
|
+
this.horizontalTouch = false;
|
|
245
342
|
this.selectPage(next, true);
|
|
246
343
|
};
|
|
344
|
+
onTouchCancel = () => {
|
|
345
|
+
const wasHorizontal = this.horizontalTouch;
|
|
346
|
+
this.touchStartX = null;
|
|
347
|
+
this.touchStartY = null;
|
|
348
|
+
this.horizontalTouch = false;
|
|
349
|
+
if (wasHorizontal) this.finishPageTransition();
|
|
350
|
+
};
|
|
247
351
|
render() {
|
|
248
352
|
const {
|
|
353
|
+
children: _children,
|
|
249
354
|
header,
|
|
250
355
|
stickyHeader,
|
|
356
|
+
headerHeight: _headerHeight,
|
|
357
|
+
stickyHeaderHeight: _stickyHeaderHeight,
|
|
358
|
+
pageRetentionDistance: _pageRetentionDistance,
|
|
359
|
+
layoutDirection: _layoutDirection,
|
|
360
|
+
scrollEnabled: _scrollEnabled,
|
|
361
|
+
initialPage: _initialPage,
|
|
362
|
+
offscreenPageLimit: _offscreenPageLimit,
|
|
363
|
+
onPageScroll: _onPageScroll,
|
|
364
|
+
onPageSelected: _onPageSelected,
|
|
365
|
+
onPageScrollStateChanged: _onPageScrollStateChanged,
|
|
366
|
+
onCollapsibleStateChanged: _onCollapsibleStateChanged,
|
|
367
|
+
onMountedPagesChanged: _onMountedPagesChanged,
|
|
251
368
|
style,
|
|
252
|
-
|
|
253
|
-
accessibilityLabel
|
|
369
|
+
...viewProps
|
|
254
370
|
} = this.props;
|
|
255
371
|
const pages = this.pages();
|
|
256
372
|
const keys = pages.map(pageKey);
|
|
@@ -274,14 +390,13 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
274
390
|
transitionDuration: this.state.animateTransition ? "240ms" : "0ms"
|
|
275
391
|
}];
|
|
276
392
|
return /*#__PURE__*/_jsxs(View, {
|
|
393
|
+
...viewProps,
|
|
277
394
|
ref: node => {
|
|
278
|
-
this.root = node;
|
|
395
|
+
this.root = webElement(node);
|
|
279
396
|
},
|
|
280
397
|
style: [styles.root, {
|
|
281
398
|
timelineScope: this.timelineName
|
|
282
399
|
}, style],
|
|
283
|
-
testID: testID,
|
|
284
|
-
accessibilityLabel: accessibilityLabel,
|
|
285
400
|
children: [/*#__PURE__*/_jsx(View, {
|
|
286
401
|
style: [styles.header, {
|
|
287
402
|
height: Math.max(0, this.props.headerHeight)
|
|
@@ -294,17 +409,16 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
294
409
|
}, collapseAnimation],
|
|
295
410
|
children: stickyHeader
|
|
296
411
|
}), /*#__PURE__*/_jsx(View, {
|
|
412
|
+
ref: this.setTrack,
|
|
297
413
|
style: trackStyle,
|
|
298
414
|
onTouchStart: this.onTouchStart,
|
|
415
|
+
onTouchMove: this.onTouchMove,
|
|
299
416
|
onTouchEnd: this.onTouchEnd,
|
|
300
|
-
onTouchCancel:
|
|
301
|
-
this.touchStartX = null;
|
|
302
|
-
this.touchStartY = null;
|
|
303
|
-
},
|
|
417
|
+
onTouchCancel: this.onTouchCancel,
|
|
304
418
|
children: pages.map((page, index) => /*#__PURE__*/_jsx(View, {
|
|
305
419
|
ref: node => {
|
|
306
|
-
|
|
307
|
-
|
|
420
|
+
const host = webElement(node);
|
|
421
|
+
if (host) {
|
|
308
422
|
host.inert = index !== this.state.selectedPage;
|
|
309
423
|
this.pageHosts.set(index, host);
|
|
310
424
|
} else {
|
|
@@ -45,6 +45,8 @@ export interface NativeProps extends ViewProps {
|
|
|
45
45
|
layoutDirection?: WithDefault<"ltr" | "rtl", "ltr">;
|
|
46
46
|
initialPage?: Int32;
|
|
47
47
|
offscreenPageLimit?: Int32;
|
|
48
|
+
// OneKey patch: Preserve nested pager gesture coordination for collapsible pages.
|
|
49
|
+
nestedScrollEnabled?: WithDefault<boolean, false>;
|
|
48
50
|
headerHeight?: Int32;
|
|
49
51
|
stickyHeaderHeight?: Int32;
|
|
50
52
|
pageKeys?: string;
|
package/lib/module/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import { PagerView } from
|
|
3
|
+
import { PagerView } from './PagerView';
|
|
4
4
|
export default PagerView;
|
|
5
5
|
export * from "./usePagerView.js";
|
|
6
|
-
export * from
|
|
6
|
+
export * from './CollapsiblePagerView';
|
|
7
7
|
//# sourceMappingURL=index.js.map
|
|
@@ -52,14 +52,18 @@ type State = {
|
|
|
52
52
|
export declare class CollapsiblePagerView extends React.PureComponent<CollapsiblePagerViewProps, State> {
|
|
53
53
|
state: State;
|
|
54
54
|
private root;
|
|
55
|
+
private track;
|
|
55
56
|
private touchStartX;
|
|
56
57
|
private touchStartY;
|
|
58
|
+
private horizontalTouch;
|
|
57
59
|
private pageOffsets;
|
|
58
60
|
private pageHosts;
|
|
59
61
|
private sharedHeaderOffset;
|
|
60
62
|
private scrollEnabled;
|
|
61
63
|
private lastMountSignature;
|
|
62
64
|
private configureFrame;
|
|
65
|
+
private transitionTimer;
|
|
66
|
+
private pageScrollState;
|
|
63
67
|
private configuredScrollElement;
|
|
64
68
|
private readonly timelineName;
|
|
65
69
|
componentDidMount(): void;
|
|
@@ -72,7 +76,13 @@ export declare class CollapsiblePagerView extends React.PureComponent<Collapsibl
|
|
|
72
76
|
private retentionDistance;
|
|
73
77
|
private mountedPages;
|
|
74
78
|
private nativeEvent;
|
|
79
|
+
private emitPageScrollState;
|
|
80
|
+
private finishPageTransition;
|
|
81
|
+
private beginPageTransition;
|
|
82
|
+
private onTrackTransitionEnd;
|
|
83
|
+
private setTrack;
|
|
75
84
|
private pageScrollElement;
|
|
85
|
+
private notifyInsetsChanged;
|
|
76
86
|
private restoreConfiguredScrollElement;
|
|
77
87
|
private configureActiveScrollElement;
|
|
78
88
|
private scheduleScrollConfiguration;
|
|
@@ -83,7 +93,9 @@ export declare class CollapsiblePagerView extends React.PureComponent<Collapsibl
|
|
|
83
93
|
private notifyMountedPagesChanged;
|
|
84
94
|
private emitDiagnostics;
|
|
85
95
|
private onTouchStart;
|
|
96
|
+
private onTouchMove;
|
|
86
97
|
private onTouchEnd;
|
|
98
|
+
private onTouchCancel;
|
|
87
99
|
render(): import("react/jsx-runtime").JSX.Element;
|
|
88
100
|
}
|
|
89
101
|
export type CollapsiblePagerViewOnPageScrollEvent = ReactNative.NativeSyntheticEvent<OnPageScrollEventData>;
|
|
@@ -29,6 +29,7 @@ export interface NativeProps extends ViewProps {
|
|
|
29
29
|
layoutDirection?: WithDefault<"ltr" | "rtl", "ltr">;
|
|
30
30
|
initialPage?: Int32;
|
|
31
31
|
offscreenPageLimit?: Int32;
|
|
32
|
+
nestedScrollEnabled?: WithDefault<boolean, false>;
|
|
32
33
|
headerHeight?: Int32;
|
|
33
34
|
stickyHeaderHeight?: Int32;
|
|
34
35
|
pageKeys?: string;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type * as ReactNative from
|
|
2
|
-
import { PagerView } from
|
|
1
|
+
import type * as ReactNative from 'react-native';
|
|
2
|
+
import { PagerView } from './PagerView';
|
|
3
3
|
export default PagerView;
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
import type { OnPageScrollEventData as PagerViewOnPageScrollEventData, OnPageSelectedEventData as PagerViewOnPageSelectedEventData, OnPageScrollStateChangedEventData as PageScrollStateChangedNativeEventData, NativeProps } from
|
|
4
|
+
export * from './usePagerView';
|
|
5
|
+
export * from './CollapsiblePagerView';
|
|
6
|
+
import type { OnPageScrollEventData as PagerViewOnPageScrollEventData, OnPageSelectedEventData as PagerViewOnPageSelectedEventData, OnPageScrollStateChangedEventData as PageScrollStateChangedNativeEventData, NativeProps } from './PagerViewNativeComponent';
|
|
7
7
|
export type { PagerViewOnPageScrollEventData, PagerViewOnPageSelectedEventData, PageScrollStateChangedNativeEventData, NativeProps as PagerViewProps, };
|
|
8
8
|
export type PagerViewOnPageScrollEvent = ReactNative.NativeSyntheticEvent<PagerViewOnPageScrollEventData>;
|
|
9
9
|
export type PagerViewOnPageSelectedEvent = ReactNative.NativeSyntheticEvent<PagerViewOnPageSelectedEventData>;
|
package/package.json
CHANGED
|
@@ -55,6 +55,17 @@ type State = {
|
|
|
55
55
|
selectedPage: number;
|
|
56
56
|
};
|
|
57
57
|
|
|
58
|
+
const pageIndex = (value: number) => {
|
|
59
|
+
const index = Math.trunc(value);
|
|
60
|
+
return Number.isFinite(index) ? index : null;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const clampedPageIndex = (value: number, pageCount: number) =>
|
|
64
|
+
Math.min(
|
|
65
|
+
Math.max(0, pageIndex(value) ?? 0),
|
|
66
|
+
Math.max(0, pageCount - 1)
|
|
67
|
+
);
|
|
68
|
+
|
|
58
69
|
const pageKey = (child: React.ReactNode, index: number) => {
|
|
59
70
|
if (React.isValidElement(child) && child.key != null) {
|
|
60
71
|
return String(child.key);
|
|
@@ -72,7 +83,10 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
72
83
|
State
|
|
73
84
|
> {
|
|
74
85
|
state: State = {
|
|
75
|
-
selectedPage:
|
|
86
|
+
selectedPage: clampedPageIndex(
|
|
87
|
+
this.props.initialPage ?? 0,
|
|
88
|
+
React.Children.toArray(this.props.children).length
|
|
89
|
+
),
|
|
76
90
|
};
|
|
77
91
|
|
|
78
92
|
private nativeRef: React.ElementRef<
|
|
@@ -86,20 +100,38 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
86
100
|
}
|
|
87
101
|
|
|
88
102
|
componentDidUpdate() {
|
|
103
|
+
const pageCount = this.pages().length;
|
|
104
|
+
const selectedPage = clampedPageIndex(this.state.selectedPage, pageCount);
|
|
105
|
+
if (selectedPage !== this.state.selectedPage) {
|
|
106
|
+
this.setState({ selectedPage });
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
89
109
|
this.notifyMountedPagesChanged();
|
|
90
110
|
}
|
|
91
111
|
|
|
92
112
|
public setPage = (selectedPage: number) => {
|
|
93
|
-
|
|
94
|
-
|
|
113
|
+
const position = pageIndex(selectedPage);
|
|
114
|
+
if (
|
|
115
|
+
this.nativeRef &&
|
|
116
|
+
position !== null &&
|
|
117
|
+
position >= 0 &&
|
|
118
|
+
position < this.pages().length
|
|
119
|
+
) {
|
|
120
|
+
CollapsiblePagerViewNativeCommands.setPage(this.nativeRef, position);
|
|
95
121
|
}
|
|
96
122
|
};
|
|
97
123
|
|
|
98
124
|
public setPageWithoutAnimation = (selectedPage: number) => {
|
|
99
|
-
|
|
125
|
+
const position = pageIndex(selectedPage);
|
|
126
|
+
if (
|
|
127
|
+
this.nativeRef &&
|
|
128
|
+
position !== null &&
|
|
129
|
+
position >= 0 &&
|
|
130
|
+
position < this.pages().length
|
|
131
|
+
) {
|
|
100
132
|
CollapsiblePagerViewNativeCommands.setPageWithoutAnimation(
|
|
101
133
|
this.nativeRef,
|
|
102
|
-
|
|
134
|
+
position
|
|
103
135
|
);
|
|
104
136
|
}
|
|
105
137
|
};
|
|
@@ -157,7 +189,10 @@ export class CollapsiblePagerView extends React.PureComponent<
|
|
|
157
189
|
private onPageSelected = (
|
|
158
190
|
event: ReactNative.NativeSyntheticEvent<OnPageSelectedEventData>
|
|
159
191
|
) => {
|
|
160
|
-
const position =
|
|
192
|
+
const position = clampedPageIndex(
|
|
193
|
+
event.nativeEvent.position,
|
|
194
|
+
this.pages().length
|
|
195
|
+
);
|
|
161
196
|
if (position !== this.state.selectedPage) {
|
|
162
197
|
this.setState({ selectedPage: position }, this.notifyMountedPagesChanged);
|
|
163
198
|
}
|