@legendapp/list 1.0.15 → 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/CHANGELOG.md CHANGED
@@ -1,3 +1,24 @@
1
+ ## 1.0.16
2
+ - Fix: isAtEnd was going to false when overscrolling
3
+ - Fix: refreshControl not being top padded correctly
4
+ - Fix: type of useLastItem hook
5
+ - Fix: header component was not displaying if a list had no data
6
+ - Fix: scrollToIndex logic that fixes scroll after items layout was not using viewPosition/viewOffset
7
+ - Fix: Improve scrollToIndex accuracy
8
+ - Fix: Improve scrollToEnd accuracy
9
+
10
+ ## 1.0.15
11
+ - Feat: Add a useIsLastItem hook
12
+ - Feat: Support horizontal lists without an intrinsic height, it takes the maximum height of list items
13
+ - Feat: Add onLoad prop
14
+ - Fix: maintainVisibleContentPosition not working on horizontal lists
15
+ - Perf: scrollForNextCalculateItemsInView was not taking drawDistance into account correctly
16
+ - Perf: Improved the algorithm for allocating containers to items
17
+ - Perf: Use useLayoutEffect in LegendList if available to get the outer ScrollView layout as soon as possible
18
+
19
+ ## 1.0.14
20
+ - Fix: A container changing size while inactive but not yet recycled could potentially overlap with elements onscreen if large enough
21
+
1
22
  ## 1.0.13
2
23
  - Fix: Missing React import in ListHeaderComponentContainer crashing some environments
3
24
  - Fix: `initialScrollIndex` was off by padding if using "padding" or "paddingVertical" props
package/animated.d.mts CHANGED
@@ -3,7 +3,7 @@ import * as _legendapp_list from '@legendapp/list';
3
3
  import * as react_native from 'react-native';
4
4
  import { Animated } from 'react-native';
5
5
 
6
- declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "maintainVisibleContentPosition" | "removeClippedSubviews" | "stickyHeaderIndices" | "contentInset" | "contentOffset"> & {
6
+ declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews"> & {
7
7
  alignItemsAtEnd?: boolean;
8
8
  columnWrapperStyle?: _legendapp_list.ColumnWrapperStyle;
9
9
  data: readonly T[];
@@ -48,7 +48,7 @@ declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: Omit<Om
48
48
  recycleItems?: boolean;
49
49
  refScrollView?: React.Ref<react_native.ScrollView>;
50
50
  refreshing?: boolean;
51
- renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<T>) => React$1.ReactNode) | undefined;
51
+ renderItem?: React$1.ComponentType<_legendapp_list.LegendListRenderItemProps<T>> | ((props: _legendapp_list.LegendListRenderItemProps<T>) => React$1.ReactNode) | undefined;
52
52
  renderScrollComponent?: (props: react_native.ScrollViewProps) => React.ReactElement<react_native.ScrollViewProps>;
53
53
  suggestEstimatedItemSize?: boolean;
54
54
  viewabilityConfig?: _legendapp_list.ViewabilityConfig;
package/animated.d.ts CHANGED
@@ -3,7 +3,7 @@ import * as _legendapp_list from '@legendapp/list';
3
3
  import * as react_native from 'react-native';
4
4
  import { Animated } from 'react-native';
5
5
 
6
- declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "maintainVisibleContentPosition" | "removeClippedSubviews" | "stickyHeaderIndices" | "contentInset" | "contentOffset"> & {
6
+ declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews"> & {
7
7
  alignItemsAtEnd?: boolean;
8
8
  columnWrapperStyle?: _legendapp_list.ColumnWrapperStyle;
9
9
  data: readonly T[];
@@ -48,7 +48,7 @@ declare const AnimatedLegendList: Animated.AnimatedComponent<(<T>(props: Omit<Om
48
48
  recycleItems?: boolean;
49
49
  refScrollView?: React.Ref<react_native.ScrollView>;
50
50
  refreshing?: boolean;
51
- renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<T>) => React$1.ReactNode) | undefined;
51
+ renderItem?: React$1.ComponentType<_legendapp_list.LegendListRenderItemProps<T>> | ((props: _legendapp_list.LegendListRenderItemProps<T>) => React$1.ReactNode) | undefined;
52
52
  renderScrollComponent?: (props: react_native.ScrollViewProps) => React.ReactElement<react_native.ScrollViewProps>;
53
53
  suggestEstimatedItemSize?: boolean;
54
54
  viewabilityConfig?: _legendapp_list.ViewabilityConfig;
package/index.d.mts CHANGED
@@ -180,10 +180,13 @@ type LegendListPropsBase<ItemT, TScrollView extends ComponentProps<typeof Scroll
180
180
  */
181
181
  refreshing?: boolean;
182
182
  /**
183
- * Function to render each item in the list.
183
+ * Function or React component to render each item in the list.
184
+ * Can be either:
185
+ * - A function: (props: LegendListRenderItemProps<ItemT>) => ReactNode
186
+ * - A React component: React.ComponentType<LegendListRenderItemProps<ItemT>>
184
187
  * @required
185
188
  */
186
- renderItem?: (props: LegendListRenderItemProps<ItemT>) => ReactNode;
189
+ renderItem?: ((props: LegendListRenderItemProps<ItemT>) => ReactNode) | React.ComponentType<LegendListRenderItemProps<ItemT>>;
187
190
  /**
188
191
  * Render custom ScrollView component.
189
192
  * @default (props) => <ScrollView {...props} />
@@ -237,8 +240,8 @@ interface InternalState {
237
240
  pendingAdjust: number;
238
241
  isStartReached: boolean;
239
242
  isEndReached: boolean;
240
- isAtBottom: boolean;
241
- isAtTop: boolean;
243
+ isAtEnd: boolean;
244
+ isAtStart: boolean;
242
245
  data: readonly any[];
243
246
  hasScrolled?: boolean;
244
247
  scrollLength: number;
@@ -262,7 +265,7 @@ interface InternalState {
262
265
  nativeMarginTop: number;
263
266
  indexByKey: Map<string, number>;
264
267
  viewabilityConfigCallbackPairs: ViewabilityConfigCallbackPairs | undefined;
265
- renderItem: (props: LegendListRenderItemProps<any>) => ReactNode;
268
+ renderItem: ((props: LegendListRenderItemProps<any>) => ReactNode) | React.ComponentType<LegendListRenderItemProps<any>>;
266
269
  scrollHistory: Array<{
267
270
  scroll: number;
268
271
  time: number;
@@ -281,7 +284,13 @@ interface InternalState {
281
284
  lastBatchingAction: number;
282
285
  ignoreScrollFromCalcTotal?: boolean;
283
286
  disableScrollJumpsFrom?: number;
284
- scrollingToOffset?: number | undefined;
287
+ scrollingTo?: {
288
+ offset: number;
289
+ index?: number;
290
+ viewOffset?: number;
291
+ viewPosition?: number;
292
+ animated?: boolean;
293
+ } | undefined;
285
294
  previousTotalSize?: number;
286
295
  needsOtherAxisSize?: boolean;
287
296
  averageSizes: Record<string, {
@@ -468,7 +477,7 @@ type TypedMemo = <T extends React.ComponentType<any>>(Component: T, propsAreEqua
468
477
  };
469
478
  declare const typedMemo: TypedMemo;
470
479
 
471
- declare const LegendList: <T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "maintainVisibleContentPosition" | "removeClippedSubviews" | "stickyHeaderIndices" | "contentInset" | "contentOffset"> & {
480
+ declare const LegendList: <T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews"> & {
472
481
  alignItemsAtEnd?: boolean;
473
482
  columnWrapperStyle?: ColumnWrapperStyle;
474
483
  data: readonly T[];
@@ -513,7 +522,7 @@ declare const LegendList: <T>(props: Omit<Omit<react_native.ScrollViewProps, "sc
513
522
  recycleItems?: boolean;
514
523
  refScrollView?: React$1.Ref<ScrollView>;
515
524
  refreshing?: boolean;
516
- renderItem?: ((props: LegendListRenderItemProps<T>) => React$1.ReactNode) | undefined;
525
+ renderItem?: React$1.ComponentType<LegendListRenderItemProps<T>> | ((props: LegendListRenderItemProps<T>) => React$1.ReactNode) | undefined;
517
526
  renderScrollComponent?: (props: react_native.ScrollViewProps) => React$1.ReactElement<react_native.ScrollViewProps>;
518
527
  suggestEstimatedItemSize?: boolean;
519
528
  viewabilityConfig?: ViewabilityConfig;
@@ -528,6 +537,6 @@ declare function useViewability(callback: ViewabilityCallback, configId?: string
528
537
  declare function useViewabilityAmount(callback: ViewabilityAmountCallback): void;
529
538
  declare function useRecyclingEffect(effect: (info: LegendListRecyclingState<unknown>) => void | (() => void)): void;
530
539
  declare function useRecyclingState<ItemT>(valueOrFun: ((info: LegendListRecyclingState<ItemT>) => ItemT) | ItemT): readonly [ItemT | null, Dispatch<SetStateAction<ItemT>>];
531
- declare function useIsLastItem(): any;
540
+ declare function useIsLastItem(): boolean;
532
541
 
533
542
  export { type AnchoredPosition, type ColumnWrapperStyle, type InternalState, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type OnViewableItemsChanged, type ScrollState, type TypedForwardRef, type TypedMemo, type ViewAmountToken, type ViewToken, type ViewabilityAmountCallback, type ViewabilityCallback, type ViewabilityConfig, type ViewabilityConfigCallbackPair, type ViewabilityConfigCallbackPairs, type ViewableRange, typedForwardRef, typedMemo, useIsLastItem, useRecyclingEffect, useRecyclingState, useViewability, useViewabilityAmount };
package/index.d.ts CHANGED
@@ -180,10 +180,13 @@ type LegendListPropsBase<ItemT, TScrollView extends ComponentProps<typeof Scroll
180
180
  */
181
181
  refreshing?: boolean;
182
182
  /**
183
- * Function to render each item in the list.
183
+ * Function or React component to render each item in the list.
184
+ * Can be either:
185
+ * - A function: (props: LegendListRenderItemProps<ItemT>) => ReactNode
186
+ * - A React component: React.ComponentType<LegendListRenderItemProps<ItemT>>
184
187
  * @required
185
188
  */
186
- renderItem?: (props: LegendListRenderItemProps<ItemT>) => ReactNode;
189
+ renderItem?: ((props: LegendListRenderItemProps<ItemT>) => ReactNode) | React.ComponentType<LegendListRenderItemProps<ItemT>>;
187
190
  /**
188
191
  * Render custom ScrollView component.
189
192
  * @default (props) => <ScrollView {...props} />
@@ -237,8 +240,8 @@ interface InternalState {
237
240
  pendingAdjust: number;
238
241
  isStartReached: boolean;
239
242
  isEndReached: boolean;
240
- isAtBottom: boolean;
241
- isAtTop: boolean;
243
+ isAtEnd: boolean;
244
+ isAtStart: boolean;
242
245
  data: readonly any[];
243
246
  hasScrolled?: boolean;
244
247
  scrollLength: number;
@@ -262,7 +265,7 @@ interface InternalState {
262
265
  nativeMarginTop: number;
263
266
  indexByKey: Map<string, number>;
264
267
  viewabilityConfigCallbackPairs: ViewabilityConfigCallbackPairs | undefined;
265
- renderItem: (props: LegendListRenderItemProps<any>) => ReactNode;
268
+ renderItem: ((props: LegendListRenderItemProps<any>) => ReactNode) | React.ComponentType<LegendListRenderItemProps<any>>;
266
269
  scrollHistory: Array<{
267
270
  scroll: number;
268
271
  time: number;
@@ -281,7 +284,13 @@ interface InternalState {
281
284
  lastBatchingAction: number;
282
285
  ignoreScrollFromCalcTotal?: boolean;
283
286
  disableScrollJumpsFrom?: number;
284
- scrollingToOffset?: number | undefined;
287
+ scrollingTo?: {
288
+ offset: number;
289
+ index?: number;
290
+ viewOffset?: number;
291
+ viewPosition?: number;
292
+ animated?: boolean;
293
+ } | undefined;
285
294
  previousTotalSize?: number;
286
295
  needsOtherAxisSize?: boolean;
287
296
  averageSizes: Record<string, {
@@ -468,7 +477,7 @@ type TypedMemo = <T extends React.ComponentType<any>>(Component: T, propsAreEqua
468
477
  };
469
478
  declare const typedMemo: TypedMemo;
470
479
 
471
- declare const LegendList: <T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "maintainVisibleContentPosition" | "removeClippedSubviews" | "stickyHeaderIndices" | "contentInset" | "contentOffset"> & {
480
+ declare const LegendList: <T>(props: Omit<Omit<react_native.ScrollViewProps, "scrollEventThrottle">, "contentOffset" | "contentInset" | "maintainVisibleContentPosition" | "stickyHeaderIndices" | "removeClippedSubviews"> & {
472
481
  alignItemsAtEnd?: boolean;
473
482
  columnWrapperStyle?: ColumnWrapperStyle;
474
483
  data: readonly T[];
@@ -513,7 +522,7 @@ declare const LegendList: <T>(props: Omit<Omit<react_native.ScrollViewProps, "sc
513
522
  recycleItems?: boolean;
514
523
  refScrollView?: React$1.Ref<ScrollView>;
515
524
  refreshing?: boolean;
516
- renderItem?: ((props: LegendListRenderItemProps<T>) => React$1.ReactNode) | undefined;
525
+ renderItem?: React$1.ComponentType<LegendListRenderItemProps<T>> | ((props: LegendListRenderItemProps<T>) => React$1.ReactNode) | undefined;
517
526
  renderScrollComponent?: (props: react_native.ScrollViewProps) => React$1.ReactElement<react_native.ScrollViewProps>;
518
527
  suggestEstimatedItemSize?: boolean;
519
528
  viewabilityConfig?: ViewabilityConfig;
@@ -528,6 +537,6 @@ declare function useViewability(callback: ViewabilityCallback, configId?: string
528
537
  declare function useViewabilityAmount(callback: ViewabilityAmountCallback): void;
529
538
  declare function useRecyclingEffect(effect: (info: LegendListRecyclingState<unknown>) => void | (() => void)): void;
530
539
  declare function useRecyclingState<ItemT>(valueOrFun: ((info: LegendListRecyclingState<ItemT>) => ItemT) | ItemT): readonly [ItemT | null, Dispatch<SetStateAction<ItemT>>];
531
- declare function useIsLastItem(): any;
540
+ declare function useIsLastItem(): boolean;
532
541
 
533
542
  export { type AnchoredPosition, type ColumnWrapperStyle, type InternalState, LegendList, type LegendListProps, type LegendListPropsBase, type LegendListRecyclingState, type LegendListRef, type LegendListRenderItemProps, type OnViewableItemsChanged, type ScrollState, type TypedForwardRef, type TypedMemo, type ViewAmountToken, type ViewToken, type ViewabilityAmountCallback, type ViewabilityCallback, type ViewabilityConfig, type ViewabilityConfigCallbackPair, type ViewabilityConfigCallbackPairs, type ViewableRange, typedForwardRef, typedMemo, useIsLastItem, useRecyclingEffect, useRecyclingState, useViewability, useViewabilityAmount };
package/index.js CHANGED
@@ -173,7 +173,7 @@ var DebugView = React2__namespace.memo(function DebugView2({ state }) {
173
173
  },
174
174
  /* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, "TotalSize:"), /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, totalSize.toFixed(2))),
175
175
  /* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, "ContentSize:"), /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, contentSize.toFixed(2))),
176
- /* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, "At end:"), /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, String(state.isAtBottom))),
176
+ /* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, "At end:"), /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, String(state.isAtEnd))),
177
177
  /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null),
178
178
  /* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, "ScrollAdjust:"), /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, scrollAdjust.toFixed(2))),
179
179
  /* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, "TotalSizeReal: "), /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, totalSizeWithScrollAdjust.toFixed(2))),
@@ -200,9 +200,6 @@ function warnDevOnce(id, text) {
200
200
  console.warn(`[legend-list] ${text}`);
201
201
  }
202
202
  }
203
- function roundSize(size) {
204
- return Math.floor(size * 8) / 8;
205
- }
206
203
  function isNullOrUndefined(value) {
207
204
  return value === null || value === void 0;
208
205
  }
@@ -565,11 +562,14 @@ function ListHeaderComponentContainer({
565
562
  horizontal,
566
563
  waitForInitialLayout
567
564
  }) {
568
- const scrollAdjust = useValue$("scrollAdjust", (v) => v, true);
565
+ var _a;
566
+ const hasData = ((_a = peek$(ctx, "lastItemKeys")) == null ? void 0 : _a.length) > 0;
567
+ const scrollAdjust = useValue$("scrollAdjust", (v) => v != null ? v : 0, true);
569
568
  const animOpacity = waitForInitialLayout ? useValue$("containersDidLayout", (value) => value ? 1 : 0) : void 0;
570
569
  const additionalSize = {
571
570
  transform: [{ translateY: reactNative.Animated.multiply(scrollAdjust, -1) }],
572
- opacity: animOpacity
571
+ // Header should show if there's no data yet, but containersDidLayout will be false until it has some data
572
+ opacity: hasData ? animOpacity : 1
573
573
  };
574
574
  return /* @__PURE__ */ React2__namespace.createElement(
575
575
  reactNative.Animated.View,
@@ -666,9 +666,6 @@ var ListComponent = typedMemo(function ListComponent2({
666
666
  refScrollView,
667
667
  maintainVisibleContentPosition,
668
668
  renderScrollComponent,
669
- onRefresh,
670
- refreshing,
671
- progressViewOffset,
672
669
  ...rest
673
670
  }) {
674
671
  const ctx = useStateContext();
@@ -1077,20 +1074,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1077
1074
  };
1078
1075
  const getItemSize = (key, index, data, useAverageSize = false) => {
1079
1076
  const state = refState.current;
1080
- const sizeKnown = state.sizesKnown.get(key);
1077
+ state.sizesKnown.get(key);
1081
1078
  const sizePrevious = state.sizes.get(key);
1082
1079
  let size;
1083
- const numColumns = peek$(ctx, "numColumns");
1084
- if (sizeKnown === void 0 && !getEstimatedItemSize && numColumns === 1 && useAverageSize) {
1085
- const itemType = "";
1086
- const average = state.averageSizes[itemType];
1087
- if (average) {
1088
- size = roundSize(average.avg);
1089
- if (size !== sizePrevious) {
1090
- addTotalSize(key, size - sizePrevious, 0);
1091
- }
1092
- }
1093
- }
1080
+ peek$(ctx, "numColumns");
1094
1081
  if (size === void 0 && sizePrevious !== void 0) {
1095
1082
  return sizePrevious;
1096
1083
  }
@@ -1111,7 +1098,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1111
1098
  if (canGetSize || getEstimatedItemSize) {
1112
1099
  const sizeFn = (index2) => {
1113
1100
  if (canGetSize) {
1114
- return getItemSize(getId(index2), index2, data[index2]);
1101
+ return getItemSize(getId(index2), index2, data[index2], true);
1115
1102
  }
1116
1103
  return getEstimatedItemSize(index2, data[index2]);
1117
1104
  };
@@ -1138,8 +1125,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1138
1125
  pendingAdjust: 0,
1139
1126
  isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
1140
1127
  isEndReached: false,
1141
- isAtBottom: false,
1142
- isAtTop: false,
1128
+ isAtEnd: false,
1129
+ isAtStart: false,
1143
1130
  data: dataProp,
1144
1131
  scrollLength: initialScrollLength,
1145
1132
  startBuffered: -1,
@@ -1224,6 +1211,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1224
1211
  index = 0;
1225
1212
  }
1226
1213
  const firstIndexOffset = calculateOffsetForIndex(index);
1214
+ const isLast = index === state.data.length - 1;
1215
+ if (isLast && viewPosition !== void 0) {
1216
+ viewPosition = 1;
1217
+ }
1227
1218
  let firstIndexScrollPostion = firstIndexOffset - viewOffset;
1228
1219
  const diff = Math.abs(state.scroll - firstIndexScrollPostion);
1229
1220
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
@@ -1239,10 +1230,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1239
1230
  state.minIndexSizeChanged = index;
1240
1231
  firstIndexScrollPostion = firstIndexOffset - viewOffset + state.scrollAdjustHandler.getAppliedAdjust();
1241
1232
  }
1242
- if (viewPosition) {
1243
- firstIndexScrollPostion -= viewPosition * (state.scrollLength - getItemSize(getId(index), index, state.data[index]));
1244
- }
1245
- scrollTo(firstIndexScrollPostion, animated);
1233
+ scrollTo({ offset: firstIndexScrollPostion, animated, index, viewPosition, viewOffset });
1246
1234
  };
1247
1235
  const setDidLayout = () => {
1248
1236
  refState.current.queuedInitialLayout = true;
@@ -1350,7 +1338,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1350
1338
  };
1351
1339
  const disableScrollJumps = (timeout) => {
1352
1340
  const state = refState.current;
1353
- if (state.scrollingToOffset === void 0) {
1341
+ if (state.scrollingTo === void 0) {
1354
1342
  state.disableScrollJumpsFrom = state.scroll - state.scrollAdjustHandler.getAppliedAdjust();
1355
1343
  state.scrollHistory.length = 0;
1356
1344
  setTimeout(() => {
@@ -1753,18 +1741,26 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1753
1741
  const finishScrollTo = () => {
1754
1742
  const state = refState.current;
1755
1743
  if (state) {
1756
- state.scrollingToOffset = void 0;
1744
+ state.scrollingTo = void 0;
1757
1745
  state.scrollAdjustHandler.setDisableAdjust(false);
1758
1746
  state.scrollHistory.length = 0;
1759
1747
  calculateItemsInView();
1760
1748
  }
1761
1749
  };
1762
- const scrollTo = (offset, animated) => {
1750
+ const scrollTo = (params = {}) => {
1763
1751
  var _a;
1764
1752
  const state = refState.current;
1753
+ const { animated, index, viewPosition, viewOffset } = params;
1754
+ let { offset } = params;
1755
+ if (viewOffset) {
1756
+ offset -= viewOffset;
1757
+ }
1758
+ if (viewPosition !== void 0 && index !== void 0) {
1759
+ offset -= viewPosition * (state.scrollLength - getItemSize(getId(index), index, state.data[index]));
1760
+ }
1765
1761
  state.scrollAdjustHandler.setDisableAdjust(true);
1766
1762
  state.scrollHistory.length = 0;
1767
- state.scrollingToOffset = offset;
1763
+ state.scrollingTo = params;
1768
1764
  (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
1769
1765
  x: horizontal ? offset : 0,
1770
1766
  y: horizontal ? 0 : offset,
@@ -1776,7 +1772,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1776
1772
  };
1777
1773
  const doMaintainScrollAtEnd = (animated) => {
1778
1774
  const state = refState.current;
1779
- if ((state == null ? void 0 : state.isAtBottom) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
1775
+ if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
1780
1776
  const paddingTop = peek$(ctx, "alignItemsPaddingTop");
1781
1777
  if (paddingTop > 0) {
1782
1778
  state.scroll = 0;
@@ -1825,9 +1821,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1825
1821
  const contentSize = getContentSize(ctx);
1826
1822
  if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1827
1823
  const distanceFromEnd = contentSize - scroll - scrollLength;
1828
- const distanceFromEndAbs = Math.abs(distanceFromEnd);
1829
1824
  const isContentLess = contentSize < scrollLength;
1830
- refState.current.isAtBottom = isContentLess || distanceFromEndAbs < scrollLength * maintainScrollAtEndThreshold;
1825
+ refState.current.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1831
1826
  refState.current.isEndReached = checkThreshold(
1832
1827
  distanceFromEnd,
1833
1828
  isContentLess,
@@ -1850,7 +1845,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1850
1845
  }
1851
1846
  const { scrollLength, scroll } = refState.current;
1852
1847
  const distanceFromTop = scroll;
1853
- refState.current.isAtTop = distanceFromTop <= 0;
1848
+ refState.current.isAtStart = distanceFromTop <= 0;
1854
1849
  refState.current.isStartReached = checkThreshold(
1855
1850
  distanceFromTop,
1856
1851
  false,
@@ -1945,7 +1940,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1945
1940
  };
1946
1941
  state.anchorElement = newAnchorElement;
1947
1942
  (_b = state.belowAnchorElementPositions) == null ? void 0 : _b.clear();
1948
- scrollTo(0, false);
1943
+ scrollTo({ offset: 0, animated: false });
1949
1944
  setTimeout(() => {
1950
1945
  calculateItemsInView(
1951
1946
  /*reset*/
@@ -1963,7 +1958,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1963
1958
  } else {
1964
1959
  state.startBufferedId = void 0;
1965
1960
  }
1966
- scrollTo(0, false);
1961
+ scrollTo({ offset: 0, animated: false });
1967
1962
  setTimeout(() => {
1968
1963
  calculateItemsInView(
1969
1964
  /*reset*/
@@ -2071,7 +2066,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2071
2066
  const paddingDiff = stylePaddingTopState - prevPaddingTop;
2072
2067
  if (paddingDiff && prevPaddingTop !== void 0 && reactNative.Platform.OS === "ios") {
2073
2068
  queueMicrotask(() => {
2074
- scrollTo(refState.current.scroll + paddingDiff, false);
2069
+ scrollTo({ offset: refState.current.scroll + paddingDiff, animated: false });
2075
2070
  });
2076
2071
  }
2077
2072
  };
@@ -2106,7 +2101,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2106
2101
  refState.current.renderItem = renderItem;
2107
2102
  React2.useEffect(initalizeStateVars, [memoizedLastItemKeys.join(","), numColumnsProp, stylePaddingTopState]);
2108
2103
  const getRenderedItem = React2.useCallback((key) => {
2109
- var _a, _b;
2110
2104
  const state = refState.current;
2111
2105
  if (!state) {
2112
2106
  return null;
@@ -2116,11 +2110,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2116
2110
  if (index === void 0) {
2117
2111
  return null;
2118
2112
  }
2119
- const renderedItem = (_b = (_a = refState.current).renderItem) == null ? void 0 : _b.call(_a, {
2120
- item: data[index],
2121
- index,
2122
- extraData: peek$(ctx, "extraData")
2123
- });
2113
+ const renderItemProp = refState.current.renderItem;
2114
+ let renderedItem = null;
2115
+ if (renderItemProp) {
2116
+ const itemProps = {
2117
+ item: data[index],
2118
+ index,
2119
+ extraData: peek$(ctx, "extraData")
2120
+ };
2121
+ renderedItem = isFunction(renderItemProp) ? renderItemProp(itemProps) : React2__namespace.createElement(renderItemProp, itemProps);
2122
+ }
2124
2123
  return { index, item: data[index], renderedItem };
2125
2124
  }, []);
2126
2125
  const doInitialAllocateContainers = () => {
@@ -2259,7 +2258,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2259
2258
  if (needsUpdateContainersDidLayout || !fromFixGaps && needsCalculate && (isInView || !queuedInitialLayout)) {
2260
2259
  const scrollVelocity = state.scrollVelocity;
2261
2260
  let didCalculate = false;
2262
- if ((Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1 || state.scrollingToOffset !== void 0) && (!waitForInitialLayout || needsUpdateContainersDidLayout || queuedInitialLayout)) {
2261
+ if ((Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1 || state.scrollingTo !== void 0) && (!waitForInitialLayout || needsUpdateContainersDidLayout || queuedInitialLayout)) {
2263
2262
  if (Date.now() - state.lastBatchingAction < 500) {
2264
2263
  if (!state.queuedCalculateItemsInView) {
2265
2264
  state.queuedCalculateItemsInView = requestAnimationFrame(() => {
@@ -2349,8 +2348,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2349
2348
  );
2350
2349
  const updateScroll = React2.useCallback((newScroll) => {
2351
2350
  const state = refState.current;
2352
- const scrollingToOffset = state.scrollingToOffset;
2353
- if (scrollingToOffset !== void 0 && Math.abs(newScroll - scrollingToOffset) < 10) {
2351
+ const scrollingTo = state.scrollingTo;
2352
+ if (scrollingTo !== void 0 && Math.abs(newScroll - scrollingTo.offset) < 10) {
2354
2353
  finishScrollTo();
2355
2354
  }
2356
2355
  if (state.disableScrollJumpsFrom !== void 0) {
@@ -2363,7 +2362,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2363
2362
  state.hasScrolled = true;
2364
2363
  state.lastBatchingAction = Date.now();
2365
2364
  const currentTime = performance.now();
2366
- if (scrollingToOffset === void 0 && !(state.scrollHistory.length === 0 && newScroll === initialContentOffset)) {
2365
+ if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === initialContentOffset)) {
2367
2366
  state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2368
2367
  }
2369
2368
  if (state.scrollHistory.length > 5) {
@@ -2429,8 +2428,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2429
2428
  contentLength: state.totalSize,
2430
2429
  end: state.endNoBuffer,
2431
2430
  endBuffered: state.endBuffered,
2432
- isAtEnd: state.isAtBottom,
2433
- isAtStart: state.isAtTop,
2431
+ isAtEnd: state.isAtEnd,
2432
+ isAtStart: state.isAtStart,
2434
2433
  scroll: state.scroll,
2435
2434
  scrollLength: state.scrollLength,
2436
2435
  start: state.startNoBuffer,
@@ -2453,10 +2452,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2453
2452
  scrollToIndex({ index, ...props2 });
2454
2453
  }
2455
2454
  },
2456
- scrollToOffset: ({ offset, animated }) => {
2457
- scrollTo(offset, animated);
2458
- },
2459
- scrollToEnd: (options) => refScroller.current.scrollToEnd(options)
2455
+ scrollToOffset: (params) => scrollTo(params),
2456
+ scrollToEnd: (options) => {
2457
+ const { data } = refState.current;
2458
+ const index = data.length - 1;
2459
+ if (index !== -1) {
2460
+ scrollToIndex({ index, ...options });
2461
+ }
2462
+ }
2460
2463
  };
2461
2464
  },
2462
2465
  []
@@ -2466,7 +2469,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2466
2469
  var _a;
2467
2470
  if (initialContentOffset) {
2468
2471
  (_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler.setDisableAdjust(true);
2469
- scrollTo(initialContentOffset, false);
2472
+ scrollTo({ offset: initialContentOffset, animated: false });
2470
2473
  setTimeout(() => {
2471
2474
  var _a2;
2472
2475
  (_a2 = refState.current) == null ? void 0 : _a2.scrollAdjustHandler.setDisableAdjust(false);
@@ -2486,11 +2489,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2486
2489
  handleScroll,
2487
2490
  onMomentumScrollEnd: (event) => {
2488
2491
  var _a;
2489
- const scrollingToOffset = (_a = refState.current) == null ? void 0 : _a.scrollingToOffset;
2490
- if (scrollingToOffset !== void 0) {
2492
+ const scrollingTo = (_a = refState.current) == null ? void 0 : _a.scrollingTo;
2493
+ if (scrollingTo !== void 0) {
2491
2494
  requestAnimationFrame(() => {
2492
- scrollTo(scrollingToOffset, false);
2493
- refState.current.scrollingToOffset = void 0;
2495
+ scrollTo({ ...scrollingTo, animated: false });
2496
+ refState.current.scrollingTo = void 0;
2494
2497
  requestAnimationFrame(() => {
2495
2498
  refState.current.scrollAdjustHandler.setDisableAdjust(false);
2496
2499
  });
@@ -2513,12 +2516,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2513
2516
  maintainVisibleContentPosition,
2514
2517
  scrollEventThrottle: reactNative.Platform.OS === "web" ? 16 : void 0,
2515
2518
  waitForInitialLayout,
2516
- refreshControl: refreshControl != null ? refreshControl : onRefresh && /* @__PURE__ */ React2__namespace.createElement(
2519
+ refreshControl: refreshControl ? stylePaddingTopState > 0 ? React2__namespace.cloneElement(refreshControl, {
2520
+ progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
2521
+ }) : refreshControl : onRefresh && /* @__PURE__ */ React2__namespace.createElement(
2517
2522
  reactNative.RefreshControl,
2518
2523
  {
2519
2524
  refreshing: !!refreshing,
2520
2525
  onRefresh,
2521
- progressViewOffset
2526
+ progressViewOffset: (progressViewOffset || 0) + stylePaddingTopState
2522
2527
  }
2523
2528
  ),
2524
2529
  style,
package/index.mjs CHANGED
@@ -152,7 +152,7 @@ var DebugView = React2.memo(function DebugView2({ state }) {
152
152
  },
153
153
  /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "TotalSize:"), /* @__PURE__ */ React2.createElement(Text, null, totalSize.toFixed(2))),
154
154
  /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ContentSize:"), /* @__PURE__ */ React2.createElement(Text, null, contentSize.toFixed(2))),
155
- /* @__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))),
156
156
  /* @__PURE__ */ React2.createElement(Text, null),
157
157
  /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React2.createElement(Text, null, scrollAdjust.toFixed(2))),
158
158
  /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "TotalSizeReal: "), /* @__PURE__ */ React2.createElement(Text, null, totalSizeWithScrollAdjust.toFixed(2))),
@@ -179,9 +179,6 @@ function warnDevOnce(id, text) {
179
179
  console.warn(`[legend-list] ${text}`);
180
180
  }
181
181
  }
182
- function roundSize(size) {
183
- return Math.floor(size * 8) / 8;
184
- }
185
182
  function isNullOrUndefined(value) {
186
183
  return value === null || value === void 0;
187
184
  }
@@ -544,11 +541,14 @@ function ListHeaderComponentContainer({
544
541
  horizontal,
545
542
  waitForInitialLayout
546
543
  }) {
547
- 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);
548
547
  const animOpacity = waitForInitialLayout ? useValue$("containersDidLayout", (value) => value ? 1 : 0) : void 0;
549
548
  const additionalSize = {
550
549
  transform: [{ translateY: Animated.multiply(scrollAdjust, -1) }],
551
- 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
552
552
  };
553
553
  return /* @__PURE__ */ React2.createElement(
554
554
  Animated.View,
@@ -645,9 +645,6 @@ var ListComponent = typedMemo(function ListComponent2({
645
645
  refScrollView,
646
646
  maintainVisibleContentPosition,
647
647
  renderScrollComponent,
648
- onRefresh,
649
- refreshing,
650
- progressViewOffset,
651
648
  ...rest
652
649
  }) {
653
650
  const ctx = useStateContext();
@@ -1056,20 +1053,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1056
1053
  };
1057
1054
  const getItemSize = (key, index, data, useAverageSize = false) => {
1058
1055
  const state = refState.current;
1059
- const sizeKnown = state.sizesKnown.get(key);
1056
+ state.sizesKnown.get(key);
1060
1057
  const sizePrevious = state.sizes.get(key);
1061
1058
  let size;
1062
- const numColumns = peek$(ctx, "numColumns");
1063
- if (sizeKnown === void 0 && !getEstimatedItemSize && numColumns === 1 && useAverageSize) {
1064
- const itemType = "";
1065
- const average = state.averageSizes[itemType];
1066
- if (average) {
1067
- size = roundSize(average.avg);
1068
- if (size !== sizePrevious) {
1069
- addTotalSize(key, size - sizePrevious, 0);
1070
- }
1071
- }
1072
- }
1059
+ peek$(ctx, "numColumns");
1073
1060
  if (size === void 0 && sizePrevious !== void 0) {
1074
1061
  return sizePrevious;
1075
1062
  }
@@ -1090,7 +1077,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1090
1077
  if (canGetSize || getEstimatedItemSize) {
1091
1078
  const sizeFn = (index2) => {
1092
1079
  if (canGetSize) {
1093
- return getItemSize(getId(index2), index2, data[index2]);
1080
+ return getItemSize(getId(index2), index2, data[index2], true);
1094
1081
  }
1095
1082
  return getEstimatedItemSize(index2, data[index2]);
1096
1083
  };
@@ -1117,8 +1104,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1117
1104
  pendingAdjust: 0,
1118
1105
  isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
1119
1106
  isEndReached: false,
1120
- isAtBottom: false,
1121
- isAtTop: false,
1107
+ isAtEnd: false,
1108
+ isAtStart: false,
1122
1109
  data: dataProp,
1123
1110
  scrollLength: initialScrollLength,
1124
1111
  startBuffered: -1,
@@ -1203,6 +1190,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1203
1190
  index = 0;
1204
1191
  }
1205
1192
  const firstIndexOffset = calculateOffsetForIndex(index);
1193
+ const isLast = index === state.data.length - 1;
1194
+ if (isLast && viewPosition !== void 0) {
1195
+ viewPosition = 1;
1196
+ }
1206
1197
  let firstIndexScrollPostion = firstIndexOffset - viewOffset;
1207
1198
  const diff = Math.abs(state.scroll - firstIndexScrollPostion);
1208
1199
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
@@ -1218,10 +1209,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1218
1209
  state.minIndexSizeChanged = index;
1219
1210
  firstIndexScrollPostion = firstIndexOffset - viewOffset + state.scrollAdjustHandler.getAppliedAdjust();
1220
1211
  }
1221
- if (viewPosition) {
1222
- firstIndexScrollPostion -= viewPosition * (state.scrollLength - getItemSize(getId(index), index, state.data[index]));
1223
- }
1224
- scrollTo(firstIndexScrollPostion, animated);
1212
+ scrollTo({ offset: firstIndexScrollPostion, animated, index, viewPosition, viewOffset });
1225
1213
  };
1226
1214
  const setDidLayout = () => {
1227
1215
  refState.current.queuedInitialLayout = true;
@@ -1329,7 +1317,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1329
1317
  };
1330
1318
  const disableScrollJumps = (timeout) => {
1331
1319
  const state = refState.current;
1332
- if (state.scrollingToOffset === void 0) {
1320
+ if (state.scrollingTo === void 0) {
1333
1321
  state.disableScrollJumpsFrom = state.scroll - state.scrollAdjustHandler.getAppliedAdjust();
1334
1322
  state.scrollHistory.length = 0;
1335
1323
  setTimeout(() => {
@@ -1732,18 +1720,26 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1732
1720
  const finishScrollTo = () => {
1733
1721
  const state = refState.current;
1734
1722
  if (state) {
1735
- state.scrollingToOffset = void 0;
1723
+ state.scrollingTo = void 0;
1736
1724
  state.scrollAdjustHandler.setDisableAdjust(false);
1737
1725
  state.scrollHistory.length = 0;
1738
1726
  calculateItemsInView();
1739
1727
  }
1740
1728
  };
1741
- const scrollTo = (offset, animated) => {
1729
+ const scrollTo = (params = {}) => {
1742
1730
  var _a;
1743
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
+ }
1744
1740
  state.scrollAdjustHandler.setDisableAdjust(true);
1745
1741
  state.scrollHistory.length = 0;
1746
- state.scrollingToOffset = offset;
1742
+ state.scrollingTo = params;
1747
1743
  (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
1748
1744
  x: horizontal ? offset : 0,
1749
1745
  y: horizontal ? 0 : offset,
@@ -1755,7 +1751,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1755
1751
  };
1756
1752
  const doMaintainScrollAtEnd = (animated) => {
1757
1753
  const state = refState.current;
1758
- if ((state == null ? void 0 : state.isAtBottom) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
1754
+ if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
1759
1755
  const paddingTop = peek$(ctx, "alignItemsPaddingTop");
1760
1756
  if (paddingTop > 0) {
1761
1757
  state.scroll = 0;
@@ -1804,9 +1800,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1804
1800
  const contentSize = getContentSize(ctx);
1805
1801
  if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1806
1802
  const distanceFromEnd = contentSize - scroll - scrollLength;
1807
- const distanceFromEndAbs = Math.abs(distanceFromEnd);
1808
1803
  const isContentLess = contentSize < scrollLength;
1809
- refState.current.isAtBottom = isContentLess || distanceFromEndAbs < scrollLength * maintainScrollAtEndThreshold;
1804
+ refState.current.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1810
1805
  refState.current.isEndReached = checkThreshold(
1811
1806
  distanceFromEnd,
1812
1807
  isContentLess,
@@ -1829,7 +1824,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1829
1824
  }
1830
1825
  const { scrollLength, scroll } = refState.current;
1831
1826
  const distanceFromTop = scroll;
1832
- refState.current.isAtTop = distanceFromTop <= 0;
1827
+ refState.current.isAtStart = distanceFromTop <= 0;
1833
1828
  refState.current.isStartReached = checkThreshold(
1834
1829
  distanceFromTop,
1835
1830
  false,
@@ -1924,7 +1919,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1924
1919
  };
1925
1920
  state.anchorElement = newAnchorElement;
1926
1921
  (_b = state.belowAnchorElementPositions) == null ? void 0 : _b.clear();
1927
- scrollTo(0, false);
1922
+ scrollTo({ offset: 0, animated: false });
1928
1923
  setTimeout(() => {
1929
1924
  calculateItemsInView(
1930
1925
  /*reset*/
@@ -1942,7 +1937,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1942
1937
  } else {
1943
1938
  state.startBufferedId = void 0;
1944
1939
  }
1945
- scrollTo(0, false);
1940
+ scrollTo({ offset: 0, animated: false });
1946
1941
  setTimeout(() => {
1947
1942
  calculateItemsInView(
1948
1943
  /*reset*/
@@ -2050,7 +2045,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2050
2045
  const paddingDiff = stylePaddingTopState - prevPaddingTop;
2051
2046
  if (paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
2052
2047
  queueMicrotask(() => {
2053
- scrollTo(refState.current.scroll + paddingDiff, false);
2048
+ scrollTo({ offset: refState.current.scroll + paddingDiff, animated: false });
2054
2049
  });
2055
2050
  }
2056
2051
  };
@@ -2085,7 +2080,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2085
2080
  refState.current.renderItem = renderItem;
2086
2081
  useEffect(initalizeStateVars, [memoizedLastItemKeys.join(","), numColumnsProp, stylePaddingTopState]);
2087
2082
  const getRenderedItem = useCallback((key) => {
2088
- var _a, _b;
2089
2083
  const state = refState.current;
2090
2084
  if (!state) {
2091
2085
  return null;
@@ -2095,11 +2089,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2095
2089
  if (index === void 0) {
2096
2090
  return null;
2097
2091
  }
2098
- const renderedItem = (_b = (_a = refState.current).renderItem) == null ? void 0 : _b.call(_a, {
2099
- item: data[index],
2100
- index,
2101
- extraData: peek$(ctx, "extraData")
2102
- });
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
+ }
2103
2102
  return { index, item: data[index], renderedItem };
2104
2103
  }, []);
2105
2104
  const doInitialAllocateContainers = () => {
@@ -2238,7 +2237,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2238
2237
  if (needsUpdateContainersDidLayout || !fromFixGaps && needsCalculate && (isInView || !queuedInitialLayout)) {
2239
2238
  const scrollVelocity = state.scrollVelocity;
2240
2239
  let didCalculate = false;
2241
- if ((Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1 || state.scrollingToOffset !== void 0) && (!waitForInitialLayout || needsUpdateContainersDidLayout || queuedInitialLayout)) {
2240
+ if ((Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1 || state.scrollingTo !== void 0) && (!waitForInitialLayout || needsUpdateContainersDidLayout || queuedInitialLayout)) {
2242
2241
  if (Date.now() - state.lastBatchingAction < 500) {
2243
2242
  if (!state.queuedCalculateItemsInView) {
2244
2243
  state.queuedCalculateItemsInView = requestAnimationFrame(() => {
@@ -2328,8 +2327,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2328
2327
  );
2329
2328
  const updateScroll = useCallback((newScroll) => {
2330
2329
  const state = refState.current;
2331
- const scrollingToOffset = state.scrollingToOffset;
2332
- 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) {
2333
2332
  finishScrollTo();
2334
2333
  }
2335
2334
  if (state.disableScrollJumpsFrom !== void 0) {
@@ -2342,7 +2341,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2342
2341
  state.hasScrolled = true;
2343
2342
  state.lastBatchingAction = Date.now();
2344
2343
  const currentTime = performance.now();
2345
- if (scrollingToOffset === void 0 && !(state.scrollHistory.length === 0 && newScroll === initialContentOffset)) {
2344
+ if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === initialContentOffset)) {
2346
2345
  state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2347
2346
  }
2348
2347
  if (state.scrollHistory.length > 5) {
@@ -2408,8 +2407,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2408
2407
  contentLength: state.totalSize,
2409
2408
  end: state.endNoBuffer,
2410
2409
  endBuffered: state.endBuffered,
2411
- isAtEnd: state.isAtBottom,
2412
- isAtStart: state.isAtTop,
2410
+ isAtEnd: state.isAtEnd,
2411
+ isAtStart: state.isAtStart,
2413
2412
  scroll: state.scroll,
2414
2413
  scrollLength: state.scrollLength,
2415
2414
  start: state.startNoBuffer,
@@ -2432,10 +2431,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2432
2431
  scrollToIndex({ index, ...props2 });
2433
2432
  }
2434
2433
  },
2435
- scrollToOffset: ({ offset, animated }) => {
2436
- scrollTo(offset, animated);
2437
- },
2438
- 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
+ }
2439
2442
  };
2440
2443
  },
2441
2444
  []
@@ -2445,7 +2448,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2445
2448
  var _a;
2446
2449
  if (initialContentOffset) {
2447
2450
  (_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler.setDisableAdjust(true);
2448
- scrollTo(initialContentOffset, false);
2451
+ scrollTo({ offset: initialContentOffset, animated: false });
2449
2452
  setTimeout(() => {
2450
2453
  var _a2;
2451
2454
  (_a2 = refState.current) == null ? void 0 : _a2.scrollAdjustHandler.setDisableAdjust(false);
@@ -2465,11 +2468,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2465
2468
  handleScroll,
2466
2469
  onMomentumScrollEnd: (event) => {
2467
2470
  var _a;
2468
- const scrollingToOffset = (_a = refState.current) == null ? void 0 : _a.scrollingToOffset;
2469
- if (scrollingToOffset !== void 0) {
2471
+ const scrollingTo = (_a = refState.current) == null ? void 0 : _a.scrollingTo;
2472
+ if (scrollingTo !== void 0) {
2470
2473
  requestAnimationFrame(() => {
2471
- scrollTo(scrollingToOffset, false);
2472
- refState.current.scrollingToOffset = void 0;
2474
+ scrollTo({ ...scrollingTo, animated: false });
2475
+ refState.current.scrollingTo = void 0;
2473
2476
  requestAnimationFrame(() => {
2474
2477
  refState.current.scrollAdjustHandler.setDisableAdjust(false);
2475
2478
  });
@@ -2492,12 +2495,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2492
2495
  maintainVisibleContentPosition,
2493
2496
  scrollEventThrottle: Platform.OS === "web" ? 16 : void 0,
2494
2497
  waitForInitialLayout,
2495
- 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(
2496
2501
  RefreshControl,
2497
2502
  {
2498
2503
  refreshing: !!refreshing,
2499
2504
  onRefresh,
2500
- progressViewOffset
2505
+ progressViewOffset: (progressViewOffset || 0) + stylePaddingTopState
2501
2506
  }
2502
2507
  ),
2503
2508
  style,
@@ -52,7 +52,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
52
52
  recycleItems?: boolean;
53
53
  refScrollView?: React.Ref<react_native.ScrollView>;
54
54
  refreshing?: boolean;
55
- renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<T>) => React.ReactNode) | undefined;
55
+ renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<T>) => React.ReactNode) | React.ComponentType<_legendapp_list.LegendListRenderItemProps<T>> | undefined;
56
56
  renderScrollComponent?: (props: react_native.ScrollViewProps) => React.ReactElement<react_native.ScrollViewProps>;
57
57
  suggestEstimatedItemSize?: boolean;
58
58
  viewabilityConfig?: _legendapp_list.ViewabilityConfig;
@@ -106,7 +106,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
106
106
  recycleItems?: boolean;
107
107
  refScrollView?: React.Ref<react_native.ScrollView>;
108
108
  refreshing?: boolean;
109
- renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<T>) => React.ReactNode) | undefined;
109
+ renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<T>) => React.ReactNode) | React.ComponentType<_legendapp_list.LegendListRenderItemProps<T>> | undefined;
110
110
  renderScrollComponent?: (props: react_native.ScrollViewProps) => React.ReactElement<react_native.ScrollViewProps>;
111
111
  suggestEstimatedItemSize?: boolean;
112
112
  viewabilityConfig?: _legendapp_list.ViewabilityConfig;
@@ -128,7 +128,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
128
128
  itemKey: string;
129
129
  itemData: ItemT_1;
130
130
  }) => void) | undefined;
131
- renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<ItemT_1>) => React.ReactNode) | undefined;
131
+ renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<ItemT_1>) => React.ReactNode) | React.ComponentType<_legendapp_list.LegendListRenderItemProps<ItemT_1>> | undefined;
132
132
  animatedProps?: Partial<{
133
133
  contentOffset?: react_native.PointProp | react_native_reanimated.SharedValue<react_native.PointProp | undefined> | undefined;
134
134
  contentInset?: Insets | react_native_reanimated.SharedValue<Insets | undefined> | undefined;
@@ -343,7 +343,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
343
343
  recycleItems?: boolean;
344
344
  refScrollView?: React.Ref<react_native.ScrollView>;
345
345
  refreshing?: boolean;
346
- renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<T>) => React.ReactNode) | undefined;
346
+ renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<T>) => React.ReactNode) | React.ComponentType<_legendapp_list.LegendListRenderItemProps<T>> | undefined;
347
347
  renderScrollComponent?: (props: react_native.ScrollViewProps) => React.ReactElement<react_native.ScrollViewProps>;
348
348
  suggestEstimatedItemSize?: boolean;
349
349
  viewabilityConfig?: _legendapp_list.ViewabilityConfig;
@@ -397,7 +397,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
397
397
  recycleItems?: boolean;
398
398
  refScrollView?: React.Ref<react_native.ScrollView>;
399
399
  refreshing?: boolean;
400
- renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<ItemT>) => React.ReactNode) | undefined;
400
+ renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<ItemT>) => React.ReactNode) | React.ComponentType<_legendapp_list.LegendListRenderItemProps<ItemT>> | undefined;
401
401
  renderScrollComponent?: (props: react_native.ScrollViewProps) => React.ReactElement<react_native.ScrollViewProps>;
402
402
  suggestEstimatedItemSize?: boolean;
403
403
  viewabilityConfig?: _legendapp_list.ViewabilityConfig;
@@ -52,7 +52,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
52
52
  recycleItems?: boolean;
53
53
  refScrollView?: React.Ref<react_native.ScrollView>;
54
54
  refreshing?: boolean;
55
- renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<T>) => React.ReactNode) | undefined;
55
+ renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<T>) => React.ReactNode) | React.ComponentType<_legendapp_list.LegendListRenderItemProps<T>> | undefined;
56
56
  renderScrollComponent?: (props: react_native.ScrollViewProps) => React.ReactElement<react_native.ScrollViewProps>;
57
57
  suggestEstimatedItemSize?: boolean;
58
58
  viewabilityConfig?: _legendapp_list.ViewabilityConfig;
@@ -106,7 +106,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
106
106
  recycleItems?: boolean;
107
107
  refScrollView?: React.Ref<react_native.ScrollView>;
108
108
  refreshing?: boolean;
109
- renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<T>) => React.ReactNode) | undefined;
109
+ renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<T>) => React.ReactNode) | React.ComponentType<_legendapp_list.LegendListRenderItemProps<T>> | undefined;
110
110
  renderScrollComponent?: (props: react_native.ScrollViewProps) => React.ReactElement<react_native.ScrollViewProps>;
111
111
  suggestEstimatedItemSize?: boolean;
112
112
  viewabilityConfig?: _legendapp_list.ViewabilityConfig;
@@ -128,7 +128,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
128
128
  itemKey: string;
129
129
  itemData: ItemT_1;
130
130
  }) => void) | undefined;
131
- renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<ItemT_1>) => React.ReactNode) | undefined;
131
+ renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<ItemT_1>) => React.ReactNode) | React.ComponentType<_legendapp_list.LegendListRenderItemProps<ItemT_1>> | undefined;
132
132
  animatedProps?: Partial<{
133
133
  contentOffset?: react_native.PointProp | react_native_reanimated.SharedValue<react_native.PointProp | undefined> | undefined;
134
134
  contentInset?: Insets | react_native_reanimated.SharedValue<Insets | undefined> | undefined;
@@ -343,7 +343,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
343
343
  recycleItems?: boolean;
344
344
  refScrollView?: React.Ref<react_native.ScrollView>;
345
345
  refreshing?: boolean;
346
- renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<T>) => React.ReactNode) | undefined;
346
+ renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<T>) => React.ReactNode) | React.ComponentType<_legendapp_list.LegendListRenderItemProps<T>> | undefined;
347
347
  renderScrollComponent?: (props: react_native.ScrollViewProps) => React.ReactElement<react_native.ScrollViewProps>;
348
348
  suggestEstimatedItemSize?: boolean;
349
349
  viewabilityConfig?: _legendapp_list.ViewabilityConfig;
@@ -397,7 +397,7 @@ declare const LegendList: <ItemT, ListT extends (<T>(props: Omit<Omit<react_nati
397
397
  recycleItems?: boolean;
398
398
  refScrollView?: React.Ref<react_native.ScrollView>;
399
399
  refreshing?: boolean;
400
- renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<ItemT>) => React.ReactNode) | undefined;
400
+ renderItem?: ((props: _legendapp_list.LegendListRenderItemProps<ItemT>) => React.ReactNode) | React.ComponentType<_legendapp_list.LegendListRenderItemProps<ItemT>> | undefined;
401
401
  renderScrollComponent?: (props: react_native.ScrollViewProps) => React.ReactElement<react_native.ScrollViewProps>;
402
402
  suggestEstimatedItemSize?: boolean;
403
403
  viewabilityConfig?: _legendapp_list.ViewabilityConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
4
4
  "description": "Legend List is a drop-in replacement for FlatList with much better performance and supporting dynamically sized items.",
5
5
  "sideEffects": false,
6
6
  "private": false,