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

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.mjs CHANGED
@@ -293,8 +293,15 @@ var PositionViewState = typedMemo(function PositionViewState2({
293
293
  };
294
294
  const composed = isArray(style) ? Object.assign({}, ...style) : style;
295
295
  const combinedStyle = horizontal ? { ...base, ...composed, left: position } : { ...base, ...composed, top: position };
296
- const { animatedScrollY, onLayout, index, ...webProps } = props;
297
- return /* @__PURE__ */ React3.createElement("div", { ref: refView, ...webProps, style: combinedStyle });
296
+ const {
297
+ animatedScrollY: _animatedScrollY,
298
+ index,
299
+ onLayout: _onLayout,
300
+ onLayoutChange: _onLayoutChange,
301
+ stickyHeaderConfig: _stickyHeaderConfig,
302
+ ...webProps
303
+ } = props;
304
+ return /* @__PURE__ */ React3.createElement("div", { "data-index": index, ref: refView, ...webProps, style: combinedStyle });
298
305
  });
299
306
  var PositionViewSticky = typedMemo(function PositionViewSticky2({
300
307
  id,
@@ -304,8 +311,10 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
304
311
  index,
305
312
  animatedScrollY: _animatedScrollY,
306
313
  stickyHeaderConfig,
314
+ onLayout: _onLayout,
315
+ onLayoutChange: _onLayoutChange,
307
316
  children,
308
- ...rest
317
+ ...webProps
309
318
  }) {
310
319
  const [position = POSITION_OUT_OF_VIEW, activeStickyIndex] = useArr$([
311
320
  `containerPosition${id}`,
@@ -337,7 +346,7 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
337
346
  }
338
347
  return styleBase;
339
348
  }, [composed, horizontal, position, index, activeStickyIndex, stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset]);
340
- return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
349
+ return /* @__PURE__ */ React3.createElement("div", { "data-index": index, ref: refView, style: viewStyle, ...webProps }, children);
341
350
  });
342
351
  var PositionView = PositionViewState;
343
352
  function useInit(cb) {
@@ -624,6 +633,7 @@ var Container = typedMemo(function Container2({
624
633
  }) {
625
634
  const ctx = useStateContext();
626
635
  const { columnWrapperStyle, animatedScrollY } = ctx;
636
+ const positionComponentInternal = ctx.state.props.positionComponentInternal;
627
637
  const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
628
638
  const [column = 0, span = 1, data, itemKey, numColumns = 1, extraData, isSticky] = useArr$([
629
639
  `containerColumn${id}`,
@@ -750,7 +760,7 @@ var Container = typedMemo(function Container2({
750
760
  },
751
761
  [itemKey, layoutRenderCount]
752
762
  );
753
- const PositionComponent = isSticky ? stickyPositionComponentInternal ? stickyPositionComponentInternal : PositionViewSticky : PositionView;
763
+ const PositionComponent = isSticky ? stickyPositionComponentInternal ? stickyPositionComponentInternal : PositionViewSticky : positionComponentInternal ? positionComponentInternal : PositionView;
754
764
  return /* @__PURE__ */ React3.createElement(
755
765
  PositionComponent,
756
766
  {
@@ -770,8 +780,12 @@ var Container = typedMemo(function Container2({
770
780
 
771
781
  // src/utils/reordering.ts
772
782
  var mapFn = (element) => {
773
- const indexStr = element.getAttribute("index");
774
- return [element, indexStr === null ? null : parseInt(indexStr)];
783
+ const indexStr = element.getAttribute("data-index");
784
+ if (indexStr === null) {
785
+ return [element, null];
786
+ }
787
+ const index = Number.parseInt(indexStr, 10);
788
+ return [element, Number.isNaN(index) ? null : index];
775
789
  };
776
790
  function sortDOMElements(container) {
777
791
  const elements = Array.from(container.children);
@@ -951,6 +965,89 @@ var StyleSheet = {
951
965
  flatten: (style) => flattenStyles(style)
952
966
  };
953
967
 
968
+ // src/components/webScrollUtils.ts
969
+ function getDocumentScrollerNode() {
970
+ if (typeof document === "undefined") {
971
+ return null;
972
+ }
973
+ return document.scrollingElement || document.documentElement || document.body;
974
+ }
975
+ function getWindowScrollPosition() {
976
+ var _a3, _b, _c, _d;
977
+ if (typeof window === "undefined") {
978
+ return { x: 0, y: 0 };
979
+ }
980
+ return {
981
+ x: (_b = (_a3 = window.scrollX) != null ? _a3 : window.pageXOffset) != null ? _b : 0,
982
+ y: (_d = (_c = window.scrollY) != null ? _c : window.pageYOffset) != null ? _d : 0
983
+ };
984
+ }
985
+ function getElementDocumentPosition(element, scroll) {
986
+ var _a3, _b;
987
+ const rect = element == null ? void 0 : element.getBoundingClientRect();
988
+ return {
989
+ left: ((_a3 = rect == null ? void 0 : rect.left) != null ? _a3 : 0) + scroll.x,
990
+ top: ((_b = rect == null ? void 0 : rect.top) != null ? _b : 0) + scroll.y
991
+ };
992
+ }
993
+ function getContentSize2(content) {
994
+ var _a3, _b;
995
+ return {
996
+ height: (_a3 = content == null ? void 0 : content.scrollHeight) != null ? _a3 : 0,
997
+ width: (_b = content == null ? void 0 : content.scrollWidth) != null ? _b : 0
998
+ };
999
+ }
1000
+ function getScrollContentSize(scrollElement, contentElement, isWindowScroll) {
1001
+ return getContentSize2(isWindowScroll ? contentElement : scrollElement);
1002
+ }
1003
+ function getLayoutMeasurement(scrollElement, isWindowScroll, horizontal) {
1004
+ var _a3, _b, _c, _d, _e, _f;
1005
+ if (isWindowScroll && typeof window !== "undefined") {
1006
+ const rect = scrollElement == null ? void 0 : scrollElement.getBoundingClientRect();
1007
+ return {
1008
+ // In window-scroll mode, use viewport size on the scroll axis.
1009
+ height: horizontal ? (_b = (_a3 = rect == null ? void 0 : rect.height) != null ? _a3 : scrollElement == null ? void 0 : scrollElement.clientHeight) != null ? _b : window.innerHeight : window.innerHeight,
1010
+ // Keep the cross-axis size list-relative to avoid inflating container measurements.
1011
+ width: horizontal ? window.innerWidth : (_d = (_c = rect == null ? void 0 : rect.width) != null ? _c : scrollElement == null ? void 0 : scrollElement.clientWidth) != null ? _d : window.innerWidth
1012
+ };
1013
+ }
1014
+ return {
1015
+ height: (_e = scrollElement == null ? void 0 : scrollElement.clientHeight) != null ? _e : 0,
1016
+ width: (_f = scrollElement == null ? void 0 : scrollElement.clientWidth) != null ? _f : 0
1017
+ };
1018
+ }
1019
+ function clampOffset(offset, maxOffset) {
1020
+ return Math.max(0, Math.min(offset, maxOffset));
1021
+ }
1022
+ function getAxisSize(size, horizontal) {
1023
+ return horizontal ? size.width : size.height;
1024
+ }
1025
+ function getMaxOffset(contentSize, layoutMeasurement, horizontal) {
1026
+ return Math.max(0, getAxisSize(contentSize, horizontal) - getAxisSize(layoutMeasurement, horizontal));
1027
+ }
1028
+ function resolveScrollableNode(scrollElement, isWindowScroll) {
1029
+ return isWindowScroll ? getDocumentScrollerNode() || scrollElement : scrollElement;
1030
+ }
1031
+ function resolveScrollEventTarget(scrollElement, isWindowScroll) {
1032
+ return isWindowScroll && typeof window !== "undefined" ? window : scrollElement;
1033
+ }
1034
+ function getLayoutRectangle(element, isWindowScroll, horizontal) {
1035
+ const rect = element.getBoundingClientRect();
1036
+ const scroll = getWindowScrollPosition();
1037
+ return {
1038
+ height: isWindowScroll && typeof window !== "undefined" && !horizontal ? window.innerHeight : rect.height,
1039
+ width: isWindowScroll && typeof window !== "undefined" && horizontal ? window.innerWidth : rect.width,
1040
+ x: isWindowScroll ? rect.left + scroll.x : rect.left,
1041
+ y: isWindowScroll ? rect.top + scroll.y : rect.top
1042
+ };
1043
+ }
1044
+ function resolveWindowScrollTarget({ clampedOffset, horizontal, listPos, scroll }) {
1045
+ return {
1046
+ left: horizontal ? listPos.left + clampedOffset : scroll.x,
1047
+ top: horizontal ? scroll.y : listPos.top + clampedOffset
1048
+ };
1049
+ }
1050
+
954
1051
  // src/components/ListComponentScrollView.tsx
955
1052
  var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
956
1053
  children,
@@ -960,114 +1057,163 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
960
1057
  contentOffset,
961
1058
  maintainVisibleContentPosition,
962
1059
  onScroll: onScroll2,
963
- onMomentumScrollEnd,
1060
+ onMomentumScrollEnd: _onMomentumScrollEnd,
964
1061
  showsHorizontalScrollIndicator = true,
965
1062
  showsVerticalScrollIndicator = true,
966
1063
  refreshControl,
1064
+ useWindowScroll = false,
967
1065
  onLayout,
968
1066
  ...props
969
1067
  }, ref) {
970
1068
  const scrollRef = useRef(null);
971
1069
  const contentRef = useRef(null);
1070
+ const isWindowScroll = useWindowScroll;
1071
+ const getScrollTarget = useCallback(
1072
+ () => resolveScrollEventTarget(scrollRef.current, isWindowScroll),
1073
+ [isWindowScroll]
1074
+ );
1075
+ const getMaxScrollOffset = useCallback(() => {
1076
+ const scrollElement = scrollRef.current;
1077
+ const contentSize = getScrollContentSize(scrollElement, contentRef.current, isWindowScroll);
1078
+ const layoutMeasurement = getLayoutMeasurement(scrollElement, isWindowScroll, horizontal);
1079
+ return getMaxOffset(contentSize, layoutMeasurement, horizontal);
1080
+ }, [horizontal, isWindowScroll]);
1081
+ const getCurrentScrollOffset = useCallback(() => {
1082
+ const scrollElement = scrollRef.current;
1083
+ if (isWindowScroll) {
1084
+ const maxOffset = getMaxScrollOffset();
1085
+ const scroll = getWindowScrollPosition();
1086
+ const listPos = getElementDocumentPosition(scrollElement, scroll);
1087
+ const rawOffset = horizontal ? scroll.x - listPos.left : scroll.y - listPos.top;
1088
+ return clampOffset(rawOffset, maxOffset);
1089
+ }
1090
+ if (!scrollElement) {
1091
+ return 0;
1092
+ }
1093
+ return horizontal ? scrollElement.scrollLeft : scrollElement.scrollTop;
1094
+ }, [getMaxScrollOffset, horizontal, isWindowScroll]);
1095
+ const scrollToLocalOffset = useCallback(
1096
+ (offset, animated) => {
1097
+ const scrollElement = scrollRef.current;
1098
+ const target = getScrollTarget();
1099
+ if (!target || typeof target.scrollTo !== "function") {
1100
+ return;
1101
+ }
1102
+ const maxOffset = getMaxScrollOffset();
1103
+ const clampedOffset = clampOffset(offset, maxOffset);
1104
+ const behavior = animated ? "smooth" : "auto";
1105
+ const options = { behavior };
1106
+ if (isWindowScroll) {
1107
+ const scroll = getWindowScrollPosition();
1108
+ const listPos = getElementDocumentPosition(scrollElement, scroll);
1109
+ const { left, top } = resolveWindowScrollTarget({
1110
+ clampedOffset,
1111
+ horizontal,
1112
+ listPos,
1113
+ scroll
1114
+ });
1115
+ options.left = left;
1116
+ options.top = top;
1117
+ } else if (horizontal) {
1118
+ options.left = clampedOffset;
1119
+ } else {
1120
+ options.top = clampedOffset;
1121
+ }
1122
+ target.scrollTo(options);
1123
+ },
1124
+ [getMaxScrollOffset, getScrollTarget, horizontal, isWindowScroll]
1125
+ );
972
1126
  useImperativeHandle(ref, () => {
973
1127
  const api = {
974
1128
  getBoundingClientRect: () => {
975
1129
  var _a3;
976
1130
  return (_a3 = scrollRef.current) == null ? void 0 : _a3.getBoundingClientRect();
977
1131
  },
978
- getScrollableNode: () => scrollRef.current,
979
- getScrollResponder: () => scrollRef.current,
1132
+ getContentNode: () => contentRef.current,
1133
+ getCurrentScrollOffset,
1134
+ getScrollableNode: () => resolveScrollableNode(scrollRef.current, isWindowScroll),
1135
+ getScrollEventTarget: () => getScrollTarget(),
1136
+ getScrollResponder: () => resolveScrollableNode(scrollRef.current, isWindowScroll),
1137
+ isWindowScroll: () => isWindowScroll,
980
1138
  scrollBy: (x, y) => {
981
- const el = scrollRef.current;
982
- if (!el) return;
983
- el.scrollBy(x, y);
1139
+ const target = getScrollTarget();
1140
+ if (!target || typeof target.scrollBy !== "function") {
1141
+ return;
1142
+ }
1143
+ target.scrollBy({ behavior: "auto", left: x, top: y });
984
1144
  },
985
1145
  scrollTo: (options) => {
986
- const el = scrollRef.current;
987
- if (!el) return;
988
1146
  const { x = 0, y = 0, animated = true } = options;
989
- el.scrollTo({ behavior: animated ? "smooth" : "auto", left: x, top: y });
1147
+ scrollToLocalOffset(horizontal ? x : y, animated);
990
1148
  },
991
1149
  scrollToEnd: (options = {}) => {
992
- const el = scrollRef.current;
993
- if (!el) return;
994
1150
  const { animated = true } = options;
995
- if (horizontal) {
996
- el.scrollTo({ behavior: animated ? "smooth" : "auto", left: el.scrollWidth });
997
- } else {
998
- el.scrollTo({ behavior: animated ? "smooth" : "auto", top: el.scrollHeight });
999
- }
1151
+ const endOffset = getMaxScrollOffset();
1152
+ scrollToLocalOffset(endOffset, animated);
1000
1153
  },
1001
1154
  scrollToOffset: (params) => {
1002
- const el = scrollRef.current;
1003
- if (!el) return;
1004
1155
  const { offset, animated = true } = params;
1005
- if (horizontal) {
1006
- el.scrollTo({ behavior: animated ? "smooth" : "auto", left: offset });
1007
- } else {
1008
- el.scrollTo({ behavior: animated ? "smooth" : "auto", top: offset });
1009
- }
1156
+ scrollToLocalOffset(offset, animated);
1010
1157
  }
1011
1158
  };
1012
1159
  return api;
1013
- }, [horizontal]);
1160
+ }, [getCurrentScrollOffset, getMaxScrollOffset, getScrollTarget, horizontal, isWindowScroll, scrollToLocalOffset]);
1014
1161
  const handleScroll = useCallback(
1015
- (event) => {
1016
- if (!onScroll2 || !(event == null ? void 0 : event.target)) {
1162
+ (_event) => {
1163
+ if (!onScroll2) {
1164
+ return;
1165
+ }
1166
+ const target = scrollRef.current;
1167
+ if (!target) {
1017
1168
  return;
1018
1169
  }
1019
- const target = event.target;
1170
+ const contentSize = getContentSize2(contentRef.current);
1171
+ const layoutMeasurement = getLayoutMeasurement(scrollRef.current, isWindowScroll, horizontal);
1172
+ const offset = getCurrentScrollOffset();
1020
1173
  const scrollEvent = {
1021
1174
  nativeEvent: {
1022
1175
  contentOffset: {
1023
- x: target.scrollLeft,
1024
- y: target.scrollTop
1176
+ x: horizontal ? offset : 0,
1177
+ y: horizontal ? 0 : offset
1025
1178
  },
1026
1179
  contentSize: {
1027
- height: target.scrollHeight,
1028
- width: target.scrollWidth
1180
+ height: contentSize.height,
1181
+ width: contentSize.width
1029
1182
  },
1030
1183
  layoutMeasurement: {
1031
- height: target.clientHeight,
1032
- width: target.clientWidth
1184
+ height: layoutMeasurement.height,
1185
+ width: layoutMeasurement.width
1033
1186
  }
1034
1187
  }
1035
1188
  };
1036
1189
  onScroll2(scrollEvent);
1037
1190
  },
1038
- [onScroll2, onMomentumScrollEnd]
1191
+ [getCurrentScrollOffset, horizontal, isWindowScroll, onScroll2]
1039
1192
  );
1040
1193
  useLayoutEffect(() => {
1041
- const element = scrollRef.current;
1042
- if (!element) return;
1043
- element.addEventListener("scroll", handleScroll);
1194
+ const target = getScrollTarget();
1195
+ if (!target) return;
1196
+ target.addEventListener("scroll", handleScroll, { passive: true });
1044
1197
  return () => {
1045
- element.removeEventListener("scroll", handleScroll);
1198
+ target.removeEventListener("scroll", handleScroll);
1046
1199
  };
1047
- }, [handleScroll]);
1200
+ }, [getScrollTarget, handleScroll]);
1048
1201
  useEffect(() => {
1049
1202
  const doScroll = () => {
1050
- if (contentOffset && scrollRef.current) {
1051
- scrollRef.current.scrollLeft = contentOffset.x || 0;
1052
- scrollRef.current.scrollTop = contentOffset.y || 0;
1203
+ if (contentOffset) {
1204
+ scrollToLocalOffset(horizontal ? contentOffset.x || 0 : contentOffset.y || 0, false);
1053
1205
  }
1054
1206
  };
1055
1207
  doScroll();
1056
1208
  requestAnimationFrame(doScroll);
1057
- }, [contentOffset == null ? void 0 : contentOffset.x, contentOffset == null ? void 0 : contentOffset.y]);
1209
+ }, [contentOffset == null ? void 0 : contentOffset.x, contentOffset == null ? void 0 : contentOffset.y, horizontal, scrollToLocalOffset]);
1058
1210
  useLayoutEffect(() => {
1059
1211
  if (!onLayout || !scrollRef.current) return;
1060
1212
  const element = scrollRef.current;
1061
1213
  const fireLayout = () => {
1062
- const rect = element.getBoundingClientRect();
1063
1214
  onLayout({
1064
1215
  nativeEvent: {
1065
- layout: {
1066
- height: rect.height,
1067
- width: rect.width,
1068
- x: rect.left,
1069
- y: rect.top
1070
- }
1216
+ layout: getLayoutRectangle(element, isWindowScroll, horizontal)
1071
1217
  }
1072
1218
  });
1073
1219
  };
@@ -1076,16 +1222,27 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1076
1222
  fireLayout();
1077
1223
  });
1078
1224
  resizeObserver.observe(element);
1079
- return () => resizeObserver.disconnect();
1080
- }, [onLayout]);
1225
+ const onWindowResize = () => {
1226
+ fireLayout();
1227
+ };
1228
+ if (isWindowScroll && typeof window !== "undefined" && typeof window.addEventListener === "function") {
1229
+ window.addEventListener("resize", onWindowResize);
1230
+ }
1231
+ return () => {
1232
+ resizeObserver.disconnect();
1233
+ if (isWindowScroll && typeof window !== "undefined" && typeof window.removeEventListener === "function") {
1234
+ window.removeEventListener("resize", onWindowResize);
1235
+ }
1236
+ };
1237
+ }, [isWindowScroll, onLayout]);
1081
1238
  const scrollViewStyle = {
1082
- overflow: "auto",
1083
- overflowX: horizontal ? "auto" : showsHorizontalScrollIndicator ? "auto" : "hidden",
1084
- overflowY: horizontal ? showsVerticalScrollIndicator ? "auto" : "hidden" : "auto",
1085
- position: "relative",
1086
- // Ensure proper positioning context
1087
- WebkitOverflowScrolling: "touch",
1088
- // iOS momentum scrolling
1239
+ ...isWindowScroll ? {} : {
1240
+ overflow: "auto",
1241
+ overflowX: horizontal ? "auto" : showsHorizontalScrollIndicator ? "auto" : "hidden",
1242
+ overflowY: horizontal ? showsVerticalScrollIndicator ? "auto" : "hidden" : "auto",
1243
+ WebkitOverflowScrolling: "touch"
1244
+ // iOS momentum scrolling
1245
+ },
1089
1246
  ...StyleSheet.flatten(style)
1090
1247
  };
1091
1248
  const contentStyle = {
@@ -1095,7 +1252,13 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1095
1252
  minWidth: horizontal ? "100%" : void 0,
1096
1253
  ...StyleSheet.flatten(contentContainerStyle)
1097
1254
  };
1098
- const { contentInset, scrollEventThrottle, ScrollComponent, ...webProps } = props;
1255
+ const {
1256
+ contentInset: _contentInset,
1257
+ scrollEventThrottle: _scrollEventThrottle,
1258
+ ScrollComponent: _ScrollComponent,
1259
+ useWindowScroll: _useWindowScroll,
1260
+ ...webProps
1261
+ } = props;
1099
1262
  return /* @__PURE__ */ React3.createElement("div", { ref: scrollRef, ...webProps, style: scrollViewStyle }, refreshControl, /* @__PURE__ */ React3.createElement("div", { ref: contentRef, style: contentStyle }, children));
1100
1263
  });
1101
1264
  function useValueListener$(key, callback) {
@@ -1122,23 +1285,29 @@ function ScrollAdjust() {
1122
1285
  if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
1123
1286
  const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1124
1287
  if (scrollDelta !== 0) {
1288
+ const contentNode = scrollView.getContentNode();
1289
+ const prevScroll = scrollView.getCurrentScrollOffset();
1125
1290
  const el = scrollView.getScrollableNode();
1126
- const prevScroll = el.scrollTop;
1291
+ if (!contentNode) {
1292
+ scrollView.scrollBy(0, scrollDelta);
1293
+ lastScrollOffsetRef.current = scrollOffset;
1294
+ return;
1295
+ }
1296
+ const totalSize = contentNode.scrollHeight;
1297
+ const viewportSize = el.clientHeight;
1127
1298
  const nextScroll = prevScroll + scrollDelta;
1128
- const totalSize = el.scrollHeight;
1129
- if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
1299
+ if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize) {
1130
1300
  const paddingBottom = ctx.state.props.stylePaddingBottom || 0;
1131
- const child = el.firstElementChild;
1132
- const pad = (nextScroll + el.clientHeight - totalSize) * 2;
1133
- child.style.paddingBottom = `${pad}px`;
1134
- void el.offsetHeight;
1301
+ const pad = (nextScroll + viewportSize - totalSize) * 2;
1302
+ contentNode.style.paddingBottom = `${pad}px`;
1303
+ void contentNode.offsetHeight;
1135
1304
  scrollView.scrollBy(0, scrollDelta);
1136
1305
  if (resetPaddingRafRef.current !== void 0) {
1137
1306
  cancelAnimationFrame(resetPaddingRafRef.current);
1138
1307
  }
1139
1308
  resetPaddingRafRef.current = requestAnimationFrame(() => {
1140
1309
  resetPaddingRafRef.current = void 0;
1141
- child.style.paddingBottom = paddingBottom ? `${paddingBottom}px` : "0";
1310
+ contentNode.style.paddingBottom = paddingBottom ? `${paddingBottom}px` : "0";
1142
1311
  });
1143
1312
  } else {
1144
1313
  scrollView.scrollBy(0, scrollDelta);
@@ -1197,6 +1366,7 @@ var ListComponent = typedMemo(function ListComponent2({
1197
1366
  snapToIndices,
1198
1367
  stickyHeaderConfig,
1199
1368
  stickyHeaderIndices,
1369
+ useWindowScroll = false,
1200
1370
  ...rest
1201
1371
  }) {
1202
1372
  const ctx = useStateContext();
@@ -1220,6 +1390,7 @@ var ListComponent = typedMemo(function ListComponent2({
1220
1390
  SnapOrScroll,
1221
1391
  {
1222
1392
  ...rest,
1393
+ ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
1223
1394
  contentContainerStyle: [
1224
1395
  contentContainerStyle,
1225
1396
  horizontal ? {
@@ -1265,24 +1436,12 @@ var ListComponent = typedMemo(function ListComponent2({
1265
1436
  );
1266
1437
  });
1267
1438
 
1268
- // src/utils/getId.ts
1269
- function getId(state, index) {
1270
- const { data, keyExtractor } = state.props;
1271
- if (!data) {
1272
- return "";
1273
- }
1274
- const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
1275
- const id = ret;
1276
- state.idCache[index] = id;
1277
- return id;
1278
- }
1279
-
1280
1439
  // src/core/calculateOffsetForIndex.ts
1281
1440
  function calculateOffsetForIndex(ctx, index) {
1282
1441
  const state = ctx.state;
1283
1442
  let position = 0;
1284
1443
  if (index !== void 0) {
1285
- position = state.positions.get(getId(state, index)) || 0;
1444
+ position = state.positions[index] || 0;
1286
1445
  const paddingTop = peek$(ctx, "stylePaddingTop");
1287
1446
  if (paddingTop) {
1288
1447
  position += paddingTop;
@@ -1295,6 +1454,18 @@ function calculateOffsetForIndex(ctx, index) {
1295
1454
  return position;
1296
1455
  }
1297
1456
 
1457
+ // src/utils/getId.ts
1458
+ function getId(state, index) {
1459
+ const { data, keyExtractor } = state.props;
1460
+ if (!data) {
1461
+ return "";
1462
+ }
1463
+ const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
1464
+ const id = ret;
1465
+ state.idCache[index] = id;
1466
+ return id;
1467
+ }
1468
+
1298
1469
  // src/core/addTotalSize.ts
1299
1470
  function addTotalSize(ctx, key, add) {
1300
1471
  const state = ctx.state;
@@ -1346,13 +1517,13 @@ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize) {
1346
1517
  return sizeKnown;
1347
1518
  }
1348
1519
  let size;
1349
- const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1350
1520
  if (preferCachedSize) {
1351
1521
  const cachedSize = sizes.get(key);
1352
1522
  if (cachedSize !== void 0) {
1353
1523
  return cachedSize;
1354
1524
  }
1355
1525
  }
1526
+ const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1356
1527
  if (getFixedItemSize) {
1357
1528
  size = getFixedItemSize(data, index, itemType);
1358
1529
  if (size !== void 0) {
@@ -1496,37 +1667,54 @@ function checkAtBottom(ctx) {
1496
1667
 
1497
1668
  // src/utils/checkAtTop.ts
1498
1669
  function checkAtTop(ctx) {
1499
- var _a3;
1500
1670
  const state = ctx == null ? void 0 : ctx.state;
1501
1671
  if (!state || state.initialScroll || state.scrollingTo) {
1502
1672
  return;
1503
1673
  }
1504
1674
  const {
1505
- scrollLength,
1675
+ dataChangeEpoch,
1676
+ isStartReached,
1677
+ props: { data, onStartReachedThreshold },
1506
1678
  scroll,
1507
- props: { onStartReachedThreshold }
1679
+ scrollLength,
1680
+ startReachedSnapshot,
1681
+ startReachedSnapshotDataChangeEpoch,
1682
+ totalSize
1508
1683
  } = state;
1509
- const distanceFromTop = scroll;
1510
- state.isAtStart = distanceFromTop <= 0;
1684
+ const dataLength = data.length;
1685
+ const threshold = onStartReachedThreshold * scrollLength;
1686
+ const dataChanged = startReachedSnapshotDataChangeEpoch !== dataChangeEpoch;
1687
+ const withinThreshold = threshold > 0 && Math.abs(scroll) <= threshold;
1688
+ const allowReentryOnDataChange = !!isStartReached && withinThreshold && !!dataChanged && !isInMVCPActiveMode(state);
1689
+ if (isStartReached && threshold > 0 && scroll > threshold && startReachedSnapshot && (dataChanged || startReachedSnapshot.contentSize !== totalSize || startReachedSnapshot.dataLength !== dataLength)) {
1690
+ state.isStartReached = false;
1691
+ state.startReachedSnapshot = void 0;
1692
+ state.startReachedSnapshotDataChangeEpoch = void 0;
1693
+ }
1694
+ state.isAtStart = scroll <= 0;
1695
+ if (isStartReached && withinThreshold && dataChanged && !allowReentryOnDataChange) {
1696
+ return;
1697
+ }
1511
1698
  state.isStartReached = checkThreshold(
1512
- distanceFromTop,
1699
+ scroll,
1513
1700
  false,
1514
- onStartReachedThreshold * scrollLength,
1701
+ threshold,
1515
1702
  state.isStartReached,
1516
- state.startReachedSnapshot,
1703
+ allowReentryOnDataChange ? void 0 : startReachedSnapshot,
1517
1704
  {
1518
- contentSize: state.totalSize,
1519
- dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length,
1705
+ contentSize: totalSize,
1706
+ dataLength,
1520
1707
  scrollPosition: scroll
1521
1708
  },
1522
1709
  (distance) => {
1523
- var _a4, _b;
1524
- return (_b = (_a4 = state.props).onStartReached) == null ? void 0 : _b.call(_a4, { distanceFromStart: distance });
1710
+ var _a3, _b;
1711
+ return (_b = (_a3 = state.props).onStartReached) == null ? void 0 : _b.call(_a3, { distanceFromStart: distance });
1525
1712
  },
1526
1713
  (snapshot) => {
1527
1714
  state.startReachedSnapshot = snapshot;
1715
+ state.startReachedSnapshotDataChangeEpoch = snapshot ? dataChangeEpoch : void 0;
1528
1716
  },
1529
- false
1717
+ allowReentryOnDataChange
1530
1718
  );
1531
1719
  }
1532
1720
 
@@ -1566,6 +1754,8 @@ function finishScrollTo(ctx) {
1566
1754
  var _a3, _b;
1567
1755
  const state = ctx.state;
1568
1756
  if (state == null ? void 0 : state.scrollingTo) {
1757
+ const resolvePendingScroll = state.pendingScrollResolve;
1758
+ state.pendingScrollResolve = void 0;
1569
1759
  const scrollingTo = state.scrollingTo;
1570
1760
  state.scrollHistory.length = 0;
1571
1761
  state.initialScroll = void 0;
@@ -1582,6 +1772,7 @@ function finishScrollTo(ctx) {
1582
1772
  }
1583
1773
  setInitialRenderState(ctx, { didInitialScroll: true });
1584
1774
  checkThresholds(ctx);
1775
+ resolvePendingScroll == null ? void 0 : resolvePendingScroll();
1585
1776
  }
1586
1777
  }
1587
1778
 
@@ -1594,42 +1785,49 @@ function doScrollTo(ctx, params) {
1594
1785
  const state = ctx.state;
1595
1786
  const { animated, horizontal, offset } = params;
1596
1787
  const scroller = state.refScroller.current;
1597
- const node = typeof (scroller == null ? void 0 : scroller.getScrollableNode) === "function" ? scroller.getScrollableNode() : scroller;
1598
- if (node) {
1599
- const left = horizontal ? offset : 0;
1600
- const top = horizontal ? 0 : offset;
1601
- node.scrollTo({ behavior: animated ? "smooth" : "auto", left, top });
1602
- if (animated) {
1603
- listenForScrollEnd(ctx, node, {
1604
- horizontal: !!horizontal,
1605
- targetOffset: offset
1606
- });
1607
- } else {
1608
- state.scroll = offset;
1609
- setTimeout(() => {
1610
- finishScrollTo(ctx);
1611
- }, 100);
1612
- }
1788
+ const node = scroller == null ? void 0 : scroller.getScrollableNode();
1789
+ if (!scroller || !node) {
1790
+ return;
1791
+ }
1792
+ const isAnimated = !!animated;
1793
+ const isHorizontal = !!horizontal;
1794
+ const left = isHorizontal ? offset : 0;
1795
+ const top = isHorizontal ? 0 : offset;
1796
+ scroller.scrollTo({ animated: isAnimated, x: left, y: top });
1797
+ if (isAnimated) {
1798
+ const target = scroller.getScrollEventTarget();
1799
+ listenForScrollEnd(ctx, {
1800
+ readOffset: () => scroller.getCurrentScrollOffset(),
1801
+ target,
1802
+ targetOffset: offset
1803
+ });
1804
+ } else {
1805
+ state.scroll = offset;
1806
+ setTimeout(() => {
1807
+ finishScrollTo(ctx);
1808
+ }, 100);
1613
1809
  }
1614
1810
  }
1615
- function listenForScrollEnd(ctx, node, params) {
1616
- const { horizontal, targetOffset } = params;
1617
- const supportsScrollEnd = "onscrollend" in node;
1811
+ function listenForScrollEnd(ctx, params) {
1812
+ const { readOffset, target, targetOffset } = params;
1813
+ if (!target) {
1814
+ finishScrollTo(ctx);
1815
+ return;
1816
+ }
1817
+ const supportsScrollEnd = "onscrollend" in target;
1618
1818
  let idleTimeout;
1619
- let maxTimeout;
1620
1819
  let settled = false;
1621
1820
  const targetToken = ctx.state.scrollingTo;
1821
+ const maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1622
1822
  const cleanup = () => {
1623
- node.removeEventListener("scroll", onScroll2);
1823
+ target.removeEventListener("scroll", onScroll2);
1624
1824
  if (supportsScrollEnd) {
1625
- node.removeEventListener("scrollend", onScrollEnd);
1825
+ target.removeEventListener("scrollend", onScrollEnd);
1626
1826
  }
1627
1827
  if (idleTimeout) {
1628
1828
  clearTimeout(idleTimeout);
1629
1829
  }
1630
- if (maxTimeout) {
1631
- clearTimeout(maxTimeout);
1632
- }
1830
+ clearTimeout(maxTimeout);
1633
1831
  };
1634
1832
  const finish = (reason) => {
1635
1833
  if (settled) return;
@@ -1638,7 +1836,7 @@ function listenForScrollEnd(ctx, node, params) {
1638
1836
  cleanup();
1639
1837
  return;
1640
1838
  }
1641
- const currentOffset = horizontal ? node.scrollLeft : node.scrollTop;
1839
+ const currentOffset = readOffset();
1642
1840
  const isNearTarget = Math.abs(currentOffset - targetOffset) <= SCROLL_END_TARGET_EPSILON;
1643
1841
  if (reason === "scrollend" && !isNearTarget) {
1644
1842
  return;
@@ -1654,13 +1852,11 @@ function listenForScrollEnd(ctx, node, params) {
1654
1852
  idleTimeout = setTimeout(() => finish("idle"), SCROLL_END_IDLE_MS);
1655
1853
  };
1656
1854
  const onScrollEnd = () => finish("scrollend");
1657
- node.addEventListener("scroll", onScroll2);
1855
+ target.addEventListener("scroll", onScroll2);
1658
1856
  if (supportsScrollEnd) {
1659
- node.addEventListener("scrollend", onScrollEnd);
1660
- maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1857
+ target.addEventListener("scrollend", onScrollEnd);
1661
1858
  } else {
1662
1859
  idleTimeout = setTimeout(() => finish("idle"), SMOOTH_SCROLL_DURATION_MS);
1663
- maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1664
1860
  }
1665
1861
  }
1666
1862
 
@@ -1695,7 +1891,7 @@ function scrollTo(ctx, params) {
1695
1891
  // src/core/updateScroll.ts
1696
1892
  function updateScroll(ctx, newScroll, forceUpdate) {
1697
1893
  const state = ctx.state;
1698
- const { scrollingTo, scrollAdjustHandler, lastScrollAdjustForHistory } = state;
1894
+ const { ignoreScrollFromMVCP, lastScrollAdjustForHistory, scrollAdjustHandler, scrollHistory, scrollingTo } = state;
1699
1895
  const prevScroll = state.scroll;
1700
1896
  state.hasScrolled = true;
1701
1897
  state.lastBatchingAction = Date.now();
@@ -1703,22 +1899,17 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1703
1899
  const adjust = scrollAdjustHandler.getAdjust();
1704
1900
  const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
1705
1901
  if (adjustChanged) {
1706
- state.scrollHistory.length = 0;
1902
+ scrollHistory.length = 0;
1707
1903
  }
1708
1904
  state.lastScrollAdjustForHistory = adjust;
1709
- if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
1905
+ if (scrollingTo === void 0 && !(scrollHistory.length === 0 && newScroll === state.scroll)) {
1710
1906
  if (!adjustChanged) {
1711
- state.scrollHistory.push({ scroll: newScroll, time: currentTime });
1907
+ scrollHistory.push({ scroll: newScroll, time: currentTime });
1712
1908
  }
1713
1909
  }
1714
- if (state.scrollHistory.length > 5) {
1715
- state.scrollHistory.shift();
1910
+ if (scrollHistory.length > 5) {
1911
+ scrollHistory.shift();
1716
1912
  }
1717
- state.scrollPrev = prevScroll;
1718
- state.scrollPrevTime = state.scrollTime;
1719
- state.scroll = newScroll;
1720
- state.scrollTime = currentTime;
1721
- const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
1722
1913
  if (ignoreScrollFromMVCP && !scrollingTo) {
1723
1914
  const { lt, gt } = ignoreScrollFromMVCP;
1724
1915
  if (lt && newScroll < lt || gt && newScroll > gt) {
@@ -1726,6 +1917,10 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1726
1917
  return;
1727
1918
  }
1728
1919
  }
1920
+ state.scrollPrev = prevScroll;
1921
+ state.scrollPrevTime = state.scrollTime;
1922
+ state.scroll = newScroll;
1923
+ state.scrollTime = currentTime;
1729
1924
  const scrollDelta = Math.abs(newScroll - prevScroll);
1730
1925
  const scrollLength = state.scrollLength;
1731
1926
  const lastCalculated = state.scrollLastCalculate;
@@ -1849,12 +2044,18 @@ function prepareMVCP(ctx, dataChanged) {
1849
2044
  const id = idsInView[i];
1850
2045
  const index = indexByKey.get(id);
1851
2046
  if (index !== void 0) {
1852
- idsInViewWithPositions.push({ id, position: positions.get(id) });
2047
+ const position = positions[index];
2048
+ if (position !== void 0) {
2049
+ idsInViewWithPositions.push({ id, position });
2050
+ }
1853
2051
  }
1854
2052
  }
1855
2053
  }
1856
2054
  if (targetId !== void 0 && prevPosition === void 0) {
1857
- prevPosition = positions.get(targetId);
2055
+ const targetIndex = indexByKey.get(targetId);
2056
+ if (targetIndex !== void 0) {
2057
+ prevPosition = positions[targetIndex];
2058
+ }
1858
2059
  }
1859
2060
  return () => {
1860
2061
  let positionDiff = 0;
@@ -1873,7 +2074,13 @@ function prepareMVCP(ctx, dataChanged) {
1873
2074
  }
1874
2075
  }
1875
2076
  }
1876
- const shouldUseFallbackVisibleAnchor = dataChanged && mvcpData && scrollTarget === void 0 && (targetId === void 0 || positions.get(targetId) === void 0 || skipTargetAnchor);
2077
+ const shouldUseFallbackVisibleAnchor = dataChanged && mvcpData && scrollTarget === void 0 && (() => {
2078
+ if (targetId === void 0 || skipTargetAnchor) {
2079
+ return true;
2080
+ }
2081
+ const targetIndex = indexByKey.get(targetId);
2082
+ return targetIndex === void 0 || positions[targetIndex] === void 0;
2083
+ })();
1877
2084
  if (shouldUseFallbackVisibleAnchor) {
1878
2085
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1879
2086
  const { id, position } = idsInViewWithPositions[i];
@@ -1884,7 +2091,7 @@ function prepareMVCP(ctx, dataChanged) {
1884
2091
  continue;
1885
2092
  }
1886
2093
  }
1887
- const newPosition = positions.get(id);
2094
+ const newPosition = index !== void 0 ? positions[index] : void 0;
1888
2095
  if (newPosition !== void 0) {
1889
2096
  positionDiff = newPosition - position;
1890
2097
  anchorIdForLock = id;
@@ -1894,7 +2101,8 @@ function prepareMVCP(ctx, dataChanged) {
1894
2101
  }
1895
2102
  }
1896
2103
  if (!skipTargetAnchor && targetId !== void 0 && prevPosition !== void 0) {
1897
- const newPosition = positions.get(targetId);
2104
+ const targetIndex = indexByKey.get(targetId);
2105
+ const newPosition = targetIndex !== void 0 ? positions[targetIndex] : void 0;
1898
2106
  if (newPosition !== void 0) {
1899
2107
  const totalSize = getContentSize(ctx);
1900
2108
  let diff = newPosition - prevPosition;
@@ -1941,17 +2149,15 @@ function prepareColumnStartState(ctx, startIndex, useAverageSize) {
1941
2149
  const state = ctx.state;
1942
2150
  const numColumns = peek$(ctx, "numColumns");
1943
2151
  let rowStartIndex = startIndex;
1944
- const columnAtStart = state.columns.get(state.idCache[startIndex]);
2152
+ const columnAtStart = state.columns[startIndex];
1945
2153
  if (columnAtStart !== 1) {
1946
2154
  rowStartIndex = findRowStartIndex(state, numColumns, startIndex);
1947
2155
  }
1948
2156
  let currentRowTop = 0;
1949
- const curId = state.idCache[rowStartIndex];
1950
- const column = state.columns.get(curId);
2157
+ const column = state.columns[rowStartIndex];
1951
2158
  if (rowStartIndex > 0) {
1952
2159
  const prevIndex = rowStartIndex - 1;
1953
- const prevId = state.idCache[prevIndex];
1954
- const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
2160
+ const prevPosition = (_a3 = state.positions[prevIndex]) != null ? _a3 : 0;
1955
2161
  const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1956
2162
  const prevRowHeight = calculateRowMaxSize(ctx, prevRowStart, prevIndex, useAverageSize);
1957
2163
  currentRowTop = prevPosition + prevRowHeight;
@@ -1968,7 +2174,7 @@ function findRowStartIndex(state, numColumns, index) {
1968
2174
  }
1969
2175
  let rowStart = Math.max(0, index);
1970
2176
  while (rowStart > 0) {
1971
- const columnForIndex = state.columns.get(state.idCache[rowStart]);
2177
+ const columnForIndex = state.columns[rowStart];
1972
2178
  if (columnForIndex === 1) {
1973
2179
  break;
1974
2180
  }
@@ -2001,7 +2207,7 @@ function calculateRowMaxSize(ctx, startIndex, endIndex, useAverageSize) {
2001
2207
 
2002
2208
  // src/core/updateTotalSize.ts
2003
2209
  function updateTotalSize(ctx) {
2004
- var _a3, _b, _c;
2210
+ var _a3, _b;
2005
2211
  const state = ctx.state;
2006
2212
  const {
2007
2213
  positions,
@@ -2011,36 +2217,34 @@ function updateTotalSize(ctx) {
2011
2217
  if (data.length === 0) {
2012
2218
  addTotalSize(ctx, null, 0);
2013
2219
  } else {
2014
- const lastId = getId(state, data.length - 1);
2015
- if (lastId !== void 0) {
2016
- const lastPosition = positions.get(lastId);
2017
- if (lastPosition !== void 0) {
2018
- if (numColumns > 1) {
2019
- let rowStart = data.length - 1;
2020
- while (rowStart > 0) {
2021
- const rowId = (_b = state.idCache[rowStart]) != null ? _b : getId(state, rowStart);
2022
- const column = state.columns.get(rowId);
2023
- if (column === 1 || column === void 0) {
2024
- break;
2025
- }
2026
- rowStart -= 1;
2027
- }
2028
- let maxSize = 0;
2029
- for (let i = rowStart; i < data.length; i++) {
2030
- const rowId = (_c = state.idCache[i]) != null ? _c : getId(state, i);
2031
- const size = getItemSize(ctx, rowId, i, data[i]);
2032
- if (size > maxSize) {
2033
- maxSize = size;
2034
- }
2220
+ const lastIndex = data.length - 1;
2221
+ const lastId = getId(state, lastIndex);
2222
+ const lastPosition = positions[lastIndex];
2223
+ if (lastId !== void 0 && lastPosition !== void 0) {
2224
+ if (numColumns > 1) {
2225
+ let rowStart = lastIndex;
2226
+ while (rowStart > 0) {
2227
+ const column = state.columns[rowStart];
2228
+ if (column === 1 || column === void 0) {
2229
+ break;
2035
2230
  }
2036
- addTotalSize(ctx, null, lastPosition + maxSize);
2037
- } else {
2038
- const lastSize = getItemSize(ctx, lastId, data.length - 1, data[data.length - 1]);
2039
- if (lastSize !== void 0) {
2040
- const totalSize = lastPosition + lastSize;
2041
- addTotalSize(ctx, null, totalSize);
2231
+ rowStart -= 1;
2232
+ }
2233
+ let maxSize = 0;
2234
+ for (let i = rowStart; i <= lastIndex; i++) {
2235
+ const rowId = (_b = state.idCache[i]) != null ? _b : getId(state, i);
2236
+ const size = getItemSize(ctx, rowId, i, data[i]);
2237
+ if (size > maxSize) {
2238
+ maxSize = size;
2042
2239
  }
2043
2240
  }
2241
+ addTotalSize(ctx, null, lastPosition + maxSize);
2242
+ } else {
2243
+ const lastSize = getItemSize(ctx, lastId, lastIndex, data[lastIndex]);
2244
+ if (lastSize !== void 0) {
2245
+ const totalSize = lastPosition + lastSize;
2246
+ addTotalSize(ctx, null, totalSize);
2247
+ }
2044
2248
  }
2045
2249
  }
2046
2250
  }
@@ -2089,14 +2293,13 @@ var getScrollVelocity = (state) => {
2089
2293
  function updateSnapToOffsets(ctx) {
2090
2294
  const state = ctx.state;
2091
2295
  const {
2092
- positions,
2093
2296
  props: { snapToIndices }
2094
2297
  } = state;
2095
2298
  const snapToOffsets = Array(snapToIndices.length);
2096
2299
  for (let i = 0; i < snapToIndices.length; i++) {
2097
2300
  const idx = snapToIndices[i];
2098
- const key = getId(state, idx);
2099
- snapToOffsets[i] = positions.get(key);
2301
+ getId(state, idx);
2302
+ snapToOffsets[i] = state.positions[idx];
2100
2303
  }
2101
2304
  set$(ctx, "snapToOffsets", snapToOffsets);
2102
2305
  }
@@ -2108,8 +2311,9 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
2108
2311
  scrollBottomBuffered: -1,
2109
2312
  startIndex: 0
2110
2313
  }) {
2111
- var _a3, _b, _c, _d, _e, _f;
2314
+ var _a3, _b, _c, _d, _e;
2112
2315
  const state = ctx.state;
2316
+ const hasPositionListeners = ctx.positionListeners.size > 0;
2113
2317
  const {
2114
2318
  columns,
2115
2319
  columnSpans,
@@ -2136,7 +2340,15 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
2136
2340
  let column = 1;
2137
2341
  let maxSizeInRow = 0;
2138
2342
  if (dataChanged) {
2139
- columnSpans.clear();
2343
+ columnSpans.length = 0;
2344
+ }
2345
+ if (!hasColumns) {
2346
+ if (columns.length) {
2347
+ columns.length = 0;
2348
+ }
2349
+ if (columnSpans.length) {
2350
+ columnSpans.length = 0;
2351
+ }
2140
2352
  }
2141
2353
  if (startIndex > 0) {
2142
2354
  if (hasColumns) {
@@ -2150,12 +2362,13 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
2150
2362
  } else if (startIndex < dataLength) {
2151
2363
  const prevIndex = startIndex - 1;
2152
2364
  const prevId = getId(state, prevIndex);
2153
- const prevPosition = (_c = positions.get(prevId)) != null ? _c : 0;
2365
+ const prevPosition = (_c = positions[prevIndex]) != null ? _c : 0;
2154
2366
  const prevSize = (_d = sizesKnown.get(prevId)) != null ? _d : getItemSize(ctx, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
2155
2367
  currentRowTop = prevPosition + prevSize;
2156
2368
  }
2157
2369
  }
2158
2370
  const needsIndexByKey = dataChanged || indexByKey.size === 0;
2371
+ const canOverrideSpan = hasColumns && !!overrideItemLayout && !!layoutConfig;
2159
2372
  let didBreakEarly = false;
2160
2373
  let breakAt;
2161
2374
  for (let i = startIndex; i < dataLength; i++) {
@@ -2169,7 +2382,7 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
2169
2382
  }
2170
2383
  const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2171
2384
  let span = 1;
2172
- if (hasColumns && overrideItemLayout && layoutConfig) {
2385
+ if (canOverrideSpan) {
2173
2386
  layoutConfig.span = 1;
2174
2387
  overrideItemLayout(layoutConfig, data[i], i, numColumns, extraData);
2175
2388
  const requestedSpan = layoutConfig.span;
@@ -2182,7 +2395,8 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
2182
2395
  column = 1;
2183
2396
  maxSizeInRow = 0;
2184
2397
  }
2185
- const size = (_f = sizesKnown.get(id)) != null ? _f : getItemSize(ctx, id, i, data[i], useAverageSize, preferCachedSize);
2398
+ const knownSize = sizesKnown.get(id);
2399
+ const size = knownSize !== void 0 ? knownSize : getItemSize(ctx, id, i, data[i], useAverageSize, preferCachedSize);
2186
2400
  if (IS_DEV && needsIndexByKey) {
2187
2401
  if (indexByKeyForChecking.has(id)) {
2188
2402
  console.error(
@@ -2191,16 +2405,20 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
2191
2405
  }
2192
2406
  indexByKeyForChecking.set(id, i);
2193
2407
  }
2194
- if (currentRowTop !== positions.get(id)) {
2195
- positions.set(id, currentRowTop);
2196
- notifyPosition$(ctx, id, currentRowTop);
2408
+ if (currentRowTop !== positions[i]) {
2409
+ positions[i] = currentRowTop;
2410
+ if (hasPositionListeners) {
2411
+ notifyPosition$(ctx, id, currentRowTop);
2412
+ }
2197
2413
  }
2198
2414
  if (needsIndexByKey) {
2199
2415
  indexByKey.set(id, i);
2200
2416
  }
2201
- columns.set(id, column);
2202
- columnSpans.set(id, span);
2203
- if (hasColumns) {
2417
+ if (!hasColumns) {
2418
+ currentRowTop += size;
2419
+ } else {
2420
+ columns[i] = column;
2421
+ columnSpans[i] = span;
2204
2422
  if (size > maxSizeInRow) {
2205
2423
  maxSizeInRow = size;
2206
2424
  }
@@ -2210,8 +2428,6 @@ function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffere
2210
2428
  column = 1;
2211
2429
  maxSizeInRow = 0;
2212
2430
  }
2213
- } else {
2214
- currentRowTop += size;
2215
2431
  }
2216
2432
  }
2217
2433
  if (!didBreakEarly) {
@@ -2363,14 +2579,38 @@ function shallowEqual(prev, next) {
2363
2579
  return true;
2364
2580
  }
2365
2581
  function computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
2366
- const { sizes, positions, scroll: scrollState } = state;
2582
+ const { sizes, scroll: scrollState } = state;
2367
2583
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2368
2584
  const { itemVisiblePercentThreshold, viewAreaCoveragePercentThreshold } = viewabilityConfig;
2369
2585
  const viewAreaMode = viewAreaCoveragePercentThreshold != null;
2370
2586
  const viewablePercentThreshold = viewAreaMode ? viewAreaCoveragePercentThreshold : itemVisiblePercentThreshold;
2371
2587
  const scroll = scrollState - topPad;
2372
- const top = positions.get(key) - scroll;
2588
+ const position = state.positions[index];
2373
2589
  const size = sizes.get(key) || 0;
2590
+ if (position === void 0) {
2591
+ const value2 = {
2592
+ containerId,
2593
+ index,
2594
+ isViewable: false,
2595
+ item,
2596
+ key,
2597
+ percentOfScroller: 0,
2598
+ percentVisible: 0,
2599
+ scrollSize,
2600
+ size,
2601
+ sizeVisible: -1
2602
+ };
2603
+ const prev2 = ctx.mapViewabilityAmountValues.get(containerId);
2604
+ if (!shallowEqual(prev2, value2)) {
2605
+ ctx.mapViewabilityAmountValues.set(containerId, value2);
2606
+ const cb = ctx.mapViewabilityAmountCallbacks.get(containerId);
2607
+ if (cb) {
2608
+ cb(value2);
2609
+ }
2610
+ }
2611
+ return value2;
2612
+ }
2613
+ const top = position - scroll;
2374
2614
  const bottom = top + size;
2375
2615
  const isEntirelyVisible = top >= 0 && bottom <= scrollSize && bottom > top;
2376
2616
  const sizeVisible = isEntirelyVisible ? size : Math.min(bottom, scrollSize) - Math.max(top, 0);
@@ -2597,13 +2837,10 @@ function setDidLayout(ctx) {
2597
2837
 
2598
2838
  // src/core/calculateItemsInView.ts
2599
2839
  function findCurrentStickyIndex(stickyArray, scroll, state) {
2600
- var _a3;
2601
- const idCache = state.idCache;
2602
2840
  const positions = state.positions;
2603
2841
  for (let i = stickyArray.length - 1; i >= 0; i--) {
2604
2842
  const stickyIndex = stickyArray[i];
2605
- const stickyId = (_a3 = idCache[stickyIndex]) != null ? _a3 : getId(state, stickyIndex);
2606
- const stickyPos = stickyId ? positions.get(stickyId) : void 0;
2843
+ const stickyPos = positions[stickyIndex];
2607
2844
  if (stickyPos !== void 0 && scroll >= stickyPos) {
2608
2845
  return i;
2609
2846
  }
@@ -2633,7 +2870,7 @@ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentSt
2633
2870
  }
2634
2871
  }
2635
2872
  function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentStickyIdx, pendingRemoval, alwaysRenderIndicesSet) {
2636
- var _a3, _b, _c;
2873
+ var _a3, _b;
2637
2874
  const state = ctx.state;
2638
2875
  for (const containerIndex of state.stickyContainerPool) {
2639
2876
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
@@ -2651,14 +2888,13 @@ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentSt
2651
2888
  const nextIndex = stickyArray[arrayIdx + 1];
2652
2889
  let shouldRecycle = false;
2653
2890
  if (nextIndex) {
2654
- const nextId = (_a3 = state.idCache[nextIndex]) != null ? _a3 : getId(state, nextIndex);
2655
- const nextPos = nextId ? state.positions.get(nextId) : void 0;
2891
+ const nextPos = state.positions[nextIndex];
2656
2892
  shouldRecycle = nextPos !== void 0 && scroll > nextPos + drawDistance * 2;
2657
2893
  } else {
2658
- const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2894
+ const currentId = (_a3 = state.idCache[itemIndex]) != null ? _a3 : getId(state, itemIndex);
2659
2895
  if (currentId) {
2660
- const currentPos = state.positions.get(currentId);
2661
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2896
+ const currentPos = state.positions[itemIndex];
2897
+ const currentSize = (_b = state.sizes.get(currentId)) != null ? _b : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
2662
2898
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + drawDistance * 3;
2663
2899
  }
2664
2900
  }
@@ -2670,7 +2906,7 @@ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentSt
2670
2906
  function calculateItemsInView(ctx, params = {}) {
2671
2907
  const state = ctx.state;
2672
2908
  unstable_batchedUpdates(() => {
2673
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
2909
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2674
2910
  const {
2675
2911
  columns,
2676
2912
  columnSpans,
@@ -2759,7 +2995,9 @@ function calculateItemsInView(ctx, params = {}) {
2759
2995
  if (dataChanged) {
2760
2996
  indexByKey.clear();
2761
2997
  idCache.length = 0;
2762
- positions.clear();
2998
+ positions.length = 0;
2999
+ columns.length = 0;
3000
+ columnSpans.length = 0;
2763
3001
  }
2764
3002
  const startIndex = forceFullItemPositions || dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2765
3003
  updateItemPositions(ctx, dataChanged, {
@@ -2780,7 +3018,7 @@ function calculateItemsInView(ctx, params = {}) {
2780
3018
  let loopStart = !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
2781
3019
  for (let i = loopStart; i >= 0; i--) {
2782
3020
  const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2783
- const top = positions.get(id);
3021
+ const top = positions[i];
2784
3022
  const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, id, i, data[i]);
2785
3023
  const bottom = top + size;
2786
3024
  if (bottom > scroll - scrollBufferTop) {
@@ -2791,8 +3029,7 @@ function calculateItemsInView(ctx, params = {}) {
2791
3029
  }
2792
3030
  if (numColumns > 1) {
2793
3031
  while (loopStart > 0) {
2794
- const loopId = (_e = idCache[loopStart]) != null ? _e : getId(state, loopStart);
2795
- const loopColumn = columns.get(loopId);
3032
+ const loopColumn = columns[loopStart];
2796
3033
  if (loopColumn === 1 || loopColumn === void 0) {
2797
3034
  break;
2798
3035
  }
@@ -2813,9 +3050,9 @@ function calculateItemsInView(ctx, params = {}) {
2813
3050
  let firstFullyOnScreenIndex;
2814
3051
  const dataLength = data.length;
2815
3052
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2816
- const id = (_f = idCache[i]) != null ? _f : getId(state, i);
2817
- const size = (_g = sizes.get(id)) != null ? _g : getItemSize(ctx, id, i, data[i]);
2818
- const top = positions.get(id);
3053
+ const id = (_e = idCache[i]) != null ? _e : getId(state, i);
3054
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, id, i, data[i]);
3055
+ const top = positions[i];
2819
3056
  if (!foundEnd) {
2820
3057
  if (startNoBuffer === null && top + size > scroll) {
2821
3058
  startNoBuffer = i;
@@ -2851,7 +3088,7 @@ function calculateItemsInView(ctx, params = {}) {
2851
3088
  }
2852
3089
  const idsInView = [];
2853
3090
  for (let i = firstFullyOnScreenIndex; i <= endNoBuffer; i++) {
2854
- const id = (_h = idCache[i]) != null ? _h : getId(state, i);
3091
+ const id = (_g = idCache[i]) != null ? _g : getId(state, i);
2855
3092
  idsInView.push(id);
2856
3093
  }
2857
3094
  Object.assign(state, {
@@ -2883,7 +3120,7 @@ function calculateItemsInView(ctx, params = {}) {
2883
3120
  const needNewContainers = [];
2884
3121
  const needNewContainersSet = /* @__PURE__ */ new Set();
2885
3122
  for (let i = startBuffered; i <= endBuffered; i++) {
2886
- const id = (_i = idCache[i]) != null ? _i : getId(state, i);
3123
+ const id = (_h = idCache[i]) != null ? _h : getId(state, i);
2887
3124
  if (!containerItemKeys.has(id)) {
2888
3125
  needNewContainersSet.add(i);
2889
3126
  needNewContainers.push(i);
@@ -2892,7 +3129,7 @@ function calculateItemsInView(ctx, params = {}) {
2892
3129
  if (alwaysRenderArr.length > 0) {
2893
3130
  for (const index of alwaysRenderArr) {
2894
3131
  if (index < 0 || index >= dataLength) continue;
2895
- const id = (_j = idCache[index]) != null ? _j : getId(state, index);
3132
+ const id = (_i = idCache[index]) != null ? _i : getId(state, index);
2896
3133
  if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
2897
3134
  needNewContainersSet.add(index);
2898
3135
  needNewContainers.push(index);
@@ -2930,7 +3167,7 @@ function calculateItemsInView(ctx, params = {}) {
2930
3167
  for (let idx = 0; idx < needNewContainers.length; idx++) {
2931
3168
  const i = needNewContainers[idx];
2932
3169
  const containerIndex = availableContainers[idx];
2933
- const id = (_k = idCache[i]) != null ? _k : getId(state, i);
3170
+ const id = (_j = idCache[i]) != null ? _j : getId(state, i);
2934
3171
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
2935
3172
  if (oldKey && oldKey !== id) {
2936
3173
  containerItemKeys.delete(oldKey);
@@ -2971,7 +3208,7 @@ function calculateItemsInView(ctx, params = {}) {
2971
3208
  if (alwaysRenderArr.length > 0) {
2972
3209
  for (const index of alwaysRenderArr) {
2973
3210
  if (index < 0 || index >= dataLength) continue;
2974
- const id = (_l = idCache[index]) != null ? _l : getId(state, index);
3211
+ const id = (_k = idCache[index]) != null ? _k : getId(state, index);
2975
3212
  const containerIndex = containerItemKeys.get(id);
2976
3213
  if (containerIndex !== void 0) {
2977
3214
  state.stickyContainerPool.add(containerIndex);
@@ -3011,14 +3248,13 @@ function calculateItemsInView(ctx, params = {}) {
3011
3248
  const itemIndex = indexByKey.get(itemKey);
3012
3249
  const item = data[itemIndex];
3013
3250
  if (item !== void 0) {
3014
- const id = (_m = idCache[itemIndex]) != null ? _m : getId(state, itemIndex);
3015
- const positionValue = positions.get(id);
3251
+ const positionValue = positions[itemIndex];
3016
3252
  if (positionValue === void 0) {
3017
3253
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
3018
3254
  } else {
3019
3255
  const position = (positionValue || 0) - scrollAdjustPending;
3020
- const column = columns.get(id) || 1;
3021
- const span = columnSpans.get(id) || 1;
3256
+ const column = columns[itemIndex] || 1;
3257
+ const span = columnSpans[itemIndex] || 1;
3022
3258
  const prevPos = peek$(ctx, `containerPosition${i}`);
3023
3259
  const prevColumn = peek$(ctx, `containerColumn${i}`);
3024
3260
  const prevSpan = peek$(ctx, `containerSpan${i}`);
@@ -3631,6 +3867,18 @@ function createColumnWrapperStyle(contentContainerStyle) {
3631
3867
  // src/utils/createImperativeHandle.ts
3632
3868
  function createImperativeHandle(ctx) {
3633
3869
  const state = ctx.state;
3870
+ const runScrollWithPromise = (run) => new Promise((resolve) => {
3871
+ var _a3;
3872
+ (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
3873
+ state.pendingScrollResolve = resolve;
3874
+ const didStartScroll = run();
3875
+ if (!didStartScroll || !state.scrollingTo) {
3876
+ if (state.pendingScrollResolve === resolve) {
3877
+ state.pendingScrollResolve = void 0;
3878
+ }
3879
+ resolve();
3880
+ }
3881
+ });
3634
3882
  const scrollIndexIntoView = (options) => {
3635
3883
  if (state) {
3636
3884
  const { index, ...rest } = options;
@@ -3642,8 +3890,10 @@ function createImperativeHandle(ctx) {
3642
3890
  index,
3643
3891
  viewPosition
3644
3892
  });
3893
+ return true;
3645
3894
  }
3646
3895
  }
3896
+ return false;
3647
3897
  };
3648
3898
  const refScroller = state.refScroller;
3649
3899
  const clearCaches = (options) => {
@@ -3662,9 +3912,9 @@ function createImperativeHandle(ctx) {
3662
3912
  if (mode === "full") {
3663
3913
  state.indexByKey.clear();
3664
3914
  state.idCache.length = 0;
3665
- state.positions.clear();
3666
- state.columns.clear();
3667
- state.columnSpans.clear();
3915
+ state.positions.length = 0;
3916
+ state.columns.length = 0;
3917
+ state.columnSpans.length = 0;
3668
3918
  }
3669
3919
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
3670
3920
  };
@@ -3688,8 +3938,11 @@ function createImperativeHandle(ctx) {
3688
3938
  isAtStart: state.isAtStart,
3689
3939
  listen: (signalName, cb) => listen$(ctx, signalName, cb),
3690
3940
  listenToPosition: (key, cb) => listenPosition$(ctx, key, cb),
3691
- positionAtIndex: (index) => state.positions.get(getId(state, index)),
3692
- positions: state.positions,
3941
+ positionAtIndex: (index) => state.positions[index],
3942
+ positionByKey: (key) => {
3943
+ const index = state.indexByKey.get(key);
3944
+ return index === void 0 ? void 0 : state.positions[index];
3945
+ },
3693
3946
  scroll: state.scroll,
3694
3947
  scrollLength: state.scrollLength,
3695
3948
  scrollVelocity: getScrollVelocity(state),
@@ -3702,15 +3955,17 @@ function createImperativeHandle(ctx) {
3702
3955
  state.contentInsetOverride = inset != null ? inset : void 0;
3703
3956
  updateScroll(ctx, state.scroll, true);
3704
3957
  },
3705
- scrollIndexIntoView,
3706
- scrollItemIntoView: ({ item, ...props }) => {
3958
+ scrollIndexIntoView: (options) => runScrollWithPromise(() => scrollIndexIntoView(options)),
3959
+ scrollItemIntoView: ({ item, ...props }) => runScrollWithPromise(() => {
3707
3960
  const data = state.props.data;
3708
3961
  const index = data.indexOf(item);
3709
3962
  if (index !== -1) {
3710
3963
  scrollIndexIntoView({ index, ...props });
3964
+ return true;
3711
3965
  }
3712
- },
3713
- scrollToEnd: (options) => {
3966
+ return false;
3967
+ }),
3968
+ scrollToEnd: (options) => runScrollWithPromise(() => {
3714
3969
  const data = state.props.data;
3715
3970
  const stylePaddingBottom = state.props.stylePaddingBottom;
3716
3971
  const index = data.length - 1;
@@ -3723,17 +3978,27 @@ function createImperativeHandle(ctx) {
3723
3978
  viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3724
3979
  viewPosition: 1
3725
3980
  });
3981
+ return true;
3726
3982
  }
3727
- },
3728
- scrollToIndex: (params) => scrollToIndex(ctx, params),
3729
- scrollToItem: ({ item, ...props }) => {
3983
+ return false;
3984
+ }),
3985
+ scrollToIndex: (params) => runScrollWithPromise(() => {
3986
+ scrollToIndex(ctx, params);
3987
+ return true;
3988
+ }),
3989
+ scrollToItem: ({ item, ...props }) => runScrollWithPromise(() => {
3730
3990
  const data = state.props.data;
3731
3991
  const index = data.indexOf(item);
3732
3992
  if (index !== -1) {
3733
3993
  scrollToIndex(ctx, { index, ...props });
3994
+ return true;
3734
3995
  }
3735
- },
3736
- scrollToOffset: (params) => scrollTo(ctx, params),
3996
+ return false;
3997
+ }),
3998
+ scrollToOffset: (params) => runScrollWithPromise(() => {
3999
+ scrollTo(ctx, params);
4000
+ return true;
4001
+ }),
3737
4002
  setScrollProcessingEnabled: (enabled) => {
3738
4003
  state.scrollProcessingEnabled = enabled;
3739
4004
  },
@@ -3970,6 +4235,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3970
4235
  refreshControl,
3971
4236
  refreshing,
3972
4237
  refScrollView,
4238
+ renderScrollComponent,
3973
4239
  renderItem,
3974
4240
  scrollEventThrottle,
3975
4241
  snapToIndices,
@@ -3978,15 +4244,18 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3978
4244
  // TODOV3: Remove from v3 release
3979
4245
  style: styleProp,
3980
4246
  suggestEstimatedItemSize,
4247
+ useWindowScroll = false,
3981
4248
  viewabilityConfig,
3982
4249
  viewabilityConfigCallbackPairs,
3983
4250
  waitForInitialLayout = true,
3984
4251
  ...rest
3985
4252
  } = props;
3986
4253
  const animatedPropsInternal = props.animatedPropsInternal;
4254
+ const positionComponentInternal = props.positionComponentInternal;
3987
4255
  const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
3988
4256
  const {
3989
4257
  childrenMode,
4258
+ positionComponentInternal: _positionComponentInternal,
3990
4259
  stickyPositionComponentInternal: _stickyPositionComponentInternal,
3991
4260
  ...restProps
3992
4261
  } = rest;
@@ -4041,6 +4310,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4041
4310
  "stickyIndices has been renamed to stickyHeaderIndices. Please update your props to use stickyHeaderIndices."
4042
4311
  );
4043
4312
  }
4313
+ if (IS_DEV && useWindowScroll && renderScrollComponent) {
4314
+ warnDevOnce(
4315
+ "useWindowScrollRenderScrollComponent",
4316
+ "useWindowScroll is not supported when renderScrollComponent is provided."
4317
+ );
4318
+ }
4319
+ const useWindowScrollResolved = !!useWindowScroll && !renderScrollComponent;
4044
4320
  const refState = useRef();
4045
4321
  const hasOverrideItemLayout = !!overrideItemLayout;
4046
4322
  const prevHasOverrideItemLayout = useRef(hasOverrideItemLayout);
@@ -4050,11 +4326,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4050
4326
  ctx.state = {
4051
4327
  activeStickyIndex: -1,
4052
4328
  averageSizes: {},
4053
- columnSpans: /* @__PURE__ */ new Map(),
4054
- columns: /* @__PURE__ */ new Map(),
4329
+ columnSpans: [],
4330
+ columns: [],
4055
4331
  containerItemKeys: /* @__PURE__ */ new Map(),
4056
4332
  containerItemTypes: /* @__PURE__ */ new Map(),
4057
4333
  contentInsetOverride: void 0,
4334
+ dataChangeEpoch: 0,
4058
4335
  dataChangeNeedsScrollUpdate: false,
4059
4336
  didColumnsChange: false,
4060
4337
  didDataChange: false,
@@ -4086,10 +4363,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4086
4363
  minIndexSizeChanged: 0,
4087
4364
  nativeContentInset: void 0,
4088
4365
  nativeMarginTop: 0,
4089
- positions: /* @__PURE__ */ new Map(),
4366
+ positions: [],
4090
4367
  props: {},
4091
4368
  queuedCalculateItemsInView: 0,
4092
- refScroller: void 0,
4369
+ refScroller: { current: null },
4093
4370
  scroll: 0,
4094
4371
  scrollAdjustHandler: new ScrollAdjustHandler(ctx),
4095
4372
  scrollForNextCalculateItemsInView: void 0,
@@ -4105,6 +4382,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4105
4382
  startBuffered: -1,
4106
4383
  startNoBuffer: -1,
4107
4384
  startReachedSnapshot: void 0,
4385
+ startReachedSnapshotDataChangeEpoch: void 0,
4108
4386
  stickyContainerPool: /* @__PURE__ */ new Set(),
4109
4387
  stickyContainers: /* @__PURE__ */ new Map(),
4110
4388
  timeoutSizeMessage: 0,
@@ -4124,6 +4402,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4124
4402
  state.didColumnsChange = numColumnsProp !== state.props.numColumns;
4125
4403
  const didDataChangeLocal = state.props.dataVersion !== dataVersion || state.props.data !== dataProp && checkActualChange(state, dataProp, state.props.data);
4126
4404
  if (didDataChangeLocal) {
4405
+ state.dataChangeEpoch += 1;
4127
4406
  state.dataChangeNeedsScrollUpdate = true;
4128
4407
  state.didDataChange = true;
4129
4408
  state.previousData = state.props.data;
@@ -4160,6 +4439,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4160
4439
  onStartReachedThreshold,
4161
4440
  onStickyHeaderChange,
4162
4441
  overrideItemLayout,
4442
+ positionComponentInternal,
4163
4443
  recycleItems: !!recycleItems,
4164
4444
  renderItem,
4165
4445
  snapToIndices,
@@ -4168,7 +4448,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4168
4448
  stickyPositionComponentInternal,
4169
4449
  stylePaddingBottom: stylePaddingBottomState,
4170
4450
  stylePaddingTop: stylePaddingTopState,
4171
- suggestEstimatedItemSize: !!suggestEstimatedItemSize
4451
+ suggestEstimatedItemSize: !!suggestEstimatedItemSize,
4452
+ useWindowScroll: useWindowScrollResolved
4172
4453
  };
4173
4454
  state.refScroller = refScroller;
4174
4455
  const memoizedLastItemKeys = useMemo(() => {
@@ -4227,7 +4508,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4227
4508
  "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."
4228
4509
  );
4229
4510
  refState.current.sizes.clear();
4230
- refState.current.positions.clear();
4511
+ refState.current.positions.length = 0;
4231
4512
  refState.current.totalSize = 0;
4232
4513
  set$(ctx, "totalSize", 0);
4233
4514
  }
@@ -4379,12 +4660,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
4379
4660
  }
4380
4661
  ),
4381
4662
  refScrollView: combinedRef,
4663
+ renderScrollComponent,
4382
4664
  scrollAdjustHandler: (_d = refState.current) == null ? void 0 : _d.scrollAdjustHandler,
4383
4665
  scrollEventThrottle: 0,
4384
4666
  snapToIndices,
4385
4667
  stickyHeaderIndices,
4386
4668
  style,
4387
4669
  updateItemSize: fns.updateItemSize,
4670
+ useWindowScroll: useWindowScrollResolved,
4388
4671
  waitForInitialLayout
4389
4672
  }
4390
4673
  ), IS_DEV && ENABLE_DEBUG_VIEW);