@legendapp/list 3.0.5 → 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,8 +131,10 @@ 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([
137
+ ["alignItemsAtEndPadding", 0],
136
138
  ["stylePaddingTop", 0],
137
139
  ["headerSize", 0],
138
140
  ["numContainers", 0],
@@ -142,6 +144,7 @@ function StateProvider({ children }) {
142
144
  ["isNearEnd", false],
143
145
  ["isNearStart", false],
144
146
  ["isWithinMaintainScrollAtEndThreshold", false],
147
+ ["adaptiveRender", "light"],
145
148
  ["totalSize", 0],
146
149
  ["scrollAdjustPending", 0]
147
150
  ]),
@@ -275,15 +278,16 @@ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
275
278
 
276
279
  // src/state/getContentSize.ts
277
280
  function getContentSize(ctx) {
278
- var _a3;
281
+ var _a3, _b;
279
282
  const { values, state } = ctx;
280
283
  const stylePaddingTop = values.get("stylePaddingTop") || 0;
281
284
  const stylePaddingBottom = state.props.stylePaddingBottom || 0;
285
+ const alignItemsAtEndPadding = values.get("alignItemsAtEndPadding") || 0;
282
286
  const headerSize = values.get("headerSize") || 0;
283
287
  const footerSize = values.get("footerSize") || 0;
284
288
  const contentInsetBottom = getContentInsetEnd(ctx);
285
- const totalSize = (_a3 = state.pendingTotalSize) != null ? _a3 : values.get("totalSize");
286
- return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom + (contentInsetBottom || 0);
289
+ const totalSize = (_b = (_a3 = state.pendingTotalSize) != null ? _a3 : state.totalSize) != null ? _b : values.get("totalSize");
290
+ return headerSize + footerSize + totalSize + stylePaddingTop + alignItemsAtEndPadding + stylePaddingBottom + (contentInsetBottom || 0);
287
291
  }
288
292
 
289
293
  // src/components/DebugView.tsx
@@ -458,8 +462,16 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
458
462
  ...rest
459
463
  }) {
460
464
  const ctx = useStateContext();
461
- const [position = POSITION_OUT_OF_VIEW, headerSize = 0, stylePaddingTop = 0, itemKey, _totalSize = 0] = useArr$([
465
+ const [
466
+ position = POSITION_OUT_OF_VIEW,
467
+ alignItemsAtEndPadding = 0,
468
+ headerSize = 0,
469
+ stylePaddingTop = 0,
470
+ itemKey,
471
+ _totalSize = 0
472
+ ] = useArr$([
462
473
  `containerPosition${id}`,
474
+ "alignItemsAtEndPadding",
463
475
  "headerSize",
464
476
  "stylePaddingTop",
465
477
  `containerItemKey${id}`,
@@ -473,7 +485,7 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
473
485
  var _a3;
474
486
  if (animatedScrollY) {
475
487
  const stickyConfigOffset = (_a3 = stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset) != null ? _a3 : 0;
476
- const stickyStart = position + headerSize + stylePaddingTop - stickyConfigOffset;
488
+ const stickyStart = position + headerSize + stylePaddingTop + alignItemsAtEndPadding - stickyConfigOffset;
477
489
  let nextStickyPosition;
478
490
  if (pushLimit !== void 0) {
479
491
  if (pushLimit <= position) {
@@ -496,7 +508,15 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
496
508
  }
497
509
  return horizontal ? [{ translateX: nextStickyPosition }] : [{ translateY: nextStickyPosition }];
498
510
  }
499
- }, [animatedScrollY, headerSize, position, pushLimit, stylePaddingTop, stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset]);
511
+ }, [
512
+ alignItemsAtEndPadding,
513
+ animatedScrollY,
514
+ headerSize,
515
+ position,
516
+ pushLimit,
517
+ stylePaddingTop,
518
+ stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset
519
+ ]);
500
520
  const viewStyle = React2.useMemo(() => [style, { zIndex: index + 1e3 }, { transform }], [style, transform]);
501
521
  const renderStickyHeaderBackdrop = React2.useMemo(() => {
502
522
  if (!(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)) {
@@ -570,6 +590,24 @@ var ContextContainer = createContext(null);
570
590
  function useContextContainer() {
571
591
  return useContext(ContextContainer);
572
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
+ }
573
611
  function useViewability(callback, configId) {
574
612
  const ctx = useStateContext();
575
613
  const containerContext = useContextContainer();
@@ -786,6 +824,7 @@ function isInMVCPActiveMode(state) {
786
824
  // src/components/Container.tsx
787
825
  function getContainerPositionStyle({
788
826
  columnWrapperStyle,
827
+ contentContainerAlignItems,
789
828
  horizontal,
790
829
  hasItemSeparator,
791
830
  isHorizontalRTLList,
@@ -811,13 +850,14 @@ function getContainerPositionStyle({
811
850
  }
812
851
  }
813
852
  return horizontal ? {
853
+ bottom: contentContainerAlignItems === "flex-end" && numColumns === 1 ? 0 : void 0,
814
854
  boxSizing: paddingStyles ? "border-box" : void 0,
815
855
  direction: isHorizontalRTLList && Platform.OS === "web" ? "ltr" : void 0,
816
856
  flexDirection: hasItemSeparator ? "row" : void 0,
817
857
  height: otherAxisSize,
818
858
  left: 0,
819
859
  position: "absolute",
820
- top: otherAxisPos,
860
+ top: contentContainerAlignItems === "flex-end" && numColumns === 1 ? void 0 : otherAxisPos,
821
861
  ...paddingStyles || {}
822
862
  } : {
823
863
  boxSizing: paddingStyles ? "border-box" : void 0,
@@ -871,6 +911,7 @@ var Container = typedMemo(function Container2({
871
911
  const style = useMemo(
872
912
  () => getContainerPositionStyle({
873
913
  columnWrapperStyle,
914
+ contentContainerAlignItems: ctx.state.props.contentContainerAlignItems,
874
915
  hasItemSeparator: !!ItemSeparatorComponent,
875
916
  horizontal,
876
917
  isHorizontalRTLList,
@@ -884,6 +925,7 @@ var Container = typedMemo(function Container2({
884
925
  otherAxisPos,
885
926
  otherAxisSize,
886
927
  columnWrapperStyle,
928
+ ctx.state.props.contentContainerAlignItems,
887
929
  numColumns,
888
930
  ItemSeparatorComponent
889
931
  ]
@@ -1153,245 +1195,267 @@ function WebAnchoredEndSpace({ horizontal }) {
1153
1195
  const style = horizontal ? { height: "100%", width: anchoredEndSpaceSize || 0 } : { height: anchoredEndSpaceSize || 0 };
1154
1196
  return /* @__PURE__ */ React2.createElement("div", { style }, null);
1155
1197
  }
1156
- function useLatestRef(value) {
1157
- const ref = React2.useRef(value);
1158
- ref.current = value;
1159
- return ref;
1160
- }
1161
1198
 
1162
- // src/hooks/useStableRenderComponent.tsx
1163
- function useStableRenderComponent(renderComponent, mapProps) {
1164
- const renderComponentRef = useLatestRef(renderComponent);
1165
- const mapPropsRef = useLatestRef(mapProps);
1166
- return React2.useMemo(
1167
- () => React2.forwardRef(
1168
- (props, ref) => {
1169
- var _a3, _b;
1170
- return (_b = (_a3 = renderComponentRef.current) == null ? void 0 : _a3.call(renderComponentRef, mapPropsRef.current(props, ref))) != null ? _b : null;
1171
- }
1172
- ),
1173
- [mapPropsRef, renderComponentRef]
1174
- );
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;
1175
1203
  }
1176
- var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
1177
- const localRef = useRef(null);
1178
- const ref = refView != null ? refView : localRef;
1179
- const { onLayout } = useOnLayoutSync({ onLayoutChange, ref });
1180
- return /* @__PURE__ */ React2.createElement(View$1, { ...rest, onLayout, ref });
1181
- };
1182
1204
 
1183
- // src/components/ListComponent.tsx
1184
- var ListComponent = typedMemo(function ListComponent2({
1185
- canRender,
1186
- style,
1187
- contentContainerStyle,
1188
- horizontal,
1189
- initialContentOffset,
1190
- recycleItems,
1191
- ItemSeparatorComponent,
1192
- alignItemsAtEnd: _alignItemsAtEnd,
1193
- onScroll: onScroll2,
1194
- onLayout,
1195
- ListHeaderComponent,
1196
- ListHeaderComponentStyle,
1197
- ListFooterComponent,
1198
- ListFooterComponentStyle,
1199
- ListEmptyComponent,
1200
- getRenderedItem: getRenderedItem2,
1201
- updateItemSize: updateItemSize2,
1202
- refScrollView,
1203
- renderScrollComponent,
1204
- onLayoutFooter,
1205
- scrollAdjustHandler,
1206
- snapToIndices,
1207
- stickyHeaderConfig,
1208
- stickyHeaderIndices,
1209
- useWindowScroll = false,
1210
- ...rest
1211
- }) {
1212
- const ctx = useStateContext();
1213
- const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1214
- const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
1215
- const autoOtherAxisStyle = getAutoOtherAxisStyle({
1216
- horizontal,
1217
- needsOtherAxisSize: ctx.state.needsOtherAxisSize,
1218
- otherAxisSize
1219
- });
1220
- const CustomScrollComponent = useStableRenderComponent(
1221
- renderScrollComponent,
1222
- (props, ref) => ({ ...props, ref })
1223
- );
1224
- const ScrollComponent = renderScrollComponent ? CustomScrollComponent : ListComponentScrollView;
1225
- const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
1226
- useLayoutEffect(() => {
1227
- if (!ListHeaderComponent) {
1228
- set$(ctx, "headerSize", 0);
1229
- }
1230
- if (!ListFooterComponent) {
1231
- set$(ctx, "footerSize", 0);
1232
- }
1233
- }, [ListHeaderComponent, ListFooterComponent, ctx]);
1234
- const onLayoutHeader = useCallback(
1235
- (rect) => {
1236
- const size = rect[horizontal ? "width" : "height"];
1237
- set$(ctx, "headerSize", size);
1238
- },
1239
- [ctx, horizontal]
1240
- );
1241
- const onLayoutFooterInternal = useCallback(
1242
- (rect, fromLayoutEffect) => {
1243
- const size = rect[horizontal ? "width" : "height"];
1244
- set$(ctx, "footerSize", size);
1245
- onLayoutFooter == null ? void 0 : onLayoutFooter(rect, fromLayoutEffect);
1246
- },
1247
- [ctx, horizontal, onLayoutFooter]
1248
- );
1249
- return /* @__PURE__ */ React2.createElement(
1250
- SnapOrScroll,
1251
- {
1252
- ...rest,
1253
- ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
1254
- contentContainerStyle: [
1255
- horizontal ? {
1256
- height: "100%"
1257
- } : {},
1258
- contentContainerStyle
1259
- ],
1260
- contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1261
- horizontal,
1262
- maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
1263
- onLayout,
1264
- onScroll: onScroll2,
1265
- ref: refScrollView,
1266
- ScrollComponent: snapToIndices ? ScrollComponent : void 0,
1267
- style: autoOtherAxisStyle ? [autoOtherAxisStyle, style] : style
1268
- },
1269
- /* @__PURE__ */ React2.createElement(ScrollAdjust, null),
1270
- ListHeaderComponent && /* @__PURE__ */ React2.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
1271
- ListEmptyComponent && getComponent(ListEmptyComponent),
1272
- canRender && !ListEmptyComponent && /* @__PURE__ */ React2.createElement(
1273
- Containers,
1274
- {
1275
- getRenderedItem: getRenderedItem2,
1276
- horizontal,
1277
- ItemSeparatorComponent,
1278
- recycleItems,
1279
- stickyHeaderConfig,
1280
- updateItemSize: updateItemSize2
1281
- }
1282
- ),
1283
- ListFooterComponent && /* @__PURE__ */ React2.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
1284
- Platform.OS === "web" && /* @__PURE__ */ React2.createElement(WebAnchoredEndSpace, { horizontal }),
1285
- IS_DEV && ENABLE_DEVMODE
1286
- );
1287
- });
1288
- var WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH = 100;
1289
- var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
1290
- var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
1291
- function useDevChecksImpl(props) {
1292
- const ctx = useStateContext();
1293
- const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
1294
- useEffect(() => {
1295
- if (useWindowScroll && renderScrollComponent) {
1296
- warnDevOnce(
1297
- "useWindowScrollRenderScrollComponent",
1298
- "useWindowScroll is not supported when renderScrollComponent is provided."
1299
- );
1300
- }
1301
- }, [renderScrollComponent, useWindowScroll]);
1302
- useEffect(() => {
1303
- if (!keyExtractor && !ctx.state.isFirst && ctx.state.didDataChange && !childrenMode) {
1304
- warnDevOnce(
1305
- "keyExtractor",
1306
- "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."
1307
- );
1308
- }
1309
- }, [childrenMode, ctx, keyExtractor]);
1310
- useEffect(() => {
1311
- const state = ctx.state;
1312
- const dataLength = state.props.data.length;
1313
- const useWindowScrollResolved = state.props.useWindowScroll;
1314
- if (Platform.OS !== "web" || useWindowScrollResolved || dataLength < WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH) {
1315
- return;
1316
- }
1317
- const warnIfUnboundedOuterSize = () => {
1318
- const readyToRender = peek$(ctx, "readyToRender");
1319
- const numContainers = peek$(ctx, "numContainers") || 0;
1320
- const totalSize = peek$(ctx, "totalSize") || 0;
1321
- const scrollLength = ctx.state.scrollLength || 0;
1322
- if (!readyToRender || totalSize <= 0 || scrollLength <= 0) {
1323
- return;
1324
- }
1325
- const rendersAlmostEverything = numContainers >= Math.ceil(dataLength * WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO);
1326
- const viewportMatchesContent = scrollLength >= totalSize * WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO;
1327
- if (rendersAlmostEverything && viewportMatchesContent) {
1328
- warnDevOnce(
1329
- "webUnboundedOuterSize",
1330
- "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."
1331
- );
1332
- }
1333
- };
1334
- warnIfUnboundedOuterSize();
1335
- const unsubscribe = [
1336
- listen$(ctx, "numContainers", warnIfUnboundedOuterSize),
1337
- listen$(ctx, "readyToRender", warnIfUnboundedOuterSize),
1338
- listen$(ctx, "totalSize", warnIfUnboundedOuterSize)
1339
- ];
1340
- return () => {
1341
- for (const unsub of unsubscribe) {
1342
- unsub();
1343
- }
1344
- };
1345
- }, [ctx]);
1346
- }
1347
- function useDevChecksNoop(_props) {
1205
+ // src/core/getTopOffsetAdjustment.ts
1206
+ function getTopOffsetAdjustment(ctx) {
1207
+ return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
1348
1208
  }
1349
- var useDevChecks = IS_DEV ? useDevChecksImpl : useDevChecksNoop;
1350
1209
 
1351
- // src/core/deferredPublicOnScroll.ts
1352
- function withResolvedContentOffset(state, event, resolvedOffset) {
1353
- return {
1354
- ...event,
1355
- nativeEvent: {
1356
- ...event.nativeEvent,
1357
- contentOffset: state.props.horizontal ? { x: resolvedOffset, y: 0 } : { x: 0, y: resolvedOffset }
1358
- }
1359
- };
1360
- }
1361
- function releaseDeferredPublicOnScroll(ctx, resolvedOffset) {
1362
- var _a3, _b, _c, _d;
1363
- const state = ctx.state;
1364
- const deferredEvent = state.deferredPublicOnScrollEvent;
1365
- state.deferredPublicOnScrollEvent = void 0;
1366
- if (deferredEvent) {
1367
- (_d = (_c = state.props).onScroll) == null ? void 0 : _d.call(
1368
- _c,
1369
- withResolvedContentOffset(
1370
- state,
1371
- deferredEvent,
1372
- (_b = (_a3 = resolvedOffset != null ? resolvedOffset : state.scrollPending) != null ? _a3 : state.scroll) != null ? _b : 0
1373
- )
1374
- );
1210
+ // src/utils/getId.ts
1211
+ function getId(state, index) {
1212
+ const { data, keyExtractor } = state.props;
1213
+ if (!data) {
1214
+ return "";
1375
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;
1376
1220
  }
1377
1221
 
1378
- // src/core/initialScrollSession.ts
1379
- var INITIAL_SCROLL_MIN_TARGET_OFFSET = 1;
1380
- function hasInitialScrollSessionCompletion(completion) {
1381
- return !!((completion == null ? void 0 : completion.didDispatchNativeScroll) || (completion == null ? void 0 : completion.didRetrySilentInitialScroll) || (completion == null ? void 0 : completion.watchdog));
1222
+ // src/core/updateContentMetricsState.ts
1223
+ function getRawContentLength(ctx) {
1224
+ var _a3, _b, _c;
1225
+ const { state, values } = ctx;
1226
+ return (values.get("headerSize") || 0) + (values.get("footerSize") || 0) + ((_c = (_b = (_a3 = state.pendingTotalSize) != null ? _a3 : state.totalSize) != null ? _b : values.get("totalSize")) != null ? _c : 0) + (state.props.stylePaddingTop || 0) + (state.props.stylePaddingBottom || 0);
1382
1227
  }
1383
- function clearInitialScrollSession(state) {
1384
- state.initialScrollSession = void 0;
1385
- return void 0;
1228
+ function getAlignItemsAtEndPadding(ctx) {
1229
+ const { state } = ctx;
1230
+ const shouldPad = !!state.props.alignItemsAtEndPaddingEnabled && !state.props.horizontal && state.props.data.length > 0 && state.scrollLength > 0;
1231
+ return shouldPad ? Math.max(0, state.scrollLength - getRawContentLength(ctx) - getContentInsetEnd(ctx)) : 0;
1386
1232
  }
1387
- function createInitialScrollSession(options) {
1388
- const { bootstrap, completion, kind, previousDataLength } = options;
1389
- return kind === "offset" ? {
1390
- completion,
1391
- kind,
1392
- previousDataLength
1393
- } : {
1394
- bootstrap,
1233
+ function updateContentMetricsState(ctx) {
1234
+ const previousPadding = peek$(ctx, "alignItemsAtEndPadding") || 0;
1235
+ const nextPadding = getAlignItemsAtEndPadding(ctx);
1236
+ if (previousPadding !== nextPadding) {
1237
+ set$(ctx, "alignItemsAtEndPadding", nextPadding);
1238
+ }
1239
+ }
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);
1268
+ }
1269
+ }
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);
1281
+ }
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;
1298
+ }
1299
+ function getKnownOrFixedItemSize(ctx, index) {
1300
+ const key = getId(ctx.state, index);
1301
+ return getKnownOrFixedSize(ctx, key, index, ctx.state.props.data[index]);
1302
+ }
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
+ }
1308
+ }
1309
+ return true;
1310
+ }
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;
1357
+ }
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]);
1364
+ }
1365
+
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;
1379
+ }
1380
+ }
1381
+ if (viewPosition !== void 0 && index !== void 0) {
1382
+ const dataLength = state.props.data.length;
1383
+ if (dataLength === 0) {
1384
+ return offset;
1385
+ }
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;
1394
+ }
1395
+ }
1396
+ return offset;
1397
+ }
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;
1413
+ }
1414
+
1415
+ // src/core/deferredPublicOnScroll.ts
1416
+ function withResolvedContentOffset(state, event, resolvedOffset) {
1417
+ return {
1418
+ ...event,
1419
+ nativeEvent: {
1420
+ ...event.nativeEvent,
1421
+ contentOffset: state.props.horizontal ? { x: resolvedOffset, y: 0 } : { x: 0, y: resolvedOffset }
1422
+ }
1423
+ };
1424
+ }
1425
+ function releaseDeferredPublicOnScroll(ctx, resolvedOffset) {
1426
+ var _a3, _b, _c, _d;
1427
+ const state = ctx.state;
1428
+ const deferredEvent = state.deferredPublicOnScrollEvent;
1429
+ state.deferredPublicOnScrollEvent = void 0;
1430
+ if (deferredEvent) {
1431
+ (_d = (_c = state.props).onScroll) == null ? void 0 : _d.call(
1432
+ _c,
1433
+ withResolvedContentOffset(
1434
+ state,
1435
+ deferredEvent,
1436
+ (_b = (_a3 = resolvedOffset != null ? resolvedOffset : state.scrollPending) != null ? _a3 : state.scroll) != null ? _b : 0
1437
+ )
1438
+ );
1439
+ }
1440
+ }
1441
+
1442
+ // src/core/initialScrollSession.ts
1443
+ var INITIAL_SCROLL_MIN_TARGET_OFFSET = 1;
1444
+ function hasInitialScrollSessionCompletion(completion) {
1445
+ return !!((completion == null ? void 0 : completion.didDispatchNativeScroll) || (completion == null ? void 0 : completion.didRetrySilentInitialScroll) || (completion == null ? void 0 : completion.watchdog));
1446
+ }
1447
+ function clearInitialScrollSession(state) {
1448
+ state.initialScrollSession = void 0;
1449
+ return void 0;
1450
+ }
1451
+ function createInitialScrollSession(options) {
1452
+ const { bootstrap, completion, kind, previousDataLength } = options;
1453
+ return kind === "offset" ? {
1454
+ completion,
1455
+ kind,
1456
+ previousDataLength
1457
+ } : {
1458
+ bootstrap,
1395
1459
  completion,
1396
1460
  kind,
1397
1461
  previousDataLength
@@ -1659,6 +1723,66 @@ function recalculateSettledScroll(ctx) {
1659
1723
  checkThresholds(ctx);
1660
1724
  }
1661
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
+
1662
1786
  // src/utils/setInitialRenderState.ts
1663
1787
  function setInitialRenderState(ctx, {
1664
1788
  didLayout,
@@ -1678,6 +1802,13 @@ function setInitialRenderState(ctx, {
1678
1802
  const isReadyToRender = Boolean(state.didContainersLayout && state.didFinishInitialScroll);
1679
1803
  if (isReadyToRender && !peek$(ctx, "readyToRender")) {
1680
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
+ }
1681
1812
  if (onLoad) {
1682
1813
  onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1683
1814
  }
@@ -1752,204 +1883,9 @@ function finishInitialScroll(ctx, options) {
1752
1883
  complete();
1753
1884
  }
1754
1885
 
1755
- // src/core/calculateOffsetForIndex.ts
1756
- function calculateOffsetForIndex(ctx, index) {
1757
- const state = ctx.state;
1758
- return index !== void 0 ? state.positions[index] || 0 : 0;
1759
- }
1760
-
1761
- // src/core/getTopOffsetAdjustment.ts
1762
- function getTopOffsetAdjustment(ctx) {
1763
- return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
1764
- }
1765
-
1766
- // src/utils/getId.ts
1767
- function getId(state, index) {
1768
- const { data, keyExtractor } = state.props;
1769
- if (!data) {
1770
- return "";
1771
- }
1772
- const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
1773
- const id = ret;
1774
- state.idCache[index] = id;
1775
- return id;
1776
- }
1777
-
1778
- // src/core/addTotalSize.ts
1779
- function addTotalSize(ctx, key, add, notifyTotalSize = true) {
1780
- const state = ctx.state;
1781
- const prevTotalSize = state.totalSize;
1782
- let totalSize = state.totalSize;
1783
- if (key === null) {
1784
- totalSize = add;
1785
- if (state.timeoutSetPaddingTop) {
1786
- clearTimeout(state.timeoutSetPaddingTop);
1787
- state.timeoutSetPaddingTop = void 0;
1788
- }
1789
- } else {
1790
- totalSize += add;
1791
- }
1792
- if (prevTotalSize !== totalSize) {
1793
- if (!IsNewArchitecture && state.initialScroll && totalSize < prevTotalSize) {
1794
- state.pendingTotalSize = totalSize;
1795
- } else {
1796
- state.pendingTotalSize = void 0;
1797
- state.totalSize = totalSize;
1798
- if (notifyTotalSize) {
1799
- set$(ctx, "totalSize", totalSize);
1800
- }
1801
- }
1802
- } else if (notifyTotalSize && ctx.values.get("totalSize") !== totalSize) {
1803
- set$(ctx, "totalSize", totalSize);
1804
- }
1805
- }
1806
-
1807
- // src/core/setSize.ts
1808
- function setSize(ctx, itemKey, size, notifyTotalSize = true) {
1809
- const state = ctx.state;
1810
- const { sizes } = state;
1811
- const previousSize = sizes.get(itemKey);
1812
- const diff = previousSize !== void 0 ? size - previousSize : size;
1813
- if (diff !== 0) {
1814
- addTotalSize(ctx, itemKey, diff, notifyTotalSize);
1815
- }
1816
- sizes.set(itemKey, size);
1817
- }
1818
-
1819
- // src/utils/getItemSize.ts
1820
- function getKnownOrFixedSize(ctx, key, index, data, resolved) {
1821
- var _a3, _b;
1822
- const state = ctx.state;
1823
- const { getFixedItemSize, getItemType } = state.props;
1824
- let size = key ? state.sizesKnown.get(key) : void 0;
1825
- if (size === void 0 && key && getFixedItemSize) {
1826
- const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1827
- size = (resolved == null ? void 0 : resolved.didResolveFixedItemSize) ? resolved.fixedItemSize : getFixedItemSize(data, index, itemType);
1828
- if (size !== void 0) {
1829
- state.sizesKnown.set(key, size);
1830
- }
1831
- }
1832
- return size;
1833
- }
1834
- function getKnownOrFixedItemSize(ctx, index) {
1835
- const key = getId(ctx.state, index);
1836
- return getKnownOrFixedSize(ctx, key, index, ctx.state.props.data[index]);
1837
- }
1838
- function areKnownOrFixedItemSizesAvailable(ctx, startIndex, endIndex) {
1839
- for (let index = startIndex; index <= endIndex; index++) {
1840
- if (getKnownOrFixedItemSize(ctx, index) === void 0) {
1841
- return false;
1842
- }
1843
- }
1844
- return true;
1845
- }
1846
- function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize, notifyTotalSize, resolved) {
1847
- var _a3, _b, _c, _d;
1848
- const state = ctx.state;
1849
- const {
1850
- sizes,
1851
- averageSizes,
1852
- props: { estimatedItemSize, getItemType },
1853
- scrollingTo
1854
- } = state;
1855
- const sizeKnown = state.sizesKnown.get(key);
1856
- if (sizeKnown !== void 0) {
1857
- return sizeKnown;
1858
- }
1859
- let size;
1860
- const renderedSize = sizes.get(key);
1861
- if (preferCachedSize) {
1862
- if (renderedSize !== void 0) {
1863
- return renderedSize;
1864
- }
1865
- }
1866
- size = getKnownOrFixedSize(ctx, key, index, data, resolved);
1867
- if (size !== void 0) {
1868
- setSize(ctx, key, size, notifyTotalSize);
1869
- return size;
1870
- }
1871
- const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1872
- if (useAverageSize && !scrollingTo) {
1873
- const averageSizeForType = (_c = averageSizes[itemType]) == null ? void 0 : _c.avg;
1874
- if (averageSizeForType !== void 0) {
1875
- size = roundSize(averageSizeForType);
1876
- }
1877
- }
1878
- if (size === void 0 && renderedSize !== void 0) {
1879
- return renderedSize;
1880
- }
1881
- if (size === void 0 && useAverageSize && scrollingTo) {
1882
- const averageSizeForType = (_d = scrollingTo.averageSizeSnapshot) == null ? void 0 : _d[itemType];
1883
- if (averageSizeForType !== void 0) {
1884
- size = roundSize(averageSizeForType);
1885
- }
1886
- }
1887
- if (size === void 0) {
1888
- size = estimatedItemSize;
1889
- }
1890
- setSize(ctx, key, size, notifyTotalSize);
1891
- return size;
1892
- }
1893
- function getItemSizeAtIndex(ctx, index) {
1894
- if (index === void 0 || index < 0) {
1895
- return void 0;
1896
- }
1897
- const targetId = getId(ctx.state, index);
1898
- return getItemSize(ctx, targetId, index, ctx.state.props.data[index]);
1899
- }
1900
-
1901
- // src/core/calculateOffsetWithOffsetPosition.ts
1902
- function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1903
- var _a3;
1904
- const state = ctx.state;
1905
- const { index, viewOffset, viewPosition } = params;
1906
- let offset = offsetParam;
1907
- if (viewOffset) {
1908
- offset -= viewOffset;
1909
- }
1910
- if (index !== void 0) {
1911
- const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
1912
- if (topOffsetAdjustment) {
1913
- offset += topOffsetAdjustment;
1914
- }
1915
- }
1916
- if (viewPosition !== void 0 && index !== void 0) {
1917
- const dataLength = state.props.data.length;
1918
- if (dataLength === 0) {
1919
- return offset;
1920
- }
1921
- const isOutOfBounds = index < 0 || index >= dataLength;
1922
- const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
1923
- const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1924
- const trailingInset = getContentInsetEnd(ctx);
1925
- offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1926
- if (!isOutOfBounds && index === state.props.data.length - 1) {
1927
- const footerSize = peek$(ctx, "footerSize") || 0;
1928
- offset += footerSize;
1929
- }
1930
- }
1931
- return offset;
1932
- }
1933
-
1934
- // src/core/clampScrollOffset.ts
1935
- function clampScrollOffset(ctx, offset, scrollTarget) {
1936
- const state = ctx.state;
1937
- const contentSize = getContentSize(ctx);
1938
- let clampedOffset = offset;
1939
- if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform.OS !== "android" || state.lastLayout)) {
1940
- const baseMaxOffset = Math.max(0, contentSize - state.scrollLength);
1941
- const viewOffset = scrollTarget == null ? void 0 : scrollTarget.viewOffset;
1942
- const extraEndOffset = typeof viewOffset === "number" && viewOffset < 0 ? -viewOffset : 0;
1943
- const maxOffset = baseMaxOffset + extraEndOffset;
1944
- clampedOffset = Math.min(offset, maxOffset);
1945
- }
1946
- clampedOffset = Math.max(0, clampedOffset);
1947
- return clampedOffset;
1948
- }
1949
-
1950
- // src/core/finishScrollTo.ts
1951
- function finishScrollTo(ctx) {
1952
- var _a3, _b;
1886
+ // src/core/finishScrollTo.ts
1887
+ function finishScrollTo(ctx) {
1888
+ var _a3, _b;
1953
1889
  const state = ctx.state;
1954
1890
  if (state == null ? void 0 : state.scrollingTo) {
1955
1891
  const resolvePendingScroll = state.pendingScrollResolve;
@@ -2112,65 +2048,374 @@ function checkFinishedScrollFallback(ctx) {
2112
2048
  state,
2113
2049
  isStillScrollingTo
2114
2050
  );
2115
- const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
2116
- const canFinishAfterSilentNativeDispatch = Platform.OS === "android" && silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
2117
- const shouldRetrySilentInitialNativeScroll = Platform.OS === "android" && canFinishAfterSilentNativeDispatch && !initialScrollCompletion.didRetrySilentInitialScroll(state);
2118
- const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
2119
- const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
2120
- const shouldRetryUnalignedEndScroll = Platform.OS === "ios" && !isStillScrollingTo.isInitialScroll && isEndAlignedLastItemTarget(ctx, isStillScrollingTo) && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
2121
- if (shouldRetrySilentInitialNativeScroll) {
2122
- const targetOffset = (_b = (_a3 = getInitialScrollWatchdogTargetOffset(state)) != null ? _a3 : isStillScrollingTo.targetOffset) != null ? _b : 0;
2123
- const jiggleOffset = targetOffset >= SILENT_INITIAL_SCROLL_TARGET_EPSILON ? targetOffset - SILENT_INITIAL_SCROLL_TARGET_EPSILON : targetOffset + SILENT_INITIAL_SCROLL_TARGET_EPSILON;
2124
- initialScrollCompletion.markSilentInitialScrollRetry(state);
2125
- scrollToFallbackOffset(ctx, jiggleOffset);
2126
- requestAnimationFrame(() => {
2127
- scrollToFallbackOffset(ctx, targetOffset);
2128
- });
2129
- scheduleFallbackCheck(SILENT_INITIAL_SCROLL_RETRY_DELAY_MS);
2130
- } else if (shouldRetryUnalignedEndScroll) {
2131
- scrollToFallbackOffset(ctx, completionState.clampedTargetOffset);
2132
- scheduleFallbackCheck(100);
2133
- } else if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
2134
- finishScrollTo(ctx);
2135
- } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
2136
- const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
2137
- scrollToFallbackOffset(ctx, targetOffset);
2138
- scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2139
- } else {
2140
- scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2141
- }
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
+ );
2142
2401
  }
2143
2402
  };
2144
- checkHasScrolled();
2145
- }, 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]);
2146
2415
  }
2147
-
2148
- // src/core/doScrollTo.native.ts
2149
- function doScrollTo(ctx, params) {
2150
- const state = ctx.state;
2151
- const { animated, horizontal, isInitialScroll, offset } = params;
2152
- const isAnimated = !!animated;
2153
- const { refScroller } = state;
2154
- const scroller = refScroller.current;
2155
- if (!scroller) {
2156
- return;
2157
- }
2158
- const isHorizontal = !!horizontal;
2159
- const contentSize = isHorizontal ? getContentSize(ctx) : void 0;
2160
- const nativeOffset = toNativeHorizontalOffset(state, offset, contentSize);
2161
- scroller.scrollTo({
2162
- animated: isAnimated,
2163
- x: isHorizontal ? nativeOffset : 0,
2164
- y: isHorizontal ? 0 : offset
2165
- });
2166
- if (isInitialScroll) {
2167
- initialScrollCompletion.markInitialScrollNativeDispatch(state);
2168
- }
2169
- if (!isAnimated) {
2170
- state.scroll = offset;
2171
- checkFinishedScrollFallback(ctx);
2172
- }
2416
+ function useDevChecksNoop(_props) {
2173
2417
  }
2418
+ var useDevChecks = IS_DEV ? useDevChecksImpl : useDevChecksNoop;
2174
2419
 
2175
2420
  // src/core/doMaintainScrollAtEnd.ts
2176
2421
  function doMaintainScrollAtEnd(ctx) {
@@ -2194,9 +2439,12 @@ function doMaintainScrollAtEnd(ctx) {
2194
2439
  state.scroll = 0;
2195
2440
  }
2196
2441
  if (!state.maintainingScrollAtEnd) {
2197
- state.maintainingScrollAtEnd = true;
2442
+ const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
2443
+ const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
2444
+ state.maintainingScrollAtEnd = pendingState;
2198
2445
  requestAnimationFrame(() => {
2199
2446
  if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
2447
+ state.maintainingScrollAtEnd = activeState;
2200
2448
  const scroller = refScroller.current;
2201
2449
  if (state.props.horizontal && isHorizontalRTL(state)) {
2202
2450
  const currentContentSize = getContentSize(ctx);
@@ -2214,12 +2462,14 @@ function doMaintainScrollAtEnd(ctx) {
2214
2462
  }
2215
2463
  setTimeout(
2216
2464
  () => {
2217
- state.maintainingScrollAtEnd = false;
2465
+ if (state.maintainingScrollAtEnd === activeState) {
2466
+ state.maintainingScrollAtEnd = void 0;
2467
+ }
2218
2468
  },
2219
2469
  maintainScrollAtEnd.animated ? 500 : 0
2220
2470
  );
2221
- } else {
2222
- state.maintainingScrollAtEnd = false;
2471
+ } else if (state.maintainingScrollAtEnd === pendingState) {
2472
+ state.maintainingScrollAtEnd = void 0;
2223
2473
  }
2224
2474
  });
2225
2475
  }
@@ -2228,58 +2478,6 @@ function doMaintainScrollAtEnd(ctx) {
2228
2478
  return false;
2229
2479
  }
2230
2480
 
2231
- // src/utils/requestAdjust.ts
2232
- function requestAdjust(ctx, positionDiff, dataChanged) {
2233
- const state = ctx.state;
2234
- if (Math.abs(positionDiff) > 0.1) {
2235
- const needsScrollWorkaround = Platform.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff;
2236
- const doit = () => {
2237
- if (needsScrollWorkaround) {
2238
- doScrollTo(ctx, { horizontal: state.props.horizontal, offset: state.scroll });
2239
- } else {
2240
- state.scrollAdjustHandler.requestAdjust(positionDiff);
2241
- if (state.adjustingFromInitialMount) {
2242
- state.adjustingFromInitialMount--;
2243
- }
2244
- }
2245
- };
2246
- state.scroll += positionDiff;
2247
- state.scrollForNextCalculateItemsInView = void 0;
2248
- const readyToRender = peek$(ctx, "readyToRender");
2249
- if (readyToRender) {
2250
- doit();
2251
- if (Platform.OS !== "web") {
2252
- const threshold = state.scroll - positionDiff / 2;
2253
- if (!state.ignoreScrollFromMVCP) {
2254
- state.ignoreScrollFromMVCP = {};
2255
- }
2256
- if (positionDiff > 0) {
2257
- state.ignoreScrollFromMVCP.lt = threshold;
2258
- } else {
2259
- state.ignoreScrollFromMVCP.gt = threshold;
2260
- }
2261
- if (state.ignoreScrollFromMVCPTimeout) {
2262
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
2263
- }
2264
- const delay = needsScrollWorkaround ? 250 : 100;
2265
- state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
2266
- var _a3;
2267
- state.ignoreScrollFromMVCP = void 0;
2268
- const shouldForceUpdate = state.ignoreScrollFromMVCPIgnored && state.scrollProcessingEnabled !== false;
2269
- if (shouldForceUpdate) {
2270
- state.ignoreScrollFromMVCPIgnored = false;
2271
- state.scrollPending = state.scroll;
2272
- (_a3 = state.reprocessCurrentScroll) == null ? void 0 : _a3.call(state);
2273
- }
2274
- }, delay);
2275
- }
2276
- } else {
2277
- state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2278
- requestAnimationFrame(doit);
2279
- }
2280
- }
2281
- }
2282
-
2283
2481
  // src/core/mvcp.ts
2284
2482
  var MVCP_POSITION_EPSILON = 0.1;
2285
2483
  var MVCP_ANCHOR_LOCK_TTL_MS = 300;
@@ -2428,6 +2626,10 @@ function prepareMVCP(ctx, dataChanged) {
2428
2626
  const now = Date.now();
2429
2627
  const enableMVCPAnchorLock = isWeb && (!!dataChanged || !!state.mvcpAnchorLock);
2430
2628
  const scrollingTo = state.scrollingTo;
2629
+ if (isWeb && dataChanged && state.pendingScrollToEnd && scrollingTo === void 0) {
2630
+ state.mvcpAnchorLock = void 0;
2631
+ return void 0;
2632
+ }
2431
2633
  const anchorLock = isWeb ? resolveAnchorLock(state, enableMVCPAnchorLock, mvcpData, now) : void 0;
2432
2634
  let prevPosition;
2433
2635
  let targetId;
@@ -2563,7 +2765,7 @@ function prepareMVCP(ctx, dataChanged) {
2563
2765
  return;
2564
2766
  }
2565
2767
  if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
2566
- const shouldSkipAdjustForMaintainedEnd = state.maintainingScrollAtEnd && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
2768
+ const shouldSkipAdjustForMaintainedEnd = (state.maintainingScrollAtEnd === "pending-animated" || state.maintainingScrollAtEnd === "animated") && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
2567
2769
  if (!shouldSkipAdjustForMaintainedEnd) {
2568
2770
  requestAdjust(ctx, positionDiff, dataChanged && mvcpData);
2569
2771
  }
@@ -2577,6 +2779,45 @@ var flushSync = (fn) => {
2577
2779
  fn();
2578
2780
  };
2579
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
+
2580
2821
  // src/core/updateScroll.ts
2581
2822
  function updateScroll(ctx, newScroll, forceUpdate, options) {
2582
2823
  var _a3;
@@ -2602,6 +2843,8 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
2602
2843
  if (scrollHistory.length > 5) {
2603
2844
  scrollHistory.shift();
2604
2845
  }
2846
+ const scrollVelocity = getScrollVelocity(state);
2847
+ updateAdaptiveRender(ctx, scrollVelocity);
2605
2848
  if (ignoreScrollFromMVCP && !scrollingTo) {
2606
2849
  const { lt, gt } = ignoreScrollFromMVCP;
2607
2850
  if (lt && newScroll < lt || gt && newScroll > gt) {
@@ -2625,7 +2868,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
2625
2868
  state.lastScrollDelta = scrollDelta;
2626
2869
  const runCalculateItems = () => {
2627
2870
  var _a4;
2628
- (_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 });
2629
2872
  checkThresholds(ctx);
2630
2873
  };
2631
2874
  if (scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength && !state.pendingNativeMVCPAdjust) {
@@ -3560,9 +3803,32 @@ function initializeInitialScrollOnMount(ctx, options) {
3560
3803
  }
3561
3804
  function handleInitialScrollDataChange(ctx, options) {
3562
3805
  var _a3, _b, _c;
3563
- 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;
3564
3815
  const state = ctx.state;
3565
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
+ }
3566
3832
  if (state.initialScrollSession) {
3567
3833
  state.initialScrollSession.previousDataLength = dataLength;
3568
3834
  }
@@ -3786,45 +4052,6 @@ function updateTotalSize(ctx) {
3786
4052
  }
3787
4053
  }
3788
4054
 
3789
- // src/utils/getScrollVelocity.ts
3790
- var getScrollVelocity = (state) => {
3791
- const { scrollHistory } = state;
3792
- const newestIndex = scrollHistory.length - 1;
3793
- if (newestIndex < 1) {
3794
- return 0;
3795
- }
3796
- const newest = scrollHistory[newestIndex];
3797
- const now = Date.now();
3798
- let direction = 0;
3799
- for (let i = newestIndex; i > 0; i--) {
3800
- const delta = scrollHistory[i].scroll - scrollHistory[i - 1].scroll;
3801
- if (delta !== 0) {
3802
- direction = Math.sign(delta);
3803
- break;
3804
- }
3805
- }
3806
- if (direction === 0) {
3807
- return 0;
3808
- }
3809
- let oldest = newest;
3810
- for (let i = newestIndex - 1; i >= 0; i--) {
3811
- const current = scrollHistory[i];
3812
- const next = scrollHistory[i + 1];
3813
- const delta = next.scroll - current.scroll;
3814
- const deltaSign = Math.sign(delta);
3815
- if (deltaSign !== 0 && deltaSign !== direction) {
3816
- break;
3817
- }
3818
- if (now - current.time > 1e3) {
3819
- break;
3820
- }
3821
- oldest = current;
3822
- }
3823
- const scrollDiff = newest.scroll - oldest.scroll;
3824
- const timeDiff = newest.time - oldest.time;
3825
- return timeDiff > 0 ? scrollDiff / timeDiff : 0;
3826
- };
3827
-
3828
4055
  // src/utils/updateSnapToOffsets.ts
3829
4056
  function updateSnapToOffsets(ctx) {
3830
4057
  const state = ctx.state;
@@ -4145,7 +4372,7 @@ function areViewabilityAmountTokensEqual(prev, next) {
4145
4372
  }
4146
4373
  function computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
4147
4374
  const { sizes, scroll: scrollState } = state;
4148
- const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
4375
+ const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
4149
4376
  const { itemVisiblePercentThreshold, viewAreaCoveragePercentThreshold } = viewabilityConfig;
4150
4377
  const viewAreaMode = viewAreaCoveragePercentThreshold != null;
4151
4378
  const viewablePercentThreshold = viewAreaMode ? viewAreaCoveragePercentThreshold : itemVisiblePercentThreshold;
@@ -4560,7 +4787,7 @@ function updateViewabilityForCachedRange(ctx, viewabilityConfigCallbackPairs, sc
4560
4787
  function calculateItemsInView(ctx, params = {}) {
4561
4788
  const state = ctx.state;
4562
4789
  batchedUpdates(() => {
4563
- 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;
4564
4791
  const {
4565
4792
  columns,
4566
4793
  containerItemKeys,
@@ -4569,14 +4796,7 @@ function calculateItemsInView(ctx, params = {}) {
4569
4796
  indexByKey,
4570
4797
  minIndexSizeChanged,
4571
4798
  positions,
4572
- props: {
4573
- alwaysRenderIndicesArr,
4574
- alwaysRenderIndicesSet,
4575
- drawDistance,
4576
- getItemType,
4577
- keyExtractor,
4578
- onStickyHeaderChange
4579
- },
4799
+ props: { alwaysRenderIndicesArr, alwaysRenderIndicesSet, getItemType, keyExtractor, onStickyHeaderChange },
4580
4800
  scrollForNextCalculateItemsInView,
4581
4801
  scrollLength,
4582
4802
  sizes,
@@ -4588,6 +4808,7 @@ function calculateItemsInView(ctx, params = {}) {
4588
4808
  const stickyHeaderIndicesSet = state.props.stickyHeaderIndicesSet || /* @__PURE__ */ new Set();
4589
4809
  const alwaysRenderArr = alwaysRenderIndicesArr || [];
4590
4810
  const alwaysRenderSet = alwaysRenderIndicesSet || /* @__PURE__ */ new Set();
4811
+ const drawDistance = getEffectiveDrawDistance(ctx);
4591
4812
  const { dataChanged, doMVCP, forceFullItemPositions } = params;
4592
4813
  const bootstrapInitialScrollState = ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap" ? state.initialScrollSession.bootstrap : void 0;
4593
4814
  const suppressInitialScrollSideEffects = !!bootstrapInitialScrollState;
@@ -4596,12 +4817,12 @@ function calculateItemsInView(ctx, params = {}) {
4596
4817
  return;
4597
4818
  }
4598
4819
  let totalSize = getContentSize(ctx);
4599
- const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
4820
+ const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "alignItemsAtEndPadding") + peek$(ctx, "headerSize");
4600
4821
  const numColumns = peek$(ctx, "numColumns");
4601
- const speed = getScrollVelocity(state);
4822
+ const speed = (_b = params.scrollVelocity) != null ? _b : getScrollVelocity(state);
4602
4823
  const scrollExtra = 0;
4603
4824
  const { initialScroll, queuedInitialLayout } = state;
4604
- 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 ? (
4605
4826
  // Before the initial layout settles, keep viewport math anchored to the
4606
4827
  // current initial-scroll target instead of transient native adjustments.
4607
4828
  resolveInitialScrollOffset(ctx, initialScroll)
@@ -4625,19 +4846,25 @@ function calculateItemsInView(ctx, params = {}) {
4625
4846
  };
4626
4847
  updateScroll2(scrollState);
4627
4848
  const previousStickyIndex = peek$(ctx, "activeStickyIndex");
4628
- const currentStickyIdx = stickyHeaderIndicesArr.length > 0 ? findCurrentStickyIndex(stickyHeaderIndicesArr, scroll, state) : -1;
4629
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyHeaderIndicesArr[currentStickyIdx] : -1;
4630
- const stickyIndexDidChange = previousStickyIndex !== nextActiveStickyIndex;
4631
- if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
4632
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
4633
- }
4634
- const shouldNotifyStickyHeaderChange = !!onStickyHeaderChange && stickyHeaderIndicesArr.length > 0 && stickyIndexDidChange;
4635
- const finishCalculateItemsInView = shouldNotifyStickyHeaderChange ? () => {
4636
- const item = data[nextActiveStickyIndex];
4637
- if (item !== void 0) {
4638
- 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);
4639
4855
  }
4640
- } : 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();
4641
4868
  let scrollBufferTop = drawDistance;
4642
4869
  let scrollBufferBottom = drawDistance;
4643
4870
  if (speed > 0 || speed === 0 && scroll < Math.max(50, drawDistance)) {
@@ -4670,7 +4897,7 @@ function calculateItemsInView(ctx, params = {}) {
4670
4897
  scrollBottom
4671
4898
  );
4672
4899
  }
4673
- finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
4900
+ (_d = stickyState == null ? void 0 : stickyState.finishCalculateItemsInView) == null ? void 0 : _d.call(stickyState);
4674
4901
  return;
4675
4902
  }
4676
4903
  }
@@ -4679,7 +4906,7 @@ function calculateItemsInView(ctx, params = {}) {
4679
4906
  if (dataChanged) {
4680
4907
  resetLayoutCachesForDataChange(state);
4681
4908
  }
4682
- 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;
4683
4910
  const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
4684
4911
  updateItemPositions(ctx, dataChanged, {
4685
4912
  doMVCP,
@@ -4705,21 +4932,24 @@ function calculateItemsInView(ctx, params = {}) {
4705
4932
  }
4706
4933
  }
4707
4934
  const scrollBeforeMVCP = state.scroll;
4708
- const scrollAdjustPendingBeforeMVCP = (_d = peek$(ctx, "scrollAdjustPending")) != null ? _d : 0;
4935
+ const scrollAdjustPendingBeforeMVCP = (_f = peek$(ctx, "scrollAdjustPending")) != null ? _f : 0;
4709
4936
  checkMVCP == null ? void 0 : checkMVCP();
4710
- 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);
4711
4938
  if (didMVCPAdjustScroll && initialScroll) {
4712
4939
  updateScroll2(state.scroll);
4713
4940
  updateScrollRange();
4714
4941
  }
4942
+ if (dataChanged) {
4943
+ stickyState = resolveStickyState();
4944
+ }
4715
4945
  let startBuffered = null;
4716
4946
  let startBufferedId = null;
4717
4947
  let endBuffered = null;
4718
- 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;
4719
4949
  for (let i = loopStart; i >= 0; i--) {
4720
- const id = (_g = idCache[i]) != null ? _g : getId(state, i);
4950
+ const id = (_i = idCache[i]) != null ? _i : getId(state, i);
4721
4951
  const top = positions[i];
4722
- 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]);
4723
4953
  const bottom = top + size;
4724
4954
  if (bottom > scrollTopBuffered) {
4725
4955
  loopStart = i;
@@ -4754,8 +4984,8 @@ function calculateItemsInView(ctx, params = {}) {
4754
4984
  };
4755
4985
  const dataLength = data.length;
4756
4986
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
4757
- const id = (_i = idCache[i]) != null ? _i : getId(state, i);
4758
- 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]);
4759
4989
  const top = positions[i];
4760
4990
  if (!foundEnd) {
4761
4991
  trackVisibleRange(visibleRange, i, top, size, scroll, scrollBottom);
@@ -4811,7 +5041,7 @@ function calculateItemsInView(ctx, params = {}) {
4811
5041
  const needNewContainers = [];
4812
5042
  const needNewContainersSet = /* @__PURE__ */ new Set();
4813
5043
  for (let i = startBuffered; i <= endBuffered; i++) {
4814
- const id = (_k = idCache[i]) != null ? _k : getId(state, i);
5044
+ const id = (_m = idCache[i]) != null ? _m : getId(state, i);
4815
5045
  if (!containerItemKeys.has(id)) {
4816
5046
  needNewContainersSet.add(i);
4817
5047
  needNewContainers.push(i);
@@ -4820,7 +5050,7 @@ function calculateItemsInView(ctx, params = {}) {
4820
5050
  if (alwaysRenderArr.length > 0) {
4821
5051
  for (const index of alwaysRenderArr) {
4822
5052
  if (index < 0 || index >= dataLength) continue;
4823
- const id = (_l = idCache[index]) != null ? _l : getId(state, index);
5053
+ const id = (_n = idCache[index]) != null ? _n : getId(state, index);
4824
5054
  if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
4825
5055
  needNewContainersSet.add(index);
4826
5056
  needNewContainers.push(index);
@@ -4831,7 +5061,7 @@ function calculateItemsInView(ctx, params = {}) {
4831
5061
  handleStickyActivation(
4832
5062
  ctx,
4833
5063
  stickyHeaderIndicesArr,
4834
- currentStickyIdx,
5064
+ (_o = stickyState == null ? void 0 : stickyState.currentStickyIdx) != null ? _o : -1,
4835
5065
  needNewContainers,
4836
5066
  needNewContainersSet,
4837
5067
  startBuffered,
@@ -4857,7 +5087,7 @@ function calculateItemsInView(ctx, params = {}) {
4857
5087
  for (const allocation of availableContainerAllocations) {
4858
5088
  const i = allocation.itemIndex;
4859
5089
  const containerIndex = allocation.containerIndex;
4860
- const id = (_m = idCache[i]) != null ? _m : getId(state, i);
5090
+ const id = (_p = idCache[i]) != null ? _p : getId(state, i);
4861
5091
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
4862
5092
  if (oldKey && oldKey !== id) {
4863
5093
  containerItemKeys.delete(oldKey);
@@ -4868,7 +5098,7 @@ function calculateItemsInView(ctx, params = {}) {
4868
5098
  state.containerItemTypes.set(containerIndex, allocation.itemType);
4869
5099
  }
4870
5100
  containerItemKeys.set(id, containerIndex);
4871
- (_n = state.userScrollAnchorReset) == null ? void 0 : _n.keys.add(id);
5101
+ (_q = state.userScrollAnchorReset) == null ? void 0 : _q.keys.add(id);
4872
5102
  const containerSticky = `containerSticky${containerIndex}`;
4873
5103
  const isSticky = stickyHeaderIndicesSet.has(i);
4874
5104
  const isAlwaysRender = alwaysRenderSet.has(i);
@@ -4899,14 +5129,12 @@ function calculateItemsInView(ctx, params = {}) {
4899
5129
  if (state.userScrollAnchorReset) {
4900
5130
  if (state.userScrollAnchorReset.keys.size === 0) {
4901
5131
  state.userScrollAnchorReset = void 0;
4902
- } else {
4903
- state.userScrollAnchorReset.batchSize = state.userScrollAnchorReset.keys.size;
4904
5132
  }
4905
5133
  }
4906
5134
  if (alwaysRenderArr.length > 0) {
4907
5135
  for (const index of alwaysRenderArr) {
4908
5136
  if (index < 0 || index >= dataLength) continue;
4909
- const id = (_o = idCache[index]) != null ? _o : getId(state, index);
5137
+ const id = (_r = idCache[index]) != null ? _r : getId(state, index);
4910
5138
  const containerIndex = containerItemKeys.get(id);
4911
5139
  if (containerIndex !== void 0) {
4912
5140
  state.stickyContainerPool.add(containerIndex);
@@ -4920,7 +5148,7 @@ function calculateItemsInView(ctx, params = {}) {
4920
5148
  stickyHeaderIndicesArr,
4921
5149
  scroll,
4922
5150
  drawDistance,
4923
- currentStickyIdx,
5151
+ (_s = stickyState == null ? void 0 : stickyState.currentStickyIdx) != null ? _s : -1,
4924
5152
  pendingRemoval,
4925
5153
  alwaysRenderSet
4926
5154
  );
@@ -4981,7 +5209,7 @@ function calculateItemsInView(ctx, params = {}) {
4981
5209
  );
4982
5210
  }
4983
5211
  }
4984
- finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
5212
+ (_t = stickyState == null ? void 0 : stickyState.finishCalculateItemsInView) == null ? void 0 : _t.call(stickyState);
4985
5213
  });
4986
5214
  }
4987
5215
 
@@ -5064,8 +5292,9 @@ function doInitialAllocateContainers(ctx) {
5064
5292
  const state = ctx.state;
5065
5293
  const {
5066
5294
  scrollLength,
5067
- props: { data, drawDistance, getFixedItemSize, getItemType, numColumns, estimatedItemSize }
5295
+ props: { data, getFixedItemSize, getItemType, numColumns, estimatedItemSize }
5068
5296
  } = state;
5297
+ const drawDistance = getEffectiveDrawDistance(ctx);
5069
5298
  const hasContainers = peek$(ctx, "numContainers");
5070
5299
  if (scrollLength > 0 && data.length > 0 && !hasContainers) {
5071
5300
  let averageItemSize;
@@ -5076,12 +5305,12 @@ function doInitialAllocateContainers(ctx) {
5076
5305
  const item = data[i];
5077
5306
  if (item !== void 0) {
5078
5307
  const itemType = (_a3 = getItemType == null ? void 0 : getItemType(item, i)) != null ? _a3 : "";
5079
- totalSize += (_b = getFixedItemSize(item, i, itemType)) != null ? _b : estimatedItemSize;
5308
+ totalSize += ((_b = getFixedItemSize(item, i, itemType)) != null ? _b : estimatedItemSize) + ctx.scrollAxisGap;
5080
5309
  }
5081
5310
  }
5082
5311
  averageItemSize = totalSize / num;
5083
5312
  } else {
5084
- averageItemSize = estimatedItemSize;
5313
+ averageItemSize = estimatedItemSize + ctx.scrollAxisGap;
5085
5314
  }
5086
5315
  const numContainers = Math.max(
5087
5316
  1,
@@ -5136,6 +5365,7 @@ function handleLayout(ctx, layoutParam, setCanRender) {
5136
5365
  if (didChange) {
5137
5366
  state.scrollLength = scrollLength;
5138
5367
  state.otherAxisSize = otherAxisSize;
5368
+ updateContentMetricsState(ctx);
5139
5369
  state.lastBatchingAction = Date.now();
5140
5370
  state.scrollForNextCalculateItemsInView = void 0;
5141
5371
  if (scrollLength > 0) {
@@ -5376,28 +5606,12 @@ function updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment)
5376
5606
 
5377
5607
  // src/core/updateItemSize.ts
5378
5608
  function runOrScheduleMVCPRecalculate(ctx) {
5379
- var _a3, _b;
5609
+ var _a3;
5380
5610
  const state = ctx.state;
5381
5611
  if (state.userScrollAnchorReset !== void 0) {
5382
- const replacementBatchSize = (_a3 = state.userScrollAnchorReset.batchSize) != null ? _a3 : state.userScrollAnchorReset.keys.size;
5383
- const replacementMeasurementBatchThreshold = 3;
5384
- const shouldBatchReplacementMeasurements = replacementBatchSize > replacementMeasurementBatchThreshold;
5385
- if (shouldBatchReplacementMeasurements) {
5386
- if (state.queuedMVCPRecalculate === void 0) {
5387
- state.queuedMVCPRecalculate = requestAnimationFrame(() => {
5388
- var _a4;
5389
- state.queuedMVCPRecalculate = void 0;
5390
- calculateItemsInView(ctx);
5391
- if (((_a4 = state.userScrollAnchorReset) == null ? void 0 : _a4.keys.size) === 0) {
5392
- state.userScrollAnchorReset = void 0;
5393
- }
5394
- });
5395
- }
5396
- } else {
5397
- calculateItemsInView(ctx);
5398
- if (((_b = state.userScrollAnchorReset) == null ? void 0 : _b.keys.size) === 0) {
5399
- state.userScrollAnchorReset = void 0;
5400
- }
5612
+ calculateItemsInView(ctx);
5613
+ if (((_a3 = state.userScrollAnchorReset) == null ? void 0 : _a3.keys.size) === 0) {
5614
+ state.userScrollAnchorReset = void 0;
5401
5615
  }
5402
5616
  } else if (Platform.OS === "web") {
5403
5617
  if (!state.mvcpAnchorLock) {
@@ -5823,10 +6037,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
5823
6037
  startBuffered: state.startBuffered
5824
6038
  }),
5825
6039
  reportContentInset: (inset) => {
5826
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
5827
- const previousInset = state.contentInsetOverride;
5828
- state.contentInsetOverride = inset != null ? inset : void 0;
5829
- const didChange = ((_a3 = previousInset == null ? void 0 : previousInset.top) != null ? _a3 : 0) !== ((_c = (_b = state.contentInsetOverride) == null ? void 0 : _b.top) != null ? _c : 0) || ((_d = previousInset == null ? void 0 : previousInset.bottom) != null ? _d : 0) !== ((_f = (_e = state.contentInsetOverride) == null ? void 0 : _e.bottom) != null ? _f : 0) || ((_g = previousInset == null ? void 0 : previousInset.left) != null ? _g : 0) !== ((_i = (_h = state.contentInsetOverride) == null ? void 0 : _h.left) != null ? _i : 0) || ((_j = previousInset == null ? void 0 : previousInset.right) != null ? _j : 0) !== ((_l = (_k = state.contentInsetOverride) == null ? void 0 : _k.right) != null ? _l : 0);
6040
+ const didChange = setContentInsetOverride(ctx, inset);
5830
6041
  updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
5831
6042
  if (didChange) {
5832
6043
  retargetActiveInitialScrollAtEnd(ctx);
@@ -5878,6 +6089,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
5878
6089
  scrollTo(ctx, params);
5879
6090
  return true;
5880
6091
  }),
6092
+ setItemSize: (itemKey, size) => {
6093
+ updateItemSize(ctx, itemKey, size);
6094
+ },
5881
6095
  setScrollProcessingEnabled: (enabled) => {
5882
6096
  state.scrollProcessingEnabled = enabled;
5883
6097
  },
@@ -6102,7 +6316,7 @@ var LegendList = typedMemo(
6102
6316
  })
6103
6317
  );
6104
6318
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
6105
- 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;
6106
6320
  const noopOnScroll = useCallback((_event) => {
6107
6321
  }, []);
6108
6322
  if (props.recycleItems === void 0) {
@@ -6133,6 +6347,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6133
6347
  initialScrollAtEnd = false,
6134
6348
  initialScrollIndex: initialScrollIndexProp,
6135
6349
  initialScrollOffset: initialScrollOffsetProp,
6350
+ experimental_adaptiveRender,
6136
6351
  itemsAreEqual,
6137
6352
  keyExtractor: keyExtractorProp,
6138
6353
  ListEmptyComponent,
@@ -6182,10 +6397,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6182
6397
  ...restProps
6183
6398
  } = rest;
6184
6399
  const contentContainerStyleBase = StyleSheet.flatten(contentContainerStyleProp);
6185
- const shouldFlexGrow = alignItemsAtEnd && (horizontal ? (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minWidth) == null : (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minHeight) == null);
6400
+ const useAlignItemsAtEndPadding = alignItemsAtEnd && !horizontal && (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minHeight) == null && dataProp.length > 0;
6401
+ const shouldFlexGrow = alignItemsAtEnd && !useAlignItemsAtEndPadding && (horizontal ? (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minWidth) == null : (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minHeight) == null);
6186
6402
  const contentContainerStyle = {
6187
6403
  ...contentContainerStyleBase,
6188
- ...alignItemsAtEnd ? {
6404
+ ...alignItemsAtEnd && !useAlignItemsAtEndPadding ? {
6189
6405
  display: "flex",
6190
6406
  flexDirection: horizontal ? "row" : "column",
6191
6407
  ...shouldFlexGrow ? { flexGrow: 1 } : {},
@@ -6228,6 +6444,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6228
6444
  const [, scheduleImperativeScrollCommit] = React2.useReducer((value) => value + 1, 0);
6229
6445
  const ctx = useStateContext();
6230
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;
6231
6449
  const refScroller = useRef(null);
6232
6450
  const combinedRef = useCombinedRef(refScroller, refScrollView);
6233
6451
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : ((_item, index) => index.toString());
@@ -6241,8 +6459,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6241
6459
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex,
6242
6460
  alwaysRender == null ? void 0 : alwaysRender.top,
6243
6461
  alwaysRender == null ? void 0 : alwaysRender.bottom,
6244
- (_d = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _d.join(","),
6245
- (_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(","),
6246
6464
  dataProp,
6247
6465
  dataVersion,
6248
6466
  keyExtractor
@@ -6270,6 +6488,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6270
6488
  endNoBuffer: -1,
6271
6489
  endReachedSnapshot: void 0,
6272
6490
  firstFullyOnScreenIndex: -1,
6491
+ hasHadNonEmptyData: dataProp.length > 0,
6273
6492
  idCache: [],
6274
6493
  idsInView: [],
6275
6494
  indexByKey: /* @__PURE__ */ new Map(),
@@ -6312,6 +6531,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6312
6531
  startReachedSnapshotDataChangeEpoch: void 0,
6313
6532
  stickyContainerPool: /* @__PURE__ */ new Set(),
6314
6533
  stickyContainers: /* @__PURE__ */ new Map(),
6534
+ timeoutAdaptiveRender: void 0,
6315
6535
  timeouts: /* @__PURE__ */ new Set(),
6316
6536
  totalSize: 0,
6317
6537
  viewabilityConfigCallbackPairs: void 0
@@ -6330,11 +6550,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6330
6550
  const state = refState.current;
6331
6551
  const isFirstLocal = state.isFirst;
6332
6552
  const previousNumColumnsProp = state.props.numColumns;
6333
- state.didColumnsChange = numColumnsProp !== previousNumColumnsProp;
6553
+ const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
6554
+ ctx.scrollAxisGap = nextScrollAxisGap;
6555
+ state.didColumnsChange = numColumnsProp !== previousNumColumnsProp || didScrollAxisGapChange;
6334
6556
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
6335
6557
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
6336
6558
  const didDataChangeLocal = didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
6337
- 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) {
6338
6560
  clearPreservedInitialScrollTarget(state);
6339
6561
  }
6340
6562
  if (didDataChangeLocal) {
@@ -6346,14 +6568,17 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6346
6568
  const throttledOnScroll = useThrottledOnScroll(onScrollProp != null ? onScrollProp : noopOnScroll, scrollEventThrottle != null ? scrollEventThrottle : 0);
6347
6569
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? throttledOnScroll : onScrollProp;
6348
6570
  const anchoredEndSpaceResolved = Platform.OS === "web" && anchoredEndSpace ? { ...anchoredEndSpace, includeInEndInset: true } : anchoredEndSpace;
6349
- 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);
6350
6572
  state.props = {
6573
+ adaptiveRender: experimental_adaptiveRender,
6351
6574
  alignItemsAtEnd,
6575
+ alignItemsAtEndPaddingEnabled: useAlignItemsAtEndPadding,
6352
6576
  alwaysRender,
6353
6577
  alwaysRenderIndicesArr: alwaysRenderIndices.arr,
6354
6578
  alwaysRenderIndicesSet: alwaysRenderIndices.set,
6355
6579
  anchoredEndSpace: anchoredEndSpaceResolved,
6356
6580
  animatedProps: animatedPropsInternal,
6581
+ contentContainerAlignItems: contentContainerStyle.alignItems,
6357
6582
  contentInset,
6358
6583
  contentInsetEndAdjustment: contentInsetEndAdjustmentResolved,
6359
6584
  data: dataProp,
@@ -6406,6 +6631,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6406
6631
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
6407
6632
  setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
6408
6633
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
6634
+ updateContentMetricsState(ctx);
6409
6635
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
6410
6636
  if (shouldAdjustPadding && maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
6411
6637
  if (state.scroll < 0) {
@@ -6442,7 +6668,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6442
6668
  useBootstrapInitialScroll: usesBootstrapInitialScroll
6443
6669
  });
6444
6670
  }, []);
6445
- if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
6671
+ if (isFirstLocal || didDataChangeLocal || state.didColumnsChange) {
6446
6672
  refState.current.lastBatchingAction = Date.now();
6447
6673
  if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
6448
6674
  refState.current.sizes.clear();
@@ -6459,6 +6685,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6459
6685
  dataLength: dataProp.length,
6460
6686
  didDataChange: didDataChangeLocal,
6461
6687
  initialScrollAtEnd,
6688
+ latestInitialScroll: initialScrollProp,
6689
+ latestInitialScrollSessionKind: initialScrollUsesOffsetOnly ? "offset" : "bootstrap",
6462
6690
  stylePaddingBottom: stylePaddingBottomState,
6463
6691
  useBootstrapInitialScroll: usesBootstrapInitialScroll
6464
6692
  });
@@ -6529,7 +6757,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6529
6757
  }, [snapToIndices]);
6530
6758
  useLayoutEffect(
6531
6759
  () => initializeStateVars(true),
6532
- [dataVersion, memoizedLastItemKeys.join(","), numColumnsProp, stylePaddingBottomState, stylePaddingTopState]
6760
+ [
6761
+ dataVersion,
6762
+ memoizedLastItemKeys.join(","),
6763
+ numColumnsProp,
6764
+ nextScrollAxisGap,
6765
+ stylePaddingBottomState,
6766
+ stylePaddingTopState,
6767
+ useAlignItemsAtEndPadding
6768
+ ]
6533
6769
  );
6534
6770
  useLayoutEffect(() => {
6535
6771
  const {
@@ -6548,7 +6784,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6548
6784
  state.didColumnsChange = false;
6549
6785
  state.didDataChange = false;
6550
6786
  state.isFirst = false;
6551
- }, [dataProp, dataVersion, numColumnsProp]);
6787
+ }, [dataProp, dataVersion, numColumnsProp, nextScrollAxisGap]);
6552
6788
  useLayoutEffect(() => {
6553
6789
  var _a4;
6554
6790
  set$(ctx, "extraData", extraData);
@@ -6599,6 +6835,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6599
6835
  }
6600
6836
  });
6601
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]);
6602
6846
  useLayoutEffect(() => {
6603
6847
  var _a4;
6604
6848
  (_a4 = state.runPendingScrollToEnd) == null ? void 0 : _a4.call(state);
@@ -6646,7 +6890,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6646
6890
  onScroll: onScrollHandler,
6647
6891
  recycleItems,
6648
6892
  refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React2.cloneElement(refreshControlElement, {
6649
- progressViewOffset: ((_h = refreshControlElement.props.progressViewOffset) != null ? _h : 0) + stylePaddingTopState
6893
+ progressViewOffset: ((_n = refreshControlElement.props.progressViewOffset) != null ? _n : 0) + stylePaddingTopState
6650
6894
  }) : refreshControlElement : onRefresh && /* @__PURE__ */ React2.createElement(
6651
6895
  RefreshControl,
6652
6896
  {
@@ -6657,7 +6901,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6657
6901
  ),
6658
6902
  refScrollView: combinedRef,
6659
6903
  renderScrollComponent,
6660
- scrollAdjustHandler: (_i = refState.current) == null ? void 0 : _i.scrollAdjustHandler,
6904
+ scrollAdjustHandler: (_o = refState.current) == null ? void 0 : _o.scrollAdjustHandler,
6661
6905
  scrollEventThrottle: 0,
6662
6906
  snapToIndices,
6663
6907
  stickyHeaderIndices,
@@ -6689,4 +6933,4 @@ var internal = {
6689
6933
  var LegendList3 = LegendListRuntime;
6690
6934
  var internal2 = internal;
6691
6935
 
6692
- 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 };