@legendapp/list 1.0.0-beta.16 → 1.0.0-beta.18

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,6 +1,6 @@
1
1
  import * as React6 from 'react';
2
2
  import React6__default, { createContext, memo, useReducer, useEffect, useMemo, useRef, useCallback, useImperativeHandle, useSyncExternalStore, useContext, useState, forwardRef, useLayoutEffect } from 'react';
3
- import { View, Text, Platform, Animated, ScrollView, Dimensions, StyleSheet } from 'react-native';
3
+ import { View, Text, Platform, Animated, ScrollView, Dimensions, StyleSheet, RefreshControl } from 'react-native';
4
4
 
5
5
  // src/LegendList.tsx
6
6
  var ContextState = React6.createContext(null);
@@ -57,6 +57,14 @@ function set$(ctx, signalName, value) {
57
57
  }
58
58
  }
59
59
  }
60
+ function getContentSize(ctx) {
61
+ const { values } = ctx;
62
+ const stylePaddingTop = values.get("stylePaddingTop") || 0;
63
+ const headerSize = values.get("headerSize") || 0;
64
+ const footerSize = values.get("footerSize") || 0;
65
+ const totalSize = values.get("totalSize") || 0;
66
+ return headerSize + footerSize + totalSize + stylePaddingTop;
67
+ }
60
68
  var symbolFirst = Symbol();
61
69
  function useInit(cb) {
62
70
  const refValue = useRef(symbolFirst);
@@ -143,7 +151,9 @@ function useRecyclingState(valueOrFun) {
143
151
  return stateInfo;
144
152
  }
145
153
  var DebugView = memo(function DebugView2({ state }) {
146
- const paddingTop = use$("paddingTop");
154
+ const ctx = useStateContext();
155
+ const totalSize = use$("totalSize");
156
+ const contentSize = getContentSize(ctx);
147
157
  const [, forceUpdate] = useReducer((x) => x + 1, 0);
148
158
  useInterval(() => {
149
159
  forceUpdate();
@@ -161,7 +171,8 @@ var DebugView = memo(function DebugView2({ state }) {
161
171
  backgroundColor: "#FFFFFFCC"
162
172
  }
163
173
  },
164
- /* @__PURE__ */ React6.createElement(Text, null, "PaddingTop: ", paddingTop),
174
+ /* @__PURE__ */ React6.createElement(Text, null, "TotalSize: ", totalSize),
175
+ /* @__PURE__ */ React6.createElement(Text, null, "ContentSize: ", contentSize),
165
176
  /* @__PURE__ */ React6.createElement(Text, null, "At end: ", String(state.isAtBottom))
166
177
  );
167
178
  });
@@ -203,13 +214,17 @@ var Container = ({
203
214
  const position = use$(`containerPosition${id}`) || ANCHORED_POSITION_OUT_OF_VIEW;
204
215
  const column = use$(`containerColumn${id}`) || 0;
205
216
  const numColumns = use$("numColumns");
217
+ const lastItemKeys = use$("lastItemKeys");
218
+ const itemKey = use$(`containerItemKey${id}`);
219
+ const data = use$(`containerItemData${id}`);
220
+ const extraData = use$("extraData");
206
221
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
207
222
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
208
223
  let verticalPaddingStyles;
209
224
  if (columnWrapperStyle && !horizontal && numColumns > 1) {
210
225
  const { columnGap, rowGap, gap } = columnWrapperStyle;
211
226
  verticalPaddingStyles = {
212
- paddingVertical: rowGap || gap || void 0,
227
+ paddingBottom: !lastItemKeys.has(itemKey) ? rowGap || gap || void 0 : void 0,
213
228
  // Apply horizontal padding based on column position (first, middle, or last)
214
229
  paddingLeft: column > 1 ? (columnGap || gap || 0) / 2 : void 0,
215
230
  paddingRight: column < numColumns ? (columnGap || gap || 0) / 2 : void 0
@@ -230,12 +245,8 @@ var Container = ({
230
245
  top: position.relativeCoordinate,
231
246
  ...verticalPaddingStyles || {}
232
247
  };
233
- const lastItemKey = use$("lastItemKey");
234
- const itemKey = use$(`containerItemKey${id}`);
235
- const data = use$(`containerItemData${id}`);
236
- const extraData = use$("extraData");
237
248
  const renderedItemInfo = useMemo(
238
- () => itemKey !== void 0 && getRenderedItem(itemKey),
249
+ () => itemKey !== void 0 ? getRenderedItem(itemKey) : null,
239
250
  [itemKey, data, extraData]
240
251
  );
241
252
  const { index, renderedItem } = renderedItemInfo || {};
@@ -244,7 +255,7 @@ var Container = ({
244
255
  const layout = event.nativeEvent.layout;
245
256
  const size = Math.floor(layout[horizontal ? "width" : "height"] * 8) / 8;
246
257
  if (size === 0) {
247
- if (layout.y !== POSITION_OUT_OF_VIEW && layout.y !== POSITION_OUT_OF_VIEW) {
258
+ if (layout.x !== POSITION_OUT_OF_VIEW && layout.y !== POSITION_OUT_OF_VIEW) {
248
259
  console.log(
249
260
  "[WARN] Container 0 height reported, possible bug in LegendList",
250
261
  id,
@@ -276,7 +287,7 @@ var Container = ({
276
287
  () => ({ containerId: id, itemKey, index, value: data }),
277
288
  [id, itemKey, index, data]
278
289
  );
279
- const contentFragment = /* @__PURE__ */ React6__default.createElement(React6__default.Fragment, { key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React6__default.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItem && ItemSeparatorComponent && itemKey !== lastItemKey && ItemSeparatorComponent));
290
+ const contentFragment = /* @__PURE__ */ React6__default.createElement(React6__default.Fragment, { key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React6__default.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && !lastItemKeys.has(itemKey) && /* @__PURE__ */ React6__default.createElement(ItemSeparatorComponent, { leadingItem: renderedItemInfo.item })));
280
291
  if (maintainVisibleContentPosition) {
281
292
  const anchorStyle = position.type === "top" ? { position: "absolute", top: 0, left: 0, right: 0 } : { position: "absolute", bottom: 0, left: 0, right: 0 };
282
293
  if (ENABLE_DEVMODE) {
@@ -287,6 +298,8 @@ var Container = ({
287
298
  }
288
299
  return /* @__PURE__ */ React6__default.createElement(LeanView, { style, onLayout, ref }, contentFragment);
289
300
  };
301
+ var typedForwardRef = forwardRef;
302
+ var typedMemo = memo;
290
303
  var useAnimatedValue = (initialValue) => {
291
304
  return useRef(new Animated.Value(initialValue)).current;
292
305
  };
@@ -315,7 +328,7 @@ function useValue$(key, getValue, useMicrotask) {
315
328
  }
316
329
 
317
330
  // src/Containers.tsx
318
- var Containers = React6.memo(function Containers2({
331
+ var Containers = typedMemo(function Containers2({
319
332
  horizontal,
320
333
  recycleItems,
321
334
  ItemSeparatorComponent,
@@ -325,7 +338,7 @@ var Containers = React6.memo(function Containers2({
325
338
  }) {
326
339
  const numContainers = use$("numContainersPooled");
327
340
  const animSize = useValue$(
328
- "totalSize",
341
+ "totalSizeWithScrollAdjust",
329
342
  void 0,
330
343
  /*useMicrotask*/
331
344
  true
@@ -334,7 +347,7 @@ var Containers = React6.memo(function Containers2({
334
347
  const containers = [];
335
348
  for (let i = 0; i < numContainers; i++) {
336
349
  containers.push(
337
- /* @__PURE__ */ React6.createElement(
350
+ /* @__PURE__ */ React.createElement(
338
351
  Container,
339
352
  {
340
353
  id: i,
@@ -349,7 +362,7 @@ var Containers = React6.memo(function Containers2({
349
362
  );
350
363
  }
351
364
  const style = horizontal ? { width: animSize, opacity: animOpacity } : { height: animSize, opacity: animOpacity };
352
- return /* @__PURE__ */ React6.createElement(Animated.View, { style }, containers);
365
+ return /* @__PURE__ */ React.createElement(Animated.View, { style }, containers);
353
366
  });
354
367
 
355
368
  // src/ListComponent.tsx
@@ -413,7 +426,7 @@ var PaddingAndAdjustDevMode = () => {
413
426
  }
414
427
  ));
415
428
  };
416
- var ListComponent = React6.memo(function ListComponent2({
429
+ var ListComponent = typedMemo(function ListComponent2({
417
430
  style,
418
431
  contentContainerStyle,
419
432
  horizontal,
@@ -434,6 +447,9 @@ var ListComponent = React6.memo(function ListComponent2({
434
447
  refScrollView,
435
448
  maintainVisibleContentPosition,
436
449
  renderScrollComponent,
450
+ onRefresh,
451
+ refreshing,
452
+ progressViewOffset,
437
453
  ...rest
438
454
  }) {
439
455
  const ctx = useStateContext();
@@ -461,15 +477,12 @@ var ListComponent = React6.memo(function ListComponent2({
461
477
  },
462
478
  ENABLE_DEVMODE ? /* @__PURE__ */ React6.createElement(PaddingAndAdjustDevMode, null) : /* @__PURE__ */ React6.createElement(PaddingAndAdjust, null),
463
479
  ListHeaderComponent && /* @__PURE__ */ React6.createElement(
464
- Animated.View,
480
+ View,
465
481
  {
466
482
  style: ListHeaderComponentStyle,
467
483
  onLayout: (event) => {
468
484
  const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
469
- const prevSize = peek$(ctx, "headerSize") || 0;
470
- if (size !== prevSize) {
471
- set$(ctx, "headerSize", size);
472
- }
485
+ set$(ctx, "headerSize", size);
473
486
  }
474
487
  },
475
488
  getComponent(ListHeaderComponent)
@@ -482,11 +495,21 @@ var ListComponent = React6.memo(function ListComponent2({
482
495
  recycleItems,
483
496
  waitForInitialLayout,
484
497
  getRenderedItem,
485
- ItemSeparatorComponent: ItemSeparatorComponent && getComponent(ItemSeparatorComponent),
498
+ ItemSeparatorComponent,
486
499
  updateItemSize
487
500
  }
488
501
  ),
489
- ListFooterComponent && /* @__PURE__ */ React6.createElement(View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
502
+ ListFooterComponent && /* @__PURE__ */ React6.createElement(
503
+ View,
504
+ {
505
+ style: ListFooterComponentStyle,
506
+ onLayout: (event) => {
507
+ const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
508
+ set$(ctx, "footerSize", size);
509
+ }
510
+ },
511
+ getComponent(ListFooterComponent)
512
+ )
490
513
  );
491
514
  });
492
515
 
@@ -531,7 +554,6 @@ var ScrollAdjustHandler = class {
531
554
  return false;
532
555
  }
533
556
  };
534
- var typedForwardRef = forwardRef;
535
557
  var useCombinedRef = (...refs) => {
536
558
  const callback = useCallback((element) => {
537
559
  for (const ref of refs) {
@@ -731,6 +753,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
731
753
  waitForInitialLayout = true,
732
754
  extraData,
733
755
  onLayout: onLayoutProp,
756
+ onRefresh,
757
+ refreshing,
758
+ progressViewOffset,
734
759
  ...rest
735
760
  } = props;
736
761
  const { style, contentContainerStyle } = props;
@@ -796,13 +821,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
796
821
  positions: /* @__PURE__ */ new Map(),
797
822
  columns: /* @__PURE__ */ new Map(),
798
823
  pendingAdjust: 0,
799
- waitingForMicrotask: false,
800
824
  isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
801
825
  isEndReached: false,
802
826
  isAtBottom: false,
803
827
  isAtTop: false,
804
828
  data: dataProp,
805
- idsInFirstRender: void 0,
806
829
  hasScrolled: false,
807
830
  scrollLength: initialScrollLength,
808
831
  startBuffered: 0,
@@ -829,11 +852,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
829
852
  belowAnchorElementPositions: void 0,
830
853
  rowHeights: /* @__PURE__ */ new Map(),
831
854
  startReachedBlockedByTimer: false,
855
+ endReachedBlockedByTimer: false,
832
856
  scrollForNextCalculateItemsInView: void 0,
833
857
  enableScrollForNextCalculateItemsInView: true,
834
- minIndexSizeChanged: 0
858
+ minIndexSizeChanged: 0,
859
+ numPendingInitialLayout: 0
835
860
  };
836
- refState.current.idsInFirstRender = new Set(dataProp.map((_, i) => getId(i)));
837
861
  if (maintainVisibleContentPosition) {
838
862
  if (initialScrollIndex) {
839
863
  refState.current.anchorElement = {
@@ -853,6 +877,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
853
877
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
854
878
  set$(ctx, "extraData", extraData);
855
879
  }
880
+ const didDataChange = refState.current.data !== dataProp;
881
+ refState.current.data = dataProp;
856
882
  const getAnchorElementIndex = () => {
857
883
  const state = refState.current;
858
884
  if (state.anchorElement) {
@@ -894,7 +920,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
894
920
  });
895
921
  }
896
922
  }
897
- set$(ctx, "totalSize", resultSize);
923
+ set$(ctx, "totalSize", state.totalSize);
924
+ set$(ctx, "totalSizeWithScrollAdjust", resultSize);
898
925
  if (alignItemsAtEnd) {
899
926
  doUpdatePaddingTop();
900
927
  }
@@ -964,10 +991,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
964
991
  columns,
965
992
  scrollAdjustHandler
966
993
  } = state;
967
- if (state.waitingForMicrotask) {
968
- state.waitingForMicrotask = false;
969
- }
970
- if (!data) {
994
+ if (!data || scrollLength === 0) {
971
995
  return;
972
996
  }
973
997
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
@@ -1200,7 +1224,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1200
1224
  }
1201
1225
  }
1202
1226
  }
1203
- set$(ctx, "containersDidLayout", true);
1227
+ if (state.numPendingInitialLayout === 0) {
1228
+ state.numPendingInitialLayout = state.endBuffered - state.startBuffered + 1;
1229
+ }
1204
1230
  if (state.viewabilityConfigCallbackPairs) {
1205
1231
  updateViewableItems(
1206
1232
  state,
@@ -1215,9 +1241,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1215
1241
  }, []);
1216
1242
  const doUpdatePaddingTop = () => {
1217
1243
  if (alignItemsAtEnd) {
1218
- const { scrollLength, totalSize } = refState.current;
1219
- const listPaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1220
- const paddingTop = Math.max(0, Math.floor(scrollLength - totalSize - listPaddingTop));
1244
+ const { scrollLength } = refState.current;
1245
+ const contentSize = getContentSize(ctx);
1246
+ const paddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1221
1247
  set$(ctx, "paddingTop", paddingTop);
1222
1248
  }
1223
1249
  };
@@ -1237,29 +1263,48 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1237
1263
  return true;
1238
1264
  }
1239
1265
  };
1266
+ const checkThreshold = (distance, threshold, isReached, isBlockedByTimer, onReached, blockTimer) => {
1267
+ const distanceAbs = Math.abs(distance);
1268
+ const isAtThreshold = distanceAbs < threshold;
1269
+ if (!isReached && !isBlockedByTimer) {
1270
+ if (isAtThreshold) {
1271
+ onReached == null ? void 0 : onReached(distance);
1272
+ blockTimer == null ? void 0 : blockTimer(true);
1273
+ setTimeout(() => {
1274
+ blockTimer == null ? void 0 : blockTimer(false);
1275
+ }, 700);
1276
+ return true;
1277
+ }
1278
+ } else {
1279
+ if (distance >= 1.3 * threshold) {
1280
+ return false;
1281
+ }
1282
+ }
1283
+ return isReached;
1284
+ };
1240
1285
  const checkAtBottom = () => {
1241
1286
  if (!refState.current) {
1242
1287
  return;
1243
1288
  }
1244
- const { scrollLength, scroll, totalSize, hasScrolled } = refState.current;
1245
- if (totalSize > 0 && hasScrolled) {
1246
- const distanceFromEnd = Math.abs(
1247
- totalSize - scroll - scrollLength + (peek$(ctx, "paddingTop") || 0)
1248
- );
1249
- if (refState.current) {
1250
- refState.current.isAtBottom = distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1251
- }
1252
- if (!refState.current.isEndReached) {
1253
- if (distanceFromEnd < onEndReachedThreshold * scrollLength) {
1254
- refState.current.isEndReached = true;
1255
- const { onEndReached } = callbacks.current;
1256
- onEndReached == null ? void 0 : onEndReached({ distanceFromEnd });
1257
- }
1258
- } else {
1259
- if (distanceFromEnd >= onEndReachedThreshold * scrollLength) {
1260
- refState.current.isEndReached = false;
1289
+ const { scrollLength, scroll, hasScrolled } = refState.current;
1290
+ const contentSize = getContentSize(ctx);
1291
+ if (contentSize > 0 && hasScrolled) {
1292
+ const distanceFromEnd = contentSize - scroll - scrollLength;
1293
+ const distanceFromEndAbs = Math.abs(distanceFromEnd);
1294
+ refState.current.isAtBottom = distanceFromEndAbs < scrollLength * maintainScrollAtEndThreshold;
1295
+ refState.current.isEndReached = checkThreshold(
1296
+ distanceFromEnd,
1297
+ onEndReachedThreshold * scrollLength,
1298
+ refState.current.isEndReached,
1299
+ refState.current.endReachedBlockedByTimer,
1300
+ (distance) => {
1301
+ var _a2, _b2;
1302
+ return (_b2 = (_a2 = callbacks.current).onEndReached) == null ? void 0 : _b2.call(_a2, { distanceFromEnd: distance });
1303
+ },
1304
+ (block) => {
1305
+ refState.current.endReachedBlockedByTimer = block;
1261
1306
  }
1262
- }
1307
+ );
1263
1308
  }
1264
1309
  };
1265
1310
  const checkAtTop = () => {
@@ -1268,22 +1313,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1268
1313
  }
1269
1314
  const { scrollLength, scroll } = refState.current;
1270
1315
  const distanceFromTop = scroll;
1271
- refState.current.isAtTop = distanceFromTop < 0;
1272
- if (!refState.current.isStartReached && !refState.current.startReachedBlockedByTimer) {
1273
- if (distanceFromTop < onStartReachedThreshold * scrollLength) {
1274
- refState.current.isStartReached = true;
1275
- const { onStartReached } = callbacks.current;
1276
- onStartReached == null ? void 0 : onStartReached({ distanceFromStart: scroll });
1277
- refState.current.startReachedBlockedByTimer = true;
1278
- setTimeout(() => {
1279
- refState.current.startReachedBlockedByTimer = false;
1280
- }, 700);
1281
- }
1282
- } else {
1283
- if (distanceFromTop >= 1.3 * onStartReachedThreshold * scrollLength) {
1284
- refState.current.isStartReached = false;
1316
+ const distanceFromTopAbs = Math.abs(distanceFromTop);
1317
+ refState.current.isAtTop = distanceFromTopAbs < 0;
1318
+ refState.current.isStartReached = checkThreshold(
1319
+ distanceFromTop,
1320
+ onStartReachedThreshold * scrollLength,
1321
+ refState.current.isStartReached,
1322
+ refState.current.startReachedBlockedByTimer,
1323
+ (distance) => {
1324
+ var _a2, _b2;
1325
+ return (_b2 = (_a2 = callbacks.current).onStartReached) == null ? void 0 : _b2.call(_a2, { distanceFromStart: distance });
1326
+ },
1327
+ (block) => {
1328
+ refState.current.startReachedBlockedByTimer = block;
1285
1329
  }
1286
- }
1330
+ );
1287
1331
  };
1288
1332
  const checkResetContainers = (isFirst2) => {
1289
1333
  const state = refState.current;
@@ -1394,12 +1438,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1394
1438
  addTotalSize(null, totalSize, totalSizeBelowIndex);
1395
1439
  };
1396
1440
  const isFirst = !refState.current.renderItem;
1397
- if (isFirst || dataProp !== refState.current.data || numColumnsProp !== peek$(ctx, "numColumns")) {
1398
- if (!keyExtractorProp && !isFirst && dataProp !== refState.current.data) {
1441
+ if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
1442
+ if (!keyExtractorProp && !isFirst && didDataChange) {
1399
1443
  refState.current.sizes.clear();
1400
1444
  refState.current.positions.clear();
1401
1445
  }
1402
- refState.current.data = dataProp;
1403
1446
  calcTotalSizesAndPositions({ forgetPositions: false });
1404
1447
  }
1405
1448
  useEffect(() => {
@@ -1412,17 +1455,22 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1412
1455
  set$(ctx, "extraData", extraData);
1413
1456
  }, [extraData]);
1414
1457
  refState.current.renderItem = renderItem;
1415
- const lastItemKey = dataProp.length > 0 ? getId(dataProp.length - 1) : void 0;
1458
+ const memoizedLastItemKeys = useMemo(() => {
1459
+ if (!dataProp.length) return [];
1460
+ return new Set(
1461
+ Array.from({ length: Math.min(numColumnsProp, dataProp.length) }, (_, i) => getId(dataProp.length - 1 - i))
1462
+ );
1463
+ }, [dataProp.length, numColumnsProp, dataProp.slice(-numColumnsProp).toString()]);
1416
1464
  const stylePaddingTop = (_d = (_c = (_a = StyleSheet.flatten(style)) == null ? void 0 : _a.paddingTop) != null ? _c : (_b = StyleSheet.flatten(contentContainerStyle)) == null ? void 0 : _b.paddingTop) != null ? _d : 0;
1417
1465
  const initalizeStateVars = () => {
1418
- set$(ctx, "lastItemKey", lastItemKey);
1466
+ set$(ctx, "lastItemKeys", memoizedLastItemKeys);
1419
1467
  set$(ctx, "numColumns", numColumnsProp);
1420
1468
  set$(ctx, "stylePaddingTop", stylePaddingTop);
1421
1469
  };
1422
1470
  if (isFirst) {
1423
1471
  initalizeStateVars();
1424
1472
  }
1425
- useEffect(initalizeStateVars, [lastItemKey, numColumnsProp, stylePaddingTop]);
1473
+ useEffect(initalizeStateVars, [memoizedLastItemKeys, numColumnsProp, stylePaddingTop]);
1426
1474
  const getRenderedItem = useCallback((key) => {
1427
1475
  var _a2, _b2;
1428
1476
  const state = refState.current;
@@ -1454,34 +1502,40 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1454
1502
  useRecyclingEffect: useRecyclingEffect2,
1455
1503
  useRecyclingState: useRecyclingState2
1456
1504
  });
1457
- return { index, renderedItem };
1505
+ return { index, item: data[index], renderedItem };
1458
1506
  }, []);
1459
- useInit(() => {
1507
+ const doInitialAllocateContainers = () => {
1460
1508
  var _a2;
1461
1509
  const state = refState.current;
1462
- const viewability = setupViewability(props);
1463
- state.viewabilityConfigCallbackPairs = viewability;
1464
- state.enableScrollForNextCalculateItemsInView = !viewability;
1465
1510
  const scrollLength = state.scrollLength;
1466
- const averageItemSize = (_a2 = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, dataProp[0])) != null ? _a2 : DEFAULT_ITEM_SIZE;
1467
- const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) * numColumnsProp;
1468
- for (let i = 0; i < numContainers; i++) {
1469
- set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1470
- set$(ctx, `containerColumn${i}`, -1);
1471
- }
1472
- set$(ctx, "numContainers", numContainers);
1473
- set$(ctx, "numContainersPooled", numContainers * 2);
1474
- if (initialScrollIndex) {
1475
- requestAnimationFrame(() => {
1511
+ if (scrollLength > 0 && !peek$(ctx, "numContainers")) {
1512
+ const averageItemSize = (_a2 = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, dataProp[0])) != null ? _a2 : DEFAULT_ITEM_SIZE;
1513
+ const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) * numColumnsProp;
1514
+ for (let i = 0; i < numContainers; i++) {
1515
+ set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1516
+ set$(ctx, `containerColumn${i}`, -1);
1517
+ }
1518
+ set$(ctx, "numContainers", numContainers);
1519
+ set$(ctx, "numContainersPooled", numContainers * 2);
1520
+ if (initialScrollIndex) {
1521
+ requestAnimationFrame(() => {
1522
+ calculateItemsInView(state.scrollVelocity);
1523
+ });
1524
+ } else {
1476
1525
  calculateItemsInView(state.scrollVelocity);
1477
- });
1478
- } else {
1479
- calculateItemsInView(state.scrollVelocity);
1526
+ }
1480
1527
  }
1528
+ };
1529
+ useInit(() => {
1530
+ const state = refState.current;
1531
+ const viewability = setupViewability(props);
1532
+ state.viewabilityConfigCallbackPairs = viewability;
1533
+ state.enableScrollForNextCalculateItemsInView = !viewability;
1534
+ doInitialAllocateContainers();
1481
1535
  });
1482
1536
  const updateItemSize = useCallback((containerId, itemKey, size) => {
1483
1537
  const state = refState.current;
1484
- const { sizes, indexByKey, columns, sizesLaidOut, data, rowHeights } = state;
1538
+ const { sizes, indexByKey, sizesLaidOut, data, rowHeights } = state;
1485
1539
  if (!data) {
1486
1540
  return;
1487
1541
  }
@@ -1489,8 +1543,20 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1489
1543
  const numColumns = peek$(ctx, "numColumns");
1490
1544
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, index) : index;
1491
1545
  const prevSize = getItemSize(itemKey, index, data);
1546
+ let needsCalculate = false;
1547
+ if (state.numPendingInitialLayout > 0) {
1548
+ state.numPendingInitialLayout--;
1549
+ if (state.numPendingInitialLayout === 0) {
1550
+ needsCalculate = true;
1551
+ state.numPendingInitialLayout = -1;
1552
+ queueMicrotask(() => {
1553
+ set$(ctx, "containersDidLayout", true);
1554
+ });
1555
+ }
1556
+ }
1492
1557
  if (!prevSize || Math.abs(prevSize - size) > 0.5) {
1493
1558
  let diff;
1559
+ needsCalculate = true;
1494
1560
  if (numColumns > 1) {
1495
1561
  const rowNumber = Math.floor(index / numColumnsProp);
1496
1562
  const prevSizeInRow = getRowHeight(rowNumber);
@@ -1524,22 +1590,20 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1524
1590
  refState.current.scrollForNextCalculateItemsInView = void 0;
1525
1591
  addTotalSize(itemKey, diff, 0);
1526
1592
  doMaintainScrollAtEnd(true);
1527
- const scrollVelocity = state.scrollVelocity;
1528
- if (!state.waitingForMicrotask && (Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1)) {
1529
- if (!peek$(ctx, "containersDidLayout")) {
1530
- state.waitingForMicrotask = true;
1531
- queueMicrotask(() => {
1532
- if (state.waitingForMicrotask) {
1533
- state.waitingForMicrotask = false;
1534
- calculateItemsInView(state.scrollVelocity);
1535
- }
1536
- });
1537
- } else {
1538
- calculateItemsInView(state.scrollVelocity);
1539
- }
1540
- }
1541
1593
  if (onItemSizeChanged) {
1542
- onItemSizeChanged({ size, previous: prevSize, index, itemKey, itemData: data[index] });
1594
+ onItemSizeChanged({
1595
+ size,
1596
+ previous: prevSize,
1597
+ index,
1598
+ itemKey,
1599
+ itemData: data[index]
1600
+ });
1601
+ }
1602
+ }
1603
+ if (needsCalculate) {
1604
+ const scrollVelocity = state.scrollVelocity;
1605
+ if ((Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1) && (!waitForInitialLayout || state.numPendingInitialLayout < 0)) {
1606
+ calculateItemsInView(state.scrollVelocity);
1543
1607
  }
1544
1608
  }
1545
1609
  }, []);
@@ -1551,7 +1615,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1551
1615
  const onLayout = useCallback((event) => {
1552
1616
  const scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
1553
1617
  const didChange = scrollLength !== refState.current.scrollLength;
1618
+ refState.current.scrollLength;
1554
1619
  refState.current.scrollLength = scrollLength;
1620
+ doInitialAllocateContainers();
1555
1621
  doMaintainScrollAtEnd(false);
1556
1622
  doUpdatePaddingTop();
1557
1623
  checkAtBottom();
@@ -1671,7 +1737,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1671
1737
  scrollToIndex({ index, animated });
1672
1738
  }
1673
1739
  },
1674
- scrollToEnd: () => refScroller.current.scrollToEnd()
1740
+ scrollToEnd: (options) => refScroller.current.scrollToEnd(options)
1675
1741
  };
1676
1742
  },
1677
1743
  []
@@ -1704,6 +1770,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1704
1770
  maintainVisibleContentPosition,
1705
1771
  scrollEventThrottle: scrollEventThrottle != null ? scrollEventThrottle : Platform.OS === "web" ? 16 : void 0,
1706
1772
  waitForInitialLayout,
1773
+ refreshControl: props.refreshControl == null ? /* @__PURE__ */ React6.createElement(
1774
+ RefreshControl,
1775
+ {
1776
+ refreshing: !!refreshing,
1777
+ onRefresh,
1778
+ progressViewOffset
1779
+ }
1780
+ ) : props.refreshControl,
1707
1781
  style
1708
1782
  }
1709
1783
  ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React6.createElement(DebugView, { state: refState.current }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "1.0.0-beta.16",
3
+ "version": "1.0.0-beta.18",
4
4
  "description": "Legend List aims to be a drop-in replacement for FlatList with much better performance and supporting dynamically sized items.",
5
5
  "sideEffects": false,
6
6
  "private": false,
package/reanimated.d.mts CHANGED
@@ -2,7 +2,7 @@ import { LegendListRef, LegendListPropsBase } from '@legendapp/list';
2
2
  import React__default, { ComponentProps } from 'react';
3
3
  import Animated from 'react-native-reanimated';
4
4
 
5
- type KeysToOmit = "getEstimatedItemSize" | "keyExtractor" | "animatedProps" | "renderItem" | "onItemSizeChanged";
5
+ type KeysToOmit = "getEstimatedItemSize" | "keyExtractor" | "animatedProps" | "renderItem" | "onItemSizeChanged" | "ItemSeparatorComponent";
6
6
  type PropsBase<ItemT> = LegendListPropsBase<ItemT, ComponentProps<typeof Animated.ScrollView>>;
7
7
  interface AnimatedLegendListProps<ItemT> extends Omit<PropsBase<ItemT>, KeysToOmit> {
8
8
  refScrollView?: React__default.Ref<Animated.ScrollView>;
package/reanimated.d.ts CHANGED
@@ -2,7 +2,7 @@ import { LegendListRef, LegendListPropsBase } from '@legendapp/list';
2
2
  import React__default, { ComponentProps } from 'react';
3
3
  import Animated from 'react-native-reanimated';
4
4
 
5
- type KeysToOmit = "getEstimatedItemSize" | "keyExtractor" | "animatedProps" | "renderItem" | "onItemSizeChanged";
5
+ type KeysToOmit = "getEstimatedItemSize" | "keyExtractor" | "animatedProps" | "renderItem" | "onItemSizeChanged" | "ItemSeparatorComponent";
6
6
  type PropsBase<ItemT> = LegendListPropsBase<ItemT, ComponentProps<typeof Animated.ScrollView>>;
7
7
  interface AnimatedLegendListProps<ItemT> extends Omit<PropsBase<ItemT>, KeysToOmit> {
8
8
  refScrollView?: React__default.Ref<Animated.ScrollView>;