@onekeyfe/react-native-native-list 3.0.113 → 3.0.115

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,7 +8,7 @@ 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 SECTION_INDEX_MIN_LABEL_SPACING = 14;
11
+ const SECTION_INDEX_LABEL_SPACING = 16;
12
12
  const SECTION_INDEX_MIN_HEIGHT = 120;
13
13
  const DEFAULT_VIEWPORT_WIDTH = 320;
14
14
  const DEFAULT_VIEWPORT_HEIGHT = 640;
@@ -394,6 +394,17 @@ export function visibleWebLayoutItems(layout, offset, viewportLength, overscan =
394
394
  }
395
395
  return visible;
396
396
  }
397
+ export function resolveWebCollapsiblePagerScrollMetrics(rawOffset, rawViewportLength, headerInset, stickyInset) {
398
+ const header = Math.max(0, headerInset);
399
+ const sticky = Math.max(0, stickyInset);
400
+ return {
401
+ offset: Math.max(0, rawOffset - header),
402
+ viewportLength: Math.max(0, rawViewportLength - sticky)
403
+ };
404
+ }
405
+ export function resolveWebCollapsiblePagerRawOffset(logicalOffset, headerInset) {
406
+ return Math.max(0, logicalOffset) + Math.max(0, headerInset);
407
+ }
397
408
  export function webLayoutItemsForMount(layout, offset, viewportLength, virtualizationEnabled, overscan = 0) {
398
409
  return virtualizationEnabled ? visibleWebLayoutItems(layout, offset, viewportLength, overscan) : layout.items;
399
410
  }
@@ -493,6 +504,11 @@ export const WEB_LIST_CSS = `
493
504
  .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}
494
505
  .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}
495
506
  @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)}}
507
+ .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{scrollbar-width:none}.ok-native-list-viewport-frame:has(>.ok-native-list-index-rail:not([hidden]))>.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}.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}
508
+ .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)}
509
+ .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)}
510
+ .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}
511
+ @media (prefers-reduced-motion:reduce){.ok-native-list-refresh{transition:none}.ok-native-list-spinner{animation:none}}
496
512
  /* OneKey patch: selector controls follow their original semantic colors and geometry. */
497
513
  .ok-native-list-checkbox[data-selector="networkSelector"]{padding:0;border-radius:4px;border-color:var(--nl-checkbox-border,var(--nl-separator));background:var(--nl-checkbox-icon,var(--nl-inverse-text))}
498
514
  .ok-native-list-checkbox[data-selector="networkSelector"]::after{display:none}
@@ -1900,8 +1916,6 @@ export class NativeListWebEngine {
1900
1916
  this.indexRail.setAttribute('role', 'navigation');
1901
1917
  this.indexRail.setAttribute('aria-label', 'Section index');
1902
1918
  this.indexRail.hidden = true;
1903
- this.indexPreview = createElement(this.document, 'div', 'ok-native-list-index-preview');
1904
- this.indexPreview.setAttribute('aria-live', 'polite');
1905
1919
  this.refreshIndicator = createElement(this.document, 'div', 'ok-native-list-refresh', 'Refreshing');
1906
1920
  this.refreshIndicator.setAttribute('role', 'status');
1907
1921
  this.reorderPreview = createElement(this.document, 'div', 'ok-native-list-reorder-preview');
@@ -1909,12 +1923,13 @@ export class NativeListWebEngine {
1909
1923
  this.reorderPreview.setAttribute('aria-hidden', 'true');
1910
1924
  this.document.body.appendChild(this.reorderPreview);
1911
1925
  this.viewport.append(this.content);
1912
- this.viewportFrame.append(this.viewport, this.sticky, this.indexRail, this.indexPreview, this.refreshIndicator);
1926
+ this.viewportFrame.append(this.viewport, this.sticky, this.indexRail, this.refreshIndicator);
1913
1927
  this.root.append(style, this.viewportFrame, this.footer);
1914
1928
  host.appendChild(this.root);
1915
1929
  this.viewport.addEventListener('scroll', this.handleScroll, {
1916
1930
  passive: true
1917
1931
  });
1932
+ this.viewport.addEventListener('ok-collapsible-pager-insets-changed', this.handleCollapsiblePagerInsetsChanged);
1918
1933
  this.root.addEventListener('click', this.handleClick);
1919
1934
  this.root.addEventListener('pointerdown', this.handleMarketPointerDown);
1920
1935
  this.root.addEventListener('pointermove', this.handleMarketPointerMove);
@@ -1941,6 +1956,8 @@ export class NativeListWebEngine {
1941
1956
  this.viewport.addEventListener('touchcancel', this.handleReorderTouchCancel);
1942
1957
  this.indexRail.addEventListener('pointerdown', this.handleIndexPointer);
1943
1958
  this.indexRail.addEventListener('pointermove', this.handleIndexPointer);
1959
+ this.indexRail.addEventListener('pointerup', this.handleIndexPointerEnd);
1960
+ this.indexRail.addEventListener('pointercancel', this.handleIndexPointerEnd);
1944
1961
  this.indexRail.addEventListener('click', this.handleIndexClick);
1945
1962
  this.viewport.addEventListener('pointerdown', this.handlePullStart, {
1946
1963
  passive: true
@@ -2117,11 +2134,11 @@ export class NativeListWebEngine {
2117
2134
  this.invalidateActionAnchor('destroy');
2118
2135
  this.destroyed = true;
2119
2136
  if (this.frameHandle !== undefined) this.cancelFrame(this.frameHandle);
2120
- if (this.previewTimer !== undefined) this.document.defaultView?.clearTimeout(this.previewTimer);
2121
2137
  if (this.reorderMovementTimer !== undefined) this.document.defaultView?.clearTimeout(this.reorderMovementTimer);
2122
2138
  this.resizeObserver?.disconnect();
2123
2139
  this.document.defaultView?.removeEventListener('resize', this.handleWindowResize);
2124
2140
  this.viewport.removeEventListener('scroll', this.handleScroll);
2141
+ this.viewport.removeEventListener('ok-collapsible-pager-insets-changed', this.handleCollapsiblePagerInsetsChanged);
2125
2142
  this.root.removeEventListener('click', this.handleClick);
2126
2143
  this.cancelMarketPointer();
2127
2144
  this.root.removeEventListener('pointerdown', this.handleMarketPointerDown);
@@ -2141,6 +2158,8 @@ export class NativeListWebEngine {
2141
2158
  this.viewport.removeEventListener('touchcancel', this.handleReorderTouchCancel);
2142
2159
  this.indexRail.removeEventListener('pointerdown', this.handleIndexPointer);
2143
2160
  this.indexRail.removeEventListener('pointermove', this.handleIndexPointer);
2161
+ this.indexRail.removeEventListener('pointerup', this.handleIndexPointerEnd);
2162
+ this.indexRail.removeEventListener('pointercancel', this.handleIndexPointerEnd);
2144
2163
  this.indexRail.removeEventListener('click', this.handleIndexClick);
2145
2164
  this.viewport.removeEventListener('pointerdown', this.handlePullStart);
2146
2165
  this.viewport.removeEventListener('pointermove', this.handlePullMove);
@@ -2207,7 +2226,17 @@ export class NativeListWebEngine {
2207
2226
  recomputeLayout = () => {
2208
2227
  if (this.destroyed) return;
2209
2228
  const viewportWidth = this.viewport.clientWidth;
2210
- const viewportHeight = this.viewport.clientHeight;
2229
+ const viewportHeight = this.snapshot.layout.orientation === 'horizontal' ? this.viewport.clientHeight : this.verticalScrollMetrics().viewportLength;
2230
+ if (this.snapshot.layout.orientation !== 'horizontal') {
2231
+ const stickyInset = this.collapsiblePagerInsets().sticky;
2232
+ this.sticky.style.top = String(stickyInset) + 'px';
2233
+ this.indexRail.style.top = String(stickyInset) + 'px';
2234
+ this.refreshIndicator.style.top = String(stickyInset + 8) + 'px';
2235
+ } else {
2236
+ this.sticky.style.top = '0px';
2237
+ this.indexRail.style.top = '0px';
2238
+ this.refreshIndicator.style.top = '8px';
2239
+ }
2211
2240
  if (this.lastViewportWidth >= 0 && (viewportWidth !== this.lastViewportWidth || viewportHeight !== this.lastViewportHeight)) {
2212
2241
  this.invalidateActionAnchor('layout');
2213
2242
  this.measuredWarningHeights.clear();
@@ -2225,7 +2254,7 @@ export class NativeListWebEngine {
2225
2254
  this.layout = computeWebListLayout(measuredSnapshot, viewportWidth, viewportHeight, this.reorderCompactKey);
2226
2255
  this.content.style.width = String(this.layout.contentWidth) + 'px';
2227
2256
  this.content.style.height = String(this.layout.contentHeight) + 'px';
2228
- this.renderSectionIndex(viewportHeight || DEFAULT_VIEWPORT_HEIGHT);
2257
+ this.renderSectionIndex(this.viewport.clientHeight <= 0 ? DEFAULT_VIEWPORT_HEIGHT : Math.max(1, viewportHeight));
2229
2258
  if (previousHorizontal !== this.layout.horizontal) {
2230
2259
  this.viewport.scrollLeft = 0;
2231
2260
  this.viewport.scrollTop = 0;
@@ -2434,19 +2463,30 @@ export class NativeListWebEngine {
2434
2463
  sectionIndexVisibleEntryIndices(viewportHeight) {
2435
2464
  const entryCount = this.sectionIndexEntries.length;
2436
2465
  if (entryCount <= 1) return entryCount ? [0] : [];
2437
- const availableHeight = Math.max(0, viewportHeight - SECTION_INDEX_EDGE_PADDING * 2);
2438
- const maxVisible = Math.max(2, Math.floor(availableHeight / SECTION_INDEX_MIN_LABEL_SPACING) + 1);
2466
+ const {
2467
+ trackHeight
2468
+ } = this.sectionIndexMetrics(viewportHeight);
2469
+ const maxVisible = Math.max(1, Math.floor(trackHeight / SECTION_INDEX_LABEL_SPACING));
2439
2470
  if (entryCount <= maxVisible) {
2440
2471
  return Array.from({
2441
2472
  length: entryCount
2442
2473
  }, (_, index) => index);
2443
2474
  }
2475
+ if (maxVisible === 1) return [0];
2444
2476
  const result = new Set();
2445
2477
  for (let slot = 0; slot < maxVisible; slot += 1) {
2446
2478
  result.add(Math.round(slot * (entryCount - 1) / (maxVisible - 1)));
2447
2479
  }
2448
2480
  return [...result].sort((left, right) => left - right);
2449
2481
  }
2482
+ sectionIndexMetrics(viewportHeight) {
2483
+ const availableHeight = Math.max(0, viewportHeight - SECTION_INDEX_EDGE_PADDING * 2);
2484
+ const trackHeight = Math.min(availableHeight, SECTION_INDEX_LABEL_SPACING * this.sectionIndexEntries.length);
2485
+ return {
2486
+ originY: (viewportHeight - trackHeight) / 2,
2487
+ trackHeight
2488
+ };
2489
+ }
2450
2490
  renderSectionIndex(viewportHeight) {
2451
2491
  this.indexRail.replaceChildren();
2452
2492
  if (!sectionIndexEnabled(this.snapshot)) {
@@ -2465,8 +2505,11 @@ export class NativeListWebEngine {
2465
2505
  }
2466
2506
  const visibleEntryIndices = this.sectionIndexVisibleEntryIndices(viewportHeight);
2467
2507
  setData(this.indexRail, 'compact', visibleEntryIndices.length < this.sectionIndexEntries.length);
2508
+ const metrics = this.sectionIndexMetrics(viewportHeight);
2509
+ const visibleTrackHeight = Math.min(metrics.trackHeight, SECTION_INDEX_LABEL_SPACING * visibleEntryIndices.length);
2510
+ const visibleOriginY = metrics.originY + (metrics.trackHeight - visibleTrackHeight) / 2;
2468
2511
  const fragment = this.document.createDocumentFragment();
2469
- visibleEntryIndices.forEach(entryIndex => {
2512
+ visibleEntryIndices.forEach((entryIndex, visibleIndex) => {
2470
2513
  const entry = this.sectionIndexEntries[entryIndex];
2471
2514
  if (!entry) return;
2472
2515
  const button = createElement(this.document, 'button', 'ok-native-list-index-button', entry.title);
@@ -2475,8 +2518,7 @@ export class NativeListWebEngine {
2475
2518
  setData(button, 'sectionEntryIndex', entryIndex);
2476
2519
  setData(button, 'sectionPosition', entry.position);
2477
2520
  setData(button, 'sectionKey', entry.key);
2478
- const progress = this.sectionIndexEntries.length === 1 ? 0.5 : entryIndex / (this.sectionIndexEntries.length - 1);
2479
- button.style.top = String(SECTION_INDEX_EDGE_PADDING + progress * (viewportHeight - SECTION_INDEX_EDGE_PADDING * 2)) + 'px';
2521
+ button.style.top = String(visibleOriginY + visibleTrackHeight * (visibleIndex + 0.5) / visibleEntryIndices.length) + 'px';
2480
2522
  fragment.appendChild(button);
2481
2523
  });
2482
2524
  this.indexRail.appendChild(fragment);
@@ -2571,7 +2613,7 @@ export class NativeListWebEngine {
2571
2613
  }
2572
2614
  }
2573
2615
  const next = this.layout.items[nextIndex];
2574
- const translate = next ? Math.min(0, next.y - this.viewport.scrollTop - item.height) : 0;
2616
+ const translate = next ? Math.min(0, next.y - this.currentOffset() - item.height) : 0;
2575
2617
  this.sticky.style.transform = 'translate3d(0,' + String(translate) + 'px,0)';
2576
2618
  this.updateVisibleSelection();
2577
2619
  }
@@ -2606,23 +2648,45 @@ export class NativeListWebEngine {
2606
2648
  return viewportLength > 0 && this.layout.items.length > 0;
2607
2649
  }
2608
2650
  viewportLength() {
2609
- return this.layout.horizontal ? this.viewport.clientWidth || DEFAULT_VIEWPORT_WIDTH : this.viewport.clientHeight || DEFAULT_VIEWPORT_HEIGHT;
2651
+ if (this.layout.horizontal) {
2652
+ return this.viewport.clientWidth || DEFAULT_VIEWPORT_WIDTH;
2653
+ }
2654
+ if (this.viewport.clientHeight <= 0) return DEFAULT_VIEWPORT_HEIGHT;
2655
+ return Math.max(1, this.verticalScrollMetrics().viewportLength);
2610
2656
  }
2611
2657
  contentLength() {
2612
2658
  return this.layout.horizontal ? this.layout.contentWidth : this.layout.contentHeight;
2613
2659
  }
2614
2660
  currentOffset() {
2615
- return this.layout.horizontal ? this.viewport.scrollLeft : this.viewport.scrollTop;
2661
+ return this.layout.horizontal ? this.viewport.scrollLeft : this.verticalScrollMetrics().offset;
2662
+ }
2663
+ collapsiblePagerInsets() {
2664
+ const readInset = name => {
2665
+ const parsed = Number.parseFloat(this.viewport.style.getPropertyValue(name));
2666
+ return Number.isFinite(parsed) ? Math.max(0, parsed) : 0;
2667
+ };
2668
+ return {
2669
+ header: readInset('--ok-collapsible-pager-header-inset'),
2670
+ sticky: readInset('--ok-collapsible-pager-sticky-inset')
2671
+ };
2672
+ }
2673
+ verticalScrollMetrics() {
2674
+ const insets = this.collapsiblePagerInsets();
2675
+ return resolveWebCollapsiblePagerScrollMetrics(this.viewport.scrollTop, this.viewport.clientHeight, insets.header, insets.sticky);
2616
2676
  }
2677
+ handleCollapsiblePagerInsetsChanged = () => {
2678
+ this.recomputeLayout();
2679
+ };
2617
2680
  scrollToAbsoluteOffset(offset, animated) {
2618
2681
  const resolved = Math.min(Math.max(0, offset), Math.max(0, this.contentLength() - this.viewportLength()));
2682
+ const rawOffset = this.layout.horizontal ? resolved : resolveWebCollapsiblePagerRawOffset(resolved, this.collapsiblePagerInsets().header);
2619
2683
  this.viewport.scrollTo(this.layout.horizontal ? {
2620
- left: resolved,
2684
+ left: rawOffset,
2621
2685
  top: 0,
2622
2686
  behavior: animated ? 'smooth' : 'auto'
2623
2687
  } : {
2624
2688
  left: 0,
2625
- top: resolved,
2689
+ top: rawOffset,
2626
2690
  behavior: animated ? 'smooth' : 'auto'
2627
2691
  });
2628
2692
  this.scheduleFrame();
@@ -2959,50 +3023,42 @@ export class NativeListWebEngine {
2959
3023
  const view = this.document.defaultView;
2960
3024
  if (view?.cancelAnimationFrame) view.cancelAnimationFrame(handle);else view?.clearTimeout(handle);
2961
3025
  }
2962
- selectIndexPosition(position, title, previewClientY) {
3026
+ selectIndexPosition(position) {
3027
+ const activeKey = this.sectionIndexEntries.find(entry => entry.position === position)?.key;
3028
+ this.indexRail.querySelectorAll('[data-section-key]').forEach(button => setData(button, 'active', button.dataset.sectionKey === activeKey));
2963
3029
  this.scrollToIndex(position, {
2964
3030
  animated: false,
2965
3031
  alignment: 'start',
2966
3032
  viewPosition: 0,
2967
3033
  viewOffset: 0
2968
3034
  });
2969
- const frame = this.viewportFrame.getBoundingClientRect();
2970
- if (previewClientY !== undefined && frame.height > 0) {
2971
- const previewY = Math.min(frame.height - 24, Math.max(24, previewClientY - frame.top));
2972
- this.indexPreview.style.top = String(previewY) + 'px';
2973
- } else {
2974
- this.indexPreview.style.top = '50%';
2975
- }
2976
- this.indexPreview.textContent = title;
2977
- setData(this.indexPreview, 'visible', true);
2978
- if (this.previewTimer !== undefined) this.document.defaultView?.clearTimeout(this.previewTimer);
2979
- this.previewTimer = this.document.defaultView?.setTimeout(() => {
2980
- setData(this.indexPreview, 'visible', false);
2981
- }, 180);
2982
3035
  }
2983
3036
  sectionIndexEntryAtEvent(event) {
2984
3037
  const rail = this.indexRail.getBoundingClientRect();
2985
3038
  if (this.sectionIndexEntries.length === 0 || rail.height <= 0) {
2986
3039
  return undefined;
2987
3040
  }
2988
- const availableHeight = Math.max(1, rail.height - SECTION_INDEX_EDGE_PADDING * 2);
2989
- const progress = Math.min(1, Math.max(0, (event.clientY - rail.top - SECTION_INDEX_EDGE_PADDING) / availableHeight));
2990
- const entryIndex = Math.round(progress * (this.sectionIndexEntries.length - 1));
2991
- const entry = this.sectionIndexEntries[entryIndex];
2992
- return entry ? {
2993
- entry,
2994
- previewClientY: event.clientY
2995
- } : undefined;
3041
+ const metrics = this.sectionIndexMetrics(rail.height);
3042
+ if (metrics.trackHeight <= 0) return undefined;
3043
+ const progress = Math.min(1, Math.max(0, (event.clientY - rail.top - metrics.originY) / metrics.trackHeight));
3044
+ const entryIndex = Math.min(this.sectionIndexEntries.length - 1, Math.floor(progress * this.sectionIndexEntries.length));
3045
+ return this.sectionIndexEntries[entryIndex];
2996
3046
  }
2997
3047
  handleIndexPointer = event => {
2998
3048
  if (event.type === 'pointermove' && event.buttons === 0) return;
2999
- const selection = this.sectionIndexEntryAtEvent(event);
3000
- if (!selection) return;
3049
+ const entry = this.sectionIndexEntryAtEvent(event);
3050
+ if (!entry) return;
3001
3051
  event.preventDefault();
3002
3052
  if (event.type === 'pointerdown') {
3003
3053
  this.indexRail.setPointerCapture?.(event.pointerId);
3004
3054
  }
3005
- this.selectIndexPosition(selection.entry.position, selection.entry.title, selection.previewClientY);
3055
+ this.selectIndexPosition(entry.position);
3056
+ };
3057
+ handleIndexPointerEnd = event => {
3058
+ if (event.type === 'pointerup') {
3059
+ const entry = this.sectionIndexEntryAtEvent(event);
3060
+ if (entry) this.selectIndexPosition(entry.position);
3061
+ }
3006
3062
  };
3007
3063
  handleIndexClick = event => {
3008
3064
  if ('detail' in event && typeof event.detail === 'number' && event.detail > 0) return;
@@ -3012,8 +3068,7 @@ export class NativeListWebEngine {
3012
3068
  if (!button) return;
3013
3069
  const entry = this.sectionIndexEntries[Number(button.dataset.sectionEntryIndex)];
3014
3070
  if (!entry) return;
3015
- const rect = button.getBoundingClientRect();
3016
- this.selectIndexPosition(entry.position, entry.title, rect.top + rect.height / 2);
3071
+ this.selectIndexPosition(entry.position);
3017
3072
  };
3018
3073
  handlePullStart = event => {
3019
3074
  if (this.pointerReorder?.pointerId === event.pointerId || !this.snapshot.capabilities?.pullToRefresh || this.viewport.scrollTop > 0 || event.pointerType !== 'touch' && event.pointerType !== 'pen') return;
@@ -3168,7 +3223,9 @@ export class NativeListWebEngine {
3168
3223
  setCurrentOffset(offset) {
3169
3224
  const maximum = Math.max(0, this.contentLength() - this.viewportLength());
3170
3225
  const next = Math.max(0, Math.min(maximum, offset));
3171
- if (this.layout.horizontal) this.viewport.scrollLeft = next;else this.viewport.scrollTop = next;
3226
+ if (this.layout.horizontal) this.viewport.scrollLeft = next;else {
3227
+ this.viewport.scrollTop = resolveWebCollapsiblePagerRawOffset(next, this.collapsiblePagerInsets().header);
3228
+ }
3172
3229
  this.scheduleFrame();
3173
3230
  }
3174
3231
  showReorderPreview(state) {
@@ -3219,8 +3276,9 @@ export class NativeListWebEngine {
3219
3276
  }
3220
3277
  this.reorderSettlingKey = state.sourceKey;
3221
3278
  const viewportRect = this.viewport.getBoundingClientRect();
3279
+ const insets = this.collapsiblePagerInsets();
3222
3280
  const left = viewportRect.left + destinationLayout.x - this.viewport.scrollLeft;
3223
- const top = viewportRect.top + destinationLayout.y - this.viewport.scrollTop;
3281
+ const top = viewportRect.top + destinationLayout.y + insets.header + insets.sticky - this.viewport.scrollTop;
3224
3282
  this.reorderPreview.getBoundingClientRect();
3225
3283
  this.reorderPreview.style.transition = 'transform ' + String(REORDER_DROP_TRANSITION_MS) + 'ms ' + WEB_REORDER_ANIMATION.dropTimingFunction + ', box-shadow ' + String(REORDER_DROP_TRANSITION_MS) + 'ms ' + WEB_REORDER_ANIMATION.dropTimingFunction;
3226
3284
  this.reorderPreview.style.boxShadow = 'none';
@@ -66,6 +66,12 @@ export declare function estimateWebRowHeight(row: RowModel, snapshot: NativeList
66
66
  export declare function computeWebListLayout(snapshot: NativeListSnapshot, viewportWidth: number, viewportHeight: number, compactRowKey?: string): WebListLayout;
67
67
  export declare function webWalletGroupReorderBadge(row: RowModel): string | undefined;
68
68
  export declare function visibleWebLayoutItems(layout: WebListLayout, offset: number, viewportLength: number, overscan?: number): readonly WebLayoutItem[];
69
+ export type WebCollapsiblePagerScrollMetrics = Readonly<{
70
+ offset: number;
71
+ viewportLength: number;
72
+ }>;
73
+ export declare function resolveWebCollapsiblePagerScrollMetrics(rawOffset: number, rawViewportLength: number, headerInset: number, stickyInset: number): WebCollapsiblePagerScrollMetrics;
74
+ export declare function resolveWebCollapsiblePagerRawOffset(logicalOffset: number, headerInset: number): number;
69
75
  export declare function webLayoutItemsForMount(layout: WebListLayout, offset: number, viewportLength: number, virtualizationEnabled: boolean, overscan?: number): readonly WebLayoutItem[];
70
76
  export declare function webRowRenderSignature(row: RowModel): string;
71
77
  export declare function isWebMarketQuotePatch(patch: RowPatch): boolean;
@@ -81,7 +87,6 @@ export declare class NativeListWebEngine {
81
87
  private readonly footer;
82
88
  private readonly sticky;
83
89
  private readonly indexRail;
84
- private readonly indexPreview;
85
90
  private readonly refreshIndicator;
86
91
  private readonly reorderPreview;
87
92
  private readonly previousHostPosition;
@@ -101,7 +106,6 @@ export declare class NativeListWebEngine {
101
106
  private avatarDirection;
102
107
  private reachedGeneration;
103
108
  private stickyKey;
104
- private previewTimer;
105
109
  private sectionIndexEntries;
106
110
  private pointerReorder;
107
111
  private keyboardReorder;
@@ -149,6 +153,7 @@ export declare class NativeListWebEngine {
149
153
  private renderElement;
150
154
  private renderFooter;
151
155
  private sectionIndexVisibleEntryIndices;
156
+ private sectionIndexMetrics;
152
157
  private renderSectionIndex;
153
158
  private updateVisibleSelection;
154
159
  private updateVisibleState;
@@ -160,6 +165,9 @@ export declare class NativeListWebEngine {
160
165
  private viewportLength;
161
166
  private contentLength;
162
167
  private currentOffset;
168
+ private collapsiblePagerInsets;
169
+ private verticalScrollMetrics;
170
+ private handleCollapsiblePagerInsetsChanged;
163
171
  private scrollToAbsoluteOffset;
164
172
  private performPendingScroll;
165
173
  private rowAtElement;
@@ -193,6 +201,7 @@ export declare class NativeListWebEngine {
193
201
  private selectIndexPosition;
194
202
  private sectionIndexEntryAtEvent;
195
203
  private handleIndexPointer;
204
+ private handleIndexPointerEnd;
196
205
  private handleIndexClick;
197
206
  private handlePullStart;
198
207
  private handlePullMove;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/react-native-native-list",
3
- "version": "3.0.113",
3
+ "version": "3.0.115",
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",
@@ -73,6 +73,7 @@
73
73
  "eslint-config-prettier": "^10.1.8",
74
74
  "eslint-plugin-prettier": "^5.5.4",
75
75
  "jest": "^29.7.0",
76
+ "jsdom": "26.1.0",
76
77
  "nitrogen": "0.37.0",
77
78
  "prettier": "^2.8.8",
78
79
  "react": "19.2.3",
@@ -82,7 +83,8 @@
82
83
  "typescript": "^5.9.2"
83
84
  },
84
85
  "peerDependencies": {
85
- "@onekeyfe/react-native-image": "3.0.113",
86
+ "@onekeyfe/react-native-image": "3.0.115",
87
+ "@onekeyfe/react-native-native-logger": "3.0.115",
86
88
  "react": "*",
87
89
  "react-native": "*",
88
90
  "react-native-nitro-modules": "0.37.0"