@onekeyfe/react-native-pager-view 6.7.0-2 → 6.7.0-21
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 +14 -0
- package/android/src/androidTest/AndroidManifest.xml +7 -0
- package/android/src/androidTest/java/com/reactnativepagerview/CollapsiblePagerTabReservationTest.kt +306 -0
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerHost.kt +130 -30
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerNativeHeaders.kt +72 -7
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerViewManager.kt +27 -0
- package/android/src/main/java/com/reactnativepagerview/NativeScrollerScrollAwayInsets.kt +19 -0
- package/android/src/main/java/com/reactnativepagerview/NativeScrollerView.kt +50 -6
- package/android/src/main/java/com/reactnativepagerview/NestedScrollableHost.kt +8 -2
- package/android/src/test/java/com/reactnativepagerview/NativeScrollerScrollAwayInsetsTest.kt +40 -0
- package/docs/SPEC.md +257 -10
- package/ios/RNCCollapsiblePagerViewComponentView.mm +614 -42
- package/ios/RNCNativeScrollerComponentView.h +2 -0
- package/ios/RNCNativeScrollerComponentView.mm +42 -0
- package/ios/tests/RNCCollapsiblePagerFirstFrameTests.mm +403 -1
- package/ios/tests/RNCCollapsiblePagerHitTestTests.mm +338 -0
- package/ios/tests/RNCCollapsiblePagerPressCancellationTests.mm +74 -9
- package/ios/tests/RNCCollapsiblePagerRefreshControlTests.mm +50 -0
- package/lib/module/CollapsiblePagerView.js +32 -7
- package/lib/module/CollapsiblePagerView.web.js +439 -39
- package/lib/module/CollapsiblePagerViewNativeComponent.ts +13 -0
- package/lib/module/NativeScroller.web.js +16 -3
- package/lib/module/WebCollapsiblePagerPage.js +182 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.native.js +9 -0
- package/lib/module/index.web.js +2 -0
- package/lib/typescript/src/CollapsiblePagerView.d.ts +10 -3
- package/lib/typescript/src/CollapsiblePagerView.web.d.ts +66 -3
- package/lib/typescript/src/CollapsiblePagerViewNativeComponent.d.ts +5 -0
- package/lib/typescript/src/WebCollapsiblePagerPage.d.ts +42 -0
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/index.native.d.ts +13 -0
- package/lib/typescript/src/index.web.d.ts +4 -0
- package/package.json +6 -4
- package/react-native-pager-view.podspec +1 -0
- package/src/CollapsiblePagerView.tsx +99 -8
- package/src/CollapsiblePagerView.web.tsx +657 -51
- package/src/CollapsiblePagerViewNativeComponent.ts +13 -0
- package/src/NativeScroller.web.tsx +24 -2
- package/src/WebCollapsiblePagerPage.tsx +258 -0
- package/src/index.native.tsx +30 -0
- package/src/index.tsx +4 -0
- package/src/index.web.tsx +4 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import React from "react";
|
|
4
|
-
import { I18nManager, StyleSheet, View } from "react-native";
|
|
4
|
+
import { I18nManager, Platform, StyleSheet, View } from "react-native";
|
|
5
|
+
import { WebCollapsiblePagerPage } from "./WebCollapsiblePagerPage.js";
|
|
5
6
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
6
7
|
const COLLAPSE_ANIMATION_NAME = "ok-collapsible-pager-collapse";
|
|
7
8
|
const COLLAPSE_STYLE_ID = "ok-collapsible-pager-styles";
|
|
@@ -18,6 +19,11 @@ const webElement = node => {
|
|
|
18
19
|
return element && typeof element.querySelector === "function" && typeof element.addEventListener === "function" ? element : null;
|
|
19
20
|
};
|
|
20
21
|
const timelineStyle = element => element.style;
|
|
22
|
+
function scrollElementTo(element, options) {
|
|
23
|
+
// RN Web decorates ScrollView nodes with a React Native scrollTo signature.
|
|
24
|
+
const scrollTo = element.ownerDocument.defaultView?.Element.prototype.scrollTo ?? element.scrollTo;
|
|
25
|
+
scrollTo.call(element, options);
|
|
26
|
+
}
|
|
21
27
|
function ensureCollapseAnimation(document) {
|
|
22
28
|
if (document.getElementById(COLLAPSE_STYLE_ID)) return;
|
|
23
29
|
const style = document.createElement("style");
|
|
@@ -25,6 +31,10 @@ function ensureCollapseAnimation(document) {
|
|
|
25
31
|
style.textContent = `@keyframes ${COLLAPSE_ANIMATION_NAME}{from{transform:translateY(0)}to{transform:translateY(calc(-1 * var(--ok-collapsible-header-height)))}}`;
|
|
26
32
|
document.head.appendChild(style);
|
|
27
33
|
}
|
|
34
|
+
function supportsScrollTimeline(document) {
|
|
35
|
+
const css = document.defaultView?.CSS;
|
|
36
|
+
return !!(typeof css?.supports === "function" && css.supports("animation-timeline", "--ok-test") && css.supports("timeline-scope", "--ok-test") && css.supports("scroll-timeline-name", "--ok-test") && css.supports("scroll-timeline-axis", "block") && css.supports("animation-range", "0px 1px") && css.supports("animation-duration", "auto"));
|
|
37
|
+
}
|
|
28
38
|
const pageKey = (child, index) => {
|
|
29
39
|
if (/*#__PURE__*/React.isValidElement(child) && child.key != null) return String(child.key);
|
|
30
40
|
return `page-${index}`;
|
|
@@ -38,11 +48,30 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
38
48
|
};
|
|
39
49
|
root = null;
|
|
40
50
|
track = null;
|
|
51
|
+
headerSlot = null;
|
|
52
|
+
stickySlot = null;
|
|
53
|
+
cssTimelineSupported = false;
|
|
54
|
+
overlayTouch = null;
|
|
41
55
|
touchStartX = null;
|
|
42
56
|
touchStartY = null;
|
|
43
57
|
horizontalTouch = false;
|
|
44
58
|
pageOffsets = new Map();
|
|
45
59
|
pageHosts = new Map();
|
|
60
|
+
pageScrollIdentities = new Map();
|
|
61
|
+
pageBridges = new Map();
|
|
62
|
+
ownerRecords = new Map();
|
|
63
|
+
ownerGeneration = 0;
|
|
64
|
+
lastRawTops = new Map();
|
|
65
|
+
routeTarget = null;
|
|
66
|
+
measuredHeaderHeight = 0;
|
|
67
|
+
measuredStickyHeight = 0;
|
|
68
|
+
headerMeasured = false;
|
|
69
|
+
stickyMeasured = false;
|
|
70
|
+
headerContent = null;
|
|
71
|
+
stickyContent = null;
|
|
72
|
+
chromeObserver = null;
|
|
73
|
+
chromeMeasureFrame = null;
|
|
74
|
+
disposed = false;
|
|
46
75
|
sharedHeaderOffset = 0;
|
|
47
76
|
selectionRestoreToken = 0;
|
|
48
77
|
bodyAlignment = null;
|
|
@@ -54,13 +83,51 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
54
83
|
pageScrollState = "idle";
|
|
55
84
|
configuredScrollElement = null;
|
|
56
85
|
timelineName = `--ok-collapsible-pager-${++collapsiblePagerWebInstance}`;
|
|
86
|
+
get headerHeight() {
|
|
87
|
+
return this.hasExplicitHeaderHeight ? this.props.headerHeight ?? this.measuredHeaderHeight : this.measuredHeaderHeight;
|
|
88
|
+
}
|
|
89
|
+
get hasExplicitHeaderHeight() {
|
|
90
|
+
return this.props.headerHeight !== undefined && Number.isFinite(this.props.headerHeight) && this.props.headerHeight >= 0;
|
|
91
|
+
}
|
|
92
|
+
get stickyHeaderHeight() {
|
|
93
|
+
return this.hasExplicitStickyHeaderHeight ? this.props.stickyHeaderHeight ?? this.measuredStickyHeight : this.measuredStickyHeight;
|
|
94
|
+
}
|
|
95
|
+
get hasExplicitStickyHeaderHeight() {
|
|
96
|
+
return this.props.stickyHeaderHeight !== undefined && Number.isFinite(this.props.stickyHeaderHeight) && this.props.stickyHeaderHeight >= 0;
|
|
97
|
+
}
|
|
98
|
+
getSnapshotBeforeUpdate(previousProps) {
|
|
99
|
+
if (previousProps.isActive !== false && this.props.isActive === false) return this.captureRouteTarget(previousProps);
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
57
102
|
componentDidMount() {
|
|
58
|
-
|
|
103
|
+
this.disposed = false;
|
|
104
|
+
if (Platform.OS !== "web" || typeof document === "undefined") throw new Error("WebCollapsiblePagerView requires a Web DOM runtime");
|
|
105
|
+
if (!this.hasExplicitHeaderHeight) this.headerMeasured = false;
|
|
106
|
+
if (!this.hasExplicitStickyHeaderHeight) this.stickyMeasured = false;
|
|
107
|
+
this.observeChrome();
|
|
108
|
+
if (this.root) {
|
|
109
|
+
this.cssTimelineSupported = supportsScrollTimeline(this.root.ownerDocument);
|
|
110
|
+
if (this.cssTimelineSupported) {
|
|
111
|
+
ensureCollapseAnimation(this.root.ownerDocument);
|
|
112
|
+
this.forceUpdate();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
59
115
|
this.scheduleScrollConfiguration();
|
|
116
|
+
this.syncFallbackHeader();
|
|
60
117
|
this.notifyMountedPagesChanged();
|
|
61
118
|
this.emitDiagnostics("mounted");
|
|
62
119
|
}
|
|
63
|
-
componentDidUpdate(previousProps) {
|
|
120
|
+
componentDidUpdate(previousProps, _previousState, routeSnapshot) {
|
|
121
|
+
if (routeSnapshot) {
|
|
122
|
+
const record = this.ownerRecords.get(routeSnapshot.key);
|
|
123
|
+
if (this.pages().map(pageKey).includes(routeSnapshot.key) && record?.element === routeSnapshot.owner && record.identity === routeSnapshot.identity && record.generation === routeSnapshot.generation) this.setRouteTarget(routeSnapshot);
|
|
124
|
+
}
|
|
125
|
+
if (previousProps.isActive === false && this.props.isActive !== false) {
|
|
126
|
+
if (!this.hasExplicitHeaderHeight) this.headerMeasured = false;
|
|
127
|
+
if (!this.hasExplicitStickyHeaderHeight) this.stickyMeasured = false;
|
|
128
|
+
this.scheduleChromeMeasurement();
|
|
129
|
+
this.restoreScrollPosition();
|
|
130
|
+
}
|
|
64
131
|
if (previousProps.scrollEnabled !== this.props.scrollEnabled) {
|
|
65
132
|
this.scrollEnabled = this.props.scrollEnabled ?? true;
|
|
66
133
|
if (!this.scrollEnabled) {
|
|
@@ -82,10 +149,29 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
82
149
|
});
|
|
83
150
|
return;
|
|
84
151
|
}
|
|
152
|
+
// Child layout effects can run before page-host refs are reattached.
|
|
153
|
+
// Recheck identities in the same commit, before a new user command runs.
|
|
154
|
+
this.mountedPages().forEach(index => this.synchronizeScrollOwnerIdentity(index));
|
|
155
|
+
const currentKeys = new Set(this.pages().map(pageKey));
|
|
156
|
+
const ownedKeys = new Set([...this.pageScrollIdentities.keys(), ...this.pageOffsets.keys(), ...this.lastRawTops.keys(), ...this.ownerRecords.keys()]);
|
|
157
|
+
for (const key of ownedKeys) {
|
|
158
|
+
if (!currentKeys.has(key)) {
|
|
159
|
+
this.pageScrollIdentities.delete(key);
|
|
160
|
+
this.pageOffsets.delete(key);
|
|
161
|
+
this.lastRawTops.delete(key);
|
|
162
|
+
this.ownerRecords.delete(key);
|
|
163
|
+
if (this.routeTarget?.key === key) this.setRouteTarget(null);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
85
166
|
this.scheduleScrollConfiguration();
|
|
167
|
+
this.syncFallbackHeader();
|
|
86
168
|
this.notifyMountedPagesChanged();
|
|
87
169
|
}
|
|
88
170
|
componentWillUnmount() {
|
|
171
|
+
// Activity can disconnect effects before the inactive update commits.
|
|
172
|
+
const routeTarget = this.captureRouteTarget(this.props);
|
|
173
|
+
if (routeTarget) this.setRouteTarget(routeTarget);
|
|
174
|
+
this.disposed = true;
|
|
89
175
|
this.selectionRestoreToken += 1;
|
|
90
176
|
this.cancelPendingTopFrame();
|
|
91
177
|
this.savePageOffset(this.state.selectedPage);
|
|
@@ -98,8 +184,148 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
98
184
|
this.transitionTimer = null;
|
|
99
185
|
}
|
|
100
186
|
this.setTrack(null);
|
|
187
|
+
this.setRoot(null);
|
|
188
|
+
this.chromeObserver?.disconnect();
|
|
189
|
+
this.chromeObserver = null;
|
|
190
|
+
if (this.chromeMeasureFrame !== null) {
|
|
191
|
+
cancelAnimationFrame(this.chromeMeasureFrame);
|
|
192
|
+
this.chromeMeasureFrame = null;
|
|
193
|
+
}
|
|
194
|
+
this.pageBridges.clear();
|
|
101
195
|
this.restoreConfiguredScrollElement();
|
|
102
196
|
}
|
|
197
|
+
setHeaderContent = node => {
|
|
198
|
+
const element = webElement(node);
|
|
199
|
+
if (element === this.headerContent) return;
|
|
200
|
+
if (this.headerContent) this.chromeObserver?.unobserve(this.headerContent);
|
|
201
|
+
this.headerContent = element;
|
|
202
|
+
this.headerMeasured = false;
|
|
203
|
+
if (element) this.chromeObserver?.observe(element);
|
|
204
|
+
this.scheduleChromeMeasurement();
|
|
205
|
+
};
|
|
206
|
+
setStickyContent = node => {
|
|
207
|
+
const element = webElement(node);
|
|
208
|
+
if (element === this.stickyContent) return;
|
|
209
|
+
if (this.stickyContent) this.chromeObserver?.unobserve(this.stickyContent);
|
|
210
|
+
this.stickyContent = element;
|
|
211
|
+
this.stickyMeasured = false;
|
|
212
|
+
if (element) this.chromeObserver?.observe(element);
|
|
213
|
+
this.scheduleChromeMeasurement();
|
|
214
|
+
};
|
|
215
|
+
observeChrome() {
|
|
216
|
+
this.chromeObserver = new ResizeObserver(this.scheduleChromeMeasurement);
|
|
217
|
+
if (this.headerContent) this.chromeObserver.observe(this.headerContent);
|
|
218
|
+
if (this.stickyContent) this.chromeObserver.observe(this.stickyContent);
|
|
219
|
+
this.scheduleChromeMeasurement();
|
|
220
|
+
}
|
|
221
|
+
scheduleChromeMeasurement = () => {
|
|
222
|
+
if (this.disposed || this.chromeMeasureFrame !== null || typeof requestAnimationFrame !== "function") return;
|
|
223
|
+
this.chromeMeasureFrame = requestAnimationFrame(() => {
|
|
224
|
+
this.chromeMeasureFrame = null;
|
|
225
|
+
const header = this.headerContent;
|
|
226
|
+
const sticky = this.stickyContent;
|
|
227
|
+
const nextHeader = header?.isConnected ? Math.max(0, header.getBoundingClientRect().height) : 0;
|
|
228
|
+
const nextSticky = sticky?.isConnected ? Math.max(0, sticky.getBoundingClientRect().height) : 0;
|
|
229
|
+
const headerChanged = this.measuredHeaderHeight !== nextHeader || this.headerMeasured !== Boolean(header?.isConnected);
|
|
230
|
+
const stickyChanged = this.measuredStickyHeight !== nextSticky || this.stickyMeasured !== Boolean(sticky?.isConnected);
|
|
231
|
+
this.measuredHeaderHeight = nextHeader;
|
|
232
|
+
this.measuredStickyHeight = nextSticky;
|
|
233
|
+
this.headerMeasured = Boolean(header?.isConnected);
|
|
234
|
+
this.stickyMeasured = Boolean(sticky?.isConnected);
|
|
235
|
+
if (headerChanged || stickyChanged) {
|
|
236
|
+
this.forceUpdate();
|
|
237
|
+
this.scheduleScrollConfiguration();
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
};
|
|
241
|
+
onPageBridge = (key, bridge) => {
|
|
242
|
+
if (bridge) {
|
|
243
|
+
this.pageBridges.set(key, bridge);
|
|
244
|
+
bridge.setPendingRouteScrollTop(this.routeTarget?.key === key ? this.routeTarget.top : null);
|
|
245
|
+
const index = this.pages().map(pageKey).indexOf(key);
|
|
246
|
+
if (index >= 0) this.syncPageOwner(index);
|
|
247
|
+
} else {
|
|
248
|
+
this.pageBridges.delete(key);
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
setRouteTarget(target) {
|
|
252
|
+
const oldKey = this.routeTarget?.key;
|
|
253
|
+
this.routeTarget = target;
|
|
254
|
+
if (oldKey) this.pageBridges.get(oldKey)?.setPendingRouteScrollTop(null);
|
|
255
|
+
if (target) this.pageBridges.get(target.key)?.setPendingRouteScrollTop(target.top);
|
|
256
|
+
}
|
|
257
|
+
syncPageOwner(index) {
|
|
258
|
+
const key = this.pages().map(pageKey)[index];
|
|
259
|
+
const element = this.pageScrollElement(index);
|
|
260
|
+
if (!key || !element) return;
|
|
261
|
+
const identity = element.getAttribute("data-collapsible-pager-scroll-key") ?? key;
|
|
262
|
+
const previous = this.ownerRecords.get(key);
|
|
263
|
+
if (previous?.element !== element || previous.identity !== identity) {
|
|
264
|
+
if (this.routeTarget?.key === key) this.setRouteTarget(null);
|
|
265
|
+
this.ownerRecords.set(key, {
|
|
266
|
+
element,
|
|
267
|
+
identity,
|
|
268
|
+
generation: ++this.ownerGeneration
|
|
269
|
+
});
|
|
270
|
+
this.lastRawTops.delete(key);
|
|
271
|
+
}
|
|
272
|
+
this.pageBridges.get(key)?.setOwner(element);
|
|
273
|
+
}
|
|
274
|
+
captureRouteTarget(previousProps) {
|
|
275
|
+
const index = this.state.selectedPage;
|
|
276
|
+
const oldKey = React.Children.toArray(previousProps.children).map(pageKey)[index];
|
|
277
|
+
const key = this.configuredScrollElement?.key ?? oldKey;
|
|
278
|
+
const record = key ? this.ownerRecords.get(key) : null;
|
|
279
|
+
if (!record?.element.isConnected) return null;
|
|
280
|
+
if (this.routeTarget?.key === key && this.routeTarget.identity === record.identity && this.routeTarget.owner === record.element && this.routeTarget.generation === record.generation) return this.routeTarget;
|
|
281
|
+
const top = record.element.clientHeight > 0 ? record.element.scrollTop : this.lastRawTops.get(key) ?? record.element.scrollTop;
|
|
282
|
+
return {
|
|
283
|
+
key,
|
|
284
|
+
identity: record.identity,
|
|
285
|
+
owner: record.element,
|
|
286
|
+
generation: record.generation,
|
|
287
|
+
top: Math.max(0, top)
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
restoreScrollPosition = () => {
|
|
291
|
+
if (this.disposed || this.props.isActive === false) return false;
|
|
292
|
+
const pending = this.routeTarget;
|
|
293
|
+
if (!pending) return true;
|
|
294
|
+
const key = this.pages().map(pageKey)[this.state.selectedPage];
|
|
295
|
+
if (key !== pending.key) return false;
|
|
296
|
+
this.syncPageOwner(this.state.selectedPage);
|
|
297
|
+
const record = this.ownerRecords.get(key);
|
|
298
|
+
if (!record || record.element !== pending.owner || record.identity !== pending.identity || record.generation !== pending.generation) return false;
|
|
299
|
+
const element = record.element;
|
|
300
|
+
const configured = this.configuredScrollElement;
|
|
301
|
+
if (!element.isConnected || element.clientHeight <= 0 || configured?.element !== element || configured.key !== key || !this.hasExplicitHeaderHeight && !this.headerMeasured || !this.hasExplicitStickyHeaderHeight && !this.stickyMeasured || element.getAttribute("data-collapsible-pager-active") !== "true" || element.style.getPropertyValue(PAGER_HEADER_INSET).trim() !== `${this.headerHeight}px` || element.style.getPropertyValue(PAGER_STICKY_INSET).trim() !== `${this.stickyHeaderHeight}px` || element.scrollHeight - element.clientHeight < pending.top) return false;
|
|
302
|
+
this.selectionRestoreToken += 1;
|
|
303
|
+
this.cancelPendingTopFrame();
|
|
304
|
+
this.setRouteTarget(null);
|
|
305
|
+
this.lastRawTops.set(key, pending.top);
|
|
306
|
+
const D = this.headerHeight;
|
|
307
|
+
this.sharedHeaderOffset = Math.min(pending.top, D);
|
|
308
|
+
this.pageOffsets.set(key, Math.max(0, pending.top - D));
|
|
309
|
+
this.bodyAlignment = {
|
|
310
|
+
element,
|
|
311
|
+
key
|
|
312
|
+
};
|
|
313
|
+
scrollElementTo(element, {
|
|
314
|
+
top: pending.top,
|
|
315
|
+
behavior: "instant"
|
|
316
|
+
});
|
|
317
|
+
this.syncFallbackHeader();
|
|
318
|
+
return true;
|
|
319
|
+
};
|
|
320
|
+
onPageScroll = (key, top) => {
|
|
321
|
+
if (this.props.isActive !== false) this.lastRawTops.set(key, top);
|
|
322
|
+
};
|
|
323
|
+
onPageGeometryChange = key => {
|
|
324
|
+
if (this.routeTarget?.key === key) this.restoreScrollPosition();
|
|
325
|
+
};
|
|
326
|
+
onPageUserInput = key => {
|
|
327
|
+
if (this.routeTarget?.key === key) this.setRouteTarget(null);
|
|
328
|
+
};
|
|
103
329
|
setPage = selectedPage => {
|
|
104
330
|
this.selectPage(selectedPage, true);
|
|
105
331
|
};
|
|
@@ -109,8 +335,17 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
109
335
|
scrollToPageTop = options => {
|
|
110
336
|
this.scrollCurrentPageToTop(0, options?.animated ?? true);
|
|
111
337
|
};
|
|
338
|
+
scrollHeaderBy = delta => {
|
|
339
|
+
if (!Number.isFinite(delta)) return;
|
|
340
|
+
const offset = Math.min(this.headerHeight, Math.max(0, this.sharedHeaderOffset + delta));
|
|
341
|
+
this.scrollCurrentPageToTop(offset, false);
|
|
342
|
+
};
|
|
343
|
+
scrollHeaderToOffset = offset => {
|
|
344
|
+
if (!Number.isFinite(offset)) return;
|
|
345
|
+
this.scrollCurrentPageToTop(Math.min(this.headerHeight, Math.max(0, offset)), false);
|
|
346
|
+
};
|
|
112
347
|
scrollToStickyTop = options => {
|
|
113
|
-
this.scrollCurrentPageToTop(
|
|
348
|
+
this.scrollCurrentPageToTop(this.headerHeight, options?.animated ?? true);
|
|
114
349
|
};
|
|
115
350
|
cancelPendingTopFrame = () => {
|
|
116
351
|
if (!this.pendingTopFrame) return;
|
|
@@ -145,11 +380,12 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
145
380
|
const element = this.pageScrollElement(this.state.selectedPage);
|
|
146
381
|
const key = this.pages().map(pageKey)[this.state.selectedPage];
|
|
147
382
|
if (!element?.isConnected || !key) return;
|
|
383
|
+
this.setRouteTarget(null);
|
|
148
384
|
this.selectionRestoreToken += 1;
|
|
149
385
|
this.cancelPendingTopFrame();
|
|
150
386
|
const EventConstructor = element.ownerDocument.defaultView?.Event;
|
|
151
387
|
if (EventConstructor) element.dispatchEvent(new EventConstructor("ok-collapsible-pager-cancel-scroll-command"));
|
|
152
|
-
element
|
|
388
|
+
scrollElementTo(element, {
|
|
153
389
|
left: element.scrollLeft,
|
|
154
390
|
top: element.scrollTop,
|
|
155
391
|
behavior: "instant"
|
|
@@ -159,15 +395,16 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
159
395
|
this.pendingTopFrame = null;
|
|
160
396
|
if (!element.isConnected || this.horizontalTouch || this.transitionTimer !== null || this.pageScrollElement(this.state.selectedPage) !== element || this.pages().map(pageKey)[this.state.selectedPage] !== key) return;
|
|
161
397
|
this.pageOffsets.set(key, 0);
|
|
162
|
-
this.sharedHeaderOffset = offset;
|
|
398
|
+
this.sharedHeaderOffset = Math.min(this.headerHeight, Math.max(0, offset));
|
|
163
399
|
this.bodyAlignment = {
|
|
164
400
|
element,
|
|
165
401
|
key
|
|
166
402
|
};
|
|
167
|
-
element
|
|
168
|
-
top:
|
|
403
|
+
scrollElementTo(element, {
|
|
404
|
+
top: this.sharedHeaderOffset,
|
|
169
405
|
behavior: animated ? "smooth" : "instant"
|
|
170
406
|
});
|
|
407
|
+
this.syncFallbackHeader();
|
|
171
408
|
});
|
|
172
409
|
this.pendingTopFrame = {
|
|
173
410
|
frame,
|
|
@@ -230,8 +467,119 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
230
467
|
};
|
|
231
468
|
pageScrollElement(index) {
|
|
232
469
|
const pageHost = this.pageHosts.get(index);
|
|
233
|
-
return pageHost?.querySelector("
|
|
470
|
+
return pageHost?.querySelector("[data-collapsible-pager-scroll]") ?? pageHost?.querySelector(".ok-native-list-viewport") ?? pageHost;
|
|
471
|
+
}
|
|
472
|
+
setRoot = node => {
|
|
473
|
+
const root = webElement(node);
|
|
474
|
+
if (root === this.root) return;
|
|
475
|
+
this.root?.removeEventListener("ok-collapsible-pager-scroll-key-changed", this.onScrollOwnerIdentityChanged);
|
|
476
|
+
this.root?.removeEventListener("wheel", this.onOverlayWheel);
|
|
477
|
+
this.root?.removeEventListener("touchstart", this.onOverlayTouchStart);
|
|
478
|
+
this.root?.removeEventListener("touchmove", this.onOverlayTouchMove);
|
|
479
|
+
this.root?.removeEventListener("touchend", this.onOverlayTouchEnd);
|
|
480
|
+
this.root?.removeEventListener("touchcancel", this.onOverlayTouchEnd);
|
|
481
|
+
this.overlayTouch = null;
|
|
482
|
+
this.root = root;
|
|
483
|
+
root?.addEventListener("ok-collapsible-pager-scroll-key-changed", this.onScrollOwnerIdentityChanged);
|
|
484
|
+
root?.addEventListener("wheel", this.onOverlayWheel, {
|
|
485
|
+
passive: false
|
|
486
|
+
});
|
|
487
|
+
root?.addEventListener("touchstart", this.onOverlayTouchStart, {
|
|
488
|
+
passive: true
|
|
489
|
+
});
|
|
490
|
+
root?.addEventListener("touchmove", this.onOverlayTouchMove, {
|
|
491
|
+
passive: false
|
|
492
|
+
});
|
|
493
|
+
root?.addEventListener("touchend", this.onOverlayTouchEnd);
|
|
494
|
+
root?.addEventListener("touchcancel", this.onOverlayTouchEnd);
|
|
495
|
+
};
|
|
496
|
+
overlayTarget(event) {
|
|
497
|
+
const target = event.target;
|
|
498
|
+
if (!target || !this.headerSlot?.contains(target) && !this.stickySlot?.contains(target) || target.closest("input,textarea,select,[contenteditable=true]")) return null;
|
|
499
|
+
return target;
|
|
500
|
+
}
|
|
501
|
+
nestedScrollConsumes(target, delta) {
|
|
502
|
+
for (let node = target; node && node !== this.root; node = node.parentElement) {
|
|
503
|
+
const style = node.ownerDocument.defaultView?.getComputedStyle(node);
|
|
504
|
+
if (/auto|scroll/.test(style?.overflowY ?? "") && node.scrollHeight > node.clientHeight && (delta < 0 ? node.scrollTop > 0 : node.scrollTop < node.scrollHeight - node.clientHeight)) return true;
|
|
505
|
+
}
|
|
506
|
+
return false;
|
|
234
507
|
}
|
|
508
|
+
scrollOverlayOwner(owner, delta, event) {
|
|
509
|
+
if (!event.cancelable) return;
|
|
510
|
+
const EventConstructor = owner.ownerDocument.defaultView?.Event;
|
|
511
|
+
if (EventConstructor) owner.dispatchEvent(new EventConstructor("ok-collapsible-pager-user-scroll"));
|
|
512
|
+
const top = Math.min(Math.max(0, owner.scrollTop + delta), owner.scrollHeight - owner.clientHeight);
|
|
513
|
+
if (top === owner.scrollTop) return;
|
|
514
|
+
this.takeOverVerticalScroll();
|
|
515
|
+
scrollElementTo(owner, {
|
|
516
|
+
top,
|
|
517
|
+
behavior: "instant"
|
|
518
|
+
});
|
|
519
|
+
event.preventDefault();
|
|
520
|
+
}
|
|
521
|
+
onOverlayWheel = event => {
|
|
522
|
+
const target = this.overlayTarget(event);
|
|
523
|
+
const owner = this.pageScrollElement(this.state.selectedPage);
|
|
524
|
+
if (!target || !owner || event.defaultPrevented || event.ctrlKey || Math.abs(event.deltaX) > Math.abs(event.deltaY)) return;
|
|
525
|
+
const lineHeight = Number.parseFloat(target.ownerDocument.defaultView?.getComputedStyle(target).lineHeight ?? "") || 16;
|
|
526
|
+
const delta = event.deltaY * (event.deltaMode === 1 ? lineHeight : event.deltaMode === 2 ? owner.clientHeight : 1);
|
|
527
|
+
if (!this.nestedScrollConsumes(target, delta)) this.scrollOverlayOwner(owner, delta, event);
|
|
528
|
+
};
|
|
529
|
+
onOverlayTouchStart = event => {
|
|
530
|
+
const target = this.overlayTarget(event);
|
|
531
|
+
const owner = this.pageScrollElement(this.state.selectedPage);
|
|
532
|
+
const touch = event.touches.length === 1 ? event.touches[0] : null;
|
|
533
|
+
this.overlayTouch = target && owner && touch ? {
|
|
534
|
+
owner,
|
|
535
|
+
target,
|
|
536
|
+
x: touch.clientX,
|
|
537
|
+
y: touch.clientY,
|
|
538
|
+
lastY: touch.clientY
|
|
539
|
+
} : null;
|
|
540
|
+
};
|
|
541
|
+
onOverlayTouchMove = event => {
|
|
542
|
+
if (event.defaultPrevented) return;
|
|
543
|
+
const pending = this.overlayTouch;
|
|
544
|
+
const touch = event.touches.length === 1 ? event.touches[0] : null;
|
|
545
|
+
if (!pending || !touch || pending.owner !== this.pageScrollElement(this.state.selectedPage)) {
|
|
546
|
+
this.overlayTouch = null;
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
const delta = pending.lastY - touch.clientY;
|
|
550
|
+
pending.lastY = touch.clientY;
|
|
551
|
+
if (Math.abs(touch.clientY - pending.y) < 8 || Math.abs(touch.clientX - pending.x) >= Math.abs(touch.clientY - pending.y)) return;
|
|
552
|
+
if (!this.nestedScrollConsumes(pending.target, delta)) this.scrollOverlayOwner(pending.owner, delta, event);
|
|
553
|
+
};
|
|
554
|
+
onOverlayTouchEnd = () => {
|
|
555
|
+
this.overlayTouch = null;
|
|
556
|
+
};
|
|
557
|
+
synchronizeScrollOwnerIdentity(index) {
|
|
558
|
+
const key = this.pages().map(pageKey)[index];
|
|
559
|
+
const element = this.pageScrollElement(index);
|
|
560
|
+
if (!key || !element) return;
|
|
561
|
+
const identity = element.getAttribute("data-collapsible-pager-scroll-key") ?? key;
|
|
562
|
+
const previous = this.pageScrollIdentities.get(key);
|
|
563
|
+
this.pageScrollIdentities.set(key, identity);
|
|
564
|
+
this.syncPageOwner(index);
|
|
565
|
+
if (previous === undefined || previous === identity) return;
|
|
566
|
+
if (index === this.state.selectedPage) {
|
|
567
|
+
this.selectionRestoreToken += 1;
|
|
568
|
+
this.cancelPendingTopFrame();
|
|
569
|
+
this.sharedHeaderOffset = 0;
|
|
570
|
+
this.bodyAlignment = null;
|
|
571
|
+
scrollElementTo(element, {
|
|
572
|
+
top: 0,
|
|
573
|
+
behavior: "instant"
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
this.pageOffsets.delete(key);
|
|
577
|
+
}
|
|
578
|
+
onScrollOwnerIdentityChanged = event => {
|
|
579
|
+
this.pages().forEach((_, index) => {
|
|
580
|
+
if (event.target === this.pageScrollElement(index)) this.synchronizeScrollOwnerIdentity(index);
|
|
581
|
+
});
|
|
582
|
+
};
|
|
235
583
|
notifyInsetsChanged(element) {
|
|
236
584
|
const EventConstructor = element.ownerDocument.defaultView?.Event;
|
|
237
585
|
if (EventConstructor) {
|
|
@@ -247,10 +595,11 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
247
595
|
configured.element.removeEventListener("pointerdown", this.onScrollbarPointerDown);
|
|
248
596
|
configured.element.removeEventListener("keydown", this.onQueuedTopKey);
|
|
249
597
|
configured.element.removeEventListener("scrollend", this.onVerticalScrollSettled);
|
|
598
|
+
configured.element.removeEventListener("scroll", this.syncFallbackHeader);
|
|
250
599
|
const style = timelineStyle(configured.element);
|
|
251
600
|
configured.rangeSpacer.remove();
|
|
252
601
|
style.position = configured.position;
|
|
253
|
-
style.paddingTop = configured.paddingTop;
|
|
602
|
+
configured.paddingTarget.style.paddingTop = configured.paddingTop;
|
|
254
603
|
style.boxSizing = configured.boxSizing;
|
|
255
604
|
style.scrollTimelineName = configured.scrollTimelineName;
|
|
256
605
|
style.scrollTimelineAxis = configured.scrollTimelineAxis;
|
|
@@ -259,16 +608,19 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
259
608
|
configured.element.removeAttribute("data-collapsible-pager-active");
|
|
260
609
|
this.notifyInsetsChanged(configured.element);
|
|
261
610
|
this.configuredScrollElement = null;
|
|
611
|
+
this.syncFallbackHeader();
|
|
262
612
|
if (this.bodyAlignment?.element === configured.element) this.bodyAlignment = null;
|
|
263
613
|
}
|
|
264
614
|
configureActiveScrollElement = () => {
|
|
265
615
|
this.configureFrame = null;
|
|
266
616
|
const element = this.pageScrollElement(this.state.selectedPage);
|
|
267
617
|
if (!element) return;
|
|
618
|
+
this.synchronizeScrollOwnerIdentity(this.state.selectedPage);
|
|
268
619
|
if (this.configuredScrollElement?.element !== element) {
|
|
269
620
|
this.restoreConfiguredScrollElement();
|
|
270
621
|
const style = timelineStyle(element);
|
|
271
|
-
const
|
|
622
|
+
const paddingTarget = element.hasAttribute("data-collapsible-pager-scroll") ? webElement(element.firstElementChild) ?? element : element;
|
|
623
|
+
const computedPaddingTop = element.ownerDocument.defaultView?.getComputedStyle(paddingTarget).paddingTop || paddingTarget.style.paddingTop || "0px";
|
|
272
624
|
const rangeSpacer = element.ownerDocument.createElement("div");
|
|
273
625
|
Object.assign(rangeSpacer.style, {
|
|
274
626
|
position: "absolute",
|
|
@@ -283,10 +635,12 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
283
635
|
if (element.ownerDocument.defaultView?.getComputedStyle(element).position === "static") style.position = "relative";
|
|
284
636
|
element.appendChild(rangeSpacer);
|
|
285
637
|
this.configuredScrollElement = {
|
|
638
|
+
key: this.pages().map(pageKey)[this.state.selectedPage],
|
|
286
639
|
element,
|
|
640
|
+
paddingTarget,
|
|
287
641
|
rangeSpacer,
|
|
288
642
|
position,
|
|
289
|
-
paddingTop: style.paddingTop,
|
|
643
|
+
paddingTop: paddingTarget.style.paddingTop,
|
|
290
644
|
basePaddingTop: computedPaddingTop,
|
|
291
645
|
boxSizing: style.boxSizing,
|
|
292
646
|
scrollTimelineName: style.scrollTimelineName,
|
|
@@ -299,17 +653,21 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
299
653
|
element.addEventListener("wheel", this.onQueuedTopWheel);
|
|
300
654
|
element.addEventListener("pointerdown", this.onScrollbarPointerDown);
|
|
301
655
|
element.addEventListener("keydown", this.onQueuedTopKey);
|
|
656
|
+
if (!this.cssTimelineSupported) element.addEventListener("scroll", this.syncFallbackHeader, {
|
|
657
|
+
passive: true
|
|
658
|
+
});
|
|
302
659
|
}
|
|
303
660
|
const style = timelineStyle(element);
|
|
304
|
-
const
|
|
305
|
-
const
|
|
661
|
+
const paddingStyle = this.configuredScrollElement?.paddingTarget.style ?? style;
|
|
662
|
+
const headerInset = this.headerHeight;
|
|
663
|
+
const stickyInset = this.stickyHeaderHeight;
|
|
306
664
|
if (this.configuredScrollElement) this.configuredScrollElement.rangeSpacer.style.height = `calc(100% + ${headerInset}px)`;
|
|
307
665
|
const basePaddingTop = this.configuredScrollElement?.basePaddingTop ?? "0px";
|
|
308
666
|
const paddingTop = `calc(${basePaddingTop} + ${headerInset + stickyInset}px)`;
|
|
309
667
|
const headerInsetValue = `${headerInset}px`;
|
|
310
668
|
const stickyInsetValue = `${stickyInset}px`;
|
|
311
|
-
const insetsChanged =
|
|
312
|
-
|
|
669
|
+
const insetsChanged = paddingStyle.paddingTop !== paddingTop || style.getPropertyValue(PAGER_HEADER_INSET) !== headerInsetValue || style.getPropertyValue(PAGER_STICKY_INSET) !== stickyInsetValue;
|
|
670
|
+
paddingStyle.paddingTop = paddingTop;
|
|
313
671
|
style.boxSizing = "border-box";
|
|
314
672
|
style.scrollTimelineName = this.timelineName;
|
|
315
673
|
style.scrollTimelineAxis = "block";
|
|
@@ -317,9 +675,20 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
317
675
|
style.setProperty(PAGER_STICKY_INSET, stickyInsetValue);
|
|
318
676
|
element.setAttribute("data-collapsible-pager-active", "true");
|
|
319
677
|
if (insetsChanged) this.notifyInsetsChanged(element);
|
|
678
|
+
this.syncFallbackHeader();
|
|
679
|
+
this.pageBridges.get(this.pages().map(pageKey)[this.state.selectedPage])?.requestMeasure();
|
|
680
|
+
this.restoreScrollPosition();
|
|
681
|
+
};
|
|
682
|
+
syncFallbackHeader = () => {
|
|
683
|
+
if (this.cssTimelineSupported) return;
|
|
684
|
+
const top = this.configuredScrollElement?.element.scrollTop ?? 0;
|
|
685
|
+
const collapse = Math.min(Math.max(top, 0), this.headerHeight);
|
|
686
|
+
const transform = `translateY(${-collapse}px)`;
|
|
687
|
+
if (this.headerSlot) this.headerSlot.style.transform = transform;
|
|
688
|
+
if (this.stickySlot) this.stickySlot.style.transform = transform;
|
|
320
689
|
};
|
|
321
690
|
scheduleScrollConfiguration() {
|
|
322
|
-
if (this.configureFrame !== null) return;
|
|
691
|
+
if (this.disposed || this.configureFrame !== null) return;
|
|
323
692
|
if (typeof requestAnimationFrame === "function") {
|
|
324
693
|
this.configureFrame = requestAnimationFrame(this.configureActiveScrollElement);
|
|
325
694
|
} else {
|
|
@@ -327,6 +696,7 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
327
696
|
}
|
|
328
697
|
}
|
|
329
698
|
takeOverVerticalScroll = () => {
|
|
699
|
+
this.setRouteTarget(null);
|
|
330
700
|
this.selectionRestoreToken += 1;
|
|
331
701
|
this.bodyAlignment = null;
|
|
332
702
|
this.cancelPendingTopFrame();
|
|
@@ -342,11 +712,13 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
342
712
|
this.emitDiagnostics("scroll-settled");
|
|
343
713
|
};
|
|
344
714
|
savePageOffset(index) {
|
|
345
|
-
const
|
|
346
|
-
const
|
|
715
|
+
const configured = index === this.state.selectedPage ? this.configuredScrollElement : null;
|
|
716
|
+
const key = configured?.key ?? this.pages().map(pageKey)[index];
|
|
717
|
+
const scrollElement = configured?.element ?? this.pageScrollElement(index);
|
|
718
|
+
if (configured && !scrollElement?.isConnected) return;
|
|
347
719
|
if (key && scrollElement) {
|
|
348
720
|
if (this.bodyAlignment?.key === key && this.bodyAlignment.element === scrollElement) return;
|
|
349
|
-
const D =
|
|
721
|
+
const D = this.headerHeight;
|
|
350
722
|
this.pageOffsets.set(key, Math.max(0, scrollElement.scrollTop - D));
|
|
351
723
|
this.sharedHeaderOffset = Math.min(Math.max(scrollElement.scrollTop, 0), D);
|
|
352
724
|
}
|
|
@@ -355,7 +727,7 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
355
727
|
const key = this.pages().map(pageKey)[index];
|
|
356
728
|
const scrollElement = this.pageScrollElement(index);
|
|
357
729
|
if (!key || !scrollElement) return;
|
|
358
|
-
const D =
|
|
730
|
+
const D = this.headerHeight;
|
|
359
731
|
const C = Math.min(Math.max(0, this.sharedHeaderOffset), D);
|
|
360
732
|
const expectedQ = C + (C === D ? this.pageOffsets.get(key) ?? 0 : 0);
|
|
361
733
|
this.bodyAlignment = {
|
|
@@ -363,6 +735,7 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
363
735
|
key
|
|
364
736
|
};
|
|
365
737
|
scrollElement.scrollTop = expectedQ;
|
|
738
|
+
this.syncFallbackHeader();
|
|
366
739
|
}
|
|
367
740
|
selectPage(selectedPage, animated) {
|
|
368
741
|
const pages = this.pages();
|
|
@@ -370,8 +743,10 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
370
743
|
if (position === null || position < 0 || position >= pages.length || position === this.state.selectedPage) {
|
|
371
744
|
return;
|
|
372
745
|
}
|
|
746
|
+
this.synchronizeScrollOwnerIdentity(this.state.selectedPage);
|
|
373
747
|
const selectionToken = ++this.selectionRestoreToken;
|
|
374
748
|
const expectedKey = this.pages().map(pageKey)[position];
|
|
749
|
+
if (this.routeTarget && this.routeTarget.key !== expectedKey) this.setRouteTarget(null);
|
|
375
750
|
this.cancelPendingTopFrame();
|
|
376
751
|
this.savePageOffset(this.state.selectedPage);
|
|
377
752
|
if (animated) this.beginPageTransition();else this.finishPageTransition();
|
|
@@ -383,6 +758,9 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
383
758
|
const restore = () => {
|
|
384
759
|
if (this.selectionRestoreToken !== selectionToken || this.state.selectedPage !== position || this.pages().map(pageKey)[position] !== expectedKey || !this.pageScrollElement(position)?.isConnected) return;
|
|
385
760
|
this.configureActiveScrollElement();
|
|
761
|
+
if (this.selectionRestoreToken !== selectionToken || this.routeTarget?.key === expectedKey) {
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
386
764
|
this.restorePageOffset(position);
|
|
387
765
|
};
|
|
388
766
|
if (typeof requestAnimationFrame === "function") {
|
|
@@ -419,7 +797,7 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
419
797
|
const retainedPages = this.mountedPages(pages.length);
|
|
420
798
|
this.props.onCollapsibleStateChanged?.(this.nativeEvent({
|
|
421
799
|
position: this.state.selectedPage,
|
|
422
|
-
headerOffset: Math.min(Math.max(this.pageScrollElement(this.state.selectedPage)?.scrollTop ?? 0, 0),
|
|
800
|
+
headerOffset: Math.min(Math.max(this.pageScrollElement(this.state.selectedPage)?.scrollTop ?? 0, 0), this.headerHeight),
|
|
423
801
|
nativePageCount: pages.length,
|
|
424
802
|
attachedPageCount: retainedPages.length,
|
|
425
803
|
observedScrollableCount: retainedPages.reduce((count, index) => count + (this.pageScrollElement(index) ? 1 : 0), 0),
|
|
@@ -489,6 +867,7 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
489
867
|
externalTopOverlayTag: _externalTopOverlayTag,
|
|
490
868
|
headerHeight: _headerHeight,
|
|
491
869
|
stickyHeaderHeight: _stickyHeaderHeight,
|
|
870
|
+
isActive: _isActive,
|
|
492
871
|
pageRetentionDistance: _pageRetentionDistance,
|
|
493
872
|
layoutDirection: _layoutDirection,
|
|
494
873
|
scrollEnabled: _scrollEnabled,
|
|
@@ -506,15 +885,15 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
506
885
|
const keys = pages.map(pageKey);
|
|
507
886
|
const retained = new Set(this.mountedPages(pages.length));
|
|
508
887
|
const pageWidth = pages.length > 0 ? `${100 / pages.length}%` : "100%";
|
|
509
|
-
const collapseAnimation = {
|
|
510
|
-
"--ok-collapsible-header-height": `${Math.max(0, this.
|
|
888
|
+
const collapseAnimation = this.cssTimelineSupported ? {
|
|
889
|
+
"--ok-collapsible-header-height": `${Math.max(0, this.headerHeight)}px`,
|
|
511
890
|
animationName: COLLAPSE_ANIMATION_NAME,
|
|
512
891
|
animationDuration: "auto",
|
|
513
892
|
animationFillMode: "both",
|
|
514
893
|
animationTimingFunction: "linear",
|
|
515
894
|
animationTimeline: this.timelineName,
|
|
516
|
-
animationRange: `0px ${Math.max(1, this.
|
|
517
|
-
};
|
|
895
|
+
animationRange: `0px ${Math.max(1, this.headerHeight)}px`
|
|
896
|
+
} : undefined;
|
|
518
897
|
const trackStyle = [styles.track, {
|
|
519
898
|
width: `${Math.max(1, pages.length) * 100}%`,
|
|
520
899
|
transform: [{
|
|
@@ -525,23 +904,33 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
525
904
|
}];
|
|
526
905
|
return /*#__PURE__*/_jsxs(View, {
|
|
527
906
|
...viewProps,
|
|
528
|
-
ref:
|
|
529
|
-
|
|
530
|
-
},
|
|
531
|
-
style: [styles.root, {
|
|
907
|
+
ref: this.setRoot,
|
|
908
|
+
style: [styles.root, this.cssTimelineSupported ? {
|
|
532
909
|
timelineScope: this.timelineName
|
|
533
|
-
}, style],
|
|
910
|
+
} : undefined, style],
|
|
534
911
|
children: [/*#__PURE__*/_jsx(View, {
|
|
912
|
+
ref: node => {
|
|
913
|
+
this.headerSlot = webElement(node);
|
|
914
|
+
},
|
|
535
915
|
style: [styles.header, {
|
|
536
|
-
height:
|
|
916
|
+
height: this.headerHeight
|
|
537
917
|
}, collapseAnimation],
|
|
538
|
-
children: header
|
|
918
|
+
children: this.hasExplicitHeaderHeight ? header : /*#__PURE__*/_jsx(View, {
|
|
919
|
+
ref: this.setHeaderContent,
|
|
920
|
+
children: header
|
|
921
|
+
})
|
|
539
922
|
}), /*#__PURE__*/_jsx(View, {
|
|
923
|
+
ref: node => {
|
|
924
|
+
this.stickySlot = webElement(node);
|
|
925
|
+
},
|
|
540
926
|
style: [styles.sticky, {
|
|
541
|
-
top:
|
|
542
|
-
height:
|
|
927
|
+
top: this.headerHeight,
|
|
928
|
+
height: this.stickyHeaderHeight
|
|
543
929
|
}, collapseAnimation],
|
|
544
|
-
children: stickyHeader
|
|
930
|
+
children: this.hasExplicitStickyHeaderHeight ? stickyHeader : /*#__PURE__*/_jsx(View, {
|
|
931
|
+
ref: this.setStickyContent,
|
|
932
|
+
children: stickyHeader
|
|
933
|
+
})
|
|
545
934
|
}), /*#__PURE__*/_jsx(View, {
|
|
546
935
|
ref: this.setTrack,
|
|
547
936
|
style: trackStyle,
|
|
@@ -563,7 +952,18 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
563
952
|
width: pageWidth
|
|
564
953
|
}],
|
|
565
954
|
"aria-hidden": index !== this.state.selectedPage,
|
|
566
|
-
children: retained.has(index) ?
|
|
955
|
+
children: retained.has(index) ? /*#__PURE__*/_jsx(WebCollapsiblePagerPage, {
|
|
956
|
+
pageKey: keys[index],
|
|
957
|
+
isFocused: index === this.state.selectedPage,
|
|
958
|
+
isRouteActive: this.props.isActive !== false,
|
|
959
|
+
headerHeight: this.headerHeight,
|
|
960
|
+
stickyHeaderHeight: this.stickyHeaderHeight,
|
|
961
|
+
onBridge: this.onPageBridge,
|
|
962
|
+
onGeometryChange: this.onPageGeometryChange,
|
|
963
|
+
onScroll: this.onPageScroll,
|
|
964
|
+
onUserInput: this.onPageUserInput,
|
|
965
|
+
children: page
|
|
966
|
+
}) : null
|
|
567
967
|
}, keys[index]))
|
|
568
968
|
})]
|
|
569
969
|
});
|
|
@@ -572,7 +972,7 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
572
972
|
const styles = StyleSheet.create({
|
|
573
973
|
root: {
|
|
574
974
|
flex: 1,
|
|
575
|
-
overflow: "
|
|
975
|
+
overflow: "clip",
|
|
576
976
|
position: "relative"
|
|
577
977
|
},
|
|
578
978
|
header: {
|
|
@@ -588,7 +988,7 @@ const styles = StyleSheet.create({
|
|
|
588
988
|
left: 0,
|
|
589
989
|
right: 0,
|
|
590
990
|
zIndex: 4,
|
|
591
|
-
overflow: "
|
|
991
|
+
overflow: "visible"
|
|
592
992
|
},
|
|
593
993
|
track: {
|
|
594
994
|
position: "absolute",
|