@legendapp/list 3.0.0-beta.13 → 3.0.0-beta.15

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
@@ -3,6 +3,25 @@
3
3
  - Feat: Web support
4
4
  - Breaking: Some of the maintainVisibleContentPosition behavior for preventing jumping while scrolling is now core behavior, and the behavior for maintaining scroll position when adding data is controlled by the prop, which is now disabled by default.
5
5
 
6
+ ## 2.0.18
7
+ - Improvement: KeyboardAvoidingLegendList now supports KeyboardGestureArea with improved interactive behavior
8
+
9
+ ## 2.0.17
10
+ - Feat: Add stickyHeaderOffset property to control sticky header positioning
11
+ - Feat: Add sticky header backdrop component support
12
+ - Fix: Improve KeyboardAvoidingLegendList quality by using animated contentOffset y instead of reanimated scrollTo
13
+ - Fix: Initial scroll could sometimes be out of range beyond the ScrollView if some items are much larger than the estimated size
14
+ - Fix: Item layout updates now work correctly when container is the exact same size as previous item on old arch
15
+
16
+ ## 2.0.16
17
+ - Feat: Add KeyboardAvoidingLegendList component for better keyboard handling integration
18
+ - Fix: Stale containers are not being removed and overlap with new data when using getItemType #335
19
+ - Fix: Suppress keyExtractor warning when using lazy list mode #330
20
+
21
+ ## 2.0.15
22
+ - Fix: Container allocation for sticky headers could duplicate containers, causing rendering issues
23
+ - Fix: Sticky positioned components scrolling out of viewport after scrolling distance exceeded 5000
24
+
6
25
  ## 2.0.14
7
26
  - Feat: Add dataVersion prop to trigger re-render when mutating the data array in place
8
27
 
package/README.md CHANGED
@@ -27,7 +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 `{ dataChanged: true }` to also anchor during data updates; pass `false` to disable; pass `{ scroll: false }` to opt out of scroll-time stabilization.
30
+ * `maintainVisibleContentPosition`: Keeps visible content steady during size/layout changes while scrolling up or when items resize above the viewport (default). Pass `true` or `{ data: true }` to also anchor during data updates; pass `false` to disable; pass `{ size: false }` to opt out of scroll-time stabilization.
31
31
  * `alignItemsAtEnd`: (boolean) Useful for chat UIs, content smaller than the View will be aligned to the bottom of the list.
32
32
 
33
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-BSoW8ni4.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-BSoW8ni4.mjs';
3
+ import { L as LegendListProps, a as LegendListRef, V as ViewabilityCallback, b as ViewabilityAmountCallback, c as LegendListRecyclingState } from './types-Dj2MEm9V.mjs';
4
+ export { C as ColumnWrapperStyle, x as GetRenderedItem, G as GetRenderedItemResult, w as InitialScrollAnchor, I as InternalState, d as LegendListPropsBase, i as LegendListRenderItemProps, j as LegendListState, f as MaintainScrollAtEndOptions, M as MaintainVisibleContentPositionConfig, e as MaintainVisibleContentPositionNormalized, O as OnViewableItemsChanged, s as ScrollIndexWithOffset, v as ScrollIndexWithOffsetAndContentOffset, u as ScrollIndexWithOffsetPosition, g as ScrollTarget, S as StickyHeaderConfig, T as ThresholdSnapshot, p as TypedForwardRef, q as TypedMemo, l as ViewAmountToken, k as ViewToken, o as ViewabilityConfig, m as ViewabilityConfigCallbackPair, n as ViewabilityConfigCallbackPairs, h as ViewableRange, t as typedForwardRef, r as typedMemo } from './types-Dj2MEm9V.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-BSoW8ni4.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-BSoW8ni4.js';
3
+ import { L as LegendListProps, a as LegendListRef, V as ViewabilityCallback, b as ViewabilityAmountCallback, c as LegendListRecyclingState } from './types-Dj2MEm9V.js';
4
+ export { C as ColumnWrapperStyle, x as GetRenderedItem, G as GetRenderedItemResult, w as InitialScrollAnchor, I as InternalState, d as LegendListPropsBase, i as LegendListRenderItemProps, j as LegendListState, f as MaintainScrollAtEndOptions, M as MaintainVisibleContentPositionConfig, e as MaintainVisibleContentPositionNormalized, O as OnViewableItemsChanged, s as ScrollIndexWithOffset, v as ScrollIndexWithOffsetAndContentOffset, u as ScrollIndexWithOffsetPosition, g as ScrollTarget, S as StickyHeaderConfig, T as ThresholdSnapshot, p as TypedForwardRef, q as TypedMemo, l as ViewAmountToken, k as ViewToken, o as ViewabilityConfig, m as ViewabilityConfigCallbackPair, n as ViewabilityConfigCallbackPairs, h as ViewableRange, t as typedForwardRef, r as typedMemo } from './types-Dj2MEm9V.js';
5
5
  import 'react-native';
6
6
  import 'react-native-reanimated';
7
7
 
package/index.js CHANGED
@@ -622,7 +622,8 @@ var Container = typedMemo(function Container2({
622
622
  horizontal,
623
623
  getRenderedItem: getRenderedItem2,
624
624
  updateItemSize: updateItemSize2,
625
- ItemSeparatorComponent
625
+ ItemSeparatorComponent,
626
+ stickyHeaderConfig
626
627
  }) {
627
628
  const ctx = useStateContext();
628
629
  const { columnWrapperStyle, animatedScrollY } = ctx;
@@ -736,6 +737,7 @@ var Container = typedMemo(function Container2({
736
737
  key: recycleItems ? void 0 : itemKey,
737
738
  onLayout,
738
739
  refView: ref,
740
+ stickyHeaderConfig,
739
741
  stickyOffset: isSticky ? stickyOffset : void 0,
740
742
  style
741
743
  },
@@ -895,7 +897,8 @@ var Containers = typedMemo(function Containers2({
895
897
  ItemSeparatorComponent,
896
898
  waitForInitialLayout,
897
899
  updateItemSize: updateItemSize2,
898
- getRenderedItem: getRenderedItem2
900
+ getRenderedItem: getRenderedItem2,
901
+ stickyHeaderConfig
899
902
  }) {
900
903
  const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
901
904
  const containers = [];
@@ -910,6 +913,7 @@ var Containers = typedMemo(function Containers2({
910
913
  id: i,
911
914
  key: i,
912
915
  recycleItems,
916
+ stickyHeaderConfig,
913
917
  updateItemSize: updateItemSize2
914
918
  }
915
919
  )
@@ -1173,8 +1177,6 @@ var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
1173
1177
  useOnLayoutSync({ onLayoutChange, ref });
1174
1178
  return /* @__PURE__ */ React3__namespace.createElement("div", { ...rest, ref }, children);
1175
1179
  };
1176
-
1177
- // src/components/ListComponent.tsx
1178
1180
  var getComponent = (Component) => {
1179
1181
  if (React3__namespace.isValidElement(Component)) {
1180
1182
  return Component;
@@ -1184,6 +1186,8 @@ var getComponent = (Component) => {
1184
1186
  }
1185
1187
  return null;
1186
1188
  };
1189
+
1190
+ // src/components/ListComponent.tsx
1187
1191
  var ListComponent = typedMemo(function ListComponent2({
1188
1192
  canRender,
1189
1193
  style,
@@ -1208,6 +1212,7 @@ var ListComponent = typedMemo(function ListComponent2({
1208
1212
  scrollAdjustHandler,
1209
1213
  onLayoutHeader,
1210
1214
  snapToIndices,
1215
+ stickyHeaderConfig,
1211
1216
  stickyHeaderIndices,
1212
1217
  ...rest
1213
1218
  }) {
@@ -1230,7 +1235,7 @@ var ListComponent = typedMemo(function ListComponent2({
1230
1235
  ],
1231
1236
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1232
1237
  horizontal,
1233
- maintainVisibleContentPosition: maintainVisibleContentPosition.scroll || maintainVisibleContentPosition.dataChanged ? { minIndexForVisible: 0 } : void 0,
1238
+ maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
1234
1239
  onLayout,
1235
1240
  onScroll: onScroll2,
1236
1241
  ref: refScrollView,
@@ -1248,6 +1253,7 @@ var ListComponent = typedMemo(function ListComponent2({
1248
1253
  horizontal,
1249
1254
  ItemSeparatorComponent,
1250
1255
  recycleItems,
1256
+ stickyHeaderConfig,
1251
1257
  updateItemSize: updateItemSize2,
1252
1258
  waitForInitialLayout
1253
1259
  }
@@ -1442,7 +1448,7 @@ function clampScrollOffset(ctx, offset) {
1442
1448
  const state = ctx.state;
1443
1449
  const contentSize = getContentSize(ctx);
1444
1450
  let clampedOffset = offset;
1445
- if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength)) {
1451
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && state.lastLayout) {
1446
1452
  const maxOffset = Math.max(0, contentSize - state.scrollLength);
1447
1453
  clampedOffset = Math.min(offset, maxOffset);
1448
1454
  }
@@ -1472,6 +1478,7 @@ function finishScrollTo(ctx) {
1472
1478
  var _a3, _b;
1473
1479
  const state = ctx.state;
1474
1480
  if (state == null ? void 0 : state.scrollingTo) {
1481
+ const scrollingTo = state.scrollingTo;
1475
1482
  state.scrollHistory.length = 0;
1476
1483
  state.initialScroll = void 0;
1477
1484
  state.initialAnchor = void 0;
@@ -1483,7 +1490,7 @@ function finishScrollTo(ctx) {
1483
1490
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1484
1491
  }
1485
1492
  {
1486
- state.scrollAdjustHandler.commitPendingAdjust();
1493
+ state.scrollAdjustHandler.commitPendingAdjust(scrollingTo);
1487
1494
  }
1488
1495
  setInitialRenderState(ctx, { didInitialScroll: true });
1489
1496
  }
@@ -1775,7 +1782,7 @@ function prepareMVCP(ctx, dataChanged) {
1775
1782
  const state = ctx.state;
1776
1783
  const { idsInView, positions, props } = state;
1777
1784
  const {
1778
- maintainVisibleContentPosition: { dataChanged: mvcpdataChanged, scroll: mvcpScroll }
1785
+ maintainVisibleContentPosition: { data: mvcpData, size: mvcpScroll }
1779
1786
  } = props;
1780
1787
  const scrollingTo = state.scrollingTo;
1781
1788
  let prevPosition;
@@ -1783,7 +1790,7 @@ function prepareMVCP(ctx, dataChanged) {
1783
1790
  const idsInViewWithPositions = [];
1784
1791
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1785
1792
  const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1786
- const shouldMVCP = dataChanged ? mvcpdataChanged : mvcpScroll;
1793
+ const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
1787
1794
  const indexByKey = state.indexByKey;
1788
1795
  if (shouldMVCP) {
1789
1796
  if (scrollTarget !== void 0) {
@@ -1806,7 +1813,7 @@ function prepareMVCP(ctx, dataChanged) {
1806
1813
  }
1807
1814
  return () => {
1808
1815
  let positionDiff = 0;
1809
- if (dataChanged && targetId === void 0 && mvcpdataChanged) {
1816
+ if (dataChanged && targetId === void 0 && mvcpData) {
1810
1817
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1811
1818
  const { id, position } = idsInViewWithPositions[i];
1812
1819
  const newPosition = positions.get(id);
@@ -2759,7 +2766,7 @@ function calculateItemsInView(ctx, params = {}) {
2759
2766
  if (needNewContainers.length > 0) {
2760
2767
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
2761
2768
  const itemType = getItemType(data[i], i);
2762
- return itemType ? String(itemType) : "";
2769
+ return itemType !== void 0 ? String(itemType) : "";
2763
2770
  }) : void 0;
2764
2771
  const availableContainers = findAvailableContainers(
2765
2772
  ctx,
@@ -3071,8 +3078,10 @@ function doInitialAllocateContainers(ctx) {
3071
3078
  const num = Math.min(20, data.length);
3072
3079
  for (let i = 0; i < num; i++) {
3073
3080
  const item = data[i];
3074
- const itemType = getItemType ? (_a3 = getItemType(item, i)) != null ? _a3 : "" : "";
3075
- totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
3081
+ if (item !== void 0) {
3082
+ const itemType = (_a3 = getItemType == null ? void 0 : getItemType(item, i)) != null ? _a3 : "";
3083
+ totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
3084
+ }
3076
3085
  }
3077
3086
  averageItemSize = totalSize / num;
3078
3087
  } else {
@@ -3202,17 +3211,28 @@ var ScrollAdjustHandler = class {
3202
3211
  getAdjust() {
3203
3212
  return this.appliedAdjust;
3204
3213
  }
3205
- commitPendingAdjust() {
3214
+ commitPendingAdjust(scrollTarget) {
3206
3215
  {
3207
3216
  const state = this.ctx.state;
3208
3217
  const pending = this.pendingAdjust;
3218
+ this.pendingAdjust = 0;
3209
3219
  if (pending !== 0) {
3210
- this.pendingAdjust = 0;
3211
- this.appliedAdjust += pending;
3212
- state.scroll += pending;
3213
- state.scrollForNextCalculateItemsInView = void 0;
3220
+ let targetScroll;
3221
+ if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
3222
+ const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
3223
+ targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
3224
+ targetScroll = clampScrollOffset(this.ctx, targetScroll);
3225
+ } else {
3226
+ targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
3227
+ }
3228
+ const adjustment = targetScroll - state.scroll;
3229
+ if (Math.abs(adjustment) > 0.1 || Math.abs(pending) > 0.1) {
3230
+ this.appliedAdjust += adjustment;
3231
+ state.scroll = targetScroll;
3232
+ state.scrollForNextCalculateItemsInView = void 0;
3233
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3234
+ }
3214
3235
  set$(this.ctx, "scrollAdjustPending", 0);
3215
- set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3216
3236
  calculateItemsInView(this.ctx);
3217
3237
  }
3218
3238
  }
@@ -3353,6 +3373,12 @@ function updateOneItemSize(ctx, itemKey, sizeObj) {
3353
3373
  }
3354
3374
  return 0;
3355
3375
  }
3376
+ function useWrapIfItem(fn) {
3377
+ return React3.useMemo(
3378
+ () => fn ? (arg1, arg2, arg3) => arg1 !== void 0 && arg2 !== void 0 ? fn(arg1, arg2, arg3) : void 0 : void 0,
3379
+ [fn]
3380
+ );
3381
+ }
3356
3382
  var useCombinedRef = (...refs) => {
3357
3383
  const callback = React3.useCallback((element) => {
3358
3384
  for (const ref of refs) {
@@ -3515,18 +3541,18 @@ function getRenderedItem(ctx, key) {
3515
3541
  function normalizeMaintainVisibleContentPosition(value) {
3516
3542
  var _a3, _b;
3517
3543
  if (value === true) {
3518
- return { dataChanged: true, scroll: true };
3544
+ return { data: true, size: true };
3519
3545
  }
3520
3546
  if (value && typeof value === "object") {
3521
3547
  return {
3522
- dataChanged: (_a3 = value.dataChanged) != null ? _a3 : false,
3523
- scroll: (_b = value.scroll) != null ? _b : true
3548
+ data: (_a3 = value.data) != null ? _a3 : false,
3549
+ size: (_b = value.size) != null ? _b : true
3524
3550
  };
3525
3551
  }
3526
3552
  if (value === false) {
3527
- return { dataChanged: false, scroll: false };
3553
+ return { data: false, size: false };
3528
3554
  }
3529
- return { dataChanged: false, scroll: true };
3555
+ return { data: false, size: true };
3530
3556
  }
3531
3557
  function useThrottleDebounce(mode) {
3532
3558
  const timeoutRef = React3.useRef(null);
@@ -3652,6 +3678,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3652
3678
  viewabilityConfig,
3653
3679
  viewabilityConfigCallbackPairs,
3654
3680
  waitForInitialLayout = true,
3681
+ stickyHeaderConfig,
3655
3682
  ...rest
3656
3683
  } = props;
3657
3684
  const animatedPropsInternal = props.animatedPropsInternal;
@@ -3769,13 +3796,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3769
3796
  data: dataProp,
3770
3797
  dataVersion,
3771
3798
  estimatedItemSize,
3772
- getEstimatedItemSize,
3773
- getFixedItemSize,
3774
- getItemType,
3799
+ getEstimatedItemSize: useWrapIfItem(getEstimatedItemSize),
3800
+ getFixedItemSize: useWrapIfItem(getFixedItemSize),
3801
+ getItemType: useWrapIfItem(getItemType),
3775
3802
  horizontal: !!horizontal,
3776
3803
  initialContainerPoolRatio,
3777
3804
  itemsAreEqual,
3778
- keyExtractor,
3805
+ keyExtractor: useWrapIfItem(keyExtractor),
3779
3806
  maintainScrollAtEnd,
3780
3807
  maintainScrollAtEndThreshold,
3781
3808
  maintainVisibleContentPosition: maintainVisibleContentPositionConfig,
@@ -3813,7 +3840,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3813
3840
  setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3814
3841
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3815
3842
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3816
- if (maintainVisibleContentPositionConfig.scroll && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3843
+ if (maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3817
3844
  if (state.scroll < 0) {
3818
3845
  paddingDiff += state.scroll;
3819
3846
  }
@@ -3989,6 +4016,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3989
4016
  scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3990
4017
  scrollEventThrottle: 0,
3991
4018
  snapToIndices,
4019
+ stickyHeaderConfig,
3992
4020
  stickyHeaderIndices,
3993
4021
  style,
3994
4022
  updateItemSize: fns.updateItemSize,
package/index.mjs CHANGED
@@ -601,7 +601,8 @@ var Container = typedMemo(function Container2({
601
601
  horizontal,
602
602
  getRenderedItem: getRenderedItem2,
603
603
  updateItemSize: updateItemSize2,
604
- ItemSeparatorComponent
604
+ ItemSeparatorComponent,
605
+ stickyHeaderConfig
605
606
  }) {
606
607
  const ctx = useStateContext();
607
608
  const { columnWrapperStyle, animatedScrollY } = ctx;
@@ -715,6 +716,7 @@ var Container = typedMemo(function Container2({
715
716
  key: recycleItems ? void 0 : itemKey,
716
717
  onLayout,
717
718
  refView: ref,
719
+ stickyHeaderConfig,
718
720
  stickyOffset: isSticky ? stickyOffset : void 0,
719
721
  style
720
722
  },
@@ -874,7 +876,8 @@ var Containers = typedMemo(function Containers2({
874
876
  ItemSeparatorComponent,
875
877
  waitForInitialLayout,
876
878
  updateItemSize: updateItemSize2,
877
- getRenderedItem: getRenderedItem2
879
+ getRenderedItem: getRenderedItem2,
880
+ stickyHeaderConfig
878
881
  }) {
879
882
  const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
880
883
  const containers = [];
@@ -889,6 +892,7 @@ var Containers = typedMemo(function Containers2({
889
892
  id: i,
890
893
  key: i,
891
894
  recycleItems,
895
+ stickyHeaderConfig,
892
896
  updateItemSize: updateItemSize2
893
897
  }
894
898
  )
@@ -1152,8 +1156,6 @@ var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
1152
1156
  useOnLayoutSync({ onLayoutChange, ref });
1153
1157
  return /* @__PURE__ */ React3.createElement("div", { ...rest, ref }, children);
1154
1158
  };
1155
-
1156
- // src/components/ListComponent.tsx
1157
1159
  var getComponent = (Component) => {
1158
1160
  if (React3.isValidElement(Component)) {
1159
1161
  return Component;
@@ -1163,6 +1165,8 @@ var getComponent = (Component) => {
1163
1165
  }
1164
1166
  return null;
1165
1167
  };
1168
+
1169
+ // src/components/ListComponent.tsx
1166
1170
  var ListComponent = typedMemo(function ListComponent2({
1167
1171
  canRender,
1168
1172
  style,
@@ -1187,6 +1191,7 @@ var ListComponent = typedMemo(function ListComponent2({
1187
1191
  scrollAdjustHandler,
1188
1192
  onLayoutHeader,
1189
1193
  snapToIndices,
1194
+ stickyHeaderConfig,
1190
1195
  stickyHeaderIndices,
1191
1196
  ...rest
1192
1197
  }) {
@@ -1209,7 +1214,7 @@ var ListComponent = typedMemo(function ListComponent2({
1209
1214
  ],
1210
1215
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1211
1216
  horizontal,
1212
- maintainVisibleContentPosition: maintainVisibleContentPosition.scroll || maintainVisibleContentPosition.dataChanged ? { minIndexForVisible: 0 } : void 0,
1217
+ maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
1213
1218
  onLayout,
1214
1219
  onScroll: onScroll2,
1215
1220
  ref: refScrollView,
@@ -1227,6 +1232,7 @@ var ListComponent = typedMemo(function ListComponent2({
1227
1232
  horizontal,
1228
1233
  ItemSeparatorComponent,
1229
1234
  recycleItems,
1235
+ stickyHeaderConfig,
1230
1236
  updateItemSize: updateItemSize2,
1231
1237
  waitForInitialLayout
1232
1238
  }
@@ -1421,7 +1427,7 @@ function clampScrollOffset(ctx, offset) {
1421
1427
  const state = ctx.state;
1422
1428
  const contentSize = getContentSize(ctx);
1423
1429
  let clampedOffset = offset;
1424
- if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength)) {
1430
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && state.lastLayout) {
1425
1431
  const maxOffset = Math.max(0, contentSize - state.scrollLength);
1426
1432
  clampedOffset = Math.min(offset, maxOffset);
1427
1433
  }
@@ -1451,6 +1457,7 @@ function finishScrollTo(ctx) {
1451
1457
  var _a3, _b;
1452
1458
  const state = ctx.state;
1453
1459
  if (state == null ? void 0 : state.scrollingTo) {
1460
+ const scrollingTo = state.scrollingTo;
1454
1461
  state.scrollHistory.length = 0;
1455
1462
  state.initialScroll = void 0;
1456
1463
  state.initialAnchor = void 0;
@@ -1462,7 +1469,7 @@ function finishScrollTo(ctx) {
1462
1469
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1463
1470
  }
1464
1471
  {
1465
- state.scrollAdjustHandler.commitPendingAdjust();
1472
+ state.scrollAdjustHandler.commitPendingAdjust(scrollingTo);
1466
1473
  }
1467
1474
  setInitialRenderState(ctx, { didInitialScroll: true });
1468
1475
  }
@@ -1754,7 +1761,7 @@ function prepareMVCP(ctx, dataChanged) {
1754
1761
  const state = ctx.state;
1755
1762
  const { idsInView, positions, props } = state;
1756
1763
  const {
1757
- maintainVisibleContentPosition: { dataChanged: mvcpdataChanged, scroll: mvcpScroll }
1764
+ maintainVisibleContentPosition: { data: mvcpData, size: mvcpScroll }
1758
1765
  } = props;
1759
1766
  const scrollingTo = state.scrollingTo;
1760
1767
  let prevPosition;
@@ -1762,7 +1769,7 @@ function prepareMVCP(ctx, dataChanged) {
1762
1769
  const idsInViewWithPositions = [];
1763
1770
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1764
1771
  const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1765
- const shouldMVCP = dataChanged ? mvcpdataChanged : mvcpScroll;
1772
+ const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
1766
1773
  const indexByKey = state.indexByKey;
1767
1774
  if (shouldMVCP) {
1768
1775
  if (scrollTarget !== void 0) {
@@ -1785,7 +1792,7 @@ function prepareMVCP(ctx, dataChanged) {
1785
1792
  }
1786
1793
  return () => {
1787
1794
  let positionDiff = 0;
1788
- if (dataChanged && targetId === void 0 && mvcpdataChanged) {
1795
+ if (dataChanged && targetId === void 0 && mvcpData) {
1789
1796
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1790
1797
  const { id, position } = idsInViewWithPositions[i];
1791
1798
  const newPosition = positions.get(id);
@@ -2738,7 +2745,7 @@ function calculateItemsInView(ctx, params = {}) {
2738
2745
  if (needNewContainers.length > 0) {
2739
2746
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
2740
2747
  const itemType = getItemType(data[i], i);
2741
- return itemType ? String(itemType) : "";
2748
+ return itemType !== void 0 ? String(itemType) : "";
2742
2749
  }) : void 0;
2743
2750
  const availableContainers = findAvailableContainers(
2744
2751
  ctx,
@@ -3050,8 +3057,10 @@ function doInitialAllocateContainers(ctx) {
3050
3057
  const num = Math.min(20, data.length);
3051
3058
  for (let i = 0; i < num; i++) {
3052
3059
  const item = data[i];
3053
- const itemType = getItemType ? (_a3 = getItemType(item, i)) != null ? _a3 : "" : "";
3054
- totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
3060
+ if (item !== void 0) {
3061
+ const itemType = (_a3 = getItemType == null ? void 0 : getItemType(item, i)) != null ? _a3 : "";
3062
+ totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
3063
+ }
3055
3064
  }
3056
3065
  averageItemSize = totalSize / num;
3057
3066
  } else {
@@ -3181,17 +3190,28 @@ var ScrollAdjustHandler = class {
3181
3190
  getAdjust() {
3182
3191
  return this.appliedAdjust;
3183
3192
  }
3184
- commitPendingAdjust() {
3193
+ commitPendingAdjust(scrollTarget) {
3185
3194
  {
3186
3195
  const state = this.ctx.state;
3187
3196
  const pending = this.pendingAdjust;
3197
+ this.pendingAdjust = 0;
3188
3198
  if (pending !== 0) {
3189
- this.pendingAdjust = 0;
3190
- this.appliedAdjust += pending;
3191
- state.scroll += pending;
3192
- state.scrollForNextCalculateItemsInView = void 0;
3199
+ let targetScroll;
3200
+ if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
3201
+ const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
3202
+ targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
3203
+ targetScroll = clampScrollOffset(this.ctx, targetScroll);
3204
+ } else {
3205
+ targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
3206
+ }
3207
+ const adjustment = targetScroll - state.scroll;
3208
+ if (Math.abs(adjustment) > 0.1 || Math.abs(pending) > 0.1) {
3209
+ this.appliedAdjust += adjustment;
3210
+ state.scroll = targetScroll;
3211
+ state.scrollForNextCalculateItemsInView = void 0;
3212
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3213
+ }
3193
3214
  set$(this.ctx, "scrollAdjustPending", 0);
3194
- set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3195
3215
  calculateItemsInView(this.ctx);
3196
3216
  }
3197
3217
  }
@@ -3332,6 +3352,12 @@ function updateOneItemSize(ctx, itemKey, sizeObj) {
3332
3352
  }
3333
3353
  return 0;
3334
3354
  }
3355
+ function useWrapIfItem(fn) {
3356
+ return useMemo(
3357
+ () => fn ? (arg1, arg2, arg3) => arg1 !== void 0 && arg2 !== void 0 ? fn(arg1, arg2, arg3) : void 0 : void 0,
3358
+ [fn]
3359
+ );
3360
+ }
3335
3361
  var useCombinedRef = (...refs) => {
3336
3362
  const callback = useCallback((element) => {
3337
3363
  for (const ref of refs) {
@@ -3494,18 +3520,18 @@ function getRenderedItem(ctx, key) {
3494
3520
  function normalizeMaintainVisibleContentPosition(value) {
3495
3521
  var _a3, _b;
3496
3522
  if (value === true) {
3497
- return { dataChanged: true, scroll: true };
3523
+ return { data: true, size: true };
3498
3524
  }
3499
3525
  if (value && typeof value === "object") {
3500
3526
  return {
3501
- dataChanged: (_a3 = value.dataChanged) != null ? _a3 : false,
3502
- scroll: (_b = value.scroll) != null ? _b : true
3527
+ data: (_a3 = value.data) != null ? _a3 : false,
3528
+ size: (_b = value.size) != null ? _b : true
3503
3529
  };
3504
3530
  }
3505
3531
  if (value === false) {
3506
- return { dataChanged: false, scroll: false };
3532
+ return { data: false, size: false };
3507
3533
  }
3508
- return { dataChanged: false, scroll: true };
3534
+ return { data: false, size: true };
3509
3535
  }
3510
3536
  function useThrottleDebounce(mode) {
3511
3537
  const timeoutRef = useRef(null);
@@ -3631,6 +3657,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3631
3657
  viewabilityConfig,
3632
3658
  viewabilityConfigCallbackPairs,
3633
3659
  waitForInitialLayout = true,
3660
+ stickyHeaderConfig,
3634
3661
  ...rest
3635
3662
  } = props;
3636
3663
  const animatedPropsInternal = props.animatedPropsInternal;
@@ -3748,13 +3775,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3748
3775
  data: dataProp,
3749
3776
  dataVersion,
3750
3777
  estimatedItemSize,
3751
- getEstimatedItemSize,
3752
- getFixedItemSize,
3753
- getItemType,
3778
+ getEstimatedItemSize: useWrapIfItem(getEstimatedItemSize),
3779
+ getFixedItemSize: useWrapIfItem(getFixedItemSize),
3780
+ getItemType: useWrapIfItem(getItemType),
3754
3781
  horizontal: !!horizontal,
3755
3782
  initialContainerPoolRatio,
3756
3783
  itemsAreEqual,
3757
- keyExtractor,
3784
+ keyExtractor: useWrapIfItem(keyExtractor),
3758
3785
  maintainScrollAtEnd,
3759
3786
  maintainScrollAtEndThreshold,
3760
3787
  maintainVisibleContentPosition: maintainVisibleContentPositionConfig,
@@ -3792,7 +3819,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3792
3819
  setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3793
3820
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3794
3821
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3795
- if (maintainVisibleContentPositionConfig.scroll && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3822
+ if (maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3796
3823
  if (state.scroll < 0) {
3797
3824
  paddingDiff += state.scroll;
3798
3825
  }
@@ -3968,6 +3995,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3968
3995
  scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3969
3996
  scrollEventThrottle: 0,
3970
3997
  snapToIndices,
3998
+ stickyHeaderConfig,
3971
3999
  stickyHeaderIndices,
3972
4000
  style,
3973
4001
  updateItemSize: fns.updateItemSize,
@@ -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-BSoW8ni4.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-BSoW8ni4.mjs';
3
+ import { L as LegendListProps, a as LegendListRef, V as ViewabilityCallback, b as ViewabilityAmountCallback, c as LegendListRecyclingState } from './types-Dj2MEm9V.mjs';
4
+ export { C as ColumnWrapperStyle, x as GetRenderedItem, G as GetRenderedItemResult, w as InitialScrollAnchor, I as InternalState, d as LegendListPropsBase, i as LegendListRenderItemProps, j as LegendListState, f as MaintainScrollAtEndOptions, M as MaintainVisibleContentPositionConfig, e as MaintainVisibleContentPositionNormalized, O as OnViewableItemsChanged, s as ScrollIndexWithOffset, v as ScrollIndexWithOffsetAndContentOffset, u as ScrollIndexWithOffsetPosition, g as ScrollTarget, S as StickyHeaderConfig, T as ThresholdSnapshot, p as TypedForwardRef, q as TypedMemo, l as ViewAmountToken, k as ViewToken, o as ViewabilityConfig, m as ViewabilityConfigCallbackPair, n as ViewabilityConfigCallbackPairs, h as ViewableRange, t as typedForwardRef, r as typedMemo } from './types-Dj2MEm9V.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-BSoW8ni4.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-BSoW8ni4.js';
3
+ import { L as LegendListProps, a as LegendListRef, V as ViewabilityCallback, b as ViewabilityAmountCallback, c as LegendListRecyclingState } from './types-Dj2MEm9V.js';
4
+ export { C as ColumnWrapperStyle, x as GetRenderedItem, G as GetRenderedItemResult, w as InitialScrollAnchor, I as InternalState, d as LegendListPropsBase, i as LegendListRenderItemProps, j as LegendListState, f as MaintainScrollAtEndOptions, M as MaintainVisibleContentPositionConfig, e as MaintainVisibleContentPositionNormalized, O as OnViewableItemsChanged, s as ScrollIndexWithOffset, v as ScrollIndexWithOffsetAndContentOffset, u as ScrollIndexWithOffsetPosition, g as ScrollTarget, S as StickyHeaderConfig, T as ThresholdSnapshot, p as TypedForwardRef, q as TypedMemo, l as ViewAmountToken, k as ViewToken, o as ViewabilityConfig, m as ViewabilityConfigCallbackPair, n as ViewabilityConfigCallbackPairs, h as ViewableRange, t as typedForwardRef, r as typedMemo } from './types-Dj2MEm9V.js';
5
5
  import 'react-native';
6
6
  import 'react-native-reanimated';
7
7