@legendapp/list 3.0.6 → 3.1.0

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/react-native.mjs CHANGED
@@ -131,6 +131,7 @@ function StateProvider({ children }) {
131
131
  mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
132
132
  mapViewabilityValues: /* @__PURE__ */ new Map(),
133
133
  positionListeners: /* @__PURE__ */ new Map(),
134
+ scrollAxisGap: 0,
134
135
  state: void 0,
135
136
  values: /* @__PURE__ */ new Map([
136
137
  ["alignItemsAtEndPadding", 0],
@@ -143,6 +144,7 @@ function StateProvider({ children }) {
143
144
  ["isNearEnd", false],
144
145
  ["isNearStart", false],
145
146
  ["isWithinMaintainScrollAtEndThreshold", false],
147
+ ["adaptiveRender", "light"],
146
148
  ["totalSize", 0],
147
149
  ["scrollAdjustPending", 0]
148
150
  ]),
@@ -588,6 +590,24 @@ var ContextContainer = createContext(null);
588
590
  function useContextContainer() {
589
591
  return useContext(ContextContainer);
590
592
  }
593
+ function useAdaptiveRender() {
594
+ const [mode] = useArr$(["adaptiveRender"]);
595
+ return mode;
596
+ }
597
+ function useAdaptiveRenderChange(callback) {
598
+ const ctx = useStateContext();
599
+ const callbackRef = useRef(callback);
600
+ callbackRef.current = callback;
601
+ useLayoutEffect(() => {
602
+ let mode = peek$(ctx, "adaptiveRender");
603
+ return listen$(ctx, "adaptiveRender", (nextMode) => {
604
+ if (mode !== nextMode) {
605
+ mode = nextMode;
606
+ callbackRef.current(nextMode);
607
+ }
608
+ });
609
+ }, [ctx]);
610
+ }
591
611
  function useViewability(callback, configId) {
592
612
  const ctx = useStateContext();
593
613
  const containerContext = useContextContainer();
@@ -804,6 +824,7 @@ function isInMVCPActiveMode(state) {
804
824
  // src/components/Container.tsx
805
825
  function getContainerPositionStyle({
806
826
  columnWrapperStyle,
827
+ contentContainerAlignItems,
807
828
  horizontal,
808
829
  hasItemSeparator,
809
830
  isHorizontalRTLList,
@@ -829,13 +850,14 @@ function getContainerPositionStyle({
829
850
  }
830
851
  }
831
852
  return horizontal ? {
853
+ bottom: contentContainerAlignItems === "flex-end" && numColumns === 1 ? 0 : void 0,
832
854
  boxSizing: paddingStyles ? "border-box" : void 0,
833
855
  direction: isHorizontalRTLList && Platform.OS === "web" ? "ltr" : void 0,
834
856
  flexDirection: hasItemSeparator ? "row" : void 0,
835
857
  height: otherAxisSize,
836
858
  left: 0,
837
859
  position: "absolute",
838
- top: otherAxisPos,
860
+ top: contentContainerAlignItems === "flex-end" && numColumns === 1 ? void 0 : otherAxisPos,
839
861
  ...paddingStyles || {}
840
862
  } : {
841
863
  boxSizing: paddingStyles ? "border-box" : void 0,
@@ -889,6 +911,7 @@ var Container = typedMemo(function Container2({
889
911
  const style = useMemo(
890
912
  () => getContainerPositionStyle({
891
913
  columnWrapperStyle,
914
+ contentContainerAlignItems: ctx.state.props.contentContainerAlignItems,
892
915
  hasItemSeparator: !!ItemSeparatorComponent,
893
916
  horizontal,
894
917
  isHorizontalRTLList,
@@ -902,6 +925,7 @@ var Container = typedMemo(function Container2({
902
925
  otherAxisPos,
903
926
  otherAxisSize,
904
927
  columnWrapperStyle,
928
+ ctx.state.props.contentContainerAlignItems,
905
929
  numColumns,
906
930
  ItemSeparatorComponent
907
931
  ]
@@ -1172,7 +1196,30 @@ function WebAnchoredEndSpace({ horizontal }) {
1172
1196
  return /* @__PURE__ */ React2.createElement("div", { style }, null);
1173
1197
  }
1174
1198
 
1175
- // src/core/updateContentMetrics.ts
1199
+ // src/core/calculateOffsetForIndex.ts
1200
+ function calculateOffsetForIndex(ctx, index) {
1201
+ const state = ctx.state;
1202
+ return index !== void 0 ? state.positions[index] || 0 : 0;
1203
+ }
1204
+
1205
+ // src/core/getTopOffsetAdjustment.ts
1206
+ function getTopOffsetAdjustment(ctx) {
1207
+ return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
1208
+ }
1209
+
1210
+ // src/utils/getId.ts
1211
+ function getId(state, index) {
1212
+ const { data, keyExtractor } = state.props;
1213
+ if (!data) {
1214
+ return "";
1215
+ }
1216
+ const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
1217
+ const id = ret;
1218
+ state.idCache[index] = id;
1219
+ return id;
1220
+ }
1221
+
1222
+ // src/core/updateContentMetricsState.ts
1176
1223
  function getRawContentLength(ctx) {
1177
1224
  var _a3, _b, _c;
1178
1225
  const { state, values } = ctx;
@@ -1183,240 +1230,187 @@ function getAlignItemsAtEndPadding(ctx) {
1183
1230
  const shouldPad = !!state.props.alignItemsAtEndPaddingEnabled && !state.props.horizontal && state.props.data.length > 0 && state.scrollLength > 0;
1184
1231
  return shouldPad ? Math.max(0, state.scrollLength - getRawContentLength(ctx) - getContentInsetEnd(ctx)) : 0;
1185
1232
  }
1186
- function updateContentMetrics(ctx) {
1233
+ function updateContentMetricsState(ctx) {
1234
+ const previousPadding = peek$(ctx, "alignItemsAtEndPadding") || 0;
1187
1235
  const nextPadding = getAlignItemsAtEndPadding(ctx);
1188
- if (peek$(ctx, "alignItemsAtEndPadding") !== nextPadding) {
1236
+ if (previousPadding !== nextPadding) {
1189
1237
  set$(ctx, "alignItemsAtEndPadding", nextPadding);
1190
1238
  }
1191
1239
  }
1192
- function setContentLengthSignal(ctx, signalName, size) {
1193
- if (peek$(ctx, signalName) !== size) {
1194
- set$(ctx, signalName, size);
1195
- updateContentMetrics(ctx);
1240
+
1241
+ // src/core/addTotalSize.ts
1242
+ function addTotalSize(ctx, key, add, notifyTotalSize = true) {
1243
+ const state = ctx.state;
1244
+ const prevTotalSize = state.totalSize;
1245
+ let totalSize = state.totalSize;
1246
+ if (key === null) {
1247
+ totalSize = add;
1248
+ if (state.timeoutSetPaddingTop) {
1249
+ clearTimeout(state.timeoutSetPaddingTop);
1250
+ state.timeoutSetPaddingTop = void 0;
1251
+ }
1252
+ } else {
1253
+ totalSize += add;
1254
+ }
1255
+ if (prevTotalSize !== totalSize) {
1256
+ if (!IsNewArchitecture && state.initialScroll && totalSize < prevTotalSize) {
1257
+ state.pendingTotalSize = totalSize;
1258
+ } else {
1259
+ state.pendingTotalSize = void 0;
1260
+ state.totalSize = totalSize;
1261
+ if (notifyTotalSize) {
1262
+ set$(ctx, "totalSize", totalSize);
1263
+ }
1264
+ updateContentMetricsState(ctx);
1265
+ }
1266
+ } else if (notifyTotalSize && ctx.values.get("totalSize") !== totalSize) {
1267
+ set$(ctx, "totalSize", totalSize);
1196
1268
  }
1197
1269
  }
1198
- function setHeaderSize(ctx, size) {
1199
- setContentLengthSignal(ctx, "headerSize", size);
1270
+
1271
+ // src/core/setSize.ts
1272
+ function setSize(ctx, itemKey, size, notifyTotalSize = true) {
1273
+ const state = ctx.state;
1274
+ const { sizes } = state;
1275
+ const previousSize = sizes.get(itemKey);
1276
+ const diff = previousSize !== void 0 ? size - previousSize : size;
1277
+ if (diff !== 0) {
1278
+ addTotalSize(ctx, itemKey, diff, notifyTotalSize);
1279
+ }
1280
+ sizes.set(itemKey, size);
1200
1281
  }
1201
- function setFooterSize(ctx, size) {
1202
- setContentLengthSignal(ctx, "footerSize", size);
1282
+
1283
+ // src/utils/getItemSize.ts
1284
+ function getKnownOrFixedSize(ctx, key, index, data, resolved) {
1285
+ var _a3, _b;
1286
+ const state = ctx.state;
1287
+ const { getFixedItemSize, getItemType } = state.props;
1288
+ let size = key ? state.sizesKnown.get(key) : void 0;
1289
+ if (size === void 0 && key && getFixedItemSize) {
1290
+ const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1291
+ const fixedSize = (resolved == null ? void 0 : resolved.didResolveFixedItemSize) ? resolved.fixedItemSize : getFixedItemSize(data, index, itemType);
1292
+ if (fixedSize !== void 0) {
1293
+ size = fixedSize + ctx.scrollAxisGap;
1294
+ state.sizesKnown.set(key, size);
1295
+ }
1296
+ }
1297
+ return size;
1203
1298
  }
1204
- function areInsetsEqual(left, right) {
1205
- var _a3, _b, _c, _d, _e, _f, _g, _h;
1206
- return ((_a3 = left == null ? void 0 : left.top) != null ? _a3 : 0) === ((_b = right == null ? void 0 : right.top) != null ? _b : 0) && ((_c = left == null ? void 0 : left.bottom) != null ? _c : 0) === ((_d = right == null ? void 0 : right.bottom) != null ? _d : 0) && ((_e = left == null ? void 0 : left.left) != null ? _e : 0) === ((_f = right == null ? void 0 : right.left) != null ? _f : 0) && ((_g = left == null ? void 0 : left.right) != null ? _g : 0) === ((_h = right == null ? void 0 : right.right) != null ? _h : 0);
1299
+ function getKnownOrFixedItemSize(ctx, index) {
1300
+ const key = getId(ctx.state, index);
1301
+ return getKnownOrFixedSize(ctx, key, index, ctx.state.props.data[index]);
1207
1302
  }
1208
- function setContentInsetOverride(ctx, inset) {
1209
- const { state } = ctx;
1210
- const previousInset = state.contentInsetOverride;
1211
- const nextInset = inset != null ? inset : void 0;
1212
- const didChange = !areInsetsEqual(previousInset, nextInset);
1213
- state.contentInsetOverride = nextInset;
1214
- if (didChange) {
1215
- updateContentMetrics(ctx);
1303
+ function areKnownOrFixedItemSizesAvailable(ctx, startIndex, endIndex) {
1304
+ for (let index = startIndex; index <= endIndex; index++) {
1305
+ if (getKnownOrFixedItemSize(ctx, index) === void 0) {
1306
+ return false;
1307
+ }
1216
1308
  }
1217
- return didChange;
1309
+ return true;
1218
1310
  }
1219
- function useLatestRef(value) {
1220
- const ref = React2.useRef(value);
1221
- ref.current = value;
1222
- return ref;
1311
+ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize, notifyTotalSize, resolved) {
1312
+ var _a3, _b, _c, _d;
1313
+ const state = ctx.state;
1314
+ const {
1315
+ sizes,
1316
+ averageSizes,
1317
+ props: { estimatedItemSize, getItemType },
1318
+ scrollingTo
1319
+ } = state;
1320
+ const sizeKnown = state.sizesKnown.get(key);
1321
+ if (sizeKnown !== void 0) {
1322
+ return sizeKnown;
1323
+ }
1324
+ let size;
1325
+ const renderedSize = sizes.get(key);
1326
+ if (preferCachedSize) {
1327
+ if (renderedSize !== void 0) {
1328
+ return renderedSize;
1329
+ }
1330
+ }
1331
+ size = getKnownOrFixedSize(ctx, key, index, data, resolved);
1332
+ if (size !== void 0) {
1333
+ setSize(ctx, key, size, notifyTotalSize);
1334
+ return size;
1335
+ }
1336
+ const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1337
+ if (useAverageSize && !scrollingTo) {
1338
+ const averageSizeForType = (_c = averageSizes[itemType]) == null ? void 0 : _c.avg;
1339
+ if (averageSizeForType !== void 0) {
1340
+ size = roundSize(averageSizeForType);
1341
+ }
1342
+ }
1343
+ if (size === void 0 && renderedSize !== void 0) {
1344
+ return renderedSize;
1345
+ }
1346
+ if (size === void 0 && useAverageSize && scrollingTo) {
1347
+ const averageSizeForType = (_d = scrollingTo.averageSizeSnapshot) == null ? void 0 : _d[itemType];
1348
+ if (averageSizeForType !== void 0) {
1349
+ size = roundSize(averageSizeForType);
1350
+ }
1351
+ }
1352
+ if (size === void 0) {
1353
+ size = estimatedItemSize + ctx.scrollAxisGap;
1354
+ }
1355
+ setSize(ctx, key, size, notifyTotalSize);
1356
+ return size;
1223
1357
  }
1224
-
1225
- // src/hooks/useStableRenderComponent.tsx
1226
- function useStableRenderComponent(renderComponent, mapProps) {
1227
- const renderComponentRef = useLatestRef(renderComponent);
1228
- const mapPropsRef = useLatestRef(mapProps);
1229
- return React2.useMemo(
1230
- () => React2.forwardRef(
1231
- (props, ref) => {
1232
- var _a3, _b;
1233
- return (_b = (_a3 = renderComponentRef.current) == null ? void 0 : _a3.call(renderComponentRef, mapPropsRef.current(props, ref))) != null ? _b : null;
1234
- }
1235
- ),
1236
- [mapPropsRef, renderComponentRef]
1237
- );
1358
+ function getItemSizeAtIndex(ctx, index) {
1359
+ if (index === void 0 || index < 0) {
1360
+ return void 0;
1361
+ }
1362
+ const targetId = getId(ctx.state, index);
1363
+ return getItemSize(ctx, targetId, index, ctx.state.props.data[index]);
1238
1364
  }
1239
- var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
1240
- const localRef = useRef(null);
1241
- const ref = refView != null ? refView : localRef;
1242
- const { onLayout } = useOnLayoutSync({ onLayoutChange, ref });
1243
- return /* @__PURE__ */ React2.createElement(View$1, { ...rest, onLayout, ref });
1244
- };
1245
1365
 
1246
- // src/components/ListComponent.tsx
1247
- var ListComponent = typedMemo(function ListComponent2({
1248
- canRender,
1249
- style,
1250
- contentContainerStyle,
1251
- horizontal,
1252
- initialContentOffset,
1253
- recycleItems,
1254
- ItemSeparatorComponent,
1255
- alignItemsAtEnd: _alignItemsAtEnd,
1256
- onScroll: onScroll2,
1257
- onLayout,
1258
- ListHeaderComponent,
1259
- ListHeaderComponentStyle,
1260
- ListFooterComponent,
1261
- ListFooterComponentStyle,
1262
- ListEmptyComponent,
1263
- getRenderedItem: getRenderedItem2,
1264
- updateItemSize: updateItemSize2,
1265
- refScrollView,
1266
- renderScrollComponent,
1267
- onLayoutFooter,
1268
- scrollAdjustHandler,
1269
- snapToIndices,
1270
- stickyHeaderConfig,
1271
- stickyHeaderIndices,
1272
- useWindowScroll = false,
1273
- ...rest
1274
- }) {
1275
- const ctx = useStateContext();
1276
- const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1277
- const [alignItemsAtEndPadding = 0, otherAxisSize = 0] = useArr$(["alignItemsAtEndPadding", "otherAxisSize"]);
1278
- const autoOtherAxisStyle = getAutoOtherAxisStyle({
1279
- horizontal,
1280
- needsOtherAxisSize: ctx.state.needsOtherAxisSize,
1281
- otherAxisSize
1282
- });
1283
- const CustomScrollComponent = useStableRenderComponent(
1284
- renderScrollComponent,
1285
- (props, ref) => ({ ...props, ref })
1286
- );
1287
- const ScrollComponent = renderScrollComponent ? CustomScrollComponent : ListComponentScrollView;
1288
- const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
1289
- useLayoutEffect(() => {
1290
- if (!ListHeaderComponent) {
1291
- setHeaderSize(ctx, 0);
1366
+ // src/core/calculateOffsetWithOffsetPosition.ts
1367
+ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1368
+ var _a3;
1369
+ const state = ctx.state;
1370
+ const { index, viewOffset, viewPosition } = params;
1371
+ let offset = offsetParam;
1372
+ if (viewOffset) {
1373
+ offset -= viewOffset;
1374
+ }
1375
+ if (index !== void 0) {
1376
+ const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
1377
+ if (topOffsetAdjustment) {
1378
+ offset += topOffsetAdjustment;
1292
1379
  }
1293
- if (!ListFooterComponent) {
1294
- setFooterSize(ctx, 0);
1380
+ }
1381
+ if (viewPosition !== void 0 && index !== void 0) {
1382
+ const dataLength = state.props.data.length;
1383
+ if (dataLength === 0) {
1384
+ return offset;
1295
1385
  }
1296
- }, [ListHeaderComponent, ListFooterComponent, ctx]);
1297
- const onLayoutHeader = useCallback(
1298
- (rect) => {
1299
- const size = rect[horizontal ? "width" : "height"];
1300
- setHeaderSize(ctx, size);
1301
- },
1302
- [ctx, horizontal]
1303
- );
1304
- const onLayoutFooterInternal = useCallback(
1305
- (rect, fromLayoutEffect) => {
1306
- const size = rect[horizontal ? "width" : "height"];
1307
- setFooterSize(ctx, size);
1308
- onLayoutFooter == null ? void 0 : onLayoutFooter(rect, fromLayoutEffect);
1309
- },
1310
- [ctx, horizontal, onLayoutFooter]
1311
- );
1312
- return /* @__PURE__ */ React2.createElement(
1313
- SnapOrScroll,
1314
- {
1315
- ...rest,
1316
- ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
1317
- contentContainerStyle: [
1318
- horizontal ? {
1319
- height: "100%"
1320
- } : {},
1321
- contentContainerStyle
1322
- ],
1323
- contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1324
- horizontal,
1325
- maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
1326
- onLayout,
1327
- onScroll: onScroll2,
1328
- ref: refScrollView,
1329
- ScrollComponent: snapToIndices ? ScrollComponent : void 0,
1330
- style: autoOtherAxisStyle ? [autoOtherAxisStyle, style] : style
1331
- },
1332
- /* @__PURE__ */ React2.createElement(ScrollAdjust, null),
1333
- ListHeaderComponent && /* @__PURE__ */ React2.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
1334
- ListEmptyComponent && getComponent(ListEmptyComponent),
1335
- alignItemsAtEndPadding > 0 && /* @__PURE__ */ React2.createElement(
1336
- View,
1337
- {
1338
- style: horizontal ? { flexShrink: 0, width: alignItemsAtEndPadding } : { flexShrink: 0, height: alignItemsAtEndPadding }
1339
- },
1340
- null
1341
- ),
1342
- canRender && !ListEmptyComponent && /* @__PURE__ */ React2.createElement(
1343
- Containers,
1344
- {
1345
- getRenderedItem: getRenderedItem2,
1346
- horizontal,
1347
- ItemSeparatorComponent,
1348
- recycleItems,
1349
- stickyHeaderConfig,
1350
- updateItemSize: updateItemSize2
1351
- }
1352
- ),
1353
- ListFooterComponent && /* @__PURE__ */ React2.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
1354
- Platform.OS === "web" && /* @__PURE__ */ React2.createElement(WebAnchoredEndSpace, { horizontal }),
1355
- IS_DEV && ENABLE_DEVMODE
1356
- );
1357
- });
1358
- var WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH = 100;
1359
- var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
1360
- var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
1361
- function useDevChecksImpl(props) {
1362
- const ctx = useStateContext();
1363
- const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
1364
- useEffect(() => {
1365
- if (useWindowScroll && renderScrollComponent) {
1366
- warnDevOnce(
1367
- "useWindowScrollRenderScrollComponent",
1368
- "useWindowScroll is not supported when renderScrollComponent is provided."
1369
- );
1370
- }
1371
- }, [renderScrollComponent, useWindowScroll]);
1372
- useEffect(() => {
1373
- if (!keyExtractor && !ctx.state.isFirst && ctx.state.didDataChange && !childrenMode) {
1374
- warnDevOnce(
1375
- "keyExtractor",
1376
- "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."
1377
- );
1378
- }
1379
- }, [childrenMode, ctx, keyExtractor]);
1380
- useEffect(() => {
1381
- const state = ctx.state;
1382
- const dataLength = state.props.data.length;
1383
- const useWindowScrollResolved = state.props.useWindowScroll;
1384
- if (Platform.OS !== "web" || useWindowScrollResolved || dataLength < WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH) {
1385
- return;
1386
+ const isOutOfBounds = index < 0 || index >= dataLength;
1387
+ const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
1388
+ const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1389
+ const trailingInset = getContentInsetEnd(ctx);
1390
+ offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1391
+ if (!isOutOfBounds && index === state.props.data.length - 1) {
1392
+ const footerSize = peek$(ctx, "footerSize") || 0;
1393
+ offset += footerSize;
1386
1394
  }
1387
- const warnIfUnboundedOuterSize = () => {
1388
- const readyToRender = peek$(ctx, "readyToRender");
1389
- const numContainers = peek$(ctx, "numContainers") || 0;
1390
- const totalSize = peek$(ctx, "totalSize") || 0;
1391
- const scrollLength = ctx.state.scrollLength || 0;
1392
- if (!readyToRender || totalSize <= 0 || scrollLength <= 0) {
1393
- return;
1394
- }
1395
- const rendersAlmostEverything = numContainers >= Math.ceil(dataLength * WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO);
1396
- const viewportMatchesContent = scrollLength >= totalSize * WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO;
1397
- if (rendersAlmostEverything && viewportMatchesContent) {
1398
- warnDevOnce(
1399
- "webUnboundedOuterSize",
1400
- "LegendList appears to have an unbounded outer height on web, so virtualization is effectively disabled. Set a bounded height or flex: 1 on the list container, or use useWindowScroll."
1401
- );
1402
- }
1403
- };
1404
- warnIfUnboundedOuterSize();
1405
- const unsubscribe = [
1406
- listen$(ctx, "numContainers", warnIfUnboundedOuterSize),
1407
- listen$(ctx, "readyToRender", warnIfUnboundedOuterSize),
1408
- listen$(ctx, "totalSize", warnIfUnboundedOuterSize)
1409
- ];
1410
- return () => {
1411
- for (const unsub of unsubscribe) {
1412
- unsub();
1413
- }
1414
- };
1415
- }, [ctx]);
1395
+ }
1396
+ return offset;
1416
1397
  }
1417
- function useDevChecksNoop(_props) {
1398
+
1399
+ // src/core/clampScrollOffset.ts
1400
+ function clampScrollOffset(ctx, offset, scrollTarget) {
1401
+ const state = ctx.state;
1402
+ const contentSize = getContentSize(ctx);
1403
+ let clampedOffset = offset;
1404
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform.OS !== "android" || state.lastLayout)) {
1405
+ const baseMaxOffset = Math.max(0, contentSize - state.scrollLength);
1406
+ const viewOffset = scrollTarget == null ? void 0 : scrollTarget.viewOffset;
1407
+ const extraEndOffset = typeof viewOffset === "number" && viewOffset < 0 ? -viewOffset : 0;
1408
+ const maxOffset = baseMaxOffset + extraEndOffset;
1409
+ clampedOffset = Math.min(offset, maxOffset);
1410
+ }
1411
+ clampedOffset = Math.max(0, clampedOffset);
1412
+ return clampedOffset;
1418
1413
  }
1419
- var useDevChecks = IS_DEV ? useDevChecksImpl : useDevChecksNoop;
1420
1414
 
1421
1415
  // src/core/deferredPublicOnScroll.ts
1422
1416
  function withResolvedContentOffset(state, event, resolvedOffset) {
@@ -1729,6 +1723,66 @@ function recalculateSettledScroll(ctx) {
1729
1723
  checkThresholds(ctx);
1730
1724
  }
1731
1725
 
1726
+ // src/core/adaptiveRender.ts
1727
+ var DEFAULT_ENTER_VELOCITY = 4;
1728
+ var DEFAULT_EXIT_VELOCITY = 1;
1729
+ var DEFAULT_EXIT_DELAY = 1e3;
1730
+ function scheduleAdaptiveRenderExit(ctx, exitDelay) {
1731
+ const state = ctx.state;
1732
+ const previousTimeout = state.timeoutAdaptiveRender;
1733
+ if (previousTimeout !== void 0) {
1734
+ clearTimeout(previousTimeout);
1735
+ state.timeouts.delete(previousTimeout);
1736
+ state.timeoutAdaptiveRender = void 0;
1737
+ }
1738
+ if (exitDelay <= 0) {
1739
+ setAdaptiveRender(ctx, "normal");
1740
+ } else {
1741
+ const timeout = setTimeout(() => {
1742
+ state.timeouts.delete(timeout);
1743
+ state.timeoutAdaptiveRender = void 0;
1744
+ setAdaptiveRender(ctx, "normal");
1745
+ }, exitDelay);
1746
+ state.timeoutAdaptiveRender = timeout;
1747
+ state.timeouts.add(timeout);
1748
+ }
1749
+ }
1750
+ function setAdaptiveRender(ctx, mode) {
1751
+ var _a3, _b;
1752
+ const previousMode = peek$(ctx, "adaptiveRender");
1753
+ if (previousMode !== mode) {
1754
+ set$(ctx, "adaptiveRender", mode);
1755
+ (_b = (_a3 = ctx.state.props.adaptiveRender) == null ? void 0 : _a3.onChange) == null ? void 0 : _b.call(_a3, mode);
1756
+ }
1757
+ }
1758
+ function updateAdaptiveRender(ctx, scrollVelocity) {
1759
+ var _a3, _b, _c;
1760
+ const state = ctx.state;
1761
+ const adaptiveRender = state.props.adaptiveRender;
1762
+ const enterVelocity = (_a3 = adaptiveRender == null ? void 0 : adaptiveRender.enterVelocity) != null ? _a3 : DEFAULT_ENTER_VELOCITY;
1763
+ const exitVelocity = (_b = adaptiveRender == null ? void 0 : adaptiveRender.exitVelocity) != null ? _b : DEFAULT_EXIT_VELOCITY;
1764
+ const exitDelay = (_c = adaptiveRender == null ? void 0 : adaptiveRender.exitDelay) != null ? _c : DEFAULT_EXIT_DELAY;
1765
+ const currentMode = peek$(ctx, "adaptiveRender");
1766
+ const threshold = currentMode === "light" ? exitVelocity : enterVelocity;
1767
+ const nextMode = Math.abs(scrollVelocity) > threshold ? "light" : "normal";
1768
+ const previousMode = state.timeoutAdaptiveRender !== void 0 ? "normal" : currentMode;
1769
+ if (nextMode !== previousMode) {
1770
+ if (nextMode === "light") {
1771
+ setAdaptiveRender(ctx, "light");
1772
+ scheduleAdaptiveRenderExit(ctx, exitDelay);
1773
+ } else if (currentMode === "light") {
1774
+ scheduleAdaptiveRenderExit(ctx, exitDelay);
1775
+ }
1776
+ }
1777
+ }
1778
+
1779
+ // src/utils/getEffectiveDrawDistance.ts
1780
+ var INITIAL_DRAW_DISTANCE = 100;
1781
+ function getEffectiveDrawDistance(ctx) {
1782
+ const drawDistance = ctx.state.props.drawDistance;
1783
+ return peek$(ctx, "readyToRender") ? drawDistance : Math.min(drawDistance, INITIAL_DRAW_DISTANCE);
1784
+ }
1785
+
1732
1786
  // src/utils/setInitialRenderState.ts
1733
1787
  function setInitialRenderState(ctx, {
1734
1788
  didLayout,
@@ -1748,6 +1802,13 @@ function setInitialRenderState(ctx, {
1748
1802
  const isReadyToRender = Boolean(state.didContainersLayout && state.didFinishInitialScroll);
1749
1803
  if (isReadyToRender && !peek$(ctx, "readyToRender")) {
1750
1804
  set$(ctx, "readyToRender", true);
1805
+ setAdaptiveRender(ctx, "normal");
1806
+ if (state.props.drawDistance > INITIAL_DRAW_DISTANCE) {
1807
+ requestAnimationFrame(() => {
1808
+ var _a3;
1809
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
1810
+ });
1811
+ }
1751
1812
  if (onLoad) {
1752
1813
  onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1753
1814
  }
@@ -1822,259 +1883,63 @@ function finishInitialScroll(ctx, options) {
1822
1883
  complete();
1823
1884
  }
1824
1885
 
1825
- // src/core/calculateOffsetForIndex.ts
1826
- function calculateOffsetForIndex(ctx, index) {
1886
+ // src/core/finishScrollTo.ts
1887
+ function finishScrollTo(ctx) {
1888
+ var _a3, _b;
1827
1889
  const state = ctx.state;
1828
- return index !== void 0 ? state.positions[index] || 0 : 0;
1829
- }
1830
-
1831
- // src/core/getTopOffsetAdjustment.ts
1832
- function getTopOffsetAdjustment(ctx) {
1833
- return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
1834
- }
1835
-
1836
- // src/utils/getId.ts
1837
- function getId(state, index) {
1838
- const { data, keyExtractor } = state.props;
1839
- if (!data) {
1840
- return "";
1890
+ if (state == null ? void 0 : state.scrollingTo) {
1891
+ const resolvePendingScroll = state.pendingScrollResolve;
1892
+ state.pendingScrollResolve = void 0;
1893
+ const scrollingTo = state.scrollingTo;
1894
+ state.scrollHistory.length = 0;
1895
+ state.scrollingTo = void 0;
1896
+ if (state.pendingTotalSize !== void 0) {
1897
+ addTotalSize(ctx, null, state.pendingTotalSize);
1898
+ }
1899
+ if (PlatformAdjustBreaksScroll) {
1900
+ state.scrollAdjustHandler.commitPendingAdjust(scrollingTo);
1901
+ }
1902
+ if (scrollingTo.isInitialScroll || state.initialScroll) {
1903
+ const isOffsetSession = ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset";
1904
+ const shouldPreserveResizeTarget = !!scrollingTo.isInitialScroll && !state.clearPreservedInitialScrollOnNextFinish && state.props.data.length > 0 && ((_b = state.initialScroll) == null ? void 0 : _b.viewPosition) === 1;
1905
+ finishInitialScroll(ctx, {
1906
+ onFinished: () => {
1907
+ resolvePendingScroll == null ? void 0 : resolvePendingScroll();
1908
+ },
1909
+ preserveTarget: isOffsetSession && state.props.data.length === 0 || shouldPreserveResizeTarget,
1910
+ recalculateItems: true,
1911
+ schedulePreservedTargetClear: shouldPreserveResizeTarget,
1912
+ syncObservedOffset: isOffsetSession,
1913
+ waitForCompletionFrame: !!scrollingTo.waitForInitialScrollCompletionFrame
1914
+ });
1915
+ return;
1916
+ }
1917
+ recalculateSettledScroll(ctx);
1918
+ resolvePendingScroll == null ? void 0 : resolvePendingScroll();
1841
1919
  }
1842
- const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
1843
- const id = ret;
1844
- state.idCache[index] = id;
1845
- return id;
1846
1920
  }
1847
1921
 
1848
- // src/core/addTotalSize.ts
1849
- function addTotalSize(ctx, key, add, notifyTotalSize = true) {
1850
- const state = ctx.state;
1851
- const prevTotalSize = state.totalSize;
1852
- let totalSize = state.totalSize;
1853
- if (key === null) {
1854
- totalSize = add;
1855
- if (state.timeoutSetPaddingTop) {
1856
- clearTimeout(state.timeoutSetPaddingTop);
1857
- state.timeoutSetPaddingTop = void 0;
1922
+ // src/core/checkFinishedScroll.ts
1923
+ var INITIAL_SCROLL_MAX_FALLBACK_CHECKS = 20;
1924
+ var INITIAL_SCROLL_COMPLETION_TARGET_EPSILON = 1;
1925
+ var INITIAL_SCROLL_ZERO_TARGET_EPSILON = 1;
1926
+ var SILENT_INITIAL_SCROLL_RETRY_DELAY_MS = 16;
1927
+ var SILENT_INITIAL_SCROLL_TARGET_EPSILON = 1;
1928
+ function checkFinishedScroll(ctx, options) {
1929
+ const scrollingTo = ctx.state.scrollingTo;
1930
+ if (options == null ? void 0 : options.onlyIfAligned) {
1931
+ if (!(scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) || scrollingTo.animated) {
1932
+ return;
1858
1933
  }
1859
- } else {
1860
- totalSize += add;
1861
- }
1862
- if (prevTotalSize !== totalSize) {
1863
- if (!IsNewArchitecture && state.initialScroll && totalSize < prevTotalSize) {
1864
- state.pendingTotalSize = totalSize;
1865
- } else {
1866
- state.pendingTotalSize = void 0;
1867
- state.totalSize = totalSize;
1868
- if (notifyTotalSize) {
1869
- set$(ctx, "totalSize", totalSize);
1870
- }
1871
- updateContentMetrics(ctx);
1934
+ if (!getResolvedScrollCompletionState(ctx, scrollingTo).isAtResolvedTarget) {
1935
+ return;
1872
1936
  }
1873
- } else if (notifyTotalSize && ctx.values.get("totalSize") !== totalSize) {
1874
- set$(ctx, "totalSize", totalSize);
1875
1937
  }
1938
+ ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
1876
1939
  }
1877
-
1878
- // src/core/setSize.ts
1879
- function setSize(ctx, itemKey, size, notifyTotalSize = true) {
1880
- const state = ctx.state;
1881
- const { sizes } = state;
1882
- const previousSize = sizes.get(itemKey);
1883
- const diff = previousSize !== void 0 ? size - previousSize : size;
1884
- if (diff !== 0) {
1885
- addTotalSize(ctx, itemKey, diff, notifyTotalSize);
1886
- }
1887
- sizes.set(itemKey, size);
1888
- }
1889
-
1890
- // src/utils/getItemSize.ts
1891
- function getKnownOrFixedSize(ctx, key, index, data, resolved) {
1892
- var _a3, _b;
1893
- const state = ctx.state;
1894
- const { getFixedItemSize, getItemType } = state.props;
1895
- let size = key ? state.sizesKnown.get(key) : void 0;
1896
- if (size === void 0 && key && getFixedItemSize) {
1897
- const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1898
- size = (resolved == null ? void 0 : resolved.didResolveFixedItemSize) ? resolved.fixedItemSize : getFixedItemSize(data, index, itemType);
1899
- if (size !== void 0) {
1900
- state.sizesKnown.set(key, size);
1901
- }
1902
- }
1903
- return size;
1904
- }
1905
- function getKnownOrFixedItemSize(ctx, index) {
1906
- const key = getId(ctx.state, index);
1907
- return getKnownOrFixedSize(ctx, key, index, ctx.state.props.data[index]);
1908
- }
1909
- function areKnownOrFixedItemSizesAvailable(ctx, startIndex, endIndex) {
1910
- for (let index = startIndex; index <= endIndex; index++) {
1911
- if (getKnownOrFixedItemSize(ctx, index) === void 0) {
1912
- return false;
1913
- }
1914
- }
1915
- return true;
1916
- }
1917
- function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize, notifyTotalSize, resolved) {
1918
- var _a3, _b, _c, _d;
1919
- const state = ctx.state;
1920
- const {
1921
- sizes,
1922
- averageSizes,
1923
- props: { estimatedItemSize, getItemType },
1924
- scrollingTo
1925
- } = state;
1926
- const sizeKnown = state.sizesKnown.get(key);
1927
- if (sizeKnown !== void 0) {
1928
- return sizeKnown;
1929
- }
1930
- let size;
1931
- const renderedSize = sizes.get(key);
1932
- if (preferCachedSize) {
1933
- if (renderedSize !== void 0) {
1934
- return renderedSize;
1935
- }
1936
- }
1937
- size = getKnownOrFixedSize(ctx, key, index, data, resolved);
1938
- if (size !== void 0) {
1939
- setSize(ctx, key, size, notifyTotalSize);
1940
- return size;
1941
- }
1942
- const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1943
- if (useAverageSize && !scrollingTo) {
1944
- const averageSizeForType = (_c = averageSizes[itemType]) == null ? void 0 : _c.avg;
1945
- if (averageSizeForType !== void 0) {
1946
- size = roundSize(averageSizeForType);
1947
- }
1948
- }
1949
- if (size === void 0 && renderedSize !== void 0) {
1950
- return renderedSize;
1951
- }
1952
- if (size === void 0 && useAverageSize && scrollingTo) {
1953
- const averageSizeForType = (_d = scrollingTo.averageSizeSnapshot) == null ? void 0 : _d[itemType];
1954
- if (averageSizeForType !== void 0) {
1955
- size = roundSize(averageSizeForType);
1956
- }
1957
- }
1958
- if (size === void 0) {
1959
- size = estimatedItemSize;
1960
- }
1961
- setSize(ctx, key, size, notifyTotalSize);
1962
- return size;
1963
- }
1964
- function getItemSizeAtIndex(ctx, index) {
1965
- if (index === void 0 || index < 0) {
1966
- return void 0;
1967
- }
1968
- const targetId = getId(ctx.state, index);
1969
- return getItemSize(ctx, targetId, index, ctx.state.props.data[index]);
1970
- }
1971
-
1972
- // src/core/calculateOffsetWithOffsetPosition.ts
1973
- function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1974
- var _a3;
1975
- const state = ctx.state;
1976
- const { index, viewOffset, viewPosition } = params;
1977
- let offset = offsetParam;
1978
- if (viewOffset) {
1979
- offset -= viewOffset;
1980
- }
1981
- if (index !== void 0) {
1982
- const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
1983
- if (topOffsetAdjustment) {
1984
- offset += topOffsetAdjustment;
1985
- }
1986
- }
1987
- if (viewPosition !== void 0 && index !== void 0) {
1988
- const dataLength = state.props.data.length;
1989
- if (dataLength === 0) {
1990
- return offset;
1991
- }
1992
- const isOutOfBounds = index < 0 || index >= dataLength;
1993
- const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
1994
- const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1995
- const trailingInset = getContentInsetEnd(ctx);
1996
- offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1997
- if (!isOutOfBounds && index === state.props.data.length - 1) {
1998
- const footerSize = peek$(ctx, "footerSize") || 0;
1999
- offset += footerSize;
2000
- }
2001
- }
2002
- return offset;
2003
- }
2004
-
2005
- // src/core/clampScrollOffset.ts
2006
- function clampScrollOffset(ctx, offset, scrollTarget) {
2007
- const state = ctx.state;
2008
- const contentSize = getContentSize(ctx);
2009
- let clampedOffset = offset;
2010
- if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform.OS !== "android" || state.lastLayout)) {
2011
- const baseMaxOffset = Math.max(0, contentSize - state.scrollLength);
2012
- const viewOffset = scrollTarget == null ? void 0 : scrollTarget.viewOffset;
2013
- const extraEndOffset = typeof viewOffset === "number" && viewOffset < 0 ? -viewOffset : 0;
2014
- const maxOffset = baseMaxOffset + extraEndOffset;
2015
- clampedOffset = Math.min(offset, maxOffset);
2016
- }
2017
- clampedOffset = Math.max(0, clampedOffset);
2018
- return clampedOffset;
2019
- }
2020
-
2021
- // src/core/finishScrollTo.ts
2022
- function finishScrollTo(ctx) {
2023
- var _a3, _b;
2024
- const state = ctx.state;
2025
- if (state == null ? void 0 : state.scrollingTo) {
2026
- const resolvePendingScroll = state.pendingScrollResolve;
2027
- state.pendingScrollResolve = void 0;
2028
- const scrollingTo = state.scrollingTo;
2029
- state.scrollHistory.length = 0;
2030
- state.scrollingTo = void 0;
2031
- if (state.pendingTotalSize !== void 0) {
2032
- addTotalSize(ctx, null, state.pendingTotalSize);
2033
- }
2034
- if (PlatformAdjustBreaksScroll) {
2035
- state.scrollAdjustHandler.commitPendingAdjust(scrollingTo);
2036
- }
2037
- if (scrollingTo.isInitialScroll || state.initialScroll) {
2038
- const isOffsetSession = ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset";
2039
- const shouldPreserveResizeTarget = !!scrollingTo.isInitialScroll && !state.clearPreservedInitialScrollOnNextFinish && state.props.data.length > 0 && ((_b = state.initialScroll) == null ? void 0 : _b.viewPosition) === 1;
2040
- finishInitialScroll(ctx, {
2041
- onFinished: () => {
2042
- resolvePendingScroll == null ? void 0 : resolvePendingScroll();
2043
- },
2044
- preserveTarget: isOffsetSession && state.props.data.length === 0 || shouldPreserveResizeTarget,
2045
- recalculateItems: true,
2046
- schedulePreservedTargetClear: shouldPreserveResizeTarget,
2047
- syncObservedOffset: isOffsetSession,
2048
- waitForCompletionFrame: !!scrollingTo.waitForInitialScrollCompletionFrame
2049
- });
2050
- return;
2051
- }
2052
- recalculateSettledScroll(ctx);
2053
- resolvePendingScroll == null ? void 0 : resolvePendingScroll();
2054
- }
2055
- }
2056
-
2057
- // src/core/checkFinishedScroll.ts
2058
- var INITIAL_SCROLL_MAX_FALLBACK_CHECKS = 20;
2059
- var INITIAL_SCROLL_COMPLETION_TARGET_EPSILON = 1;
2060
- var INITIAL_SCROLL_ZERO_TARGET_EPSILON = 1;
2061
- var SILENT_INITIAL_SCROLL_RETRY_DELAY_MS = 16;
2062
- var SILENT_INITIAL_SCROLL_TARGET_EPSILON = 1;
2063
- function checkFinishedScroll(ctx, options) {
2064
- const scrollingTo = ctx.state.scrollingTo;
2065
- if (options == null ? void 0 : options.onlyIfAligned) {
2066
- if (!(scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) || scrollingTo.animated) {
2067
- return;
2068
- }
2069
- if (!getResolvedScrollCompletionState(ctx, scrollingTo).isAtResolvedTarget) {
2070
- return;
2071
- }
2072
- }
2073
- ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
2074
- }
2075
- function hasScrollCompletionOwnership(state, options) {
2076
- const { clampedTargetOffset, scrollingTo } = options;
2077
- return !scrollingTo.isInitialScroll || state.hasScrolled || clampedTargetOffset <= INITIAL_SCROLL_COMPLETION_TARGET_EPSILON;
1940
+ function hasScrollCompletionOwnership(state, options) {
1941
+ const { clampedTargetOffset, scrollingTo } = options;
1942
+ return !scrollingTo.isInitialScroll || state.hasScrolled || clampedTargetOffset <= INITIAL_SCROLL_COMPLETION_TARGET_EPSILON;
2078
1943
  }
2079
1944
  function isSilentInitialDispatch(state, scrollingTo) {
2080
1945
  return !!(scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) && initialScrollCompletion.didDispatchNativeScroll(state) && !state.hasScrolled;
@@ -2183,65 +2048,374 @@ function checkFinishedScrollFallback(ctx) {
2183
2048
  state,
2184
2049
  isStillScrollingTo
2185
2050
  );
2186
- const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
2187
- const canFinishAfterSilentNativeDispatch = Platform.OS === "android" && silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
2188
- const shouldRetrySilentInitialNativeScroll = Platform.OS === "android" && canFinishAfterSilentNativeDispatch && !initialScrollCompletion.didRetrySilentInitialScroll(state);
2189
- const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
2190
- const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
2191
- const shouldRetryUnalignedEndScroll = Platform.OS === "ios" && !isStillScrollingTo.isInitialScroll && isEndAlignedLastItemTarget(ctx, isStillScrollingTo) && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
2192
- if (shouldRetrySilentInitialNativeScroll) {
2193
- const targetOffset = (_b = (_a3 = getInitialScrollWatchdogTargetOffset(state)) != null ? _a3 : isStillScrollingTo.targetOffset) != null ? _b : 0;
2194
- const jiggleOffset = targetOffset >= SILENT_INITIAL_SCROLL_TARGET_EPSILON ? targetOffset - SILENT_INITIAL_SCROLL_TARGET_EPSILON : targetOffset + SILENT_INITIAL_SCROLL_TARGET_EPSILON;
2195
- initialScrollCompletion.markSilentInitialScrollRetry(state);
2196
- scrollToFallbackOffset(ctx, jiggleOffset);
2197
- requestAnimationFrame(() => {
2198
- scrollToFallbackOffset(ctx, targetOffset);
2199
- });
2200
- scheduleFallbackCheck(SILENT_INITIAL_SCROLL_RETRY_DELAY_MS);
2201
- } else if (shouldRetryUnalignedEndScroll) {
2202
- scrollToFallbackOffset(ctx, completionState.clampedTargetOffset);
2203
- scheduleFallbackCheck(100);
2204
- } else if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
2205
- finishScrollTo(ctx);
2206
- } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
2207
- const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
2208
- scrollToFallbackOffset(ctx, targetOffset);
2209
- scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2210
- } else {
2211
- scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2212
- }
2051
+ const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
2052
+ const canFinishAfterSilentNativeDispatch = Platform.OS === "android" && silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
2053
+ const shouldRetrySilentInitialNativeScroll = Platform.OS === "android" && canFinishAfterSilentNativeDispatch && !initialScrollCompletion.didRetrySilentInitialScroll(state);
2054
+ const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
2055
+ const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
2056
+ const shouldRetryUnalignedEndScroll = Platform.OS === "ios" && !isStillScrollingTo.isInitialScroll && isEndAlignedLastItemTarget(ctx, isStillScrollingTo) && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
2057
+ if (shouldRetrySilentInitialNativeScroll) {
2058
+ const targetOffset = (_b = (_a3 = getInitialScrollWatchdogTargetOffset(state)) != null ? _a3 : isStillScrollingTo.targetOffset) != null ? _b : 0;
2059
+ const jiggleOffset = targetOffset >= SILENT_INITIAL_SCROLL_TARGET_EPSILON ? targetOffset - SILENT_INITIAL_SCROLL_TARGET_EPSILON : targetOffset + SILENT_INITIAL_SCROLL_TARGET_EPSILON;
2060
+ initialScrollCompletion.markSilentInitialScrollRetry(state);
2061
+ scrollToFallbackOffset(ctx, jiggleOffset);
2062
+ requestAnimationFrame(() => {
2063
+ scrollToFallbackOffset(ctx, targetOffset);
2064
+ });
2065
+ scheduleFallbackCheck(SILENT_INITIAL_SCROLL_RETRY_DELAY_MS);
2066
+ } else if (shouldRetryUnalignedEndScroll) {
2067
+ scrollToFallbackOffset(ctx, completionState.clampedTargetOffset);
2068
+ scheduleFallbackCheck(100);
2069
+ } else if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
2070
+ finishScrollTo(ctx);
2071
+ } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
2072
+ const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
2073
+ scrollToFallbackOffset(ctx, targetOffset);
2074
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2075
+ } else {
2076
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2077
+ }
2078
+ }
2079
+ };
2080
+ checkHasScrolled();
2081
+ }, initialDelay);
2082
+ }
2083
+
2084
+ // src/core/doScrollTo.native.ts
2085
+ function doScrollTo(ctx, params) {
2086
+ const state = ctx.state;
2087
+ const { animated, horizontal, isInitialScroll, offset } = params;
2088
+ const isAnimated = !!animated;
2089
+ const { refScroller } = state;
2090
+ const scroller = refScroller.current;
2091
+ if (!scroller) {
2092
+ return;
2093
+ }
2094
+ const isHorizontal = !!horizontal;
2095
+ const contentSize = isHorizontal ? getContentSize(ctx) : void 0;
2096
+ const nativeOffset = toNativeHorizontalOffset(state, offset, contentSize);
2097
+ scroller.scrollTo({
2098
+ animated: isAnimated,
2099
+ x: isHorizontal ? nativeOffset : 0,
2100
+ y: isHorizontal ? 0 : offset
2101
+ });
2102
+ if (isInitialScroll) {
2103
+ initialScrollCompletion.markInitialScrollNativeDispatch(state);
2104
+ }
2105
+ if (!isAnimated) {
2106
+ state.scroll = offset;
2107
+ checkFinishedScrollFallback(ctx);
2108
+ }
2109
+ }
2110
+
2111
+ // src/utils/requestAdjust.ts
2112
+ function requestAdjust(ctx, positionDiff, dataChanged) {
2113
+ const state = ctx.state;
2114
+ if (Math.abs(positionDiff) > 0.1) {
2115
+ const needsScrollWorkaround = Platform.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff;
2116
+ const doit = () => {
2117
+ if (needsScrollWorkaround) {
2118
+ doScrollTo(ctx, { horizontal: state.props.horizontal, offset: state.scroll });
2119
+ } else {
2120
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
2121
+ if (state.adjustingFromInitialMount) {
2122
+ state.adjustingFromInitialMount--;
2123
+ }
2124
+ }
2125
+ };
2126
+ state.scroll += positionDiff;
2127
+ state.scrollForNextCalculateItemsInView = void 0;
2128
+ const readyToRender = peek$(ctx, "readyToRender");
2129
+ if (readyToRender) {
2130
+ doit();
2131
+ if (Platform.OS !== "web") {
2132
+ const threshold = state.scroll - positionDiff / 2;
2133
+ if (!state.ignoreScrollFromMVCP) {
2134
+ state.ignoreScrollFromMVCP = {};
2135
+ }
2136
+ if (positionDiff > 0) {
2137
+ state.ignoreScrollFromMVCP.lt = threshold;
2138
+ } else {
2139
+ state.ignoreScrollFromMVCP.gt = threshold;
2140
+ }
2141
+ if (state.ignoreScrollFromMVCPTimeout) {
2142
+ clearTimeout(state.ignoreScrollFromMVCPTimeout);
2143
+ }
2144
+ const delay = needsScrollWorkaround ? 250 : 100;
2145
+ state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
2146
+ var _a3;
2147
+ state.ignoreScrollFromMVCP = void 0;
2148
+ const shouldForceUpdate = state.ignoreScrollFromMVCPIgnored && state.scrollProcessingEnabled !== false;
2149
+ if (shouldForceUpdate) {
2150
+ state.ignoreScrollFromMVCPIgnored = false;
2151
+ state.scrollPending = state.scroll;
2152
+ (_a3 = state.reprocessCurrentScroll) == null ? void 0 : _a3.call(state);
2153
+ }
2154
+ }, delay);
2155
+ }
2156
+ } else {
2157
+ state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2158
+ requestAnimationFrame(doit);
2159
+ }
2160
+ }
2161
+ }
2162
+
2163
+ // src/core/updateContentMetrics.ts
2164
+ var SCROLL_ADJUST_EPSILON = 0.1;
2165
+ function setContentLengthSignal(ctx, signalName, size) {
2166
+ if (peek$(ctx, signalName) !== size) {
2167
+ set$(ctx, signalName, size);
2168
+ updateContentMetricsState(ctx);
2169
+ }
2170
+ }
2171
+ function shouldAdjustForHeaderSizeChange(ctx, previousHeaderSize, nextHeaderSize) {
2172
+ const { didContainersLayout, didFinishInitialScroll, props, scroll, scrollingTo } = ctx.state;
2173
+ const sizeDiff = nextHeaderSize - previousHeaderSize;
2174
+ const leadingPadding = props.horizontal ? props.stylePaddingLeft : props.stylePaddingTop;
2175
+ const previousHeaderEnd = (leadingPadding || 0) + previousHeaderSize;
2176
+ return Platform.OS === "web" && props.maintainVisibleContentPosition.size && didContainersLayout && didFinishInitialScroll && !scrollingTo && scroll >= previousHeaderEnd - SCROLL_ADJUST_EPSILON && Math.abs(sizeDiff) > SCROLL_ADJUST_EPSILON;
2177
+ }
2178
+ function setHeaderSize(ctx, size) {
2179
+ const { state } = ctx;
2180
+ const previousHeaderSize = peek$(ctx, "headerSize") || 0;
2181
+ const didChange = previousHeaderSize !== size;
2182
+ const hasMeasuredOrEstimatedHeaderBaseline = state.didMeasureHeader || previousHeaderSize > SCROLL_ADJUST_EPSILON;
2183
+ if (didChange) {
2184
+ set$(ctx, "headerSize", size);
2185
+ updateContentMetricsState(ctx);
2186
+ if (hasMeasuredOrEstimatedHeaderBaseline && shouldAdjustForHeaderSizeChange(ctx, previousHeaderSize, size)) {
2187
+ requestAdjust(ctx, size - previousHeaderSize);
2188
+ }
2189
+ }
2190
+ state.didMeasureHeader = true;
2191
+ }
2192
+ function setFooterSize(ctx, size) {
2193
+ setContentLengthSignal(ctx, "footerSize", size);
2194
+ }
2195
+ function areInsetsEqual(left, right) {
2196
+ var _a3, _b, _c, _d, _e, _f, _g, _h;
2197
+ return ((_a3 = left == null ? void 0 : left.top) != null ? _a3 : 0) === ((_b = right == null ? void 0 : right.top) != null ? _b : 0) && ((_c = left == null ? void 0 : left.bottom) != null ? _c : 0) === ((_d = right == null ? void 0 : right.bottom) != null ? _d : 0) && ((_e = left == null ? void 0 : left.left) != null ? _e : 0) === ((_f = right == null ? void 0 : right.left) != null ? _f : 0) && ((_g = left == null ? void 0 : left.right) != null ? _g : 0) === ((_h = right == null ? void 0 : right.right) != null ? _h : 0);
2198
+ }
2199
+ function setContentInsetOverride(ctx, inset) {
2200
+ const { state } = ctx;
2201
+ const previousInset = state.contentInsetOverride;
2202
+ const nextInset = inset != null ? inset : void 0;
2203
+ const didChange = !areInsetsEqual(previousInset, nextInset);
2204
+ state.contentInsetOverride = nextInset;
2205
+ if (didChange) {
2206
+ updateContentMetricsState(ctx);
2207
+ }
2208
+ return didChange;
2209
+ }
2210
+ function useLatestRef(value) {
2211
+ const ref = React2.useRef(value);
2212
+ ref.current = value;
2213
+ return ref;
2214
+ }
2215
+
2216
+ // src/hooks/useStableRenderComponent.tsx
2217
+ function useStableRenderComponent(renderComponent, mapProps) {
2218
+ const renderComponentRef = useLatestRef(renderComponent);
2219
+ const mapPropsRef = useLatestRef(mapProps);
2220
+ return React2.useMemo(
2221
+ () => React2.forwardRef(
2222
+ (props, ref) => {
2223
+ var _a3, _b;
2224
+ return (_b = (_a3 = renderComponentRef.current) == null ? void 0 : _a3.call(renderComponentRef, mapPropsRef.current(props, ref))) != null ? _b : null;
2225
+ }
2226
+ ),
2227
+ [mapPropsRef, renderComponentRef]
2228
+ );
2229
+ }
2230
+ var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
2231
+ const localRef = useRef(null);
2232
+ const ref = refView != null ? refView : localRef;
2233
+ const { onLayout } = useOnLayoutSync({ onLayoutChange, ref });
2234
+ return /* @__PURE__ */ React2.createElement(View$1, { ...rest, onLayout, ref });
2235
+ };
2236
+
2237
+ // src/components/ListComponent.tsx
2238
+ var AlignItemsAtEndSpacer = typedMemo(function AlignItemsAtEndSpacer2({ horizontal }) {
2239
+ const [alignItemsAtEndPadding = 0] = useArr$(["alignItemsAtEndPadding"]);
2240
+ if (alignItemsAtEndPadding <= 0) {
2241
+ return null;
2242
+ }
2243
+ return /* @__PURE__ */ React2.createElement(
2244
+ View,
2245
+ {
2246
+ style: horizontal ? { flexShrink: 0, width: alignItemsAtEndPadding } : { flexShrink: 0, height: alignItemsAtEndPadding }
2247
+ },
2248
+ null
2249
+ );
2250
+ });
2251
+ var ListComponent = typedMemo(function ListComponent2({
2252
+ canRender,
2253
+ style,
2254
+ contentContainerStyle,
2255
+ horizontal,
2256
+ initialContentOffset,
2257
+ recycleItems,
2258
+ ItemSeparatorComponent,
2259
+ alignItemsAtEnd: _alignItemsAtEnd,
2260
+ onScroll: onScroll2,
2261
+ onLayout,
2262
+ ListHeaderComponent,
2263
+ ListHeaderComponentStyle,
2264
+ ListFooterComponent,
2265
+ ListFooterComponentStyle,
2266
+ ListEmptyComponent,
2267
+ getRenderedItem: getRenderedItem2,
2268
+ updateItemSize: updateItemSize2,
2269
+ refScrollView,
2270
+ renderScrollComponent,
2271
+ onLayoutFooter,
2272
+ scrollAdjustHandler,
2273
+ snapToIndices,
2274
+ stickyHeaderConfig,
2275
+ stickyHeaderIndices,
2276
+ useWindowScroll = false,
2277
+ ...rest
2278
+ }) {
2279
+ const ctx = useStateContext();
2280
+ const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
2281
+ const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
2282
+ const shouldRenderAlignItemsAtEndSpacer = ctx.state.props.alignItemsAtEndPaddingEnabled;
2283
+ const autoOtherAxisStyle = getAutoOtherAxisStyle({
2284
+ horizontal,
2285
+ needsOtherAxisSize: ctx.state.needsOtherAxisSize,
2286
+ otherAxisSize
2287
+ });
2288
+ const CustomScrollComponent = useStableRenderComponent(
2289
+ renderScrollComponent,
2290
+ (props, ref) => ({ ...props, ref })
2291
+ );
2292
+ const ScrollComponent = renderScrollComponent ? CustomScrollComponent : ListComponentScrollView;
2293
+ const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
2294
+ useLayoutEffect(() => {
2295
+ if (!ListHeaderComponent) {
2296
+ setHeaderSize(ctx, 0);
2297
+ }
2298
+ if (!ListFooterComponent) {
2299
+ setFooterSize(ctx, 0);
2300
+ }
2301
+ }, [ListHeaderComponent, ListFooterComponent, ctx]);
2302
+ const onLayoutHeader = useCallback(
2303
+ (rect) => {
2304
+ const size = rect[horizontal ? "width" : "height"];
2305
+ setHeaderSize(ctx, size);
2306
+ },
2307
+ [ctx, horizontal]
2308
+ );
2309
+ const onLayoutFooterInternal = useCallback(
2310
+ (rect, fromLayoutEffect) => {
2311
+ const size = rect[horizontal ? "width" : "height"];
2312
+ setFooterSize(ctx, size);
2313
+ onLayoutFooter == null ? void 0 : onLayoutFooter(rect, fromLayoutEffect);
2314
+ },
2315
+ [ctx, horizontal, onLayoutFooter]
2316
+ );
2317
+ return /* @__PURE__ */ React2.createElement(
2318
+ SnapOrScroll,
2319
+ {
2320
+ ...rest,
2321
+ ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
2322
+ contentContainerStyle: [
2323
+ horizontal ? {
2324
+ height: "100%"
2325
+ } : {},
2326
+ contentContainerStyle
2327
+ ],
2328
+ contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
2329
+ horizontal,
2330
+ maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
2331
+ onLayout,
2332
+ onScroll: onScroll2,
2333
+ ref: refScrollView,
2334
+ ScrollComponent: snapToIndices ? ScrollComponent : void 0,
2335
+ style: autoOtherAxisStyle ? [autoOtherAxisStyle, style] : style
2336
+ },
2337
+ /* @__PURE__ */ React2.createElement(ScrollAdjust, null),
2338
+ ListHeaderComponent && /* @__PURE__ */ React2.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
2339
+ ListEmptyComponent && getComponent(ListEmptyComponent),
2340
+ shouldRenderAlignItemsAtEndSpacer && /* @__PURE__ */ React2.createElement(AlignItemsAtEndSpacer, { horizontal }),
2341
+ canRender && !ListEmptyComponent && /* @__PURE__ */ React2.createElement(
2342
+ Containers,
2343
+ {
2344
+ getRenderedItem: getRenderedItem2,
2345
+ horizontal,
2346
+ ItemSeparatorComponent,
2347
+ recycleItems,
2348
+ stickyHeaderConfig,
2349
+ updateItemSize: updateItemSize2
2350
+ }
2351
+ ),
2352
+ ListFooterComponent && /* @__PURE__ */ React2.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
2353
+ Platform.OS === "web" && /* @__PURE__ */ React2.createElement(WebAnchoredEndSpace, { horizontal }),
2354
+ IS_DEV && ENABLE_DEVMODE
2355
+ );
2356
+ });
2357
+ var WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH = 100;
2358
+ var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
2359
+ var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
2360
+ function useDevChecksImpl(props) {
2361
+ const ctx = useStateContext();
2362
+ const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
2363
+ useEffect(() => {
2364
+ if (useWindowScroll && renderScrollComponent) {
2365
+ warnDevOnce(
2366
+ "useWindowScrollRenderScrollComponent",
2367
+ "useWindowScroll is not supported when renderScrollComponent is provided."
2368
+ );
2369
+ }
2370
+ }, [renderScrollComponent, useWindowScroll]);
2371
+ useEffect(() => {
2372
+ if (!keyExtractor && !ctx.state.isFirst && ctx.state.didDataChange && !childrenMode) {
2373
+ warnDevOnce(
2374
+ "keyExtractor",
2375
+ "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."
2376
+ );
2377
+ }
2378
+ }, [childrenMode, ctx, keyExtractor]);
2379
+ useEffect(() => {
2380
+ const state = ctx.state;
2381
+ const dataLength = state.props.data.length;
2382
+ const useWindowScrollResolved = state.props.useWindowScroll;
2383
+ if (Platform.OS !== "web" || useWindowScrollResolved || dataLength < WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH) {
2384
+ return;
2385
+ }
2386
+ const warnIfUnboundedOuterSize = () => {
2387
+ const readyToRender = peek$(ctx, "readyToRender");
2388
+ const numContainers = peek$(ctx, "numContainers") || 0;
2389
+ const totalSize = peek$(ctx, "totalSize") || 0;
2390
+ const scrollLength = ctx.state.scrollLength || 0;
2391
+ if (!readyToRender || totalSize <= 0 || scrollLength <= 0) {
2392
+ return;
2393
+ }
2394
+ const rendersAlmostEverything = numContainers >= Math.ceil(dataLength * WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO);
2395
+ const viewportMatchesContent = scrollLength >= totalSize * WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO;
2396
+ if (rendersAlmostEverything && viewportMatchesContent) {
2397
+ warnDevOnce(
2398
+ "webUnboundedOuterSize",
2399
+ "LegendList appears to have an unbounded outer height on web, so virtualization is effectively disabled. Set a bounded height or flex: 1 on the list container, or use useWindowScroll."
2400
+ );
2213
2401
  }
2214
2402
  };
2215
- checkHasScrolled();
2216
- }, initialDelay);
2403
+ warnIfUnboundedOuterSize();
2404
+ const unsubscribe = [
2405
+ listen$(ctx, "numContainers", warnIfUnboundedOuterSize),
2406
+ listen$(ctx, "readyToRender", warnIfUnboundedOuterSize),
2407
+ listen$(ctx, "totalSize", warnIfUnboundedOuterSize)
2408
+ ];
2409
+ return () => {
2410
+ for (const unsub of unsubscribe) {
2411
+ unsub();
2412
+ }
2413
+ };
2414
+ }, [ctx]);
2217
2415
  }
2218
-
2219
- // src/core/doScrollTo.native.ts
2220
- function doScrollTo(ctx, params) {
2221
- const state = ctx.state;
2222
- const { animated, horizontal, isInitialScroll, offset } = params;
2223
- const isAnimated = !!animated;
2224
- const { refScroller } = state;
2225
- const scroller = refScroller.current;
2226
- if (!scroller) {
2227
- return;
2228
- }
2229
- const isHorizontal = !!horizontal;
2230
- const contentSize = isHorizontal ? getContentSize(ctx) : void 0;
2231
- const nativeOffset = toNativeHorizontalOffset(state, offset, contentSize);
2232
- scroller.scrollTo({
2233
- animated: isAnimated,
2234
- x: isHorizontal ? nativeOffset : 0,
2235
- y: isHorizontal ? 0 : offset
2236
- });
2237
- if (isInitialScroll) {
2238
- initialScrollCompletion.markInitialScrollNativeDispatch(state);
2239
- }
2240
- if (!isAnimated) {
2241
- state.scroll = offset;
2242
- checkFinishedScrollFallback(ctx);
2243
- }
2416
+ function useDevChecksNoop(_props) {
2244
2417
  }
2418
+ var useDevChecks = IS_DEV ? useDevChecksImpl : useDevChecksNoop;
2245
2419
 
2246
2420
  // src/core/doMaintainScrollAtEnd.ts
2247
2421
  function doMaintainScrollAtEnd(ctx) {
@@ -2265,9 +2439,12 @@ function doMaintainScrollAtEnd(ctx) {
2265
2439
  state.scroll = 0;
2266
2440
  }
2267
2441
  if (!state.maintainingScrollAtEnd) {
2268
- state.maintainingScrollAtEnd = true;
2442
+ const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
2443
+ const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
2444
+ state.maintainingScrollAtEnd = pendingState;
2269
2445
  requestAnimationFrame(() => {
2270
2446
  if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
2447
+ state.maintainingScrollAtEnd = activeState;
2271
2448
  const scroller = refScroller.current;
2272
2449
  if (state.props.horizontal && isHorizontalRTL(state)) {
2273
2450
  const currentContentSize = getContentSize(ctx);
@@ -2285,12 +2462,14 @@ function doMaintainScrollAtEnd(ctx) {
2285
2462
  }
2286
2463
  setTimeout(
2287
2464
  () => {
2288
- state.maintainingScrollAtEnd = false;
2465
+ if (state.maintainingScrollAtEnd === activeState) {
2466
+ state.maintainingScrollAtEnd = void 0;
2467
+ }
2289
2468
  },
2290
2469
  maintainScrollAtEnd.animated ? 500 : 0
2291
2470
  );
2292
- } else {
2293
- state.maintainingScrollAtEnd = false;
2471
+ } else if (state.maintainingScrollAtEnd === pendingState) {
2472
+ state.maintainingScrollAtEnd = void 0;
2294
2473
  }
2295
2474
  });
2296
2475
  }
@@ -2299,58 +2478,6 @@ function doMaintainScrollAtEnd(ctx) {
2299
2478
  return false;
2300
2479
  }
2301
2480
 
2302
- // src/utils/requestAdjust.ts
2303
- function requestAdjust(ctx, positionDiff, dataChanged) {
2304
- const state = ctx.state;
2305
- if (Math.abs(positionDiff) > 0.1) {
2306
- const needsScrollWorkaround = Platform.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff;
2307
- const doit = () => {
2308
- if (needsScrollWorkaround) {
2309
- doScrollTo(ctx, { horizontal: state.props.horizontal, offset: state.scroll });
2310
- } else {
2311
- state.scrollAdjustHandler.requestAdjust(positionDiff);
2312
- if (state.adjustingFromInitialMount) {
2313
- state.adjustingFromInitialMount--;
2314
- }
2315
- }
2316
- };
2317
- state.scroll += positionDiff;
2318
- state.scrollForNextCalculateItemsInView = void 0;
2319
- const readyToRender = peek$(ctx, "readyToRender");
2320
- if (readyToRender) {
2321
- doit();
2322
- if (Platform.OS !== "web") {
2323
- const threshold = state.scroll - positionDiff / 2;
2324
- if (!state.ignoreScrollFromMVCP) {
2325
- state.ignoreScrollFromMVCP = {};
2326
- }
2327
- if (positionDiff > 0) {
2328
- state.ignoreScrollFromMVCP.lt = threshold;
2329
- } else {
2330
- state.ignoreScrollFromMVCP.gt = threshold;
2331
- }
2332
- if (state.ignoreScrollFromMVCPTimeout) {
2333
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
2334
- }
2335
- const delay = needsScrollWorkaround ? 250 : 100;
2336
- state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
2337
- var _a3;
2338
- state.ignoreScrollFromMVCP = void 0;
2339
- const shouldForceUpdate = state.ignoreScrollFromMVCPIgnored && state.scrollProcessingEnabled !== false;
2340
- if (shouldForceUpdate) {
2341
- state.ignoreScrollFromMVCPIgnored = false;
2342
- state.scrollPending = state.scroll;
2343
- (_a3 = state.reprocessCurrentScroll) == null ? void 0 : _a3.call(state);
2344
- }
2345
- }, delay);
2346
- }
2347
- } else {
2348
- state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2349
- requestAnimationFrame(doit);
2350
- }
2351
- }
2352
- }
2353
-
2354
2481
  // src/core/mvcp.ts
2355
2482
  var MVCP_POSITION_EPSILON = 0.1;
2356
2483
  var MVCP_ANCHOR_LOCK_TTL_MS = 300;
@@ -2499,6 +2626,10 @@ function prepareMVCP(ctx, dataChanged) {
2499
2626
  const now = Date.now();
2500
2627
  const enableMVCPAnchorLock = isWeb && (!!dataChanged || !!state.mvcpAnchorLock);
2501
2628
  const scrollingTo = state.scrollingTo;
2629
+ if (isWeb && dataChanged && state.pendingScrollToEnd && scrollingTo === void 0) {
2630
+ state.mvcpAnchorLock = void 0;
2631
+ return void 0;
2632
+ }
2502
2633
  const anchorLock = isWeb ? resolveAnchorLock(state, enableMVCPAnchorLock, mvcpData, now) : void 0;
2503
2634
  let prevPosition;
2504
2635
  let targetId;
@@ -2634,7 +2765,7 @@ function prepareMVCP(ctx, dataChanged) {
2634
2765
  return;
2635
2766
  }
2636
2767
  if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
2637
- const shouldSkipAdjustForMaintainedEnd = state.maintainingScrollAtEnd && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
2768
+ const shouldSkipAdjustForMaintainedEnd = (state.maintainingScrollAtEnd === "pending-animated" || state.maintainingScrollAtEnd === "animated") && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
2638
2769
  if (!shouldSkipAdjustForMaintainedEnd) {
2639
2770
  requestAdjust(ctx, positionDiff, dataChanged && mvcpData);
2640
2771
  }
@@ -2648,6 +2779,45 @@ var flushSync = (fn) => {
2648
2779
  fn();
2649
2780
  };
2650
2781
 
2782
+ // src/utils/getScrollVelocity.ts
2783
+ var getScrollVelocity = (state) => {
2784
+ const { scrollHistory } = state;
2785
+ const newestIndex = scrollHistory.length - 1;
2786
+ if (newestIndex < 1) {
2787
+ return 0;
2788
+ }
2789
+ const newest = scrollHistory[newestIndex];
2790
+ const now = Date.now();
2791
+ let direction = 0;
2792
+ for (let i = newestIndex; i > 0; i--) {
2793
+ const delta = scrollHistory[i].scroll - scrollHistory[i - 1].scroll;
2794
+ if (delta !== 0) {
2795
+ direction = Math.sign(delta);
2796
+ break;
2797
+ }
2798
+ }
2799
+ if (direction === 0) {
2800
+ return 0;
2801
+ }
2802
+ let oldest = newest;
2803
+ for (let i = newestIndex - 1; i >= 0; i--) {
2804
+ const current = scrollHistory[i];
2805
+ const next = scrollHistory[i + 1];
2806
+ const delta = next.scroll - current.scroll;
2807
+ const deltaSign = Math.sign(delta);
2808
+ if (deltaSign !== 0 && deltaSign !== direction) {
2809
+ break;
2810
+ }
2811
+ if (now - current.time > 1e3) {
2812
+ break;
2813
+ }
2814
+ oldest = current;
2815
+ }
2816
+ const scrollDiff = newest.scroll - oldest.scroll;
2817
+ const timeDiff = newest.time - oldest.time;
2818
+ return timeDiff > 0 ? scrollDiff / timeDiff : 0;
2819
+ };
2820
+
2651
2821
  // src/core/updateScroll.ts
2652
2822
  function updateScroll(ctx, newScroll, forceUpdate, options) {
2653
2823
  var _a3;
@@ -2673,6 +2843,8 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
2673
2843
  if (scrollHistory.length > 5) {
2674
2844
  scrollHistory.shift();
2675
2845
  }
2846
+ const scrollVelocity = getScrollVelocity(state);
2847
+ updateAdaptiveRender(ctx, scrollVelocity);
2676
2848
  if (ignoreScrollFromMVCP && !scrollingTo) {
2677
2849
  const { lt, gt } = ignoreScrollFromMVCP;
2678
2850
  if (lt && newScroll < lt || gt && newScroll > gt) {
@@ -2696,7 +2868,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
2696
2868
  state.lastScrollDelta = scrollDelta;
2697
2869
  const runCalculateItems = () => {
2698
2870
  var _a4;
2699
- (_a4 = state.triggerCalculateItemsInView) == null ? void 0 : _a4.call(state, { doMVCP: scrollingTo !== void 0 });
2871
+ (_a4 = state.triggerCalculateItemsInView) == null ? void 0 : _a4.call(state, { doMVCP: scrollingTo !== void 0, scrollVelocity });
2700
2872
  checkThresholds(ctx);
2701
2873
  };
2702
2874
  if (scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength && !state.pendingNativeMVCPAdjust) {
@@ -3631,9 +3803,32 @@ function initializeInitialScrollOnMount(ctx, options) {
3631
3803
  }
3632
3804
  function handleInitialScrollDataChange(ctx, options) {
3633
3805
  var _a3, _b, _c;
3634
- const { dataLength, didDataChange, initialScrollAtEnd, stylePaddingBottom, useBootstrapInitialScroll } = options;
3806
+ const {
3807
+ dataLength,
3808
+ didDataChange,
3809
+ initialScrollAtEnd,
3810
+ latestInitialScroll,
3811
+ latestInitialScrollSessionKind,
3812
+ stylePaddingBottom,
3813
+ useBootstrapInitialScroll
3814
+ } = options;
3635
3815
  const state = ctx.state;
3636
3816
  const previousDataLength = (_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.previousDataLength) != null ? _b : 0;
3817
+ const isFirstNonEmptyData = !state.hasHadNonEmptyData && dataLength > 0;
3818
+ if (dataLength > 0) {
3819
+ state.hasHadNonEmptyData = true;
3820
+ }
3821
+ if (isFirstNonEmptyData) {
3822
+ if (latestInitialScroll) {
3823
+ setInitialScrollTarget(state, latestInitialScroll);
3824
+ setInitialScrollSession(state, {
3825
+ kind: latestInitialScrollSessionKind,
3826
+ previousDataLength
3827
+ });
3828
+ } else {
3829
+ clearPreservedInitialScrollTarget(state);
3830
+ }
3831
+ }
3637
3832
  if (state.initialScrollSession) {
3638
3833
  state.initialScrollSession.previousDataLength = dataLength;
3639
3834
  }
@@ -3857,45 +4052,6 @@ function updateTotalSize(ctx) {
3857
4052
  }
3858
4053
  }
3859
4054
 
3860
- // src/utils/getScrollVelocity.ts
3861
- var getScrollVelocity = (state) => {
3862
- const { scrollHistory } = state;
3863
- const newestIndex = scrollHistory.length - 1;
3864
- if (newestIndex < 1) {
3865
- return 0;
3866
- }
3867
- const newest = scrollHistory[newestIndex];
3868
- const now = Date.now();
3869
- let direction = 0;
3870
- for (let i = newestIndex; i > 0; i--) {
3871
- const delta = scrollHistory[i].scroll - scrollHistory[i - 1].scroll;
3872
- if (delta !== 0) {
3873
- direction = Math.sign(delta);
3874
- break;
3875
- }
3876
- }
3877
- if (direction === 0) {
3878
- return 0;
3879
- }
3880
- let oldest = newest;
3881
- for (let i = newestIndex - 1; i >= 0; i--) {
3882
- const current = scrollHistory[i];
3883
- const next = scrollHistory[i + 1];
3884
- const delta = next.scroll - current.scroll;
3885
- const deltaSign = Math.sign(delta);
3886
- if (deltaSign !== 0 && deltaSign !== direction) {
3887
- break;
3888
- }
3889
- if (now - current.time > 1e3) {
3890
- break;
3891
- }
3892
- oldest = current;
3893
- }
3894
- const scrollDiff = newest.scroll - oldest.scroll;
3895
- const timeDiff = newest.time - oldest.time;
3896
- return timeDiff > 0 ? scrollDiff / timeDiff : 0;
3897
- };
3898
-
3899
4055
  // src/utils/updateSnapToOffsets.ts
3900
4056
  function updateSnapToOffsets(ctx) {
3901
4057
  const state = ctx.state;
@@ -4631,7 +4787,7 @@ function updateViewabilityForCachedRange(ctx, viewabilityConfigCallbackPairs, sc
4631
4787
  function calculateItemsInView(ctx, params = {}) {
4632
4788
  const state = ctx.state;
4633
4789
  batchedUpdates(() => {
4634
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
4790
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t;
4635
4791
  const {
4636
4792
  columns,
4637
4793
  containerItemKeys,
@@ -4640,14 +4796,7 @@ function calculateItemsInView(ctx, params = {}) {
4640
4796
  indexByKey,
4641
4797
  minIndexSizeChanged,
4642
4798
  positions,
4643
- props: {
4644
- alwaysRenderIndicesArr,
4645
- alwaysRenderIndicesSet,
4646
- drawDistance,
4647
- getItemType,
4648
- keyExtractor,
4649
- onStickyHeaderChange
4650
- },
4799
+ props: { alwaysRenderIndicesArr, alwaysRenderIndicesSet, getItemType, keyExtractor, onStickyHeaderChange },
4651
4800
  scrollForNextCalculateItemsInView,
4652
4801
  scrollLength,
4653
4802
  sizes,
@@ -4659,6 +4808,7 @@ function calculateItemsInView(ctx, params = {}) {
4659
4808
  const stickyHeaderIndicesSet = state.props.stickyHeaderIndicesSet || /* @__PURE__ */ new Set();
4660
4809
  const alwaysRenderArr = alwaysRenderIndicesArr || [];
4661
4810
  const alwaysRenderSet = alwaysRenderIndicesSet || /* @__PURE__ */ new Set();
4811
+ const drawDistance = getEffectiveDrawDistance(ctx);
4662
4812
  const { dataChanged, doMVCP, forceFullItemPositions } = params;
4663
4813
  const bootstrapInitialScrollState = ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap" ? state.initialScrollSession.bootstrap : void 0;
4664
4814
  const suppressInitialScrollSideEffects = !!bootstrapInitialScrollState;
@@ -4669,10 +4819,10 @@ function calculateItemsInView(ctx, params = {}) {
4669
4819
  let totalSize = getContentSize(ctx);
4670
4820
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "alignItemsAtEndPadding") + peek$(ctx, "headerSize");
4671
4821
  const numColumns = peek$(ctx, "numColumns");
4672
- const speed = getScrollVelocity(state);
4822
+ const speed = (_b = params.scrollVelocity) != null ? _b : getScrollVelocity(state);
4673
4823
  const scrollExtra = 0;
4674
4824
  const { initialScroll, queuedInitialLayout } = state;
4675
- const scrollState = suppressInitialScrollSideEffects ? (_b = bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.scroll) != null ? _b : state.scroll : !queuedInitialLayout && hasActiveInitialScroll(state) && initialScroll ? (
4825
+ const scrollState = suppressInitialScrollSideEffects ? (_c = bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.scroll) != null ? _c : state.scroll : !queuedInitialLayout && hasActiveInitialScroll(state) && initialScroll ? (
4676
4826
  // Before the initial layout settles, keep viewport math anchored to the
4677
4827
  // current initial-scroll target instead of transient native adjustments.
4678
4828
  resolveInitialScrollOffset(ctx, initialScroll)
@@ -4696,19 +4846,25 @@ function calculateItemsInView(ctx, params = {}) {
4696
4846
  };
4697
4847
  updateScroll2(scrollState);
4698
4848
  const previousStickyIndex = peek$(ctx, "activeStickyIndex");
4699
- const currentStickyIdx = stickyHeaderIndicesArr.length > 0 ? findCurrentStickyIndex(stickyHeaderIndicesArr, scroll, state) : -1;
4700
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyHeaderIndicesArr[currentStickyIdx] : -1;
4701
- const stickyIndexDidChange = previousStickyIndex !== nextActiveStickyIndex;
4702
- if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
4703
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
4704
- }
4705
- const shouldNotifyStickyHeaderChange = !!onStickyHeaderChange && stickyHeaderIndicesArr.length > 0 && stickyIndexDidChange;
4706
- const finishCalculateItemsInView = shouldNotifyStickyHeaderChange ? () => {
4707
- const item = data[nextActiveStickyIndex];
4708
- if (item !== void 0) {
4709
- onStickyHeaderChange == null ? void 0 : onStickyHeaderChange({ index: nextActiveStickyIndex, item });
4849
+ const resolveStickyState = () => {
4850
+ const currentStickyIdx = stickyHeaderIndicesArr.length > 0 ? findCurrentStickyIndex(stickyHeaderIndicesArr, scroll, state) : -1;
4851
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyHeaderIndicesArr[currentStickyIdx] : -1;
4852
+ const stickyIndexDidChange = previousStickyIndex !== nextActiveStickyIndex;
4853
+ if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
4854
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
4710
4855
  }
4711
- } : void 0;
4856
+ const shouldNotifyStickyHeaderChange = !!onStickyHeaderChange && stickyHeaderIndicesArr.length > 0 && stickyIndexDidChange;
4857
+ return {
4858
+ currentStickyIdx,
4859
+ finishCalculateItemsInView: shouldNotifyStickyHeaderChange ? () => {
4860
+ const item = data[nextActiveStickyIndex];
4861
+ if (item !== void 0) {
4862
+ onStickyHeaderChange == null ? void 0 : onStickyHeaderChange({ index: nextActiveStickyIndex, item });
4863
+ }
4864
+ } : void 0
4865
+ };
4866
+ };
4867
+ let stickyState = dataChanged ? void 0 : resolveStickyState();
4712
4868
  let scrollBufferTop = drawDistance;
4713
4869
  let scrollBufferBottom = drawDistance;
4714
4870
  if (speed > 0 || speed === 0 && scroll < Math.max(50, drawDistance)) {
@@ -4741,7 +4897,7 @@ function calculateItemsInView(ctx, params = {}) {
4741
4897
  scrollBottom
4742
4898
  );
4743
4899
  }
4744
- finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
4900
+ (_d = stickyState == null ? void 0 : stickyState.finishCalculateItemsInView) == null ? void 0 : _d.call(stickyState);
4745
4901
  return;
4746
4902
  }
4747
4903
  }
@@ -4750,7 +4906,7 @@ function calculateItemsInView(ctx, params = {}) {
4750
4906
  if (dataChanged) {
4751
4907
  resetLayoutCachesForDataChange(state);
4752
4908
  }
4753
- const startIndex = forceFullItemPositions || dataChanged ? 0 : (_c = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _c : 0;
4909
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_e = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _e : 0;
4754
4910
  const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
4755
4911
  updateItemPositions(ctx, dataChanged, {
4756
4912
  doMVCP,
@@ -4776,21 +4932,24 @@ function calculateItemsInView(ctx, params = {}) {
4776
4932
  }
4777
4933
  }
4778
4934
  const scrollBeforeMVCP = state.scroll;
4779
- const scrollAdjustPendingBeforeMVCP = (_d = peek$(ctx, "scrollAdjustPending")) != null ? _d : 0;
4935
+ const scrollAdjustPendingBeforeMVCP = (_f = peek$(ctx, "scrollAdjustPending")) != null ? _f : 0;
4780
4936
  checkMVCP == null ? void 0 : checkMVCP();
4781
- const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0) !== scrollAdjustPendingBeforeMVCP);
4937
+ const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_g = peek$(ctx, "scrollAdjustPending")) != null ? _g : 0) !== scrollAdjustPendingBeforeMVCP);
4782
4938
  if (didMVCPAdjustScroll && initialScroll) {
4783
4939
  updateScroll2(state.scroll);
4784
4940
  updateScrollRange();
4785
4941
  }
4942
+ if (dataChanged) {
4943
+ stickyState = resolveStickyState();
4944
+ }
4786
4945
  let startBuffered = null;
4787
4946
  let startBufferedId = null;
4788
4947
  let endBuffered = null;
4789
- let loopStart = (_f = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _f : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
4948
+ let loopStart = (_h = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _h : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
4790
4949
  for (let i = loopStart; i >= 0; i--) {
4791
- const id = (_g = idCache[i]) != null ? _g : getId(state, i);
4950
+ const id = (_i = idCache[i]) != null ? _i : getId(state, i);
4792
4951
  const top = positions[i];
4793
- const size = (_h = sizes.get(id)) != null ? _h : getItemSize(ctx, id, i, data[i]);
4952
+ const size = (_j = sizes.get(id)) != null ? _j : getItemSize(ctx, id, i, data[i]);
4794
4953
  const bottom = top + size;
4795
4954
  if (bottom > scrollTopBuffered) {
4796
4955
  loopStart = i;
@@ -4825,8 +4984,8 @@ function calculateItemsInView(ctx, params = {}) {
4825
4984
  };
4826
4985
  const dataLength = data.length;
4827
4986
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
4828
- const id = (_i = idCache[i]) != null ? _i : getId(state, i);
4829
- const size = (_j = sizes.get(id)) != null ? _j : getItemSize(ctx, id, i, data[i]);
4987
+ const id = (_k = idCache[i]) != null ? _k : getId(state, i);
4988
+ const size = (_l = sizes.get(id)) != null ? _l : getItemSize(ctx, id, i, data[i]);
4830
4989
  const top = positions[i];
4831
4990
  if (!foundEnd) {
4832
4991
  trackVisibleRange(visibleRange, i, top, size, scroll, scrollBottom);
@@ -4882,7 +5041,7 @@ function calculateItemsInView(ctx, params = {}) {
4882
5041
  const needNewContainers = [];
4883
5042
  const needNewContainersSet = /* @__PURE__ */ new Set();
4884
5043
  for (let i = startBuffered; i <= endBuffered; i++) {
4885
- const id = (_k = idCache[i]) != null ? _k : getId(state, i);
5044
+ const id = (_m = idCache[i]) != null ? _m : getId(state, i);
4886
5045
  if (!containerItemKeys.has(id)) {
4887
5046
  needNewContainersSet.add(i);
4888
5047
  needNewContainers.push(i);
@@ -4891,7 +5050,7 @@ function calculateItemsInView(ctx, params = {}) {
4891
5050
  if (alwaysRenderArr.length > 0) {
4892
5051
  for (const index of alwaysRenderArr) {
4893
5052
  if (index < 0 || index >= dataLength) continue;
4894
- const id = (_l = idCache[index]) != null ? _l : getId(state, index);
5053
+ const id = (_n = idCache[index]) != null ? _n : getId(state, index);
4895
5054
  if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
4896
5055
  needNewContainersSet.add(index);
4897
5056
  needNewContainers.push(index);
@@ -4902,7 +5061,7 @@ function calculateItemsInView(ctx, params = {}) {
4902
5061
  handleStickyActivation(
4903
5062
  ctx,
4904
5063
  stickyHeaderIndicesArr,
4905
- currentStickyIdx,
5064
+ (_o = stickyState == null ? void 0 : stickyState.currentStickyIdx) != null ? _o : -1,
4906
5065
  needNewContainers,
4907
5066
  needNewContainersSet,
4908
5067
  startBuffered,
@@ -4928,7 +5087,7 @@ function calculateItemsInView(ctx, params = {}) {
4928
5087
  for (const allocation of availableContainerAllocations) {
4929
5088
  const i = allocation.itemIndex;
4930
5089
  const containerIndex = allocation.containerIndex;
4931
- const id = (_m = idCache[i]) != null ? _m : getId(state, i);
5090
+ const id = (_p = idCache[i]) != null ? _p : getId(state, i);
4932
5091
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
4933
5092
  if (oldKey && oldKey !== id) {
4934
5093
  containerItemKeys.delete(oldKey);
@@ -4939,7 +5098,7 @@ function calculateItemsInView(ctx, params = {}) {
4939
5098
  state.containerItemTypes.set(containerIndex, allocation.itemType);
4940
5099
  }
4941
5100
  containerItemKeys.set(id, containerIndex);
4942
- (_n = state.userScrollAnchorReset) == null ? void 0 : _n.keys.add(id);
5101
+ (_q = state.userScrollAnchorReset) == null ? void 0 : _q.keys.add(id);
4943
5102
  const containerSticky = `containerSticky${containerIndex}`;
4944
5103
  const isSticky = stickyHeaderIndicesSet.has(i);
4945
5104
  const isAlwaysRender = alwaysRenderSet.has(i);
@@ -4970,14 +5129,12 @@ function calculateItemsInView(ctx, params = {}) {
4970
5129
  if (state.userScrollAnchorReset) {
4971
5130
  if (state.userScrollAnchorReset.keys.size === 0) {
4972
5131
  state.userScrollAnchorReset = void 0;
4973
- } else {
4974
- state.userScrollAnchorReset.batchSize = state.userScrollAnchorReset.keys.size;
4975
5132
  }
4976
5133
  }
4977
5134
  if (alwaysRenderArr.length > 0) {
4978
5135
  for (const index of alwaysRenderArr) {
4979
5136
  if (index < 0 || index >= dataLength) continue;
4980
- const id = (_o = idCache[index]) != null ? _o : getId(state, index);
5137
+ const id = (_r = idCache[index]) != null ? _r : getId(state, index);
4981
5138
  const containerIndex = containerItemKeys.get(id);
4982
5139
  if (containerIndex !== void 0) {
4983
5140
  state.stickyContainerPool.add(containerIndex);
@@ -4991,7 +5148,7 @@ function calculateItemsInView(ctx, params = {}) {
4991
5148
  stickyHeaderIndicesArr,
4992
5149
  scroll,
4993
5150
  drawDistance,
4994
- currentStickyIdx,
5151
+ (_s = stickyState == null ? void 0 : stickyState.currentStickyIdx) != null ? _s : -1,
4995
5152
  pendingRemoval,
4996
5153
  alwaysRenderSet
4997
5154
  );
@@ -5052,7 +5209,7 @@ function calculateItemsInView(ctx, params = {}) {
5052
5209
  );
5053
5210
  }
5054
5211
  }
5055
- finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
5212
+ (_t = stickyState == null ? void 0 : stickyState.finishCalculateItemsInView) == null ? void 0 : _t.call(stickyState);
5056
5213
  });
5057
5214
  }
5058
5215
 
@@ -5135,8 +5292,9 @@ function doInitialAllocateContainers(ctx) {
5135
5292
  const state = ctx.state;
5136
5293
  const {
5137
5294
  scrollLength,
5138
- props: { data, drawDistance, getFixedItemSize, getItemType, numColumns, estimatedItemSize }
5295
+ props: { data, getFixedItemSize, getItemType, numColumns, estimatedItemSize }
5139
5296
  } = state;
5297
+ const drawDistance = getEffectiveDrawDistance(ctx);
5140
5298
  const hasContainers = peek$(ctx, "numContainers");
5141
5299
  if (scrollLength > 0 && data.length > 0 && !hasContainers) {
5142
5300
  let averageItemSize;
@@ -5147,12 +5305,12 @@ function doInitialAllocateContainers(ctx) {
5147
5305
  const item = data[i];
5148
5306
  if (item !== void 0) {
5149
5307
  const itemType = (_a3 = getItemType == null ? void 0 : getItemType(item, i)) != null ? _a3 : "";
5150
- totalSize += (_b = getFixedItemSize(item, i, itemType)) != null ? _b : estimatedItemSize;
5308
+ totalSize += ((_b = getFixedItemSize(item, i, itemType)) != null ? _b : estimatedItemSize) + ctx.scrollAxisGap;
5151
5309
  }
5152
5310
  }
5153
5311
  averageItemSize = totalSize / num;
5154
5312
  } else {
5155
- averageItemSize = estimatedItemSize;
5313
+ averageItemSize = estimatedItemSize + ctx.scrollAxisGap;
5156
5314
  }
5157
5315
  const numContainers = Math.max(
5158
5316
  1,
@@ -5207,7 +5365,7 @@ function handleLayout(ctx, layoutParam, setCanRender) {
5207
5365
  if (didChange) {
5208
5366
  state.scrollLength = scrollLength;
5209
5367
  state.otherAxisSize = otherAxisSize;
5210
- updateContentMetrics(ctx);
5368
+ updateContentMetricsState(ctx);
5211
5369
  state.lastBatchingAction = Date.now();
5212
5370
  state.scrollForNextCalculateItemsInView = void 0;
5213
5371
  if (scrollLength > 0) {
@@ -5448,28 +5606,12 @@ function updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment)
5448
5606
 
5449
5607
  // src/core/updateItemSize.ts
5450
5608
  function runOrScheduleMVCPRecalculate(ctx) {
5451
- var _a3, _b;
5609
+ var _a3;
5452
5610
  const state = ctx.state;
5453
5611
  if (state.userScrollAnchorReset !== void 0) {
5454
- const replacementBatchSize = (_a3 = state.userScrollAnchorReset.batchSize) != null ? _a3 : state.userScrollAnchorReset.keys.size;
5455
- const replacementMeasurementBatchThreshold = 3;
5456
- const shouldBatchReplacementMeasurements = replacementBatchSize > replacementMeasurementBatchThreshold;
5457
- if (shouldBatchReplacementMeasurements) {
5458
- if (state.queuedMVCPRecalculate === void 0) {
5459
- state.queuedMVCPRecalculate = requestAnimationFrame(() => {
5460
- var _a4;
5461
- state.queuedMVCPRecalculate = void 0;
5462
- calculateItemsInView(ctx);
5463
- if (((_a4 = state.userScrollAnchorReset) == null ? void 0 : _a4.keys.size) === 0) {
5464
- state.userScrollAnchorReset = void 0;
5465
- }
5466
- });
5467
- }
5468
- } else {
5469
- calculateItemsInView(ctx);
5470
- if (((_b = state.userScrollAnchorReset) == null ? void 0 : _b.keys.size) === 0) {
5471
- state.userScrollAnchorReset = void 0;
5472
- }
5612
+ calculateItemsInView(ctx);
5613
+ if (((_a3 = state.userScrollAnchorReset) == null ? void 0 : _a3.keys.size) === 0) {
5614
+ state.userScrollAnchorReset = void 0;
5473
5615
  }
5474
5616
  } else if (Platform.OS === "web") {
5475
5617
  if (!state.mvcpAnchorLock) {
@@ -5947,6 +6089,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
5947
6089
  scrollTo(ctx, params);
5948
6090
  return true;
5949
6091
  }),
6092
+ setItemSize: (itemKey, size) => {
6093
+ updateItemSize(ctx, itemKey, size);
6094
+ },
5950
6095
  setScrollProcessingEnabled: (enabled) => {
5951
6096
  state.scrollProcessingEnabled = enabled;
5952
6097
  },
@@ -6171,7 +6316,7 @@ var LegendList = typedMemo(
6171
6316
  })
6172
6317
  );
6173
6318
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
6174
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
6319
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
6175
6320
  const noopOnScroll = useCallback((_event) => {
6176
6321
  }, []);
6177
6322
  if (props.recycleItems === void 0) {
@@ -6202,6 +6347,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6202
6347
  initialScrollAtEnd = false,
6203
6348
  initialScrollIndex: initialScrollIndexProp,
6204
6349
  initialScrollOffset: initialScrollOffsetProp,
6350
+ experimental_adaptiveRender,
6205
6351
  itemsAreEqual,
6206
6352
  keyExtractor: keyExtractorProp,
6207
6353
  ListEmptyComponent,
@@ -6298,6 +6444,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6298
6444
  const [, scheduleImperativeScrollCommit] = React2.useReducer((value) => value + 1, 0);
6299
6445
  const ctx = useStateContext();
6300
6446
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
6447
+ const scrollAxisGap = horizontal ? (_f = (_d = ctx.columnWrapperStyle) == null ? void 0 : _d.columnGap) != null ? _f : (_e = ctx.columnWrapperStyle) == null ? void 0 : _e.gap : (_i = (_g = ctx.columnWrapperStyle) == null ? void 0 : _g.rowGap) != null ? _i : (_h = ctx.columnWrapperStyle) == null ? void 0 : _h.gap;
6448
+ const nextScrollAxisGap = typeof scrollAxisGap === "number" && Number.isFinite(scrollAxisGap) ? scrollAxisGap : 0;
6301
6449
  const refScroller = useRef(null);
6302
6450
  const combinedRef = useCombinedRef(refScroller, refScrollView);
6303
6451
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : ((_item, index) => index.toString());
@@ -6311,8 +6459,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6311
6459
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex,
6312
6460
  alwaysRender == null ? void 0 : alwaysRender.top,
6313
6461
  alwaysRender == null ? void 0 : alwaysRender.bottom,
6314
- (_d = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _d.join(","),
6315
- (_e = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _e.join(","),
6462
+ (_j = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _j.join(","),
6463
+ (_k = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _k.join(","),
6316
6464
  dataProp,
6317
6465
  dataVersion,
6318
6466
  keyExtractor
@@ -6340,6 +6488,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6340
6488
  endNoBuffer: -1,
6341
6489
  endReachedSnapshot: void 0,
6342
6490
  firstFullyOnScreenIndex: -1,
6491
+ hasHadNonEmptyData: dataProp.length > 0,
6343
6492
  idCache: [],
6344
6493
  idsInView: [],
6345
6494
  indexByKey: /* @__PURE__ */ new Map(),
@@ -6382,6 +6531,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6382
6531
  startReachedSnapshotDataChangeEpoch: void 0,
6383
6532
  stickyContainerPool: /* @__PURE__ */ new Set(),
6384
6533
  stickyContainers: /* @__PURE__ */ new Map(),
6534
+ timeoutAdaptiveRender: void 0,
6385
6535
  timeouts: /* @__PURE__ */ new Set(),
6386
6536
  totalSize: 0,
6387
6537
  viewabilityConfigCallbackPairs: void 0
@@ -6400,11 +6550,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6400
6550
  const state = refState.current;
6401
6551
  const isFirstLocal = state.isFirst;
6402
6552
  const previousNumColumnsProp = state.props.numColumns;
6403
- state.didColumnsChange = numColumnsProp !== previousNumColumnsProp;
6553
+ const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
6554
+ ctx.scrollAxisGap = nextScrollAxisGap;
6555
+ state.didColumnsChange = numColumnsProp !== previousNumColumnsProp || didScrollAxisGapChange;
6404
6556
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
6405
6557
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
6406
6558
  const didDataChangeLocal = didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
6407
- if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
6559
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_l = state.initialScroll) == null ? void 0 : _l.viewPosition) === 1 && state.props.data.length > 0) {
6408
6560
  clearPreservedInitialScrollTarget(state);
6409
6561
  }
6410
6562
  if (didDataChangeLocal) {
@@ -6416,8 +6568,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6416
6568
  const throttledOnScroll = useThrottledOnScroll(onScrollProp != null ? onScrollProp : noopOnScroll, scrollEventThrottle != null ? scrollEventThrottle : 0);
6417
6569
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? throttledOnScroll : onScrollProp;
6418
6570
  const anchoredEndSpaceResolved = Platform.OS === "web" && anchoredEndSpace ? { ...anchoredEndSpace, includeInEndInset: true } : anchoredEndSpace;
6419
- const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_g = state.props.anchoredEndSpace) == null ? void 0 : _g.anchorIndex) !== (anchoredEndSpaceResolved == null ? void 0 : anchoredEndSpaceResolved.anchorIndex);
6571
+ const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_m = state.props.anchoredEndSpace) == null ? void 0 : _m.anchorIndex) !== (anchoredEndSpaceResolved == null ? void 0 : anchoredEndSpaceResolved.anchorIndex);
6420
6572
  state.props = {
6573
+ adaptiveRender: experimental_adaptiveRender,
6421
6574
  alignItemsAtEnd,
6422
6575
  alignItemsAtEndPaddingEnabled: useAlignItemsAtEndPadding,
6423
6576
  alwaysRender,
@@ -6425,6 +6578,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6425
6578
  alwaysRenderIndicesSet: alwaysRenderIndices.set,
6426
6579
  anchoredEndSpace: anchoredEndSpaceResolved,
6427
6580
  animatedProps: animatedPropsInternal,
6581
+ contentContainerAlignItems: contentContainerStyle.alignItems,
6428
6582
  contentInset,
6429
6583
  contentInsetEndAdjustment: contentInsetEndAdjustmentResolved,
6430
6584
  data: dataProp,
@@ -6477,7 +6631,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6477
6631
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
6478
6632
  setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
6479
6633
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
6480
- updateContentMetrics(ctx);
6634
+ updateContentMetricsState(ctx);
6481
6635
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
6482
6636
  if (shouldAdjustPadding && maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
6483
6637
  if (state.scroll < 0) {
@@ -6514,7 +6668,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6514
6668
  useBootstrapInitialScroll: usesBootstrapInitialScroll
6515
6669
  });
6516
6670
  }, []);
6517
- if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
6671
+ if (isFirstLocal || didDataChangeLocal || state.didColumnsChange) {
6518
6672
  refState.current.lastBatchingAction = Date.now();
6519
6673
  if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
6520
6674
  refState.current.sizes.clear();
@@ -6531,6 +6685,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6531
6685
  dataLength: dataProp.length,
6532
6686
  didDataChange: didDataChangeLocal,
6533
6687
  initialScrollAtEnd,
6688
+ latestInitialScroll: initialScrollProp,
6689
+ latestInitialScrollSessionKind: initialScrollUsesOffsetOnly ? "offset" : "bootstrap",
6534
6690
  stylePaddingBottom: stylePaddingBottomState,
6535
6691
  useBootstrapInitialScroll: usesBootstrapInitialScroll
6536
6692
  });
@@ -6605,6 +6761,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6605
6761
  dataVersion,
6606
6762
  memoizedLastItemKeys.join(","),
6607
6763
  numColumnsProp,
6764
+ nextScrollAxisGap,
6608
6765
  stylePaddingBottomState,
6609
6766
  stylePaddingTopState,
6610
6767
  useAlignItemsAtEndPadding
@@ -6627,7 +6784,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6627
6784
  state.didColumnsChange = false;
6628
6785
  state.didDataChange = false;
6629
6786
  state.isFirst = false;
6630
- }, [dataProp, dataVersion, numColumnsProp]);
6787
+ }, [dataProp, dataVersion, numColumnsProp, nextScrollAxisGap]);
6631
6788
  useLayoutEffect(() => {
6632
6789
  var _a4;
6633
6790
  set$(ctx, "extraData", extraData);
@@ -6678,6 +6835,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6678
6835
  }
6679
6836
  });
6680
6837
  useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, scheduleImperativeScrollCommit), []);
6838
+ useEffect(() => {
6839
+ return () => {
6840
+ for (const timeout of state.timeouts) {
6841
+ clearTimeout(timeout);
6842
+ }
6843
+ state.timeouts.clear();
6844
+ };
6845
+ }, [state]);
6681
6846
  useLayoutEffect(() => {
6682
6847
  var _a4;
6683
6848
  (_a4 = state.runPendingScrollToEnd) == null ? void 0 : _a4.call(state);
@@ -6725,7 +6890,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6725
6890
  onScroll: onScrollHandler,
6726
6891
  recycleItems,
6727
6892
  refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React2.cloneElement(refreshControlElement, {
6728
- progressViewOffset: ((_h = refreshControlElement.props.progressViewOffset) != null ? _h : 0) + stylePaddingTopState
6893
+ progressViewOffset: ((_n = refreshControlElement.props.progressViewOffset) != null ? _n : 0) + stylePaddingTopState
6729
6894
  }) : refreshControlElement : onRefresh && /* @__PURE__ */ React2.createElement(
6730
6895
  RefreshControl,
6731
6896
  {
@@ -6736,7 +6901,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6736
6901
  ),
6737
6902
  refScrollView: combinedRef,
6738
6903
  renderScrollComponent,
6739
- scrollAdjustHandler: (_i = refState.current) == null ? void 0 : _i.scrollAdjustHandler,
6904
+ scrollAdjustHandler: (_o = refState.current) == null ? void 0 : _o.scrollAdjustHandler,
6740
6905
  scrollEventThrottle: 0,
6741
6906
  snapToIndices,
6742
6907
  stickyHeaderIndices,
@@ -6768,4 +6933,4 @@ var internal = {
6768
6933
  var LegendList3 = LegendListRuntime;
6769
6934
  var internal2 = internal;
6770
6935
 
6771
- export { LegendList3 as LegendList, internal2 as internal, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };
6936
+ export { LegendList3 as LegendList, internal2 as internal, useAdaptiveRender, useAdaptiveRenderChange, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };