@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.js CHANGED
@@ -152,8 +152,10 @@ function StateProvider({ children }) {
152
152
  mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
153
153
  mapViewabilityValues: /* @__PURE__ */ new Map(),
154
154
  positionListeners: /* @__PURE__ */ new Map(),
155
+ scrollAxisGap: 0,
155
156
  state: void 0,
156
157
  values: /* @__PURE__ */ new Map([
158
+ ["alignItemsAtEndPadding", 0],
157
159
  ["stylePaddingTop", 0],
158
160
  ["headerSize", 0],
159
161
  ["numContainers", 0],
@@ -163,6 +165,7 @@ function StateProvider({ children }) {
163
165
  ["isNearEnd", false],
164
166
  ["isNearStart", false],
165
167
  ["isWithinMaintainScrollAtEndThreshold", false],
168
+ ["adaptiveRender", "light"],
166
169
  ["totalSize", 0],
167
170
  ["scrollAdjustPending", 0]
168
171
  ]),
@@ -296,15 +299,16 @@ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
296
299
 
297
300
  // src/state/getContentSize.ts
298
301
  function getContentSize(ctx) {
299
- var _a3;
302
+ var _a3, _b;
300
303
  const { values, state } = ctx;
301
304
  const stylePaddingTop = values.get("stylePaddingTop") || 0;
302
305
  const stylePaddingBottom = state.props.stylePaddingBottom || 0;
306
+ const alignItemsAtEndPadding = values.get("alignItemsAtEndPadding") || 0;
303
307
  const headerSize = values.get("headerSize") || 0;
304
308
  const footerSize = values.get("footerSize") || 0;
305
309
  const contentInsetBottom = getContentInsetEnd(ctx);
306
- const totalSize = (_a3 = state.pendingTotalSize) != null ? _a3 : values.get("totalSize");
307
- return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom + (contentInsetBottom || 0);
310
+ const totalSize = (_b = (_a3 = state.pendingTotalSize) != null ? _a3 : state.totalSize) != null ? _b : values.get("totalSize");
311
+ return headerSize + footerSize + totalSize + stylePaddingTop + alignItemsAtEndPadding + stylePaddingBottom + (contentInsetBottom || 0);
308
312
  }
309
313
 
310
314
  // src/components/DebugView.tsx
@@ -479,8 +483,16 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
479
483
  ...rest
480
484
  }) {
481
485
  const ctx = useStateContext();
482
- const [position = POSITION_OUT_OF_VIEW, headerSize = 0, stylePaddingTop = 0, itemKey, _totalSize = 0] = useArr$([
486
+ const [
487
+ position = POSITION_OUT_OF_VIEW,
488
+ alignItemsAtEndPadding = 0,
489
+ headerSize = 0,
490
+ stylePaddingTop = 0,
491
+ itemKey,
492
+ _totalSize = 0
493
+ ] = useArr$([
483
494
  `containerPosition${id}`,
495
+ "alignItemsAtEndPadding",
484
496
  "headerSize",
485
497
  "stylePaddingTop",
486
498
  `containerItemKey${id}`,
@@ -494,7 +506,7 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
494
506
  var _a3;
495
507
  if (animatedScrollY) {
496
508
  const stickyConfigOffset = (_a3 = stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset) != null ? _a3 : 0;
497
- const stickyStart = position + headerSize + stylePaddingTop - stickyConfigOffset;
509
+ const stickyStart = position + headerSize + stylePaddingTop + alignItemsAtEndPadding - stickyConfigOffset;
498
510
  let nextStickyPosition;
499
511
  if (pushLimit !== void 0) {
500
512
  if (pushLimit <= position) {
@@ -517,7 +529,15 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
517
529
  }
518
530
  return horizontal ? [{ translateX: nextStickyPosition }] : [{ translateY: nextStickyPosition }];
519
531
  }
520
- }, [animatedScrollY, headerSize, position, pushLimit, stylePaddingTop, stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset]);
532
+ }, [
533
+ alignItemsAtEndPadding,
534
+ animatedScrollY,
535
+ headerSize,
536
+ position,
537
+ pushLimit,
538
+ stylePaddingTop,
539
+ stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset
540
+ ]);
521
541
  const viewStyle = React2__namespace.useMemo(() => [style, { zIndex: index + 1e3 }, { transform }], [style, transform]);
522
542
  const renderStickyHeaderBackdrop = React2__namespace.useMemo(() => {
523
543
  if (!(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)) {
@@ -591,6 +611,24 @@ var ContextContainer = React2.createContext(null);
591
611
  function useContextContainer() {
592
612
  return React2.useContext(ContextContainer);
593
613
  }
614
+ function useAdaptiveRender() {
615
+ const [mode] = useArr$(["adaptiveRender"]);
616
+ return mode;
617
+ }
618
+ function useAdaptiveRenderChange(callback) {
619
+ const ctx = useStateContext();
620
+ const callbackRef = React2.useRef(callback);
621
+ callbackRef.current = callback;
622
+ React2.useLayoutEffect(() => {
623
+ let mode = peek$(ctx, "adaptiveRender");
624
+ return listen$(ctx, "adaptiveRender", (nextMode) => {
625
+ if (mode !== nextMode) {
626
+ mode = nextMode;
627
+ callbackRef.current(nextMode);
628
+ }
629
+ });
630
+ }, [ctx]);
631
+ }
594
632
  function useViewability(callback, configId) {
595
633
  const ctx = useStateContext();
596
634
  const containerContext = useContextContainer();
@@ -807,6 +845,7 @@ function isInMVCPActiveMode(state) {
807
845
  // src/components/Container.tsx
808
846
  function getContainerPositionStyle({
809
847
  columnWrapperStyle,
848
+ contentContainerAlignItems,
810
849
  horizontal,
811
850
  hasItemSeparator,
812
851
  isHorizontalRTLList,
@@ -832,13 +871,14 @@ function getContainerPositionStyle({
832
871
  }
833
872
  }
834
873
  return horizontal ? {
874
+ bottom: contentContainerAlignItems === "flex-end" && numColumns === 1 ? 0 : void 0,
835
875
  boxSizing: paddingStyles ? "border-box" : void 0,
836
876
  direction: isHorizontalRTLList && Platform.OS === "web" ? "ltr" : void 0,
837
877
  flexDirection: hasItemSeparator ? "row" : void 0,
838
878
  height: otherAxisSize,
839
879
  left: 0,
840
880
  position: "absolute",
841
- top: otherAxisPos,
881
+ top: contentContainerAlignItems === "flex-end" && numColumns === 1 ? void 0 : otherAxisPos,
842
882
  ...paddingStyles || {}
843
883
  } : {
844
884
  boxSizing: paddingStyles ? "border-box" : void 0,
@@ -892,6 +932,7 @@ var Container = typedMemo(function Container2({
892
932
  const style = React2.useMemo(
893
933
  () => getContainerPositionStyle({
894
934
  columnWrapperStyle,
935
+ contentContainerAlignItems: ctx.state.props.contentContainerAlignItems,
895
936
  hasItemSeparator: !!ItemSeparatorComponent,
896
937
  horizontal,
897
938
  isHorizontalRTLList,
@@ -905,6 +946,7 @@ var Container = typedMemo(function Container2({
905
946
  otherAxisPos,
906
947
  otherAxisSize,
907
948
  columnWrapperStyle,
949
+ ctx.state.props.contentContainerAlignItems,
908
950
  numColumns,
909
951
  ItemSeparatorComponent
910
952
  ]
@@ -1174,245 +1216,267 @@ function WebAnchoredEndSpace({ horizontal }) {
1174
1216
  const style = horizontal ? { height: "100%", width: anchoredEndSpaceSize || 0 } : { height: anchoredEndSpaceSize || 0 };
1175
1217
  return /* @__PURE__ */ React2__namespace.createElement("div", { style }, null);
1176
1218
  }
1177
- function useLatestRef(value) {
1178
- const ref = React2__namespace.useRef(value);
1179
- ref.current = value;
1180
- return ref;
1181
- }
1182
1219
 
1183
- // src/hooks/useStableRenderComponent.tsx
1184
- function useStableRenderComponent(renderComponent, mapProps) {
1185
- const renderComponentRef = useLatestRef(renderComponent);
1186
- const mapPropsRef = useLatestRef(mapProps);
1187
- return React2__namespace.useMemo(
1188
- () => React2__namespace.forwardRef(
1189
- (props, ref) => {
1190
- var _a3, _b;
1191
- return (_b = (_a3 = renderComponentRef.current) == null ? void 0 : _a3.call(renderComponentRef, mapPropsRef.current(props, ref))) != null ? _b : null;
1192
- }
1193
- ),
1194
- [mapPropsRef, renderComponentRef]
1195
- );
1220
+ // src/core/calculateOffsetForIndex.ts
1221
+ function calculateOffsetForIndex(ctx, index) {
1222
+ const state = ctx.state;
1223
+ return index !== void 0 ? state.positions[index] || 0 : 0;
1196
1224
  }
1197
- var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
1198
- const localRef = React2.useRef(null);
1199
- const ref = refView != null ? refView : localRef;
1200
- const { onLayout } = useOnLayoutSync({ onLayoutChange, ref });
1201
- return /* @__PURE__ */ React2__namespace.createElement(ReactNative.View, { ...rest, onLayout, ref });
1202
- };
1203
1225
 
1204
- // src/components/ListComponent.tsx
1205
- var ListComponent = typedMemo(function ListComponent2({
1206
- canRender,
1207
- style,
1208
- contentContainerStyle,
1209
- horizontal,
1210
- initialContentOffset,
1211
- recycleItems,
1212
- ItemSeparatorComponent,
1213
- alignItemsAtEnd: _alignItemsAtEnd,
1214
- onScroll: onScroll2,
1215
- onLayout,
1216
- ListHeaderComponent,
1217
- ListHeaderComponentStyle,
1218
- ListFooterComponent,
1219
- ListFooterComponentStyle,
1220
- ListEmptyComponent,
1221
- getRenderedItem: getRenderedItem2,
1222
- updateItemSize: updateItemSize2,
1223
- refScrollView,
1224
- renderScrollComponent,
1225
- onLayoutFooter,
1226
- scrollAdjustHandler,
1227
- snapToIndices,
1228
- stickyHeaderConfig,
1229
- stickyHeaderIndices,
1230
- useWindowScroll = false,
1231
- ...rest
1232
- }) {
1233
- const ctx = useStateContext();
1234
- const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1235
- const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
1236
- const autoOtherAxisStyle = getAutoOtherAxisStyle({
1237
- horizontal,
1238
- needsOtherAxisSize: ctx.state.needsOtherAxisSize,
1239
- otherAxisSize
1240
- });
1241
- const CustomScrollComponent = useStableRenderComponent(
1242
- renderScrollComponent,
1243
- (props, ref) => ({ ...props, ref })
1244
- );
1245
- const ScrollComponent = renderScrollComponent ? CustomScrollComponent : ListComponentScrollView;
1246
- const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
1247
- React2.useLayoutEffect(() => {
1248
- if (!ListHeaderComponent) {
1249
- set$(ctx, "headerSize", 0);
1250
- }
1251
- if (!ListFooterComponent) {
1252
- set$(ctx, "footerSize", 0);
1253
- }
1254
- }, [ListHeaderComponent, ListFooterComponent, ctx]);
1255
- const onLayoutHeader = React2.useCallback(
1256
- (rect) => {
1257
- const size = rect[horizontal ? "width" : "height"];
1258
- set$(ctx, "headerSize", size);
1259
- },
1260
- [ctx, horizontal]
1261
- );
1262
- const onLayoutFooterInternal = React2.useCallback(
1263
- (rect, fromLayoutEffect) => {
1264
- const size = rect[horizontal ? "width" : "height"];
1265
- set$(ctx, "footerSize", size);
1266
- onLayoutFooter == null ? void 0 : onLayoutFooter(rect, fromLayoutEffect);
1267
- },
1268
- [ctx, horizontal, onLayoutFooter]
1269
- );
1270
- return /* @__PURE__ */ React2__namespace.createElement(
1271
- SnapOrScroll,
1272
- {
1273
- ...rest,
1274
- ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
1275
- contentContainerStyle: [
1276
- horizontal ? {
1277
- height: "100%"
1278
- } : {},
1279
- contentContainerStyle
1280
- ],
1281
- contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1282
- horizontal,
1283
- maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
1284
- onLayout,
1285
- onScroll: onScroll2,
1286
- ref: refScrollView,
1287
- ScrollComponent: snapToIndices ? ScrollComponent : void 0,
1288
- style: autoOtherAxisStyle ? [autoOtherAxisStyle, style] : style
1289
- },
1290
- /* @__PURE__ */ React2__namespace.createElement(ScrollAdjust, null),
1291
- ListHeaderComponent && /* @__PURE__ */ React2__namespace.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
1292
- ListEmptyComponent && getComponent(ListEmptyComponent),
1293
- canRender && !ListEmptyComponent && /* @__PURE__ */ React2__namespace.createElement(
1294
- Containers,
1295
- {
1296
- getRenderedItem: getRenderedItem2,
1297
- horizontal,
1298
- ItemSeparatorComponent,
1299
- recycleItems,
1300
- stickyHeaderConfig,
1301
- updateItemSize: updateItemSize2
1302
- }
1303
- ),
1304
- ListFooterComponent && /* @__PURE__ */ React2__namespace.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
1305
- Platform.OS === "web" && /* @__PURE__ */ React2__namespace.createElement(WebAnchoredEndSpace, { horizontal }),
1306
- IS_DEV && ENABLE_DEVMODE
1307
- );
1308
- });
1309
- var WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH = 100;
1310
- var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
1311
- var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
1312
- function useDevChecksImpl(props) {
1313
- const ctx = useStateContext();
1314
- const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
1315
- React2.useEffect(() => {
1316
- if (useWindowScroll && renderScrollComponent) {
1317
- warnDevOnce(
1318
- "useWindowScrollRenderScrollComponent",
1319
- "useWindowScroll is not supported when renderScrollComponent is provided."
1320
- );
1321
- }
1322
- }, [renderScrollComponent, useWindowScroll]);
1323
- React2.useEffect(() => {
1324
- if (!keyExtractor && !ctx.state.isFirst && ctx.state.didDataChange && !childrenMode) {
1325
- warnDevOnce(
1326
- "keyExtractor",
1327
- "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."
1328
- );
1329
- }
1330
- }, [childrenMode, ctx, keyExtractor]);
1331
- React2.useEffect(() => {
1332
- const state = ctx.state;
1333
- const dataLength = state.props.data.length;
1334
- const useWindowScrollResolved = state.props.useWindowScroll;
1335
- if (Platform.OS !== "web" || useWindowScrollResolved || dataLength < WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH) {
1336
- return;
1337
- }
1338
- const warnIfUnboundedOuterSize = () => {
1339
- const readyToRender = peek$(ctx, "readyToRender");
1340
- const numContainers = peek$(ctx, "numContainers") || 0;
1341
- const totalSize = peek$(ctx, "totalSize") || 0;
1342
- const scrollLength = ctx.state.scrollLength || 0;
1343
- if (!readyToRender || totalSize <= 0 || scrollLength <= 0) {
1344
- return;
1345
- }
1346
- const rendersAlmostEverything = numContainers >= Math.ceil(dataLength * WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO);
1347
- const viewportMatchesContent = scrollLength >= totalSize * WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO;
1348
- if (rendersAlmostEverything && viewportMatchesContent) {
1349
- warnDevOnce(
1350
- "webUnboundedOuterSize",
1351
- "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."
1352
- );
1353
- }
1354
- };
1355
- warnIfUnboundedOuterSize();
1356
- const unsubscribe = [
1357
- listen$(ctx, "numContainers", warnIfUnboundedOuterSize),
1358
- listen$(ctx, "readyToRender", warnIfUnboundedOuterSize),
1359
- listen$(ctx, "totalSize", warnIfUnboundedOuterSize)
1360
- ];
1361
- return () => {
1362
- for (const unsub of unsubscribe) {
1363
- unsub();
1364
- }
1365
- };
1366
- }, [ctx]);
1367
- }
1368
- function useDevChecksNoop(_props) {
1226
+ // src/core/getTopOffsetAdjustment.ts
1227
+ function getTopOffsetAdjustment(ctx) {
1228
+ return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
1369
1229
  }
1370
- var useDevChecks = IS_DEV ? useDevChecksImpl : useDevChecksNoop;
1371
1230
 
1372
- // src/core/deferredPublicOnScroll.ts
1373
- function withResolvedContentOffset(state, event, resolvedOffset) {
1374
- return {
1375
- ...event,
1376
- nativeEvent: {
1377
- ...event.nativeEvent,
1378
- contentOffset: state.props.horizontal ? { x: resolvedOffset, y: 0 } : { x: 0, y: resolvedOffset }
1379
- }
1380
- };
1381
- }
1382
- function releaseDeferredPublicOnScroll(ctx, resolvedOffset) {
1383
- var _a3, _b, _c, _d;
1384
- const state = ctx.state;
1385
- const deferredEvent = state.deferredPublicOnScrollEvent;
1386
- state.deferredPublicOnScrollEvent = void 0;
1387
- if (deferredEvent) {
1388
- (_d = (_c = state.props).onScroll) == null ? void 0 : _d.call(
1389
- _c,
1390
- withResolvedContentOffset(
1391
- state,
1392
- deferredEvent,
1393
- (_b = (_a3 = resolvedOffset != null ? resolvedOffset : state.scrollPending) != null ? _a3 : state.scroll) != null ? _b : 0
1394
- )
1395
- );
1231
+ // src/utils/getId.ts
1232
+ function getId(state, index) {
1233
+ const { data, keyExtractor } = state.props;
1234
+ if (!data) {
1235
+ return "";
1396
1236
  }
1237
+ const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
1238
+ const id = ret;
1239
+ state.idCache[index] = id;
1240
+ return id;
1397
1241
  }
1398
1242
 
1399
- // src/core/initialScrollSession.ts
1400
- var INITIAL_SCROLL_MIN_TARGET_OFFSET = 1;
1401
- function hasInitialScrollSessionCompletion(completion) {
1402
- return !!((completion == null ? void 0 : completion.didDispatchNativeScroll) || (completion == null ? void 0 : completion.didRetrySilentInitialScroll) || (completion == null ? void 0 : completion.watchdog));
1243
+ // src/core/updateContentMetricsState.ts
1244
+ function getRawContentLength(ctx) {
1245
+ var _a3, _b, _c;
1246
+ const { state, values } = ctx;
1247
+ 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);
1403
1248
  }
1404
- function clearInitialScrollSession(state) {
1405
- state.initialScrollSession = void 0;
1406
- return void 0;
1249
+ function getAlignItemsAtEndPadding(ctx) {
1250
+ const { state } = ctx;
1251
+ const shouldPad = !!state.props.alignItemsAtEndPaddingEnabled && !state.props.horizontal && state.props.data.length > 0 && state.scrollLength > 0;
1252
+ return shouldPad ? Math.max(0, state.scrollLength - getRawContentLength(ctx) - getContentInsetEnd(ctx)) : 0;
1407
1253
  }
1408
- function createInitialScrollSession(options) {
1409
- const { bootstrap, completion, kind, previousDataLength } = options;
1410
- return kind === "offset" ? {
1411
- completion,
1412
- kind,
1413
- previousDataLength
1414
- } : {
1415
- bootstrap,
1254
+ function updateContentMetricsState(ctx) {
1255
+ const previousPadding = peek$(ctx, "alignItemsAtEndPadding") || 0;
1256
+ const nextPadding = getAlignItemsAtEndPadding(ctx);
1257
+ if (previousPadding !== nextPadding) {
1258
+ set$(ctx, "alignItemsAtEndPadding", nextPadding);
1259
+ }
1260
+ }
1261
+
1262
+ // src/core/addTotalSize.ts
1263
+ function addTotalSize(ctx, key, add, notifyTotalSize = true) {
1264
+ const state = ctx.state;
1265
+ const prevTotalSize = state.totalSize;
1266
+ let totalSize = state.totalSize;
1267
+ if (key === null) {
1268
+ totalSize = add;
1269
+ if (state.timeoutSetPaddingTop) {
1270
+ clearTimeout(state.timeoutSetPaddingTop);
1271
+ state.timeoutSetPaddingTop = void 0;
1272
+ }
1273
+ } else {
1274
+ totalSize += add;
1275
+ }
1276
+ if (prevTotalSize !== totalSize) {
1277
+ if (!IsNewArchitecture && state.initialScroll && totalSize < prevTotalSize) {
1278
+ state.pendingTotalSize = totalSize;
1279
+ } else {
1280
+ state.pendingTotalSize = void 0;
1281
+ state.totalSize = totalSize;
1282
+ if (notifyTotalSize) {
1283
+ set$(ctx, "totalSize", totalSize);
1284
+ }
1285
+ updateContentMetricsState(ctx);
1286
+ }
1287
+ } else if (notifyTotalSize && ctx.values.get("totalSize") !== totalSize) {
1288
+ set$(ctx, "totalSize", totalSize);
1289
+ }
1290
+ }
1291
+
1292
+ // src/core/setSize.ts
1293
+ function setSize(ctx, itemKey, size, notifyTotalSize = true) {
1294
+ const state = ctx.state;
1295
+ const { sizes } = state;
1296
+ const previousSize = sizes.get(itemKey);
1297
+ const diff = previousSize !== void 0 ? size - previousSize : size;
1298
+ if (diff !== 0) {
1299
+ addTotalSize(ctx, itemKey, diff, notifyTotalSize);
1300
+ }
1301
+ sizes.set(itemKey, size);
1302
+ }
1303
+
1304
+ // src/utils/getItemSize.ts
1305
+ function getKnownOrFixedSize(ctx, key, index, data, resolved) {
1306
+ var _a3, _b;
1307
+ const state = ctx.state;
1308
+ const { getFixedItemSize, getItemType } = state.props;
1309
+ let size = key ? state.sizesKnown.get(key) : void 0;
1310
+ if (size === void 0 && key && getFixedItemSize) {
1311
+ const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1312
+ const fixedSize = (resolved == null ? void 0 : resolved.didResolveFixedItemSize) ? resolved.fixedItemSize : getFixedItemSize(data, index, itemType);
1313
+ if (fixedSize !== void 0) {
1314
+ size = fixedSize + ctx.scrollAxisGap;
1315
+ state.sizesKnown.set(key, size);
1316
+ }
1317
+ }
1318
+ return size;
1319
+ }
1320
+ function getKnownOrFixedItemSize(ctx, index) {
1321
+ const key = getId(ctx.state, index);
1322
+ return getKnownOrFixedSize(ctx, key, index, ctx.state.props.data[index]);
1323
+ }
1324
+ function areKnownOrFixedItemSizesAvailable(ctx, startIndex, endIndex) {
1325
+ for (let index = startIndex; index <= endIndex; index++) {
1326
+ if (getKnownOrFixedItemSize(ctx, index) === void 0) {
1327
+ return false;
1328
+ }
1329
+ }
1330
+ return true;
1331
+ }
1332
+ function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize, notifyTotalSize, resolved) {
1333
+ var _a3, _b, _c, _d;
1334
+ const state = ctx.state;
1335
+ const {
1336
+ sizes,
1337
+ averageSizes,
1338
+ props: { estimatedItemSize, getItemType },
1339
+ scrollingTo
1340
+ } = state;
1341
+ const sizeKnown = state.sizesKnown.get(key);
1342
+ if (sizeKnown !== void 0) {
1343
+ return sizeKnown;
1344
+ }
1345
+ let size;
1346
+ const renderedSize = sizes.get(key);
1347
+ if (preferCachedSize) {
1348
+ if (renderedSize !== void 0) {
1349
+ return renderedSize;
1350
+ }
1351
+ }
1352
+ size = getKnownOrFixedSize(ctx, key, index, data, resolved);
1353
+ if (size !== void 0) {
1354
+ setSize(ctx, key, size, notifyTotalSize);
1355
+ return size;
1356
+ }
1357
+ const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1358
+ if (useAverageSize && !scrollingTo) {
1359
+ const averageSizeForType = (_c = averageSizes[itemType]) == null ? void 0 : _c.avg;
1360
+ if (averageSizeForType !== void 0) {
1361
+ size = roundSize(averageSizeForType);
1362
+ }
1363
+ }
1364
+ if (size === void 0 && renderedSize !== void 0) {
1365
+ return renderedSize;
1366
+ }
1367
+ if (size === void 0 && useAverageSize && scrollingTo) {
1368
+ const averageSizeForType = (_d = scrollingTo.averageSizeSnapshot) == null ? void 0 : _d[itemType];
1369
+ if (averageSizeForType !== void 0) {
1370
+ size = roundSize(averageSizeForType);
1371
+ }
1372
+ }
1373
+ if (size === void 0) {
1374
+ size = estimatedItemSize + ctx.scrollAxisGap;
1375
+ }
1376
+ setSize(ctx, key, size, notifyTotalSize);
1377
+ return size;
1378
+ }
1379
+ function getItemSizeAtIndex(ctx, index) {
1380
+ if (index === void 0 || index < 0) {
1381
+ return void 0;
1382
+ }
1383
+ const targetId = getId(ctx.state, index);
1384
+ return getItemSize(ctx, targetId, index, ctx.state.props.data[index]);
1385
+ }
1386
+
1387
+ // src/core/calculateOffsetWithOffsetPosition.ts
1388
+ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1389
+ var _a3;
1390
+ const state = ctx.state;
1391
+ const { index, viewOffset, viewPosition } = params;
1392
+ let offset = offsetParam;
1393
+ if (viewOffset) {
1394
+ offset -= viewOffset;
1395
+ }
1396
+ if (index !== void 0) {
1397
+ const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
1398
+ if (topOffsetAdjustment) {
1399
+ offset += topOffsetAdjustment;
1400
+ }
1401
+ }
1402
+ if (viewPosition !== void 0 && index !== void 0) {
1403
+ const dataLength = state.props.data.length;
1404
+ if (dataLength === 0) {
1405
+ return offset;
1406
+ }
1407
+ const isOutOfBounds = index < 0 || index >= dataLength;
1408
+ const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
1409
+ const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1410
+ const trailingInset = getContentInsetEnd(ctx);
1411
+ offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1412
+ if (!isOutOfBounds && index === state.props.data.length - 1) {
1413
+ const footerSize = peek$(ctx, "footerSize") || 0;
1414
+ offset += footerSize;
1415
+ }
1416
+ }
1417
+ return offset;
1418
+ }
1419
+
1420
+ // src/core/clampScrollOffset.ts
1421
+ function clampScrollOffset(ctx, offset, scrollTarget) {
1422
+ const state = ctx.state;
1423
+ const contentSize = getContentSize(ctx);
1424
+ let clampedOffset = offset;
1425
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform.OS !== "android" || state.lastLayout)) {
1426
+ const baseMaxOffset = Math.max(0, contentSize - state.scrollLength);
1427
+ const viewOffset = scrollTarget == null ? void 0 : scrollTarget.viewOffset;
1428
+ const extraEndOffset = typeof viewOffset === "number" && viewOffset < 0 ? -viewOffset : 0;
1429
+ const maxOffset = baseMaxOffset + extraEndOffset;
1430
+ clampedOffset = Math.min(offset, maxOffset);
1431
+ }
1432
+ clampedOffset = Math.max(0, clampedOffset);
1433
+ return clampedOffset;
1434
+ }
1435
+
1436
+ // src/core/deferredPublicOnScroll.ts
1437
+ function withResolvedContentOffset(state, event, resolvedOffset) {
1438
+ return {
1439
+ ...event,
1440
+ nativeEvent: {
1441
+ ...event.nativeEvent,
1442
+ contentOffset: state.props.horizontal ? { x: resolvedOffset, y: 0 } : { x: 0, y: resolvedOffset }
1443
+ }
1444
+ };
1445
+ }
1446
+ function releaseDeferredPublicOnScroll(ctx, resolvedOffset) {
1447
+ var _a3, _b, _c, _d;
1448
+ const state = ctx.state;
1449
+ const deferredEvent = state.deferredPublicOnScrollEvent;
1450
+ state.deferredPublicOnScrollEvent = void 0;
1451
+ if (deferredEvent) {
1452
+ (_d = (_c = state.props).onScroll) == null ? void 0 : _d.call(
1453
+ _c,
1454
+ withResolvedContentOffset(
1455
+ state,
1456
+ deferredEvent,
1457
+ (_b = (_a3 = resolvedOffset != null ? resolvedOffset : state.scrollPending) != null ? _a3 : state.scroll) != null ? _b : 0
1458
+ )
1459
+ );
1460
+ }
1461
+ }
1462
+
1463
+ // src/core/initialScrollSession.ts
1464
+ var INITIAL_SCROLL_MIN_TARGET_OFFSET = 1;
1465
+ function hasInitialScrollSessionCompletion(completion) {
1466
+ return !!((completion == null ? void 0 : completion.didDispatchNativeScroll) || (completion == null ? void 0 : completion.didRetrySilentInitialScroll) || (completion == null ? void 0 : completion.watchdog));
1467
+ }
1468
+ function clearInitialScrollSession(state) {
1469
+ state.initialScrollSession = void 0;
1470
+ return void 0;
1471
+ }
1472
+ function createInitialScrollSession(options) {
1473
+ const { bootstrap, completion, kind, previousDataLength } = options;
1474
+ return kind === "offset" ? {
1475
+ completion,
1476
+ kind,
1477
+ previousDataLength
1478
+ } : {
1479
+ bootstrap,
1416
1480
  completion,
1417
1481
  kind,
1418
1482
  previousDataLength
@@ -1680,6 +1744,66 @@ function recalculateSettledScroll(ctx) {
1680
1744
  checkThresholds(ctx);
1681
1745
  }
1682
1746
 
1747
+ // src/core/adaptiveRender.ts
1748
+ var DEFAULT_ENTER_VELOCITY = 4;
1749
+ var DEFAULT_EXIT_VELOCITY = 1;
1750
+ var DEFAULT_EXIT_DELAY = 1e3;
1751
+ function scheduleAdaptiveRenderExit(ctx, exitDelay) {
1752
+ const state = ctx.state;
1753
+ const previousTimeout = state.timeoutAdaptiveRender;
1754
+ if (previousTimeout !== void 0) {
1755
+ clearTimeout(previousTimeout);
1756
+ state.timeouts.delete(previousTimeout);
1757
+ state.timeoutAdaptiveRender = void 0;
1758
+ }
1759
+ if (exitDelay <= 0) {
1760
+ setAdaptiveRender(ctx, "normal");
1761
+ } else {
1762
+ const timeout = setTimeout(() => {
1763
+ state.timeouts.delete(timeout);
1764
+ state.timeoutAdaptiveRender = void 0;
1765
+ setAdaptiveRender(ctx, "normal");
1766
+ }, exitDelay);
1767
+ state.timeoutAdaptiveRender = timeout;
1768
+ state.timeouts.add(timeout);
1769
+ }
1770
+ }
1771
+ function setAdaptiveRender(ctx, mode) {
1772
+ var _a3, _b;
1773
+ const previousMode = peek$(ctx, "adaptiveRender");
1774
+ if (previousMode !== mode) {
1775
+ set$(ctx, "adaptiveRender", mode);
1776
+ (_b = (_a3 = ctx.state.props.adaptiveRender) == null ? void 0 : _a3.onChange) == null ? void 0 : _b.call(_a3, mode);
1777
+ }
1778
+ }
1779
+ function updateAdaptiveRender(ctx, scrollVelocity) {
1780
+ var _a3, _b, _c;
1781
+ const state = ctx.state;
1782
+ const adaptiveRender = state.props.adaptiveRender;
1783
+ const enterVelocity = (_a3 = adaptiveRender == null ? void 0 : adaptiveRender.enterVelocity) != null ? _a3 : DEFAULT_ENTER_VELOCITY;
1784
+ const exitVelocity = (_b = adaptiveRender == null ? void 0 : adaptiveRender.exitVelocity) != null ? _b : DEFAULT_EXIT_VELOCITY;
1785
+ const exitDelay = (_c = adaptiveRender == null ? void 0 : adaptiveRender.exitDelay) != null ? _c : DEFAULT_EXIT_DELAY;
1786
+ const currentMode = peek$(ctx, "adaptiveRender");
1787
+ const threshold = currentMode === "light" ? exitVelocity : enterVelocity;
1788
+ const nextMode = Math.abs(scrollVelocity) > threshold ? "light" : "normal";
1789
+ const previousMode = state.timeoutAdaptiveRender !== void 0 ? "normal" : currentMode;
1790
+ if (nextMode !== previousMode) {
1791
+ if (nextMode === "light") {
1792
+ setAdaptiveRender(ctx, "light");
1793
+ scheduleAdaptiveRenderExit(ctx, exitDelay);
1794
+ } else if (currentMode === "light") {
1795
+ scheduleAdaptiveRenderExit(ctx, exitDelay);
1796
+ }
1797
+ }
1798
+ }
1799
+
1800
+ // src/utils/getEffectiveDrawDistance.ts
1801
+ var INITIAL_DRAW_DISTANCE = 100;
1802
+ function getEffectiveDrawDistance(ctx) {
1803
+ const drawDistance = ctx.state.props.drawDistance;
1804
+ return peek$(ctx, "readyToRender") ? drawDistance : Math.min(drawDistance, INITIAL_DRAW_DISTANCE);
1805
+ }
1806
+
1683
1807
  // src/utils/setInitialRenderState.ts
1684
1808
  function setInitialRenderState(ctx, {
1685
1809
  didLayout,
@@ -1699,6 +1823,13 @@ function setInitialRenderState(ctx, {
1699
1823
  const isReadyToRender = Boolean(state.didContainersLayout && state.didFinishInitialScroll);
1700
1824
  if (isReadyToRender && !peek$(ctx, "readyToRender")) {
1701
1825
  set$(ctx, "readyToRender", true);
1826
+ setAdaptiveRender(ctx, "normal");
1827
+ if (state.props.drawDistance > INITIAL_DRAW_DISTANCE) {
1828
+ requestAnimationFrame(() => {
1829
+ var _a3;
1830
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
1831
+ });
1832
+ }
1702
1833
  if (onLoad) {
1703
1834
  onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1704
1835
  }
@@ -1773,204 +1904,9 @@ function finishInitialScroll(ctx, options) {
1773
1904
  complete();
1774
1905
  }
1775
1906
 
1776
- // src/core/calculateOffsetForIndex.ts
1777
- function calculateOffsetForIndex(ctx, index) {
1778
- const state = ctx.state;
1779
- return index !== void 0 ? state.positions[index] || 0 : 0;
1780
- }
1781
-
1782
- // src/core/getTopOffsetAdjustment.ts
1783
- function getTopOffsetAdjustment(ctx) {
1784
- return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
1785
- }
1786
-
1787
- // src/utils/getId.ts
1788
- function getId(state, index) {
1789
- const { data, keyExtractor } = state.props;
1790
- if (!data) {
1791
- return "";
1792
- }
1793
- const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
1794
- const id = ret;
1795
- state.idCache[index] = id;
1796
- return id;
1797
- }
1798
-
1799
- // src/core/addTotalSize.ts
1800
- function addTotalSize(ctx, key, add, notifyTotalSize = true) {
1801
- const state = ctx.state;
1802
- const prevTotalSize = state.totalSize;
1803
- let totalSize = state.totalSize;
1804
- if (key === null) {
1805
- totalSize = add;
1806
- if (state.timeoutSetPaddingTop) {
1807
- clearTimeout(state.timeoutSetPaddingTop);
1808
- state.timeoutSetPaddingTop = void 0;
1809
- }
1810
- } else {
1811
- totalSize += add;
1812
- }
1813
- if (prevTotalSize !== totalSize) {
1814
- if (!IsNewArchitecture && state.initialScroll && totalSize < prevTotalSize) {
1815
- state.pendingTotalSize = totalSize;
1816
- } else {
1817
- state.pendingTotalSize = void 0;
1818
- state.totalSize = totalSize;
1819
- if (notifyTotalSize) {
1820
- set$(ctx, "totalSize", totalSize);
1821
- }
1822
- }
1823
- } else if (notifyTotalSize && ctx.values.get("totalSize") !== totalSize) {
1824
- set$(ctx, "totalSize", totalSize);
1825
- }
1826
- }
1827
-
1828
- // src/core/setSize.ts
1829
- function setSize(ctx, itemKey, size, notifyTotalSize = true) {
1830
- const state = ctx.state;
1831
- const { sizes } = state;
1832
- const previousSize = sizes.get(itemKey);
1833
- const diff = previousSize !== void 0 ? size - previousSize : size;
1834
- if (diff !== 0) {
1835
- addTotalSize(ctx, itemKey, diff, notifyTotalSize);
1836
- }
1837
- sizes.set(itemKey, size);
1838
- }
1839
-
1840
- // src/utils/getItemSize.ts
1841
- function getKnownOrFixedSize(ctx, key, index, data, resolved) {
1842
- var _a3, _b;
1843
- const state = ctx.state;
1844
- const { getFixedItemSize, getItemType } = state.props;
1845
- let size = key ? state.sizesKnown.get(key) : void 0;
1846
- if (size === void 0 && key && getFixedItemSize) {
1847
- const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1848
- size = (resolved == null ? void 0 : resolved.didResolveFixedItemSize) ? resolved.fixedItemSize : getFixedItemSize(data, index, itemType);
1849
- if (size !== void 0) {
1850
- state.sizesKnown.set(key, size);
1851
- }
1852
- }
1853
- return size;
1854
- }
1855
- function getKnownOrFixedItemSize(ctx, index) {
1856
- const key = getId(ctx.state, index);
1857
- return getKnownOrFixedSize(ctx, key, index, ctx.state.props.data[index]);
1858
- }
1859
- function areKnownOrFixedItemSizesAvailable(ctx, startIndex, endIndex) {
1860
- for (let index = startIndex; index <= endIndex; index++) {
1861
- if (getKnownOrFixedItemSize(ctx, index) === void 0) {
1862
- return false;
1863
- }
1864
- }
1865
- return true;
1866
- }
1867
- function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize, notifyTotalSize, resolved) {
1868
- var _a3, _b, _c, _d;
1869
- const state = ctx.state;
1870
- const {
1871
- sizes,
1872
- averageSizes,
1873
- props: { estimatedItemSize, getItemType },
1874
- scrollingTo
1875
- } = state;
1876
- const sizeKnown = state.sizesKnown.get(key);
1877
- if (sizeKnown !== void 0) {
1878
- return sizeKnown;
1879
- }
1880
- let size;
1881
- const renderedSize = sizes.get(key);
1882
- if (preferCachedSize) {
1883
- if (renderedSize !== void 0) {
1884
- return renderedSize;
1885
- }
1886
- }
1887
- size = getKnownOrFixedSize(ctx, key, index, data, resolved);
1888
- if (size !== void 0) {
1889
- setSize(ctx, key, size, notifyTotalSize);
1890
- return size;
1891
- }
1892
- const itemType = (_b = resolved == null ? void 0 : resolved.itemType) != null ? _b : getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1893
- if (useAverageSize && !scrollingTo) {
1894
- const averageSizeForType = (_c = averageSizes[itemType]) == null ? void 0 : _c.avg;
1895
- if (averageSizeForType !== void 0) {
1896
- size = roundSize(averageSizeForType);
1897
- }
1898
- }
1899
- if (size === void 0 && renderedSize !== void 0) {
1900
- return renderedSize;
1901
- }
1902
- if (size === void 0 && useAverageSize && scrollingTo) {
1903
- const averageSizeForType = (_d = scrollingTo.averageSizeSnapshot) == null ? void 0 : _d[itemType];
1904
- if (averageSizeForType !== void 0) {
1905
- size = roundSize(averageSizeForType);
1906
- }
1907
- }
1908
- if (size === void 0) {
1909
- size = estimatedItemSize;
1910
- }
1911
- setSize(ctx, key, size, notifyTotalSize);
1912
- return size;
1913
- }
1914
- function getItemSizeAtIndex(ctx, index) {
1915
- if (index === void 0 || index < 0) {
1916
- return void 0;
1917
- }
1918
- const targetId = getId(ctx.state, index);
1919
- return getItemSize(ctx, targetId, index, ctx.state.props.data[index]);
1920
- }
1921
-
1922
- // src/core/calculateOffsetWithOffsetPosition.ts
1923
- function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1924
- var _a3;
1925
- const state = ctx.state;
1926
- const { index, viewOffset, viewPosition } = params;
1927
- let offset = offsetParam;
1928
- if (viewOffset) {
1929
- offset -= viewOffset;
1930
- }
1931
- if (index !== void 0) {
1932
- const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
1933
- if (topOffsetAdjustment) {
1934
- offset += topOffsetAdjustment;
1935
- }
1936
- }
1937
- if (viewPosition !== void 0 && index !== void 0) {
1938
- const dataLength = state.props.data.length;
1939
- if (dataLength === 0) {
1940
- return offset;
1941
- }
1942
- const isOutOfBounds = index < 0 || index >= dataLength;
1943
- const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
1944
- const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1945
- const trailingInset = getContentInsetEnd(ctx);
1946
- offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1947
- if (!isOutOfBounds && index === state.props.data.length - 1) {
1948
- const footerSize = peek$(ctx, "footerSize") || 0;
1949
- offset += footerSize;
1950
- }
1951
- }
1952
- return offset;
1953
- }
1954
-
1955
- // src/core/clampScrollOffset.ts
1956
- function clampScrollOffset(ctx, offset, scrollTarget) {
1957
- const state = ctx.state;
1958
- const contentSize = getContentSize(ctx);
1959
- let clampedOffset = offset;
1960
- if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform.OS !== "android" || state.lastLayout)) {
1961
- const baseMaxOffset = Math.max(0, contentSize - state.scrollLength);
1962
- const viewOffset = scrollTarget == null ? void 0 : scrollTarget.viewOffset;
1963
- const extraEndOffset = typeof viewOffset === "number" && viewOffset < 0 ? -viewOffset : 0;
1964
- const maxOffset = baseMaxOffset + extraEndOffset;
1965
- clampedOffset = Math.min(offset, maxOffset);
1966
- }
1967
- clampedOffset = Math.max(0, clampedOffset);
1968
- return clampedOffset;
1969
- }
1970
-
1971
- // src/core/finishScrollTo.ts
1972
- function finishScrollTo(ctx) {
1973
- var _a3, _b;
1907
+ // src/core/finishScrollTo.ts
1908
+ function finishScrollTo(ctx) {
1909
+ var _a3, _b;
1974
1910
  const state = ctx.state;
1975
1911
  if (state == null ? void 0 : state.scrollingTo) {
1976
1912
  const resolvePendingScroll = state.pendingScrollResolve;
@@ -2133,65 +2069,374 @@ function checkFinishedScrollFallback(ctx) {
2133
2069
  state,
2134
2070
  isStillScrollingTo
2135
2071
  );
2136
- const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
2137
- const canFinishAfterSilentNativeDispatch = Platform.OS === "android" && silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
2138
- const shouldRetrySilentInitialNativeScroll = Platform.OS === "android" && canFinishAfterSilentNativeDispatch && !initialScrollCompletion.didRetrySilentInitialScroll(state);
2139
- const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
2140
- const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
2141
- const shouldRetryUnalignedEndScroll = Platform.OS === "ios" && !isStillScrollingTo.isInitialScroll && isEndAlignedLastItemTarget(ctx, isStillScrollingTo) && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
2142
- if (shouldRetrySilentInitialNativeScroll) {
2143
- const targetOffset = (_b = (_a3 = getInitialScrollWatchdogTargetOffset(state)) != null ? _a3 : isStillScrollingTo.targetOffset) != null ? _b : 0;
2144
- const jiggleOffset = targetOffset >= SILENT_INITIAL_SCROLL_TARGET_EPSILON ? targetOffset - SILENT_INITIAL_SCROLL_TARGET_EPSILON : targetOffset + SILENT_INITIAL_SCROLL_TARGET_EPSILON;
2145
- initialScrollCompletion.markSilentInitialScrollRetry(state);
2146
- scrollToFallbackOffset(ctx, jiggleOffset);
2147
- requestAnimationFrame(() => {
2148
- scrollToFallbackOffset(ctx, targetOffset);
2149
- });
2150
- scheduleFallbackCheck(SILENT_INITIAL_SCROLL_RETRY_DELAY_MS);
2151
- } else if (shouldRetryUnalignedEndScroll) {
2152
- scrollToFallbackOffset(ctx, completionState.clampedTargetOffset);
2153
- scheduleFallbackCheck(100);
2154
- } else if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
2155
- finishScrollTo(ctx);
2156
- } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
2157
- const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
2158
- scrollToFallbackOffset(ctx, targetOffset);
2159
- scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2160
- } else {
2161
- scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2162
- }
2072
+ const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
2073
+ const canFinishAfterSilentNativeDispatch = Platform.OS === "android" && silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
2074
+ const shouldRetrySilentInitialNativeScroll = Platform.OS === "android" && canFinishAfterSilentNativeDispatch && !initialScrollCompletion.didRetrySilentInitialScroll(state);
2075
+ const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
2076
+ const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
2077
+ const shouldRetryUnalignedEndScroll = Platform.OS === "ios" && !isStillScrollingTo.isInitialScroll && isEndAlignedLastItemTarget(ctx, isStillScrollingTo) && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
2078
+ if (shouldRetrySilentInitialNativeScroll) {
2079
+ const targetOffset = (_b = (_a3 = getInitialScrollWatchdogTargetOffset(state)) != null ? _a3 : isStillScrollingTo.targetOffset) != null ? _b : 0;
2080
+ const jiggleOffset = targetOffset >= SILENT_INITIAL_SCROLL_TARGET_EPSILON ? targetOffset - SILENT_INITIAL_SCROLL_TARGET_EPSILON : targetOffset + SILENT_INITIAL_SCROLL_TARGET_EPSILON;
2081
+ initialScrollCompletion.markSilentInitialScrollRetry(state);
2082
+ scrollToFallbackOffset(ctx, jiggleOffset);
2083
+ requestAnimationFrame(() => {
2084
+ scrollToFallbackOffset(ctx, targetOffset);
2085
+ });
2086
+ scheduleFallbackCheck(SILENT_INITIAL_SCROLL_RETRY_DELAY_MS);
2087
+ } else if (shouldRetryUnalignedEndScroll) {
2088
+ scrollToFallbackOffset(ctx, completionState.clampedTargetOffset);
2089
+ scheduleFallbackCheck(100);
2090
+ } else if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
2091
+ finishScrollTo(ctx);
2092
+ } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
2093
+ const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
2094
+ scrollToFallbackOffset(ctx, targetOffset);
2095
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2096
+ } else {
2097
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2098
+ }
2099
+ }
2100
+ };
2101
+ checkHasScrolled();
2102
+ }, initialDelay);
2103
+ }
2104
+
2105
+ // src/core/doScrollTo.native.ts
2106
+ function doScrollTo(ctx, params) {
2107
+ const state = ctx.state;
2108
+ const { animated, horizontal, isInitialScroll, offset } = params;
2109
+ const isAnimated = !!animated;
2110
+ const { refScroller } = state;
2111
+ const scroller = refScroller.current;
2112
+ if (!scroller) {
2113
+ return;
2114
+ }
2115
+ const isHorizontal = !!horizontal;
2116
+ const contentSize = isHorizontal ? getContentSize(ctx) : void 0;
2117
+ const nativeOffset = toNativeHorizontalOffset(state, offset, contentSize);
2118
+ scroller.scrollTo({
2119
+ animated: isAnimated,
2120
+ x: isHorizontal ? nativeOffset : 0,
2121
+ y: isHorizontal ? 0 : offset
2122
+ });
2123
+ if (isInitialScroll) {
2124
+ initialScrollCompletion.markInitialScrollNativeDispatch(state);
2125
+ }
2126
+ if (!isAnimated) {
2127
+ state.scroll = offset;
2128
+ checkFinishedScrollFallback(ctx);
2129
+ }
2130
+ }
2131
+
2132
+ // src/utils/requestAdjust.ts
2133
+ function requestAdjust(ctx, positionDiff, dataChanged) {
2134
+ const state = ctx.state;
2135
+ if (Math.abs(positionDiff) > 0.1) {
2136
+ const needsScrollWorkaround = Platform.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff;
2137
+ const doit = () => {
2138
+ if (needsScrollWorkaround) {
2139
+ doScrollTo(ctx, { horizontal: state.props.horizontal, offset: state.scroll });
2140
+ } else {
2141
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
2142
+ if (state.adjustingFromInitialMount) {
2143
+ state.adjustingFromInitialMount--;
2144
+ }
2145
+ }
2146
+ };
2147
+ state.scroll += positionDiff;
2148
+ state.scrollForNextCalculateItemsInView = void 0;
2149
+ const readyToRender = peek$(ctx, "readyToRender");
2150
+ if (readyToRender) {
2151
+ doit();
2152
+ if (Platform.OS !== "web") {
2153
+ const threshold = state.scroll - positionDiff / 2;
2154
+ if (!state.ignoreScrollFromMVCP) {
2155
+ state.ignoreScrollFromMVCP = {};
2156
+ }
2157
+ if (positionDiff > 0) {
2158
+ state.ignoreScrollFromMVCP.lt = threshold;
2159
+ } else {
2160
+ state.ignoreScrollFromMVCP.gt = threshold;
2161
+ }
2162
+ if (state.ignoreScrollFromMVCPTimeout) {
2163
+ clearTimeout(state.ignoreScrollFromMVCPTimeout);
2164
+ }
2165
+ const delay = needsScrollWorkaround ? 250 : 100;
2166
+ state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
2167
+ var _a3;
2168
+ state.ignoreScrollFromMVCP = void 0;
2169
+ const shouldForceUpdate = state.ignoreScrollFromMVCPIgnored && state.scrollProcessingEnabled !== false;
2170
+ if (shouldForceUpdate) {
2171
+ state.ignoreScrollFromMVCPIgnored = false;
2172
+ state.scrollPending = state.scroll;
2173
+ (_a3 = state.reprocessCurrentScroll) == null ? void 0 : _a3.call(state);
2174
+ }
2175
+ }, delay);
2176
+ }
2177
+ } else {
2178
+ state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2179
+ requestAnimationFrame(doit);
2180
+ }
2181
+ }
2182
+ }
2183
+
2184
+ // src/core/updateContentMetrics.ts
2185
+ var SCROLL_ADJUST_EPSILON = 0.1;
2186
+ function setContentLengthSignal(ctx, signalName, size) {
2187
+ if (peek$(ctx, signalName) !== size) {
2188
+ set$(ctx, signalName, size);
2189
+ updateContentMetricsState(ctx);
2190
+ }
2191
+ }
2192
+ function shouldAdjustForHeaderSizeChange(ctx, previousHeaderSize, nextHeaderSize) {
2193
+ const { didContainersLayout, didFinishInitialScroll, props, scroll, scrollingTo } = ctx.state;
2194
+ const sizeDiff = nextHeaderSize - previousHeaderSize;
2195
+ const leadingPadding = props.horizontal ? props.stylePaddingLeft : props.stylePaddingTop;
2196
+ const previousHeaderEnd = (leadingPadding || 0) + previousHeaderSize;
2197
+ return Platform.OS === "web" && props.maintainVisibleContentPosition.size && didContainersLayout && didFinishInitialScroll && !scrollingTo && scroll >= previousHeaderEnd - SCROLL_ADJUST_EPSILON && Math.abs(sizeDiff) > SCROLL_ADJUST_EPSILON;
2198
+ }
2199
+ function setHeaderSize(ctx, size) {
2200
+ const { state } = ctx;
2201
+ const previousHeaderSize = peek$(ctx, "headerSize") || 0;
2202
+ const didChange = previousHeaderSize !== size;
2203
+ const hasMeasuredOrEstimatedHeaderBaseline = state.didMeasureHeader || previousHeaderSize > SCROLL_ADJUST_EPSILON;
2204
+ if (didChange) {
2205
+ set$(ctx, "headerSize", size);
2206
+ updateContentMetricsState(ctx);
2207
+ if (hasMeasuredOrEstimatedHeaderBaseline && shouldAdjustForHeaderSizeChange(ctx, previousHeaderSize, size)) {
2208
+ requestAdjust(ctx, size - previousHeaderSize);
2209
+ }
2210
+ }
2211
+ state.didMeasureHeader = true;
2212
+ }
2213
+ function setFooterSize(ctx, size) {
2214
+ setContentLengthSignal(ctx, "footerSize", size);
2215
+ }
2216
+ function areInsetsEqual(left, right) {
2217
+ var _a3, _b, _c, _d, _e, _f, _g, _h;
2218
+ 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);
2219
+ }
2220
+ function setContentInsetOverride(ctx, inset) {
2221
+ const { state } = ctx;
2222
+ const previousInset = state.contentInsetOverride;
2223
+ const nextInset = inset != null ? inset : void 0;
2224
+ const didChange = !areInsetsEqual(previousInset, nextInset);
2225
+ state.contentInsetOverride = nextInset;
2226
+ if (didChange) {
2227
+ updateContentMetricsState(ctx);
2228
+ }
2229
+ return didChange;
2230
+ }
2231
+ function useLatestRef(value) {
2232
+ const ref = React2__namespace.useRef(value);
2233
+ ref.current = value;
2234
+ return ref;
2235
+ }
2236
+
2237
+ // src/hooks/useStableRenderComponent.tsx
2238
+ function useStableRenderComponent(renderComponent, mapProps) {
2239
+ const renderComponentRef = useLatestRef(renderComponent);
2240
+ const mapPropsRef = useLatestRef(mapProps);
2241
+ return React2__namespace.useMemo(
2242
+ () => React2__namespace.forwardRef(
2243
+ (props, ref) => {
2244
+ var _a3, _b;
2245
+ return (_b = (_a3 = renderComponentRef.current) == null ? void 0 : _a3.call(renderComponentRef, mapPropsRef.current(props, ref))) != null ? _b : null;
2246
+ }
2247
+ ),
2248
+ [mapPropsRef, renderComponentRef]
2249
+ );
2250
+ }
2251
+ var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
2252
+ const localRef = React2.useRef(null);
2253
+ const ref = refView != null ? refView : localRef;
2254
+ const { onLayout } = useOnLayoutSync({ onLayoutChange, ref });
2255
+ return /* @__PURE__ */ React2__namespace.createElement(ReactNative.View, { ...rest, onLayout, ref });
2256
+ };
2257
+
2258
+ // src/components/ListComponent.tsx
2259
+ var AlignItemsAtEndSpacer = typedMemo(function AlignItemsAtEndSpacer2({ horizontal }) {
2260
+ const [alignItemsAtEndPadding = 0] = useArr$(["alignItemsAtEndPadding"]);
2261
+ if (alignItemsAtEndPadding <= 0) {
2262
+ return null;
2263
+ }
2264
+ return /* @__PURE__ */ React2__namespace.createElement(
2265
+ View,
2266
+ {
2267
+ style: horizontal ? { flexShrink: 0, width: alignItemsAtEndPadding } : { flexShrink: 0, height: alignItemsAtEndPadding }
2268
+ },
2269
+ null
2270
+ );
2271
+ });
2272
+ var ListComponent = typedMemo(function ListComponent2({
2273
+ canRender,
2274
+ style,
2275
+ contentContainerStyle,
2276
+ horizontal,
2277
+ initialContentOffset,
2278
+ recycleItems,
2279
+ ItemSeparatorComponent,
2280
+ alignItemsAtEnd: _alignItemsAtEnd,
2281
+ onScroll: onScroll2,
2282
+ onLayout,
2283
+ ListHeaderComponent,
2284
+ ListHeaderComponentStyle,
2285
+ ListFooterComponent,
2286
+ ListFooterComponentStyle,
2287
+ ListEmptyComponent,
2288
+ getRenderedItem: getRenderedItem2,
2289
+ updateItemSize: updateItemSize2,
2290
+ refScrollView,
2291
+ renderScrollComponent,
2292
+ onLayoutFooter,
2293
+ scrollAdjustHandler,
2294
+ snapToIndices,
2295
+ stickyHeaderConfig,
2296
+ stickyHeaderIndices,
2297
+ useWindowScroll = false,
2298
+ ...rest
2299
+ }) {
2300
+ const ctx = useStateContext();
2301
+ const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
2302
+ const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
2303
+ const shouldRenderAlignItemsAtEndSpacer = ctx.state.props.alignItemsAtEndPaddingEnabled;
2304
+ const autoOtherAxisStyle = getAutoOtherAxisStyle({
2305
+ horizontal,
2306
+ needsOtherAxisSize: ctx.state.needsOtherAxisSize,
2307
+ otherAxisSize
2308
+ });
2309
+ const CustomScrollComponent = useStableRenderComponent(
2310
+ renderScrollComponent,
2311
+ (props, ref) => ({ ...props, ref })
2312
+ );
2313
+ const ScrollComponent = renderScrollComponent ? CustomScrollComponent : ListComponentScrollView;
2314
+ const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
2315
+ React2.useLayoutEffect(() => {
2316
+ if (!ListHeaderComponent) {
2317
+ setHeaderSize(ctx, 0);
2318
+ }
2319
+ if (!ListFooterComponent) {
2320
+ setFooterSize(ctx, 0);
2321
+ }
2322
+ }, [ListHeaderComponent, ListFooterComponent, ctx]);
2323
+ const onLayoutHeader = React2.useCallback(
2324
+ (rect) => {
2325
+ const size = rect[horizontal ? "width" : "height"];
2326
+ setHeaderSize(ctx, size);
2327
+ },
2328
+ [ctx, horizontal]
2329
+ );
2330
+ const onLayoutFooterInternal = React2.useCallback(
2331
+ (rect, fromLayoutEffect) => {
2332
+ const size = rect[horizontal ? "width" : "height"];
2333
+ setFooterSize(ctx, size);
2334
+ onLayoutFooter == null ? void 0 : onLayoutFooter(rect, fromLayoutEffect);
2335
+ },
2336
+ [ctx, horizontal, onLayoutFooter]
2337
+ );
2338
+ return /* @__PURE__ */ React2__namespace.createElement(
2339
+ SnapOrScroll,
2340
+ {
2341
+ ...rest,
2342
+ ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
2343
+ contentContainerStyle: [
2344
+ horizontal ? {
2345
+ height: "100%"
2346
+ } : {},
2347
+ contentContainerStyle
2348
+ ],
2349
+ contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
2350
+ horizontal,
2351
+ maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
2352
+ onLayout,
2353
+ onScroll: onScroll2,
2354
+ ref: refScrollView,
2355
+ ScrollComponent: snapToIndices ? ScrollComponent : void 0,
2356
+ style: autoOtherAxisStyle ? [autoOtherAxisStyle, style] : style
2357
+ },
2358
+ /* @__PURE__ */ React2__namespace.createElement(ScrollAdjust, null),
2359
+ ListHeaderComponent && /* @__PURE__ */ React2__namespace.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
2360
+ ListEmptyComponent && getComponent(ListEmptyComponent),
2361
+ shouldRenderAlignItemsAtEndSpacer && /* @__PURE__ */ React2__namespace.createElement(AlignItemsAtEndSpacer, { horizontal }),
2362
+ canRender && !ListEmptyComponent && /* @__PURE__ */ React2__namespace.createElement(
2363
+ Containers,
2364
+ {
2365
+ getRenderedItem: getRenderedItem2,
2366
+ horizontal,
2367
+ ItemSeparatorComponent,
2368
+ recycleItems,
2369
+ stickyHeaderConfig,
2370
+ updateItemSize: updateItemSize2
2371
+ }
2372
+ ),
2373
+ ListFooterComponent && /* @__PURE__ */ React2__namespace.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
2374
+ Platform.OS === "web" && /* @__PURE__ */ React2__namespace.createElement(WebAnchoredEndSpace, { horizontal }),
2375
+ IS_DEV && ENABLE_DEVMODE
2376
+ );
2377
+ });
2378
+ var WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH = 100;
2379
+ var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
2380
+ var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
2381
+ function useDevChecksImpl(props) {
2382
+ const ctx = useStateContext();
2383
+ const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
2384
+ React2.useEffect(() => {
2385
+ if (useWindowScroll && renderScrollComponent) {
2386
+ warnDevOnce(
2387
+ "useWindowScrollRenderScrollComponent",
2388
+ "useWindowScroll is not supported when renderScrollComponent is provided."
2389
+ );
2390
+ }
2391
+ }, [renderScrollComponent, useWindowScroll]);
2392
+ React2.useEffect(() => {
2393
+ if (!keyExtractor && !ctx.state.isFirst && ctx.state.didDataChange && !childrenMode) {
2394
+ warnDevOnce(
2395
+ "keyExtractor",
2396
+ "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."
2397
+ );
2398
+ }
2399
+ }, [childrenMode, ctx, keyExtractor]);
2400
+ React2.useEffect(() => {
2401
+ const state = ctx.state;
2402
+ const dataLength = state.props.data.length;
2403
+ const useWindowScrollResolved = state.props.useWindowScroll;
2404
+ if (Platform.OS !== "web" || useWindowScrollResolved || dataLength < WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH) {
2405
+ return;
2406
+ }
2407
+ const warnIfUnboundedOuterSize = () => {
2408
+ const readyToRender = peek$(ctx, "readyToRender");
2409
+ const numContainers = peek$(ctx, "numContainers") || 0;
2410
+ const totalSize = peek$(ctx, "totalSize") || 0;
2411
+ const scrollLength = ctx.state.scrollLength || 0;
2412
+ if (!readyToRender || totalSize <= 0 || scrollLength <= 0) {
2413
+ return;
2414
+ }
2415
+ const rendersAlmostEverything = numContainers >= Math.ceil(dataLength * WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO);
2416
+ const viewportMatchesContent = scrollLength >= totalSize * WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO;
2417
+ if (rendersAlmostEverything && viewportMatchesContent) {
2418
+ warnDevOnce(
2419
+ "webUnboundedOuterSize",
2420
+ "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."
2421
+ );
2163
2422
  }
2164
2423
  };
2165
- checkHasScrolled();
2166
- }, initialDelay);
2424
+ warnIfUnboundedOuterSize();
2425
+ const unsubscribe = [
2426
+ listen$(ctx, "numContainers", warnIfUnboundedOuterSize),
2427
+ listen$(ctx, "readyToRender", warnIfUnboundedOuterSize),
2428
+ listen$(ctx, "totalSize", warnIfUnboundedOuterSize)
2429
+ ];
2430
+ return () => {
2431
+ for (const unsub of unsubscribe) {
2432
+ unsub();
2433
+ }
2434
+ };
2435
+ }, [ctx]);
2167
2436
  }
2168
-
2169
- // src/core/doScrollTo.native.ts
2170
- function doScrollTo(ctx, params) {
2171
- const state = ctx.state;
2172
- const { animated, horizontal, isInitialScroll, offset } = params;
2173
- const isAnimated = !!animated;
2174
- const { refScroller } = state;
2175
- const scroller = refScroller.current;
2176
- if (!scroller) {
2177
- return;
2178
- }
2179
- const isHorizontal = !!horizontal;
2180
- const contentSize = isHorizontal ? getContentSize(ctx) : void 0;
2181
- const nativeOffset = toNativeHorizontalOffset(state, offset, contentSize);
2182
- scroller.scrollTo({
2183
- animated: isAnimated,
2184
- x: isHorizontal ? nativeOffset : 0,
2185
- y: isHorizontal ? 0 : offset
2186
- });
2187
- if (isInitialScroll) {
2188
- initialScrollCompletion.markInitialScrollNativeDispatch(state);
2189
- }
2190
- if (!isAnimated) {
2191
- state.scroll = offset;
2192
- checkFinishedScrollFallback(ctx);
2193
- }
2437
+ function useDevChecksNoop(_props) {
2194
2438
  }
2439
+ var useDevChecks = IS_DEV ? useDevChecksImpl : useDevChecksNoop;
2195
2440
 
2196
2441
  // src/core/doMaintainScrollAtEnd.ts
2197
2442
  function doMaintainScrollAtEnd(ctx) {
@@ -2215,9 +2460,12 @@ function doMaintainScrollAtEnd(ctx) {
2215
2460
  state.scroll = 0;
2216
2461
  }
2217
2462
  if (!state.maintainingScrollAtEnd) {
2218
- state.maintainingScrollAtEnd = true;
2463
+ const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
2464
+ const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
2465
+ state.maintainingScrollAtEnd = pendingState;
2219
2466
  requestAnimationFrame(() => {
2220
2467
  if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
2468
+ state.maintainingScrollAtEnd = activeState;
2221
2469
  const scroller = refScroller.current;
2222
2470
  if (state.props.horizontal && isHorizontalRTL(state)) {
2223
2471
  const currentContentSize = getContentSize(ctx);
@@ -2235,12 +2483,14 @@ function doMaintainScrollAtEnd(ctx) {
2235
2483
  }
2236
2484
  setTimeout(
2237
2485
  () => {
2238
- state.maintainingScrollAtEnd = false;
2486
+ if (state.maintainingScrollAtEnd === activeState) {
2487
+ state.maintainingScrollAtEnd = void 0;
2488
+ }
2239
2489
  },
2240
2490
  maintainScrollAtEnd.animated ? 500 : 0
2241
2491
  );
2242
- } else {
2243
- state.maintainingScrollAtEnd = false;
2492
+ } else if (state.maintainingScrollAtEnd === pendingState) {
2493
+ state.maintainingScrollAtEnd = void 0;
2244
2494
  }
2245
2495
  });
2246
2496
  }
@@ -2249,58 +2499,6 @@ function doMaintainScrollAtEnd(ctx) {
2249
2499
  return false;
2250
2500
  }
2251
2501
 
2252
- // src/utils/requestAdjust.ts
2253
- function requestAdjust(ctx, positionDiff, dataChanged) {
2254
- const state = ctx.state;
2255
- if (Math.abs(positionDiff) > 0.1) {
2256
- const needsScrollWorkaround = Platform.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff;
2257
- const doit = () => {
2258
- if (needsScrollWorkaround) {
2259
- doScrollTo(ctx, { horizontal: state.props.horizontal, offset: state.scroll });
2260
- } else {
2261
- state.scrollAdjustHandler.requestAdjust(positionDiff);
2262
- if (state.adjustingFromInitialMount) {
2263
- state.adjustingFromInitialMount--;
2264
- }
2265
- }
2266
- };
2267
- state.scroll += positionDiff;
2268
- state.scrollForNextCalculateItemsInView = void 0;
2269
- const readyToRender = peek$(ctx, "readyToRender");
2270
- if (readyToRender) {
2271
- doit();
2272
- if (Platform.OS !== "web") {
2273
- const threshold = state.scroll - positionDiff / 2;
2274
- if (!state.ignoreScrollFromMVCP) {
2275
- state.ignoreScrollFromMVCP = {};
2276
- }
2277
- if (positionDiff > 0) {
2278
- state.ignoreScrollFromMVCP.lt = threshold;
2279
- } else {
2280
- state.ignoreScrollFromMVCP.gt = threshold;
2281
- }
2282
- if (state.ignoreScrollFromMVCPTimeout) {
2283
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
2284
- }
2285
- const delay = needsScrollWorkaround ? 250 : 100;
2286
- state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
2287
- var _a3;
2288
- state.ignoreScrollFromMVCP = void 0;
2289
- const shouldForceUpdate = state.ignoreScrollFromMVCPIgnored && state.scrollProcessingEnabled !== false;
2290
- if (shouldForceUpdate) {
2291
- state.ignoreScrollFromMVCPIgnored = false;
2292
- state.scrollPending = state.scroll;
2293
- (_a3 = state.reprocessCurrentScroll) == null ? void 0 : _a3.call(state);
2294
- }
2295
- }, delay);
2296
- }
2297
- } else {
2298
- state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
2299
- requestAnimationFrame(doit);
2300
- }
2301
- }
2302
- }
2303
-
2304
2502
  // src/core/mvcp.ts
2305
2503
  var MVCP_POSITION_EPSILON = 0.1;
2306
2504
  var MVCP_ANCHOR_LOCK_TTL_MS = 300;
@@ -2449,6 +2647,10 @@ function prepareMVCP(ctx, dataChanged) {
2449
2647
  const now = Date.now();
2450
2648
  const enableMVCPAnchorLock = isWeb && (!!dataChanged || !!state.mvcpAnchorLock);
2451
2649
  const scrollingTo = state.scrollingTo;
2650
+ if (isWeb && dataChanged && state.pendingScrollToEnd && scrollingTo === void 0) {
2651
+ state.mvcpAnchorLock = void 0;
2652
+ return void 0;
2653
+ }
2452
2654
  const anchorLock = isWeb ? resolveAnchorLock(state, enableMVCPAnchorLock, mvcpData, now) : void 0;
2453
2655
  let prevPosition;
2454
2656
  let targetId;
@@ -2584,7 +2786,7 @@ function prepareMVCP(ctx, dataChanged) {
2584
2786
  return;
2585
2787
  }
2586
2788
  if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
2587
- const shouldSkipAdjustForMaintainedEnd = state.maintainingScrollAtEnd && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
2789
+ const shouldSkipAdjustForMaintainedEnd = (state.maintainingScrollAtEnd === "pending-animated" || state.maintainingScrollAtEnd === "animated") && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
2588
2790
  if (!shouldSkipAdjustForMaintainedEnd) {
2589
2791
  requestAdjust(ctx, positionDiff, dataChanged && mvcpData);
2590
2792
  }
@@ -2598,6 +2800,45 @@ var flushSync = (fn) => {
2598
2800
  fn();
2599
2801
  };
2600
2802
 
2803
+ // src/utils/getScrollVelocity.ts
2804
+ var getScrollVelocity = (state) => {
2805
+ const { scrollHistory } = state;
2806
+ const newestIndex = scrollHistory.length - 1;
2807
+ if (newestIndex < 1) {
2808
+ return 0;
2809
+ }
2810
+ const newest = scrollHistory[newestIndex];
2811
+ const now = Date.now();
2812
+ let direction = 0;
2813
+ for (let i = newestIndex; i > 0; i--) {
2814
+ const delta = scrollHistory[i].scroll - scrollHistory[i - 1].scroll;
2815
+ if (delta !== 0) {
2816
+ direction = Math.sign(delta);
2817
+ break;
2818
+ }
2819
+ }
2820
+ if (direction === 0) {
2821
+ return 0;
2822
+ }
2823
+ let oldest = newest;
2824
+ for (let i = newestIndex - 1; i >= 0; i--) {
2825
+ const current = scrollHistory[i];
2826
+ const next = scrollHistory[i + 1];
2827
+ const delta = next.scroll - current.scroll;
2828
+ const deltaSign = Math.sign(delta);
2829
+ if (deltaSign !== 0 && deltaSign !== direction) {
2830
+ break;
2831
+ }
2832
+ if (now - current.time > 1e3) {
2833
+ break;
2834
+ }
2835
+ oldest = current;
2836
+ }
2837
+ const scrollDiff = newest.scroll - oldest.scroll;
2838
+ const timeDiff = newest.time - oldest.time;
2839
+ return timeDiff > 0 ? scrollDiff / timeDiff : 0;
2840
+ };
2841
+
2601
2842
  // src/core/updateScroll.ts
2602
2843
  function updateScroll(ctx, newScroll, forceUpdate, options) {
2603
2844
  var _a3;
@@ -2623,6 +2864,8 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
2623
2864
  if (scrollHistory.length > 5) {
2624
2865
  scrollHistory.shift();
2625
2866
  }
2867
+ const scrollVelocity = getScrollVelocity(state);
2868
+ updateAdaptiveRender(ctx, scrollVelocity);
2626
2869
  if (ignoreScrollFromMVCP && !scrollingTo) {
2627
2870
  const { lt, gt } = ignoreScrollFromMVCP;
2628
2871
  if (lt && newScroll < lt || gt && newScroll > gt) {
@@ -2646,7 +2889,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
2646
2889
  state.lastScrollDelta = scrollDelta;
2647
2890
  const runCalculateItems = () => {
2648
2891
  var _a4;
2649
- (_a4 = state.triggerCalculateItemsInView) == null ? void 0 : _a4.call(state, { doMVCP: scrollingTo !== void 0 });
2892
+ (_a4 = state.triggerCalculateItemsInView) == null ? void 0 : _a4.call(state, { doMVCP: scrollingTo !== void 0, scrollVelocity });
2650
2893
  checkThresholds(ctx);
2651
2894
  };
2652
2895
  if (scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength && !state.pendingNativeMVCPAdjust) {
@@ -3581,9 +3824,32 @@ function initializeInitialScrollOnMount(ctx, options) {
3581
3824
  }
3582
3825
  function handleInitialScrollDataChange(ctx, options) {
3583
3826
  var _a3, _b, _c;
3584
- const { dataLength, didDataChange, initialScrollAtEnd, stylePaddingBottom, useBootstrapInitialScroll } = options;
3827
+ const {
3828
+ dataLength,
3829
+ didDataChange,
3830
+ initialScrollAtEnd,
3831
+ latestInitialScroll,
3832
+ latestInitialScrollSessionKind,
3833
+ stylePaddingBottom,
3834
+ useBootstrapInitialScroll
3835
+ } = options;
3585
3836
  const state = ctx.state;
3586
3837
  const previousDataLength = (_b = (_a3 = state.initialScrollSession) == null ? void 0 : _a3.previousDataLength) != null ? _b : 0;
3838
+ const isFirstNonEmptyData = !state.hasHadNonEmptyData && dataLength > 0;
3839
+ if (dataLength > 0) {
3840
+ state.hasHadNonEmptyData = true;
3841
+ }
3842
+ if (isFirstNonEmptyData) {
3843
+ if (latestInitialScroll) {
3844
+ setInitialScrollTarget(state, latestInitialScroll);
3845
+ setInitialScrollSession(state, {
3846
+ kind: latestInitialScrollSessionKind,
3847
+ previousDataLength
3848
+ });
3849
+ } else {
3850
+ clearPreservedInitialScrollTarget(state);
3851
+ }
3852
+ }
3587
3853
  if (state.initialScrollSession) {
3588
3854
  state.initialScrollSession.previousDataLength = dataLength;
3589
3855
  }
@@ -3807,45 +4073,6 @@ function updateTotalSize(ctx) {
3807
4073
  }
3808
4074
  }
3809
4075
 
3810
- // src/utils/getScrollVelocity.ts
3811
- var getScrollVelocity = (state) => {
3812
- const { scrollHistory } = state;
3813
- const newestIndex = scrollHistory.length - 1;
3814
- if (newestIndex < 1) {
3815
- return 0;
3816
- }
3817
- const newest = scrollHistory[newestIndex];
3818
- const now = Date.now();
3819
- let direction = 0;
3820
- for (let i = newestIndex; i > 0; i--) {
3821
- const delta = scrollHistory[i].scroll - scrollHistory[i - 1].scroll;
3822
- if (delta !== 0) {
3823
- direction = Math.sign(delta);
3824
- break;
3825
- }
3826
- }
3827
- if (direction === 0) {
3828
- return 0;
3829
- }
3830
- let oldest = newest;
3831
- for (let i = newestIndex - 1; i >= 0; i--) {
3832
- const current = scrollHistory[i];
3833
- const next = scrollHistory[i + 1];
3834
- const delta = next.scroll - current.scroll;
3835
- const deltaSign = Math.sign(delta);
3836
- if (deltaSign !== 0 && deltaSign !== direction) {
3837
- break;
3838
- }
3839
- if (now - current.time > 1e3) {
3840
- break;
3841
- }
3842
- oldest = current;
3843
- }
3844
- const scrollDiff = newest.scroll - oldest.scroll;
3845
- const timeDiff = newest.time - oldest.time;
3846
- return timeDiff > 0 ? scrollDiff / timeDiff : 0;
3847
- };
3848
-
3849
4076
  // src/utils/updateSnapToOffsets.ts
3850
4077
  function updateSnapToOffsets(ctx) {
3851
4078
  const state = ctx.state;
@@ -4166,7 +4393,7 @@ function areViewabilityAmountTokensEqual(prev, next) {
4166
4393
  }
4167
4394
  function computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
4168
4395
  const { sizes, scroll: scrollState } = state;
4169
- const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
4396
+ const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
4170
4397
  const { itemVisiblePercentThreshold, viewAreaCoveragePercentThreshold } = viewabilityConfig;
4171
4398
  const viewAreaMode = viewAreaCoveragePercentThreshold != null;
4172
4399
  const viewablePercentThreshold = viewAreaMode ? viewAreaCoveragePercentThreshold : itemVisiblePercentThreshold;
@@ -4581,7 +4808,7 @@ function updateViewabilityForCachedRange(ctx, viewabilityConfigCallbackPairs, sc
4581
4808
  function calculateItemsInView(ctx, params = {}) {
4582
4809
  const state = ctx.state;
4583
4810
  batchedUpdates(() => {
4584
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
4811
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t;
4585
4812
  const {
4586
4813
  columns,
4587
4814
  containerItemKeys,
@@ -4590,14 +4817,7 @@ function calculateItemsInView(ctx, params = {}) {
4590
4817
  indexByKey,
4591
4818
  minIndexSizeChanged,
4592
4819
  positions,
4593
- props: {
4594
- alwaysRenderIndicesArr,
4595
- alwaysRenderIndicesSet,
4596
- drawDistance,
4597
- getItemType,
4598
- keyExtractor,
4599
- onStickyHeaderChange
4600
- },
4820
+ props: { alwaysRenderIndicesArr, alwaysRenderIndicesSet, getItemType, keyExtractor, onStickyHeaderChange },
4601
4821
  scrollForNextCalculateItemsInView,
4602
4822
  scrollLength,
4603
4823
  sizes,
@@ -4609,6 +4829,7 @@ function calculateItemsInView(ctx, params = {}) {
4609
4829
  const stickyHeaderIndicesSet = state.props.stickyHeaderIndicesSet || /* @__PURE__ */ new Set();
4610
4830
  const alwaysRenderArr = alwaysRenderIndicesArr || [];
4611
4831
  const alwaysRenderSet = alwaysRenderIndicesSet || /* @__PURE__ */ new Set();
4832
+ const drawDistance = getEffectiveDrawDistance(ctx);
4612
4833
  const { dataChanged, doMVCP, forceFullItemPositions } = params;
4613
4834
  const bootstrapInitialScrollState = ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap" ? state.initialScrollSession.bootstrap : void 0;
4614
4835
  const suppressInitialScrollSideEffects = !!bootstrapInitialScrollState;
@@ -4617,12 +4838,12 @@ function calculateItemsInView(ctx, params = {}) {
4617
4838
  return;
4618
4839
  }
4619
4840
  let totalSize = getContentSize(ctx);
4620
- const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
4841
+ const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "alignItemsAtEndPadding") + peek$(ctx, "headerSize");
4621
4842
  const numColumns = peek$(ctx, "numColumns");
4622
- const speed = getScrollVelocity(state);
4843
+ const speed = (_b = params.scrollVelocity) != null ? _b : getScrollVelocity(state);
4623
4844
  const scrollExtra = 0;
4624
4845
  const { initialScroll, queuedInitialLayout } = state;
4625
- const scrollState = suppressInitialScrollSideEffects ? (_b = bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.scroll) != null ? _b : state.scroll : !queuedInitialLayout && hasActiveInitialScroll(state) && initialScroll ? (
4846
+ const scrollState = suppressInitialScrollSideEffects ? (_c = bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.scroll) != null ? _c : state.scroll : !queuedInitialLayout && hasActiveInitialScroll(state) && initialScroll ? (
4626
4847
  // Before the initial layout settles, keep viewport math anchored to the
4627
4848
  // current initial-scroll target instead of transient native adjustments.
4628
4849
  resolveInitialScrollOffset(ctx, initialScroll)
@@ -4646,19 +4867,25 @@ function calculateItemsInView(ctx, params = {}) {
4646
4867
  };
4647
4868
  updateScroll2(scrollState);
4648
4869
  const previousStickyIndex = peek$(ctx, "activeStickyIndex");
4649
- const currentStickyIdx = stickyHeaderIndicesArr.length > 0 ? findCurrentStickyIndex(stickyHeaderIndicesArr, scroll, state) : -1;
4650
- const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyHeaderIndicesArr[currentStickyIdx] : -1;
4651
- const stickyIndexDidChange = previousStickyIndex !== nextActiveStickyIndex;
4652
- if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
4653
- set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
4654
- }
4655
- const shouldNotifyStickyHeaderChange = !!onStickyHeaderChange && stickyHeaderIndicesArr.length > 0 && stickyIndexDidChange;
4656
- const finishCalculateItemsInView = shouldNotifyStickyHeaderChange ? () => {
4657
- const item = data[nextActiveStickyIndex];
4658
- if (item !== void 0) {
4659
- onStickyHeaderChange == null ? void 0 : onStickyHeaderChange({ index: nextActiveStickyIndex, item });
4870
+ const resolveStickyState = () => {
4871
+ const currentStickyIdx = stickyHeaderIndicesArr.length > 0 ? findCurrentStickyIndex(stickyHeaderIndicesArr, scroll, state) : -1;
4872
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyHeaderIndicesArr[currentStickyIdx] : -1;
4873
+ const stickyIndexDidChange = previousStickyIndex !== nextActiveStickyIndex;
4874
+ if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
4875
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
4660
4876
  }
4661
- } : void 0;
4877
+ const shouldNotifyStickyHeaderChange = !!onStickyHeaderChange && stickyHeaderIndicesArr.length > 0 && stickyIndexDidChange;
4878
+ return {
4879
+ currentStickyIdx,
4880
+ finishCalculateItemsInView: shouldNotifyStickyHeaderChange ? () => {
4881
+ const item = data[nextActiveStickyIndex];
4882
+ if (item !== void 0) {
4883
+ onStickyHeaderChange == null ? void 0 : onStickyHeaderChange({ index: nextActiveStickyIndex, item });
4884
+ }
4885
+ } : void 0
4886
+ };
4887
+ };
4888
+ let stickyState = dataChanged ? void 0 : resolveStickyState();
4662
4889
  let scrollBufferTop = drawDistance;
4663
4890
  let scrollBufferBottom = drawDistance;
4664
4891
  if (speed > 0 || speed === 0 && scroll < Math.max(50, drawDistance)) {
@@ -4691,7 +4918,7 @@ function calculateItemsInView(ctx, params = {}) {
4691
4918
  scrollBottom
4692
4919
  );
4693
4920
  }
4694
- finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
4921
+ (_d = stickyState == null ? void 0 : stickyState.finishCalculateItemsInView) == null ? void 0 : _d.call(stickyState);
4695
4922
  return;
4696
4923
  }
4697
4924
  }
@@ -4700,7 +4927,7 @@ function calculateItemsInView(ctx, params = {}) {
4700
4927
  if (dataChanged) {
4701
4928
  resetLayoutCachesForDataChange(state);
4702
4929
  }
4703
- const startIndex = forceFullItemPositions || dataChanged ? 0 : (_c = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _c : 0;
4930
+ const startIndex = forceFullItemPositions || dataChanged ? 0 : (_e = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _e : 0;
4704
4931
  const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
4705
4932
  updateItemPositions(ctx, dataChanged, {
4706
4933
  doMVCP,
@@ -4726,21 +4953,24 @@ function calculateItemsInView(ctx, params = {}) {
4726
4953
  }
4727
4954
  }
4728
4955
  const scrollBeforeMVCP = state.scroll;
4729
- const scrollAdjustPendingBeforeMVCP = (_d = peek$(ctx, "scrollAdjustPending")) != null ? _d : 0;
4956
+ const scrollAdjustPendingBeforeMVCP = (_f = peek$(ctx, "scrollAdjustPending")) != null ? _f : 0;
4730
4957
  checkMVCP == null ? void 0 : checkMVCP();
4731
- const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_e = peek$(ctx, "scrollAdjustPending")) != null ? _e : 0) !== scrollAdjustPendingBeforeMVCP);
4958
+ const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_g = peek$(ctx, "scrollAdjustPending")) != null ? _g : 0) !== scrollAdjustPendingBeforeMVCP);
4732
4959
  if (didMVCPAdjustScroll && initialScroll) {
4733
4960
  updateScroll2(state.scroll);
4734
4961
  updateScrollRange();
4735
4962
  }
4963
+ if (dataChanged) {
4964
+ stickyState = resolveStickyState();
4965
+ }
4736
4966
  let startBuffered = null;
4737
4967
  let startBufferedId = null;
4738
4968
  let endBuffered = null;
4739
- let loopStart = (_f = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _f : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
4969
+ let loopStart = (_h = suppressInitialScrollSideEffects ? bootstrapInitialScrollState == null ? void 0 : bootstrapInitialScrollState.targetIndexSeed : void 0) != null ? _h : !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
4740
4970
  for (let i = loopStart; i >= 0; i--) {
4741
- const id = (_g = idCache[i]) != null ? _g : getId(state, i);
4971
+ const id = (_i = idCache[i]) != null ? _i : getId(state, i);
4742
4972
  const top = positions[i];
4743
- const size = (_h = sizes.get(id)) != null ? _h : getItemSize(ctx, id, i, data[i]);
4973
+ const size = (_j = sizes.get(id)) != null ? _j : getItemSize(ctx, id, i, data[i]);
4744
4974
  const bottom = top + size;
4745
4975
  if (bottom > scrollTopBuffered) {
4746
4976
  loopStart = i;
@@ -4775,8 +5005,8 @@ function calculateItemsInView(ctx, params = {}) {
4775
5005
  };
4776
5006
  const dataLength = data.length;
4777
5007
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
4778
- const id = (_i = idCache[i]) != null ? _i : getId(state, i);
4779
- const size = (_j = sizes.get(id)) != null ? _j : getItemSize(ctx, id, i, data[i]);
5008
+ const id = (_k = idCache[i]) != null ? _k : getId(state, i);
5009
+ const size = (_l = sizes.get(id)) != null ? _l : getItemSize(ctx, id, i, data[i]);
4780
5010
  const top = positions[i];
4781
5011
  if (!foundEnd) {
4782
5012
  trackVisibleRange(visibleRange, i, top, size, scroll, scrollBottom);
@@ -4832,7 +5062,7 @@ function calculateItemsInView(ctx, params = {}) {
4832
5062
  const needNewContainers = [];
4833
5063
  const needNewContainersSet = /* @__PURE__ */ new Set();
4834
5064
  for (let i = startBuffered; i <= endBuffered; i++) {
4835
- const id = (_k = idCache[i]) != null ? _k : getId(state, i);
5065
+ const id = (_m = idCache[i]) != null ? _m : getId(state, i);
4836
5066
  if (!containerItemKeys.has(id)) {
4837
5067
  needNewContainersSet.add(i);
4838
5068
  needNewContainers.push(i);
@@ -4841,7 +5071,7 @@ function calculateItemsInView(ctx, params = {}) {
4841
5071
  if (alwaysRenderArr.length > 0) {
4842
5072
  for (const index of alwaysRenderArr) {
4843
5073
  if (index < 0 || index >= dataLength) continue;
4844
- const id = (_l = idCache[index]) != null ? _l : getId(state, index);
5074
+ const id = (_n = idCache[index]) != null ? _n : getId(state, index);
4845
5075
  if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
4846
5076
  needNewContainersSet.add(index);
4847
5077
  needNewContainers.push(index);
@@ -4852,7 +5082,7 @@ function calculateItemsInView(ctx, params = {}) {
4852
5082
  handleStickyActivation(
4853
5083
  ctx,
4854
5084
  stickyHeaderIndicesArr,
4855
- currentStickyIdx,
5085
+ (_o = stickyState == null ? void 0 : stickyState.currentStickyIdx) != null ? _o : -1,
4856
5086
  needNewContainers,
4857
5087
  needNewContainersSet,
4858
5088
  startBuffered,
@@ -4878,7 +5108,7 @@ function calculateItemsInView(ctx, params = {}) {
4878
5108
  for (const allocation of availableContainerAllocations) {
4879
5109
  const i = allocation.itemIndex;
4880
5110
  const containerIndex = allocation.containerIndex;
4881
- const id = (_m = idCache[i]) != null ? _m : getId(state, i);
5111
+ const id = (_p = idCache[i]) != null ? _p : getId(state, i);
4882
5112
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
4883
5113
  if (oldKey && oldKey !== id) {
4884
5114
  containerItemKeys.delete(oldKey);
@@ -4889,7 +5119,7 @@ function calculateItemsInView(ctx, params = {}) {
4889
5119
  state.containerItemTypes.set(containerIndex, allocation.itemType);
4890
5120
  }
4891
5121
  containerItemKeys.set(id, containerIndex);
4892
- (_n = state.userScrollAnchorReset) == null ? void 0 : _n.keys.add(id);
5122
+ (_q = state.userScrollAnchorReset) == null ? void 0 : _q.keys.add(id);
4893
5123
  const containerSticky = `containerSticky${containerIndex}`;
4894
5124
  const isSticky = stickyHeaderIndicesSet.has(i);
4895
5125
  const isAlwaysRender = alwaysRenderSet.has(i);
@@ -4920,14 +5150,12 @@ function calculateItemsInView(ctx, params = {}) {
4920
5150
  if (state.userScrollAnchorReset) {
4921
5151
  if (state.userScrollAnchorReset.keys.size === 0) {
4922
5152
  state.userScrollAnchorReset = void 0;
4923
- } else {
4924
- state.userScrollAnchorReset.batchSize = state.userScrollAnchorReset.keys.size;
4925
5153
  }
4926
5154
  }
4927
5155
  if (alwaysRenderArr.length > 0) {
4928
5156
  for (const index of alwaysRenderArr) {
4929
5157
  if (index < 0 || index >= dataLength) continue;
4930
- const id = (_o = idCache[index]) != null ? _o : getId(state, index);
5158
+ const id = (_r = idCache[index]) != null ? _r : getId(state, index);
4931
5159
  const containerIndex = containerItemKeys.get(id);
4932
5160
  if (containerIndex !== void 0) {
4933
5161
  state.stickyContainerPool.add(containerIndex);
@@ -4941,7 +5169,7 @@ function calculateItemsInView(ctx, params = {}) {
4941
5169
  stickyHeaderIndicesArr,
4942
5170
  scroll,
4943
5171
  drawDistance,
4944
- currentStickyIdx,
5172
+ (_s = stickyState == null ? void 0 : stickyState.currentStickyIdx) != null ? _s : -1,
4945
5173
  pendingRemoval,
4946
5174
  alwaysRenderSet
4947
5175
  );
@@ -5002,7 +5230,7 @@ function calculateItemsInView(ctx, params = {}) {
5002
5230
  );
5003
5231
  }
5004
5232
  }
5005
- finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
5233
+ (_t = stickyState == null ? void 0 : stickyState.finishCalculateItemsInView) == null ? void 0 : _t.call(stickyState);
5006
5234
  });
5007
5235
  }
5008
5236
 
@@ -5085,8 +5313,9 @@ function doInitialAllocateContainers(ctx) {
5085
5313
  const state = ctx.state;
5086
5314
  const {
5087
5315
  scrollLength,
5088
- props: { data, drawDistance, getFixedItemSize, getItemType, numColumns, estimatedItemSize }
5316
+ props: { data, getFixedItemSize, getItemType, numColumns, estimatedItemSize }
5089
5317
  } = state;
5318
+ const drawDistance = getEffectiveDrawDistance(ctx);
5090
5319
  const hasContainers = peek$(ctx, "numContainers");
5091
5320
  if (scrollLength > 0 && data.length > 0 && !hasContainers) {
5092
5321
  let averageItemSize;
@@ -5097,12 +5326,12 @@ function doInitialAllocateContainers(ctx) {
5097
5326
  const item = data[i];
5098
5327
  if (item !== void 0) {
5099
5328
  const itemType = (_a3 = getItemType == null ? void 0 : getItemType(item, i)) != null ? _a3 : "";
5100
- totalSize += (_b = getFixedItemSize(item, i, itemType)) != null ? _b : estimatedItemSize;
5329
+ totalSize += ((_b = getFixedItemSize(item, i, itemType)) != null ? _b : estimatedItemSize) + ctx.scrollAxisGap;
5101
5330
  }
5102
5331
  }
5103
5332
  averageItemSize = totalSize / num;
5104
5333
  } else {
5105
- averageItemSize = estimatedItemSize;
5334
+ averageItemSize = estimatedItemSize + ctx.scrollAxisGap;
5106
5335
  }
5107
5336
  const numContainers = Math.max(
5108
5337
  1,
@@ -5157,6 +5386,7 @@ function handleLayout(ctx, layoutParam, setCanRender) {
5157
5386
  if (didChange) {
5158
5387
  state.scrollLength = scrollLength;
5159
5388
  state.otherAxisSize = otherAxisSize;
5389
+ updateContentMetricsState(ctx);
5160
5390
  state.lastBatchingAction = Date.now();
5161
5391
  state.scrollForNextCalculateItemsInView = void 0;
5162
5392
  if (scrollLength > 0) {
@@ -5397,28 +5627,12 @@ function updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment)
5397
5627
 
5398
5628
  // src/core/updateItemSize.ts
5399
5629
  function runOrScheduleMVCPRecalculate(ctx) {
5400
- var _a3, _b;
5630
+ var _a3;
5401
5631
  const state = ctx.state;
5402
5632
  if (state.userScrollAnchorReset !== void 0) {
5403
- const replacementBatchSize = (_a3 = state.userScrollAnchorReset.batchSize) != null ? _a3 : state.userScrollAnchorReset.keys.size;
5404
- const replacementMeasurementBatchThreshold = 3;
5405
- const shouldBatchReplacementMeasurements = replacementBatchSize > replacementMeasurementBatchThreshold;
5406
- if (shouldBatchReplacementMeasurements) {
5407
- if (state.queuedMVCPRecalculate === void 0) {
5408
- state.queuedMVCPRecalculate = requestAnimationFrame(() => {
5409
- var _a4;
5410
- state.queuedMVCPRecalculate = void 0;
5411
- calculateItemsInView(ctx);
5412
- if (((_a4 = state.userScrollAnchorReset) == null ? void 0 : _a4.keys.size) === 0) {
5413
- state.userScrollAnchorReset = void 0;
5414
- }
5415
- });
5416
- }
5417
- } else {
5418
- calculateItemsInView(ctx);
5419
- if (((_b = state.userScrollAnchorReset) == null ? void 0 : _b.keys.size) === 0) {
5420
- state.userScrollAnchorReset = void 0;
5421
- }
5633
+ calculateItemsInView(ctx);
5634
+ if (((_a3 = state.userScrollAnchorReset) == null ? void 0 : _a3.keys.size) === 0) {
5635
+ state.userScrollAnchorReset = void 0;
5422
5636
  }
5423
5637
  } else if (Platform.OS === "web") {
5424
5638
  if (!state.mvcpAnchorLock) {
@@ -5844,10 +6058,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
5844
6058
  startBuffered: state.startBuffered
5845
6059
  }),
5846
6060
  reportContentInset: (inset) => {
5847
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
5848
- const previousInset = state.contentInsetOverride;
5849
- state.contentInsetOverride = inset != null ? inset : void 0;
5850
- 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);
6061
+ const didChange = setContentInsetOverride(ctx, inset);
5851
6062
  updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
5852
6063
  if (didChange) {
5853
6064
  retargetActiveInitialScrollAtEnd(ctx);
@@ -5899,6 +6110,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
5899
6110
  scrollTo(ctx, params);
5900
6111
  return true;
5901
6112
  }),
6113
+ setItemSize: (itemKey, size) => {
6114
+ updateItemSize(ctx, itemKey, size);
6115
+ },
5902
6116
  setScrollProcessingEnabled: (enabled) => {
5903
6117
  state.scrollProcessingEnabled = enabled;
5904
6118
  },
@@ -6123,7 +6337,7 @@ var LegendList = typedMemo(
6123
6337
  })
6124
6338
  );
6125
6339
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
6126
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
6340
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
6127
6341
  const noopOnScroll = React2.useCallback((_event) => {
6128
6342
  }, []);
6129
6343
  if (props.recycleItems === void 0) {
@@ -6154,6 +6368,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6154
6368
  initialScrollAtEnd = false,
6155
6369
  initialScrollIndex: initialScrollIndexProp,
6156
6370
  initialScrollOffset: initialScrollOffsetProp,
6371
+ experimental_adaptiveRender,
6157
6372
  itemsAreEqual,
6158
6373
  keyExtractor: keyExtractorProp,
6159
6374
  ListEmptyComponent,
@@ -6203,10 +6418,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6203
6418
  ...restProps
6204
6419
  } = rest;
6205
6420
  const contentContainerStyleBase = StyleSheet.flatten(contentContainerStyleProp);
6206
- const shouldFlexGrow = alignItemsAtEnd && (horizontal ? (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minWidth) == null : (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minHeight) == null);
6421
+ const useAlignItemsAtEndPadding = alignItemsAtEnd && !horizontal && (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minHeight) == null && dataProp.length > 0;
6422
+ const shouldFlexGrow = alignItemsAtEnd && !useAlignItemsAtEndPadding && (horizontal ? (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minWidth) == null : (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minHeight) == null);
6207
6423
  const contentContainerStyle = {
6208
6424
  ...contentContainerStyleBase,
6209
- ...alignItemsAtEnd ? {
6425
+ ...alignItemsAtEnd && !useAlignItemsAtEndPadding ? {
6210
6426
  display: "flex",
6211
6427
  flexDirection: horizontal ? "row" : "column",
6212
6428
  ...shouldFlexGrow ? { flexGrow: 1 } : {},
@@ -6249,6 +6465,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6249
6465
  const [, scheduleImperativeScrollCommit] = React2__namespace.useReducer((value) => value + 1, 0);
6250
6466
  const ctx = useStateContext();
6251
6467
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
6468
+ 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;
6469
+ const nextScrollAxisGap = typeof scrollAxisGap === "number" && Number.isFinite(scrollAxisGap) ? scrollAxisGap : 0;
6252
6470
  const refScroller = React2.useRef(null);
6253
6471
  const combinedRef = useCombinedRef(refScroller, refScrollView);
6254
6472
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : ((_item, index) => index.toString());
@@ -6262,8 +6480,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6262
6480
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex,
6263
6481
  alwaysRender == null ? void 0 : alwaysRender.top,
6264
6482
  alwaysRender == null ? void 0 : alwaysRender.bottom,
6265
- (_d = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _d.join(","),
6266
- (_e = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _e.join(","),
6483
+ (_j = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _j.join(","),
6484
+ (_k = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _k.join(","),
6267
6485
  dataProp,
6268
6486
  dataVersion,
6269
6487
  keyExtractor
@@ -6291,6 +6509,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6291
6509
  endNoBuffer: -1,
6292
6510
  endReachedSnapshot: void 0,
6293
6511
  firstFullyOnScreenIndex: -1,
6512
+ hasHadNonEmptyData: dataProp.length > 0,
6294
6513
  idCache: [],
6295
6514
  idsInView: [],
6296
6515
  indexByKey: /* @__PURE__ */ new Map(),
@@ -6333,6 +6552,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6333
6552
  startReachedSnapshotDataChangeEpoch: void 0,
6334
6553
  stickyContainerPool: /* @__PURE__ */ new Set(),
6335
6554
  stickyContainers: /* @__PURE__ */ new Map(),
6555
+ timeoutAdaptiveRender: void 0,
6336
6556
  timeouts: /* @__PURE__ */ new Set(),
6337
6557
  totalSize: 0,
6338
6558
  viewabilityConfigCallbackPairs: void 0
@@ -6351,11 +6571,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6351
6571
  const state = refState.current;
6352
6572
  const isFirstLocal = state.isFirst;
6353
6573
  const previousNumColumnsProp = state.props.numColumns;
6354
- state.didColumnsChange = numColumnsProp !== previousNumColumnsProp;
6574
+ const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
6575
+ ctx.scrollAxisGap = nextScrollAxisGap;
6576
+ state.didColumnsChange = numColumnsProp !== previousNumColumnsProp || didScrollAxisGapChange;
6355
6577
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
6356
6578
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
6357
6579
  const didDataChangeLocal = didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
6358
- if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_f = state.initialScroll) == null ? void 0 : _f.viewPosition) === 1 && state.props.data.length > 0) {
6580
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_l = state.initialScroll) == null ? void 0 : _l.viewPosition) === 1 && state.props.data.length > 0) {
6359
6581
  clearPreservedInitialScrollTarget(state);
6360
6582
  }
6361
6583
  if (didDataChangeLocal) {
@@ -6367,14 +6589,17 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6367
6589
  const throttledOnScroll = useThrottledOnScroll(onScrollProp != null ? onScrollProp : noopOnScroll, scrollEventThrottle != null ? scrollEventThrottle : 0);
6368
6590
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? throttledOnScroll : onScrollProp;
6369
6591
  const anchoredEndSpaceResolved = Platform.OS === "web" && anchoredEndSpace ? { ...anchoredEndSpace, includeInEndInset: true } : anchoredEndSpace;
6370
- const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_g = state.props.anchoredEndSpace) == null ? void 0 : _g.anchorIndex) !== (anchoredEndSpaceResolved == null ? void 0 : anchoredEndSpaceResolved.anchorIndex);
6592
+ const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_m = state.props.anchoredEndSpace) == null ? void 0 : _m.anchorIndex) !== (anchoredEndSpaceResolved == null ? void 0 : anchoredEndSpaceResolved.anchorIndex);
6371
6593
  state.props = {
6594
+ adaptiveRender: experimental_adaptiveRender,
6372
6595
  alignItemsAtEnd,
6596
+ alignItemsAtEndPaddingEnabled: useAlignItemsAtEndPadding,
6373
6597
  alwaysRender,
6374
6598
  alwaysRenderIndicesArr: alwaysRenderIndices.arr,
6375
6599
  alwaysRenderIndicesSet: alwaysRenderIndices.set,
6376
6600
  anchoredEndSpace: anchoredEndSpaceResolved,
6377
6601
  animatedProps: animatedPropsInternal,
6602
+ contentContainerAlignItems: contentContainerStyle.alignItems,
6378
6603
  contentInset,
6379
6604
  contentInsetEndAdjustment: contentInsetEndAdjustmentResolved,
6380
6605
  data: dataProp,
@@ -6427,6 +6652,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6427
6652
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
6428
6653
  setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
6429
6654
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
6655
+ updateContentMetricsState(ctx);
6430
6656
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
6431
6657
  if (shouldAdjustPadding && maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
6432
6658
  if (state.scroll < 0) {
@@ -6463,7 +6689,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6463
6689
  useBootstrapInitialScroll: usesBootstrapInitialScroll
6464
6690
  });
6465
6691
  }, []);
6466
- if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
6692
+ if (isFirstLocal || didDataChangeLocal || state.didColumnsChange) {
6467
6693
  refState.current.lastBatchingAction = Date.now();
6468
6694
  if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
6469
6695
  refState.current.sizes.clear();
@@ -6480,6 +6706,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6480
6706
  dataLength: dataProp.length,
6481
6707
  didDataChange: didDataChangeLocal,
6482
6708
  initialScrollAtEnd,
6709
+ latestInitialScroll: initialScrollProp,
6710
+ latestInitialScrollSessionKind: initialScrollUsesOffsetOnly ? "offset" : "bootstrap",
6483
6711
  stylePaddingBottom: stylePaddingBottomState,
6484
6712
  useBootstrapInitialScroll: usesBootstrapInitialScroll
6485
6713
  });
@@ -6550,7 +6778,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6550
6778
  }, [snapToIndices]);
6551
6779
  React2.useLayoutEffect(
6552
6780
  () => initializeStateVars(true),
6553
- [dataVersion, memoizedLastItemKeys.join(","), numColumnsProp, stylePaddingBottomState, stylePaddingTopState]
6781
+ [
6782
+ dataVersion,
6783
+ memoizedLastItemKeys.join(","),
6784
+ numColumnsProp,
6785
+ nextScrollAxisGap,
6786
+ stylePaddingBottomState,
6787
+ stylePaddingTopState,
6788
+ useAlignItemsAtEndPadding
6789
+ ]
6554
6790
  );
6555
6791
  React2.useLayoutEffect(() => {
6556
6792
  const {
@@ -6569,7 +6805,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6569
6805
  state.didColumnsChange = false;
6570
6806
  state.didDataChange = false;
6571
6807
  state.isFirst = false;
6572
- }, [dataProp, dataVersion, numColumnsProp]);
6808
+ }, [dataProp, dataVersion, numColumnsProp, nextScrollAxisGap]);
6573
6809
  React2.useLayoutEffect(() => {
6574
6810
  var _a4;
6575
6811
  set$(ctx, "extraData", extraData);
@@ -6620,6 +6856,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6620
6856
  }
6621
6857
  });
6622
6858
  React2.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, scheduleImperativeScrollCommit), []);
6859
+ React2.useEffect(() => {
6860
+ return () => {
6861
+ for (const timeout of state.timeouts) {
6862
+ clearTimeout(timeout);
6863
+ }
6864
+ state.timeouts.clear();
6865
+ };
6866
+ }, [state]);
6623
6867
  React2.useLayoutEffect(() => {
6624
6868
  var _a4;
6625
6869
  (_a4 = state.runPendingScrollToEnd) == null ? void 0 : _a4.call(state);
@@ -6667,7 +6911,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6667
6911
  onScroll: onScrollHandler,
6668
6912
  recycleItems,
6669
6913
  refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React2__namespace.cloneElement(refreshControlElement, {
6670
- progressViewOffset: ((_h = refreshControlElement.props.progressViewOffset) != null ? _h : 0) + stylePaddingTopState
6914
+ progressViewOffset: ((_n = refreshControlElement.props.progressViewOffset) != null ? _n : 0) + stylePaddingTopState
6671
6915
  }) : refreshControlElement : onRefresh && /* @__PURE__ */ React2__namespace.createElement(
6672
6916
  ReactNative.RefreshControl,
6673
6917
  {
@@ -6678,7 +6922,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6678
6922
  ),
6679
6923
  refScrollView: combinedRef,
6680
6924
  renderScrollComponent,
6681
- scrollAdjustHandler: (_i = refState.current) == null ? void 0 : _i.scrollAdjustHandler,
6925
+ scrollAdjustHandler: (_o = refState.current) == null ? void 0 : _o.scrollAdjustHandler,
6682
6926
  scrollEventThrottle: 0,
6683
6927
  snapToIndices,
6684
6928
  stickyHeaderIndices,
@@ -6712,6 +6956,8 @@ var internal2 = internal;
6712
6956
 
6713
6957
  exports.LegendList = LegendList3;
6714
6958
  exports.internal = internal2;
6959
+ exports.useAdaptiveRender = useAdaptiveRender;
6960
+ exports.useAdaptiveRenderChange = useAdaptiveRenderChange;
6715
6961
  exports.useIsLastItem = useIsLastItem;
6716
6962
  exports.useListScrollSize = useListScrollSize;
6717
6963
  exports.useRecyclingEffect = useRecyclingEffect;