@legendapp/list 3.3.3 → 3.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/react-native.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
@@ -789,13 +804,7 @@ var DEFAULT_WEB_ADAPTIVE_RENDER_ENTER_VELOCITY = 6;
789
804
  var DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_VELOCITY = 3;
790
805
  var DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_DELAY = 250;
791
806
  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
- }
807
+ ctx.state.scheduledWork.cancel("adaptiveRender");
799
808
  }
800
809
  function scheduleAdaptiveRenderExit(ctx, exitDelay) {
801
810
  const state = ctx.state;
@@ -803,13 +812,7 @@ function scheduleAdaptiveRenderExit(ctx, exitDelay) {
803
812
  if (exitDelay <= 0) {
804
813
  setAdaptiveRender(ctx, "normal", "scroll");
805
814
  } 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);
815
+ state.scheduledWork.timeout(() => setAdaptiveRender(ctx, "normal", "scroll"), exitDelay, "adaptiveRender");
813
816
  }
814
817
  }
815
818
  function setAdaptiveRender(ctx, mode, reason) {
@@ -841,7 +844,7 @@ function updateAdaptiveRender(ctx, scrollVelocity, options) {
841
844
  const exitDelay = (_c = adaptiveRender.exitDelay) != null ? _c : isWeb ? DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_DELAY : DEFAULT_ADAPTIVE_RENDER_EXIT_DELAY;
842
845
  const threshold = currentMode === "light" ? exitVelocity : enterVelocity;
843
846
  const nextMode = (options == null ? void 0 : options.forceLight) || Math.abs(scrollVelocity) > threshold ? "light" : "normal";
844
- const previousMode = state.timeoutAdaptiveRender !== void 0 ? "normal" : currentMode;
847
+ const previousMode = state.scheduledWork.has("adaptiveRender") ? "normal" : currentMode;
845
848
  if (nextMode !== previousMode) {
846
849
  if (nextMode === "light") {
847
850
  setAdaptiveRender(ctx, "light", "scroll");
@@ -868,14 +871,13 @@ function getEffectiveDrawDistance(ctx, mode) {
868
871
  }
869
872
  function scheduleFullDrawDistancePrewarm(ctx) {
870
873
  const { state } = ctx;
871
- if (state.props.drawDistance <= INITIAL_DRAW_DISTANCE || state.queuedFullDrawDistancePrewarm !== void 0) {
874
+ if (state.props.drawDistance <= INITIAL_DRAW_DISTANCE || state.scheduledWork.has("fullDrawDistancePrewarm")) {
872
875
  return;
873
876
  }
874
- state.queuedFullDrawDistancePrewarm = requestAnimationFrame(() => {
877
+ state.scheduledWork.frame(() => {
875
878
  var _a3;
876
- state.queuedFullDrawDistancePrewarm = void 0;
877
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
878
- });
879
+ return (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
880
+ }, "fullDrawDistancePrewarm");
879
881
  }
880
882
 
881
883
  // src/utils/setInitialRenderState.ts
@@ -933,10 +935,7 @@ function syncInitialScrollOffset(state, offset) {
933
935
  state.scrollPrev = offset;
934
936
  }
935
937
  function clearPreservedInitialScrollTargetTimeout(state) {
936
- if (state.timeoutPreservedInitialScrollClear !== void 0) {
937
- clearTimeout(state.timeoutPreservedInitialScrollClear);
938
- state.timeoutPreservedInitialScrollClear = void 0;
939
- }
938
+ state.scheduledWork.cancel("preservedInitialScroll");
940
939
  }
941
940
  function clearPreservedInitialScrollTarget(state) {
942
941
  clearPreservedInitialScrollTargetTimeout(state);
@@ -965,14 +964,17 @@ function finishInitialScroll(ctx, options) {
965
964
  setInitialScrollSession(state);
966
965
  clearPreservedInitialScrollTargetTimeout(state);
967
966
  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);
967
+ state.scheduledWork.timeout(
968
+ () => {
969
+ var _a5;
970
+ if (!state.didFinishInitialScroll || ((_a5 = state.scrollingTo) == null ? void 0 : _a5.isInitialScroll) || !state.initialScroll) {
971
+ return;
972
+ }
973
+ clearPreservedInitialScrollTarget(state);
974
+ },
975
+ PRESERVED_INITIAL_SCROLL_FALLBACK_CLEAR_DELAY_MS,
976
+ "preservedInitialScroll"
977
+ );
976
978
  }
977
979
  } else {
978
980
  clearPreservedInitialScrollTarget(state);
@@ -999,9 +1001,11 @@ function calculateOffsetForIndex(ctx, index) {
999
1001
  return index !== void 0 ? state.positions[index] || 0 : 0;
1000
1002
  }
1001
1003
 
1002
- // src/core/getTopOffsetAdjustment.ts
1003
- function getTopOffsetAdjustment(ctx) {
1004
- return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
1004
+ // src/core/getStartOffsetAdjustment.ts
1005
+ function getStartOffsetAdjustment(ctx) {
1006
+ const { state } = ctx;
1007
+ const stylePaddingStart = state.props.horizontal ? (isHorizontalRTL(state) ? state.props.stylePaddingRight : state.props.stylePaddingLeft) || 0 : peek$(ctx, "stylePaddingTop") || 0;
1008
+ return stylePaddingStart + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
1005
1009
  }
1006
1010
 
1007
1011
  // src/utils/getId.ts
@@ -1214,9 +1218,9 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1214
1218
  offset -= viewOffset;
1215
1219
  }
1216
1220
  if (index !== void 0) {
1217
- const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
1218
- if (topOffsetAdjustment) {
1219
- offset += topOffsetAdjustment;
1221
+ const startOffsetAdjustment = getStartOffsetAdjustment(ctx);
1222
+ if (startOffsetAdjustment) {
1223
+ offset += startOffsetAdjustment;
1220
1224
  }
1221
1225
  }
1222
1226
  if (viewPosition !== void 0 && index !== void 0) {
@@ -1226,7 +1230,8 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1226
1230
  }
1227
1231
  const isOutOfBounds = index < 0 || index >= dataLength;
1228
1232
  const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
1229
- const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1233
+ const measuredItemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1234
+ const itemSize = Math.max(0, measuredItemSize - (isOutOfBounds ? 0 : ctx.scrollAxisGap));
1230
1235
  const trailingInset = getContentInsetEnd(ctx);
1231
1236
  offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1232
1237
  if (!isOutOfBounds && index === state.props.data.length - 1) {
@@ -1253,11 +1258,35 @@ function clampScrollOffset(ctx, offset, scrollTarget) {
1253
1258
  return clampedOffset;
1254
1259
  }
1255
1260
 
1261
+ // src/core/cancelImperativeScroll.ts
1262
+ function cancelScrollCompletionChecks({ scheduledWork }) {
1263
+ scheduledWork.cancel("checkFinishedScrollFrame");
1264
+ scheduledWork.cancel("checkFinishedScrollRetryFrame");
1265
+ scheduledWork.cancel("checkFinishedScrollFallback");
1266
+ scheduledWork.cancel("platformScrollCompletion");
1267
+ }
1268
+ function settlePendingImperativeScroll(state) {
1269
+ var _a3, _b;
1270
+ const resolvePendingScroll = (_b = state.pendingScrollResolve) != null ? _b : (_a3 = state.pendingScrollToEnd) == null ? void 0 : _a3.resolve;
1271
+ state.pendingScrollResolve = void 0;
1272
+ state.pendingScrollToEnd = void 0;
1273
+ resolvePendingScroll == null ? void 0 : resolvePendingScroll();
1274
+ }
1275
+ function cancelImperativeScroll(state) {
1276
+ cancelScrollCompletionChecks(state);
1277
+ state.scheduledWork.cancel("imperativeScrollReady");
1278
+ state.runPendingScrollToEnd = void 0;
1279
+ state.scrollingTo = void 0;
1280
+ state.scrollTargetPinnedRange = void 0;
1281
+ settlePendingImperativeScroll(state);
1282
+ }
1283
+
1256
1284
  // src/core/finishScrollTo.ts
1257
1285
  function finishScrollTo(ctx) {
1258
1286
  var _a3, _b;
1259
1287
  const state = ctx.state;
1260
1288
  if (state == null ? void 0 : state.scrollingTo) {
1289
+ cancelScrollCompletionChecks(state);
1261
1290
  const resolvePendingScroll = state.pendingScrollResolve;
1262
1291
  state.pendingScrollResolve = void 0;
1263
1292
  const scrollingTo = state.scrollingTo;
@@ -1306,7 +1335,7 @@ function checkFinishedScroll(ctx, options) {
1306
1335
  return;
1307
1336
  }
1308
1337
  }
1309
- ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
1338
+ ctx.state.scheduledWork.frame(() => checkFinishedScrollFrame(ctx), "checkFinishedScrollFrame");
1310
1339
  }
1311
1340
  function hasScrollCompletionOwnership(state, options) {
1312
1341
  const { clampedTargetOffset, scrollingTo } = options;
@@ -1376,7 +1405,6 @@ function checkFinishedScrollFrame(ctx) {
1376
1405
  return;
1377
1406
  }
1378
1407
  const { state } = ctx;
1379
- state.animFrameCheckFinishedScroll = void 0;
1380
1408
  const completionState = getResolvedScrollCompletionState(ctx, scrollingTo);
1381
1409
  if (completionState.isAtResolvedTarget && hasScrollCompletionOwnership(state, {
1382
1410
  clampedTargetOffset: completionState.clampedTargetOffset,
@@ -1395,61 +1423,62 @@ function scrollToFallbackOffset(ctx, offset) {
1395
1423
  }
1396
1424
  function checkFinishedScrollFallback(ctx) {
1397
1425
  const state = ctx.state;
1426
+ if (state.scheduledWork.has("checkFinishedScrollFallback")) {
1427
+ return;
1428
+ }
1398
1429
  const scrollingTo = state.scrollingTo;
1399
1430
  const shouldFinishInitialZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
1400
1431
  const silentInitialDispatch = isSilentInitialDispatch(state, scrollingTo);
1401
1432
  const canFinishInitialWithoutNativeProgress = scrollingTo !== void 0 ? shouldFinishInitialScrollWithoutNativeProgress(state, scrollingTo) : false;
1402
1433
  const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) && !shouldFinishInitialZeroTarget && !canFinishInitialWithoutNativeProgress || !state.didContainersLayout;
1403
1434
  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
1435
+ let numChecks = 0;
1436
+ const scheduleFallbackCheck = (delay) => {
1437
+ state.scheduledWork.timeout(checkHasScrolled, delay, "checkFinishedScrollFallback");
1438
+ };
1439
+ const checkHasScrolled = () => {
1440
+ var _a3, _b, _c, _d;
1441
+ const isStillScrollingTo = state.scrollingTo;
1442
+ if (isStillScrollingTo) {
1443
+ numChecks++;
1444
+ const isNativeInitialPending = isNativeInitialNonZeroTarget(state) && !state.hasScrolled;
1445
+ const maxChecks = silentInitialDispatch ? 5 : isNativeInitialPending ? INITIAL_SCROLL_MAX_FALLBACK_CHECKS : 5;
1446
+ const shouldFinishZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
1447
+ const canFinishInitialScrollWithoutNativeProgress = shouldFinishInitialScrollWithoutNativeProgress(
1448
+ state,
1449
+ isStillScrollingTo
1450
+ );
1451
+ const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
1452
+ const canFinishAfterSilentNativeDispatch = Platform.OS === "android" && silentInitialDispatch && completionState.isAtResolvedTarget && numChecks >= 1;
1453
+ const shouldRetrySilentInitialNativeScroll = Platform.OS === "android" && canFinishAfterSilentNativeDispatch && !initialScrollCompletion.didRetrySilentInitialScroll(state);
1454
+ const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
1455
+ const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
1456
+ const shouldRetryUnalignedEndScroll = Platform.OS === "ios" && !isStillScrollingTo.isInitialScroll && isEndAlignedLastItemTarget(ctx, isStillScrollingTo) && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
1457
+ if (shouldRetrySilentInitialNativeScroll) {
1458
+ const targetOffset = (_b = (_a3 = getInitialScrollWatchdogTargetOffset(state)) != null ? _a3 : isStillScrollingTo.targetOffset) != null ? _b : 0;
1459
+ const jiggleOffset = targetOffset >= SILENT_INITIAL_SCROLL_TARGET_EPSILON ? targetOffset - SILENT_INITIAL_SCROLL_TARGET_EPSILON : targetOffset + SILENT_INITIAL_SCROLL_TARGET_EPSILON;
1460
+ initialScrollCompletion.markSilentInitialScrollRetry(state);
1461
+ scrollToFallbackOffset(ctx, jiggleOffset);
1462
+ state.scheduledWork.frame(
1463
+ () => scrollToFallbackOffset(ctx, targetOffset),
1464
+ "checkFinishedScrollRetryFrame"
1421
1465
  );
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
- }
1466
+ scheduleFallbackCheck(SILENT_INITIAL_SCROLL_RETRY_DELAY_MS);
1467
+ } else if (shouldRetryUnalignedEndScroll) {
1468
+ scrollToFallbackOffset(ctx, completionState.clampedTargetOffset);
1469
+ scheduleFallbackCheck(100);
1470
+ } else if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
1471
+ finishScrollTo(ctx);
1472
+ } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
1473
+ const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
1474
+ scrollToFallbackOffset(ctx, targetOffset);
1475
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
1476
+ } else {
1477
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
1449
1478
  }
1450
- };
1451
- checkHasScrolled();
1452
- }, initialDelay);
1479
+ }
1480
+ };
1481
+ scheduleFallbackCheck(initialDelay);
1453
1482
  }
1454
1483
 
1455
1484
  // src/core/doScrollTo.native.ts
@@ -1473,6 +1502,9 @@ function doScrollTo(ctx, params) {
1473
1502
  if (isInitialScroll) {
1474
1503
  initialScrollCompletion.markInitialScrollNativeDispatch(state);
1475
1504
  }
1505
+ if (isAnimated && Math.abs(state.scroll - offset) <= 1) {
1506
+ checkFinishedScroll(ctx);
1507
+ }
1476
1508
  if (!isAnimated) {
1477
1509
  state.scroll = offset;
1478
1510
  checkFinishedScrollFallback(ctx);
@@ -1503,9 +1535,12 @@ function doMaintainScrollAtEnd(ctx) {
1503
1535
  if (!state.maintainingScrollAtEnd) {
1504
1536
  const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
1505
1537
  const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
1538
+ const scrollAtRequest = state.scroll;
1506
1539
  state.maintainingScrollAtEnd = pendingState;
1507
1540
  requestAnimationFrame(() => {
1508
- if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
1541
+ const isStillWithinThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
1542
+ const didScrollSinceRequest = state.scroll !== scrollAtRequest;
1543
+ if (isStillWithinThreshold || !didScrollSinceRequest) {
1509
1544
  state.maintainingScrollAtEnd = activeState;
1510
1545
  const scroller = refScroller.current;
1511
1546
  if (state.props.horizontal && isHorizontalRTL(state)) {
@@ -1535,6 +1570,7 @@ function doMaintainScrollAtEnd(ctx) {
1535
1570
  );
1536
1571
  } else if (state.maintainingScrollAtEnd === pendingState) {
1537
1572
  state.maintainingScrollAtEnd = void 0;
1573
+ state.pendingMaintainScrollAtEnd = false;
1538
1574
  }
1539
1575
  });
1540
1576
  } else {
@@ -1576,20 +1612,21 @@ function requestAdjust(ctx, positionDiff, dataChanged) {
1576
1612
  } else {
1577
1613
  state.ignoreScrollFromMVCP.gt = threshold;
1578
1614
  }
1579
- if (state.ignoreScrollFromMVCPTimeout) {
1580
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
1581
- }
1582
1615
  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);
1616
+ state.scheduledWork.timeout(
1617
+ () => {
1618
+ var _a3;
1619
+ state.ignoreScrollFromMVCP = void 0;
1620
+ const shouldForceUpdate = state.ignoreScrollFromMVCPIgnored && state.scrollProcessingEnabled !== false;
1621
+ if (shouldForceUpdate) {
1622
+ state.ignoreScrollFromMVCPIgnored = false;
1623
+ state.scrollPending = state.scroll;
1624
+ (_a3 = state.reprocessCurrentScroll) == null ? void 0 : _a3.call(state);
1625
+ }
1626
+ },
1627
+ delay,
1628
+ "ignoreScrollFromMVCP"
1629
+ );
1593
1630
  }
1594
1631
  } else {
1595
1632
  state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
@@ -2017,10 +2054,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
2017
2054
  state.mvcpAnchorLock = void 0;
2018
2055
  state.pendingNativeMVCPAdjust = void 0;
2019
2056
  state.userScrollAnchorReset = { keys: /* @__PURE__ */ new Set() };
2020
- if (state.queuedMVCPRecalculate !== void 0) {
2021
- cancelAnimationFrame(state.queuedMVCPRecalculate);
2022
- state.queuedMVCPRecalculate = void 0;
2023
- }
2057
+ state.scheduledWork.cancel("mvcpRecalculate");
2024
2058
  flushSync(runCalculateItems);
2025
2059
  scheduleFullDrawDistancePrewarm(ctx);
2026
2060
  } else {
@@ -2165,12 +2199,7 @@ function scrollTo(ctx, params) {
2165
2199
  const {
2166
2200
  props: { horizontal }
2167
2201
  } = state;
2168
- if (state.animFrameCheckFinishedScroll) {
2169
- cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
2170
- }
2171
- if (state.timeoutCheckFinishedScrollFallback) {
2172
- clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
2173
- }
2202
+ cancelScrollCompletionChecks(state);
2174
2203
  const requestedOffset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
2175
2204
  const shouldPreserveRawInitialOffsetRequest = !!isInitialScroll && ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset";
2176
2205
  const targetOffset = clampScrollOffset(ctx, requestedOffset, scrollTarget);
@@ -2275,10 +2304,7 @@ function setInitialScrollTarget(ctx, target, options) {
2275
2304
  var _a3;
2276
2305
  const { state } = ctx;
2277
2306
  state.clearPreservedInitialScrollOnNextFinish = void 0;
2278
- if (state.timeoutPreservedInitialScrollClear !== void 0) {
2279
- clearTimeout(state.timeoutPreservedInitialScrollClear);
2280
- state.timeoutPreservedInitialScrollClear = void 0;
2281
- }
2307
+ state.scheduledWork.cancel("preservedInitialScroll");
2282
2308
  state.initialScroll = target;
2283
2309
  if (options == null ? void 0 : options.resetDidFinish) {
2284
2310
  resetInitialRenderState(ctx, { resetInitialScroll: true });
@@ -2571,13 +2597,13 @@ function rearmBootstrapInitialScroll(ctx, options) {
2571
2597
  queueBootstrapInitialScrollReevaluation(ctx.state);
2572
2598
  }
2573
2599
  function createInitialScrollAtEndTarget(options) {
2574
- const { dataLength, footerSize, preserveForFooterLayout, stylePaddingBottom } = options;
2600
+ const { dataLength, footerSize, preserveForFooterLayout, stylePaddingEnd } = options;
2575
2601
  return {
2576
2602
  contentOffset: void 0,
2577
2603
  index: Math.max(0, dataLength - 1),
2578
2604
  preserveForBottomPadding: true,
2579
2605
  preserveForFooterLayout,
2580
- viewOffset: -stylePaddingBottom - footerSize,
2606
+ viewOffset: -stylePaddingEnd - footerSize,
2581
2607
  viewPosition: 1
2582
2608
  };
2583
2609
  }
@@ -2591,7 +2617,7 @@ function isRetargetableBottomAlignedInitialScrollTarget(target) {
2591
2617
  return !!(target && target.viewPosition === 1 && (shouldPreserveInitialScrollForBottomPadding(target) || shouldPreserveInitialScrollForFooterLayout(target)));
2592
2618
  }
2593
2619
  function createRetargetedBottomAlignedInitialScroll(options) {
2594
- const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom, target } = options;
2620
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd, target } = options;
2595
2621
  const preserveForFooterLayout = shouldPreserveInitialScrollForFooterLayout(target);
2596
2622
  return {
2597
2623
  ...target,
@@ -2599,7 +2625,7 @@ function createRetargetedBottomAlignedInitialScroll(options) {
2599
2625
  index: initialScrollAtEnd ? Math.max(0, dataLength - 1) : target.index,
2600
2626
  preserveForBottomPadding: true,
2601
2627
  preserveForFooterLayout,
2602
- viewOffset: -stylePaddingBottom - (preserveForFooterLayout ? footerSize : 0),
2628
+ viewOffset: -stylePaddingEnd - (preserveForFooterLayout ? footerSize : 0),
2603
2629
  viewPosition: 1
2604
2630
  };
2605
2631
  }
@@ -2607,7 +2633,7 @@ function areEquivalentBootstrapInitialScrollTargets(current, next) {
2607
2633
  return current.index === next.index && current.preserveForBottomPadding === next.preserveForBottomPadding && current.preserveForFooterLayout === next.preserveForFooterLayout && current.viewOffset === next.viewOffset && current.viewPosition === next.viewPosition;
2608
2634
  }
2609
2635
  function clearPendingInitialScrollFooterLayout(ctx, options) {
2610
- const { dataLength, stylePaddingBottom, target } = options;
2636
+ const { dataLength, stylePaddingEnd, target } = options;
2611
2637
  if (!shouldPreserveInitialScrollForFooterLayout(target)) {
2612
2638
  return;
2613
2639
  }
@@ -2615,7 +2641,7 @@ function clearPendingInitialScrollFooterLayout(ctx, options) {
2615
2641
  dataLength,
2616
2642
  footerSize: 0,
2617
2643
  preserveForFooterLayout: void 0,
2618
- stylePaddingBottom
2644
+ stylePaddingEnd
2619
2645
  });
2620
2646
  setInitialScrollTarget(ctx, clearedFooterTarget);
2621
2647
  }
@@ -2676,7 +2702,7 @@ function schedulePreservedEndAnchorCorrectionFrame(ctx, correction) {
2676
2702
  });
2677
2703
  }
2678
2704
  function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2679
- var _a3, _b;
2705
+ var _a3;
2680
2706
  const state = ctx.state;
2681
2707
  const initialScroll = state.initialScroll;
2682
2708
  if (!state.didFinishInitialScroll || ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) || (initialScroll == null ? void 0 : initialScroll.viewPosition) !== 1 || state.preservedEndAnchorCorrection) {
@@ -2688,7 +2714,7 @@ function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2688
2714
  if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
2689
2715
  clearPendingInitialScrollFooterLayout(ctx, {
2690
2716
  dataLength: state.props.data.length,
2691
- stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
2717
+ stylePaddingEnd: getStylePaddingEnd(state.props),
2692
2718
  target: initialScroll
2693
2719
  });
2694
2720
  } else {
@@ -2725,7 +2751,7 @@ function startBootstrapInitialScrollOnMount(ctx, options) {
2725
2751
  }
2726
2752
  }
2727
2753
  function handleBootstrapInitialScrollDataChange(ctx, options) {
2728
- const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingBottom } = options;
2754
+ const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingEnd } = options;
2729
2755
  const state = ctx.state;
2730
2756
  const initialScroll = state.initialScroll;
2731
2757
  if (isOffsetInitialScrollSession(state) || !initialScroll) {
@@ -2747,18 +2773,18 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2747
2773
  dataLength,
2748
2774
  footerSize: peek$(ctx, "footerSize") || 0,
2749
2775
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2750
- stylePaddingBottom
2776
+ stylePaddingEnd
2751
2777
  }) : createRetargetedBottomAlignedInitialScroll({
2752
2778
  dataLength,
2753
2779
  footerSize: peek$(ctx, "footerSize") || 0,
2754
2780
  initialScrollAtEnd,
2755
- stylePaddingBottom,
2781
+ stylePaddingEnd,
2756
2782
  target: initialScroll
2757
2783
  });
2758
2784
  if (!shouldResetDidFinish && didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2759
2785
  clearPendingInitialScrollFooterLayout(ctx, {
2760
2786
  dataLength,
2761
- stylePaddingBottom,
2787
+ stylePaddingEnd,
2762
2788
  target: initialScroll
2763
2789
  });
2764
2790
  return;
@@ -2790,7 +2816,7 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2790
2816
  }
2791
2817
  }
2792
2818
  function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2793
- const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom } = options;
2819
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd } = options;
2794
2820
  const state = ctx.state;
2795
2821
  if (!initialScrollAtEnd) {
2796
2822
  return;
@@ -2806,7 +2832,7 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2806
2832
  if (didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2807
2833
  clearPendingInitialScrollFooterLayout(ctx, {
2808
2834
  dataLength,
2809
- stylePaddingBottom,
2835
+ stylePaddingEnd,
2810
2836
  target: initialScroll
2811
2837
  });
2812
2838
  } else {
@@ -2814,13 +2840,13 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2814
2840
  dataLength,
2815
2841
  footerSize,
2816
2842
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2817
- stylePaddingBottom
2843
+ stylePaddingEnd
2818
2844
  });
2819
2845
  const didTargetChange = initialScroll.index !== updatedInitialScroll.index || initialScroll.viewPosition !== updatedInitialScroll.viewPosition || initialScroll.viewOffset !== updatedInitialScroll.viewOffset;
2820
2846
  if (!didTargetChange) {
2821
2847
  clearPendingInitialScrollFooterLayout(ctx, {
2822
2848
  dataLength,
2823
- stylePaddingBottom,
2849
+ stylePaddingEnd,
2824
2850
  target: initialScroll
2825
2851
  });
2826
2852
  } else {
@@ -3047,7 +3073,7 @@ function handleInitialScrollDataChange(ctx, options) {
3047
3073
  initialScrollAtEnd,
3048
3074
  latestInitialScroll,
3049
3075
  latestInitialScrollSessionKind,
3050
- stylePaddingBottom,
3076
+ stylePaddingEnd,
3051
3077
  useBootstrapInitialScroll
3052
3078
  } = options;
3053
3079
  const state = ctx.state;
@@ -3077,7 +3103,7 @@ function handleInitialScrollDataChange(ctx, options) {
3077
3103
  didDataChange,
3078
3104
  initialScrollAtEnd,
3079
3105
  previousDataLength: previousInitialScrollDataLength,
3080
- stylePaddingBottom
3106
+ stylePaddingEnd
3081
3107
  });
3082
3108
  return;
3083
3109
  }
@@ -3547,7 +3573,6 @@ function setupViewability(props) {
3547
3573
  }
3548
3574
  function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end, startBuffered = start, endBuffered = end) {
3549
3575
  const {
3550
- timeouts,
3551
3576
  props: { data }
3552
3577
  } = state;
3553
3578
  for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
@@ -3557,11 +3582,10 @@ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollS
3557
3582
  viewabilityState.startBuffered = startBuffered;
3558
3583
  viewabilityState.endBuffered = endBuffered;
3559
3584
  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);
3585
+ state.scheduledWork.timeout(
3586
+ () => updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize),
3587
+ viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime
3588
+ );
3565
3589
  } else {
3566
3590
  updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
3567
3591
  }
@@ -3920,20 +3944,15 @@ function getProjectedBufferAdjustment(scrollVelocity, trailingBuffer) {
3920
3944
  }
3921
3945
  function scheduleRenderRangeProjectionSettle(ctx) {
3922
3946
  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);
3947
+ state.scheduledWork.timeout(
3948
+ () => {
3949
+ var _a3;
3950
+ state.scrollHistory.length = 0;
3951
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
3952
+ },
3953
+ RENDER_RANGE_PROJECTION_SETTLE_DELAY,
3954
+ "renderRangeProjection"
3955
+ );
3937
3956
  }
3938
3957
  function findCurrentStickyIndex(stickyArray, scroll, state) {
3939
3958
  const positions = state.positions;
@@ -4601,8 +4620,6 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4601
4620
  if (anchorIndex >= 0 && anchorIndex < data.length && state.scrollLength > 0) {
4602
4621
  nextAnchorKey = getId(state, anchorIndex);
4603
4622
  let contentBelowAnchor = 0;
4604
- const footerSize = ctx.values.get("footerSize") || 0;
4605
- const stylePaddingBottom = state.props.stylePaddingBottom || 0;
4606
4623
  let hasUnknownTailSize = false;
4607
4624
  for (let index = anchorIndex; index < data.length; index++) {
4608
4625
  const size = getKnownOrFixedItemSize(ctx, index);
@@ -4614,14 +4631,16 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4614
4631
  contentBelowAnchor += effectiveSize;
4615
4632
  }
4616
4633
  }
4617
- contentBelowAnchor += footerSize + stylePaddingBottom;
4634
+ contentBelowAnchor = Math.max(0, contentBelowAnchor - ctx.scrollAxisGap);
4635
+ contentBelowAnchor += (ctx.values.get("footerSize") || 0) + getStylePaddingEnd(state.props);
4618
4636
  isReady = !hasUnknownTailSize;
4619
4637
  nextSize = hasUnknownTailSize ? previousSize || 0 : Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
4620
4638
  } else if (anchorIndex >= 0) {
4621
4639
  isReady = false;
4622
4640
  }
4623
4641
  }
4624
- const didSizeChange = previousSize !== nextSize;
4642
+ const didSizeChange = previousSize !== nextSize && (previousSize !== void 0 || anchoredEndSpace !== void 0);
4643
+ const didEffectiveSizeChange = (previousSize || 0) !== nextSize;
4625
4644
  const didReadyAnchorChange = previousReadyAnchorIndex !== nextAnchorIndex || previousReadyAnchorKey !== nextAnchorKey;
4626
4645
  if (isReady && (didSizeChange || didReadyAnchorChange)) {
4627
4646
  state.anchoredEndSpaceReadyAnchorIndex = nextAnchorIndex;
@@ -4630,8 +4649,9 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4630
4649
  set$(ctx, "anchoredEndSpaceSize", nextSize);
4631
4650
  (_a3 = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onSizeChanged) == null ? void 0 : _a3.call(anchoredEndSpace, nextSize);
4632
4651
  }
4633
- if (didSizeChange && (anchoredEndSpace == null ? void 0 : anchoredEndSpace.includeInEndInset)) {
4634
- updateScroll(ctx, state.scroll, true);
4652
+ if (didEffectiveSizeChange) {
4653
+ updateContentMetricsState(ctx);
4654
+ updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
4635
4655
  }
4636
4656
  (_b = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onReady) == null ? void 0 : _b.call(anchoredEndSpace, { anchorIndex: nextAnchorIndex, anchorKey: nextAnchorKey, size: nextSize });
4637
4657
  }
@@ -4660,16 +4680,10 @@ function runOrScheduleMVCPRecalculate(ctx) {
4660
4680
  }
4661
4681
  } else if (Platform.OS === "web") {
4662
4682
  if (!state.mvcpAnchorLock) {
4663
- if (state.queuedMVCPRecalculate !== void 0) {
4664
- cancelAnimationFrame(state.queuedMVCPRecalculate);
4665
- state.queuedMVCPRecalculate = void 0;
4666
- }
4683
+ state.scheduledWork.cancel("mvcpRecalculate");
4667
4684
  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
- });
4685
+ } else if (!state.scheduledWork.has("mvcpRecalculate")) {
4686
+ state.scheduledWork.frame(() => calculateItemsInView(ctx, { doMVCP: true }), "mvcpRecalculate");
4673
4687
  }
4674
4688
  } else {
4675
4689
  calculateItemsInView(ctx, { doMVCP: true });
@@ -4716,6 +4730,9 @@ function flushItemSizeUpdates(ctx, result) {
4716
4730
  } else if (result.didMeasureUserScrollAnchorResetItem && ((_a3 = state.userScrollAnchorReset) == null ? void 0 : _a3.keys.size) === 0) {
4717
4731
  state.userScrollAnchorReset = void 0;
4718
4732
  }
4733
+ if (result.didChange) {
4734
+ maybeUpdateAnchoredEndSpace(ctx);
4735
+ }
4719
4736
  if (result.didChange && result.shouldMaintainScrollAtEnd) {
4720
4737
  doMaintainScrollAtEnd(ctx);
4721
4738
  }
@@ -4805,7 +4822,6 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
4805
4822
  previous: size - diff,
4806
4823
  size
4807
4824
  });
4808
- maybeUpdateAnchoredEndSpace(ctx);
4809
4825
  }
4810
4826
  if (minIndexSizeChanged !== void 0) {
4811
4827
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
@@ -5645,19 +5661,34 @@ function ContainerSlotBase({
5645
5661
  var ContainerSlot = typedMemo(function ContainerSlot2(props) {
5646
5662
  return /* @__PURE__ */ React2.createElement(ContainerSlotBase, { ...props });
5647
5663
  });
5664
+ function useFreshDataTransitionVisibility(readyToRender, transitionEpoch) {
5665
+ const completedTransitionEpoch = useRef(transitionEpoch);
5666
+ const isTransitionPending = completedTransitionEpoch.current !== transitionEpoch;
5667
+ useLayoutEffect(() => {
5668
+ if (!readyToRender) {
5669
+ completedTransitionEpoch.current = transitionEpoch;
5670
+ }
5671
+ }, [readyToRender, transitionEpoch]);
5672
+ return readyToRender && !isTransitionPending;
5673
+ }
5648
5674
 
5649
5675
  // src/components/Containers.native.tsx
5650
- var ContainersLayer = typedMemo(function ContainersLayer2({ children, horizontal }) {
5676
+ var ContainersLayer = typedMemo(function ContainersLayer2({
5677
+ children,
5678
+ freshDataTransitionEpoch,
5679
+ horizontal
5680
+ }) {
5651
5681
  const ctx = useStateContext();
5652
5682
  const columnWrapperStyle = ctx.columnWrapperStyle;
5653
5683
  const animSize = useValue$("totalSize");
5654
5684
  const [readyToRender, numColumns, otherAxisSize = 0] = useArr$(["readyToRender", "numColumns", "otherAxisSize"]);
5685
+ const isVisible = useFreshDataTransitionVisibility(!!readyToRender, freshDataTransitionEpoch);
5655
5686
  const style = horizontal ? {
5656
5687
  height: otherAxisSize || "100%",
5657
5688
  minHeight: otherAxisSize,
5658
- opacity: readyToRender ? 1 : 0,
5689
+ opacity: isVisible ? 1 : 0,
5659
5690
  width: animSize
5660
- } : { height: animSize, minWidth: otherAxisSize, opacity: readyToRender ? 1 : 0 };
5691
+ } : { height: animSize, minWidth: otherAxisSize, opacity: isVisible ? 1 : 0 };
5661
5692
  if (columnWrapperStyle) {
5662
5693
  const { columnGap, rowGap, gap } = columnWrapperStyle;
5663
5694
  const gapX = columnGap || gap || 0;
@@ -5678,9 +5709,10 @@ var ContainersLayer = typedMemo(function ContainersLayer2({ children, horizontal
5678
5709
  }
5679
5710
  }
5680
5711
  }
5681
- return /* @__PURE__ */ React2.createElement(Animated.View, { style }, /* @__PURE__ */ React2.createElement(ContainerLayoutCoordinator, null, children));
5712
+ return /* @__PURE__ */ React2.createElement(Animated.View, { pointerEvents: isVisible ? void 0 : "none", style }, /* @__PURE__ */ React2.createElement(ContainerLayoutCoordinator, null, children));
5682
5713
  });
5683
5714
  var Containers = typedMemo(function Containers2({
5715
+ freshDataTransitionEpoch,
5684
5716
  horizontal,
5685
5717
  recycleItems,
5686
5718
  ItemSeparatorComponent,
@@ -5705,7 +5737,7 @@ var Containers = typedMemo(function Containers2({
5705
5737
  )
5706
5738
  );
5707
5739
  }
5708
- return /* @__PURE__ */ React2.createElement(ContainersLayer, { horizontal }, containers);
5740
+ return /* @__PURE__ */ React2.createElement(ContainersLayer, { freshDataTransitionEpoch, horizontal }, containers);
5709
5741
  });
5710
5742
  var ListComponentScrollView = Animated.ScrollView;
5711
5743
 
@@ -5744,16 +5776,6 @@ var SnapWrapper = React2.forwardRef(function SnapWrapperInner({ ScrollComponent,
5744
5776
  const [snapToOffsets] = useArr$(["snapToOffsets"]);
5745
5777
  return /* @__PURE__ */ React2.createElement(ScrollComponent, { ...props, ref, snapToOffsets });
5746
5778
  });
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
5779
 
5758
5780
  // src/core/updateContentMetrics.ts
5759
5781
  var SCROLL_ADJUST_EPSILON = 0.1;
@@ -5787,7 +5809,11 @@ function setHeaderSize(ctx, size) {
5787
5809
  state.didMeasureHeader = true;
5788
5810
  }
5789
5811
  function setFooterSize(ctx, size) {
5790
- return setContentLengthSignal(ctx, "footerSize", size);
5812
+ const didChange = setContentLengthSignal(ctx, "footerSize", size);
5813
+ if (didChange) {
5814
+ maybeUpdateAnchoredEndSpace(ctx);
5815
+ }
5816
+ return didChange;
5791
5817
  }
5792
5818
  function areInsetsEqual(left, right) {
5793
5819
  var _a3, _b, _c, _d, _e, _f, _g, _h;
@@ -5830,6 +5856,7 @@ var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
5830
5856
  const { onLayout } = useOnLayoutSync({ onLayoutChange, ref });
5831
5857
  return /* @__PURE__ */ React2.createElement(View$1, { ...rest, onLayout, ref });
5832
5858
  };
5859
+ var StyleSheet = StyleSheet$1;
5833
5860
 
5834
5861
  // src/components/ListComponent.tsx
5835
5862
  var AlignItemsAtEndSpacer = typedMemo(function AlignItemsAtEndSpacer2({ horizontal }) {
@@ -5847,6 +5874,7 @@ var AlignItemsAtEndSpacer = typedMemo(function AlignItemsAtEndSpacer2({ horizont
5847
5874
  });
5848
5875
  var ListComponent = typedMemo(function ListComponent2({
5849
5876
  canRender,
5877
+ freshDataTransitionEpoch,
5850
5878
  style,
5851
5879
  contentContainerStyle,
5852
5880
  horizontal,
@@ -5876,8 +5904,17 @@ var ListComponent = typedMemo(function ListComponent2({
5876
5904
  }) {
5877
5905
  const ctx = useStateContext();
5878
5906
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
5879
- const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
5907
+ const [anchoredEndSpaceSize = 0, otherAxisSize = 0] = useArr$(["anchoredEndSpaceSize", "otherAxisSize"]);
5880
5908
  const shouldRenderAlignItemsAtEndSpacer = ctx.state.props.alignItemsAtEndPaddingEnabled;
5909
+ const shouldMaterializeAnchoredEndSpace = !!ctx.state.props.anchoredEndSpace && ctx.state.props.anchoredEndSpaceOwner === "list" && anchoredEndSpaceSize > 0;
5910
+ let anchoredEndSpaceStyle;
5911
+ if (shouldMaterializeAnchoredEndSpace) {
5912
+ const paddingEnd = horizontal ? isHorizontalRTL(ctx.state) ? "Left" : "Right" : "Bottom";
5913
+ const flattenedContentContainerStyle = StyleSheet.flatten(contentContainerStyle);
5914
+ anchoredEndSpaceStyle = {
5915
+ [`padding${paddingEnd}`]: extractPadding({}, flattenedContentContainerStyle || {}, paddingEnd) + anchoredEndSpaceSize
5916
+ };
5917
+ }
5881
5918
  const autoOtherAxisStyle = getAutoOtherAxisStyle({
5882
5919
  horizontal,
5883
5920
  needsOtherAxisSize: ctx.state.needsOtherAxisSize,
@@ -5930,10 +5967,10 @@ var ListComponent = typedMemo(function ListComponent2({
5930
5967
  ...rest,
5931
5968
  ...Platform.OS === "web" ? ScrollComponent === ListComponentScrollView ? { onInternalScrollEnd, useWindowScroll } : {} : { onScrollBeginDrag: onInternalScrollBeginDrag },
5932
5969
  contentContainerStyle: [
5933
- horizontal ? {
5934
- height: "100%"
5935
- } : {},
5936
- contentContainerStyle
5970
+ horizontal ? { height: "100%" } : {},
5971
+ contentContainerStyle,
5972
+ anchoredEndSpaceStyle,
5973
+ Platform.OS === "web" ? { boxSizing: "border-box" } : void 0
5937
5974
  ],
5938
5975
  contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
5939
5976
  horizontal,
@@ -5951,6 +5988,7 @@ var ListComponent = typedMemo(function ListComponent2({
5951
5988
  canRender && !ListEmptyComponent && /* @__PURE__ */ React2.createElement(
5952
5989
  Containers,
5953
5990
  {
5991
+ freshDataTransitionEpoch,
5954
5992
  getRenderedItem: getRenderedItem2,
5955
5993
  horizontal,
5956
5994
  ItemSeparatorComponent,
@@ -5959,7 +5997,6 @@ var ListComponent = typedMemo(function ListComponent2({
5959
5997
  }
5960
5998
  ),
5961
5999
  ListFooterComponent && /* @__PURE__ */ React2.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
5962
- Platform.OS === "web" && /* @__PURE__ */ React2.createElement(WebAnchoredEndSpace, { horizontal }),
5963
6000
  IS_DEV && ENABLE_DEVMODE
5964
6001
  );
5965
6002
  });
@@ -5968,7 +6005,16 @@ var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
5968
6005
  var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
5969
6006
  function useDevChecksImpl(props) {
5970
6007
  const ctx = useStateContext();
5971
- const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
6008
+ const { anchoredEndSpace, childrenMode, keyExtractor, numColumns, renderScrollComponent, useWindowScroll } = props;
6009
+ const hasAnchoredEndSpace = !!anchoredEndSpace;
6010
+ useEffect(() => {
6011
+ if (hasAnchoredEndSpace && (numColumns != null ? numColumns : 1) > 1) {
6012
+ warnDevOnce(
6013
+ "anchoredEndSpaceNumColumns",
6014
+ "anchoredEndSpace is only supported when numColumns is 1. Using it with multiple columns may produce incorrect anchored spacing."
6015
+ );
6016
+ }
6017
+ }, [hasAnchoredEndSpace, numColumns]);
5972
6018
  useEffect(() => {
5973
6019
  if (useWindowScroll && renderScrollComponent) {
5974
6020
  warnDevOnce(
@@ -6296,6 +6342,59 @@ function onScroll(ctx, event) {
6296
6342
  }
6297
6343
  }
6298
6344
 
6345
+ // src/core/ScheduledWork.ts
6346
+ var ScheduledWork = class {
6347
+ constructor() {
6348
+ this.work = /* @__PURE__ */ new Map();
6349
+ }
6350
+ timeout(callback, delay, key) {
6351
+ if (key) {
6352
+ this.cancel(key);
6353
+ }
6354
+ const work = [void 0, clearTimeout];
6355
+ const handle = setTimeout(() => {
6356
+ const workKey = key != null ? key : handle;
6357
+ if (this.work.get(workKey) === work) {
6358
+ this.work.delete(workKey);
6359
+ callback();
6360
+ }
6361
+ }, delay);
6362
+ work[0] = handle;
6363
+ this.work.set(key != null ? key : handle, work);
6364
+ }
6365
+ frame(callback, key) {
6366
+ this.cancel(key);
6367
+ const work = [void 0, cancelAnimationFrame];
6368
+ this.work.set(key, work);
6369
+ work[0] = requestAnimationFrame(() => {
6370
+ if (this.work.get(key) === work) {
6371
+ this.work.delete(key);
6372
+ callback();
6373
+ }
6374
+ });
6375
+ }
6376
+ register(key, cancel) {
6377
+ this.cancel(key);
6378
+ this.work.set(key, [void 0, cancel]);
6379
+ }
6380
+ cancel(key) {
6381
+ const work = this.work.get(key);
6382
+ if (work) {
6383
+ this.work.delete(key);
6384
+ work[1](work[0]);
6385
+ }
6386
+ }
6387
+ has(key) {
6388
+ return this.work.has(key);
6389
+ }
6390
+ dispose() {
6391
+ for (const [handle, cancel] of this.work.values()) {
6392
+ cancel(handle);
6393
+ }
6394
+ this.work.clear();
6395
+ }
6396
+ };
6397
+
6299
6398
  // src/core/ScrollAdjustHandler.ts
6300
6399
  var ScrollAdjustHandler = class {
6301
6400
  constructor(ctx) {
@@ -6383,7 +6482,6 @@ var useCombinedRef = (...refs) => {
6383
6482
  }, refs);
6384
6483
  return callback;
6385
6484
  };
6386
- var StyleSheet = StyleSheet$1;
6387
6485
  function useStickyScrollHandler(stickyHeaderIndices, horizontal, ctx, onScroll2) {
6388
6486
  const shouldUseRnAnimatedEngine = !ctx.state.props.stickyPositionComponentInternal;
6389
6487
  return useMemo(() => {
@@ -6470,7 +6568,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6470
6568
  const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
6471
6569
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
6472
6570
  let imperativeScrollToken = 0;
6473
- const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0;
6571
+ const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.scheduledWork.has("mvcpRecalculate") || state.ignoreScrollFromMVCP !== void 0;
6474
6572
  const isScrollToIndexReady = (targetIndex, allowEmpty = false) => {
6475
6573
  var _a3;
6476
6574
  const props = state.props;
@@ -6504,9 +6602,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6504
6602
  run();
6505
6603
  return;
6506
6604
  }
6507
- requestAnimationFrame(check);
6605
+ state.scheduledWork.frame(check, "imperativeScrollReady");
6508
6606
  };
6509
- requestAnimationFrame(check);
6607
+ state.scheduledWork.frame(check, "imperativeScrollReady");
6510
6608
  };
6511
6609
  const runScrollRequest = (token, resolve, run, isReady = () => true) => {
6512
6610
  const runNow = () => {
@@ -6528,10 +6626,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6528
6626
  }
6529
6627
  };
6530
6628
  const startImperativeScroll = (resolve) => {
6531
- var _a3;
6629
+ state.scheduledWork.cancel("imperativeScrollReady");
6532
6630
  const token = ++imperativeScrollToken;
6533
- state.pendingScrollToEnd = void 0;
6534
- (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
6631
+ settlePendingImperativeScroll(state);
6535
6632
  state.pendingScrollResolve = resolve;
6536
6633
  return token;
6537
6634
  };
@@ -6615,6 +6712,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6615
6712
  end: state.endNoBuffer,
6616
6713
  endBuffered: state.endBuffered,
6617
6714
  getAverageItemSizes: () => getAverageItemSizes(state),
6715
+ indexByKey: (key) => state.indexByKey.get(key),
6618
6716
  isAtEnd: peek$(ctx, "isAtEnd"),
6619
6717
  isAtStart: peek$(ctx, "isAtStart"),
6620
6718
  isEndReached: state.isEndReached,
@@ -6918,7 +7016,7 @@ var LegendList = typedMemo(
6918
7016
  })
6919
7017
  );
6920
7018
  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;
7019
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
6922
7020
  const noopOnScroll = useCallback((_event) => {
6923
7021
  }, []);
6924
7022
  if (props.recycleItems === void 0) {
@@ -6994,9 +7092,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6994
7092
  ...rest
6995
7093
  } = props;
6996
7094
  const animatedPropsInternal = props.animatedPropsInternal;
7095
+ const anchoredEndSpaceOwner = (_a3 = props.anchoredEndSpaceOwnerInternal) != null ? _a3 : "list";
6997
7096
  const positionComponentInternal = props.positionComponentInternal;
6998
7097
  const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
6999
7098
  const {
7099
+ anchoredEndSpaceOwnerInternal: _anchoredEndSpaceOwnerInternal,
7000
7100
  positionComponentInternal: _positionComponentInternal,
7001
7101
  stickyPositionComponentInternal: _stickyPositionComponentInternal,
7002
7102
  ...restProps
@@ -7018,6 +7118,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7018
7118
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
7019
7119
  const stylePaddingLeftState = extractPadding(style, contentContainerStyle, "Left");
7020
7120
  const stylePaddingRightState = extractPadding(style, contentContainerStyle, "Right");
7121
+ const stylePaddingEndState = getStylePaddingEnd({
7122
+ horizontal,
7123
+ rtl,
7124
+ stylePaddingBottom: stylePaddingBottomState,
7125
+ stylePaddingLeft: stylePaddingLeftState,
7126
+ stylePaddingRight: stylePaddingRightState
7127
+ });
7021
7128
  const maintainScrollAtEndConfig = normalizeMaintainScrollAtEnd(maintainScrollAtEnd);
7022
7129
  const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
7023
7130
  maintainVisibleContentPositionProp
@@ -7030,13 +7137,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7030
7137
  const initialScrollProp = initialScrollAtEnd ? {
7031
7138
  index: Math.max(0, dataProp.length - 1),
7032
7139
  preserveForBottomPadding: true,
7033
- viewOffset: -stylePaddingBottomState,
7140
+ viewOffset: -stylePaddingEndState,
7034
7141
  viewPosition: 1
7035
7142
  } : hasInitialScrollIndex ? typeof initialScrollIndexProp === "object" ? {
7036
- index: (_a3 = initialScrollIndexProp.index) != null ? _a3 : 0,
7143
+ index: (_b = initialScrollIndexProp.index) != null ? _b : 0,
7037
7144
  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
7145
+ viewOffset: (_c = initialScrollIndexProp.viewOffset) != null ? _c : initialScrollIndexProp.viewPosition === 1 ? -stylePaddingEndState : 0,
7146
+ viewPosition: (_d = initialScrollIndexProp.viewPosition) != null ? _d : 0
7040
7147
  } : {
7041
7148
  index: initialScrollIndexProp != null ? initialScrollIndexProp : 0,
7042
7149
  viewOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : 0
@@ -7049,7 +7156,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7049
7156
  const [, scheduleImperativeScrollCommit] = React2.useReducer((value) => value + 1, 0);
7050
7157
  const ctx = useStateContext();
7051
7158
  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;
7159
+ 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
7160
  const nextScrollAxisGap = typeof scrollAxisGap === "number" && Number.isFinite(scrollAxisGap) ? scrollAxisGap : 0;
7054
7161
  const refScroller = useRef(null);
7055
7162
  const combinedRef = useCombinedRef(refScroller, refScrollView);
@@ -7064,8 +7171,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7064
7171
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex,
7065
7172
  alwaysRender == null ? void 0 : alwaysRender.top,
7066
7173
  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(","),
7174
+ (_k = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _k.join(","),
7175
+ (_l = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _l.join(","),
7069
7176
  dataProp,
7070
7177
  dataKey,
7071
7178
  dataVersion,
@@ -7078,7 +7185,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7078
7185
  if (!refState.current) {
7079
7186
  if (!ctx.state) {
7080
7187
  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");
7188
+ ctx.values.set("adaptiveRender", (_m = experimental_adaptiveRender == null ? void 0 : experimental_adaptiveRender.initialMode) != null ? _m : "normal");
7082
7189
  ctx.state = {
7083
7190
  averageSizes: {},
7084
7191
  columnSpans: [],
@@ -7097,6 +7204,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7097
7204
  endNoBuffer: -1,
7098
7205
  endReachedSnapshot: void 0,
7099
7206
  firstFullyOnScreenIndex: -1,
7207
+ freshDataTransitionEpoch: 0,
7100
7208
  hasHadNonEmptyData: dataProp.length > 0,
7101
7209
  idCache: [],
7102
7210
  idsInView: [],
@@ -7121,8 +7229,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7121
7229
  positions: [],
7122
7230
  props: {},
7123
7231
  queuedCalculateItemsInView: 0,
7124
- queuedFullDrawDistancePrewarm: void 0,
7125
7232
  refScroller: { current: null },
7233
+ scheduledWork: new ScheduledWork(),
7126
7234
  scroll: 0,
7127
7235
  scrollAdjustHandler: new ScrollAdjustHandler(ctx),
7128
7236
  scrollForNextCalculateItemsInView: void 0,
@@ -7140,8 +7248,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7140
7248
  startReachedSnapshot: void 0,
7141
7249
  stickyContainerPool: /* @__PURE__ */ new Set(),
7142
7250
  stickyContainers: /* @__PURE__ */ new Map(),
7143
- timeoutAdaptiveRender: void 0,
7144
- timeouts: /* @__PURE__ */ new Set(),
7145
7251
  totalSize: 0,
7146
7252
  viewabilityConfigCallbackPairs: void 0
7147
7253
  };
@@ -7163,13 +7269,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7163
7269
  const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
7164
7270
  ctx.scrollAxisGap = nextScrollAxisGap;
7165
7271
  state.didColumnsChange = numColumnsProp !== previousNumColumnsProp || didScrollAxisGapChange;
7166
- const previousDataLength = (_n = (_m = state.props.data) == null ? void 0 : _m.length) != null ? _n : 0;
7272
+ const previousDataLength = (_o = (_n = state.props.data) == null ? void 0 : _n.length) != null ? _o : 0;
7167
7273
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
7168
7274
  const didDataKeyChangeLocal = state.props.dataKey !== dataKey;
7169
7275
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
7170
7276
  const didDataChangeLocal = didDataKeyChangeLocal || didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
7171
7277
  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) {
7278
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_p = state.initialScroll) == null ? void 0 : _p.viewPosition) === 1 && state.props.data.length > 0) {
7173
7279
  clearPreservedInitialScrollTarget(state);
7174
7280
  }
7175
7281
  if (didDataChangeLocal) {
@@ -7178,10 +7284,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7178
7284
  state.didDataChange = true;
7179
7285
  state.previousData = state.props.data;
7180
7286
  }
7287
+ if (shouldResetFreshDataLayout) {
7288
+ state.freshDataTransitionEpoch += 1;
7289
+ }
7181
7290
  const throttledOnScroll = useThrottledOnScroll(onScrollProp != null ? onScrollProp : noopOnScroll, scrollEventThrottle != null ? scrollEventThrottle : 0);
7182
7291
  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);
7292
+ const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_q = state.props.anchoredEndSpace) == null ? void 0 : _q.anchorIndex) !== (anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex);
7185
7293
  state.props = {
7186
7294
  adaptiveRender: experimental_adaptiveRender,
7187
7295
  alignItemsAtEnd,
@@ -7189,7 +7297,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7189
7297
  alwaysRender,
7190
7298
  alwaysRenderIndicesArr: alwaysRenderIndices.arr,
7191
7299
  alwaysRenderIndicesSet: alwaysRenderIndices.set,
7192
- anchoredEndSpace: anchoredEndSpaceResolved,
7300
+ anchoredEndSpace,
7301
+ anchoredEndSpaceOwner,
7193
7302
  animatedProps: animatedPropsInternal,
7194
7303
  contentContainerAlignItems: contentContainerStyle.alignItems,
7195
7304
  contentInset,
@@ -7238,12 +7347,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7238
7347
  if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
7239
7348
  resetAdaptiveRender(ctx);
7240
7349
  }
7241
- if (shouldResetFreshDataLayout) {
7242
- resetInitialRenderState(ctx, {
7243
- resetInitialScroll: !!initialScrollProp,
7244
- resetLayout: true
7245
- });
7246
- }
7247
7350
  const memoizedLastItemKeys = useMemo(() => {
7248
7351
  if (!dataProp.length) return [];
7249
7352
  return Array.from(
@@ -7307,6 +7410,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7307
7410
  useDevChecks(props);
7308
7411
  }
7309
7412
  useLayoutEffect(() => {
7413
+ if (shouldResetFreshDataLayout) {
7414
+ resetInitialRenderState(ctx, {
7415
+ resetInitialScroll: !!initialScrollProp,
7416
+ resetLayout: true
7417
+ });
7418
+ }
7310
7419
  handleInitialScrollDataChange(ctx, {
7311
7420
  dataLength: dataProp.length,
7312
7421
  didDataChange: didDataChangeLocal,
@@ -7314,7 +7423,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7314
7423
  initialScrollAtEnd,
7315
7424
  latestInitialScroll: initialScrollProp,
7316
7425
  latestInitialScrollSessionKind: initialScrollUsesOffsetOnly ? "offset" : "bootstrap",
7317
- stylePaddingBottom: stylePaddingBottomState,
7426
+ stylePaddingEnd: stylePaddingEndState,
7318
7427
  useBootstrapInitialScroll: usesBootstrapInitialScroll
7319
7428
  });
7320
7429
  }, [
@@ -7323,7 +7432,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7323
7432
  didDataChangeLocal,
7324
7433
  shouldResetFreshDataLayout,
7325
7434
  initialScrollAtEnd,
7326
- stylePaddingBottomState,
7435
+ stylePaddingEndState,
7327
7436
  usesBootstrapInitialScroll
7328
7437
  ]);
7329
7438
  useLayoutEffect(() => {
@@ -7341,7 +7450,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7341
7450
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorMaxSize,
7342
7451
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorOffset,
7343
7452
  didAnchoredEndSpaceAnchorIndexChange,
7344
- numColumnsProp
7453
+ horizontal,
7454
+ numColumnsProp,
7455
+ rtl,
7456
+ stylePaddingBottomState,
7457
+ stylePaddingLeftState,
7458
+ stylePaddingRightState
7345
7459
  ]);
7346
7460
  useLayoutEffect(() => {
7347
7461
  const previousContentInsetEndAdjustment = previousContentInsetEndAdjustmentRef.current;
@@ -7357,10 +7471,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7357
7471
  dataLength: dataProp.length,
7358
7472
  footerSize: layout[horizontal ? "width" : "height"],
7359
7473
  initialScrollAtEnd,
7360
- stylePaddingBottom: stylePaddingBottomState
7474
+ stylePaddingEnd: stylePaddingEndState
7361
7475
  });
7362
7476
  },
7363
- [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingBottomState, usesBootstrapInitialScroll]
7477
+ [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingEndState, usesBootstrapInitialScroll]
7364
7478
  );
7365
7479
  const onLayoutChange = useCallback(
7366
7480
  (layout, fromLayoutEffect) => {
@@ -7377,7 +7491,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7377
7491
  }
7378
7492
  advanceCurrentInitialScrollSession(ctx);
7379
7493
  },
7380
- [dataProp.length, initialScrollAtEnd, stylePaddingBottomState, usesBootstrapInitialScroll]
7494
+ [dataProp.length, initialScrollAtEnd, stylePaddingEndState, usesBootstrapInitialScroll]
7381
7495
  );
7382
7496
  const { onLayout } = useOnLayoutSync({
7383
7497
  onLayoutChange,
@@ -7473,14 +7587,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7473
7587
  useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, scheduleImperativeScrollCommit), []);
7474
7588
  useEffect(() => {
7475
7589
  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();
7590
+ cancelImperativeScroll(state);
7591
+ state.scheduledWork.dispose();
7484
7592
  };
7485
7593
  }, [state]);
7486
7594
  useLayoutEffect(() => {
@@ -7522,6 +7630,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7522
7630
  canRender,
7523
7631
  contentContainerStyle,
7524
7632
  contentInset,
7633
+ freshDataTransitionEpoch: state.freshDataTransitionEpoch,
7525
7634
  getRenderedItem: fns.getRenderedItem,
7526
7635
  horizontal,
7527
7636
  initialContentOffset,
@@ -7537,7 +7646,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7537
7646
  onScroll: onScrollHandler,
7538
7647
  recycleItems,
7539
7648
  refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React2.cloneElement(refreshControlElement, {
7540
- progressViewOffset: ((_q = refreshControlElement.props.progressViewOffset) != null ? _q : 0) + stylePaddingTopState
7649
+ progressViewOffset: ((_r = refreshControlElement.props.progressViewOffset) != null ? _r : 0) + stylePaddingTopState
7541
7650
  }) : refreshControlElement : onRefresh && /* @__PURE__ */ React2.createElement(
7542
7651
  RefreshControl,
7543
7652
  {
@@ -7548,7 +7657,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7548
7657
  ),
7549
7658
  refScrollView: combinedRef,
7550
7659
  renderScrollComponent,
7551
- scrollAdjustHandler: (_r = refState.current) == null ? void 0 : _r.scrollAdjustHandler,
7660
+ scrollAdjustHandler: (_s = refState.current) == null ? void 0 : _s.scrollAdjustHandler,
7552
7661
  scrollEventThrottle: 0,
7553
7662
  snapToIndices,
7554
7663
  stickyHeaderIndices,