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

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/animated.d.mts CHANGED
@@ -34,7 +34,9 @@ declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: Omit<re
34
34
  ListFooterComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
35
35
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
36
36
  ListEmptyComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
37
- ItemSeparatorComponent?: React.ComponentType<any>;
37
+ ItemSeparatorComponent?: React$1.ComponentType<{
38
+ leadingItem: T;
39
+ }> | undefined;
38
40
  viewabilityConfigCallbackPairs?: _legendapp_list.ViewabilityConfigCallbackPairs | undefined;
39
41
  viewabilityConfig?: _legendapp_list.ViewabilityConfig;
40
42
  onViewableItemsChanged?: _legendapp_list.OnViewableItemsChanged | undefined;
@@ -47,6 +49,9 @@ declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: Omit<re
47
49
  }) => void) | undefined;
48
50
  renderScrollComponent?: (props: react_native.ScrollViewProps) => React.ReactElement<react_native.ScrollViewProps>;
49
51
  extraData?: any;
52
+ refreshing?: boolean;
53
+ onRefresh?: () => void;
54
+ progressViewOffset?: number;
50
55
  } & React$1.RefAttributes<_legendapp_list.LegendListRef>) => React.ReactNode)>;
51
56
 
52
57
  export { AnimatedLegendList };
package/animated.d.ts CHANGED
@@ -34,7 +34,9 @@ declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: Omit<re
34
34
  ListFooterComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
35
35
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
36
36
  ListEmptyComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
37
- ItemSeparatorComponent?: React.ComponentType<any>;
37
+ ItemSeparatorComponent?: React$1.ComponentType<{
38
+ leadingItem: T;
39
+ }> | undefined;
38
40
  viewabilityConfigCallbackPairs?: _legendapp_list.ViewabilityConfigCallbackPairs | undefined;
39
41
  viewabilityConfig?: _legendapp_list.ViewabilityConfig;
40
42
  onViewableItemsChanged?: _legendapp_list.OnViewableItemsChanged | undefined;
@@ -47,6 +49,9 @@ declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: Omit<re
47
49
  }) => void) | undefined;
48
50
  renderScrollComponent?: (props: react_native.ScrollViewProps) => React.ReactElement<react_native.ScrollViewProps>;
49
51
  extraData?: any;
52
+ refreshing?: boolean;
53
+ onRefresh?: () => void;
54
+ progressViewOffset?: number;
50
55
  } & React$1.RefAttributes<_legendapp_list.LegendListRef>) => React.ReactNode)>;
51
56
 
52
57
  export { AnimatedLegendList };
package/index.d.mts CHANGED
@@ -49,7 +49,9 @@ type LegendListPropsBase<ItemT, TScrollView extends ComponentProps<typeof Scroll
49
49
  ListFooterComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
50
50
  ListFooterComponentStyle?: StyleProp<ViewStyle> | undefined;
51
51
  ListEmptyComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
52
- ItemSeparatorComponent?: React.ComponentType<any>;
52
+ ItemSeparatorComponent?: React.ComponentType<{
53
+ leadingItem: ItemT;
54
+ }>;
53
55
  viewabilityConfigCallbackPairs?: ViewabilityConfigCallbackPairs | undefined;
54
56
  viewabilityConfig?: ViewabilityConfig;
55
57
  onViewableItemsChanged?: OnViewableItemsChanged | undefined;
@@ -66,6 +68,9 @@ type LegendListPropsBase<ItemT, TScrollView extends ComponentProps<typeof Scroll
66
68
  */
67
69
  renderScrollComponent?: (props: ScrollViewProps) => React.ReactElement<ScrollViewProps>;
68
70
  extraData?: any;
71
+ refreshing?: boolean;
72
+ onRefresh?: () => void;
73
+ progressViewOffset?: number;
69
74
  };
70
75
  interface ColumnWrapperStyle {
71
76
  rowGap?: number;
@@ -90,13 +95,11 @@ interface InternalState {
90
95
  sizes: Map<string, number>;
91
96
  sizesLaidOut: Map<string, number> | undefined;
92
97
  pendingAdjust: number;
93
- waitingForMicrotask: any;
94
98
  isStartReached: boolean;
95
99
  isEndReached: boolean;
96
100
  isAtBottom: boolean;
97
101
  isAtTop: boolean;
98
102
  data: readonly any[];
99
- idsInFirstRender: Set<string>;
100
103
  hasScrolled: boolean;
101
104
  scrollLength: number;
102
105
  startBuffered: number;
@@ -130,6 +133,7 @@ interface InternalState {
130
133
  } | undefined;
131
134
  enableScrollForNextCalculateItemsInView: boolean;
132
135
  minIndexSizeChanged: number | undefined;
136
+ numPendingInitialLayout: number;
133
137
  }
134
138
  interface ViewableRange<T> {
135
139
  startBuffered: number;
@@ -243,6 +247,10 @@ interface LegendListRecyclingState<T> {
243
247
  }
244
248
  type TypedForwardRef = <T, P = {}>(render: (props: P, ref: React.Ref<T>) => React.ReactNode) => (props: P & React.RefAttributes<T>) => React.ReactNode;
245
249
  declare const typedForwardRef: TypedForwardRef;
250
+ type TypedMemo = <T extends React.ComponentType<any>>(Component: T, propsAreEqual?: (prevProps: Readonly<ComponentProps<T>>, nextProps: Readonly<ComponentProps<T>>) => boolean) => T & {
251
+ displayName?: string;
252
+ };
253
+ declare const typedMemo: TypedMemo;
246
254
 
247
255
  declare const LegendList: <T>(props: Omit<react_native.ScrollViewProps, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices"> & {
248
256
  data: readonly T[];
@@ -275,7 +283,9 @@ declare const LegendList: <T>(props: Omit<react_native.ScrollViewProps, "content
275
283
  ListFooterComponent?: React$1.ComponentType<any> | React$1.ReactElement | null | undefined;
276
284
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
277
285
  ListEmptyComponent?: React$1.ComponentType<any> | React$1.ReactElement | null | undefined;
278
- ItemSeparatorComponent?: React$1.ComponentType<any>;
286
+ ItemSeparatorComponent?: React$1.ComponentType<{
287
+ leadingItem: T;
288
+ }> | undefined;
279
289
  viewabilityConfigCallbackPairs?: ViewabilityConfigCallbackPairs | undefined;
280
290
  viewabilityConfig?: ViewabilityConfig;
281
291
  onViewableItemsChanged?: OnViewableItemsChanged | undefined;
@@ -288,6 +298,9 @@ declare const LegendList: <T>(props: Omit<react_native.ScrollViewProps, "content
288
298
  }) => void) | undefined;
289
299
  renderScrollComponent?: (props: react_native.ScrollViewProps) => React$1.ReactElement<react_native.ScrollViewProps>;
290
300
  extraData?: any;
301
+ refreshing?: boolean;
302
+ onRefresh?: () => void;
303
+ progressViewOffset?: number;
291
304
  } & React$1.RefAttributes<LegendListRef>) => React$1.ReactNode;
292
305
 
293
306
  declare function useViewability(configId: string, callback: ViewabilityCallback): void;
@@ -295,4 +308,4 @@ declare function useViewabilityAmount(callback: ViewabilityAmountCallback): void
295
308
  declare function useRecyclingEffect(effect: (info: LegendListRecyclingState<unknown>) => void | (() => void)): void;
296
309
  declare function useRecyclingState(valueOrFun: ((info: LegendListRecyclingState<unknown>) => any) | any): [any, React$1.Dispatch<any>];
297
310
 
298
- export { type AnchoredPosition, type ColumnWrapperStyle, type InternalState, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type OnViewableItemsChanged, type TypedForwardRef, type ViewAmountToken, type ViewToken, type ViewabilityAmountCallback, type ViewabilityCallback, type ViewabilityConfig, type ViewabilityConfigCallbackPair, type ViewabilityConfigCallbackPairs, type ViewableRange, typedForwardRef, useRecyclingEffect, useRecyclingState, useViewability, useViewabilityAmount };
311
+ export { type AnchoredPosition, type ColumnWrapperStyle, type InternalState, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type OnViewableItemsChanged, type TypedForwardRef, type TypedMemo, type ViewAmountToken, type ViewToken, type ViewabilityAmountCallback, type ViewabilityCallback, type ViewabilityConfig, type ViewabilityConfigCallbackPair, type ViewabilityConfigCallbackPairs, type ViewableRange, typedForwardRef, typedMemo, useRecyclingEffect, useRecyclingState, useViewability, useViewabilityAmount };
package/index.d.ts CHANGED
@@ -49,7 +49,9 @@ type LegendListPropsBase<ItemT, TScrollView extends ComponentProps<typeof Scroll
49
49
  ListFooterComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
50
50
  ListFooterComponentStyle?: StyleProp<ViewStyle> | undefined;
51
51
  ListEmptyComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
52
- ItemSeparatorComponent?: React.ComponentType<any>;
52
+ ItemSeparatorComponent?: React.ComponentType<{
53
+ leadingItem: ItemT;
54
+ }>;
53
55
  viewabilityConfigCallbackPairs?: ViewabilityConfigCallbackPairs | undefined;
54
56
  viewabilityConfig?: ViewabilityConfig;
55
57
  onViewableItemsChanged?: OnViewableItemsChanged | undefined;
@@ -66,6 +68,9 @@ type LegendListPropsBase<ItemT, TScrollView extends ComponentProps<typeof Scroll
66
68
  */
67
69
  renderScrollComponent?: (props: ScrollViewProps) => React.ReactElement<ScrollViewProps>;
68
70
  extraData?: any;
71
+ refreshing?: boolean;
72
+ onRefresh?: () => void;
73
+ progressViewOffset?: number;
69
74
  };
70
75
  interface ColumnWrapperStyle {
71
76
  rowGap?: number;
@@ -90,13 +95,11 @@ interface InternalState {
90
95
  sizes: Map<string, number>;
91
96
  sizesLaidOut: Map<string, number> | undefined;
92
97
  pendingAdjust: number;
93
- waitingForMicrotask: any;
94
98
  isStartReached: boolean;
95
99
  isEndReached: boolean;
96
100
  isAtBottom: boolean;
97
101
  isAtTop: boolean;
98
102
  data: readonly any[];
99
- idsInFirstRender: Set<string>;
100
103
  hasScrolled: boolean;
101
104
  scrollLength: number;
102
105
  startBuffered: number;
@@ -130,6 +133,7 @@ interface InternalState {
130
133
  } | undefined;
131
134
  enableScrollForNextCalculateItemsInView: boolean;
132
135
  minIndexSizeChanged: number | undefined;
136
+ numPendingInitialLayout: number;
133
137
  }
134
138
  interface ViewableRange<T> {
135
139
  startBuffered: number;
@@ -243,6 +247,10 @@ interface LegendListRecyclingState<T> {
243
247
  }
244
248
  type TypedForwardRef = <T, P = {}>(render: (props: P, ref: React.Ref<T>) => React.ReactNode) => (props: P & React.RefAttributes<T>) => React.ReactNode;
245
249
  declare const typedForwardRef: TypedForwardRef;
250
+ type TypedMemo = <T extends React.ComponentType<any>>(Component: T, propsAreEqual?: (prevProps: Readonly<ComponentProps<T>>, nextProps: Readonly<ComponentProps<T>>) => boolean) => T & {
251
+ displayName?: string;
252
+ };
253
+ declare const typedMemo: TypedMemo;
246
254
 
247
255
  declare const LegendList: <T>(props: Omit<react_native.ScrollViewProps, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices"> & {
248
256
  data: readonly T[];
@@ -275,7 +283,9 @@ declare const LegendList: <T>(props: Omit<react_native.ScrollViewProps, "content
275
283
  ListFooterComponent?: React$1.ComponentType<any> | React$1.ReactElement | null | undefined;
276
284
  ListFooterComponentStyle?: react_native.StyleProp<react_native.ViewStyle> | undefined;
277
285
  ListEmptyComponent?: React$1.ComponentType<any> | React$1.ReactElement | null | undefined;
278
- ItemSeparatorComponent?: React$1.ComponentType<any>;
286
+ ItemSeparatorComponent?: React$1.ComponentType<{
287
+ leadingItem: T;
288
+ }> | undefined;
279
289
  viewabilityConfigCallbackPairs?: ViewabilityConfigCallbackPairs | undefined;
280
290
  viewabilityConfig?: ViewabilityConfig;
281
291
  onViewableItemsChanged?: OnViewableItemsChanged | undefined;
@@ -288,6 +298,9 @@ declare const LegendList: <T>(props: Omit<react_native.ScrollViewProps, "content
288
298
  }) => void) | undefined;
289
299
  renderScrollComponent?: (props: react_native.ScrollViewProps) => React$1.ReactElement<react_native.ScrollViewProps>;
290
300
  extraData?: any;
301
+ refreshing?: boolean;
302
+ onRefresh?: () => void;
303
+ progressViewOffset?: number;
291
304
  } & React$1.RefAttributes<LegendListRef>) => React$1.ReactNode;
292
305
 
293
306
  declare function useViewability(configId: string, callback: ViewabilityCallback): void;
@@ -295,4 +308,4 @@ declare function useViewabilityAmount(callback: ViewabilityAmountCallback): void
295
308
  declare function useRecyclingEffect(effect: (info: LegendListRecyclingState<unknown>) => void | (() => void)): void;
296
309
  declare function useRecyclingState(valueOrFun: ((info: LegendListRecyclingState<unknown>) => any) | any): [any, React$1.Dispatch<any>];
297
310
 
298
- export { type AnchoredPosition, type ColumnWrapperStyle, type InternalState, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type OnViewableItemsChanged, type TypedForwardRef, type ViewAmountToken, type ViewToken, type ViewabilityAmountCallback, type ViewabilityCallback, type ViewabilityConfig, type ViewabilityConfigCallbackPair, type ViewabilityConfigCallbackPairs, type ViewableRange, typedForwardRef, useRecyclingEffect, useRecyclingState, useViewability, useViewabilityAmount };
311
+ export { type AnchoredPosition, type ColumnWrapperStyle, type InternalState, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type OnViewableItemsChanged, type TypedForwardRef, type TypedMemo, type ViewAmountToken, type ViewToken, type ViewabilityAmountCallback, type ViewabilityCallback, type ViewabilityConfig, type ViewabilityConfigCallbackPair, type ViewabilityConfigCallbackPairs, type ViewableRange, typedForwardRef, typedMemo, useRecyclingEffect, useRecyclingState, useViewability, useViewabilityAmount };
package/index.js CHANGED
@@ -224,13 +224,17 @@ var Container = ({
224
224
  const position = use$(`containerPosition${id}`) || ANCHORED_POSITION_OUT_OF_VIEW;
225
225
  const column = use$(`containerColumn${id}`) || 0;
226
226
  const numColumns = use$("numColumns");
227
+ const lastItemKeys = use$("lastItemKeys");
228
+ const itemKey = use$(`containerItemKey${id}`);
229
+ const data = use$(`containerItemData${id}`);
230
+ const extraData = use$("extraData");
227
231
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
228
232
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
229
233
  let verticalPaddingStyles;
230
234
  if (columnWrapperStyle && !horizontal && numColumns > 1) {
231
235
  const { columnGap, rowGap, gap } = columnWrapperStyle;
232
236
  verticalPaddingStyles = {
233
- paddingVertical: rowGap || gap || void 0,
237
+ paddingBottom: !lastItemKeys.has(itemKey) ? rowGap || gap || void 0 : void 0,
234
238
  // Apply horizontal padding based on column position (first, middle, or last)
235
239
  paddingLeft: column > 1 ? (columnGap || gap || 0) / 2 : void 0,
236
240
  paddingRight: column < numColumns ? (columnGap || gap || 0) / 2 : void 0
@@ -251,12 +255,8 @@ var Container = ({
251
255
  top: position.relativeCoordinate,
252
256
  ...verticalPaddingStyles || {}
253
257
  };
254
- const lastItemKey = use$("lastItemKey");
255
- const itemKey = use$(`containerItemKey${id}`);
256
- const data = use$(`containerItemData${id}`);
257
- const extraData = use$("extraData");
258
258
  const renderedItemInfo = React6.useMemo(
259
- () => itemKey !== void 0 && getRenderedItem(itemKey),
259
+ () => itemKey !== void 0 ? getRenderedItem(itemKey) : null,
260
260
  [itemKey, data, extraData]
261
261
  );
262
262
  const { index, renderedItem } = renderedItemInfo || {};
@@ -265,7 +265,7 @@ var Container = ({
265
265
  const layout = event.nativeEvent.layout;
266
266
  const size = Math.floor(layout[horizontal ? "width" : "height"] * 8) / 8;
267
267
  if (size === 0) {
268
- if (layout.y !== POSITION_OUT_OF_VIEW && layout.y !== POSITION_OUT_OF_VIEW) {
268
+ if (layout.x !== POSITION_OUT_OF_VIEW && layout.y !== POSITION_OUT_OF_VIEW) {
269
269
  console.log(
270
270
  "[WARN] Container 0 height reported, possible bug in LegendList",
271
271
  id,
@@ -297,7 +297,7 @@ var Container = ({
297
297
  () => ({ containerId: id, itemKey, index, value: data }),
298
298
  [id, itemKey, index, data]
299
299
  );
300
- const contentFragment = /* @__PURE__ */ React6__namespace.default.createElement(React6__namespace.default.Fragment, { key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React6__namespace.default.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItem && ItemSeparatorComponent && itemKey !== lastItemKey && ItemSeparatorComponent));
300
+ const contentFragment = /* @__PURE__ */ React6__namespace.default.createElement(React6__namespace.default.Fragment, { key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React6__namespace.default.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && !lastItemKeys.has(itemKey) && /* @__PURE__ */ React6__namespace.default.createElement(ItemSeparatorComponent, { leadingItem: renderedItemInfo.item })));
301
301
  if (maintainVisibleContentPosition) {
302
302
  const anchorStyle = position.type === "top" ? { position: "absolute", top: 0, left: 0, right: 0 } : { position: "absolute", bottom: 0, left: 0, right: 0 };
303
303
  if (ENABLE_DEVMODE) {
@@ -308,6 +308,8 @@ var Container = ({
308
308
  }
309
309
  return /* @__PURE__ */ React6__namespace.default.createElement(LeanView, { style, onLayout, ref }, contentFragment);
310
310
  };
311
+ var typedForwardRef = React6.forwardRef;
312
+ var typedMemo = React6.memo;
311
313
  var useAnimatedValue = (initialValue) => {
312
314
  return React6.useRef(new reactNative.Animated.Value(initialValue)).current;
313
315
  };
@@ -336,7 +338,7 @@ function useValue$(key, getValue, useMicrotask) {
336
338
  }
337
339
 
338
340
  // src/Containers.tsx
339
- var Containers = React6__namespace.memo(function Containers2({
341
+ var Containers = typedMemo(function Containers2({
340
342
  horizontal,
341
343
  recycleItems,
342
344
  ItemSeparatorComponent,
@@ -355,7 +357,7 @@ var Containers = React6__namespace.memo(function Containers2({
355
357
  const containers = [];
356
358
  for (let i = 0; i < numContainers; i++) {
357
359
  containers.push(
358
- /* @__PURE__ */ React6__namespace.createElement(
360
+ /* @__PURE__ */ React.createElement(
359
361
  Container,
360
362
  {
361
363
  id: i,
@@ -370,7 +372,7 @@ var Containers = React6__namespace.memo(function Containers2({
370
372
  );
371
373
  }
372
374
  const style = horizontal ? { width: animSize, opacity: animOpacity } : { height: animSize, opacity: animOpacity };
373
- return /* @__PURE__ */ React6__namespace.createElement(reactNative.Animated.View, { style }, containers);
375
+ return /* @__PURE__ */ React.createElement(reactNative.Animated.View, { style }, containers);
374
376
  });
375
377
 
376
378
  // src/ListComponent.tsx
@@ -434,7 +436,7 @@ var PaddingAndAdjustDevMode = () => {
434
436
  }
435
437
  ));
436
438
  };
437
- var ListComponent = React6__namespace.memo(function ListComponent2({
439
+ var ListComponent = typedMemo(function ListComponent2({
438
440
  style,
439
441
  contentContainerStyle,
440
442
  horizontal,
@@ -455,6 +457,9 @@ var ListComponent = React6__namespace.memo(function ListComponent2({
455
457
  refScrollView,
456
458
  maintainVisibleContentPosition,
457
459
  renderScrollComponent,
460
+ onRefresh,
461
+ refreshing,
462
+ progressViewOffset,
458
463
  ...rest
459
464
  }) {
460
465
  const ctx = useStateContext();
@@ -503,7 +508,7 @@ var ListComponent = React6__namespace.memo(function ListComponent2({
503
508
  recycleItems,
504
509
  waitForInitialLayout,
505
510
  getRenderedItem,
506
- ItemSeparatorComponent: ItemSeparatorComponent && getComponent(ItemSeparatorComponent),
511
+ ItemSeparatorComponent,
507
512
  updateItemSize
508
513
  }
509
514
  ),
@@ -552,7 +557,6 @@ var ScrollAdjustHandler = class {
552
557
  return false;
553
558
  }
554
559
  };
555
- var typedForwardRef = React6.forwardRef;
556
560
  var useCombinedRef = (...refs) => {
557
561
  const callback = React6.useCallback((element) => {
558
562
  for (const ref of refs) {
@@ -752,6 +756,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
752
756
  waitForInitialLayout = true,
753
757
  extraData,
754
758
  onLayout: onLayoutProp,
759
+ onRefresh,
760
+ refreshing,
761
+ progressViewOffset,
755
762
  ...rest
756
763
  } = props;
757
764
  const { style, contentContainerStyle } = props;
@@ -817,13 +824,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
817
824
  positions: /* @__PURE__ */ new Map(),
818
825
  columns: /* @__PURE__ */ new Map(),
819
826
  pendingAdjust: 0,
820
- waitingForMicrotask: false,
821
827
  isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
822
828
  isEndReached: false,
823
829
  isAtBottom: false,
824
830
  isAtTop: false,
825
831
  data: dataProp,
826
- idsInFirstRender: void 0,
827
832
  hasScrolled: false,
828
833
  scrollLength: initialScrollLength,
829
834
  startBuffered: 0,
@@ -852,9 +857,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
852
857
  startReachedBlockedByTimer: false,
853
858
  scrollForNextCalculateItemsInView: void 0,
854
859
  enableScrollForNextCalculateItemsInView: true,
855
- minIndexSizeChanged: 0
860
+ minIndexSizeChanged: 0,
861
+ numPendingInitialLayout: 0
856
862
  };
857
- refState.current.idsInFirstRender = new Set(dataProp.map((_, i) => getId(i)));
858
863
  if (maintainVisibleContentPosition) {
859
864
  if (initialScrollIndex) {
860
865
  refState.current.anchorElement = {
@@ -874,6 +879,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
874
879
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
875
880
  set$(ctx, "extraData", extraData);
876
881
  }
882
+ const didDataChange = refState.current.data !== dataProp;
883
+ refState.current.data = dataProp;
877
884
  const getAnchorElementIndex = () => {
878
885
  const state = refState.current;
879
886
  if (state.anchorElement) {
@@ -985,10 +992,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
985
992
  columns,
986
993
  scrollAdjustHandler
987
994
  } = state;
988
- if (state.waitingForMicrotask) {
989
- state.waitingForMicrotask = false;
990
- }
991
- if (!data) {
995
+ if (!data || scrollLength === 0) {
992
996
  return;
993
997
  }
994
998
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
@@ -1221,7 +1225,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1221
1225
  }
1222
1226
  }
1223
1227
  }
1224
- set$(ctx, "containersDidLayout", true);
1228
+ if (state.numPendingInitialLayout === 0) {
1229
+ state.numPendingInitialLayout = state.endBuffered - state.startBuffered + 1;
1230
+ }
1225
1231
  if (state.viewabilityConfigCallbackPairs) {
1226
1232
  updateViewableItems(
1227
1233
  state,
@@ -1415,12 +1421,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1415
1421
  addTotalSize(null, totalSize, totalSizeBelowIndex);
1416
1422
  };
1417
1423
  const isFirst = !refState.current.renderItem;
1418
- if (isFirst || dataProp !== refState.current.data || numColumnsProp !== peek$(ctx, "numColumns")) {
1419
- if (!keyExtractorProp && !isFirst && dataProp !== refState.current.data) {
1424
+ if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
1425
+ if (!keyExtractorProp && !isFirst && didDataChange) {
1420
1426
  refState.current.sizes.clear();
1421
1427
  refState.current.positions.clear();
1422
1428
  }
1423
- refState.current.data = dataProp;
1424
1429
  calcTotalSizesAndPositions({ forgetPositions: false });
1425
1430
  }
1426
1431
  React6.useEffect(() => {
@@ -1433,17 +1438,22 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1433
1438
  set$(ctx, "extraData", extraData);
1434
1439
  }, [extraData]);
1435
1440
  refState.current.renderItem = renderItem;
1436
- const lastItemKey = dataProp.length > 0 ? getId(dataProp.length - 1) : void 0;
1441
+ const memoizedLastItemKeys = React6.useMemo(() => {
1442
+ if (!dataProp.length) return [];
1443
+ return new Set(
1444
+ Array.from({ length: Math.min(numColumnsProp, dataProp.length) }, (_, i) => getId(dataProp.length - 1 - i))
1445
+ );
1446
+ }, [dataProp.length, numColumnsProp, dataProp.slice(-numColumnsProp).toString()]);
1437
1447
  const stylePaddingTop = (_d = (_c = (_a = reactNative.StyleSheet.flatten(style)) == null ? void 0 : _a.paddingTop) != null ? _c : (_b = reactNative.StyleSheet.flatten(contentContainerStyle)) == null ? void 0 : _b.paddingTop) != null ? _d : 0;
1438
1448
  const initalizeStateVars = () => {
1439
- set$(ctx, "lastItemKey", lastItemKey);
1449
+ set$(ctx, "lastItemKeys", memoizedLastItemKeys);
1440
1450
  set$(ctx, "numColumns", numColumnsProp);
1441
1451
  set$(ctx, "stylePaddingTop", stylePaddingTop);
1442
1452
  };
1443
1453
  if (isFirst) {
1444
1454
  initalizeStateVars();
1445
1455
  }
1446
- React6.useEffect(initalizeStateVars, [lastItemKey, numColumnsProp, stylePaddingTop]);
1456
+ React6.useEffect(initalizeStateVars, [memoizedLastItemKeys, numColumnsProp, stylePaddingTop]);
1447
1457
  const getRenderedItem = React6.useCallback((key) => {
1448
1458
  var _a2, _b2;
1449
1459
  const state = refState.current;
@@ -1475,34 +1485,40 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1475
1485
  useRecyclingEffect: useRecyclingEffect2,
1476
1486
  useRecyclingState: useRecyclingState2
1477
1487
  });
1478
- return { index, renderedItem };
1488
+ return { index, item: data[index], renderedItem };
1479
1489
  }, []);
1480
- useInit(() => {
1490
+ const doInitialAllocateContainers = () => {
1481
1491
  var _a2;
1482
1492
  const state = refState.current;
1483
- const viewability = setupViewability(props);
1484
- state.viewabilityConfigCallbackPairs = viewability;
1485
- state.enableScrollForNextCalculateItemsInView = !viewability;
1486
1493
  const scrollLength = state.scrollLength;
1487
- const averageItemSize = (_a2 = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, dataProp[0])) != null ? _a2 : DEFAULT_ITEM_SIZE;
1488
- const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) * numColumnsProp;
1489
- for (let i = 0; i < numContainers; i++) {
1490
- set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1491
- set$(ctx, `containerColumn${i}`, -1);
1492
- }
1493
- set$(ctx, "numContainers", numContainers);
1494
- set$(ctx, "numContainersPooled", numContainers * 2);
1495
- if (initialScrollIndex) {
1496
- requestAnimationFrame(() => {
1494
+ if (scrollLength > 0 && !peek$(ctx, "numContainers")) {
1495
+ const averageItemSize = (_a2 = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, dataProp[0])) != null ? _a2 : DEFAULT_ITEM_SIZE;
1496
+ const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) * numColumnsProp;
1497
+ for (let i = 0; i < numContainers; i++) {
1498
+ set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1499
+ set$(ctx, `containerColumn${i}`, -1);
1500
+ }
1501
+ set$(ctx, "numContainers", numContainers);
1502
+ set$(ctx, "numContainersPooled", numContainers * 2);
1503
+ if (initialScrollIndex) {
1504
+ requestAnimationFrame(() => {
1505
+ calculateItemsInView(state.scrollVelocity);
1506
+ });
1507
+ } else {
1497
1508
  calculateItemsInView(state.scrollVelocity);
1498
- });
1499
- } else {
1500
- calculateItemsInView(state.scrollVelocity);
1509
+ }
1501
1510
  }
1511
+ };
1512
+ useInit(() => {
1513
+ const state = refState.current;
1514
+ const viewability = setupViewability(props);
1515
+ state.viewabilityConfigCallbackPairs = viewability;
1516
+ state.enableScrollForNextCalculateItemsInView = !viewability;
1517
+ doInitialAllocateContainers();
1502
1518
  });
1503
1519
  const updateItemSize = React6.useCallback((containerId, itemKey, size) => {
1504
1520
  const state = refState.current;
1505
- const { sizes, indexByKey, columns, sizesLaidOut, data, rowHeights } = state;
1521
+ const { sizes, indexByKey, sizesLaidOut, data, rowHeights } = state;
1506
1522
  if (!data) {
1507
1523
  return;
1508
1524
  }
@@ -1510,8 +1526,20 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1510
1526
  const numColumns = peek$(ctx, "numColumns");
1511
1527
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, index) : index;
1512
1528
  const prevSize = getItemSize(itemKey, index, data);
1529
+ let needsCalculate = false;
1530
+ if (state.numPendingInitialLayout > 0) {
1531
+ state.numPendingInitialLayout--;
1532
+ if (state.numPendingInitialLayout === 0) {
1533
+ needsCalculate = true;
1534
+ state.numPendingInitialLayout = -1;
1535
+ queueMicrotask(() => {
1536
+ set$(ctx, "containersDidLayout", true);
1537
+ });
1538
+ }
1539
+ }
1513
1540
  if (!prevSize || Math.abs(prevSize - size) > 0.5) {
1514
1541
  let diff;
1542
+ needsCalculate = true;
1515
1543
  if (numColumns > 1) {
1516
1544
  const rowNumber = Math.floor(index / numColumnsProp);
1517
1545
  const prevSizeInRow = getRowHeight(rowNumber);
@@ -1545,22 +1573,20 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1545
1573
  refState.current.scrollForNextCalculateItemsInView = void 0;
1546
1574
  addTotalSize(itemKey, diff, 0);
1547
1575
  doMaintainScrollAtEnd(true);
1548
- const scrollVelocity = state.scrollVelocity;
1549
- if (!state.waitingForMicrotask && (Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1)) {
1550
- if (!peek$(ctx, "containersDidLayout")) {
1551
- state.waitingForMicrotask = true;
1552
- queueMicrotask(() => {
1553
- if (state.waitingForMicrotask) {
1554
- state.waitingForMicrotask = false;
1555
- calculateItemsInView(state.scrollVelocity);
1556
- }
1557
- });
1558
- } else {
1559
- calculateItemsInView(state.scrollVelocity);
1560
- }
1561
- }
1562
1576
  if (onItemSizeChanged) {
1563
- onItemSizeChanged({ size, previous: prevSize, index, itemKey, itemData: data[index] });
1577
+ onItemSizeChanged({
1578
+ size,
1579
+ previous: prevSize,
1580
+ index,
1581
+ itemKey,
1582
+ itemData: data[index]
1583
+ });
1584
+ }
1585
+ }
1586
+ if (needsCalculate) {
1587
+ const scrollVelocity = state.scrollVelocity;
1588
+ if ((Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1) && (!waitForInitialLayout || state.numPendingInitialLayout < 0)) {
1589
+ calculateItemsInView(state.scrollVelocity);
1564
1590
  }
1565
1591
  }
1566
1592
  }, []);
@@ -1572,7 +1598,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1572
1598
  const onLayout = React6.useCallback((event) => {
1573
1599
  const scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
1574
1600
  const didChange = scrollLength !== refState.current.scrollLength;
1601
+ refState.current.scrollLength;
1575
1602
  refState.current.scrollLength = scrollLength;
1603
+ doInitialAllocateContainers();
1576
1604
  doMaintainScrollAtEnd(false);
1577
1605
  doUpdatePaddingTop();
1578
1606
  checkAtBottom();
@@ -1692,7 +1720,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1692
1720
  scrollToIndex({ index, animated });
1693
1721
  }
1694
1722
  },
1695
- scrollToEnd: () => refScroller.current.scrollToEnd()
1723
+ scrollToEnd: (options) => refScroller.current.scrollToEnd(options)
1696
1724
  };
1697
1725
  },
1698
1726
  []
@@ -1725,6 +1753,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1725
1753
  maintainVisibleContentPosition,
1726
1754
  scrollEventThrottle: scrollEventThrottle != null ? scrollEventThrottle : reactNative.Platform.OS === "web" ? 16 : void 0,
1727
1755
  waitForInitialLayout,
1756
+ refreshControl: props.refreshControl == null ? /* @__PURE__ */ React6__namespace.createElement(
1757
+ reactNative.RefreshControl,
1758
+ {
1759
+ refreshing: !!refreshing,
1760
+ onRefresh,
1761
+ progressViewOffset
1762
+ }
1763
+ ) : props.refreshControl,
1728
1764
  style
1729
1765
  }
1730
1766
  ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React6__namespace.createElement(DebugView, { state: refState.current }));
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);
@@ -203,13 +203,17 @@ var Container = ({
203
203
  const position = use$(`containerPosition${id}`) || ANCHORED_POSITION_OUT_OF_VIEW;
204
204
  const column = use$(`containerColumn${id}`) || 0;
205
205
  const numColumns = use$("numColumns");
206
+ const lastItemKeys = use$("lastItemKeys");
207
+ const itemKey = use$(`containerItemKey${id}`);
208
+ const data = use$(`containerItemData${id}`);
209
+ const extraData = use$("extraData");
206
210
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
207
211
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
208
212
  let verticalPaddingStyles;
209
213
  if (columnWrapperStyle && !horizontal && numColumns > 1) {
210
214
  const { columnGap, rowGap, gap } = columnWrapperStyle;
211
215
  verticalPaddingStyles = {
212
- paddingVertical: rowGap || gap || void 0,
216
+ paddingBottom: !lastItemKeys.has(itemKey) ? rowGap || gap || void 0 : void 0,
213
217
  // Apply horizontal padding based on column position (first, middle, or last)
214
218
  paddingLeft: column > 1 ? (columnGap || gap || 0) / 2 : void 0,
215
219
  paddingRight: column < numColumns ? (columnGap || gap || 0) / 2 : void 0
@@ -230,12 +234,8 @@ var Container = ({
230
234
  top: position.relativeCoordinate,
231
235
  ...verticalPaddingStyles || {}
232
236
  };
233
- const lastItemKey = use$("lastItemKey");
234
- const itemKey = use$(`containerItemKey${id}`);
235
- const data = use$(`containerItemData${id}`);
236
- const extraData = use$("extraData");
237
237
  const renderedItemInfo = useMemo(
238
- () => itemKey !== void 0 && getRenderedItem(itemKey),
238
+ () => itemKey !== void 0 ? getRenderedItem(itemKey) : null,
239
239
  [itemKey, data, extraData]
240
240
  );
241
241
  const { index, renderedItem } = renderedItemInfo || {};
@@ -244,7 +244,7 @@ var Container = ({
244
244
  const layout = event.nativeEvent.layout;
245
245
  const size = Math.floor(layout[horizontal ? "width" : "height"] * 8) / 8;
246
246
  if (size === 0) {
247
- if (layout.y !== POSITION_OUT_OF_VIEW && layout.y !== POSITION_OUT_OF_VIEW) {
247
+ if (layout.x !== POSITION_OUT_OF_VIEW && layout.y !== POSITION_OUT_OF_VIEW) {
248
248
  console.log(
249
249
  "[WARN] Container 0 height reported, possible bug in LegendList",
250
250
  id,
@@ -276,7 +276,7 @@ var Container = ({
276
276
  () => ({ containerId: id, itemKey, index, value: data }),
277
277
  [id, itemKey, index, data]
278
278
  );
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));
279
+ 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
280
  if (maintainVisibleContentPosition) {
281
281
  const anchorStyle = position.type === "top" ? { position: "absolute", top: 0, left: 0, right: 0 } : { position: "absolute", bottom: 0, left: 0, right: 0 };
282
282
  if (ENABLE_DEVMODE) {
@@ -287,6 +287,8 @@ var Container = ({
287
287
  }
288
288
  return /* @__PURE__ */ React6__default.createElement(LeanView, { style, onLayout, ref }, contentFragment);
289
289
  };
290
+ var typedForwardRef = forwardRef;
291
+ var typedMemo = memo;
290
292
  var useAnimatedValue = (initialValue) => {
291
293
  return useRef(new Animated.Value(initialValue)).current;
292
294
  };
@@ -315,7 +317,7 @@ function useValue$(key, getValue, useMicrotask) {
315
317
  }
316
318
 
317
319
  // src/Containers.tsx
318
- var Containers = React6.memo(function Containers2({
320
+ var Containers = typedMemo(function Containers2({
319
321
  horizontal,
320
322
  recycleItems,
321
323
  ItemSeparatorComponent,
@@ -334,7 +336,7 @@ var Containers = React6.memo(function Containers2({
334
336
  const containers = [];
335
337
  for (let i = 0; i < numContainers; i++) {
336
338
  containers.push(
337
- /* @__PURE__ */ React6.createElement(
339
+ /* @__PURE__ */ React.createElement(
338
340
  Container,
339
341
  {
340
342
  id: i,
@@ -349,7 +351,7 @@ var Containers = React6.memo(function Containers2({
349
351
  );
350
352
  }
351
353
  const style = horizontal ? { width: animSize, opacity: animOpacity } : { height: animSize, opacity: animOpacity };
352
- return /* @__PURE__ */ React6.createElement(Animated.View, { style }, containers);
354
+ return /* @__PURE__ */ React.createElement(Animated.View, { style }, containers);
353
355
  });
354
356
 
355
357
  // src/ListComponent.tsx
@@ -413,7 +415,7 @@ var PaddingAndAdjustDevMode = () => {
413
415
  }
414
416
  ));
415
417
  };
416
- var ListComponent = React6.memo(function ListComponent2({
418
+ var ListComponent = typedMemo(function ListComponent2({
417
419
  style,
418
420
  contentContainerStyle,
419
421
  horizontal,
@@ -434,6 +436,9 @@ var ListComponent = React6.memo(function ListComponent2({
434
436
  refScrollView,
435
437
  maintainVisibleContentPosition,
436
438
  renderScrollComponent,
439
+ onRefresh,
440
+ refreshing,
441
+ progressViewOffset,
437
442
  ...rest
438
443
  }) {
439
444
  const ctx = useStateContext();
@@ -482,7 +487,7 @@ var ListComponent = React6.memo(function ListComponent2({
482
487
  recycleItems,
483
488
  waitForInitialLayout,
484
489
  getRenderedItem,
485
- ItemSeparatorComponent: ItemSeparatorComponent && getComponent(ItemSeparatorComponent),
490
+ ItemSeparatorComponent,
486
491
  updateItemSize
487
492
  }
488
493
  ),
@@ -531,7 +536,6 @@ var ScrollAdjustHandler = class {
531
536
  return false;
532
537
  }
533
538
  };
534
- var typedForwardRef = forwardRef;
535
539
  var useCombinedRef = (...refs) => {
536
540
  const callback = useCallback((element) => {
537
541
  for (const ref of refs) {
@@ -731,6 +735,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
731
735
  waitForInitialLayout = true,
732
736
  extraData,
733
737
  onLayout: onLayoutProp,
738
+ onRefresh,
739
+ refreshing,
740
+ progressViewOffset,
734
741
  ...rest
735
742
  } = props;
736
743
  const { style, contentContainerStyle } = props;
@@ -796,13 +803,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
796
803
  positions: /* @__PURE__ */ new Map(),
797
804
  columns: /* @__PURE__ */ new Map(),
798
805
  pendingAdjust: 0,
799
- waitingForMicrotask: false,
800
806
  isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
801
807
  isEndReached: false,
802
808
  isAtBottom: false,
803
809
  isAtTop: false,
804
810
  data: dataProp,
805
- idsInFirstRender: void 0,
806
811
  hasScrolled: false,
807
812
  scrollLength: initialScrollLength,
808
813
  startBuffered: 0,
@@ -831,9 +836,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
831
836
  startReachedBlockedByTimer: false,
832
837
  scrollForNextCalculateItemsInView: void 0,
833
838
  enableScrollForNextCalculateItemsInView: true,
834
- minIndexSizeChanged: 0
839
+ minIndexSizeChanged: 0,
840
+ numPendingInitialLayout: 0
835
841
  };
836
- refState.current.idsInFirstRender = new Set(dataProp.map((_, i) => getId(i)));
837
842
  if (maintainVisibleContentPosition) {
838
843
  if (initialScrollIndex) {
839
844
  refState.current.anchorElement = {
@@ -853,6 +858,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
853
858
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
854
859
  set$(ctx, "extraData", extraData);
855
860
  }
861
+ const didDataChange = refState.current.data !== dataProp;
862
+ refState.current.data = dataProp;
856
863
  const getAnchorElementIndex = () => {
857
864
  const state = refState.current;
858
865
  if (state.anchorElement) {
@@ -964,10 +971,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
964
971
  columns,
965
972
  scrollAdjustHandler
966
973
  } = state;
967
- if (state.waitingForMicrotask) {
968
- state.waitingForMicrotask = false;
969
- }
970
- if (!data) {
974
+ if (!data || scrollLength === 0) {
971
975
  return;
972
976
  }
973
977
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
@@ -1200,7 +1204,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1200
1204
  }
1201
1205
  }
1202
1206
  }
1203
- set$(ctx, "containersDidLayout", true);
1207
+ if (state.numPendingInitialLayout === 0) {
1208
+ state.numPendingInitialLayout = state.endBuffered - state.startBuffered + 1;
1209
+ }
1204
1210
  if (state.viewabilityConfigCallbackPairs) {
1205
1211
  updateViewableItems(
1206
1212
  state,
@@ -1394,12 +1400,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1394
1400
  addTotalSize(null, totalSize, totalSizeBelowIndex);
1395
1401
  };
1396
1402
  const isFirst = !refState.current.renderItem;
1397
- if (isFirst || dataProp !== refState.current.data || numColumnsProp !== peek$(ctx, "numColumns")) {
1398
- if (!keyExtractorProp && !isFirst && dataProp !== refState.current.data) {
1403
+ if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
1404
+ if (!keyExtractorProp && !isFirst && didDataChange) {
1399
1405
  refState.current.sizes.clear();
1400
1406
  refState.current.positions.clear();
1401
1407
  }
1402
- refState.current.data = dataProp;
1403
1408
  calcTotalSizesAndPositions({ forgetPositions: false });
1404
1409
  }
1405
1410
  useEffect(() => {
@@ -1412,17 +1417,22 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1412
1417
  set$(ctx, "extraData", extraData);
1413
1418
  }, [extraData]);
1414
1419
  refState.current.renderItem = renderItem;
1415
- const lastItemKey = dataProp.length > 0 ? getId(dataProp.length - 1) : void 0;
1420
+ const memoizedLastItemKeys = useMemo(() => {
1421
+ if (!dataProp.length) return [];
1422
+ return new Set(
1423
+ Array.from({ length: Math.min(numColumnsProp, dataProp.length) }, (_, i) => getId(dataProp.length - 1 - i))
1424
+ );
1425
+ }, [dataProp.length, numColumnsProp, dataProp.slice(-numColumnsProp).toString()]);
1416
1426
  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
1427
  const initalizeStateVars = () => {
1418
- set$(ctx, "lastItemKey", lastItemKey);
1428
+ set$(ctx, "lastItemKeys", memoizedLastItemKeys);
1419
1429
  set$(ctx, "numColumns", numColumnsProp);
1420
1430
  set$(ctx, "stylePaddingTop", stylePaddingTop);
1421
1431
  };
1422
1432
  if (isFirst) {
1423
1433
  initalizeStateVars();
1424
1434
  }
1425
- useEffect(initalizeStateVars, [lastItemKey, numColumnsProp, stylePaddingTop]);
1435
+ useEffect(initalizeStateVars, [memoizedLastItemKeys, numColumnsProp, stylePaddingTop]);
1426
1436
  const getRenderedItem = useCallback((key) => {
1427
1437
  var _a2, _b2;
1428
1438
  const state = refState.current;
@@ -1454,34 +1464,40 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1454
1464
  useRecyclingEffect: useRecyclingEffect2,
1455
1465
  useRecyclingState: useRecyclingState2
1456
1466
  });
1457
- return { index, renderedItem };
1467
+ return { index, item: data[index], renderedItem };
1458
1468
  }, []);
1459
- useInit(() => {
1469
+ const doInitialAllocateContainers = () => {
1460
1470
  var _a2;
1461
1471
  const state = refState.current;
1462
- const viewability = setupViewability(props);
1463
- state.viewabilityConfigCallbackPairs = viewability;
1464
- state.enableScrollForNextCalculateItemsInView = !viewability;
1465
1472
  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(() => {
1473
+ if (scrollLength > 0 && !peek$(ctx, "numContainers")) {
1474
+ const averageItemSize = (_a2 = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, dataProp[0])) != null ? _a2 : DEFAULT_ITEM_SIZE;
1475
+ const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) * numColumnsProp;
1476
+ for (let i = 0; i < numContainers; i++) {
1477
+ set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1478
+ set$(ctx, `containerColumn${i}`, -1);
1479
+ }
1480
+ set$(ctx, "numContainers", numContainers);
1481
+ set$(ctx, "numContainersPooled", numContainers * 2);
1482
+ if (initialScrollIndex) {
1483
+ requestAnimationFrame(() => {
1484
+ calculateItemsInView(state.scrollVelocity);
1485
+ });
1486
+ } else {
1476
1487
  calculateItemsInView(state.scrollVelocity);
1477
- });
1478
- } else {
1479
- calculateItemsInView(state.scrollVelocity);
1488
+ }
1480
1489
  }
1490
+ };
1491
+ useInit(() => {
1492
+ const state = refState.current;
1493
+ const viewability = setupViewability(props);
1494
+ state.viewabilityConfigCallbackPairs = viewability;
1495
+ state.enableScrollForNextCalculateItemsInView = !viewability;
1496
+ doInitialAllocateContainers();
1481
1497
  });
1482
1498
  const updateItemSize = useCallback((containerId, itemKey, size) => {
1483
1499
  const state = refState.current;
1484
- const { sizes, indexByKey, columns, sizesLaidOut, data, rowHeights } = state;
1500
+ const { sizes, indexByKey, sizesLaidOut, data, rowHeights } = state;
1485
1501
  if (!data) {
1486
1502
  return;
1487
1503
  }
@@ -1489,8 +1505,20 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1489
1505
  const numColumns = peek$(ctx, "numColumns");
1490
1506
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, index) : index;
1491
1507
  const prevSize = getItemSize(itemKey, index, data);
1508
+ let needsCalculate = false;
1509
+ if (state.numPendingInitialLayout > 0) {
1510
+ state.numPendingInitialLayout--;
1511
+ if (state.numPendingInitialLayout === 0) {
1512
+ needsCalculate = true;
1513
+ state.numPendingInitialLayout = -1;
1514
+ queueMicrotask(() => {
1515
+ set$(ctx, "containersDidLayout", true);
1516
+ });
1517
+ }
1518
+ }
1492
1519
  if (!prevSize || Math.abs(prevSize - size) > 0.5) {
1493
1520
  let diff;
1521
+ needsCalculate = true;
1494
1522
  if (numColumns > 1) {
1495
1523
  const rowNumber = Math.floor(index / numColumnsProp);
1496
1524
  const prevSizeInRow = getRowHeight(rowNumber);
@@ -1524,22 +1552,20 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1524
1552
  refState.current.scrollForNextCalculateItemsInView = void 0;
1525
1553
  addTotalSize(itemKey, diff, 0);
1526
1554
  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
1555
  if (onItemSizeChanged) {
1542
- onItemSizeChanged({ size, previous: prevSize, index, itemKey, itemData: data[index] });
1556
+ onItemSizeChanged({
1557
+ size,
1558
+ previous: prevSize,
1559
+ index,
1560
+ itemKey,
1561
+ itemData: data[index]
1562
+ });
1563
+ }
1564
+ }
1565
+ if (needsCalculate) {
1566
+ const scrollVelocity = state.scrollVelocity;
1567
+ if ((Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1) && (!waitForInitialLayout || state.numPendingInitialLayout < 0)) {
1568
+ calculateItemsInView(state.scrollVelocity);
1543
1569
  }
1544
1570
  }
1545
1571
  }, []);
@@ -1551,7 +1577,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1551
1577
  const onLayout = useCallback((event) => {
1552
1578
  const scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
1553
1579
  const didChange = scrollLength !== refState.current.scrollLength;
1580
+ refState.current.scrollLength;
1554
1581
  refState.current.scrollLength = scrollLength;
1582
+ doInitialAllocateContainers();
1555
1583
  doMaintainScrollAtEnd(false);
1556
1584
  doUpdatePaddingTop();
1557
1585
  checkAtBottom();
@@ -1671,7 +1699,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1671
1699
  scrollToIndex({ index, animated });
1672
1700
  }
1673
1701
  },
1674
- scrollToEnd: () => refScroller.current.scrollToEnd()
1702
+ scrollToEnd: (options) => refScroller.current.scrollToEnd(options)
1675
1703
  };
1676
1704
  },
1677
1705
  []
@@ -1704,6 +1732,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1704
1732
  maintainVisibleContentPosition,
1705
1733
  scrollEventThrottle: scrollEventThrottle != null ? scrollEventThrottle : Platform.OS === "web" ? 16 : void 0,
1706
1734
  waitForInitialLayout,
1735
+ refreshControl: props.refreshControl == null ? /* @__PURE__ */ React6.createElement(
1736
+ RefreshControl,
1737
+ {
1738
+ refreshing: !!refreshing,
1739
+ onRefresh,
1740
+ progressViewOffset
1741
+ }
1742
+ ) : props.refreshControl,
1707
1743
  style
1708
1744
  }
1709
1745
  ), __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.17",
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>;