@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.mjs CHANGED
@@ -41,6 +41,12 @@ function isHorizontalRTL(state) {
41
41
  function isHorizontalRTLProps(props) {
42
42
  return !!(props == null ? void 0 : props.horizontal) && isRTLProps(props);
43
43
  }
44
+ function getStylePaddingEnd(props) {
45
+ if (!(props == null ? void 0 : props.horizontal)) {
46
+ return (props == null ? void 0 : props.stylePaddingBottom) || 0;
47
+ }
48
+ return (isHorizontalRTLProps(props) ? props.stylePaddingLeft : props.stylePaddingRight) || 0;
49
+ }
44
50
  function getLogicalHorizontalMaxOffset(state, contentWidth) {
45
51
  var _a3;
46
52
  return (_a3 = getHorizontalMaxOffset(state, contentWidth)) != null ? _a3 : 0;
@@ -159,6 +165,14 @@ function useStateContext() {
159
165
  return React2.useContext(ContextState);
160
166
  }
161
167
  function createSelectorFunctionsArr(ctx, signalNames) {
168
+ if (!ctx) {
169
+ const emptyValues = [];
170
+ return {
171
+ get: () => emptyValues,
172
+ subscribe: () => () => {
173
+ }
174
+ };
175
+ }
162
176
  let lastValues = [];
163
177
  let lastSignalValues = [];
164
178
  return {
@@ -265,7 +279,7 @@ function getContentInsetEndAdjustmentEnd(adjustment) {
265
279
  return Math.max(0, adjustment != null ? adjustment : 0);
266
280
  }
267
281
  function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
268
- var _a3, _b;
282
+ var _a3;
269
283
  const state = ctx.state;
270
284
  const { props } = state;
271
285
  const horizontal = props.horizontal;
@@ -276,8 +290,8 @@ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
276
290
  contentInsetEndAdjustmentOverride != null ? contentInsetEndAdjustmentOverride : props.contentInsetEndAdjustment
277
291
  );
278
292
  const anchoredEndSpaceSize = peek$(ctx, "anchoredEndSpaceSize");
279
- const anchoredEndInset = ((_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.includeInEndInset) && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
280
- const overrideInset = (_b = state.contentInsetOverride) != null ? _b : void 0;
293
+ const anchoredEndInset = props.anchoredEndSpace && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
294
+ const overrideInset = (_a3 = state.contentInsetOverride) != null ? _a3 : void 0;
281
295
  const adjustedBaseEndInset = baseEndInset + contentInsetEndAdjustment;
282
296
  if (overrideInset) {
283
297
  const mergedInset = { bottom: 0, left: 0, right: 0, ...baseInset, ...overrideInset };
@@ -293,14 +307,15 @@ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
293
307
  function getContentSize(ctx) {
294
308
  var _a3, _b;
295
309
  const { values, state } = ctx;
296
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
297
- const stylePaddingBottom = state.props.stylePaddingBottom || 0;
310
+ const stylePaddingStart = state.props.horizontal ? state.props.stylePaddingLeft || 0 : values.get("stylePaddingTop") || 0;
311
+ const stylePaddingEnd = state.props.horizontal ? state.props.stylePaddingRight || 0 : state.props.stylePaddingBottom || 0;
298
312
  const alignItemsAtEndPadding = values.get("alignItemsAtEndPadding") || 0;
299
313
  const headerSize = values.get("headerSize") || 0;
300
314
  const footerSize = values.get("footerSize") || 0;
301
- const contentInsetBottom = getContentInsetEnd(ctx);
315
+ const contentInsetEnd = getContentInsetEnd(ctx);
302
316
  const totalSize = (_b = (_a3 = state.pendingTotalSize) != null ? _a3 : state.totalSize) != null ? _b : values.get("totalSize");
303
- return headerSize + footerSize + totalSize + stylePaddingTop + alignItemsAtEndPadding + stylePaddingBottom + (contentInsetBottom || 0);
317
+ const layoutSize = Math.max(0, totalSize - (state.props.data.length > 0 ? ctx.scrollAxisGap : 0));
318
+ return headerSize + footerSize + layoutSize + stylePaddingStart + alignItemsAtEndPadding + stylePaddingEnd + (contentInsetEnd || 0);
304
319
  }
305
320
 
306
321
  // src/components/DebugView.tsx
@@ -421,6 +436,28 @@ var EDGE_POSITION_EPSILON = 1;
421
436
  var ENABLE_DEVMODE = IS_DEV && false;
422
437
  var ENABLE_DEBUG_VIEW = IS_DEV && false;
423
438
 
439
+ // src/core/cancelImperativeScroll.ts
440
+ function cancelScrollCompletionChecks({ scheduledWork }) {
441
+ scheduledWork.cancel("checkFinishedScrollFrame");
442
+ scheduledWork.cancel("checkFinishedScrollRetryFrame");
443
+ scheduledWork.cancel("checkFinishedScrollFallback");
444
+ scheduledWork.cancel("platformScrollCompletion");
445
+ }
446
+ function settlePendingImperativeScroll(state) {
447
+ var _a3, _b;
448
+ const resolvePendingScroll = (_b = state.pendingScrollResolve) != null ? _b : (_a3 = state.pendingScrollToEnd) == null ? void 0 : _a3.resolve;
449
+ state.pendingScrollResolve = void 0;
450
+ state.pendingScrollToEnd = void 0;
451
+ resolvePendingScroll == null ? void 0 : resolvePendingScroll();
452
+ }
453
+ function cancelImperativeScroll(state) {
454
+ cancelScrollCompletionChecks(state);
455
+ state.scheduledWork.cancel("imperativeScrollReady");
456
+ state.scrollingTo = void 0;
457
+ state.scrollTargetPinnedRange = void 0;
458
+ settlePendingImperativeScroll(state);
459
+ }
460
+
424
461
  // src/core/deferredPublicOnScroll.ts
425
462
  function withResolvedContentOffset(state, event, resolvedOffset) {
426
463
  return {
@@ -789,13 +826,7 @@ var DEFAULT_WEB_ADAPTIVE_RENDER_ENTER_VELOCITY = 6;
789
826
  var DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_VELOCITY = 3;
790
827
  var DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_DELAY = 250;
791
828
  function clearAdaptiveRenderExitTimeout(ctx) {
792
- const state = ctx.state;
793
- const previousTimeout = state.timeoutAdaptiveRender;
794
- if (previousTimeout !== void 0) {
795
- clearTimeout(previousTimeout);
796
- state.timeouts.delete(previousTimeout);
797
- state.timeoutAdaptiveRender = void 0;
798
- }
829
+ ctx.state.scheduledWork.cancel("adaptiveRender");
799
830
  }
800
831
  function scheduleAdaptiveRenderExit(ctx, exitDelay) {
801
832
  const state = ctx.state;
@@ -803,13 +834,7 @@ function scheduleAdaptiveRenderExit(ctx, exitDelay) {
803
834
  if (exitDelay <= 0) {
804
835
  setAdaptiveRender(ctx, "normal", "scroll");
805
836
  } else {
806
- const timeout = setTimeout(() => {
807
- state.timeouts.delete(timeout);
808
- state.timeoutAdaptiveRender = void 0;
809
- setAdaptiveRender(ctx, "normal", "scroll");
810
- }, exitDelay);
811
- state.timeoutAdaptiveRender = timeout;
812
- state.timeouts.add(timeout);
837
+ state.scheduledWork.timeout(() => setAdaptiveRender(ctx, "normal", "scroll"), exitDelay, "adaptiveRender");
813
838
  }
814
839
  }
815
840
  function setAdaptiveRender(ctx, mode, reason) {
@@ -841,7 +866,7 @@ function updateAdaptiveRender(ctx, scrollVelocity, options) {
841
866
  const exitDelay = (_c = adaptiveRender.exitDelay) != null ? _c : isWeb ? DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_DELAY : DEFAULT_ADAPTIVE_RENDER_EXIT_DELAY;
842
867
  const threshold = currentMode === "light" ? exitVelocity : enterVelocity;
843
868
  const nextMode = (options == null ? void 0 : options.forceLight) || Math.abs(scrollVelocity) > threshold ? "light" : "normal";
844
- const previousMode = state.timeoutAdaptiveRender !== void 0 ? "normal" : currentMode;
869
+ const previousMode = state.scheduledWork.has("adaptiveRender") ? "normal" : currentMode;
845
870
  if (nextMode !== previousMode) {
846
871
  if (nextMode === "light") {
847
872
  setAdaptiveRender(ctx, "light", "scroll");
@@ -868,14 +893,13 @@ function getEffectiveDrawDistance(ctx, mode) {
868
893
  }
869
894
  function scheduleFullDrawDistancePrewarm(ctx) {
870
895
  const { state } = ctx;
871
- if (state.props.drawDistance <= INITIAL_DRAW_DISTANCE || state.queuedFullDrawDistancePrewarm !== void 0) {
896
+ if (state.props.drawDistance <= INITIAL_DRAW_DISTANCE || state.scheduledWork.has("fullDrawDistancePrewarm")) {
872
897
  return;
873
898
  }
874
- state.queuedFullDrawDistancePrewarm = requestAnimationFrame(() => {
899
+ state.scheduledWork.frame(() => {
875
900
  var _a3;
876
- state.queuedFullDrawDistancePrewarm = void 0;
877
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
878
- });
901
+ return (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
902
+ }, "fullDrawDistancePrewarm");
879
903
  }
880
904
 
881
905
  // src/utils/setInitialRenderState.ts
@@ -933,10 +957,7 @@ function syncInitialScrollOffset(state, offset) {
933
957
  state.scrollPrev = offset;
934
958
  }
935
959
  function clearPreservedInitialScrollTargetTimeout(state) {
936
- if (state.timeoutPreservedInitialScrollClear !== void 0) {
937
- clearTimeout(state.timeoutPreservedInitialScrollClear);
938
- state.timeoutPreservedInitialScrollClear = void 0;
939
- }
960
+ state.scheduledWork.cancel("preservedInitialScroll");
940
961
  }
941
962
  function clearPreservedInitialScrollTarget(state) {
942
963
  clearPreservedInitialScrollTargetTimeout(state);
@@ -944,6 +965,24 @@ function clearPreservedInitialScrollTarget(state) {
944
965
  state.initialScroll = void 0;
945
966
  setInitialScrollSession(state);
946
967
  }
968
+ function supersedeInitialScroll(ctx) {
969
+ var _a3, _b, _c;
970
+ const state = ctx.state;
971
+ const bootstrapInitialScroll = ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap" ? state.initialScrollSession.bootstrap : void 0;
972
+ if (state.initialScroll || bootstrapInitialScroll || ((_b = state.scrollingTo) == null ? void 0 : _b.isInitialScroll)) {
973
+ if ((bootstrapInitialScroll == null ? void 0 : bootstrapInitialScroll.frameHandle) !== void 0 && typeof cancelAnimationFrame === "function") {
974
+ cancelAnimationFrame(bootstrapInitialScroll.frameHandle);
975
+ }
976
+ if ((_c = state.scrollingTo) == null ? void 0 : _c.isInitialScroll) {
977
+ cancelScrollCompletionChecks(state);
978
+ state.scrollingTo = void 0;
979
+ state.scrollTargetPinnedRange = void 0;
980
+ }
981
+ initialScrollCompletion.resetFlags(state);
982
+ setInitialScrollSession(state, { bootstrap: null });
983
+ finishInitialScroll(ctx);
984
+ }
985
+ }
947
986
  function finishInitialScroll(ctx, options) {
948
987
  var _a3, _b, _c;
949
988
  const state = ctx.state;
@@ -965,14 +1004,17 @@ function finishInitialScroll(ctx, options) {
965
1004
  setInitialScrollSession(state);
966
1005
  clearPreservedInitialScrollTargetTimeout(state);
967
1006
  if (options == null ? void 0 : options.schedulePreservedTargetClear) {
968
- state.timeoutPreservedInitialScrollClear = setTimeout(() => {
969
- var _a5;
970
- state.timeoutPreservedInitialScrollClear = void 0;
971
- if (!state.didFinishInitialScroll || ((_a5 = state.scrollingTo) == null ? void 0 : _a5.isInitialScroll) || !state.initialScroll) {
972
- return;
973
- }
974
- clearPreservedInitialScrollTarget(state);
975
- }, PRESERVED_INITIAL_SCROLL_FALLBACK_CLEAR_DELAY_MS);
1007
+ state.scheduledWork.timeout(
1008
+ () => {
1009
+ var _a5;
1010
+ if (!state.didFinishInitialScroll || ((_a5 = state.scrollingTo) == null ? void 0 : _a5.isInitialScroll) || !state.initialScroll) {
1011
+ return;
1012
+ }
1013
+ clearPreservedInitialScrollTarget(state);
1014
+ },
1015
+ PRESERVED_INITIAL_SCROLL_FALLBACK_CLEAR_DELAY_MS,
1016
+ "preservedInitialScroll"
1017
+ );
976
1018
  }
977
1019
  } else {
978
1020
  clearPreservedInitialScrollTarget(state);
@@ -999,9 +1041,11 @@ function calculateOffsetForIndex(ctx, index) {
999
1041
  return index !== void 0 ? state.positions[index] || 0 : 0;
1000
1042
  }
1001
1043
 
1002
- // src/core/getTopOffsetAdjustment.ts
1003
- function getTopOffsetAdjustment(ctx) {
1004
- return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
1044
+ // src/core/getStartOffsetAdjustment.ts
1045
+ function getStartOffsetAdjustment(ctx) {
1046
+ const { state } = ctx;
1047
+ const stylePaddingStart = state.props.horizontal ? (isHorizontalRTL(state) ? state.props.stylePaddingRight : state.props.stylePaddingLeft) || 0 : peek$(ctx, "stylePaddingTop") || 0;
1048
+ return stylePaddingStart + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
1005
1049
  }
1006
1050
 
1007
1051
  // src/utils/getId.ts
@@ -1214,9 +1258,9 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1214
1258
  offset -= viewOffset;
1215
1259
  }
1216
1260
  if (index !== void 0) {
1217
- const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
1218
- if (topOffsetAdjustment) {
1219
- offset += topOffsetAdjustment;
1261
+ const startOffsetAdjustment = getStartOffsetAdjustment(ctx);
1262
+ if (startOffsetAdjustment) {
1263
+ offset += startOffsetAdjustment;
1220
1264
  }
1221
1265
  }
1222
1266
  if (viewPosition !== void 0 && index !== void 0) {
@@ -1226,7 +1270,8 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1226
1270
  }
1227
1271
  const isOutOfBounds = index < 0 || index >= dataLength;
1228
1272
  const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
1229
- const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1273
+ const measuredItemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1274
+ const itemSize = Math.max(0, measuredItemSize - (isOutOfBounds ? 0 : ctx.scrollAxisGap));
1230
1275
  const trailingInset = getContentInsetEnd(ctx);
1231
1276
  offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1232
1277
  if (!isOutOfBounds && index === state.props.data.length - 1) {
@@ -1258,6 +1303,7 @@ function finishScrollTo(ctx) {
1258
1303
  var _a3, _b;
1259
1304
  const state = ctx.state;
1260
1305
  if (state == null ? void 0 : state.scrollingTo) {
1306
+ cancelScrollCompletionChecks(state);
1261
1307
  const resolvePendingScroll = state.pendingScrollResolve;
1262
1308
  state.pendingScrollResolve = void 0;
1263
1309
  const scrollingTo = state.scrollingTo;
@@ -1306,7 +1352,7 @@ function checkFinishedScroll(ctx, options) {
1306
1352
  return;
1307
1353
  }
1308
1354
  }
1309
- ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
1355
+ ctx.state.scheduledWork.frame(() => checkFinishedScrollFrame(ctx), "checkFinishedScrollFrame");
1310
1356
  }
1311
1357
  function hasScrollCompletionOwnership(state, options) {
1312
1358
  const { clampedTargetOffset, scrollingTo } = options;
@@ -1376,7 +1422,6 @@ function checkFinishedScrollFrame(ctx) {
1376
1422
  return;
1377
1423
  }
1378
1424
  const { state } = ctx;
1379
- state.animFrameCheckFinishedScroll = void 0;
1380
1425
  const completionState = getResolvedScrollCompletionState(ctx, scrollingTo);
1381
1426
  if (completionState.isAtResolvedTarget && hasScrollCompletionOwnership(state, {
1382
1427
  clampedTargetOffset: completionState.clampedTargetOffset,
@@ -1395,61 +1440,62 @@ function scrollToFallbackOffset(ctx, offset) {
1395
1440
  }
1396
1441
  function checkFinishedScrollFallback(ctx) {
1397
1442
  const state = ctx.state;
1443
+ if (state.scheduledWork.has("checkFinishedScrollFallback")) {
1444
+ return;
1445
+ }
1398
1446
  const scrollingTo = state.scrollingTo;
1399
1447
  const shouldFinishInitialZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
1400
1448
  const silentInitialDispatch = isSilentInitialDispatch(state, scrollingTo);
1401
1449
  const canFinishInitialWithoutNativeProgress = scrollingTo !== void 0 ? shouldFinishInitialScrollWithoutNativeProgress(state, scrollingTo) : false;
1402
1450
  const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) && !shouldFinishInitialZeroTarget && !canFinishInitialWithoutNativeProgress || !state.didContainersLayout;
1403
1451
  const initialDelay = shouldFinishInitialZeroTarget || canFinishInitialWithoutNativeProgress ? 0 : silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : slowTimeout ? 500 : 100;
1404
- state.timeoutCheckFinishedScrollFallback = setTimeout(() => {
1405
- let numChecks = 0;
1406
- const scheduleFallbackCheck = (delay) => {
1407
- state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, delay);
1408
- };
1409
- const checkHasScrolled = () => {
1410
- var _a3, _b, _c, _d;
1411
- state.timeoutCheckFinishedScrollFallback = void 0;
1412
- const isStillScrollingTo = state.scrollingTo;
1413
- if (isStillScrollingTo) {
1414
- numChecks++;
1415
- const isNativeInitialPending = isNativeInitialNonZeroTarget(state) && !state.hasScrolled;
1416
- const maxChecks = silentInitialDispatch ? 5 : isNativeInitialPending ? INITIAL_SCROLL_MAX_FALLBACK_CHECKS : 5;
1417
- const shouldFinishZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
1418
- const canFinishInitialScrollWithoutNativeProgress = shouldFinishInitialScrollWithoutNativeProgress(
1419
- state,
1420
- isStillScrollingTo
1452
+ let numChecks = 0;
1453
+ const scheduleFallbackCheck = (delay) => {
1454
+ state.scheduledWork.timeout(checkHasScrolled, delay, "checkFinishedScrollFallback");
1455
+ };
1456
+ const checkHasScrolled = () => {
1457
+ var _a3, _b, _c, _d;
1458
+ const isStillScrollingTo = state.scrollingTo;
1459
+ if (isStillScrollingTo) {
1460
+ numChecks++;
1461
+ const isNativeInitialPending = isNativeInitialNonZeroTarget(state) && !state.hasScrolled;
1462
+ const maxChecks = silentInitialDispatch ? 5 : isNativeInitialPending ? INITIAL_SCROLL_MAX_FALLBACK_CHECKS : 5;
1463
+ const shouldFinishZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
1464
+ const canFinishInitialScrollWithoutNativeProgress = shouldFinishInitialScrollWithoutNativeProgress(
1465
+ state,
1466
+ isStillScrollingTo
1467
+ );
1468
+ const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
1469
+ const canFinishAfterSilentNativeDispatch = Platform.OS === "android" && silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
1470
+ const shouldRetrySilentInitialNativeScroll = Platform.OS === "android" && canFinishAfterSilentNativeDispatch && !initialScrollCompletion.didRetrySilentInitialScroll(state);
1471
+ const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
1472
+ const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
1473
+ const shouldRetryUnalignedEndScroll = Platform.OS === "ios" && !isStillScrollingTo.isInitialScroll && isEndAlignedLastItemTarget(ctx, isStillScrollingTo) && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
1474
+ if (shouldRetrySilentInitialNativeScroll) {
1475
+ const targetOffset = (_b = (_a3 = getInitialScrollWatchdogTargetOffset(state)) != null ? _a3 : isStillScrollingTo.targetOffset) != null ? _b : 0;
1476
+ const jiggleOffset = targetOffset >= SILENT_INITIAL_SCROLL_TARGET_EPSILON ? targetOffset - SILENT_INITIAL_SCROLL_TARGET_EPSILON : targetOffset + SILENT_INITIAL_SCROLL_TARGET_EPSILON;
1477
+ initialScrollCompletion.markSilentInitialScrollRetry(state);
1478
+ scrollToFallbackOffset(ctx, jiggleOffset);
1479
+ state.scheduledWork.frame(
1480
+ () => scrollToFallbackOffset(ctx, targetOffset),
1481
+ "checkFinishedScrollRetryFrame"
1421
1482
  );
1422
- const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
1423
- const canFinishAfterSilentNativeDispatch = Platform.OS === "android" && silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
1424
- const shouldRetrySilentInitialNativeScroll = Platform.OS === "android" && canFinishAfterSilentNativeDispatch && !initialScrollCompletion.didRetrySilentInitialScroll(state);
1425
- const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
1426
- const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
1427
- const shouldRetryUnalignedEndScroll = Platform.OS === "ios" && !isStillScrollingTo.isInitialScroll && isEndAlignedLastItemTarget(ctx, isStillScrollingTo) && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
1428
- if (shouldRetrySilentInitialNativeScroll) {
1429
- const targetOffset = (_b = (_a3 = getInitialScrollWatchdogTargetOffset(state)) != null ? _a3 : isStillScrollingTo.targetOffset) != null ? _b : 0;
1430
- const jiggleOffset = targetOffset >= SILENT_INITIAL_SCROLL_TARGET_EPSILON ? targetOffset - SILENT_INITIAL_SCROLL_TARGET_EPSILON : targetOffset + SILENT_INITIAL_SCROLL_TARGET_EPSILON;
1431
- initialScrollCompletion.markSilentInitialScrollRetry(state);
1432
- scrollToFallbackOffset(ctx, jiggleOffset);
1433
- requestAnimationFrame(() => {
1434
- scrollToFallbackOffset(ctx, targetOffset);
1435
- });
1436
- scheduleFallbackCheck(SILENT_INITIAL_SCROLL_RETRY_DELAY_MS);
1437
- } else if (shouldRetryUnalignedEndScroll) {
1438
- scrollToFallbackOffset(ctx, completionState.clampedTargetOffset);
1439
- scheduleFallbackCheck(100);
1440
- } else if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
1441
- finishScrollTo(ctx);
1442
- } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
1443
- const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
1444
- scrollToFallbackOffset(ctx, targetOffset);
1445
- scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
1446
- } else {
1447
- scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
1448
- }
1483
+ scheduleFallbackCheck(SILENT_INITIAL_SCROLL_RETRY_DELAY_MS);
1484
+ } else if (shouldRetryUnalignedEndScroll) {
1485
+ scrollToFallbackOffset(ctx, completionState.clampedTargetOffset);
1486
+ scheduleFallbackCheck(100);
1487
+ } else if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
1488
+ finishScrollTo(ctx);
1489
+ } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
1490
+ const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
1491
+ scrollToFallbackOffset(ctx, targetOffset);
1492
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
1493
+ } else {
1494
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
1449
1495
  }
1450
- };
1451
- checkHasScrolled();
1452
- }, initialDelay);
1496
+ }
1497
+ };
1498
+ scheduleFallbackCheck(initialDelay);
1453
1499
  }
1454
1500
 
1455
1501
  // src/core/doScrollTo.native.ts
@@ -1473,6 +1519,9 @@ function doScrollTo(ctx, params) {
1473
1519
  if (isInitialScroll) {
1474
1520
  initialScrollCompletion.markInitialScrollNativeDispatch(state);
1475
1521
  }
1522
+ if (isAnimated && Math.abs(state.scroll - offset) <= 1) {
1523
+ checkFinishedScroll(ctx);
1524
+ }
1476
1525
  if (!isAnimated) {
1477
1526
  state.scroll = offset;
1478
1527
  checkFinishedScrollFallback(ctx);
@@ -1503,9 +1552,12 @@ function doMaintainScrollAtEnd(ctx) {
1503
1552
  if (!state.maintainingScrollAtEnd) {
1504
1553
  const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
1505
1554
  const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
1555
+ const scrollAtRequest = state.scroll;
1506
1556
  state.maintainingScrollAtEnd = pendingState;
1507
1557
  requestAnimationFrame(() => {
1508
- if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
1558
+ const isStillWithinThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
1559
+ const didScrollSinceRequest = state.scroll !== scrollAtRequest;
1560
+ if (isStillWithinThreshold || !didScrollSinceRequest) {
1509
1561
  state.maintainingScrollAtEnd = activeState;
1510
1562
  const scroller = refScroller.current;
1511
1563
  if (state.props.horizontal && isHorizontalRTL(state)) {
@@ -1535,6 +1587,7 @@ function doMaintainScrollAtEnd(ctx) {
1535
1587
  );
1536
1588
  } else if (state.maintainingScrollAtEnd === pendingState) {
1537
1589
  state.maintainingScrollAtEnd = void 0;
1590
+ state.pendingMaintainScrollAtEnd = false;
1538
1591
  }
1539
1592
  });
1540
1593
  } else {
@@ -1576,20 +1629,21 @@ function requestAdjust(ctx, positionDiff, dataChanged) {
1576
1629
  } else {
1577
1630
  state.ignoreScrollFromMVCP.gt = threshold;
1578
1631
  }
1579
- if (state.ignoreScrollFromMVCPTimeout) {
1580
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
1581
- }
1582
1632
  const delay = needsScrollWorkaround ? 250 : 100;
1583
- state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
1584
- var _a3;
1585
- state.ignoreScrollFromMVCP = void 0;
1586
- const shouldForceUpdate = state.ignoreScrollFromMVCPIgnored && state.scrollProcessingEnabled !== false;
1587
- if (shouldForceUpdate) {
1588
- state.ignoreScrollFromMVCPIgnored = false;
1589
- state.scrollPending = state.scroll;
1590
- (_a3 = state.reprocessCurrentScroll) == null ? void 0 : _a3.call(state);
1591
- }
1592
- }, delay);
1633
+ state.scheduledWork.timeout(
1634
+ () => {
1635
+ var _a3;
1636
+ state.ignoreScrollFromMVCP = void 0;
1637
+ const shouldForceUpdate = state.ignoreScrollFromMVCPIgnored && state.scrollProcessingEnabled !== false;
1638
+ if (shouldForceUpdate) {
1639
+ state.ignoreScrollFromMVCPIgnored = false;
1640
+ state.scrollPending = state.scroll;
1641
+ (_a3 = state.reprocessCurrentScroll) == null ? void 0 : _a3.call(state);
1642
+ }
1643
+ },
1644
+ delay,
1645
+ "ignoreScrollFromMVCP"
1646
+ );
1593
1647
  }
1594
1648
  } else {
1595
1649
  state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
@@ -2017,10 +2071,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
2017
2071
  state.mvcpAnchorLock = void 0;
2018
2072
  state.pendingNativeMVCPAdjust = void 0;
2019
2073
  state.userScrollAnchorReset = { keys: /* @__PURE__ */ new Set() };
2020
- if (state.queuedMVCPRecalculate !== void 0) {
2021
- cancelAnimationFrame(state.queuedMVCPRecalculate);
2022
- state.queuedMVCPRecalculate = void 0;
2023
- }
2074
+ state.scheduledWork.cancel("mvcpRecalculate");
2024
2075
  flushSync(runCalculateItems);
2025
2076
  scheduleFullDrawDistancePrewarm(ctx);
2026
2077
  } else {
@@ -2165,12 +2216,7 @@ function scrollTo(ctx, params) {
2165
2216
  const {
2166
2217
  props: { horizontal }
2167
2218
  } = state;
2168
- if (state.animFrameCheckFinishedScroll) {
2169
- cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
2170
- }
2171
- if (state.timeoutCheckFinishedScrollFallback) {
2172
- clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
2173
- }
2219
+ cancelScrollCompletionChecks(state);
2174
2220
  const requestedOffset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
2175
2221
  const shouldPreserveRawInitialOffsetRequest = !!isInitialScroll && ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset";
2176
2222
  const targetOffset = clampScrollOffset(ctx, requestedOffset, scrollTarget);
@@ -2275,10 +2321,7 @@ function setInitialScrollTarget(ctx, target, options) {
2275
2321
  var _a3;
2276
2322
  const { state } = ctx;
2277
2323
  state.clearPreservedInitialScrollOnNextFinish = void 0;
2278
- if (state.timeoutPreservedInitialScrollClear !== void 0) {
2279
- clearTimeout(state.timeoutPreservedInitialScrollClear);
2280
- state.timeoutPreservedInitialScrollClear = void 0;
2281
- }
2324
+ state.scheduledWork.cancel("preservedInitialScroll");
2282
2325
  state.initialScroll = target;
2283
2326
  if (options == null ? void 0 : options.resetDidFinish) {
2284
2327
  resetInitialRenderState(ctx, { resetInitialScroll: true });
@@ -2571,13 +2614,13 @@ function rearmBootstrapInitialScroll(ctx, options) {
2571
2614
  queueBootstrapInitialScrollReevaluation(ctx.state);
2572
2615
  }
2573
2616
  function createInitialScrollAtEndTarget(options) {
2574
- const { dataLength, footerSize, preserveForFooterLayout, stylePaddingBottom } = options;
2617
+ const { dataLength, footerSize, preserveForFooterLayout, stylePaddingEnd } = options;
2575
2618
  return {
2576
2619
  contentOffset: void 0,
2577
2620
  index: Math.max(0, dataLength - 1),
2578
2621
  preserveForBottomPadding: true,
2579
2622
  preserveForFooterLayout,
2580
- viewOffset: -stylePaddingBottom - footerSize,
2623
+ viewOffset: -stylePaddingEnd - footerSize,
2581
2624
  viewPosition: 1
2582
2625
  };
2583
2626
  }
@@ -2591,7 +2634,7 @@ function isRetargetableBottomAlignedInitialScrollTarget(target) {
2591
2634
  return !!(target && target.viewPosition === 1 && (shouldPreserveInitialScrollForBottomPadding(target) || shouldPreserveInitialScrollForFooterLayout(target)));
2592
2635
  }
2593
2636
  function createRetargetedBottomAlignedInitialScroll(options) {
2594
- const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom, target } = options;
2637
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd, target } = options;
2595
2638
  const preserveForFooterLayout = shouldPreserveInitialScrollForFooterLayout(target);
2596
2639
  return {
2597
2640
  ...target,
@@ -2599,7 +2642,7 @@ function createRetargetedBottomAlignedInitialScroll(options) {
2599
2642
  index: initialScrollAtEnd ? Math.max(0, dataLength - 1) : target.index,
2600
2643
  preserveForBottomPadding: true,
2601
2644
  preserveForFooterLayout,
2602
- viewOffset: -stylePaddingBottom - (preserveForFooterLayout ? footerSize : 0),
2645
+ viewOffset: -stylePaddingEnd - (preserveForFooterLayout ? footerSize : 0),
2603
2646
  viewPosition: 1
2604
2647
  };
2605
2648
  }
@@ -2607,7 +2650,7 @@ function areEquivalentBootstrapInitialScrollTargets(current, next) {
2607
2650
  return current.index === next.index && current.preserveForBottomPadding === next.preserveForBottomPadding && current.preserveForFooterLayout === next.preserveForFooterLayout && current.viewOffset === next.viewOffset && current.viewPosition === next.viewPosition;
2608
2651
  }
2609
2652
  function clearPendingInitialScrollFooterLayout(ctx, options) {
2610
- const { dataLength, stylePaddingBottom, target } = options;
2653
+ const { dataLength, stylePaddingEnd, target } = options;
2611
2654
  if (!shouldPreserveInitialScrollForFooterLayout(target)) {
2612
2655
  return;
2613
2656
  }
@@ -2615,7 +2658,7 @@ function clearPendingInitialScrollFooterLayout(ctx, options) {
2615
2658
  dataLength,
2616
2659
  footerSize: 0,
2617
2660
  preserveForFooterLayout: void 0,
2618
- stylePaddingBottom
2661
+ stylePaddingEnd
2619
2662
  });
2620
2663
  setInitialScrollTarget(ctx, clearedFooterTarget);
2621
2664
  }
@@ -2676,7 +2719,7 @@ function schedulePreservedEndAnchorCorrectionFrame(ctx, correction) {
2676
2719
  });
2677
2720
  }
2678
2721
  function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2679
- var _a3, _b;
2722
+ var _a3;
2680
2723
  const state = ctx.state;
2681
2724
  const initialScroll = state.initialScroll;
2682
2725
  if (!state.didFinishInitialScroll || ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) || (initialScroll == null ? void 0 : initialScroll.viewPosition) !== 1 || state.preservedEndAnchorCorrection) {
@@ -2688,7 +2731,7 @@ function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2688
2731
  if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
2689
2732
  clearPendingInitialScrollFooterLayout(ctx, {
2690
2733
  dataLength: state.props.data.length,
2691
- stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
2734
+ stylePaddingEnd: getStylePaddingEnd(state.props),
2692
2735
  target: initialScroll
2693
2736
  });
2694
2737
  } else {
@@ -2725,7 +2768,7 @@ function startBootstrapInitialScrollOnMount(ctx, options) {
2725
2768
  }
2726
2769
  }
2727
2770
  function handleBootstrapInitialScrollDataChange(ctx, options) {
2728
- const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingBottom } = options;
2771
+ const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingEnd } = options;
2729
2772
  const state = ctx.state;
2730
2773
  const initialScroll = state.initialScroll;
2731
2774
  if (isOffsetInitialScrollSession(state) || !initialScroll) {
@@ -2747,18 +2790,18 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2747
2790
  dataLength,
2748
2791
  footerSize: peek$(ctx, "footerSize") || 0,
2749
2792
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2750
- stylePaddingBottom
2793
+ stylePaddingEnd
2751
2794
  }) : createRetargetedBottomAlignedInitialScroll({
2752
2795
  dataLength,
2753
2796
  footerSize: peek$(ctx, "footerSize") || 0,
2754
2797
  initialScrollAtEnd,
2755
- stylePaddingBottom,
2798
+ stylePaddingEnd,
2756
2799
  target: initialScroll
2757
2800
  });
2758
2801
  if (!shouldResetDidFinish && didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2759
2802
  clearPendingInitialScrollFooterLayout(ctx, {
2760
2803
  dataLength,
2761
- stylePaddingBottom,
2804
+ stylePaddingEnd,
2762
2805
  target: initialScroll
2763
2806
  });
2764
2807
  return;
@@ -2790,7 +2833,7 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2790
2833
  }
2791
2834
  }
2792
2835
  function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2793
- const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom } = options;
2836
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd } = options;
2794
2837
  const state = ctx.state;
2795
2838
  if (!initialScrollAtEnd) {
2796
2839
  return;
@@ -2806,7 +2849,7 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2806
2849
  if (didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2807
2850
  clearPendingInitialScrollFooterLayout(ctx, {
2808
2851
  dataLength,
2809
- stylePaddingBottom,
2852
+ stylePaddingEnd,
2810
2853
  target: initialScroll
2811
2854
  });
2812
2855
  } else {
@@ -2814,13 +2857,13 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2814
2857
  dataLength,
2815
2858
  footerSize,
2816
2859
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2817
- stylePaddingBottom
2860
+ stylePaddingEnd
2818
2861
  });
2819
2862
  const didTargetChange = initialScroll.index !== updatedInitialScroll.index || initialScroll.viewPosition !== updatedInitialScroll.viewPosition || initialScroll.viewOffset !== updatedInitialScroll.viewOffset;
2820
2863
  if (!didTargetChange) {
2821
2864
  clearPendingInitialScrollFooterLayout(ctx, {
2822
2865
  dataLength,
2823
- stylePaddingBottom,
2866
+ stylePaddingEnd,
2824
2867
  target: initialScroll
2825
2868
  });
2826
2869
  } else {
@@ -3047,7 +3090,7 @@ function handleInitialScrollDataChange(ctx, options) {
3047
3090
  initialScrollAtEnd,
3048
3091
  latestInitialScroll,
3049
3092
  latestInitialScrollSessionKind,
3050
- stylePaddingBottom,
3093
+ stylePaddingEnd,
3051
3094
  useBootstrapInitialScroll
3052
3095
  } = options;
3053
3096
  const state = ctx.state;
@@ -3077,7 +3120,7 @@ function handleInitialScrollDataChange(ctx, options) {
3077
3120
  didDataChange,
3078
3121
  initialScrollAtEnd,
3079
3122
  previousDataLength: previousInitialScrollDataLength,
3080
- stylePaddingBottom
3123
+ stylePaddingEnd
3081
3124
  });
3082
3125
  return;
3083
3126
  }
@@ -3547,7 +3590,6 @@ function setupViewability(props) {
3547
3590
  }
3548
3591
  function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end, startBuffered = start, endBuffered = end) {
3549
3592
  const {
3550
- timeouts,
3551
3593
  props: { data }
3552
3594
  } = state;
3553
3595
  for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
@@ -3557,11 +3599,10 @@ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollS
3557
3599
  viewabilityState.startBuffered = startBuffered;
3558
3600
  viewabilityState.endBuffered = endBuffered;
3559
3601
  if (viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime) {
3560
- const timer = setTimeout(() => {
3561
- timeouts.delete(timer);
3562
- updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
3563
- }, viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime);
3564
- timeouts.add(timer);
3602
+ state.scheduledWork.timeout(
3603
+ () => updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize),
3604
+ viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime
3605
+ );
3565
3606
  } else {
3566
3607
  updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
3567
3608
  }
@@ -3920,20 +3961,15 @@ function getProjectedBufferAdjustment(scrollVelocity, trailingBuffer) {
3920
3961
  }
3921
3962
  function scheduleRenderRangeProjectionSettle(ctx) {
3922
3963
  const state = ctx.state;
3923
- const previousTimeout = state.timeoutRenderRangeProjectionSettle;
3924
- if (previousTimeout !== void 0) {
3925
- clearTimeout(previousTimeout);
3926
- state.timeouts.delete(previousTimeout);
3927
- }
3928
- const timeout = setTimeout(() => {
3929
- var _a3;
3930
- state.timeoutRenderRangeProjectionSettle = void 0;
3931
- state.timeouts.delete(timeout);
3932
- state.scrollHistory.length = 0;
3933
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
3934
- }, RENDER_RANGE_PROJECTION_SETTLE_DELAY);
3935
- state.timeoutRenderRangeProjectionSettle = timeout;
3936
- state.timeouts.add(timeout);
3964
+ state.scheduledWork.timeout(
3965
+ () => {
3966
+ var _a3;
3967
+ state.scrollHistory.length = 0;
3968
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
3969
+ },
3970
+ RENDER_RANGE_PROJECTION_SETTLE_DELAY,
3971
+ "renderRangeProjection"
3972
+ );
3937
3973
  }
3938
3974
  function findCurrentStickyIndex(stickyArray, scroll, state) {
3939
3975
  const positions = state.positions;
@@ -4601,8 +4637,6 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4601
4637
  if (anchorIndex >= 0 && anchorIndex < data.length && state.scrollLength > 0) {
4602
4638
  nextAnchorKey = getId(state, anchorIndex);
4603
4639
  let contentBelowAnchor = 0;
4604
- const footerSize = ctx.values.get("footerSize") || 0;
4605
- const stylePaddingBottom = state.props.stylePaddingBottom || 0;
4606
4640
  let hasUnknownTailSize = false;
4607
4641
  for (let index = anchorIndex; index < data.length; index++) {
4608
4642
  const size = getKnownOrFixedItemSize(ctx, index);
@@ -4614,14 +4648,16 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4614
4648
  contentBelowAnchor += effectiveSize;
4615
4649
  }
4616
4650
  }
4617
- contentBelowAnchor += footerSize + stylePaddingBottom;
4651
+ contentBelowAnchor = Math.max(0, contentBelowAnchor - ctx.scrollAxisGap);
4652
+ contentBelowAnchor += (ctx.values.get("footerSize") || 0) + getStylePaddingEnd(state.props);
4618
4653
  isReady = !hasUnknownTailSize;
4619
4654
  nextSize = hasUnknownTailSize ? previousSize || 0 : Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
4620
4655
  } else if (anchorIndex >= 0) {
4621
4656
  isReady = false;
4622
4657
  }
4623
4658
  }
4624
- const didSizeChange = previousSize !== nextSize;
4659
+ const didSizeChange = previousSize !== nextSize && (previousSize !== void 0 || anchoredEndSpace !== void 0);
4660
+ const didEffectiveSizeChange = (previousSize || 0) !== nextSize;
4625
4661
  const didReadyAnchorChange = previousReadyAnchorIndex !== nextAnchorIndex || previousReadyAnchorKey !== nextAnchorKey;
4626
4662
  if (isReady && (didSizeChange || didReadyAnchorChange)) {
4627
4663
  state.anchoredEndSpaceReadyAnchorIndex = nextAnchorIndex;
@@ -4630,8 +4666,9 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4630
4666
  set$(ctx, "anchoredEndSpaceSize", nextSize);
4631
4667
  (_a3 = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onSizeChanged) == null ? void 0 : _a3.call(anchoredEndSpace, nextSize);
4632
4668
  }
4633
- if (didSizeChange && (anchoredEndSpace == null ? void 0 : anchoredEndSpace.includeInEndInset)) {
4634
- updateScroll(ctx, state.scroll, true);
4669
+ if (didEffectiveSizeChange) {
4670
+ updateContentMetricsState(ctx);
4671
+ updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
4635
4672
  }
4636
4673
  (_b = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onReady) == null ? void 0 : _b.call(anchoredEndSpace, { anchorIndex: nextAnchorIndex, anchorKey: nextAnchorKey, size: nextSize });
4637
4674
  }
@@ -4660,16 +4697,10 @@ function runOrScheduleMVCPRecalculate(ctx) {
4660
4697
  }
4661
4698
  } else if (Platform.OS === "web") {
4662
4699
  if (!state.mvcpAnchorLock) {
4663
- if (state.queuedMVCPRecalculate !== void 0) {
4664
- cancelAnimationFrame(state.queuedMVCPRecalculate);
4665
- state.queuedMVCPRecalculate = void 0;
4666
- }
4700
+ state.scheduledWork.cancel("mvcpRecalculate");
4667
4701
  calculateItemsInView(ctx, { doMVCP: true });
4668
- } else if (state.queuedMVCPRecalculate === void 0) {
4669
- state.queuedMVCPRecalculate = requestAnimationFrame(() => {
4670
- state.queuedMVCPRecalculate = void 0;
4671
- calculateItemsInView(ctx, { doMVCP: true });
4672
- });
4702
+ } else if (!state.scheduledWork.has("mvcpRecalculate")) {
4703
+ state.scheduledWork.frame(() => calculateItemsInView(ctx, { doMVCP: true }), "mvcpRecalculate");
4673
4704
  }
4674
4705
  } else {
4675
4706
  calculateItemsInView(ctx, { doMVCP: true });
@@ -4716,6 +4747,9 @@ function flushItemSizeUpdates(ctx, result) {
4716
4747
  } else if (result.didMeasureUserScrollAnchorResetItem && ((_a3 = state.userScrollAnchorReset) == null ? void 0 : _a3.keys.size) === 0) {
4717
4748
  state.userScrollAnchorReset = void 0;
4718
4749
  }
4750
+ if (result.didChange) {
4751
+ maybeUpdateAnchoredEndSpace(ctx);
4752
+ }
4719
4753
  if (result.didChange && result.shouldMaintainScrollAtEnd) {
4720
4754
  doMaintainScrollAtEnd(ctx);
4721
4755
  }
@@ -4795,7 +4829,7 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
4795
4829
  if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
4796
4830
  needsRecalculate = true;
4797
4831
  }
4798
- if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
4832
+ if (prevSizeKnown === void 0 || Math.abs(prevSizeKnown - size) > 5) {
4799
4833
  shouldMaintainScrollAtEnd = true;
4800
4834
  }
4801
4835
  onItemSizeChanged == null ? void 0 : onItemSizeChanged({
@@ -4805,7 +4839,6 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
4805
4839
  previous: size - diff,
4806
4840
  size
4807
4841
  });
4808
- maybeUpdateAnchoredEndSpace(ctx);
4809
4842
  }
4810
4843
  if (minIndexSizeChanged !== void 0) {
4811
4844
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
@@ -5645,19 +5678,32 @@ function ContainerSlotBase({
5645
5678
  var ContainerSlot = typedMemo(function ContainerSlot2(props) {
5646
5679
  return /* @__PURE__ */ React2.createElement(ContainerSlotBase, { ...props });
5647
5680
  });
5681
+ function useFreshDataTransitionVisibility(readyToRender, transitionEpoch) {
5682
+ const [completedTransitionEpoch, setCompletedTransitionEpoch] = useState(transitionEpoch);
5683
+ const isTransitionPending = completedTransitionEpoch !== transitionEpoch;
5684
+ useLayoutEffect(() => {
5685
+ setCompletedTransitionEpoch(transitionEpoch);
5686
+ }, [transitionEpoch]);
5687
+ return readyToRender && !isTransitionPending;
5688
+ }
5648
5689
 
5649
5690
  // src/components/Containers.native.tsx
5650
- var ContainersLayer = typedMemo(function ContainersLayer2({ children, horizontal }) {
5691
+ var ContainersLayer = typedMemo(function ContainersLayer2({
5692
+ children,
5693
+ freshDataTransitionEpoch,
5694
+ horizontal
5695
+ }) {
5651
5696
  const ctx = useStateContext();
5652
5697
  const columnWrapperStyle = ctx.columnWrapperStyle;
5653
5698
  const animSize = useValue$("totalSize");
5654
5699
  const [readyToRender, numColumns, otherAxisSize = 0] = useArr$(["readyToRender", "numColumns", "otherAxisSize"]);
5700
+ const isVisible = useFreshDataTransitionVisibility(!!readyToRender, freshDataTransitionEpoch);
5655
5701
  const style = horizontal ? {
5656
5702
  height: otherAxisSize || "100%",
5657
5703
  minHeight: otherAxisSize,
5658
- opacity: readyToRender ? 1 : 0,
5704
+ opacity: isVisible ? 1 : 0,
5659
5705
  width: animSize
5660
- } : { height: animSize, minWidth: otherAxisSize, opacity: readyToRender ? 1 : 0 };
5706
+ } : { height: animSize, minWidth: otherAxisSize, opacity: isVisible ? 1 : 0 };
5661
5707
  if (columnWrapperStyle) {
5662
5708
  const { columnGap, rowGap, gap } = columnWrapperStyle;
5663
5709
  const gapX = columnGap || gap || 0;
@@ -5678,9 +5724,10 @@ var ContainersLayer = typedMemo(function ContainersLayer2({ children, horizontal
5678
5724
  }
5679
5725
  }
5680
5726
  }
5681
- return /* @__PURE__ */ React2.createElement(Animated.View, { style }, /* @__PURE__ */ React2.createElement(ContainerLayoutCoordinator, null, children));
5727
+ return /* @__PURE__ */ React2.createElement(Animated.View, { pointerEvents: isVisible ? void 0 : "none", style }, /* @__PURE__ */ React2.createElement(ContainerLayoutCoordinator, null, children));
5682
5728
  });
5683
5729
  var Containers = typedMemo(function Containers2({
5730
+ freshDataTransitionEpoch,
5684
5731
  horizontal,
5685
5732
  recycleItems,
5686
5733
  ItemSeparatorComponent,
@@ -5705,7 +5752,7 @@ var Containers = typedMemo(function Containers2({
5705
5752
  )
5706
5753
  );
5707
5754
  }
5708
- return /* @__PURE__ */ React2.createElement(ContainersLayer, { horizontal }, containers);
5755
+ return /* @__PURE__ */ React2.createElement(ContainersLayer, { freshDataTransitionEpoch, horizontal }, containers);
5709
5756
  });
5710
5757
  var ListComponentScrollView = Animated.ScrollView;
5711
5758
 
@@ -5744,16 +5791,6 @@ var SnapWrapper = React2.forwardRef(function SnapWrapperInner({ ScrollComponent,
5744
5791
  const [snapToOffsets] = useArr$(["snapToOffsets"]);
5745
5792
  return /* @__PURE__ */ React2.createElement(ScrollComponent, { ...props, ref, snapToOffsets });
5746
5793
  });
5747
- function WebAnchoredEndSpace({ horizontal }) {
5748
- const ctx = useStateContext();
5749
- const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
5750
- const shouldRenderAnchoredEndSpace = !!ctx.state.props.anchoredEndSpace && (anchoredEndSpaceSize || 0) > 0;
5751
- if (!shouldRenderAnchoredEndSpace) {
5752
- return null;
5753
- }
5754
- const style = horizontal ? { height: "100%", width: anchoredEndSpaceSize || 0 } : { height: anchoredEndSpaceSize || 0 };
5755
- return /* @__PURE__ */ React2.createElement("div", { style }, null);
5756
- }
5757
5794
 
5758
5795
  // src/core/updateContentMetrics.ts
5759
5796
  var SCROLL_ADJUST_EPSILON = 0.1;
@@ -5787,7 +5824,11 @@ function setHeaderSize(ctx, size) {
5787
5824
  state.didMeasureHeader = true;
5788
5825
  }
5789
5826
  function setFooterSize(ctx, size) {
5790
- return setContentLengthSignal(ctx, "footerSize", size);
5827
+ const didChange = setContentLengthSignal(ctx, "footerSize", size);
5828
+ if (didChange) {
5829
+ maybeUpdateAnchoredEndSpace(ctx);
5830
+ }
5831
+ return didChange;
5791
5832
  }
5792
5833
  function areInsetsEqual(left, right) {
5793
5834
  var _a3, _b, _c, _d, _e, _f, _g, _h;
@@ -5830,6 +5871,7 @@ var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
5830
5871
  const { onLayout } = useOnLayoutSync({ onLayoutChange, ref });
5831
5872
  return /* @__PURE__ */ React2.createElement(View$1, { ...rest, onLayout, ref });
5832
5873
  };
5874
+ var StyleSheet = StyleSheet$1;
5833
5875
 
5834
5876
  // src/components/ListComponent.tsx
5835
5877
  var AlignItemsAtEndSpacer = typedMemo(function AlignItemsAtEndSpacer2({ horizontal }) {
@@ -5847,6 +5889,7 @@ var AlignItemsAtEndSpacer = typedMemo(function AlignItemsAtEndSpacer2({ horizont
5847
5889
  });
5848
5890
  var ListComponent = typedMemo(function ListComponent2({
5849
5891
  canRender,
5892
+ freshDataTransitionEpoch,
5850
5893
  style,
5851
5894
  contentContainerStyle,
5852
5895
  horizontal,
@@ -5876,8 +5919,17 @@ var ListComponent = typedMemo(function ListComponent2({
5876
5919
  }) {
5877
5920
  const ctx = useStateContext();
5878
5921
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
5879
- const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
5922
+ const [anchoredEndSpaceSize = 0, otherAxisSize = 0] = useArr$(["anchoredEndSpaceSize", "otherAxisSize"]);
5880
5923
  const shouldRenderAlignItemsAtEndSpacer = ctx.state.props.alignItemsAtEndPaddingEnabled;
5924
+ const shouldMaterializeAnchoredEndSpace = !!ctx.state.props.anchoredEndSpace && ctx.state.props.anchoredEndSpaceOwner === "list" && anchoredEndSpaceSize > 0;
5925
+ let anchoredEndSpaceStyle;
5926
+ if (shouldMaterializeAnchoredEndSpace) {
5927
+ const paddingEnd = horizontal ? isHorizontalRTL(ctx.state) ? "Left" : "Right" : "Bottom";
5928
+ const flattenedContentContainerStyle = StyleSheet.flatten(contentContainerStyle);
5929
+ anchoredEndSpaceStyle = {
5930
+ [`padding${paddingEnd}`]: extractPadding({}, flattenedContentContainerStyle || {}, paddingEnd) + anchoredEndSpaceSize
5931
+ };
5932
+ }
5881
5933
  const autoOtherAxisStyle = getAutoOtherAxisStyle({
5882
5934
  horizontal,
5883
5935
  needsOtherAxisSize: ctx.state.needsOtherAxisSize,
@@ -5930,10 +5982,10 @@ var ListComponent = typedMemo(function ListComponent2({
5930
5982
  ...rest,
5931
5983
  ...Platform.OS === "web" ? ScrollComponent === ListComponentScrollView ? { onInternalScrollEnd, useWindowScroll } : {} : { onScrollBeginDrag: onInternalScrollBeginDrag },
5932
5984
  contentContainerStyle: [
5933
- horizontal ? {
5934
- height: "100%"
5935
- } : {},
5936
- contentContainerStyle
5985
+ horizontal ? { height: "100%" } : {},
5986
+ contentContainerStyle,
5987
+ anchoredEndSpaceStyle,
5988
+ Platform.OS === "web" ? { boxSizing: "border-box" } : void 0
5937
5989
  ],
5938
5990
  contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
5939
5991
  horizontal,
@@ -5951,6 +6003,7 @@ var ListComponent = typedMemo(function ListComponent2({
5951
6003
  canRender && !ListEmptyComponent && /* @__PURE__ */ React2.createElement(
5952
6004
  Containers,
5953
6005
  {
6006
+ freshDataTransitionEpoch,
5954
6007
  getRenderedItem: getRenderedItem2,
5955
6008
  horizontal,
5956
6009
  ItemSeparatorComponent,
@@ -5959,7 +6012,6 @@ var ListComponent = typedMemo(function ListComponent2({
5959
6012
  }
5960
6013
  ),
5961
6014
  ListFooterComponent && /* @__PURE__ */ React2.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
5962
- Platform.OS === "web" && /* @__PURE__ */ React2.createElement(WebAnchoredEndSpace, { horizontal }),
5963
6015
  IS_DEV && ENABLE_DEVMODE
5964
6016
  );
5965
6017
  });
@@ -5968,7 +6020,16 @@ var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
5968
6020
  var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
5969
6021
  function useDevChecksImpl(props) {
5970
6022
  const ctx = useStateContext();
5971
- const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
6023
+ const { anchoredEndSpace, childrenMode, keyExtractor, numColumns, renderScrollComponent, useWindowScroll } = props;
6024
+ const hasAnchoredEndSpace = !!anchoredEndSpace;
6025
+ useEffect(() => {
6026
+ if (hasAnchoredEndSpace && (numColumns != null ? numColumns : 1) > 1) {
6027
+ warnDevOnce(
6028
+ "anchoredEndSpaceNumColumns",
6029
+ "anchoredEndSpace is only supported when numColumns is 1. Using it with multiple columns may produce incorrect anchored spacing."
6030
+ );
6031
+ }
6032
+ }, [hasAnchoredEndSpace, numColumns]);
5972
6033
  useEffect(() => {
5973
6034
  if (useWindowScroll && renderScrollComponent) {
5974
6035
  warnDevOnce(
@@ -6296,6 +6357,60 @@ function onScroll(ctx, event) {
6296
6357
  }
6297
6358
  }
6298
6359
 
6360
+ // src/core/ScheduledWork.ts
6361
+ var ScheduledWork = class {
6362
+ constructor() {
6363
+ this.work = /* @__PURE__ */ new Map();
6364
+ }
6365
+ timeout(callback, delay, key) {
6366
+ if (key) {
6367
+ this.cancel(key);
6368
+ }
6369
+ const work = [void 0, clearTimeout];
6370
+ const handle = setTimeout(() => {
6371
+ const workKey = key != null ? key : handle;
6372
+ if (this.work.get(workKey) === work) {
6373
+ this.work.delete(workKey);
6374
+ callback();
6375
+ }
6376
+ }, delay);
6377
+ work[0] = handle;
6378
+ this.work.set(key != null ? key : handle, work);
6379
+ }
6380
+ frame(callback, key) {
6381
+ this.cancel(key);
6382
+ const work = [void 0, cancelAnimationFrame];
6383
+ this.work.set(key, work);
6384
+ work[0] = requestAnimationFrame(() => {
6385
+ if (this.work.get(key) === work) {
6386
+ this.work.delete(key);
6387
+ callback();
6388
+ }
6389
+ });
6390
+ }
6391
+ register(key, cancel) {
6392
+ this.cancel(key);
6393
+ this.work.set(key, [void 0, cancel]);
6394
+ }
6395
+ cancel(key) {
6396
+ const work = this.work.get(key);
6397
+ if (work) {
6398
+ this.work.delete(key);
6399
+ const [handle, cancel] = work;
6400
+ cancel(handle);
6401
+ }
6402
+ }
6403
+ has(key) {
6404
+ return this.work.has(key);
6405
+ }
6406
+ dispose() {
6407
+ for (const [handle, cancel] of this.work.values()) {
6408
+ cancel(handle);
6409
+ }
6410
+ this.work.clear();
6411
+ }
6412
+ };
6413
+
6299
6414
  // src/core/ScrollAdjustHandler.ts
6300
6415
  var ScrollAdjustHandler = class {
6301
6416
  constructor(ctx) {
@@ -6383,7 +6498,6 @@ var useCombinedRef = (...refs) => {
6383
6498
  }, refs);
6384
6499
  return callback;
6385
6500
  };
6386
- var StyleSheet = StyleSheet$1;
6387
6501
  function useStickyScrollHandler(stickyHeaderIndices, horizontal, ctx, onScroll2) {
6388
6502
  const shouldUseRnAnimatedEngine = !ctx.state.props.stickyPositionComponentInternal;
6389
6503
  return useMemo(() => {
@@ -6470,7 +6584,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6470
6584
  const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
6471
6585
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
6472
6586
  let imperativeScrollToken = 0;
6473
- const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0;
6587
+ const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.scheduledWork.has("mvcpRecalculate") || state.ignoreScrollFromMVCP !== void 0;
6474
6588
  const isScrollToIndexReady = (targetIndex, allowEmpty = false) => {
6475
6589
  var _a3;
6476
6590
  const props = state.props;
@@ -6504,9 +6618,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6504
6618
  run();
6505
6619
  return;
6506
6620
  }
6507
- requestAnimationFrame(check);
6621
+ state.scheduledWork.frame(check, "imperativeScrollReady");
6508
6622
  };
6509
- requestAnimationFrame(check);
6623
+ state.scheduledWork.frame(check, "imperativeScrollReady");
6510
6624
  };
6511
6625
  const runScrollRequest = (token, resolve, run, isReady = () => true) => {
6512
6626
  const runNow = () => {
@@ -6528,15 +6642,15 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6528
6642
  }
6529
6643
  };
6530
6644
  const startImperativeScroll = (resolve) => {
6531
- var _a3;
6645
+ state.scheduledWork.cancel("imperativeScrollReady");
6532
6646
  const token = ++imperativeScrollToken;
6533
- state.pendingScrollToEnd = void 0;
6534
- (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
6647
+ settlePendingImperativeScroll(state);
6535
6648
  state.pendingScrollResolve = resolve;
6536
6649
  return token;
6537
6650
  };
6538
6651
  const runScrollWithPromise = (run, isReady = () => true) => new Promise((resolve) => {
6539
6652
  const token = startImperativeScroll(resolve);
6653
+ supersedeInitialScroll(ctx);
6540
6654
  runScrollRequest(token, resolve, run, isReady);
6541
6655
  });
6542
6656
  state.runPendingScrollToEnd = () => {
@@ -6615,6 +6729,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6615
6729
  end: state.endNoBuffer,
6616
6730
  endBuffered: state.endBuffered,
6617
6731
  getAverageItemSizes: () => getAverageItemSizes(state),
6732
+ indexByKey: (key) => state.indexByKey.get(key),
6618
6733
  isAtEnd: peek$(ctx, "isAtEnd"),
6619
6734
  isAtStart: peek$(ctx, "isAtStart"),
6620
6735
  isEndReached: state.isEndReached,
@@ -6662,9 +6777,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6662
6777
  resolve,
6663
6778
  token
6664
6779
  };
6665
- if (scheduleImperativeScrollCommit) {
6666
- scheduleImperativeScrollCommit();
6667
- } else {
6780
+ scheduleImperativeScrollCommit == null ? void 0 : scheduleImperativeScrollCommit();
6781
+ supersedeInitialScroll(ctx);
6782
+ if (!scheduleImperativeScrollCommit) {
6668
6783
  (_a3 = state.runPendingScrollToEnd) == null ? void 0 : _a3.call(state);
6669
6784
  }
6670
6785
  }),
@@ -6918,7 +7033,7 @@ var LegendList = typedMemo(
6918
7033
  })
6919
7034
  );
6920
7035
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
6921
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
7036
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
6922
7037
  const noopOnScroll = useCallback((_event) => {
6923
7038
  }, []);
6924
7039
  if (props.recycleItems === void 0) {
@@ -6994,9 +7109,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6994
7109
  ...rest
6995
7110
  } = props;
6996
7111
  const animatedPropsInternal = props.animatedPropsInternal;
7112
+ const anchoredEndSpaceOwner = (_a3 = props.anchoredEndSpaceOwnerInternal) != null ? _a3 : "list";
6997
7113
  const positionComponentInternal = props.positionComponentInternal;
6998
7114
  const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
6999
7115
  const {
7116
+ anchoredEndSpaceOwnerInternal: _anchoredEndSpaceOwnerInternal,
7000
7117
  positionComponentInternal: _positionComponentInternal,
7001
7118
  stickyPositionComponentInternal: _stickyPositionComponentInternal,
7002
7119
  ...restProps
@@ -7018,6 +7135,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7018
7135
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
7019
7136
  const stylePaddingLeftState = extractPadding(style, contentContainerStyle, "Left");
7020
7137
  const stylePaddingRightState = extractPadding(style, contentContainerStyle, "Right");
7138
+ const stylePaddingEndState = getStylePaddingEnd({
7139
+ horizontal,
7140
+ rtl,
7141
+ stylePaddingBottom: stylePaddingBottomState,
7142
+ stylePaddingLeft: stylePaddingLeftState,
7143
+ stylePaddingRight: stylePaddingRightState
7144
+ });
7021
7145
  const maintainScrollAtEndConfig = normalizeMaintainScrollAtEnd(maintainScrollAtEnd);
7022
7146
  const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
7023
7147
  maintainVisibleContentPositionProp
@@ -7030,13 +7154,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7030
7154
  const initialScrollProp = initialScrollAtEnd ? {
7031
7155
  index: Math.max(0, dataProp.length - 1),
7032
7156
  preserveForBottomPadding: true,
7033
- viewOffset: -stylePaddingBottomState,
7157
+ viewOffset: -stylePaddingEndState,
7034
7158
  viewPosition: 1
7035
7159
  } : hasInitialScrollIndex ? typeof initialScrollIndexProp === "object" ? {
7036
- index: (_a3 = initialScrollIndexProp.index) != null ? _a3 : 0,
7160
+ index: (_b = initialScrollIndexProp.index) != null ? _b : 0,
7037
7161
  preserveForBottomPadding: initialScrollIndexProp.viewOffset === void 0 && initialScrollIndexProp.viewPosition === 1 ? true : void 0,
7038
- viewOffset: (_b = initialScrollIndexProp.viewOffset) != null ? _b : initialScrollIndexProp.viewPosition === 1 ? -stylePaddingBottomState : 0,
7039
- viewPosition: (_c = initialScrollIndexProp.viewPosition) != null ? _c : 0
7162
+ viewOffset: (_c = initialScrollIndexProp.viewOffset) != null ? _c : initialScrollIndexProp.viewPosition === 1 ? -stylePaddingEndState : 0,
7163
+ viewPosition: (_d = initialScrollIndexProp.viewPosition) != null ? _d : 0
7040
7164
  } : {
7041
7165
  index: initialScrollIndexProp != null ? initialScrollIndexProp : 0,
7042
7166
  viewOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : 0
@@ -7049,7 +7173,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7049
7173
  const [, scheduleImperativeScrollCommit] = React2.useReducer((value) => value + 1, 0);
7050
7174
  const ctx = useStateContext();
7051
7175
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
7052
- 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;
7176
+ 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;
7053
7177
  const nextScrollAxisGap = typeof scrollAxisGap === "number" && Number.isFinite(scrollAxisGap) ? scrollAxisGap : 0;
7054
7178
  const refScroller = useRef(null);
7055
7179
  const combinedRef = useCombinedRef(refScroller, refScrollView);
@@ -7064,8 +7188,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7064
7188
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex,
7065
7189
  alwaysRender == null ? void 0 : alwaysRender.top,
7066
7190
  alwaysRender == null ? void 0 : alwaysRender.bottom,
7067
- (_j = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _j.join(","),
7068
- (_k = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _k.join(","),
7191
+ (_k = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _k.join(","),
7192
+ (_l = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _l.join(","),
7069
7193
  dataProp,
7070
7194
  dataKey,
7071
7195
  dataVersion,
@@ -7078,7 +7202,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7078
7202
  if (!refState.current) {
7079
7203
  if (!ctx.state) {
7080
7204
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { height: 0, width: 0 } : getWindowSize())[horizontal ? "width" : "height"];
7081
- ctx.values.set("adaptiveRender", (_l = experimental_adaptiveRender == null ? void 0 : experimental_adaptiveRender.initialMode) != null ? _l : "normal");
7205
+ ctx.values.set("adaptiveRender", (_m = experimental_adaptiveRender == null ? void 0 : experimental_adaptiveRender.initialMode) != null ? _m : "normal");
7082
7206
  ctx.state = {
7083
7207
  averageSizes: {},
7084
7208
  columnSpans: [],
@@ -7097,6 +7221,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7097
7221
  endNoBuffer: -1,
7098
7222
  endReachedSnapshot: void 0,
7099
7223
  firstFullyOnScreenIndex: -1,
7224
+ freshDataTransitionEpoch: 0,
7100
7225
  hasHadNonEmptyData: dataProp.length > 0,
7101
7226
  idCache: [],
7102
7227
  idsInView: [],
@@ -7121,8 +7246,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7121
7246
  positions: [],
7122
7247
  props: {},
7123
7248
  queuedCalculateItemsInView: 0,
7124
- queuedFullDrawDistancePrewarm: void 0,
7125
7249
  refScroller: { current: null },
7250
+ scheduledWork: new ScheduledWork(),
7126
7251
  scroll: 0,
7127
7252
  scrollAdjustHandler: new ScrollAdjustHandler(ctx),
7128
7253
  scrollForNextCalculateItemsInView: void 0,
@@ -7140,8 +7265,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7140
7265
  startReachedSnapshot: void 0,
7141
7266
  stickyContainerPool: /* @__PURE__ */ new Set(),
7142
7267
  stickyContainers: /* @__PURE__ */ new Map(),
7143
- timeoutAdaptiveRender: void 0,
7144
- timeouts: /* @__PURE__ */ new Set(),
7145
7268
  totalSize: 0,
7146
7269
  viewabilityConfigCallbackPairs: void 0
7147
7270
  };
@@ -7163,13 +7286,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7163
7286
  const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
7164
7287
  ctx.scrollAxisGap = nextScrollAxisGap;
7165
7288
  state.didColumnsChange = numColumnsProp !== previousNumColumnsProp || didScrollAxisGapChange;
7166
- const previousDataLength = (_n = (_m = state.props.data) == null ? void 0 : _m.length) != null ? _n : 0;
7289
+ const previousDataLength = (_o = (_n = state.props.data) == null ? void 0 : _n.length) != null ? _o : 0;
7167
7290
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
7168
7291
  const didDataKeyChangeLocal = state.props.dataKey !== dataKey;
7169
7292
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
7170
7293
  const didDataChangeLocal = didDataKeyChangeLocal || didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
7171
7294
  const shouldResetFreshDataLayout = !isFirstLocal && didDataChangeLocal && state.hasHadNonEmptyData && (didDataKeyChangeLocal || previousDataLength === 0) && dataProp.length > 0;
7172
- if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_o = state.initialScroll) == null ? void 0 : _o.viewPosition) === 1 && state.props.data.length > 0) {
7295
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_p = state.initialScroll) == null ? void 0 : _p.viewPosition) === 1 && state.props.data.length > 0) {
7173
7296
  clearPreservedInitialScrollTarget(state);
7174
7297
  }
7175
7298
  if (didDataChangeLocal) {
@@ -7178,10 +7301,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7178
7301
  state.didDataChange = true;
7179
7302
  state.previousData = state.props.data;
7180
7303
  }
7304
+ if (shouldResetFreshDataLayout) {
7305
+ state.freshDataTransitionEpoch += 1;
7306
+ }
7181
7307
  const throttledOnScroll = useThrottledOnScroll(onScrollProp != null ? onScrollProp : noopOnScroll, scrollEventThrottle != null ? scrollEventThrottle : 0);
7182
7308
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? throttledOnScroll : onScrollProp;
7183
- const anchoredEndSpaceResolved = Platform.OS === "web" && anchoredEndSpace ? { ...anchoredEndSpace, includeInEndInset: true } : anchoredEndSpace;
7184
- const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_p = state.props.anchoredEndSpace) == null ? void 0 : _p.anchorIndex) !== (anchoredEndSpaceResolved == null ? void 0 : anchoredEndSpaceResolved.anchorIndex);
7309
+ const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_q = state.props.anchoredEndSpace) == null ? void 0 : _q.anchorIndex) !== (anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex);
7185
7310
  state.props = {
7186
7311
  adaptiveRender: experimental_adaptiveRender,
7187
7312
  alignItemsAtEnd,
@@ -7189,7 +7314,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7189
7314
  alwaysRender,
7190
7315
  alwaysRenderIndicesArr: alwaysRenderIndices.arr,
7191
7316
  alwaysRenderIndicesSet: alwaysRenderIndices.set,
7192
- anchoredEndSpace: anchoredEndSpaceResolved,
7317
+ anchoredEndSpace,
7318
+ anchoredEndSpaceOwner,
7193
7319
  animatedProps: animatedPropsInternal,
7194
7320
  contentContainerAlignItems: contentContainerStyle.alignItems,
7195
7321
  contentInset,
@@ -7238,12 +7364,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7238
7364
  if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
7239
7365
  resetAdaptiveRender(ctx);
7240
7366
  }
7241
- if (shouldResetFreshDataLayout) {
7242
- resetInitialRenderState(ctx, {
7243
- resetInitialScroll: !!initialScrollProp,
7244
- resetLayout: true
7245
- });
7246
- }
7247
7367
  const memoizedLastItemKeys = useMemo(() => {
7248
7368
  if (!dataProp.length) return [];
7249
7369
  return Array.from(
@@ -7307,6 +7427,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7307
7427
  useDevChecks(props);
7308
7428
  }
7309
7429
  useLayoutEffect(() => {
7430
+ if (shouldResetFreshDataLayout) {
7431
+ resetInitialRenderState(ctx, {
7432
+ resetInitialScroll: !!initialScrollProp,
7433
+ resetLayout: true
7434
+ });
7435
+ }
7310
7436
  handleInitialScrollDataChange(ctx, {
7311
7437
  dataLength: dataProp.length,
7312
7438
  didDataChange: didDataChangeLocal,
@@ -7314,7 +7440,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7314
7440
  initialScrollAtEnd,
7315
7441
  latestInitialScroll: initialScrollProp,
7316
7442
  latestInitialScrollSessionKind: initialScrollUsesOffsetOnly ? "offset" : "bootstrap",
7317
- stylePaddingBottom: stylePaddingBottomState,
7443
+ stylePaddingEnd: stylePaddingEndState,
7318
7444
  useBootstrapInitialScroll: usesBootstrapInitialScroll
7319
7445
  });
7320
7446
  }, [
@@ -7323,7 +7449,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7323
7449
  didDataChangeLocal,
7324
7450
  shouldResetFreshDataLayout,
7325
7451
  initialScrollAtEnd,
7326
- stylePaddingBottomState,
7452
+ stylePaddingEndState,
7327
7453
  usesBootstrapInitialScroll
7328
7454
  ]);
7329
7455
  useLayoutEffect(() => {
@@ -7341,7 +7467,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7341
7467
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorMaxSize,
7342
7468
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorOffset,
7343
7469
  didAnchoredEndSpaceAnchorIndexChange,
7344
- numColumnsProp
7470
+ horizontal,
7471
+ numColumnsProp,
7472
+ rtl,
7473
+ stylePaddingBottomState,
7474
+ stylePaddingLeftState,
7475
+ stylePaddingRightState
7345
7476
  ]);
7346
7477
  useLayoutEffect(() => {
7347
7478
  const previousContentInsetEndAdjustment = previousContentInsetEndAdjustmentRef.current;
@@ -7357,10 +7488,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7357
7488
  dataLength: dataProp.length,
7358
7489
  footerSize: layout[horizontal ? "width" : "height"],
7359
7490
  initialScrollAtEnd,
7360
- stylePaddingBottom: stylePaddingBottomState
7491
+ stylePaddingEnd: stylePaddingEndState
7361
7492
  });
7362
7493
  },
7363
- [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingBottomState, usesBootstrapInitialScroll]
7494
+ [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingEndState, usesBootstrapInitialScroll]
7364
7495
  );
7365
7496
  const onLayoutChange = useCallback(
7366
7497
  (layout, fromLayoutEffect) => {
@@ -7377,7 +7508,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7377
7508
  }
7378
7509
  advanceCurrentInitialScrollSession(ctx);
7379
7510
  },
7380
- [dataProp.length, initialScrollAtEnd, stylePaddingBottomState, usesBootstrapInitialScroll]
7511
+ [dataProp.length, initialScrollAtEnd, stylePaddingEndState, usesBootstrapInitialScroll]
7381
7512
  );
7382
7513
  const { onLayout } = useOnLayoutSync({
7383
7514
  onLayoutChange,
@@ -7473,14 +7604,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7473
7604
  useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, scheduleImperativeScrollCommit), []);
7474
7605
  useEffect(() => {
7475
7606
  return () => {
7476
- if (state.queuedFullDrawDistancePrewarm !== void 0) {
7477
- cancelAnimationFrame(state.queuedFullDrawDistancePrewarm);
7478
- state.queuedFullDrawDistancePrewarm = void 0;
7479
- }
7480
- for (const timeout of state.timeouts) {
7481
- clearTimeout(timeout);
7482
- }
7483
- state.timeouts.clear();
7607
+ cancelImperativeScroll(state);
7608
+ state.scheduledWork.dispose();
7484
7609
  };
7485
7610
  }, [state]);
7486
7611
  useLayoutEffect(() => {
@@ -7522,6 +7647,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7522
7647
  canRender,
7523
7648
  contentContainerStyle,
7524
7649
  contentInset,
7650
+ freshDataTransitionEpoch: state.freshDataTransitionEpoch,
7525
7651
  getRenderedItem: fns.getRenderedItem,
7526
7652
  horizontal,
7527
7653
  initialContentOffset,
@@ -7537,7 +7663,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7537
7663
  onScroll: onScrollHandler,
7538
7664
  recycleItems,
7539
7665
  refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React2.cloneElement(refreshControlElement, {
7540
- progressViewOffset: ((_q = refreshControlElement.props.progressViewOffset) != null ? _q : 0) + stylePaddingTopState
7666
+ progressViewOffset: ((_r = refreshControlElement.props.progressViewOffset) != null ? _r : 0) + stylePaddingTopState
7541
7667
  }) : refreshControlElement : onRefresh && /* @__PURE__ */ React2.createElement(
7542
7668
  RefreshControl,
7543
7669
  {
@@ -7548,7 +7674,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7548
7674
  ),
7549
7675
  refScrollView: combinedRef,
7550
7676
  renderScrollComponent,
7551
- scrollAdjustHandler: (_r = refState.current) == null ? void 0 : _r.scrollAdjustHandler,
7677
+ scrollAdjustHandler: (_s = refState.current) == null ? void 0 : _s.scrollAdjustHandler,
7552
7678
  scrollEventThrottle: 0,
7553
7679
  snapToIndices,
7554
7680
  stickyHeaderIndices,