@legendapp/list 3.3.3 → 3.3.4

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
@@ -62,6 +62,12 @@ function isHorizontalRTL(state) {
62
62
  function isHorizontalRTLProps(props) {
63
63
  return !!(props == null ? void 0 : props.horizontal) && isRTLProps(props);
64
64
  }
65
+ function getStylePaddingEnd(props) {
66
+ if (!(props == null ? void 0 : props.horizontal)) {
67
+ return (props == null ? void 0 : props.stylePaddingBottom) || 0;
68
+ }
69
+ return (isHorizontalRTLProps(props) ? props.stylePaddingLeft : props.stylePaddingRight) || 0;
70
+ }
65
71
  function getLogicalHorizontalMaxOffset(state, contentWidth) {
66
72
  var _a3;
67
73
  return (_a3 = getHorizontalMaxOffset(state, contentWidth)) != null ? _a3 : 0;
@@ -180,6 +186,14 @@ function useStateContext() {
180
186
  return React2__namespace.useContext(ContextState);
181
187
  }
182
188
  function createSelectorFunctionsArr(ctx, signalNames) {
189
+ if (!ctx) {
190
+ const emptyValues = [];
191
+ return {
192
+ get: () => emptyValues,
193
+ subscribe: () => () => {
194
+ }
195
+ };
196
+ }
183
197
  let lastValues = [];
184
198
  let lastSignalValues = [];
185
199
  return {
@@ -286,7 +300,7 @@ function getContentInsetEndAdjustmentEnd(adjustment) {
286
300
  return Math.max(0, adjustment != null ? adjustment : 0);
287
301
  }
288
302
  function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
289
- var _a3, _b;
303
+ var _a3;
290
304
  const state = ctx.state;
291
305
  const { props } = state;
292
306
  const horizontal = props.horizontal;
@@ -297,8 +311,8 @@ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
297
311
  contentInsetEndAdjustmentOverride != null ? contentInsetEndAdjustmentOverride : props.contentInsetEndAdjustment
298
312
  );
299
313
  const anchoredEndSpaceSize = peek$(ctx, "anchoredEndSpaceSize");
300
- const anchoredEndInset = ((_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.includeInEndInset) && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
301
- const overrideInset = (_b = state.contentInsetOverride) != null ? _b : void 0;
314
+ const anchoredEndInset = props.anchoredEndSpace && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
315
+ const overrideInset = (_a3 = state.contentInsetOverride) != null ? _a3 : void 0;
302
316
  const adjustedBaseEndInset = baseEndInset + contentInsetEndAdjustment;
303
317
  if (overrideInset) {
304
318
  const mergedInset = { bottom: 0, left: 0, right: 0, ...baseInset, ...overrideInset };
@@ -314,14 +328,15 @@ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
314
328
  function getContentSize(ctx) {
315
329
  var _a3, _b;
316
330
  const { values, state } = ctx;
317
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
318
- const stylePaddingBottom = state.props.stylePaddingBottom || 0;
331
+ const stylePaddingStart = state.props.horizontal ? state.props.stylePaddingLeft || 0 : values.get("stylePaddingTop") || 0;
332
+ const stylePaddingEnd = state.props.horizontal ? state.props.stylePaddingRight || 0 : state.props.stylePaddingBottom || 0;
319
333
  const alignItemsAtEndPadding = values.get("alignItemsAtEndPadding") || 0;
320
334
  const headerSize = values.get("headerSize") || 0;
321
335
  const footerSize = values.get("footerSize") || 0;
322
- const contentInsetBottom = getContentInsetEnd(ctx);
336
+ const contentInsetEnd = getContentInsetEnd(ctx);
323
337
  const totalSize = (_b = (_a3 = state.pendingTotalSize) != null ? _a3 : state.totalSize) != null ? _b : values.get("totalSize");
324
- return headerSize + footerSize + totalSize + stylePaddingTop + alignItemsAtEndPadding + stylePaddingBottom + (contentInsetBottom || 0);
338
+ const layoutSize = Math.max(0, totalSize - (state.props.data.length > 0 ? ctx.scrollAxisGap : 0));
339
+ return headerSize + footerSize + layoutSize + stylePaddingStart + alignItemsAtEndPadding + stylePaddingEnd + (contentInsetEnd || 0);
325
340
  }
326
341
 
327
342
  // src/components/DebugView.tsx
@@ -810,13 +825,7 @@ var DEFAULT_WEB_ADAPTIVE_RENDER_ENTER_VELOCITY = 6;
810
825
  var DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_VELOCITY = 3;
811
826
  var DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_DELAY = 250;
812
827
  function clearAdaptiveRenderExitTimeout(ctx) {
813
- const state = ctx.state;
814
- const previousTimeout = state.timeoutAdaptiveRender;
815
- if (previousTimeout !== void 0) {
816
- clearTimeout(previousTimeout);
817
- state.timeouts.delete(previousTimeout);
818
- state.timeoutAdaptiveRender = void 0;
819
- }
828
+ ctx.state.scheduledWork.cancel("adaptiveRender");
820
829
  }
821
830
  function scheduleAdaptiveRenderExit(ctx, exitDelay) {
822
831
  const state = ctx.state;
@@ -824,13 +833,7 @@ function scheduleAdaptiveRenderExit(ctx, exitDelay) {
824
833
  if (exitDelay <= 0) {
825
834
  setAdaptiveRender(ctx, "normal", "scroll");
826
835
  } else {
827
- const timeout = setTimeout(() => {
828
- state.timeouts.delete(timeout);
829
- state.timeoutAdaptiveRender = void 0;
830
- setAdaptiveRender(ctx, "normal", "scroll");
831
- }, exitDelay);
832
- state.timeoutAdaptiveRender = timeout;
833
- state.timeouts.add(timeout);
836
+ state.scheduledWork.timeout(() => setAdaptiveRender(ctx, "normal", "scroll"), exitDelay, "adaptiveRender");
834
837
  }
835
838
  }
836
839
  function setAdaptiveRender(ctx, mode, reason) {
@@ -862,7 +865,7 @@ function updateAdaptiveRender(ctx, scrollVelocity, options) {
862
865
  const exitDelay = (_c = adaptiveRender.exitDelay) != null ? _c : isWeb ? DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_DELAY : DEFAULT_ADAPTIVE_RENDER_EXIT_DELAY;
863
866
  const threshold = currentMode === "light" ? exitVelocity : enterVelocity;
864
867
  const nextMode = (options == null ? void 0 : options.forceLight) || Math.abs(scrollVelocity) > threshold ? "light" : "normal";
865
- const previousMode = state.timeoutAdaptiveRender !== void 0 ? "normal" : currentMode;
868
+ const previousMode = state.scheduledWork.has("adaptiveRender") ? "normal" : currentMode;
866
869
  if (nextMode !== previousMode) {
867
870
  if (nextMode === "light") {
868
871
  setAdaptiveRender(ctx, "light", "scroll");
@@ -889,14 +892,13 @@ function getEffectiveDrawDistance(ctx, mode) {
889
892
  }
890
893
  function scheduleFullDrawDistancePrewarm(ctx) {
891
894
  const { state } = ctx;
892
- if (state.props.drawDistance <= INITIAL_DRAW_DISTANCE || state.queuedFullDrawDistancePrewarm !== void 0) {
895
+ if (state.props.drawDistance <= INITIAL_DRAW_DISTANCE || state.scheduledWork.has("fullDrawDistancePrewarm")) {
893
896
  return;
894
897
  }
895
- state.queuedFullDrawDistancePrewarm = requestAnimationFrame(() => {
898
+ state.scheduledWork.frame(() => {
896
899
  var _a3;
897
- state.queuedFullDrawDistancePrewarm = void 0;
898
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
899
- });
900
+ return (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
901
+ }, "fullDrawDistancePrewarm");
900
902
  }
901
903
 
902
904
  // src/utils/setInitialRenderState.ts
@@ -954,10 +956,7 @@ function syncInitialScrollOffset(state, offset) {
954
956
  state.scrollPrev = offset;
955
957
  }
956
958
  function clearPreservedInitialScrollTargetTimeout(state) {
957
- if (state.timeoutPreservedInitialScrollClear !== void 0) {
958
- clearTimeout(state.timeoutPreservedInitialScrollClear);
959
- state.timeoutPreservedInitialScrollClear = void 0;
960
- }
959
+ state.scheduledWork.cancel("preservedInitialScroll");
961
960
  }
962
961
  function clearPreservedInitialScrollTarget(state) {
963
962
  clearPreservedInitialScrollTargetTimeout(state);
@@ -986,14 +985,17 @@ function finishInitialScroll(ctx, options) {
986
985
  setInitialScrollSession(state);
987
986
  clearPreservedInitialScrollTargetTimeout(state);
988
987
  if (options == null ? void 0 : options.schedulePreservedTargetClear) {
989
- state.timeoutPreservedInitialScrollClear = setTimeout(() => {
990
- var _a5;
991
- state.timeoutPreservedInitialScrollClear = void 0;
992
- if (!state.didFinishInitialScroll || ((_a5 = state.scrollingTo) == null ? void 0 : _a5.isInitialScroll) || !state.initialScroll) {
993
- return;
994
- }
995
- clearPreservedInitialScrollTarget(state);
996
- }, PRESERVED_INITIAL_SCROLL_FALLBACK_CLEAR_DELAY_MS);
988
+ state.scheduledWork.timeout(
989
+ () => {
990
+ var _a5;
991
+ if (!state.didFinishInitialScroll || ((_a5 = state.scrollingTo) == null ? void 0 : _a5.isInitialScroll) || !state.initialScroll) {
992
+ return;
993
+ }
994
+ clearPreservedInitialScrollTarget(state);
995
+ },
996
+ PRESERVED_INITIAL_SCROLL_FALLBACK_CLEAR_DELAY_MS,
997
+ "preservedInitialScroll"
998
+ );
997
999
  }
998
1000
  } else {
999
1001
  clearPreservedInitialScrollTarget(state);
@@ -1020,9 +1022,11 @@ function calculateOffsetForIndex(ctx, index) {
1020
1022
  return index !== void 0 ? state.positions[index] || 0 : 0;
1021
1023
  }
1022
1024
 
1023
- // src/core/getTopOffsetAdjustment.ts
1024
- function getTopOffsetAdjustment(ctx) {
1025
- return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
1025
+ // src/core/getStartOffsetAdjustment.ts
1026
+ function getStartOffsetAdjustment(ctx) {
1027
+ const { state } = ctx;
1028
+ const stylePaddingStart = state.props.horizontal ? (isHorizontalRTL(state) ? state.props.stylePaddingRight : state.props.stylePaddingLeft) || 0 : peek$(ctx, "stylePaddingTop") || 0;
1029
+ return stylePaddingStart + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
1026
1030
  }
1027
1031
 
1028
1032
  // src/utils/getId.ts
@@ -1235,9 +1239,9 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1235
1239
  offset -= viewOffset;
1236
1240
  }
1237
1241
  if (index !== void 0) {
1238
- const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
1239
- if (topOffsetAdjustment) {
1240
- offset += topOffsetAdjustment;
1242
+ const startOffsetAdjustment = getStartOffsetAdjustment(ctx);
1243
+ if (startOffsetAdjustment) {
1244
+ offset += startOffsetAdjustment;
1241
1245
  }
1242
1246
  }
1243
1247
  if (viewPosition !== void 0 && index !== void 0) {
@@ -1247,7 +1251,8 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1247
1251
  }
1248
1252
  const isOutOfBounds = index < 0 || index >= dataLength;
1249
1253
  const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
1250
- const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1254
+ const measuredItemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1255
+ const itemSize = Math.max(0, measuredItemSize - (isOutOfBounds ? 0 : ctx.scrollAxisGap));
1251
1256
  const trailingInset = getContentInsetEnd(ctx);
1252
1257
  offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1253
1258
  if (!isOutOfBounds && index === state.props.data.length - 1) {
@@ -1274,11 +1279,35 @@ function clampScrollOffset(ctx, offset, scrollTarget) {
1274
1279
  return clampedOffset;
1275
1280
  }
1276
1281
 
1282
+ // src/core/cancelImperativeScroll.ts
1283
+ function cancelScrollCompletionChecks({ scheduledWork }) {
1284
+ scheduledWork.cancel("checkFinishedScrollFrame");
1285
+ scheduledWork.cancel("checkFinishedScrollRetryFrame");
1286
+ scheduledWork.cancel("checkFinishedScrollFallback");
1287
+ scheduledWork.cancel("platformScrollCompletion");
1288
+ }
1289
+ function settlePendingImperativeScroll(state) {
1290
+ var _a3, _b;
1291
+ const resolvePendingScroll = (_b = state.pendingScrollResolve) != null ? _b : (_a3 = state.pendingScrollToEnd) == null ? void 0 : _a3.resolve;
1292
+ state.pendingScrollResolve = void 0;
1293
+ state.pendingScrollToEnd = void 0;
1294
+ resolvePendingScroll == null ? void 0 : resolvePendingScroll();
1295
+ }
1296
+ function cancelImperativeScroll(state) {
1297
+ cancelScrollCompletionChecks(state);
1298
+ state.scheduledWork.cancel("imperativeScrollReady");
1299
+ state.runPendingScrollToEnd = void 0;
1300
+ state.scrollingTo = void 0;
1301
+ state.scrollTargetPinnedRange = void 0;
1302
+ settlePendingImperativeScroll(state);
1303
+ }
1304
+
1277
1305
  // src/core/finishScrollTo.ts
1278
1306
  function finishScrollTo(ctx) {
1279
1307
  var _a3, _b;
1280
1308
  const state = ctx.state;
1281
1309
  if (state == null ? void 0 : state.scrollingTo) {
1310
+ cancelScrollCompletionChecks(state);
1282
1311
  const resolvePendingScroll = state.pendingScrollResolve;
1283
1312
  state.pendingScrollResolve = void 0;
1284
1313
  const scrollingTo = state.scrollingTo;
@@ -1327,7 +1356,7 @@ function checkFinishedScroll(ctx, options) {
1327
1356
  return;
1328
1357
  }
1329
1358
  }
1330
- ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
1359
+ ctx.state.scheduledWork.frame(() => checkFinishedScrollFrame(ctx), "checkFinishedScrollFrame");
1331
1360
  }
1332
1361
  function hasScrollCompletionOwnership(state, options) {
1333
1362
  const { clampedTargetOffset, scrollingTo } = options;
@@ -1397,7 +1426,6 @@ function checkFinishedScrollFrame(ctx) {
1397
1426
  return;
1398
1427
  }
1399
1428
  const { state } = ctx;
1400
- state.animFrameCheckFinishedScroll = void 0;
1401
1429
  const completionState = getResolvedScrollCompletionState(ctx, scrollingTo);
1402
1430
  if (completionState.isAtResolvedTarget && hasScrollCompletionOwnership(state, {
1403
1431
  clampedTargetOffset: completionState.clampedTargetOffset,
@@ -1416,61 +1444,62 @@ function scrollToFallbackOffset(ctx, offset) {
1416
1444
  }
1417
1445
  function checkFinishedScrollFallback(ctx) {
1418
1446
  const state = ctx.state;
1447
+ if (state.scheduledWork.has("checkFinishedScrollFallback")) {
1448
+ return;
1449
+ }
1419
1450
  const scrollingTo = state.scrollingTo;
1420
1451
  const shouldFinishInitialZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
1421
1452
  const silentInitialDispatch = isSilentInitialDispatch(state, scrollingTo);
1422
1453
  const canFinishInitialWithoutNativeProgress = scrollingTo !== void 0 ? shouldFinishInitialScrollWithoutNativeProgress(state, scrollingTo) : false;
1423
1454
  const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) && !shouldFinishInitialZeroTarget && !canFinishInitialWithoutNativeProgress || !state.didContainersLayout;
1424
1455
  const initialDelay = shouldFinishInitialZeroTarget || canFinishInitialWithoutNativeProgress ? 0 : silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : slowTimeout ? 500 : 100;
1425
- state.timeoutCheckFinishedScrollFallback = setTimeout(() => {
1426
- let numChecks = 0;
1427
- const scheduleFallbackCheck = (delay) => {
1428
- state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, delay);
1429
- };
1430
- const checkHasScrolled = () => {
1431
- var _a3, _b, _c, _d;
1432
- state.timeoutCheckFinishedScrollFallback = void 0;
1433
- const isStillScrollingTo = state.scrollingTo;
1434
- if (isStillScrollingTo) {
1435
- numChecks++;
1436
- const isNativeInitialPending = isNativeInitialNonZeroTarget(state) && !state.hasScrolled;
1437
- const maxChecks = silentInitialDispatch ? 5 : isNativeInitialPending ? INITIAL_SCROLL_MAX_FALLBACK_CHECKS : 5;
1438
- const shouldFinishZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
1439
- const canFinishInitialScrollWithoutNativeProgress = shouldFinishInitialScrollWithoutNativeProgress(
1440
- state,
1441
- isStillScrollingTo
1456
+ let numChecks = 0;
1457
+ const scheduleFallbackCheck = (delay) => {
1458
+ state.scheduledWork.timeout(checkHasScrolled, delay, "checkFinishedScrollFallback");
1459
+ };
1460
+ const checkHasScrolled = () => {
1461
+ var _a3, _b, _c, _d;
1462
+ const isStillScrollingTo = state.scrollingTo;
1463
+ if (isStillScrollingTo) {
1464
+ numChecks++;
1465
+ const isNativeInitialPending = isNativeInitialNonZeroTarget(state) && !state.hasScrolled;
1466
+ const maxChecks = silentInitialDispatch ? 5 : isNativeInitialPending ? INITIAL_SCROLL_MAX_FALLBACK_CHECKS : 5;
1467
+ const shouldFinishZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
1468
+ const canFinishInitialScrollWithoutNativeProgress = shouldFinishInitialScrollWithoutNativeProgress(
1469
+ state,
1470
+ isStillScrollingTo
1471
+ );
1472
+ const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
1473
+ const canFinishAfterSilentNativeDispatch = Platform.OS === "android" && silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
1474
+ const shouldRetrySilentInitialNativeScroll = Platform.OS === "android" && canFinishAfterSilentNativeDispatch && !initialScrollCompletion.didRetrySilentInitialScroll(state);
1475
+ const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
1476
+ const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
1477
+ const shouldRetryUnalignedEndScroll = Platform.OS === "ios" && !isStillScrollingTo.isInitialScroll && isEndAlignedLastItemTarget(ctx, isStillScrollingTo) && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
1478
+ if (shouldRetrySilentInitialNativeScroll) {
1479
+ const targetOffset = (_b = (_a3 = getInitialScrollWatchdogTargetOffset(state)) != null ? _a3 : isStillScrollingTo.targetOffset) != null ? _b : 0;
1480
+ const jiggleOffset = targetOffset >= SILENT_INITIAL_SCROLL_TARGET_EPSILON ? targetOffset - SILENT_INITIAL_SCROLL_TARGET_EPSILON : targetOffset + SILENT_INITIAL_SCROLL_TARGET_EPSILON;
1481
+ initialScrollCompletion.markSilentInitialScrollRetry(state);
1482
+ scrollToFallbackOffset(ctx, jiggleOffset);
1483
+ state.scheduledWork.frame(
1484
+ () => scrollToFallbackOffset(ctx, targetOffset),
1485
+ "checkFinishedScrollRetryFrame"
1442
1486
  );
1443
- const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
1444
- const canFinishAfterSilentNativeDispatch = Platform.OS === "android" && silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
1445
- const shouldRetrySilentInitialNativeScroll = Platform.OS === "android" && canFinishAfterSilentNativeDispatch && !initialScrollCompletion.didRetrySilentInitialScroll(state);
1446
- const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
1447
- const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
1448
- const shouldRetryUnalignedEndScroll = Platform.OS === "ios" && !isStillScrollingTo.isInitialScroll && isEndAlignedLastItemTarget(ctx, isStillScrollingTo) && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
1449
- if (shouldRetrySilentInitialNativeScroll) {
1450
- const targetOffset = (_b = (_a3 = getInitialScrollWatchdogTargetOffset(state)) != null ? _a3 : isStillScrollingTo.targetOffset) != null ? _b : 0;
1451
- const jiggleOffset = targetOffset >= SILENT_INITIAL_SCROLL_TARGET_EPSILON ? targetOffset - SILENT_INITIAL_SCROLL_TARGET_EPSILON : targetOffset + SILENT_INITIAL_SCROLL_TARGET_EPSILON;
1452
- initialScrollCompletion.markSilentInitialScrollRetry(state);
1453
- scrollToFallbackOffset(ctx, jiggleOffset);
1454
- requestAnimationFrame(() => {
1455
- scrollToFallbackOffset(ctx, targetOffset);
1456
- });
1457
- scheduleFallbackCheck(SILENT_INITIAL_SCROLL_RETRY_DELAY_MS);
1458
- } else if (shouldRetryUnalignedEndScroll) {
1459
- scrollToFallbackOffset(ctx, completionState.clampedTargetOffset);
1460
- scheduleFallbackCheck(100);
1461
- } else if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
1462
- finishScrollTo(ctx);
1463
- } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
1464
- const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
1465
- scrollToFallbackOffset(ctx, targetOffset);
1466
- scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
1467
- } else {
1468
- scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
1469
- }
1487
+ scheduleFallbackCheck(SILENT_INITIAL_SCROLL_RETRY_DELAY_MS);
1488
+ } else if (shouldRetryUnalignedEndScroll) {
1489
+ scrollToFallbackOffset(ctx, completionState.clampedTargetOffset);
1490
+ scheduleFallbackCheck(100);
1491
+ } else if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
1492
+ finishScrollTo(ctx);
1493
+ } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
1494
+ const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
1495
+ scrollToFallbackOffset(ctx, targetOffset);
1496
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
1497
+ } else {
1498
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
1470
1499
  }
1471
- };
1472
- checkHasScrolled();
1473
- }, initialDelay);
1500
+ }
1501
+ };
1502
+ scheduleFallbackCheck(initialDelay);
1474
1503
  }
1475
1504
 
1476
1505
  // src/core/doScrollTo.native.ts
@@ -1494,6 +1523,9 @@ function doScrollTo(ctx, params) {
1494
1523
  if (isInitialScroll) {
1495
1524
  initialScrollCompletion.markInitialScrollNativeDispatch(state);
1496
1525
  }
1526
+ if (isAnimated && Math.abs(state.scroll - offset) <= 1) {
1527
+ checkFinishedScroll(ctx);
1528
+ }
1497
1529
  if (!isAnimated) {
1498
1530
  state.scroll = offset;
1499
1531
  checkFinishedScrollFallback(ctx);
@@ -1524,9 +1556,12 @@ function doMaintainScrollAtEnd(ctx) {
1524
1556
  if (!state.maintainingScrollAtEnd) {
1525
1557
  const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
1526
1558
  const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
1559
+ const scrollAtRequest = state.scroll;
1527
1560
  state.maintainingScrollAtEnd = pendingState;
1528
1561
  requestAnimationFrame(() => {
1529
- if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
1562
+ const isStillWithinThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
1563
+ const didScrollSinceRequest = state.scroll !== scrollAtRequest;
1564
+ if (isStillWithinThreshold || !didScrollSinceRequest) {
1530
1565
  state.maintainingScrollAtEnd = activeState;
1531
1566
  const scroller = refScroller.current;
1532
1567
  if (state.props.horizontal && isHorizontalRTL(state)) {
@@ -1556,6 +1591,7 @@ function doMaintainScrollAtEnd(ctx) {
1556
1591
  );
1557
1592
  } else if (state.maintainingScrollAtEnd === pendingState) {
1558
1593
  state.maintainingScrollAtEnd = void 0;
1594
+ state.pendingMaintainScrollAtEnd = false;
1559
1595
  }
1560
1596
  });
1561
1597
  } else {
@@ -1597,20 +1633,21 @@ function requestAdjust(ctx, positionDiff, dataChanged) {
1597
1633
  } else {
1598
1634
  state.ignoreScrollFromMVCP.gt = threshold;
1599
1635
  }
1600
- if (state.ignoreScrollFromMVCPTimeout) {
1601
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
1602
- }
1603
1636
  const delay = needsScrollWorkaround ? 250 : 100;
1604
- state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
1605
- var _a3;
1606
- state.ignoreScrollFromMVCP = void 0;
1607
- const shouldForceUpdate = state.ignoreScrollFromMVCPIgnored && state.scrollProcessingEnabled !== false;
1608
- if (shouldForceUpdate) {
1609
- state.ignoreScrollFromMVCPIgnored = false;
1610
- state.scrollPending = state.scroll;
1611
- (_a3 = state.reprocessCurrentScroll) == null ? void 0 : _a3.call(state);
1612
- }
1613
- }, delay);
1637
+ state.scheduledWork.timeout(
1638
+ () => {
1639
+ var _a3;
1640
+ state.ignoreScrollFromMVCP = void 0;
1641
+ const shouldForceUpdate = state.ignoreScrollFromMVCPIgnored && state.scrollProcessingEnabled !== false;
1642
+ if (shouldForceUpdate) {
1643
+ state.ignoreScrollFromMVCPIgnored = false;
1644
+ state.scrollPending = state.scroll;
1645
+ (_a3 = state.reprocessCurrentScroll) == null ? void 0 : _a3.call(state);
1646
+ }
1647
+ },
1648
+ delay,
1649
+ "ignoreScrollFromMVCP"
1650
+ );
1614
1651
  }
1615
1652
  } else {
1616
1653
  state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
@@ -2038,10 +2075,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
2038
2075
  state.mvcpAnchorLock = void 0;
2039
2076
  state.pendingNativeMVCPAdjust = void 0;
2040
2077
  state.userScrollAnchorReset = { keys: /* @__PURE__ */ new Set() };
2041
- if (state.queuedMVCPRecalculate !== void 0) {
2042
- cancelAnimationFrame(state.queuedMVCPRecalculate);
2043
- state.queuedMVCPRecalculate = void 0;
2044
- }
2078
+ state.scheduledWork.cancel("mvcpRecalculate");
2045
2079
  flushSync(runCalculateItems);
2046
2080
  scheduleFullDrawDistancePrewarm(ctx);
2047
2081
  } else {
@@ -2186,12 +2220,7 @@ function scrollTo(ctx, params) {
2186
2220
  const {
2187
2221
  props: { horizontal }
2188
2222
  } = state;
2189
- if (state.animFrameCheckFinishedScroll) {
2190
- cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
2191
- }
2192
- if (state.timeoutCheckFinishedScrollFallback) {
2193
- clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
2194
- }
2223
+ cancelScrollCompletionChecks(state);
2195
2224
  const requestedOffset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
2196
2225
  const shouldPreserveRawInitialOffsetRequest = !!isInitialScroll && ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset";
2197
2226
  const targetOffset = clampScrollOffset(ctx, requestedOffset, scrollTarget);
@@ -2296,10 +2325,7 @@ function setInitialScrollTarget(ctx, target, options) {
2296
2325
  var _a3;
2297
2326
  const { state } = ctx;
2298
2327
  state.clearPreservedInitialScrollOnNextFinish = void 0;
2299
- if (state.timeoutPreservedInitialScrollClear !== void 0) {
2300
- clearTimeout(state.timeoutPreservedInitialScrollClear);
2301
- state.timeoutPreservedInitialScrollClear = void 0;
2302
- }
2328
+ state.scheduledWork.cancel("preservedInitialScroll");
2303
2329
  state.initialScroll = target;
2304
2330
  if (options == null ? void 0 : options.resetDidFinish) {
2305
2331
  resetInitialRenderState(ctx, { resetInitialScroll: true });
@@ -2592,13 +2618,13 @@ function rearmBootstrapInitialScroll(ctx, options) {
2592
2618
  queueBootstrapInitialScrollReevaluation(ctx.state);
2593
2619
  }
2594
2620
  function createInitialScrollAtEndTarget(options) {
2595
- const { dataLength, footerSize, preserveForFooterLayout, stylePaddingBottom } = options;
2621
+ const { dataLength, footerSize, preserveForFooterLayout, stylePaddingEnd } = options;
2596
2622
  return {
2597
2623
  contentOffset: void 0,
2598
2624
  index: Math.max(0, dataLength - 1),
2599
2625
  preserveForBottomPadding: true,
2600
2626
  preserveForFooterLayout,
2601
- viewOffset: -stylePaddingBottom - footerSize,
2627
+ viewOffset: -stylePaddingEnd - footerSize,
2602
2628
  viewPosition: 1
2603
2629
  };
2604
2630
  }
@@ -2612,7 +2638,7 @@ function isRetargetableBottomAlignedInitialScrollTarget(target) {
2612
2638
  return !!(target && target.viewPosition === 1 && (shouldPreserveInitialScrollForBottomPadding(target) || shouldPreserveInitialScrollForFooterLayout(target)));
2613
2639
  }
2614
2640
  function createRetargetedBottomAlignedInitialScroll(options) {
2615
- const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom, target } = options;
2641
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd, target } = options;
2616
2642
  const preserveForFooterLayout = shouldPreserveInitialScrollForFooterLayout(target);
2617
2643
  return {
2618
2644
  ...target,
@@ -2620,7 +2646,7 @@ function createRetargetedBottomAlignedInitialScroll(options) {
2620
2646
  index: initialScrollAtEnd ? Math.max(0, dataLength - 1) : target.index,
2621
2647
  preserveForBottomPadding: true,
2622
2648
  preserveForFooterLayout,
2623
- viewOffset: -stylePaddingBottom - (preserveForFooterLayout ? footerSize : 0),
2649
+ viewOffset: -stylePaddingEnd - (preserveForFooterLayout ? footerSize : 0),
2624
2650
  viewPosition: 1
2625
2651
  };
2626
2652
  }
@@ -2628,7 +2654,7 @@ function areEquivalentBootstrapInitialScrollTargets(current, next) {
2628
2654
  return current.index === next.index && current.preserveForBottomPadding === next.preserveForBottomPadding && current.preserveForFooterLayout === next.preserveForFooterLayout && current.viewOffset === next.viewOffset && current.viewPosition === next.viewPosition;
2629
2655
  }
2630
2656
  function clearPendingInitialScrollFooterLayout(ctx, options) {
2631
- const { dataLength, stylePaddingBottom, target } = options;
2657
+ const { dataLength, stylePaddingEnd, target } = options;
2632
2658
  if (!shouldPreserveInitialScrollForFooterLayout(target)) {
2633
2659
  return;
2634
2660
  }
@@ -2636,7 +2662,7 @@ function clearPendingInitialScrollFooterLayout(ctx, options) {
2636
2662
  dataLength,
2637
2663
  footerSize: 0,
2638
2664
  preserveForFooterLayout: void 0,
2639
- stylePaddingBottom
2665
+ stylePaddingEnd
2640
2666
  });
2641
2667
  setInitialScrollTarget(ctx, clearedFooterTarget);
2642
2668
  }
@@ -2697,7 +2723,7 @@ function schedulePreservedEndAnchorCorrectionFrame(ctx, correction) {
2697
2723
  });
2698
2724
  }
2699
2725
  function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2700
- var _a3, _b;
2726
+ var _a3;
2701
2727
  const state = ctx.state;
2702
2728
  const initialScroll = state.initialScroll;
2703
2729
  if (!state.didFinishInitialScroll || ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) || (initialScroll == null ? void 0 : initialScroll.viewPosition) !== 1 || state.preservedEndAnchorCorrection) {
@@ -2709,7 +2735,7 @@ function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2709
2735
  if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
2710
2736
  clearPendingInitialScrollFooterLayout(ctx, {
2711
2737
  dataLength: state.props.data.length,
2712
- stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
2738
+ stylePaddingEnd: getStylePaddingEnd(state.props),
2713
2739
  target: initialScroll
2714
2740
  });
2715
2741
  } else {
@@ -2746,7 +2772,7 @@ function startBootstrapInitialScrollOnMount(ctx, options) {
2746
2772
  }
2747
2773
  }
2748
2774
  function handleBootstrapInitialScrollDataChange(ctx, options) {
2749
- const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingBottom } = options;
2775
+ const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingEnd } = options;
2750
2776
  const state = ctx.state;
2751
2777
  const initialScroll = state.initialScroll;
2752
2778
  if (isOffsetInitialScrollSession(state) || !initialScroll) {
@@ -2768,18 +2794,18 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2768
2794
  dataLength,
2769
2795
  footerSize: peek$(ctx, "footerSize") || 0,
2770
2796
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2771
- stylePaddingBottom
2797
+ stylePaddingEnd
2772
2798
  }) : createRetargetedBottomAlignedInitialScroll({
2773
2799
  dataLength,
2774
2800
  footerSize: peek$(ctx, "footerSize") || 0,
2775
2801
  initialScrollAtEnd,
2776
- stylePaddingBottom,
2802
+ stylePaddingEnd,
2777
2803
  target: initialScroll
2778
2804
  });
2779
2805
  if (!shouldResetDidFinish && didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2780
2806
  clearPendingInitialScrollFooterLayout(ctx, {
2781
2807
  dataLength,
2782
- stylePaddingBottom,
2808
+ stylePaddingEnd,
2783
2809
  target: initialScroll
2784
2810
  });
2785
2811
  return;
@@ -2811,7 +2837,7 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2811
2837
  }
2812
2838
  }
2813
2839
  function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2814
- const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom } = options;
2840
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd } = options;
2815
2841
  const state = ctx.state;
2816
2842
  if (!initialScrollAtEnd) {
2817
2843
  return;
@@ -2827,7 +2853,7 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2827
2853
  if (didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2828
2854
  clearPendingInitialScrollFooterLayout(ctx, {
2829
2855
  dataLength,
2830
- stylePaddingBottom,
2856
+ stylePaddingEnd,
2831
2857
  target: initialScroll
2832
2858
  });
2833
2859
  } else {
@@ -2835,13 +2861,13 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2835
2861
  dataLength,
2836
2862
  footerSize,
2837
2863
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2838
- stylePaddingBottom
2864
+ stylePaddingEnd
2839
2865
  });
2840
2866
  const didTargetChange = initialScroll.index !== updatedInitialScroll.index || initialScroll.viewPosition !== updatedInitialScroll.viewPosition || initialScroll.viewOffset !== updatedInitialScroll.viewOffset;
2841
2867
  if (!didTargetChange) {
2842
2868
  clearPendingInitialScrollFooterLayout(ctx, {
2843
2869
  dataLength,
2844
- stylePaddingBottom,
2870
+ stylePaddingEnd,
2845
2871
  target: initialScroll
2846
2872
  });
2847
2873
  } else {
@@ -3068,7 +3094,7 @@ function handleInitialScrollDataChange(ctx, options) {
3068
3094
  initialScrollAtEnd,
3069
3095
  latestInitialScroll,
3070
3096
  latestInitialScrollSessionKind,
3071
- stylePaddingBottom,
3097
+ stylePaddingEnd,
3072
3098
  useBootstrapInitialScroll
3073
3099
  } = options;
3074
3100
  const state = ctx.state;
@@ -3098,7 +3124,7 @@ function handleInitialScrollDataChange(ctx, options) {
3098
3124
  didDataChange,
3099
3125
  initialScrollAtEnd,
3100
3126
  previousDataLength: previousInitialScrollDataLength,
3101
- stylePaddingBottom
3127
+ stylePaddingEnd
3102
3128
  });
3103
3129
  return;
3104
3130
  }
@@ -3568,7 +3594,6 @@ function setupViewability(props) {
3568
3594
  }
3569
3595
  function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end, startBuffered = start, endBuffered = end) {
3570
3596
  const {
3571
- timeouts,
3572
3597
  props: { data }
3573
3598
  } = state;
3574
3599
  for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
@@ -3578,11 +3603,10 @@ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollS
3578
3603
  viewabilityState.startBuffered = startBuffered;
3579
3604
  viewabilityState.endBuffered = endBuffered;
3580
3605
  if (viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime) {
3581
- const timer = setTimeout(() => {
3582
- timeouts.delete(timer);
3583
- updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
3584
- }, viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime);
3585
- timeouts.add(timer);
3606
+ state.scheduledWork.timeout(
3607
+ () => updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize),
3608
+ viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime
3609
+ );
3586
3610
  } else {
3587
3611
  updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
3588
3612
  }
@@ -3941,20 +3965,15 @@ function getProjectedBufferAdjustment(scrollVelocity, trailingBuffer) {
3941
3965
  }
3942
3966
  function scheduleRenderRangeProjectionSettle(ctx) {
3943
3967
  const state = ctx.state;
3944
- const previousTimeout = state.timeoutRenderRangeProjectionSettle;
3945
- if (previousTimeout !== void 0) {
3946
- clearTimeout(previousTimeout);
3947
- state.timeouts.delete(previousTimeout);
3948
- }
3949
- const timeout = setTimeout(() => {
3950
- var _a3;
3951
- state.timeoutRenderRangeProjectionSettle = void 0;
3952
- state.timeouts.delete(timeout);
3953
- state.scrollHistory.length = 0;
3954
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
3955
- }, RENDER_RANGE_PROJECTION_SETTLE_DELAY);
3956
- state.timeoutRenderRangeProjectionSettle = timeout;
3957
- state.timeouts.add(timeout);
3968
+ state.scheduledWork.timeout(
3969
+ () => {
3970
+ var _a3;
3971
+ state.scrollHistory.length = 0;
3972
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
3973
+ },
3974
+ RENDER_RANGE_PROJECTION_SETTLE_DELAY,
3975
+ "renderRangeProjection"
3976
+ );
3958
3977
  }
3959
3978
  function findCurrentStickyIndex(stickyArray, scroll, state) {
3960
3979
  const positions = state.positions;
@@ -4622,8 +4641,6 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4622
4641
  if (anchorIndex >= 0 && anchorIndex < data.length && state.scrollLength > 0) {
4623
4642
  nextAnchorKey = getId(state, anchorIndex);
4624
4643
  let contentBelowAnchor = 0;
4625
- const footerSize = ctx.values.get("footerSize") || 0;
4626
- const stylePaddingBottom = state.props.stylePaddingBottom || 0;
4627
4644
  let hasUnknownTailSize = false;
4628
4645
  for (let index = anchorIndex; index < data.length; index++) {
4629
4646
  const size = getKnownOrFixedItemSize(ctx, index);
@@ -4635,14 +4652,16 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4635
4652
  contentBelowAnchor += effectiveSize;
4636
4653
  }
4637
4654
  }
4638
- contentBelowAnchor += footerSize + stylePaddingBottom;
4655
+ contentBelowAnchor = Math.max(0, contentBelowAnchor - ctx.scrollAxisGap);
4656
+ contentBelowAnchor += (ctx.values.get("footerSize") || 0) + getStylePaddingEnd(state.props);
4639
4657
  isReady = !hasUnknownTailSize;
4640
4658
  nextSize = hasUnknownTailSize ? previousSize || 0 : Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
4641
4659
  } else if (anchorIndex >= 0) {
4642
4660
  isReady = false;
4643
4661
  }
4644
4662
  }
4645
- const didSizeChange = previousSize !== nextSize;
4663
+ const didSizeChange = previousSize !== nextSize && (previousSize !== void 0 || anchoredEndSpace !== void 0);
4664
+ const didEffectiveSizeChange = (previousSize || 0) !== nextSize;
4646
4665
  const didReadyAnchorChange = previousReadyAnchorIndex !== nextAnchorIndex || previousReadyAnchorKey !== nextAnchorKey;
4647
4666
  if (isReady && (didSizeChange || didReadyAnchorChange)) {
4648
4667
  state.anchoredEndSpaceReadyAnchorIndex = nextAnchorIndex;
@@ -4651,8 +4670,9 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4651
4670
  set$(ctx, "anchoredEndSpaceSize", nextSize);
4652
4671
  (_a3 = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onSizeChanged) == null ? void 0 : _a3.call(anchoredEndSpace, nextSize);
4653
4672
  }
4654
- if (didSizeChange && (anchoredEndSpace == null ? void 0 : anchoredEndSpace.includeInEndInset)) {
4655
- updateScroll(ctx, state.scroll, true);
4673
+ if (didEffectiveSizeChange) {
4674
+ updateContentMetricsState(ctx);
4675
+ updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
4656
4676
  }
4657
4677
  (_b = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onReady) == null ? void 0 : _b.call(anchoredEndSpace, { anchorIndex: nextAnchorIndex, anchorKey: nextAnchorKey, size: nextSize });
4658
4678
  }
@@ -4681,16 +4701,10 @@ function runOrScheduleMVCPRecalculate(ctx) {
4681
4701
  }
4682
4702
  } else if (Platform.OS === "web") {
4683
4703
  if (!state.mvcpAnchorLock) {
4684
- if (state.queuedMVCPRecalculate !== void 0) {
4685
- cancelAnimationFrame(state.queuedMVCPRecalculate);
4686
- state.queuedMVCPRecalculate = void 0;
4687
- }
4704
+ state.scheduledWork.cancel("mvcpRecalculate");
4688
4705
  calculateItemsInView(ctx, { doMVCP: true });
4689
- } else if (state.queuedMVCPRecalculate === void 0) {
4690
- state.queuedMVCPRecalculate = requestAnimationFrame(() => {
4691
- state.queuedMVCPRecalculate = void 0;
4692
- calculateItemsInView(ctx, { doMVCP: true });
4693
- });
4706
+ } else if (!state.scheduledWork.has("mvcpRecalculate")) {
4707
+ state.scheduledWork.frame(() => calculateItemsInView(ctx, { doMVCP: true }), "mvcpRecalculate");
4694
4708
  }
4695
4709
  } else {
4696
4710
  calculateItemsInView(ctx, { doMVCP: true });
@@ -4737,6 +4751,9 @@ function flushItemSizeUpdates(ctx, result) {
4737
4751
  } else if (result.didMeasureUserScrollAnchorResetItem && ((_a3 = state.userScrollAnchorReset) == null ? void 0 : _a3.keys.size) === 0) {
4738
4752
  state.userScrollAnchorReset = void 0;
4739
4753
  }
4754
+ if (result.didChange) {
4755
+ maybeUpdateAnchoredEndSpace(ctx);
4756
+ }
4740
4757
  if (result.didChange && result.shouldMaintainScrollAtEnd) {
4741
4758
  doMaintainScrollAtEnd(ctx);
4742
4759
  }
@@ -4826,7 +4843,6 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
4826
4843
  previous: size - diff,
4827
4844
  size
4828
4845
  });
4829
- maybeUpdateAnchoredEndSpace(ctx);
4830
4846
  }
4831
4847
  if (minIndexSizeChanged !== void 0) {
4832
4848
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
@@ -5666,19 +5682,34 @@ function ContainerSlotBase({
5666
5682
  var ContainerSlot = typedMemo(function ContainerSlot2(props) {
5667
5683
  return /* @__PURE__ */ React2__namespace.createElement(ContainerSlotBase, { ...props });
5668
5684
  });
5685
+ function useFreshDataTransitionVisibility(readyToRender, transitionEpoch) {
5686
+ const completedTransitionEpoch = React2.useRef(transitionEpoch);
5687
+ const isTransitionPending = completedTransitionEpoch.current !== transitionEpoch;
5688
+ React2.useLayoutEffect(() => {
5689
+ if (!readyToRender) {
5690
+ completedTransitionEpoch.current = transitionEpoch;
5691
+ }
5692
+ }, [readyToRender, transitionEpoch]);
5693
+ return readyToRender && !isTransitionPending;
5694
+ }
5669
5695
 
5670
5696
  // src/components/Containers.native.tsx
5671
- var ContainersLayer = typedMemo(function ContainersLayer2({ children, horizontal }) {
5697
+ var ContainersLayer = typedMemo(function ContainersLayer2({
5698
+ children,
5699
+ freshDataTransitionEpoch,
5700
+ horizontal
5701
+ }) {
5672
5702
  const ctx = useStateContext();
5673
5703
  const columnWrapperStyle = ctx.columnWrapperStyle;
5674
5704
  const animSize = useValue$("totalSize");
5675
5705
  const [readyToRender, numColumns, otherAxisSize = 0] = useArr$(["readyToRender", "numColumns", "otherAxisSize"]);
5706
+ const isVisible = useFreshDataTransitionVisibility(!!readyToRender, freshDataTransitionEpoch);
5676
5707
  const style = horizontal ? {
5677
5708
  height: otherAxisSize || "100%",
5678
5709
  minHeight: otherAxisSize,
5679
- opacity: readyToRender ? 1 : 0,
5710
+ opacity: isVisible ? 1 : 0,
5680
5711
  width: animSize
5681
- } : { height: animSize, minWidth: otherAxisSize, opacity: readyToRender ? 1 : 0 };
5712
+ } : { height: animSize, minWidth: otherAxisSize, opacity: isVisible ? 1 : 0 };
5682
5713
  if (columnWrapperStyle) {
5683
5714
  const { columnGap, rowGap, gap } = columnWrapperStyle;
5684
5715
  const gapX = columnGap || gap || 0;
@@ -5699,9 +5730,10 @@ var ContainersLayer = typedMemo(function ContainersLayer2({ children, horizontal
5699
5730
  }
5700
5731
  }
5701
5732
  }
5702
- return /* @__PURE__ */ React2__namespace.createElement(ReactNative.Animated.View, { style }, /* @__PURE__ */ React2__namespace.createElement(ContainerLayoutCoordinator, null, children));
5733
+ return /* @__PURE__ */ React2__namespace.createElement(ReactNative.Animated.View, { pointerEvents: isVisible ? void 0 : "none", style }, /* @__PURE__ */ React2__namespace.createElement(ContainerLayoutCoordinator, null, children));
5703
5734
  });
5704
5735
  var Containers = typedMemo(function Containers2({
5736
+ freshDataTransitionEpoch,
5705
5737
  horizontal,
5706
5738
  recycleItems,
5707
5739
  ItemSeparatorComponent,
@@ -5726,7 +5758,7 @@ var Containers = typedMemo(function Containers2({
5726
5758
  )
5727
5759
  );
5728
5760
  }
5729
- return /* @__PURE__ */ React2__namespace.createElement(ContainersLayer, { horizontal }, containers);
5761
+ return /* @__PURE__ */ React2__namespace.createElement(ContainersLayer, { freshDataTransitionEpoch, horizontal }, containers);
5730
5762
  });
5731
5763
  var ListComponentScrollView = ReactNative.Animated.ScrollView;
5732
5764
 
@@ -5765,16 +5797,6 @@ var SnapWrapper = React2__namespace.forwardRef(function SnapWrapperInner({ Scrol
5765
5797
  const [snapToOffsets] = useArr$(["snapToOffsets"]);
5766
5798
  return /* @__PURE__ */ React2__namespace.createElement(ScrollComponent, { ...props, ref, snapToOffsets });
5767
5799
  });
5768
- function WebAnchoredEndSpace({ horizontal }) {
5769
- const ctx = useStateContext();
5770
- const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
5771
- const shouldRenderAnchoredEndSpace = !!ctx.state.props.anchoredEndSpace && (anchoredEndSpaceSize || 0) > 0;
5772
- if (!shouldRenderAnchoredEndSpace) {
5773
- return null;
5774
- }
5775
- const style = horizontal ? { height: "100%", width: anchoredEndSpaceSize || 0 } : { height: anchoredEndSpaceSize || 0 };
5776
- return /* @__PURE__ */ React2__namespace.createElement("div", { style }, null);
5777
- }
5778
5800
 
5779
5801
  // src/core/updateContentMetrics.ts
5780
5802
  var SCROLL_ADJUST_EPSILON = 0.1;
@@ -5808,7 +5830,11 @@ function setHeaderSize(ctx, size) {
5808
5830
  state.didMeasureHeader = true;
5809
5831
  }
5810
5832
  function setFooterSize(ctx, size) {
5811
- return setContentLengthSignal(ctx, "footerSize", size);
5833
+ const didChange = setContentLengthSignal(ctx, "footerSize", size);
5834
+ if (didChange) {
5835
+ maybeUpdateAnchoredEndSpace(ctx);
5836
+ }
5837
+ return didChange;
5812
5838
  }
5813
5839
  function areInsetsEqual(left, right) {
5814
5840
  var _a3, _b, _c, _d, _e, _f, _g, _h;
@@ -5851,6 +5877,7 @@ var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
5851
5877
  const { onLayout } = useOnLayoutSync({ onLayoutChange, ref });
5852
5878
  return /* @__PURE__ */ React2__namespace.createElement(ReactNative.View, { ...rest, onLayout, ref });
5853
5879
  };
5880
+ var StyleSheet = ReactNative.StyleSheet;
5854
5881
 
5855
5882
  // src/components/ListComponent.tsx
5856
5883
  var AlignItemsAtEndSpacer = typedMemo(function AlignItemsAtEndSpacer2({ horizontal }) {
@@ -5868,6 +5895,7 @@ var AlignItemsAtEndSpacer = typedMemo(function AlignItemsAtEndSpacer2({ horizont
5868
5895
  });
5869
5896
  var ListComponent = typedMemo(function ListComponent2({
5870
5897
  canRender,
5898
+ freshDataTransitionEpoch,
5871
5899
  style,
5872
5900
  contentContainerStyle,
5873
5901
  horizontal,
@@ -5897,8 +5925,17 @@ var ListComponent = typedMemo(function ListComponent2({
5897
5925
  }) {
5898
5926
  const ctx = useStateContext();
5899
5927
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
5900
- const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
5928
+ const [anchoredEndSpaceSize = 0, otherAxisSize = 0] = useArr$(["anchoredEndSpaceSize", "otherAxisSize"]);
5901
5929
  const shouldRenderAlignItemsAtEndSpacer = ctx.state.props.alignItemsAtEndPaddingEnabled;
5930
+ const shouldMaterializeAnchoredEndSpace = !!ctx.state.props.anchoredEndSpace && ctx.state.props.anchoredEndSpaceOwner === "list" && anchoredEndSpaceSize > 0;
5931
+ let anchoredEndSpaceStyle;
5932
+ if (shouldMaterializeAnchoredEndSpace) {
5933
+ const paddingEnd = horizontal ? isHorizontalRTL(ctx.state) ? "Left" : "Right" : "Bottom";
5934
+ const flattenedContentContainerStyle = StyleSheet.flatten(contentContainerStyle);
5935
+ anchoredEndSpaceStyle = {
5936
+ [`padding${paddingEnd}`]: extractPadding({}, flattenedContentContainerStyle || {}, paddingEnd) + anchoredEndSpaceSize
5937
+ };
5938
+ }
5902
5939
  const autoOtherAxisStyle = getAutoOtherAxisStyle({
5903
5940
  horizontal,
5904
5941
  needsOtherAxisSize: ctx.state.needsOtherAxisSize,
@@ -5951,10 +5988,10 @@ var ListComponent = typedMemo(function ListComponent2({
5951
5988
  ...rest,
5952
5989
  ...Platform.OS === "web" ? ScrollComponent === ListComponentScrollView ? { onInternalScrollEnd, useWindowScroll } : {} : { onScrollBeginDrag: onInternalScrollBeginDrag },
5953
5990
  contentContainerStyle: [
5954
- horizontal ? {
5955
- height: "100%"
5956
- } : {},
5957
- contentContainerStyle
5991
+ horizontal ? { height: "100%" } : {},
5992
+ contentContainerStyle,
5993
+ anchoredEndSpaceStyle,
5994
+ Platform.OS === "web" ? { boxSizing: "border-box" } : void 0
5958
5995
  ],
5959
5996
  contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
5960
5997
  horizontal,
@@ -5972,6 +6009,7 @@ var ListComponent = typedMemo(function ListComponent2({
5972
6009
  canRender && !ListEmptyComponent && /* @__PURE__ */ React2__namespace.createElement(
5973
6010
  Containers,
5974
6011
  {
6012
+ freshDataTransitionEpoch,
5975
6013
  getRenderedItem: getRenderedItem2,
5976
6014
  horizontal,
5977
6015
  ItemSeparatorComponent,
@@ -5980,7 +6018,6 @@ var ListComponent = typedMemo(function ListComponent2({
5980
6018
  }
5981
6019
  ),
5982
6020
  ListFooterComponent && /* @__PURE__ */ React2__namespace.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
5983
- Platform.OS === "web" && /* @__PURE__ */ React2__namespace.createElement(WebAnchoredEndSpace, { horizontal }),
5984
6021
  IS_DEV && ENABLE_DEVMODE
5985
6022
  );
5986
6023
  });
@@ -5989,7 +6026,16 @@ var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
5989
6026
  var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
5990
6027
  function useDevChecksImpl(props) {
5991
6028
  const ctx = useStateContext();
5992
- const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
6029
+ const { anchoredEndSpace, childrenMode, keyExtractor, numColumns, renderScrollComponent, useWindowScroll } = props;
6030
+ const hasAnchoredEndSpace = !!anchoredEndSpace;
6031
+ React2.useEffect(() => {
6032
+ if (hasAnchoredEndSpace && (numColumns != null ? numColumns : 1) > 1) {
6033
+ warnDevOnce(
6034
+ "anchoredEndSpaceNumColumns",
6035
+ "anchoredEndSpace is only supported when numColumns is 1. Using it with multiple columns may produce incorrect anchored spacing."
6036
+ );
6037
+ }
6038
+ }, [hasAnchoredEndSpace, numColumns]);
5993
6039
  React2.useEffect(() => {
5994
6040
  if (useWindowScroll && renderScrollComponent) {
5995
6041
  warnDevOnce(
@@ -6317,6 +6363,59 @@ function onScroll(ctx, event) {
6317
6363
  }
6318
6364
  }
6319
6365
 
6366
+ // src/core/ScheduledWork.ts
6367
+ var ScheduledWork = class {
6368
+ constructor() {
6369
+ this.work = /* @__PURE__ */ new Map();
6370
+ }
6371
+ timeout(callback, delay, key) {
6372
+ if (key) {
6373
+ this.cancel(key);
6374
+ }
6375
+ const work = [void 0, clearTimeout];
6376
+ const handle = setTimeout(() => {
6377
+ const workKey = key != null ? key : handle;
6378
+ if (this.work.get(workKey) === work) {
6379
+ this.work.delete(workKey);
6380
+ callback();
6381
+ }
6382
+ }, delay);
6383
+ work[0] = handle;
6384
+ this.work.set(key != null ? key : handle, work);
6385
+ }
6386
+ frame(callback, key) {
6387
+ this.cancel(key);
6388
+ const work = [void 0, cancelAnimationFrame];
6389
+ this.work.set(key, work);
6390
+ work[0] = requestAnimationFrame(() => {
6391
+ if (this.work.get(key) === work) {
6392
+ this.work.delete(key);
6393
+ callback();
6394
+ }
6395
+ });
6396
+ }
6397
+ register(key, cancel) {
6398
+ this.cancel(key);
6399
+ this.work.set(key, [void 0, cancel]);
6400
+ }
6401
+ cancel(key) {
6402
+ const work = this.work.get(key);
6403
+ if (work) {
6404
+ this.work.delete(key);
6405
+ work[1](work[0]);
6406
+ }
6407
+ }
6408
+ has(key) {
6409
+ return this.work.has(key);
6410
+ }
6411
+ dispose() {
6412
+ for (const [handle, cancel] of this.work.values()) {
6413
+ cancel(handle);
6414
+ }
6415
+ this.work.clear();
6416
+ }
6417
+ };
6418
+
6320
6419
  // src/core/ScrollAdjustHandler.ts
6321
6420
  var ScrollAdjustHandler = class {
6322
6421
  constructor(ctx) {
@@ -6404,7 +6503,6 @@ var useCombinedRef = (...refs) => {
6404
6503
  }, refs);
6405
6504
  return callback;
6406
6505
  };
6407
- var StyleSheet = ReactNative.StyleSheet;
6408
6506
  function useStickyScrollHandler(stickyHeaderIndices, horizontal, ctx, onScroll2) {
6409
6507
  const shouldUseRnAnimatedEngine = !ctx.state.props.stickyPositionComponentInternal;
6410
6508
  return React2.useMemo(() => {
@@ -6491,7 +6589,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6491
6589
  const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
6492
6590
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
6493
6591
  let imperativeScrollToken = 0;
6494
- const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0;
6592
+ const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.scheduledWork.has("mvcpRecalculate") || state.ignoreScrollFromMVCP !== void 0;
6495
6593
  const isScrollToIndexReady = (targetIndex, allowEmpty = false) => {
6496
6594
  var _a3;
6497
6595
  const props = state.props;
@@ -6525,9 +6623,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6525
6623
  run();
6526
6624
  return;
6527
6625
  }
6528
- requestAnimationFrame(check);
6626
+ state.scheduledWork.frame(check, "imperativeScrollReady");
6529
6627
  };
6530
- requestAnimationFrame(check);
6628
+ state.scheduledWork.frame(check, "imperativeScrollReady");
6531
6629
  };
6532
6630
  const runScrollRequest = (token, resolve, run, isReady = () => true) => {
6533
6631
  const runNow = () => {
@@ -6549,10 +6647,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6549
6647
  }
6550
6648
  };
6551
6649
  const startImperativeScroll = (resolve) => {
6552
- var _a3;
6650
+ state.scheduledWork.cancel("imperativeScrollReady");
6553
6651
  const token = ++imperativeScrollToken;
6554
- state.pendingScrollToEnd = void 0;
6555
- (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
6652
+ settlePendingImperativeScroll(state);
6556
6653
  state.pendingScrollResolve = resolve;
6557
6654
  return token;
6558
6655
  };
@@ -6636,6 +6733,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6636
6733
  end: state.endNoBuffer,
6637
6734
  endBuffered: state.endBuffered,
6638
6735
  getAverageItemSizes: () => getAverageItemSizes(state),
6736
+ indexByKey: (key) => state.indexByKey.get(key),
6639
6737
  isAtEnd: peek$(ctx, "isAtEnd"),
6640
6738
  isAtStart: peek$(ctx, "isAtStart"),
6641
6739
  isEndReached: state.isEndReached,
@@ -6939,7 +7037,7 @@ var LegendList = typedMemo(
6939
7037
  })
6940
7038
  );
6941
7039
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
6942
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
7040
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
6943
7041
  const noopOnScroll = React2.useCallback((_event) => {
6944
7042
  }, []);
6945
7043
  if (props.recycleItems === void 0) {
@@ -7015,9 +7113,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7015
7113
  ...rest
7016
7114
  } = props;
7017
7115
  const animatedPropsInternal = props.animatedPropsInternal;
7116
+ const anchoredEndSpaceOwner = (_a3 = props.anchoredEndSpaceOwnerInternal) != null ? _a3 : "list";
7018
7117
  const positionComponentInternal = props.positionComponentInternal;
7019
7118
  const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
7020
7119
  const {
7120
+ anchoredEndSpaceOwnerInternal: _anchoredEndSpaceOwnerInternal,
7021
7121
  positionComponentInternal: _positionComponentInternal,
7022
7122
  stickyPositionComponentInternal: _stickyPositionComponentInternal,
7023
7123
  ...restProps
@@ -7039,6 +7139,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7039
7139
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
7040
7140
  const stylePaddingLeftState = extractPadding(style, contentContainerStyle, "Left");
7041
7141
  const stylePaddingRightState = extractPadding(style, contentContainerStyle, "Right");
7142
+ const stylePaddingEndState = getStylePaddingEnd({
7143
+ horizontal,
7144
+ rtl,
7145
+ stylePaddingBottom: stylePaddingBottomState,
7146
+ stylePaddingLeft: stylePaddingLeftState,
7147
+ stylePaddingRight: stylePaddingRightState
7148
+ });
7042
7149
  const maintainScrollAtEndConfig = normalizeMaintainScrollAtEnd(maintainScrollAtEnd);
7043
7150
  const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
7044
7151
  maintainVisibleContentPositionProp
@@ -7051,13 +7158,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7051
7158
  const initialScrollProp = initialScrollAtEnd ? {
7052
7159
  index: Math.max(0, dataProp.length - 1),
7053
7160
  preserveForBottomPadding: true,
7054
- viewOffset: -stylePaddingBottomState,
7161
+ viewOffset: -stylePaddingEndState,
7055
7162
  viewPosition: 1
7056
7163
  } : hasInitialScrollIndex ? typeof initialScrollIndexProp === "object" ? {
7057
- index: (_a3 = initialScrollIndexProp.index) != null ? _a3 : 0,
7164
+ index: (_b = initialScrollIndexProp.index) != null ? _b : 0,
7058
7165
  preserveForBottomPadding: initialScrollIndexProp.viewOffset === void 0 && initialScrollIndexProp.viewPosition === 1 ? true : void 0,
7059
- viewOffset: (_b = initialScrollIndexProp.viewOffset) != null ? _b : initialScrollIndexProp.viewPosition === 1 ? -stylePaddingBottomState : 0,
7060
- viewPosition: (_c = initialScrollIndexProp.viewPosition) != null ? _c : 0
7166
+ viewOffset: (_c = initialScrollIndexProp.viewOffset) != null ? _c : initialScrollIndexProp.viewPosition === 1 ? -stylePaddingEndState : 0,
7167
+ viewPosition: (_d = initialScrollIndexProp.viewPosition) != null ? _d : 0
7061
7168
  } : {
7062
7169
  index: initialScrollIndexProp != null ? initialScrollIndexProp : 0,
7063
7170
  viewOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : 0
@@ -7070,7 +7177,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7070
7177
  const [, scheduleImperativeScrollCommit] = React2__namespace.useReducer((value) => value + 1, 0);
7071
7178
  const ctx = useStateContext();
7072
7179
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
7073
- 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;
7180
+ const scrollAxisGap = horizontal ? (_g = (_e = ctx.columnWrapperStyle) == null ? void 0 : _e.columnGap) != null ? _g : (_f = ctx.columnWrapperStyle) == null ? void 0 : _f.gap : (_j = (_h = ctx.columnWrapperStyle) == null ? void 0 : _h.rowGap) != null ? _j : (_i = ctx.columnWrapperStyle) == null ? void 0 : _i.gap;
7074
7181
  const nextScrollAxisGap = typeof scrollAxisGap === "number" && Number.isFinite(scrollAxisGap) ? scrollAxisGap : 0;
7075
7182
  const refScroller = React2.useRef(null);
7076
7183
  const combinedRef = useCombinedRef(refScroller, refScrollView);
@@ -7085,8 +7192,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7085
7192
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex,
7086
7193
  alwaysRender == null ? void 0 : alwaysRender.top,
7087
7194
  alwaysRender == null ? void 0 : alwaysRender.bottom,
7088
- (_j = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _j.join(","),
7089
- (_k = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _k.join(","),
7195
+ (_k = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _k.join(","),
7196
+ (_l = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _l.join(","),
7090
7197
  dataProp,
7091
7198
  dataKey,
7092
7199
  dataVersion,
@@ -7099,7 +7206,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7099
7206
  if (!refState.current) {
7100
7207
  if (!ctx.state) {
7101
7208
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { height: 0, width: 0 } : getWindowSize())[horizontal ? "width" : "height"];
7102
- ctx.values.set("adaptiveRender", (_l = experimental_adaptiveRender == null ? void 0 : experimental_adaptiveRender.initialMode) != null ? _l : "normal");
7209
+ ctx.values.set("adaptiveRender", (_m = experimental_adaptiveRender == null ? void 0 : experimental_adaptiveRender.initialMode) != null ? _m : "normal");
7103
7210
  ctx.state = {
7104
7211
  averageSizes: {},
7105
7212
  columnSpans: [],
@@ -7118,6 +7225,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7118
7225
  endNoBuffer: -1,
7119
7226
  endReachedSnapshot: void 0,
7120
7227
  firstFullyOnScreenIndex: -1,
7228
+ freshDataTransitionEpoch: 0,
7121
7229
  hasHadNonEmptyData: dataProp.length > 0,
7122
7230
  idCache: [],
7123
7231
  idsInView: [],
@@ -7142,8 +7250,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7142
7250
  positions: [],
7143
7251
  props: {},
7144
7252
  queuedCalculateItemsInView: 0,
7145
- queuedFullDrawDistancePrewarm: void 0,
7146
7253
  refScroller: { current: null },
7254
+ scheduledWork: new ScheduledWork(),
7147
7255
  scroll: 0,
7148
7256
  scrollAdjustHandler: new ScrollAdjustHandler(ctx),
7149
7257
  scrollForNextCalculateItemsInView: void 0,
@@ -7161,8 +7269,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7161
7269
  startReachedSnapshot: void 0,
7162
7270
  stickyContainerPool: /* @__PURE__ */ new Set(),
7163
7271
  stickyContainers: /* @__PURE__ */ new Map(),
7164
- timeoutAdaptiveRender: void 0,
7165
- timeouts: /* @__PURE__ */ new Set(),
7166
7272
  totalSize: 0,
7167
7273
  viewabilityConfigCallbackPairs: void 0
7168
7274
  };
@@ -7184,13 +7290,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7184
7290
  const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
7185
7291
  ctx.scrollAxisGap = nextScrollAxisGap;
7186
7292
  state.didColumnsChange = numColumnsProp !== previousNumColumnsProp || didScrollAxisGapChange;
7187
- const previousDataLength = (_n = (_m = state.props.data) == null ? void 0 : _m.length) != null ? _n : 0;
7293
+ const previousDataLength = (_o = (_n = state.props.data) == null ? void 0 : _n.length) != null ? _o : 0;
7188
7294
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
7189
7295
  const didDataKeyChangeLocal = state.props.dataKey !== dataKey;
7190
7296
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
7191
7297
  const didDataChangeLocal = didDataKeyChangeLocal || didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
7192
7298
  const shouldResetFreshDataLayout = !isFirstLocal && didDataChangeLocal && state.hasHadNonEmptyData && (didDataKeyChangeLocal || previousDataLength === 0) && dataProp.length > 0;
7193
- if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_o = state.initialScroll) == null ? void 0 : _o.viewPosition) === 1 && state.props.data.length > 0) {
7299
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_p = state.initialScroll) == null ? void 0 : _p.viewPosition) === 1 && state.props.data.length > 0) {
7194
7300
  clearPreservedInitialScrollTarget(state);
7195
7301
  }
7196
7302
  if (didDataChangeLocal) {
@@ -7199,10 +7305,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7199
7305
  state.didDataChange = true;
7200
7306
  state.previousData = state.props.data;
7201
7307
  }
7308
+ if (shouldResetFreshDataLayout) {
7309
+ state.freshDataTransitionEpoch += 1;
7310
+ }
7202
7311
  const throttledOnScroll = useThrottledOnScroll(onScrollProp != null ? onScrollProp : noopOnScroll, scrollEventThrottle != null ? scrollEventThrottle : 0);
7203
7312
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? throttledOnScroll : onScrollProp;
7204
- const anchoredEndSpaceResolved = Platform.OS === "web" && anchoredEndSpace ? { ...anchoredEndSpace, includeInEndInset: true } : anchoredEndSpace;
7205
- const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_p = state.props.anchoredEndSpace) == null ? void 0 : _p.anchorIndex) !== (anchoredEndSpaceResolved == null ? void 0 : anchoredEndSpaceResolved.anchorIndex);
7313
+ const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_q = state.props.anchoredEndSpace) == null ? void 0 : _q.anchorIndex) !== (anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex);
7206
7314
  state.props = {
7207
7315
  adaptiveRender: experimental_adaptiveRender,
7208
7316
  alignItemsAtEnd,
@@ -7210,7 +7318,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7210
7318
  alwaysRender,
7211
7319
  alwaysRenderIndicesArr: alwaysRenderIndices.arr,
7212
7320
  alwaysRenderIndicesSet: alwaysRenderIndices.set,
7213
- anchoredEndSpace: anchoredEndSpaceResolved,
7321
+ anchoredEndSpace,
7322
+ anchoredEndSpaceOwner,
7214
7323
  animatedProps: animatedPropsInternal,
7215
7324
  contentContainerAlignItems: contentContainerStyle.alignItems,
7216
7325
  contentInset,
@@ -7259,12 +7368,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7259
7368
  if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
7260
7369
  resetAdaptiveRender(ctx);
7261
7370
  }
7262
- if (shouldResetFreshDataLayout) {
7263
- resetInitialRenderState(ctx, {
7264
- resetInitialScroll: !!initialScrollProp,
7265
- resetLayout: true
7266
- });
7267
- }
7268
7371
  const memoizedLastItemKeys = React2.useMemo(() => {
7269
7372
  if (!dataProp.length) return [];
7270
7373
  return Array.from(
@@ -7328,6 +7431,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7328
7431
  useDevChecks(props);
7329
7432
  }
7330
7433
  React2.useLayoutEffect(() => {
7434
+ if (shouldResetFreshDataLayout) {
7435
+ resetInitialRenderState(ctx, {
7436
+ resetInitialScroll: !!initialScrollProp,
7437
+ resetLayout: true
7438
+ });
7439
+ }
7331
7440
  handleInitialScrollDataChange(ctx, {
7332
7441
  dataLength: dataProp.length,
7333
7442
  didDataChange: didDataChangeLocal,
@@ -7335,7 +7444,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7335
7444
  initialScrollAtEnd,
7336
7445
  latestInitialScroll: initialScrollProp,
7337
7446
  latestInitialScrollSessionKind: initialScrollUsesOffsetOnly ? "offset" : "bootstrap",
7338
- stylePaddingBottom: stylePaddingBottomState,
7447
+ stylePaddingEnd: stylePaddingEndState,
7339
7448
  useBootstrapInitialScroll: usesBootstrapInitialScroll
7340
7449
  });
7341
7450
  }, [
@@ -7344,7 +7453,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7344
7453
  didDataChangeLocal,
7345
7454
  shouldResetFreshDataLayout,
7346
7455
  initialScrollAtEnd,
7347
- stylePaddingBottomState,
7456
+ stylePaddingEndState,
7348
7457
  usesBootstrapInitialScroll
7349
7458
  ]);
7350
7459
  React2.useLayoutEffect(() => {
@@ -7362,7 +7471,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7362
7471
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorMaxSize,
7363
7472
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorOffset,
7364
7473
  didAnchoredEndSpaceAnchorIndexChange,
7365
- numColumnsProp
7474
+ horizontal,
7475
+ numColumnsProp,
7476
+ rtl,
7477
+ stylePaddingBottomState,
7478
+ stylePaddingLeftState,
7479
+ stylePaddingRightState
7366
7480
  ]);
7367
7481
  React2.useLayoutEffect(() => {
7368
7482
  const previousContentInsetEndAdjustment = previousContentInsetEndAdjustmentRef.current;
@@ -7378,10 +7492,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7378
7492
  dataLength: dataProp.length,
7379
7493
  footerSize: layout[horizontal ? "width" : "height"],
7380
7494
  initialScrollAtEnd,
7381
- stylePaddingBottom: stylePaddingBottomState
7495
+ stylePaddingEnd: stylePaddingEndState
7382
7496
  });
7383
7497
  },
7384
- [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingBottomState, usesBootstrapInitialScroll]
7498
+ [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingEndState, usesBootstrapInitialScroll]
7385
7499
  );
7386
7500
  const onLayoutChange = React2.useCallback(
7387
7501
  (layout, fromLayoutEffect) => {
@@ -7398,7 +7512,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7398
7512
  }
7399
7513
  advanceCurrentInitialScrollSession(ctx);
7400
7514
  },
7401
- [dataProp.length, initialScrollAtEnd, stylePaddingBottomState, usesBootstrapInitialScroll]
7515
+ [dataProp.length, initialScrollAtEnd, stylePaddingEndState, usesBootstrapInitialScroll]
7402
7516
  );
7403
7517
  const { onLayout } = useOnLayoutSync({
7404
7518
  onLayoutChange,
@@ -7494,14 +7608,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7494
7608
  React2.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, scheduleImperativeScrollCommit), []);
7495
7609
  React2.useEffect(() => {
7496
7610
  return () => {
7497
- if (state.queuedFullDrawDistancePrewarm !== void 0) {
7498
- cancelAnimationFrame(state.queuedFullDrawDistancePrewarm);
7499
- state.queuedFullDrawDistancePrewarm = void 0;
7500
- }
7501
- for (const timeout of state.timeouts) {
7502
- clearTimeout(timeout);
7503
- }
7504
- state.timeouts.clear();
7611
+ cancelImperativeScroll(state);
7612
+ state.scheduledWork.dispose();
7505
7613
  };
7506
7614
  }, [state]);
7507
7615
  React2.useLayoutEffect(() => {
@@ -7543,6 +7651,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7543
7651
  canRender,
7544
7652
  contentContainerStyle,
7545
7653
  contentInset,
7654
+ freshDataTransitionEpoch: state.freshDataTransitionEpoch,
7546
7655
  getRenderedItem: fns.getRenderedItem,
7547
7656
  horizontal,
7548
7657
  initialContentOffset,
@@ -7558,7 +7667,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7558
7667
  onScroll: onScrollHandler,
7559
7668
  recycleItems,
7560
7669
  refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React2__namespace.cloneElement(refreshControlElement, {
7561
- progressViewOffset: ((_q = refreshControlElement.props.progressViewOffset) != null ? _q : 0) + stylePaddingTopState
7670
+ progressViewOffset: ((_r = refreshControlElement.props.progressViewOffset) != null ? _r : 0) + stylePaddingTopState
7562
7671
  }) : refreshControlElement : onRefresh && /* @__PURE__ */ React2__namespace.createElement(
7563
7672
  ReactNative.RefreshControl,
7564
7673
  {
@@ -7569,7 +7678,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7569
7678
  ),
7570
7679
  refScrollView: combinedRef,
7571
7680
  renderScrollComponent,
7572
- scrollAdjustHandler: (_r = refState.current) == null ? void 0 : _r.scrollAdjustHandler,
7681
+ scrollAdjustHandler: (_s = refState.current) == null ? void 0 : _s.scrollAdjustHandler,
7573
7682
  scrollEventThrottle: 0,
7574
7683
  snapToIndices,
7575
7684
  stickyHeaderIndices,