@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.
@@ -70,6 +70,12 @@ function isHorizontalRTL(state) {
70
70
  function isHorizontalRTLProps(props) {
71
71
  return !!(props == null ? void 0 : props.horizontal) && isRTLProps(props);
72
72
  }
73
+ function getStylePaddingEnd(props) {
74
+ if (!(props == null ? void 0 : props.horizontal)) {
75
+ return (props == null ? void 0 : props.stylePaddingBottom) || 0;
76
+ }
77
+ return (isHorizontalRTLProps(props) ? props.stylePaddingLeft : props.stylePaddingRight) || 0;
78
+ }
73
79
  function getLogicalHorizontalMaxOffset(state, contentWidth) {
74
80
  var _a3;
75
81
  return (_a3 = getHorizontalMaxOffset(state, contentWidth)) != null ? _a3 : 0;
@@ -190,6 +196,14 @@ function useStateContext() {
190
196
  return React3__namespace.useContext(ContextState);
191
197
  }
192
198
  function createSelectorFunctionsArr(ctx, signalNames) {
199
+ if (!ctx) {
200
+ const emptyValues = [];
201
+ return {
202
+ get: () => emptyValues,
203
+ subscribe: () => () => {
204
+ }
205
+ };
206
+ }
193
207
  let lastValues = [];
194
208
  let lastSignalValues = [];
195
209
  return {
@@ -296,7 +310,7 @@ function getContentInsetEndAdjustmentEnd(adjustment) {
296
310
  return Math.max(0, adjustment != null ? adjustment : 0);
297
311
  }
298
312
  function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
299
- var _a3, _b;
313
+ var _a3;
300
314
  const state = ctx.state;
301
315
  const { props } = state;
302
316
  const horizontal = props.horizontal;
@@ -307,8 +321,8 @@ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
307
321
  contentInsetEndAdjustmentOverride != null ? contentInsetEndAdjustmentOverride : props.contentInsetEndAdjustment
308
322
  );
309
323
  const anchoredEndSpaceSize = peek$(ctx, "anchoredEndSpaceSize");
310
- const anchoredEndInset = ((_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.includeInEndInset) && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
311
- const overrideInset = (_b = state.contentInsetOverride) != null ? _b : void 0;
324
+ const anchoredEndInset = props.anchoredEndSpace && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
325
+ const overrideInset = (_a3 = state.contentInsetOverride) != null ? _a3 : void 0;
312
326
  const adjustedBaseEndInset = baseEndInset + contentInsetEndAdjustment;
313
327
  if (overrideInset) {
314
328
  const mergedInset = { bottom: 0, left: 0, right: 0, ...baseInset, ...overrideInset };
@@ -324,14 +338,15 @@ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
324
338
  function getContentSize(ctx) {
325
339
  var _a3, _b;
326
340
  const { values, state } = ctx;
327
- const stylePaddingTop = values.get("stylePaddingTop") || 0;
328
- const stylePaddingBottom = state.props.stylePaddingBottom || 0;
341
+ const stylePaddingStart = state.props.horizontal ? state.props.stylePaddingLeft || 0 : values.get("stylePaddingTop") || 0;
342
+ const stylePaddingEnd = state.props.horizontal ? state.props.stylePaddingRight || 0 : state.props.stylePaddingBottom || 0;
329
343
  const alignItemsAtEndPadding = values.get("alignItemsAtEndPadding") || 0;
330
344
  const headerSize = values.get("headerSize") || 0;
331
345
  const footerSize = values.get("footerSize") || 0;
332
- const contentInsetBottom = getContentInsetEnd(ctx);
346
+ const contentInsetEnd = getContentInsetEnd(ctx);
333
347
  const totalSize = (_b = (_a3 = state.pendingTotalSize) != null ? _a3 : state.totalSize) != null ? _b : values.get("totalSize");
334
- return headerSize + footerSize + totalSize + stylePaddingTop + alignItemsAtEndPadding + stylePaddingBottom + (contentInsetBottom || 0);
348
+ const layoutSize = Math.max(0, totalSize - (state.props.data.length > 0 ? ctx.scrollAxisGap : 0));
349
+ return headerSize + footerSize + layoutSize + stylePaddingStart + alignItemsAtEndPadding + stylePaddingEnd + (contentInsetEnd || 0);
335
350
  }
336
351
 
337
352
  // src/components/DebugView.tsx
@@ -782,13 +797,7 @@ var DEFAULT_WEB_ADAPTIVE_RENDER_ENTER_VELOCITY = 6;
782
797
  var DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_VELOCITY = 3;
783
798
  var DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_DELAY = 250;
784
799
  function clearAdaptiveRenderExitTimeout(ctx) {
785
- const state = ctx.state;
786
- const previousTimeout = state.timeoutAdaptiveRender;
787
- if (previousTimeout !== void 0) {
788
- clearTimeout(previousTimeout);
789
- state.timeouts.delete(previousTimeout);
790
- state.timeoutAdaptiveRender = void 0;
791
- }
800
+ ctx.state.scheduledWork.cancel("adaptiveRender");
792
801
  }
793
802
  function scheduleAdaptiveRenderExit(ctx, exitDelay) {
794
803
  const state = ctx.state;
@@ -796,13 +805,7 @@ function scheduleAdaptiveRenderExit(ctx, exitDelay) {
796
805
  if (exitDelay <= 0) {
797
806
  setAdaptiveRender(ctx, "normal", "scroll");
798
807
  } else {
799
- const timeout = setTimeout(() => {
800
- state.timeouts.delete(timeout);
801
- state.timeoutAdaptiveRender = void 0;
802
- setAdaptiveRender(ctx, "normal", "scroll");
803
- }, exitDelay);
804
- state.timeoutAdaptiveRender = timeout;
805
- state.timeouts.add(timeout);
808
+ state.scheduledWork.timeout(() => setAdaptiveRender(ctx, "normal", "scroll"), exitDelay, "adaptiveRender");
806
809
  }
807
810
  }
808
811
  function setAdaptiveRender(ctx, mode, reason) {
@@ -833,7 +836,7 @@ function updateAdaptiveRender(ctx, scrollVelocity, options) {
833
836
  const exitDelay = (_c = adaptiveRender.exitDelay) != null ? _c : DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_DELAY ;
834
837
  const threshold = currentMode === "light" ? exitVelocity : enterVelocity;
835
838
  const nextMode = (options == null ? void 0 : options.forceLight) || Math.abs(scrollVelocity) > threshold ? "light" : "normal";
836
- const previousMode = state.timeoutAdaptiveRender !== void 0 ? "normal" : currentMode;
839
+ const previousMode = state.scheduledWork.has("adaptiveRender") ? "normal" : currentMode;
837
840
  if (nextMode !== previousMode) {
838
841
  if (nextMode === "light") {
839
842
  setAdaptiveRender(ctx, "light", "scroll");
@@ -860,14 +863,13 @@ function getEffectiveDrawDistance(ctx, mode) {
860
863
  }
861
864
  function scheduleFullDrawDistancePrewarm(ctx) {
862
865
  const { state } = ctx;
863
- if (state.props.drawDistance <= INITIAL_DRAW_DISTANCE || state.queuedFullDrawDistancePrewarm !== void 0) {
866
+ if (state.props.drawDistance <= INITIAL_DRAW_DISTANCE || state.scheduledWork.has("fullDrawDistancePrewarm")) {
864
867
  return;
865
868
  }
866
- state.queuedFullDrawDistancePrewarm = requestAnimationFrame(() => {
869
+ state.scheduledWork.frame(() => {
867
870
  var _a3;
868
- state.queuedFullDrawDistancePrewarm = void 0;
869
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
870
- });
871
+ return (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
872
+ }, "fullDrawDistancePrewarm");
871
873
  }
872
874
 
873
875
  // src/utils/setInitialRenderState.ts
@@ -925,10 +927,7 @@ function syncInitialScrollOffset(state, offset) {
925
927
  state.scrollPrev = offset;
926
928
  }
927
929
  function clearPreservedInitialScrollTargetTimeout(state) {
928
- if (state.timeoutPreservedInitialScrollClear !== void 0) {
929
- clearTimeout(state.timeoutPreservedInitialScrollClear);
930
- state.timeoutPreservedInitialScrollClear = void 0;
931
- }
930
+ state.scheduledWork.cancel("preservedInitialScroll");
932
931
  }
933
932
  function clearPreservedInitialScrollTarget(state) {
934
933
  clearPreservedInitialScrollTargetTimeout(state);
@@ -957,14 +956,17 @@ function finishInitialScroll(ctx, options) {
957
956
  setInitialScrollSession(state);
958
957
  clearPreservedInitialScrollTargetTimeout(state);
959
958
  if (options == null ? void 0 : options.schedulePreservedTargetClear) {
960
- state.timeoutPreservedInitialScrollClear = setTimeout(() => {
961
- var _a5;
962
- state.timeoutPreservedInitialScrollClear = void 0;
963
- if (!state.didFinishInitialScroll || ((_a5 = state.scrollingTo) == null ? void 0 : _a5.isInitialScroll) || !state.initialScroll) {
964
- return;
965
- }
966
- clearPreservedInitialScrollTarget(state);
967
- }, PRESERVED_INITIAL_SCROLL_FALLBACK_CLEAR_DELAY_MS);
959
+ state.scheduledWork.timeout(
960
+ () => {
961
+ var _a5;
962
+ if (!state.didFinishInitialScroll || ((_a5 = state.scrollingTo) == null ? void 0 : _a5.isInitialScroll) || !state.initialScroll) {
963
+ return;
964
+ }
965
+ clearPreservedInitialScrollTarget(state);
966
+ },
967
+ PRESERVED_INITIAL_SCROLL_FALLBACK_CLEAR_DELAY_MS,
968
+ "preservedInitialScroll"
969
+ );
968
970
  }
969
971
  } else {
970
972
  clearPreservedInitialScrollTarget(state);
@@ -991,9 +993,11 @@ function calculateOffsetForIndex(ctx, index) {
991
993
  return index !== void 0 ? state.positions[index] || 0 : 0;
992
994
  }
993
995
 
994
- // src/core/getTopOffsetAdjustment.ts
995
- function getTopOffsetAdjustment(ctx) {
996
- return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
996
+ // src/core/getStartOffsetAdjustment.ts
997
+ function getStartOffsetAdjustment(ctx) {
998
+ const { state } = ctx;
999
+ const stylePaddingStart = state.props.horizontal ? (isHorizontalRTL(state) ? state.props.stylePaddingRight : state.props.stylePaddingLeft) || 0 : peek$(ctx, "stylePaddingTop") || 0;
1000
+ return stylePaddingStart + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
997
1001
  }
998
1002
 
999
1003
  // src/utils/getId.ts
@@ -1204,9 +1208,9 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1204
1208
  offset -= viewOffset;
1205
1209
  }
1206
1210
  if (index !== void 0) {
1207
- const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
1208
- if (topOffsetAdjustment) {
1209
- offset += topOffsetAdjustment;
1211
+ const startOffsetAdjustment = getStartOffsetAdjustment(ctx);
1212
+ if (startOffsetAdjustment) {
1213
+ offset += startOffsetAdjustment;
1210
1214
  }
1211
1215
  }
1212
1216
  if (viewPosition !== void 0 && index !== void 0) {
@@ -1216,7 +1220,8 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1216
1220
  }
1217
1221
  const isOutOfBounds = index < 0 || index >= dataLength;
1218
1222
  const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
1219
- const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1223
+ const measuredItemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1224
+ const itemSize = Math.max(0, measuredItemSize - (isOutOfBounds ? 0 : ctx.scrollAxisGap));
1220
1225
  const trailingInset = getContentInsetEnd(ctx);
1221
1226
  offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1222
1227
  if (!isOutOfBounds && index === state.props.data.length - 1) {
@@ -1243,11 +1248,35 @@ function clampScrollOffset(ctx, offset, scrollTarget) {
1243
1248
  return clampedOffset;
1244
1249
  }
1245
1250
 
1251
+ // src/core/cancelImperativeScroll.ts
1252
+ function cancelScrollCompletionChecks({ scheduledWork }) {
1253
+ scheduledWork.cancel("checkFinishedScrollFrame");
1254
+ scheduledWork.cancel("checkFinishedScrollRetryFrame");
1255
+ scheduledWork.cancel("checkFinishedScrollFallback");
1256
+ scheduledWork.cancel("platformScrollCompletion");
1257
+ }
1258
+ function settlePendingImperativeScroll(state) {
1259
+ var _a3, _b;
1260
+ const resolvePendingScroll = (_b = state.pendingScrollResolve) != null ? _b : (_a3 = state.pendingScrollToEnd) == null ? void 0 : _a3.resolve;
1261
+ state.pendingScrollResolve = void 0;
1262
+ state.pendingScrollToEnd = void 0;
1263
+ resolvePendingScroll == null ? void 0 : resolvePendingScroll();
1264
+ }
1265
+ function cancelImperativeScroll(state) {
1266
+ cancelScrollCompletionChecks(state);
1267
+ state.scheduledWork.cancel("imperativeScrollReady");
1268
+ state.runPendingScrollToEnd = void 0;
1269
+ state.scrollingTo = void 0;
1270
+ state.scrollTargetPinnedRange = void 0;
1271
+ settlePendingImperativeScroll(state);
1272
+ }
1273
+
1246
1274
  // src/core/finishScrollTo.ts
1247
1275
  function finishScrollTo(ctx) {
1248
1276
  var _a3, _b;
1249
1277
  const state = ctx.state;
1250
1278
  if (state == null ? void 0 : state.scrollingTo) {
1279
+ cancelScrollCompletionChecks(state);
1251
1280
  const resolvePendingScroll = state.pendingScrollResolve;
1252
1281
  state.pendingScrollResolve = void 0;
1253
1282
  const scrollingTo = state.scrollingTo;
@@ -1289,6 +1318,7 @@ function doScrollTo(ctx, params) {
1289
1318
  var _a3, _b;
1290
1319
  const state = ctx.state;
1291
1320
  const { animated, horizontal, offset } = params;
1321
+ state.scheduledWork.cancel("platformScrollCompletion");
1292
1322
  const scroller = state.refScroller.current;
1293
1323
  const node = scroller == null ? void 0 : scroller.getScrollableNode();
1294
1324
  if (!scroller || !node) {
@@ -1309,9 +1339,16 @@ function doScrollTo(ctx, params) {
1309
1339
  });
1310
1340
  } else {
1311
1341
  state.scroll = offset;
1312
- setTimeout(() => {
1313
- finishScrollTo(ctx);
1314
- }, 100);
1342
+ const targetToken = state.scrollingTo;
1343
+ state.scheduledWork.timeout(
1344
+ () => {
1345
+ if (targetToken === state.scrollingTo) {
1346
+ finishScrollTo(ctx);
1347
+ }
1348
+ },
1349
+ 100,
1350
+ "platformScrollCompletion"
1351
+ );
1315
1352
  }
1316
1353
  }
1317
1354
  function listenForScrollEnd(ctx, params) {
@@ -1323,23 +1360,28 @@ function listenForScrollEnd(ctx, params) {
1323
1360
  const supportsScrollEnd = "onscrollend" in target;
1324
1361
  let idleTimeout;
1325
1362
  let settled = false;
1326
- const targetToken = ctx.state.scrollingTo;
1363
+ const { scheduledWork, scrollingTo: targetToken } = ctx.state;
1327
1364
  const maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1328
1365
  const cleanup = () => {
1329
1366
  target.removeEventListener("scroll", onScroll2);
1330
1367
  if (supportsScrollEnd) {
1331
1368
  target.removeEventListener("scrollend", onScrollEnd);
1332
1369
  }
1333
- if (idleTimeout) {
1370
+ if (idleTimeout !== void 0) {
1334
1371
  clearTimeout(idleTimeout);
1335
1372
  }
1336
1373
  clearTimeout(maxTimeout);
1337
1374
  };
1375
+ const cancel = () => {
1376
+ if (!settled) {
1377
+ settled = true;
1378
+ cleanup();
1379
+ }
1380
+ };
1338
1381
  const finish = (reason) => {
1339
1382
  if (settled) return;
1340
1383
  if (targetToken !== ctx.state.scrollingTo) {
1341
- settled = true;
1342
- cleanup();
1384
+ scheduledWork.cancel("platformScrollCompletion");
1343
1385
  return;
1344
1386
  }
1345
1387
  const currentOffset = readOffset();
@@ -1347,12 +1389,11 @@ function listenForScrollEnd(ctx, params) {
1347
1389
  if (reason === "scrollend" && !isNearTarget) {
1348
1390
  return;
1349
1391
  }
1350
- settled = true;
1351
- cleanup();
1392
+ scheduledWork.cancel("platformScrollCompletion");
1352
1393
  finishScrollTo(ctx);
1353
1394
  };
1354
1395
  const onScroll2 = () => {
1355
- if (idleTimeout) {
1396
+ if (idleTimeout !== void 0) {
1356
1397
  clearTimeout(idleTimeout);
1357
1398
  }
1358
1399
  idleTimeout = setTimeout(() => finish("idle"), SCROLL_END_IDLE_MS);
@@ -1364,6 +1405,7 @@ function listenForScrollEnd(ctx, params) {
1364
1405
  } else {
1365
1406
  idleTimeout = setTimeout(() => finish("idle"), SMOOTH_SCROLL_DURATION_MS);
1366
1407
  }
1408
+ scheduledWork.register("platformScrollCompletion", cancel);
1367
1409
  }
1368
1410
 
1369
1411
  // src/core/doMaintainScrollAtEnd.ts
@@ -1390,9 +1432,12 @@ function doMaintainScrollAtEnd(ctx) {
1390
1432
  if (!state.maintainingScrollAtEnd) {
1391
1433
  const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
1392
1434
  const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
1435
+ const scrollAtRequest = state.scroll;
1393
1436
  state.maintainingScrollAtEnd = pendingState;
1394
1437
  requestAnimationFrame(() => {
1395
- if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
1438
+ const isStillWithinThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
1439
+ const didScrollSinceRequest = state.scroll !== scrollAtRequest;
1440
+ if (isStillWithinThreshold || !didScrollSinceRequest) {
1396
1441
  state.maintainingScrollAtEnd = activeState;
1397
1442
  const scroller = refScroller.current;
1398
1443
  if (state.props.horizontal && isHorizontalRTL(state)) {
@@ -1422,6 +1467,7 @@ function doMaintainScrollAtEnd(ctx) {
1422
1467
  );
1423
1468
  } else if (state.maintainingScrollAtEnd === pendingState) {
1424
1469
  state.maintainingScrollAtEnd = void 0;
1470
+ state.pendingMaintainScrollAtEnd = false;
1425
1471
  }
1426
1472
  });
1427
1473
  } else {
@@ -1874,10 +1920,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
1874
1920
  state.mvcpAnchorLock = void 0;
1875
1921
  state.pendingNativeMVCPAdjust = void 0;
1876
1922
  state.userScrollAnchorReset = { keys: /* @__PURE__ */ new Set() };
1877
- if (state.queuedMVCPRecalculate !== void 0) {
1878
- cancelAnimationFrame(state.queuedMVCPRecalculate);
1879
- state.queuedMVCPRecalculate = void 0;
1880
- }
1923
+ state.scheduledWork.cancel("mvcpRecalculate");
1881
1924
  ReactDOM.flushSync(runCalculateItems);
1882
1925
  scheduleFullDrawDistancePrewarm(ctx);
1883
1926
  } else {
@@ -2022,12 +2065,7 @@ function scrollTo(ctx, params) {
2022
2065
  const {
2023
2066
  props: { horizontal }
2024
2067
  } = state;
2025
- if (state.animFrameCheckFinishedScroll) {
2026
- cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
2027
- }
2028
- if (state.timeoutCheckFinishedScrollFallback) {
2029
- clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
2030
- }
2068
+ cancelScrollCompletionChecks(state);
2031
2069
  const requestedOffset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
2032
2070
  const shouldPreserveRawInitialOffsetRequest = !!isInitialScroll && ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset";
2033
2071
  const targetOffset = clampScrollOffset(ctx, requestedOffset, scrollTarget);
@@ -2132,10 +2170,7 @@ function setInitialScrollTarget(ctx, target, options) {
2132
2170
  var _a3;
2133
2171
  const { state } = ctx;
2134
2172
  state.clearPreservedInitialScrollOnNextFinish = void 0;
2135
- if (state.timeoutPreservedInitialScrollClear !== void 0) {
2136
- clearTimeout(state.timeoutPreservedInitialScrollClear);
2137
- state.timeoutPreservedInitialScrollClear = void 0;
2138
- }
2173
+ state.scheduledWork.cancel("preservedInitialScroll");
2139
2174
  state.initialScroll = target;
2140
2175
  if (options == null ? void 0 : options.resetDidFinish) {
2141
2176
  resetInitialRenderState(ctx, { resetInitialScroll: true });
@@ -2428,13 +2463,13 @@ function rearmBootstrapInitialScroll(ctx, options) {
2428
2463
  queueBootstrapInitialScrollReevaluation(ctx.state);
2429
2464
  }
2430
2465
  function createInitialScrollAtEndTarget(options) {
2431
- const { dataLength, footerSize, preserveForFooterLayout, stylePaddingBottom } = options;
2466
+ const { dataLength, footerSize, preserveForFooterLayout, stylePaddingEnd } = options;
2432
2467
  return {
2433
2468
  contentOffset: void 0,
2434
2469
  index: Math.max(0, dataLength - 1),
2435
2470
  preserveForBottomPadding: true,
2436
2471
  preserveForFooterLayout,
2437
- viewOffset: -stylePaddingBottom - footerSize,
2472
+ viewOffset: -stylePaddingEnd - footerSize,
2438
2473
  viewPosition: 1
2439
2474
  };
2440
2475
  }
@@ -2448,7 +2483,7 @@ function isRetargetableBottomAlignedInitialScrollTarget(target) {
2448
2483
  return !!(target && target.viewPosition === 1 && (shouldPreserveInitialScrollForBottomPadding(target) || shouldPreserveInitialScrollForFooterLayout(target)));
2449
2484
  }
2450
2485
  function createRetargetedBottomAlignedInitialScroll(options) {
2451
- const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom, target } = options;
2486
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd, target } = options;
2452
2487
  const preserveForFooterLayout = shouldPreserveInitialScrollForFooterLayout(target);
2453
2488
  return {
2454
2489
  ...target,
@@ -2456,7 +2491,7 @@ function createRetargetedBottomAlignedInitialScroll(options) {
2456
2491
  index: initialScrollAtEnd ? Math.max(0, dataLength - 1) : target.index,
2457
2492
  preserveForBottomPadding: true,
2458
2493
  preserveForFooterLayout,
2459
- viewOffset: -stylePaddingBottom - (preserveForFooterLayout ? footerSize : 0),
2494
+ viewOffset: -stylePaddingEnd - (preserveForFooterLayout ? footerSize : 0),
2460
2495
  viewPosition: 1
2461
2496
  };
2462
2497
  }
@@ -2464,7 +2499,7 @@ function areEquivalentBootstrapInitialScrollTargets(current, next) {
2464
2499
  return current.index === next.index && current.preserveForBottomPadding === next.preserveForBottomPadding && current.preserveForFooterLayout === next.preserveForFooterLayout && current.viewOffset === next.viewOffset && current.viewPosition === next.viewPosition;
2465
2500
  }
2466
2501
  function clearPendingInitialScrollFooterLayout(ctx, options) {
2467
- const { dataLength, stylePaddingBottom, target } = options;
2502
+ const { dataLength, stylePaddingEnd, target } = options;
2468
2503
  if (!shouldPreserveInitialScrollForFooterLayout(target)) {
2469
2504
  return;
2470
2505
  }
@@ -2472,7 +2507,7 @@ function clearPendingInitialScrollFooterLayout(ctx, options) {
2472
2507
  dataLength,
2473
2508
  footerSize: 0,
2474
2509
  preserveForFooterLayout: void 0,
2475
- stylePaddingBottom
2510
+ stylePaddingEnd
2476
2511
  });
2477
2512
  setInitialScrollTarget(ctx, clearedFooterTarget);
2478
2513
  }
@@ -2533,7 +2568,7 @@ function schedulePreservedEndAnchorCorrectionFrame(ctx, correction) {
2533
2568
  });
2534
2569
  }
2535
2570
  function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2536
- var _a3, _b;
2571
+ var _a3;
2537
2572
  const state = ctx.state;
2538
2573
  const initialScroll = state.initialScroll;
2539
2574
  if (!state.didFinishInitialScroll || ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) || (initialScroll == null ? void 0 : initialScroll.viewPosition) !== 1 || state.preservedEndAnchorCorrection) {
@@ -2545,7 +2580,7 @@ function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2545
2580
  if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
2546
2581
  clearPendingInitialScrollFooterLayout(ctx, {
2547
2582
  dataLength: state.props.data.length,
2548
- stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
2583
+ stylePaddingEnd: getStylePaddingEnd(state.props),
2549
2584
  target: initialScroll
2550
2585
  });
2551
2586
  } else {
@@ -2582,7 +2617,7 @@ function startBootstrapInitialScrollOnMount(ctx, options) {
2582
2617
  }
2583
2618
  }
2584
2619
  function handleBootstrapInitialScrollDataChange(ctx, options) {
2585
- const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingBottom } = options;
2620
+ const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingEnd } = options;
2586
2621
  const state = ctx.state;
2587
2622
  const initialScroll = state.initialScroll;
2588
2623
  if (isOffsetInitialScrollSession(state) || !initialScroll) {
@@ -2604,18 +2639,18 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2604
2639
  dataLength,
2605
2640
  footerSize: peek$(ctx, "footerSize") || 0,
2606
2641
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2607
- stylePaddingBottom
2642
+ stylePaddingEnd
2608
2643
  }) : createRetargetedBottomAlignedInitialScroll({
2609
2644
  dataLength,
2610
2645
  footerSize: peek$(ctx, "footerSize") || 0,
2611
2646
  initialScrollAtEnd,
2612
- stylePaddingBottom,
2647
+ stylePaddingEnd,
2613
2648
  target: initialScroll
2614
2649
  });
2615
2650
  if (!shouldResetDidFinish && didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2616
2651
  clearPendingInitialScrollFooterLayout(ctx, {
2617
2652
  dataLength,
2618
- stylePaddingBottom,
2653
+ stylePaddingEnd,
2619
2654
  target: initialScroll
2620
2655
  });
2621
2656
  return;
@@ -2647,7 +2682,7 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2647
2682
  }
2648
2683
  }
2649
2684
  function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2650
- const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom } = options;
2685
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd } = options;
2651
2686
  const state = ctx.state;
2652
2687
  if (!initialScrollAtEnd) {
2653
2688
  return;
@@ -2663,7 +2698,7 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2663
2698
  if (didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2664
2699
  clearPendingInitialScrollFooterLayout(ctx, {
2665
2700
  dataLength,
2666
- stylePaddingBottom,
2701
+ stylePaddingEnd,
2667
2702
  target: initialScroll
2668
2703
  });
2669
2704
  } else {
@@ -2671,13 +2706,13 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2671
2706
  dataLength,
2672
2707
  footerSize,
2673
2708
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2674
- stylePaddingBottom
2709
+ stylePaddingEnd
2675
2710
  });
2676
2711
  const didTargetChange = initialScroll.index !== updatedInitialScroll.index || initialScroll.viewPosition !== updatedInitialScroll.viewPosition || initialScroll.viewOffset !== updatedInitialScroll.viewOffset;
2677
2712
  if (!didTargetChange) {
2678
2713
  clearPendingInitialScrollFooterLayout(ctx, {
2679
2714
  dataLength,
2680
- stylePaddingBottom,
2715
+ stylePaddingEnd,
2681
2716
  target: initialScroll
2682
2717
  });
2683
2718
  } else {
@@ -2885,7 +2920,7 @@ function checkFinishedScroll(ctx, options) {
2885
2920
  return;
2886
2921
  }
2887
2922
  }
2888
- ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
2923
+ ctx.state.scheduledWork.frame(() => checkFinishedScrollFrame(ctx), "checkFinishedScrollFrame");
2889
2924
  }
2890
2925
  function hasScrollCompletionOwnership(state, options) {
2891
2926
  const { clampedTargetOffset, scrollingTo } = options;
@@ -2955,7 +2990,6 @@ function checkFinishedScrollFrame(ctx) {
2955
2990
  return;
2956
2991
  }
2957
2992
  const { state } = ctx;
2958
- state.animFrameCheckFinishedScroll = void 0;
2959
2993
  const completionState = getResolvedScrollCompletionState(ctx, scrollingTo);
2960
2994
  if (completionState.isAtResolvedTarget && hasScrollCompletionOwnership(state, {
2961
2995
  clampedTargetOffset: completionState.clampedTargetOffset,
@@ -2974,47 +3008,47 @@ function scrollToFallbackOffset(ctx, offset) {
2974
3008
  }
2975
3009
  function checkFinishedScrollFallback(ctx) {
2976
3010
  const state = ctx.state;
3011
+ if (state.scheduledWork.has("checkFinishedScrollFallback")) {
3012
+ return;
3013
+ }
2977
3014
  const scrollingTo = state.scrollingTo;
2978
3015
  const shouldFinishInitialZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
2979
3016
  const silentInitialDispatch = isSilentInitialDispatch(state, scrollingTo);
2980
3017
  const canFinishInitialWithoutNativeProgress = scrollingTo !== void 0 ? shouldFinishInitialScrollWithoutNativeProgress(state, scrollingTo) : false;
2981
3018
  const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) && !shouldFinishInitialZeroTarget && !canFinishInitialWithoutNativeProgress || !state.didContainersLayout;
2982
3019
  const initialDelay = shouldFinishInitialZeroTarget || canFinishInitialWithoutNativeProgress ? 0 : silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : slowTimeout ? 500 : 100;
2983
- state.timeoutCheckFinishedScrollFallback = setTimeout(() => {
2984
- let numChecks = 0;
2985
- const scheduleFallbackCheck = (delay) => {
2986
- state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, delay);
2987
- };
2988
- const checkHasScrolled = () => {
2989
- var _c, _d;
2990
- state.timeoutCheckFinishedScrollFallback = void 0;
2991
- const isStillScrollingTo = state.scrollingTo;
2992
- if (isStillScrollingTo) {
2993
- numChecks++;
2994
- const isNativeInitialPending = isNativeInitialNonZeroTarget(state) && !state.hasScrolled;
2995
- const maxChecks = silentInitialDispatch ? 5 : isNativeInitialPending ? INITIAL_SCROLL_MAX_FALLBACK_CHECKS : 5;
2996
- const shouldFinishZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
2997
- const canFinishInitialScrollWithoutNativeProgress = shouldFinishInitialScrollWithoutNativeProgress(
2998
- state,
2999
- isStillScrollingTo
3000
- );
3001
- const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
3002
- const canFinishAfterSilentNativeDispatch = Platform.OS === "android";
3003
- const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
3004
- const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
3005
- if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
3006
- finishScrollTo(ctx);
3007
- } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
3008
- const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
3009
- scrollToFallbackOffset(ctx, targetOffset);
3010
- scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
3011
- } else {
3012
- scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
3013
- }
3020
+ let numChecks = 0;
3021
+ const scheduleFallbackCheck = (delay) => {
3022
+ state.scheduledWork.timeout(checkHasScrolled, delay, "checkFinishedScrollFallback");
3023
+ };
3024
+ const checkHasScrolled = () => {
3025
+ var _c, _d;
3026
+ const isStillScrollingTo = state.scrollingTo;
3027
+ if (isStillScrollingTo) {
3028
+ numChecks++;
3029
+ const isNativeInitialPending = isNativeInitialNonZeroTarget(state) && !state.hasScrolled;
3030
+ const maxChecks = silentInitialDispatch ? 5 : isNativeInitialPending ? INITIAL_SCROLL_MAX_FALLBACK_CHECKS : 5;
3031
+ const shouldFinishZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
3032
+ const canFinishInitialScrollWithoutNativeProgress = shouldFinishInitialScrollWithoutNativeProgress(
3033
+ state,
3034
+ isStillScrollingTo
3035
+ );
3036
+ const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
3037
+ const canFinishAfterSilentNativeDispatch = Platform.OS === "android";
3038
+ const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
3039
+ const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
3040
+ if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
3041
+ finishScrollTo(ctx);
3042
+ } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
3043
+ const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
3044
+ scrollToFallbackOffset(ctx, targetOffset);
3045
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
3046
+ } else {
3047
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
3014
3048
  }
3015
- };
3016
- checkHasScrolled();
3017
- }, initialDelay);
3049
+ }
3050
+ };
3051
+ scheduleFallbackCheck(initialDelay);
3018
3052
  }
3019
3053
 
3020
3054
  // src/core/initialScrollLifecycle.ts
@@ -3090,7 +3124,7 @@ function handleInitialScrollDataChange(ctx, options) {
3090
3124
  initialScrollAtEnd,
3091
3125
  latestInitialScroll,
3092
3126
  latestInitialScrollSessionKind,
3093
- stylePaddingBottom,
3127
+ stylePaddingEnd,
3094
3128
  useBootstrapInitialScroll
3095
3129
  } = options;
3096
3130
  const state = ctx.state;
@@ -3120,7 +3154,7 @@ function handleInitialScrollDataChange(ctx, options) {
3120
3154
  didDataChange,
3121
3155
  initialScrollAtEnd,
3122
3156
  previousDataLength: previousInitialScrollDataLength,
3123
- stylePaddingBottom
3157
+ stylePaddingEnd
3124
3158
  });
3125
3159
  return;
3126
3160
  }
@@ -3590,7 +3624,6 @@ function setupViewability(props) {
3590
3624
  }
3591
3625
  function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end, startBuffered = start, endBuffered = end) {
3592
3626
  const {
3593
- timeouts,
3594
3627
  props: { data }
3595
3628
  } = state;
3596
3629
  for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
@@ -3600,11 +3633,10 @@ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollS
3600
3633
  viewabilityState.startBuffered = startBuffered;
3601
3634
  viewabilityState.endBuffered = endBuffered;
3602
3635
  if (viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime) {
3603
- const timer = setTimeout(() => {
3604
- timeouts.delete(timer);
3605
- updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
3606
- }, viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime);
3607
- timeouts.add(timer);
3636
+ state.scheduledWork.timeout(
3637
+ () => updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize),
3638
+ viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime
3639
+ );
3608
3640
  } else {
3609
3641
  updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
3610
3642
  }
@@ -3963,20 +3995,15 @@ function getProjectedBufferAdjustment(scrollVelocity, trailingBuffer) {
3963
3995
  }
3964
3996
  function scheduleRenderRangeProjectionSettle(ctx) {
3965
3997
  const state = ctx.state;
3966
- const previousTimeout = state.timeoutRenderRangeProjectionSettle;
3967
- if (previousTimeout !== void 0) {
3968
- clearTimeout(previousTimeout);
3969
- state.timeouts.delete(previousTimeout);
3970
- }
3971
- const timeout = setTimeout(() => {
3972
- var _a3;
3973
- state.timeoutRenderRangeProjectionSettle = void 0;
3974
- state.timeouts.delete(timeout);
3975
- state.scrollHistory.length = 0;
3976
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
3977
- }, RENDER_RANGE_PROJECTION_SETTLE_DELAY);
3978
- state.timeoutRenderRangeProjectionSettle = timeout;
3979
- state.timeouts.add(timeout);
3998
+ state.scheduledWork.timeout(
3999
+ () => {
4000
+ var _a3;
4001
+ state.scrollHistory.length = 0;
4002
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
4003
+ },
4004
+ RENDER_RANGE_PROJECTION_SETTLE_DELAY,
4005
+ "renderRangeProjection"
4006
+ );
3980
4007
  }
3981
4008
  function findCurrentStickyIndex(stickyArray, scroll, state) {
3982
4009
  const positions = state.positions;
@@ -4644,8 +4671,6 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4644
4671
  if (anchorIndex >= 0 && anchorIndex < data.length && state.scrollLength > 0) {
4645
4672
  nextAnchorKey = getId(state, anchorIndex);
4646
4673
  let contentBelowAnchor = 0;
4647
- const footerSize = ctx.values.get("footerSize") || 0;
4648
- const stylePaddingBottom = state.props.stylePaddingBottom || 0;
4649
4674
  let hasUnknownTailSize = false;
4650
4675
  for (let index = anchorIndex; index < data.length; index++) {
4651
4676
  const size = getKnownOrFixedItemSize(ctx, index);
@@ -4657,14 +4682,16 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4657
4682
  contentBelowAnchor += effectiveSize;
4658
4683
  }
4659
4684
  }
4660
- contentBelowAnchor += footerSize + stylePaddingBottom;
4685
+ contentBelowAnchor = Math.max(0, contentBelowAnchor - ctx.scrollAxisGap);
4686
+ contentBelowAnchor += (ctx.values.get("footerSize") || 0) + getStylePaddingEnd(state.props);
4661
4687
  isReady = !hasUnknownTailSize;
4662
4688
  nextSize = hasUnknownTailSize ? previousSize || 0 : Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
4663
4689
  } else if (anchorIndex >= 0) {
4664
4690
  isReady = false;
4665
4691
  }
4666
4692
  }
4667
- const didSizeChange = previousSize !== nextSize;
4693
+ const didSizeChange = previousSize !== nextSize && (previousSize !== void 0 || anchoredEndSpace !== void 0);
4694
+ const didEffectiveSizeChange = (previousSize || 0) !== nextSize;
4668
4695
  const didReadyAnchorChange = previousReadyAnchorIndex !== nextAnchorIndex || previousReadyAnchorKey !== nextAnchorKey;
4669
4696
  if (isReady && (didSizeChange || didReadyAnchorChange)) {
4670
4697
  state.anchoredEndSpaceReadyAnchorIndex = nextAnchorIndex;
@@ -4673,8 +4700,9 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4673
4700
  set$(ctx, "anchoredEndSpaceSize", nextSize);
4674
4701
  (_a3 = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onSizeChanged) == null ? void 0 : _a3.call(anchoredEndSpace, nextSize);
4675
4702
  }
4676
- if (didSizeChange && (anchoredEndSpace == null ? void 0 : anchoredEndSpace.includeInEndInset)) {
4677
- updateScroll(ctx, state.scroll, true);
4703
+ if (didEffectiveSizeChange) {
4704
+ updateContentMetricsState(ctx);
4705
+ updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
4678
4706
  }
4679
4707
  (_b = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onReady) == null ? void 0 : _b.call(anchoredEndSpace, { anchorIndex: nextAnchorIndex, anchorKey: nextAnchorKey, size: nextSize });
4680
4708
  }
@@ -4692,16 +4720,10 @@ function runOrScheduleMVCPRecalculate(ctx) {
4692
4720
  }
4693
4721
  } else {
4694
4722
  if (!state.mvcpAnchorLock) {
4695
- if (state.queuedMVCPRecalculate !== void 0) {
4696
- cancelAnimationFrame(state.queuedMVCPRecalculate);
4697
- state.queuedMVCPRecalculate = void 0;
4698
- }
4723
+ state.scheduledWork.cancel("mvcpRecalculate");
4699
4724
  calculateItemsInView(ctx, { doMVCP: true });
4700
- } else if (state.queuedMVCPRecalculate === void 0) {
4701
- state.queuedMVCPRecalculate = requestAnimationFrame(() => {
4702
- state.queuedMVCPRecalculate = void 0;
4703
- calculateItemsInView(ctx, { doMVCP: true });
4704
- });
4725
+ } else if (!state.scheduledWork.has("mvcpRecalculate")) {
4726
+ state.scheduledWork.frame(() => calculateItemsInView(ctx, { doMVCP: true }), "mvcpRecalculate");
4705
4727
  }
4706
4728
  }
4707
4729
  }
@@ -4746,6 +4768,9 @@ function flushItemSizeUpdates(ctx, result) {
4746
4768
  } else if (result.didMeasureUserScrollAnchorResetItem && ((_a3 = state.userScrollAnchorReset) == null ? void 0 : _a3.keys.size) === 0) {
4747
4769
  state.userScrollAnchorReset = void 0;
4748
4770
  }
4771
+ if (result.didChange) {
4772
+ maybeUpdateAnchoredEndSpace(ctx);
4773
+ }
4749
4774
  if (result.didChange && result.shouldMaintainScrollAtEnd) {
4750
4775
  doMaintainScrollAtEnd(ctx);
4751
4776
  }
@@ -4835,7 +4860,6 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
4835
4860
  previous: size - diff,
4836
4861
  size
4837
4862
  });
4838
- maybeUpdateAnchoredEndSpace(ctx);
4839
4863
  }
4840
4864
  if (minIndexSizeChanged !== void 0) {
4841
4865
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
@@ -5725,24 +5749,40 @@ function useDOMOrder(ref) {
5725
5749
  };
5726
5750
  }, [ctx]);
5727
5751
  }
5752
+ function useFreshDataTransitionVisibility(readyToRender, transitionEpoch) {
5753
+ const completedTransitionEpoch = React3.useRef(transitionEpoch);
5754
+ const isTransitionPending = completedTransitionEpoch.current !== transitionEpoch;
5755
+ React3.useLayoutEffect(() => {
5756
+ if (!readyToRender) {
5757
+ completedTransitionEpoch.current = transitionEpoch;
5758
+ }
5759
+ }, [readyToRender, transitionEpoch]);
5760
+ return readyToRender && !isTransitionPending;
5761
+ }
5728
5762
 
5729
5763
  // src/components/Containers.tsx
5730
- var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColumns, children }) {
5764
+ var ContainersInner = typedMemo(function ContainersInner2({
5765
+ freshDataTransitionEpoch,
5766
+ horizontal,
5767
+ numColumns,
5768
+ children
5769
+ }) {
5731
5770
  const ref = React3.useRef(null);
5732
5771
  const ctx = useStateContext();
5733
5772
  const columnWrapperStyle = ctx.columnWrapperStyle;
5734
5773
  const isHorizontalRTLList = isHorizontalRTL(ctx.state);
5735
5774
  const [otherAxisSize, readyToRender, totalSize] = useArr$(["otherAxisSize", "readyToRender", "totalSize"]);
5775
+ const isVisible = useFreshDataTransitionVisibility(!!readyToRender, freshDataTransitionEpoch);
5736
5776
  useDOMOrder(ref);
5737
5777
  const style = horizontal ? {
5738
5778
  direction: isHorizontalRTLList ? "ltr" : void 0,
5739
5779
  flexShrink: 0,
5740
5780
  minHeight: otherAxisSize,
5741
- opacity: readyToRender ? 1 : 0,
5781
+ opacity: isVisible ? 1 : 0,
5742
5782
  position: "relative",
5743
5783
  width: totalSize
5744
- } : { height: totalSize, minWidth: otherAxisSize, opacity: readyToRender ? 1 : 0, position: "relative" };
5745
- if (!readyToRender) {
5784
+ } : { height: totalSize, minWidth: otherAxisSize, opacity: isVisible ? 1 : 0, position: "relative" };
5785
+ if (!isVisible) {
5746
5786
  style.pointerEvents = "none";
5747
5787
  }
5748
5788
  if (columnWrapperStyle && numColumns > 1) {
@@ -5765,6 +5805,7 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
5765
5805
  return /* @__PURE__ */ React3__namespace.createElement("div", { ref, style }, /* @__PURE__ */ React3__namespace.createElement(ContainerLayoutCoordinator, null, children));
5766
5806
  });
5767
5807
  var Containers = typedMemo(function Containers2({
5808
+ freshDataTransitionEpoch,
5768
5809
  horizontal,
5769
5810
  recycleItems,
5770
5811
  ItemSeparatorComponent,
@@ -5789,7 +5830,15 @@ var Containers = typedMemo(function Containers2({
5789
5830
  )
5790
5831
  );
5791
5832
  }
5792
- return /* @__PURE__ */ React3__namespace.createElement(ContainersInner, { horizontal, numColumns }, containers);
5833
+ return /* @__PURE__ */ React3__namespace.createElement(
5834
+ ContainersInner,
5835
+ {
5836
+ freshDataTransitionEpoch,
5837
+ horizontal,
5838
+ numColumns
5839
+ },
5840
+ containers
5841
+ );
5793
5842
  });
5794
5843
 
5795
5844
  // src/platform/StyleSheet.tsx
@@ -6000,7 +6049,7 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
6000
6049
  onLayout,
6001
6050
  ...props
6002
6051
  }, ref) {
6003
- var _a3, _b, _c, _d;
6052
+ var _a3, _b, _c;
6004
6053
  const ctx = useStateContext();
6005
6054
  const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
6006
6055
  const scrollRef = React3.useRef(null);
@@ -6232,7 +6281,7 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
6232
6281
  } : {}
6233
6282
  };
6234
6283
  const contentInsetEndAdjustment = getContentInsetEndAdjustmentEnd2(ctx);
6235
- 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;
6284
+ const anchoredEndInset = ((_b = (_a3 = ctx.state) == null ? void 0 : _a3.props) == null ? void 0 : _b.anchoredEndSpace) && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
6236
6285
  const renderedContentInsetEndAdjustment = Math.max(0, contentInsetEndAdjustment - anchoredEndInset);
6237
6286
  const contentInsetEndAdjustmentSpacerStyle = renderedContentInsetEndAdjustment ? horizontal ? { flexShrink: 0, width: renderedContentInsetEndAdjustment } : { height: renderedContentInsetEndAdjustment } : void 0;
6238
6287
  const contentStyle = {
@@ -6259,7 +6308,7 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
6259
6308
  const snapOffsets = !isWindowScroll ? getFiniteSnapOffsets(snapToOffsets) : [];
6260
6309
  if (snapOffsets.length > 0) {
6261
6310
  scrollViewStyle.scrollSnapType = horizontal ? "x mandatory" : "y mandatory";
6262
- contentStyle.position = (_d = contentStyle.position) != null ? _d : "relative";
6311
+ contentStyle.position = (_c = contentStyle.position) != null ? _c : "relative";
6263
6312
  }
6264
6313
  const scrollViewClassName = hiddenScrollIndicatorClassName ? scrollViewClassNameProp ? `${scrollViewClassNameProp} ${hiddenScrollIndicatorClassName}` : hiddenScrollIndicatorClassName : scrollViewClassNameProp;
6265
6314
  if (IS_DEV) {
@@ -6408,16 +6457,6 @@ var SnapWrapper = React3__namespace.forwardRef(function SnapWrapperInner({ Scrol
6408
6457
  const [snapToOffsets] = useArr$(["snapToOffsets"]);
6409
6458
  return /* @__PURE__ */ React3__namespace.createElement(ScrollComponent, { ...props, ref, snapToOffsets });
6410
6459
  });
6411
- function WebAnchoredEndSpace({ horizontal }) {
6412
- const ctx = useStateContext();
6413
- const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
6414
- const shouldRenderAnchoredEndSpace = !!ctx.state.props.anchoredEndSpace && (anchoredEndSpaceSize || 0) > 0;
6415
- if (!shouldRenderAnchoredEndSpace) {
6416
- return null;
6417
- }
6418
- const style = horizontal ? { height: "100%", width: anchoredEndSpaceSize || 0 } : { height: anchoredEndSpaceSize || 0 };
6419
- return /* @__PURE__ */ React3__namespace.createElement("div", { style }, null);
6420
- }
6421
6460
 
6422
6461
  // src/core/updateContentMetrics.ts
6423
6462
  var SCROLL_ADJUST_EPSILON = 0.1;
@@ -6451,7 +6490,11 @@ function setHeaderSize(ctx, size) {
6451
6490
  state.didMeasureHeader = true;
6452
6491
  }
6453
6492
  function setFooterSize(ctx, size) {
6454
- return setContentLengthSignal(ctx, "footerSize", size);
6493
+ const didChange = setContentLengthSignal(ctx, "footerSize", size);
6494
+ if (didChange) {
6495
+ maybeUpdateAnchoredEndSpace(ctx);
6496
+ }
6497
+ return didChange;
6455
6498
  }
6456
6499
  function areInsetsEqual(left, right) {
6457
6500
  var _a3, _b, _c, _d, _e, _f, _g, _h;
@@ -6504,6 +6547,7 @@ var AlignItemsAtEndSpacer = typedMemo(function AlignItemsAtEndSpacer2({ horizont
6504
6547
  });
6505
6548
  var ListComponent = typedMemo(function ListComponent2({
6506
6549
  canRender,
6550
+ freshDataTransitionEpoch,
6507
6551
  style,
6508
6552
  contentContainerStyle,
6509
6553
  horizontal,
@@ -6533,8 +6577,17 @@ var ListComponent = typedMemo(function ListComponent2({
6533
6577
  }) {
6534
6578
  const ctx = useStateContext();
6535
6579
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
6536
- const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
6580
+ const [anchoredEndSpaceSize = 0, otherAxisSize = 0] = useArr$(["anchoredEndSpaceSize", "otherAxisSize"]);
6537
6581
  const shouldRenderAlignItemsAtEndSpacer = ctx.state.props.alignItemsAtEndPaddingEnabled;
6582
+ const shouldMaterializeAnchoredEndSpace = !!ctx.state.props.anchoredEndSpace && ctx.state.props.anchoredEndSpaceOwner === "list" && anchoredEndSpaceSize > 0;
6583
+ let anchoredEndSpaceStyle;
6584
+ if (shouldMaterializeAnchoredEndSpace) {
6585
+ const paddingEnd = horizontal ? isHorizontalRTL(ctx.state) ? "Left" : "Right" : "Bottom";
6586
+ const flattenedContentContainerStyle = StyleSheet.flatten(contentContainerStyle);
6587
+ anchoredEndSpaceStyle = {
6588
+ [`padding${paddingEnd}`]: extractPadding({}, flattenedContentContainerStyle || {}, paddingEnd) + anchoredEndSpaceSize
6589
+ };
6590
+ }
6538
6591
  const autoOtherAxisStyle = getAutoOtherAxisStyle({
6539
6592
  horizontal,
6540
6593
  needsOtherAxisSize: ctx.state.needsOtherAxisSize,
@@ -6587,10 +6640,10 @@ var ListComponent = typedMemo(function ListComponent2({
6587
6640
  ...rest,
6588
6641
  ...ScrollComponent === ListComponentScrollView ? { onInternalScrollEnd, useWindowScroll } : {} ,
6589
6642
  contentContainerStyle: [
6590
- horizontal ? {
6591
- height: "100%"
6592
- } : {},
6593
- contentContainerStyle
6643
+ horizontal ? { height: "100%" } : {},
6644
+ contentContainerStyle,
6645
+ anchoredEndSpaceStyle,
6646
+ { boxSizing: "border-box" }
6594
6647
  ],
6595
6648
  contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
6596
6649
  horizontal,
@@ -6608,6 +6661,7 @@ var ListComponent = typedMemo(function ListComponent2({
6608
6661
  canRender && !ListEmptyComponent && /* @__PURE__ */ React3__namespace.createElement(
6609
6662
  Containers,
6610
6663
  {
6664
+ freshDataTransitionEpoch,
6611
6665
  getRenderedItem: getRenderedItem2,
6612
6666
  horizontal,
6613
6667
  ItemSeparatorComponent,
@@ -6616,7 +6670,6 @@ var ListComponent = typedMemo(function ListComponent2({
6616
6670
  }
6617
6671
  ),
6618
6672
  ListFooterComponent && /* @__PURE__ */ React3__namespace.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
6619
- /* @__PURE__ */ React3__namespace.createElement(WebAnchoredEndSpace, { horizontal }),
6620
6673
  IS_DEV && ENABLE_DEVMODE
6621
6674
  );
6622
6675
  });
@@ -6625,7 +6678,16 @@ var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
6625
6678
  var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
6626
6679
  function useDevChecksImpl(props) {
6627
6680
  const ctx = useStateContext();
6628
- const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
6681
+ const { anchoredEndSpace, childrenMode, keyExtractor, numColumns, renderScrollComponent, useWindowScroll } = props;
6682
+ const hasAnchoredEndSpace = !!anchoredEndSpace;
6683
+ React3.useEffect(() => {
6684
+ if (hasAnchoredEndSpace && (numColumns != null ? numColumns : 1) > 1) {
6685
+ warnDevOnce(
6686
+ "anchoredEndSpaceNumColumns",
6687
+ "anchoredEndSpace is only supported when numColumns is 1. Using it with multiple columns may produce incorrect anchored spacing."
6688
+ );
6689
+ }
6690
+ }, [hasAnchoredEndSpace, numColumns]);
6629
6691
  React3.useEffect(() => {
6630
6692
  if (useWindowScroll && renderScrollComponent) {
6631
6693
  warnDevOnce(
@@ -6953,6 +7015,59 @@ function onScroll(ctx, event) {
6953
7015
  }
6954
7016
  }
6955
7017
 
7018
+ // src/core/ScheduledWork.ts
7019
+ var ScheduledWork = class {
7020
+ constructor() {
7021
+ this.work = /* @__PURE__ */ new Map();
7022
+ }
7023
+ timeout(callback, delay, key) {
7024
+ if (key) {
7025
+ this.cancel(key);
7026
+ }
7027
+ const work = [void 0, clearTimeout];
7028
+ const handle = setTimeout(() => {
7029
+ const workKey = key != null ? key : handle;
7030
+ if (this.work.get(workKey) === work) {
7031
+ this.work.delete(workKey);
7032
+ callback();
7033
+ }
7034
+ }, delay);
7035
+ work[0] = handle;
7036
+ this.work.set(key != null ? key : handle, work);
7037
+ }
7038
+ frame(callback, key) {
7039
+ this.cancel(key);
7040
+ const work = [void 0, cancelAnimationFrame];
7041
+ this.work.set(key, work);
7042
+ work[0] = requestAnimationFrame(() => {
7043
+ if (this.work.get(key) === work) {
7044
+ this.work.delete(key);
7045
+ callback();
7046
+ }
7047
+ });
7048
+ }
7049
+ register(key, cancel) {
7050
+ this.cancel(key);
7051
+ this.work.set(key, [void 0, cancel]);
7052
+ }
7053
+ cancel(key) {
7054
+ const work = this.work.get(key);
7055
+ if (work) {
7056
+ this.work.delete(key);
7057
+ work[1](work[0]);
7058
+ }
7059
+ }
7060
+ has(key) {
7061
+ return this.work.has(key);
7062
+ }
7063
+ dispose() {
7064
+ for (const [handle, cancel] of this.work.values()) {
7065
+ cancel(handle);
7066
+ }
7067
+ this.work.clear();
7068
+ }
7069
+ };
7070
+
6956
7071
  // src/core/ScrollAdjustHandler.ts
6957
7072
  var ScrollAdjustHandler = class {
6958
7073
  constructor(ctx) {
@@ -7110,7 +7225,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7110
7225
  const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
7111
7226
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
7112
7227
  let imperativeScrollToken = 0;
7113
- const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0;
7228
+ const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.scheduledWork.has("mvcpRecalculate") || state.ignoreScrollFromMVCP !== void 0;
7114
7229
  const isScrollToIndexReady = (targetIndex, allowEmpty = false) => {
7115
7230
  var _a3;
7116
7231
  const props = state.props;
@@ -7144,9 +7259,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7144
7259
  run();
7145
7260
  return;
7146
7261
  }
7147
- requestAnimationFrame(check);
7262
+ state.scheduledWork.frame(check, "imperativeScrollReady");
7148
7263
  };
7149
- requestAnimationFrame(check);
7264
+ state.scheduledWork.frame(check, "imperativeScrollReady");
7150
7265
  };
7151
7266
  const runScrollRequest = (token, resolve, run, isReady = () => true) => {
7152
7267
  const runNow = () => {
@@ -7168,10 +7283,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7168
7283
  }
7169
7284
  };
7170
7285
  const startImperativeScroll = (resolve) => {
7171
- var _a3;
7286
+ state.scheduledWork.cancel("imperativeScrollReady");
7172
7287
  const token = ++imperativeScrollToken;
7173
- state.pendingScrollToEnd = void 0;
7174
- (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
7288
+ settlePendingImperativeScroll(state);
7175
7289
  state.pendingScrollResolve = resolve;
7176
7290
  return token;
7177
7291
  };
@@ -7255,6 +7369,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7255
7369
  end: state.endNoBuffer,
7256
7370
  endBuffered: state.endBuffered,
7257
7371
  getAverageItemSizes: () => getAverageItemSizes(state),
7372
+ indexByKey: (key) => state.indexByKey.get(key),
7258
7373
  isAtEnd: peek$(ctx, "isAtEnd"),
7259
7374
  isAtStart: peek$(ctx, "isAtStart"),
7260
7375
  isEndReached: state.isEndReached,
@@ -7558,7 +7673,7 @@ var LegendList = typedMemo(
7558
7673
  })
7559
7674
  );
7560
7675
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
7561
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
7676
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
7562
7677
  const noopOnScroll = React3.useCallback((_event) => {
7563
7678
  }, []);
7564
7679
  if (props.recycleItems === void 0) {
@@ -7634,9 +7749,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7634
7749
  ...rest
7635
7750
  } = props;
7636
7751
  const animatedPropsInternal = props.animatedPropsInternal;
7752
+ const anchoredEndSpaceOwner = (_a3 = props.anchoredEndSpaceOwnerInternal) != null ? _a3 : "list";
7637
7753
  const positionComponentInternal = props.positionComponentInternal;
7638
7754
  const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
7639
7755
  const {
7756
+ anchoredEndSpaceOwnerInternal: _anchoredEndSpaceOwnerInternal,
7640
7757
  positionComponentInternal: _positionComponentInternal,
7641
7758
  stickyPositionComponentInternal: _stickyPositionComponentInternal,
7642
7759
  ...restProps
@@ -7658,6 +7775,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7658
7775
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
7659
7776
  const stylePaddingLeftState = extractPadding(style, contentContainerStyle, "Left");
7660
7777
  const stylePaddingRightState = extractPadding(style, contentContainerStyle, "Right");
7778
+ const stylePaddingEndState = getStylePaddingEnd({
7779
+ horizontal,
7780
+ rtl,
7781
+ stylePaddingBottom: stylePaddingBottomState,
7782
+ stylePaddingLeft: stylePaddingLeftState,
7783
+ stylePaddingRight: stylePaddingRightState
7784
+ });
7661
7785
  const maintainScrollAtEndConfig = normalizeMaintainScrollAtEnd(maintainScrollAtEnd);
7662
7786
  const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
7663
7787
  maintainVisibleContentPositionProp
@@ -7670,13 +7794,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7670
7794
  const initialScrollProp = initialScrollAtEnd ? {
7671
7795
  index: Math.max(0, dataProp.length - 1),
7672
7796
  preserveForBottomPadding: true,
7673
- viewOffset: -stylePaddingBottomState,
7797
+ viewOffset: -stylePaddingEndState,
7674
7798
  viewPosition: 1
7675
7799
  } : hasInitialScrollIndex ? typeof initialScrollIndexProp === "object" ? {
7676
- index: (_a3 = initialScrollIndexProp.index) != null ? _a3 : 0,
7800
+ index: (_b = initialScrollIndexProp.index) != null ? _b : 0,
7677
7801
  preserveForBottomPadding: initialScrollIndexProp.viewOffset === void 0 && initialScrollIndexProp.viewPosition === 1 ? true : void 0,
7678
- viewOffset: (_b = initialScrollIndexProp.viewOffset) != null ? _b : initialScrollIndexProp.viewPosition === 1 ? -stylePaddingBottomState : 0,
7679
- viewPosition: (_c = initialScrollIndexProp.viewPosition) != null ? _c : 0
7802
+ viewOffset: (_c = initialScrollIndexProp.viewOffset) != null ? _c : initialScrollIndexProp.viewPosition === 1 ? -stylePaddingEndState : 0,
7803
+ viewPosition: (_d = initialScrollIndexProp.viewPosition) != null ? _d : 0
7680
7804
  } : {
7681
7805
  index: initialScrollIndexProp != null ? initialScrollIndexProp : 0,
7682
7806
  viewOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : 0
@@ -7689,7 +7813,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7689
7813
  const [, scheduleImperativeScrollCommit] = React3__namespace.useReducer((value) => value + 1, 0);
7690
7814
  const ctx = useStateContext();
7691
7815
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
7692
- 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;
7816
+ 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;
7693
7817
  const nextScrollAxisGap = typeof scrollAxisGap === "number" && Number.isFinite(scrollAxisGap) ? scrollAxisGap : 0;
7694
7818
  const refScroller = React3.useRef(null);
7695
7819
  const combinedRef = useCombinedRef(refScroller, refScrollView);
@@ -7704,8 +7828,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7704
7828
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex,
7705
7829
  alwaysRender == null ? void 0 : alwaysRender.top,
7706
7830
  alwaysRender == null ? void 0 : alwaysRender.bottom,
7707
- (_j = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _j.join(","),
7708
- (_k = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _k.join(","),
7831
+ (_k = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _k.join(","),
7832
+ (_l = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _l.join(","),
7709
7833
  dataProp,
7710
7834
  dataKey,
7711
7835
  dataVersion,
@@ -7718,7 +7842,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7718
7842
  if (!refState.current) {
7719
7843
  if (!ctx.state) {
7720
7844
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : { height: 0, width: 0 } )[horizontal ? "width" : "height"];
7721
- ctx.values.set("adaptiveRender", (_l = experimental_adaptiveRender == null ? void 0 : experimental_adaptiveRender.initialMode) != null ? _l : "normal");
7845
+ ctx.values.set("adaptiveRender", (_m = experimental_adaptiveRender == null ? void 0 : experimental_adaptiveRender.initialMode) != null ? _m : "normal");
7722
7846
  ctx.state = {
7723
7847
  averageSizes: {},
7724
7848
  columnSpans: [],
@@ -7737,6 +7861,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7737
7861
  endNoBuffer: -1,
7738
7862
  endReachedSnapshot: void 0,
7739
7863
  firstFullyOnScreenIndex: -1,
7864
+ freshDataTransitionEpoch: 0,
7740
7865
  hasHadNonEmptyData: dataProp.length > 0,
7741
7866
  idCache: [],
7742
7867
  idsInView: [],
@@ -7761,8 +7886,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7761
7886
  positions: [],
7762
7887
  props: {},
7763
7888
  queuedCalculateItemsInView: 0,
7764
- queuedFullDrawDistancePrewarm: void 0,
7765
7889
  refScroller: { current: null },
7890
+ scheduledWork: new ScheduledWork(),
7766
7891
  scroll: 0,
7767
7892
  scrollAdjustHandler: new ScrollAdjustHandler(ctx),
7768
7893
  scrollForNextCalculateItemsInView: void 0,
@@ -7780,8 +7905,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7780
7905
  startReachedSnapshot: void 0,
7781
7906
  stickyContainerPool: /* @__PURE__ */ new Set(),
7782
7907
  stickyContainers: /* @__PURE__ */ new Map(),
7783
- timeoutAdaptiveRender: void 0,
7784
- timeouts: /* @__PURE__ */ new Set(),
7785
7908
  totalSize: 0,
7786
7909
  viewabilityConfigCallbackPairs: void 0
7787
7910
  };
@@ -7803,13 +7926,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7803
7926
  const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
7804
7927
  ctx.scrollAxisGap = nextScrollAxisGap;
7805
7928
  state.didColumnsChange = numColumnsProp !== previousNumColumnsProp || didScrollAxisGapChange;
7806
- const previousDataLength = (_n = (_m = state.props.data) == null ? void 0 : _m.length) != null ? _n : 0;
7929
+ const previousDataLength = (_o = (_n = state.props.data) == null ? void 0 : _n.length) != null ? _o : 0;
7807
7930
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
7808
7931
  const didDataKeyChangeLocal = state.props.dataKey !== dataKey;
7809
7932
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
7810
7933
  const didDataChangeLocal = didDataKeyChangeLocal || didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
7811
7934
  const shouldResetFreshDataLayout = !isFirstLocal && didDataChangeLocal && state.hasHadNonEmptyData && (didDataKeyChangeLocal || previousDataLength === 0) && dataProp.length > 0;
7812
- if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_o = state.initialScroll) == null ? void 0 : _o.viewPosition) === 1 && state.props.data.length > 0) {
7935
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_p = state.initialScroll) == null ? void 0 : _p.viewPosition) === 1 && state.props.data.length > 0) {
7813
7936
  clearPreservedInitialScrollTarget(state);
7814
7937
  }
7815
7938
  if (didDataChangeLocal) {
@@ -7818,10 +7941,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7818
7941
  state.didDataChange = true;
7819
7942
  state.previousData = state.props.data;
7820
7943
  }
7944
+ if (shouldResetFreshDataLayout) {
7945
+ state.freshDataTransitionEpoch += 1;
7946
+ }
7821
7947
  const throttledOnScroll = useThrottledOnScroll(onScrollProp != null ? onScrollProp : noopOnScroll, scrollEventThrottle != null ? scrollEventThrottle : 0);
7822
7948
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? throttledOnScroll : onScrollProp;
7823
- const anchoredEndSpaceResolved = anchoredEndSpace ? { ...anchoredEndSpace, includeInEndInset: true } : anchoredEndSpace;
7824
- const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_p = state.props.anchoredEndSpace) == null ? void 0 : _p.anchorIndex) !== (anchoredEndSpaceResolved == null ? void 0 : anchoredEndSpaceResolved.anchorIndex);
7949
+ const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_q = state.props.anchoredEndSpace) == null ? void 0 : _q.anchorIndex) !== (anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex);
7825
7950
  state.props = {
7826
7951
  adaptiveRender: experimental_adaptiveRender,
7827
7952
  alignItemsAtEnd,
@@ -7829,7 +7954,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7829
7954
  alwaysRender,
7830
7955
  alwaysRenderIndicesArr: alwaysRenderIndices.arr,
7831
7956
  alwaysRenderIndicesSet: alwaysRenderIndices.set,
7832
- anchoredEndSpace: anchoredEndSpaceResolved,
7957
+ anchoredEndSpace,
7958
+ anchoredEndSpaceOwner,
7833
7959
  animatedProps: animatedPropsInternal,
7834
7960
  contentContainerAlignItems: contentContainerStyle.alignItems,
7835
7961
  contentInset,
@@ -7878,12 +8004,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7878
8004
  if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
7879
8005
  resetAdaptiveRender(ctx);
7880
8006
  }
7881
- if (shouldResetFreshDataLayout) {
7882
- resetInitialRenderState(ctx, {
7883
- resetInitialScroll: !!initialScrollProp,
7884
- resetLayout: true
7885
- });
7886
- }
7887
8007
  const memoizedLastItemKeys = React3.useMemo(() => {
7888
8008
  if (!dataProp.length) return [];
7889
8009
  return Array.from(
@@ -7942,6 +8062,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7942
8062
  useDevChecks(props);
7943
8063
  }
7944
8064
  React3.useLayoutEffect(() => {
8065
+ if (shouldResetFreshDataLayout) {
8066
+ resetInitialRenderState(ctx, {
8067
+ resetInitialScroll: !!initialScrollProp,
8068
+ resetLayout: true
8069
+ });
8070
+ }
7945
8071
  handleInitialScrollDataChange(ctx, {
7946
8072
  dataLength: dataProp.length,
7947
8073
  didDataChange: didDataChangeLocal,
@@ -7949,7 +8075,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7949
8075
  initialScrollAtEnd,
7950
8076
  latestInitialScroll: initialScrollProp,
7951
8077
  latestInitialScrollSessionKind: initialScrollUsesOffsetOnly ? "offset" : "bootstrap",
7952
- stylePaddingBottom: stylePaddingBottomState,
8078
+ stylePaddingEnd: stylePaddingEndState,
7953
8079
  useBootstrapInitialScroll: usesBootstrapInitialScroll
7954
8080
  });
7955
8081
  }, [
@@ -7958,7 +8084,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7958
8084
  didDataChangeLocal,
7959
8085
  shouldResetFreshDataLayout,
7960
8086
  initialScrollAtEnd,
7961
- stylePaddingBottomState,
8087
+ stylePaddingEndState,
7962
8088
  usesBootstrapInitialScroll
7963
8089
  ]);
7964
8090
  React3.useLayoutEffect(() => {
@@ -7976,7 +8102,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7976
8102
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorMaxSize,
7977
8103
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorOffset,
7978
8104
  didAnchoredEndSpaceAnchorIndexChange,
7979
- numColumnsProp
8105
+ horizontal,
8106
+ numColumnsProp,
8107
+ rtl,
8108
+ stylePaddingBottomState,
8109
+ stylePaddingLeftState,
8110
+ stylePaddingRightState
7980
8111
  ]);
7981
8112
  React3.useLayoutEffect(() => {
7982
8113
  const previousContentInsetEndAdjustment = previousContentInsetEndAdjustmentRef.current;
@@ -7992,10 +8123,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7992
8123
  dataLength: dataProp.length,
7993
8124
  footerSize: layout[horizontal ? "width" : "height"],
7994
8125
  initialScrollAtEnd,
7995
- stylePaddingBottom: stylePaddingBottomState
8126
+ stylePaddingEnd: stylePaddingEndState
7996
8127
  });
7997
8128
  },
7998
- [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingBottomState, usesBootstrapInitialScroll]
8129
+ [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingEndState, usesBootstrapInitialScroll]
7999
8130
  );
8000
8131
  const onLayoutChange = React3.useCallback(
8001
8132
  (layout, fromLayoutEffect) => {
@@ -8012,7 +8143,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8012
8143
  }
8013
8144
  advanceCurrentInitialScrollSession(ctx);
8014
8145
  },
8015
- [dataProp.length, initialScrollAtEnd, stylePaddingBottomState, usesBootstrapInitialScroll]
8146
+ [dataProp.length, initialScrollAtEnd, stylePaddingEndState, usesBootstrapInitialScroll]
8016
8147
  );
8017
8148
  const { onLayout } = useOnLayoutSync({
8018
8149
  onLayoutChange,
@@ -8105,14 +8236,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8105
8236
  React3.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, scheduleImperativeScrollCommit), []);
8106
8237
  React3.useEffect(() => {
8107
8238
  return () => {
8108
- if (state.queuedFullDrawDistancePrewarm !== void 0) {
8109
- cancelAnimationFrame(state.queuedFullDrawDistancePrewarm);
8110
- state.queuedFullDrawDistancePrewarm = void 0;
8111
- }
8112
- for (const timeout of state.timeouts) {
8113
- clearTimeout(timeout);
8114
- }
8115
- state.timeouts.clear();
8239
+ cancelImperativeScroll(state);
8240
+ state.scheduledWork.dispose();
8116
8241
  };
8117
8242
  }, [state]);
8118
8243
  React3.useLayoutEffect(() => {
@@ -8154,6 +8279,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8154
8279
  canRender,
8155
8280
  contentContainerStyle,
8156
8281
  contentInset,
8282
+ freshDataTransitionEpoch: state.freshDataTransitionEpoch,
8157
8283
  getRenderedItem: fns.getRenderedItem,
8158
8284
  horizontal,
8159
8285
  initialContentOffset,
@@ -8169,7 +8295,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8169
8295
  onScroll: onScrollHandler,
8170
8296
  recycleItems,
8171
8297
  refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React3__namespace.cloneElement(refreshControlElement, {
8172
- progressViewOffset: ((_q = refreshControlElement.props.progressViewOffset) != null ? _q : 0) + stylePaddingTopState
8298
+ progressViewOffset: ((_r = refreshControlElement.props.progressViewOffset) != null ? _r : 0) + stylePaddingTopState
8173
8299
  }) : refreshControlElement : onRefresh && /* @__PURE__ */ React3__namespace.createElement(
8174
8300
  RefreshControl,
8175
8301
  {
@@ -8180,7 +8306,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8180
8306
  ),
8181
8307
  refScrollView: combinedRef,
8182
8308
  renderScrollComponent,
8183
- scrollAdjustHandler: (_r = refState.current) == null ? void 0 : _r.scrollAdjustHandler,
8309
+ scrollAdjustHandler: (_s = refState.current) == null ? void 0 : _s.scrollAdjustHandler,
8184
8310
  scrollEventThrottle: 0,
8185
8311
  snapToIndices,
8186
8312
  stickyHeaderIndices,