@legendapp/list 3.3.3 → 3.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/react.js CHANGED
@@ -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
@@ -419,6 +434,28 @@ var EDGE_POSITION_EPSILON = 1;
419
434
  var ENABLE_DEVMODE = IS_DEV && false;
420
435
  var ENABLE_DEBUG_VIEW = IS_DEV && false;
421
436
 
437
+ // src/core/cancelImperativeScroll.ts
438
+ function cancelScrollCompletionChecks({ scheduledWork }) {
439
+ scheduledWork.cancel("checkFinishedScrollFrame");
440
+ scheduledWork.cancel("checkFinishedScrollRetryFrame");
441
+ scheduledWork.cancel("checkFinishedScrollFallback");
442
+ scheduledWork.cancel("platformScrollCompletion");
443
+ }
444
+ function settlePendingImperativeScroll(state) {
445
+ var _a3, _b;
446
+ const resolvePendingScroll = (_b = state.pendingScrollResolve) != null ? _b : (_a3 = state.pendingScrollToEnd) == null ? void 0 : _a3.resolve;
447
+ state.pendingScrollResolve = void 0;
448
+ state.pendingScrollToEnd = void 0;
449
+ resolvePendingScroll == null ? void 0 : resolvePendingScroll();
450
+ }
451
+ function cancelImperativeScroll(state) {
452
+ cancelScrollCompletionChecks(state);
453
+ state.scheduledWork.cancel("imperativeScrollReady");
454
+ state.scrollingTo = void 0;
455
+ state.scrollTargetPinnedRange = void 0;
456
+ settlePendingImperativeScroll(state);
457
+ }
458
+
422
459
  // src/core/deferredPublicOnScroll.ts
423
460
  function withResolvedContentOffset(state, event, resolvedOffset) {
424
461
  return {
@@ -782,13 +819,7 @@ var DEFAULT_WEB_ADAPTIVE_RENDER_ENTER_VELOCITY = 6;
782
819
  var DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_VELOCITY = 3;
783
820
  var DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_DELAY = 250;
784
821
  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
- }
822
+ ctx.state.scheduledWork.cancel("adaptiveRender");
792
823
  }
793
824
  function scheduleAdaptiveRenderExit(ctx, exitDelay) {
794
825
  const state = ctx.state;
@@ -796,13 +827,7 @@ function scheduleAdaptiveRenderExit(ctx, exitDelay) {
796
827
  if (exitDelay <= 0) {
797
828
  setAdaptiveRender(ctx, "normal", "scroll");
798
829
  } 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);
830
+ state.scheduledWork.timeout(() => setAdaptiveRender(ctx, "normal", "scroll"), exitDelay, "adaptiveRender");
806
831
  }
807
832
  }
808
833
  function setAdaptiveRender(ctx, mode, reason) {
@@ -833,7 +858,7 @@ function updateAdaptiveRender(ctx, scrollVelocity, options) {
833
858
  const exitDelay = (_c = adaptiveRender.exitDelay) != null ? _c : DEFAULT_WEB_ADAPTIVE_RENDER_EXIT_DELAY ;
834
859
  const threshold = currentMode === "light" ? exitVelocity : enterVelocity;
835
860
  const nextMode = (options == null ? void 0 : options.forceLight) || Math.abs(scrollVelocity) > threshold ? "light" : "normal";
836
- const previousMode = state.timeoutAdaptiveRender !== void 0 ? "normal" : currentMode;
861
+ const previousMode = state.scheduledWork.has("adaptiveRender") ? "normal" : currentMode;
837
862
  if (nextMode !== previousMode) {
838
863
  if (nextMode === "light") {
839
864
  setAdaptiveRender(ctx, "light", "scroll");
@@ -860,14 +885,13 @@ function getEffectiveDrawDistance(ctx, mode) {
860
885
  }
861
886
  function scheduleFullDrawDistancePrewarm(ctx) {
862
887
  const { state } = ctx;
863
- if (state.props.drawDistance <= INITIAL_DRAW_DISTANCE || state.queuedFullDrawDistancePrewarm !== void 0) {
888
+ if (state.props.drawDistance <= INITIAL_DRAW_DISTANCE || state.scheduledWork.has("fullDrawDistancePrewarm")) {
864
889
  return;
865
890
  }
866
- state.queuedFullDrawDistancePrewarm = requestAnimationFrame(() => {
891
+ state.scheduledWork.frame(() => {
867
892
  var _a3;
868
- state.queuedFullDrawDistancePrewarm = void 0;
869
- (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
870
- });
893
+ return (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
894
+ }, "fullDrawDistancePrewarm");
871
895
  }
872
896
 
873
897
  // src/utils/setInitialRenderState.ts
@@ -925,10 +949,7 @@ function syncInitialScrollOffset(state, offset) {
925
949
  state.scrollPrev = offset;
926
950
  }
927
951
  function clearPreservedInitialScrollTargetTimeout(state) {
928
- if (state.timeoutPreservedInitialScrollClear !== void 0) {
929
- clearTimeout(state.timeoutPreservedInitialScrollClear);
930
- state.timeoutPreservedInitialScrollClear = void 0;
931
- }
952
+ state.scheduledWork.cancel("preservedInitialScroll");
932
953
  }
933
954
  function clearPreservedInitialScrollTarget(state) {
934
955
  clearPreservedInitialScrollTargetTimeout(state);
@@ -936,6 +957,24 @@ function clearPreservedInitialScrollTarget(state) {
936
957
  state.initialScroll = void 0;
937
958
  setInitialScrollSession(state);
938
959
  }
960
+ function supersedeInitialScroll(ctx) {
961
+ var _a3, _b, _c;
962
+ const state = ctx.state;
963
+ const bootstrapInitialScroll = ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap" ? state.initialScrollSession.bootstrap : void 0;
964
+ if (state.initialScroll || bootstrapInitialScroll || ((_b = state.scrollingTo) == null ? void 0 : _b.isInitialScroll)) {
965
+ if ((bootstrapInitialScroll == null ? void 0 : bootstrapInitialScroll.frameHandle) !== void 0 && typeof cancelAnimationFrame === "function") {
966
+ cancelAnimationFrame(bootstrapInitialScroll.frameHandle);
967
+ }
968
+ if ((_c = state.scrollingTo) == null ? void 0 : _c.isInitialScroll) {
969
+ cancelScrollCompletionChecks(state);
970
+ state.scrollingTo = void 0;
971
+ state.scrollTargetPinnedRange = void 0;
972
+ }
973
+ initialScrollCompletion.resetFlags(state);
974
+ setInitialScrollSession(state, { bootstrap: null });
975
+ finishInitialScroll(ctx);
976
+ }
977
+ }
939
978
  function finishInitialScroll(ctx, options) {
940
979
  var _a3, _b, _c;
941
980
  const state = ctx.state;
@@ -957,14 +996,17 @@ function finishInitialScroll(ctx, options) {
957
996
  setInitialScrollSession(state);
958
997
  clearPreservedInitialScrollTargetTimeout(state);
959
998
  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);
999
+ state.scheduledWork.timeout(
1000
+ () => {
1001
+ var _a5;
1002
+ if (!state.didFinishInitialScroll || ((_a5 = state.scrollingTo) == null ? void 0 : _a5.isInitialScroll) || !state.initialScroll) {
1003
+ return;
1004
+ }
1005
+ clearPreservedInitialScrollTarget(state);
1006
+ },
1007
+ PRESERVED_INITIAL_SCROLL_FALLBACK_CLEAR_DELAY_MS,
1008
+ "preservedInitialScroll"
1009
+ );
968
1010
  }
969
1011
  } else {
970
1012
  clearPreservedInitialScrollTarget(state);
@@ -991,9 +1033,11 @@ function calculateOffsetForIndex(ctx, index) {
991
1033
  return index !== void 0 ? state.positions[index] || 0 : 0;
992
1034
  }
993
1035
 
994
- // src/core/getTopOffsetAdjustment.ts
995
- function getTopOffsetAdjustment(ctx) {
996
- return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
1036
+ // src/core/getStartOffsetAdjustment.ts
1037
+ function getStartOffsetAdjustment(ctx) {
1038
+ const { state } = ctx;
1039
+ const stylePaddingStart = state.props.horizontal ? (isHorizontalRTL(state) ? state.props.stylePaddingRight : state.props.stylePaddingLeft) || 0 : peek$(ctx, "stylePaddingTop") || 0;
1040
+ return stylePaddingStart + (peek$(ctx, "alignItemsAtEndPadding") || 0) + (peek$(ctx, "headerSize") || 0);
997
1041
  }
998
1042
 
999
1043
  // src/utils/getId.ts
@@ -1204,9 +1248,9 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1204
1248
  offset -= viewOffset;
1205
1249
  }
1206
1250
  if (index !== void 0) {
1207
- const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
1208
- if (topOffsetAdjustment) {
1209
- offset += topOffsetAdjustment;
1251
+ const startOffsetAdjustment = getStartOffsetAdjustment(ctx);
1252
+ if (startOffsetAdjustment) {
1253
+ offset += startOffsetAdjustment;
1210
1254
  }
1211
1255
  }
1212
1256
  if (viewPosition !== void 0 && index !== void 0) {
@@ -1216,7 +1260,8 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
1216
1260
  }
1217
1261
  const isOutOfBounds = index < 0 || index >= dataLength;
1218
1262
  const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
1219
- const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1263
+ const measuredItemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
1264
+ const itemSize = Math.max(0, measuredItemSize - (isOutOfBounds ? 0 : ctx.scrollAxisGap));
1220
1265
  const trailingInset = getContentInsetEnd(ctx);
1221
1266
  offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
1222
1267
  if (!isOutOfBounds && index === state.props.data.length - 1) {
@@ -1248,6 +1293,7 @@ function finishScrollTo(ctx) {
1248
1293
  var _a3, _b;
1249
1294
  const state = ctx.state;
1250
1295
  if (state == null ? void 0 : state.scrollingTo) {
1296
+ cancelScrollCompletionChecks(state);
1251
1297
  const resolvePendingScroll = state.pendingScrollResolve;
1252
1298
  state.pendingScrollResolve = void 0;
1253
1299
  const scrollingTo = state.scrollingTo;
@@ -1289,6 +1335,7 @@ function doScrollTo(ctx, params) {
1289
1335
  var _a3, _b;
1290
1336
  const state = ctx.state;
1291
1337
  const { animated, horizontal, offset } = params;
1338
+ state.scheduledWork.cancel("platformScrollCompletion");
1292
1339
  const scroller = state.refScroller.current;
1293
1340
  const node = scroller == null ? void 0 : scroller.getScrollableNode();
1294
1341
  if (!scroller || !node) {
@@ -1309,9 +1356,16 @@ function doScrollTo(ctx, params) {
1309
1356
  });
1310
1357
  } else {
1311
1358
  state.scroll = offset;
1312
- setTimeout(() => {
1313
- finishScrollTo(ctx);
1314
- }, 100);
1359
+ const targetToken = state.scrollingTo;
1360
+ state.scheduledWork.timeout(
1361
+ () => {
1362
+ if (targetToken === state.scrollingTo) {
1363
+ finishScrollTo(ctx);
1364
+ }
1365
+ },
1366
+ 100,
1367
+ "platformScrollCompletion"
1368
+ );
1315
1369
  }
1316
1370
  }
1317
1371
  function listenForScrollEnd(ctx, params) {
@@ -1323,23 +1377,28 @@ function listenForScrollEnd(ctx, params) {
1323
1377
  const supportsScrollEnd = "onscrollend" in target;
1324
1378
  let idleTimeout;
1325
1379
  let settled = false;
1326
- const targetToken = ctx.state.scrollingTo;
1380
+ const { scheduledWork, scrollingTo: targetToken } = ctx.state;
1327
1381
  const maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
1328
1382
  const cleanup = () => {
1329
1383
  target.removeEventListener("scroll", onScroll2);
1330
1384
  if (supportsScrollEnd) {
1331
1385
  target.removeEventListener("scrollend", onScrollEnd);
1332
1386
  }
1333
- if (idleTimeout) {
1387
+ if (idleTimeout !== void 0) {
1334
1388
  clearTimeout(idleTimeout);
1335
1389
  }
1336
1390
  clearTimeout(maxTimeout);
1337
1391
  };
1392
+ const cancel = () => {
1393
+ if (!settled) {
1394
+ settled = true;
1395
+ cleanup();
1396
+ }
1397
+ };
1338
1398
  const finish = (reason) => {
1339
1399
  if (settled) return;
1340
1400
  if (targetToken !== ctx.state.scrollingTo) {
1341
- settled = true;
1342
- cleanup();
1401
+ scheduledWork.cancel("platformScrollCompletion");
1343
1402
  return;
1344
1403
  }
1345
1404
  const currentOffset = readOffset();
@@ -1347,12 +1406,11 @@ function listenForScrollEnd(ctx, params) {
1347
1406
  if (reason === "scrollend" && !isNearTarget) {
1348
1407
  return;
1349
1408
  }
1350
- settled = true;
1351
- cleanup();
1409
+ scheduledWork.cancel("platformScrollCompletion");
1352
1410
  finishScrollTo(ctx);
1353
1411
  };
1354
1412
  const onScroll2 = () => {
1355
- if (idleTimeout) {
1413
+ if (idleTimeout !== void 0) {
1356
1414
  clearTimeout(idleTimeout);
1357
1415
  }
1358
1416
  idleTimeout = setTimeout(() => finish("idle"), SCROLL_END_IDLE_MS);
@@ -1364,6 +1422,7 @@ function listenForScrollEnd(ctx, params) {
1364
1422
  } else {
1365
1423
  idleTimeout = setTimeout(() => finish("idle"), SMOOTH_SCROLL_DURATION_MS);
1366
1424
  }
1425
+ scheduledWork.register("platformScrollCompletion", cancel);
1367
1426
  }
1368
1427
 
1369
1428
  // src/core/doMaintainScrollAtEnd.ts
@@ -1390,9 +1449,12 @@ function doMaintainScrollAtEnd(ctx) {
1390
1449
  if (!state.maintainingScrollAtEnd) {
1391
1450
  const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
1392
1451
  const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
1452
+ const scrollAtRequest = state.scroll;
1393
1453
  state.maintainingScrollAtEnd = pendingState;
1394
1454
  requestAnimationFrame(() => {
1395
- if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
1455
+ const isStillWithinThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
1456
+ const didScrollSinceRequest = state.scroll !== scrollAtRequest;
1457
+ if (isStillWithinThreshold || !didScrollSinceRequest) {
1396
1458
  state.maintainingScrollAtEnd = activeState;
1397
1459
  const scroller = refScroller.current;
1398
1460
  if (state.props.horizontal && isHorizontalRTL(state)) {
@@ -1422,6 +1484,7 @@ function doMaintainScrollAtEnd(ctx) {
1422
1484
  );
1423
1485
  } else if (state.maintainingScrollAtEnd === pendingState) {
1424
1486
  state.maintainingScrollAtEnd = void 0;
1487
+ state.pendingMaintainScrollAtEnd = false;
1425
1488
  }
1426
1489
  });
1427
1490
  } else {
@@ -1874,10 +1937,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
1874
1937
  state.mvcpAnchorLock = void 0;
1875
1938
  state.pendingNativeMVCPAdjust = void 0;
1876
1939
  state.userScrollAnchorReset = { keys: /* @__PURE__ */ new Set() };
1877
- if (state.queuedMVCPRecalculate !== void 0) {
1878
- cancelAnimationFrame(state.queuedMVCPRecalculate);
1879
- state.queuedMVCPRecalculate = void 0;
1880
- }
1940
+ state.scheduledWork.cancel("mvcpRecalculate");
1881
1941
  ReactDOM.flushSync(runCalculateItems);
1882
1942
  scheduleFullDrawDistancePrewarm(ctx);
1883
1943
  } else {
@@ -2022,12 +2082,7 @@ function scrollTo(ctx, params) {
2022
2082
  const {
2023
2083
  props: { horizontal }
2024
2084
  } = state;
2025
- if (state.animFrameCheckFinishedScroll) {
2026
- cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
2027
- }
2028
- if (state.timeoutCheckFinishedScrollFallback) {
2029
- clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
2030
- }
2085
+ cancelScrollCompletionChecks(state);
2031
2086
  const requestedOffset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
2032
2087
  const shouldPreserveRawInitialOffsetRequest = !!isInitialScroll && ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset";
2033
2088
  const targetOffset = clampScrollOffset(ctx, requestedOffset, scrollTarget);
@@ -2132,10 +2187,7 @@ function setInitialScrollTarget(ctx, target, options) {
2132
2187
  var _a3;
2133
2188
  const { state } = ctx;
2134
2189
  state.clearPreservedInitialScrollOnNextFinish = void 0;
2135
- if (state.timeoutPreservedInitialScrollClear !== void 0) {
2136
- clearTimeout(state.timeoutPreservedInitialScrollClear);
2137
- state.timeoutPreservedInitialScrollClear = void 0;
2138
- }
2190
+ state.scheduledWork.cancel("preservedInitialScroll");
2139
2191
  state.initialScroll = target;
2140
2192
  if (options == null ? void 0 : options.resetDidFinish) {
2141
2193
  resetInitialRenderState(ctx, { resetInitialScroll: true });
@@ -2428,13 +2480,13 @@ function rearmBootstrapInitialScroll(ctx, options) {
2428
2480
  queueBootstrapInitialScrollReevaluation(ctx.state);
2429
2481
  }
2430
2482
  function createInitialScrollAtEndTarget(options) {
2431
- const { dataLength, footerSize, preserveForFooterLayout, stylePaddingBottom } = options;
2483
+ const { dataLength, footerSize, preserveForFooterLayout, stylePaddingEnd } = options;
2432
2484
  return {
2433
2485
  contentOffset: void 0,
2434
2486
  index: Math.max(0, dataLength - 1),
2435
2487
  preserveForBottomPadding: true,
2436
2488
  preserveForFooterLayout,
2437
- viewOffset: -stylePaddingBottom - footerSize,
2489
+ viewOffset: -stylePaddingEnd - footerSize,
2438
2490
  viewPosition: 1
2439
2491
  };
2440
2492
  }
@@ -2448,7 +2500,7 @@ function isRetargetableBottomAlignedInitialScrollTarget(target) {
2448
2500
  return !!(target && target.viewPosition === 1 && (shouldPreserveInitialScrollForBottomPadding(target) || shouldPreserveInitialScrollForFooterLayout(target)));
2449
2501
  }
2450
2502
  function createRetargetedBottomAlignedInitialScroll(options) {
2451
- const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom, target } = options;
2503
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd, target } = options;
2452
2504
  const preserveForFooterLayout = shouldPreserveInitialScrollForFooterLayout(target);
2453
2505
  return {
2454
2506
  ...target,
@@ -2456,7 +2508,7 @@ function createRetargetedBottomAlignedInitialScroll(options) {
2456
2508
  index: initialScrollAtEnd ? Math.max(0, dataLength - 1) : target.index,
2457
2509
  preserveForBottomPadding: true,
2458
2510
  preserveForFooterLayout,
2459
- viewOffset: -stylePaddingBottom - (preserveForFooterLayout ? footerSize : 0),
2511
+ viewOffset: -stylePaddingEnd - (preserveForFooterLayout ? footerSize : 0),
2460
2512
  viewPosition: 1
2461
2513
  };
2462
2514
  }
@@ -2464,7 +2516,7 @@ function areEquivalentBootstrapInitialScrollTargets(current, next) {
2464
2516
  return current.index === next.index && current.preserveForBottomPadding === next.preserveForBottomPadding && current.preserveForFooterLayout === next.preserveForFooterLayout && current.viewOffset === next.viewOffset && current.viewPosition === next.viewPosition;
2465
2517
  }
2466
2518
  function clearPendingInitialScrollFooterLayout(ctx, options) {
2467
- const { dataLength, stylePaddingBottom, target } = options;
2519
+ const { dataLength, stylePaddingEnd, target } = options;
2468
2520
  if (!shouldPreserveInitialScrollForFooterLayout(target)) {
2469
2521
  return;
2470
2522
  }
@@ -2472,7 +2524,7 @@ function clearPendingInitialScrollFooterLayout(ctx, options) {
2472
2524
  dataLength,
2473
2525
  footerSize: 0,
2474
2526
  preserveForFooterLayout: void 0,
2475
- stylePaddingBottom
2527
+ stylePaddingEnd
2476
2528
  });
2477
2529
  setInitialScrollTarget(ctx, clearedFooterTarget);
2478
2530
  }
@@ -2533,7 +2585,7 @@ function schedulePreservedEndAnchorCorrectionFrame(ctx, correction) {
2533
2585
  });
2534
2586
  }
2535
2587
  function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2536
- var _a3, _b;
2588
+ var _a3;
2537
2589
  const state = ctx.state;
2538
2590
  const initialScroll = state.initialScroll;
2539
2591
  if (!state.didFinishInitialScroll || ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) || (initialScroll == null ? void 0 : initialScroll.viewPosition) !== 1 || state.preservedEndAnchorCorrection) {
@@ -2545,7 +2597,7 @@ function clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx) {
2545
2597
  if (shouldPreserveInitialScrollForFooterLayout(initialScroll)) {
2546
2598
  clearPendingInitialScrollFooterLayout(ctx, {
2547
2599
  dataLength: state.props.data.length,
2548
- stylePaddingBottom: (_b = state.props.stylePaddingBottom) != null ? _b : 0,
2600
+ stylePaddingEnd: getStylePaddingEnd(state.props),
2549
2601
  target: initialScroll
2550
2602
  });
2551
2603
  } else {
@@ -2582,7 +2634,7 @@ function startBootstrapInitialScrollOnMount(ctx, options) {
2582
2634
  }
2583
2635
  }
2584
2636
  function handleBootstrapInitialScrollDataChange(ctx, options) {
2585
- const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingBottom } = options;
2637
+ const { dataLength, didDataChange, initialScrollAtEnd, previousDataLength, stylePaddingEnd } = options;
2586
2638
  const state = ctx.state;
2587
2639
  const initialScroll = state.initialScroll;
2588
2640
  if (isOffsetInitialScrollSession(state) || !initialScroll) {
@@ -2604,18 +2656,18 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2604
2656
  dataLength,
2605
2657
  footerSize: peek$(ctx, "footerSize") || 0,
2606
2658
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2607
- stylePaddingBottom
2659
+ stylePaddingEnd
2608
2660
  }) : createRetargetedBottomAlignedInitialScroll({
2609
2661
  dataLength,
2610
2662
  footerSize: peek$(ctx, "footerSize") || 0,
2611
2663
  initialScrollAtEnd,
2612
- stylePaddingBottom,
2664
+ stylePaddingEnd,
2613
2665
  target: initialScroll
2614
2666
  });
2615
2667
  if (!shouldResetDidFinish && didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2616
2668
  clearPendingInitialScrollFooterLayout(ctx, {
2617
2669
  dataLength,
2618
- stylePaddingBottom,
2670
+ stylePaddingEnd,
2619
2671
  target: initialScroll
2620
2672
  });
2621
2673
  return;
@@ -2647,7 +2699,7 @@ function handleBootstrapInitialScrollDataChange(ctx, options) {
2647
2699
  }
2648
2700
  }
2649
2701
  function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2650
- const { dataLength, footerSize, initialScrollAtEnd, stylePaddingBottom } = options;
2702
+ const { dataLength, footerSize, initialScrollAtEnd, stylePaddingEnd } = options;
2651
2703
  const state = ctx.state;
2652
2704
  if (!initialScrollAtEnd) {
2653
2705
  return;
@@ -2663,7 +2715,7 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2663
2715
  if (didFinishedInitialScrollMoveAwayFromTarget(ctx, initialScroll)) {
2664
2716
  clearPendingInitialScrollFooterLayout(ctx, {
2665
2717
  dataLength,
2666
- stylePaddingBottom,
2718
+ stylePaddingEnd,
2667
2719
  target: initialScroll
2668
2720
  });
2669
2721
  } else {
@@ -2671,13 +2723,13 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
2671
2723
  dataLength,
2672
2724
  footerSize,
2673
2725
  preserveForFooterLayout: shouldPreserveInitialScrollForFooterLayout(initialScroll),
2674
- stylePaddingBottom
2726
+ stylePaddingEnd
2675
2727
  });
2676
2728
  const didTargetChange = initialScroll.index !== updatedInitialScroll.index || initialScroll.viewPosition !== updatedInitialScroll.viewPosition || initialScroll.viewOffset !== updatedInitialScroll.viewOffset;
2677
2729
  if (!didTargetChange) {
2678
2730
  clearPendingInitialScrollFooterLayout(ctx, {
2679
2731
  dataLength,
2680
- stylePaddingBottom,
2732
+ stylePaddingEnd,
2681
2733
  target: initialScroll
2682
2734
  });
2683
2735
  } else {
@@ -2885,7 +2937,7 @@ function checkFinishedScroll(ctx, options) {
2885
2937
  return;
2886
2938
  }
2887
2939
  }
2888
- ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
2940
+ ctx.state.scheduledWork.frame(() => checkFinishedScrollFrame(ctx), "checkFinishedScrollFrame");
2889
2941
  }
2890
2942
  function hasScrollCompletionOwnership(state, options) {
2891
2943
  const { clampedTargetOffset, scrollingTo } = options;
@@ -2955,7 +3007,6 @@ function checkFinishedScrollFrame(ctx) {
2955
3007
  return;
2956
3008
  }
2957
3009
  const { state } = ctx;
2958
- state.animFrameCheckFinishedScroll = void 0;
2959
3010
  const completionState = getResolvedScrollCompletionState(ctx, scrollingTo);
2960
3011
  if (completionState.isAtResolvedTarget && hasScrollCompletionOwnership(state, {
2961
3012
  clampedTargetOffset: completionState.clampedTargetOffset,
@@ -2974,47 +3025,47 @@ function scrollToFallbackOffset(ctx, offset) {
2974
3025
  }
2975
3026
  function checkFinishedScrollFallback(ctx) {
2976
3027
  const state = ctx.state;
3028
+ if (state.scheduledWork.has("checkFinishedScrollFallback")) {
3029
+ return;
3030
+ }
2977
3031
  const scrollingTo = state.scrollingTo;
2978
3032
  const shouldFinishInitialZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
2979
3033
  const silentInitialDispatch = isSilentInitialDispatch(state, scrollingTo);
2980
3034
  const canFinishInitialWithoutNativeProgress = scrollingTo !== void 0 ? shouldFinishInitialScrollWithoutNativeProgress(state, scrollingTo) : false;
2981
3035
  const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) && !shouldFinishInitialZeroTarget && !canFinishInitialWithoutNativeProgress || !state.didContainersLayout;
2982
3036
  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
- }
3037
+ let numChecks = 0;
3038
+ const scheduleFallbackCheck = (delay) => {
3039
+ state.scheduledWork.timeout(checkHasScrolled, delay, "checkFinishedScrollFallback");
3040
+ };
3041
+ const checkHasScrolled = () => {
3042
+ var _c, _d;
3043
+ const isStillScrollingTo = state.scrollingTo;
3044
+ if (isStillScrollingTo) {
3045
+ numChecks++;
3046
+ const isNativeInitialPending = isNativeInitialNonZeroTarget(state) && !state.hasScrolled;
3047
+ const maxChecks = silentInitialDispatch ? 5 : isNativeInitialPending ? INITIAL_SCROLL_MAX_FALLBACK_CHECKS : 5;
3048
+ const shouldFinishZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
3049
+ const canFinishInitialScrollWithoutNativeProgress = shouldFinishInitialScrollWithoutNativeProgress(
3050
+ state,
3051
+ isStillScrollingTo
3052
+ );
3053
+ const completionState = getResolvedScrollCompletionState(ctx, isStillScrollingTo);
3054
+ const canFinishAfterSilentNativeDispatch = Platform.OS === "android";
3055
+ const shouldFinishAfterObservedScroll = state.hasScrolled && (!isStillScrollingTo.isInitialScroll || completionState.isAtResolvedTarget);
3056
+ const shouldRetryUnalignedInitialScroll = isStillScrollingTo.isInitialScroll && !completionState.isAtResolvedTarget && numChecks <= maxChecks;
3057
+ if (shouldFinishZeroTarget || shouldFinishAfterObservedScroll || canFinishInitialScrollWithoutNativeProgress || canFinishAfterSilentNativeDispatch || numChecks > maxChecks) {
3058
+ finishScrollTo(ctx);
3059
+ } else if ((isNativeInitialPending || shouldRetryUnalignedInitialScroll) && numChecks <= maxChecks) {
3060
+ const targetOffset = (_d = (_c = getInitialScrollWatchdogTargetOffset(state)) != null ? _c : isStillScrollingTo.targetOffset) != null ? _d : state.scrollPending;
3061
+ scrollToFallbackOffset(ctx, targetOffset);
3062
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
3063
+ } else {
3064
+ scheduleFallbackCheck(silentInitialDispatch ? SILENT_INITIAL_SCROLL_RETRY_DELAY_MS : 100);
3014
3065
  }
3015
- };
3016
- checkHasScrolled();
3017
- }, initialDelay);
3066
+ }
3067
+ };
3068
+ scheduleFallbackCheck(initialDelay);
3018
3069
  }
3019
3070
 
3020
3071
  // src/core/initialScrollLifecycle.ts
@@ -3090,7 +3141,7 @@ function handleInitialScrollDataChange(ctx, options) {
3090
3141
  initialScrollAtEnd,
3091
3142
  latestInitialScroll,
3092
3143
  latestInitialScrollSessionKind,
3093
- stylePaddingBottom,
3144
+ stylePaddingEnd,
3094
3145
  useBootstrapInitialScroll
3095
3146
  } = options;
3096
3147
  const state = ctx.state;
@@ -3120,7 +3171,7 @@ function handleInitialScrollDataChange(ctx, options) {
3120
3171
  didDataChange,
3121
3172
  initialScrollAtEnd,
3122
3173
  previousDataLength: previousInitialScrollDataLength,
3123
- stylePaddingBottom
3174
+ stylePaddingEnd
3124
3175
  });
3125
3176
  return;
3126
3177
  }
@@ -3590,7 +3641,6 @@ function setupViewability(props) {
3590
3641
  }
3591
3642
  function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end, startBuffered = start, endBuffered = end) {
3592
3643
  const {
3593
- timeouts,
3594
3644
  props: { data }
3595
3645
  } = state;
3596
3646
  for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
@@ -3600,11 +3650,10 @@ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollS
3600
3650
  viewabilityState.startBuffered = startBuffered;
3601
3651
  viewabilityState.endBuffered = endBuffered;
3602
3652
  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);
3653
+ state.scheduledWork.timeout(
3654
+ () => updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize),
3655
+ viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime
3656
+ );
3608
3657
  } else {
3609
3658
  updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
3610
3659
  }
@@ -3963,20 +4012,15 @@ function getProjectedBufferAdjustment(scrollVelocity, trailingBuffer) {
3963
4012
  }
3964
4013
  function scheduleRenderRangeProjectionSettle(ctx) {
3965
4014
  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);
4015
+ state.scheduledWork.timeout(
4016
+ () => {
4017
+ var _a3;
4018
+ state.scrollHistory.length = 0;
4019
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state);
4020
+ },
4021
+ RENDER_RANGE_PROJECTION_SETTLE_DELAY,
4022
+ "renderRangeProjection"
4023
+ );
3980
4024
  }
3981
4025
  function findCurrentStickyIndex(stickyArray, scroll, state) {
3982
4026
  const positions = state.positions;
@@ -4644,8 +4688,6 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4644
4688
  if (anchorIndex >= 0 && anchorIndex < data.length && state.scrollLength > 0) {
4645
4689
  nextAnchorKey = getId(state, anchorIndex);
4646
4690
  let contentBelowAnchor = 0;
4647
- const footerSize = ctx.values.get("footerSize") || 0;
4648
- const stylePaddingBottom = state.props.stylePaddingBottom || 0;
4649
4691
  let hasUnknownTailSize = false;
4650
4692
  for (let index = anchorIndex; index < data.length; index++) {
4651
4693
  const size = getKnownOrFixedItemSize(ctx, index);
@@ -4657,14 +4699,16 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4657
4699
  contentBelowAnchor += effectiveSize;
4658
4700
  }
4659
4701
  }
4660
- contentBelowAnchor += footerSize + stylePaddingBottom;
4702
+ contentBelowAnchor = Math.max(0, contentBelowAnchor - ctx.scrollAxisGap);
4703
+ contentBelowAnchor += (ctx.values.get("footerSize") || 0) + getStylePaddingEnd(state.props);
4661
4704
  isReady = !hasUnknownTailSize;
4662
4705
  nextSize = hasUnknownTailSize ? previousSize || 0 : Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
4663
4706
  } else if (anchorIndex >= 0) {
4664
4707
  isReady = false;
4665
4708
  }
4666
4709
  }
4667
- const didSizeChange = previousSize !== nextSize;
4710
+ const didSizeChange = previousSize !== nextSize && (previousSize !== void 0 || anchoredEndSpace !== void 0);
4711
+ const didEffectiveSizeChange = (previousSize || 0) !== nextSize;
4668
4712
  const didReadyAnchorChange = previousReadyAnchorIndex !== nextAnchorIndex || previousReadyAnchorKey !== nextAnchorKey;
4669
4713
  if (isReady && (didSizeChange || didReadyAnchorChange)) {
4670
4714
  state.anchoredEndSpaceReadyAnchorIndex = nextAnchorIndex;
@@ -4673,8 +4717,9 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4673
4717
  set$(ctx, "anchoredEndSpaceSize", nextSize);
4674
4718
  (_a3 = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onSizeChanged) == null ? void 0 : _a3.call(anchoredEndSpace, nextSize);
4675
4719
  }
4676
- if (didSizeChange && (anchoredEndSpace == null ? void 0 : anchoredEndSpace.includeInEndInset)) {
4677
- updateScroll(ctx, state.scroll, true);
4720
+ if (didEffectiveSizeChange) {
4721
+ updateContentMetricsState(ctx);
4722
+ updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
4678
4723
  }
4679
4724
  (_b = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onReady) == null ? void 0 : _b.call(anchoredEndSpace, { anchorIndex: nextAnchorIndex, anchorKey: nextAnchorKey, size: nextSize });
4680
4725
  }
@@ -4692,16 +4737,10 @@ function runOrScheduleMVCPRecalculate(ctx) {
4692
4737
  }
4693
4738
  } else {
4694
4739
  if (!state.mvcpAnchorLock) {
4695
- if (state.queuedMVCPRecalculate !== void 0) {
4696
- cancelAnimationFrame(state.queuedMVCPRecalculate);
4697
- state.queuedMVCPRecalculate = void 0;
4698
- }
4740
+ state.scheduledWork.cancel("mvcpRecalculate");
4699
4741
  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
- });
4742
+ } else if (!state.scheduledWork.has("mvcpRecalculate")) {
4743
+ state.scheduledWork.frame(() => calculateItemsInView(ctx, { doMVCP: true }), "mvcpRecalculate");
4705
4744
  }
4706
4745
  }
4707
4746
  }
@@ -4746,6 +4785,9 @@ function flushItemSizeUpdates(ctx, result) {
4746
4785
  } else if (result.didMeasureUserScrollAnchorResetItem && ((_a3 = state.userScrollAnchorReset) == null ? void 0 : _a3.keys.size) === 0) {
4747
4786
  state.userScrollAnchorReset = void 0;
4748
4787
  }
4788
+ if (result.didChange) {
4789
+ maybeUpdateAnchoredEndSpace(ctx);
4790
+ }
4749
4791
  if (result.didChange && result.shouldMaintainScrollAtEnd) {
4750
4792
  doMaintainScrollAtEnd(ctx);
4751
4793
  }
@@ -4825,7 +4867,7 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
4825
4867
  if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
4826
4868
  needsRecalculate = true;
4827
4869
  }
4828
- if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
4870
+ if (prevSizeKnown === void 0 || Math.abs(prevSizeKnown - size) > 5) {
4829
4871
  shouldMaintainScrollAtEnd = true;
4830
4872
  }
4831
4873
  onItemSizeChanged == null ? void 0 : onItemSizeChanged({
@@ -4835,7 +4877,6 @@ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
4835
4877
  previous: size - diff,
4836
4878
  size
4837
4879
  });
4838
- maybeUpdateAnchoredEndSpace(ctx);
4839
4880
  }
4840
4881
  if (minIndexSizeChanged !== void 0) {
4841
4882
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
@@ -5725,24 +5766,38 @@ function useDOMOrder(ref) {
5725
5766
  };
5726
5767
  }, [ctx]);
5727
5768
  }
5769
+ function useFreshDataTransitionVisibility(readyToRender, transitionEpoch) {
5770
+ const [completedTransitionEpoch, setCompletedTransitionEpoch] = React3.useState(transitionEpoch);
5771
+ const isTransitionPending = completedTransitionEpoch !== transitionEpoch;
5772
+ React3.useLayoutEffect(() => {
5773
+ setCompletedTransitionEpoch(transitionEpoch);
5774
+ }, [transitionEpoch]);
5775
+ return readyToRender && !isTransitionPending;
5776
+ }
5728
5777
 
5729
5778
  // src/components/Containers.tsx
5730
- var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColumns, children }) {
5779
+ var ContainersInner = typedMemo(function ContainersInner2({
5780
+ freshDataTransitionEpoch,
5781
+ horizontal,
5782
+ numColumns,
5783
+ children
5784
+ }) {
5731
5785
  const ref = React3.useRef(null);
5732
5786
  const ctx = useStateContext();
5733
5787
  const columnWrapperStyle = ctx.columnWrapperStyle;
5734
5788
  const isHorizontalRTLList = isHorizontalRTL(ctx.state);
5735
5789
  const [otherAxisSize, readyToRender, totalSize] = useArr$(["otherAxisSize", "readyToRender", "totalSize"]);
5790
+ const isVisible = useFreshDataTransitionVisibility(!!readyToRender, freshDataTransitionEpoch);
5736
5791
  useDOMOrder(ref);
5737
5792
  const style = horizontal ? {
5738
5793
  direction: isHorizontalRTLList ? "ltr" : void 0,
5739
5794
  flexShrink: 0,
5740
5795
  minHeight: otherAxisSize,
5741
- opacity: readyToRender ? 1 : 0,
5796
+ opacity: isVisible ? 1 : 0,
5742
5797
  position: "relative",
5743
5798
  width: totalSize
5744
- } : { height: totalSize, minWidth: otherAxisSize, opacity: readyToRender ? 1 : 0, position: "relative" };
5745
- if (!readyToRender) {
5799
+ } : { height: totalSize, minWidth: otherAxisSize, opacity: isVisible ? 1 : 0, position: "relative" };
5800
+ if (!isVisible) {
5746
5801
  style.pointerEvents = "none";
5747
5802
  }
5748
5803
  if (columnWrapperStyle && numColumns > 1) {
@@ -5765,6 +5820,7 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
5765
5820
  return /* @__PURE__ */ React3__namespace.createElement("div", { ref, style }, /* @__PURE__ */ React3__namespace.createElement(ContainerLayoutCoordinator, null, children));
5766
5821
  });
5767
5822
  var Containers = typedMemo(function Containers2({
5823
+ freshDataTransitionEpoch,
5768
5824
  horizontal,
5769
5825
  recycleItems,
5770
5826
  ItemSeparatorComponent,
@@ -5789,7 +5845,15 @@ var Containers = typedMemo(function Containers2({
5789
5845
  )
5790
5846
  );
5791
5847
  }
5792
- return /* @__PURE__ */ React3__namespace.createElement(ContainersInner, { horizontal, numColumns }, containers);
5848
+ return /* @__PURE__ */ React3__namespace.createElement(
5849
+ ContainersInner,
5850
+ {
5851
+ freshDataTransitionEpoch,
5852
+ horizontal,
5853
+ numColumns
5854
+ },
5855
+ containers
5856
+ );
5793
5857
  });
5794
5858
 
5795
5859
  // src/platform/StyleSheet.tsx
@@ -6000,7 +6064,7 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
6000
6064
  onLayout,
6001
6065
  ...props
6002
6066
  }, ref) {
6003
- var _a3, _b, _c, _d;
6067
+ var _a3, _b, _c;
6004
6068
  const ctx = useStateContext();
6005
6069
  const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
6006
6070
  const scrollRef = React3.useRef(null);
@@ -6232,7 +6296,7 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
6232
6296
  } : {}
6233
6297
  };
6234
6298
  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;
6299
+ const anchoredEndInset = ((_b = (_a3 = ctx.state) == null ? void 0 : _a3.props) == null ? void 0 : _b.anchoredEndSpace) && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
6236
6300
  const renderedContentInsetEndAdjustment = Math.max(0, contentInsetEndAdjustment - anchoredEndInset);
6237
6301
  const contentInsetEndAdjustmentSpacerStyle = renderedContentInsetEndAdjustment ? horizontal ? { flexShrink: 0, width: renderedContentInsetEndAdjustment } : { height: renderedContentInsetEndAdjustment } : void 0;
6238
6302
  const contentStyle = {
@@ -6259,7 +6323,7 @@ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView
6259
6323
  const snapOffsets = !isWindowScroll ? getFiniteSnapOffsets(snapToOffsets) : [];
6260
6324
  if (snapOffsets.length > 0) {
6261
6325
  scrollViewStyle.scrollSnapType = horizontal ? "x mandatory" : "y mandatory";
6262
- contentStyle.position = (_d = contentStyle.position) != null ? _d : "relative";
6326
+ contentStyle.position = (_c = contentStyle.position) != null ? _c : "relative";
6263
6327
  }
6264
6328
  const scrollViewClassName = hiddenScrollIndicatorClassName ? scrollViewClassNameProp ? `${scrollViewClassNameProp} ${hiddenScrollIndicatorClassName}` : hiddenScrollIndicatorClassName : scrollViewClassNameProp;
6265
6329
  if (IS_DEV) {
@@ -6348,10 +6412,9 @@ function ScrollAdjust() {
6348
6412
  const lastScrollOffsetRef = React3__namespace.useRef(0);
6349
6413
  const lastScrollAdjustUserOffsetRef = React3__namespace.useRef(0);
6350
6414
  const resetPaddingRafRef = React3__namespace.useRef(void 0);
6351
- const resetPaddingBaselineRef = React3__namespace.useRef(void 0);
6415
+ const temporaryPaddingRef = React3__namespace.useRef(void 0);
6352
6416
  const contentNodeRef = React3__namespace.useRef(null);
6353
6417
  const callback = React3__namespace.useCallback(() => {
6354
- var _a3;
6355
6418
  const scrollAdjust = peek$(ctx, "scrollAdjust");
6356
6419
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
6357
6420
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
@@ -6375,19 +6438,28 @@ function ScrollAdjust() {
6375
6438
  const nextScroll = currentScroll + scrollDelta;
6376
6439
  const needsTemporaryPadding = scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + viewportSize;
6377
6440
  if (needsTemporaryPadding) {
6378
- const previousPaddingEnd = (_a3 = resetPaddingBaselineRef.current) != null ? _a3 : contentNode.style[axis.paddingEndProp];
6379
- resetPaddingBaselineRef.current = previousPaddingEnd;
6441
+ const currentInlinePaddingEnd = contentNode.style[axis.paddingEndProp];
6442
+ const previousTemporaryPadding = temporaryPaddingRef.current;
6443
+ const baselinePaddingEnd = (previousTemporaryPadding == null ? void 0 : previousTemporaryPadding.value) === currentInlinePaddingEnd ? previousTemporaryPadding.baseline : currentInlinePaddingEnd;
6380
6444
  const pad = (nextScroll + viewportSize - totalSize) * 2;
6381
- contentNode.style[axis.paddingEndProp] = `${pad}px`;
6445
+ const currentPaddingEnd = Number.parseFloat(
6446
+ window.getComputedStyle(contentNode)[axis.paddingEndProp]
6447
+ );
6448
+ const temporaryPaddingEnd = `${(currentPaddingEnd || 0) + pad}px`;
6449
+ temporaryPaddingRef.current = { baseline: baselinePaddingEnd, value: temporaryPaddingEnd };
6450
+ contentNode.style[axis.paddingEndProp] = temporaryPaddingEnd;
6382
6451
  void contentNode.offsetHeight;
6383
6452
  scrollBy();
6384
6453
  if (resetPaddingRafRef.current !== void 0) {
6385
6454
  cancelAnimationFrame(resetPaddingRafRef.current);
6386
6455
  }
6387
6456
  resetPaddingRafRef.current = requestAnimationFrame(() => {
6457
+ const temporaryPadding = temporaryPaddingRef.current;
6388
6458
  resetPaddingRafRef.current = void 0;
6389
- resetPaddingBaselineRef.current = void 0;
6390
- contentNode.style[axis.paddingEndProp] = previousPaddingEnd;
6459
+ temporaryPaddingRef.current = void 0;
6460
+ if (contentNode.style[axis.paddingEndProp] === (temporaryPadding == null ? void 0 : temporaryPadding.value)) {
6461
+ contentNode.style[axis.paddingEndProp] = temporaryPadding.baseline;
6462
+ }
6391
6463
  });
6392
6464
  } else {
6393
6465
  scrollBy();
@@ -6408,16 +6480,6 @@ var SnapWrapper = React3__namespace.forwardRef(function SnapWrapperInner({ Scrol
6408
6480
  const [snapToOffsets] = useArr$(["snapToOffsets"]);
6409
6481
  return /* @__PURE__ */ React3__namespace.createElement(ScrollComponent, { ...props, ref, snapToOffsets });
6410
6482
  });
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
6483
 
6422
6484
  // src/core/updateContentMetrics.ts
6423
6485
  var SCROLL_ADJUST_EPSILON = 0.1;
@@ -6451,7 +6513,11 @@ function setHeaderSize(ctx, size) {
6451
6513
  state.didMeasureHeader = true;
6452
6514
  }
6453
6515
  function setFooterSize(ctx, size) {
6454
- return setContentLengthSignal(ctx, "footerSize", size);
6516
+ const didChange = setContentLengthSignal(ctx, "footerSize", size);
6517
+ if (didChange) {
6518
+ maybeUpdateAnchoredEndSpace(ctx);
6519
+ }
6520
+ return didChange;
6455
6521
  }
6456
6522
  function areInsetsEqual(left, right) {
6457
6523
  var _a3, _b, _c, _d, _e, _f, _g, _h;
@@ -6504,6 +6570,7 @@ var AlignItemsAtEndSpacer = typedMemo(function AlignItemsAtEndSpacer2({ horizont
6504
6570
  });
6505
6571
  var ListComponent = typedMemo(function ListComponent2({
6506
6572
  canRender,
6573
+ freshDataTransitionEpoch,
6507
6574
  style,
6508
6575
  contentContainerStyle,
6509
6576
  horizontal,
@@ -6533,8 +6600,17 @@ var ListComponent = typedMemo(function ListComponent2({
6533
6600
  }) {
6534
6601
  const ctx = useStateContext();
6535
6602
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
6536
- const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
6603
+ const [anchoredEndSpaceSize = 0, otherAxisSize = 0] = useArr$(["anchoredEndSpaceSize", "otherAxisSize"]);
6537
6604
  const shouldRenderAlignItemsAtEndSpacer = ctx.state.props.alignItemsAtEndPaddingEnabled;
6605
+ const shouldMaterializeAnchoredEndSpace = !!ctx.state.props.anchoredEndSpace && ctx.state.props.anchoredEndSpaceOwner === "list" && anchoredEndSpaceSize > 0;
6606
+ let anchoredEndSpaceStyle;
6607
+ if (shouldMaterializeAnchoredEndSpace) {
6608
+ const paddingEnd = horizontal ? isHorizontalRTL(ctx.state) ? "Left" : "Right" : "Bottom";
6609
+ const flattenedContentContainerStyle = StyleSheet.flatten(contentContainerStyle);
6610
+ anchoredEndSpaceStyle = {
6611
+ [`padding${paddingEnd}`]: extractPadding({}, flattenedContentContainerStyle || {}, paddingEnd) + anchoredEndSpaceSize
6612
+ };
6613
+ }
6538
6614
  const autoOtherAxisStyle = getAutoOtherAxisStyle({
6539
6615
  horizontal,
6540
6616
  needsOtherAxisSize: ctx.state.needsOtherAxisSize,
@@ -6587,10 +6663,10 @@ var ListComponent = typedMemo(function ListComponent2({
6587
6663
  ...rest,
6588
6664
  ...ScrollComponent === ListComponentScrollView ? { onInternalScrollEnd, useWindowScroll } : {} ,
6589
6665
  contentContainerStyle: [
6590
- horizontal ? {
6591
- height: "100%"
6592
- } : {},
6593
- contentContainerStyle
6666
+ horizontal ? { height: "100%" } : {},
6667
+ contentContainerStyle,
6668
+ anchoredEndSpaceStyle,
6669
+ { boxSizing: "border-box" }
6594
6670
  ],
6595
6671
  contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
6596
6672
  horizontal,
@@ -6608,6 +6684,7 @@ var ListComponent = typedMemo(function ListComponent2({
6608
6684
  canRender && !ListEmptyComponent && /* @__PURE__ */ React3__namespace.createElement(
6609
6685
  Containers,
6610
6686
  {
6687
+ freshDataTransitionEpoch,
6611
6688
  getRenderedItem: getRenderedItem2,
6612
6689
  horizontal,
6613
6690
  ItemSeparatorComponent,
@@ -6616,7 +6693,6 @@ var ListComponent = typedMemo(function ListComponent2({
6616
6693
  }
6617
6694
  ),
6618
6695
  ListFooterComponent && /* @__PURE__ */ React3__namespace.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
6619
- /* @__PURE__ */ React3__namespace.createElement(WebAnchoredEndSpace, { horizontal }),
6620
6696
  IS_DEV && ENABLE_DEVMODE
6621
6697
  );
6622
6698
  });
@@ -6625,7 +6701,16 @@ var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
6625
6701
  var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
6626
6702
  function useDevChecksImpl(props) {
6627
6703
  const ctx = useStateContext();
6628
- const { childrenMode, keyExtractor, renderScrollComponent, useWindowScroll } = props;
6704
+ const { anchoredEndSpace, childrenMode, keyExtractor, numColumns, renderScrollComponent, useWindowScroll } = props;
6705
+ const hasAnchoredEndSpace = !!anchoredEndSpace;
6706
+ React3.useEffect(() => {
6707
+ if (hasAnchoredEndSpace && (numColumns != null ? numColumns : 1) > 1) {
6708
+ warnDevOnce(
6709
+ "anchoredEndSpaceNumColumns",
6710
+ "anchoredEndSpace is only supported when numColumns is 1. Using it with multiple columns may produce incorrect anchored spacing."
6711
+ );
6712
+ }
6713
+ }, [hasAnchoredEndSpace, numColumns]);
6629
6714
  React3.useEffect(() => {
6630
6715
  if (useWindowScroll && renderScrollComponent) {
6631
6716
  warnDevOnce(
@@ -6953,6 +7038,60 @@ function onScroll(ctx, event) {
6953
7038
  }
6954
7039
  }
6955
7040
 
7041
+ // src/core/ScheduledWork.ts
7042
+ var ScheduledWork = class {
7043
+ constructor() {
7044
+ this.work = /* @__PURE__ */ new Map();
7045
+ }
7046
+ timeout(callback, delay, key) {
7047
+ if (key) {
7048
+ this.cancel(key);
7049
+ }
7050
+ const work = [void 0, clearTimeout];
7051
+ const handle = setTimeout(() => {
7052
+ const workKey = key != null ? key : handle;
7053
+ if (this.work.get(workKey) === work) {
7054
+ this.work.delete(workKey);
7055
+ callback();
7056
+ }
7057
+ }, delay);
7058
+ work[0] = handle;
7059
+ this.work.set(key != null ? key : handle, work);
7060
+ }
7061
+ frame(callback, key) {
7062
+ this.cancel(key);
7063
+ const work = [void 0, cancelAnimationFrame];
7064
+ this.work.set(key, work);
7065
+ work[0] = requestAnimationFrame(() => {
7066
+ if (this.work.get(key) === work) {
7067
+ this.work.delete(key);
7068
+ callback();
7069
+ }
7070
+ });
7071
+ }
7072
+ register(key, cancel) {
7073
+ this.cancel(key);
7074
+ this.work.set(key, [void 0, cancel]);
7075
+ }
7076
+ cancel(key) {
7077
+ const work = this.work.get(key);
7078
+ if (work) {
7079
+ this.work.delete(key);
7080
+ const [handle, cancel] = work;
7081
+ cancel(handle);
7082
+ }
7083
+ }
7084
+ has(key) {
7085
+ return this.work.has(key);
7086
+ }
7087
+ dispose() {
7088
+ for (const [handle, cancel] of this.work.values()) {
7089
+ cancel(handle);
7090
+ }
7091
+ this.work.clear();
7092
+ }
7093
+ };
7094
+
6956
7095
  // src/core/ScrollAdjustHandler.ts
6957
7096
  var ScrollAdjustHandler = class {
6958
7097
  constructor(ctx) {
@@ -7110,7 +7249,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7110
7249
  const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
7111
7250
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
7112
7251
  let imperativeScrollToken = 0;
7113
- const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0;
7252
+ const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.scheduledWork.has("mvcpRecalculate") || state.ignoreScrollFromMVCP !== void 0;
7114
7253
  const isScrollToIndexReady = (targetIndex, allowEmpty = false) => {
7115
7254
  var _a3;
7116
7255
  const props = state.props;
@@ -7144,9 +7283,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7144
7283
  run();
7145
7284
  return;
7146
7285
  }
7147
- requestAnimationFrame(check);
7286
+ state.scheduledWork.frame(check, "imperativeScrollReady");
7148
7287
  };
7149
- requestAnimationFrame(check);
7288
+ state.scheduledWork.frame(check, "imperativeScrollReady");
7150
7289
  };
7151
7290
  const runScrollRequest = (token, resolve, run, isReady = () => true) => {
7152
7291
  const runNow = () => {
@@ -7168,15 +7307,15 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7168
7307
  }
7169
7308
  };
7170
7309
  const startImperativeScroll = (resolve) => {
7171
- var _a3;
7310
+ state.scheduledWork.cancel("imperativeScrollReady");
7172
7311
  const token = ++imperativeScrollToken;
7173
- state.pendingScrollToEnd = void 0;
7174
- (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
7312
+ settlePendingImperativeScroll(state);
7175
7313
  state.pendingScrollResolve = resolve;
7176
7314
  return token;
7177
7315
  };
7178
7316
  const runScrollWithPromise = (run, isReady = () => true) => new Promise((resolve) => {
7179
7317
  const token = startImperativeScroll(resolve);
7318
+ supersedeInitialScroll(ctx);
7180
7319
  runScrollRequest(token, resolve, run, isReady);
7181
7320
  });
7182
7321
  state.runPendingScrollToEnd = () => {
@@ -7255,6 +7394,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7255
7394
  end: state.endNoBuffer,
7256
7395
  endBuffered: state.endBuffered,
7257
7396
  getAverageItemSizes: () => getAverageItemSizes(state),
7397
+ indexByKey: (key) => state.indexByKey.get(key),
7258
7398
  isAtEnd: peek$(ctx, "isAtEnd"),
7259
7399
  isAtStart: peek$(ctx, "isAtStart"),
7260
7400
  isEndReached: state.isEndReached,
@@ -7302,9 +7442,9 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
7302
7442
  resolve,
7303
7443
  token
7304
7444
  };
7305
- if (scheduleImperativeScrollCommit) {
7306
- scheduleImperativeScrollCommit();
7307
- } else {
7445
+ scheduleImperativeScrollCommit == null ? void 0 : scheduleImperativeScrollCommit();
7446
+ supersedeInitialScroll(ctx);
7447
+ if (!scheduleImperativeScrollCommit) {
7308
7448
  (_a3 = state.runPendingScrollToEnd) == null ? void 0 : _a3.call(state);
7309
7449
  }
7310
7450
  }),
@@ -7558,7 +7698,7 @@ var LegendList = typedMemo(
7558
7698
  })
7559
7699
  );
7560
7700
  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;
7701
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
7562
7702
  const noopOnScroll = React3.useCallback((_event) => {
7563
7703
  }, []);
7564
7704
  if (props.recycleItems === void 0) {
@@ -7634,9 +7774,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7634
7774
  ...rest
7635
7775
  } = props;
7636
7776
  const animatedPropsInternal = props.animatedPropsInternal;
7777
+ const anchoredEndSpaceOwner = (_a3 = props.anchoredEndSpaceOwnerInternal) != null ? _a3 : "list";
7637
7778
  const positionComponentInternal = props.positionComponentInternal;
7638
7779
  const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
7639
7780
  const {
7781
+ anchoredEndSpaceOwnerInternal: _anchoredEndSpaceOwnerInternal,
7640
7782
  positionComponentInternal: _positionComponentInternal,
7641
7783
  stickyPositionComponentInternal: _stickyPositionComponentInternal,
7642
7784
  ...restProps
@@ -7658,6 +7800,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7658
7800
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
7659
7801
  const stylePaddingLeftState = extractPadding(style, contentContainerStyle, "Left");
7660
7802
  const stylePaddingRightState = extractPadding(style, contentContainerStyle, "Right");
7803
+ const stylePaddingEndState = getStylePaddingEnd({
7804
+ horizontal,
7805
+ rtl,
7806
+ stylePaddingBottom: stylePaddingBottomState,
7807
+ stylePaddingLeft: stylePaddingLeftState,
7808
+ stylePaddingRight: stylePaddingRightState
7809
+ });
7661
7810
  const maintainScrollAtEndConfig = normalizeMaintainScrollAtEnd(maintainScrollAtEnd);
7662
7811
  const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
7663
7812
  maintainVisibleContentPositionProp
@@ -7670,13 +7819,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7670
7819
  const initialScrollProp = initialScrollAtEnd ? {
7671
7820
  index: Math.max(0, dataProp.length - 1),
7672
7821
  preserveForBottomPadding: true,
7673
- viewOffset: -stylePaddingBottomState,
7822
+ viewOffset: -stylePaddingEndState,
7674
7823
  viewPosition: 1
7675
7824
  } : hasInitialScrollIndex ? typeof initialScrollIndexProp === "object" ? {
7676
- index: (_a3 = initialScrollIndexProp.index) != null ? _a3 : 0,
7825
+ index: (_b = initialScrollIndexProp.index) != null ? _b : 0,
7677
7826
  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
7827
+ viewOffset: (_c = initialScrollIndexProp.viewOffset) != null ? _c : initialScrollIndexProp.viewPosition === 1 ? -stylePaddingEndState : 0,
7828
+ viewPosition: (_d = initialScrollIndexProp.viewPosition) != null ? _d : 0
7680
7829
  } : {
7681
7830
  index: initialScrollIndexProp != null ? initialScrollIndexProp : 0,
7682
7831
  viewOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : 0
@@ -7689,7 +7838,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7689
7838
  const [, scheduleImperativeScrollCommit] = React3__namespace.useReducer((value) => value + 1, 0);
7690
7839
  const ctx = useStateContext();
7691
7840
  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;
7841
+ 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
7842
  const nextScrollAxisGap = typeof scrollAxisGap === "number" && Number.isFinite(scrollAxisGap) ? scrollAxisGap : 0;
7694
7843
  const refScroller = React3.useRef(null);
7695
7844
  const combinedRef = useCombinedRef(refScroller, refScrollView);
@@ -7704,8 +7853,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7704
7853
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex,
7705
7854
  alwaysRender == null ? void 0 : alwaysRender.top,
7706
7855
  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(","),
7856
+ (_k = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _k.join(","),
7857
+ (_l = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _l.join(","),
7709
7858
  dataProp,
7710
7859
  dataKey,
7711
7860
  dataVersion,
@@ -7718,7 +7867,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7718
7867
  if (!refState.current) {
7719
7868
  if (!ctx.state) {
7720
7869
  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");
7870
+ ctx.values.set("adaptiveRender", (_m = experimental_adaptiveRender == null ? void 0 : experimental_adaptiveRender.initialMode) != null ? _m : "normal");
7722
7871
  ctx.state = {
7723
7872
  averageSizes: {},
7724
7873
  columnSpans: [],
@@ -7737,6 +7886,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7737
7886
  endNoBuffer: -1,
7738
7887
  endReachedSnapshot: void 0,
7739
7888
  firstFullyOnScreenIndex: -1,
7889
+ freshDataTransitionEpoch: 0,
7740
7890
  hasHadNonEmptyData: dataProp.length > 0,
7741
7891
  idCache: [],
7742
7892
  idsInView: [],
@@ -7761,8 +7911,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7761
7911
  positions: [],
7762
7912
  props: {},
7763
7913
  queuedCalculateItemsInView: 0,
7764
- queuedFullDrawDistancePrewarm: void 0,
7765
7914
  refScroller: { current: null },
7915
+ scheduledWork: new ScheduledWork(),
7766
7916
  scroll: 0,
7767
7917
  scrollAdjustHandler: new ScrollAdjustHandler(ctx),
7768
7918
  scrollForNextCalculateItemsInView: void 0,
@@ -7780,8 +7930,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7780
7930
  startReachedSnapshot: void 0,
7781
7931
  stickyContainerPool: /* @__PURE__ */ new Set(),
7782
7932
  stickyContainers: /* @__PURE__ */ new Map(),
7783
- timeoutAdaptiveRender: void 0,
7784
- timeouts: /* @__PURE__ */ new Set(),
7785
7933
  totalSize: 0,
7786
7934
  viewabilityConfigCallbackPairs: void 0
7787
7935
  };
@@ -7803,13 +7951,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7803
7951
  const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
7804
7952
  ctx.scrollAxisGap = nextScrollAxisGap;
7805
7953
  state.didColumnsChange = numColumnsProp !== previousNumColumnsProp || didScrollAxisGapChange;
7806
- const previousDataLength = (_n = (_m = state.props.data) == null ? void 0 : _m.length) != null ? _n : 0;
7954
+ const previousDataLength = (_o = (_n = state.props.data) == null ? void 0 : _n.length) != null ? _o : 0;
7807
7955
  const didDataReferenceChangeLocal = state.props.data !== dataProp;
7808
7956
  const didDataKeyChangeLocal = state.props.dataKey !== dataKey;
7809
7957
  const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
7810
7958
  const didDataChangeLocal = didDataKeyChangeLocal || didDataVersionChangeLocal || didDataReferenceChangeLocal && checkStructuralDataChange(state, dataProp, state.props.data);
7811
7959
  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) {
7960
+ if (didDataChangeLocal && !initialScrollAtEnd && state.didFinishInitialScroll && ((_p = state.initialScroll) == null ? void 0 : _p.viewPosition) === 1 && state.props.data.length > 0) {
7813
7961
  clearPreservedInitialScrollTarget(state);
7814
7962
  }
7815
7963
  if (didDataChangeLocal) {
@@ -7818,10 +7966,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7818
7966
  state.didDataChange = true;
7819
7967
  state.previousData = state.props.data;
7820
7968
  }
7969
+ if (shouldResetFreshDataLayout) {
7970
+ state.freshDataTransitionEpoch += 1;
7971
+ }
7821
7972
  const throttledOnScroll = useThrottledOnScroll(onScrollProp != null ? onScrollProp : noopOnScroll, scrollEventThrottle != null ? scrollEventThrottle : 0);
7822
7973
  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);
7974
+ const didAnchoredEndSpaceAnchorIndexChange = !isFirstLocal && !didDataChangeLocal && ((_q = state.props.anchoredEndSpace) == null ? void 0 : _q.anchorIndex) !== (anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex);
7825
7975
  state.props = {
7826
7976
  adaptiveRender: experimental_adaptiveRender,
7827
7977
  alignItemsAtEnd,
@@ -7829,7 +7979,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7829
7979
  alwaysRender,
7830
7980
  alwaysRenderIndicesArr: alwaysRenderIndices.arr,
7831
7981
  alwaysRenderIndicesSet: alwaysRenderIndices.set,
7832
- anchoredEndSpace: anchoredEndSpaceResolved,
7982
+ anchoredEndSpace,
7983
+ anchoredEndSpaceOwner,
7833
7984
  animatedProps: animatedPropsInternal,
7834
7985
  contentContainerAlignItems: contentContainerStyle.alignItems,
7835
7986
  contentInset,
@@ -7878,12 +8029,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7878
8029
  if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
7879
8030
  resetAdaptiveRender(ctx);
7880
8031
  }
7881
- if (shouldResetFreshDataLayout) {
7882
- resetInitialRenderState(ctx, {
7883
- resetInitialScroll: !!initialScrollProp,
7884
- resetLayout: true
7885
- });
7886
- }
7887
8032
  const memoizedLastItemKeys = React3.useMemo(() => {
7888
8033
  if (!dataProp.length) return [];
7889
8034
  return Array.from(
@@ -7942,6 +8087,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7942
8087
  useDevChecks(props);
7943
8088
  }
7944
8089
  React3.useLayoutEffect(() => {
8090
+ if (shouldResetFreshDataLayout) {
8091
+ resetInitialRenderState(ctx, {
8092
+ resetInitialScroll: !!initialScrollProp,
8093
+ resetLayout: true
8094
+ });
8095
+ }
7945
8096
  handleInitialScrollDataChange(ctx, {
7946
8097
  dataLength: dataProp.length,
7947
8098
  didDataChange: didDataChangeLocal,
@@ -7949,7 +8100,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7949
8100
  initialScrollAtEnd,
7950
8101
  latestInitialScroll: initialScrollProp,
7951
8102
  latestInitialScrollSessionKind: initialScrollUsesOffsetOnly ? "offset" : "bootstrap",
7952
- stylePaddingBottom: stylePaddingBottomState,
8103
+ stylePaddingEnd: stylePaddingEndState,
7953
8104
  useBootstrapInitialScroll: usesBootstrapInitialScroll
7954
8105
  });
7955
8106
  }, [
@@ -7958,7 +8109,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7958
8109
  didDataChangeLocal,
7959
8110
  shouldResetFreshDataLayout,
7960
8111
  initialScrollAtEnd,
7961
- stylePaddingBottomState,
8112
+ stylePaddingEndState,
7962
8113
  usesBootstrapInitialScroll
7963
8114
  ]);
7964
8115
  React3.useLayoutEffect(() => {
@@ -7976,7 +8127,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7976
8127
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorMaxSize,
7977
8128
  anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorOffset,
7978
8129
  didAnchoredEndSpaceAnchorIndexChange,
7979
- numColumnsProp
8130
+ horizontal,
8131
+ numColumnsProp,
8132
+ rtl,
8133
+ stylePaddingBottomState,
8134
+ stylePaddingLeftState,
8135
+ stylePaddingRightState
7980
8136
  ]);
7981
8137
  React3.useLayoutEffect(() => {
7982
8138
  const previousContentInsetEndAdjustment = previousContentInsetEndAdjustmentRef.current;
@@ -7992,10 +8148,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7992
8148
  dataLength: dataProp.length,
7993
8149
  footerSize: layout[horizontal ? "width" : "height"],
7994
8150
  initialScrollAtEnd,
7995
- stylePaddingBottom: stylePaddingBottomState
8151
+ stylePaddingEnd: stylePaddingEndState
7996
8152
  });
7997
8153
  },
7998
- [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingBottomState, usesBootstrapInitialScroll]
8154
+ [dataProp.length, initialScrollAtEnd, horizontal, stylePaddingEndState, usesBootstrapInitialScroll]
7999
8155
  );
8000
8156
  const onLayoutChange = React3.useCallback(
8001
8157
  (layout, fromLayoutEffect) => {
@@ -8012,7 +8168,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8012
8168
  }
8013
8169
  advanceCurrentInitialScrollSession(ctx);
8014
8170
  },
8015
- [dataProp.length, initialScrollAtEnd, stylePaddingBottomState, usesBootstrapInitialScroll]
8171
+ [dataProp.length, initialScrollAtEnd, stylePaddingEndState, usesBootstrapInitialScroll]
8016
8172
  );
8017
8173
  const { onLayout } = useOnLayoutSync({
8018
8174
  onLayoutChange,
@@ -8105,14 +8261,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8105
8261
  React3.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, scheduleImperativeScrollCommit), []);
8106
8262
  React3.useEffect(() => {
8107
8263
  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();
8264
+ cancelImperativeScroll(state);
8265
+ state.scheduledWork.dispose();
8116
8266
  };
8117
8267
  }, [state]);
8118
8268
  React3.useLayoutEffect(() => {
@@ -8154,6 +8304,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8154
8304
  canRender,
8155
8305
  contentContainerStyle,
8156
8306
  contentInset,
8307
+ freshDataTransitionEpoch: state.freshDataTransitionEpoch,
8157
8308
  getRenderedItem: fns.getRenderedItem,
8158
8309
  horizontal,
8159
8310
  initialContentOffset,
@@ -8169,7 +8320,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8169
8320
  onScroll: onScrollHandler,
8170
8321
  recycleItems,
8171
8322
  refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React3__namespace.cloneElement(refreshControlElement, {
8172
- progressViewOffset: ((_q = refreshControlElement.props.progressViewOffset) != null ? _q : 0) + stylePaddingTopState
8323
+ progressViewOffset: ((_r = refreshControlElement.props.progressViewOffset) != null ? _r : 0) + stylePaddingTopState
8173
8324
  }) : refreshControlElement : onRefresh && /* @__PURE__ */ React3__namespace.createElement(
8174
8325
  RefreshControl,
8175
8326
  {
@@ -8180,7 +8331,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
8180
8331
  ),
8181
8332
  refScrollView: combinedRef,
8182
8333
  renderScrollComponent,
8183
- scrollAdjustHandler: (_r = refState.current) == null ? void 0 : _r.scrollAdjustHandler,
8334
+ scrollAdjustHandler: (_s = refState.current) == null ? void 0 : _s.scrollAdjustHandler,
8184
8335
  scrollEventThrottle: 0,
8185
8336
  snapToIndices,
8186
8337
  stickyHeaderIndices,