@tarojs/components-advanced 4.1.12-beta.6 → 4.1.12-beta.7

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.
@@ -1,8 +1,9 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { View, ScrollView } from '@tarojs/components';
3
3
  import Taro from '@tarojs/taro';
4
- import React from 'react';
4
+ import React, { useContext } from 'react';
5
5
  import { useItemSizeCache } from './hooks/useItemSizeCache.js';
6
+ import { useMeasureStartOffset } from './hooks/useMeasureStartOffset.js';
6
7
  import { useRefresher, DEFAULT_REFRESHER_HEIGHT } from './hooks/useRefresher.js';
7
8
  import { useResizeObserver } from './hooks/useResizeObserver.js';
8
9
  import { useScrollCorrection } from './hooks/useScrollCorrection.js';
@@ -10,7 +11,7 @@ import { ListItem } from './ListItem.js';
10
11
  import { NoMore } from './NoMore.js';
11
12
  import { StickyHeader } from './StickyHeader.js';
12
13
  import { StickySection } from './StickySection.js';
13
- import { isWeapp, isH5, supportsNativeRefresher } from './utils.js';
14
+ import { isH5, isWeapp, supportsNativeRefresher } from './utils.js';
14
15
 
15
16
  // 工具:累加数组
16
17
  function accumulate(arr) {
@@ -42,10 +43,35 @@ function shouldMeasureWeappItem(index, measuredSet) {
42
43
  }
43
44
  // 小程序端暂不外抛 onItemSizeChange,避免父层重渲染导致 List remount 引发回顶或空白
44
45
  function weappDeferItemSizeChange(_index, _size, _onItemSizeChange) { }
46
+ const EMPTY_SCROLL_REF = { current: null };
47
+ /** 任务 4.1/4.2:List 内嵌 WaterFlow/List 时,向子组件提供 scrollRef、containerHeight、startOffset、reportNestedHeightChange */
48
+ const ListScrollElementContext = React.createContext(null);
49
+ /** 抽离 scrollElement 模式逻辑,降低 InnerList 圈复杂度 */
50
+ function useListScrollElement(listType, scrollElement,
51
+ /** 无 Context 时自动测量的 startOffset(上方内容高度),与下方 DOM stacking 对称 */
52
+ measuredStartOffset) {
53
+ var _a, _b;
54
+ const listScrollCtx = useContext(ListScrollElementContext);
55
+ const effectiveScrollElement = scrollElement !== null && scrollElement !== void 0 ? scrollElement : listScrollCtx === null || listScrollCtx === void 0 ? void 0 : listScrollCtx.scrollRef;
56
+ const effectiveStartOffset = (_b = (_a = listScrollCtx === null || listScrollCtx === void 0 ? void 0 : listScrollCtx.startOffset) !== null && _a !== void 0 ? _a : measuredStartOffset) !== null && _b !== void 0 ? _b : 0;
57
+ const useScrollElementMode = listType === 'nested' && !!(effectiveScrollElement && isH5);
58
+ if (listType === 'nested' && !effectiveScrollElement && isH5) {
59
+ // eslint-disable-next-line no-console
60
+ console.warn('[List] type=nested 但无 scrollElement(props 或 Context),回退为 default');
61
+ }
62
+ return { effectiveScrollElement, effectiveStartOffset, useScrollElementMode, hasListScrollCtx: !!listScrollCtx };
63
+ }
45
64
  const InnerList = (props, ref) => {
46
- var _a;
47
- const { stickyHeader = false, space = 0, height = 400, width = '100%', showScrollbar = true, scrollTop: controlledScrollTop, scrollX = false, scrollY = true, onScroll, onScrollToUpper, onScrollToLower, onScrollStart, onScrollEnd, upperThreshold = 50, lowerThreshold = 50, cacheCount = 2, cacheExtent, enableBackToTop, className, style, children, } = props;
65
+ var _a, _b, _c, _d;
66
+ const { stickyHeader = false, space = 0, height = 400, width = '100%', showScrollbar = true, scrollTop: controlledScrollTop, scrollX = false, scrollY = true, onScroll, onScrollToUpper, onScrollToLower, onScrollStart, onScrollEnd, upperThreshold = 50, lowerThreshold = 50, cacheCount = 2, cacheExtent, enableBackToTop, className, style, children, type: listType = 'default', scrollElement, scrollRef: scrollRefProp, } = props;
48
67
  const isHorizontal = scrollX === true;
68
+ const contentWrapperRef = React.useRef(null);
69
+ const result1 = useListScrollElement(listType, scrollElement, 0);
70
+ const measuredStartOffset = useMeasureStartOffset((_a = result1.effectiveScrollElement) !== null && _a !== void 0 ? _a : EMPTY_SCROLL_REF, contentWrapperRef, {
71
+ enabled: result1.useScrollElementMode && !result1.hasListScrollCtx && !!result1.effectiveScrollElement && isH5,
72
+ isHorizontal,
73
+ });
74
+ const { effectiveScrollElement, effectiveStartOffset, useScrollElementMode } = useListScrollElement(listType, scrollElement, measuredStartOffset);
49
75
  const DEFAULT_ITEM_WIDTH = 120;
50
76
  const DEFAULT_ITEM_HEIGHT = 40;
51
77
  // 滚动状态管理
@@ -170,9 +196,23 @@ const InnerList = (props, ref) => {
170
196
  if (!Number.isFinite(targetOffset)) {
171
197
  targetOffset = 0;
172
198
  }
173
- updateRenderOffset(targetOffset, true, 'imperative');
199
+ // 任务 2.2:scrollElement 模式下直接操作外部容器(内嵌时需加上 startOffset)
200
+ const el = effectiveScrollElement === null || effectiveScrollElement === void 0 ? void 0 : effectiveScrollElement.current;
201
+ if (el && isH5) {
202
+ const scrollTarget = targetOffset + effectiveStartOffset;
203
+ if (isHorizontal) {
204
+ el.scrollTo({ left: scrollTarget });
205
+ }
206
+ else {
207
+ el.scrollTo({ top: scrollTarget });
208
+ }
209
+ updateRenderOffset(targetOffset, false, 'scrollElement');
210
+ }
211
+ else {
212
+ updateRenderOffset(targetOffset, true, 'imperative');
213
+ }
174
214
  },
175
- }), [scrollX, updateRenderOffset]);
215
+ }), [scrollX, effectiveScrollElement, effectiveStartOffset, isH5, isHorizontal, updateRenderOffset]);
176
216
  // 提取 Refresher 配置(List 属性为 base,Refresher 子组件覆盖)
177
217
  const refresherConfig = React.useMemo(() => {
178
218
  const listRefresherEnabled = props.refresherEnabled !== false && (props.refresherEnabled === true || props.onRefresherRefresh != null);
@@ -254,7 +294,9 @@ const InnerList = (props, ref) => {
254
294
  return config;
255
295
  }, [children, props.showNoMore, props.noMoreText, props.noMoreStyle, props.renderNoMore]);
256
296
  // Refresher 平台适配:H5 用 addImperativeTouchListeners
257
- const { scrollViewRefresherProps, scrollViewRefresherHandlers, h5RefresherProps, addImperativeTouchListeners, renderRefresherContent, } = useRefresher(refresherConfig, isH5 && refresherConfig && !supportsNativeRefresher ? 0 : renderOffset);
297
+ const { scrollViewRefresherProps, scrollViewRefresherHandlers, h5RefresherProps, addImperativeTouchListeners, renderRefresherContent, } = useRefresher(refresherConfig, isH5 && refresherConfig && !supportsNativeRefresher ? 0 : renderOffset, useScrollElementMode
298
+ ? (ev) => { var _a, _b; return (_b = (ev.target != null && ((_a = contentWrapperRef.current) === null || _a === void 0 ? void 0 : _a.contains(ev.target)))) !== null && _b !== void 0 ? _b : false; }
299
+ : undefined);
258
300
  const refresherTeardownRef = React.useRef(null);
259
301
  const addImperativeTouchListenersRef = React.useRef(addImperativeTouchListeners);
260
302
  addImperativeTouchListenersRef.current = addImperativeTouchListeners;
@@ -296,7 +338,7 @@ const InnerList = (props, ref) => {
296
338
  }, [children]);
297
339
  // 动态尺寸管理
298
340
  const defaultEstimatedSize = isHorizontal ? DEFAULT_ITEM_WIDTH : DEFAULT_ITEM_HEIGHT;
299
- const estimatedSize = (_a = props.estimatedItemSize) !== null && _a !== void 0 ? _a : defaultEstimatedSize;
341
+ const estimatedSize = (_b = props.estimatedItemSize) !== null && _b !== void 0 ? _b : defaultEstimatedSize;
300
342
  // 计算总 item 数量(跨所有 section)
301
343
  const totalItemCount = React.useMemo(() => {
302
344
  return sections.reduce((sum, section) => sum + section.items.length, 0);
@@ -334,6 +376,16 @@ const InnerList = (props, ref) => {
334
376
  updateRenderOffset(newOffset, true, 'scrollCorrection'); // 程序性修正需同步到 ScrollView
335
377
  }
336
378
  });
379
+ const scrollCorrectionRef = React.useRef(scrollCorrection);
380
+ scrollCorrectionRef.current = scrollCorrection;
381
+ const onScrollRef = React.useRef(onScroll);
382
+ onScrollRef.current = onScroll;
383
+ const onScrollToUpperRef = React.useRef(onScrollToUpper);
384
+ onScrollToUpperRef.current = onScrollToUpper;
385
+ const onScrollToLowerRef = React.useRef(onScrollToLower);
386
+ onScrollToLowerRef.current = onScrollToLower;
387
+ const thresholdRef = React.useRef({ upper: upperThreshold, lower: lowerThreshold });
388
+ thresholdRef.current = { upper: upperThreshold, lower: lowerThreshold };
337
389
  // 小程序 + 动高(virtual-list 风格):测量变化后同帧重排,不做程序性 scrollTop 回拉
338
390
  const scheduleWeappDynamicReflow = React.useCallback(() => {
339
391
  if (!isWeapp || props.useResizeObserver !== true)
@@ -564,6 +616,74 @@ const InnerList = (props, ref) => {
564
616
  }
565
617
  onScrollEnd === null || onScrollEnd === void 0 ? void 0 : onScrollEnd();
566
618
  }, [isWeapp, onScrollEnd]);
619
+ // scrollElement 模式:containerLength 从 scrollElement 获取(任务 1.6)
620
+ React.useEffect(() => {
621
+ if (!effectiveScrollElement || !isH5)
622
+ return;
623
+ const el = effectiveScrollElement.current;
624
+ if (!el || typeof ResizeObserver === 'undefined')
625
+ return;
626
+ const update = () => {
627
+ const measured = isHorizontal ? el.clientWidth : el.clientHeight;
628
+ if (measured > 0) {
629
+ setContainerLength(measured);
630
+ }
631
+ // scrollElement 模式下 useLayoutEffect 可能早于 ref 挂载,ResizeObserver 作为兜底确保 scrollRef 正确
632
+ if (scrollRefProp)
633
+ scrollRefProp.current = el;
634
+ };
635
+ update();
636
+ const ro = new ResizeObserver(update);
637
+ ro.observe(el);
638
+ return () => ro.disconnect();
639
+ }, [effectiveScrollElement, isH5, isHorizontal]);
640
+ // scrollElement 模式:监听外部滚动,驱动 renderOffset
641
+ // 使用 ref 保存 scrollCorrection/onScroll,避免每次渲染 deps 变化导致 effect 反复执行形成循环
642
+ const effectiveStartOffsetRef = React.useRef(effectiveStartOffset);
643
+ effectiveStartOffsetRef.current = effectiveStartOffset;
644
+ React.useEffect(() => {
645
+ if (!effectiveScrollElement || !isH5)
646
+ return;
647
+ const el = effectiveScrollElement.current;
648
+ if (!el)
649
+ return;
650
+ const handler = () => {
651
+ var _a, _b, _c;
652
+ const scrollPos = isHorizontal ? el.scrollLeft : el.scrollTop;
653
+ const adjustedPos = scrollPos - effectiveStartOffsetRef.current;
654
+ const clientSize = isHorizontal ? el.clientWidth : el.clientHeight;
655
+ const scrollSize = isHorizontal ? el.scrollWidth : el.scrollHeight;
656
+ scrollCorrectionRef.current.markUserScrolling();
657
+ updateRenderOffset(adjustedPos, false, 'scrollElement');
658
+ (_a = onScrollRef.current) === null || _a === void 0 ? void 0 : _a.call(onScrollRef, {
659
+ scrollTop: isHorizontal ? 0 : scrollPos,
660
+ scrollLeft: isHorizontal ? scrollPos : 0
661
+ });
662
+ // 任务 2.1:onScrollToUpper / onScrollToLower(scrollElement 模式用 adjustedPos,使有上方混排时以 List 顶为基准)
663
+ const { upper, lower } = thresholdRef.current;
664
+ const effectiveAdjusted = Math.max(0, adjustedPos);
665
+ if (effectiveAdjusted <= upper) {
666
+ (_b = onScrollToUpperRef.current) === null || _b === void 0 ? void 0 : _b.call(onScrollToUpperRef);
667
+ }
668
+ if (scrollPos + clientSize >= scrollSize - lower) {
669
+ (_c = onScrollToLowerRef.current) === null || _c === void 0 ? void 0 : _c.call(onScrollToLowerRef);
670
+ }
671
+ };
672
+ // 同步初始 scroll 位置(内嵌时需减去 startOffset)
673
+ const initialScroll = isHorizontal ? el.scrollLeft : el.scrollTop;
674
+ updateRenderOffset(initialScroll - effectiveStartOffsetRef.current, false, 'scrollElement');
675
+ el.addEventListener('scroll', handler, { passive: true });
676
+ return () => el.removeEventListener('scroll', handler);
677
+ }, [effectiveScrollElement, isH5, isHorizontal, updateRenderOffset]);
678
+ // 任务 2.3:暴露 scrollRef 给父组件(供内层 List/WaterFlow 传入 scrollElement)
679
+ // 收敛到此处统一赋值,不再在 ResizeObserver 中重复
680
+ React.useLayoutEffect(() => {
681
+ if (!scrollRefProp)
682
+ return;
683
+ const el = useScrollElementMode ? effectiveScrollElement === null || effectiveScrollElement === void 0 ? void 0 : effectiveScrollElement.current : containerRef.current;
684
+ if (el)
685
+ scrollRefProp.current = el;
686
+ }, [scrollRefProp, useScrollElementMode, effectiveScrollElement]);
567
687
  // controlledScrollTop 变化时同步到 ScrollView
568
688
  React.useEffect(() => {
569
689
  if (typeof controlledScrollTop === 'number') {
@@ -641,19 +761,30 @@ const InnerList = (props, ref) => {
641
761
  }
642
762
  }
643
763
  updateRenderOffset(targetOffset, true, 'scrollIntoView');
764
+ // scrollElement 模式下需显式滚动外部容器,否则仅 updateRenderOffset 不会滚动 div
765
+ if (useScrollElementMode && (effectiveScrollElement === null || effectiveScrollElement === void 0 ? void 0 : effectiveScrollElement.current) && isH5) {
766
+ const el = effectiveScrollElement.current;
767
+ const scrollTarget = targetOffset + effectiveStartOffset;
768
+ if (isHorizontal) {
769
+ el.scrollTo({ left: scrollTarget });
770
+ }
771
+ else {
772
+ el.scrollTo({ top: scrollTarget });
773
+ }
774
+ }
644
775
  }
645
- }, [props.scrollIntoView, totalItemCount, sections, getHeaderSize, getItemSize, space, updateRenderOffset]);
776
+ }, [props.scrollIntoView, totalItemCount, sections, getHeaderSize, getItemSize, space, updateRenderOffset, useScrollElementMode, effectiveScrollElement, effectiveStartOffset, isH5, isHorizontal]);
646
777
  // 容器样式;H5 刷新中禁止滚动
647
778
  const containerStyle = Object.assign(Object.assign({ position: 'relative', boxSizing: 'border-box', height,
648
779
  width }, style), (isH5 && refresherConfig && !supportsNativeRefresher && h5RefresherProps.isRefreshing
649
780
  ? { overflow: 'hidden' }
650
781
  : {}));
651
782
  // ScrollView 属性
652
- const scrollViewProps = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ scrollY: !scrollX && scrollY, scrollX, style: containerStyle, className, enhanced: true, showScrollbar,
783
+ const scrollViewProps = Object.assign(Object.assign(Object.assign(Object.assign({ scrollY: !scrollX && scrollY, scrollX, style: containerStyle, className, enhanced: true, showScrollbar,
653
784
  upperThreshold,
654
785
  lowerThreshold, scrollWithAnimation: false, onScroll: handleScroll, onScrollToUpper,
655
786
  onScrollToLower,
656
- onScrollStart, onScrollEnd: handleNativeScrollEnd, enableBackToTop }, (isWeapp ? { scrollAnchoring: true } : {})), (typeof cacheExtent === 'number' ? { cacheExtent } : {})), { 'data-testid': 'taro-list-container' }), scrollViewRefresherProps), scrollViewRefresherHandlers);
787
+ onScrollStart, onScrollEnd: handleNativeScrollEnd, enableBackToTop }, (isWeapp ? { scrollAnchoring: true } : {})), (typeof cacheExtent === 'number' ? { cacheExtent } : {})), scrollViewRefresherProps), scrollViewRefresherHandlers);
657
788
  // H5 对齐小程序:refresherTriggered=true 时顶部立即显示加载指示器,滚到顶部并锁定滚动直至设为 false
658
789
  React.useEffect(() => {
659
790
  if (!isH5 || !refresherConfig || supportsNativeRefresher || !h5RefresherProps.isRefreshing)
@@ -667,7 +798,7 @@ const InnerList = (props, ref) => {
667
798
  return;
668
799
  let teardown = null;
669
800
  const tryAttach = () => {
670
- const el = containerRef.current;
801
+ const el = useScrollElementMode ? effectiveScrollElement === null || effectiveScrollElement === void 0 ? void 0 : effectiveScrollElement.current : containerRef.current;
671
802
  if (el && !refresherTeardownRef.current) {
672
803
  teardown = attach(el);
673
804
  refresherTeardownRef.current = teardown;
@@ -682,7 +813,7 @@ const InnerList = (props, ref) => {
682
813
  }
683
814
  refresherTeardownRef.current = null;
684
815
  };
685
- }, []);
816
+ }, [useScrollElementMode, effectiveScrollElement]);
686
817
  scrollViewOffsetRef.current = scrollViewOffset;
687
818
  // scrollTop:weapp 传 scrollViewOffset(reflow 帧传 eff 防跳变);H5 仅非用户滑动时传
688
819
  if (isWeapp) {
@@ -1018,10 +1149,79 @@ const InnerList = (props, ref) => {
1018
1149
  innerProps.id = `${listId}-list-item-inner-${currentGlobalIndex}`;
1019
1150
  }
1020
1151
  innerProps['data-index'] = String(currentGlobalIndex);
1021
- nodes.push(React.createElement(View, outerItemProps, React.createElement(View, innerProps, section.items[i])));
1152
+ const itemNode = React.createElement(View, outerItemProps, React.createElement(View, innerProps, section.items[i]));
1153
+ // 任务 4.1:当 List 暴露 scrollRef 时,为每个 item 提供 Context,供内层 WaterFlow 使用
1154
+ const itemWithContext = scrollRefProp && !useScrollElementMode
1155
+ ? React.createElement(ListScrollElementContext.Provider, {
1156
+ key: outerItemProps.key,
1157
+ value: {
1158
+ scrollRef: scrollRefProp,
1159
+ containerHeight: containerLength,
1160
+ startOffset: offset + itemOffsets[i],
1161
+ reportNestedHeightChange: props.useResizeObserver
1162
+ ? (height) => {
1163
+ if (height <= 0)
1164
+ return;
1165
+ const idx = currentGlobalIndex;
1166
+ const estimatedHeader = estimatedSize * 0.5;
1167
+ const fullHeight = height + estimatedHeader;
1168
+ const oldSize = sizeCache.getItemSize(idx);
1169
+ if (Math.abs(oldSize - fullHeight) < 1)
1170
+ return;
1171
+ sizeCache.setItemSize(idx, fullHeight);
1172
+ scrollCorrection.recordSizeChange(idx, oldSize, fullHeight);
1173
+ if (isWeapp && props.useResizeObserver === true) {
1174
+ scheduleWeappDynamicReflow();
1175
+ }
1176
+ else if (sizeCacheRafRef.current == null) {
1177
+ sizeCacheRafRef.current = requestAnimationFrame(() => {
1178
+ sizeCacheRafRef.current = null;
1179
+ setSizeCacheVersion((v) => v + 1);
1180
+ });
1181
+ }
1182
+ }
1183
+ : undefined,
1184
+ },
1185
+ }, itemNode)
1186
+ : itemNode;
1187
+ nodes.push(itemWithContext);
1022
1188
  }
1023
1189
  else {
1024
- nodes.push(React.createElement(View, outerItemProps, section.items[i]));
1190
+ const itemNode = React.createElement(View, outerItemProps, section.items[i]);
1191
+ const itemWithContext = scrollRefProp && !useScrollElementMode
1192
+ ? React.createElement(ListScrollElementContext.Provider, {
1193
+ key: outerItemProps.key,
1194
+ value: {
1195
+ scrollRef: scrollRefProp,
1196
+ containerHeight: containerLength,
1197
+ startOffset: offset + itemOffsets[i],
1198
+ reportNestedHeightChange: props.useResizeObserver
1199
+ ? (height) => {
1200
+ if (height <= 0)
1201
+ return;
1202
+ const idx = currentGlobalIndex;
1203
+ const estimatedHeader = estimatedSize * 0.5;
1204
+ const fullHeight = height + estimatedHeader;
1205
+ const oldSize = sizeCache.getItemSize(idx);
1206
+ if (Math.abs(oldSize - fullHeight) < 1)
1207
+ return;
1208
+ sizeCache.setItemSize(idx, fullHeight);
1209
+ scrollCorrection.recordSizeChange(idx, oldSize, fullHeight);
1210
+ if (isWeapp && props.useResizeObserver === true) {
1211
+ scheduleWeappDynamicReflow();
1212
+ }
1213
+ else if (sizeCacheRafRef.current == null) {
1214
+ sizeCacheRafRef.current = requestAnimationFrame(() => {
1215
+ sizeCacheRafRef.current = null;
1216
+ setSizeCacheVersion((v) => v + 1);
1217
+ });
1218
+ }
1219
+ }
1220
+ : undefined,
1221
+ },
1222
+ }, itemNode)
1223
+ : itemNode;
1224
+ nodes.push(itemWithContext);
1025
1225
  }
1026
1226
  }
1027
1227
  globalItemIndex += section.items.length;
@@ -1038,16 +1238,17 @@ const InnerList = (props, ref) => {
1038
1238
  const defaultStyle = Object.assign(Object.assign(Object.assign({ position: 'absolute' }, (isHorizontal
1039
1239
  ? { left: listContentEnd, top: 0, width: noMoreHeightValue, height: '100%' }
1040
1240
  : { top: listContentEnd, left: 0, width: '100%', height: noMoreHeightValue })), { display: 'flex', alignItems: 'center', justifyContent: 'center', textAlign: 'center', color: '#999', fontSize: '14px', boxSizing: 'border-box' }), noMoreConfig.style);
1041
- return (jsx(View, { style: defaultStyle, "data-testid": "list-nomore", children: noMoreConfig.children || noMoreConfig.text || '没有更多了' }));
1241
+ return (jsx(View, { style: defaultStyle, children: noMoreConfig.children || noMoreConfig.text || '没有更多了' }));
1042
1242
  };
1043
1243
  // 空列表场景:仅显示 NoMore
1044
1244
  if (sections.length === 0 && (noMoreConfig === null || noMoreConfig === void 0 ? void 0 : noMoreConfig.visible)) {
1045
1245
  return (jsx(ScrollView, Object.assign({ ref: containerRef }, scrollViewProps, { children: jsx(View, { style: Object.assign({ minHeight: containerLength, display: 'flex', alignItems: 'center', justifyContent: 'center' }, containerStyle), children: renderNoMoreContent() }) })));
1046
1246
  }
1047
1247
  // 可滚区域总尺寸
1248
+ // H5 refresher 用负 translateY 隐藏,有上方混排时可能延伸到 sibling 区域;overflow:hidden 裁剪避免重叠
1249
+ const needsRefresherClip = refresherHeightForH5 > 0;
1048
1250
  const contentWrapperStyle = isHorizontal
1049
- ? { width: totalLength, position: 'relative', height: '100%' }
1050
- : { height: totalLength, position: 'relative', width: '100%' };
1251
+ ? Object.assign({ width: totalLength, position: 'relative', height: '100%' }, (needsRefresherClip && { overflow: 'hidden' })) : Object.assign({ height: totalLength, position: 'relative', width: '100%' }, (needsRefresherClip && { overflow: 'hidden' }));
1051
1252
  const listWrapperStyle = isHorizontal
1052
1253
  ? { width: listContentLength, position: 'relative', height: '100%' }
1053
1254
  : { height: listContentLength, position: 'relative', width: '100%' };
@@ -1068,9 +1269,21 @@ const InnerList = (props, ref) => {
1068
1269
  transform: `translateY(${h5RefresherTranslateY}px)`,
1069
1270
  }, children: renderRefresherContent() }), jsxs(View, { style: Object.assign(Object.assign(Object.assign({}, listWrapperStyle), pullTranslate), { zIndex: 1, background: (_b = (_a = style === null || style === void 0 ? void 0 : style.background) !== null && _a !== void 0 ? _a : style === null || style === void 0 ? void 0 : style.backgroundColor) !== null && _b !== void 0 ? _b : '#fff' }), children: [stickyHeaderNode, renderSections(), renderNoMoreContent()] })] })) : (jsxs(Fragment, { children: [!supportsNativeRefresher && renderRefresherContent(), stickyHeaderNode, renderSections(), renderNoMoreContent()] })) }));
1070
1271
  };
1272
+ if (useScrollElementMode) {
1273
+ // 任务 2.4:恢复 refresher DOM 结构(refresher 层 + listWrapperStyle)
1274
+ return (jsx(View, { ref: contentWrapperRef, style: contentWrapperStyle, children: refresherHeightForH5 > 0 ? (jsxs(Fragment, { children: [jsx(View, { style: {
1275
+ position: 'absolute',
1276
+ top: 0,
1277
+ left: 0,
1278
+ right: 0,
1279
+ height: refresherHeightForH5,
1280
+ zIndex: 0,
1281
+ transform: `translateY(${h5RefresherTranslateY}px)`,
1282
+ }, children: renderRefresherContent() }), jsxs(View, { style: Object.assign(Object.assign(Object.assign({}, listWrapperStyle), pullTranslate), { zIndex: 1, background: (_d = (_c = style === null || style === void 0 ? void 0 : style.background) !== null && _c !== void 0 ? _c : style === null || style === void 0 ? void 0 : style.backgroundColor) !== null && _d !== void 0 ? _d : '#fff' }), children: [stickyHeaderNode, renderSections(), renderNoMoreContent()] })] })) : (jsxs(Fragment, { children: [stickyHeaderNode, renderSections(), renderNoMoreContent()] })) }));
1283
+ }
1071
1284
  return (jsxs(ScrollView, Object.assign({ ref: containerRef }, scrollViewProps, { id: listId, children: [supportsNativeRefresher && renderRefresherContent(), renderContentArea()] })));
1072
1285
  };
1073
1286
  const List = React.forwardRef(InnerList);
1074
1287
 
1075
- export { List, ListItem, NoMore, StickyHeader, StickySection, accumulate, List as default, isShaking };
1288
+ export { List, ListItem, ListScrollElementContext, NoMore, StickyHeader, StickySection, accumulate, List as default, isShaking };
1076
1289
  //# sourceMappingURL=index.js.map