@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.
@@ -49,6 +49,12 @@ function isHorizontalRTL(state) {
49
49
  function isHorizontalRTLProps(props) {
50
50
  return !!(props == null ? void 0 : props.horizontal) && isRTLProps(props);
51
51
  }
52
+ function getStylePaddingEnd(props) {
53
+ if (!(props == null ? void 0 : props.horizontal)) {
54
+ return (props == null ? void 0 : props.stylePaddingBottom) || 0;
55
+ }
56
+ return (isHorizontalRTLProps(props) ? props.stylePaddingLeft : props.stylePaddingRight) || 0;
57
+ }
52
58
  function getLogicalHorizontalMaxOffset(state, contentWidth) {
53
59
  var _a3;
54
60
  return (_a3 = getHorizontalMaxOffset(state, contentWidth)) != null ? _a3 : 0;
@@ -169,6 +175,14 @@ function useStateContext() {
169
175
  return React3.useContext(ContextState);
170
176
  }
171
177
  function createSelectorFunctionsArr(ctx, signalNames) {
178
+ if (!ctx) {
179
+ const emptyValues = [];
180
+ return {
181
+ get: () => emptyValues,
182
+ subscribe: () => () => {
183
+ }
184
+ };
185
+ }
172
186
  let lastValues = [];
173
187
  let lastSignalValues = [];
174
188
  return {
@@ -275,7 +289,7 @@ function getContentInsetEndAdjustmentEnd(adjustment) {
275
289
  return Math.max(0, adjustment != null ? adjustment : 0);
276
290
  }
277
291
  function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
278
- var _a3, _b;
292
+ var _a3;
279
293
  const state = ctx.state;
280
294
  const { props } = state;
281
295
  const horizontal = props.horizontal;
@@ -286,8 +300,8 @@ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
286
300
  contentInsetEndAdjustmentOverride != null ? contentInsetEndAdjustmentOverride : props.contentInsetEndAdjustment
287
301
  );
288
302
  const anchoredEndSpaceSize = peek$(ctx, "anchoredEndSpaceSize");
289
- const anchoredEndInset = ((_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.includeInEndInset) && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
290
- const overrideInset = (_b = state.contentInsetOverride) != null ? _b : void 0;
303
+ const anchoredEndInset = props.anchoredEndSpace && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
304
+ const overrideInset = (_a3 = state.contentInsetOverride) != null ? _a3 : void 0;
291
305
  const adjustedBaseEndInset = baseEndInset + contentInsetEndAdjustment;
292
306
  if (overrideInset) {
293
307
  const mergedInset = { bottom: 0, left: 0, right: 0, ...baseInset, ...overrideInset };
@@ -303,14 +317,15 @@ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
303
317
  function getContentSize(ctx) {
304
318
  var _a3, _b;
305
319
  const { values, state } = ctx;
306
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
307
- const stylePaddingBottom = state.props.stylePaddingBottom || 0;
320
+ const stylePaddingStart = state.props.horizontal ? state.props.stylePaddingLeft || 0 : values.get("stylePaddingTop") || 0;
321
+ const stylePaddingEnd = state.props.horizontal ? state.props.stylePaddingRight || 0 : state.props.stylePaddingBottom || 0;
308
322
  const alignItemsAtEndPadding = values.get("alignItemsAtEndPadding") || 0;
309
323
  const headerSize = values.get("headerSize") || 0;
310
324
  const footerSize = values.get("footerSize") || 0;
311
- const contentInsetBottom = getContentInsetEnd(ctx);
325
+ const contentInsetEnd = getContentInsetEnd(ctx);
312
326
  const totalSize = (_b = (_a3 = state.pendingTotalSize) != null ? _a3 : state.totalSize) != null ? _b : values.get("totalSize");
313
- return headerSize + footerSize + totalSize + stylePaddingTop + alignItemsAtEndPadding + stylePaddingBottom + (contentInsetBottom || 0);
327
+ const layoutSize = Math.max(0, totalSize - (state.props.data.length > 0 ? ctx.scrollAxisGap : 0));
328
+ return headerSize + footerSize + layoutSize + stylePaddingStart + alignItemsAtEndPadding + stylePaddingEnd + (contentInsetEnd || 0);
314
329
  }
315
330
 
316
331
  // src/components/DebugView.tsx
@@ -398,6 +413,28 @@ var EDGE_POSITION_EPSILON = 1;
398
413
  var ENABLE_DEVMODE = IS_DEV && false;
399
414
  var ENABLE_DEBUG_VIEW = IS_DEV && false;
400
415
 
416
+ // src/core/cancelImperativeScroll.ts
417
+ function cancelScrollCompletionChecks({ scheduledWork }) {
418
+ scheduledWork.cancel("checkFinishedScrollFrame");
419
+ scheduledWork.cancel("checkFinishedScrollRetryFrame");
420
+ scheduledWork.cancel("checkFinishedScrollFallback");
421
+ scheduledWork.cancel("platformScrollCompletion");
422
+ }
423
+ function settlePendingImperativeScroll(state) {
424
+ var _a3, _b;
425
+ const resolvePendingScroll = (_b = state.pendingScrollResolve) != null ? _b : (_a3 = state.pendingScrollToEnd) == null ? void 0 : _a3.resolve;
426
+ state.pendingScrollResolve = void 0;
427
+ state.pendingScrollToEnd = void 0;
428
+ resolvePendingScroll == null ? void 0 : resolvePendingScroll();
429
+ }
430
+ function cancelImperativeScroll(state) {
431
+ cancelScrollCompletionChecks(state);
432
+ state.scheduledWork.cancel("imperativeScrollReady");
433
+ state.scrollingTo = void 0;
434
+ state.scrollTargetPinnedRange = void 0;
435
+ settlePendingImperativeScroll(state);
436
+ }
437
+
401
438
  // src/core/deferredPublicOnScroll.ts
402
439
  function withResolvedContentOffset(state, event, resolvedOffset) {
403
440
  return {
@@ -761,13 +798,7 @@ var DEFAULT_WEB_ADAPTIVE_RENDER_ENTER_VELOCITY = 6;
761
798
  var DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_VELOCITY = 3;
762
799
  var DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_DELAY = 250;
763
800
  function clearAdaptiveRenderExitTimeout(ctx) {
764
- const state = ctx.state;
765
- const previousTimeout = state.timeoutAdaptiveRender;
766
- if (previousTimeout !== void 0) {
767
- clearTimeout(previousTimeout);
768
- state.timeouts.delete(previousTimeout);
769
- state.timeoutAdaptiveRender = void 0;
770
- }
801
+ ctx.state.scheduledWork.cancel("adaptiveRender");
771
802
  }
772
803
  function scheduleAdaptiveRenderExit(ctx, exitDelay) {
773
804
  const state = ctx.state;
@@ -775,13 +806,7 @@ function scheduleAdaptiveRenderExit(ctx, exitDelay) {
775
806
  if (exitDelay <= 0) {
776
807
  setAdaptiveRender(ctx, "normal", "scroll");
777
808
  } else {
778
- const timeout = setTimeout(() => {
779
- state.timeouts.delete(timeout);
780
- state.timeoutAdaptiveRender = void 0;
781
- setAdaptiveRender(ctx, "normal", "scroll");
782
- }, exitDelay);
783
- state.timeoutAdaptiveRender = timeout;
784
- state.timeouts.add(timeout);
809
+ state.scheduledWork.timeout(() => setAdaptiveRender(ctx, "normal", "scroll"), exitDelay, "adaptiveRender");
785
810
  }
786
811
  }
787
812
  function setAdaptiveRender(ctx, mode, reason) {
@@ -812,7 +837,7 @@ function updateAdaptiveRender(ctx, scrollVelocity, options) {
812
837
  const exitDelay = (_c = adaptiveRender.exitDelay) != null ? _c : DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_DELAY ;
813
838
  const threshold = currentMode === "light" ? exitVelocity : enterVelocity;
814
839
  const nextMode = (options == null ? void 0 : options.forceLight) || Math.abs(scrollVelocity) > threshold ? "light" : "normal";
815
- const previousMode = state.timeoutAdaptiveRender !== void 0 ? "normal" : currentMode;
840
+ const previousMode = state.scheduledWork.has("adaptiveRender") ? "normal" : currentMode;
816
841
  if (nextMode !== previousMode) {
817
842
  if (nextMode === "light") {
818
843
  setAdaptiveRender(ctx, "light", "scroll");
@@ -839,14 +864,13 @@ function getEffectiveDrawDistance(ctx, mode) {
839
864
  }
840
865
  function scheduleFullDrawDistancePrewarm(ctx) {
841
866
  const { state } = ctx;
842
- if (state.props.drawDistance <= INITIAL_DRAW_DISTANCE || state.queuedFullDrawDistancePrewarm !== void 0) {
867
+ if (state.props.drawDistance <= INITIAL_DRAW_DISTANCE || state.scheduledWork.has("fullDrawDistancePrewarm")) {
843
868
  return;
844
869
  }
845
- state.queuedFullDrawDistancePrewarm = requestAnimationFrame(() => {
870
+ state.scheduledWork.frame(() => {
846
871
  var _a3;
847
- state.queuedFullDrawDistancePrewarm = void 0;
848
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
849
- });
872
+ return (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
873
+ }, "fullDrawDistancePrewarm");
850
874
  }
851
875
 
852
876
  // src/utils/setInitialRenderState.ts
@@ -904,10 +928,7 @@ function syncInitialScrollOffset(state, offset) {
904
928
  state.scrollPrev = offset;
905
929
  }
906
930
  function clearPreservedInitialScrollTargetTimeout(state) {
907
- if (state.timeoutPreservedInitialScrollClear !== void 0) {
908
- clearTimeout(state.timeoutPreservedInitialScrollClear);
909
- state.timeoutPreservedInitialScrollClear = void 0;
910
- }
931
+ state.scheduledWork.cancel("preservedInitialScroll");
911
932
  }
912
933
  function clearPreservedInitialScrollTarget(state) {
913
934
  clearPreservedInitialScrollTargetTimeout(state);
@@ -915,6 +936,24 @@ function clearPreservedInitialScrollTarget(state) {
915
936
  state.initialScroll = void 0;
916
937
  setInitialScrollSession(state);
917
938
  }
939
+ function supersedeInitialScroll(ctx) {
940
+ var _a3, _b, _c;
941
+ const state = ctx.state;
942
+ const bootstrapInitialScroll = ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap" ? state.initialScrollSession.bootstrap : void 0;
943
+ if (state.initialScroll || bootstrapInitialScroll || ((_b = state.scrollingTo) == null ? void 0 : _b.isInitialScroll)) {
944
+ if ((bootstrapInitialScroll == null ? void 0 : bootstrapInitialScroll.frameHandle) !== void 0 && typeof cancelAnimationFrame === "function") {
945
+ cancelAnimationFrame(bootstrapInitialScroll.frameHandle);
946
+ }
947
+ if ((_c = state.scrollingTo) == null ? void 0 : _c.isInitialScroll) {
948
+ cancelScrollCompletionChecks(state);
949
+ state.scrollingTo = void 0;
950
+ state.scrollTargetPinnedRange = void 0;
951
+ }
952
+ initialScrollCompletion.resetFlags(state);
953
+ setInitialScrollSession(state, { bootstrap: null });
954
+ finishInitialScroll(ctx);
955
+ }
956
+ }
918
957
  function finishInitialScroll(ctx, options) {
919
958
  var _a3, _b, _c;
920
959
  const state = ctx.state;
@@ -936,14 +975,17 @@ function finishInitialScroll(ctx, options) {
936
975
  setInitialScrollSession(state);
937
976
  clearPreservedInitialScrollTargetTimeout(state);
938
977
  if (options == null ? void 0 : options.schedulePreservedTargetClear) {
939
- state.timeoutPreservedInitialScrollClear = setTimeout(() => {
940
- var _a5;
941
- state.timeoutPreservedInitialScrollClear = void 0;
942
- if (!state.didFinishInitialScroll || ((_a5 = state.scrollingTo) == null ? void 0 : _a5.isInitialScroll) || !state.initialScroll) {
943
- return;
944
- }
945
- clearPreservedInitialScrollTarget(state);
946
- }, PRESERVED_INITIAL_SCROLL_FALLBACK_CLEAR_DELAY_MS);
978
+ state.scheduledWork.timeout(
979
+ () => {
980
+ var _a5;
981
+ if (!state.didFinishInitialScroll || ((_a5 = state.scrollingTo) == null ? void 0 : _a5.isInitialScroll) || !state.initialScroll) {
982
+ return;
983
+ }
984
+ clearPreservedInitialScrollTarget(state);
985
+ },
986
+ PRESERVED_INITIAL_SCROLL_FALLBACK_CLEAR_DELAY_MS,
987
+ "preservedInitialScroll"
988
+ );
947
989
  }
948
990
  } else {
949
991
  clearPreservedInitialScrollTarget(state);
@@ -970,9 +1012,11 @@ function calculateOffsetForIndex(ctx, index) {
970
1012
  return index !== void 0 ? state.positions[index] || 0 : 0;
971
1013
  }
972
1014
 
973
- // src/core/getTopOffsetAdjustment.ts
974
- function getTopOffsetAdjustment(ctx) {
975
- return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
1015
+ // src/core/getStartOffsetAdjustment.ts
1016
+ function getStartOffsetAdjustment(ctx) {
1017
+ const { state } = ctx;
1018
+ const stylePaddingStart = state.props.horizontal ? (isHorizontalRTL(state) ? state.props.stylePaddingRight : state.props.stylePaddingLeft) || 0 : peek$(ctx, "stylePaddingTop") || 0;
1019
+ return stylePaddingStart + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
976
1020
  }
977
1021
 
978
1022
  // src/utils/getId.ts
@@ -1183,9 +1227,9 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1183
1227
  offset -= viewOffset;
1184
1228
  }
1185
1229
  if (index !== void 0) {
1186
- const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
1187
- if (topOffsetAdjustment) {
1188
- offset += topOffsetAdjustment;
1230
+ const startOffsetAdjustment = getStartOffsetAdjustment(ctx);
1231
+ if (startOffsetAdjustment) {
1232
+ offset += startOffsetAdjustment;
1189
1233
  }
1190
1234
  }
1191
1235
  if (viewPosition !== void 0 && index !== void 0) {
@@ -1195,7 +1239,8 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1195
1239
  }
1196
1240
  const isOutOfBounds = index < 0 || index >= dataLength;
1197
1241
  const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
1198
- const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1242
+ const measuredItemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1243
+ const itemSize = Math.max(0, measuredItemSize - (isOutOfBounds ? 0 : ctx.scrollAxisGap));
1199
1244
  const trailingInset = getContentInsetEnd(ctx);
1200
1245
  offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1201
1246
  if (!isOutOfBounds && index === state.props.data.length - 1) {
@@ -1227,6 +1272,7 @@ function finishScrollTo(ctx) {
1227
1272
  var _a3, _b;
1228
1273
  const state = ctx.state;
1229
1274
  if (state == null ? void 0 : state.scrollingTo) {
1275
+ cancelScrollCompletionChecks(state);
1230
1276
  const resolvePendingScroll = state.pendingScrollResolve;
1231
1277
  state.pendingScrollResolve = void 0;
1232
1278
  const scrollingTo = state.scrollingTo;
@@ -1268,6 +1314,7 @@ function doScrollTo(ctx, params) {
1268
1314
  var _a3, _b;
1269
1315
  const state = ctx.state;
1270
1316
  const { animated, horizontal, offset } = params;
1317
+ state.scheduledWork.cancel("platformScrollCompletion");
1271
1318
  const scroller = state.refScroller.current;
1272
1319
  const node = scroller == null ? void 0 : scroller.getScrollableNode();
1273
1320
  if (!scroller || !node) {
@@ -1288,9 +1335,16 @@ function doScrollTo(ctx, params) {
1288
1335
  });
1289
1336
  } else {
1290
1337
  state.scroll = offset;
1291
- setTimeout(() => {
1292
- finishScrollTo(ctx);
1293
- }, 100);
1338
+ const targetToken = state.scrollingTo;
1339
+ state.scheduledWork.timeout(
1340
+ () => {
1341
+ if (targetToken === state.scrollingTo) {
1342
+ finishScrollTo(ctx);
1343
+ }
1344
+ },
1345
+ 100,
1346
+ "platformScrollCompletion"
1347
+ );
1294
1348
  }
1295
1349
  }
1296
1350
  function listenForScrollEnd(ctx, params) {
@@ -1302,23 +1356,28 @@ function listenForScrollEnd(ctx, params) {
1302
1356
  const supportsScrollEnd = "onscrollend" in target;
1303
1357
  let idleTimeout;
1304
1358
  let settled = false;
1305
- const targetToken = ctx.state.scrollingTo;
1359
+ const { scheduledWork, scrollingTo: targetToken } = ctx.state;
1306
1360
  const maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1307
1361
  const cleanup = () => {
1308
1362
  target.removeEventListener("scroll", onScroll2);
1309
1363
  if (supportsScrollEnd) {
1310
1364
  target.removeEventListener("scrollend", onScrollEnd);
1311
1365
  }
1312
- if (idleTimeout) {
1366
+ if (idleTimeout !== void 0) {
1313
1367
  clearTimeout(idleTimeout);
1314
1368
  }
1315
1369
  clearTimeout(maxTimeout);
1316
1370
  };
1371
+ const cancel = () => {
1372
+ if (!settled) {
1373
+ settled = true;
1374
+ cleanup();
1375
+ }
1376
+ };
1317
1377
  const finish = (reason) => {
1318
1378
  if (settled) return;
1319
1379
  if (targetToken !== ctx.state.scrollingTo) {
1320
- settled = true;
1321
- cleanup();
1380
+ scheduledWork.cancel("platformScrollCompletion");
1322
1381
  return;
1323
1382
  }
1324
1383
  const currentOffset = readOffset();
@@ -1326,12 +1385,11 @@ function listenForScrollEnd(ctx, params) {
1326
1385
  if (reason === "scrollend" && !isNearTarget) {
1327
1386
  return;
1328
1387
  }
1329
- settled = true;
1330
- cleanup();
1388
+ scheduledWork.cancel("platformScrollCompletion");
1331
1389
  finishScrollTo(ctx);
1332
1390
  };
1333
1391
  const onScroll2 = () => {
1334
- if (idleTimeout) {
1392
+ if (idleTimeout !== void 0) {
1335
1393
  clearTimeout(idleTimeout);
1336
1394
  }
1337
1395
  idleTimeout = setTimeout(() => finish("idle"), SCROLL_END_IDLE_MS);
@@ -1343,6 +1401,7 @@ function listenForScrollEnd(ctx, params) {
1343
1401
  } else {
1344
1402
  idleTimeout = setTimeout(() => finish("idle"), SMOOTH_SCROLL_DURATION_MS);
1345
1403
  }
1404
+ scheduledWork.register("platformScrollCompletion", cancel);
1346
1405
  }
1347
1406
 
1348
1407
  // src/core/doMaintainScrollAtEnd.ts
@@ -1369,9 +1428,12 @@ function doMaintainScrollAtEnd(ctx) {
1369
1428
  if (!state.maintainingScrollAtEnd) {
1370
1429
  const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
1371
1430
  const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
1431
+ const scrollAtRequest = state.scroll;
1372
1432
  state.maintainingScrollAtEnd = pendingState;
1373
1433
  requestAnimationFrame(() => {
1374
- if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
1434
+ const isStillWithinThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
1435
+ const didScrollSinceRequest = state.scroll !== scrollAtRequest;
1436
+ if (isStillWithinThreshold || !didScrollSinceRequest) {
1375
1437
  state.maintainingScrollAtEnd = activeState;
1376
1438
  const scroller = refScroller.current;
1377
1439
  if (state.props.horizontal && isHorizontalRTL(state)) {
@@ -1401,6 +1463,7 @@ function doMaintainScrollAtEnd(ctx) {
1401
1463
  );
1402
1464
  } else if (state.maintainingScrollAtEnd === pendingState) {
1403
1465
  state.maintainingScrollAtEnd = void 0;
1466
+ state.pendingMaintainScrollAtEnd = false;
1404
1467
  }
1405
1468
  });
1406
1469
  } else {
@@ -1853,10 +1916,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
1853
1916
  state.mvcpAnchorLock = void 0;
1854
1917
  state.pendingNativeMVCPAdjust = void 0;
1855
1918
  state.userScrollAnchorReset = { keys: /* @__PURE__ */ new Set() };
1856
- if (state.queuedMVCPRecalculate !== void 0) {
1857
- cancelAnimationFrame(state.queuedMVCPRecalculate);
1858
- state.queuedMVCPRecalculate = void 0;
1859
- }
1919
+ state.scheduledWork.cancel("mvcpRecalculate");
1860
1920
  flushSync(runCalculateItems);
1861
1921
  scheduleFullDrawDistancePrewarm(ctx);
1862
1922
  } else {
@@ -2001,12 +2061,7 @@ function scrollTo(ctx, params) {
2001
2061
  const {
2002
2062
  props: { horizontal }
2003
2063
  } = state;
2004
- if (state.animFrameCheckFinishedScroll) {
2005
- cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
2006
- }
2007
- if (state.timeoutCheckFinishedScrollFallback) {
2008
- clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
2009
- }
2064
+ cancelScrollCompletionChecks(state);
2010
2065
  const requestedOffset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
2011
2066
  const shouldPreserveRawInitialOffsetRequest = !!isInitialScroll && ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset";
2012
2067
  const targetOffset = clampScrollOffset(ctx, requestedOffset, scrollTarget);
@@ -2111,10 +2166,7 @@ function setInitialScrollTarget(ctx, target, options) {
2111
2166
  var _a3;
2112
2167
  const { state } = ctx;
2113
2168
  state.clearPreservedInitialScrollOnNextFinish = void 0;
2114
- if (state.timeoutPreservedInitialScrollClear !== void 0) {
2115
- clearTimeout(state.timeoutPreservedInitialScrollClear);
2116
- state.timeoutPreservedInitialScrollClear = void 0;
2117
- }
2169
+ state.scheduledWork.cancel("preservedInitialScroll");
2118
2170
  state.initialScroll = target;
2119
2171
  if (options == null ? void 0 : options.resetDidFinish) {
2120
2172
  resetInitialRenderState(ctx, { resetInitialScroll: true });
@@ -2407,13 +2459,13 @@ function rearmBootstrapInitialScroll(ctx, options) {
2407
2459
  queueBootstrapInitialScrollReevaluation(ctx.state);
2408
2460
  }
2409
2461
  function createInitialScrollAtEndTarget(options) {
2410
- const { dataLength, footerSize, preserveForFooterLayout, stylePaddingBottom } = options;
2462
+ const { dataLength, footerSize, preserveForFooterLayout, stylePaddingEnd } = options;
2411
2463
  return {
2412
2464
  contentOffset: void 0,
2413
2465
  index: Math.max(0, dataLength - 1),
2414
2466
  preserveForBottomPadding: true,
2415
2467
  preserveForFooterLayout,
2416
- viewOffset: -stylePaddingBottom - footerSize,
2468
+ viewOffset: -stylePaddingEnd - footerSize,
2417
2469
  viewPosition: 1
2418
2470
  };
2419
2471
  }
@@ -2427,7 +2479,7 @@ function isRetargetableBottomAlignedInitialScrollTarget(target) {
2427
2479
  return !!(target && target.viewPosition === 1 && (shouldPreserveInitialScrollForBottomPadding(target) || shouldPreserveInitialScrollForFooterLayout(target)));
2428
2480
  }
2429
2481
  function createRetargetedBottomAlignedInitialScroll(options) {
2430
- const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom, target } = options;
2482
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd, target } = options;
2431
2483
  const preserveForFooterLayout = shouldPreserveInitialScrollForFooterLayout(target);
2432
2484
  return {
2433
2485
  ...target,
@@ -2435,7 +2487,7 @@ function createRetargetedBottomAlignedInitialScroll(options) {
2435
2487
  index: initialScrollAtEnd ? Math.max(0, dataLength - 1) : target.index,
2436
2488
  preserveForBottomPadding: true,
2437
2489
  preserveForFooterLayout,
2438
- viewOffset: -stylePaddingBottom - (preserveForFooterLayout ? footerSize : 0),
2490
+ viewOffset: -stylePaddingEnd - (preserveForFooterLayout ? footerSize : 0),
2439
2491
  viewPosition: 1
2440
2492
  };
2441
2493
  }
@@ -2443,7 +2495,7 @@ function areEquivalentBootstrapInitialScrollTargets(current, next) {
2443
2495
  return current.index === next.index && current.preserveForBottomPadding === next.preserveForBottomPadding && current.preserveForFooterLayout === next.preserveForFooterLayout && current.viewOffset === next.viewOffset && current.viewPosition === next.viewPosition;
2444
2496
  }
2445
2497
  function clearPendingInitialScrollFooterLayout(ctx, options) {
2446
- const { dataLength, stylePaddingBottom, target } = options;
2498
+ const { dataLength, stylePaddingEnd, target } = options;
2447
2499
  if (!shouldPreserveInitialScrollForFooterLayout(target)) {
2448
2500
  return;
2449
2501
  }
@@ -2451,7 +2503,7 @@ function clearPendingInitialScrollFooterLayout(ctx, options) {
2451
2503
  dataLength,
2452
2504
  footerSize: 0,
2453
2505
  preserveForFooterLayout: void 0,
2454
- stylePaddingBottom
2506
+ stylePaddingEnd
2455
2507
  });
2456
2508
  setInitialScrollTarget(ctx, clearedFooterTarget);
2457
2509
  }
@@ -2512,7 +2564,7 @@ function schedulePreservedEndAnchorCorrectionFrame(ctx, correction) {
2512
2564
  });
2513
2565
  }
2514
2566
  function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2515
- var _a3, _b;
2567
+ var _a3;
2516
2568
  const state = ctx.state;
2517
2569
  const initialScroll = state.initialScroll;
2518
2570
  if (!state.didFinishInitialScroll || ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) || (initialScroll == null ? void 0 : initialScroll.viewPosition) !== 1 || state.preservedEndAnchorCorrection) {
@@ -2524,7 +2576,7 @@ function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2524
2576
  if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
2525
2577
  clearPendingInitialScrollFooterLayout(ctx, {
2526
2578
  dataLength: state.props.data.length,
2527
- stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
2579
+ stylePaddingEnd: getStylePaddingEnd(state.props),
2528
2580
  target: initialScroll
2529
2581
  });
2530
2582
  } else {
@@ -2561,7 +2613,7 @@ function startBootstrapInitialScrollOnMount(ctx, options) {
2561
2613
  }
2562
2614
  }
2563
2615
  function handleBootstrapInitialScrollDataChange(ctx, options) {
2564
- const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingBottom } = options;
2616
+ const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingEnd } = options;
2565
2617
  const state = ctx.state;
2566
2618
  const initialScroll = state.initialScroll;
2567
2619
  if (isOffsetInitialScrollSession(state) || !initialScroll) {
@@ -2583,18 +2635,18 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2583
2635
  dataLength,
2584
2636
  footerSize: peek$(ctx, "footerSize") || 0,
2585
2637
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2586
- stylePaddingBottom
2638
+ stylePaddingEnd
2587
2639
  }) : createRetargetedBottomAlignedInitialScroll({
2588
2640
  dataLength,
2589
2641
  footerSize: peek$(ctx, "footerSize") || 0,
2590
2642
  initialScrollAtEnd,
2591
- stylePaddingBottom,
2643
+ stylePaddingEnd,
2592
2644
  target: initialScroll
2593
2645
  });
2594
2646
  if (!shouldResetDidFinish && didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2595
2647
  clearPendingInitialScrollFooterLayout(ctx, {
2596
2648
  dataLength,
2597
- stylePaddingBottom,
2649
+ stylePaddingEnd,
2598
2650
  target: initialScroll
2599
2651
  });
2600
2652
  return;
@@ -2626,7 +2678,7 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2626
2678
  }
2627
2679
  }
2628
2680
  function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2629
- const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom } = options;
2681
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd } = options;
2630
2682
  const state = ctx.state;
2631
2683
  if (!initialScrollAtEnd) {
2632
2684
  return;
@@ -2642,7 +2694,7 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2642
2694
  if (didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2643
2695
  clearPendingInitialScrollFooterLayout(ctx, {
2644
2696
  dataLength,
2645
- stylePaddingBottom,
2697
+ stylePaddingEnd,
2646
2698
  target: initialScroll
2647
2699
  });
2648
2700
  } else {
@@ -2650,13 +2702,13 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2650
2702
  dataLength,
2651
2703
  footerSize,
2652
2704
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2653
- stylePaddingBottom
2705
+ stylePaddingEnd
2654
2706
  });
2655
2707
  const didTargetChange = initialScroll.index !== updatedInitialScroll.index || initialScroll.viewPosition !== updatedInitialScroll.viewPosition || initialScroll.viewOffset !== updatedInitialScroll.viewOffset;
2656
2708
  if (!didTargetChange) {
2657
2709
  clearPendingInitialScrollFooterLayout(ctx, {
2658
2710
  dataLength,
2659
- stylePaddingBottom,
2711
+ stylePaddingEnd,
2660
2712
  target: initialScroll
2661
2713
  });
2662
2714
  } else {
@@ -2864,7 +2916,7 @@ function checkFinishedScroll(ctx, options) {
2864
2916
  return;
2865
2917
  }
2866
2918
  }
2867
- ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
2919
+ ctx.state.scheduledWork.frame(() => checkFinishedScrollFrame(ctx), "checkFinishedScrollFrame");
2868
2920
  }
2869
2921
  function hasScrollCompletionOwnership(state, options) {
2870
2922
  const { clampedTargetOffset, scrollingTo } = options;
@@ -2934,7 +2986,6 @@ function checkFinishedScrollFrame(ctx) {
2934
2986
  return;
2935
2987
  }
2936
2988
  const { state } = ctx;
2937
- state.animFrameCheckFinishedScroll = void 0;
2938
2989
  const completionState = getResolvedScrollCompletionState(ctx, scrollingTo);
2939
2990
  if (completionState.isAtResolvedTarget && hasScrollCompletionOwnership(state, {
2940
2991
  clampedTargetOffset: completionState.clampedTargetOffset,
@@ -2953,47 +3004,47 @@ function scrollToFallbackOffset(ctx, offset) {
2953
3004
  }
2954
3005
  function checkFinishedScrollFallback(ctx) {
2955
3006
  const state = ctx.state;
3007
+ if (state.scheduledWork.has("checkFinishedScrollFallback")) {
3008
+ return;
3009
+ }
2956
3010
  const scrollingTo = state.scrollingTo;
2957
3011
  const shouldFinishInitialZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
2958
3012
  const silentInitialDispatch = isSilentInitialDispatch(state, scrollingTo);
2959
3013
  const canFinishInitialWithoutNativeProgress = scrollingTo !== void 0 ? shouldFinishInitialScrollWithoutNativeProgress(state, scrollingTo) : false;
2960
3014
  const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) && !shouldFinishInitialZeroTarget && !canFinishInitialWithoutNativeProgress || !state.didContainersLayout;
2961
3015
  const initialDelay = shouldFinishInitialZeroTarget || canFinishInitialWithoutNativeProgress ? 0 : silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : slowTimeout ? 500 : 100;
2962
- state.timeoutCheckFinishedScrollFallback = setTimeout(() => {
2963
- let numChecks = 0;
2964
- const scheduleFallbackCheck = (delay) => {
2965
- state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, delay);
2966
- };
2967
- const checkHasScrolled = () => {
2968
- var _c, _d;
2969
- state.timeoutCheckFinishedScrollFallback = void 0;
2970
- const isStillScrollingTo = state.scrollingTo;
2971
- if (isStillScrollingTo) {
2972
- numChecks++;
2973
- const isNativeInitialPending = isNativeInitialNonZeroTarget(state) && !state.hasScrolled;
2974
- const maxChecks = silentInitialDispatch ? 5 : isNativeInitialPending ? INITIAL_SCROLL_MAX_FALLBACK_CHECKS : 5;
2975
- const shouldFinishZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
2976
- const canFinishInitialScrollWithoutNativeProgress = shouldFinishInitialScrollWithoutNativeProgress(
2977
- state,
2978
- isStillScrollingTo
2979
- );
2980
- const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
2981
- const canFinishAfterSilentNativeDispatch = Platform.OS === "android";
2982
- const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
2983
- const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
2984
- if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
2985
- finishScrollTo(ctx);
2986
- } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
2987
- const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
2988
- scrollToFallbackOffset(ctx, targetOffset);
2989
- scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2990
- } else {
2991
- scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2992
- }
3016
+ let numChecks = 0;
3017
+ const scheduleFallbackCheck = (delay) => {
3018
+ state.scheduledWork.timeout(checkHasScrolled, delay, "checkFinishedScrollFallback");
3019
+ };
3020
+ const checkHasScrolled = () => {
3021
+ var _c, _d;
3022
+ const isStillScrollingTo = state.scrollingTo;
3023
+ if (isStillScrollingTo) {
3024
+ numChecks++;
3025
+ const isNativeInitialPending = isNativeInitialNonZeroTarget(state) && !state.hasScrolled;
3026
+ const maxChecks = silentInitialDispatch ? 5 : isNativeInitialPending ? INITIAL_SCROLL_MAX_FALLBACK_CHECKS : 5;
3027
+ const shouldFinishZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
3028
+ const canFinishInitialScrollWithoutNativeProgress = shouldFinishInitialScrollWithoutNativeProgress(
3029
+ state,
3030
+ isStillScrollingTo
3031
+ );
3032
+ const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
3033
+ const canFinishAfterSilentNativeDispatch = Platform.OS === "android";
3034
+ const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
3035
+ const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
3036
+ if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
3037
+ finishScrollTo(ctx);
3038
+ } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
3039
+ const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
3040
+ scrollToFallbackOffset(ctx, targetOffset);
3041
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
3042
+ } else {
3043
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2993
3044
  }
2994
- };
2995
- checkHasScrolled();
2996
- }, initialDelay);
3045
+ }
3046
+ };
3047
+ scheduleFallbackCheck(initialDelay);
2997
3048
  }
2998
3049
 
2999
3050
  // src/core/initialScrollLifecycle.ts
@@ -3069,7 +3120,7 @@ function handleInitialScrollDataChange(ctx, options) {
3069
3120
  initialScrollAtEnd,
3070
3121
  latestInitialScroll,
3071
3122
  latestInitialScrollSessionKind,
3072
- stylePaddingBottom,
3123
+ stylePaddingEnd,
3073
3124
  useBootstrapInitialScroll
3074
3125
  } = options;
3075
3126
  const state = ctx.state;
@@ -3099,7 +3150,7 @@ function handleInitialScrollDataChange(ctx, options) {
3099
3150
  didDataChange,
3100
3151
  initialScrollAtEnd,
3101
3152
  previousDataLength: previousInitialScrollDataLength,
3102
- stylePaddingBottom
3153
+ stylePaddingEnd
3103
3154
  });
3104
3155
  return;
3105
3156
  }
@@ -3569,7 +3620,6 @@ function setupViewability(props) {
3569
3620
  }
3570
3621
  function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end, startBuffered = start, endBuffered = end) {
3571
3622
  const {
3572
- timeouts,
3573
3623
  props: { data }
3574
3624
  } = state;
3575
3625
  for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
@@ -3579,11 +3629,10 @@ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollS
3579
3629
  viewabilityState.startBuffered = startBuffered;
3580
3630
  viewabilityState.endBuffered = endBuffered;
3581
3631
  if (viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime) {
3582
- const timer = setTimeout(() => {
3583
- timeouts.delete(timer);
3584
- updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
3585
- }, viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime);
3586
- timeouts.add(timer);
3632
+ state.scheduledWork.timeout(
3633
+ () => updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize),
3634
+ viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime
3635
+ );
3587
3636
  } else {
3588
3637
  updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
3589
3638
  }
@@ -3942,20 +3991,15 @@ function getProjectedBufferAdjustment(scrollVelocity, trailingBuffer) {
3942
3991
  }
3943
3992
  function scheduleRenderRangeProjectionSettle(ctx) {
3944
3993
  const state = ctx.state;
3945
- const previousTimeout = state.timeoutRenderRangeProjectionSettle;
3946
- if (previousTimeout !== void 0) {
3947
- clearTimeout(previousTimeout);
3948
- state.timeouts.delete(previousTimeout);
3949
- }
3950
- const timeout = setTimeout(() => {
3951
- var _a3;
3952
- state.timeoutRenderRangeProjectionSettle = void 0;
3953
- state.timeouts.delete(timeout);
3954
- state.scrollHistory.length = 0;
3955
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
3956
- }, RENDER_RANGE_PROJECTION_SETTLE_DELAY);
3957
- state.timeoutRenderRangeProjectionSettle = timeout;
3958
- state.timeouts.add(timeout);
3994
+ state.scheduledWork.timeout(
3995
+ () => {
3996
+ var _a3;
3997
+ state.scrollHistory.length = 0;
3998
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
3999
+ },
4000
+ RENDER_RANGE_PROJECTION_SETTLE_DELAY,
4001
+ "renderRangeProjection"
4002
+ );
3959
4003
  }
3960
4004
  function findCurrentStickyIndex(stickyArray, scroll, state) {
3961
4005
  const positions = state.positions;
@@ -4623,8 +4667,6 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4623
4667
  if (anchorIndex >= 0 && anchorIndex < data.length && state.scrollLength > 0) {
4624
4668
  nextAnchorKey = getId(state, anchorIndex);
4625
4669
  let contentBelowAnchor = 0;
4626
- const footerSize = ctx.values.get("footerSize") || 0;
4627
- const stylePaddingBottom = state.props.stylePaddingBottom || 0;
4628
4670
  let hasUnknownTailSize = false;
4629
4671
  for (let index = anchorIndex; index < data.length; index++) {
4630
4672
  const size = getKnownOrFixedItemSize(ctx, index);
@@ -4636,14 +4678,16 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4636
4678
  contentBelowAnchor += effectiveSize;
4637
4679
  }
4638
4680
  }
4639
- contentBelowAnchor += footerSize + stylePaddingBottom;
4681
+ contentBelowAnchor = Math.max(0, contentBelowAnchor - ctx.scrollAxisGap);
4682
+ contentBelowAnchor += (ctx.values.get("footerSize") || 0) + getStylePaddingEnd(state.props);
4640
4683
  isReady = !hasUnknownTailSize;
4641
4684
  nextSize = hasUnknownTailSize ? previousSize || 0 : Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
4642
4685
  } else if (anchorIndex >= 0) {
4643
4686
  isReady = false;
4644
4687
  }
4645
4688
  }
4646
- const didSizeChange = previousSize !== nextSize;
4689
+ const didSizeChange = previousSize !== nextSize && (previousSize !== void 0 || anchoredEndSpace !== void 0);
4690
+ const didEffectiveSizeChange = (previousSize || 0) !== nextSize;
4647
4691
  const didReadyAnchorChange = previousReadyAnchorIndex !== nextAnchorIndex || previousReadyAnchorKey !== nextAnchorKey;
4648
4692
  if (isReady && (didSizeChange || didReadyAnchorChange)) {
4649
4693
  state.anchoredEndSpaceReadyAnchorIndex = nextAnchorIndex;
@@ -4652,8 +4696,9 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4652
4696
  set$(ctx, "anchoredEndSpaceSize", nextSize);
4653
4697
  (_a3 = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onSizeChanged) == null ? void 0 : _a3.call(anchoredEndSpace, nextSize);
4654
4698
  }
4655
- if (didSizeChange && (anchoredEndSpace == null ? void 0 : anchoredEndSpace.includeInEndInset)) {
4656
- updateScroll(ctx, state.scroll, true);
4699
+ if (didEffectiveSizeChange) {
4700
+ updateContentMetricsState(ctx);
4701
+ updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
4657
4702
  }
4658
4703
  (_b = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onReady) == null ? void 0 : _b.call(anchoredEndSpace, { anchorIndex: nextAnchorIndex, anchorKey: nextAnchorKey, size: nextSize });
4659
4704
  }
@@ -4671,16 +4716,10 @@ function runOrScheduleMVCPRecalculate(ctx) {
4671
4716
  }
4672
4717
  } else {
4673
4718
  if (!state.mvcpAnchorLock) {
4674
- if (state.queuedMVCPRecalculate !== void 0) {
4675
- cancelAnimationFrame(state.queuedMVCPRecalculate);
4676
- state.queuedMVCPRecalculate = void 0;
4677
- }
4719
+ state.scheduledWork.cancel("mvcpRecalculate");
4678
4720
  calculateItemsInView(ctx, { doMVCP: true });
4679
- } else if (state.queuedMVCPRecalculate === void 0) {
4680
- state.queuedMVCPRecalculate = requestAnimationFrame(() => {
4681
- state.queuedMVCPRecalculate = void 0;
4682
- calculateItemsInView(ctx, { doMVCP: true });
4683
- });
4721
+ } else if (!state.scheduledWork.has("mvcpRecalculate")) {
4722
+ state.scheduledWork.frame(() => calculateItemsInView(ctx, { doMVCP: true }), "mvcpRecalculate");
4684
4723
  }
4685
4724
  }
4686
4725
  }
@@ -4725,6 +4764,9 @@ function flushItemSizeUpdates(ctx, result) {
4725
4764
  } else if (result.didMeasureUserScrollAnchorResetItem && ((_a3 = state.userScrollAnchorReset) == null ? void 0 : _a3.keys.size) === 0) {
4726
4765
  state.userScrollAnchorReset = void 0;
4727
4766
  }
4767
+ if (result.didChange) {
4768
+ maybeUpdateAnchoredEndSpace(ctx);
4769
+ }
4728
4770
  if (result.didChange && result.shouldMaintainScrollAtEnd) {
4729
4771
  doMaintainScrollAtEnd(ctx);
4730
4772
  }
@@ -4804,7 +4846,7 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
4804
4846
  if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
4805
4847
  needsRecalculate = true;
4806
4848
  }
4807
- if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
4849
+ if (prevSizeKnown === void 0 || Math.abs(prevSizeKnown - size) > 5) {
4808
4850
  shouldMaintainScrollAtEnd = true;
4809
4851
  }
4810
4852
  onItemSizeChanged == null ? void 0 : onItemSizeChanged({
@@ -4814,7 +4856,6 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
4814
4856
  previous: size - diff,
4815
4857
  size
4816
4858
  });
4817
- maybeUpdateAnchoredEndSpace(ctx);
4818
4859
  }
4819
4860
  if (minIndexSizeChanged !== void 0) {
4820
4861
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
@@ -5704,24 +5745,38 @@ function useDOMOrder(ref) {
5704
5745
  };
5705
5746
  }, [ctx]);
5706
5747
  }
5748
+ function useFreshDataTransitionVisibility(readyToRender, transitionEpoch) {
5749
+ const [completedTransitionEpoch, setCompletedTransitionEpoch] = useState(transitionEpoch);
5750
+ const isTransitionPending = completedTransitionEpoch !== transitionEpoch;
5751
+ useLayoutEffect(() => {
5752
+ setCompletedTransitionEpoch(transitionEpoch);
5753
+ }, [transitionEpoch]);
5754
+ return readyToRender && !isTransitionPending;
5755
+ }
5707
5756
 
5708
5757
  // src/components/Containers.tsx
5709
- var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColumns, children }) {
5758
+ var ContainersInner = typedMemo(function ContainersInner2({
5759
+ freshDataTransitionEpoch,
5760
+ horizontal,
5761
+ numColumns,
5762
+ children
5763
+ }) {
5710
5764
  const ref = useRef(null);
5711
5765
  const ctx = useStateContext();
5712
5766
  const columnWrapperStyle = ctx.columnWrapperStyle;
5713
5767
  const isHorizontalRTLList = isHorizontalRTL(ctx.state);
5714
5768
  const [otherAxisSize, readyToRender, totalSize] = useArr$(["otherAxisSize", "readyToRender", "totalSize"]);
5769
+ const isVisible = useFreshDataTransitionVisibility(!!readyToRender, freshDataTransitionEpoch);
5715
5770
  useDOMOrder(ref);
5716
5771
  const style = horizontal ? {
5717
5772
  direction: isHorizontalRTLList ? "ltr" : void 0,
5718
5773
  flexShrink: 0,
5719
5774
  minHeight: otherAxisSize,
5720
- opacity: readyToRender ? 1 : 0,
5775
+ opacity: isVisible ? 1 : 0,
5721
5776
  position: "relative",
5722
5777
  width: totalSize
5723
- } : { height: totalSize, minWidth: otherAxisSize, opacity: readyToRender ? 1 : 0, position: "relative" };
5724
- if (!readyToRender) {
5778
+ } : { height: totalSize, minWidth: otherAxisSize, opacity: isVisible ? 1 : 0, position: "relative" };
5779
+ if (!isVisible) {
5725
5780
  style.pointerEvents = "none";
5726
5781
  }
5727
5782
  if (columnWrapperStyle && numColumns > 1) {
@@ -5744,6 +5799,7 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
5744
5799
  return /* @__PURE__ */ React3.createElement("div", { ref, style }, /* @__PURE__ */ React3.createElement(ContainerLayoutCoordinator, null, children));
5745
5800
  });
5746
5801
  var Containers = typedMemo(function Containers2({
5802
+ freshDataTransitionEpoch,
5747
5803
  horizontal,
5748
5804
  recycleItems,
5749
5805
  ItemSeparatorComponent,
@@ -5768,7 +5824,15 @@ var Containers = typedMemo(function Containers2({
5768
5824
  )
5769
5825
  );
5770
5826
  }
5771
- return /* @__PURE__ */ React3.createElement(ContainersInner, { horizontal, numColumns }, containers);
5827
+ return /* @__PURE__ */ React3.createElement(
5828
+ ContainersInner,
5829
+ {
5830
+ freshDataTransitionEpoch,
5831
+ horizontal,
5832
+ numColumns
5833
+ },
5834
+ containers
5835
+ );
5772
5836
  });
5773
5837
 
5774
5838
  // src/platform/StyleSheet.tsx
@@ -5979,7 +6043,7 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
5979
6043
  onLayout,
5980
6044
  ...props
5981
6045
  }, ref) {
5982
- var _a3, _b, _c, _d;
6046
+ var _a3, _b, _c;
5983
6047
  const ctx = useStateContext();
5984
6048
  const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
5985
6049
  const scrollRef = useRef(null);
@@ -6211,7 +6275,7 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
6211
6275
  } : {}
6212
6276
  };
6213
6277
  const contentInsetEndAdjustment = getContentInsetEndAdjustmentEnd2(ctx);
6214
- const anchoredEndInset = ((_c = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.props) == null ? void 0 : _b.anchoredEndSpace) == null ? void 0 : _c.includeInEndInset) && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
6278
+ const anchoredEndInset = ((_b = (_a3 = ctx.state) == null ? void 0 : _a3.props) == null ? void 0 : _b.anchoredEndSpace) && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
6215
6279
  const renderedContentInsetEndAdjustment = Math.max(0, contentInsetEndAdjustment - anchoredEndInset);
6216
6280
  const contentInsetEndAdjustmentSpacerStyle = renderedContentInsetEndAdjustment ? horizontal ? { flexShrink: 0, width: renderedContentInsetEndAdjustment } : { height: renderedContentInsetEndAdjustment } : void 0;
6217
6281
  const contentStyle = {
@@ -6238,7 +6302,7 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
6238
6302
  const snapOffsets = !isWindowScroll ? getFiniteSnapOffsets(snapToOffsets) : [];
6239
6303
  if (snapOffsets.length > 0) {
6240
6304
  scrollViewStyle.scrollSnapType = horizontal ? "x mandatory" : "y mandatory";
6241
- contentStyle.position = (_d = contentStyle.position) != null ? _d : "relative";
6305
+ contentStyle.position = (_c = contentStyle.position) != null ? _c : "relative";
6242
6306
  }
6243
6307
  const scrollViewClassName = hiddenScrollIndicatorClassName ? scrollViewClassNameProp ? `${scrollViewClassNameProp} ${hiddenScrollIndicatorClassName}` : hiddenScrollIndicatorClassName : scrollViewClassNameProp;
6244
6308
  if (IS_DEV) {
@@ -6327,10 +6391,9 @@ function ScrollAdjust() {
6327
6391
  const lastScrollOffsetRef = React3.useRef(0);
6328
6392
  const lastScrollAdjustUserOffsetRef = React3.useRef(0);
6329
6393
  const resetPaddingRafRef = React3.useRef(void 0);
6330
- const resetPaddingBaselineRef = React3.useRef(void 0);
6394
+ const temporaryPaddingRef = React3.useRef(void 0);
6331
6395
  const contentNodeRef = React3.useRef(null);
6332
6396
  const callback = React3.useCallback(() => {
6333
- var _a3;
6334
6397
  const scrollAdjust = peek$(ctx, "scrollAdjust");
6335
6398
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
6336
6399
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
@@ -6354,19 +6417,28 @@ function ScrollAdjust() {
6354
6417
  const nextScroll = currentScroll + scrollDelta;
6355
6418
  const needsTemporaryPadding = scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize;
6356
6419
  if (needsTemporaryPadding) {
6357
- const previousPaddingEnd = (_a3 = resetPaddingBaselineRef.current) != null ? _a3 : contentNode.style[axis.paddingEndProp];
6358
- resetPaddingBaselineRef.current = previousPaddingEnd;
6420
+ const currentInlinePaddingEnd = contentNode.style[axis.paddingEndProp];
6421
+ const previousTemporaryPadding = temporaryPaddingRef.current;
6422
+ const baselinePaddingEnd = (previousTemporaryPadding == null ? void 0 : previousTemporaryPadding.value) === currentInlinePaddingEnd ? previousTemporaryPadding.baseline : currentInlinePaddingEnd;
6359
6423
  const pad = (nextScroll + viewportSize - totalSize) * 2;
6360
- contentNode.style[axis.paddingEndProp] = `${pad}px`;
6424
+ const currentPaddingEnd = Number.parseFloat(
6425
+ window.getComputedStyle(contentNode)[axis.paddingEndProp]
6426
+ );
6427
+ const temporaryPaddingEnd = `${(currentPaddingEnd || 0) + pad}px`;
6428
+ temporaryPaddingRef.current = { baseline: baselinePaddingEnd, value: temporaryPaddingEnd };
6429
+ contentNode.style[axis.paddingEndProp] = temporaryPaddingEnd;
6361
6430
  void contentNode.offsetHeight;
6362
6431
  scrollBy();
6363
6432
  if (resetPaddingRafRef.current !== void 0) {
6364
6433
  cancelAnimationFrame(resetPaddingRafRef.current);
6365
6434
  }
6366
6435
  resetPaddingRafRef.current = requestAnimationFrame(() => {
6436
+ const temporaryPadding = temporaryPaddingRef.current;
6367
6437
  resetPaddingRafRef.current = void 0;
6368
- resetPaddingBaselineRef.current = void 0;
6369
- contentNode.style[axis.paddingEndProp] = previousPaddingEnd;
6438
+ temporaryPaddingRef.current = void 0;
6439
+ if (contentNode.style[axis.paddingEndProp] === (temporaryPadding == null ? void 0 : temporaryPadding.value)) {
6440
+ contentNode.style[axis.paddingEndProp] = temporaryPadding.baseline;
6441
+ }
6370
6442
  });
6371
6443
  } else {
6372
6444
  scrollBy();
@@ -6387,16 +6459,6 @@ var SnapWrapper = React3.forwardRef(function SnapWrapperInner({ ScrollComponent,
6387
6459
  const [snapToOffsets] = useArr$(["snapToOffsets"]);
6388
6460
  return /* @__PURE__ */ React3.createElement(ScrollComponent, { ...props, ref, snapToOffsets });
6389
6461
  });
6390
- function WebAnchoredEndSpace({ horizontal }) {
6391
- const ctx = useStateContext();
6392
- const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
6393
- const shouldRenderAnchoredEndSpace = !!ctx.state.props.anchoredEndSpace && (anchoredEndSpaceSize || 0) > 0;
6394
- if (!shouldRenderAnchoredEndSpace) {
6395
- return null;
6396
- }
6397
- const style = horizontal ? { height: "100%", width: anchoredEndSpaceSize || 0 } : { height: anchoredEndSpaceSize || 0 };
6398
- return /* @__PURE__ */ React3.createElement("div", { style }, null);
6399
- }
6400
6462
 
6401
6463
  // src/core/updateContentMetrics.ts
6402
6464
  var SCROLL_ADJUST_EPSILON = 0.1;
@@ -6430,7 +6492,11 @@ function setHeaderSize(ctx, size) {
6430
6492
  state.didMeasureHeader = true;
6431
6493
  }
6432
6494
  function setFooterSize(ctx, size) {
6433
- return setContentLengthSignal(ctx, "footerSize", size);
6495
+ const didChange = setContentLengthSignal(ctx, "footerSize", size);
6496
+ if (didChange) {
6497
+ maybeUpdateAnchoredEndSpace(ctx);
6498
+ }
6499
+ return didChange;
6434
6500
  }
6435
6501
  function areInsetsEqual(left, right) {
6436
6502
  var _a3, _b, _c, _d, _e, _f, _g, _h;
@@ -6483,6 +6549,7 @@ var AlignItemsAtEndSpacer = typedMemo(function AlignItemsAtEndSpacer2({ horizont
6483
6549
  });
6484
6550
  var ListComponent = typedMemo(function ListComponent2({
6485
6551
  canRender,
6552
+ freshDataTransitionEpoch,
6486
6553
  style,
6487
6554
  contentContainerStyle,
6488
6555
  horizontal,
@@ -6512,8 +6579,17 @@ var ListComponent = typedMemo(function ListComponent2({
6512
6579
  }) {
6513
6580
  const ctx = useStateContext();
6514
6581
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
6515
- const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
6582
+ const [anchoredEndSpaceSize = 0, otherAxisSize = 0] = useArr$(["anchoredEndSpaceSize", "otherAxisSize"]);
6516
6583
  const shouldRenderAlignItemsAtEndSpacer = ctx.state.props.alignItemsAtEndPaddingEnabled;
6584
+ const shouldMaterializeAnchoredEndSpace = !!ctx.state.props.anchoredEndSpace && ctx.state.props.anchoredEndSpaceOwner === "list" && anchoredEndSpaceSize > 0;
6585
+ let anchoredEndSpaceStyle;
6586
+ if (shouldMaterializeAnchoredEndSpace) {
6587
+ const paddingEnd = horizontal ? isHorizontalRTL(ctx.state) ? "Left" : "Right" : "Bottom";
6588
+ const flattenedContentContainerStyle = StyleSheet.flatten(contentContainerStyle);
6589
+ anchoredEndSpaceStyle = {
6590
+ [`padding${paddingEnd}`]: extractPadding({}, flattenedContentContainerStyle || {}, paddingEnd) + anchoredEndSpaceSize
6591
+ };
6592
+ }
6517
6593
  const autoOtherAxisStyle = getAutoOtherAxisStyle({
6518
6594
  horizontal,
6519
6595
  needsOtherAxisSize: ctx.state.needsOtherAxisSize,
@@ -6566,10 +6642,10 @@ var ListComponent = typedMemo(function ListComponent2({
6566
6642
  ...rest,
6567
6643
  ...ScrollComponent === ListComponentScrollView ? { onInternalScrollEnd, useWindowScroll } : {} ,
6568
6644
  contentContainerStyle: [
6569
- horizontal ? {
6570
- height: "100%"
6571
- } : {},
6572
- contentContainerStyle
6645
+ horizontal ? { height: "100%" } : {},
6646
+ contentContainerStyle,
6647
+ anchoredEndSpaceStyle,
6648
+ { boxSizing: "border-box" }
6573
6649
  ],
6574
6650
  contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
6575
6651
  horizontal,
@@ -6587,6 +6663,7 @@ var ListComponent = typedMemo(function ListComponent2({
6587
6663
  canRender && !ListEmptyComponent && /* @__PURE__ */ React3.createElement(
6588
6664
  Containers,
6589
6665
  {
6666
+ freshDataTransitionEpoch,
6590
6667
  getRenderedItem: getRenderedItem2,
6591
6668
  horizontal,
6592
6669
  ItemSeparatorComponent,
@@ -6595,7 +6672,6 @@ var ListComponent = typedMemo(function ListComponent2({
6595
6672
  }
6596
6673
  ),
6597
6674
  ListFooterComponent && /* @__PURE__ */ React3.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
6598
- /* @__PURE__ */ React3.createElement(WebAnchoredEndSpace, { horizontal }),
6599
6675
  IS_DEV && ENABLE_DEVMODE
6600
6676
  );
6601
6677
  });
@@ -6604,7 +6680,16 @@ var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
6604
6680
  var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
6605
6681
  function useDevChecksImpl(props) {
6606
6682
  const ctx = useStateContext();
6607
- const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
6683
+ const { anchoredEndSpace, childrenMode, keyExtractor, numColumns, renderScrollComponent, useWindowScroll } = props;
6684
+ const hasAnchoredEndSpace = !!anchoredEndSpace;
6685
+ useEffect(() => {
6686
+ if (hasAnchoredEndSpace && (numColumns != null ? numColumns : 1) > 1) {
6687
+ warnDevOnce(
6688
+ "anchoredEndSpaceNumColumns",
6689
+ "anchoredEndSpace is only supported when numColumns is 1. Using it with multiple columns may produce incorrect anchored spacing."
6690
+ );
6691
+ }
6692
+ }, [hasAnchoredEndSpace, numColumns]);
6608
6693
  useEffect(() => {
6609
6694
  if (useWindowScroll && renderScrollComponent) {
6610
6695
  warnDevOnce(
@@ -6932,6 +7017,60 @@ function onScroll(ctx, event) {
6932
7017
  }
6933
7018
  }
6934
7019
 
7020
+ // src/core/ScheduledWork.ts
7021
+ var ScheduledWork = class {
7022
+ constructor() {
7023
+ this.work = /* @__PURE__ */ new Map();
7024
+ }
7025
+ timeout(callback, delay, key) {
7026
+ if (key) {
7027
+ this.cancel(key);
7028
+ }
7029
+ const work = [void 0, clearTimeout];
7030
+ const handle = setTimeout(() => {
7031
+ const workKey = key != null ? key : handle;
7032
+ if (this.work.get(workKey) === work) {
7033
+ this.work.delete(workKey);
7034
+ callback();
7035
+ }
7036
+ }, delay);
7037
+ work[0] = handle;
7038
+ this.work.set(key != null ? key : handle, work);
7039
+ }
7040
+ frame(callback, key) {
7041
+ this.cancel(key);
7042
+ const work = [void 0, cancelAnimationFrame];
7043
+ this.work.set(key, work);
7044
+ work[0] = requestAnimationFrame(() => {
7045
+ if (this.work.get(key) === work) {
7046
+ this.work.delete(key);
7047
+ callback();
7048
+ }
7049
+ });
7050
+ }
7051
+ register(key, cancel) {
7052
+ this.cancel(key);
7053
+ this.work.set(key, [void 0, cancel]);
7054
+ }
7055
+ cancel(key) {
7056
+ const work = this.work.get(key);
7057
+ if (work) {
7058
+ this.work.delete(key);
7059
+ const [handle, cancel] = work;
7060
+ cancel(handle);
7061
+ }
7062
+ }
7063
+ has(key) {
7064
+ return this.work.has(key);
7065
+ }
7066
+ dispose() {
7067
+ for (const [handle, cancel] of this.work.values()) {
7068
+ cancel(handle);
7069
+ }
7070
+ this.work.clear();
7071
+ }
7072
+ };
7073
+
6935
7074
  // src/core/ScrollAdjustHandler.ts
6936
7075
  var ScrollAdjustHandler = class {
6937
7076
  constructor(ctx) {
@@ -7089,7 +7228,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7089
7228
  const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
7090
7229
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
7091
7230
  let imperativeScrollToken = 0;
7092
- const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0;
7231
+ const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.scheduledWork.has("mvcpRecalculate") || state.ignoreScrollFromMVCP !== void 0;
7093
7232
  const isScrollToIndexReady = (targetIndex, allowEmpty = false) => {
7094
7233
  var _a3;
7095
7234
  const props = state.props;
@@ -7123,9 +7262,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7123
7262
  run();
7124
7263
  return;
7125
7264
  }
7126
- requestAnimationFrame(check);
7265
+ state.scheduledWork.frame(check, "imperativeScrollReady");
7127
7266
  };
7128
- requestAnimationFrame(check);
7267
+ state.scheduledWork.frame(check, "imperativeScrollReady");
7129
7268
  };
7130
7269
  const runScrollRequest = (token, resolve, run, isReady = () => true) => {
7131
7270
  const runNow = () => {
@@ -7147,15 +7286,15 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7147
7286
  }
7148
7287
  };
7149
7288
  const startImperativeScroll = (resolve) => {
7150
- var _a3;
7289
+ state.scheduledWork.cancel("imperativeScrollReady");
7151
7290
  const token = ++imperativeScrollToken;
7152
- state.pendingScrollToEnd = void 0;
7153
- (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
7291
+ settlePendingImperativeScroll(state);
7154
7292
  state.pendingScrollResolve = resolve;
7155
7293
  return token;
7156
7294
  };
7157
7295
  const runScrollWithPromise = (run, isReady = () => true) => new Promise((resolve) => {
7158
7296
  const token = startImperativeScroll(resolve);
7297
+ supersedeInitialScroll(ctx);
7159
7298
  runScrollRequest(token, resolve, run, isReady);
7160
7299
  });
7161
7300
  state.runPendingScrollToEnd = () => {
@@ -7234,6 +7373,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7234
7373
  end: state.endNoBuffer,
7235
7374
  endBuffered: state.endBuffered,
7236
7375
  getAverageItemSizes: () => getAverageItemSizes(state),
7376
+ indexByKey: (key) => state.indexByKey.get(key),
7237
7377
  isAtEnd: peek$(ctx, "isAtEnd"),
7238
7378
  isAtStart: peek$(ctx, "isAtStart"),
7239
7379
  isEndReached: state.isEndReached,
@@ -7281,9 +7421,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7281
7421
  resolve,
7282
7422
  token
7283
7423
  };
7284
- if (scheduleImperativeScrollCommit) {
7285
- scheduleImperativeScrollCommit();
7286
- } else {
7424
+ scheduleImperativeScrollCommit == null ? void 0 : scheduleImperativeScrollCommit();
7425
+ supersedeInitialScroll(ctx);
7426
+ if (!scheduleImperativeScrollCommit) {
7287
7427
  (_a3 = state.runPendingScrollToEnd) == null ? void 0 : _a3.call(state);
7288
7428
  }
7289
7429
  }),
@@ -7537,7 +7677,7 @@ var LegendList = typedMemo(
7537
7677
  })
7538
7678
  );
7539
7679
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
7540
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
7680
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
7541
7681
  const noopOnScroll = useCallback((_event) => {
7542
7682
  }, []);
7543
7683
  if (props.recycleItems === void 0) {
@@ -7613,9 +7753,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7613
7753
  ...rest
7614
7754
  } = props;
7615
7755
  const animatedPropsInternal = props.animatedPropsInternal;
7756
+ const anchoredEndSpaceOwner = (_a3 = props.anchoredEndSpaceOwnerInternal) != null ? _a3 : "list";
7616
7757
  const positionComponentInternal = props.positionComponentInternal;
7617
7758
  const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
7618
7759
  const {
7760
+ anchoredEndSpaceOwnerInternal: _anchoredEndSpaceOwnerInternal,
7619
7761
  positionComponentInternal: _positionComponentInternal,
7620
7762
  stickyPositionComponentInternal: _stickyPositionComponentInternal,
7621
7763
  ...restProps
@@ -7637,6 +7779,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7637
7779
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
7638
7780
  const stylePaddingLeftState = extractPadding(style, contentContainerStyle, "Left");
7639
7781
  const stylePaddingRightState = extractPadding(style, contentContainerStyle, "Right");
7782
+ const stylePaddingEndState = getStylePaddingEnd({
7783
+ horizontal,
7784
+ rtl,
7785
+ stylePaddingBottom: stylePaddingBottomState,
7786
+ stylePaddingLeft: stylePaddingLeftState,
7787
+ stylePaddingRight: stylePaddingRightState
7788
+ });
7640
7789
  const maintainScrollAtEndConfig = normalizeMaintainScrollAtEnd(maintainScrollAtEnd);
7641
7790
  const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
7642
7791
  maintainVisibleContentPositionProp
@@ -7649,13 +7798,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7649
7798
  const initialScrollProp = initialScrollAtEnd ? {
7650
7799
  index: Math.max(0, dataProp.length - 1),
7651
7800
  preserveForBottomPadding: true,
7652
- viewOffset: -stylePaddingBottomState,
7801
+ viewOffset: -stylePaddingEndState,
7653
7802
  viewPosition: 1
7654
7803
  } : hasInitialScrollIndex ? typeof initialScrollIndexProp === "object" ? {
7655
- index: (_a3 = initialScrollIndexProp.index) != null ? _a3 : 0,
7804
+ index: (_b = initialScrollIndexProp.index) != null ? _b : 0,
7656
7805
  preserveForBottomPadding: initialScrollIndexProp.viewOffset === void 0 && initialScrollIndexProp.viewPosition === 1 ? true : void 0,
7657
- viewOffset: (_b = initialScrollIndexProp.viewOffset) != null ? _b : initialScrollIndexProp.viewPosition === 1 ? -stylePaddingBottomState : 0,
7658
- viewPosition: (_c = initialScrollIndexProp.viewPosition) != null ? _c : 0
7806
+ viewOffset: (_c = initialScrollIndexProp.viewOffset) != null ? _c : initialScrollIndexProp.viewPosition === 1 ? -stylePaddingEndState : 0,
7807
+ viewPosition: (_d = initialScrollIndexProp.viewPosition) != null ? _d : 0
7659
7808
  } : {
7660
7809
  index: initialScrollIndexProp != null ? initialScrollIndexProp : 0,
7661
7810
  viewOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : 0
@@ -7668,7 +7817,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7668
7817
  const [, scheduleImperativeScrollCommit] = React3.useReducer((value) => value + 1, 0);
7669
7818
  const ctx = useStateContext();
7670
7819
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
7671
- 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;
7820
+ 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;
7672
7821
  const nextScrollAxisGap = typeof scrollAxisGap === "number" && Number.isFinite(scrollAxisGap) ? scrollAxisGap : 0;
7673
7822
  const refScroller = useRef(null);
7674
7823
  const combinedRef = useCombinedRef(refScroller, refScrollView);
@@ -7683,8 +7832,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7683
7832
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex,
7684
7833
  alwaysRender == null ? void 0 : alwaysRender.top,
7685
7834
  alwaysRender == null ? void 0 : alwaysRender.bottom,
7686
- (_j = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _j.join(","),
7687
- (_k = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _k.join(","),
7835
+ (_k = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _k.join(","),
7836
+ (_l = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _l.join(","),
7688
7837
  dataProp,
7689
7838
  dataKey,
7690
7839
  dataVersion,
@@ -7697,7 +7846,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7697
7846
  if (!refState.current) {
7698
7847
  if (!ctx.state) {
7699
7848
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : { height: 0, width: 0 } )[horizontal ? "width" : "height"];
7700
- ctx.values.set("adaptiveRender", (_l = experimental_adaptiveRender == null ? void 0 : experimental_adaptiveRender.initialMode) != null ? _l : "normal");
7849
+ ctx.values.set("adaptiveRender", (_m = experimental_adaptiveRender == null ? void 0 : experimental_adaptiveRender.initialMode) != null ? _m : "normal");
7701
7850
  ctx.state = {
7702
7851
  averageSizes: {},
7703
7852
  columnSpans: [],
@@ -7716,6 +7865,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7716
7865
  endNoBuffer: -1,
7717
7866
  endReachedSnapshot: void 0,
7718
7867
  firstFullyOnScreenIndex: -1,
7868
+ freshDataTransitionEpoch: 0,
7719
7869
  hasHadNonEmptyData: dataProp.length > 0,
7720
7870
  idCache: [],
7721
7871
  idsInView: [],
@@ -7740,8 +7890,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7740
7890
  positions: [],
7741
7891
  props: {},
7742
7892
  queuedCalculateItemsInView: 0,
7743
- queuedFullDrawDistancePrewarm: void 0,
7744
7893
  refScroller: { current: null },
7894
+ scheduledWork: new ScheduledWork(),
7745
7895
  scroll: 0,
7746
7896
  scrollAdjustHandler: new ScrollAdjustHandler(ctx),
7747
7897
  scrollForNextCalculateItemsInView: void 0,
@@ -7759,8 +7909,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7759
7909
  startReachedSnapshot: void 0,
7760
7910
  stickyContainerPool: /* @__PURE__ */ new Set(),
7761
7911
  stickyContainers: /* @__PURE__ */ new Map(),
7762
- timeoutAdaptiveRender: void 0,
7763
- timeouts: /* @__PURE__ */ new Set(),
7764
7912
  totalSize: 0,
7765
7913
  viewabilityConfigCallbackPairs: void 0
7766
7914
  };
@@ -7782,13 +7930,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7782
7930
  const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
7783
7931
  ctx.scrollAxisGap = nextScrollAxisGap;
7784
7932
  state.didColumnsChange = numColumnsProp !== previousNumColumnsProp || didScrollAxisGapChange;
7785
- const previousDataLength = (_n = (_m = state.props.data) == null ? void 0 : _m.length) != null ? _n : 0;
7933
+ const previousDataLength = (_o = (_n = state.props.data) == null ? void 0 : _n.length) != null ? _o : 0;
7786
7934
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
7787
7935
  const didDataKeyChangeLocal = state.props.dataKey !== dataKey;
7788
7936
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
7789
7937
  const didDataChangeLocal = didDataKeyChangeLocal || didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
7790
7938
  const shouldResetFreshDataLayout = !isFirstLocal && didDataChangeLocal && state.hasHadNonEmptyData && (didDataKeyChangeLocal || previousDataLength === 0) && dataProp.length > 0;
7791
- if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_o = state.initialScroll) == null ? void 0 : _o.viewPosition) === 1 && state.props.data.length > 0) {
7939
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_p = state.initialScroll) == null ? void 0 : _p.viewPosition) === 1 && state.props.data.length > 0) {
7792
7940
  clearPreservedInitialScrollTarget(state);
7793
7941
  }
7794
7942
  if (didDataChangeLocal) {
@@ -7797,10 +7945,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7797
7945
  state.didDataChange = true;
7798
7946
  state.previousData = state.props.data;
7799
7947
  }
7948
+ if (shouldResetFreshDataLayout) {
7949
+ state.freshDataTransitionEpoch += 1;
7950
+ }
7800
7951
  const throttledOnScroll = useThrottledOnScroll(onScrollProp != null ? onScrollProp : noopOnScroll, scrollEventThrottle != null ? scrollEventThrottle : 0);
7801
7952
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? throttledOnScroll : onScrollProp;
7802
- const anchoredEndSpaceResolved = anchoredEndSpace ? { ...anchoredEndSpace, includeInEndInset: true } : anchoredEndSpace;
7803
- const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_p = state.props.anchoredEndSpace) == null ? void 0 : _p.anchorIndex) !== (anchoredEndSpaceResolved == null ? void 0 : anchoredEndSpaceResolved.anchorIndex);
7953
+ const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_q = state.props.anchoredEndSpace) == null ? void 0 : _q.anchorIndex) !== (anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex);
7804
7954
  state.props = {
7805
7955
  adaptiveRender: experimental_adaptiveRender,
7806
7956
  alignItemsAtEnd,
@@ -7808,7 +7958,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7808
7958
  alwaysRender,
7809
7959
  alwaysRenderIndicesArr: alwaysRenderIndices.arr,
7810
7960
  alwaysRenderIndicesSet: alwaysRenderIndices.set,
7811
- anchoredEndSpace: anchoredEndSpaceResolved,
7961
+ anchoredEndSpace,
7962
+ anchoredEndSpaceOwner,
7812
7963
  animatedProps: animatedPropsInternal,
7813
7964
  contentContainerAlignItems: contentContainerStyle.alignItems,
7814
7965
  contentInset,
@@ -7857,12 +8008,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7857
8008
  if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
7858
8009
  resetAdaptiveRender(ctx);
7859
8010
  }
7860
- if (shouldResetFreshDataLayout) {
7861
- resetInitialRenderState(ctx, {
7862
- resetInitialScroll: !!initialScrollProp,
7863
- resetLayout: true
7864
- });
7865
- }
7866
8011
  const memoizedLastItemKeys = useMemo(() => {
7867
8012
  if (!dataProp.length) return [];
7868
8013
  return Array.from(
@@ -7921,6 +8066,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7921
8066
  useDevChecks(props);
7922
8067
  }
7923
8068
  useLayoutEffect(() => {
8069
+ if (shouldResetFreshDataLayout) {
8070
+ resetInitialRenderState(ctx, {
8071
+ resetInitialScroll: !!initialScrollProp,
8072
+ resetLayout: true
8073
+ });
8074
+ }
7924
8075
  handleInitialScrollDataChange(ctx, {
7925
8076
  dataLength: dataProp.length,
7926
8077
  didDataChange: didDataChangeLocal,
@@ -7928,7 +8079,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7928
8079
  initialScrollAtEnd,
7929
8080
  latestInitialScroll: initialScrollProp,
7930
8081
  latestInitialScrollSessionKind: initialScrollUsesOffsetOnly ? "offset" : "bootstrap",
7931
- stylePaddingBottom: stylePaddingBottomState,
8082
+ stylePaddingEnd: stylePaddingEndState,
7932
8083
  useBootstrapInitialScroll: usesBootstrapInitialScroll
7933
8084
  });
7934
8085
  }, [
@@ -7937,7 +8088,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7937
8088
  didDataChangeLocal,
7938
8089
  shouldResetFreshDataLayout,
7939
8090
  initialScrollAtEnd,
7940
- stylePaddingBottomState,
8091
+ stylePaddingEndState,
7941
8092
  usesBootstrapInitialScroll
7942
8093
  ]);
7943
8094
  useLayoutEffect(() => {
@@ -7955,7 +8106,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7955
8106
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorMaxSize,
7956
8107
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorOffset,
7957
8108
  didAnchoredEndSpaceAnchorIndexChange,
7958
- numColumnsProp
8109
+ horizontal,
8110
+ numColumnsProp,
8111
+ rtl,
8112
+ stylePaddingBottomState,
8113
+ stylePaddingLeftState,
8114
+ stylePaddingRightState
7959
8115
  ]);
7960
8116
  useLayoutEffect(() => {
7961
8117
  const previousContentInsetEndAdjustment = previousContentInsetEndAdjustmentRef.current;
@@ -7971,10 +8127,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7971
8127
  dataLength: dataProp.length,
7972
8128
  footerSize: layout[horizontal ? "width" : "height"],
7973
8129
  initialScrollAtEnd,
7974
- stylePaddingBottom: stylePaddingBottomState
8130
+ stylePaddingEnd: stylePaddingEndState
7975
8131
  });
7976
8132
  },
7977
- [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingBottomState, usesBootstrapInitialScroll]
8133
+ [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingEndState, usesBootstrapInitialScroll]
7978
8134
  );
7979
8135
  const onLayoutChange = useCallback(
7980
8136
  (layout, fromLayoutEffect) => {
@@ -7991,7 +8147,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7991
8147
  }
7992
8148
  advanceCurrentInitialScrollSession(ctx);
7993
8149
  },
7994
- [dataProp.length, initialScrollAtEnd, stylePaddingBottomState, usesBootstrapInitialScroll]
8150
+ [dataProp.length, initialScrollAtEnd, stylePaddingEndState, usesBootstrapInitialScroll]
7995
8151
  );
7996
8152
  const { onLayout } = useOnLayoutSync({
7997
8153
  onLayoutChange,
@@ -8084,14 +8240,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8084
8240
  useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, scheduleImperativeScrollCommit), []);
8085
8241
  useEffect(() => {
8086
8242
  return () => {
8087
- if (state.queuedFullDrawDistancePrewarm !== void 0) {
8088
- cancelAnimationFrame(state.queuedFullDrawDistancePrewarm);
8089
- state.queuedFullDrawDistancePrewarm = void 0;
8090
- }
8091
- for (const timeout of state.timeouts) {
8092
- clearTimeout(timeout);
8093
- }
8094
- state.timeouts.clear();
8243
+ cancelImperativeScroll(state);
8244
+ state.scheduledWork.dispose();
8095
8245
  };
8096
8246
  }, [state]);
8097
8247
  useLayoutEffect(() => {
@@ -8133,6 +8283,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8133
8283
  canRender,
8134
8284
  contentContainerStyle,
8135
8285
  contentInset,
8286
+ freshDataTransitionEpoch: state.freshDataTransitionEpoch,
8136
8287
  getRenderedItem: fns.getRenderedItem,
8137
8288
  horizontal,
8138
8289
  initialContentOffset,
@@ -8148,7 +8299,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8148
8299
  onScroll: onScrollHandler,
8149
8300
  recycleItems,
8150
8301
  refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React3.cloneElement(refreshControlElement, {
8151
- progressViewOffset: ((_q = refreshControlElement.props.progressViewOffset) != null ? _q : 0) + stylePaddingTopState
8302
+ progressViewOffset: ((_r = refreshControlElement.props.progressViewOffset) != null ? _r : 0) + stylePaddingTopState
8152
8303
  }) : refreshControlElement : onRefresh && /* @__PURE__ */ React3.createElement(
8153
8304
  RefreshControl,
8154
8305
  {
@@ -8159,7 +8310,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8159
8310
  ),
8160
8311
  refScrollView: combinedRef,
8161
8312
  renderScrollComponent,
8162
- scrollAdjustHandler: (_r = refState.current) == null ? void 0 : _r.scrollAdjustHandler,
8313
+ scrollAdjustHandler: (_s = refState.current) == null ? void 0 : _s.scrollAdjustHandler,
8163
8314
  scrollEventThrottle: 0,
8164
8315
  snapToIndices,
8165
8316
  stickyHeaderIndices,