@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.
@@ -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
@@ -761,13 +776,7 @@ var DEFAULT_WEB_ADAPTIVE_RENDER_ENTER_VELOCITY = 6;
761
776
  var DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_VELOCITY = 3;
762
777
  var DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_DELAY = 250;
763
778
  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
- }
779
+ ctx.state.scheduledWork.cancel("adaptiveRender");
771
780
  }
772
781
  function scheduleAdaptiveRenderExit(ctx, exitDelay) {
773
782
  const state = ctx.state;
@@ -775,13 +784,7 @@ function scheduleAdaptiveRenderExit(ctx, exitDelay) {
775
784
  if (exitDelay <= 0) {
776
785
  setAdaptiveRender(ctx, "normal", "scroll");
777
786
  } 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);
787
+ state.scheduledWork.timeout(() => setAdaptiveRender(ctx, "normal", "scroll"), exitDelay, "adaptiveRender");
785
788
  }
786
789
  }
787
790
  function setAdaptiveRender(ctx, mode, reason) {
@@ -812,7 +815,7 @@ function updateAdaptiveRender(ctx, scrollVelocity, options) {
812
815
  const exitDelay = (_c = adaptiveRender.exitDelay) != null ? _c : DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_DELAY ;
813
816
  const threshold = currentMode === "light" ? exitVelocity : enterVelocity;
814
817
  const nextMode = (options == null ? void 0 : options.forceLight) || Math.abs(scrollVelocity) > threshold ? "light" : "normal";
815
- const previousMode = state.timeoutAdaptiveRender !== void 0 ? "normal" : currentMode;
818
+ const previousMode = state.scheduledWork.has("adaptiveRender") ? "normal" : currentMode;
816
819
  if (nextMode !== previousMode) {
817
820
  if (nextMode === "light") {
818
821
  setAdaptiveRender(ctx, "light", "scroll");
@@ -839,14 +842,13 @@ function getEffectiveDrawDistance(ctx, mode) {
839
842
  }
840
843
  function scheduleFullDrawDistancePrewarm(ctx) {
841
844
  const { state } = ctx;
842
- if (state.props.drawDistance <= INITIAL_DRAW_DISTANCE || state.queuedFullDrawDistancePrewarm !== void 0) {
845
+ if (state.props.drawDistance <= INITIAL_DRAW_DISTANCE || state.scheduledWork.has("fullDrawDistancePrewarm")) {
843
846
  return;
844
847
  }
845
- state.queuedFullDrawDistancePrewarm = requestAnimationFrame(() => {
848
+ state.scheduledWork.frame(() => {
846
849
  var _a3;
847
- state.queuedFullDrawDistancePrewarm = void 0;
848
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
849
- });
850
+ return (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
851
+ }, "fullDrawDistancePrewarm");
850
852
  }
851
853
 
852
854
  // src/utils/setInitialRenderState.ts
@@ -904,10 +906,7 @@ function syncInitialScrollOffset(state, offset) {
904
906
  state.scrollPrev = offset;
905
907
  }
906
908
  function clearPreservedInitialScrollTargetTimeout(state) {
907
- if (state.timeoutPreservedInitialScrollClear !== void 0) {
908
- clearTimeout(state.timeoutPreservedInitialScrollClear);
909
- state.timeoutPreservedInitialScrollClear = void 0;
910
- }
909
+ state.scheduledWork.cancel("preservedInitialScroll");
911
910
  }
912
911
  function clearPreservedInitialScrollTarget(state) {
913
912
  clearPreservedInitialScrollTargetTimeout(state);
@@ -936,14 +935,17 @@ function finishInitialScroll(ctx, options) {
936
935
  setInitialScrollSession(state);
937
936
  clearPreservedInitialScrollTargetTimeout(state);
938
937
  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);
938
+ state.scheduledWork.timeout(
939
+ () => {
940
+ var _a5;
941
+ if (!state.didFinishInitialScroll || ((_a5 = state.scrollingTo) == null ? void 0 : _a5.isInitialScroll) || !state.initialScroll) {
942
+ return;
943
+ }
944
+ clearPreservedInitialScrollTarget(state);
945
+ },
946
+ PRESERVED_INITIAL_SCROLL_FALLBACK_CLEAR_DELAY_MS,
947
+ "preservedInitialScroll"
948
+ );
947
949
  }
948
950
  } else {
949
951
  clearPreservedInitialScrollTarget(state);
@@ -970,9 +972,11 @@ function calculateOffsetForIndex(ctx, index) {
970
972
  return index !== void 0 ? state.positions[index] || 0 : 0;
971
973
  }
972
974
 
973
- // src/core/getTopOffsetAdjustment.ts
974
- function getTopOffsetAdjustment(ctx) {
975
- return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
975
+ // src/core/getStartOffsetAdjustment.ts
976
+ function getStartOffsetAdjustment(ctx) {
977
+ const { state } = ctx;
978
+ const stylePaddingStart = state.props.horizontal ? (isHorizontalRTL(state) ? state.props.stylePaddingRight : state.props.stylePaddingLeft) || 0 : peek$(ctx, "stylePaddingTop") || 0;
979
+ return stylePaddingStart + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
976
980
  }
977
981
 
978
982
  // src/utils/getId.ts
@@ -1183,9 +1187,9 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1183
1187
  offset -= viewOffset;
1184
1188
  }
1185
1189
  if (index !== void 0) {
1186
- const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
1187
- if (topOffsetAdjustment) {
1188
- offset += topOffsetAdjustment;
1190
+ const startOffsetAdjustment = getStartOffsetAdjustment(ctx);
1191
+ if (startOffsetAdjustment) {
1192
+ offset += startOffsetAdjustment;
1189
1193
  }
1190
1194
  }
1191
1195
  if (viewPosition !== void 0 && index !== void 0) {
@@ -1195,7 +1199,8 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1195
1199
  }
1196
1200
  const isOutOfBounds = index < 0 || index >= dataLength;
1197
1201
  const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
1198
- const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1202
+ const measuredItemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1203
+ const itemSize = Math.max(0, measuredItemSize - (isOutOfBounds ? 0 : ctx.scrollAxisGap));
1199
1204
  const trailingInset = getContentInsetEnd(ctx);
1200
1205
  offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1201
1206
  if (!isOutOfBounds && index === state.props.data.length - 1) {
@@ -1222,11 +1227,35 @@ function clampScrollOffset(ctx, offset, scrollTarget) {
1222
1227
  return clampedOffset;
1223
1228
  }
1224
1229
 
1230
+ // src/core/cancelImperativeScroll.ts
1231
+ function cancelScrollCompletionChecks({ scheduledWork }) {
1232
+ scheduledWork.cancel("checkFinishedScrollFrame");
1233
+ scheduledWork.cancel("checkFinishedScrollRetryFrame");
1234
+ scheduledWork.cancel("checkFinishedScrollFallback");
1235
+ scheduledWork.cancel("platformScrollCompletion");
1236
+ }
1237
+ function settlePendingImperativeScroll(state) {
1238
+ var _a3, _b;
1239
+ const resolvePendingScroll = (_b = state.pendingScrollResolve) != null ? _b : (_a3 = state.pendingScrollToEnd) == null ? void 0 : _a3.resolve;
1240
+ state.pendingScrollResolve = void 0;
1241
+ state.pendingScrollToEnd = void 0;
1242
+ resolvePendingScroll == null ? void 0 : resolvePendingScroll();
1243
+ }
1244
+ function cancelImperativeScroll(state) {
1245
+ cancelScrollCompletionChecks(state);
1246
+ state.scheduledWork.cancel("imperativeScrollReady");
1247
+ state.runPendingScrollToEnd = void 0;
1248
+ state.scrollingTo = void 0;
1249
+ state.scrollTargetPinnedRange = void 0;
1250
+ settlePendingImperativeScroll(state);
1251
+ }
1252
+
1225
1253
  // src/core/finishScrollTo.ts
1226
1254
  function finishScrollTo(ctx) {
1227
1255
  var _a3, _b;
1228
1256
  const state = ctx.state;
1229
1257
  if (state == null ? void 0 : state.scrollingTo) {
1258
+ cancelScrollCompletionChecks(state);
1230
1259
  const resolvePendingScroll = state.pendingScrollResolve;
1231
1260
  state.pendingScrollResolve = void 0;
1232
1261
  const scrollingTo = state.scrollingTo;
@@ -1268,6 +1297,7 @@ function doScrollTo(ctx, params) {
1268
1297
  var _a3, _b;
1269
1298
  const state = ctx.state;
1270
1299
  const { animated, horizontal, offset } = params;
1300
+ state.scheduledWork.cancel("platformScrollCompletion");
1271
1301
  const scroller = state.refScroller.current;
1272
1302
  const node = scroller == null ? void 0 : scroller.getScrollableNode();
1273
1303
  if (!scroller || !node) {
@@ -1288,9 +1318,16 @@ function doScrollTo(ctx, params) {
1288
1318
  });
1289
1319
  } else {
1290
1320
  state.scroll = offset;
1291
- setTimeout(() => {
1292
- finishScrollTo(ctx);
1293
- }, 100);
1321
+ const targetToken = state.scrollingTo;
1322
+ state.scheduledWork.timeout(
1323
+ () => {
1324
+ if (targetToken === state.scrollingTo) {
1325
+ finishScrollTo(ctx);
1326
+ }
1327
+ },
1328
+ 100,
1329
+ "platformScrollCompletion"
1330
+ );
1294
1331
  }
1295
1332
  }
1296
1333
  function listenForScrollEnd(ctx, params) {
@@ -1302,23 +1339,28 @@ function listenForScrollEnd(ctx, params) {
1302
1339
  const supportsScrollEnd = "onscrollend" in target;
1303
1340
  let idleTimeout;
1304
1341
  let settled = false;
1305
- const targetToken = ctx.state.scrollingTo;
1342
+ const { scheduledWork, scrollingTo: targetToken } = ctx.state;
1306
1343
  const maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1307
1344
  const cleanup = () => {
1308
1345
  target.removeEventListener("scroll", onScroll2);
1309
1346
  if (supportsScrollEnd) {
1310
1347
  target.removeEventListener("scrollend", onScrollEnd);
1311
1348
  }
1312
- if (idleTimeout) {
1349
+ if (idleTimeout !== void 0) {
1313
1350
  clearTimeout(idleTimeout);
1314
1351
  }
1315
1352
  clearTimeout(maxTimeout);
1316
1353
  };
1354
+ const cancel = () => {
1355
+ if (!settled) {
1356
+ settled = true;
1357
+ cleanup();
1358
+ }
1359
+ };
1317
1360
  const finish = (reason) => {
1318
1361
  if (settled) return;
1319
1362
  if (targetToken !== ctx.state.scrollingTo) {
1320
- settled = true;
1321
- cleanup();
1363
+ scheduledWork.cancel("platformScrollCompletion");
1322
1364
  return;
1323
1365
  }
1324
1366
  const currentOffset = readOffset();
@@ -1326,12 +1368,11 @@ function listenForScrollEnd(ctx, params) {
1326
1368
  if (reason === "scrollend" && !isNearTarget) {
1327
1369
  return;
1328
1370
  }
1329
- settled = true;
1330
- cleanup();
1371
+ scheduledWork.cancel("platformScrollCompletion");
1331
1372
  finishScrollTo(ctx);
1332
1373
  };
1333
1374
  const onScroll2 = () => {
1334
- if (idleTimeout) {
1375
+ if (idleTimeout !== void 0) {
1335
1376
  clearTimeout(idleTimeout);
1336
1377
  }
1337
1378
  idleTimeout = setTimeout(() => finish("idle"), SCROLL_END_IDLE_MS);
@@ -1343,6 +1384,7 @@ function listenForScrollEnd(ctx, params) {
1343
1384
  } else {
1344
1385
  idleTimeout = setTimeout(() => finish("idle"), SMOOTH_SCROLL_DURATION_MS);
1345
1386
  }
1387
+ scheduledWork.register("platformScrollCompletion", cancel);
1346
1388
  }
1347
1389
 
1348
1390
  // src/core/doMaintainScrollAtEnd.ts
@@ -1369,9 +1411,12 @@ function doMaintainScrollAtEnd(ctx) {
1369
1411
  if (!state.maintainingScrollAtEnd) {
1370
1412
  const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
1371
1413
  const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
1414
+ const scrollAtRequest = state.scroll;
1372
1415
  state.maintainingScrollAtEnd = pendingState;
1373
1416
  requestAnimationFrame(() => {
1374
- if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
1417
+ const isStillWithinThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
1418
+ const didScrollSinceRequest = state.scroll !== scrollAtRequest;
1419
+ if (isStillWithinThreshold || !didScrollSinceRequest) {
1375
1420
  state.maintainingScrollAtEnd = activeState;
1376
1421
  const scroller = refScroller.current;
1377
1422
  if (state.props.horizontal && isHorizontalRTL(state)) {
@@ -1401,6 +1446,7 @@ function doMaintainScrollAtEnd(ctx) {
1401
1446
  );
1402
1447
  } else if (state.maintainingScrollAtEnd === pendingState) {
1403
1448
  state.maintainingScrollAtEnd = void 0;
1449
+ state.pendingMaintainScrollAtEnd = false;
1404
1450
  }
1405
1451
  });
1406
1452
  } else {
@@ -1853,10 +1899,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
1853
1899
  state.mvcpAnchorLock = void 0;
1854
1900
  state.pendingNativeMVCPAdjust = void 0;
1855
1901
  state.userScrollAnchorReset = { keys: /* @__PURE__ */ new Set() };
1856
- if (state.queuedMVCPRecalculate !== void 0) {
1857
- cancelAnimationFrame(state.queuedMVCPRecalculate);
1858
- state.queuedMVCPRecalculate = void 0;
1859
- }
1902
+ state.scheduledWork.cancel("mvcpRecalculate");
1860
1903
  flushSync(runCalculateItems);
1861
1904
  scheduleFullDrawDistancePrewarm(ctx);
1862
1905
  } else {
@@ -2001,12 +2044,7 @@ function scrollTo(ctx, params) {
2001
2044
  const {
2002
2045
  props: { horizontal }
2003
2046
  } = state;
2004
- if (state.animFrameCheckFinishedScroll) {
2005
- cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
2006
- }
2007
- if (state.timeoutCheckFinishedScrollFallback) {
2008
- clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
2009
- }
2047
+ cancelScrollCompletionChecks(state);
2010
2048
  const requestedOffset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
2011
2049
  const shouldPreserveRawInitialOffsetRequest = !!isInitialScroll && ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset";
2012
2050
  const targetOffset = clampScrollOffset(ctx, requestedOffset, scrollTarget);
@@ -2111,10 +2149,7 @@ function setInitialScrollTarget(ctx, target, options) {
2111
2149
  var _a3;
2112
2150
  const { state } = ctx;
2113
2151
  state.clearPreservedInitialScrollOnNextFinish = void 0;
2114
- if (state.timeoutPreservedInitialScrollClear !== void 0) {
2115
- clearTimeout(state.timeoutPreservedInitialScrollClear);
2116
- state.timeoutPreservedInitialScrollClear = void 0;
2117
- }
2152
+ state.scheduledWork.cancel("preservedInitialScroll");
2118
2153
  state.initialScroll = target;
2119
2154
  if (options == null ? void 0 : options.resetDidFinish) {
2120
2155
  resetInitialRenderState(ctx, { resetInitialScroll: true });
@@ -2407,13 +2442,13 @@ function rearmBootstrapInitialScroll(ctx, options) {
2407
2442
  queueBootstrapInitialScrollReevaluation(ctx.state);
2408
2443
  }
2409
2444
  function createInitialScrollAtEndTarget(options) {
2410
- const { dataLength, footerSize, preserveForFooterLayout, stylePaddingBottom } = options;
2445
+ const { dataLength, footerSize, preserveForFooterLayout, stylePaddingEnd } = options;
2411
2446
  return {
2412
2447
  contentOffset: void 0,
2413
2448
  index: Math.max(0, dataLength - 1),
2414
2449
  preserveForBottomPadding: true,
2415
2450
  preserveForFooterLayout,
2416
- viewOffset: -stylePaddingBottom - footerSize,
2451
+ viewOffset: -stylePaddingEnd - footerSize,
2417
2452
  viewPosition: 1
2418
2453
  };
2419
2454
  }
@@ -2427,7 +2462,7 @@ function isRetargetableBottomAlignedInitialScrollTarget(target) {
2427
2462
  return !!(target && target.viewPosition === 1 && (shouldPreserveInitialScrollForBottomPadding(target) || shouldPreserveInitialScrollForFooterLayout(target)));
2428
2463
  }
2429
2464
  function createRetargetedBottomAlignedInitialScroll(options) {
2430
- const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom, target } = options;
2465
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd, target } = options;
2431
2466
  const preserveForFooterLayout = shouldPreserveInitialScrollForFooterLayout(target);
2432
2467
  return {
2433
2468
  ...target,
@@ -2435,7 +2470,7 @@ function createRetargetedBottomAlignedInitialScroll(options) {
2435
2470
  index: initialScrollAtEnd ? Math.max(0, dataLength - 1) : target.index,
2436
2471
  preserveForBottomPadding: true,
2437
2472
  preserveForFooterLayout,
2438
- viewOffset: -stylePaddingBottom - (preserveForFooterLayout ? footerSize : 0),
2473
+ viewOffset: -stylePaddingEnd - (preserveForFooterLayout ? footerSize : 0),
2439
2474
  viewPosition: 1
2440
2475
  };
2441
2476
  }
@@ -2443,7 +2478,7 @@ function areEquivalentBootstrapInitialScrollTargets(current, next) {
2443
2478
  return current.index === next.index && current.preserveForBottomPadding === next.preserveForBottomPadding && current.preserveForFooterLayout === next.preserveForFooterLayout && current.viewOffset === next.viewOffset && current.viewPosition === next.viewPosition;
2444
2479
  }
2445
2480
  function clearPendingInitialScrollFooterLayout(ctx, options) {
2446
- const { dataLength, stylePaddingBottom, target } = options;
2481
+ const { dataLength, stylePaddingEnd, target } = options;
2447
2482
  if (!shouldPreserveInitialScrollForFooterLayout(target)) {
2448
2483
  return;
2449
2484
  }
@@ -2451,7 +2486,7 @@ function clearPendingInitialScrollFooterLayout(ctx, options) {
2451
2486
  dataLength,
2452
2487
  footerSize: 0,
2453
2488
  preserveForFooterLayout: void 0,
2454
- stylePaddingBottom
2489
+ stylePaddingEnd
2455
2490
  });
2456
2491
  setInitialScrollTarget(ctx, clearedFooterTarget);
2457
2492
  }
@@ -2512,7 +2547,7 @@ function schedulePreservedEndAnchorCorrectionFrame(ctx, correction) {
2512
2547
  });
2513
2548
  }
2514
2549
  function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2515
- var _a3, _b;
2550
+ var _a3;
2516
2551
  const state = ctx.state;
2517
2552
  const initialScroll = state.initialScroll;
2518
2553
  if (!state.didFinishInitialScroll || ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) || (initialScroll == null ? void 0 : initialScroll.viewPosition) !== 1 || state.preservedEndAnchorCorrection) {
@@ -2524,7 +2559,7 @@ function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2524
2559
  if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
2525
2560
  clearPendingInitialScrollFooterLayout(ctx, {
2526
2561
  dataLength: state.props.data.length,
2527
- stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
2562
+ stylePaddingEnd: getStylePaddingEnd(state.props),
2528
2563
  target: initialScroll
2529
2564
  });
2530
2565
  } else {
@@ -2561,7 +2596,7 @@ function startBootstrapInitialScrollOnMount(ctx, options) {
2561
2596
  }
2562
2597
  }
2563
2598
  function handleBootstrapInitialScrollDataChange(ctx, options) {
2564
- const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingBottom } = options;
2599
+ const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingEnd } = options;
2565
2600
  const state = ctx.state;
2566
2601
  const initialScroll = state.initialScroll;
2567
2602
  if (isOffsetInitialScrollSession(state) || !initialScroll) {
@@ -2583,18 +2618,18 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2583
2618
  dataLength,
2584
2619
  footerSize: peek$(ctx, "footerSize") || 0,
2585
2620
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2586
- stylePaddingBottom
2621
+ stylePaddingEnd
2587
2622
  }) : createRetargetedBottomAlignedInitialScroll({
2588
2623
  dataLength,
2589
2624
  footerSize: peek$(ctx, "footerSize") || 0,
2590
2625
  initialScrollAtEnd,
2591
- stylePaddingBottom,
2626
+ stylePaddingEnd,
2592
2627
  target: initialScroll
2593
2628
  });
2594
2629
  if (!shouldResetDidFinish && didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2595
2630
  clearPendingInitialScrollFooterLayout(ctx, {
2596
2631
  dataLength,
2597
- stylePaddingBottom,
2632
+ stylePaddingEnd,
2598
2633
  target: initialScroll
2599
2634
  });
2600
2635
  return;
@@ -2626,7 +2661,7 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2626
2661
  }
2627
2662
  }
2628
2663
  function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2629
- const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom } = options;
2664
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd } = options;
2630
2665
  const state = ctx.state;
2631
2666
  if (!initialScrollAtEnd) {
2632
2667
  return;
@@ -2642,7 +2677,7 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2642
2677
  if (didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2643
2678
  clearPendingInitialScrollFooterLayout(ctx, {
2644
2679
  dataLength,
2645
- stylePaddingBottom,
2680
+ stylePaddingEnd,
2646
2681
  target: initialScroll
2647
2682
  });
2648
2683
  } else {
@@ -2650,13 +2685,13 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2650
2685
  dataLength,
2651
2686
  footerSize,
2652
2687
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2653
- stylePaddingBottom
2688
+ stylePaddingEnd
2654
2689
  });
2655
2690
  const didTargetChange = initialScroll.index !== updatedInitialScroll.index || initialScroll.viewPosition !== updatedInitialScroll.viewPosition || initialScroll.viewOffset !== updatedInitialScroll.viewOffset;
2656
2691
  if (!didTargetChange) {
2657
2692
  clearPendingInitialScrollFooterLayout(ctx, {
2658
2693
  dataLength,
2659
- stylePaddingBottom,
2694
+ stylePaddingEnd,
2660
2695
  target: initialScroll
2661
2696
  });
2662
2697
  } else {
@@ -2864,7 +2899,7 @@ function checkFinishedScroll(ctx, options) {
2864
2899
  return;
2865
2900
  }
2866
2901
  }
2867
- ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
2902
+ ctx.state.scheduledWork.frame(() => checkFinishedScrollFrame(ctx), "checkFinishedScrollFrame");
2868
2903
  }
2869
2904
  function hasScrollCompletionOwnership(state, options) {
2870
2905
  const { clampedTargetOffset, scrollingTo } = options;
@@ -2934,7 +2969,6 @@ function checkFinishedScrollFrame(ctx) {
2934
2969
  return;
2935
2970
  }
2936
2971
  const { state } = ctx;
2937
- state.animFrameCheckFinishedScroll = void 0;
2938
2972
  const completionState = getResolvedScrollCompletionState(ctx, scrollingTo);
2939
2973
  if (completionState.isAtResolvedTarget && hasScrollCompletionOwnership(state, {
2940
2974
  clampedTargetOffset: completionState.clampedTargetOffset,
@@ -2953,47 +2987,47 @@ function scrollToFallbackOffset(ctx, offset) {
2953
2987
  }
2954
2988
  function checkFinishedScrollFallback(ctx) {
2955
2989
  const state = ctx.state;
2990
+ if (state.scheduledWork.has("checkFinishedScrollFallback")) {
2991
+ return;
2992
+ }
2956
2993
  const scrollingTo = state.scrollingTo;
2957
2994
  const shouldFinishInitialZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
2958
2995
  const silentInitialDispatch = isSilentInitialDispatch(state, scrollingTo);
2959
2996
  const canFinishInitialWithoutNativeProgress = scrollingTo !== void 0 ? shouldFinishInitialScrollWithoutNativeProgress(state, scrollingTo) : false;
2960
2997
  const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) && !shouldFinishInitialZeroTarget && !canFinishInitialWithoutNativeProgress || !state.didContainersLayout;
2961
2998
  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
- }
2999
+ let numChecks = 0;
3000
+ const scheduleFallbackCheck = (delay) => {
3001
+ state.scheduledWork.timeout(checkHasScrolled, delay, "checkFinishedScrollFallback");
3002
+ };
3003
+ const checkHasScrolled = () => {
3004
+ var _c, _d;
3005
+ const isStillScrollingTo = state.scrollingTo;
3006
+ if (isStillScrollingTo) {
3007
+ numChecks++;
3008
+ const isNativeInitialPending = isNativeInitialNonZeroTarget(state) && !state.hasScrolled;
3009
+ const maxChecks = silentInitialDispatch ? 5 : isNativeInitialPending ? INITIAL_SCROLL_MAX_FALLBACK_CHECKS : 5;
3010
+ const shouldFinishZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
3011
+ const canFinishInitialScrollWithoutNativeProgress = shouldFinishInitialScrollWithoutNativeProgress(
3012
+ state,
3013
+ isStillScrollingTo
3014
+ );
3015
+ const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
3016
+ const canFinishAfterSilentNativeDispatch = Platform.OS === "android";
3017
+ const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
3018
+ const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
3019
+ if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
3020
+ finishScrollTo(ctx);
3021
+ } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
3022
+ const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
3023
+ scrollToFallbackOffset(ctx, targetOffset);
3024
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
3025
+ } else {
3026
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
2993
3027
  }
2994
- };
2995
- checkHasScrolled();
2996
- }, initialDelay);
3028
+ }
3029
+ };
3030
+ scheduleFallbackCheck(initialDelay);
2997
3031
  }
2998
3032
 
2999
3033
  // src/core/initialScrollLifecycle.ts
@@ -3069,7 +3103,7 @@ function handleInitialScrollDataChange(ctx, options) {
3069
3103
  initialScrollAtEnd,
3070
3104
  latestInitialScroll,
3071
3105
  latestInitialScrollSessionKind,
3072
- stylePaddingBottom,
3106
+ stylePaddingEnd,
3073
3107
  useBootstrapInitialScroll
3074
3108
  } = options;
3075
3109
  const state = ctx.state;
@@ -3099,7 +3133,7 @@ function handleInitialScrollDataChange(ctx, options) {
3099
3133
  didDataChange,
3100
3134
  initialScrollAtEnd,
3101
3135
  previousDataLength: previousInitialScrollDataLength,
3102
- stylePaddingBottom
3136
+ stylePaddingEnd
3103
3137
  });
3104
3138
  return;
3105
3139
  }
@@ -3569,7 +3603,6 @@ function setupViewability(props) {
3569
3603
  }
3570
3604
  function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end, startBuffered = start, endBuffered = end) {
3571
3605
  const {
3572
- timeouts,
3573
3606
  props: { data }
3574
3607
  } = state;
3575
3608
  for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
@@ -3579,11 +3612,10 @@ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollS
3579
3612
  viewabilityState.startBuffered = startBuffered;
3580
3613
  viewabilityState.endBuffered = endBuffered;
3581
3614
  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);
3615
+ state.scheduledWork.timeout(
3616
+ () => updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize),
3617
+ viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime
3618
+ );
3587
3619
  } else {
3588
3620
  updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
3589
3621
  }
@@ -3942,20 +3974,15 @@ function getProjectedBufferAdjustment(scrollVelocity, trailingBuffer) {
3942
3974
  }
3943
3975
  function scheduleRenderRangeProjectionSettle(ctx) {
3944
3976
  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);
3977
+ state.scheduledWork.timeout(
3978
+ () => {
3979
+ var _a3;
3980
+ state.scrollHistory.length = 0;
3981
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
3982
+ },
3983
+ RENDER_RANGE_PROJECTION_SETTLE_DELAY,
3984
+ "renderRangeProjection"
3985
+ );
3959
3986
  }
3960
3987
  function findCurrentStickyIndex(stickyArray, scroll, state) {
3961
3988
  const positions = state.positions;
@@ -4623,8 +4650,6 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4623
4650
  if (anchorIndex >= 0 && anchorIndex < data.length && state.scrollLength > 0) {
4624
4651
  nextAnchorKey = getId(state, anchorIndex);
4625
4652
  let contentBelowAnchor = 0;
4626
- const footerSize = ctx.values.get("footerSize") || 0;
4627
- const stylePaddingBottom = state.props.stylePaddingBottom || 0;
4628
4653
  let hasUnknownTailSize = false;
4629
4654
  for (let index = anchorIndex; index < data.length; index++) {
4630
4655
  const size = getKnownOrFixedItemSize(ctx, index);
@@ -4636,14 +4661,16 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4636
4661
  contentBelowAnchor += effectiveSize;
4637
4662
  }
4638
4663
  }
4639
- contentBelowAnchor += footerSize + stylePaddingBottom;
4664
+ contentBelowAnchor = Math.max(0, contentBelowAnchor - ctx.scrollAxisGap);
4665
+ contentBelowAnchor += (ctx.values.get("footerSize") || 0) + getStylePaddingEnd(state.props);
4640
4666
  isReady = !hasUnknownTailSize;
4641
4667
  nextSize = hasUnknownTailSize ? previousSize || 0 : Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
4642
4668
  } else if (anchorIndex >= 0) {
4643
4669
  isReady = false;
4644
4670
  }
4645
4671
  }
4646
- const didSizeChange = previousSize !== nextSize;
4672
+ const didSizeChange = previousSize !== nextSize && (previousSize !== void 0 || anchoredEndSpace !== void 0);
4673
+ const didEffectiveSizeChange = (previousSize || 0) !== nextSize;
4647
4674
  const didReadyAnchorChange = previousReadyAnchorIndex !== nextAnchorIndex || previousReadyAnchorKey !== nextAnchorKey;
4648
4675
  if (isReady && (didSizeChange || didReadyAnchorChange)) {
4649
4676
  state.anchoredEndSpaceReadyAnchorIndex = nextAnchorIndex;
@@ -4652,8 +4679,9 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4652
4679
  set$(ctx, "anchoredEndSpaceSize", nextSize);
4653
4680
  (_a3 = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onSizeChanged) == null ? void 0 : _a3.call(anchoredEndSpace, nextSize);
4654
4681
  }
4655
- if (didSizeChange && (anchoredEndSpace == null ? void 0 : anchoredEndSpace.includeInEndInset)) {
4656
- updateScroll(ctx, state.scroll, true);
4682
+ if (didEffectiveSizeChange) {
4683
+ updateContentMetricsState(ctx);
4684
+ updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
4657
4685
  }
4658
4686
  (_b = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onReady) == null ? void 0 : _b.call(anchoredEndSpace, { anchorIndex: nextAnchorIndex, anchorKey: nextAnchorKey, size: nextSize });
4659
4687
  }
@@ -4671,16 +4699,10 @@ function runOrScheduleMVCPRecalculate(ctx) {
4671
4699
  }
4672
4700
  } else {
4673
4701
  if (!state.mvcpAnchorLock) {
4674
- if (state.queuedMVCPRecalculate !== void 0) {
4675
- cancelAnimationFrame(state.queuedMVCPRecalculate);
4676
- state.queuedMVCPRecalculate = void 0;
4677
- }
4702
+ state.scheduledWork.cancel("mvcpRecalculate");
4678
4703
  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
- });
4704
+ } else if (!state.scheduledWork.has("mvcpRecalculate")) {
4705
+ state.scheduledWork.frame(() => calculateItemsInView(ctx, { doMVCP: true }), "mvcpRecalculate");
4684
4706
  }
4685
4707
  }
4686
4708
  }
@@ -4725,6 +4747,9 @@ function flushItemSizeUpdates(ctx, result) {
4725
4747
  } else if (result.didMeasureUserScrollAnchorResetItem && ((_a3 = state.userScrollAnchorReset) == null ? void 0 : _a3.keys.size) === 0) {
4726
4748
  state.userScrollAnchorReset = void 0;
4727
4749
  }
4750
+ if (result.didChange) {
4751
+ maybeUpdateAnchoredEndSpace(ctx);
4752
+ }
4728
4753
  if (result.didChange && result.shouldMaintainScrollAtEnd) {
4729
4754
  doMaintainScrollAtEnd(ctx);
4730
4755
  }
@@ -4814,7 +4839,6 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
4814
4839
  previous: size - diff,
4815
4840
  size
4816
4841
  });
4817
- maybeUpdateAnchoredEndSpace(ctx);
4818
4842
  }
4819
4843
  if (minIndexSizeChanged !== void 0) {
4820
4844
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
@@ -5704,24 +5728,40 @@ function useDOMOrder(ref) {
5704
5728
  };
5705
5729
  }, [ctx]);
5706
5730
  }
5731
+ function useFreshDataTransitionVisibility(readyToRender, transitionEpoch) {
5732
+ const completedTransitionEpoch = useRef(transitionEpoch);
5733
+ const isTransitionPending = completedTransitionEpoch.current !== transitionEpoch;
5734
+ useLayoutEffect(() => {
5735
+ if (!readyToRender) {
5736
+ completedTransitionEpoch.current = transitionEpoch;
5737
+ }
5738
+ }, [readyToRender, transitionEpoch]);
5739
+ return readyToRender && !isTransitionPending;
5740
+ }
5707
5741
 
5708
5742
  // src/components/Containers.tsx
5709
- var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColumns, children }) {
5743
+ var ContainersInner = typedMemo(function ContainersInner2({
5744
+ freshDataTransitionEpoch,
5745
+ horizontal,
5746
+ numColumns,
5747
+ children
5748
+ }) {
5710
5749
  const ref = useRef(null);
5711
5750
  const ctx = useStateContext();
5712
5751
  const columnWrapperStyle = ctx.columnWrapperStyle;
5713
5752
  const isHorizontalRTLList = isHorizontalRTL(ctx.state);
5714
5753
  const [otherAxisSize, readyToRender, totalSize] = useArr$(["otherAxisSize", "readyToRender", "totalSize"]);
5754
+ const isVisible = useFreshDataTransitionVisibility(!!readyToRender, freshDataTransitionEpoch);
5715
5755
  useDOMOrder(ref);
5716
5756
  const style = horizontal ? {
5717
5757
  direction: isHorizontalRTLList ? "ltr" : void 0,
5718
5758
  flexShrink: 0,
5719
5759
  minHeight: otherAxisSize,
5720
- opacity: readyToRender ? 1 : 0,
5760
+ opacity: isVisible ? 1 : 0,
5721
5761
  position: "relative",
5722
5762
  width: totalSize
5723
- } : { height: totalSize, minWidth: otherAxisSize, opacity: readyToRender ? 1 : 0, position: "relative" };
5724
- if (!readyToRender) {
5763
+ } : { height: totalSize, minWidth: otherAxisSize, opacity: isVisible ? 1 : 0, position: "relative" };
5764
+ if (!isVisible) {
5725
5765
  style.pointerEvents = "none";
5726
5766
  }
5727
5767
  if (columnWrapperStyle && numColumns > 1) {
@@ -5744,6 +5784,7 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
5744
5784
  return /* @__PURE__ */ React3.createElement("div", { ref, style }, /* @__PURE__ */ React3.createElement(ContainerLayoutCoordinator, null, children));
5745
5785
  });
5746
5786
  var Containers = typedMemo(function Containers2({
5787
+ freshDataTransitionEpoch,
5747
5788
  horizontal,
5748
5789
  recycleItems,
5749
5790
  ItemSeparatorComponent,
@@ -5768,7 +5809,15 @@ var Containers = typedMemo(function Containers2({
5768
5809
  )
5769
5810
  );
5770
5811
  }
5771
- return /* @__PURE__ */ React3.createElement(ContainersInner, { horizontal, numColumns }, containers);
5812
+ return /* @__PURE__ */ React3.createElement(
5813
+ ContainersInner,
5814
+ {
5815
+ freshDataTransitionEpoch,
5816
+ horizontal,
5817
+ numColumns
5818
+ },
5819
+ containers
5820
+ );
5772
5821
  });
5773
5822
 
5774
5823
  // src/platform/StyleSheet.tsx
@@ -5979,7 +6028,7 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
5979
6028
  onLayout,
5980
6029
  ...props
5981
6030
  }, ref) {
5982
- var _a3, _b, _c, _d;
6031
+ var _a3, _b, _c;
5983
6032
  const ctx = useStateContext();
5984
6033
  const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
5985
6034
  const scrollRef = useRef(null);
@@ -6211,7 +6260,7 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
6211
6260
  } : {}
6212
6261
  };
6213
6262
  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;
6263
+ const anchoredEndInset = ((_b = (_a3 = ctx.state) == null ? void 0 : _a3.props) == null ? void 0 : _b.anchoredEndSpace) && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
6215
6264
  const renderedContentInsetEndAdjustment = Math.max(0, contentInsetEndAdjustment - anchoredEndInset);
6216
6265
  const contentInsetEndAdjustmentSpacerStyle = renderedContentInsetEndAdjustment ? horizontal ? { flexShrink: 0, width: renderedContentInsetEndAdjustment } : { height: renderedContentInsetEndAdjustment } : void 0;
6217
6266
  const contentStyle = {
@@ -6238,7 +6287,7 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
6238
6287
  const snapOffsets = !isWindowScroll ? getFiniteSnapOffsets(snapToOffsets) : [];
6239
6288
  if (snapOffsets.length > 0) {
6240
6289
  scrollViewStyle.scrollSnapType = horizontal ? "x mandatory" : "y mandatory";
6241
- contentStyle.position = (_d = contentStyle.position) != null ? _d : "relative";
6290
+ contentStyle.position = (_c = contentStyle.position) != null ? _c : "relative";
6242
6291
  }
6243
6292
  const scrollViewClassName = hiddenScrollIndicatorClassName ? scrollViewClassNameProp ? `${scrollViewClassNameProp} ${hiddenScrollIndicatorClassName}` : hiddenScrollIndicatorClassName : scrollViewClassNameProp;
6244
6293
  if (IS_DEV) {
@@ -6387,16 +6436,6 @@ var SnapWrapper = React3.forwardRef(function SnapWrapperInner({ ScrollComponent,
6387
6436
  const [snapToOffsets] = useArr$(["snapToOffsets"]);
6388
6437
  return /* @__PURE__ */ React3.createElement(ScrollComponent, { ...props, ref, snapToOffsets });
6389
6438
  });
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
6439
 
6401
6440
  // src/core/updateContentMetrics.ts
6402
6441
  var SCROLL_ADJUST_EPSILON = 0.1;
@@ -6430,7 +6469,11 @@ function setHeaderSize(ctx, size) {
6430
6469
  state.didMeasureHeader = true;
6431
6470
  }
6432
6471
  function setFooterSize(ctx, size) {
6433
- return setContentLengthSignal(ctx, "footerSize", size);
6472
+ const didChange = setContentLengthSignal(ctx, "footerSize", size);
6473
+ if (didChange) {
6474
+ maybeUpdateAnchoredEndSpace(ctx);
6475
+ }
6476
+ return didChange;
6434
6477
  }
6435
6478
  function areInsetsEqual(left, right) {
6436
6479
  var _a3, _b, _c, _d, _e, _f, _g, _h;
@@ -6483,6 +6526,7 @@ var AlignItemsAtEndSpacer = typedMemo(function AlignItemsAtEndSpacer2({ horizont
6483
6526
  });
6484
6527
  var ListComponent = typedMemo(function ListComponent2({
6485
6528
  canRender,
6529
+ freshDataTransitionEpoch,
6486
6530
  style,
6487
6531
  contentContainerStyle,
6488
6532
  horizontal,
@@ -6512,8 +6556,17 @@ var ListComponent = typedMemo(function ListComponent2({
6512
6556
  }) {
6513
6557
  const ctx = useStateContext();
6514
6558
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
6515
- const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
6559
+ const [anchoredEndSpaceSize = 0, otherAxisSize = 0] = useArr$(["anchoredEndSpaceSize", "otherAxisSize"]);
6516
6560
  const shouldRenderAlignItemsAtEndSpacer = ctx.state.props.alignItemsAtEndPaddingEnabled;
6561
+ const shouldMaterializeAnchoredEndSpace = !!ctx.state.props.anchoredEndSpace && ctx.state.props.anchoredEndSpaceOwner === "list" && anchoredEndSpaceSize > 0;
6562
+ let anchoredEndSpaceStyle;
6563
+ if (shouldMaterializeAnchoredEndSpace) {
6564
+ const paddingEnd = horizontal ? isHorizontalRTL(ctx.state) ? "Left" : "Right" : "Bottom";
6565
+ const flattenedContentContainerStyle = StyleSheet.flatten(contentContainerStyle);
6566
+ anchoredEndSpaceStyle = {
6567
+ [`padding${paddingEnd}`]: extractPadding({}, flattenedContentContainerStyle || {}, paddingEnd) + anchoredEndSpaceSize
6568
+ };
6569
+ }
6517
6570
  const autoOtherAxisStyle = getAutoOtherAxisStyle({
6518
6571
  horizontal,
6519
6572
  needsOtherAxisSize: ctx.state.needsOtherAxisSize,
@@ -6566,10 +6619,10 @@ var ListComponent = typedMemo(function ListComponent2({
6566
6619
  ...rest,
6567
6620
  ...ScrollComponent === ListComponentScrollView ? { onInternalScrollEnd, useWindowScroll } : {} ,
6568
6621
  contentContainerStyle: [
6569
- horizontal ? {
6570
- height: "100%"
6571
- } : {},
6572
- contentContainerStyle
6622
+ horizontal ? { height: "100%" } : {},
6623
+ contentContainerStyle,
6624
+ anchoredEndSpaceStyle,
6625
+ { boxSizing: "border-box" }
6573
6626
  ],
6574
6627
  contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
6575
6628
  horizontal,
@@ -6587,6 +6640,7 @@ var ListComponent = typedMemo(function ListComponent2({
6587
6640
  canRender && !ListEmptyComponent && /* @__PURE__ */ React3.createElement(
6588
6641
  Containers,
6589
6642
  {
6643
+ freshDataTransitionEpoch,
6590
6644
  getRenderedItem: getRenderedItem2,
6591
6645
  horizontal,
6592
6646
  ItemSeparatorComponent,
@@ -6595,7 +6649,6 @@ var ListComponent = typedMemo(function ListComponent2({
6595
6649
  }
6596
6650
  ),
6597
6651
  ListFooterComponent && /* @__PURE__ */ React3.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
6598
- /* @__PURE__ */ React3.createElement(WebAnchoredEndSpace, { horizontal }),
6599
6652
  IS_DEV && ENABLE_DEVMODE
6600
6653
  );
6601
6654
  });
@@ -6604,7 +6657,16 @@ var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
6604
6657
  var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
6605
6658
  function useDevChecksImpl(props) {
6606
6659
  const ctx = useStateContext();
6607
- const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
6660
+ const { anchoredEndSpace, childrenMode, keyExtractor, numColumns, renderScrollComponent, useWindowScroll } = props;
6661
+ const hasAnchoredEndSpace = !!anchoredEndSpace;
6662
+ useEffect(() => {
6663
+ if (hasAnchoredEndSpace && (numColumns != null ? numColumns : 1) > 1) {
6664
+ warnDevOnce(
6665
+ "anchoredEndSpaceNumColumns",
6666
+ "anchoredEndSpace is only supported when numColumns is 1. Using it with multiple columns may produce incorrect anchored spacing."
6667
+ );
6668
+ }
6669
+ }, [hasAnchoredEndSpace, numColumns]);
6608
6670
  useEffect(() => {
6609
6671
  if (useWindowScroll && renderScrollComponent) {
6610
6672
  warnDevOnce(
@@ -6932,6 +6994,59 @@ function onScroll(ctx, event) {
6932
6994
  }
6933
6995
  }
6934
6996
 
6997
+ // src/core/ScheduledWork.ts
6998
+ var ScheduledWork = class {
6999
+ constructor() {
7000
+ this.work = /* @__PURE__ */ new Map();
7001
+ }
7002
+ timeout(callback, delay, key) {
7003
+ if (key) {
7004
+ this.cancel(key);
7005
+ }
7006
+ const work = [void 0, clearTimeout];
7007
+ const handle = setTimeout(() => {
7008
+ const workKey = key != null ? key : handle;
7009
+ if (this.work.get(workKey) === work) {
7010
+ this.work.delete(workKey);
7011
+ callback();
7012
+ }
7013
+ }, delay);
7014
+ work[0] = handle;
7015
+ this.work.set(key != null ? key : handle, work);
7016
+ }
7017
+ frame(callback, key) {
7018
+ this.cancel(key);
7019
+ const work = [void 0, cancelAnimationFrame];
7020
+ this.work.set(key, work);
7021
+ work[0] = requestAnimationFrame(() => {
7022
+ if (this.work.get(key) === work) {
7023
+ this.work.delete(key);
7024
+ callback();
7025
+ }
7026
+ });
7027
+ }
7028
+ register(key, cancel) {
7029
+ this.cancel(key);
7030
+ this.work.set(key, [void 0, cancel]);
7031
+ }
7032
+ cancel(key) {
7033
+ const work = this.work.get(key);
7034
+ if (work) {
7035
+ this.work.delete(key);
7036
+ work[1](work[0]);
7037
+ }
7038
+ }
7039
+ has(key) {
7040
+ return this.work.has(key);
7041
+ }
7042
+ dispose() {
7043
+ for (const [handle, cancel] of this.work.values()) {
7044
+ cancel(handle);
7045
+ }
7046
+ this.work.clear();
7047
+ }
7048
+ };
7049
+
6935
7050
  // src/core/ScrollAdjustHandler.ts
6936
7051
  var ScrollAdjustHandler = class {
6937
7052
  constructor(ctx) {
@@ -7089,7 +7204,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7089
7204
  const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
7090
7205
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
7091
7206
  let imperativeScrollToken = 0;
7092
- const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0;
7207
+ const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.scheduledWork.has("mvcpRecalculate") || state.ignoreScrollFromMVCP !== void 0;
7093
7208
  const isScrollToIndexReady = (targetIndex, allowEmpty = false) => {
7094
7209
  var _a3;
7095
7210
  const props = state.props;
@@ -7123,9 +7238,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7123
7238
  run();
7124
7239
  return;
7125
7240
  }
7126
- requestAnimationFrame(check);
7241
+ state.scheduledWork.frame(check, "imperativeScrollReady");
7127
7242
  };
7128
- requestAnimationFrame(check);
7243
+ state.scheduledWork.frame(check, "imperativeScrollReady");
7129
7244
  };
7130
7245
  const runScrollRequest = (token, resolve, run, isReady = () => true) => {
7131
7246
  const runNow = () => {
@@ -7147,10 +7262,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7147
7262
  }
7148
7263
  };
7149
7264
  const startImperativeScroll = (resolve) => {
7150
- var _a3;
7265
+ state.scheduledWork.cancel("imperativeScrollReady");
7151
7266
  const token = ++imperativeScrollToken;
7152
- state.pendingScrollToEnd = void 0;
7153
- (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
7267
+ settlePendingImperativeScroll(state);
7154
7268
  state.pendingScrollResolve = resolve;
7155
7269
  return token;
7156
7270
  };
@@ -7234,6 +7348,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7234
7348
  end: state.endNoBuffer,
7235
7349
  endBuffered: state.endBuffered,
7236
7350
  getAverageItemSizes: () => getAverageItemSizes(state),
7351
+ indexByKey: (key) => state.indexByKey.get(key),
7237
7352
  isAtEnd: peek$(ctx, "isAtEnd"),
7238
7353
  isAtStart: peek$(ctx, "isAtStart"),
7239
7354
  isEndReached: state.isEndReached,
@@ -7537,7 +7652,7 @@ var LegendList = typedMemo(
7537
7652
  })
7538
7653
  );
7539
7654
  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;
7655
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
7541
7656
  const noopOnScroll = useCallback((_event) => {
7542
7657
  }, []);
7543
7658
  if (props.recycleItems === void 0) {
@@ -7613,9 +7728,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7613
7728
  ...rest
7614
7729
  } = props;
7615
7730
  const animatedPropsInternal = props.animatedPropsInternal;
7731
+ const anchoredEndSpaceOwner = (_a3 = props.anchoredEndSpaceOwnerInternal) != null ? _a3 : "list";
7616
7732
  const positionComponentInternal = props.positionComponentInternal;
7617
7733
  const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
7618
7734
  const {
7735
+ anchoredEndSpaceOwnerInternal: _anchoredEndSpaceOwnerInternal,
7619
7736
  positionComponentInternal: _positionComponentInternal,
7620
7737
  stickyPositionComponentInternal: _stickyPositionComponentInternal,
7621
7738
  ...restProps
@@ -7637,6 +7754,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7637
7754
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
7638
7755
  const stylePaddingLeftState = extractPadding(style, contentContainerStyle, "Left");
7639
7756
  const stylePaddingRightState = extractPadding(style, contentContainerStyle, "Right");
7757
+ const stylePaddingEndState = getStylePaddingEnd({
7758
+ horizontal,
7759
+ rtl,
7760
+ stylePaddingBottom: stylePaddingBottomState,
7761
+ stylePaddingLeft: stylePaddingLeftState,
7762
+ stylePaddingRight: stylePaddingRightState
7763
+ });
7640
7764
  const maintainScrollAtEndConfig = normalizeMaintainScrollAtEnd(maintainScrollAtEnd);
7641
7765
  const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
7642
7766
  maintainVisibleContentPositionProp
@@ -7649,13 +7773,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7649
7773
  const initialScrollProp = initialScrollAtEnd ? {
7650
7774
  index: Math.max(0, dataProp.length - 1),
7651
7775
  preserveForBottomPadding: true,
7652
- viewOffset: -stylePaddingBottomState,
7776
+ viewOffset: -stylePaddingEndState,
7653
7777
  viewPosition: 1
7654
7778
  } : hasInitialScrollIndex ? typeof initialScrollIndexProp === "object" ? {
7655
- index: (_a3 = initialScrollIndexProp.index) != null ? _a3 : 0,
7779
+ index: (_b = initialScrollIndexProp.index) != null ? _b : 0,
7656
7780
  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
7781
+ viewOffset: (_c = initialScrollIndexProp.viewOffset) != null ? _c : initialScrollIndexProp.viewPosition === 1 ? -stylePaddingEndState : 0,
7782
+ viewPosition: (_d = initialScrollIndexProp.viewPosition) != null ? _d : 0
7659
7783
  } : {
7660
7784
  index: initialScrollIndexProp != null ? initialScrollIndexProp : 0,
7661
7785
  viewOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : 0
@@ -7668,7 +7792,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7668
7792
  const [, scheduleImperativeScrollCommit] = React3.useReducer((value) => value + 1, 0);
7669
7793
  const ctx = useStateContext();
7670
7794
  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;
7795
+ 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
7796
  const nextScrollAxisGap = typeof scrollAxisGap === "number" && Number.isFinite(scrollAxisGap) ? scrollAxisGap : 0;
7673
7797
  const refScroller = useRef(null);
7674
7798
  const combinedRef = useCombinedRef(refScroller, refScrollView);
@@ -7683,8 +7807,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7683
7807
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex,
7684
7808
  alwaysRender == null ? void 0 : alwaysRender.top,
7685
7809
  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(","),
7810
+ (_k = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _k.join(","),
7811
+ (_l = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _l.join(","),
7688
7812
  dataProp,
7689
7813
  dataKey,
7690
7814
  dataVersion,
@@ -7697,7 +7821,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7697
7821
  if (!refState.current) {
7698
7822
  if (!ctx.state) {
7699
7823
  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");
7824
+ ctx.values.set("adaptiveRender", (_m = experimental_adaptiveRender == null ? void 0 : experimental_adaptiveRender.initialMode) != null ? _m : "normal");
7701
7825
  ctx.state = {
7702
7826
  averageSizes: {},
7703
7827
  columnSpans: [],
@@ -7716,6 +7840,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7716
7840
  endNoBuffer: -1,
7717
7841
  endReachedSnapshot: void 0,
7718
7842
  firstFullyOnScreenIndex: -1,
7843
+ freshDataTransitionEpoch: 0,
7719
7844
  hasHadNonEmptyData: dataProp.length > 0,
7720
7845
  idCache: [],
7721
7846
  idsInView: [],
@@ -7740,8 +7865,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7740
7865
  positions: [],
7741
7866
  props: {},
7742
7867
  queuedCalculateItemsInView: 0,
7743
- queuedFullDrawDistancePrewarm: void 0,
7744
7868
  refScroller: { current: null },
7869
+ scheduledWork: new ScheduledWork(),
7745
7870
  scroll: 0,
7746
7871
  scrollAdjustHandler: new ScrollAdjustHandler(ctx),
7747
7872
  scrollForNextCalculateItemsInView: void 0,
@@ -7759,8 +7884,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7759
7884
  startReachedSnapshot: void 0,
7760
7885
  stickyContainerPool: /* @__PURE__ */ new Set(),
7761
7886
  stickyContainers: /* @__PURE__ */ new Map(),
7762
- timeoutAdaptiveRender: void 0,
7763
- timeouts: /* @__PURE__ */ new Set(),
7764
7887
  totalSize: 0,
7765
7888
  viewabilityConfigCallbackPairs: void 0
7766
7889
  };
@@ -7782,13 +7905,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7782
7905
  const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
7783
7906
  ctx.scrollAxisGap = nextScrollAxisGap;
7784
7907
  state.didColumnsChange = numColumnsProp !== previousNumColumnsProp || didScrollAxisGapChange;
7785
- const previousDataLength = (_n = (_m = state.props.data) == null ? void 0 : _m.length) != null ? _n : 0;
7908
+ const previousDataLength = (_o = (_n = state.props.data) == null ? void 0 : _n.length) != null ? _o : 0;
7786
7909
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
7787
7910
  const didDataKeyChangeLocal = state.props.dataKey !== dataKey;
7788
7911
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
7789
7912
  const didDataChangeLocal = didDataKeyChangeLocal || didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
7790
7913
  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) {
7914
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_p = state.initialScroll) == null ? void 0 : _p.viewPosition) === 1 && state.props.data.length > 0) {
7792
7915
  clearPreservedInitialScrollTarget(state);
7793
7916
  }
7794
7917
  if (didDataChangeLocal) {
@@ -7797,10 +7920,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7797
7920
  state.didDataChange = true;
7798
7921
  state.previousData = state.props.data;
7799
7922
  }
7923
+ if (shouldResetFreshDataLayout) {
7924
+ state.freshDataTransitionEpoch += 1;
7925
+ }
7800
7926
  const throttledOnScroll = useThrottledOnScroll(onScrollProp != null ? onScrollProp : noopOnScroll, scrollEventThrottle != null ? scrollEventThrottle : 0);
7801
7927
  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);
7928
+ const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_q = state.props.anchoredEndSpace) == null ? void 0 : _q.anchorIndex) !== (anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex);
7804
7929
  state.props = {
7805
7930
  adaptiveRender: experimental_adaptiveRender,
7806
7931
  alignItemsAtEnd,
@@ -7808,7 +7933,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7808
7933
  alwaysRender,
7809
7934
  alwaysRenderIndicesArr: alwaysRenderIndices.arr,
7810
7935
  alwaysRenderIndicesSet: alwaysRenderIndices.set,
7811
- anchoredEndSpace: anchoredEndSpaceResolved,
7936
+ anchoredEndSpace,
7937
+ anchoredEndSpaceOwner,
7812
7938
  animatedProps: animatedPropsInternal,
7813
7939
  contentContainerAlignItems: contentContainerStyle.alignItems,
7814
7940
  contentInset,
@@ -7857,12 +7983,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7857
7983
  if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
7858
7984
  resetAdaptiveRender(ctx);
7859
7985
  }
7860
- if (shouldResetFreshDataLayout) {
7861
- resetInitialRenderState(ctx, {
7862
- resetInitialScroll: !!initialScrollProp,
7863
- resetLayout: true
7864
- });
7865
- }
7866
7986
  const memoizedLastItemKeys = useMemo(() => {
7867
7987
  if (!dataProp.length) return [];
7868
7988
  return Array.from(
@@ -7921,6 +8041,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7921
8041
  useDevChecks(props);
7922
8042
  }
7923
8043
  useLayoutEffect(() => {
8044
+ if (shouldResetFreshDataLayout) {
8045
+ resetInitialRenderState(ctx, {
8046
+ resetInitialScroll: !!initialScrollProp,
8047
+ resetLayout: true
8048
+ });
8049
+ }
7924
8050
  handleInitialScrollDataChange(ctx, {
7925
8051
  dataLength: dataProp.length,
7926
8052
  didDataChange: didDataChangeLocal,
@@ -7928,7 +8054,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7928
8054
  initialScrollAtEnd,
7929
8055
  latestInitialScroll: initialScrollProp,
7930
8056
  latestInitialScrollSessionKind: initialScrollUsesOffsetOnly ? "offset" : "bootstrap",
7931
- stylePaddingBottom: stylePaddingBottomState,
8057
+ stylePaddingEnd: stylePaddingEndState,
7932
8058
  useBootstrapInitialScroll: usesBootstrapInitialScroll
7933
8059
  });
7934
8060
  }, [
@@ -7937,7 +8063,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7937
8063
  didDataChangeLocal,
7938
8064
  shouldResetFreshDataLayout,
7939
8065
  initialScrollAtEnd,
7940
- stylePaddingBottomState,
8066
+ stylePaddingEndState,
7941
8067
  usesBootstrapInitialScroll
7942
8068
  ]);
7943
8069
  useLayoutEffect(() => {
@@ -7955,7 +8081,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7955
8081
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorMaxSize,
7956
8082
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorOffset,
7957
8083
  didAnchoredEndSpaceAnchorIndexChange,
7958
- numColumnsProp
8084
+ horizontal,
8085
+ numColumnsProp,
8086
+ rtl,
8087
+ stylePaddingBottomState,
8088
+ stylePaddingLeftState,
8089
+ stylePaddingRightState
7959
8090
  ]);
7960
8091
  useLayoutEffect(() => {
7961
8092
  const previousContentInsetEndAdjustment = previousContentInsetEndAdjustmentRef.current;
@@ -7971,10 +8102,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7971
8102
  dataLength: dataProp.length,
7972
8103
  footerSize: layout[horizontal ? "width" : "height"],
7973
8104
  initialScrollAtEnd,
7974
- stylePaddingBottom: stylePaddingBottomState
8105
+ stylePaddingEnd: stylePaddingEndState
7975
8106
  });
7976
8107
  },
7977
- [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingBottomState, usesBootstrapInitialScroll]
8108
+ [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingEndState, usesBootstrapInitialScroll]
7978
8109
  );
7979
8110
  const onLayoutChange = useCallback(
7980
8111
  (layout, fromLayoutEffect) => {
@@ -7991,7 +8122,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7991
8122
  }
7992
8123
  advanceCurrentInitialScrollSession(ctx);
7993
8124
  },
7994
- [dataProp.length, initialScrollAtEnd, stylePaddingBottomState, usesBootstrapInitialScroll]
8125
+ [dataProp.length, initialScrollAtEnd, stylePaddingEndState, usesBootstrapInitialScroll]
7995
8126
  );
7996
8127
  const { onLayout } = useOnLayoutSync({
7997
8128
  onLayoutChange,
@@ -8084,14 +8215,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8084
8215
  useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, scheduleImperativeScrollCommit), []);
8085
8216
  useEffect(() => {
8086
8217
  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();
8218
+ cancelImperativeScroll(state);
8219
+ state.scheduledWork.dispose();
8095
8220
  };
8096
8221
  }, [state]);
8097
8222
  useLayoutEffect(() => {
@@ -8133,6 +8258,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8133
8258
  canRender,
8134
8259
  contentContainerStyle,
8135
8260
  contentInset,
8261
+ freshDataTransitionEpoch: state.freshDataTransitionEpoch,
8136
8262
  getRenderedItem: fns.getRenderedItem,
8137
8263
  horizontal,
8138
8264
  initialContentOffset,
@@ -8148,7 +8274,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8148
8274
  onScroll: onScrollHandler,
8149
8275
  recycleItems,
8150
8276
  refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React3.cloneElement(refreshControlElement, {
8151
- progressViewOffset: ((_q = refreshControlElement.props.progressViewOffset) != null ? _q : 0) + stylePaddingTopState
8277
+ progressViewOffset: ((_r = refreshControlElement.props.progressViewOffset) != null ? _r : 0) + stylePaddingTopState
8152
8278
  }) : refreshControlElement : onRefresh && /* @__PURE__ */ React3.createElement(
8153
8279
  RefreshControl,
8154
8280
  {
@@ -8159,7 +8285,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8159
8285
  ),
8160
8286
  refScrollView: combinedRef,
8161
8287
  renderScrollComponent,
8162
- scrollAdjustHandler: (_r = refState.current) == null ? void 0 : _r.scrollAdjustHandler,
8288
+ scrollAdjustHandler: (_s = refState.current) == null ? void 0 : _s.scrollAdjustHandler,
8163
8289
  scrollEventThrottle: 0,
8164
8290
  snapToIndices,
8165
8291
  stickyHeaderIndices,