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

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.
Files changed (5) hide show
  1. package/index.d.mts +13 -11
  2. package/index.d.ts +13 -11
  3. package/index.js +294 -249
  4. package/index.mjs +294 -249
  5. package/package.json +1 -1
package/index.mjs CHANGED
@@ -33,7 +33,10 @@ function StateProvider({ children }) {
33
33
  ["stylePaddingTop", 0],
34
34
  ["headerSize", 0],
35
35
  ["numContainers", 0],
36
- ["totalSize", 0]
36
+ ["activeStickyIndex", void 0],
37
+ ["totalSize", 0],
38
+ ["scrollAdjustPending", 0],
39
+ ["scrollingTo", void 0]
37
40
  ]),
38
41
  viewRefs: /* @__PURE__ */ new Map()
39
42
  }));
@@ -196,8 +199,11 @@ var PositionViewState = typedMemo(function PositionView({
196
199
  ...rest
197
200
  }) {
198
201
  const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
199
- const base = Array.isArray(style) ? Object.assign({}, ...style) : style;
200
- const combinedStyle = horizontal ? { ...base, left: position } : { ...base, top: position };
202
+ const base = {
203
+ contain: "paint layout style"
204
+ };
205
+ const composed = Array.isArray(style) ? Object.assign({}, ...style) : style;
206
+ const combinedStyle = horizontal ? { ...base, ...composed, left: position } : { ...base, ...composed, top: position };
201
207
  return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: combinedStyle, ...rest });
202
208
  });
203
209
  var PositionViewSticky = typedMemo(function PositionViewSticky2({
@@ -206,19 +212,42 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
206
212
  style,
207
213
  refView,
208
214
  index,
215
+ stickyOffset,
216
+ animatedScrollY: _animatedScrollY,
217
+ children,
209
218
  ...rest
210
219
  }) {
211
- const [position = POSITION_OUT_OF_VIEW, _headerSize] = useArr$([`containerPosition${id}`, "headerSize"]);
220
+ const [position = POSITION_OUT_OF_VIEW, headerSize = 0, activeStickyIndex] = useArr$([
221
+ `containerPosition${id}`,
222
+ "headerSize",
223
+ "activeStickyIndex"
224
+ ]);
225
+ const base = {
226
+ contain: "paint layout style"
227
+ };
228
+ const composed = React3.useMemo(
229
+ () => {
230
+ var _a3;
231
+ return (_a3 = Array.isArray(style) ? Object.assign({}, ...style) : style) != null ? _a3 : {};
232
+ },
233
+ [style]
234
+ );
212
235
  const viewStyle = React3.useMemo(() => {
213
- const base = Array.isArray(style) ? Object.assign({}, ...style) : style;
214
- const axisStyle = horizontal ? { transform: `translateX(${position}px)` } : { top: position };
215
- return {
216
- ...base,
217
- zIndex: index + 1e3,
218
- ...axisStyle
219
- };
220
- }, [style, position, horizontal, index]);
221
- return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: viewStyle, ...rest });
236
+ var _a3;
237
+ const styleBase = { ...base, ...composed };
238
+ delete styleBase.transform;
239
+ const offset = (_a3 = stickyOffset != null ? stickyOffset : headerSize) != null ? _a3 : 0;
240
+ const isActive = activeStickyIndex === index;
241
+ styleBase.position = isActive ? "sticky" : "absolute";
242
+ styleBase.zIndex = index + 1e3;
243
+ if (horizontal) {
244
+ styleBase.left = isActive ? offset : position;
245
+ } else {
246
+ styleBase.top = isActive ? offset : position;
247
+ }
248
+ return styleBase;
249
+ }, [composed, horizontal, position, index, stickyOffset, headerSize, activeStickyIndex]);
250
+ return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
222
251
  });
223
252
  var PositionView2 = PositionViewState;
224
253
 
@@ -970,10 +999,11 @@ function PaddingDevMode() {
970
999
  function useValueListener$(key, callback) {
971
1000
  const ctx = useStateContext();
972
1001
  useLayoutEffect(() => {
973
- listen$(ctx, key, (value) => {
1002
+ const unsubscribe = listen$(ctx, key, (value) => {
974
1003
  callback(value);
975
1004
  });
976
- }, []);
1005
+ return unsubscribe;
1006
+ }, [callback, ctx, key]);
977
1007
  }
978
1008
 
979
1009
  // src/components/ScrollAdjust.tsx
@@ -1139,12 +1169,11 @@ function calculateOffsetForIndex(ctx, state, index) {
1139
1169
  }
1140
1170
 
1141
1171
  // src/utils/getItemSize.ts
1142
- function getItemSize(state, key, index, data, useAverageSize) {
1172
+ function getItemSize(ctx, state, key, index, data, useAverageSize) {
1143
1173
  var _a3, _b;
1144
1174
  const {
1145
1175
  sizesKnown,
1146
1176
  sizes,
1147
- scrollingTo,
1148
1177
  averageSizes,
1149
1178
  props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
1150
1179
  } = state;
@@ -1154,6 +1183,7 @@ function getItemSize(state, key, index, data, useAverageSize) {
1154
1183
  }
1155
1184
  let size;
1156
1185
  const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1186
+ const scrollingTo = peek$(ctx, "scrollingTo");
1157
1187
  if (getFixedItemSize) {
1158
1188
  size = getFixedItemSize(index, data, itemType);
1159
1189
  if (size !== void 0) {
@@ -1180,41 +1210,211 @@ function getItemSize(state, key, index, data, useAverageSize) {
1180
1210
  }
1181
1211
 
1182
1212
  // src/core/calculateOffsetWithOffsetPosition.ts
1183
- function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
1213
+ function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
1184
1214
  const { index, viewOffset, viewPosition } = params;
1185
1215
  let offset = offsetParam;
1186
1216
  if (viewOffset) {
1187
1217
  offset -= viewOffset;
1188
1218
  }
1189
1219
  if (viewPosition !== void 0 && index !== void 0) {
1190
- offset -= viewPosition * (state.scrollLength - getItemSize(state, getId(state, index), index, state.props.data[index]));
1220
+ offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
1191
1221
  }
1192
1222
  return offset;
1193
1223
  }
1194
1224
 
1225
+ // src/utils/checkThreshold.ts
1226
+ var HYSTERESIS_MULTIPLIER = 1.3;
1227
+ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1228
+ const absDistance = Math.abs(distance);
1229
+ const within = atThreshold || threshold > 0 && absDistance <= threshold;
1230
+ const updateSnapshot = () => {
1231
+ setSnapshot == null ? void 0 : setSnapshot({
1232
+ atThreshold,
1233
+ contentSize: context.contentSize,
1234
+ dataLength: context.dataLength,
1235
+ scrollPosition: context.scrollPosition
1236
+ });
1237
+ };
1238
+ if (!wasReached) {
1239
+ if (!within) {
1240
+ return false;
1241
+ }
1242
+ onReached == null ? void 0 : onReached(distance);
1243
+ updateSnapshot();
1244
+ return true;
1245
+ }
1246
+ const reset = !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
1247
+ if (reset) {
1248
+ setSnapshot == null ? void 0 : setSnapshot(void 0);
1249
+ return false;
1250
+ }
1251
+ if (within) {
1252
+ const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
1253
+ if (changed) {
1254
+ onReached == null ? void 0 : onReached(distance);
1255
+ updateSnapshot();
1256
+ }
1257
+ }
1258
+ return true;
1259
+ };
1260
+
1261
+ // src/utils/checkAtBottom.ts
1262
+ function checkAtBottom(ctx, state) {
1263
+ var _a3;
1264
+ if (!state) {
1265
+ return;
1266
+ }
1267
+ const {
1268
+ queuedInitialLayout,
1269
+ scrollLength,
1270
+ scroll,
1271
+ maintainingScrollAtEnd,
1272
+ props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
1273
+ } = state;
1274
+ const contentSize = getContentSize(ctx);
1275
+ if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1276
+ const distanceFromEnd = contentSize - scroll - scrollLength;
1277
+ const isContentLess = contentSize < scrollLength;
1278
+ state.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1279
+ state.isEndReached = checkThreshold(
1280
+ distanceFromEnd,
1281
+ isContentLess,
1282
+ onEndReachedThreshold * scrollLength,
1283
+ state.isEndReached,
1284
+ state.endReachedSnapshot,
1285
+ {
1286
+ contentSize,
1287
+ dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length,
1288
+ scrollPosition: scroll
1289
+ },
1290
+ (distance) => {
1291
+ var _a4, _b;
1292
+ return (_b = (_a4 = state.props).onEndReached) == null ? void 0 : _b.call(_a4, { distanceFromEnd: distance });
1293
+ },
1294
+ (snapshot) => {
1295
+ state.endReachedSnapshot = snapshot;
1296
+ }
1297
+ );
1298
+ }
1299
+ }
1300
+
1301
+ // src/utils/checkAtTop.ts
1302
+ function checkAtTop(state) {
1303
+ var _a3;
1304
+ if (!state) {
1305
+ return;
1306
+ }
1307
+ const {
1308
+ scrollLength,
1309
+ scroll,
1310
+ props: { onStartReachedThreshold }
1311
+ } = state;
1312
+ const distanceFromTop = scroll;
1313
+ state.isAtStart = distanceFromTop <= 0;
1314
+ state.isStartReached = checkThreshold(
1315
+ distanceFromTop,
1316
+ false,
1317
+ onStartReachedThreshold * scrollLength,
1318
+ state.isStartReached,
1319
+ state.startReachedSnapshot,
1320
+ {
1321
+ contentSize: state.totalSize,
1322
+ dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length,
1323
+ scrollPosition: scroll
1324
+ },
1325
+ (distance) => {
1326
+ var _a4, _b;
1327
+ return (_b = (_a4 = state.props).onStartReached) == null ? void 0 : _b.call(_a4, { distanceFromStart: distance });
1328
+ },
1329
+ (snapshot) => {
1330
+ state.startReachedSnapshot = snapshot;
1331
+ }
1332
+ );
1333
+ }
1334
+
1335
+ // src/core/onScroll.ts
1336
+ function onScroll(ctx, state, event) {
1337
+ var _a3, _b, _c;
1338
+ const {
1339
+ scrollProcessingEnabled,
1340
+ props: { onScroll: onScrollProp }
1341
+ } = state;
1342
+ if (scrollProcessingEnabled === false) {
1343
+ return;
1344
+ }
1345
+ 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) {
1346
+ return;
1347
+ }
1348
+ const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
1349
+ state.scrollPending = newScroll;
1350
+ updateScroll(ctx, state, newScroll);
1351
+ onScrollProp == null ? void 0 : onScrollProp(event);
1352
+ }
1353
+ function updateScroll(ctx, state, newScroll, forceUpdate) {
1354
+ const scrollingTo = peek$(ctx, "scrollingTo");
1355
+ state.hasScrolled = true;
1356
+ state.lastBatchingAction = Date.now();
1357
+ const currentTime = Date.now();
1358
+ const adjust = state.scrollAdjustHandler.getAdjust();
1359
+ const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1360
+ const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1361
+ if (adjustChanged) {
1362
+ state.scrollHistory.length = 0;
1363
+ }
1364
+ state.lastScrollAdjustForHistory = adjust;
1365
+ if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
1366
+ if (!adjustChanged) {
1367
+ state.scrollHistory.push({ scroll: newScroll, time: currentTime });
1368
+ }
1369
+ }
1370
+ if (state.scrollHistory.length > 5) {
1371
+ state.scrollHistory.shift();
1372
+ }
1373
+ state.scrollPrev = state.scroll;
1374
+ state.scrollPrevTime = state.scrollTime;
1375
+ state.scroll = newScroll;
1376
+ state.scrollTime = currentTime;
1377
+ const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
1378
+ if (ignoreScrollFromMVCP && !scrollingTo) {
1379
+ const { lt, gt } = ignoreScrollFromMVCP;
1380
+ if (lt && newScroll < lt || gt && newScroll > gt) {
1381
+ state.ignoreScrollFromMVCPIgnored = true;
1382
+ return;
1383
+ }
1384
+ }
1385
+ if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1386
+ state.ignoreScrollFromMVCPIgnored = false;
1387
+ calculateItemsInView(ctx, state, { doMVCP: scrollingTo !== void 0 });
1388
+ checkAtBottom(ctx, state);
1389
+ checkAtTop(state);
1390
+ state.dataChangeNeedsScrollUpdate = false;
1391
+ }
1392
+ }
1393
+
1195
1394
  // src/core/finishScrollTo.ts
1196
- var finishScrollTo = (state) => {
1395
+ function finishScrollTo(ctx, state) {
1197
1396
  if (state) {
1198
- state.scrollingTo = void 0;
1397
+ set$(ctx, "scrollingTo", void 0);
1199
1398
  state.scrollHistory.length = 0;
1200
1399
  }
1201
- };
1400
+ }
1202
1401
 
1203
1402
  // src/core/scrollTo.ts
1204
- function scrollTo(state, params = {}) {
1403
+ function scrollTo(ctx, state, params) {
1205
1404
  var _a3;
1206
- const { animated, noScrollingTo, isInitialScroll } = params;
1405
+ const { noScrollingTo, ...scrollTarget } = params;
1406
+ const { animated, isInitialScroll, offset: scrollTargetOffset } = scrollTarget;
1207
1407
  const {
1208
1408
  refScroller,
1209
1409
  props: { horizontal }
1210
1410
  } = state;
1211
- const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
1411
+ const offset = calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1212
1412
  state.scrollHistory.length = 0;
1213
1413
  if (!noScrollingTo) {
1214
- state.scrollingTo = params;
1414
+ set$(ctx, "scrollingTo", scrollTarget);
1215
1415
  }
1216
1416
  state.scrollPending = offset;
1217
- if (!params.isInitialScroll || Platform.OS === "android") {
1417
+ if (!isInitialScroll || Platform.OS === "android") {
1218
1418
  (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1219
1419
  animated: !!animated,
1220
1420
  x: horizontal ? offset : 0,
@@ -1223,7 +1423,7 @@ function scrollTo(state, params = {}) {
1223
1423
  }
1224
1424
  if (!animated) {
1225
1425
  state.scroll = offset;
1226
- setTimeout(() => finishScrollTo(state), 100);
1426
+ setTimeout(() => finishScrollTo(ctx, state), 100);
1227
1427
  if (isInitialScroll) {
1228
1428
  setTimeout(() => {
1229
1429
  state.initialScroll = void 0;
@@ -1245,24 +1445,6 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1245
1445
  const didLayout = peek$(ctx, "containersDidLayout");
1246
1446
  if (didLayout) {
1247
1447
  doit();
1248
- const threshold = state.scroll - positionDiff / 2;
1249
- if (!state.ignoreScrollFromMVCP) {
1250
- state.ignoreScrollFromMVCP = {};
1251
- }
1252
- if (positionDiff > 0) {
1253
- state.ignoreScrollFromMVCP.lt = threshold;
1254
- } else {
1255
- state.ignoreScrollFromMVCP.gt = threshold;
1256
- }
1257
- if (state.ignoreScrollFromMVCPTimeout) {
1258
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
1259
- }
1260
- state.ignoreScrollFromMVCPTimeout = setTimeout(
1261
- () => {
1262
- state.ignoreScrollFromMVCP = void 0;
1263
- },
1264
- 100
1265
- );
1266
1448
  } else {
1267
1449
  requestAnimationFrame(doit);
1268
1450
  }
@@ -1274,9 +1456,9 @@ function prepareMVCP(ctx, state, dataChanged) {
1274
1456
  const {
1275
1457
  idsInView,
1276
1458
  positions,
1277
- scrollingTo,
1278
1459
  props: { maintainVisibleContentPosition }
1279
1460
  } = state;
1461
+ const scrollingTo = peek$(ctx, "scrollingTo");
1280
1462
  let prevPosition;
1281
1463
  let targetId;
1282
1464
  const idsInViewWithPositions = [];
@@ -1352,7 +1534,7 @@ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1352
1534
  const prevId = state.idCache[prevIndex];
1353
1535
  const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1354
1536
  const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1355
- const prevRowHeight = calculateRowMaxSize(state, prevRowStart, prevIndex, useAverageSize);
1537
+ const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1356
1538
  currentRowTop = prevPosition + prevRowHeight;
1357
1539
  }
1358
1540
  return {
@@ -1375,7 +1557,7 @@ function findRowStartIndex(state, numColumns, index) {
1375
1557
  }
1376
1558
  return rowStart;
1377
1559
  }
1378
- function calculateRowMaxSize(state, startIndex, endIndex, useAverageSize) {
1560
+ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1379
1561
  if (endIndex < startIndex) {
1380
1562
  return 0;
1381
1563
  }
@@ -1389,7 +1571,7 @@ function calculateRowMaxSize(state, startIndex, endIndex, useAverageSize) {
1389
1571
  continue;
1390
1572
  }
1391
1573
  const id = state.idCache[i];
1392
- const size = getItemSize(state, id, i, data[i], useAverageSize);
1574
+ const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1393
1575
  if (size > maxSize) {
1394
1576
  maxSize = size;
1395
1577
  }
@@ -1445,7 +1627,7 @@ function updateTotalSize(ctx, state) {
1445
1627
  if (lastId !== void 0) {
1446
1628
  const lastPosition = positions.get(lastId);
1447
1629
  if (lastPosition !== void 0) {
1448
- const lastSize = getItemSize(state, lastId, data.length - 1, data[data.length - 1]);
1630
+ const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1449
1631
  if (lastSize !== void 0) {
1450
1632
  const totalSize = lastPosition + lastSize;
1451
1633
  addTotalSize(ctx, state, null, totalSize);
@@ -1503,6 +1685,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1503
1685
  const data = state.props.data;
1504
1686
  const dataLength = data.length;
1505
1687
  const numColumns = peek$(ctx, "numColumns");
1688
+ const scrollingTo = peek$(ctx, "scrollingTo");
1506
1689
  const hasColumns = numColumns > 1;
1507
1690
  const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1508
1691
  const maxVisibleArea = scrollBottomBuffered + 1e3;
@@ -1524,7 +1707,7 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1524
1707
  const prevIndex = startIndex - 1;
1525
1708
  const prevId = getId(state, prevIndex);
1526
1709
  const prevPosition = (_a3 = positions.get(prevId)) != null ? _a3 : 0;
1527
- const prevSize = (_b = sizesKnown.get(prevId)) != null ? _b : getItemSize(state, prevId, prevIndex, data[prevIndex], useAverageSize);
1710
+ const prevSize = (_b = sizesKnown.get(prevId)) != null ? _b : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize);
1528
1711
  currentRowTop = prevPosition + prevSize;
1529
1712
  }
1530
1713
  }
@@ -1536,12 +1719,12 @@ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottom
1536
1719
  didBreakEarly = true;
1537
1720
  break;
1538
1721
  }
1539
- if (breakAt === void 0 && !dataChanged && currentRowTop > maxVisibleArea) {
1722
+ if (breakAt === void 0 && !scrollingTo && !dataChanged && currentRowTop > maxVisibleArea) {
1540
1723
  const itemsPerRow = hasColumns ? numColumns : 1;
1541
1724
  breakAt = i + itemsPerRow + 10;
1542
1725
  }
1543
1726
  const id = (_c = idCache[i]) != null ? _c : getId(state, i);
1544
- const size = (_d = sizesKnown.get(id)) != null ? _d : getItemSize(state, id, i, data[i], useAverageSize);
1727
+ const size = (_d = sizesKnown.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i], useAverageSize);
1545
1728
  if (IS_DEV && needsIndexByKey) {
1546
1729
  if (indexByKeyForChecking.has(id)) {
1547
1730
  console.error(
@@ -1965,7 +2148,7 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
1965
2148
  viewPosition = 1;
1966
2149
  }
1967
2150
  state.scrollForNextCalculateItemsInView = void 0;
1968
- scrollTo(state, {
2151
+ scrollTo(ctx, state, {
1969
2152
  animated,
1970
2153
  index,
1971
2154
  offset: firstIndexOffset,
@@ -1974,82 +2157,6 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
1974
2157
  });
1975
2158
  }
1976
2159
 
1977
- // src/utils/checkThreshold.ts
1978
- var HYSTERESIS_MULTIPLIER = 1.3;
1979
- var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1980
- const absDistance = Math.abs(distance);
1981
- const within = atThreshold || threshold > 0 && absDistance <= threshold;
1982
- const updateSnapshot = () => {
1983
- setSnapshot == null ? void 0 : setSnapshot({
1984
- atThreshold,
1985
- contentSize: context.contentSize,
1986
- dataLength: context.dataLength,
1987
- scrollPosition: context.scrollPosition
1988
- });
1989
- };
1990
- if (!wasReached) {
1991
- if (!within) {
1992
- return false;
1993
- }
1994
- onReached == null ? void 0 : onReached(distance);
1995
- updateSnapshot();
1996
- return true;
1997
- }
1998
- const reset = !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
1999
- if (reset) {
2000
- setSnapshot == null ? void 0 : setSnapshot(void 0);
2001
- return false;
2002
- }
2003
- if (within) {
2004
- const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
2005
- if (changed) {
2006
- onReached == null ? void 0 : onReached(distance);
2007
- updateSnapshot();
2008
- }
2009
- }
2010
- return true;
2011
- };
2012
-
2013
- // src/utils/checkAtBottom.ts
2014
- function checkAtBottom(ctx, state) {
2015
- var _a3;
2016
- if (!state) {
2017
- return;
2018
- }
2019
- const {
2020
- queuedInitialLayout,
2021
- scrollLength,
2022
- scroll,
2023
- maintainingScrollAtEnd,
2024
- props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
2025
- } = state;
2026
- const contentSize = getContentSize(ctx);
2027
- if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
2028
- const distanceFromEnd = contentSize - scroll - scrollLength;
2029
- const isContentLess = contentSize < scrollLength;
2030
- state.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
2031
- state.isEndReached = checkThreshold(
2032
- distanceFromEnd,
2033
- isContentLess,
2034
- onEndReachedThreshold * scrollLength,
2035
- state.isEndReached,
2036
- state.endReachedSnapshot,
2037
- {
2038
- scrollPosition: scroll,
2039
- contentSize,
2040
- dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length
2041
- },
2042
- (distance) => {
2043
- var _a4, _b;
2044
- return (_b = (_a4 = state.props).onEndReached) == null ? void 0 : _b.call(_a4, { distanceFromEnd: distance });
2045
- },
2046
- (snapshot) => {
2047
- state.endReachedSnapshot = snapshot;
2048
- }
2049
- );
2050
- }
2051
- }
2052
-
2053
2160
  // src/utils/setDidLayout.ts
2054
2161
  function setDidLayout(ctx, state) {
2055
2162
  const {
@@ -2129,7 +2236,7 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2129
2236
  const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
2130
2237
  if (currentId) {
2131
2238
  const currentPos = state.positions.get(currentId);
2132
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(state, currentId, itemIndex, state.props.data[itemIndex]);
2239
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
2133
2240
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
2134
2241
  }
2135
2242
  }
@@ -2140,7 +2247,7 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, cu
2140
2247
  }
2141
2248
  function calculateItemsInView(ctx, state, params = {}) {
2142
2249
  unstable_batchedUpdates(() => {
2143
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
2250
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2144
2251
  const {
2145
2252
  columns,
2146
2253
  containerItemKeys,
@@ -2173,13 +2280,15 @@ function calculateItemsInView(ctx, state, params = {}) {
2173
2280
  let { scroll: scrollState } = state;
2174
2281
  if (!queuedInitialLayout && initialScroll) {
2175
2282
  const updatedOffset = calculateOffsetWithOffsetPosition(
2283
+ ctx,
2176
2284
  state,
2177
2285
  calculateOffsetForIndex(ctx, state, initialScroll.index),
2178
2286
  initialScroll
2179
2287
  );
2180
2288
  scrollState = updatedOffset;
2181
2289
  }
2182
- const scrollAdjustPad = -topPad;
2290
+ const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2291
+ const scrollAdjustPad = scrollAdjustPending - topPad;
2183
2292
  let scroll = scrollState + scrollExtra + scrollAdjustPad;
2184
2293
  if (scroll + scrollLength > totalSize) {
2185
2294
  scroll = Math.max(0, totalSize - scrollLength);
@@ -2192,6 +2301,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2192
2301
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2193
2302
  const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2194
2303
  state.activeStickyIndex = nextActiveStickyIndex;
2304
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2195
2305
  let scrollBufferTop = scrollBuffer;
2196
2306
  let scrollBufferBottom = scrollBuffer;
2197
2307
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2216,7 +2326,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2216
2326
  idCache.length = 0;
2217
2327
  positions.clear();
2218
2328
  }
2219
- const startIndex = dataChanged ? 0 : (_a3 = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _a3 : 0;
2329
+ const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2220
2330
  updateItemPositions(ctx, state, dataChanged, { scrollBottomBuffered, startIndex });
2221
2331
  if (minIndexSizeChanged !== void 0) {
2222
2332
  state.minIndexSizeChanged = void 0;
@@ -2229,9 +2339,9 @@ function calculateItemsInView(ctx, state, params = {}) {
2229
2339
  let endBuffered = null;
2230
2340
  let loopStart = !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
2231
2341
  for (let i = loopStart; i >= 0; i--) {
2232
- const id = (_b = idCache[i]) != null ? _b : getId(state, i);
2342
+ const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2233
2343
  const top = positions.get(id);
2234
- const size = (_c = sizes.get(id)) != null ? _c : getItemSize(state, id, i, data[i]);
2344
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2235
2345
  const bottom = top + size;
2236
2346
  if (bottom > scroll - scrollBuffer) {
2237
2347
  loopStart = i;
@@ -2257,8 +2367,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2257
2367
  let firstFullyOnScreenIndex;
2258
2368
  const dataLength = data.length;
2259
2369
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2260
- const id = (_d = idCache[i]) != null ? _d : getId(state, i);
2261
- const size = (_e = sizes.get(id)) != null ? _e : getItemSize(state, id, i, data[i]);
2370
+ const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2371
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2262
2372
  const top = positions.get(id);
2263
2373
  if (!foundEnd) {
2264
2374
  if (startNoBuffer === null && top + size > scroll) {
@@ -2287,7 +2397,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2287
2397
  }
2288
2398
  const idsInView = [];
2289
2399
  for (let i = firstFullyOnScreenIndex; i <= endNoBuffer; i++) {
2290
- const id = (_f = idCache[i]) != null ? _f : getId(state, i);
2400
+ const id = (_g = idCache[i]) != null ? _g : getId(state, i);
2291
2401
  idsInView.push(id);
2292
2402
  }
2293
2403
  Object.assign(state, {
@@ -2319,7 +2429,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2319
2429
  let numContainers2 = prevNumContainers;
2320
2430
  const needNewContainers = [];
2321
2431
  for (let i = startBuffered; i <= endBuffered; i++) {
2322
- const id = (_g = idCache[i]) != null ? _g : getId(state, i);
2432
+ const id = (_h = idCache[i]) != null ? _h : getId(state, i);
2323
2433
  if (!containerItemKeys.has(id)) {
2324
2434
  needNewContainers.push(i);
2325
2435
  }
@@ -2337,6 +2447,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2337
2447
  );
2338
2448
  } else {
2339
2449
  state.activeStickyIndex = void 0;
2450
+ set$(ctx, "activeStickyIndex", void 0);
2340
2451
  }
2341
2452
  if (needNewContainers.length > 0) {
2342
2453
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
@@ -2356,7 +2467,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2356
2467
  for (let idx = 0; idx < needNewContainers.length; idx++) {
2357
2468
  const i = needNewContainers[idx];
2358
2469
  const containerIndex = availableContainers[idx];
2359
- const id = (_h = idCache[i]) != null ? _h : getId(state, i);
2470
+ const id = (_i = idCache[i]) != null ? _i : getId(state, i);
2360
2471
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
2361
2472
  if (oldKey && oldKey !== id) {
2362
2473
  containerItemKeys.delete(oldKey);
@@ -2412,11 +2523,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2412
2523
  const itemIndex = indexByKey.get(itemKey);
2413
2524
  const item = data[itemIndex];
2414
2525
  if (item !== void 0) {
2415
- const id = (_i = idCache[itemIndex]) != null ? _i : getId(state, itemIndex);
2416
- const position = positions.get(id);
2417
- if (position === void 0) {
2526
+ const id = (_j = idCache[itemIndex]) != null ? _j : getId(state, itemIndex);
2527
+ const positionValue = positions.get(id);
2528
+ if (positionValue === void 0) {
2418
2529
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2419
2530
  } else {
2531
+ const position = (positionValue || 0) - scrollAdjustPending;
2420
2532
  const column = columns.get(id) || 1;
2421
2533
  const prevPos = peek$(ctx, `containerPosition${i}`);
2422
2534
  const prevColumn = peek$(ctx, `containerColumn${i}`);
@@ -2485,40 +2597,6 @@ function doMaintainScrollAtEnd(ctx, state, animated) {
2485
2597
  }
2486
2598
  }
2487
2599
 
2488
- // src/utils/checkAtTop.ts
2489
- function checkAtTop(state) {
2490
- var _a3;
2491
- if (!state) {
2492
- return;
2493
- }
2494
- const {
2495
- scrollLength,
2496
- scroll,
2497
- props: { onStartReachedThreshold }
2498
- } = state;
2499
- const distanceFromTop = scroll;
2500
- state.isAtStart = distanceFromTop <= 0;
2501
- state.isStartReached = checkThreshold(
2502
- distanceFromTop,
2503
- false,
2504
- onStartReachedThreshold * scrollLength,
2505
- state.isStartReached,
2506
- state.startReachedSnapshot,
2507
- {
2508
- scrollPosition: scroll,
2509
- contentSize: state.totalSize,
2510
- dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length
2511
- },
2512
- (distance) => {
2513
- var _a4, _b;
2514
- return (_b = (_a4 = state.props).onStartReached) == null ? void 0 : _b.call(_a4, { distanceFromStart: distance });
2515
- },
2516
- (snapshot) => {
2517
- state.startReachedSnapshot = snapshot;
2518
- }
2519
- );
2520
- }
2521
-
2522
2600
  // src/utils/updateAveragesOnDataChange.ts
2523
2601
  function updateAveragesOnDataChange(state, oldData, newData) {
2524
2602
  var _a3;
@@ -2687,78 +2765,45 @@ function handleLayout(ctx, state, layout, setCanRender) {
2687
2765
  setCanRender(true);
2688
2766
  }
2689
2767
 
2690
- // src/core/onScroll.ts
2691
- function onScroll(ctx, state, event) {
2692
- var _a3, _b, _c;
2693
- const {
2694
- scrollProcessingEnabled,
2695
- props: { onScroll: onScrollProp }
2696
- } = state;
2697
- if (scrollProcessingEnabled === false) {
2698
- return;
2699
- }
2700
- 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) {
2701
- return;
2702
- }
2703
- const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2704
- state.scrollPending = newScroll;
2705
- updateScroll(ctx, state, newScroll);
2706
- onScrollProp == null ? void 0 : onScrollProp(event);
2707
- }
2708
- function updateScroll(ctx, state, newScroll) {
2709
- const scrollingTo = state.scrollingTo;
2710
- state.hasScrolled = true;
2711
- state.lastBatchingAction = Date.now();
2712
- const currentTime = Date.now();
2713
- const adjust = state.scrollAdjustHandler.getAdjust();
2714
- const lastHistoryAdjust = state.lastScrollAdjustForHistory;
2715
- const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
2716
- if (adjustChanged) {
2717
- state.scrollHistory.length = 0;
2718
- }
2719
- state.lastScrollAdjustForHistory = adjust;
2720
- if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
2721
- if (!adjustChanged) {
2722
- state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2723
- }
2724
- }
2725
- if (state.scrollHistory.length > 5) {
2726
- state.scrollHistory.shift();
2727
- }
2728
- state.scrollPrev = state.scroll;
2729
- state.scrollPrevTime = state.scrollTime;
2730
- state.scroll = newScroll;
2731
- state.scrollTime = currentTime;
2732
- const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
2733
- if (ignoreScrollFromMVCP && !state.scrollingTo) {
2734
- const { lt, gt } = ignoreScrollFromMVCP;
2735
- if (lt && newScroll < lt || gt && newScroll > gt) {
2736
- return;
2737
- }
2738
- }
2739
- if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
2740
- calculateItemsInView(ctx, state, { doMVCP: state.scrollingTo !== void 0 });
2741
- checkAtBottom(ctx, state);
2742
- checkAtTop(state);
2743
- state.dataChangeNeedsScrollUpdate = false;
2744
- }
2745
- }
2746
-
2747
2768
  // src/core/ScrollAdjustHandler.ts
2748
2769
  var ScrollAdjustHandler = class {
2749
2770
  constructor(ctx) {
2750
2771
  this.appliedAdjust = 0;
2772
+ this.pendingAdjust = 0;
2751
2773
  this.mounted = false;
2752
2774
  this.context = ctx;
2775
+ {
2776
+ const commitPendingAdjust = () => {
2777
+ const state = this.context.internalState;
2778
+ const pending = this.pendingAdjust;
2779
+ this.pendingAdjust = 0;
2780
+ this.appliedAdjust += pending;
2781
+ state.scroll += pending;
2782
+ state.scrollForNextCalculateItemsInView = void 0;
2783
+ set$(this.context, "scrollAdjustPending", 0);
2784
+ set$(this.context, "scrollAdjust", this.appliedAdjust);
2785
+ calculateItemsInView(this.context, this.context.internalState);
2786
+ };
2787
+ listen$(this.context, "scrollingTo", (value) => {
2788
+ if (value === void 0) {
2789
+ commitPendingAdjust();
2790
+ }
2791
+ });
2792
+ }
2753
2793
  }
2754
2794
  requestAdjust(add) {
2755
- const oldAdjustTop = this.appliedAdjust;
2756
- this.appliedAdjust = add + oldAdjustTop;
2757
- const set = () => set$(this.context, "scrollAdjust", this.appliedAdjust);
2758
- if (this.mounted) {
2759
- set();
2795
+ const scrollingTo = peek$(this.context, "scrollingTo");
2796
+ if ((scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2797
+ this.pendingAdjust += add;
2798
+ set$(this.context, "scrollAdjustPending", this.pendingAdjust);
2760
2799
  } else {
2761
- requestAnimationFrame(set);
2800
+ this.appliedAdjust += add;
2801
+ const setter = () => set$(this.context, "scrollAdjust", this.appliedAdjust);
2802
+ if (this.mounted) {
2803
+ setter();
2804
+ } else {
2805
+ requestAnimationFrame(setter);
2806
+ }
2762
2807
  }
2763
2808
  }
2764
2809
  setMounted() {
@@ -2806,7 +2851,7 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2806
2851
  let minIndexSizeChanged;
2807
2852
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2808
2853
  const prevSizeKnown = state.sizesKnown.get(itemKey);
2809
- const diff = updateOneItemSize(state, itemKey, sizeObj);
2854
+ const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
2810
2855
  const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2811
2856
  if (diff !== 0) {
2812
2857
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
@@ -2868,7 +2913,7 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2868
2913
  }
2869
2914
  }
2870
2915
  }
2871
- function updateOneItemSize(state, itemKey, sizeObj) {
2916
+ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
2872
2917
  var _a3;
2873
2918
  const {
2874
2919
  sizes,
@@ -2879,7 +2924,7 @@ function updateOneItemSize(state, itemKey, sizeObj) {
2879
2924
  } = state;
2880
2925
  if (!data) return 0;
2881
2926
  const index = indexByKey.get(itemKey);
2882
- const prevSize = getItemSize(state, itemKey, index, data[index]);
2927
+ const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
2883
2928
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
2884
2929
  const size = Math.round(rawSize) ;
2885
2930
  sizesKnown.set(itemKey, size);
@@ -3242,7 +3287,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3242
3287
  }
3243
3288
  refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
3244
3289
  if (initialContentOffset2 > 0) {
3245
- scrollTo(state, {
3290
+ scrollTo(ctx, state, {
3246
3291
  animated: false,
3247
3292
  index,
3248
3293
  isInitialScroll: true,
@@ -3392,7 +3437,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3392
3437
  scrollToIndex(ctx, state, { index, ...props2 });
3393
3438
  }
3394
3439
  },
3395
- scrollToOffset: (params) => scrollTo(state, params),
3440
+ scrollToOffset: (params) => scrollTo(ctx, state, params),
3396
3441
  setScrollProcessingEnabled: (enabled) => {
3397
3442
  refState.current.scrollProcessingEnabled = enabled;
3398
3443
  },
@@ -3405,7 +3450,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3405
3450
  {
3406
3451
  useEffect(() => {
3407
3452
  if (initialContentOffset) {
3408
- scrollTo(state, { animated: false, offset: initialContentOffset, ...initialScroll || {} });
3453
+ scrollTo(ctx, state, { animated: false, offset: initialContentOffset, ...initialScroll || {} });
3409
3454
  }
3410
3455
  }, []);
3411
3456
  }
@@ -3436,7 +3481,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3436
3481
  onMomentumScrollEnd: (event) => {
3437
3482
  {
3438
3483
  requestAnimationFrame(() => {
3439
- finishScrollTo(refState.current);
3484
+ finishScrollTo(ctx, refState.current);
3440
3485
  });
3441
3486
  }
3442
3487
  if (onMomentumScrollEnd) {