@legendapp/list 3.0.0-beta.11 → 3.0.0-beta.12

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/README.md CHANGED
@@ -27,6 +27,7 @@ Beyond standard `FlatList` capabilities:
27
27
  * `true`: Reuses item components for optimal performance. Be cautious if your item components contain local state, as it might be reused unexpectedly.
28
28
  * `false` (default): Creates new item components every time. Less performant but safer if items have complex internal state.
29
29
  * `maintainScrollAtEnd`: (boolean) If `true` and the user is scrolled near the bottom (within `maintainScrollAtEndThreshold * screen height`), the list automatically scrolls to the end when items are added or heights change. Useful for chat interfaces.
30
+ * `maintainVisibleContentPosition`: Keeps visible content steady during size/layout changes while scrolling (default). Pass `true` or `{ dataChanges: true }` to also anchor during data updates; pass `false` to disable; pass `{ scroll: false }` to opt out of scroll-time stabilization.
30
31
  * `alignItemsAtEnd`: (boolean) Useful for chat UIs, content smaller than the View will be aligned to the bottom of the list.
31
32
 
32
33
  ---
package/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { Dispatch, SetStateAction } from 'react';
3
- import { L as LegendListProps, a as LegendListRef, V as ViewabilityCallback, b as ViewabilityAmountCallback, c as LegendListRecyclingState } from './types-1Hgg1rTO.mjs';
4
- export { C as ColumnWrapperStyle, u as GetRenderedItem, G as GetRenderedItemResult, s as InitialScrollAnchor, I as InternalState, d as LegendListPropsBase, f as LegendListRenderItemProps, g as LegendListState, M as MaintainScrollAtEndOptions, O as OnViewableItemsChanged, p as ScrollIndexWithOffset, r as ScrollIndexWithOffsetAndContentOffset, q as ScrollIndexWithOffsetPosition, S as ScrollTarget, T as ThresholdSnapshot, m as TypedForwardRef, n as TypedMemo, i as ViewAmountToken, h as ViewToken, l as ViewabilityConfig, j as ViewabilityConfigCallbackPair, k as ViewabilityConfigCallbackPairs, e as ViewableRange, t as typedForwardRef, o as typedMemo } from './types-1Hgg1rTO.mjs';
3
+ import { L as LegendListProps, a as LegendListRef, V as ViewabilityCallback, b as ViewabilityAmountCallback, c as LegendListRecyclingState } from './types-C83aU7VI.mjs';
4
+ export { C as ColumnWrapperStyle, w as GetRenderedItem, G as GetRenderedItemResult, v as InitialScrollAnchor, I as InternalState, d as LegendListPropsBase, h as LegendListRenderItemProps, i as LegendListState, f as MaintainScrollAtEndOptions, M as MaintainVisibleContentPositionConfig, e as MaintainVisibleContentPositionNormalized, O as OnViewableItemsChanged, r as ScrollIndexWithOffset, u as ScrollIndexWithOffsetAndContentOffset, s as ScrollIndexWithOffsetPosition, S as ScrollTarget, T as ThresholdSnapshot, o as TypedForwardRef, p as TypedMemo, k as ViewAmountToken, j as ViewToken, n as ViewabilityConfig, l as ViewabilityConfigCallbackPair, m as ViewabilityConfigCallbackPairs, g as ViewableRange, t as typedForwardRef, q as typedMemo } from './types-C83aU7VI.mjs';
5
5
  import 'react-native';
6
6
  import 'react-native-reanimated';
7
7
 
package/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { Dispatch, SetStateAction } from 'react';
3
- import { L as LegendListProps, a as LegendListRef, V as ViewabilityCallback, b as ViewabilityAmountCallback, c as LegendListRecyclingState } from './types-1Hgg1rTO.js';
4
- export { C as ColumnWrapperStyle, u as GetRenderedItem, G as GetRenderedItemResult, s as InitialScrollAnchor, I as InternalState, d as LegendListPropsBase, f as LegendListRenderItemProps, g as LegendListState, M as MaintainScrollAtEndOptions, O as OnViewableItemsChanged, p as ScrollIndexWithOffset, r as ScrollIndexWithOffsetAndContentOffset, q as ScrollIndexWithOffsetPosition, S as ScrollTarget, T as ThresholdSnapshot, m as TypedForwardRef, n as TypedMemo, i as ViewAmountToken, h as ViewToken, l as ViewabilityConfig, j as ViewabilityConfigCallbackPair, k as ViewabilityConfigCallbackPairs, e as ViewableRange, t as typedForwardRef, o as typedMemo } from './types-1Hgg1rTO.js';
3
+ import { L as LegendListProps, a as LegendListRef, V as ViewabilityCallback, b as ViewabilityAmountCallback, c as LegendListRecyclingState } from './types-C83aU7VI.js';
4
+ export { C as ColumnWrapperStyle, w as GetRenderedItem, G as GetRenderedItemResult, v as InitialScrollAnchor, I as InternalState, d as LegendListPropsBase, h as LegendListRenderItemProps, i as LegendListState, f as MaintainScrollAtEndOptions, M as MaintainVisibleContentPositionConfig, e as MaintainVisibleContentPositionNormalized, O as OnViewableItemsChanged, r as ScrollIndexWithOffset, u as ScrollIndexWithOffsetAndContentOffset, s as ScrollIndexWithOffsetPosition, S as ScrollTarget, T as ThresholdSnapshot, o as TypedForwardRef, p as TypedMemo, k as ViewAmountToken, j as ViewToken, n as ViewabilityConfig, l as ViewabilityConfigCallbackPair, m as ViewabilityConfigCallbackPairs, g as ViewableRange, t as typedForwardRef, q as typedMemo } from './types-C83aU7VI.js';
5
5
  import 'react-native';
6
6
  import 'react-native-reanimated';
7
7
 
package/index.js CHANGED
@@ -1204,7 +1204,6 @@ var ListComponent = typedMemo(function ListComponent2({
1204
1204
  getRenderedItem: getRenderedItem2,
1205
1205
  updateItemSize: updateItemSize2,
1206
1206
  refScrollView,
1207
- maintainVisibleContentPosition,
1208
1207
  renderScrollComponent,
1209
1208
  scrollAdjustHandler,
1210
1209
  onLayoutHeader,
@@ -1213,6 +1212,7 @@ var ListComponent = typedMemo(function ListComponent2({
1213
1212
  ...rest
1214
1213
  }) {
1215
1214
  const ctx = useStateContext();
1215
+ const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1216
1216
  const ScrollComponent = renderScrollComponent ? React3.useMemo(
1217
1217
  () => React3__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1218
1218
  [renderScrollComponent]
@@ -1230,7 +1230,7 @@ var ListComponent = typedMemo(function ListComponent2({
1230
1230
  ],
1231
1231
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1232
1232
  horizontal,
1233
- maintainVisibleContentPosition: maintainVisibleContentPosition ? { minIndexForVisible: 0 } : void 0,
1233
+ maintainVisibleContentPosition: maintainVisibleContentPosition.scroll || maintainVisibleContentPosition.dataChanges ? { minIndexForVisible: 0 } : void 0,
1234
1234
  onLayout,
1235
1235
  onScroll: onScroll2,
1236
1236
  ref: refScrollView,
@@ -1774,14 +1774,16 @@ function requestAdjust(ctx, positionDiff, dataChanged) {
1774
1774
  function prepareMVCP(ctx, dataChanged) {
1775
1775
  const state = ctx.state;
1776
1776
  const { idsInView, positions, props } = state;
1777
- const { maintainVisibleContentPosition } = props;
1777
+ const {
1778
+ maintainVisibleContentPosition: { dataChanges: mvcpDataChanges, scroll: mvcpScroll }
1779
+ } = props;
1778
1780
  const scrollingTo = state.scrollingTo;
1779
1781
  let prevPosition;
1780
1782
  let targetId;
1781
1783
  const idsInViewWithPositions = [];
1782
1784
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1783
1785
  const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1784
- const shouldMVCP = !dataChanged || maintainVisibleContentPosition;
1786
+ const shouldMVCP = dataChanged ? mvcpDataChanges : mvcpScroll;
1785
1787
  const indexByKey = state.indexByKey;
1786
1788
  if (shouldMVCP) {
1787
1789
  if (scrollTarget !== void 0) {
@@ -1804,7 +1806,7 @@ function prepareMVCP(ctx, dataChanged) {
1804
1806
  }
1805
1807
  return () => {
1806
1808
  let positionDiff = 0;
1807
- if (dataChanged && targetId === void 0 && maintainVisibleContentPosition) {
1809
+ if (dataChanged && targetId === void 0 && mvcpDataChanges) {
1808
1810
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1809
1811
  const { id, position } = idsInViewWithPositions[i];
1810
1812
  const newPosition = positions.get(id);
@@ -1938,39 +1940,40 @@ function updateTotalSize(ctx) {
1938
1940
  // src/utils/getScrollVelocity.ts
1939
1941
  var getScrollVelocity = (state) => {
1940
1942
  const { scrollHistory } = state;
1941
- let velocity = 0;
1942
- if (scrollHistory.length >= 1) {
1943
- const newest = scrollHistory[scrollHistory.length - 1];
1944
- let oldest;
1945
- let start = 0;
1946
- const now = Date.now();
1947
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1948
- const entry = scrollHistory[i];
1949
- const nextEntry = scrollHistory[i + 1];
1950
- if (i > 0) {
1951
- const prevEntry = scrollHistory[i - 1];
1952
- const prevDirection = entry.scroll - prevEntry.scroll;
1953
- const currentDirection = nextEntry.scroll - entry.scroll;
1954
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1955
- start = i;
1956
- break;
1957
- }
1958
- }
1943
+ const newestIndex = scrollHistory.length - 1;
1944
+ if (newestIndex < 1) {
1945
+ return 0;
1946
+ }
1947
+ const newest = scrollHistory[newestIndex];
1948
+ const now = Date.now();
1949
+ let direction = 0;
1950
+ for (let i = newestIndex; i > 0; i--) {
1951
+ const delta = scrollHistory[i].scroll - scrollHistory[i - 1].scroll;
1952
+ if (delta !== 0) {
1953
+ direction = Math.sign(delta);
1954
+ break;
1959
1955
  }
1960
- for (let i = start; i < scrollHistory.length - 1; i++) {
1961
- const entry = scrollHistory[i];
1962
- if (now - entry.time <= 1e3) {
1963
- oldest = entry;
1964
- break;
1965
- }
1956
+ }
1957
+ if (direction === 0) {
1958
+ return 0;
1959
+ }
1960
+ let oldest = newest;
1961
+ for (let i = newestIndex - 1; i >= 0; i--) {
1962
+ const current = scrollHistory[i];
1963
+ const next = scrollHistory[i + 1];
1964
+ const delta = next.scroll - current.scroll;
1965
+ const deltaSign = Math.sign(delta);
1966
+ if (deltaSign !== 0 && deltaSign !== direction) {
1967
+ break;
1966
1968
  }
1967
- if (oldest && oldest !== newest) {
1968
- const scrollDiff = newest.scroll - oldest.scroll;
1969
- const timeDiff = newest.time - oldest.time;
1970
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1969
+ if (now - current.time > 1e3) {
1970
+ break;
1971
1971
  }
1972
+ oldest = current;
1972
1973
  }
1973
- return velocity;
1974
+ const scrollDiff = newest.scroll - oldest.scroll;
1975
+ const timeDiff = newest.time - oldest.time;
1976
+ return timeDiff > 0 ? scrollDiff / timeDiff : 0;
1974
1977
  };
1975
1978
 
1976
1979
  // src/utils/updateSnapToOffsets.ts
@@ -2900,7 +2903,7 @@ function checkFinishedScrollFrame(ctx) {
2900
2903
  if (scrollingTo) {
2901
2904
  const { state } = ctx;
2902
2905
  state.animFrameCheckFinishedScroll = void 0;
2903
- const scroll = state.scroll;
2906
+ const scroll = state.scrollPending;
2904
2907
  const adjust = state.scrollAdjustHandler.getAdjust();
2905
2908
  const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
2906
2909
  const maxOffset = clampScrollOffset(ctx, scroll);
@@ -3155,7 +3158,6 @@ function onScroll(ctx, event) {
3155
3158
  return;
3156
3159
  }
3157
3160
  let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3158
- state.scrollPending = newScroll;
3159
3161
  if (state.scrollingTo) {
3160
3162
  const maxOffset = clampScrollOffset(ctx, newScroll);
3161
3163
  if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
@@ -3169,8 +3171,11 @@ function onScroll(ctx, event) {
3169
3171
  return;
3170
3172
  }
3171
3173
  }
3174
+ state.scrollPending = newScroll;
3172
3175
  updateScroll(ctx, newScroll);
3173
- checkFinishedScroll(ctx);
3176
+ if (state.scrollingTo) {
3177
+ checkFinishedScroll(ctx);
3178
+ }
3174
3179
  onScrollProp == null ? void 0 : onScrollProp(event);
3175
3180
  }
3176
3181
 
@@ -3505,6 +3510,24 @@ function getRenderedItem(ctx, key) {
3505
3510
  }
3506
3511
  return { index, item: data[index], renderedItem };
3507
3512
  }
3513
+
3514
+ // src/utils/normalizeMaintainVisibleContentPosition.ts
3515
+ function normalizeMaintainVisibleContentPosition(value) {
3516
+ var _a3, _b;
3517
+ if (value === true) {
3518
+ return { dataChanges: true, scroll: true };
3519
+ }
3520
+ if (value && typeof value === "object") {
3521
+ return {
3522
+ dataChanges: (_a3 = value.dataChanges) != null ? _a3 : false,
3523
+ scroll: (_b = value.scroll) != null ? _b : true
3524
+ };
3525
+ }
3526
+ if (value === false) {
3527
+ return { dataChanges: false, scroll: false };
3528
+ }
3529
+ return { dataChanges: false, scroll: true };
3530
+ }
3508
3531
  function useThrottleDebounce(mode) {
3509
3532
  const timeoutRef = React3.useRef(null);
3510
3533
  const lastCallTimeRef = React3.useRef(0);
@@ -3599,7 +3622,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3599
3622
  ListHeaderComponent,
3600
3623
  maintainScrollAtEnd = false,
3601
3624
  maintainScrollAtEndThreshold = 0.1,
3602
- maintainVisibleContentPosition = false,
3625
+ maintainVisibleContentPosition: maintainVisibleContentPositionProp,
3603
3626
  numColumns: numColumnsProp = 1,
3604
3627
  onEndReached,
3605
3628
  onEndReachedThreshold = 0.5,
@@ -3637,6 +3660,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3637
3660
  const style = { ...StyleSheet.flatten(styleProp) };
3638
3661
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
3639
3662
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
3663
+ const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
3664
+ maintainVisibleContentPositionProp
3665
+ );
3640
3666
  const [renderNum, setRenderNum] = React3.useState(0);
3641
3667
  const initialScrollProp = initialScrollAtEnd ? { index: Math.max(0, dataProp.length - 1), viewOffset: -stylePaddingBottomState } : initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
3642
3668
  const [canRender, setCanRender] = React3__namespace.useState(!IsNewArchitecture);
@@ -3721,7 +3747,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3721
3747
  };
3722
3748
  const internalState = ctx.state;
3723
3749
  internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
3724
- set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
3750
+ set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPositionConfig);
3725
3751
  set$(ctx, "extraData", extraData);
3726
3752
  }
3727
3753
  refState.current = ctx.state;
@@ -3752,7 +3778,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3752
3778
  keyExtractor,
3753
3779
  maintainScrollAtEnd,
3754
3780
  maintainScrollAtEndThreshold,
3755
- maintainVisibleContentPosition,
3781
+ maintainVisibleContentPosition: maintainVisibleContentPositionConfig,
3756
3782
  numColumns: numColumnsProp,
3757
3783
  onEndReached,
3758
3784
  onEndReachedThreshold,
@@ -3787,7 +3813,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3787
3813
  setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3788
3814
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3789
3815
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3790
- if (paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3816
+ if (maintainVisibleContentPositionConfig.scroll && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3791
3817
  if (state.scroll < 0) {
3792
3818
  paddingDiff += state.scroll;
3793
3819
  }
@@ -3822,7 +3848,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3822
3848
  value = 0;
3823
3849
  }
3824
3850
  if (!value) {
3825
- state.didFinishInitialScroll = true;
3851
+ setInitialRenderState(ctx, { didInitialScroll: true });
3826
3852
  }
3827
3853
  return value;
3828
3854
  }, [renderNum]);
@@ -3944,7 +3970,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3944
3970
  initialContentOffset,
3945
3971
  ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
3946
3972
  ListHeaderComponent,
3947
- maintainVisibleContentPosition,
3948
3973
  onLayout,
3949
3974
  onLayoutHeader,
3950
3975
  onMomentumScrollEnd: fns.onMomentumScrollEnd,
package/index.mjs CHANGED
@@ -1183,7 +1183,6 @@ var ListComponent = typedMemo(function ListComponent2({
1183
1183
  getRenderedItem: getRenderedItem2,
1184
1184
  updateItemSize: updateItemSize2,
1185
1185
  refScrollView,
1186
- maintainVisibleContentPosition,
1187
1186
  renderScrollComponent,
1188
1187
  scrollAdjustHandler,
1189
1188
  onLayoutHeader,
@@ -1192,6 +1191,7 @@ var ListComponent = typedMemo(function ListComponent2({
1192
1191
  ...rest
1193
1192
  }) {
1194
1193
  const ctx = useStateContext();
1194
+ const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1195
1195
  const ScrollComponent = renderScrollComponent ? useMemo(
1196
1196
  () => React3.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1197
1197
  [renderScrollComponent]
@@ -1209,7 +1209,7 @@ var ListComponent = typedMemo(function ListComponent2({
1209
1209
  ],
1210
1210
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1211
1211
  horizontal,
1212
- maintainVisibleContentPosition: maintainVisibleContentPosition ? { minIndexForVisible: 0 } : void 0,
1212
+ maintainVisibleContentPosition: maintainVisibleContentPosition.scroll || maintainVisibleContentPosition.dataChanges ? { minIndexForVisible: 0 } : void 0,
1213
1213
  onLayout,
1214
1214
  onScroll: onScroll2,
1215
1215
  ref: refScrollView,
@@ -1753,14 +1753,16 @@ function requestAdjust(ctx, positionDiff, dataChanged) {
1753
1753
  function prepareMVCP(ctx, dataChanged) {
1754
1754
  const state = ctx.state;
1755
1755
  const { idsInView, positions, props } = state;
1756
- const { maintainVisibleContentPosition } = props;
1756
+ const {
1757
+ maintainVisibleContentPosition: { dataChanges: mvcpDataChanges, scroll: mvcpScroll }
1758
+ } = props;
1757
1759
  const scrollingTo = state.scrollingTo;
1758
1760
  let prevPosition;
1759
1761
  let targetId;
1760
1762
  const idsInViewWithPositions = [];
1761
1763
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1762
1764
  const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1763
- const shouldMVCP = !dataChanged || maintainVisibleContentPosition;
1765
+ const shouldMVCP = dataChanged ? mvcpDataChanges : mvcpScroll;
1764
1766
  const indexByKey = state.indexByKey;
1765
1767
  if (shouldMVCP) {
1766
1768
  if (scrollTarget !== void 0) {
@@ -1783,7 +1785,7 @@ function prepareMVCP(ctx, dataChanged) {
1783
1785
  }
1784
1786
  return () => {
1785
1787
  let positionDiff = 0;
1786
- if (dataChanged && targetId === void 0 && maintainVisibleContentPosition) {
1788
+ if (dataChanged && targetId === void 0 && mvcpDataChanges) {
1787
1789
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1788
1790
  const { id, position } = idsInViewWithPositions[i];
1789
1791
  const newPosition = positions.get(id);
@@ -1917,39 +1919,40 @@ function updateTotalSize(ctx) {
1917
1919
  // src/utils/getScrollVelocity.ts
1918
1920
  var getScrollVelocity = (state) => {
1919
1921
  const { scrollHistory } = state;
1920
- let velocity = 0;
1921
- if (scrollHistory.length >= 1) {
1922
- const newest = scrollHistory[scrollHistory.length - 1];
1923
- let oldest;
1924
- let start = 0;
1925
- const now = Date.now();
1926
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1927
- const entry = scrollHistory[i];
1928
- const nextEntry = scrollHistory[i + 1];
1929
- if (i > 0) {
1930
- const prevEntry = scrollHistory[i - 1];
1931
- const prevDirection = entry.scroll - prevEntry.scroll;
1932
- const currentDirection = nextEntry.scroll - entry.scroll;
1933
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1934
- start = i;
1935
- break;
1936
- }
1937
- }
1922
+ const newestIndex = scrollHistory.length - 1;
1923
+ if (newestIndex < 1) {
1924
+ return 0;
1925
+ }
1926
+ const newest = scrollHistory[newestIndex];
1927
+ const now = Date.now();
1928
+ let direction = 0;
1929
+ for (let i = newestIndex; i > 0; i--) {
1930
+ const delta = scrollHistory[i].scroll - scrollHistory[i - 1].scroll;
1931
+ if (delta !== 0) {
1932
+ direction = Math.sign(delta);
1933
+ break;
1938
1934
  }
1939
- for (let i = start; i < scrollHistory.length - 1; i++) {
1940
- const entry = scrollHistory[i];
1941
- if (now - entry.time <= 1e3) {
1942
- oldest = entry;
1943
- break;
1944
- }
1935
+ }
1936
+ if (direction === 0) {
1937
+ return 0;
1938
+ }
1939
+ let oldest = newest;
1940
+ for (let i = newestIndex - 1; i >= 0; i--) {
1941
+ const current = scrollHistory[i];
1942
+ const next = scrollHistory[i + 1];
1943
+ const delta = next.scroll - current.scroll;
1944
+ const deltaSign = Math.sign(delta);
1945
+ if (deltaSign !== 0 && deltaSign !== direction) {
1946
+ break;
1945
1947
  }
1946
- if (oldest && oldest !== newest) {
1947
- const scrollDiff = newest.scroll - oldest.scroll;
1948
- const timeDiff = newest.time - oldest.time;
1949
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1948
+ if (now - current.time > 1e3) {
1949
+ break;
1950
1950
  }
1951
+ oldest = current;
1951
1952
  }
1952
- return velocity;
1953
+ const scrollDiff = newest.scroll - oldest.scroll;
1954
+ const timeDiff = newest.time - oldest.time;
1955
+ return timeDiff > 0 ? scrollDiff / timeDiff : 0;
1953
1956
  };
1954
1957
 
1955
1958
  // src/utils/updateSnapToOffsets.ts
@@ -2879,7 +2882,7 @@ function checkFinishedScrollFrame(ctx) {
2879
2882
  if (scrollingTo) {
2880
2883
  const { state } = ctx;
2881
2884
  state.animFrameCheckFinishedScroll = void 0;
2882
- const scroll = state.scroll;
2885
+ const scroll = state.scrollPending;
2883
2886
  const adjust = state.scrollAdjustHandler.getAdjust();
2884
2887
  const clampedTargetOffset = clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0));
2885
2888
  const maxOffset = clampScrollOffset(ctx, scroll);
@@ -3134,7 +3137,6 @@ function onScroll(ctx, event) {
3134
3137
  return;
3135
3138
  }
3136
3139
  let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3137
- state.scrollPending = newScroll;
3138
3140
  if (state.scrollingTo) {
3139
3141
  const maxOffset = clampScrollOffset(ctx, newScroll);
3140
3142
  if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
@@ -3148,8 +3150,11 @@ function onScroll(ctx, event) {
3148
3150
  return;
3149
3151
  }
3150
3152
  }
3153
+ state.scrollPending = newScroll;
3151
3154
  updateScroll(ctx, newScroll);
3152
- checkFinishedScroll(ctx);
3155
+ if (state.scrollingTo) {
3156
+ checkFinishedScroll(ctx);
3157
+ }
3153
3158
  onScrollProp == null ? void 0 : onScrollProp(event);
3154
3159
  }
3155
3160
 
@@ -3484,6 +3489,24 @@ function getRenderedItem(ctx, key) {
3484
3489
  }
3485
3490
  return { index, item: data[index], renderedItem };
3486
3491
  }
3492
+
3493
+ // src/utils/normalizeMaintainVisibleContentPosition.ts
3494
+ function normalizeMaintainVisibleContentPosition(value) {
3495
+ var _a3, _b;
3496
+ if (value === true) {
3497
+ return { dataChanges: true, scroll: true };
3498
+ }
3499
+ if (value && typeof value === "object") {
3500
+ return {
3501
+ dataChanges: (_a3 = value.dataChanges) != null ? _a3 : false,
3502
+ scroll: (_b = value.scroll) != null ? _b : true
3503
+ };
3504
+ }
3505
+ if (value === false) {
3506
+ return { dataChanges: false, scroll: false };
3507
+ }
3508
+ return { dataChanges: false, scroll: true };
3509
+ }
3487
3510
  function useThrottleDebounce(mode) {
3488
3511
  const timeoutRef = useRef(null);
3489
3512
  const lastCallTimeRef = useRef(0);
@@ -3578,7 +3601,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3578
3601
  ListHeaderComponent,
3579
3602
  maintainScrollAtEnd = false,
3580
3603
  maintainScrollAtEndThreshold = 0.1,
3581
- maintainVisibleContentPosition = false,
3604
+ maintainVisibleContentPosition: maintainVisibleContentPositionProp,
3582
3605
  numColumns: numColumnsProp = 1,
3583
3606
  onEndReached,
3584
3607
  onEndReachedThreshold = 0.5,
@@ -3616,6 +3639,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3616
3639
  const style = { ...StyleSheet.flatten(styleProp) };
3617
3640
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
3618
3641
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
3642
+ const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
3643
+ maintainVisibleContentPositionProp
3644
+ );
3619
3645
  const [renderNum, setRenderNum] = useState(0);
3620
3646
  const initialScrollProp = initialScrollAtEnd ? { index: Math.max(0, dataProp.length - 1), viewOffset: -stylePaddingBottomState } : initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
3621
3647
  const [canRender, setCanRender] = React3.useState(!IsNewArchitecture);
@@ -3700,7 +3726,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3700
3726
  };
3701
3727
  const internalState = ctx.state;
3702
3728
  internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
3703
- set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
3729
+ set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPositionConfig);
3704
3730
  set$(ctx, "extraData", extraData);
3705
3731
  }
3706
3732
  refState.current = ctx.state;
@@ -3731,7 +3757,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3731
3757
  keyExtractor,
3732
3758
  maintainScrollAtEnd,
3733
3759
  maintainScrollAtEndThreshold,
3734
- maintainVisibleContentPosition,
3760
+ maintainVisibleContentPosition: maintainVisibleContentPositionConfig,
3735
3761
  numColumns: numColumnsProp,
3736
3762
  onEndReached,
3737
3763
  onEndReachedThreshold,
@@ -3766,7 +3792,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3766
3792
  setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3767
3793
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3768
3794
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3769
- if (paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3795
+ if (maintainVisibleContentPositionConfig.scroll && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3770
3796
  if (state.scroll < 0) {
3771
3797
  paddingDiff += state.scroll;
3772
3798
  }
@@ -3801,7 +3827,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3801
3827
  value = 0;
3802
3828
  }
3803
3829
  if (!value) {
3804
- state.didFinishInitialScroll = true;
3830
+ setInitialRenderState(ctx, { didInitialScroll: true });
3805
3831
  }
3806
3832
  return value;
3807
3833
  }, [renderNum]);
@@ -3923,7 +3949,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3923
3949
  initialContentOffset,
3924
3950
  ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
3925
3951
  ListHeaderComponent,
3926
- maintainVisibleContentPosition,
3927
3952
  onLayout,
3928
3953
  onLayoutHeader,
3929
3954
  onMomentumScrollEnd: fns.onMomentumScrollEnd,
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { Dispatch, SetStateAction } from 'react';
3
- import { L as LegendListProps, a as LegendListRef, V as ViewabilityCallback, b as ViewabilityAmountCallback, c as LegendListRecyclingState } from './types-1Hgg1rTO.mjs';
4
- export { C as ColumnWrapperStyle, u as GetRenderedItem, G as GetRenderedItemResult, s as InitialScrollAnchor, I as InternalState, d as LegendListPropsBase, f as LegendListRenderItemProps, g as LegendListState, M as MaintainScrollAtEndOptions, O as OnViewableItemsChanged, p as ScrollIndexWithOffset, r as ScrollIndexWithOffsetAndContentOffset, q as ScrollIndexWithOffsetPosition, S as ScrollTarget, T as ThresholdSnapshot, m as TypedForwardRef, n as TypedMemo, i as ViewAmountToken, h as ViewToken, l as ViewabilityConfig, j as ViewabilityConfigCallbackPair, k as ViewabilityConfigCallbackPairs, e as ViewableRange, t as typedForwardRef, o as typedMemo } from './types-1Hgg1rTO.mjs';
3
+ import { L as LegendListProps, a as LegendListRef, V as ViewabilityCallback, b as ViewabilityAmountCallback, c as LegendListRecyclingState } from './types-C83aU7VI.mjs';
4
+ export { C as ColumnWrapperStyle, w as GetRenderedItem, G as GetRenderedItemResult, v as InitialScrollAnchor, I as InternalState, d as LegendListPropsBase, h as LegendListRenderItemProps, i as LegendListState, f as MaintainScrollAtEndOptions, M as MaintainVisibleContentPositionConfig, e as MaintainVisibleContentPositionNormalized, O as OnViewableItemsChanged, r as ScrollIndexWithOffset, u as ScrollIndexWithOffsetAndContentOffset, s as ScrollIndexWithOffsetPosition, S as ScrollTarget, T as ThresholdSnapshot, o as TypedForwardRef, p as TypedMemo, k as ViewAmountToken, j as ViewToken, n as ViewabilityConfig, l as ViewabilityConfigCallbackPair, m as ViewabilityConfigCallbackPairs, g as ViewableRange, t as typedForwardRef, q as typedMemo } from './types-C83aU7VI.mjs';
5
5
  import 'react-native';
6
6
  import 'react-native-reanimated';
7
7
 
package/index.native.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { Dispatch, SetStateAction } from 'react';
3
- import { L as LegendListProps, a as LegendListRef, V as ViewabilityCallback, b as ViewabilityAmountCallback, c as LegendListRecyclingState } from './types-1Hgg1rTO.js';
4
- export { C as ColumnWrapperStyle, u as GetRenderedItem, G as GetRenderedItemResult, s as InitialScrollAnchor, I as InternalState, d as LegendListPropsBase, f as LegendListRenderItemProps, g as LegendListState, M as MaintainScrollAtEndOptions, O as OnViewableItemsChanged, p as ScrollIndexWithOffset, r as ScrollIndexWithOffsetAndContentOffset, q as ScrollIndexWithOffsetPosition, S as ScrollTarget, T as ThresholdSnapshot, m as TypedForwardRef, n as TypedMemo, i as ViewAmountToken, h as ViewToken, l as ViewabilityConfig, j as ViewabilityConfigCallbackPair, k as ViewabilityConfigCallbackPairs, e as ViewableRange, t as typedForwardRef, o as typedMemo } from './types-1Hgg1rTO.js';
3
+ import { L as LegendListProps, a as LegendListRef, V as ViewabilityCallback, b as ViewabilityAmountCallback, c as LegendListRecyclingState } from './types-C83aU7VI.js';
4
+ export { C as ColumnWrapperStyle, w as GetRenderedItem, G as GetRenderedItemResult, v as InitialScrollAnchor, I as InternalState, d as LegendListPropsBase, h as LegendListRenderItemProps, i as LegendListState, f as MaintainScrollAtEndOptions, M as MaintainVisibleContentPositionConfig, e as MaintainVisibleContentPositionNormalized, O as OnViewableItemsChanged, r as ScrollIndexWithOffset, u as ScrollIndexWithOffsetAndContentOffset, s as ScrollIndexWithOffsetPosition, S as ScrollTarget, T as ThresholdSnapshot, o as TypedForwardRef, p as TypedMemo, k as ViewAmountToken, j as ViewToken, n as ViewabilityConfig, l as ViewabilityConfigCallbackPair, m as ViewabilityConfigCallbackPairs, g as ViewableRange, t as typedForwardRef, q as typedMemo } from './types-C83aU7VI.js';
5
5
  import 'react-native';
6
6
  import 'react-native-reanimated';
7
7