@legendapp/list 3.3.3 → 3.3.5

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
@@ -442,6 +457,28 @@ var EDGE_POSITION_EPSILON = 1;
442
457
  var ENABLE_DEVMODE = IS_DEV && false;
443
458
  var ENABLE_DEBUG_VIEW = IS_DEV && false;
444
459
 
460
+ // src/core/cancelImperativeScroll.ts
461
+ function cancelScrollCompletionChecks({ scheduledWork }) {
462
+ scheduledWork.cancel("checkFinishedScrollFrame");
463
+ scheduledWork.cancel("checkFinishedScrollRetryFrame");
464
+ scheduledWork.cancel("checkFinishedScrollFallback");
465
+ scheduledWork.cancel("platformScrollCompletion");
466
+ }
467
+ function settlePendingImperativeScroll(state) {
468
+ var _a3, _b;
469
+ const resolvePendingScroll = (_b = state.pendingScrollResolve) != null ? _b : (_a3 = state.pendingScrollToEnd) == null ? void 0 : _a3.resolve;
470
+ state.pendingScrollResolve = void 0;
471
+ state.pendingScrollToEnd = void 0;
472
+ resolvePendingScroll == null ? void 0 : resolvePendingScroll();
473
+ }
474
+ function cancelImperativeScroll(state) {
475
+ cancelScrollCompletionChecks(state);
476
+ state.scheduledWork.cancel("imperativeScrollReady");
477
+ state.scrollingTo = void 0;
478
+ state.scrollTargetPinnedRange = void 0;
479
+ settlePendingImperativeScroll(state);
480
+ }
481
+
445
482
  // src/core/deferredPublicOnScroll.ts
446
483
  function withResolvedContentOffset(state, event, resolvedOffset) {
447
484
  return {
@@ -810,13 +847,7 @@ var DEFAULT_WEB_ADAPTIVE_RENDER_ENTER_VELOCITY = 6;
810
847
  var DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_VELOCITY = 3;
811
848
  var DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_DELAY = 250;
812
849
  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
- }
850
+ ctx.state.scheduledWork.cancel("adaptiveRender");
820
851
  }
821
852
  function scheduleAdaptiveRenderExit(ctx, exitDelay) {
822
853
  const state = ctx.state;
@@ -824,13 +855,7 @@ function scheduleAdaptiveRenderExit(ctx, exitDelay) {
824
855
  if (exitDelay <= 0) {
825
856
  setAdaptiveRender(ctx, "normal", "scroll");
826
857
  } 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);
858
+ state.scheduledWork.timeout(() => setAdaptiveRender(ctx, "normal", "scroll"), exitDelay, "adaptiveRender");
834
859
  }
835
860
  }
836
861
  function setAdaptiveRender(ctx, mode, reason) {
@@ -862,7 +887,7 @@ function updateAdaptiveRender(ctx, scrollVelocity, options) {
862
887
  const exitDelay = (_c = adaptiveRender.exitDelay) != null ? _c : isWeb ? DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_DELAY : DEFAULT_ADAPTIVE_RENDER_EXIT_DELAY;
863
888
  const threshold = currentMode === "light" ? exitVelocity : enterVelocity;
864
889
  const nextMode = (options == null ? void 0 : options.forceLight) || Math.abs(scrollVelocity) > threshold ? "light" : "normal";
865
- const previousMode = state.timeoutAdaptiveRender !== void 0 ? "normal" : currentMode;
890
+ const previousMode = state.scheduledWork.has("adaptiveRender") ? "normal" : currentMode;
866
891
  if (nextMode !== previousMode) {
867
892
  if (nextMode === "light") {
868
893
  setAdaptiveRender(ctx, "light", "scroll");
@@ -889,14 +914,13 @@ function getEffectiveDrawDistance(ctx, mode) {
889
914
  }
890
915
  function scheduleFullDrawDistancePrewarm(ctx) {
891
916
  const { state } = ctx;
892
- if (state.props.drawDistance <= INITIAL_DRAW_DISTANCE || state.queuedFullDrawDistancePrewarm !== void 0) {
917
+ if (state.props.drawDistance <= INITIAL_DRAW_DISTANCE || state.scheduledWork.has("fullDrawDistancePrewarm")) {
893
918
  return;
894
919
  }
895
- state.queuedFullDrawDistancePrewarm = requestAnimationFrame(() => {
920
+ state.scheduledWork.frame(() => {
896
921
  var _a3;
897
- state.queuedFullDrawDistancePrewarm = void 0;
898
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
899
- });
922
+ return (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
923
+ }, "fullDrawDistancePrewarm");
900
924
  }
901
925
 
902
926
  // src/utils/setInitialRenderState.ts
@@ -954,10 +978,7 @@ function syncInitialScrollOffset(state, offset) {
954
978
  state.scrollPrev = offset;
955
979
  }
956
980
  function clearPreservedInitialScrollTargetTimeout(state) {
957
- if (state.timeoutPreservedInitialScrollClear !== void 0) {
958
- clearTimeout(state.timeoutPreservedInitialScrollClear);
959
- state.timeoutPreservedInitialScrollClear = void 0;
960
- }
981
+ state.scheduledWork.cancel("preservedInitialScroll");
961
982
  }
962
983
  function clearPreservedInitialScrollTarget(state) {
963
984
  clearPreservedInitialScrollTargetTimeout(state);
@@ -965,6 +986,24 @@ function clearPreservedInitialScrollTarget(state) {
965
986
  state.initialScroll = void 0;
966
987
  setInitialScrollSession(state);
967
988
  }
989
+ function supersedeInitialScroll(ctx) {
990
+ var _a3, _b, _c;
991
+ const state = ctx.state;
992
+ const bootstrapInitialScroll = ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap" ? state.initialScrollSession.bootstrap : void 0;
993
+ if (state.initialScroll || bootstrapInitialScroll || ((_b = state.scrollingTo) == null ? void 0 : _b.isInitialScroll)) {
994
+ if ((bootstrapInitialScroll == null ? void 0 : bootstrapInitialScroll.frameHandle) !== void 0 && typeof cancelAnimationFrame === "function") {
995
+ cancelAnimationFrame(bootstrapInitialScroll.frameHandle);
996
+ }
997
+ if ((_c = state.scrollingTo) == null ? void 0 : _c.isInitialScroll) {
998
+ cancelScrollCompletionChecks(state);
999
+ state.scrollingTo = void 0;
1000
+ state.scrollTargetPinnedRange = void 0;
1001
+ }
1002
+ initialScrollCompletion.resetFlags(state);
1003
+ setInitialScrollSession(state, { bootstrap: null });
1004
+ finishInitialScroll(ctx);
1005
+ }
1006
+ }
968
1007
  function finishInitialScroll(ctx, options) {
969
1008
  var _a3, _b, _c;
970
1009
  const state = ctx.state;
@@ -986,14 +1025,17 @@ function finishInitialScroll(ctx, options) {
986
1025
  setInitialScrollSession(state);
987
1026
  clearPreservedInitialScrollTargetTimeout(state);
988
1027
  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);
1028
+ state.scheduledWork.timeout(
1029
+ () => {
1030
+ var _a5;
1031
+ if (!state.didFinishInitialScroll || ((_a5 = state.scrollingTo) == null ? void 0 : _a5.isInitialScroll) || !state.initialScroll) {
1032
+ return;
1033
+ }
1034
+ clearPreservedInitialScrollTarget(state);
1035
+ },
1036
+ PRESERVED_INITIAL_SCROLL_FALLBACK_CLEAR_DELAY_MS,
1037
+ "preservedInitialScroll"
1038
+ );
997
1039
  }
998
1040
  } else {
999
1041
  clearPreservedInitialScrollTarget(state);
@@ -1020,9 +1062,11 @@ function calculateOffsetForIndex(ctx, index) {
1020
1062
  return index !== void 0 ? state.positions[index] || 0 : 0;
1021
1063
  }
1022
1064
 
1023
- // src/core/getTopOffsetAdjustment.ts
1024
- function getTopOffsetAdjustment(ctx) {
1025
- return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
1065
+ // src/core/getStartOffsetAdjustment.ts
1066
+ function getStartOffsetAdjustment(ctx) {
1067
+ const { state } = ctx;
1068
+ const stylePaddingStart = state.props.horizontal ? (isHorizontalRTL(state) ? state.props.stylePaddingRight : state.props.stylePaddingLeft) || 0 : peek$(ctx, "stylePaddingTop") || 0;
1069
+ return stylePaddingStart + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
1026
1070
  }
1027
1071
 
1028
1072
  // src/utils/getId.ts
@@ -1235,9 +1279,9 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1235
1279
  offset -= viewOffset;
1236
1280
  }
1237
1281
  if (index !== void 0) {
1238
- const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
1239
- if (topOffsetAdjustment) {
1240
- offset += topOffsetAdjustment;
1282
+ const startOffsetAdjustment = getStartOffsetAdjustment(ctx);
1283
+ if (startOffsetAdjustment) {
1284
+ offset += startOffsetAdjustment;
1241
1285
  }
1242
1286
  }
1243
1287
  if (viewPosition !== void 0 && index !== void 0) {
@@ -1247,7 +1291,8 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1247
1291
  }
1248
1292
  const isOutOfBounds = index < 0 || index >= dataLength;
1249
1293
  const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
1250
- const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1294
+ const measuredItemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1295
+ const itemSize = Math.max(0, measuredItemSize - (isOutOfBounds ? 0 : ctx.scrollAxisGap));
1251
1296
  const trailingInset = getContentInsetEnd(ctx);
1252
1297
  offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1253
1298
  if (!isOutOfBounds && index === state.props.data.length - 1) {
@@ -1279,6 +1324,7 @@ function finishScrollTo(ctx) {
1279
1324
  var _a3, _b;
1280
1325
  const state = ctx.state;
1281
1326
  if (state == null ? void 0 : state.scrollingTo) {
1327
+ cancelScrollCompletionChecks(state);
1282
1328
  const resolvePendingScroll = state.pendingScrollResolve;
1283
1329
  state.pendingScrollResolve = void 0;
1284
1330
  const scrollingTo = state.scrollingTo;
@@ -1327,7 +1373,7 @@ function checkFinishedScroll(ctx, options) {
1327
1373
  return;
1328
1374
  }
1329
1375
  }
1330
- ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
1376
+ ctx.state.scheduledWork.frame(() => checkFinishedScrollFrame(ctx), "checkFinishedScrollFrame");
1331
1377
  }
1332
1378
  function hasScrollCompletionOwnership(state, options) {
1333
1379
  const { clampedTargetOffset, scrollingTo } = options;
@@ -1397,7 +1443,6 @@ function checkFinishedScrollFrame(ctx) {
1397
1443
  return;
1398
1444
  }
1399
1445
  const { state } = ctx;
1400
- state.animFrameCheckFinishedScroll = void 0;
1401
1446
  const completionState = getResolvedScrollCompletionState(ctx, scrollingTo);
1402
1447
  if (completionState.isAtResolvedTarget && hasScrollCompletionOwnership(state, {
1403
1448
  clampedTargetOffset: completionState.clampedTargetOffset,
@@ -1416,61 +1461,62 @@ function scrollToFallbackOffset(ctx, offset) {
1416
1461
  }
1417
1462
  function checkFinishedScrollFallback(ctx) {
1418
1463
  const state = ctx.state;
1464
+ if (state.scheduledWork.has("checkFinishedScrollFallback")) {
1465
+ return;
1466
+ }
1419
1467
  const scrollingTo = state.scrollingTo;
1420
1468
  const shouldFinishInitialZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
1421
1469
  const silentInitialDispatch = isSilentInitialDispatch(state, scrollingTo);
1422
1470
  const canFinishInitialWithoutNativeProgress = scrollingTo !== void 0 ? shouldFinishInitialScrollWithoutNativeProgress(state, scrollingTo) : false;
1423
1471
  const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) && !shouldFinishInitialZeroTarget && !canFinishInitialWithoutNativeProgress || !state.didContainersLayout;
1424
1472
  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
1473
+ let numChecks = 0;
1474
+ const scheduleFallbackCheck = (delay) => {
1475
+ state.scheduledWork.timeout(checkHasScrolled, delay, "checkFinishedScrollFallback");
1476
+ };
1477
+ const checkHasScrolled = () => {
1478
+ var _a3, _b, _c, _d;
1479
+ const isStillScrollingTo = state.scrollingTo;
1480
+ if (isStillScrollingTo) {
1481
+ numChecks++;
1482
+ const isNativeInitialPending = isNativeInitialNonZeroTarget(state) && !state.hasScrolled;
1483
+ const maxChecks = silentInitialDispatch ? 5 : isNativeInitialPending ? INITIAL_SCROLL_MAX_FALLBACK_CHECKS : 5;
1484
+ const shouldFinishZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
1485
+ const canFinishInitialScrollWithoutNativeProgress = shouldFinishInitialScrollWithoutNativeProgress(
1486
+ state,
1487
+ isStillScrollingTo
1488
+ );
1489
+ const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
1490
+ const canFinishAfterSilentNativeDispatch = Platform.OS === "android" && silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
1491
+ const shouldRetrySilentInitialNativeScroll = Platform.OS === "android" && canFinishAfterSilentNativeDispatch && !initialScrollCompletion.didRetrySilentInitialScroll(state);
1492
+ const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
1493
+ const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
1494
+ const shouldRetryUnalignedEndScroll = Platform.OS === "ios" && !isStillScrollingTo.isInitialScroll && isEndAlignedLastItemTarget(ctx, isStillScrollingTo) && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
1495
+ if (shouldRetrySilentInitialNativeScroll) {
1496
+ const targetOffset = (_b = (_a3 = getInitialScrollWatchdogTargetOffset(state)) != null ? _a3 : isStillScrollingTo.targetOffset) != null ? _b : 0;
1497
+ const jiggleOffset = targetOffset >= SILENT_INITIAL_SCROLL_TARGET_EPSILON ? targetOffset - SILENT_INITIAL_SCROLL_TARGET_EPSILON : targetOffset + SILENT_INITIAL_SCROLL_TARGET_EPSILON;
1498
+ initialScrollCompletion.markSilentInitialScrollRetry(state);
1499
+ scrollToFallbackOffset(ctx, jiggleOffset);
1500
+ state.scheduledWork.frame(
1501
+ () => scrollToFallbackOffset(ctx, targetOffset),
1502
+ "checkFinishedScrollRetryFrame"
1442
1503
  );
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
- }
1504
+ scheduleFallbackCheck(SILENT_INITIAL_SCROLL_RETRY_DELAY_MS);
1505
+ } else if (shouldRetryUnalignedEndScroll) {
1506
+ scrollToFallbackOffset(ctx, completionState.clampedTargetOffset);
1507
+ scheduleFallbackCheck(100);
1508
+ } else if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
1509
+ finishScrollTo(ctx);
1510
+ } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
1511
+ const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
1512
+ scrollToFallbackOffset(ctx, targetOffset);
1513
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
1514
+ } else {
1515
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
1470
1516
  }
1471
- };
1472
- checkHasScrolled();
1473
- }, initialDelay);
1517
+ }
1518
+ };
1519
+ scheduleFallbackCheck(initialDelay);
1474
1520
  }
1475
1521
 
1476
1522
  // src/core/doScrollTo.native.ts
@@ -1494,6 +1540,9 @@ function doScrollTo(ctx, params) {
1494
1540
  if (isInitialScroll) {
1495
1541
  initialScrollCompletion.markInitialScrollNativeDispatch(state);
1496
1542
  }
1543
+ if (isAnimated && Math.abs(state.scroll - offset) <= 1) {
1544
+ checkFinishedScroll(ctx);
1545
+ }
1497
1546
  if (!isAnimated) {
1498
1547
  state.scroll = offset;
1499
1548
  checkFinishedScrollFallback(ctx);
@@ -1524,9 +1573,12 @@ function doMaintainScrollAtEnd(ctx) {
1524
1573
  if (!state.maintainingScrollAtEnd) {
1525
1574
  const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
1526
1575
  const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
1576
+ const scrollAtRequest = state.scroll;
1527
1577
  state.maintainingScrollAtEnd = pendingState;
1528
1578
  requestAnimationFrame(() => {
1529
- if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
1579
+ const isStillWithinThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
1580
+ const didScrollSinceRequest = state.scroll !== scrollAtRequest;
1581
+ if (isStillWithinThreshold || !didScrollSinceRequest) {
1530
1582
  state.maintainingScrollAtEnd = activeState;
1531
1583
  const scroller = refScroller.current;
1532
1584
  if (state.props.horizontal && isHorizontalRTL(state)) {
@@ -1556,6 +1608,7 @@ function doMaintainScrollAtEnd(ctx) {
1556
1608
  );
1557
1609
  } else if (state.maintainingScrollAtEnd === pendingState) {
1558
1610
  state.maintainingScrollAtEnd = void 0;
1611
+ state.pendingMaintainScrollAtEnd = false;
1559
1612
  }
1560
1613
  });
1561
1614
  } else {
@@ -1597,20 +1650,21 @@ function requestAdjust(ctx, positionDiff, dataChanged) {
1597
1650
  } else {
1598
1651
  state.ignoreScrollFromMVCP.gt = threshold;
1599
1652
  }
1600
- if (state.ignoreScrollFromMVCPTimeout) {
1601
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
1602
- }
1603
1653
  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);
1654
+ state.scheduledWork.timeout(
1655
+ () => {
1656
+ var _a3;
1657
+ state.ignoreScrollFromMVCP = void 0;
1658
+ const shouldForceUpdate = state.ignoreScrollFromMVCPIgnored && state.scrollProcessingEnabled !== false;
1659
+ if (shouldForceUpdate) {
1660
+ state.ignoreScrollFromMVCPIgnored = false;
1661
+ state.scrollPending = state.scroll;
1662
+ (_a3 = state.reprocessCurrentScroll) == null ? void 0 : _a3.call(state);
1663
+ }
1664
+ },
1665
+ delay,
1666
+ "ignoreScrollFromMVCP"
1667
+ );
1614
1668
  }
1615
1669
  } else {
1616
1670
  state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
@@ -2038,10 +2092,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
2038
2092
  state.mvcpAnchorLock = void 0;
2039
2093
  state.pendingNativeMVCPAdjust = void 0;
2040
2094
  state.userScrollAnchorReset = { keys: /* @__PURE__ */ new Set() };
2041
- if (state.queuedMVCPRecalculate !== void 0) {
2042
- cancelAnimationFrame(state.queuedMVCPRecalculate);
2043
- state.queuedMVCPRecalculate = void 0;
2044
- }
2095
+ state.scheduledWork.cancel("mvcpRecalculate");
2045
2096
  flushSync(runCalculateItems);
2046
2097
  scheduleFullDrawDistancePrewarm(ctx);
2047
2098
  } else {
@@ -2186,12 +2237,7 @@ function scrollTo(ctx, params) {
2186
2237
  const {
2187
2238
  props: { horizontal }
2188
2239
  } = state;
2189
- if (state.animFrameCheckFinishedScroll) {
2190
- cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
2191
- }
2192
- if (state.timeoutCheckFinishedScrollFallback) {
2193
- clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
2194
- }
2240
+ cancelScrollCompletionChecks(state);
2195
2241
  const requestedOffset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
2196
2242
  const shouldPreserveRawInitialOffsetRequest = !!isInitialScroll && ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset";
2197
2243
  const targetOffset = clampScrollOffset(ctx, requestedOffset, scrollTarget);
@@ -2296,10 +2342,7 @@ function setInitialScrollTarget(ctx, target, options) {
2296
2342
  var _a3;
2297
2343
  const { state } = ctx;
2298
2344
  state.clearPreservedInitialScrollOnNextFinish = void 0;
2299
- if (state.timeoutPreservedInitialScrollClear !== void 0) {
2300
- clearTimeout(state.timeoutPreservedInitialScrollClear);
2301
- state.timeoutPreservedInitialScrollClear = void 0;
2302
- }
2345
+ state.scheduledWork.cancel("preservedInitialScroll");
2303
2346
  state.initialScroll = target;
2304
2347
  if (options == null ? void 0 : options.resetDidFinish) {
2305
2348
  resetInitialRenderState(ctx, { resetInitialScroll: true });
@@ -2592,13 +2635,13 @@ function rearmBootstrapInitialScroll(ctx, options) {
2592
2635
  queueBootstrapInitialScrollReevaluation(ctx.state);
2593
2636
  }
2594
2637
  function createInitialScrollAtEndTarget(options) {
2595
- const { dataLength, footerSize, preserveForFooterLayout, stylePaddingBottom } = options;
2638
+ const { dataLength, footerSize, preserveForFooterLayout, stylePaddingEnd } = options;
2596
2639
  return {
2597
2640
  contentOffset: void 0,
2598
2641
  index: Math.max(0, dataLength - 1),
2599
2642
  preserveForBottomPadding: true,
2600
2643
  preserveForFooterLayout,
2601
- viewOffset: -stylePaddingBottom - footerSize,
2644
+ viewOffset: -stylePaddingEnd - footerSize,
2602
2645
  viewPosition: 1
2603
2646
  };
2604
2647
  }
@@ -2612,7 +2655,7 @@ function isRetargetableBottomAlignedInitialScrollTarget(target) {
2612
2655
  return !!(target && target.viewPosition === 1 && (shouldPreserveInitialScrollForBottomPadding(target) || shouldPreserveInitialScrollForFooterLayout(target)));
2613
2656
  }
2614
2657
  function createRetargetedBottomAlignedInitialScroll(options) {
2615
- const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom, target } = options;
2658
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd, target } = options;
2616
2659
  const preserveForFooterLayout = shouldPreserveInitialScrollForFooterLayout(target);
2617
2660
  return {
2618
2661
  ...target,
@@ -2620,7 +2663,7 @@ function createRetargetedBottomAlignedInitialScroll(options) {
2620
2663
  index: initialScrollAtEnd ? Math.max(0, dataLength - 1) : target.index,
2621
2664
  preserveForBottomPadding: true,
2622
2665
  preserveForFooterLayout,
2623
- viewOffset: -stylePaddingBottom - (preserveForFooterLayout ? footerSize : 0),
2666
+ viewOffset: -stylePaddingEnd - (preserveForFooterLayout ? footerSize : 0),
2624
2667
  viewPosition: 1
2625
2668
  };
2626
2669
  }
@@ -2628,7 +2671,7 @@ function areEquivalentBootstrapInitialScrollTargets(current, next) {
2628
2671
  return current.index === next.index && current.preserveForBottomPadding === next.preserveForBottomPadding && current.preserveForFooterLayout === next.preserveForFooterLayout && current.viewOffset === next.viewOffset && current.viewPosition === next.viewPosition;
2629
2672
  }
2630
2673
  function clearPendingInitialScrollFooterLayout(ctx, options) {
2631
- const { dataLength, stylePaddingBottom, target } = options;
2674
+ const { dataLength, stylePaddingEnd, target } = options;
2632
2675
  if (!shouldPreserveInitialScrollForFooterLayout(target)) {
2633
2676
  return;
2634
2677
  }
@@ -2636,7 +2679,7 @@ function clearPendingInitialScrollFooterLayout(ctx, options) {
2636
2679
  dataLength,
2637
2680
  footerSize: 0,
2638
2681
  preserveForFooterLayout: void 0,
2639
- stylePaddingBottom
2682
+ stylePaddingEnd
2640
2683
  });
2641
2684
  setInitialScrollTarget(ctx, clearedFooterTarget);
2642
2685
  }
@@ -2697,7 +2740,7 @@ function schedulePreservedEndAnchorCorrectionFrame(ctx, correction) {
2697
2740
  });
2698
2741
  }
2699
2742
  function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2700
- var _a3, _b;
2743
+ var _a3;
2701
2744
  const state = ctx.state;
2702
2745
  const initialScroll = state.initialScroll;
2703
2746
  if (!state.didFinishInitialScroll || ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) || (initialScroll == null ? void 0 : initialScroll.viewPosition) !== 1 || state.preservedEndAnchorCorrection) {
@@ -2709,7 +2752,7 @@ function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2709
2752
  if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
2710
2753
  clearPendingInitialScrollFooterLayout(ctx, {
2711
2754
  dataLength: state.props.data.length,
2712
- stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
2755
+ stylePaddingEnd: getStylePaddingEnd(state.props),
2713
2756
  target: initialScroll
2714
2757
  });
2715
2758
  } else {
@@ -2746,7 +2789,7 @@ function startBootstrapInitialScrollOnMount(ctx, options) {
2746
2789
  }
2747
2790
  }
2748
2791
  function handleBootstrapInitialScrollDataChange(ctx, options) {
2749
- const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingBottom } = options;
2792
+ const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingEnd } = options;
2750
2793
  const state = ctx.state;
2751
2794
  const initialScroll = state.initialScroll;
2752
2795
  if (isOffsetInitialScrollSession(state) || !initialScroll) {
@@ -2768,18 +2811,18 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2768
2811
  dataLength,
2769
2812
  footerSize: peek$(ctx, "footerSize") || 0,
2770
2813
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2771
- stylePaddingBottom
2814
+ stylePaddingEnd
2772
2815
  }) : createRetargetedBottomAlignedInitialScroll({
2773
2816
  dataLength,
2774
2817
  footerSize: peek$(ctx, "footerSize") || 0,
2775
2818
  initialScrollAtEnd,
2776
- stylePaddingBottom,
2819
+ stylePaddingEnd,
2777
2820
  target: initialScroll
2778
2821
  });
2779
2822
  if (!shouldResetDidFinish && didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2780
2823
  clearPendingInitialScrollFooterLayout(ctx, {
2781
2824
  dataLength,
2782
- stylePaddingBottom,
2825
+ stylePaddingEnd,
2783
2826
  target: initialScroll
2784
2827
  });
2785
2828
  return;
@@ -2811,7 +2854,7 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2811
2854
  }
2812
2855
  }
2813
2856
  function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2814
- const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom } = options;
2857
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd } = options;
2815
2858
  const state = ctx.state;
2816
2859
  if (!initialScrollAtEnd) {
2817
2860
  return;
@@ -2827,7 +2870,7 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2827
2870
  if (didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2828
2871
  clearPendingInitialScrollFooterLayout(ctx, {
2829
2872
  dataLength,
2830
- stylePaddingBottom,
2873
+ stylePaddingEnd,
2831
2874
  target: initialScroll
2832
2875
  });
2833
2876
  } else {
@@ -2835,13 +2878,13 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2835
2878
  dataLength,
2836
2879
  footerSize,
2837
2880
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2838
- stylePaddingBottom
2881
+ stylePaddingEnd
2839
2882
  });
2840
2883
  const didTargetChange = initialScroll.index !== updatedInitialScroll.index || initialScroll.viewPosition !== updatedInitialScroll.viewPosition || initialScroll.viewOffset !== updatedInitialScroll.viewOffset;
2841
2884
  if (!didTargetChange) {
2842
2885
  clearPendingInitialScrollFooterLayout(ctx, {
2843
2886
  dataLength,
2844
- stylePaddingBottom,
2887
+ stylePaddingEnd,
2845
2888
  target: initialScroll
2846
2889
  });
2847
2890
  } else {
@@ -3068,7 +3111,7 @@ function handleInitialScrollDataChange(ctx, options) {
3068
3111
  initialScrollAtEnd,
3069
3112
  latestInitialScroll,
3070
3113
  latestInitialScrollSessionKind,
3071
- stylePaddingBottom,
3114
+ stylePaddingEnd,
3072
3115
  useBootstrapInitialScroll
3073
3116
  } = options;
3074
3117
  const state = ctx.state;
@@ -3098,7 +3141,7 @@ function handleInitialScrollDataChange(ctx, options) {
3098
3141
  didDataChange,
3099
3142
  initialScrollAtEnd,
3100
3143
  previousDataLength: previousInitialScrollDataLength,
3101
- stylePaddingBottom
3144
+ stylePaddingEnd
3102
3145
  });
3103
3146
  return;
3104
3147
  }
@@ -3568,7 +3611,6 @@ function setupViewability(props) {
3568
3611
  }
3569
3612
  function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end, startBuffered = start, endBuffered = end) {
3570
3613
  const {
3571
- timeouts,
3572
3614
  props: { data }
3573
3615
  } = state;
3574
3616
  for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
@@ -3578,11 +3620,10 @@ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollS
3578
3620
  viewabilityState.startBuffered = startBuffered;
3579
3621
  viewabilityState.endBuffered = endBuffered;
3580
3622
  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);
3623
+ state.scheduledWork.timeout(
3624
+ () => updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize),
3625
+ viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime
3626
+ );
3586
3627
  } else {
3587
3628
  updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
3588
3629
  }
@@ -3941,20 +3982,15 @@ function getProjectedBufferAdjustment(scrollVelocity, trailingBuffer) {
3941
3982
  }
3942
3983
  function scheduleRenderRangeProjectionSettle(ctx) {
3943
3984
  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);
3985
+ state.scheduledWork.timeout(
3986
+ () => {
3987
+ var _a3;
3988
+ state.scrollHistory.length = 0;
3989
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
3990
+ },
3991
+ RENDER_RANGE_PROJECTION_SETTLE_DELAY,
3992
+ "renderRangeProjection"
3993
+ );
3958
3994
  }
3959
3995
  function findCurrentStickyIndex(stickyArray, scroll, state) {
3960
3996
  const positions = state.positions;
@@ -4622,8 +4658,6 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4622
4658
  if (anchorIndex >= 0 && anchorIndex < data.length && state.scrollLength > 0) {
4623
4659
  nextAnchorKey = getId(state, anchorIndex);
4624
4660
  let contentBelowAnchor = 0;
4625
- const footerSize = ctx.values.get("footerSize") || 0;
4626
- const stylePaddingBottom = state.props.stylePaddingBottom || 0;
4627
4661
  let hasUnknownTailSize = false;
4628
4662
  for (let index = anchorIndex; index < data.length; index++) {
4629
4663
  const size = getKnownOrFixedItemSize(ctx, index);
@@ -4635,14 +4669,16 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4635
4669
  contentBelowAnchor += effectiveSize;
4636
4670
  }
4637
4671
  }
4638
- contentBelowAnchor += footerSize + stylePaddingBottom;
4672
+ contentBelowAnchor = Math.max(0, contentBelowAnchor - ctx.scrollAxisGap);
4673
+ contentBelowAnchor += (ctx.values.get("footerSize") || 0) + getStylePaddingEnd(state.props);
4639
4674
  isReady = !hasUnknownTailSize;
4640
4675
  nextSize = hasUnknownTailSize ? previousSize || 0 : Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
4641
4676
  } else if (anchorIndex >= 0) {
4642
4677
  isReady = false;
4643
4678
  }
4644
4679
  }
4645
- const didSizeChange = previousSize !== nextSize;
4680
+ const didSizeChange = previousSize !== nextSize && (previousSize !== void 0 || anchoredEndSpace !== void 0);
4681
+ const didEffectiveSizeChange = (previousSize || 0) !== nextSize;
4646
4682
  const didReadyAnchorChange = previousReadyAnchorIndex !== nextAnchorIndex || previousReadyAnchorKey !== nextAnchorKey;
4647
4683
  if (isReady && (didSizeChange || didReadyAnchorChange)) {
4648
4684
  state.anchoredEndSpaceReadyAnchorIndex = nextAnchorIndex;
@@ -4651,8 +4687,9 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4651
4687
  set$(ctx, "anchoredEndSpaceSize", nextSize);
4652
4688
  (_a3 = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onSizeChanged) == null ? void 0 : _a3.call(anchoredEndSpace, nextSize);
4653
4689
  }
4654
- if (didSizeChange && (anchoredEndSpace == null ? void 0 : anchoredEndSpace.includeInEndInset)) {
4655
- updateScroll(ctx, state.scroll, true);
4690
+ if (didEffectiveSizeChange) {
4691
+ updateContentMetricsState(ctx);
4692
+ updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
4656
4693
  }
4657
4694
  (_b = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onReady) == null ? void 0 : _b.call(anchoredEndSpace, { anchorIndex: nextAnchorIndex, anchorKey: nextAnchorKey, size: nextSize });
4658
4695
  }
@@ -4681,16 +4718,10 @@ function runOrScheduleMVCPRecalculate(ctx) {
4681
4718
  }
4682
4719
  } else if (Platform.OS === "web") {
4683
4720
  if (!state.mvcpAnchorLock) {
4684
- if (state.queuedMVCPRecalculate !== void 0) {
4685
- cancelAnimationFrame(state.queuedMVCPRecalculate);
4686
- state.queuedMVCPRecalculate = void 0;
4687
- }
4721
+ state.scheduledWork.cancel("mvcpRecalculate");
4688
4722
  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
- });
4723
+ } else if (!state.scheduledWork.has("mvcpRecalculate")) {
4724
+ state.scheduledWork.frame(() => calculateItemsInView(ctx, { doMVCP: true }), "mvcpRecalculate");
4694
4725
  }
4695
4726
  } else {
4696
4727
  calculateItemsInView(ctx, { doMVCP: true });
@@ -4737,6 +4768,9 @@ function flushItemSizeUpdates(ctx, result) {
4737
4768
  } else if (result.didMeasureUserScrollAnchorResetItem && ((_a3 = state.userScrollAnchorReset) == null ? void 0 : _a3.keys.size) === 0) {
4738
4769
  state.userScrollAnchorReset = void 0;
4739
4770
  }
4771
+ if (result.didChange) {
4772
+ maybeUpdateAnchoredEndSpace(ctx);
4773
+ }
4740
4774
  if (result.didChange && result.shouldMaintainScrollAtEnd) {
4741
4775
  doMaintainScrollAtEnd(ctx);
4742
4776
  }
@@ -4816,7 +4850,7 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
4816
4850
  if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
4817
4851
  needsRecalculate = true;
4818
4852
  }
4819
- if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
4853
+ if (prevSizeKnown === void 0 || Math.abs(prevSizeKnown - size) > 5) {
4820
4854
  shouldMaintainScrollAtEnd = true;
4821
4855
  }
4822
4856
  onItemSizeChanged == null ? void 0 : onItemSizeChanged({
@@ -4826,7 +4860,6 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
4826
4860
  previous: size - diff,
4827
4861
  size
4828
4862
  });
4829
- maybeUpdateAnchoredEndSpace(ctx);
4830
4863
  }
4831
4864
  if (minIndexSizeChanged !== void 0) {
4832
4865
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
@@ -5666,19 +5699,32 @@ function ContainerSlotBase({
5666
5699
  var ContainerSlot = typedMemo(function ContainerSlot2(props) {
5667
5700
  return /* @__PURE__ */ React2__namespace.createElement(ContainerSlotBase, { ...props });
5668
5701
  });
5702
+ function useFreshDataTransitionVisibility(readyToRender, transitionEpoch) {
5703
+ const [completedTransitionEpoch, setCompletedTransitionEpoch] = React2.useState(transitionEpoch);
5704
+ const isTransitionPending = completedTransitionEpoch !== transitionEpoch;
5705
+ React2.useLayoutEffect(() => {
5706
+ setCompletedTransitionEpoch(transitionEpoch);
5707
+ }, [transitionEpoch]);
5708
+ return readyToRender && !isTransitionPending;
5709
+ }
5669
5710
 
5670
5711
  // src/components/Containers.native.tsx
5671
- var ContainersLayer = typedMemo(function ContainersLayer2({ children, horizontal }) {
5712
+ var ContainersLayer = typedMemo(function ContainersLayer2({
5713
+ children,
5714
+ freshDataTransitionEpoch,
5715
+ horizontal
5716
+ }) {
5672
5717
  const ctx = useStateContext();
5673
5718
  const columnWrapperStyle = ctx.columnWrapperStyle;
5674
5719
  const animSize = useValue$("totalSize");
5675
5720
  const [readyToRender, numColumns, otherAxisSize = 0] = useArr$(["readyToRender", "numColumns", "otherAxisSize"]);
5721
+ const isVisible = useFreshDataTransitionVisibility(!!readyToRender, freshDataTransitionEpoch);
5676
5722
  const style = horizontal ? {
5677
5723
  height: otherAxisSize || "100%",
5678
5724
  minHeight: otherAxisSize,
5679
- opacity: readyToRender ? 1 : 0,
5725
+ opacity: isVisible ? 1 : 0,
5680
5726
  width: animSize
5681
- } : { height: animSize, minWidth: otherAxisSize, opacity: readyToRender ? 1 : 0 };
5727
+ } : { height: animSize, minWidth: otherAxisSize, opacity: isVisible ? 1 : 0 };
5682
5728
  if (columnWrapperStyle) {
5683
5729
  const { columnGap, rowGap, gap } = columnWrapperStyle;
5684
5730
  const gapX = columnGap || gap || 0;
@@ -5699,9 +5745,10 @@ var ContainersLayer = typedMemo(function ContainersLayer2({ children, horizontal
5699
5745
  }
5700
5746
  }
5701
5747
  }
5702
- return /* @__PURE__ */ React2__namespace.createElement(ReactNative.Animated.View, { style }, /* @__PURE__ */ React2__namespace.createElement(ContainerLayoutCoordinator, null, children));
5748
+ return /* @__PURE__ */ React2__namespace.createElement(ReactNative.Animated.View, { pointerEvents: isVisible ? void 0 : "none", style }, /* @__PURE__ */ React2__namespace.createElement(ContainerLayoutCoordinator, null, children));
5703
5749
  });
5704
5750
  var Containers = typedMemo(function Containers2({
5751
+ freshDataTransitionEpoch,
5705
5752
  horizontal,
5706
5753
  recycleItems,
5707
5754
  ItemSeparatorComponent,
@@ -5726,7 +5773,7 @@ var Containers = typedMemo(function Containers2({
5726
5773
  )
5727
5774
  );
5728
5775
  }
5729
- return /* @__PURE__ */ React2__namespace.createElement(ContainersLayer, { horizontal }, containers);
5776
+ return /* @__PURE__ */ React2__namespace.createElement(ContainersLayer, { freshDataTransitionEpoch, horizontal }, containers);
5730
5777
  });
5731
5778
  var ListComponentScrollView = ReactNative.Animated.ScrollView;
5732
5779
 
@@ -5765,16 +5812,6 @@ var SnapWrapper = React2__namespace.forwardRef(function SnapWrapperInner({ Scrol
5765
5812
  const [snapToOffsets] = useArr$(["snapToOffsets"]);
5766
5813
  return /* @__PURE__ */ React2__namespace.createElement(ScrollComponent, { ...props, ref, snapToOffsets });
5767
5814
  });
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
5815
 
5779
5816
  // src/core/updateContentMetrics.ts
5780
5817
  var SCROLL_ADJUST_EPSILON = 0.1;
@@ -5808,7 +5845,11 @@ function setHeaderSize(ctx, size) {
5808
5845
  state.didMeasureHeader = true;
5809
5846
  }
5810
5847
  function setFooterSize(ctx, size) {
5811
- return setContentLengthSignal(ctx, "footerSize", size);
5848
+ const didChange = setContentLengthSignal(ctx, "footerSize", size);
5849
+ if (didChange) {
5850
+ maybeUpdateAnchoredEndSpace(ctx);
5851
+ }
5852
+ return didChange;
5812
5853
  }
5813
5854
  function areInsetsEqual(left, right) {
5814
5855
  var _a3, _b, _c, _d, _e, _f, _g, _h;
@@ -5851,6 +5892,7 @@ var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
5851
5892
  const { onLayout } = useOnLayoutSync({ onLayoutChange, ref });
5852
5893
  return /* @__PURE__ */ React2__namespace.createElement(ReactNative.View, { ...rest, onLayout, ref });
5853
5894
  };
5895
+ var StyleSheet = ReactNative.StyleSheet;
5854
5896
 
5855
5897
  // src/components/ListComponent.tsx
5856
5898
  var AlignItemsAtEndSpacer = typedMemo(function AlignItemsAtEndSpacer2({ horizontal }) {
@@ -5868,6 +5910,7 @@ var AlignItemsAtEndSpacer = typedMemo(function AlignItemsAtEndSpacer2({ horizont
5868
5910
  });
5869
5911
  var ListComponent = typedMemo(function ListComponent2({
5870
5912
  canRender,
5913
+ freshDataTransitionEpoch,
5871
5914
  style,
5872
5915
  contentContainerStyle,
5873
5916
  horizontal,
@@ -5897,8 +5940,17 @@ var ListComponent = typedMemo(function ListComponent2({
5897
5940
  }) {
5898
5941
  const ctx = useStateContext();
5899
5942
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
5900
- const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
5943
+ const [anchoredEndSpaceSize = 0, otherAxisSize = 0] = useArr$(["anchoredEndSpaceSize", "otherAxisSize"]);
5901
5944
  const shouldRenderAlignItemsAtEndSpacer = ctx.state.props.alignItemsAtEndPaddingEnabled;
5945
+ const shouldMaterializeAnchoredEndSpace = !!ctx.state.props.anchoredEndSpace && ctx.state.props.anchoredEndSpaceOwner === "list" && anchoredEndSpaceSize > 0;
5946
+ let anchoredEndSpaceStyle;
5947
+ if (shouldMaterializeAnchoredEndSpace) {
5948
+ const paddingEnd = horizontal ? isHorizontalRTL(ctx.state) ? "Left" : "Right" : "Bottom";
5949
+ const flattenedContentContainerStyle = StyleSheet.flatten(contentContainerStyle);
5950
+ anchoredEndSpaceStyle = {
5951
+ [`padding${paddingEnd}`]: extractPadding({}, flattenedContentContainerStyle || {}, paddingEnd) + anchoredEndSpaceSize
5952
+ };
5953
+ }
5902
5954
  const autoOtherAxisStyle = getAutoOtherAxisStyle({
5903
5955
  horizontal,
5904
5956
  needsOtherAxisSize: ctx.state.needsOtherAxisSize,
@@ -5951,10 +6003,10 @@ var ListComponent = typedMemo(function ListComponent2({
5951
6003
  ...rest,
5952
6004
  ...Platform.OS === "web" ? ScrollComponent === ListComponentScrollView ? { onInternalScrollEnd, useWindowScroll } : {} : { onScrollBeginDrag: onInternalScrollBeginDrag },
5953
6005
  contentContainerStyle: [
5954
- horizontal ? {
5955
- height: "100%"
5956
- } : {},
5957
- contentContainerStyle
6006
+ horizontal ? { height: "100%" } : {},
6007
+ contentContainerStyle,
6008
+ anchoredEndSpaceStyle,
6009
+ Platform.OS === "web" ? { boxSizing: "border-box" } : void 0
5958
6010
  ],
5959
6011
  contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
5960
6012
  horizontal,
@@ -5972,6 +6024,7 @@ var ListComponent = typedMemo(function ListComponent2({
5972
6024
  canRender && !ListEmptyComponent && /* @__PURE__ */ React2__namespace.createElement(
5973
6025
  Containers,
5974
6026
  {
6027
+ freshDataTransitionEpoch,
5975
6028
  getRenderedItem: getRenderedItem2,
5976
6029
  horizontal,
5977
6030
  ItemSeparatorComponent,
@@ -5980,7 +6033,6 @@ var ListComponent = typedMemo(function ListComponent2({
5980
6033
  }
5981
6034
  ),
5982
6035
  ListFooterComponent && /* @__PURE__ */ React2__namespace.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
5983
- Platform.OS === "web" && /* @__PURE__ */ React2__namespace.createElement(WebAnchoredEndSpace, { horizontal }),
5984
6036
  IS_DEV && ENABLE_DEVMODE
5985
6037
  );
5986
6038
  });
@@ -5989,7 +6041,16 @@ var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
5989
6041
  var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
5990
6042
  function useDevChecksImpl(props) {
5991
6043
  const ctx = useStateContext();
5992
- const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
6044
+ const { anchoredEndSpace, childrenMode, keyExtractor, numColumns, renderScrollComponent, useWindowScroll } = props;
6045
+ const hasAnchoredEndSpace = !!anchoredEndSpace;
6046
+ React2.useEffect(() => {
6047
+ if (hasAnchoredEndSpace && (numColumns != null ? numColumns : 1) > 1) {
6048
+ warnDevOnce(
6049
+ "anchoredEndSpaceNumColumns",
6050
+ "anchoredEndSpace is only supported when numColumns is 1. Using it with multiple columns may produce incorrect anchored spacing."
6051
+ );
6052
+ }
6053
+ }, [hasAnchoredEndSpace, numColumns]);
5993
6054
  React2.useEffect(() => {
5994
6055
  if (useWindowScroll && renderScrollComponent) {
5995
6056
  warnDevOnce(
@@ -6317,6 +6378,60 @@ function onScroll(ctx, event) {
6317
6378
  }
6318
6379
  }
6319
6380
 
6381
+ // src/core/ScheduledWork.ts
6382
+ var ScheduledWork = class {
6383
+ constructor() {
6384
+ this.work = /* @__PURE__ */ new Map();
6385
+ }
6386
+ timeout(callback, delay, key) {
6387
+ if (key) {
6388
+ this.cancel(key);
6389
+ }
6390
+ const work = [void 0, clearTimeout];
6391
+ const handle = setTimeout(() => {
6392
+ const workKey = key != null ? key : handle;
6393
+ if (this.work.get(workKey) === work) {
6394
+ this.work.delete(workKey);
6395
+ callback();
6396
+ }
6397
+ }, delay);
6398
+ work[0] = handle;
6399
+ this.work.set(key != null ? key : handle, work);
6400
+ }
6401
+ frame(callback, key) {
6402
+ this.cancel(key);
6403
+ const work = [void 0, cancelAnimationFrame];
6404
+ this.work.set(key, work);
6405
+ work[0] = requestAnimationFrame(() => {
6406
+ if (this.work.get(key) === work) {
6407
+ this.work.delete(key);
6408
+ callback();
6409
+ }
6410
+ });
6411
+ }
6412
+ register(key, cancel) {
6413
+ this.cancel(key);
6414
+ this.work.set(key, [void 0, cancel]);
6415
+ }
6416
+ cancel(key) {
6417
+ const work = this.work.get(key);
6418
+ if (work) {
6419
+ this.work.delete(key);
6420
+ const [handle, cancel] = work;
6421
+ cancel(handle);
6422
+ }
6423
+ }
6424
+ has(key) {
6425
+ return this.work.has(key);
6426
+ }
6427
+ dispose() {
6428
+ for (const [handle, cancel] of this.work.values()) {
6429
+ cancel(handle);
6430
+ }
6431
+ this.work.clear();
6432
+ }
6433
+ };
6434
+
6320
6435
  // src/core/ScrollAdjustHandler.ts
6321
6436
  var ScrollAdjustHandler = class {
6322
6437
  constructor(ctx) {
@@ -6404,7 +6519,6 @@ var useCombinedRef = (...refs) => {
6404
6519
  }, refs);
6405
6520
  return callback;
6406
6521
  };
6407
- var StyleSheet = ReactNative.StyleSheet;
6408
6522
  function useStickyScrollHandler(stickyHeaderIndices, horizontal, ctx, onScroll2) {
6409
6523
  const shouldUseRnAnimatedEngine = !ctx.state.props.stickyPositionComponentInternal;
6410
6524
  return React2.useMemo(() => {
@@ -6491,7 +6605,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6491
6605
  const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
6492
6606
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
6493
6607
  let imperativeScrollToken = 0;
6494
- const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0;
6608
+ const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.scheduledWork.has("mvcpRecalculate") || state.ignoreScrollFromMVCP !== void 0;
6495
6609
  const isScrollToIndexReady = (targetIndex, allowEmpty = false) => {
6496
6610
  var _a3;
6497
6611
  const props = state.props;
@@ -6525,9 +6639,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6525
6639
  run();
6526
6640
  return;
6527
6641
  }
6528
- requestAnimationFrame(check);
6642
+ state.scheduledWork.frame(check, "imperativeScrollReady");
6529
6643
  };
6530
- requestAnimationFrame(check);
6644
+ state.scheduledWork.frame(check, "imperativeScrollReady");
6531
6645
  };
6532
6646
  const runScrollRequest = (token, resolve, run, isReady = () => true) => {
6533
6647
  const runNow = () => {
@@ -6549,15 +6663,15 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6549
6663
  }
6550
6664
  };
6551
6665
  const startImperativeScroll = (resolve) => {
6552
- var _a3;
6666
+ state.scheduledWork.cancel("imperativeScrollReady");
6553
6667
  const token = ++imperativeScrollToken;
6554
- state.pendingScrollToEnd = void 0;
6555
- (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
6668
+ settlePendingImperativeScroll(state);
6556
6669
  state.pendingScrollResolve = resolve;
6557
6670
  return token;
6558
6671
  };
6559
6672
  const runScrollWithPromise = (run, isReady = () => true) => new Promise((resolve) => {
6560
6673
  const token = startImperativeScroll(resolve);
6674
+ supersedeInitialScroll(ctx);
6561
6675
  runScrollRequest(token, resolve, run, isReady);
6562
6676
  });
6563
6677
  state.runPendingScrollToEnd = () => {
@@ -6636,6 +6750,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6636
6750
  end: state.endNoBuffer,
6637
6751
  endBuffered: state.endBuffered,
6638
6752
  getAverageItemSizes: () => getAverageItemSizes(state),
6753
+ indexByKey: (key) => state.indexByKey.get(key),
6639
6754
  isAtEnd: peek$(ctx, "isAtEnd"),
6640
6755
  isAtStart: peek$(ctx, "isAtStart"),
6641
6756
  isEndReached: state.isEndReached,
@@ -6683,9 +6798,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6683
6798
  resolve,
6684
6799
  token
6685
6800
  };
6686
- if (scheduleImperativeScrollCommit) {
6687
- scheduleImperativeScrollCommit();
6688
- } else {
6801
+ scheduleImperativeScrollCommit == null ? void 0 : scheduleImperativeScrollCommit();
6802
+ supersedeInitialScroll(ctx);
6803
+ if (!scheduleImperativeScrollCommit) {
6689
6804
  (_a3 = state.runPendingScrollToEnd) == null ? void 0 : _a3.call(state);
6690
6805
  }
6691
6806
  }),
@@ -6939,7 +7054,7 @@ var LegendList = typedMemo(
6939
7054
  })
6940
7055
  );
6941
7056
  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;
7057
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
6943
7058
  const noopOnScroll = React2.useCallback((_event) => {
6944
7059
  }, []);
6945
7060
  if (props.recycleItems === void 0) {
@@ -7015,9 +7130,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7015
7130
  ...rest
7016
7131
  } = props;
7017
7132
  const animatedPropsInternal = props.animatedPropsInternal;
7133
+ const anchoredEndSpaceOwner = (_a3 = props.anchoredEndSpaceOwnerInternal) != null ? _a3 : "list";
7018
7134
  const positionComponentInternal = props.positionComponentInternal;
7019
7135
  const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
7020
7136
  const {
7137
+ anchoredEndSpaceOwnerInternal: _anchoredEndSpaceOwnerInternal,
7021
7138
  positionComponentInternal: _positionComponentInternal,
7022
7139
  stickyPositionComponentInternal: _stickyPositionComponentInternal,
7023
7140
  ...restProps
@@ -7039,6 +7156,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7039
7156
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
7040
7157
  const stylePaddingLeftState = extractPadding(style, contentContainerStyle, "Left");
7041
7158
  const stylePaddingRightState = extractPadding(style, contentContainerStyle, "Right");
7159
+ const stylePaddingEndState = getStylePaddingEnd({
7160
+ horizontal,
7161
+ rtl,
7162
+ stylePaddingBottom: stylePaddingBottomState,
7163
+ stylePaddingLeft: stylePaddingLeftState,
7164
+ stylePaddingRight: stylePaddingRightState
7165
+ });
7042
7166
  const maintainScrollAtEndConfig = normalizeMaintainScrollAtEnd(maintainScrollAtEnd);
7043
7167
  const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
7044
7168
  maintainVisibleContentPositionProp
@@ -7051,13 +7175,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7051
7175
  const initialScrollProp = initialScrollAtEnd ? {
7052
7176
  index: Math.max(0, dataProp.length - 1),
7053
7177
  preserveForBottomPadding: true,
7054
- viewOffset: -stylePaddingBottomState,
7178
+ viewOffset: -stylePaddingEndState,
7055
7179
  viewPosition: 1
7056
7180
  } : hasInitialScrollIndex ? typeof initialScrollIndexProp === "object" ? {
7057
- index: (_a3 = initialScrollIndexProp.index) != null ? _a3 : 0,
7181
+ index: (_b = initialScrollIndexProp.index) != null ? _b : 0,
7058
7182
  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
7183
+ viewOffset: (_c = initialScrollIndexProp.viewOffset) != null ? _c : initialScrollIndexProp.viewPosition === 1 ? -stylePaddingEndState : 0,
7184
+ viewPosition: (_d = initialScrollIndexProp.viewPosition) != null ? _d : 0
7061
7185
  } : {
7062
7186
  index: initialScrollIndexProp != null ? initialScrollIndexProp : 0,
7063
7187
  viewOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : 0
@@ -7070,7 +7194,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7070
7194
  const [, scheduleImperativeScrollCommit] = React2__namespace.useReducer((value) => value + 1, 0);
7071
7195
  const ctx = useStateContext();
7072
7196
  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;
7197
+ 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
7198
  const nextScrollAxisGap = typeof scrollAxisGap === "number" && Number.isFinite(scrollAxisGap) ? scrollAxisGap : 0;
7075
7199
  const refScroller = React2.useRef(null);
7076
7200
  const combinedRef = useCombinedRef(refScroller, refScrollView);
@@ -7085,8 +7209,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7085
7209
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex,
7086
7210
  alwaysRender == null ? void 0 : alwaysRender.top,
7087
7211
  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(","),
7212
+ (_k = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _k.join(","),
7213
+ (_l = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _l.join(","),
7090
7214
  dataProp,
7091
7215
  dataKey,
7092
7216
  dataVersion,
@@ -7099,7 +7223,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7099
7223
  if (!refState.current) {
7100
7224
  if (!ctx.state) {
7101
7225
  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");
7226
+ ctx.values.set("adaptiveRender", (_m = experimental_adaptiveRender == null ? void 0 : experimental_adaptiveRender.initialMode) != null ? _m : "normal");
7103
7227
  ctx.state = {
7104
7228
  averageSizes: {},
7105
7229
  columnSpans: [],
@@ -7118,6 +7242,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7118
7242
  endNoBuffer: -1,
7119
7243
  endReachedSnapshot: void 0,
7120
7244
  firstFullyOnScreenIndex: -1,
7245
+ freshDataTransitionEpoch: 0,
7121
7246
  hasHadNonEmptyData: dataProp.length > 0,
7122
7247
  idCache: [],
7123
7248
  idsInView: [],
@@ -7142,8 +7267,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7142
7267
  positions: [],
7143
7268
  props: {},
7144
7269
  queuedCalculateItemsInView: 0,
7145
- queuedFullDrawDistancePrewarm: void 0,
7146
7270
  refScroller: { current: null },
7271
+ scheduledWork: new ScheduledWork(),
7147
7272
  scroll: 0,
7148
7273
  scrollAdjustHandler: new ScrollAdjustHandler(ctx),
7149
7274
  scrollForNextCalculateItemsInView: void 0,
@@ -7161,8 +7286,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7161
7286
  startReachedSnapshot: void 0,
7162
7287
  stickyContainerPool: /* @__PURE__ */ new Set(),
7163
7288
  stickyContainers: /* @__PURE__ */ new Map(),
7164
- timeoutAdaptiveRender: void 0,
7165
- timeouts: /* @__PURE__ */ new Set(),
7166
7289
  totalSize: 0,
7167
7290
  viewabilityConfigCallbackPairs: void 0
7168
7291
  };
@@ -7184,13 +7307,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7184
7307
  const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
7185
7308
  ctx.scrollAxisGap = nextScrollAxisGap;
7186
7309
  state.didColumnsChange = numColumnsProp !== previousNumColumnsProp || didScrollAxisGapChange;
7187
- const previousDataLength = (_n = (_m = state.props.data) == null ? void 0 : _m.length) != null ? _n : 0;
7310
+ const previousDataLength = (_o = (_n = state.props.data) == null ? void 0 : _n.length) != null ? _o : 0;
7188
7311
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
7189
7312
  const didDataKeyChangeLocal = state.props.dataKey !== dataKey;
7190
7313
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
7191
7314
  const didDataChangeLocal = didDataKeyChangeLocal || didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
7192
7315
  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) {
7316
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_p = state.initialScroll) == null ? void 0 : _p.viewPosition) === 1 && state.props.data.length > 0) {
7194
7317
  clearPreservedInitialScrollTarget(state);
7195
7318
  }
7196
7319
  if (didDataChangeLocal) {
@@ -7199,10 +7322,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7199
7322
  state.didDataChange = true;
7200
7323
  state.previousData = state.props.data;
7201
7324
  }
7325
+ if (shouldResetFreshDataLayout) {
7326
+ state.freshDataTransitionEpoch += 1;
7327
+ }
7202
7328
  const throttledOnScroll = useThrottledOnScroll(onScrollProp != null ? onScrollProp : noopOnScroll, scrollEventThrottle != null ? scrollEventThrottle : 0);
7203
7329
  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);
7330
+ const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_q = state.props.anchoredEndSpace) == null ? void 0 : _q.anchorIndex) !== (anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex);
7206
7331
  state.props = {
7207
7332
  adaptiveRender: experimental_adaptiveRender,
7208
7333
  alignItemsAtEnd,
@@ -7210,7 +7335,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7210
7335
  alwaysRender,
7211
7336
  alwaysRenderIndicesArr: alwaysRenderIndices.arr,
7212
7337
  alwaysRenderIndicesSet: alwaysRenderIndices.set,
7213
- anchoredEndSpace: anchoredEndSpaceResolved,
7338
+ anchoredEndSpace,
7339
+ anchoredEndSpaceOwner,
7214
7340
  animatedProps: animatedPropsInternal,
7215
7341
  contentContainerAlignItems: contentContainerStyle.alignItems,
7216
7342
  contentInset,
@@ -7259,12 +7385,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7259
7385
  if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
7260
7386
  resetAdaptiveRender(ctx);
7261
7387
  }
7262
- if (shouldResetFreshDataLayout) {
7263
- resetInitialRenderState(ctx, {
7264
- resetInitialScroll: !!initialScrollProp,
7265
- resetLayout: true
7266
- });
7267
- }
7268
7388
  const memoizedLastItemKeys = React2.useMemo(() => {
7269
7389
  if (!dataProp.length) return [];
7270
7390
  return Array.from(
@@ -7328,6 +7448,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7328
7448
  useDevChecks(props);
7329
7449
  }
7330
7450
  React2.useLayoutEffect(() => {
7451
+ if (shouldResetFreshDataLayout) {
7452
+ resetInitialRenderState(ctx, {
7453
+ resetInitialScroll: !!initialScrollProp,
7454
+ resetLayout: true
7455
+ });
7456
+ }
7331
7457
  handleInitialScrollDataChange(ctx, {
7332
7458
  dataLength: dataProp.length,
7333
7459
  didDataChange: didDataChangeLocal,
@@ -7335,7 +7461,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7335
7461
  initialScrollAtEnd,
7336
7462
  latestInitialScroll: initialScrollProp,
7337
7463
  latestInitialScrollSessionKind: initialScrollUsesOffsetOnly ? "offset" : "bootstrap",
7338
- stylePaddingBottom: stylePaddingBottomState,
7464
+ stylePaddingEnd: stylePaddingEndState,
7339
7465
  useBootstrapInitialScroll: usesBootstrapInitialScroll
7340
7466
  });
7341
7467
  }, [
@@ -7344,7 +7470,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7344
7470
  didDataChangeLocal,
7345
7471
  shouldResetFreshDataLayout,
7346
7472
  initialScrollAtEnd,
7347
- stylePaddingBottomState,
7473
+ stylePaddingEndState,
7348
7474
  usesBootstrapInitialScroll
7349
7475
  ]);
7350
7476
  React2.useLayoutEffect(() => {
@@ -7362,7 +7488,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7362
7488
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorMaxSize,
7363
7489
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorOffset,
7364
7490
  didAnchoredEndSpaceAnchorIndexChange,
7365
- numColumnsProp
7491
+ horizontal,
7492
+ numColumnsProp,
7493
+ rtl,
7494
+ stylePaddingBottomState,
7495
+ stylePaddingLeftState,
7496
+ stylePaddingRightState
7366
7497
  ]);
7367
7498
  React2.useLayoutEffect(() => {
7368
7499
  const previousContentInsetEndAdjustment = previousContentInsetEndAdjustmentRef.current;
@@ -7378,10 +7509,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7378
7509
  dataLength: dataProp.length,
7379
7510
  footerSize: layout[horizontal ? "width" : "height"],
7380
7511
  initialScrollAtEnd,
7381
- stylePaddingBottom: stylePaddingBottomState
7512
+ stylePaddingEnd: stylePaddingEndState
7382
7513
  });
7383
7514
  },
7384
- [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingBottomState, usesBootstrapInitialScroll]
7515
+ [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingEndState, usesBootstrapInitialScroll]
7385
7516
  );
7386
7517
  const onLayoutChange = React2.useCallback(
7387
7518
  (layout, fromLayoutEffect) => {
@@ -7398,7 +7529,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7398
7529
  }
7399
7530
  advanceCurrentInitialScrollSession(ctx);
7400
7531
  },
7401
- [dataProp.length, initialScrollAtEnd, stylePaddingBottomState, usesBootstrapInitialScroll]
7532
+ [dataProp.length, initialScrollAtEnd, stylePaddingEndState, usesBootstrapInitialScroll]
7402
7533
  );
7403
7534
  const { onLayout } = useOnLayoutSync({
7404
7535
  onLayoutChange,
@@ -7494,14 +7625,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7494
7625
  React2.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, scheduleImperativeScrollCommit), []);
7495
7626
  React2.useEffect(() => {
7496
7627
  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();
7628
+ cancelImperativeScroll(state);
7629
+ state.scheduledWork.dispose();
7505
7630
  };
7506
7631
  }, [state]);
7507
7632
  React2.useLayoutEffect(() => {
@@ -7543,6 +7668,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7543
7668
  canRender,
7544
7669
  contentContainerStyle,
7545
7670
  contentInset,
7671
+ freshDataTransitionEpoch: state.freshDataTransitionEpoch,
7546
7672
  getRenderedItem: fns.getRenderedItem,
7547
7673
  horizontal,
7548
7674
  initialContentOffset,
@@ -7558,7 +7684,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7558
7684
  onScroll: onScrollHandler,
7559
7685
  recycleItems,
7560
7686
  refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React2__namespace.cloneElement(refreshControlElement, {
7561
- progressViewOffset: ((_q = refreshControlElement.props.progressViewOffset) != null ? _q : 0) + stylePaddingTopState
7687
+ progressViewOffset: ((_r = refreshControlElement.props.progressViewOffset) != null ? _r : 0) + stylePaddingTopState
7562
7688
  }) : refreshControlElement : onRefresh && /* @__PURE__ */ React2__namespace.createElement(
7563
7689
  ReactNative.RefreshControl,
7564
7690
  {
@@ -7569,7 +7695,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7569
7695
  ),
7570
7696
  refScrollView: combinedRef,
7571
7697
  renderScrollComponent,
7572
- scrollAdjustHandler: (_r = refState.current) == null ? void 0 : _r.scrollAdjustHandler,
7698
+ scrollAdjustHandler: (_s = refState.current) == null ? void 0 : _s.scrollAdjustHandler,
7573
7699
  scrollEventThrottle: 0,
7574
7700
  snapToIndices,
7575
7701
  stickyHeaderIndices,