@legendapp/list 1.0.14 → 1.0.16

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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React2 from 'react';
2
- import React2__default, { useReducer, useEffect, createContext, useMemo, useRef, useCallback, useImperativeHandle, useContext, useState, forwardRef, memo, useLayoutEffect } from 'react';
2
+ import React2__default, { useReducer, useEffect, createContext, useMemo, useRef, useCallback, useLayoutEffect, useImperativeHandle, useContext, useState, forwardRef, memo } from 'react';
3
3
  import { View, Text, Platform, Animated, ScrollView, StyleSheet, Dimensions, RefreshControl } from 'react-native';
4
4
  import { useSyncExternalStore } from 'use-sync-external-store/shim';
5
5
 
@@ -99,6 +99,12 @@ function useArr$(signalNames) {
99
99
  const value = useSyncExternalStore(subscribe, get);
100
100
  return value;
101
101
  }
102
+ function useSelector$(signalName, selector) {
103
+ const ctx = React2.useContext(ContextState);
104
+ const { subscribe, get } = React2.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
105
+ const value = useSyncExternalStore(subscribe, () => selector(get()[0]));
106
+ return value;
107
+ }
102
108
 
103
109
  // src/DebugView.tsx
104
110
  var DebugRow = ({ children }) => {
@@ -146,7 +152,7 @@ var DebugView = React2.memo(function DebugView2({ state }) {
146
152
  },
147
153
  /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "TotalSize:"), /* @__PURE__ */ React2.createElement(Text, null, totalSize.toFixed(2))),
148
154
  /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ContentSize:"), /* @__PURE__ */ React2.createElement(Text, null, contentSize.toFixed(2))),
149
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "At end:"), /* @__PURE__ */ React2.createElement(Text, null, String(state.isAtBottom))),
155
+ /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "At end:"), /* @__PURE__ */ React2.createElement(Text, null, String(state.isAtEnd))),
150
156
  /* @__PURE__ */ React2.createElement(Text, null),
151
157
  /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React2.createElement(Text, null, scrollAdjust.toFixed(2))),
152
158
  /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "TotalSizeReal: "), /* @__PURE__ */ React2.createElement(Text, null, totalSizeWithScrollAdjust.toFixed(2))),
@@ -173,9 +179,6 @@ function warnDevOnce(id, text) {
173
179
  console.warn(`[legend-list] ${text}`);
174
180
  }
175
181
  }
176
- function roundSize(size) {
177
- return Math.floor(size * 8) / 8;
178
- }
179
182
  function isNullOrUndefined(value) {
180
183
  return value === null || value === void 0;
181
184
  }
@@ -287,6 +290,11 @@ function useRecyclingState(valueOrFun) {
287
290
  );
288
291
  return [refState.current.value, setState];
289
292
  }
293
+ function useIsLastItem() {
294
+ const { itemKey } = useContext(ContextContainer);
295
+ const isLast = useSelector$("lastItemKeys", (lastItemKeys) => (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false);
296
+ return isLast;
297
+ }
290
298
  var LeanViewComponent = React2.forwardRef((props, ref) => {
291
299
  return React2.createElement("RCTView", { ...props, ref });
292
300
  });
@@ -345,12 +353,12 @@ var Container = ({
345
353
  if (horizontal) {
346
354
  paddingStyles = {
347
355
  paddingRight: !lastItemKeys.includes(itemKey) ? columnGap || gap || void 0 : void 0,
348
- paddingVertical: (rowGap || gap || 0) / 2
356
+ paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
349
357
  };
350
358
  } else {
351
359
  paddingStyles = {
352
360
  paddingBottom: !lastItemKeys.includes(itemKey) ? rowGap || gap || void 0 : void 0,
353
- paddingHorizontal: (columnGap || gap || 0) / 2
361
+ paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
354
362
  };
355
363
  }
356
364
  }
@@ -358,7 +366,6 @@ var Container = ({
358
366
  flexDirection: ItemSeparatorComponent ? "row" : void 0,
359
367
  position: "absolute",
360
368
  top: otherAxisPos,
361
- bottom: numColumns > 1 ? null : 0,
362
369
  height: otherAxisSize,
363
370
  left: position.relativeCoordinate,
364
371
  ...paddingStyles || {}
@@ -381,17 +388,17 @@ var Container = ({
381
388
  const onLayout = (event) => {
382
389
  var _a, _b;
383
390
  if (!isNullOrUndefined(itemKey)) {
384
- const layout = event.nativeEvent.layout;
385
- let size = roundSize(layout[horizontal ? "width" : "height"]);
391
+ let layout = event.nativeEvent.layout;
392
+ const size = layout[horizontal ? "width" : "height"];
386
393
  const doUpdate = () => {
387
- refLastSize.current = size;
388
- updateItemSize(itemKey, size);
394
+ refLastSize.current = { width: layout.width, height: layout.height };
395
+ updateItemSize(itemKey, layout);
389
396
  };
390
397
  if (IsNewArchitecture || size > 0) {
391
398
  doUpdate();
392
399
  } else {
393
400
  (_b = (_a = ref.current) == null ? void 0 : _a.measure) == null ? void 0 : _b.call(_a, (x, y, width, height) => {
394
- size = roundSize(horizontal ? width : height);
401
+ layout = { width, height };
395
402
  doUpdate();
396
403
  });
397
404
  }
@@ -405,7 +412,7 @@ var Container = ({
405
412
  if (measured) {
406
413
  const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
407
414
  if (size) {
408
- updateItemSize(itemKey, size);
415
+ updateItemSize(itemKey, measured);
409
416
  }
410
417
  }
411
418
  }
@@ -430,7 +437,7 @@ var Container = ({
430
437
  }, [id, itemKey, index, data]);
431
438
  const contentFragment = /* @__PURE__ */ React2__default.createElement(React2__default.Fragment, { key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React2__default.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && !lastItemKeys.includes(itemKey) && /* @__PURE__ */ React2__default.createElement(ItemSeparatorComponent, { leadingItem: renderedItemInfo.item })));
432
439
  if (maintainVisibleContentPosition) {
433
- const anchorStyle = position.type === "top" ? { position: "absolute", top: 0, left: 0, right: 0 } : { position: "absolute", bottom: 0, left: 0, right: 0 };
440
+ const anchorStyle = horizontal ? position.type === "top" ? { position: "absolute", left: 0, top: 0, bottom: 0, flexDirection: "row", alignItems: "stretch" } : { position: "absolute", right: 0, top: 0, bottom: 0, flexDirection: "row", alignItems: "stretch" } : position.type === "top" ? { position: "absolute", top: 0, left: 0, right: 0 } : { position: "absolute", bottom: 0, left: 0, right: 0 };
434
441
  if (__DEV__ && ENABLE_DEVMODE) {
435
442
  anchorStyle.borderColor = position.type === "top" ? "red" : "blue";
436
443
  anchorStyle.borderWidth = 1;
@@ -479,7 +486,7 @@ var Containers = typedMemo(function Containers2({
479
486
  }) {
480
487
  const ctx = useStateContext();
481
488
  const columnWrapperStyle = ctx.columnWrapperStyle;
482
- const [numContainers] = useArr$(["numContainersPooled"]);
489
+ const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
483
490
  const animSize = useValue$(
484
491
  "totalSizeWithScrollAdjust",
485
492
  void 0,
@@ -487,6 +494,12 @@ var Containers = typedMemo(function Containers2({
487
494
  true
488
495
  );
489
496
  const animOpacity = waitForInitialLayout ? useValue$("containersDidLayout", (value) => value ? 1 : 0) : void 0;
497
+ const otherAxisSize = useValue$(
498
+ "otherAxisSize",
499
+ void 0,
500
+ /*useMicrotask*/
501
+ true
502
+ );
490
503
  const containers = [];
491
504
  for (let i = 0; i < numContainers; i++) {
492
505
  containers.push(
@@ -504,8 +517,8 @@ var Containers = typedMemo(function Containers2({
504
517
  )
505
518
  );
506
519
  }
507
- const style = horizontal ? { width: animSize, opacity: animOpacity } : { height: animSize, opacity: animOpacity };
508
- if (columnWrapperStyle) {
520
+ const style = horizontal ? { width: animSize, opacity: animOpacity, minHeight: otherAxisSize } : { height: animSize, opacity: animOpacity, minWidth: otherAxisSize };
521
+ if (columnWrapperStyle && numColumns > 1) {
509
522
  const { columnGap, rowGap, gap } = columnWrapperStyle;
510
523
  if (horizontal) {
511
524
  const my = (rowGap || gap || 0) / 2;
@@ -528,11 +541,14 @@ function ListHeaderComponentContainer({
528
541
  horizontal,
529
542
  waitForInitialLayout
530
543
  }) {
531
- const scrollAdjust = useValue$("scrollAdjust", (v) => v, true);
544
+ var _a;
545
+ const hasData = ((_a = peek$(ctx, "lastItemKeys")) == null ? void 0 : _a.length) > 0;
546
+ const scrollAdjust = useValue$("scrollAdjust", (v) => v != null ? v : 0, true);
532
547
  const animOpacity = waitForInitialLayout ? useValue$("containersDidLayout", (value) => value ? 1 : 0) : void 0;
533
548
  const additionalSize = {
534
549
  transform: [{ translateY: Animated.multiply(scrollAdjust, -1) }],
535
- opacity: animOpacity
550
+ // Header should show if there's no data yet, but containersDidLayout will be false until it has some data
551
+ opacity: hasData ? animOpacity : 1
536
552
  };
537
553
  return /* @__PURE__ */ React2.createElement(
538
554
  Animated.View,
@@ -629,9 +645,6 @@ var ListComponent = typedMemo(function ListComponent2({
629
645
  refScrollView,
630
646
  maintainVisibleContentPosition,
631
647
  renderScrollComponent,
632
- onRefresh,
633
- refreshing,
634
- progressViewOffset,
635
648
  ...rest
636
649
  }) {
637
650
  const ctx = useStateContext();
@@ -1005,6 +1018,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1005
1018
  onViewableItemsChanged,
1006
1019
  ...rest
1007
1020
  } = props;
1021
+ const refLoadStartTime = useRef(Date.now());
1008
1022
  const callbacks = useRef({
1009
1023
  onStartReached: rest.onStartReached,
1010
1024
  onEndReached: rest.onEndReached
@@ -1039,20 +1053,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1039
1053
  };
1040
1054
  const getItemSize = (key, index, data, useAverageSize = false) => {
1041
1055
  const state = refState.current;
1042
- const sizeKnown = state.sizesKnown.get(key);
1056
+ state.sizesKnown.get(key);
1043
1057
  const sizePrevious = state.sizes.get(key);
1044
1058
  let size;
1045
- const numColumns = peek$(ctx, "numColumns");
1046
- if (sizeKnown === void 0 && !getEstimatedItemSize && numColumns === 1 && useAverageSize) {
1047
- const itemType = "";
1048
- const average = state.averageSizes[itemType];
1049
- if (average) {
1050
- size = roundSize(average.avg);
1051
- if (size !== sizePrevious) {
1052
- addTotalSize(key, size - sizePrevious, 0);
1053
- }
1054
- }
1055
- }
1059
+ peek$(ctx, "numColumns");
1056
1060
  if (size === void 0 && sizePrevious !== void 0) {
1057
1061
  return sizePrevious;
1058
1062
  }
@@ -1073,7 +1077,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1073
1077
  if (canGetSize || getEstimatedItemSize) {
1074
1078
  const sizeFn = (index2) => {
1075
1079
  if (canGetSize) {
1076
- return getItemSize(getId(index2), index2, data[index2]);
1080
+ return getItemSize(getId(index2), index2, data[index2], true);
1077
1081
  }
1078
1082
  return getEstimatedItemSize(index2, data[index2]);
1079
1083
  };
@@ -1100,8 +1104,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1100
1104
  pendingAdjust: 0,
1101
1105
  isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
1102
1106
  isEndReached: false,
1103
- isAtBottom: false,
1104
- isAtTop: false,
1107
+ isAtEnd: false,
1108
+ isAtStart: false,
1105
1109
  data: dataProp,
1106
1110
  scrollLength: initialScrollLength,
1107
1111
  startBuffered: -1,
@@ -1186,6 +1190,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1186
1190
  index = 0;
1187
1191
  }
1188
1192
  const firstIndexOffset = calculateOffsetForIndex(index);
1193
+ const isLast = index === state.data.length - 1;
1194
+ if (isLast && viewPosition !== void 0) {
1195
+ viewPosition = 1;
1196
+ }
1189
1197
  let firstIndexScrollPostion = firstIndexOffset - viewOffset;
1190
1198
  const diff = Math.abs(state.scroll - firstIndexScrollPostion);
1191
1199
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
@@ -1201,14 +1209,17 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1201
1209
  state.minIndexSizeChanged = index;
1202
1210
  firstIndexScrollPostion = firstIndexOffset - viewOffset + state.scrollAdjustHandler.getAppliedAdjust();
1203
1211
  }
1204
- if (viewPosition) {
1205
- firstIndexScrollPostion -= viewPosition * (state.scrollLength - getItemSize(getId(index), index, state.data[index]));
1206
- }
1207
- scrollTo(firstIndexScrollPostion, animated);
1212
+ scrollTo({ offset: firstIndexScrollPostion, animated, index, viewPosition, viewOffset });
1208
1213
  };
1209
1214
  const setDidLayout = () => {
1210
1215
  refState.current.queuedInitialLayout = true;
1211
1216
  checkAtBottom();
1217
+ const setIt = () => {
1218
+ set$(ctx, "containersDidLayout", true);
1219
+ if (props.onLoad) {
1220
+ props.onLoad({ elapsedTimeInMs: Date.now() - refLoadStartTime.current });
1221
+ }
1222
+ };
1212
1223
  if (initialScrollIndex) {
1213
1224
  queueMicrotask(() => {
1214
1225
  scrollToIndex({ index: initialScrollIndex, animated: false });
@@ -1216,13 +1227,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1216
1227
  if (!IsNewArchitecture) {
1217
1228
  scrollToIndex({ index: initialScrollIndex, animated: false });
1218
1229
  }
1219
- set$(ctx, "containersDidLayout", true);
1230
+ setIt();
1220
1231
  });
1221
1232
  });
1222
1233
  } else {
1223
- queueMicrotask(() => {
1224
- set$(ctx, "containersDidLayout", true);
1225
- });
1234
+ queueMicrotask(setIt);
1226
1235
  }
1227
1236
  };
1228
1237
  const addTotalSize = useCallback((key, add, totalSizeBelowAnchor) => {
@@ -1308,7 +1317,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1308
1317
  };
1309
1318
  const disableScrollJumps = (timeout) => {
1310
1319
  const state = refState.current;
1311
- if (state.scrollingToOffset === void 0) {
1320
+ if (state.scrollingTo === void 0) {
1312
1321
  state.disableScrollJumpsFrom = state.scroll - state.scrollAdjustHandler.getAppliedAdjust();
1313
1322
  state.scrollHistory.length = 0;
1314
1323
  setTimeout(() => {
@@ -1354,10 +1363,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1354
1363
  });
1355
1364
  numMeasurements++;
1356
1365
  if (measured) {
1357
- const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
1358
1366
  updateItemSize(
1359
1367
  itemKey,
1360
- size,
1368
+ measured,
1361
1369
  /*fromFixGaps*/
1362
1370
  true
1363
1371
  );
@@ -1455,13 +1463,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1455
1463
  scrollBufferBottom = scrollBuffer * 0.1;
1456
1464
  }
1457
1465
  }
1466
+ const scrollTopBuffered = scroll - scrollBufferTop;
1467
+ const scrollBottom = scroll + scrollLength;
1468
+ const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
1458
1469
  if (state.scrollForNextCalculateItemsInView) {
1459
1470
  const { top: top2, bottom } = state.scrollForNextCalculateItemsInView;
1460
- if (scroll > top2 && scroll < bottom) {
1471
+ if (scrollTopBuffered > top2 && scrollBottomBuffered < bottom) {
1461
1472
  return;
1462
1473
  }
1463
1474
  }
1464
- const scrollBottom = scroll + scrollLength;
1465
1475
  let startNoBuffer = null;
1466
1476
  let startBuffered = null;
1467
1477
  let startBufferedId = null;
@@ -1541,7 +1551,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1541
1551
  if (startNoBuffer === null && top + size > scroll) {
1542
1552
  startNoBuffer = i;
1543
1553
  }
1544
- if (startBuffered === null && top + size > scroll - scrollBufferTop) {
1554
+ if (startBuffered === null && top + size > scrollTopBuffered) {
1545
1555
  startBuffered = i;
1546
1556
  startBufferedId = id;
1547
1557
  nextTop = top;
@@ -1550,7 +1560,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1550
1560
  if (top <= scrollBottom) {
1551
1561
  endNoBuffer = i;
1552
1562
  }
1553
- if (top <= scrollBottom + scrollBufferBottom) {
1563
+ if (top <= scrollBottomBuffered) {
1554
1564
  endBuffered = i;
1555
1565
  nextBottom = top + maxSizeInRow - scrollLength;
1556
1566
  } else {
@@ -1710,18 +1720,26 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1710
1720
  const finishScrollTo = () => {
1711
1721
  const state = refState.current;
1712
1722
  if (state) {
1713
- state.scrollingToOffset = void 0;
1723
+ state.scrollingTo = void 0;
1714
1724
  state.scrollAdjustHandler.setDisableAdjust(false);
1715
1725
  state.scrollHistory.length = 0;
1716
1726
  calculateItemsInView();
1717
1727
  }
1718
1728
  };
1719
- const scrollTo = (offset, animated) => {
1729
+ const scrollTo = (params = {}) => {
1720
1730
  var _a;
1721
1731
  const state = refState.current;
1732
+ const { animated, index, viewPosition, viewOffset } = params;
1733
+ let { offset } = params;
1734
+ if (viewOffset) {
1735
+ offset -= viewOffset;
1736
+ }
1737
+ if (viewPosition !== void 0 && index !== void 0) {
1738
+ offset -= viewPosition * (state.scrollLength - getItemSize(getId(index), index, state.data[index]));
1739
+ }
1722
1740
  state.scrollAdjustHandler.setDisableAdjust(true);
1723
1741
  state.scrollHistory.length = 0;
1724
- state.scrollingToOffset = offset;
1742
+ state.scrollingTo = params;
1725
1743
  (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
1726
1744
  x: horizontal ? offset : 0,
1727
1745
  y: horizontal ? 0 : offset,
@@ -1733,7 +1751,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1733
1751
  };
1734
1752
  const doMaintainScrollAtEnd = (animated) => {
1735
1753
  const state = refState.current;
1736
- if ((state == null ? void 0 : state.isAtBottom) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
1754
+ if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
1737
1755
  const paddingTop = peek$(ctx, "alignItemsPaddingTop");
1738
1756
  if (paddingTop > 0) {
1739
1757
  state.scroll = 0;
@@ -1782,9 +1800,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1782
1800
  const contentSize = getContentSize(ctx);
1783
1801
  if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1784
1802
  const distanceFromEnd = contentSize - scroll - scrollLength;
1785
- const distanceFromEndAbs = Math.abs(distanceFromEnd);
1786
1803
  const isContentLess = contentSize < scrollLength;
1787
- refState.current.isAtBottom = isContentLess || distanceFromEndAbs < scrollLength * maintainScrollAtEndThreshold;
1804
+ refState.current.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1788
1805
  refState.current.isEndReached = checkThreshold(
1789
1806
  distanceFromEnd,
1790
1807
  isContentLess,
@@ -1807,7 +1824,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1807
1824
  }
1808
1825
  const { scrollLength, scroll } = refState.current;
1809
1826
  const distanceFromTop = scroll;
1810
- refState.current.isAtTop = distanceFromTop <= 0;
1827
+ refState.current.isAtStart = distanceFromTop <= 0;
1811
1828
  refState.current.isStartReached = checkThreshold(
1812
1829
  distanceFromTop,
1813
1830
  false,
@@ -1839,8 +1856,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1839
1856
  for (let i = 0; i < numContainers; i++) {
1840
1857
  const itemKey = peek$(ctx, `containerItemKey${i}`);
1841
1858
  if (!keyExtractorProp || itemKey && state.indexByKey.get(itemKey) === void 0) {
1842
- set$(ctx, `containerItemKey${i}`, null);
1843
- set$(ctx, `containerItemData${i}`, null);
1859
+ set$(ctx, `containerItemKey${i}`, void 0);
1860
+ set$(ctx, `containerItemData${i}`, void 0);
1844
1861
  set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1845
1862
  set$(ctx, `containerColumn${i}`, -1);
1846
1863
  }
@@ -1902,7 +1919,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1902
1919
  };
1903
1920
  state.anchorElement = newAnchorElement;
1904
1921
  (_b = state.belowAnchorElementPositions) == null ? void 0 : _b.clear();
1905
- scrollTo(0, false);
1922
+ scrollTo({ offset: 0, animated: false });
1906
1923
  setTimeout(() => {
1907
1924
  calculateItemsInView(
1908
1925
  /*reset*/
@@ -1920,7 +1937,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1920
1937
  } else {
1921
1938
  state.startBufferedId = void 0;
1922
1939
  }
1923
- scrollTo(0, false);
1940
+ scrollTo({ offset: 0, animated: false });
1924
1941
  setTimeout(() => {
1925
1942
  calculateItemsInView(
1926
1943
  /*reset*/
@@ -2028,7 +2045,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2028
2045
  const paddingDiff = stylePaddingTopState - prevPaddingTop;
2029
2046
  if (paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
2030
2047
  queueMicrotask(() => {
2031
- scrollTo(refState.current.scroll + paddingDiff, false);
2048
+ scrollTo({ offset: refState.current.scroll + paddingDiff, animated: false });
2032
2049
  });
2033
2050
  }
2034
2051
  };
@@ -2063,7 +2080,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2063
2080
  refState.current.renderItem = renderItem;
2064
2081
  useEffect(initalizeStateVars, [memoizedLastItemKeys.join(","), numColumnsProp, stylePaddingTopState]);
2065
2082
  const getRenderedItem = useCallback((key) => {
2066
- var _a, _b;
2067
2083
  const state = refState.current;
2068
2084
  if (!state) {
2069
2085
  return null;
@@ -2073,11 +2089,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2073
2089
  if (index === void 0) {
2074
2090
  return null;
2075
2091
  }
2076
- const renderedItem = (_b = (_a = refState.current).renderItem) == null ? void 0 : _b.call(_a, {
2077
- item: data[index],
2078
- index,
2079
- extraData: peek$(ctx, "extraData")
2080
- });
2092
+ const renderItemProp = refState.current.renderItem;
2093
+ let renderedItem = null;
2094
+ if (renderItemProp) {
2095
+ const itemProps = {
2096
+ item: data[index],
2097
+ index,
2098
+ extraData: peek$(ctx, "extraData")
2099
+ };
2100
+ renderedItem = isFunction(renderItemProp) ? renderItemProp(itemProps) : React2.createElement(renderItemProp, itemProps);
2101
+ }
2081
2102
  return { index, item: data[index], renderedItem };
2082
2103
  }, []);
2083
2104
  const doInitialAllocateContainers = () => {
@@ -2121,120 +2142,130 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2121
2142
  useInit(() => {
2122
2143
  doInitialAllocateContainers();
2123
2144
  });
2124
- const updateItemSize = useCallback((itemKey, size, fromFixGaps) => {
2125
- const state = refState.current;
2126
- const {
2127
- sizes,
2128
- indexByKey,
2129
- sizesKnown,
2130
- data,
2131
- rowHeights,
2132
- startBuffered,
2133
- endBuffered,
2134
- averageSizes,
2135
- queuedInitialLayout
2136
- } = state;
2137
- if (!data) {
2138
- return;
2139
- }
2140
- const index = indexByKey.get(itemKey);
2141
- const numColumns = peek$(ctx, "numColumns");
2142
- state.scrollForNextCalculateItemsInView = void 0;
2143
- state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, index) : index;
2144
- const prevSize = getItemSize(itemKey, index, data);
2145
- const prevSizeKnown = sizesKnown.get(itemKey);
2146
- let needsCalculate = false;
2147
- let needsUpdateContainersDidLayout = false;
2148
- sizesKnown.set(itemKey, size);
2149
- const itemType = "";
2150
- let averages = averageSizes[itemType];
2151
- if (!averages) {
2152
- averages = averageSizes[itemType] = {
2153
- num: 0,
2154
- avg: 0
2155
- };
2156
- }
2157
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2158
- averages.num++;
2159
- if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2160
- let diff;
2161
- needsCalculate = true;
2162
- if (numColumns > 1) {
2163
- const rowNumber = Math.floor(index / numColumnsProp);
2164
- const prevSizeInRow = getRowHeight(rowNumber);
2165
- sizes.set(itemKey, size);
2166
- rowHeights.delete(rowNumber);
2167
- const sizeInRow = getRowHeight(rowNumber);
2168
- diff = sizeInRow - prevSizeInRow;
2169
- } else {
2170
- sizes.set(itemKey, size);
2171
- diff = size - prevSize;
2145
+ const updateItemSize = useCallback(
2146
+ (itemKey, sizeObj, fromFixGaps) => {
2147
+ const state = refState.current;
2148
+ const {
2149
+ sizes,
2150
+ indexByKey,
2151
+ sizesKnown,
2152
+ data,
2153
+ rowHeights,
2154
+ startBuffered,
2155
+ endBuffered,
2156
+ averageSizes,
2157
+ queuedInitialLayout
2158
+ } = state;
2159
+ if (!data) {
2160
+ return;
2161
+ }
2162
+ const index = indexByKey.get(itemKey);
2163
+ const numColumns = peek$(ctx, "numColumns");
2164
+ state.scrollForNextCalculateItemsInView = void 0;
2165
+ state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, index) : index;
2166
+ const prevSize = getItemSize(itemKey, index, data);
2167
+ const prevSizeKnown = sizesKnown.get(itemKey);
2168
+ let needsCalculate = false;
2169
+ let needsUpdateContainersDidLayout = false;
2170
+ const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2171
+ sizesKnown.set(itemKey, size);
2172
+ const itemType = "";
2173
+ let averages = averageSizes[itemType];
2174
+ if (!averages) {
2175
+ averages = averageSizes[itemType] = {
2176
+ num: 0,
2177
+ avg: 0
2178
+ };
2172
2179
  }
2173
- if (__DEV__ && suggestEstimatedItemSize) {
2174
- if (state.timeoutSizeMessage) {
2175
- clearTimeout(state.timeoutSizeMessage);
2180
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2181
+ averages.num++;
2182
+ if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2183
+ let diff;
2184
+ needsCalculate = true;
2185
+ if (numColumns > 1) {
2186
+ const rowNumber = Math.floor(index / numColumnsProp);
2187
+ const prevSizeInRow = getRowHeight(rowNumber);
2188
+ sizes.set(itemKey, size);
2189
+ rowHeights.delete(rowNumber);
2190
+ const sizeInRow = getRowHeight(rowNumber);
2191
+ diff = sizeInRow - prevSizeInRow;
2192
+ } else {
2193
+ sizes.set(itemKey, size);
2194
+ diff = size - prevSize;
2195
+ }
2196
+ if (__DEV__ && suggestEstimatedItemSize) {
2197
+ if (state.timeoutSizeMessage) {
2198
+ clearTimeout(state.timeoutSizeMessage);
2199
+ }
2200
+ state.timeoutSizeMessage = setTimeout(() => {
2201
+ state.timeoutSizeMessage = void 0;
2202
+ const num = sizesKnown.size;
2203
+ const avg = state.averageSizes[""].avg;
2204
+ console.warn(
2205
+ `[legend-list] estimatedItemSize or getEstimatedItemSize are not defined. Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
2206
+ );
2207
+ }, 1e3);
2208
+ }
2209
+ state.scrollForNextCalculateItemsInView = void 0;
2210
+ addTotalSize(itemKey, diff, 0);
2211
+ if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2212
+ doMaintainScrollAtEnd(false);
2213
+ }
2214
+ if (onItemSizeChanged) {
2215
+ onItemSizeChanged({
2216
+ size,
2217
+ previous: prevSize,
2218
+ index,
2219
+ itemKey,
2220
+ itemData: data[index]
2221
+ });
2176
2222
  }
2177
- state.timeoutSizeMessage = setTimeout(() => {
2178
- state.timeoutSizeMessage = void 0;
2179
- const num = sizesKnown.size;
2180
- const avg = state.averageSizes[""].avg;
2181
- console.warn(
2182
- `[legend-list] estimatedItemSize or getEstimatedItemSize are not defined. Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
2183
- );
2184
- }, 1e3);
2185
2223
  }
2186
- state.scrollForNextCalculateItemsInView = void 0;
2187
- addTotalSize(itemKey, diff, 0);
2188
- if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2189
- doMaintainScrollAtEnd(false);
2190
- }
2191
- if (onItemSizeChanged) {
2192
- onItemSizeChanged({
2193
- size,
2194
- previous: prevSize,
2195
- index,
2196
- itemKey,
2197
- itemData: data[index]
2198
- });
2224
+ if (!queuedInitialLayout && checkAllSizesKnown()) {
2225
+ needsUpdateContainersDidLayout = true;
2199
2226
  }
2200
- }
2201
- if (!queuedInitialLayout && checkAllSizesKnown()) {
2202
- needsUpdateContainersDidLayout = true;
2203
- }
2204
- let isInView = index >= startBuffered && index <= endBuffered;
2205
- if (!isInView) {
2206
- const numContainers = ctx.values.get("numContainers");
2207
- for (let i = 0; i < numContainers; i++) {
2208
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
2209
- isInView = true;
2210
- break;
2227
+ let isInView = index >= startBuffered && index <= endBuffered;
2228
+ if (!isInView) {
2229
+ const numContainers = ctx.values.get("numContainers");
2230
+ for (let i = 0; i < numContainers; i++) {
2231
+ if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
2232
+ isInView = true;
2233
+ break;
2234
+ }
2211
2235
  }
2212
2236
  }
2213
- }
2214
- if (needsUpdateContainersDidLayout || !fromFixGaps && needsCalculate && (isInView || !queuedInitialLayout)) {
2215
- const scrollVelocity = state.scrollVelocity;
2216
- let didCalculate = false;
2217
- if ((Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1 || state.scrollingToOffset !== void 0) && (!waitForInitialLayout || needsUpdateContainersDidLayout || queuedInitialLayout)) {
2218
- if (Date.now() - state.lastBatchingAction < 500) {
2219
- if (!state.queuedCalculateItemsInView) {
2220
- state.queuedCalculateItemsInView = requestAnimationFrame(() => {
2221
- state.queuedCalculateItemsInView = void 0;
2222
- calculateItemsInView();
2223
- });
2237
+ if (needsUpdateContainersDidLayout || !fromFixGaps && needsCalculate && (isInView || !queuedInitialLayout)) {
2238
+ const scrollVelocity = state.scrollVelocity;
2239
+ let didCalculate = false;
2240
+ if ((Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1 || state.scrollingTo !== void 0) && (!waitForInitialLayout || needsUpdateContainersDidLayout || queuedInitialLayout)) {
2241
+ if (Date.now() - state.lastBatchingAction < 500) {
2242
+ if (!state.queuedCalculateItemsInView) {
2243
+ state.queuedCalculateItemsInView = requestAnimationFrame(() => {
2244
+ state.queuedCalculateItemsInView = void 0;
2245
+ calculateItemsInView();
2246
+ });
2247
+ }
2248
+ } else {
2249
+ calculateItemsInView();
2250
+ didCalculate = true;
2224
2251
  }
2225
- } else {
2226
- calculateItemsInView();
2227
- didCalculate = true;
2252
+ }
2253
+ if (!didCalculate && !needsUpdateContainersDidLayout && IsNewArchitecture) {
2254
+ fixGaps();
2228
2255
  }
2229
2256
  }
2230
- if (!didCalculate && !needsUpdateContainersDidLayout && IsNewArchitecture) {
2231
- fixGaps();
2257
+ if (state.needsOtherAxisSize) {
2258
+ const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
2259
+ const cur = peek$(ctx, "otherAxisSize");
2260
+ if (!cur || otherAxisSize > cur) {
2261
+ set$(ctx, "otherAxisSize", otherAxisSize);
2262
+ }
2232
2263
  }
2233
- }
2234
- }, []);
2235
- const onLayout = useCallback((event) => {
2264
+ },
2265
+ []
2266
+ );
2267
+ const handleLayout = useCallback((scrollLength) => {
2236
2268
  const state = refState.current;
2237
- const scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
2238
2269
  const didChange = scrollLength !== state.scrollLength;
2239
2270
  state.scrollLength = scrollLength;
2240
2271
  state.lastBatchingAction = Date.now();
@@ -2247,20 +2278,36 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2247
2278
  if (didChange) {
2248
2279
  calculateItemsInView();
2249
2280
  }
2250
- if (__DEV__) {
2251
- const isWidthZero = event.nativeEvent.layout.width === 0;
2252
- const isHeightZero = event.nativeEvent.layout.height === 0;
2253
- if (isWidthZero || isHeightZero) {
2254
- warnDevOnce(
2255
- "height0",
2256
- `[legend-list] List ${isWidthZero ? "width" : "height"} is 0. You may need to set a style or \`flex: \` for the list, because children are absolutely positioned.`
2257
- );
2258
- }
2281
+ }, []);
2282
+ const onLayout = useCallback((event) => {
2283
+ const scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
2284
+ handleLayout(scrollLength);
2285
+ const otherAxisSize = event.nativeEvent.layout[horizontal ? "height" : "width"];
2286
+ if (refState.current) {
2287
+ refState.current.needsOtherAxisSize = otherAxisSize - (stylePaddingTopState || 0) < 10;
2288
+ }
2289
+ if (__DEV__ && scrollLength === 0) {
2290
+ warnDevOnce(
2291
+ "height0",
2292
+ `List ${horizontal ? "width" : "height"} is 0. You may need to set a style or \`flex: \` for the list, because children are absolutely positioned.`
2293
+ );
2259
2294
  }
2260
2295
  if (onLayoutProp) {
2261
2296
  onLayoutProp(event);
2262
2297
  }
2263
2298
  }, []);
2299
+ if (IsNewArchitecture) {
2300
+ useLayoutEffect(() => {
2301
+ var _a, _b;
2302
+ const measured = (_b = (_a = refScroller.current) == null ? void 0 : _a.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a);
2303
+ if (measured) {
2304
+ const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
2305
+ if (size) {
2306
+ handleLayout(size);
2307
+ }
2308
+ }
2309
+ }, []);
2310
+ }
2264
2311
  const handleScroll = useCallback(
2265
2312
  (event) => {
2266
2313
  var _a, _b, _c, _d;
@@ -2280,8 +2327,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2280
2327
  );
2281
2328
  const updateScroll = useCallback((newScroll) => {
2282
2329
  const state = refState.current;
2283
- const scrollingToOffset = state.scrollingToOffset;
2284
- if (scrollingToOffset !== void 0 && Math.abs(newScroll - scrollingToOffset) < 10) {
2330
+ const scrollingTo = state.scrollingTo;
2331
+ if (scrollingTo !== void 0 && Math.abs(newScroll - scrollingTo.offset) < 10) {
2285
2332
  finishScrollTo();
2286
2333
  }
2287
2334
  if (state.disableScrollJumpsFrom !== void 0) {
@@ -2294,7 +2341,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2294
2341
  state.hasScrolled = true;
2295
2342
  state.lastBatchingAction = Date.now();
2296
2343
  const currentTime = performance.now();
2297
- if (scrollingToOffset === void 0 && !(state.scrollHistory.length === 0 && newScroll === initialContentOffset)) {
2344
+ if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === initialContentOffset)) {
2298
2345
  state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2299
2346
  }
2300
2347
  if (state.scrollHistory.length > 5) {
@@ -2360,8 +2407,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2360
2407
  contentLength: state.totalSize,
2361
2408
  end: state.endNoBuffer,
2362
2409
  endBuffered: state.endBuffered,
2363
- isAtEnd: state.isAtBottom,
2364
- isAtStart: state.isAtTop,
2410
+ isAtEnd: state.isAtEnd,
2411
+ isAtStart: state.isAtStart,
2365
2412
  scroll: state.scroll,
2366
2413
  scrollLength: state.scrollLength,
2367
2414
  start: state.startNoBuffer,
@@ -2384,10 +2431,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2384
2431
  scrollToIndex({ index, ...props2 });
2385
2432
  }
2386
2433
  },
2387
- scrollToOffset: ({ offset, animated }) => {
2388
- scrollTo(offset, animated);
2389
- },
2390
- scrollToEnd: (options) => refScroller.current.scrollToEnd(options)
2434
+ scrollToOffset: (params) => scrollTo(params),
2435
+ scrollToEnd: (options) => {
2436
+ const { data } = refState.current;
2437
+ const index = data.length - 1;
2438
+ if (index !== -1) {
2439
+ scrollToIndex({ index, ...options });
2440
+ }
2441
+ }
2391
2442
  };
2392
2443
  },
2393
2444
  []
@@ -2397,7 +2448,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2397
2448
  var _a;
2398
2449
  if (initialContentOffset) {
2399
2450
  (_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler.setDisableAdjust(true);
2400
- scrollTo(initialContentOffset, false);
2451
+ scrollTo({ offset: initialContentOffset, animated: false });
2401
2452
  setTimeout(() => {
2402
2453
  var _a2;
2403
2454
  (_a2 = refState.current) == null ? void 0 : _a2.scrollAdjustHandler.setDisableAdjust(false);
@@ -2417,11 +2468,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2417
2468
  handleScroll,
2418
2469
  onMomentumScrollEnd: (event) => {
2419
2470
  var _a;
2420
- const scrollingToOffset = (_a = refState.current) == null ? void 0 : _a.scrollingToOffset;
2421
- if (scrollingToOffset !== void 0) {
2471
+ const scrollingTo = (_a = refState.current) == null ? void 0 : _a.scrollingTo;
2472
+ if (scrollingTo !== void 0) {
2422
2473
  requestAnimationFrame(() => {
2423
- scrollTo(scrollingToOffset, false);
2424
- refState.current.scrollingToOffset = void 0;
2474
+ scrollTo({ ...scrollingTo, animated: false });
2475
+ refState.current.scrollingTo = void 0;
2425
2476
  requestAnimationFrame(() => {
2426
2477
  refState.current.scrollAdjustHandler.setDisableAdjust(false);
2427
2478
  });
@@ -2444,12 +2495,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2444
2495
  maintainVisibleContentPosition,
2445
2496
  scrollEventThrottle: Platform.OS === "web" ? 16 : void 0,
2446
2497
  waitForInitialLayout,
2447
- refreshControl: refreshControl != null ? refreshControl : onRefresh && /* @__PURE__ */ React2.createElement(
2498
+ refreshControl: refreshControl ? stylePaddingTopState > 0 ? React2.cloneElement(refreshControl, {
2499
+ progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
2500
+ }) : refreshControl : onRefresh && /* @__PURE__ */ React2.createElement(
2448
2501
  RefreshControl,
2449
2502
  {
2450
2503
  refreshing: !!refreshing,
2451
2504
  onRefresh,
2452
- progressViewOffset
2505
+ progressViewOffset: (progressViewOffset || 0) + stylePaddingTopState
2453
2506
  }
2454
2507
  ),
2455
2508
  style,
@@ -2458,4 +2511,4 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2458
2511
  ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React2.createElement(DebugView, { state: refState.current }));
2459
2512
  });
2460
2513
 
2461
- export { LegendList, useRecyclingEffect, useRecyclingState, useViewability, useViewabilityAmount };
2514
+ export { LegendList, useIsLastItem, useRecyclingEffect, useRecyclingState, useViewability, useViewabilityAmount };