@legendapp/list 2.1.0-beta.1 → 2.1.0-beta.10

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/index.js CHANGED
@@ -54,7 +54,10 @@ function StateProvider({ children }) {
54
54
  ["stylePaddingTop", 0],
55
55
  ["headerSize", 0],
56
56
  ["numContainers", 0],
57
- ["totalSize", 0]
57
+ ["activeStickyIndex", void 0],
58
+ ["totalSize", 0],
59
+ ["scrollAdjustPending", 0],
60
+ ["scrollingTo", void 0]
58
61
  ]),
59
62
  viewRefs: /* @__PURE__ */ new Map()
60
63
  }));
@@ -208,6 +211,47 @@ var ENABLE_DEBUG_VIEW = IS_DEV && false;
208
211
  var typedForwardRef = React3.forwardRef;
209
212
  var typedMemo = React3.memo;
210
213
 
214
+ // src/utils/helpers.ts
215
+ function isFunction(obj) {
216
+ return typeof obj === "function";
217
+ }
218
+ function isArray(obj) {
219
+ return Array.isArray(obj);
220
+ }
221
+ var warned = /* @__PURE__ */ new Set();
222
+ function warnDevOnce(id, text) {
223
+ if (IS_DEV && !warned.has(id)) {
224
+ warned.add(id);
225
+ console.warn(`[legend-list] ${text}`);
226
+ }
227
+ }
228
+ function roundSize(size) {
229
+ return Math.floor(size * 8) / 8;
230
+ }
231
+ function isNullOrUndefined(value) {
232
+ return value === null || value === void 0;
233
+ }
234
+ function comparatorDefault(a, b) {
235
+ return a - b;
236
+ }
237
+ function getPadding(s, type) {
238
+ var _a3, _b, _c;
239
+ return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : s.paddingVertical) != null ? _b : s.padding) != null ? _c : 0;
240
+ }
241
+ function extractPadding(style, contentContainerStyle, type) {
242
+ return getPadding(style, type) + getPadding(contentContainerStyle, type);
243
+ }
244
+ function findContainerId(ctx, key) {
245
+ const numContainers = peek$(ctx, "numContainers");
246
+ for (let i = 0; i < numContainers; i++) {
247
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
248
+ if (itemKey === key) {
249
+ return i;
250
+ }
251
+ }
252
+ return -1;
253
+ }
254
+
211
255
  // src/components/PositionView.tsx
212
256
  var PositionViewState = typedMemo(function PositionView({
213
257
  id,
@@ -217,8 +261,11 @@ var PositionViewState = typedMemo(function PositionView({
217
261
  ...rest
218
262
  }) {
219
263
  const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
220
- const base = Array.isArray(style) ? Object.assign({}, ...style) : style;
221
- const combinedStyle = horizontal ? { ...base, left: position } : { ...base, top: position };
264
+ const base = {
265
+ contain: "paint layout style"
266
+ };
267
+ const composed = isArray(style) ? Object.assign({}, ...style) : style;
268
+ const combinedStyle = horizontal ? { ...base, ...composed, left: position } : { ...base, ...composed, top: position };
222
269
  return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, style: combinedStyle, ...rest });
223
270
  });
224
271
  var PositionViewSticky = typedMemo(function PositionViewSticky2({
@@ -227,19 +274,42 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
227
274
  style,
228
275
  refView,
229
276
  index,
277
+ stickyOffset,
278
+ animatedScrollY: _animatedScrollY,
279
+ children,
230
280
  ...rest
231
281
  }) {
232
- const [position = POSITION_OUT_OF_VIEW, _headerSize] = useArr$([`containerPosition${id}`, "headerSize"]);
282
+ const [position = POSITION_OUT_OF_VIEW, headerSize = 0, activeStickyIndex] = useArr$([
283
+ `containerPosition${id}`,
284
+ "headerSize",
285
+ "activeStickyIndex"
286
+ ]);
287
+ const base = {
288
+ contain: "paint layout style"
289
+ };
290
+ const composed = React3__namespace.useMemo(
291
+ () => {
292
+ var _a3;
293
+ return (_a3 = isArray(style) ? Object.assign({}, ...style) : style) != null ? _a3 : {};
294
+ },
295
+ [style]
296
+ );
233
297
  const viewStyle = React3__namespace.useMemo(() => {
234
- const base = Array.isArray(style) ? Object.assign({}, ...style) : style;
235
- const axisStyle = horizontal ? { transform: `translateX(${position}px)` } : { top: position };
236
- return {
237
- ...base,
238
- zIndex: index + 1e3,
239
- ...axisStyle
240
- };
241
- }, [style, position, horizontal, index]);
242
- return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, style: viewStyle, ...rest });
298
+ var _a3;
299
+ const styleBase = { ...base, ...composed };
300
+ delete styleBase.transform;
301
+ const offset = (_a3 = stickyOffset != null ? stickyOffset : headerSize) != null ? _a3 : 0;
302
+ const isActive = activeStickyIndex === index;
303
+ styleBase.position = isActive ? "sticky" : "absolute";
304
+ styleBase.zIndex = index + 1e3;
305
+ if (horizontal) {
306
+ styleBase.left = isActive ? offset : position;
307
+ } else {
308
+ styleBase.top = isActive ? offset : position;
309
+ }
310
+ return styleBase;
311
+ }, [composed, horizontal, position, index, stickyOffset, headerSize, activeStickyIndex]);
312
+ return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
243
313
  });
244
314
  var PositionView2 = PositionViewState;
245
315
 
@@ -254,37 +324,6 @@ function useInit(cb) {
254
324
  return refValue.current;
255
325
  }
256
326
 
257
- // src/utils/helpers.ts
258
- function isFunction(obj) {
259
- return typeof obj === "function";
260
- }
261
- function isArray(obj) {
262
- return Array.isArray(obj);
263
- }
264
- var warned = /* @__PURE__ */ new Set();
265
- function warnDevOnce(id, text) {
266
- if (IS_DEV && !warned.has(id)) {
267
- warned.add(id);
268
- console.warn(`[legend-list] ${text}`);
269
- }
270
- }
271
- function roundSize(size) {
272
- return Math.floor(size * 8) / 8;
273
- }
274
- function isNullOrUndefined(value) {
275
- return value === null || value === void 0;
276
- }
277
- function comparatorDefault(a, b) {
278
- return a - b;
279
- }
280
- function getPadding(s, type) {
281
- var _a3, _b, _c;
282
- return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : s.paddingVertical) != null ? _b : s.padding) != null ? _c : 0;
283
- }
284
- function extractPadding(style, contentContainerStyle, type) {
285
- return getPadding(style, type) + getPadding(contentContainerStyle, type);
286
- }
287
-
288
327
  // src/state/ContextContainer.ts
289
328
  var ContextContainer = React3.createContext(null);
290
329
  function useViewability(callback, configId) {
@@ -413,6 +452,10 @@ function getGlobalResizeObserver() {
413
452
  }
414
453
  var callbackMap = /* @__PURE__ */ new WeakMap();
415
454
  function createResizeObserver(element, callback) {
455
+ if (typeof ResizeObserver === "undefined") {
456
+ return () => {
457
+ };
458
+ }
416
459
  if (!element) {
417
460
  return () => {
418
461
  };
@@ -448,7 +491,7 @@ function useOnLayoutSync({
448
491
  const current = ref.current;
449
492
  const scrollableNode = (_b = (_a3 = current == null ? void 0 : current.getScrollableNode) == null ? void 0 : _a3.call(current)) != null ? _b : null;
450
493
  const element = scrollableNode || current;
451
- if (!element || !(element instanceof HTMLElement)) {
494
+ if (!element) {
452
495
  return;
453
496
  }
454
497
  const emit = (layout, fromLayoutEffect) => {
@@ -470,6 +513,9 @@ function useOnLayoutSync({
470
513
  return {};
471
514
  }
472
515
  function toLayout(rect) {
516
+ if (!rect) {
517
+ return { height: 0, width: 0, x: 0, y: 0 };
518
+ }
473
519
  return {
474
520
  height: rect.height,
475
521
  width: rect.width,
@@ -571,7 +617,7 @@ var Container = typedMemo(function Container2({
571
617
  }
572
618
  didLayoutRef.current = true;
573
619
  let layout = rectangle;
574
- Math.floor(rectangle[currentHorizontal ? "width" : "height"] * 8) / 8;
620
+ roundSize(rectangle[currentHorizontal ? "width" : "height"]);
575
621
  const doUpdate = () => {
576
622
  itemLayoutRef.current.lastSize = { height: layout.height, width: layout.width };
577
623
  updateItemSizeFn(currentItemKey, layout);
@@ -729,7 +775,7 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
729
775
  const columnWrapperStyle = ctx.columnWrapperStyle;
730
776
  const [totalSize, otherAxisSize] = useArr$(["totalSize", "otherAxisSize"]);
731
777
  useDOMOrder(ref);
732
- const style = horizontal ? { minHeight: otherAxisSize, width: totalSize } : { height: totalSize, minWidth: otherAxisSize };
778
+ const style = horizontal ? { minHeight: otherAxisSize, position: "relative", width: totalSize } : { height: totalSize, minWidth: otherAxisSize, position: "relative" };
733
779
  if (columnWrapperStyle && numColumns > 1) {
734
780
  const { columnGap, rowGap, gap } = columnWrapperStyle;
735
781
  const gapX = columnGap || gap || 0;
@@ -801,7 +847,7 @@ function DevNumbers() {
801
847
 
802
848
  // src/platform/StyleSheet.tsx
803
849
  function flattenStyles(styles) {
804
- if (Array.isArray(styles)) {
850
+ if (isArray(styles)) {
805
851
  return Object.assign({}, ...styles.filter(Boolean));
806
852
  }
807
853
  return styles;
@@ -991,10 +1037,11 @@ function PaddingDevMode() {
991
1037
  function useValueListener$(key, callback) {
992
1038
  const ctx = useStateContext();
993
1039
  React3.useLayoutEffect(() => {
994
- listen$(ctx, key, (value) => {
1040
+ const unsubscribe = listen$(ctx, key, (value) => {
995
1041
  callback(value);
996
1042
  });
997
- }, []);
1043
+ return unsubscribe;
1044
+ }, [callback, ctx, key]);
998
1045
  }
999
1046
 
1000
1047
  // src/components/ScrollAdjust.tsx
@@ -1159,13 +1206,100 @@ function calculateOffsetForIndex(ctx, state, index) {
1159
1206
  return position;
1160
1207
  }
1161
1208
 
1209
+ // src/utils/setPaddingTop.ts
1210
+ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1211
+ if (stylePaddingTop !== void 0) {
1212
+ const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1213
+ if (stylePaddingTop < prevStylePaddingTop) {
1214
+ let prevTotalSize = peek$(ctx, "totalSize") || 0;
1215
+ set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1216
+ state.timeoutSetPaddingTop = setTimeout(() => {
1217
+ prevTotalSize = peek$(ctx, "totalSize") || 0;
1218
+ set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
1219
+ }, 16);
1220
+ }
1221
+ set$(ctx, "stylePaddingTop", stylePaddingTop);
1222
+ }
1223
+ if (alignItemsPaddingTop !== void 0) {
1224
+ set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1225
+ }
1226
+ }
1227
+
1228
+ // src/utils/updateAlignItemsPaddingTop.ts
1229
+ function updateAlignItemsPaddingTop(ctx, state) {
1230
+ const {
1231
+ scrollLength,
1232
+ props: { alignItemsAtEnd, data }
1233
+ } = state;
1234
+ if (alignItemsAtEnd) {
1235
+ let alignItemsPaddingTop = 0;
1236
+ if ((data == null ? void 0 : data.length) > 0) {
1237
+ const contentSize = getContentSize(ctx);
1238
+ alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1239
+ }
1240
+ setPaddingTop(ctx, state, { alignItemsPaddingTop });
1241
+ }
1242
+ }
1243
+
1244
+ // src/core/updateTotalSize.ts
1245
+ function updateTotalSize(ctx, state) {
1246
+ const {
1247
+ positions,
1248
+ props: { data }
1249
+ } = state;
1250
+ if (data.length === 0) {
1251
+ addTotalSize(ctx, state, null, 0);
1252
+ } else {
1253
+ const lastId = getId(state, data.length - 1);
1254
+ if (lastId !== void 0) {
1255
+ const lastPosition = positions.get(lastId);
1256
+ if (lastPosition !== void 0) {
1257
+ const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1258
+ if (lastSize !== void 0) {
1259
+ const totalSize = lastPosition + lastSize;
1260
+ addTotalSize(ctx, state, null, totalSize);
1261
+ }
1262
+ }
1263
+ }
1264
+ }
1265
+ }
1266
+ function addTotalSize(ctx, state, key, add) {
1267
+ const { alignItemsAtEnd } = state.props;
1268
+ const prevTotalSize = state.totalSize;
1269
+ if (key === null) {
1270
+ state.totalSize = add;
1271
+ if (state.timeoutSetPaddingTop) {
1272
+ clearTimeout(state.timeoutSetPaddingTop);
1273
+ state.timeoutSetPaddingTop = void 0;
1274
+ }
1275
+ } else {
1276
+ state.totalSize += add;
1277
+ }
1278
+ if (prevTotalSize !== state.totalSize) {
1279
+ set$(ctx, "totalSize", state.totalSize);
1280
+ if (alignItemsAtEnd) {
1281
+ updateAlignItemsPaddingTop(ctx, state);
1282
+ }
1283
+ }
1284
+ }
1285
+
1286
+ // src/core/setSize.ts
1287
+ function setSize(ctx, state, itemKey, size) {
1288
+ const { sizes } = state;
1289
+ const previousSize = sizes.get(itemKey);
1290
+ const diff = previousSize !== void 0 ? size - previousSize : size;
1291
+ if (diff !== 0) {
1292
+ addTotalSize(ctx, state, itemKey, diff);
1293
+ }
1294
+ sizes.set(itemKey, size);
1295
+ }
1296
+
1162
1297
  // src/utils/getItemSize.ts
1163
- function getItemSize(state, key, index, data, useAverageSize) {
1298
+ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedSize) {
1164
1299
  var _a3, _b;
1165
1300
  const {
1166
1301
  sizesKnown,
1167
1302
  sizes,
1168
- scrollingTo,
1169
1303
  averageSizes,
1170
1304
  props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
1171
1305
  } = state;
@@ -1175,6 +1309,13 @@ function getItemSize(state, key, index, data, useAverageSize) {
1175
1309
  }
1176
1310
  let size;
1177
1311
  const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1312
+ const scrollingTo = peek$(ctx, "scrollingTo");
1313
+ if (preferCachedSize) {
1314
+ const cachedSize = sizes.get(key);
1315
+ if (cachedSize !== void 0) {
1316
+ return cachedSize;
1317
+ }
1318
+ }
1178
1319
  if (getFixedItemSize) {
1179
1320
  size = getFixedItemSize(index, data, itemType);
1180
1321
  if (size !== void 0) {
@@ -1196,56 +1337,235 @@ function getItemSize(state, key, index, data, useAverageSize) {
1196
1337
  if (size === void 0) {
1197
1338
  size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
1198
1339
  }
1199
- sizes.set(key, size);
1340
+ setSize(ctx, state, key, size);
1200
1341
  return size;
1201
1342
  }
1202
1343
 
1203
1344
  // src/core/calculateOffsetWithOffsetPosition.ts
1204
- function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
1345
+ function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
1205
1346
  const { index, viewOffset, viewPosition } = params;
1206
1347
  let offset = offsetParam;
1207
1348
  if (viewOffset) {
1208
1349
  offset -= viewOffset;
1209
1350
  }
1210
1351
  if (viewPosition !== void 0 && index !== void 0) {
1211
- offset -= viewPosition * (state.scrollLength - getItemSize(state, getId(state, index), index, state.props.data[index]));
1352
+ offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
1212
1353
  }
1213
1354
  return offset;
1214
1355
  }
1215
1356
 
1216
- // src/core/finishScrollTo.ts
1217
- var finishScrollTo = (state) => {
1218
- if (state) {
1219
- state.scrollingTo = void 0;
1220
- state.scrollHistory.length = 0;
1357
+ // src/utils/checkThreshold.ts
1358
+ var HYSTERESIS_MULTIPLIER = 1.3;
1359
+ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1360
+ const absDistance = Math.abs(distance);
1361
+ const within = atThreshold || threshold > 0 && absDistance <= threshold;
1362
+ const updateSnapshot = () => {
1363
+ setSnapshot == null ? void 0 : setSnapshot({
1364
+ atThreshold,
1365
+ contentSize: context.contentSize,
1366
+ dataLength: context.dataLength,
1367
+ scrollPosition: context.scrollPosition
1368
+ });
1369
+ };
1370
+ if (!wasReached) {
1371
+ if (!within) {
1372
+ return false;
1373
+ }
1374
+ onReached == null ? void 0 : onReached(distance);
1375
+ updateSnapshot();
1376
+ return true;
1377
+ }
1378
+ const reset = !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
1379
+ if (reset) {
1380
+ setSnapshot == null ? void 0 : setSnapshot(void 0);
1381
+ return false;
1382
+ }
1383
+ if (within) {
1384
+ const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
1385
+ if (changed) {
1386
+ onReached == null ? void 0 : onReached(distance);
1387
+ updateSnapshot();
1388
+ }
1221
1389
  }
1390
+ return true;
1222
1391
  };
1223
1392
 
1224
- // src/core/scrollTo.ts
1225
- function scrollTo(state, params = {}) {
1393
+ // src/utils/checkAtBottom.ts
1394
+ function checkAtBottom(ctx, state) {
1226
1395
  var _a3;
1227
- const { animated, noScrollingTo, isInitialScroll } = params;
1396
+ if (!state) {
1397
+ return;
1398
+ }
1228
1399
  const {
1229
- refScroller,
1230
- props: { horizontal }
1400
+ queuedInitialLayout,
1401
+ scrollLength,
1402
+ scroll,
1403
+ maintainingScrollAtEnd,
1404
+ props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
1231
1405
  } = state;
1232
- const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
1233
- state.scrollHistory.length = 0;
1234
- if (!noScrollingTo) {
1235
- state.scrollingTo = params;
1236
- }
1237
- state.scrollPending = offset;
1238
- if (!params.isInitialScroll || Platform.OS === "android") {
1239
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1240
- animated: !!animated,
1241
- x: horizontal ? offset : 0,
1242
- y: horizontal ? 0 : offset
1243
- });
1406
+ const contentSize = getContentSize(ctx);
1407
+ if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1408
+ const distanceFromEnd = contentSize - scroll - scrollLength;
1409
+ const isContentLess = contentSize < scrollLength;
1410
+ state.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1411
+ state.isEndReached = checkThreshold(
1412
+ distanceFromEnd,
1413
+ isContentLess,
1414
+ onEndReachedThreshold * scrollLength,
1415
+ state.isEndReached,
1416
+ state.endReachedSnapshot,
1417
+ {
1418
+ contentSize,
1419
+ dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length,
1420
+ scrollPosition: scroll
1421
+ },
1422
+ (distance) => {
1423
+ var _a4, _b;
1424
+ return (_b = (_a4 = state.props).onEndReached) == null ? void 0 : _b.call(_a4, { distanceFromEnd: distance });
1425
+ },
1426
+ (snapshot) => {
1427
+ state.endReachedSnapshot = snapshot;
1428
+ }
1429
+ );
1244
1430
  }
1245
- if (!animated) {
1246
- state.scroll = offset;
1247
- setTimeout(() => finishScrollTo(state), 100);
1248
- if (isInitialScroll) {
1431
+ }
1432
+
1433
+ // src/utils/checkAtTop.ts
1434
+ function checkAtTop(state) {
1435
+ var _a3;
1436
+ if (!state) {
1437
+ return;
1438
+ }
1439
+ const {
1440
+ scrollLength,
1441
+ scroll,
1442
+ props: { onStartReachedThreshold }
1443
+ } = state;
1444
+ const distanceFromTop = scroll;
1445
+ state.isAtStart = distanceFromTop <= 0;
1446
+ state.isStartReached = checkThreshold(
1447
+ distanceFromTop,
1448
+ false,
1449
+ onStartReachedThreshold * scrollLength,
1450
+ state.isStartReached,
1451
+ state.startReachedSnapshot,
1452
+ {
1453
+ contentSize: state.totalSize,
1454
+ dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length,
1455
+ scrollPosition: scroll
1456
+ },
1457
+ (distance) => {
1458
+ var _a4, _b;
1459
+ return (_b = (_a4 = state.props).onStartReached) == null ? void 0 : _b.call(_a4, { distanceFromStart: distance });
1460
+ },
1461
+ (snapshot) => {
1462
+ state.startReachedSnapshot = snapshot;
1463
+ }
1464
+ );
1465
+ }
1466
+
1467
+ // src/core/onScroll.ts
1468
+ function onScroll(ctx, state, event) {
1469
+ var _a3, _b, _c;
1470
+ const {
1471
+ scrollProcessingEnabled,
1472
+ props: { onScroll: onScrollProp }
1473
+ } = state;
1474
+ if (scrollProcessingEnabled === false) {
1475
+ return;
1476
+ }
1477
+ if (((_b = (_a3 = event.nativeEvent) == null ? void 0 : _a3.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
1478
+ return;
1479
+ }
1480
+ const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
1481
+ state.scrollPending = newScroll;
1482
+ updateScroll(ctx, state, newScroll);
1483
+ onScrollProp == null ? void 0 : onScrollProp(event);
1484
+ }
1485
+ function updateScroll(ctx, state, newScroll, forceUpdate) {
1486
+ const scrollingTo = peek$(ctx, "scrollingTo");
1487
+ state.hasScrolled = true;
1488
+ state.lastBatchingAction = Date.now();
1489
+ const currentTime = Date.now();
1490
+ const adjust = state.scrollAdjustHandler.getAdjust();
1491
+ const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1492
+ const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1493
+ if (adjustChanged) {
1494
+ state.scrollHistory.length = 0;
1495
+ }
1496
+ state.lastScrollAdjustForHistory = adjust;
1497
+ if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
1498
+ if (!adjustChanged) {
1499
+ state.scrollHistory.push({ scroll: newScroll, time: currentTime });
1500
+ }
1501
+ }
1502
+ if (state.scrollHistory.length > 5) {
1503
+ state.scrollHistory.shift();
1504
+ }
1505
+ state.scrollPrev = state.scroll;
1506
+ state.scrollPrevTime = state.scrollTime;
1507
+ state.scroll = newScroll;
1508
+ state.scrollTime = currentTime;
1509
+ const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
1510
+ if (ignoreScrollFromMVCP && !scrollingTo) {
1511
+ const { lt, gt } = ignoreScrollFromMVCP;
1512
+ if (lt && newScroll < lt || gt && newScroll > gt) {
1513
+ state.ignoreScrollFromMVCPIgnored = true;
1514
+ return;
1515
+ }
1516
+ }
1517
+ if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1518
+ state.ignoreScrollFromMVCPIgnored = false;
1519
+ calculateItemsInView(ctx, state, { doMVCP: scrollingTo !== void 0 });
1520
+ checkAtBottom(ctx, state);
1521
+ checkAtTop(state);
1522
+ state.dataChangeNeedsScrollUpdate = false;
1523
+ }
1524
+ }
1525
+
1526
+ // src/core/finishScrollTo.ts
1527
+ function finishScrollTo(ctx, state) {
1528
+ var _a3, _b;
1529
+ if (state) {
1530
+ state.scrollHistory.length = 0;
1531
+ state.initialScroll = void 0;
1532
+ set$(ctx, "scrollingTo", void 0);
1533
+ if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1534
+ (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1535
+ }
1536
+ }
1537
+ }
1538
+
1539
+ // src/core/scrollTo.ts
1540
+ function scrollTo(ctx, state, params) {
1541
+ var _a3;
1542
+ const { noScrollingTo, ...scrollTarget } = params;
1543
+ const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1544
+ const {
1545
+ refScroller,
1546
+ props: { horizontal }
1547
+ } = state;
1548
+ let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1549
+ if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1550
+ const maxOffset = Math.max(0, getContentSize(ctx) - state.scrollLength);
1551
+ offset = Math.min(offset, maxOffset);
1552
+ }
1553
+ state.scrollHistory.length = 0;
1554
+ if (!noScrollingTo) {
1555
+ set$(ctx, "scrollingTo", scrollTarget);
1556
+ }
1557
+ state.scrollPending = offset;
1558
+ if (!isInitialScroll || Platform.OS === "android") {
1559
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1560
+ animated: !!animated,
1561
+ x: horizontal ? offset : 0,
1562
+ y: horizontal ? 0 : offset
1563
+ });
1564
+ }
1565
+ if (!animated) {
1566
+ state.scroll = offset;
1567
+ setTimeout(() => finishScrollTo(ctx, state), 100);
1568
+ if (isInitialScroll) {
1249
1569
  setTimeout(() => {
1250
1570
  state.initialScroll = void 0;
1251
1571
  }, 500);
@@ -1266,24 +1586,6 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1266
1586
  const didLayout = peek$(ctx, "containersDidLayout");
1267
1587
  if (didLayout) {
1268
1588
  doit();
1269
- const threshold = state.scroll - positionDiff / 2;
1270
- if (!state.ignoreScrollFromMVCP) {
1271
- state.ignoreScrollFromMVCP = {};
1272
- }
1273
- if (positionDiff > 0) {
1274
- state.ignoreScrollFromMVCP.lt = threshold;
1275
- } else {
1276
- state.ignoreScrollFromMVCP.gt = threshold;
1277
- }
1278
- if (state.ignoreScrollFromMVCPTimeout) {
1279
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
1280
- }
1281
- state.ignoreScrollFromMVCPTimeout = setTimeout(
1282
- () => {
1283
- state.ignoreScrollFromMVCP = void 0;
1284
- },
1285
- 100
1286
- );
1287
1589
  } else {
1288
1590
  requestAnimationFrame(doit);
1289
1591
  }
@@ -1295,9 +1597,9 @@ function prepareMVCP(ctx, state, dataChanged) {
1295
1597
  const {
1296
1598
  idsInView,
1297
1599
  positions,
1298
- scrollingTo,
1299
1600
  props: { maintainVisibleContentPosition }
1300
1601
  } = state;
1602
+ const scrollingTo = peek$(ctx, "scrollingTo");
1301
1603
  let prevPosition;
1302
1604
  let targetId;
1303
1605
  const idsInViewWithPositions = [];
@@ -1373,7 +1675,7 @@ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1373
1675
  const prevId = state.idCache[prevIndex];
1374
1676
  const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1375
1677
  const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1376
- const prevRowHeight = calculateRowMaxSize(state, prevRowStart, prevIndex, useAverageSize);
1678
+ const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1377
1679
  currentRowTop = prevPosition + prevRowHeight;
1378
1680
  }
1379
1681
  return {
@@ -1396,7 +1698,7 @@ function findRowStartIndex(state, numColumns, index) {
1396
1698
  }
1397
1699
  return rowStart;
1398
1700
  }
1399
- function calculateRowMaxSize(state, startIndex, endIndex, useAverageSize) {
1701
+ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1400
1702
  if (endIndex < startIndex) {
1401
1703
  return 0;
1402
1704
  }
@@ -1410,7 +1712,7 @@ function calculateRowMaxSize(state, startIndex, endIndex, useAverageSize) {
1410
1712
  continue;
1411
1713
  }
1412
1714
  const id = state.idCache[i];
1413
- const size = getItemSize(state, id, i, data[i], useAverageSize);
1715
+ const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1414
1716
  if (size > maxSize) {
1415
1717
  maxSize = size;
1416
1718
  }
@@ -1418,82 +1720,43 @@ function calculateRowMaxSize(state, startIndex, endIndex, useAverageSize) {
1418
1720
  return maxSize;
1419
1721
  }
1420
1722
 
1421
- // src/utils/setPaddingTop.ts
1422
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1423
- if (stylePaddingTop !== void 0) {
1424
- const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1425
- if (stylePaddingTop < prevStylePaddingTop) {
1426
- let prevTotalSize = peek$(ctx, "totalSize") || 0;
1427
- set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1428
- state.timeoutSetPaddingTop = setTimeout(() => {
1429
- prevTotalSize = peek$(ctx, "totalSize") || 0;
1430
- set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
1431
- }, 16);
1432
- }
1433
- set$(ctx, "stylePaddingTop", stylePaddingTop);
1434
- }
1435
- if (alignItemsPaddingTop !== void 0) {
1436
- set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1437
- }
1438
- }
1439
-
1440
- // src/utils/updateAlignItemsPaddingTop.ts
1441
- function updateAlignItemsPaddingTop(ctx, state) {
1442
- const {
1443
- scrollLength,
1444
- props: { alignItemsAtEnd, data }
1445
- } = state;
1446
- if (alignItemsAtEnd) {
1447
- let alignItemsPaddingTop = 0;
1448
- if ((data == null ? void 0 : data.length) > 0) {
1449
- const contentSize = getContentSize(ctx);
1450
- alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1451
- }
1452
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
1453
- }
1454
- }
1455
-
1456
- // src/core/updateTotalSize.ts
1457
- function updateTotalSize(ctx, state) {
1458
- const {
1459
- positions,
1460
- props: { data }
1461
- } = state;
1462
- if (data.length === 0) {
1463
- addTotalSize(ctx, state, null, 0);
1464
- } else {
1465
- const lastId = getId(state, data.length - 1);
1466
- if (lastId !== void 0) {
1467
- const lastPosition = positions.get(lastId);
1468
- if (lastPosition !== void 0) {
1469
- const lastSize = getItemSize(state, lastId, data.length - 1, data[data.length - 1]);
1470
- if (lastSize !== void 0) {
1471
- const totalSize = lastPosition + lastSize;
1472
- addTotalSize(ctx, state, null, totalSize);
1723
+ // src/utils/getScrollVelocity.ts
1724
+ var getScrollVelocity = (state) => {
1725
+ const { scrollHistory } = state;
1726
+ let velocity = 0;
1727
+ if (scrollHistory.length >= 1) {
1728
+ const newest = scrollHistory[scrollHistory.length - 1];
1729
+ let oldest;
1730
+ let start = 0;
1731
+ const now = Date.now();
1732
+ for (let i = 0; i < scrollHistory.length - 1; i++) {
1733
+ const entry = scrollHistory[i];
1734
+ const nextEntry = scrollHistory[i + 1];
1735
+ if (i > 0) {
1736
+ const prevEntry = scrollHistory[i - 1];
1737
+ const prevDirection = entry.scroll - prevEntry.scroll;
1738
+ const currentDirection = nextEntry.scroll - entry.scroll;
1739
+ if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1740
+ start = i;
1741
+ break;
1473
1742
  }
1474
1743
  }
1475
1744
  }
1476
- }
1477
- }
1478
- function addTotalSize(ctx, state, key, add) {
1479
- const { alignItemsAtEnd } = state.props;
1480
- const prevTotalSize = state.totalSize;
1481
- if (key === null) {
1482
- state.totalSize = add;
1483
- if (state.timeoutSetPaddingTop) {
1484
- clearTimeout(state.timeoutSetPaddingTop);
1485
- state.timeoutSetPaddingTop = void 0;
1745
+ for (let i = start; i < scrollHistory.length - 1; i++) {
1746
+ const entry = scrollHistory[i];
1747
+ if (now - entry.time <= 1e3) {
1748
+ oldest = entry;
1749
+ break;
1750
+ }
1486
1751
  }
1487
- } else {
1488
- state.totalSize += add;
1489
- }
1490
- if (prevTotalSize !== state.totalSize) {
1491
- set$(ctx, "totalSize", state.totalSize);
1492
- if (alignItemsAtEnd) {
1493
- updateAlignItemsPaddingTop(ctx, state);
1752
+ if (oldest && oldest !== newest) {
1753
+ const scrollDiff = newest.scroll - oldest.scroll;
1754
+ const timeDiff = newest.time - oldest.time;
1755
+ velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1494
1756
  }
1495
1757
  }
1496
- }
1758
+ return velocity;
1759
+ };
1497
1760
 
1498
1761
  // src/utils/updateSnapToOffsets.ts
1499
1762
  function updateSnapToOffsets(ctx, state) {
@@ -1511,23 +1774,30 @@ function updateSnapToOffsets(ctx, state) {
1511
1774
  }
1512
1775
 
1513
1776
  // src/core/updateItemPositions.ts
1514
- function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered } = { scrollBottomBuffered: -1, startIndex: 0 }) {
1515
- var _a3, _b, _c, _d;
1777
+ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false } = {
1778
+ forceFullUpdate: false,
1779
+ scrollBottomBuffered: -1,
1780
+ startIndex: 0
1781
+ }) {
1782
+ var _a3, _b, _c, _d, _e;
1516
1783
  const {
1517
1784
  columns,
1518
1785
  indexByKey,
1519
1786
  positions,
1520
1787
  idCache,
1521
1788
  sizesKnown,
1522
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
1789
+ props: { getEstimatedItemSize, snapToIndices, enableAverages, maintainVisibleContentPosition }
1523
1790
  } = state;
1524
1791
  const data = state.props.data;
1525
1792
  const dataLength = data.length;
1526
1793
  const numColumns = peek$(ctx, "numColumns");
1794
+ const scrollingTo = peek$(ctx, "scrollingTo");
1527
1795
  const hasColumns = numColumns > 1;
1528
1796
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1797
+ const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1529
1798
  const maxVisibleArea = scrollBottomBuffered + 1e3;
1530
1799
  const useAverageSize = enableAverages && !getEstimatedItemSize;
1800
+ const preferCachedSize = maintainVisibleContentPosition && (dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0);
1531
1801
  let currentRowTop = 0;
1532
1802
  let column = 1;
1533
1803
  let maxSizeInRow = 0;
@@ -1544,8 +1814,8 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1544
1814
  } else if (startIndex < dataLength) {
1545
1815
  const prevIndex = startIndex - 1;
1546
1816
  const prevId = getId(state, prevIndex);
1547
- const prevPosition = (_a3 = positions.get(prevId)) != null ? _a3 : 0;
1548
- const prevSize = (_b = sizesKnown.get(prevId)) != null ? _b : getItemSize(state, prevId, prevIndex, data[prevIndex], useAverageSize);
1817
+ const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1818
+ const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1549
1819
  currentRowTop = prevPosition + prevSize;
1550
1820
  }
1551
1821
  }
@@ -1553,16 +1823,16 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1553
1823
  let didBreakEarly = false;
1554
1824
  let breakAt;
1555
1825
  for (let i = startIndex; i < dataLength; i++) {
1556
- if (breakAt && i > breakAt) {
1826
+ if (shouldOptimize && breakAt !== void 0 && i > breakAt) {
1557
1827
  didBreakEarly = true;
1558
1828
  break;
1559
1829
  }
1560
- if (breakAt === void 0 && !dataChanged && currentRowTop > maxVisibleArea) {
1830
+ if (shouldOptimize && breakAt === void 0 && !scrollingTo && !dataChanged && currentRowTop > maxVisibleArea) {
1561
1831
  const itemsPerRow = hasColumns ? numColumns : 1;
1562
1832
  breakAt = i + itemsPerRow + 10;
1563
1833
  }
1564
- const id = (_c = idCache[i]) != null ? _c : getId(state, i);
1565
- const size = (_d = sizesKnown.get(id)) != null ? _d : getItemSize(state, id, i, data[i], useAverageSize);
1834
+ const id = (_d = idCache[i]) != null ? _d : getId(state, i);
1835
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, state, id, i, data[i], useAverageSize, preferCachedSize);
1566
1836
  if (IS_DEV && needsIndexByKey) {
1567
1837
  if (indexByKeyForChecking.has(id)) {
1568
1838
  console.error(
@@ -1780,16 +2050,6 @@ function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize,
1780
2050
  const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
1781
2051
  return value.isViewable;
1782
2052
  }
1783
- function findContainerId(ctx, key) {
1784
- const numContainers = peek$(ctx, "numContainers");
1785
- for (let i = 0; i < numContainers; i++) {
1786
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1787
- if (itemKey === key) {
1788
- return i;
1789
- }
1790
- }
1791
- return -1;
1792
- }
1793
2053
  function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
1794
2054
  const key = containerId + configId;
1795
2055
  ctx.mapViewabilityValues.set(key, viewToken);
@@ -1838,7 +2098,7 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1838
2098
  for (const containerIndex of stickyContainerPool) {
1839
2099
  const key = peek$(ctx, `containerItemKey${containerIndex}`);
1840
2100
  const isPendingRemoval = pendingRemovalSet.has(containerIndex);
1841
- if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType)) {
2101
+ if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType) && !result.includes(containerIndex)) {
1842
2102
  result.push(containerIndex);
1843
2103
  if (isPendingRemoval && pendingRemovalSet.delete(containerIndex)) {
1844
2104
  pendingRemovalChanged = true;
@@ -1926,149 +2186,35 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1926
2186
  if (pendingRemovalChanged) {
1927
2187
  pendingRemoval.length = 0;
1928
2188
  for (const value of pendingRemovalSet) {
1929
- pendingRemoval.push(value);
1930
- }
1931
- }
1932
- return result.sort(comparatorDefault);
1933
- }
1934
- function comparatorByDistance(a, b) {
1935
- return b.distance - a.distance;
1936
- }
1937
-
1938
- // src/utils/getScrollVelocity.ts
1939
- var getScrollVelocity = (state) => {
1940
- const { scrollHistory } = state;
1941
- let velocity = 0;
1942
- if (scrollHistory.length >= 1) {
1943
- const newest = scrollHistory[scrollHistory.length - 1];
1944
- let oldest;
1945
- let start = 0;
1946
- const now = Date.now();
1947
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1948
- const entry = scrollHistory[i];
1949
- const nextEntry = scrollHistory[i + 1];
1950
- if (i > 0) {
1951
- const prevEntry = scrollHistory[i - 1];
1952
- const prevDirection = entry.scroll - prevEntry.scroll;
1953
- const currentDirection = nextEntry.scroll - entry.scroll;
1954
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1955
- start = i;
1956
- break;
1957
- }
1958
- }
1959
- }
1960
- for (let i = start; i < scrollHistory.length - 1; i++) {
1961
- const entry = scrollHistory[i];
1962
- if (now - entry.time <= 1e3) {
1963
- oldest = entry;
1964
- break;
1965
- }
1966
- }
1967
- if (oldest && oldest !== newest) {
1968
- const scrollDiff = newest.scroll - oldest.scroll;
1969
- const timeDiff = newest.time - oldest.time;
1970
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1971
- }
1972
- }
1973
- return velocity;
1974
- };
1975
-
1976
- // src/core/scrollToIndex.ts
1977
- function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
1978
- if (index >= state.props.data.length) {
1979
- index = state.props.data.length - 1;
1980
- } else if (index < 0) {
1981
- index = 0;
1982
- }
1983
- const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
1984
- const isLast = index === state.props.data.length - 1;
1985
- if (isLast && viewPosition === void 0) {
1986
- viewPosition = 1;
1987
- }
1988
- state.scrollForNextCalculateItemsInView = void 0;
1989
- scrollTo(state, {
1990
- animated,
1991
- index,
1992
- offset: firstIndexOffset,
1993
- viewOffset,
1994
- viewPosition: viewPosition != null ? viewPosition : 0
1995
- });
1996
- }
1997
-
1998
- // src/utils/checkThreshold.ts
1999
- var HYSTERESIS_MULTIPLIER = 1.3;
2000
- var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
2001
- const absDistance = Math.abs(distance);
2002
- const within = atThreshold || threshold > 0 && absDistance <= threshold;
2003
- const updateSnapshot = () => {
2004
- setSnapshot == null ? void 0 : setSnapshot({
2005
- atThreshold,
2006
- contentSize: context.contentSize,
2007
- dataLength: context.dataLength,
2008
- scrollPosition: context.scrollPosition
2009
- });
2010
- };
2011
- if (!wasReached) {
2012
- if (!within) {
2013
- return false;
2014
- }
2015
- onReached == null ? void 0 : onReached(distance);
2016
- updateSnapshot();
2017
- return true;
2018
- }
2019
- const reset = !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
2020
- if (reset) {
2021
- setSnapshot == null ? void 0 : setSnapshot(void 0);
2022
- return false;
2023
- }
2024
- if (within) {
2025
- const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
2026
- if (changed) {
2027
- onReached == null ? void 0 : onReached(distance);
2028
- updateSnapshot();
2189
+ pendingRemoval.push(value);
2029
2190
  }
2030
2191
  }
2031
- return true;
2032
- };
2192
+ return result.sort(comparatorDefault);
2193
+ }
2194
+ function comparatorByDistance(a, b) {
2195
+ return b.distance - a.distance;
2196
+ }
2033
2197
 
2034
- // src/utils/checkAtBottom.ts
2035
- function checkAtBottom(ctx, state) {
2036
- var _a3;
2037
- if (!state) {
2038
- return;
2198
+ // src/core/scrollToIndex.ts
2199
+ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
2200
+ if (index >= state.props.data.length) {
2201
+ index = state.props.data.length - 1;
2202
+ } else if (index < 0) {
2203
+ index = 0;
2039
2204
  }
2040
- const {
2041
- queuedInitialLayout,
2042
- scrollLength,
2043
- scroll,
2044
- maintainingScrollAtEnd,
2045
- props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
2046
- } = state;
2047
- const contentSize = getContentSize(ctx);
2048
- if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
2049
- const distanceFromEnd = contentSize - scroll - scrollLength;
2050
- const isContentLess = contentSize < scrollLength;
2051
- state.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
2052
- state.isEndReached = checkThreshold(
2053
- distanceFromEnd,
2054
- isContentLess,
2055
- onEndReachedThreshold * scrollLength,
2056
- state.isEndReached,
2057
- state.endReachedSnapshot,
2058
- {
2059
- scrollPosition: scroll,
2060
- contentSize,
2061
- dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length
2062
- },
2063
- (distance) => {
2064
- var _a4, _b;
2065
- return (_b = (_a4 = state.props).onEndReached) == null ? void 0 : _b.call(_a4, { distanceFromEnd: distance });
2066
- },
2067
- (snapshot) => {
2068
- state.endReachedSnapshot = snapshot;
2069
- }
2070
- );
2205
+ const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
2206
+ const isLast = index === state.props.data.length - 1;
2207
+ if (isLast && viewPosition === void 0) {
2208
+ viewPosition = 1;
2071
2209
  }
2210
+ state.scrollForNextCalculateItemsInView = void 0;
2211
+ scrollTo(ctx, state, {
2212
+ animated,
2213
+ index,
2214
+ offset: firstIndexOffset,
2215
+ viewOffset,
2216
+ viewPosition: viewPosition != null ? viewPosition : 0
2217
+ });
2072
2218
  }
2073
2219
 
2074
2220
  // src/utils/setDidLayout.ts
@@ -2150,7 +2296,7 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2150
2296
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2151
2297
  if (currentId) {
2152
2298
  const currentPos = state.positions.get(currentId);
2153
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(state, currentId, itemIndex, state.props.data[itemIndex]);
2299
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
2154
2300
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2155
2301
  }
2156
2302
  }
@@ -2161,21 +2307,22 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2161
2307
  }
2162
2308
  function calculateItemsInView(ctx, state, params = {}) {
2163
2309
  reactDom.unstable_batchedUpdates(() => {
2164
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
2310
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2165
2311
  const {
2166
2312
  columns,
2167
2313
  containerItemKeys,
2168
2314
  enableScrollForNextCalculateItemsInView,
2169
2315
  idCache,
2170
2316
  indexByKey,
2317
+ initialScroll,
2171
2318
  minIndexSizeChanged,
2172
2319
  positions,
2320
+ props: { getItemType, itemsAreEqual, keyExtractor, onStickyHeaderChange, scrollBuffer },
2173
2321
  scrollForNextCalculateItemsInView,
2174
2322
  scrollLength,
2175
2323
  sizes,
2176
2324
  startBufferedId: startBufferedIdOrig,
2177
- viewabilityConfigCallbackPairs,
2178
- props: { getItemType, initialScroll, itemsAreEqual, keyExtractor, onStickyHeaderChange, scrollBuffer }
2325
+ viewabilityConfigCallbackPairs
2179
2326
  } = state;
2180
2327
  const { data } = state.props;
2181
2328
  const stickyIndicesArr = state.props.stickyIndicesArr || [];
@@ -2187,20 +2334,22 @@ function calculateItemsInView(ctx, state, params = {}) {
2187
2334
  const totalSize = peek$(ctx, "totalSize");
2188
2335
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
2189
2336
  const numColumns = peek$(ctx, "numColumns");
2190
- const { dataChanged, doMVCP } = params;
2337
+ const { dataChanged, doMVCP, forceFullItemPositions } = params;
2191
2338
  const speed = getScrollVelocity(state);
2192
2339
  const scrollExtra = 0;
2193
2340
  const { queuedInitialLayout } = state;
2194
2341
  let { scroll: scrollState } = state;
2195
2342
  if (!queuedInitialLayout && initialScroll) {
2196
2343
  const updatedOffset = calculateOffsetWithOffsetPosition(
2344
+ ctx,
2197
2345
  state,
2198
2346
  calculateOffsetForIndex(ctx, state, initialScroll.index),
2199
2347
  initialScroll
2200
2348
  );
2201
2349
  scrollState = updatedOffset;
2202
2350
  }
2203
- const scrollAdjustPad = -topPad;
2351
+ const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2352
+ const scrollAdjustPad = scrollAdjustPending - topPad;
2204
2353
  let scroll = scrollState + scrollExtra + scrollAdjustPad;
2205
2354
  if (scroll + scrollLength > totalSize) {
2206
2355
  scroll = Math.max(0, totalSize - scrollLength);
@@ -2213,6 +2362,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2213
2362
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2214
2363
  const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2215
2364
  state.activeStickyIndex = nextActiveStickyIndex;
2365
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2216
2366
  let scrollBufferTop = scrollBuffer;
2217
2367
  let scrollBufferBottom = scrollBuffer;
2218
2368
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2237,8 +2387,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2237
2387
  idCache.length = 0;
2238
2388
  positions.clear();
2239
2389
  }
2240
- const startIndex = dataChanged ? 0 : (_a3 = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _a3 : 0;
2241
- updateItemPositions(ctx, state, dataChanged, { scrollBottomBuffered, startIndex });
2390
+ const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2391
+ updateItemPositions(ctx, state, dataChanged, {
2392
+ forceFullUpdate: !!forceFullItemPositions,
2393
+ scrollBottomBuffered,
2394
+ startIndex
2395
+ });
2242
2396
  if (minIndexSizeChanged !== void 0) {
2243
2397
  state.minIndexSizeChanged = void 0;
2244
2398
  }
@@ -2250,9 +2404,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2250
2404
  let endBuffered = null;
2251
2405
  let loopStart = !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
2252
2406
  for (let i = loopStart; i >= 0; i--) {
2253
- const id = (_b = idCache[i]) != null ? _b : getId(state, i);
2407
+ const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2254
2408
  const top = positions.get(id);
2255
- const size = (_c = sizes.get(id)) != null ? _c : getItemSize(state, id, i, data[i]);
2409
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2256
2410
  const bottom = top + size;
2257
2411
  if (bottom > scroll - scrollBuffer) {
2258
2412
  loopStart = i;
@@ -2278,8 +2432,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2278
2432
  let firstFullyOnScreenIndex;
2279
2433
  const dataLength = data.length;
2280
2434
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2281
- const id = (_d = idCache[i]) != null ? _d : getId(state, i);
2282
- const size = (_e = sizes.get(id)) != null ? _e : getItemSize(state, id, i, data[i]);
2435
+ const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2436
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2283
2437
  const top = positions.get(id);
2284
2438
  if (!foundEnd) {
2285
2439
  if (startNoBuffer === null && top + size > scroll) {
@@ -2308,7 +2462,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2308
2462
  }
2309
2463
  const idsInView = [];
2310
2464
  for (let i = firstFullyOnScreenIndex; i <= endNoBuffer; i++) {
2311
- const id = (_f = idCache[i]) != null ? _f : getId(state, i);
2465
+ const id = (_g = idCache[i]) != null ? _g : getId(state, i);
2312
2466
  idsInView.push(id);
2313
2467
  }
2314
2468
  Object.assign(state, {
@@ -2340,7 +2494,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2340
2494
  let numContainers2 = prevNumContainers;
2341
2495
  const needNewContainers = [];
2342
2496
  for (let i = startBuffered; i <= endBuffered; i++) {
2343
- const id = (_g = idCache[i]) != null ? _g : getId(state, i);
2497
+ const id = (_h = idCache[i]) != null ? _h : getId(state, i);
2344
2498
  if (!containerItemKeys.has(id)) {
2345
2499
  needNewContainers.push(i);
2346
2500
  }
@@ -2358,6 +2512,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2358
2512
  );
2359
2513
  } else {
2360
2514
  state.activeStickyIndex = void 0;
2515
+ set$(ctx, "activeStickyIndex", void 0);
2361
2516
  }
2362
2517
  if (needNewContainers.length > 0) {
2363
2518
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
@@ -2377,7 +2532,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2377
2532
  for (let idx = 0; idx < needNewContainers.length; idx++) {
2378
2533
  const i = needNewContainers[idx];
2379
2534
  const containerIndex = availableContainers[idx];
2380
- const id = (_h = idCache[i]) != null ? _h : getId(state, i);
2535
+ const id = (_i = idCache[i]) != null ? _i : getId(state, i);
2381
2536
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
2382
2537
  if (oldKey && oldKey !== id) {
2383
2538
  containerItemKeys.delete(oldKey);
@@ -2416,7 +2571,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2416
2571
  for (let i = 0; i < numContainers; i++) {
2417
2572
  const itemKey = peek$(ctx, `containerItemKey${i}`);
2418
2573
  if (pendingRemoval.includes(i)) {
2419
- if (itemKey) {
2574
+ if (itemKey !== void 0) {
2420
2575
  containerItemKeys.delete(itemKey);
2421
2576
  }
2422
2577
  state.containerItemTypes.delete(i);
@@ -2433,11 +2588,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2433
2588
  const itemIndex = indexByKey.get(itemKey);
2434
2589
  const item = data[itemIndex];
2435
2590
  if (item !== void 0) {
2436
- const id = (_i = idCache[itemIndex]) != null ? _i : getId(state, itemIndex);
2437
- const position = positions.get(id);
2438
- if (position === void 0) {
2591
+ const id = (_j = idCache[itemIndex]) != null ? _j : getId(state, itemIndex);
2592
+ const positionValue = positions.get(id);
2593
+ if (positionValue === void 0) {
2439
2594
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2440
2595
  } else {
2596
+ const position = (positionValue || 0) - scrollAdjustPending;
2441
2597
  const column = columns.get(id) || 1;
2442
2598
  const prevPos = peek$(ctx, `containerPosition${i}`);
2443
2599
  const prevColumn = peek$(ctx, `containerColumn${i}`);
@@ -2476,6 +2632,26 @@ function calculateItemsInView(ctx, state, params = {}) {
2476
2632
  });
2477
2633
  }
2478
2634
 
2635
+ // src/core/checkActualChange.ts
2636
+ function checkActualChange(state, dataProp, previousData) {
2637
+ if (!previousData || !dataProp || dataProp.length !== previousData.length) {
2638
+ return true;
2639
+ }
2640
+ const {
2641
+ idCache,
2642
+ props: { keyExtractor }
2643
+ } = state;
2644
+ for (let i = 0; i < dataProp.length; i++) {
2645
+ if (dataProp[i] !== previousData[i]) {
2646
+ return true;
2647
+ }
2648
+ if (keyExtractor ? idCache[i] !== keyExtractor(previousData[i], i) : dataProp[i] !== previousData[i]) {
2649
+ return true;
2650
+ }
2651
+ }
2652
+ return false;
2653
+ }
2654
+
2479
2655
  // src/core/doMaintainScrollAtEnd.ts
2480
2656
  function doMaintainScrollAtEnd(ctx, state, animated) {
2481
2657
  const {
@@ -2506,40 +2682,6 @@ function doMaintainScrollAtEnd(ctx, state, animated) {
2506
2682
  }
2507
2683
  }
2508
2684
 
2509
- // src/utils/checkAtTop.ts
2510
- function checkAtTop(state) {
2511
- var _a3;
2512
- if (!state) {
2513
- return;
2514
- }
2515
- const {
2516
- scrollLength,
2517
- scroll,
2518
- props: { onStartReachedThreshold }
2519
- } = state;
2520
- const distanceFromTop = scroll;
2521
- state.isAtStart = distanceFromTop <= 0;
2522
- state.isStartReached = checkThreshold(
2523
- distanceFromTop,
2524
- false,
2525
- onStartReachedThreshold * scrollLength,
2526
- state.isStartReached,
2527
- state.startReachedSnapshot,
2528
- {
2529
- scrollPosition: scroll,
2530
- contentSize: state.totalSize,
2531
- dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length
2532
- },
2533
- (distance) => {
2534
- var _a4, _b;
2535
- return (_b = (_a4 = state.props).onStartReached) == null ? void 0 : _b.call(_a4, { distanceFromStart: distance });
2536
- },
2537
- (snapshot) => {
2538
- state.startReachedSnapshot = snapshot;
2539
- }
2540
- );
2541
- }
2542
-
2543
2685
  // src/utils/updateAveragesOnDataChange.ts
2544
2686
  function updateAveragesOnDataChange(state, oldData, newData) {
2545
2687
  var _a3;
@@ -2593,25 +2735,23 @@ function updateAveragesOnDataChange(state, oldData, newData) {
2593
2735
  }
2594
2736
 
2595
2737
  // src/core/checkResetContainers.ts
2596
- function checkResetContainers(ctx, state, isFirst, dataProp) {
2597
- if (state) {
2598
- if (!isFirst && state.props.data !== dataProp) {
2599
- updateAveragesOnDataChange(state, state.props.data, dataProp);
2600
- }
2601
- const { maintainScrollAtEnd } = state.props;
2602
- if (!isFirst) {
2603
- calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2604
- const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2605
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2606
- if (!didMaintainScrollAtEnd && dataProp.length > state.props.data.length) {
2607
- state.isEndReached = false;
2608
- }
2609
- if (!didMaintainScrollAtEnd) {
2610
- checkAtTop(state);
2611
- checkAtBottom(ctx, state);
2612
- }
2613
- }
2738
+ function checkResetContainers(ctx, state, dataProp) {
2739
+ const { previousData } = state;
2740
+ if (previousData) {
2741
+ updateAveragesOnDataChange(state, previousData, dataProp);
2742
+ }
2743
+ const { maintainScrollAtEnd } = state.props;
2744
+ calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2745
+ const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2746
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2747
+ if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2748
+ state.isEndReached = false;
2614
2749
  }
2750
+ if (!didMaintainScrollAtEnd) {
2751
+ checkAtTop(state);
2752
+ checkAtBottom(ctx, state);
2753
+ }
2754
+ delete state.previousData;
2615
2755
  }
2616
2756
 
2617
2757
  // src/core/doInitialAllocateContainers.ts
@@ -2652,7 +2792,7 @@ function doInitialAllocateContainers(ctx, state) {
2652
2792
  set$(ctx, "numContainers", numContainers);
2653
2793
  set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
2654
2794
  if (state.lastLayout) {
2655
- if (state.props.initialScroll) {
2795
+ if (state.initialScroll) {
2656
2796
  requestAnimationFrame(() => {
2657
2797
  calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2658
2798
  });
@@ -2708,78 +2848,47 @@ function handleLayout(ctx, state, layout, setCanRender) {
2708
2848
  setCanRender(true);
2709
2849
  }
2710
2850
 
2711
- // src/core/onScroll.ts
2712
- function onScroll(ctx, state, event) {
2713
- var _a3, _b, _c;
2714
- const {
2715
- scrollProcessingEnabled,
2716
- props: { onScroll: onScrollProp }
2717
- } = state;
2718
- if (scrollProcessingEnabled === false) {
2719
- return;
2720
- }
2721
- if (((_b = (_a3 = event.nativeEvent) == null ? void 0 : _a3.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
2722
- return;
2723
- }
2724
- const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2725
- state.scrollPending = newScroll;
2726
- updateScroll(ctx, state, newScroll);
2727
- onScrollProp == null ? void 0 : onScrollProp(event);
2728
- }
2729
- function updateScroll(ctx, state, newScroll) {
2730
- const scrollingTo = state.scrollingTo;
2731
- state.hasScrolled = true;
2732
- state.lastBatchingAction = Date.now();
2733
- const currentTime = Date.now();
2734
- const adjust = state.scrollAdjustHandler.getAdjust();
2735
- const lastHistoryAdjust = state.lastScrollAdjustForHistory;
2736
- const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
2737
- if (adjustChanged) {
2738
- state.scrollHistory.length = 0;
2739
- }
2740
- state.lastScrollAdjustForHistory = adjust;
2741
- if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
2742
- if (!adjustChanged) {
2743
- state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2744
- }
2745
- }
2746
- if (state.scrollHistory.length > 5) {
2747
- state.scrollHistory.shift();
2748
- }
2749
- state.scrollPrev = state.scroll;
2750
- state.scrollPrevTime = state.scrollTime;
2751
- state.scroll = newScroll;
2752
- state.scrollTime = currentTime;
2753
- const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
2754
- if (ignoreScrollFromMVCP && !state.scrollingTo) {
2755
- const { lt, gt } = ignoreScrollFromMVCP;
2756
- if (lt && newScroll < lt || gt && newScroll > gt) {
2757
- return;
2758
- }
2759
- }
2760
- if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
2761
- calculateItemsInView(ctx, state, { doMVCP: state.scrollingTo !== void 0 });
2762
- checkAtBottom(ctx, state);
2763
- checkAtTop(state);
2764
- state.dataChangeNeedsScrollUpdate = false;
2765
- }
2766
- }
2767
-
2768
2851
  // src/core/ScrollAdjustHandler.ts
2769
2852
  var ScrollAdjustHandler = class {
2770
2853
  constructor(ctx) {
2771
2854
  this.appliedAdjust = 0;
2855
+ this.pendingAdjust = 0;
2772
2856
  this.mounted = false;
2773
2857
  this.context = ctx;
2858
+ {
2859
+ const commitPendingAdjust = () => {
2860
+ const state = this.context.internalState;
2861
+ const pending = this.pendingAdjust;
2862
+ if (pending !== 0) {
2863
+ this.pendingAdjust = 0;
2864
+ this.appliedAdjust += pending;
2865
+ state.scroll += pending;
2866
+ state.scrollForNextCalculateItemsInView = void 0;
2867
+ set$(this.context, "scrollAdjustPending", 0);
2868
+ set$(this.context, "scrollAdjust", this.appliedAdjust);
2869
+ calculateItemsInView(this.context, this.context.internalState);
2870
+ }
2871
+ };
2872
+ listen$(this.context, "scrollingTo", (value) => {
2873
+ if (value === void 0) {
2874
+ commitPendingAdjust();
2875
+ }
2876
+ });
2877
+ }
2774
2878
  }
2775
2879
  requestAdjust(add) {
2776
- const oldAdjustTop = this.appliedAdjust;
2777
- this.appliedAdjust = add + oldAdjustTop;
2778
- const set = () => set$(this.context, "scrollAdjust", this.appliedAdjust);
2779
- if (this.mounted) {
2780
- set();
2880
+ const scrollingTo = peek$(this.context, "scrollingTo");
2881
+ if ((scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2882
+ this.pendingAdjust += add;
2883
+ set$(this.context, "scrollAdjustPending", this.pendingAdjust);
2781
2884
  } else {
2782
- requestAnimationFrame(set);
2885
+ this.appliedAdjust += add;
2886
+ const setter = () => set$(this.context, "scrollAdjust", this.appliedAdjust);
2887
+ if (this.mounted) {
2888
+ setter();
2889
+ } else {
2890
+ requestAnimationFrame(setter);
2891
+ }
2783
2892
  }
2784
2893
  }
2785
2894
  setMounted() {
@@ -2827,8 +2936,8 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2827
2936
  let minIndexSizeChanged;
2828
2937
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2829
2938
  const prevSizeKnown = state.sizesKnown.get(itemKey);
2830
- const diff = updateOneItemSize(state, itemKey, sizeObj);
2831
- const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2939
+ const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
2940
+ const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
2832
2941
  if (diff !== 0) {
2833
2942
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
2834
2943
  const { startBuffered, endBuffered } = state;
@@ -2849,7 +2958,6 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2849
2958
  if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2850
2959
  shouldMaintainScrollAtEnd = true;
2851
2960
  }
2852
- addTotalSize(ctx, state, itemKey, diff);
2853
2961
  onItemSizeChanged == null ? void 0 : onItemSizeChanged({
2854
2962
  index,
2855
2963
  itemData: state.props.data[index],
@@ -2889,7 +2997,7 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2889
2997
  }
2890
2998
  }
2891
2999
  }
2892
- function updateOneItemSize(state, itemKey, sizeObj) {
3000
+ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
2893
3001
  var _a3;
2894
3002
  const {
2895
3003
  sizes,
@@ -2900,7 +3008,7 @@ function updateOneItemSize(state, itemKey, sizeObj) {
2900
3008
  } = state;
2901
3009
  if (!data) return 0;
2902
3010
  const index = indexByKey.get(itemKey);
2903
- const prevSize = getItemSize(state, itemKey, index, data[index]);
3011
+ const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
2904
3012
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
2905
3013
  const size = Math.round(rawSize) ;
2906
3014
  sizesKnown.set(itemKey, size);
@@ -2914,7 +3022,7 @@ function updateOneItemSize(state, itemKey, sizeObj) {
2914
3022
  averages.num++;
2915
3023
  }
2916
3024
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2917
- sizes.set(itemKey, size);
3025
+ setSize(ctx, state, itemKey, size);
2918
3026
  return size - prevSize;
2919
3027
  }
2920
3028
  return 0;
@@ -2959,6 +3067,91 @@ function createColumnWrapperStyle(contentContainerStyle) {
2959
3067
  };
2960
3068
  }
2961
3069
  }
3070
+
3071
+ // src/utils/createImperativeHandle.ts
3072
+ function createImperativeHandle(ctx, state) {
3073
+ const scrollIndexIntoView = (options) => {
3074
+ if (state) {
3075
+ const { index, ...rest } = options;
3076
+ const { startNoBuffer, endNoBuffer } = state;
3077
+ if (index < startNoBuffer || index > endNoBuffer) {
3078
+ const viewPosition = index < startNoBuffer ? 0 : 1;
3079
+ scrollToIndex(ctx, state, {
3080
+ ...rest,
3081
+ index,
3082
+ viewPosition
3083
+ });
3084
+ }
3085
+ }
3086
+ };
3087
+ const refScroller = state.refScroller;
3088
+ return {
3089
+ flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
3090
+ getNativeScrollRef: () => refScroller.current,
3091
+ getScrollableNode: () => refScroller.current.getScrollableNode(),
3092
+ getScrollResponder: () => refScroller.current.getScrollResponder(),
3093
+ getState: () => ({
3094
+ activeStickyIndex: state.activeStickyIndex,
3095
+ contentLength: state.totalSize,
3096
+ data: state.props.data,
3097
+ elementAtIndex: (index) => {
3098
+ var _a3;
3099
+ return (_a3 = ctx.viewRefs.get(findContainerId(ctx, getId(state, index)))) == null ? void 0 : _a3.current;
3100
+ },
3101
+ end: state.endNoBuffer,
3102
+ endBuffered: state.endBuffered,
3103
+ isAtEnd: state.isAtEnd,
3104
+ isAtStart: state.isAtStart,
3105
+ positionAtIndex: (index) => state.positions.get(getId(state, index)),
3106
+ positions: state.positions,
3107
+ scroll: state.scroll,
3108
+ scrollLength: state.scrollLength,
3109
+ sizeAtIndex: (index) => state.sizesKnown.get(getId(state, index)),
3110
+ sizes: state.sizesKnown,
3111
+ start: state.startNoBuffer,
3112
+ startBuffered: state.startBuffered
3113
+ }),
3114
+ scrollIndexIntoView,
3115
+ scrollItemIntoView: ({ item, ...props }) => {
3116
+ const data = state.props.data;
3117
+ const index = data.indexOf(item);
3118
+ if (index !== -1) {
3119
+ scrollIndexIntoView({ index, ...props });
3120
+ }
3121
+ },
3122
+ scrollToEnd: (options) => {
3123
+ const data = state.props.data;
3124
+ const stylePaddingBottom = state.props.stylePaddingBottom;
3125
+ const index = data.length - 1;
3126
+ if (index !== -1) {
3127
+ const paddingBottom = stylePaddingBottom || 0;
3128
+ const footerSize = peek$(ctx, "footerSize") || 0;
3129
+ scrollToIndex(ctx, state, {
3130
+ index,
3131
+ viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3132
+ viewPosition: 1,
3133
+ ...options
3134
+ });
3135
+ }
3136
+ },
3137
+ scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3138
+ scrollToItem: ({ item, ...props }) => {
3139
+ const data = state.props.data;
3140
+ const index = data.indexOf(item);
3141
+ if (index !== -1) {
3142
+ scrollToIndex(ctx, state, { index, ...props });
3143
+ }
3144
+ },
3145
+ scrollToOffset: (params) => scrollTo(ctx, state, params),
3146
+ setScrollProcessingEnabled: (enabled) => {
3147
+ state.scrollProcessingEnabled = enabled;
3148
+ },
3149
+ setVisibleContentAnchorOffset: (value) => {
3150
+ const val = isFunction(value) ? value(peek$(ctx, "scrollAdjustUserOffset") || 0) : value;
3151
+ set$(ctx, "scrollAdjustUserOffset", val);
3152
+ }
3153
+ };
3154
+ }
2962
3155
  function getRenderedItem(ctx, state, key) {
2963
3156
  var _a3;
2964
3157
  if (!state) {
@@ -3059,6 +3252,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3059
3252
  columnWrapperStyle,
3060
3253
  contentContainerStyle: contentContainerStyleProp,
3061
3254
  data: dataProp = [],
3255
+ dataVersion,
3062
3256
  drawDistance = 250,
3063
3257
  enableAverages = true,
3064
3258
  estimatedItemSize: estimatedItemSizeProp,
@@ -3069,6 +3263,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3069
3263
  getItemType,
3070
3264
  horizontal,
3071
3265
  initialContainerPoolRatio = 2,
3266
+ initialScrollAtEnd = false,
3072
3267
  initialScrollIndex: initialScrollIndexProp,
3073
3268
  initialScrollOffset: initialScrollOffsetProp,
3074
3269
  itemsAreEqual,
@@ -3107,13 +3302,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3107
3302
  waitForInitialLayout = true,
3108
3303
  ...rest
3109
3304
  } = props;
3110
- const [renderNum, setRenderNum] = React3.useState(0);
3111
- const initialScroll = initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
3112
- const [canRender, setCanRender] = React3__namespace.useState(!IsNewArchitecture);
3113
3305
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
3114
3306
  const style = { ...StyleSheet.flatten(styleProp) };
3115
3307
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
3116
3308
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
3309
+ const [renderNum, setRenderNum] = React3.useState(0);
3310
+ const initialScrollProp = initialScrollAtEnd ? { index: Math.max(0, dataProp.length - 1), viewOffset: -stylePaddingBottomState } : initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
3311
+ const [canRender, setCanRender] = React3__namespace.useState(!IsNewArchitecture);
3117
3312
  const ctx = useStateContext();
3118
3313
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
3119
3314
  const refScroller = React3.useRef(null);
@@ -3132,6 +3327,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3132
3327
  containerItemKeys: /* @__PURE__ */ new Set(),
3133
3328
  containerItemTypes: /* @__PURE__ */ new Map(),
3134
3329
  dataChangeNeedsScrollUpdate: false,
3330
+ didColumnsChange: false,
3331
+ didDataChange: false,
3135
3332
  enableScrollForNextCalculateItemsInView: true,
3136
3333
  endBuffered: -1,
3137
3334
  endNoBuffer: -1,
@@ -3140,10 +3337,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3140
3337
  idCache: [],
3141
3338
  idsInView: [],
3142
3339
  indexByKey: /* @__PURE__ */ new Map(),
3143
- initialScroll,
3340
+ initialScroll: initialScrollProp,
3144
3341
  isAtEnd: false,
3145
3342
  isAtStart: false,
3146
3343
  isEndReached: false,
3344
+ isFirst: true,
3147
3345
  isStartReached: false,
3148
3346
  lastBatchingAction: Date.now(),
3149
3347
  lastLayout: void 0,
@@ -3176,21 +3374,27 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3176
3374
  totalSize: 0,
3177
3375
  viewabilityConfigCallbackPairs: void 0
3178
3376
  };
3377
+ const internalState = ctx.internalState;
3378
+ internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, internalState, params);
3179
3379
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
3180
3380
  set$(ctx, "extraData", extraData);
3181
3381
  }
3182
3382
  refState.current = ctx.internalState;
3183
3383
  }
3184
3384
  const state = refState.current;
3185
- const isFirst = !state.props.renderItem;
3186
- const didDataChange = state.props.data !== dataProp;
3187
- if (didDataChange) {
3385
+ const isFirstLocal = state.isFirst;
3386
+ state.didColumnsChange = numColumnsProp !== state.props.numColumns;
3387
+ const didDataChangeLocal = state.props.dataVersion !== dataVersion || state.props.data !== dataProp && checkActualChange(state, dataProp, state.props.data);
3388
+ if (didDataChangeLocal) {
3188
3389
  state.dataChangeNeedsScrollUpdate = true;
3390
+ state.didDataChange = true;
3391
+ state.previousData = state.props.data;
3189
3392
  }
3190
3393
  const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
3191
3394
  state.props = {
3192
3395
  alignItemsAtEnd,
3193
3396
  data: dataProp,
3397
+ dataVersion,
3194
3398
  enableAverages,
3195
3399
  estimatedItemSize,
3196
3400
  getEstimatedItemSize,
@@ -3198,7 +3402,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3198
3402
  getItemType,
3199
3403
  horizontal: !!horizontal,
3200
3404
  initialContainerPoolRatio,
3201
- initialScroll,
3202
3405
  itemsAreEqual,
3203
3406
  keyExtractor,
3204
3407
  maintainScrollAtEnd,
@@ -3230,7 +3433,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3230
3433
  { length: Math.min(numColumnsProp, dataProp.length) },
3231
3434
  (_, i) => getId(state, dataProp.length - 1 - i)
3232
3435
  );
3233
- }, [dataProp, numColumnsProp]);
3436
+ }, [dataProp, dataVersion, numColumnsProp]);
3234
3437
  const initializeStateVars = () => {
3235
3438
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
3236
3439
  set$(ctx, "numColumns", numColumnsProp);
@@ -3245,7 +3448,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3245
3448
  requestAdjust(ctx, state, paddingDiff);
3246
3449
  }
3247
3450
  };
3248
- if (isFirst) {
3451
+ if (isFirstLocal) {
3249
3452
  initializeStateVars();
3250
3453
  updateItemPositions(
3251
3454
  ctx,
@@ -3255,38 +3458,42 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3255
3458
  );
3256
3459
  }
3257
3460
  const initialContentOffset = React3.useMemo(() => {
3258
- if (initialScroll) {
3259
- const { index, viewOffset } = initialScroll;
3260
- let initialContentOffset2 = viewOffset || 0;
3261
- if (index !== void 0) {
3262
- initialContentOffset2 += calculateOffsetForIndex(ctx, state, index);
3263
- }
3264
- refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
3265
- if (initialContentOffset2 > 0) {
3266
- scrollTo(state, {
3267
- animated: false,
3268
- index,
3269
- isInitialScroll: true,
3270
- offset: initialContentOffset2,
3271
- viewPosition: index === dataProp.length - 1 ? 1 : 0
3272
- });
3273
- }
3274
- return initialContentOffset2;
3275
- }
3276
- return 0;
3277
- }, [renderNum]);
3278
- if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
3461
+ const { initialScroll } = refState.current;
3462
+ if (!initialScroll) {
3463
+ return 0;
3464
+ }
3465
+ if (initialScroll.contentOffset !== void 0) {
3466
+ return initialScroll.contentOffset;
3467
+ }
3468
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, state, initialScroll.index) : 0;
3469
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, state, baseOffset, initialScroll);
3470
+ let clampedOffset = resolvedOffset;
3471
+ if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
3472
+ const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
3473
+ clampedOffset = Math.min(clampedOffset, maxOffset);
3474
+ }
3475
+ clampedOffset = Math.max(0, clampedOffset);
3476
+ const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3477
+ refState.current.initialScroll = updatedInitialScroll;
3478
+ state.initialScroll = updatedInitialScroll;
3479
+ refState.current.isStartReached = clampedOffset < refState.current.scrollLength * onStartReachedThreshold;
3480
+ return clampedOffset;
3481
+ }, [renderNum, state.initialScroll]);
3482
+ if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3279
3483
  refState.current.lastBatchingAction = Date.now();
3280
- if (!keyExtractorProp && !isFirst && didDataChange) {
3484
+ if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
3281
3485
  IS_DEV && warnDevOnce(
3282
3486
  "keyExtractor",
3283
3487
  "Changing data without a keyExtractor can cause slow performance and resetting scroll. If your list data can change you should use a keyExtractor with a unique id for best performance and behavior."
3284
3488
  );
3285
3489
  refState.current.sizes.clear();
3286
3490
  refState.current.positions.clear();
3491
+ refState.current.totalSize = 0;
3492
+ set$(ctx, "totalSize", 0);
3287
3493
  }
3288
3494
  }
3289
3495
  const onLayoutHeader = React3.useCallback((rect, fromLayoutEffect) => {
3496
+ const { initialScroll } = refState.current;
3290
3497
  const size = rect[horizontal ? "width" : "height"];
3291
3498
  set$(ctx, "headerSize", size);
3292
3499
  if ((initialScroll == null ? void 0 : initialScroll.index) !== void 0) {
@@ -3297,31 +3504,57 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3297
3504
  }
3298
3505
  }
3299
3506
  }, []);
3507
+ const doInitialScroll = React3.useCallback(() => {
3508
+ var _a4;
3509
+ const initialScroll = state.initialScroll;
3510
+ if (initialScroll) {
3511
+ scrollTo(ctx, state, {
3512
+ animated: false,
3513
+ index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3514
+ offset: initialContentOffset,
3515
+ precomputedWithViewOffset: true
3516
+ });
3517
+ }
3518
+ }, [initialContentOffset, state.initialScroll]);
3519
+ const onLayoutChange = React3.useCallback((layout) => {
3520
+ doInitialScroll();
3521
+ handleLayout(ctx, state, layout, setCanRender);
3522
+ }, []);
3523
+ const { onLayout } = useOnLayoutSync({
3524
+ onLayoutChange,
3525
+ onLayoutProp,
3526
+ ref: refScroller
3527
+ // the type of ScrollView doesn't include measure?
3528
+ });
3300
3529
  React3.useLayoutEffect(() => {
3301
3530
  if (snapToIndices) {
3302
3531
  updateSnapToOffsets(ctx, state);
3303
3532
  }
3304
3533
  }, [snapToIndices]);
3305
3534
  React3.useLayoutEffect(() => {
3306
- const didAllocateContainers = dataProp.length > 0 && doInitialAllocateContainers(ctx, state);
3307
- if (!didAllocateContainers) {
3308
- checkResetContainers(
3309
- ctx,
3310
- state,
3311
- /*isFirst*/
3312
- isFirst,
3313
- dataProp
3314
- );
3315
- }
3316
- }, [dataProp, numColumnsProp]);
3535
+ const {
3536
+ didColumnsChange,
3537
+ didDataChange,
3538
+ isFirst,
3539
+ props: { data }
3540
+ } = state;
3541
+ const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3542
+ if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3543
+ checkResetContainers(ctx, state, data);
3544
+ }
3545
+ state.didColumnsChange = false;
3546
+ state.didDataChange = false;
3547
+ state.isFirst = false;
3548
+ }, [dataProp, dataVersion, numColumnsProp]);
3317
3549
  React3.useLayoutEffect(() => {
3318
3550
  set$(ctx, "extraData", extraData);
3319
3551
  }, [extraData]);
3320
3552
  React3.useLayoutEffect(initializeStateVars, [
3553
+ dataVersion,
3321
3554
  memoizedLastItemKeys.join(","),
3322
3555
  numColumnsProp,
3323
- stylePaddingTopState,
3324
- stylePaddingBottomState
3556
+ stylePaddingBottomState,
3557
+ stylePaddingTopState
3325
3558
  ]);
3326
3559
  React3.useEffect(() => {
3327
3560
  const viewability = setupViewability({
@@ -3332,103 +3565,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3332
3565
  state.viewabilityConfigCallbackPairs = viewability;
3333
3566
  state.enableScrollForNextCalculateItemsInView = !viewability;
3334
3567
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3335
- const onLayoutChange = React3.useCallback((layout) => {
3336
- handleLayout(ctx, state, layout, setCanRender);
3337
- }, []);
3338
- const { onLayout } = useOnLayoutSync({
3339
- onLayoutChange,
3340
- onLayoutProp,
3341
- ref: refScroller
3342
- // the type of ScrollView doesn't include measure?
3343
- });
3344
- React3.useImperativeHandle(forwardedRef, () => {
3345
- const scrollIndexIntoView = (options) => {
3346
- const state2 = refState.current;
3347
- if (state2) {
3348
- const { index, ...rest2 } = options;
3349
- const { startNoBuffer, endNoBuffer } = state2;
3350
- if (index < startNoBuffer || index > endNoBuffer) {
3351
- const viewPosition = index < startNoBuffer ? 0 : 1;
3352
- scrollToIndex(ctx, state2, {
3353
- ...rest2,
3354
- index,
3355
- viewPosition
3356
- });
3357
- }
3358
- }
3359
- };
3360
- return {
3361
- flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
3362
- getNativeScrollRef: () => refScroller.current,
3363
- getScrollableNode: () => refScroller.current.getScrollableNode(),
3364
- getScrollResponder: () => refScroller.current.getScrollResponder(),
3365
- getState: () => {
3366
- const state2 = refState.current;
3367
- return state2 ? {
3368
- activeStickyIndex: state2.activeStickyIndex,
3369
- contentLength: state2.totalSize,
3370
- data: state2.props.data,
3371
- end: state2.endNoBuffer,
3372
- endBuffered: state2.endBuffered,
3373
- isAtEnd: state2.isAtEnd,
3374
- isAtStart: state2.isAtStart,
3375
- positionAtIndex: (index) => state2.positions.get(getId(state2, index)),
3376
- positions: state2.positions,
3377
- scroll: state2.scroll,
3378
- scrollLength: state2.scrollLength,
3379
- sizeAtIndex: (index) => state2.sizesKnown.get(getId(state2, index)),
3380
- sizes: state2.sizesKnown,
3381
- start: state2.startNoBuffer,
3382
- startBuffered: state2.startBuffered
3383
- } : {};
3384
- },
3385
- scrollIndexIntoView,
3386
- scrollItemIntoView: ({ item, ...props2 }) => {
3387
- const data = refState.current.props.data;
3388
- const index = data.indexOf(item);
3389
- if (index !== -1) {
3390
- scrollIndexIntoView({ index, ...props2 });
3391
- }
3392
- },
3393
- scrollToEnd: (options) => {
3394
- const data = refState.current.props.data;
3395
- const stylePaddingBottom = refState.current.props.stylePaddingBottom;
3396
- const index = data.length - 1;
3397
- if (index !== -1) {
3398
- const paddingBottom = stylePaddingBottom || 0;
3399
- const footerSize = peek$(ctx, "footerSize") || 0;
3400
- scrollToIndex(ctx, state, {
3401
- index,
3402
- viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3403
- viewPosition: 1,
3404
- ...options
3405
- });
3406
- }
3407
- },
3408
- scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3409
- scrollToItem: ({ item, ...props2 }) => {
3410
- const data = refState.current.props.data;
3411
- const index = data.indexOf(item);
3412
- if (index !== -1) {
3413
- scrollToIndex(ctx, state, { index, ...props2 });
3414
- }
3415
- },
3416
- scrollToOffset: (params) => scrollTo(state, params),
3417
- setScrollProcessingEnabled: (enabled) => {
3418
- refState.current.scrollProcessingEnabled = enabled;
3419
- },
3420
- setVisibleContentAnchorOffset: (value) => {
3421
- const val = typeof value === "function" ? value(peek$(ctx, "scrollAdjustUserOffset") || 0) : value;
3422
- set$(ctx, "scrollAdjustUserOffset", val);
3423
- }
3424
- };
3425
- }, []);
3568
+ React3.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, state), []);
3426
3569
  {
3427
- React3.useEffect(() => {
3428
- if (initialContentOffset) {
3429
- scrollTo(state, { animated: false, offset: initialContentOffset, ...initialScroll || {} });
3430
- }
3431
- }, []);
3570
+ React3.useEffect(doInitialScroll, []);
3432
3571
  }
3433
3572
  const fns = React3.useMemo(
3434
3573
  () => ({
@@ -3457,7 +3596,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3457
3596
  onMomentumScrollEnd: (event) => {
3458
3597
  {
3459
3598
  requestAnimationFrame(() => {
3460
- finishScrollTo(refState.current);
3599
+ finishScrollTo(ctx, refState.current);
3461
3600
  });
3462
3601
  }
3463
3602
  if (onMomentumScrollEnd) {