@onekeyfe/react-native-native-list 3.0.152 → 3.0.154
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/onekey/nativelist/NativeListRowView.kt +15 -1
- package/lib/module/NativeList.js +1 -0
- package/lib/module/NativeList.web.js +3 -2
- package/lib/module/web/NativeListWebEngine.js +141 -22
- package/lib/typescript/src/NativeList.types.d.ts +4 -1
- package/lib/typescript/src/web/NativeListWebEngine.d.ts +22 -1
- package/package.json +3 -3
- package/src/NativeList.tsx +1 -0
- package/src/NativeList.types.ts +4 -1
- package/src/NativeList.web.tsx +4 -2
- package/src/web/NativeListWebEngine.ts +226 -33
|
@@ -3417,6 +3417,7 @@ internal class NativeListRowView(
|
|
|
3417
3417
|
val fallbackIcon = if (index == 0) fallbackIconData else null
|
|
3418
3418
|
val expectedEpoch = bindingEpoch
|
|
3419
3419
|
bindImage(source, image, boundKey ?: "", index, variant,
|
|
3420
|
+
round = shape == "circle",
|
|
3420
3421
|
onLoad = if (!ownsSourceFallback) null else ({
|
|
3421
3422
|
if (bindingEpoch == expectedEpoch) {
|
|
3422
3423
|
sourceFallbackKey?.let(NativeListSourceFallbackState::forget)
|
|
@@ -4226,6 +4227,7 @@ internal class NativeListRowView(
|
|
|
4226
4227
|
token: String,
|
|
4227
4228
|
slot: Int,
|
|
4228
4229
|
variant: String,
|
|
4230
|
+
round: Boolean = false,
|
|
4229
4231
|
onLoad: (() -> Unit)? = null,
|
|
4230
4232
|
onError: (() -> Unit)? = null,
|
|
4231
4233
|
hideUntilLoaded: Boolean = false,
|
|
@@ -4263,6 +4265,7 @@ internal class NativeListRowView(
|
|
|
4263
4265
|
autoplay = source.optBoolean("autoplay", false),
|
|
4264
4266
|
recyclingKey = recyclingKey,
|
|
4265
4267
|
optimizeTos = retryAttempt == 0 && source.optBoolean("optimizeTos", true),
|
|
4268
|
+
round = round,
|
|
4266
4269
|
overscan = source.optDouble("overscan", 1.1),
|
|
4267
4270
|
loadingStrategy = source.optString("loadingStrategy", "none"),
|
|
4268
4271
|
placeholderColor = imagePlaceholderColor,
|
|
@@ -4279,7 +4282,18 @@ internal class NativeListRowView(
|
|
|
4279
4282
|
val retry = Runnable {
|
|
4280
4283
|
if (bindingEpoch == expectedEpoch) {
|
|
4281
4284
|
selectorImageRetries.remove(imageView)
|
|
4282
|
-
bindImage(
|
|
4285
|
+
bindImage(
|
|
4286
|
+
source = source,
|
|
4287
|
+
imageView = imageView,
|
|
4288
|
+
token = token,
|
|
4289
|
+
slot = slot,
|
|
4290
|
+
variant = variant,
|
|
4291
|
+
round = round,
|
|
4292
|
+
onLoad = onLoad,
|
|
4293
|
+
onError = onError,
|
|
4294
|
+
hideUntilLoaded = hideUntilLoaded,
|
|
4295
|
+
retryAttempt = retryAttempt + 1,
|
|
4296
|
+
)
|
|
4283
4297
|
}
|
|
4284
4298
|
}
|
|
4285
4299
|
selectorImageRetries[imageView] = retry
|
package/lib/module/NativeList.js
CHANGED
|
@@ -27,6 +27,7 @@ function parsePayload(payloadJson) {
|
|
|
27
27
|
export const NativeList = /*#__PURE__*/forwardRef(function NativeList({
|
|
28
28
|
snapshot,
|
|
29
29
|
webVirtualizationEnabled: _webVirtualizationEnabled,
|
|
30
|
+
webSectionIndexContainerRef: _webSectionIndexContainerRef,
|
|
30
31
|
keyboardDismissMode = 'none',
|
|
31
32
|
keyboardShouldPersistTaps = 'never',
|
|
32
33
|
onRowAction,
|
|
@@ -23,6 +23,7 @@ export function preloadNativeListAvatarImages(sources) {
|
|
|
23
23
|
export const NativeList = /*#__PURE__*/forwardRef(function NativeList({
|
|
24
24
|
snapshot,
|
|
25
25
|
webVirtualizationEnabled = true,
|
|
26
|
+
webSectionIndexContainerRef,
|
|
26
27
|
keyboardDismissMode: _keyboardDismissMode,
|
|
27
28
|
keyboardShouldPersistTaps: _keyboardShouldPersistTaps,
|
|
28
29
|
onRowAction,
|
|
@@ -81,7 +82,7 @@ export const NativeList = /*#__PURE__*/forwardRef(function NativeList({
|
|
|
81
82
|
const didApplyInitialScroll = useRef(false);
|
|
82
83
|
useEffect(() => {
|
|
83
84
|
if (!host) return;
|
|
84
|
-
const engine = new NativeListWebEngine(host, snapshotRef.current, callbacksRef.current, webVirtualizationEnabledRef.current);
|
|
85
|
+
const engine = new NativeListWebEngine(host, snapshotRef.current, callbacksRef.current, webVirtualizationEnabledRef.current, webSectionIndexContainerRef?.current);
|
|
85
86
|
engineRef.current = engine;
|
|
86
87
|
appliedSnapshotRef.current = snapshotRef.current;
|
|
87
88
|
const pending = pendingPatchesRef.current;
|
|
@@ -96,7 +97,7 @@ export const NativeList = /*#__PURE__*/forwardRef(function NativeList({
|
|
|
96
97
|
engine.destroy();
|
|
97
98
|
if (engineRef.current === engine) engineRef.current = undefined;
|
|
98
99
|
};
|
|
99
|
-
}, [host]);
|
|
100
|
+
}, [host, webSectionIndexContainerRef]);
|
|
100
101
|
useEffect(() => {
|
|
101
102
|
engineRef.current?.setVirtualizationEnabled(webVirtualizationEnabled);
|
|
102
103
|
}, [webVirtualizationEnabled]);
|
|
@@ -8,9 +8,14 @@ import { acquireNativeListAvatar, canonicalNativeListAvatarUri } from "./NativeL
|
|
|
8
8
|
const SECTION_INDEX_CONTENT_INSET = 16;
|
|
9
9
|
const SECTION_INDEX_RAIL_WIDTH = 32;
|
|
10
10
|
const SECTION_INDEX_EDGE_PADDING = 8;
|
|
11
|
-
const
|
|
11
|
+
const SECTION_INDEX_MIN_LABEL_SPACING = 16;
|
|
12
|
+
const SECTION_INDEX_CONTAINER_LABEL_SPACING = 22;
|
|
12
13
|
const SECTION_INDEX_MIN_HEIGHT = 120;
|
|
13
14
|
const SECTION_INDEX_WINDOW_Z_INDEX = 100_000;
|
|
15
|
+
const SECTION_INDEX_TRANSFORM_MIN_TRACKING_FRAMES = 12;
|
|
16
|
+
const SECTION_INDEX_TRANSFORM_MAX_TRACKING_FRAMES = 90;
|
|
17
|
+
const SECTION_INDEX_TRANSFORM_SETTLED_FRAMES = 4;
|
|
18
|
+
const SECTION_INDEX_TRANSFORM_SETTLED_EPSILON = 0.0001;
|
|
14
19
|
const DEFAULT_VIEWPORT_WIDTH = 320;
|
|
15
20
|
const DEFAULT_VIEWPORT_HEIGHT = 640;
|
|
16
21
|
const OVERSCAN_VIEWPORTS = 1;
|
|
@@ -54,6 +59,46 @@ const defaultTheme = {
|
|
|
54
59
|
inverseText: '#FCFCFC',
|
|
55
60
|
info: '#0D74CE'
|
|
56
61
|
};
|
|
62
|
+
export function webSectionIndexMetrics(entryCount, viewportHeight, alignStart = false) {
|
|
63
|
+
const availableHeight = Math.max(0, viewportHeight - SECTION_INDEX_EDGE_PADDING * 2);
|
|
64
|
+
const labelSpacing = alignStart ? SECTION_INDEX_CONTAINER_LABEL_SPACING : SECTION_INDEX_MIN_LABEL_SPACING;
|
|
65
|
+
const trackHeight = Math.min(availableHeight, labelSpacing * entryCount);
|
|
66
|
+
return {
|
|
67
|
+
originY: alignStart ? SECTION_INDEX_EDGE_PADDING : (viewportHeight - trackHeight) / 2,
|
|
68
|
+
trackHeight
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export function webSectionIndexContainerLayout(entryCount, containerHeight) {
|
|
72
|
+
const height = Math.min(Math.max(0, containerHeight), SECTION_INDEX_EDGE_PADDING * 2 + SECTION_INDEX_CONTAINER_LABEL_SPACING * entryCount);
|
|
73
|
+
return {
|
|
74
|
+
top: Math.max(0, (containerHeight - height) / 2),
|
|
75
|
+
height
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export function webSectionIndexInverseScale(layoutHeight, renderedHeight) {
|
|
79
|
+
if (layoutHeight <= 0 || renderedHeight <= 0) return 1;
|
|
80
|
+
return layoutHeight / renderedHeight;
|
|
81
|
+
}
|
|
82
|
+
export function webSectionIndexActiveKey(rows, layout, offset, viewportLength) {
|
|
83
|
+
const indexedRows = rows.flatMap((row, index) => row.type === 'sectionHeader' && row.sticky !== false && row.indexTitle ? [{
|
|
84
|
+
key: row.key,
|
|
85
|
+
index
|
|
86
|
+
}] : []);
|
|
87
|
+
const maxOffset = Math.max(0, layout.contentHeight - viewportLength);
|
|
88
|
+
if (maxOffset > 0 && offset >= maxOffset - 1) {
|
|
89
|
+
return indexedRows.at(-1)?.key;
|
|
90
|
+
}
|
|
91
|
+
let activeKey;
|
|
92
|
+
indexedRows.forEach(({
|
|
93
|
+
key,
|
|
94
|
+
index
|
|
95
|
+
}) => {
|
|
96
|
+
if (itemStart(layout.items[index], layout.horizontal) <= offset) {
|
|
97
|
+
activeKey = key;
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
return activeKey;
|
|
101
|
+
}
|
|
57
102
|
/** Resolves every reusable Market geometry field, including legacy defaults. */
|
|
58
103
|
export function resolveWebMarketLayoutStyle(row) {
|
|
59
104
|
const style = row.style;
|
|
@@ -512,7 +557,7 @@ export const WEB_LIST_CSS = `
|
|
|
512
557
|
.ok-native-list-subtitle-segments{display:flex;align-items:center;min-width:0;max-width:100%;height:20px}.ok-native-list-subtitle-segments>.ok-native-list-secondary{flex:0 1 auto;min-width:0}.ok-native-list-subtitle-dot{flex:0 0 4px;width:4px;height:4px;margin:0 6px;border-radius:50%;background:var(--nl-disabled)}.ok-native-list-wallet-row>.ok-native-list-flex{flex:0 1 auto;width:100%;align-items:center}.ok-native-list-wallet-badges{display:flex;gap:4px;justify-content:center;margin-top:4px;height:20px;max-width:100%}.ok-native-list-wallet-badges>.ok-native-list-badge{background:var(--nl-strong);color:var(--nl-secondary);font-size:12px;line-height:16px;height:20px;box-sizing:border-box;padding:2px 4px}.ok-native-list-visual-overlay{position:absolute;display:flex;align-items:center;justify-content:center;box-sizing:border-box;border-radius:50%;overflow:hidden;line-height:1;font-size:10px}.ok-native-list-visual-overlay img,.ok-native-list-visual-overlay svg{width:100%;height:100%;object-fit:contain}
|
|
513
558
|
.ok-native-list-row.ok-native-list-market-skeleton{padding:12px 20px;gap:0}.ok-native-list-skeleton-left{display:flex;align-items:center;gap:12px;flex:1}.ok-native-list-skeleton-text{display:flex;flex-direction:column;gap:4px}.ok-native-list-skeleton-right{display:flex;align-items:center;gap:8px}.ok-native-list-skeleton-mark{display:block;flex-shrink:0;border-radius:8px;animation:ok-native-list-skeleton 1.5s linear infinite alternate}@keyframes ok-native-list-skeleton{from{background-color:var(--nl-skeleton-base)}to{background-color:var(--nl-skeleton-highlight)}}.ok-native-list-market-spinner{display:block;width:20px;height:20px;flex-shrink:0;color:var(--nl-icon);animation:ok-native-list-spin .75s linear infinite}
|
|
514
559
|
@media (prefers-reduced-motion:reduce){.ok-native-list-index-preview,.ok-native-list-refresh{transition:none}.ok-native-list-spinner,.ok-native-list-market-spinner{animation:none}.ok-native-list-skeleton-mark{animation:none;background:var(--nl-skeleton-base)}}
|
|
515
|
-
.ok-native-list-footer{flex:0 0 auto;min-height:0}.ok-native-list-sticky{position:absolute;z-index:4;left:0;right:0;top:0;pointer-events:auto;box-shadow:0 1px 0 var(--nl-separator)}.ok-native-list-viewport-frame:has(>.ok-native-list-index-rail:not([hidden]))>.ok-native-list-viewport,.ok-native-list-viewport-frame[data-section-index-visible="true"]>.ok-native-list-viewport{scrollbar-width:none}.ok-native-list-viewport-frame:has(>.ok-native-list-index-rail:not([hidden]))>.ok-native-list-viewport::-webkit-scrollbar,.ok-native-list-viewport-frame[data-section-index-visible="true"]>.ok-native-list-viewport::-webkit-scrollbar{display:none}.ok-native-list-index-rail{position:absolute;z-index:6;top:0;right:0;bottom:0;width:${SECTION_INDEX_RAIL_WIDTH}px;touch-action:none;cursor:pointer;font-family:Roobert,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}.ok-native-list-index-rail[hidden]{display:none}.ok-native-list-index-button{appearance:none;position:absolute;left:15px;display:flex;width:14px;height:14px;align-items:center;justify-content:center;padding:0;transform:translateY(-50%);border:0;border-radius:7px;background:transparent;color:var(--nl-disabled);font-family:inherit;font-size:10px;font-weight:400;line-height:1;cursor:pointer}.ok-native-list-index-button[data-active="true"]{background:var(--nl-positive);color:var(--nl-inverse-text);font-weight:500}.ok-native-list-index-button:focus-visible{outline:2px solid var(--nl-positive);outline-offset:1px}
|
|
560
|
+
.ok-native-list-footer{flex:0 0 auto;min-height:0}.ok-native-list-sticky{position:absolute;z-index:4;left:0;right:0;top:0;pointer-events:auto;box-shadow:0 1px 0 var(--nl-separator)}.ok-native-list-viewport-frame:has(>.ok-native-list-index-rail:not([hidden]))>.ok-native-list-viewport,.ok-native-list-viewport-frame[data-section-index-visible="true"]>.ok-native-list-viewport{scrollbar-width:none}.ok-native-list-viewport-frame:has(>.ok-native-list-index-rail:not([hidden]))>.ok-native-list-viewport::-webkit-scrollbar,.ok-native-list-viewport-frame[data-section-index-visible="true"]>.ok-native-list-viewport::-webkit-scrollbar{display:none}.ok-native-list-index-rail{position:absolute;z-index:6;top:0;right:0;bottom:0;width:${SECTION_INDEX_RAIL_WIDTH}px;touch-action:none;cursor:pointer;font-family:Roobert,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}.ok-native-list-index-rail[hidden]{display:none}.ok-native-list-index-button{appearance:none;position:absolute;left:15px;display:flex;width:14px;height:14px;align-items:center;justify-content:center;padding:0;transform:translateY(-50%);border:0;border-radius:7px;background:transparent;color:var(--nl-disabled);font-family:inherit;font-size:10px;font-weight:400;line-height:1;cursor:pointer;opacity:.5;transition:opacity .15s ease}.ok-native-list-index-rail:hover .ok-native-list-index-button,.ok-native-list-index-rail:focus-within .ok-native-list-index-button,.ok-native-list-index-button[data-active="true"]{opacity:1}.ok-native-list-index-button[data-active="true"]{background:var(--nl-positive);color:var(--nl-inverse-text);font-weight:500}.ok-native-list-index-button:focus-visible{outline:2px solid var(--nl-positive);outline-offset:1px}
|
|
516
561
|
.ok-native-list-refresh{position:absolute;z-index:7;left:50%;top:8px;display:flex;align-items:center;gap:6px;padding:6px 10px;border-radius:999px;background:var(--nl-inverse);color:var(--nl-inverse-text);font-size:12px;opacity:0;transform:translate(-50%,-16px);transition:opacity .15s ease,transform .15s ease;pointer-events:none}.ok-native-list-refresh[data-visible="true"]{opacity:1;transform:translate(-50%,0)}
|
|
517
562
|
.ok-native-list-warning{height:auto;display:flex;flex-direction:column;align-items:stretch;gap:4px;padding:14px 12px;border-top:1px solid;border-bottom:1px solid;box-sizing:border-box;cursor:default}.ok-native-list-warning-title,.ok-native-list-warning-message{font-size:14px;line-height:20px;white-space:normal;overflow-wrap:anywhere}.ok-native-list-warning-title{font-weight:500;color:var(--nl-primary)}.ok-native-list-warning-message{font-weight:400;color:var(--nl-secondary)}
|
|
518
563
|
.ok-native-list-subtitle-segments{display:flex;align-items:center;min-width:0;max-width:100%;height:20px}.ok-native-list-subtitle-segments>.ok-native-list-secondary{flex:0 1 auto;min-width:0}.ok-native-list-subtitle-dot{flex:0 0 4px;width:4px;height:4px;margin:0 6px;border-radius:50%;background:var(--nl-disabled)}.ok-native-list-wallet-row>.ok-native-list-flex{flex:0 1 auto;width:100%;align-items:center}.ok-native-list-wallet-badges{display:flex;gap:4px;justify-content:center;margin-top:4px;height:20px;max-width:100%}.ok-native-list-wallet-badges>.ok-native-list-badge{background:var(--nl-strong);color:var(--nl-secondary);font-size:12px;line-height:16px;height:20px;box-sizing:border-box;padding:2px 4px}.ok-native-list-visual-overlay{position:absolute;display:flex;align-items:center;justify-content:center;box-sizing:border-box;border-radius:50%;overflow:hidden;line-height:1;font-size:10px}.ok-native-list-visual-overlay img,.ok-native-list-visual-overlay svg{width:100%;height:100%;object-fit:contain}
|
|
@@ -1982,6 +2027,8 @@ export class NativeListWebEngine {
|
|
|
1982
2027
|
};
|
|
1983
2028
|
mounted = new Map();
|
|
1984
2029
|
pool = [];
|
|
2030
|
+
sectionIndexTransformTrackingFrames = 0;
|
|
2031
|
+
sectionIndexTransformSettledFrames = 0;
|
|
1985
2032
|
// OneKey patch: URI leases outlive DOM overscan only inside this bounded window.
|
|
1986
2033
|
avatarLeases = new Map();
|
|
1987
2034
|
avatarOffset = 0;
|
|
@@ -1996,13 +2043,15 @@ export class NativeListWebEngine {
|
|
|
1996
2043
|
lastViewportWidth = -1;
|
|
1997
2044
|
lastViewportHeight = -1;
|
|
1998
2045
|
destroyed = false;
|
|
2046
|
+
sectionIndexAlignStart = false;
|
|
1999
2047
|
// OneKey patch: warning banners are measured after normal browser text wrapping.
|
|
2000
2048
|
measuredWarningHeights = new Map();
|
|
2001
|
-
constructor(host, snapshot, callbacks, virtualizationEnabled = true) {
|
|
2049
|
+
constructor(host, snapshot, callbacks, virtualizationEnabled = true, sectionIndexContainer) {
|
|
2002
2050
|
this.document = host.ownerDocument;
|
|
2003
2051
|
this.snapshot = validateSnapshot(snapshot);
|
|
2004
2052
|
this.callbacks = callbacks;
|
|
2005
2053
|
this.virtualizationEnabled = virtualizationEnabled;
|
|
2054
|
+
this.sectionIndexContainer = sectionIndexContainer ?? undefined;
|
|
2006
2055
|
this.previousHostPosition = host.style.position;
|
|
2007
2056
|
if (!host.style.position) host.style.position = 'relative';
|
|
2008
2057
|
this.root = createElement(this.document, 'div', 'ok-native-list-root');
|
|
@@ -2078,6 +2127,7 @@ export class NativeListWebEngine {
|
|
|
2078
2127
|
} else {
|
|
2079
2128
|
this.document.defaultView?.addEventListener('resize', this.handleWindowResize);
|
|
2080
2129
|
}
|
|
2130
|
+
this.observeSectionIndexTransforms();
|
|
2081
2131
|
this.applySnapshot(this.snapshot);
|
|
2082
2132
|
}
|
|
2083
2133
|
updateCallbacks(callbacks) {
|
|
@@ -2238,8 +2288,10 @@ export class NativeListWebEngine {
|
|
|
2238
2288
|
this.invalidateActionAnchor('destroy');
|
|
2239
2289
|
this.destroyed = true;
|
|
2240
2290
|
if (this.frameHandle !== undefined) this.cancelFrame(this.frameHandle);
|
|
2291
|
+
if (this.sectionIndexTransformFrame !== undefined) this.cancelFrame(this.sectionIndexTransformFrame);
|
|
2241
2292
|
if (this.reorderMovementTimer !== undefined) this.document.defaultView?.clearTimeout(this.reorderMovementTimer);
|
|
2242
2293
|
this.resizeObserver?.disconnect();
|
|
2294
|
+
this.sectionIndexTransformObserver?.disconnect();
|
|
2243
2295
|
this.document.defaultView?.removeEventListener('resize', this.handleWindowResize);
|
|
2244
2296
|
this.viewport.removeEventListener('scroll', this.handleScroll);
|
|
2245
2297
|
this.viewport.removeEventListener('ok-collapsible-pager-insets-changed', this.handleCollapsiblePagerInsetsChanged);
|
|
@@ -2571,7 +2623,7 @@ export class NativeListWebEngine {
|
|
|
2571
2623
|
const {
|
|
2572
2624
|
trackHeight
|
|
2573
2625
|
} = this.sectionIndexMetrics(viewportHeight);
|
|
2574
|
-
const maxVisible = Math.max(1, Math.floor(trackHeight /
|
|
2626
|
+
const maxVisible = Math.max(1, Math.floor(trackHeight / SECTION_INDEX_MIN_LABEL_SPACING));
|
|
2575
2627
|
if (entryCount <= maxVisible) {
|
|
2576
2628
|
return Array.from({
|
|
2577
2629
|
length: entryCount
|
|
@@ -2585,18 +2637,15 @@ export class NativeListWebEngine {
|
|
|
2585
2637
|
return [...result].sort((left, right) => left - right);
|
|
2586
2638
|
}
|
|
2587
2639
|
sectionIndexMetrics(viewportHeight) {
|
|
2588
|
-
|
|
2589
|
-
const trackHeight = Math.min(availableHeight, SECTION_INDEX_LABEL_SPACING * this.sectionIndexEntries.length);
|
|
2590
|
-
return {
|
|
2591
|
-
originY: (viewportHeight - trackHeight) / 2,
|
|
2592
|
-
trackHeight
|
|
2593
|
-
};
|
|
2640
|
+
return webSectionIndexMetrics(this.sectionIndexEntries.length, viewportHeight, this.sectionIndexAlignStart);
|
|
2594
2641
|
}
|
|
2595
2642
|
configureSectionIndexRail(viewportHeight, stickyInset, windowCentered) {
|
|
2596
2643
|
const view = this.document.defaultView;
|
|
2597
2644
|
const direction = view?.getComputedStyle(this.viewportFrame).direction === 'rtl' ? 'rtl' : 'ltr';
|
|
2598
2645
|
this.indexRail.style.direction = direction;
|
|
2599
2646
|
if (!windowCentered) {
|
|
2647
|
+
this.sectionIndexAlignStart = false;
|
|
2648
|
+
this.resetSectionIndexTransformCompensation();
|
|
2600
2649
|
if (this.indexRail.parentElement !== this.viewportFrame) {
|
|
2601
2650
|
this.viewportFrame.appendChild(this.indexRail);
|
|
2602
2651
|
}
|
|
@@ -2611,11 +2660,32 @@ export class NativeListWebEngine {
|
|
|
2611
2660
|
return viewportHeight;
|
|
2612
2661
|
}
|
|
2613
2662
|
if (!view) return viewportHeight;
|
|
2663
|
+
const sectionIndexContainer = this.sectionIndexContainer?.isConnected ? this.sectionIndexContainer : undefined;
|
|
2664
|
+
const frame = this.viewportFrame.getBoundingClientRect();
|
|
2665
|
+
if (sectionIndexContainer) {
|
|
2666
|
+
const container = sectionIndexContainer.getBoundingClientRect();
|
|
2667
|
+
const railLayout = webSectionIndexContainerLayout(this.sectionIndexEntries.length, sectionIndexContainer.clientHeight || container.height);
|
|
2668
|
+
if (this.indexRail.parentElement !== sectionIndexContainer) {
|
|
2669
|
+
sectionIndexContainer.appendChild(this.indexRail);
|
|
2670
|
+
}
|
|
2671
|
+
this.sectionIndexAlignStart = true;
|
|
2672
|
+
this.indexRail.style.position = 'absolute';
|
|
2673
|
+
this.indexRail.style.removeProperty('left');
|
|
2674
|
+
this.indexRail.style.removeProperty('right');
|
|
2675
|
+
this.indexRail.style.insetInlineEnd = String(Math.max(0, direction === 'rtl' ? frame.left - container.left : container.right - frame.right)) + 'px';
|
|
2676
|
+
this.indexRail.style.top = String(railLayout.top) + 'px';
|
|
2677
|
+
this.indexRail.style.bottom = 'auto';
|
|
2678
|
+
this.indexRail.style.height = String(railLayout.height) + 'px';
|
|
2679
|
+
this.indexRail.style.zIndex = String(SECTION_INDEX_WINDOW_Z_INDEX);
|
|
2680
|
+
this.startSectionIndexTransformCompensation();
|
|
2681
|
+
return railLayout.height;
|
|
2682
|
+
}
|
|
2683
|
+
this.sectionIndexAlignStart = false;
|
|
2684
|
+
this.resetSectionIndexTransformCompensation();
|
|
2614
2685
|
const visualViewport = view.visualViewport;
|
|
2615
2686
|
const windowTop = visualViewport?.offsetTop ?? 0;
|
|
2616
2687
|
const windowHeight = visualViewport?.height ?? view.innerHeight;
|
|
2617
|
-
const railHeight = Math.min(windowHeight, SECTION_INDEX_EDGE_PADDING * 2 +
|
|
2618
|
-
const frame = this.viewportFrame.getBoundingClientRect();
|
|
2688
|
+
const railHeight = Math.min(windowHeight, SECTION_INDEX_EDGE_PADDING * 2 + SECTION_INDEX_MIN_LABEL_SPACING * this.sectionIndexEntries.length);
|
|
2619
2689
|
if (this.indexRail.parentElement !== this.document.body) {
|
|
2620
2690
|
this.document.body.appendChild(this.indexRail);
|
|
2621
2691
|
}
|
|
@@ -2629,6 +2699,59 @@ export class NativeListWebEngine {
|
|
|
2629
2699
|
this.indexRail.style.zIndex = String(SECTION_INDEX_WINDOW_Z_INDEX);
|
|
2630
2700
|
return railHeight;
|
|
2631
2701
|
}
|
|
2702
|
+
observeSectionIndexTransforms() {
|
|
2703
|
+
const container = this.sectionIndexContainer;
|
|
2704
|
+
const MutationObserverConstructor = this.document.defaultView?.MutationObserver;
|
|
2705
|
+
if (!container || !MutationObserverConstructor) return;
|
|
2706
|
+
this.sectionIndexTransformObserver = new MutationObserverConstructor(() => this.startSectionIndexTransformCompensation());
|
|
2707
|
+
let element = container;
|
|
2708
|
+
while (element) {
|
|
2709
|
+
this.sectionIndexTransformObserver.observe(element, {
|
|
2710
|
+
attributes: true,
|
|
2711
|
+
attributeFilter: ['style']
|
|
2712
|
+
});
|
|
2713
|
+
if (element === this.document.body) break;
|
|
2714
|
+
element = element.parentElement;
|
|
2715
|
+
}
|
|
2716
|
+
}
|
|
2717
|
+
startSectionIndexTransformCompensation() {
|
|
2718
|
+
this.sectionIndexTransformTrackingFrames = 0;
|
|
2719
|
+
this.sectionIndexTransformSettledFrames = 0;
|
|
2720
|
+
this.updateSectionIndexTransformCompensation();
|
|
2721
|
+
this.scheduleSectionIndexTransformCompensation();
|
|
2722
|
+
}
|
|
2723
|
+
scheduleSectionIndexTransformCompensation() {
|
|
2724
|
+
if (this.destroyed || this.sectionIndexTransformFrame !== undefined || this.indexRail.parentElement !== this.sectionIndexContainer) {
|
|
2725
|
+
return;
|
|
2726
|
+
}
|
|
2727
|
+
this.sectionIndexTransformFrame = this.requestFrame(() => {
|
|
2728
|
+
this.sectionIndexTransformFrame = undefined;
|
|
2729
|
+
const settled = this.updateSectionIndexTransformCompensation();
|
|
2730
|
+
this.sectionIndexTransformTrackingFrames += 1;
|
|
2731
|
+
this.sectionIndexTransformSettledFrames = settled ? this.sectionIndexTransformSettledFrames + 1 : 0;
|
|
2732
|
+
if (this.sectionIndexTransformTrackingFrames < SECTION_INDEX_TRANSFORM_MAX_TRACKING_FRAMES && (this.sectionIndexTransformTrackingFrames < SECTION_INDEX_TRANSFORM_MIN_TRACKING_FRAMES || this.sectionIndexTransformSettledFrames < SECTION_INDEX_TRANSFORM_SETTLED_FRAMES)) {
|
|
2733
|
+
this.scheduleSectionIndexTransformCompensation();
|
|
2734
|
+
}
|
|
2735
|
+
});
|
|
2736
|
+
}
|
|
2737
|
+
updateSectionIndexTransformCompensation() {
|
|
2738
|
+
const container = this.sectionIndexContainer;
|
|
2739
|
+
if (!container || this.indexRail.parentElement !== container) return true;
|
|
2740
|
+
const inverseScale = webSectionIndexInverseScale(container.clientHeight, container.getBoundingClientRect().height);
|
|
2741
|
+
this.indexRail.style.transformOrigin = 'center center';
|
|
2742
|
+
this.indexRail.style.transform = Math.abs(inverseScale - 1) < SECTION_INDEX_TRANSFORM_SETTLED_EPSILON ? 'none' : `scale(${String(inverseScale)})`;
|
|
2743
|
+
return Math.abs(inverseScale - 1) < SECTION_INDEX_TRANSFORM_SETTLED_EPSILON;
|
|
2744
|
+
}
|
|
2745
|
+
resetSectionIndexTransformCompensation() {
|
|
2746
|
+
if (this.sectionIndexTransformFrame !== undefined) {
|
|
2747
|
+
this.cancelFrame(this.sectionIndexTransformFrame);
|
|
2748
|
+
this.sectionIndexTransformFrame = undefined;
|
|
2749
|
+
}
|
|
2750
|
+
this.sectionIndexTransformTrackingFrames = 0;
|
|
2751
|
+
this.sectionIndexTransformSettledFrames = 0;
|
|
2752
|
+
this.indexRail.style.removeProperty('transform');
|
|
2753
|
+
this.indexRail.style.removeProperty('transform-origin');
|
|
2754
|
+
}
|
|
2632
2755
|
renderSectionIndex(viewportHeight, stickyInset) {
|
|
2633
2756
|
this.indexRail.replaceChildren();
|
|
2634
2757
|
if (!sectionIndexEnabled(this.snapshot)) {
|
|
@@ -2654,8 +2777,10 @@ export class NativeListWebEngine {
|
|
|
2654
2777
|
const visibleEntryIndices = this.sectionIndexVisibleEntryIndices(indexLayoutHeight);
|
|
2655
2778
|
setData(this.indexRail, 'compact', visibleEntryIndices.length < this.sectionIndexEntries.length);
|
|
2656
2779
|
const metrics = this.sectionIndexMetrics(indexLayoutHeight);
|
|
2657
|
-
const visibleTrackHeight = Math.min(metrics.trackHeight,
|
|
2658
|
-
const
|
|
2780
|
+
const visibleTrackHeight = Math.min(metrics.trackHeight, SECTION_INDEX_MIN_LABEL_SPACING * visibleEntryIndices.length);
|
|
2781
|
+
const allEntriesVisible = visibleEntryIndices.length === this.sectionIndexEntries.length;
|
|
2782
|
+
const resolvedVisibleTrackHeight = allEntriesVisible ? metrics.trackHeight : visibleTrackHeight;
|
|
2783
|
+
const visibleOriginY = metrics.originY + (metrics.trackHeight - resolvedVisibleTrackHeight) / 2;
|
|
2659
2784
|
const fragment = this.document.createDocumentFragment();
|
|
2660
2785
|
visibleEntryIndices.forEach((entryIndex, visibleIndex) => {
|
|
2661
2786
|
const entry = this.sectionIndexEntries[entryIndex];
|
|
@@ -2666,7 +2791,7 @@ export class NativeListWebEngine {
|
|
|
2666
2791
|
setData(button, 'sectionEntryIndex', entryIndex);
|
|
2667
2792
|
setData(button, 'sectionPosition', entry.position);
|
|
2668
2793
|
setData(button, 'sectionKey', entry.key);
|
|
2669
|
-
button.style.top = String(visibleOriginY +
|
|
2794
|
+
button.style.top = String(visibleOriginY + resolvedVisibleTrackHeight * (visibleIndex + 0.5) / visibleEntryIndices.length) + 'px';
|
|
2670
2795
|
fragment.appendChild(button);
|
|
2671
2796
|
});
|
|
2672
2797
|
this.indexRail.appendChild(fragment);
|
|
@@ -2769,13 +2894,7 @@ export class NativeListWebEngine {
|
|
|
2769
2894
|
|
|
2770
2895
|
// private updateSectionIndex(firstVisibleIndex: number) {
|
|
2771
2896
|
updateSectionIndex() {
|
|
2772
|
-
|
|
2773
|
-
this.snapshot.rows.forEach((row, index) => {
|
|
2774
|
-
if (
|
|
2775
|
-
// OneKey patch: a spacer ending exactly at the viewport is not the active section.
|
|
2776
|
-
// index <= firstVisibleIndex &&
|
|
2777
|
-
itemStart(this.layout.items[index], this.layout.horizontal) <= this.currentOffset() && row.type === 'sectionHeader' && row.sticky !== false && row.indexTitle) activeKey = row.key;
|
|
2778
|
-
});
|
|
2897
|
+
const activeKey = webSectionIndexActiveKey(this.snapshot.rows, this.layout, this.currentOffset(), this.viewportLength());
|
|
2779
2898
|
this.indexRail.querySelectorAll('[data-section-key]').forEach(button => setData(button, 'active', button.dataset.sectionKey === activeKey));
|
|
2780
2899
|
}
|
|
2781
2900
|
checkEndReached(lastVisibleIndex) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
import type { View, ViewProps } from 'react-native';
|
|
2
3
|
import type { ActionAnchorInvalidatedEvent, EndReachedEvent, NativeListSnapshot, ReorderEvent, RowActionEvent, RowModel, RowPatch, SelectionDeltaEvent, VisibleRangeChangedEvent } from './models';
|
|
3
4
|
export type ActionAnchorState = Readonly<{
|
|
4
5
|
token: string;
|
|
@@ -76,6 +77,8 @@ export type NativeListProps = Omit<ViewProps, 'children'> & Readonly<{
|
|
|
76
77
|
snapshot: NativeListSnapshot;
|
|
77
78
|
/** Web only. Defaults to true and is ignored by the native host. */
|
|
78
79
|
webVirtualizationEnabled?: boolean;
|
|
80
|
+
/** Web only. Hosts the section index inside this container. */
|
|
81
|
+
webSectionIndexContainerRef?: RefObject<View | null>;
|
|
79
82
|
/** Defaults to `none`. `interactive` behaves as `none` on Android. */
|
|
80
83
|
keyboardDismissMode?: NativeListKeyboardDismissMode;
|
|
81
84
|
/**
|
|
@@ -22,6 +22,16 @@ export type WebListLayout = Readonly<{
|
|
|
22
22
|
contentHeight: number;
|
|
23
23
|
horizontal: boolean;
|
|
24
24
|
}>;
|
|
25
|
+
export declare function webSectionIndexMetrics(entryCount: number, viewportHeight: number, alignStart?: boolean): {
|
|
26
|
+
originY: number;
|
|
27
|
+
trackHeight: number;
|
|
28
|
+
};
|
|
29
|
+
export declare function webSectionIndexContainerLayout(entryCount: number, containerHeight: number): {
|
|
30
|
+
top: number;
|
|
31
|
+
height: number;
|
|
32
|
+
};
|
|
33
|
+
export declare function webSectionIndexInverseScale(layoutHeight: number, renderedHeight: number): number;
|
|
34
|
+
export declare function webSectionIndexActiveKey(rows: readonly RowModel[], layout: WebListLayout, offset: number, viewportLength: number): string | undefined;
|
|
25
35
|
export type WebMarketLayoutStyle = Readonly<{
|
|
26
36
|
horizontalPadding: number;
|
|
27
37
|
verticalPadding: number;
|
|
@@ -91,6 +101,7 @@ export declare class NativeListWebEngine {
|
|
|
91
101
|
private readonly refreshIndicator;
|
|
92
102
|
private readonly reorderPreview;
|
|
93
103
|
private readonly previousHostPosition;
|
|
104
|
+
private readonly sectionIndexContainer;
|
|
94
105
|
private snapshot;
|
|
95
106
|
private rows;
|
|
96
107
|
private selectedKeys;
|
|
@@ -100,6 +111,10 @@ export declare class NativeListWebEngine {
|
|
|
100
111
|
private readonly pool;
|
|
101
112
|
private frameHandle;
|
|
102
113
|
private resizeObserver;
|
|
114
|
+
private sectionIndexTransformObserver;
|
|
115
|
+
private sectionIndexTransformFrame;
|
|
116
|
+
private sectionIndexTransformTrackingFrames;
|
|
117
|
+
private sectionIndexTransformSettledFrames;
|
|
103
118
|
private pendingScroll;
|
|
104
119
|
private lastVisibleSignature;
|
|
105
120
|
private readonly avatarLeases;
|
|
@@ -130,8 +145,9 @@ export declare class NativeListWebEngine {
|
|
|
130
145
|
private lastViewportWidth;
|
|
131
146
|
private lastViewportHeight;
|
|
132
147
|
private destroyed;
|
|
148
|
+
private sectionIndexAlignStart;
|
|
133
149
|
private measuredWarningHeights;
|
|
134
|
-
constructor(host: HTMLElement, snapshot: NativeListSnapshot, callbacks: NativeListWebCallbacks, virtualizationEnabled?: boolean);
|
|
150
|
+
constructor(host: HTMLElement, snapshot: NativeListSnapshot, callbacks: NativeListWebCallbacks, virtualizationEnabled?: boolean, sectionIndexContainer?: HTMLElement | null);
|
|
135
151
|
updateCallbacks(callbacks: NativeListWebCallbacks): void;
|
|
136
152
|
setVirtualizationEnabled(enabled: boolean): void;
|
|
137
153
|
applySnapshot(snapshot: NativeListSnapshot): void;
|
|
@@ -156,6 +172,11 @@ export declare class NativeListWebEngine {
|
|
|
156
172
|
private sectionIndexVisibleEntryIndices;
|
|
157
173
|
private sectionIndexMetrics;
|
|
158
174
|
private configureSectionIndexRail;
|
|
175
|
+
private observeSectionIndexTransforms;
|
|
176
|
+
private startSectionIndexTransformCompensation;
|
|
177
|
+
private scheduleSectionIndexTransformCompensation;
|
|
178
|
+
private updateSectionIndexTransformCompensation;
|
|
179
|
+
private resetSectionIndexTransformCompensation;
|
|
159
180
|
private renderSectionIndex;
|
|
160
181
|
private updateVisibleSelection;
|
|
161
182
|
private updateVisibleState;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/react-native-native-list",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.154",
|
|
4
4
|
"description": "Template-driven native RecyclerView and UICollectionView for React Native",
|
|
5
5
|
"source": "./src/index.ts",
|
|
6
6
|
"main": "./lib/module/index.js",
|
|
@@ -83,8 +83,8 @@
|
|
|
83
83
|
"typescript": "^5.9.2"
|
|
84
84
|
},
|
|
85
85
|
"peerDependencies": {
|
|
86
|
-
"@onekeyfe/react-native-image": "3.0.
|
|
87
|
-
"@onekeyfe/react-native-native-logger": "3.0.
|
|
86
|
+
"@onekeyfe/react-native-image": "3.0.154",
|
|
87
|
+
"@onekeyfe/react-native-native-logger": "3.0.154",
|
|
88
88
|
"react": "*",
|
|
89
89
|
"react-native": "*",
|
|
90
90
|
"react-native-nitro-modules": "0.37.0"
|
package/src/NativeList.tsx
CHANGED
|
@@ -97,6 +97,7 @@ export const NativeList = forwardRef<NativeListRef, NativeListProps>(
|
|
|
97
97
|
{
|
|
98
98
|
snapshot,
|
|
99
99
|
webVirtualizationEnabled: _webVirtualizationEnabled,
|
|
100
|
+
webSectionIndexContainerRef: _webSectionIndexContainerRef,
|
|
100
101
|
keyboardDismissMode = 'none',
|
|
101
102
|
keyboardShouldPersistTaps = 'never',
|
|
102
103
|
onRowAction,
|
package/src/NativeList.types.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
import type { View, ViewProps } from 'react-native';
|
|
2
3
|
import type {
|
|
3
4
|
ActionAnchorInvalidatedEvent,
|
|
4
5
|
EndReachedEvent,
|
|
@@ -120,6 +121,8 @@ export type NativeListProps = Omit<ViewProps, 'children'> &
|
|
|
120
121
|
snapshot: NativeListSnapshot;
|
|
121
122
|
/** Web only. Defaults to true and is ignored by the native host. */
|
|
122
123
|
webVirtualizationEnabled?: boolean;
|
|
124
|
+
/** Web only. Hosts the section index inside this container. */
|
|
125
|
+
webSectionIndexContainerRef?: RefObject<View | null>;
|
|
123
126
|
/** Defaults to `none`. `interactive` behaves as `none` on Android. */
|
|
124
127
|
keyboardDismissMode?: NativeListKeyboardDismissMode;
|
|
125
128
|
/**
|
package/src/NativeList.web.tsx
CHANGED
|
@@ -83,6 +83,7 @@ export const NativeList = forwardRef<NativeListRef, NativeListProps>(
|
|
|
83
83
|
{
|
|
84
84
|
snapshot,
|
|
85
85
|
webVirtualizationEnabled = true,
|
|
86
|
+
webSectionIndexContainerRef,
|
|
86
87
|
keyboardDismissMode: _keyboardDismissMode,
|
|
87
88
|
keyboardShouldPersistTaps: _keyboardShouldPersistTaps,
|
|
88
89
|
onRowAction,
|
|
@@ -175,7 +176,8 @@ export const NativeList = forwardRef<NativeListRef, NativeListProps>(
|
|
|
175
176
|
host,
|
|
176
177
|
snapshotRef.current,
|
|
177
178
|
callbacksRef.current,
|
|
178
|
-
webVirtualizationEnabledRef.current
|
|
179
|
+
webVirtualizationEnabledRef.current,
|
|
180
|
+
webSectionIndexContainerRef?.current as unknown as HTMLElement | null
|
|
179
181
|
);
|
|
180
182
|
engineRef.current = engine;
|
|
181
183
|
appliedSnapshotRef.current = snapshotRef.current;
|
|
@@ -195,7 +197,7 @@ export const NativeList = forwardRef<NativeListRef, NativeListProps>(
|
|
|
195
197
|
engine.destroy();
|
|
196
198
|
if (engineRef.current === engine) engineRef.current = undefined;
|
|
197
199
|
};
|
|
198
|
-
}, [host]);
|
|
200
|
+
}, [host, webSectionIndexContainerRef]);
|
|
199
201
|
|
|
200
202
|
useEffect(() => {
|
|
201
203
|
engineRef.current?.setVirtualizationEnabled(webVirtualizationEnabled);
|
|
@@ -50,9 +50,14 @@ import {
|
|
|
50
50
|
const SECTION_INDEX_CONTENT_INSET = 16;
|
|
51
51
|
const SECTION_INDEX_RAIL_WIDTH = 32;
|
|
52
52
|
const SECTION_INDEX_EDGE_PADDING = 8;
|
|
53
|
-
const
|
|
53
|
+
const SECTION_INDEX_MIN_LABEL_SPACING = 16;
|
|
54
|
+
const SECTION_INDEX_CONTAINER_LABEL_SPACING = 22;
|
|
54
55
|
const SECTION_INDEX_MIN_HEIGHT = 120;
|
|
55
56
|
const SECTION_INDEX_WINDOW_Z_INDEX = 100_000;
|
|
57
|
+
const SECTION_INDEX_TRANSFORM_MIN_TRACKING_FRAMES = 12;
|
|
58
|
+
const SECTION_INDEX_TRANSFORM_MAX_TRACKING_FRAMES = 90;
|
|
59
|
+
const SECTION_INDEX_TRANSFORM_SETTLED_FRAMES = 4;
|
|
60
|
+
const SECTION_INDEX_TRANSFORM_SETTLED_EPSILON = 0.0001;
|
|
56
61
|
const DEFAULT_VIEWPORT_WIDTH = 320;
|
|
57
62
|
const DEFAULT_VIEWPORT_HEIGHT = 640;
|
|
58
63
|
const OVERSCAN_VIEWPORTS = 1;
|
|
@@ -116,6 +121,74 @@ export type WebListLayout = Readonly<{
|
|
|
116
121
|
horizontal: boolean;
|
|
117
122
|
}>;
|
|
118
123
|
|
|
124
|
+
export function webSectionIndexMetrics(
|
|
125
|
+
entryCount: number,
|
|
126
|
+
viewportHeight: number,
|
|
127
|
+
alignStart = false
|
|
128
|
+
) {
|
|
129
|
+
const availableHeight = Math.max(
|
|
130
|
+
0,
|
|
131
|
+
viewportHeight - SECTION_INDEX_EDGE_PADDING * 2
|
|
132
|
+
);
|
|
133
|
+
const labelSpacing = alignStart
|
|
134
|
+
? SECTION_INDEX_CONTAINER_LABEL_SPACING
|
|
135
|
+
: SECTION_INDEX_MIN_LABEL_SPACING;
|
|
136
|
+
const trackHeight = Math.min(availableHeight, labelSpacing * entryCount);
|
|
137
|
+
return {
|
|
138
|
+
originY: alignStart
|
|
139
|
+
? SECTION_INDEX_EDGE_PADDING
|
|
140
|
+
: (viewportHeight - trackHeight) / 2,
|
|
141
|
+
trackHeight,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function webSectionIndexContainerLayout(
|
|
146
|
+
entryCount: number,
|
|
147
|
+
containerHeight: number
|
|
148
|
+
) {
|
|
149
|
+
const height = Math.min(
|
|
150
|
+
Math.max(0, containerHeight),
|
|
151
|
+
SECTION_INDEX_EDGE_PADDING * 2 +
|
|
152
|
+
SECTION_INDEX_CONTAINER_LABEL_SPACING * entryCount
|
|
153
|
+
);
|
|
154
|
+
return {
|
|
155
|
+
top: Math.max(0, (containerHeight - height) / 2),
|
|
156
|
+
height,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function webSectionIndexInverseScale(
|
|
161
|
+
layoutHeight: number,
|
|
162
|
+
renderedHeight: number
|
|
163
|
+
) {
|
|
164
|
+
if (layoutHeight <= 0 || renderedHeight <= 0) return 1;
|
|
165
|
+
return layoutHeight / renderedHeight;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function webSectionIndexActiveKey(
|
|
169
|
+
rows: readonly RowModel[],
|
|
170
|
+
layout: WebListLayout,
|
|
171
|
+
offset: number,
|
|
172
|
+
viewportLength: number
|
|
173
|
+
): string | undefined {
|
|
174
|
+
const indexedRows = rows.flatMap((row, index) =>
|
|
175
|
+
row.type === 'sectionHeader' && row.sticky !== false && row.indexTitle
|
|
176
|
+
? [{ key: row.key, index }]
|
|
177
|
+
: []
|
|
178
|
+
);
|
|
179
|
+
const maxOffset = Math.max(0, layout.contentHeight - viewportLength);
|
|
180
|
+
if (maxOffset > 0 && offset >= maxOffset - 1) {
|
|
181
|
+
return indexedRows.at(-1)?.key;
|
|
182
|
+
}
|
|
183
|
+
let activeKey: string | undefined;
|
|
184
|
+
indexedRows.forEach(({ key, index }) => {
|
|
185
|
+
if (itemStart(layout.items[index], layout.horizontal) <= offset) {
|
|
186
|
+
activeKey = key;
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
return activeKey;
|
|
190
|
+
}
|
|
191
|
+
|
|
119
192
|
export type WebMarketLayoutStyle = Readonly<{
|
|
120
193
|
horizontalPadding: number;
|
|
121
194
|
verticalPadding: number;
|
|
@@ -940,7 +1013,7 @@ export const WEB_LIST_CSS = `
|
|
|
940
1013
|
.ok-native-list-subtitle-segments{display:flex;align-items:center;min-width:0;max-width:100%;height:20px}.ok-native-list-subtitle-segments>.ok-native-list-secondary{flex:0 1 auto;min-width:0}.ok-native-list-subtitle-dot{flex:0 0 4px;width:4px;height:4px;margin:0 6px;border-radius:50%;background:var(--nl-disabled)}.ok-native-list-wallet-row>.ok-native-list-flex{flex:0 1 auto;width:100%;align-items:center}.ok-native-list-wallet-badges{display:flex;gap:4px;justify-content:center;margin-top:4px;height:20px;max-width:100%}.ok-native-list-wallet-badges>.ok-native-list-badge{background:var(--nl-strong);color:var(--nl-secondary);font-size:12px;line-height:16px;height:20px;box-sizing:border-box;padding:2px 4px}.ok-native-list-visual-overlay{position:absolute;display:flex;align-items:center;justify-content:center;box-sizing:border-box;border-radius:50%;overflow:hidden;line-height:1;font-size:10px}.ok-native-list-visual-overlay img,.ok-native-list-visual-overlay svg{width:100%;height:100%;object-fit:contain}
|
|
941
1014
|
.ok-native-list-row.ok-native-list-market-skeleton{padding:12px 20px;gap:0}.ok-native-list-skeleton-left{display:flex;align-items:center;gap:12px;flex:1}.ok-native-list-skeleton-text{display:flex;flex-direction:column;gap:4px}.ok-native-list-skeleton-right{display:flex;align-items:center;gap:8px}.ok-native-list-skeleton-mark{display:block;flex-shrink:0;border-radius:8px;animation:ok-native-list-skeleton 1.5s linear infinite alternate}@keyframes ok-native-list-skeleton{from{background-color:var(--nl-skeleton-base)}to{background-color:var(--nl-skeleton-highlight)}}.ok-native-list-market-spinner{display:block;width:20px;height:20px;flex-shrink:0;color:var(--nl-icon);animation:ok-native-list-spin .75s linear infinite}
|
|
942
1015
|
@media (prefers-reduced-motion:reduce){.ok-native-list-index-preview,.ok-native-list-refresh{transition:none}.ok-native-list-spinner,.ok-native-list-market-spinner{animation:none}.ok-native-list-skeleton-mark{animation:none;background:var(--nl-skeleton-base)}}
|
|
943
|
-
.ok-native-list-footer{flex:0 0 auto;min-height:0}.ok-native-list-sticky{position:absolute;z-index:4;left:0;right:0;top:0;pointer-events:auto;box-shadow:0 1px 0 var(--nl-separator)}.ok-native-list-viewport-frame:has(>.ok-native-list-index-rail:not([hidden]))>.ok-native-list-viewport,.ok-native-list-viewport-frame[data-section-index-visible="true"]>.ok-native-list-viewport{scrollbar-width:none}.ok-native-list-viewport-frame:has(>.ok-native-list-index-rail:not([hidden]))>.ok-native-list-viewport::-webkit-scrollbar,.ok-native-list-viewport-frame[data-section-index-visible="true"]>.ok-native-list-viewport::-webkit-scrollbar{display:none}.ok-native-list-index-rail{position:absolute;z-index:6;top:0;right:0;bottom:0;width:${SECTION_INDEX_RAIL_WIDTH}px;touch-action:none;cursor:pointer;font-family:Roobert,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}.ok-native-list-index-rail[hidden]{display:none}.ok-native-list-index-button{appearance:none;position:absolute;left:15px;display:flex;width:14px;height:14px;align-items:center;justify-content:center;padding:0;transform:translateY(-50%);border:0;border-radius:7px;background:transparent;color:var(--nl-disabled);font-family:inherit;font-size:10px;font-weight:400;line-height:1;cursor:pointer}.ok-native-list-index-button[data-active="true"]{background:var(--nl-positive);color:var(--nl-inverse-text);font-weight:500}.ok-native-list-index-button:focus-visible{outline:2px solid var(--nl-positive);outline-offset:1px}
|
|
1016
|
+
.ok-native-list-footer{flex:0 0 auto;min-height:0}.ok-native-list-sticky{position:absolute;z-index:4;left:0;right:0;top:0;pointer-events:auto;box-shadow:0 1px 0 var(--nl-separator)}.ok-native-list-viewport-frame:has(>.ok-native-list-index-rail:not([hidden]))>.ok-native-list-viewport,.ok-native-list-viewport-frame[data-section-index-visible="true"]>.ok-native-list-viewport{scrollbar-width:none}.ok-native-list-viewport-frame:has(>.ok-native-list-index-rail:not([hidden]))>.ok-native-list-viewport::-webkit-scrollbar,.ok-native-list-viewport-frame[data-section-index-visible="true"]>.ok-native-list-viewport::-webkit-scrollbar{display:none}.ok-native-list-index-rail{position:absolute;z-index:6;top:0;right:0;bottom:0;width:${SECTION_INDEX_RAIL_WIDTH}px;touch-action:none;cursor:pointer;font-family:Roobert,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}.ok-native-list-index-rail[hidden]{display:none}.ok-native-list-index-button{appearance:none;position:absolute;left:15px;display:flex;width:14px;height:14px;align-items:center;justify-content:center;padding:0;transform:translateY(-50%);border:0;border-radius:7px;background:transparent;color:var(--nl-disabled);font-family:inherit;font-size:10px;font-weight:400;line-height:1;cursor:pointer;opacity:.5;transition:opacity .15s ease}.ok-native-list-index-rail:hover .ok-native-list-index-button,.ok-native-list-index-rail:focus-within .ok-native-list-index-button,.ok-native-list-index-button[data-active="true"]{opacity:1}.ok-native-list-index-button[data-active="true"]{background:var(--nl-positive);color:var(--nl-inverse-text);font-weight:500}.ok-native-list-index-button:focus-visible{outline:2px solid var(--nl-positive);outline-offset:1px}
|
|
944
1017
|
.ok-native-list-refresh{position:absolute;z-index:7;left:50%;top:8px;display:flex;align-items:center;gap:6px;padding:6px 10px;border-radius:999px;background:var(--nl-inverse);color:var(--nl-inverse-text);font-size:12px;opacity:0;transform:translate(-50%,-16px);transition:opacity .15s ease,transform .15s ease;pointer-events:none}.ok-native-list-refresh[data-visible="true"]{opacity:1;transform:translate(-50%,0)}
|
|
945
1018
|
.ok-native-list-warning{height:auto;display:flex;flex-direction:column;align-items:stretch;gap:4px;padding:14px 12px;border-top:1px solid;border-bottom:1px solid;box-sizing:border-box;cursor:default}.ok-native-list-warning-title,.ok-native-list-warning-message{font-size:14px;line-height:20px;white-space:normal;overflow-wrap:anywhere}.ok-native-list-warning-title{font-weight:500;color:var(--nl-primary)}.ok-native-list-warning-message{font-weight:400;color:var(--nl-secondary)}
|
|
946
1019
|
.ok-native-list-subtitle-segments{display:flex;align-items:center;min-width:0;max-width:100%;height:20px}.ok-native-list-subtitle-segments>.ok-native-list-secondary{flex:0 1 auto;min-width:0}.ok-native-list-subtitle-dot{flex:0 0 4px;width:4px;height:4px;margin:0 6px;border-radius:50%;background:var(--nl-disabled)}.ok-native-list-wallet-row>.ok-native-list-flex{flex:0 1 auto;width:100%;align-items:center}.ok-native-list-wallet-badges{display:flex;gap:4px;justify-content:center;margin-top:4px;height:20px;max-width:100%}.ok-native-list-wallet-badges>.ok-native-list-badge{background:var(--nl-strong);color:var(--nl-secondary);font-size:12px;line-height:16px;height:20px;box-sizing:border-box;padding:2px 4px}.ok-native-list-visual-overlay{position:absolute;display:flex;align-items:center;justify-content:center;box-sizing:border-box;border-radius:50%;overflow:hidden;line-height:1;font-size:10px}.ok-native-list-visual-overlay img,.ok-native-list-visual-overlay svg{width:100%;height:100%;object-fit:contain}
|
|
@@ -3469,6 +3542,7 @@ export class NativeListWebEngine {
|
|
|
3469
3542
|
private readonly refreshIndicator: HTMLElement;
|
|
3470
3543
|
private readonly reorderPreview: HTMLElement;
|
|
3471
3544
|
private readonly previousHostPosition: string;
|
|
3545
|
+
private readonly sectionIndexContainer: HTMLElement | undefined;
|
|
3472
3546
|
private snapshot: NativeListSnapshot;
|
|
3473
3547
|
private rows: readonly RowModel[] = [];
|
|
3474
3548
|
private selectedKeys: ReadonlySet<string> = new Set();
|
|
@@ -3483,6 +3557,10 @@ export class NativeListWebEngine {
|
|
|
3483
3557
|
private readonly pool: HTMLElement[] = [];
|
|
3484
3558
|
private frameHandle: number | undefined;
|
|
3485
3559
|
private resizeObserver: ResizeObserver | undefined;
|
|
3560
|
+
private sectionIndexTransformObserver: MutationObserver | undefined;
|
|
3561
|
+
private sectionIndexTransformFrame: number | undefined;
|
|
3562
|
+
private sectionIndexTransformTrackingFrames = 0;
|
|
3563
|
+
private sectionIndexTransformSettledFrames = 0;
|
|
3486
3564
|
private pendingScroll: PendingScroll | undefined;
|
|
3487
3565
|
private lastVisibleSignature: string | undefined;
|
|
3488
3566
|
// OneKey patch: URI leases outlive DOM overscan only inside this bounded window.
|
|
@@ -3528,6 +3606,7 @@ export class NativeListWebEngine {
|
|
|
3528
3606
|
private lastViewportWidth = -1;
|
|
3529
3607
|
private lastViewportHeight = -1;
|
|
3530
3608
|
private destroyed = false;
|
|
3609
|
+
private sectionIndexAlignStart = false;
|
|
3531
3610
|
// OneKey patch: warning banners are measured after normal browser text wrapping.
|
|
3532
3611
|
private measuredWarningHeights = new Map<string, number>();
|
|
3533
3612
|
|
|
@@ -3535,12 +3614,14 @@ export class NativeListWebEngine {
|
|
|
3535
3614
|
host: HTMLElement,
|
|
3536
3615
|
snapshot: NativeListSnapshot,
|
|
3537
3616
|
callbacks: NativeListWebCallbacks,
|
|
3538
|
-
virtualizationEnabled = true
|
|
3617
|
+
virtualizationEnabled = true,
|
|
3618
|
+
sectionIndexContainer?: HTMLElement | null
|
|
3539
3619
|
) {
|
|
3540
3620
|
this.document = host.ownerDocument;
|
|
3541
3621
|
this.snapshot = validateSnapshot(snapshot);
|
|
3542
3622
|
this.callbacks = callbacks;
|
|
3543
3623
|
this.virtualizationEnabled = virtualizationEnabled;
|
|
3624
|
+
this.sectionIndexContainer = sectionIndexContainer ?? undefined;
|
|
3544
3625
|
this.previousHostPosition = host.style.position;
|
|
3545
3626
|
if (!host.style.position) host.style.position = 'relative';
|
|
3546
3627
|
|
|
@@ -3674,6 +3755,7 @@ export class NativeListWebEngine {
|
|
|
3674
3755
|
this.handleWindowResize
|
|
3675
3756
|
);
|
|
3676
3757
|
}
|
|
3758
|
+
this.observeSectionIndexTransforms();
|
|
3677
3759
|
this.applySnapshot(this.snapshot);
|
|
3678
3760
|
}
|
|
3679
3761
|
|
|
@@ -3853,9 +3935,12 @@ export class NativeListWebEngine {
|
|
|
3853
3935
|
this.invalidateActionAnchor('destroy');
|
|
3854
3936
|
this.destroyed = true;
|
|
3855
3937
|
if (this.frameHandle !== undefined) this.cancelFrame(this.frameHandle);
|
|
3938
|
+
if (this.sectionIndexTransformFrame !== undefined)
|
|
3939
|
+
this.cancelFrame(this.sectionIndexTransformFrame);
|
|
3856
3940
|
if (this.reorderMovementTimer !== undefined)
|
|
3857
3941
|
this.document.defaultView?.clearTimeout(this.reorderMovementTimer);
|
|
3858
3942
|
this.resizeObserver?.disconnect();
|
|
3943
|
+
this.sectionIndexTransformObserver?.disconnect();
|
|
3859
3944
|
this.document.defaultView?.removeEventListener(
|
|
3860
3945
|
'resize',
|
|
3861
3946
|
this.handleWindowResize
|
|
@@ -4342,7 +4427,7 @@ export class NativeListWebEngine {
|
|
|
4342
4427
|
const { trackHeight } = this.sectionIndexMetrics(viewportHeight);
|
|
4343
4428
|
const maxVisible = Math.max(
|
|
4344
4429
|
1,
|
|
4345
|
-
Math.floor(trackHeight /
|
|
4430
|
+
Math.floor(trackHeight / SECTION_INDEX_MIN_LABEL_SPACING)
|
|
4346
4431
|
);
|
|
4347
4432
|
if (entryCount <= maxVisible) {
|
|
4348
4433
|
return Array.from({ length: entryCount }, (_, index) => index);
|
|
@@ -4356,18 +4441,11 @@ export class NativeListWebEngine {
|
|
|
4356
4441
|
}
|
|
4357
4442
|
|
|
4358
4443
|
private sectionIndexMetrics(viewportHeight: number) {
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
viewportHeight
|
|
4362
|
-
|
|
4363
|
-
const trackHeight = Math.min(
|
|
4364
|
-
availableHeight,
|
|
4365
|
-
SECTION_INDEX_LABEL_SPACING * this.sectionIndexEntries.length
|
|
4444
|
+
return webSectionIndexMetrics(
|
|
4445
|
+
this.sectionIndexEntries.length,
|
|
4446
|
+
viewportHeight,
|
|
4447
|
+
this.sectionIndexAlignStart
|
|
4366
4448
|
);
|
|
4367
|
-
return {
|
|
4368
|
-
originY: (viewportHeight - trackHeight) / 2,
|
|
4369
|
-
trackHeight,
|
|
4370
|
-
};
|
|
4371
4449
|
}
|
|
4372
4450
|
|
|
4373
4451
|
private configureSectionIndexRail(
|
|
@@ -4382,6 +4460,8 @@ export class NativeListWebEngine {
|
|
|
4382
4460
|
: 'ltr';
|
|
4383
4461
|
this.indexRail.style.direction = direction;
|
|
4384
4462
|
if (!windowCentered) {
|
|
4463
|
+
this.sectionIndexAlignStart = false;
|
|
4464
|
+
this.resetSectionIndexTransformCompensation();
|
|
4385
4465
|
if (this.indexRail.parentElement !== this.viewportFrame) {
|
|
4386
4466
|
this.viewportFrame.appendChild(this.indexRail);
|
|
4387
4467
|
}
|
|
@@ -4397,15 +4477,50 @@ export class NativeListWebEngine {
|
|
|
4397
4477
|
}
|
|
4398
4478
|
|
|
4399
4479
|
if (!view) return viewportHeight;
|
|
4480
|
+
const sectionIndexContainer = this.sectionIndexContainer?.isConnected
|
|
4481
|
+
? this.sectionIndexContainer
|
|
4482
|
+
: undefined;
|
|
4483
|
+
const frame = this.viewportFrame.getBoundingClientRect();
|
|
4484
|
+
if (sectionIndexContainer) {
|
|
4485
|
+
const container = sectionIndexContainer.getBoundingClientRect();
|
|
4486
|
+
const railLayout = webSectionIndexContainerLayout(
|
|
4487
|
+
this.sectionIndexEntries.length,
|
|
4488
|
+
sectionIndexContainer.clientHeight || container.height
|
|
4489
|
+
);
|
|
4490
|
+
if (this.indexRail.parentElement !== sectionIndexContainer) {
|
|
4491
|
+
sectionIndexContainer.appendChild(this.indexRail);
|
|
4492
|
+
}
|
|
4493
|
+
this.sectionIndexAlignStart = true;
|
|
4494
|
+
this.indexRail.style.position = 'absolute';
|
|
4495
|
+
this.indexRail.style.removeProperty('left');
|
|
4496
|
+
this.indexRail.style.removeProperty('right');
|
|
4497
|
+
this.indexRail.style.insetInlineEnd =
|
|
4498
|
+
String(
|
|
4499
|
+
Math.max(
|
|
4500
|
+
0,
|
|
4501
|
+
direction === 'rtl'
|
|
4502
|
+
? frame.left - container.left
|
|
4503
|
+
: container.right - frame.right
|
|
4504
|
+
)
|
|
4505
|
+
) + 'px';
|
|
4506
|
+
this.indexRail.style.top = String(railLayout.top) + 'px';
|
|
4507
|
+
this.indexRail.style.bottom = 'auto';
|
|
4508
|
+
this.indexRail.style.height = String(railLayout.height) + 'px';
|
|
4509
|
+
this.indexRail.style.zIndex = String(SECTION_INDEX_WINDOW_Z_INDEX);
|
|
4510
|
+
this.startSectionIndexTransformCompensation();
|
|
4511
|
+
return railLayout.height;
|
|
4512
|
+
}
|
|
4513
|
+
|
|
4514
|
+
this.sectionIndexAlignStart = false;
|
|
4515
|
+
this.resetSectionIndexTransformCompensation();
|
|
4400
4516
|
const visualViewport = view.visualViewport;
|
|
4401
4517
|
const windowTop = visualViewport?.offsetTop ?? 0;
|
|
4402
4518
|
const windowHeight = visualViewport?.height ?? view.innerHeight;
|
|
4403
4519
|
const railHeight = Math.min(
|
|
4404
4520
|
windowHeight,
|
|
4405
4521
|
SECTION_INDEX_EDGE_PADDING * 2 +
|
|
4406
|
-
|
|
4522
|
+
SECTION_INDEX_MIN_LABEL_SPACING * this.sectionIndexEntries.length
|
|
4407
4523
|
);
|
|
4408
|
-
const frame = this.viewportFrame.getBoundingClientRect();
|
|
4409
4524
|
if (this.indexRail.parentElement !== this.document.body) {
|
|
4410
4525
|
this.document.body.appendChild(this.indexRail);
|
|
4411
4526
|
}
|
|
@@ -4427,6 +4542,86 @@ export class NativeListWebEngine {
|
|
|
4427
4542
|
return railHeight;
|
|
4428
4543
|
}
|
|
4429
4544
|
|
|
4545
|
+
private observeSectionIndexTransforms() {
|
|
4546
|
+
const container = this.sectionIndexContainer;
|
|
4547
|
+
const MutationObserverConstructor =
|
|
4548
|
+
this.document.defaultView?.MutationObserver;
|
|
4549
|
+
if (!container || !MutationObserverConstructor) return;
|
|
4550
|
+
this.sectionIndexTransformObserver = new MutationObserverConstructor(() =>
|
|
4551
|
+
this.startSectionIndexTransformCompensation()
|
|
4552
|
+
);
|
|
4553
|
+
let element: HTMLElement | null = container;
|
|
4554
|
+
while (element) {
|
|
4555
|
+
this.sectionIndexTransformObserver.observe(element, {
|
|
4556
|
+
attributes: true,
|
|
4557
|
+
attributeFilter: ['style'],
|
|
4558
|
+
});
|
|
4559
|
+
if (element === this.document.body) break;
|
|
4560
|
+
element = element.parentElement;
|
|
4561
|
+
}
|
|
4562
|
+
}
|
|
4563
|
+
|
|
4564
|
+
private startSectionIndexTransformCompensation() {
|
|
4565
|
+
this.sectionIndexTransformTrackingFrames = 0;
|
|
4566
|
+
this.sectionIndexTransformSettledFrames = 0;
|
|
4567
|
+
this.updateSectionIndexTransformCompensation();
|
|
4568
|
+
this.scheduleSectionIndexTransformCompensation();
|
|
4569
|
+
}
|
|
4570
|
+
|
|
4571
|
+
private scheduleSectionIndexTransformCompensation() {
|
|
4572
|
+
if (
|
|
4573
|
+
this.destroyed ||
|
|
4574
|
+
this.sectionIndexTransformFrame !== undefined ||
|
|
4575
|
+
this.indexRail.parentElement !== this.sectionIndexContainer
|
|
4576
|
+
) {
|
|
4577
|
+
return;
|
|
4578
|
+
}
|
|
4579
|
+
this.sectionIndexTransformFrame = this.requestFrame(() => {
|
|
4580
|
+
this.sectionIndexTransformFrame = undefined;
|
|
4581
|
+
const settled = this.updateSectionIndexTransformCompensation();
|
|
4582
|
+
this.sectionIndexTransformTrackingFrames += 1;
|
|
4583
|
+
this.sectionIndexTransformSettledFrames = settled
|
|
4584
|
+
? this.sectionIndexTransformSettledFrames + 1
|
|
4585
|
+
: 0;
|
|
4586
|
+
if (
|
|
4587
|
+
this.sectionIndexTransformTrackingFrames <
|
|
4588
|
+
SECTION_INDEX_TRANSFORM_MAX_TRACKING_FRAMES &&
|
|
4589
|
+
(this.sectionIndexTransformTrackingFrames <
|
|
4590
|
+
SECTION_INDEX_TRANSFORM_MIN_TRACKING_FRAMES ||
|
|
4591
|
+
this.sectionIndexTransformSettledFrames <
|
|
4592
|
+
SECTION_INDEX_TRANSFORM_SETTLED_FRAMES)
|
|
4593
|
+
) {
|
|
4594
|
+
this.scheduleSectionIndexTransformCompensation();
|
|
4595
|
+
}
|
|
4596
|
+
});
|
|
4597
|
+
}
|
|
4598
|
+
|
|
4599
|
+
private updateSectionIndexTransformCompensation() {
|
|
4600
|
+
const container = this.sectionIndexContainer;
|
|
4601
|
+
if (!container || this.indexRail.parentElement !== container) return true;
|
|
4602
|
+
const inverseScale = webSectionIndexInverseScale(
|
|
4603
|
+
container.clientHeight,
|
|
4604
|
+
container.getBoundingClientRect().height
|
|
4605
|
+
);
|
|
4606
|
+
this.indexRail.style.transformOrigin = 'center center';
|
|
4607
|
+
this.indexRail.style.transform =
|
|
4608
|
+
Math.abs(inverseScale - 1) < SECTION_INDEX_TRANSFORM_SETTLED_EPSILON
|
|
4609
|
+
? 'none'
|
|
4610
|
+
: `scale(${String(inverseScale)})`;
|
|
4611
|
+
return Math.abs(inverseScale - 1) < SECTION_INDEX_TRANSFORM_SETTLED_EPSILON;
|
|
4612
|
+
}
|
|
4613
|
+
|
|
4614
|
+
private resetSectionIndexTransformCompensation() {
|
|
4615
|
+
if (this.sectionIndexTransformFrame !== undefined) {
|
|
4616
|
+
this.cancelFrame(this.sectionIndexTransformFrame);
|
|
4617
|
+
this.sectionIndexTransformFrame = undefined;
|
|
4618
|
+
}
|
|
4619
|
+
this.sectionIndexTransformTrackingFrames = 0;
|
|
4620
|
+
this.sectionIndexTransformSettledFrames = 0;
|
|
4621
|
+
this.indexRail.style.removeProperty('transform');
|
|
4622
|
+
this.indexRail.style.removeProperty('transform-origin');
|
|
4623
|
+
}
|
|
4624
|
+
|
|
4430
4625
|
private renderSectionIndex(viewportHeight: number, stickyInset: number) {
|
|
4431
4626
|
this.indexRail.replaceChildren();
|
|
4432
4627
|
if (!sectionIndexEnabled(this.snapshot)) {
|
|
@@ -4468,10 +4663,15 @@ export class NativeListWebEngine {
|
|
|
4468
4663
|
const metrics = this.sectionIndexMetrics(indexLayoutHeight);
|
|
4469
4664
|
const visibleTrackHeight = Math.min(
|
|
4470
4665
|
metrics.trackHeight,
|
|
4471
|
-
|
|
4666
|
+
SECTION_INDEX_MIN_LABEL_SPACING * visibleEntryIndices.length
|
|
4472
4667
|
);
|
|
4668
|
+
const allEntriesVisible =
|
|
4669
|
+
visibleEntryIndices.length === this.sectionIndexEntries.length;
|
|
4670
|
+
const resolvedVisibleTrackHeight = allEntriesVisible
|
|
4671
|
+
? metrics.trackHeight
|
|
4672
|
+
: visibleTrackHeight;
|
|
4473
4673
|
const visibleOriginY =
|
|
4474
|
-
metrics.originY + (metrics.trackHeight -
|
|
4674
|
+
metrics.originY + (metrics.trackHeight - resolvedVisibleTrackHeight) / 2;
|
|
4475
4675
|
const fragment = this.document.createDocumentFragment();
|
|
4476
4676
|
visibleEntryIndices.forEach((entryIndex, visibleIndex) => {
|
|
4477
4677
|
const entry = this.sectionIndexEntries[entryIndex];
|
|
@@ -4490,7 +4690,7 @@ export class NativeListWebEngine {
|
|
|
4490
4690
|
button.style.top =
|
|
4491
4691
|
String(
|
|
4492
4692
|
visibleOriginY +
|
|
4493
|
-
(
|
|
4693
|
+
(resolvedVisibleTrackHeight * (visibleIndex + 0.5)) /
|
|
4494
4694
|
visibleEntryIndices.length
|
|
4495
4695
|
) + 'px';
|
|
4496
4696
|
fragment.appendChild(button);
|
|
@@ -4637,19 +4837,12 @@ export class NativeListWebEngine {
|
|
|
4637
4837
|
|
|
4638
4838
|
// private updateSectionIndex(firstVisibleIndex: number) {
|
|
4639
4839
|
private updateSectionIndex() {
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
this.currentOffset() &&
|
|
4647
|
-
row.type === 'sectionHeader' &&
|
|
4648
|
-
row.sticky !== false &&
|
|
4649
|
-
row.indexTitle
|
|
4650
|
-
)
|
|
4651
|
-
activeKey = row.key;
|
|
4652
|
-
});
|
|
4840
|
+
const activeKey = webSectionIndexActiveKey(
|
|
4841
|
+
this.snapshot.rows,
|
|
4842
|
+
this.layout,
|
|
4843
|
+
this.currentOffset(),
|
|
4844
|
+
this.viewportLength()
|
|
4845
|
+
);
|
|
4653
4846
|
this.indexRail
|
|
4654
4847
|
.querySelectorAll<HTMLElement>('[data-section-key]')
|
|
4655
4848
|
.forEach((button) =>
|