@legendapp/list 3.0.0-beta.33 → 3.0.0-beta.35

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/index.js CHANGED
@@ -314,8 +314,15 @@ var PositionViewState = typedMemo(function PositionViewState2({
314
314
  };
315
315
  const composed = isArray(style) ? Object.assign({}, ...style) : style;
316
316
  const combinedStyle = horizontal ? { ...base, ...composed, left: position } : { ...base, ...composed, top: position };
317
- const { animatedScrollY, onLayout, index, ...webProps } = props;
318
- return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, ...webProps, style: combinedStyle });
317
+ const {
318
+ animatedScrollY: _animatedScrollY,
319
+ index,
320
+ onLayout: _onLayout,
321
+ onLayoutChange: _onLayoutChange,
322
+ stickyHeaderConfig: _stickyHeaderConfig,
323
+ ...webProps
324
+ } = props;
325
+ return /* @__PURE__ */ React3__namespace.createElement("div", { "data-index": index, ref: refView, ...webProps, style: combinedStyle });
319
326
  });
320
327
  var PositionViewSticky = typedMemo(function PositionViewSticky2({
321
328
  id,
@@ -325,8 +332,10 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
325
332
  index,
326
333
  animatedScrollY: _animatedScrollY,
327
334
  stickyHeaderConfig,
335
+ onLayout: _onLayout,
336
+ onLayoutChange: _onLayoutChange,
328
337
  children,
329
- ...rest
338
+ ...webProps
330
339
  }) {
331
340
  const [position = POSITION_OUT_OF_VIEW, activeStickyIndex] = useArr$([
332
341
  `containerPosition${id}`,
@@ -358,7 +367,7 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
358
367
  }
359
368
  return styleBase;
360
369
  }, [composed, horizontal, position, index, activeStickyIndex, stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset]);
361
- return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
370
+ return /* @__PURE__ */ React3__namespace.createElement("div", { "data-index": index, ref: refView, style: viewStyle, ...webProps }, children);
362
371
  });
363
372
  var PositionView = PositionViewState;
364
373
  function useInit(cb) {
@@ -645,6 +654,7 @@ var Container = typedMemo(function Container2({
645
654
  }) {
646
655
  const ctx = useStateContext();
647
656
  const { columnWrapperStyle, animatedScrollY } = ctx;
657
+ const positionComponentInternal = ctx.state.props.positionComponentInternal;
648
658
  const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
649
659
  const [column = 0, span = 1, data, itemKey, numColumns = 1, extraData, isSticky] = useArr$([
650
660
  `containerColumn${id}`,
@@ -771,7 +781,7 @@ var Container = typedMemo(function Container2({
771
781
  },
772
782
  [itemKey, layoutRenderCount]
773
783
  );
774
- const PositionComponent = isSticky ? stickyPositionComponentInternal ? stickyPositionComponentInternal : PositionViewSticky : PositionView;
784
+ const PositionComponent = isSticky ? stickyPositionComponentInternal ? stickyPositionComponentInternal : PositionViewSticky : positionComponentInternal ? positionComponentInternal : PositionView;
775
785
  return /* @__PURE__ */ React3__namespace.createElement(
776
786
  PositionComponent,
777
787
  {
@@ -791,8 +801,12 @@ var Container = typedMemo(function Container2({
791
801
 
792
802
  // src/utils/reordering.ts
793
803
  var mapFn = (element) => {
794
- const indexStr = element.getAttribute("index");
795
- return [element, indexStr === null ? null : parseInt(indexStr)];
804
+ const indexStr = element.getAttribute("data-index");
805
+ if (indexStr === null) {
806
+ return [element, null];
807
+ }
808
+ const index = Number.parseInt(indexStr, 10);
809
+ return [element, Number.isNaN(index) ? null : index];
796
810
  };
797
811
  function sortDOMElements(container) {
798
812
  const elements = Array.from(container.children);
@@ -972,6 +986,89 @@ var StyleSheet = {
972
986
  flatten: (style) => flattenStyles(style)
973
987
  };
974
988
 
989
+ // src/components/webScrollUtils.ts
990
+ function getDocumentScrollerNode() {
991
+ if (typeof document === "undefined") {
992
+ return null;
993
+ }
994
+ return document.scrollingElement || document.documentElement || document.body;
995
+ }
996
+ function getWindowScrollPosition() {
997
+ var _a3, _b, _c, _d;
998
+ if (typeof window === "undefined") {
999
+ return { x: 0, y: 0 };
1000
+ }
1001
+ return {
1002
+ x: (_b = (_a3 = window.scrollX) != null ? _a3 : window.pageXOffset) != null ? _b : 0,
1003
+ y: (_d = (_c = window.scrollY) != null ? _c : window.pageYOffset) != null ? _d : 0
1004
+ };
1005
+ }
1006
+ function getElementDocumentPosition(element, scroll) {
1007
+ var _a3, _b;
1008
+ const rect = element == null ? void 0 : element.getBoundingClientRect();
1009
+ return {
1010
+ left: ((_a3 = rect == null ? void 0 : rect.left) != null ? _a3 : 0) + scroll.x,
1011
+ top: ((_b = rect == null ? void 0 : rect.top) != null ? _b : 0) + scroll.y
1012
+ };
1013
+ }
1014
+ function getContentSize2(content) {
1015
+ var _a3, _b;
1016
+ return {
1017
+ height: (_a3 = content == null ? void 0 : content.scrollHeight) != null ? _a3 : 0,
1018
+ width: (_b = content == null ? void 0 : content.scrollWidth) != null ? _b : 0
1019
+ };
1020
+ }
1021
+ function getScrollContentSize(scrollElement, contentElement, isWindowScroll) {
1022
+ return getContentSize2(isWindowScroll ? contentElement : scrollElement);
1023
+ }
1024
+ function getLayoutMeasurement(scrollElement, isWindowScroll, horizontal) {
1025
+ var _a3, _b, _c, _d, _e, _f;
1026
+ if (isWindowScroll && typeof window !== "undefined") {
1027
+ const rect = scrollElement == null ? void 0 : scrollElement.getBoundingClientRect();
1028
+ return {
1029
+ // In window-scroll mode, use viewport size on the scroll axis.
1030
+ height: horizontal ? (_b = (_a3 = rect == null ? void 0 : rect.height) != null ? _a3 : scrollElement == null ? void 0 : scrollElement.clientHeight) != null ? _b : window.innerHeight : window.innerHeight,
1031
+ // Keep the cross-axis size list-relative to avoid inflating container measurements.
1032
+ width: horizontal ? window.innerWidth : (_d = (_c = rect == null ? void 0 : rect.width) != null ? _c : scrollElement == null ? void 0 : scrollElement.clientWidth) != null ? _d : window.innerWidth
1033
+ };
1034
+ }
1035
+ return {
1036
+ height: (_e = scrollElement == null ? void 0 : scrollElement.clientHeight) != null ? _e : 0,
1037
+ width: (_f = scrollElement == null ? void 0 : scrollElement.clientWidth) != null ? _f : 0
1038
+ };
1039
+ }
1040
+ function clampOffset(offset, maxOffset) {
1041
+ return Math.max(0, Math.min(offset, maxOffset));
1042
+ }
1043
+ function getAxisSize(size, horizontal) {
1044
+ return horizontal ? size.width : size.height;
1045
+ }
1046
+ function getMaxOffset(contentSize, layoutMeasurement, horizontal) {
1047
+ return Math.max(0, getAxisSize(contentSize, horizontal) - getAxisSize(layoutMeasurement, horizontal));
1048
+ }
1049
+ function resolveScrollableNode(scrollElement, isWindowScroll) {
1050
+ return isWindowScroll ? getDocumentScrollerNode() || scrollElement : scrollElement;
1051
+ }
1052
+ function resolveScrollEventTarget(scrollElement, isWindowScroll) {
1053
+ return isWindowScroll && typeof window !== "undefined" ? window : scrollElement;
1054
+ }
1055
+ function getLayoutRectangle(element, isWindowScroll, horizontal) {
1056
+ const rect = element.getBoundingClientRect();
1057
+ const scroll = getWindowScrollPosition();
1058
+ return {
1059
+ height: isWindowScroll && typeof window !== "undefined" && !horizontal ? window.innerHeight : rect.height,
1060
+ width: isWindowScroll && typeof window !== "undefined" && horizontal ? window.innerWidth : rect.width,
1061
+ x: isWindowScroll ? rect.left + scroll.x : rect.left,
1062
+ y: isWindowScroll ? rect.top + scroll.y : rect.top
1063
+ };
1064
+ }
1065
+ function resolveWindowScrollTarget({ clampedOffset, horizontal, listPos, scroll }) {
1066
+ return {
1067
+ left: horizontal ? listPos.left + clampedOffset : scroll.x,
1068
+ top: horizontal ? scroll.y : listPos.top + clampedOffset
1069
+ };
1070
+ }
1071
+
975
1072
  // src/components/ListComponentScrollView.tsx
976
1073
  var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView2({
977
1074
  children,
@@ -981,114 +1078,163 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
981
1078
  contentOffset,
982
1079
  maintainVisibleContentPosition,
983
1080
  onScroll: onScroll2,
984
- onMomentumScrollEnd,
1081
+ onMomentumScrollEnd: _onMomentumScrollEnd,
985
1082
  showsHorizontalScrollIndicator = true,
986
1083
  showsVerticalScrollIndicator = true,
987
1084
  refreshControl,
1085
+ useWindowScroll = false,
988
1086
  onLayout,
989
1087
  ...props
990
1088
  }, ref) {
991
1089
  const scrollRef = React3.useRef(null);
992
1090
  const contentRef = React3.useRef(null);
1091
+ const isWindowScroll = useWindowScroll;
1092
+ const getScrollTarget = React3.useCallback(
1093
+ () => resolveScrollEventTarget(scrollRef.current, isWindowScroll),
1094
+ [isWindowScroll]
1095
+ );
1096
+ const getMaxScrollOffset = React3.useCallback(() => {
1097
+ const scrollElement = scrollRef.current;
1098
+ const contentSize = getScrollContentSize(scrollElement, contentRef.current, isWindowScroll);
1099
+ const layoutMeasurement = getLayoutMeasurement(scrollElement, isWindowScroll, horizontal);
1100
+ return getMaxOffset(contentSize, layoutMeasurement, horizontal);
1101
+ }, [horizontal, isWindowScroll]);
1102
+ const getCurrentScrollOffset = React3.useCallback(() => {
1103
+ const scrollElement = scrollRef.current;
1104
+ if (isWindowScroll) {
1105
+ const maxOffset = getMaxScrollOffset();
1106
+ const scroll = getWindowScrollPosition();
1107
+ const listPos = getElementDocumentPosition(scrollElement, scroll);
1108
+ const rawOffset = horizontal ? scroll.x - listPos.left : scroll.y - listPos.top;
1109
+ return clampOffset(rawOffset, maxOffset);
1110
+ }
1111
+ if (!scrollElement) {
1112
+ return 0;
1113
+ }
1114
+ return horizontal ? scrollElement.scrollLeft : scrollElement.scrollTop;
1115
+ }, [getMaxScrollOffset, horizontal, isWindowScroll]);
1116
+ const scrollToLocalOffset = React3.useCallback(
1117
+ (offset, animated) => {
1118
+ const scrollElement = scrollRef.current;
1119
+ const target = getScrollTarget();
1120
+ if (!target || typeof target.scrollTo !== "function") {
1121
+ return;
1122
+ }
1123
+ const maxOffset = getMaxScrollOffset();
1124
+ const clampedOffset = clampOffset(offset, maxOffset);
1125
+ const behavior = animated ? "smooth" : "auto";
1126
+ const options = { behavior };
1127
+ if (isWindowScroll) {
1128
+ const scroll = getWindowScrollPosition();
1129
+ const listPos = getElementDocumentPosition(scrollElement, scroll);
1130
+ const { left, top } = resolveWindowScrollTarget({
1131
+ clampedOffset,
1132
+ horizontal,
1133
+ listPos,
1134
+ scroll
1135
+ });
1136
+ options.left = left;
1137
+ options.top = top;
1138
+ } else if (horizontal) {
1139
+ options.left = clampedOffset;
1140
+ } else {
1141
+ options.top = clampedOffset;
1142
+ }
1143
+ target.scrollTo(options);
1144
+ },
1145
+ [getMaxScrollOffset, getScrollTarget, horizontal, isWindowScroll]
1146
+ );
993
1147
  React3.useImperativeHandle(ref, () => {
994
1148
  const api = {
995
1149
  getBoundingClientRect: () => {
996
1150
  var _a3;
997
1151
  return (_a3 = scrollRef.current) == null ? void 0 : _a3.getBoundingClientRect();
998
1152
  },
999
- getScrollableNode: () => scrollRef.current,
1000
- getScrollResponder: () => scrollRef.current,
1153
+ getContentNode: () => contentRef.current,
1154
+ getCurrentScrollOffset,
1155
+ getScrollableNode: () => resolveScrollableNode(scrollRef.current, isWindowScroll),
1156
+ getScrollEventTarget: () => getScrollTarget(),
1157
+ getScrollResponder: () => resolveScrollableNode(scrollRef.current, isWindowScroll),
1158
+ isWindowScroll: () => isWindowScroll,
1001
1159
  scrollBy: (x, y) => {
1002
- const el = scrollRef.current;
1003
- if (!el) return;
1004
- el.scrollBy(x, y);
1160
+ const target = getScrollTarget();
1161
+ if (!target || typeof target.scrollBy !== "function") {
1162
+ return;
1163
+ }
1164
+ target.scrollBy({ behavior: "auto", left: x, top: y });
1005
1165
  },
1006
1166
  scrollTo: (options) => {
1007
- const el = scrollRef.current;
1008
- if (!el) return;
1009
1167
  const { x = 0, y = 0, animated = true } = options;
1010
- el.scrollTo({ behavior: animated ? "smooth" : "auto", left: x, top: y });
1168
+ scrollToLocalOffset(horizontal ? x : y, animated);
1011
1169
  },
1012
1170
  scrollToEnd: (options = {}) => {
1013
- const el = scrollRef.current;
1014
- if (!el) return;
1015
1171
  const { animated = true } = options;
1016
- if (horizontal) {
1017
- el.scrollTo({ behavior: animated ? "smooth" : "auto", left: el.scrollWidth });
1018
- } else {
1019
- el.scrollTo({ behavior: animated ? "smooth" : "auto", top: el.scrollHeight });
1020
- }
1172
+ const endOffset = getMaxScrollOffset();
1173
+ scrollToLocalOffset(endOffset, animated);
1021
1174
  },
1022
1175
  scrollToOffset: (params) => {
1023
- const el = scrollRef.current;
1024
- if (!el) return;
1025
1176
  const { offset, animated = true } = params;
1026
- if (horizontal) {
1027
- el.scrollTo({ behavior: animated ? "smooth" : "auto", left: offset });
1028
- } else {
1029
- el.scrollTo({ behavior: animated ? "smooth" : "auto", top: offset });
1030
- }
1177
+ scrollToLocalOffset(offset, animated);
1031
1178
  }
1032
1179
  };
1033
1180
  return api;
1034
- }, [horizontal]);
1181
+ }, [getCurrentScrollOffset, getMaxScrollOffset, getScrollTarget, horizontal, isWindowScroll, scrollToLocalOffset]);
1035
1182
  const handleScroll = React3.useCallback(
1036
- (event) => {
1037
- if (!onScroll2 || !(event == null ? void 0 : event.target)) {
1183
+ (_event) => {
1184
+ if (!onScroll2) {
1185
+ return;
1186
+ }
1187
+ const target = scrollRef.current;
1188
+ if (!target) {
1038
1189
  return;
1039
1190
  }
1040
- const target = event.target;
1191
+ const contentSize = getContentSize2(contentRef.current);
1192
+ const layoutMeasurement = getLayoutMeasurement(scrollRef.current, isWindowScroll, horizontal);
1193
+ const offset = getCurrentScrollOffset();
1041
1194
  const scrollEvent = {
1042
1195
  nativeEvent: {
1043
1196
  contentOffset: {
1044
- x: target.scrollLeft,
1045
- y: target.scrollTop
1197
+ x: horizontal ? offset : 0,
1198
+ y: horizontal ? 0 : offset
1046
1199
  },
1047
1200
  contentSize: {
1048
- height: target.scrollHeight,
1049
- width: target.scrollWidth
1201
+ height: contentSize.height,
1202
+ width: contentSize.width
1050
1203
  },
1051
1204
  layoutMeasurement: {
1052
- height: target.clientHeight,
1053
- width: target.clientWidth
1205
+ height: layoutMeasurement.height,
1206
+ width: layoutMeasurement.width
1054
1207
  }
1055
1208
  }
1056
1209
  };
1057
1210
  onScroll2(scrollEvent);
1058
1211
  },
1059
- [onScroll2, onMomentumScrollEnd]
1212
+ [getCurrentScrollOffset, horizontal, isWindowScroll, onScroll2]
1060
1213
  );
1061
1214
  React3.useLayoutEffect(() => {
1062
- const element = scrollRef.current;
1063
- if (!element) return;
1064
- element.addEventListener("scroll", handleScroll);
1215
+ const target = getScrollTarget();
1216
+ if (!target) return;
1217
+ target.addEventListener("scroll", handleScroll, { passive: true });
1065
1218
  return () => {
1066
- element.removeEventListener("scroll", handleScroll);
1219
+ target.removeEventListener("scroll", handleScroll);
1067
1220
  };
1068
- }, [handleScroll]);
1221
+ }, [getScrollTarget, handleScroll]);
1069
1222
  React3.useEffect(() => {
1070
1223
  const doScroll = () => {
1071
- if (contentOffset && scrollRef.current) {
1072
- scrollRef.current.scrollLeft = contentOffset.x || 0;
1073
- scrollRef.current.scrollTop = contentOffset.y || 0;
1224
+ if (contentOffset) {
1225
+ scrollToLocalOffset(horizontal ? contentOffset.x || 0 : contentOffset.y || 0, false);
1074
1226
  }
1075
1227
  };
1076
1228
  doScroll();
1077
1229
  requestAnimationFrame(doScroll);
1078
- }, [contentOffset == null ? void 0 : contentOffset.x, contentOffset == null ? void 0 : contentOffset.y]);
1230
+ }, [contentOffset == null ? void 0 : contentOffset.x, contentOffset == null ? void 0 : contentOffset.y, horizontal, scrollToLocalOffset]);
1079
1231
  React3.useLayoutEffect(() => {
1080
1232
  if (!onLayout || !scrollRef.current) return;
1081
1233
  const element = scrollRef.current;
1082
1234
  const fireLayout = () => {
1083
- const rect = element.getBoundingClientRect();
1084
1235
  onLayout({
1085
1236
  nativeEvent: {
1086
- layout: {
1087
- height: rect.height,
1088
- width: rect.width,
1089
- x: rect.left,
1090
- y: rect.top
1091
- }
1237
+ layout: getLayoutRectangle(element, isWindowScroll, horizontal)
1092
1238
  }
1093
1239
  });
1094
1240
  };
@@ -1097,16 +1243,27 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1097
1243
  fireLayout();
1098
1244
  });
1099
1245
  resizeObserver.observe(element);
1100
- return () => resizeObserver.disconnect();
1101
- }, [onLayout]);
1246
+ const onWindowResize = () => {
1247
+ fireLayout();
1248
+ };
1249
+ if (isWindowScroll && typeof window !== "undefined" && typeof window.addEventListener === "function") {
1250
+ window.addEventListener("resize", onWindowResize);
1251
+ }
1252
+ return () => {
1253
+ resizeObserver.disconnect();
1254
+ if (isWindowScroll && typeof window !== "undefined" && typeof window.removeEventListener === "function") {
1255
+ window.removeEventListener("resize", onWindowResize);
1256
+ }
1257
+ };
1258
+ }, [isWindowScroll, onLayout]);
1102
1259
  const scrollViewStyle = {
1103
- overflow: "auto",
1104
- overflowX: horizontal ? "auto" : showsHorizontalScrollIndicator ? "auto" : "hidden",
1105
- overflowY: horizontal ? showsVerticalScrollIndicator ? "auto" : "hidden" : "auto",
1106
- position: "relative",
1107
- // Ensure proper positioning context
1108
- WebkitOverflowScrolling: "touch",
1109
- // iOS momentum scrolling
1260
+ ...isWindowScroll ? {} : {
1261
+ overflow: "auto",
1262
+ overflowX: horizontal ? "auto" : showsHorizontalScrollIndicator ? "auto" : "hidden",
1263
+ overflowY: horizontal ? showsVerticalScrollIndicator ? "auto" : "hidden" : "auto",
1264
+ WebkitOverflowScrolling: "touch"
1265
+ // iOS momentum scrolling
1266
+ },
1110
1267
  ...StyleSheet.flatten(style)
1111
1268
  };
1112
1269
  const contentStyle = {
@@ -1116,7 +1273,13 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
1116
1273
  minWidth: horizontal ? "100%" : void 0,
1117
1274
  ...StyleSheet.flatten(contentContainerStyle)
1118
1275
  };
1119
- const { contentInset, scrollEventThrottle, ScrollComponent, ...webProps } = props;
1276
+ const {
1277
+ contentInset: _contentInset,
1278
+ scrollEventThrottle: _scrollEventThrottle,
1279
+ ScrollComponent: _ScrollComponent,
1280
+ useWindowScroll: _useWindowScroll,
1281
+ ...webProps
1282
+ } = props;
1120
1283
  return /* @__PURE__ */ React3__namespace.createElement("div", { ref: scrollRef, ...webProps, style: scrollViewStyle }, refreshControl, /* @__PURE__ */ React3__namespace.createElement("div", { ref: contentRef, style: contentStyle }, children));
1121
1284
  });
1122
1285
  function useValueListener$(key, callback) {
@@ -1143,23 +1306,29 @@ function ScrollAdjust() {
1143
1306
  if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
1144
1307
  const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1145
1308
  if (scrollDelta !== 0) {
1309
+ const contentNode = scrollView.getContentNode();
1310
+ const prevScroll = scrollView.getCurrentScrollOffset();
1146
1311
  const el = scrollView.getScrollableNode();
1147
- const prevScroll = el.scrollTop;
1312
+ if (!contentNode) {
1313
+ scrollView.scrollBy(0, scrollDelta);
1314
+ lastScrollOffsetRef.current = scrollOffset;
1315
+ return;
1316
+ }
1317
+ const totalSize = contentNode.scrollHeight;
1318
+ const viewportSize = el.clientHeight;
1148
1319
  const nextScroll = prevScroll + scrollDelta;
1149
- const totalSize = el.scrollHeight;
1150
- if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
1320
+ if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize) {
1151
1321
  const paddingBottom = ctx.state.props.stylePaddingBottom || 0;
1152
- const child = el.firstElementChild;
1153
- const pad = (nextScroll + el.clientHeight - totalSize) * 2;
1154
- child.style.paddingBottom = `${pad}px`;
1155
- void el.offsetHeight;
1322
+ const pad = (nextScroll + viewportSize - totalSize) * 2;
1323
+ contentNode.style.paddingBottom = `${pad}px`;
1324
+ void contentNode.offsetHeight;
1156
1325
  scrollView.scrollBy(0, scrollDelta);
1157
1326
  if (resetPaddingRafRef.current !== void 0) {
1158
1327
  cancelAnimationFrame(resetPaddingRafRef.current);
1159
1328
  }
1160
1329
  resetPaddingRafRef.current = requestAnimationFrame(() => {
1161
1330
  resetPaddingRafRef.current = void 0;
1162
- child.style.paddingBottom = paddingBottom ? `${paddingBottom}px` : "0";
1331
+ contentNode.style.paddingBottom = paddingBottom ? `${paddingBottom}px` : "0";
1163
1332
  });
1164
1333
  } else {
1165
1334
  scrollView.scrollBy(0, scrollDelta);
@@ -1218,6 +1387,7 @@ var ListComponent = typedMemo(function ListComponent2({
1218
1387
  snapToIndices,
1219
1388
  stickyHeaderConfig,
1220
1389
  stickyHeaderIndices,
1390
+ useWindowScroll = false,
1221
1391
  ...rest
1222
1392
  }) {
1223
1393
  const ctx = useStateContext();
@@ -1241,6 +1411,7 @@ var ListComponent = typedMemo(function ListComponent2({
1241
1411
  SnapOrScroll,
1242
1412
  {
1243
1413
  ...rest,
1414
+ ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
1244
1415
  contentContainerStyle: [
1245
1416
  contentContainerStyle,
1246
1417
  horizontal ? {
@@ -1286,24 +1457,12 @@ var ListComponent = typedMemo(function ListComponent2({
1286
1457
  );
1287
1458
  });
1288
1459
 
1289
- // src/utils/getId.ts
1290
- function getId(state, index) {
1291
- const { data, keyExtractor } = state.props;
1292
- if (!data) {
1293
- return "";
1294
- }
1295
- const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
1296
- const id = ret;
1297
- state.idCache[index] = id;
1298
- return id;
1299
- }
1300
-
1301
1460
  // src/core/calculateOffsetForIndex.ts
1302
1461
  function calculateOffsetForIndex(ctx, index) {
1303
1462
  const state = ctx.state;
1304
1463
  let position = 0;
1305
1464
  if (index !== void 0) {
1306
- position = state.positions.get(getId(state, index)) || 0;
1465
+ position = state.positions[index] || 0;
1307
1466
  const paddingTop = peek$(ctx, "stylePaddingTop");
1308
1467
  if (paddingTop) {
1309
1468
  position += paddingTop;
@@ -1316,6 +1475,18 @@ function calculateOffsetForIndex(ctx, index) {
1316
1475
  return position;
1317
1476
  }
1318
1477
 
1478
+ // src/utils/getId.ts
1479
+ function getId(state, index) {
1480
+ const { data, keyExtractor } = state.props;
1481
+ if (!data) {
1482
+ return "";
1483
+ }
1484
+ const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
1485
+ const id = ret;
1486
+ state.idCache[index] = id;
1487
+ return id;
1488
+ }
1489
+
1319
1490
  // src/core/addTotalSize.ts
1320
1491
  function addTotalSize(ctx, key, add) {
1321
1492
  const state = ctx.state;
@@ -1367,13 +1538,13 @@ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize) {
1367
1538
  return sizeKnown;
1368
1539
  }
1369
1540
  let size;
1370
- const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1371
1541
  if (preferCachedSize) {
1372
1542
  const cachedSize = sizes.get(key);
1373
1543
  if (cachedSize !== void 0) {
1374
1544
  return cachedSize;
1375
1545
  }
1376
1546
  }
1547
+ const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1377
1548
  if (getFixedItemSize) {
1378
1549
  size = getFixedItemSize(data, index, itemType);
1379
1550
  if (size !== void 0) {
@@ -1517,37 +1688,54 @@ function checkAtBottom(ctx) {
1517
1688
 
1518
1689
  // src/utils/checkAtTop.ts
1519
1690
  function checkAtTop(ctx) {
1520
- var _a3;
1521
1691
  const state = ctx == null ? void 0 : ctx.state;
1522
1692
  if (!state || state.initialScroll || state.scrollingTo) {
1523
1693
  return;
1524
1694
  }
1525
1695
  const {
1526
- scrollLength,
1696
+ dataChangeEpoch,
1697
+ isStartReached,
1698
+ props: { data, onStartReachedThreshold },
1527
1699
  scroll,
1528
- props: { onStartReachedThreshold }
1700
+ scrollLength,
1701
+ startReachedSnapshot,
1702
+ startReachedSnapshotDataChangeEpoch,
1703
+ totalSize
1529
1704
  } = state;
1530
- const distanceFromTop = scroll;
1531
- state.isAtStart = distanceFromTop <= 0;
1705
+ const dataLength = data.length;
1706
+ const threshold = onStartReachedThreshold * scrollLength;
1707
+ const dataChanged = startReachedSnapshotDataChangeEpoch !== dataChangeEpoch;
1708
+ const withinThreshold = threshold > 0 && Math.abs(scroll) <= threshold;
1709
+ const allowReentryOnDataChange = !!isStartReached && withinThreshold && !!dataChanged && !isInMVCPActiveMode(state);
1710
+ if (isStartReached && threshold > 0 && scroll > threshold && startReachedSnapshot && (dataChanged || startReachedSnapshot.contentSize !== totalSize || startReachedSnapshot.dataLength !== dataLength)) {
1711
+ state.isStartReached = false;
1712
+ state.startReachedSnapshot = void 0;
1713
+ state.startReachedSnapshotDataChangeEpoch = void 0;
1714
+ }
1715
+ state.isAtStart = scroll <= 0;
1716
+ if (isStartReached && withinThreshold && dataChanged && !allowReentryOnDataChange) {
1717
+ return;
1718
+ }
1532
1719
  state.isStartReached = checkThreshold(
1533
- distanceFromTop,
1720
+ scroll,
1534
1721
  false,
1535
- onStartReachedThreshold * scrollLength,
1722
+ threshold,
1536
1723
  state.isStartReached,
1537
- state.startReachedSnapshot,
1724
+ allowReentryOnDataChange ? void 0 : startReachedSnapshot,
1538
1725
  {
1539
- contentSize: state.totalSize,
1540
- dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length,
1726
+ contentSize: totalSize,
1727
+ dataLength,
1541
1728
  scrollPosition: scroll
1542
1729
  },
1543
1730
  (distance) => {
1544
- var _a4, _b;
1545
- return (_b = (_a4 = state.props).onStartReached) == null ? void 0 : _b.call(_a4, { distanceFromStart: distance });
1731
+ var _a3, _b;
1732
+ return (_b = (_a3 = state.props).onStartReached) == null ? void 0 : _b.call(_a3, { distanceFromStart: distance });
1546
1733
  },
1547
1734
  (snapshot) => {
1548
1735
  state.startReachedSnapshot = snapshot;
1736
+ state.startReachedSnapshotDataChangeEpoch = snapshot ? dataChangeEpoch : void 0;
1549
1737
  },
1550
- false
1738
+ allowReentryOnDataChange
1551
1739
  );
1552
1740
  }
1553
1741
 
@@ -1587,6 +1775,8 @@ function finishScrollTo(ctx) {
1587
1775
  var _a3, _b;
1588
1776
  const state = ctx.state;
1589
1777
  if (state == null ? void 0 : state.scrollingTo) {
1778
+ const resolvePendingScroll = state.pendingScrollResolve;
1779
+ state.pendingScrollResolve = void 0;
1590
1780
  const scrollingTo = state.scrollingTo;
1591
1781
  state.scrollHistory.length = 0;
1592
1782
  state.initialScroll = void 0;
@@ -1603,6 +1793,7 @@ function finishScrollTo(ctx) {
1603
1793
  }
1604
1794
  setInitialRenderState(ctx, { didInitialScroll: true });
1605
1795
  checkThresholds(ctx);
1796
+ resolvePendingScroll == null ? void 0 : resolvePendingScroll();
1606
1797
  }
1607
1798
  }
1608
1799
 
@@ -1615,42 +1806,49 @@ function doScrollTo(ctx, params) {
1615
1806
  const state = ctx.state;
1616
1807
  const { animated, horizontal, offset } = params;
1617
1808
  const scroller = state.refScroller.current;
1618
- const node = typeof (scroller == null ? void 0 : scroller.getScrollableNode) === "function" ? scroller.getScrollableNode() : scroller;
1619
- if (node) {
1620
- const left = horizontal ? offset : 0;
1621
- const top = horizontal ? 0 : offset;
1622
- node.scrollTo({ behavior: animated ? "smooth" : "auto", left, top });
1623
- if (animated) {
1624
- listenForScrollEnd(ctx, node, {
1625
- horizontal: !!horizontal,
1626
- targetOffset: offset
1627
- });
1628
- } else {
1629
- state.scroll = offset;
1630
- setTimeout(() => {
1631
- finishScrollTo(ctx);
1632
- }, 100);
1633
- }
1809
+ const node = scroller == null ? void 0 : scroller.getScrollableNode();
1810
+ if (!scroller || !node) {
1811
+ return;
1812
+ }
1813
+ const isAnimated = !!animated;
1814
+ const isHorizontal = !!horizontal;
1815
+ const left = isHorizontal ? offset : 0;
1816
+ const top = isHorizontal ? 0 : offset;
1817
+ scroller.scrollTo({ animated: isAnimated, x: left, y: top });
1818
+ if (isAnimated) {
1819
+ const target = scroller.getScrollEventTarget();
1820
+ listenForScrollEnd(ctx, {
1821
+ readOffset: () => scroller.getCurrentScrollOffset(),
1822
+ target,
1823
+ targetOffset: offset
1824
+ });
1825
+ } else {
1826
+ state.scroll = offset;
1827
+ setTimeout(() => {
1828
+ finishScrollTo(ctx);
1829
+ }, 100);
1634
1830
  }
1635
1831
  }
1636
- function listenForScrollEnd(ctx, node, params) {
1637
- const { horizontal, targetOffset } = params;
1638
- const supportsScrollEnd = "onscrollend" in node;
1832
+ function listenForScrollEnd(ctx, params) {
1833
+ const { readOffset, target, targetOffset } = params;
1834
+ if (!target) {
1835
+ finishScrollTo(ctx);
1836
+ return;
1837
+ }
1838
+ const supportsScrollEnd = "onscrollend" in target;
1639
1839
  let idleTimeout;
1640
- let maxTimeout;
1641
1840
  let settled = false;
1642
1841
  const targetToken = ctx.state.scrollingTo;
1842
+ const maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1643
1843
  const cleanup = () => {
1644
- node.removeEventListener("scroll", onScroll2);
1844
+ target.removeEventListener("scroll", onScroll2);
1645
1845
  if (supportsScrollEnd) {
1646
- node.removeEventListener("scrollend", onScrollEnd);
1846
+ target.removeEventListener("scrollend", onScrollEnd);
1647
1847
  }
1648
1848
  if (idleTimeout) {
1649
1849
  clearTimeout(idleTimeout);
1650
1850
  }
1651
- if (maxTimeout) {
1652
- clearTimeout(maxTimeout);
1653
- }
1851
+ clearTimeout(maxTimeout);
1654
1852
  };
1655
1853
  const finish = (reason) => {
1656
1854
  if (settled) return;
@@ -1659,7 +1857,7 @@ function listenForScrollEnd(ctx, node, params) {
1659
1857
  cleanup();
1660
1858
  return;
1661
1859
  }
1662
- const currentOffset = horizontal ? node.scrollLeft : node.scrollTop;
1860
+ const currentOffset = readOffset();
1663
1861
  const isNearTarget = Math.abs(currentOffset - targetOffset) <= SCROLL_END_TARGET_EPSILON;
1664
1862
  if (reason === "scrollend" && !isNearTarget) {
1665
1863
  return;
@@ -1675,13 +1873,11 @@ function listenForScrollEnd(ctx, node, params) {
1675
1873
  idleTimeout = setTimeout(() => finish("idle"), SCROLL_END_IDLE_MS);
1676
1874
  };
1677
1875
  const onScrollEnd = () => finish("scrollend");
1678
- node.addEventListener("scroll", onScroll2);
1876
+ target.addEventListener("scroll", onScroll2);
1679
1877
  if (supportsScrollEnd) {
1680
- node.addEventListener("scrollend", onScrollEnd);
1681
- maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1878
+ target.addEventListener("scrollend", onScrollEnd);
1682
1879
  } else {
1683
1880
  idleTimeout = setTimeout(() => finish("idle"), SMOOTH_SCROLL_DURATION_MS);
1684
- maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1685
1881
  }
1686
1882
  }
1687
1883
 
@@ -1716,7 +1912,7 @@ function scrollTo(ctx, params) {
1716
1912
  // src/core/updateScroll.ts
1717
1913
  function updateScroll(ctx, newScroll, forceUpdate) {
1718
1914
  const state = ctx.state;
1719
- const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1915
+ const { ignoreScrollFromMVCP, lastScrollAdjustForHistory, scrollAdjustHandler, scrollHistory, scrollingTo } = state;
1720
1916
  const prevScroll = state.scroll;
1721
1917
  state.hasScrolled = true;
1722
1918
  state.lastBatchingAction = Date.now();
@@ -1724,22 +1920,17 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1724
1920
  const adjust = scrollAdjustHandler.getAdjust();
1725
1921
  const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
1726
1922
  if (adjustChanged) {
1727
- state.scrollHistory.length = 0;
1923
+ scrollHistory.length = 0;
1728
1924
  }
1729
1925
  state.lastScrollAdjustForHistory = adjust;
1730
- if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
1926
+ if (scrollingTo === void 0 && !(scrollHistory.length === 0 && newScroll === state.scroll)) {
1731
1927
  if (!adjustChanged) {
1732
- state.scrollHistory.push({ scroll: newScroll, time: currentTime });
1928
+ scrollHistory.push({ scroll: newScroll, time: currentTime });
1733
1929
  }
1734
1930
  }
1735
- if (state.scrollHistory.length > 5) {
1736
- state.scrollHistory.shift();
1931
+ if (scrollHistory.length > 5) {
1932
+ scrollHistory.shift();
1737
1933
  }
1738
- state.scrollPrev = prevScroll;
1739
- state.scrollPrevTime = state.scrollTime;
1740
- state.scroll = newScroll;
1741
- state.scrollTime = currentTime;
1742
- const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
1743
1934
  if (ignoreScrollFromMVCP && !scrollingTo) {
1744
1935
  const { lt, gt } = ignoreScrollFromMVCP;
1745
1936
  if (lt && newScroll < lt || gt && newScroll > gt) {
@@ -1747,6 +1938,10 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1747
1938
  return;
1748
1939
  }
1749
1940
  }
1941
+ state.scrollPrev = prevScroll;
1942
+ state.scrollPrevTime = state.scrollTime;
1943
+ state.scroll = newScroll;
1944
+ state.scrollTime = currentTime;
1750
1945
  const scrollDelta = Math.abs(newScroll - prevScroll);
1751
1946
  const scrollLength = state.scrollLength;
1752
1947
  const lastCalculated = state.scrollLastCalculate;
@@ -1870,12 +2065,18 @@ function prepareMVCP(ctx, dataChanged) {
1870
2065
  const id = idsInView[i];
1871
2066
  const index = indexByKey.get(id);
1872
2067
  if (index !== void 0) {
1873
- idsInViewWithPositions.push({ id, position: positions.get(id) });
2068
+ const position = positions[index];
2069
+ if (position !== void 0) {
2070
+ idsInViewWithPositions.push({ id, position });
2071
+ }
1874
2072
  }
1875
2073
  }
1876
2074
  }
1877
2075
  if (targetId !== void 0 && prevPosition === void 0) {
1878
- prevPosition = positions.get(targetId);
2076
+ const targetIndex = indexByKey.get(targetId);
2077
+ if (targetIndex !== void 0) {
2078
+ prevPosition = positions[targetIndex];
2079
+ }
1879
2080
  }
1880
2081
  return () => {
1881
2082
  let positionDiff = 0;
@@ -1894,7 +2095,13 @@ function prepareMVCP(ctx, dataChanged) {
1894
2095
  }
1895
2096
  }
1896
2097
  }
1897
- const shouldUseFallbackVisibleAnchor = dataChanged && mvcpData && scrollTarget === void 0 && (targetId === void 0 || positions.get(targetId) === void 0 || skipTargetAnchor);
2098
+ const shouldUseFallbackVisibleAnchor = dataChanged && mvcpData && scrollTarget === void 0 && (() => {
2099
+ if (targetId === void 0 || skipTargetAnchor) {
2100
+ return true;
2101
+ }
2102
+ const targetIndex = indexByKey.get(targetId);
2103
+ return targetIndex === void 0 || positions[targetIndex] === void 0;
2104
+ })();
1898
2105
  if (shouldUseFallbackVisibleAnchor) {
1899
2106
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1900
2107
  const { id, position } = idsInViewWithPositions[i];
@@ -1905,7 +2112,7 @@ function prepareMVCP(ctx, dataChanged) {
1905
2112
  continue;
1906
2113
  }
1907
2114
  }
1908
- const newPosition = positions.get(id);
2115
+ const newPosition = index !== void 0 ? positions[index] : void 0;
1909
2116
  if (newPosition !== void 0) {
1910
2117
  positionDiff = newPosition - position;
1911
2118
  anchorIdForLock = id;
@@ -1915,7 +2122,8 @@ function prepareMVCP(ctx, dataChanged) {
1915
2122
  }
1916
2123
  }
1917
2124
  if (!skipTargetAnchor && targetId !== void 0 && prevPosition !== void 0) {
1918
- const newPosition = positions.get(targetId);
2125
+ const targetIndex = indexByKey.get(targetId);
2126
+ const newPosition = targetIndex !== void 0 ? positions[targetIndex] : void 0;
1919
2127
  if (newPosition !== void 0) {
1920
2128
  const totalSize = getContentSize(ctx);
1921
2129
  let diff = newPosition - prevPosition;
@@ -1962,17 +2170,15 @@ function prepareColumnStartState(ctx, startIndex, useAverageSize) {
1962
2170
  const state = ctx.state;
1963
2171
  const numColumns = peek$(ctx, "numColumns");
1964
2172
  let rowStartIndex = startIndex;
1965
- const columnAtStart = state.columns.get(state.idCache[startIndex]);
2173
+ const columnAtStart = state.columns[startIndex];
1966
2174
  if (columnAtStart !== 1) {
1967
2175
  rowStartIndex = findRowStartIndex(state, numColumns, startIndex);
1968
2176
  }
1969
2177
  let currentRowTop = 0;
1970
- const curId = state.idCache[rowStartIndex];
1971
- const column = state.columns.get(curId);
2178
+ const column = state.columns[rowStartIndex];
1972
2179
  if (rowStartIndex > 0) {
1973
2180
  const prevIndex = rowStartIndex - 1;
1974
- const prevId = state.idCache[prevIndex];
1975
- const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
2181
+ const prevPosition = (_a3 = state.positions[prevIndex]) != null ? _a3 : 0;
1976
2182
  const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1977
2183
  const prevRowHeight = calculateRowMaxSize(ctx, prevRowStart, prevIndex, useAverageSize);
1978
2184
  currentRowTop = prevPosition + prevRowHeight;
@@ -1989,7 +2195,7 @@ function findRowStartIndex(state, numColumns, index) {
1989
2195
  }
1990
2196
  let rowStart = Math.max(0, index);
1991
2197
  while (rowStart > 0) {
1992
- const columnForIndex = state.columns.get(state.idCache[rowStart]);
2198
+ const columnForIndex = state.columns[rowStart];
1993
2199
  if (columnForIndex === 1) {
1994
2200
  break;
1995
2201
  }
@@ -2022,7 +2228,7 @@ function calculateRowMaxSize(ctx, startIndex, endIndex, useAverageSize) {
2022
2228
 
2023
2229
  // src/core/updateTotalSize.ts
2024
2230
  function updateTotalSize(ctx) {
2025
- var _a3, _b, _c;
2231
+ var _a3, _b;
2026
2232
  const state = ctx.state;
2027
2233
  const {
2028
2234
  positions,
@@ -2032,36 +2238,34 @@ function updateTotalSize(ctx) {
2032
2238
  if (data.length === 0) {
2033
2239
  addTotalSize(ctx, null, 0);
2034
2240
  } else {
2035
- const lastId = getId(state, data.length - 1);
2036
- if (lastId !== void 0) {
2037
- const lastPosition = positions.get(lastId);
2038
- if (lastPosition !== void 0) {
2039
- if (numColumns > 1) {
2040
- let rowStart = data.length - 1;
2041
- while (rowStart > 0) {
2042
- const rowId = (_b = state.idCache[rowStart]) != null ? _b : getId(state, rowStart);
2043
- const column = state.columns.get(rowId);
2044
- if (column === 1 || column === void 0) {
2045
- break;
2046
- }
2047
- rowStart -= 1;
2048
- }
2049
- let maxSize = 0;
2050
- for (let i = rowStart; i < data.length; i++) {
2051
- const rowId = (_c = state.idCache[i]) != null ? _c : getId(state, i);
2052
- const size = getItemSize(ctx, rowId, i, data[i]);
2053
- if (size > maxSize) {
2054
- maxSize = size;
2055
- }
2241
+ const lastIndex = data.length - 1;
2242
+ const lastId = getId(state, lastIndex);
2243
+ const lastPosition = positions[lastIndex];
2244
+ if (lastId !== void 0 && lastPosition !== void 0) {
2245
+ if (numColumns > 1) {
2246
+ let rowStart = lastIndex;
2247
+ while (rowStart > 0) {
2248
+ const column = state.columns[rowStart];
2249
+ if (column === 1 || column === void 0) {
2250
+ break;
2056
2251
  }
2057
- addTotalSize(ctx, null, lastPosition + maxSize);
2058
- } else {
2059
- const lastSize = getItemSize(ctx, lastId, data.length - 1, data[data.length - 1]);
2060
- if (lastSize !== void 0) {
2061
- const totalSize = lastPosition + lastSize;
2062
- addTotalSize(ctx, null, totalSize);
2252
+ rowStart -= 1;
2253
+ }
2254
+ let maxSize = 0;
2255
+ for (let i = rowStart; i <= lastIndex; i++) {
2256
+ const rowId = (_b = state.idCache[i]) != null ? _b : getId(state, i);
2257
+ const size = getItemSize(ctx, rowId, i, data[i]);
2258
+ if (size > maxSize) {
2259
+ maxSize = size;
2063
2260
  }
2064
2261
  }
2262
+ addTotalSize(ctx, null, lastPosition + maxSize);
2263
+ } else {
2264
+ const lastSize = getItemSize(ctx, lastId, lastIndex, data[lastIndex]);
2265
+ if (lastSize !== void 0) {
2266
+ const totalSize = lastPosition + lastSize;
2267
+ addTotalSize(ctx, null, totalSize);
2268
+ }
2065
2269
  }
2066
2270
  }
2067
2271
  }
@@ -2110,14 +2314,13 @@ var getScrollVelocity = (state) => {
2110
2314
  function updateSnapToOffsets(ctx) {
2111
2315
  const state = ctx.state;
2112
2316
  const {
2113
- positions,
2114
2317
  props: { snapToIndices }
2115
2318
  } = state;
2116
2319
  const snapToOffsets = Array(snapToIndices.length);
2117
2320
  for (let i = 0; i < snapToIndices.length; i++) {
2118
2321
  const idx = snapToIndices[i];
2119
- const key = getId(state, idx);
2120
- snapToOffsets[i] = positions.get(key);
2322
+ getId(state, idx);
2323
+ snapToOffsets[i] = state.positions[idx];
2121
2324
  }
2122
2325
  set$(ctx, "snapToOffsets", snapToOffsets);
2123
2326
  }
@@ -2129,8 +2332,9 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
2129
2332
  scrollBottomBuffered: -1,
2130
2333
  startIndex: 0
2131
2334
  }) {
2132
- var _a3, _b, _c, _d, _e, _f;
2335
+ var _a3, _b, _c, _d, _e;
2133
2336
  const state = ctx.state;
2337
+ const hasPositionListeners = ctx.positionListeners.size > 0;
2134
2338
  const {
2135
2339
  columns,
2136
2340
  columnSpans,
@@ -2157,7 +2361,15 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
2157
2361
  let column = 1;
2158
2362
  let maxSizeInRow = 0;
2159
2363
  if (dataChanged) {
2160
- columnSpans.clear();
2364
+ columnSpans.length = 0;
2365
+ }
2366
+ if (!hasColumns) {
2367
+ if (columns.length) {
2368
+ columns.length = 0;
2369
+ }
2370
+ if (columnSpans.length) {
2371
+ columnSpans.length = 0;
2372
+ }
2161
2373
  }
2162
2374
  if (startIndex > 0) {
2163
2375
  if (hasColumns) {
@@ -2171,12 +2383,13 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
2171
2383
  } else if (startIndex < dataLength) {
2172
2384
  const prevIndex = startIndex - 1;
2173
2385
  const prevId = getId(state, prevIndex);
2174
- const prevPosition = (_c = positions.get(prevId)) != null ? _c : 0;
2386
+ const prevPosition = (_c = positions[prevIndex]) != null ? _c : 0;
2175
2387
  const prevSize = (_d = sizesKnown.get(prevId)) != null ? _d : getItemSize(ctx, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
2176
2388
  currentRowTop = prevPosition + prevSize;
2177
2389
  }
2178
2390
  }
2179
2391
  const needsIndexByKey = dataChanged || indexByKey.size === 0;
2392
+ const canOverrideSpan = hasColumns && !!overrideItemLayout && !!layoutConfig;
2180
2393
  let didBreakEarly = false;
2181
2394
  let breakAt;
2182
2395
  for (let i = startIndex; i < dataLength; i++) {
@@ -2190,7 +2403,7 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
2190
2403
  }
2191
2404
  const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2192
2405
  let span = 1;
2193
- if (hasColumns && overrideItemLayout && layoutConfig) {
2406
+ if (canOverrideSpan) {
2194
2407
  layoutConfig.span = 1;
2195
2408
  overrideItemLayout(layoutConfig, data[i], i, numColumns, extraData);
2196
2409
  const requestedSpan = layoutConfig.span;
@@ -2203,7 +2416,8 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
2203
2416
  column = 1;
2204
2417
  maxSizeInRow = 0;
2205
2418
  }
2206
- const size = (_f = sizesKnown.get(id)) != null ? _f : getItemSize(ctx, id, i, data[i], useAverageSize, preferCachedSize);
2419
+ const knownSize = sizesKnown.get(id);
2420
+ const size = knownSize !== void 0 ? knownSize : getItemSize(ctx, id, i, data[i], useAverageSize, preferCachedSize);
2207
2421
  if (IS_DEV && needsIndexByKey) {
2208
2422
  if (indexByKeyForChecking.has(id)) {
2209
2423
  console.error(
@@ -2212,16 +2426,20 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
2212
2426
  }
2213
2427
  indexByKeyForChecking.set(id, i);
2214
2428
  }
2215
- if (currentRowTop !== positions.get(id)) {
2216
- positions.set(id, currentRowTop);
2217
- notifyPosition$(ctx, id, currentRowTop);
2429
+ if (currentRowTop !== positions[i]) {
2430
+ positions[i] = currentRowTop;
2431
+ if (hasPositionListeners) {
2432
+ notifyPosition$(ctx, id, currentRowTop);
2433
+ }
2218
2434
  }
2219
2435
  if (needsIndexByKey) {
2220
2436
  indexByKey.set(id, i);
2221
2437
  }
2222
- columns.set(id, column);
2223
- columnSpans.set(id, span);
2224
- if (hasColumns) {
2438
+ if (!hasColumns) {
2439
+ currentRowTop += size;
2440
+ } else {
2441
+ columns[i] = column;
2442
+ columnSpans[i] = span;
2225
2443
  if (size > maxSizeInRow) {
2226
2444
  maxSizeInRow = size;
2227
2445
  }
@@ -2231,8 +2449,6 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
2231
2449
  column = 1;
2232
2450
  maxSizeInRow = 0;
2233
2451
  }
2234
- } else {
2235
- currentRowTop += size;
2236
2452
  }
2237
2453
  }
2238
2454
  if (!didBreakEarly) {
@@ -2384,14 +2600,38 @@ function shallowEqual(prev, next) {
2384
2600
  return true;
2385
2601
  }
2386
2602
  function computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2387
- const { sizes, positions, scroll: scrollState } = state;
2603
+ const { sizes, scroll: scrollState } = state;
2388
2604
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2389
2605
  const { itemVisiblePercentThreshold, viewAreaCoveragePercentThreshold } = viewabilityConfig;
2390
2606
  const viewAreaMode = viewAreaCoveragePercentThreshold != null;
2391
2607
  const viewablePercentThreshold = viewAreaMode ? viewAreaCoveragePercentThreshold : itemVisiblePercentThreshold;
2392
2608
  const scroll = scrollState - topPad;
2393
- const top = positions.get(key) - scroll;
2609
+ const position = state.positions[index];
2394
2610
  const size = sizes.get(key) || 0;
2611
+ if (position === void 0) {
2612
+ const value2 = {
2613
+ containerId,
2614
+ index,
2615
+ isViewable: false,
2616
+ item,
2617
+ key,
2618
+ percentOfScroller: 0,
2619
+ percentVisible: 0,
2620
+ scrollSize,
2621
+ size,
2622
+ sizeVisible: -1
2623
+ };
2624
+ const prev2 = ctx.mapViewabilityAmountValues.get(containerId);
2625
+ if (!shallowEqual(prev2, value2)) {
2626
+ ctx.mapViewabilityAmountValues.set(containerId, value2);
2627
+ const cb = ctx.mapViewabilityAmountCallbacks.get(containerId);
2628
+ if (cb) {
2629
+ cb(value2);
2630
+ }
2631
+ }
2632
+ return value2;
2633
+ }
2634
+ const top = position - scroll;
2395
2635
  const bottom = top + size;
2396
2636
  const isEntirelyVisible = top >= 0 && bottom <= scrollSize && bottom > top;
2397
2637
  const sizeVisible = isEntirelyVisible ? size : Math.min(bottom, scrollSize) - Math.max(top, 0);
@@ -2618,13 +2858,10 @@ function setDidLayout(ctx) {
2618
2858
 
2619
2859
  // src/core/calculateItemsInView.ts
2620
2860
  function findCurrentStickyIndex(stickyArray, scroll, state) {
2621
- var _a3;
2622
- const idCache = state.idCache;
2623
2861
  const positions = state.positions;
2624
2862
  for (let i = stickyArray.length - 1; i >= 0; i--) {
2625
2863
  const stickyIndex = stickyArray[i];
2626
- const stickyId = (_a3 = idCache[stickyIndex]) != null ? _a3 : getId(state, stickyIndex);
2627
- const stickyPos = stickyId ? positions.get(stickyId) : void 0;
2864
+ const stickyPos = positions[stickyIndex];
2628
2865
  if (stickyPos !== void 0 && scroll >= stickyPos) {
2629
2866
  return i;
2630
2867
  }
@@ -2654,7 +2891,7 @@ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentSt
2654
2891
  }
2655
2892
  }
2656
2893
  function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentStickyIdx, pendingRemoval, alwaysRenderIndicesSet) {
2657
- var _a3, _b, _c;
2894
+ var _a3, _b;
2658
2895
  const state = ctx.state;
2659
2896
  for (const containerIndex of state.stickyContainerPool) {
2660
2897
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
@@ -2672,14 +2909,13 @@ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentSt
2672
2909
  const nextIndex = stickyArray[arrayIdx + 1];
2673
2910
  let shouldRecycle = false;
2674
2911
  if (nextIndex) {
2675
- const nextId = (_a3 = state.idCache[nextIndex]) != null ? _a3 : getId(state, nextIndex);
2676
- const nextPos = nextId ? state.positions.get(nextId) : void 0;
2912
+ const nextPos = state.positions[nextIndex];
2677
2913
  shouldRecycle = nextPos !== void 0 && scroll > nextPos + drawDistance * 2;
2678
2914
  } else {
2679
- const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2915
+ const currentId = (_a3 = state.idCache[itemIndex]) != null ? _a3 : getId(state, itemIndex);
2680
2916
  if (currentId) {
2681
- const currentPos = state.positions.get(currentId);
2682
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2917
+ const currentPos = state.positions[itemIndex];
2918
+ const currentSize = (_b = state.sizes.get(currentId)) != null ? _b : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2683
2919
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + drawDistance * 3;
2684
2920
  }
2685
2921
  }
@@ -2691,7 +2927,7 @@ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentSt
2691
2927
  function calculateItemsInView(ctx, params = {}) {
2692
2928
  const state = ctx.state;
2693
2929
  reactDom.unstable_batchedUpdates(() => {
2694
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
2930
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2695
2931
  const {
2696
2932
  columns,
2697
2933
  columnSpans,
@@ -2780,7 +3016,9 @@ function calculateItemsInView(ctx, params = {}) {
2780
3016
  if (dataChanged) {
2781
3017
  indexByKey.clear();
2782
3018
  idCache.length = 0;
2783
- positions.clear();
3019
+ positions.length = 0;
3020
+ columns.length = 0;
3021
+ columnSpans.length = 0;
2784
3022
  }
2785
3023
  const startIndex = forceFullItemPositions || dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2786
3024
  updateItemPositions(ctx, dataChanged, {
@@ -2801,7 +3039,7 @@ function calculateItemsInView(ctx, params = {}) {
2801
3039
  let loopStart = !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
2802
3040
  for (let i = loopStart; i >= 0; i--) {
2803
3041
  const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2804
- const top = positions.get(id);
3042
+ const top = positions[i];
2805
3043
  const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, id, i, data[i]);
2806
3044
  const bottom = top + size;
2807
3045
  if (bottom > scroll - scrollBufferTop) {
@@ -2812,8 +3050,7 @@ function calculateItemsInView(ctx, params = {}) {
2812
3050
  }
2813
3051
  if (numColumns > 1) {
2814
3052
  while (loopStart > 0) {
2815
- const loopId = (_e = idCache[loopStart]) != null ? _e : getId(state, loopStart);
2816
- const loopColumn = columns.get(loopId);
3053
+ const loopColumn = columns[loopStart];
2817
3054
  if (loopColumn === 1 || loopColumn === void 0) {
2818
3055
  break;
2819
3056
  }
@@ -2834,9 +3071,9 @@ function calculateItemsInView(ctx, params = {}) {
2834
3071
  let firstFullyOnScreenIndex;
2835
3072
  const dataLength = data.length;
2836
3073
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2837
- const id = (_f = idCache[i]) != null ? _f : getId(state, i);
2838
- const size = (_g = sizes.get(id)) != null ? _g : getItemSize(ctx, id, i, data[i]);
2839
- const top = positions.get(id);
3074
+ const id = (_e = idCache[i]) != null ? _e : getId(state, i);
3075
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, id, i, data[i]);
3076
+ const top = positions[i];
2840
3077
  if (!foundEnd) {
2841
3078
  if (startNoBuffer === null && top + size > scroll) {
2842
3079
  startNoBuffer = i;
@@ -2872,7 +3109,7 @@ function calculateItemsInView(ctx, params = {}) {
2872
3109
  }
2873
3110
  const idsInView = [];
2874
3111
  for (let i = firstFullyOnScreenIndex; i <= endNoBuffer; i++) {
2875
- const id = (_h = idCache[i]) != null ? _h : getId(state, i);
3112
+ const id = (_g = idCache[i]) != null ? _g : getId(state, i);
2876
3113
  idsInView.push(id);
2877
3114
  }
2878
3115
  Object.assign(state, {
@@ -2904,7 +3141,7 @@ function calculateItemsInView(ctx, params = {}) {
2904
3141
  const needNewContainers = [];
2905
3142
  const needNewContainersSet = /* @__PURE__ */ new Set();
2906
3143
  for (let i = startBuffered; i <= endBuffered; i++) {
2907
- const id = (_i = idCache[i]) != null ? _i : getId(state, i);
3144
+ const id = (_h = idCache[i]) != null ? _h : getId(state, i);
2908
3145
  if (!containerItemKeys.has(id)) {
2909
3146
  needNewContainersSet.add(i);
2910
3147
  needNewContainers.push(i);
@@ -2913,7 +3150,7 @@ function calculateItemsInView(ctx, params = {}) {
2913
3150
  if (alwaysRenderArr.length > 0) {
2914
3151
  for (const index of alwaysRenderArr) {
2915
3152
  if (index < 0 || index >= dataLength) continue;
2916
- const id = (_j = idCache[index]) != null ? _j : getId(state, index);
3153
+ const id = (_i = idCache[index]) != null ? _i : getId(state, index);
2917
3154
  if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
2918
3155
  needNewContainersSet.add(index);
2919
3156
  needNewContainers.push(index);
@@ -2951,7 +3188,7 @@ function calculateItemsInView(ctx, params = {}) {
2951
3188
  for (let idx = 0; idx < needNewContainers.length; idx++) {
2952
3189
  const i = needNewContainers[idx];
2953
3190
  const containerIndex = availableContainers[idx];
2954
- const id = (_k = idCache[i]) != null ? _k : getId(state, i);
3191
+ const id = (_j = idCache[i]) != null ? _j : getId(state, i);
2955
3192
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
2956
3193
  if (oldKey && oldKey !== id) {
2957
3194
  containerItemKeys.delete(oldKey);
@@ -2992,7 +3229,7 @@ function calculateItemsInView(ctx, params = {}) {
2992
3229
  if (alwaysRenderArr.length > 0) {
2993
3230
  for (const index of alwaysRenderArr) {
2994
3231
  if (index < 0 || index >= dataLength) continue;
2995
- const id = (_l = idCache[index]) != null ? _l : getId(state, index);
3232
+ const id = (_k = idCache[index]) != null ? _k : getId(state, index);
2996
3233
  const containerIndex = containerItemKeys.get(id);
2997
3234
  if (containerIndex !== void 0) {
2998
3235
  state.stickyContainerPool.add(containerIndex);
@@ -3032,14 +3269,13 @@ function calculateItemsInView(ctx, params = {}) {
3032
3269
  const itemIndex = indexByKey.get(itemKey);
3033
3270
  const item = data[itemIndex];
3034
3271
  if (item !== void 0) {
3035
- const id = (_m = idCache[itemIndex]) != null ? _m : getId(state, itemIndex);
3036
- const positionValue = positions.get(id);
3272
+ const positionValue = positions[itemIndex];
3037
3273
  if (positionValue === void 0) {
3038
3274
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
3039
3275
  } else {
3040
3276
  const position = (positionValue || 0) - scrollAdjustPending;
3041
- const column = columns.get(id) || 1;
3042
- const span = columnSpans.get(id) || 1;
3277
+ const column = columns[itemIndex] || 1;
3278
+ const span = columnSpans[itemIndex] || 1;
3043
3279
  const prevPos = peek$(ctx, `containerPosition${i}`);
3044
3280
  const prevColumn = peek$(ctx, `containerColumn${i}`);
3045
3281
  const prevSpan = peek$(ctx, `containerSpan${i}`);
@@ -3652,6 +3888,18 @@ function createColumnWrapperStyle(contentContainerStyle) {
3652
3888
  // src/utils/createImperativeHandle.ts
3653
3889
  function createImperativeHandle(ctx) {
3654
3890
  const state = ctx.state;
3891
+ const runScrollWithPromise = (run) => new Promise((resolve) => {
3892
+ var _a3;
3893
+ (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
3894
+ state.pendingScrollResolve = resolve;
3895
+ const didStartScroll = run();
3896
+ if (!didStartScroll || !state.scrollingTo) {
3897
+ if (state.pendingScrollResolve === resolve) {
3898
+ state.pendingScrollResolve = void 0;
3899
+ }
3900
+ resolve();
3901
+ }
3902
+ });
3655
3903
  const scrollIndexIntoView = (options) => {
3656
3904
  if (state) {
3657
3905
  const { index, ...rest } = options;
@@ -3663,8 +3911,10 @@ function createImperativeHandle(ctx) {
3663
3911
  index,
3664
3912
  viewPosition
3665
3913
  });
3914
+ return true;
3666
3915
  }
3667
3916
  }
3917
+ return false;
3668
3918
  };
3669
3919
  const refScroller = state.refScroller;
3670
3920
  const clearCaches = (options) => {
@@ -3683,9 +3933,9 @@ function createImperativeHandle(ctx) {
3683
3933
  if (mode === "full") {
3684
3934
  state.indexByKey.clear();
3685
3935
  state.idCache.length = 0;
3686
- state.positions.clear();
3687
- state.columns.clear();
3688
- state.columnSpans.clear();
3936
+ state.positions.length = 0;
3937
+ state.columns.length = 0;
3938
+ state.columnSpans.length = 0;
3689
3939
  }
3690
3940
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
3691
3941
  };
@@ -3709,8 +3959,11 @@ function createImperativeHandle(ctx) {
3709
3959
  isAtStart: state.isAtStart,
3710
3960
  listen: (signalName, cb) => listen$(ctx, signalName, cb),
3711
3961
  listenToPosition: (key, cb) => listenPosition$(ctx, key, cb),
3712
- positionAtIndex: (index) => state.positions.get(getId(state, index)),
3713
- positions: state.positions,
3962
+ positionAtIndex: (index) => state.positions[index],
3963
+ positionByKey: (key) => {
3964
+ const index = state.indexByKey.get(key);
3965
+ return index === void 0 ? void 0 : state.positions[index];
3966
+ },
3714
3967
  scroll: state.scroll,
3715
3968
  scrollLength: state.scrollLength,
3716
3969
  scrollVelocity: getScrollVelocity(state),
@@ -3723,15 +3976,17 @@ function createImperativeHandle(ctx) {
3723
3976
  state.contentInsetOverride = inset != null ? inset : void 0;
3724
3977
  updateScroll(ctx, state.scroll, true);
3725
3978
  },
3726
- scrollIndexIntoView,
3727
- scrollItemIntoView: ({ item, ...props }) => {
3979
+ scrollIndexIntoView: (options) => runScrollWithPromise(() => scrollIndexIntoView(options)),
3980
+ scrollItemIntoView: ({ item, ...props }) => runScrollWithPromise(() => {
3728
3981
  const data = state.props.data;
3729
3982
  const index = data.indexOf(item);
3730
3983
  if (index !== -1) {
3731
3984
  scrollIndexIntoView({ index, ...props });
3985
+ return true;
3732
3986
  }
3733
- },
3734
- scrollToEnd: (options) => {
3987
+ return false;
3988
+ }),
3989
+ scrollToEnd: (options) => runScrollWithPromise(() => {
3735
3990
  const data = state.props.data;
3736
3991
  const stylePaddingBottom = state.props.stylePaddingBottom;
3737
3992
  const index = data.length - 1;
@@ -3744,17 +3999,27 @@ function createImperativeHandle(ctx) {
3744
3999
  viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3745
4000
  viewPosition: 1
3746
4001
  });
4002
+ return true;
3747
4003
  }
3748
- },
3749
- scrollToIndex: (params) => scrollToIndex(ctx, params),
3750
- scrollToItem: ({ item, ...props }) => {
4004
+ return false;
4005
+ }),
4006
+ scrollToIndex: (params) => runScrollWithPromise(() => {
4007
+ scrollToIndex(ctx, params);
4008
+ return true;
4009
+ }),
4010
+ scrollToItem: ({ item, ...props }) => runScrollWithPromise(() => {
3751
4011
  const data = state.props.data;
3752
4012
  const index = data.indexOf(item);
3753
4013
  if (index !== -1) {
3754
4014
  scrollToIndex(ctx, { index, ...props });
4015
+ return true;
3755
4016
  }
3756
- },
3757
- scrollToOffset: (params) => scrollTo(ctx, params),
4017
+ return false;
4018
+ }),
4019
+ scrollToOffset: (params) => runScrollWithPromise(() => {
4020
+ scrollTo(ctx, params);
4021
+ return true;
4022
+ }),
3758
4023
  setScrollProcessingEnabled: (enabled) => {
3759
4024
  state.scrollProcessingEnabled = enabled;
3760
4025
  },
@@ -3991,6 +4256,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3991
4256
  refreshControl,
3992
4257
  refreshing,
3993
4258
  refScrollView,
4259
+ renderScrollComponent,
3994
4260
  renderItem,
3995
4261
  scrollEventThrottle,
3996
4262
  snapToIndices,
@@ -3999,15 +4265,18 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3999
4265
  // TODOV3: Remove from v3 release
4000
4266
  style: styleProp,
4001
4267
  suggestEstimatedItemSize,
4268
+ useWindowScroll = false,
4002
4269
  viewabilityConfig,
4003
4270
  viewabilityConfigCallbackPairs,
4004
4271
  waitForInitialLayout = true,
4005
4272
  ...rest
4006
4273
  } = props;
4007
4274
  const animatedPropsInternal = props.animatedPropsInternal;
4275
+ const positionComponentInternal = props.positionComponentInternal;
4008
4276
  const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
4009
4277
  const {
4010
4278
  childrenMode,
4279
+ positionComponentInternal: _positionComponentInternal,
4011
4280
  stickyPositionComponentInternal: _stickyPositionComponentInternal,
4012
4281
  ...restProps
4013
4282
  } = rest;
@@ -4062,6 +4331,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4062
4331
  "stickyIndices has been renamed to stickyHeaderIndices. Please update your props to use stickyHeaderIndices."
4063
4332
  );
4064
4333
  }
4334
+ if (IS_DEV && useWindowScroll && renderScrollComponent) {
4335
+ warnDevOnce(
4336
+ "useWindowScrollRenderScrollComponent",
4337
+ "useWindowScroll is not supported when renderScrollComponent is provided."
4338
+ );
4339
+ }
4340
+ const useWindowScrollResolved = !!useWindowScroll && !renderScrollComponent;
4065
4341
  const refState = React3.useRef();
4066
4342
  const hasOverrideItemLayout = !!overrideItemLayout;
4067
4343
  const prevHasOverrideItemLayout = React3.useRef(hasOverrideItemLayout);
@@ -4071,11 +4347,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4071
4347
  ctx.state = {
4072
4348
  activeStickyIndex: -1,
4073
4349
  averageSizes: {},
4074
- columnSpans: /* @__PURE__ */ new Map(),
4075
- columns: /* @__PURE__ */ new Map(),
4350
+ columnSpans: [],
4351
+ columns: [],
4076
4352
  containerItemKeys: /* @__PURE__ */ new Map(),
4077
4353
  containerItemTypes: /* @__PURE__ */ new Map(),
4078
4354
  contentInsetOverride: void 0,
4355
+ dataChangeEpoch: 0,
4079
4356
  dataChangeNeedsScrollUpdate: false,
4080
4357
  didColumnsChange: false,
4081
4358
  didDataChange: false,
@@ -4107,10 +4384,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4107
4384
  minIndexSizeChanged: 0,
4108
4385
  nativeContentInset: void 0,
4109
4386
  nativeMarginTop: 0,
4110
- positions: /* @__PURE__ */ new Map(),
4387
+ positions: [],
4111
4388
  props: {},
4112
4389
  queuedCalculateItemsInView: 0,
4113
- refScroller: void 0,
4390
+ refScroller: { current: null },
4114
4391
  scroll: 0,
4115
4392
  scrollAdjustHandler: new ScrollAdjustHandler(ctx),
4116
4393
  scrollForNextCalculateItemsInView: void 0,
@@ -4126,6 +4403,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4126
4403
  startBuffered: -1,
4127
4404
  startNoBuffer: -1,
4128
4405
  startReachedSnapshot: void 0,
4406
+ startReachedSnapshotDataChangeEpoch: void 0,
4129
4407
  stickyContainerPool: /* @__PURE__ */ new Set(),
4130
4408
  stickyContainers: /* @__PURE__ */ new Map(),
4131
4409
  timeoutSizeMessage: 0,
@@ -4145,6 +4423,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4145
4423
  state.didColumnsChange = numColumnsProp !== state.props.numColumns;
4146
4424
  const didDataChangeLocal = state.props.dataVersion !== dataVersion || state.props.data !== dataProp && checkActualChange(state, dataProp, state.props.data);
4147
4425
  if (didDataChangeLocal) {
4426
+ state.dataChangeEpoch += 1;
4148
4427
  state.dataChangeNeedsScrollUpdate = true;
4149
4428
  state.didDataChange = true;
4150
4429
  state.previousData = state.props.data;
@@ -4181,6 +4460,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4181
4460
  onStartReachedThreshold,
4182
4461
  onStickyHeaderChange,
4183
4462
  overrideItemLayout,
4463
+ positionComponentInternal,
4184
4464
  recycleItems: !!recycleItems,
4185
4465
  renderItem,
4186
4466
  snapToIndices,
@@ -4189,7 +4469,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4189
4469
  stickyPositionComponentInternal,
4190
4470
  stylePaddingBottom: stylePaddingBottomState,
4191
4471
  stylePaddingTop: stylePaddingTopState,
4192
- suggestEstimatedItemSize: !!suggestEstimatedItemSize
4472
+ suggestEstimatedItemSize: !!suggestEstimatedItemSize,
4473
+ useWindowScroll: useWindowScrollResolved
4193
4474
  };
4194
4475
  state.refScroller = refScroller;
4195
4476
  const memoizedLastItemKeys = React3.useMemo(() => {
@@ -4248,7 +4529,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4248
4529
  "Changing data without a keyExtractor can cause slow performance and resetting scroll. If your list data can change you should use a keyExtractor with a unique id for best performance and behavior."
4249
4530
  );
4250
4531
  refState.current.sizes.clear();
4251
- refState.current.positions.clear();
4532
+ refState.current.positions.length = 0;
4252
4533
  refState.current.totalSize = 0;
4253
4534
  set$(ctx, "totalSize", 0);
4254
4535
  }
@@ -4400,12 +4681,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4400
4681
  }
4401
4682
  ),
4402
4683
  refScrollView: combinedRef,
4684
+ renderScrollComponent,
4403
4685
  scrollAdjustHandler: (_d = refState.current) == null ? void 0 : _d.scrollAdjustHandler,
4404
4686
  scrollEventThrottle: 0,
4405
4687
  snapToIndices,
4406
4688
  stickyHeaderIndices,
4407
4689
  style,
4408
4690
  updateItemSize: fns.updateItemSize,
4691
+ useWindowScroll: useWindowScrollResolved,
4409
4692
  waitForInitialLayout
4410
4693
  }
4411
4694
  ), IS_DEV && ENABLE_DEBUG_VIEW);