@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.
@@ -339,6 +339,15 @@ function useValue$(key, params) {
339
339
  }
340
340
  var typedForwardRef = React2.forwardRef;
341
341
  var typedMemo = React2.memo;
342
+ var getComponent = (Component) => {
343
+ if (React2__namespace.isValidElement(Component)) {
344
+ return Component;
345
+ }
346
+ if (Component) {
347
+ return /* @__PURE__ */ React2__namespace.createElement(Component, null);
348
+ }
349
+ return null;
350
+ };
342
351
 
343
352
  // src/components/PositionView.native.tsx
344
353
  var PositionViewState = typedMemo(function PositionViewState2({
@@ -387,22 +396,45 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
387
396
  animatedScrollY,
388
397
  stickyOffset,
389
398
  index,
399
+ stickyHeaderConfig,
400
+ children,
390
401
  ...rest
391
402
  }) {
392
403
  const [position = POSITION_OUT_OF_VIEW, headerSize] = useArr$([`containerPosition${id}`, "headerSize"]);
393
404
  const transform = React2__namespace.useMemo(() => {
405
+ var _a3;
394
406
  if (animatedScrollY && stickyOffset !== void 0) {
407
+ const stickyConfigOffset = (_a3 = stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset) != null ? _a3 : 0;
395
408
  const stickyPosition = animatedScrollY.interpolate({
396
409
  extrapolateLeft: "clamp",
397
410
  extrapolateRight: "extend",
398
- inputRange: [position + headerSize, position + 5e3 + headerSize],
411
+ inputRange: [
412
+ position + headerSize - stickyConfigOffset - stickyOffset,
413
+ position + 5e3 + headerSize - stickyConfigOffset - stickyOffset
414
+ ],
399
415
  outputRange: [position, position + 5e3]
400
416
  });
401
417
  return horizontal ? [{ translateX: stickyPosition }] : [{ translateY: stickyPosition }];
402
418
  }
403
- }, [animatedScrollY, headerSize, horizontal, stickyOffset, position]);
419
+ }, [animatedScrollY, headerSize, horizontal, stickyOffset, position, stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset]);
404
420
  const viewStyle = React2__namespace.useMemo(() => [style, { zIndex: index + 1e3 }, { transform }], [style, transform]);
405
- return /* @__PURE__ */ React2__namespace.createElement(reactNative.Animated.View, { ref: refView, style: viewStyle, ...rest });
421
+ const renderStickyHeaderBackdrop = React2__namespace.useMemo(() => {
422
+ if (!(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)) {
423
+ return null;
424
+ }
425
+ return /* @__PURE__ */ React2__namespace.createElement(
426
+ reactNative.View,
427
+ {
428
+ style: {
429
+ inset: 0,
430
+ pointerEvents: "none",
431
+ position: "absolute"
432
+ }
433
+ },
434
+ getComponent(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)
435
+ );
436
+ }, [stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent]);
437
+ return /* @__PURE__ */ React2__namespace.createElement(reactNative.Animated.View, { ref: refView, style: viewStyle, ...rest }, renderStickyHeaderBackdrop, children);
406
438
  });
407
439
  var PositionView = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
408
440
  function useInit(cb) {
@@ -472,7 +504,8 @@ var Container = typedMemo(function Container2({
472
504
  horizontal,
473
505
  getRenderedItem: getRenderedItem2,
474
506
  updateItemSize: updateItemSize2,
475
- ItemSeparatorComponent
507
+ ItemSeparatorComponent,
508
+ stickyHeaderConfig
476
509
  }) {
477
510
  const ctx = useStateContext();
478
511
  const { columnWrapperStyle, animatedScrollY } = ctx;
@@ -615,6 +648,7 @@ var Container = typedMemo(function Container2({
615
648
  key: recycleItems ? void 0 : itemKey,
616
649
  onLayout,
617
650
  refView: ref,
651
+ stickyHeaderConfig,
618
652
  stickyOffset: isSticky ? stickyOffset : void 0,
619
653
  style
620
654
  },
@@ -752,15 +786,6 @@ var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
752
786
  };
753
787
 
754
788
  // src/components/ListComponent.tsx
755
- var getComponent = (Component) => {
756
- if (React2__namespace.isValidElement(Component)) {
757
- return Component;
758
- }
759
- if (Component) {
760
- return /* @__PURE__ */ React2__namespace.createElement(Component, null);
761
- }
762
- return null;
763
- };
764
789
  var ListComponent = typedMemo(function ListComponent2({
765
790
  canRender,
766
791
  style,
@@ -785,6 +810,7 @@ var ListComponent = typedMemo(function ListComponent2({
785
810
  scrollAdjustHandler,
786
811
  onLayoutHeader,
787
812
  snapToIndices,
813
+ stickyHeaderConfig,
788
814
  stickyHeaderIndices,
789
815
  ...rest
790
816
  }) {
@@ -807,7 +833,7 @@ var ListComponent = typedMemo(function ListComponent2({
807
833
  ],
808
834
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
809
835
  horizontal,
810
- maintainVisibleContentPosition: maintainVisibleContentPosition.scroll || maintainVisibleContentPosition.dataChanged ? { minIndexForVisible: 0 } : void 0,
836
+ maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
811
837
  onLayout,
812
838
  onScroll: onScroll2,
813
839
  ref: refScrollView,
@@ -825,6 +851,7 @@ var ListComponent = typedMemo(function ListComponent2({
825
851
  horizontal,
826
852
  ItemSeparatorComponent,
827
853
  recycleItems,
854
+ stickyHeaderConfig,
828
855
  updateItemSize: updateItemSize2,
829
856
  waitForInitialLayout
830
857
  }
@@ -1021,7 +1048,7 @@ function clampScrollOffset(ctx, offset) {
1021
1048
  const state = ctx.state;
1022
1049
  const contentSize = getContentSize(ctx);
1023
1050
  let clampedOffset = offset;
1024
- if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength)) {
1051
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && state.lastLayout) {
1025
1052
  const maxOffset = Math.max(0, contentSize - state.scrollLength);
1026
1053
  clampedOffset = Math.min(offset, maxOffset);
1027
1054
  }
@@ -1029,6 +1056,7 @@ function clampScrollOffset(ctx, offset) {
1029
1056
  return clampedOffset;
1030
1057
  }
1031
1058
  var Platform2 = reactNative.Platform;
1059
+ var PlatformAdjustBreaksScroll = Platform2.OS === "android";
1032
1060
 
1033
1061
  // src/utils/setInitialRenderState.ts
1034
1062
  function setInitialRenderState(ctx, {
@@ -1052,6 +1080,7 @@ function finishScrollTo(ctx) {
1052
1080
  var _a3, _b;
1053
1081
  const state = ctx.state;
1054
1082
  if (state == null ? void 0 : state.scrollingTo) {
1083
+ const scrollingTo = state.scrollingTo;
1055
1084
  state.scrollHistory.length = 0;
1056
1085
  state.initialScroll = void 0;
1057
1086
  state.initialAnchor = void 0;
@@ -1062,8 +1091,8 @@ function finishScrollTo(ctx) {
1062
1091
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1063
1092
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1064
1093
  }
1065
- if (Platform2.OS === "web") {
1066
- state.scrollAdjustHandler.commitPendingAdjust();
1094
+ if (PlatformAdjustBreaksScroll) {
1095
+ state.scrollAdjustHandler.commitPendingAdjust(scrollingTo);
1067
1096
  }
1068
1097
  setInitialRenderState(ctx, { didInitialScroll: true });
1069
1098
  }
@@ -1434,7 +1463,7 @@ function prepareMVCP(ctx, dataChanged) {
1434
1463
  const state = ctx.state;
1435
1464
  const { idsInView, positions, props } = state;
1436
1465
  const {
1437
- maintainVisibleContentPosition: { dataChanged: mvcpdataChanged, scroll: mvcpScroll }
1466
+ maintainVisibleContentPosition: { data: mvcpData, size: mvcpScroll }
1438
1467
  } = props;
1439
1468
  const scrollingTo = state.scrollingTo;
1440
1469
  let prevPosition;
@@ -1442,7 +1471,7 @@ function prepareMVCP(ctx, dataChanged) {
1442
1471
  const idsInViewWithPositions = [];
1443
1472
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1444
1473
  const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1445
- const shouldMVCP = dataChanged ? mvcpdataChanged : mvcpScroll;
1474
+ const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
1446
1475
  const indexByKey = state.indexByKey;
1447
1476
  if (shouldMVCP) {
1448
1477
  if (scrollTarget !== void 0) {
@@ -1468,7 +1497,7 @@ function prepareMVCP(ctx, dataChanged) {
1468
1497
  }
1469
1498
  return () => {
1470
1499
  let positionDiff = 0;
1471
- if (dataChanged && targetId === void 0 && mvcpdataChanged) {
1500
+ if (dataChanged && targetId === void 0 && mvcpData) {
1472
1501
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1473
1502
  const { id, position } = idsInViewWithPositions[i];
1474
1503
  const newPosition = positions.get(id);
@@ -1505,7 +1534,7 @@ function prepareMVCP(ctx, dataChanged) {
1505
1534
  }
1506
1535
  }
1507
1536
  if (Math.abs(positionDiff) > 0.1) {
1508
- requestAdjust(ctx, positionDiff, dataChanged && mvcpdataChanged);
1537
+ requestAdjust(ctx, positionDiff, dataChanged && mvcpData);
1509
1538
  }
1510
1539
  };
1511
1540
  }
@@ -2438,7 +2467,7 @@ function calculateItemsInView(ctx, params = {}) {
2438
2467
  if (needNewContainers.length > 0) {
2439
2468
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
2440
2469
  const itemType = getItemType(data[i], i);
2441
- return itemType ? String(itemType) : "";
2470
+ return itemType !== void 0 ? String(itemType) : "";
2442
2471
  }) : void 0;
2443
2472
  const availableContainers = findAvailableContainers(
2444
2473
  ctx,
@@ -2707,8 +2736,10 @@ function doInitialAllocateContainers(ctx) {
2707
2736
  const num = Math.min(20, data.length);
2708
2737
  for (let i = 0; i < num; i++) {
2709
2738
  const item = data[i];
2710
- const itemType = getItemType ? (_a3 = getItemType(item, i)) != null ? _a3 : "" : "";
2711
- totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
2739
+ if (item !== void 0) {
2740
+ const itemType = (_a3 = getItemType == null ? void 0 : getItemType(item, i)) != null ? _a3 : "";
2741
+ totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
2742
+ }
2712
2743
  }
2713
2744
  averageItemSize = totalSize / num;
2714
2745
  } else {
@@ -2824,7 +2855,7 @@ var ScrollAdjustHandler = class {
2824
2855
  }
2825
2856
  requestAdjust(add) {
2826
2857
  const scrollingTo = this.ctx.state.scrollingTo;
2827
- if (Platform2.OS === "web" && (scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2858
+ if (PlatformAdjustBreaksScroll && (scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2828
2859
  this.pendingAdjust += add;
2829
2860
  set$(this.ctx, "scrollAdjustPending", this.pendingAdjust);
2830
2861
  } else {
@@ -2838,17 +2869,28 @@ var ScrollAdjustHandler = class {
2838
2869
  getAdjust() {
2839
2870
  return this.appliedAdjust;
2840
2871
  }
2841
- commitPendingAdjust() {
2842
- if (Platform2.OS === "web") {
2872
+ commitPendingAdjust(scrollTarget) {
2873
+ if (PlatformAdjustBreaksScroll) {
2843
2874
  const state = this.ctx.state;
2844
2875
  const pending = this.pendingAdjust;
2876
+ this.pendingAdjust = 0;
2845
2877
  if (pending !== 0) {
2846
- this.pendingAdjust = 0;
2847
- this.appliedAdjust += pending;
2848
- state.scroll += pending;
2849
- state.scrollForNextCalculateItemsInView = void 0;
2878
+ let targetScroll;
2879
+ if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
2880
+ const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
2881
+ targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
2882
+ targetScroll = clampScrollOffset(this.ctx, targetScroll);
2883
+ } else {
2884
+ targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
2885
+ }
2886
+ const adjustment = targetScroll - state.scroll;
2887
+ if (Math.abs(adjustment) > 0.1 || Math.abs(pending) > 0.1) {
2888
+ this.appliedAdjust += adjustment;
2889
+ state.scroll = targetScroll;
2890
+ state.scrollForNextCalculateItemsInView = void 0;
2891
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
2892
+ }
2850
2893
  set$(this.ctx, "scrollAdjustPending", 0);
2851
- set$(this.ctx, "scrollAdjust", this.appliedAdjust);
2852
2894
  calculateItemsInView(this.ctx);
2853
2895
  }
2854
2896
  }
@@ -2989,6 +3031,12 @@ function updateOneItemSize(ctx, itemKey, sizeObj) {
2989
3031
  }
2990
3032
  return 0;
2991
3033
  }
3034
+ function useWrapIfItem(fn) {
3035
+ return React2.useMemo(
3036
+ () => fn ? (arg1, arg2, arg3) => arg1 !== void 0 && arg2 !== void 0 ? fn(arg1, arg2, arg3) : void 0 : void 0,
3037
+ [fn]
3038
+ );
3039
+ }
2992
3040
  var useCombinedRef = (...refs) => {
2993
3041
  const callback = React2.useCallback((element) => {
2994
3042
  for (const ref of refs) {
@@ -3170,18 +3218,18 @@ function getRenderedItem(ctx, key) {
3170
3218
  function normalizeMaintainVisibleContentPosition(value) {
3171
3219
  var _a3, _b;
3172
3220
  if (value === true) {
3173
- return { dataChanged: true, scroll: true };
3221
+ return { data: true, size: true };
3174
3222
  }
3175
3223
  if (value && typeof value === "object") {
3176
3224
  return {
3177
- dataChanged: (_a3 = value.dataChanged) != null ? _a3 : false,
3178
- scroll: (_b = value.scroll) != null ? _b : true
3225
+ data: (_a3 = value.data) != null ? _a3 : false,
3226
+ size: (_b = value.size) != null ? _b : true
3179
3227
  };
3180
3228
  }
3181
3229
  if (value === false) {
3182
- return { dataChanged: false, scroll: false };
3230
+ return { data: false, size: false };
3183
3231
  }
3184
- return { dataChanged: false, scroll: true };
3232
+ return { data: false, size: true };
3185
3233
  }
3186
3234
  function useThrottleDebounce(mode) {
3187
3235
  const timeoutRef = React2.useRef(null);
@@ -3307,6 +3355,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3307
3355
  viewabilityConfig,
3308
3356
  viewabilityConfigCallbackPairs,
3309
3357
  waitForInitialLayout = true,
3358
+ stickyHeaderConfig,
3310
3359
  ...rest
3311
3360
  } = props;
3312
3361
  const animatedPropsInternal = props.animatedPropsInternal;
@@ -3424,13 +3473,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3424
3473
  data: dataProp,
3425
3474
  dataVersion,
3426
3475
  estimatedItemSize,
3427
- getEstimatedItemSize,
3428
- getFixedItemSize,
3429
- getItemType,
3476
+ getEstimatedItemSize: useWrapIfItem(getEstimatedItemSize),
3477
+ getFixedItemSize: useWrapIfItem(getFixedItemSize),
3478
+ getItemType: useWrapIfItem(getItemType),
3430
3479
  horizontal: !!horizontal,
3431
3480
  initialContainerPoolRatio,
3432
3481
  itemsAreEqual,
3433
- keyExtractor,
3482
+ keyExtractor: useWrapIfItem(keyExtractor),
3434
3483
  maintainScrollAtEnd,
3435
3484
  maintainScrollAtEndThreshold,
3436
3485
  maintainVisibleContentPosition: maintainVisibleContentPositionConfig,
@@ -3468,7 +3517,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3468
3517
  setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3469
3518
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3470
3519
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3471
- if (maintainVisibleContentPositionConfig.scroll && paddingDiff && prevPaddingTop !== void 0 && Platform2.OS === "ios") {
3520
+ if (maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform2.OS === "ios") {
3472
3521
  if (state.scroll < 0) {
3473
3522
  paddingDiff += state.scroll;
3474
3523
  }
@@ -3661,6 +3710,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3661
3710
  scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3662
3711
  scrollEventThrottle: 0,
3663
3712
  snapToIndices,
3713
+ stickyHeaderConfig,
3664
3714
  stickyHeaderIndices,
3665
3715
  style,
3666
3716
  updateItemSize: fns.updateItemSize,
@@ -318,6 +318,15 @@ function useValue$(key, params) {
318
318
  }
319
319
  var typedForwardRef = forwardRef;
320
320
  var typedMemo = memo;
321
+ var getComponent = (Component) => {
322
+ if (React2.isValidElement(Component)) {
323
+ return Component;
324
+ }
325
+ if (Component) {
326
+ return /* @__PURE__ */ React2.createElement(Component, null);
327
+ }
328
+ return null;
329
+ };
321
330
 
322
331
  // src/components/PositionView.native.tsx
323
332
  var PositionViewState = typedMemo(function PositionViewState2({
@@ -366,22 +375,45 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
366
375
  animatedScrollY,
367
376
  stickyOffset,
368
377
  index,
378
+ stickyHeaderConfig,
379
+ children,
369
380
  ...rest
370
381
  }) {
371
382
  const [position = POSITION_OUT_OF_VIEW, headerSize] = useArr$([`containerPosition${id}`, "headerSize"]);
372
383
  const transform = React2.useMemo(() => {
384
+ var _a3;
373
385
  if (animatedScrollY && stickyOffset !== void 0) {
386
+ const stickyConfigOffset = (_a3 = stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset) != null ? _a3 : 0;
374
387
  const stickyPosition = animatedScrollY.interpolate({
375
388
  extrapolateLeft: "clamp",
376
389
  extrapolateRight: "extend",
377
- inputRange: [position + headerSize, position + 5e3 + headerSize],
390
+ inputRange: [
391
+ position + headerSize - stickyConfigOffset - stickyOffset,
392
+ position + 5e3 + headerSize - stickyConfigOffset - stickyOffset
393
+ ],
378
394
  outputRange: [position, position + 5e3]
379
395
  });
380
396
  return horizontal ? [{ translateX: stickyPosition }] : [{ translateY: stickyPosition }];
381
397
  }
382
- }, [animatedScrollY, headerSize, horizontal, stickyOffset, position]);
398
+ }, [animatedScrollY, headerSize, horizontal, stickyOffset, position, stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset]);
383
399
  const viewStyle = React2.useMemo(() => [style, { zIndex: index + 1e3 }, { transform }], [style, transform]);
384
- return /* @__PURE__ */ React2.createElement(Animated.View, { ref: refView, style: viewStyle, ...rest });
400
+ const renderStickyHeaderBackdrop = React2.useMemo(() => {
401
+ if (!(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)) {
402
+ return null;
403
+ }
404
+ return /* @__PURE__ */ React2.createElement(
405
+ View$1,
406
+ {
407
+ style: {
408
+ inset: 0,
409
+ pointerEvents: "none",
410
+ position: "absolute"
411
+ }
412
+ },
413
+ getComponent(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)
414
+ );
415
+ }, [stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent]);
416
+ return /* @__PURE__ */ React2.createElement(Animated.View, { ref: refView, style: viewStyle, ...rest }, renderStickyHeaderBackdrop, children);
385
417
  });
386
418
  var PositionView = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
387
419
  function useInit(cb) {
@@ -451,7 +483,8 @@ var Container = typedMemo(function Container2({
451
483
  horizontal,
452
484
  getRenderedItem: getRenderedItem2,
453
485
  updateItemSize: updateItemSize2,
454
- ItemSeparatorComponent
486
+ ItemSeparatorComponent,
487
+ stickyHeaderConfig
455
488
  }) {
456
489
  const ctx = useStateContext();
457
490
  const { columnWrapperStyle, animatedScrollY } = ctx;
@@ -594,6 +627,7 @@ var Container = typedMemo(function Container2({
594
627
  key: recycleItems ? void 0 : itemKey,
595
628
  onLayout,
596
629
  refView: ref,
630
+ stickyHeaderConfig,
597
631
  stickyOffset: isSticky ? stickyOffset : void 0,
598
632
  style
599
633
  },
@@ -731,15 +765,6 @@ var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
731
765
  };
732
766
 
733
767
  // src/components/ListComponent.tsx
734
- var getComponent = (Component) => {
735
- if (React2.isValidElement(Component)) {
736
- return Component;
737
- }
738
- if (Component) {
739
- return /* @__PURE__ */ React2.createElement(Component, null);
740
- }
741
- return null;
742
- };
743
768
  var ListComponent = typedMemo(function ListComponent2({
744
769
  canRender,
745
770
  style,
@@ -764,6 +789,7 @@ var ListComponent = typedMemo(function ListComponent2({
764
789
  scrollAdjustHandler,
765
790
  onLayoutHeader,
766
791
  snapToIndices,
792
+ stickyHeaderConfig,
767
793
  stickyHeaderIndices,
768
794
  ...rest
769
795
  }) {
@@ -786,7 +812,7 @@ var ListComponent = typedMemo(function ListComponent2({
786
812
  ],
787
813
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
788
814
  horizontal,
789
- maintainVisibleContentPosition: maintainVisibleContentPosition.scroll || maintainVisibleContentPosition.dataChanged ? { minIndexForVisible: 0 } : void 0,
815
+ maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
790
816
  onLayout,
791
817
  onScroll: onScroll2,
792
818
  ref: refScrollView,
@@ -804,6 +830,7 @@ var ListComponent = typedMemo(function ListComponent2({
804
830
  horizontal,
805
831
  ItemSeparatorComponent,
806
832
  recycleItems,
833
+ stickyHeaderConfig,
807
834
  updateItemSize: updateItemSize2,
808
835
  waitForInitialLayout
809
836
  }
@@ -1000,7 +1027,7 @@ function clampScrollOffset(ctx, offset) {
1000
1027
  const state = ctx.state;
1001
1028
  const contentSize = getContentSize(ctx);
1002
1029
  let clampedOffset = offset;
1003
- if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength)) {
1030
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && state.lastLayout) {
1004
1031
  const maxOffset = Math.max(0, contentSize - state.scrollLength);
1005
1032
  clampedOffset = Math.min(offset, maxOffset);
1006
1033
  }
@@ -1008,6 +1035,7 @@ function clampScrollOffset(ctx, offset) {
1008
1035
  return clampedOffset;
1009
1036
  }
1010
1037
  var Platform2 = Platform;
1038
+ var PlatformAdjustBreaksScroll = Platform2.OS === "android";
1011
1039
 
1012
1040
  // src/utils/setInitialRenderState.ts
1013
1041
  function setInitialRenderState(ctx, {
@@ -1031,6 +1059,7 @@ function finishScrollTo(ctx) {
1031
1059
  var _a3, _b;
1032
1060
  const state = ctx.state;
1033
1061
  if (state == null ? void 0 : state.scrollingTo) {
1062
+ const scrollingTo = state.scrollingTo;
1034
1063
  state.scrollHistory.length = 0;
1035
1064
  state.initialScroll = void 0;
1036
1065
  state.initialAnchor = void 0;
@@ -1041,8 +1070,8 @@ function finishScrollTo(ctx) {
1041
1070
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1042
1071
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1043
1072
  }
1044
- if (Platform2.OS === "web") {
1045
- state.scrollAdjustHandler.commitPendingAdjust();
1073
+ if (PlatformAdjustBreaksScroll) {
1074
+ state.scrollAdjustHandler.commitPendingAdjust(scrollingTo);
1046
1075
  }
1047
1076
  setInitialRenderState(ctx, { didInitialScroll: true });
1048
1077
  }
@@ -1413,7 +1442,7 @@ function prepareMVCP(ctx, dataChanged) {
1413
1442
  const state = ctx.state;
1414
1443
  const { idsInView, positions, props } = state;
1415
1444
  const {
1416
- maintainVisibleContentPosition: { dataChanged: mvcpdataChanged, scroll: mvcpScroll }
1445
+ maintainVisibleContentPosition: { data: mvcpData, size: mvcpScroll }
1417
1446
  } = props;
1418
1447
  const scrollingTo = state.scrollingTo;
1419
1448
  let prevPosition;
@@ -1421,7 +1450,7 @@ function prepareMVCP(ctx, dataChanged) {
1421
1450
  const idsInViewWithPositions = [];
1422
1451
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1423
1452
  const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1424
- const shouldMVCP = dataChanged ? mvcpdataChanged : mvcpScroll;
1453
+ const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
1425
1454
  const indexByKey = state.indexByKey;
1426
1455
  if (shouldMVCP) {
1427
1456
  if (scrollTarget !== void 0) {
@@ -1447,7 +1476,7 @@ function prepareMVCP(ctx, dataChanged) {
1447
1476
  }
1448
1477
  return () => {
1449
1478
  let positionDiff = 0;
1450
- if (dataChanged && targetId === void 0 && mvcpdataChanged) {
1479
+ if (dataChanged && targetId === void 0 && mvcpData) {
1451
1480
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1452
1481
  const { id, position } = idsInViewWithPositions[i];
1453
1482
  const newPosition = positions.get(id);
@@ -1484,7 +1513,7 @@ function prepareMVCP(ctx, dataChanged) {
1484
1513
  }
1485
1514
  }
1486
1515
  if (Math.abs(positionDiff) > 0.1) {
1487
- requestAdjust(ctx, positionDiff, dataChanged && mvcpdataChanged);
1516
+ requestAdjust(ctx, positionDiff, dataChanged && mvcpData);
1488
1517
  }
1489
1518
  };
1490
1519
  }
@@ -2417,7 +2446,7 @@ function calculateItemsInView(ctx, params = {}) {
2417
2446
  if (needNewContainers.length > 0) {
2418
2447
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
2419
2448
  const itemType = getItemType(data[i], i);
2420
- return itemType ? String(itemType) : "";
2449
+ return itemType !== void 0 ? String(itemType) : "";
2421
2450
  }) : void 0;
2422
2451
  const availableContainers = findAvailableContainers(
2423
2452
  ctx,
@@ -2686,8 +2715,10 @@ function doInitialAllocateContainers(ctx) {
2686
2715
  const num = Math.min(20, data.length);
2687
2716
  for (let i = 0; i < num; i++) {
2688
2717
  const item = data[i];
2689
- const itemType = getItemType ? (_a3 = getItemType(item, i)) != null ? _a3 : "" : "";
2690
- totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
2718
+ if (item !== void 0) {
2719
+ const itemType = (_a3 = getItemType == null ? void 0 : getItemType(item, i)) != null ? _a3 : "";
2720
+ totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
2721
+ }
2691
2722
  }
2692
2723
  averageItemSize = totalSize / num;
2693
2724
  } else {
@@ -2803,7 +2834,7 @@ var ScrollAdjustHandler = class {
2803
2834
  }
2804
2835
  requestAdjust(add) {
2805
2836
  const scrollingTo = this.ctx.state.scrollingTo;
2806
- if (Platform2.OS === "web" && (scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2837
+ if (PlatformAdjustBreaksScroll && (scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2807
2838
  this.pendingAdjust += add;
2808
2839
  set$(this.ctx, "scrollAdjustPending", this.pendingAdjust);
2809
2840
  } else {
@@ -2817,17 +2848,28 @@ var ScrollAdjustHandler = class {
2817
2848
  getAdjust() {
2818
2849
  return this.appliedAdjust;
2819
2850
  }
2820
- commitPendingAdjust() {
2821
- if (Platform2.OS === "web") {
2851
+ commitPendingAdjust(scrollTarget) {
2852
+ if (PlatformAdjustBreaksScroll) {
2822
2853
  const state = this.ctx.state;
2823
2854
  const pending = this.pendingAdjust;
2855
+ this.pendingAdjust = 0;
2824
2856
  if (pending !== 0) {
2825
- this.pendingAdjust = 0;
2826
- this.appliedAdjust += pending;
2827
- state.scroll += pending;
2828
- state.scrollForNextCalculateItemsInView = void 0;
2857
+ let targetScroll;
2858
+ if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
2859
+ const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
2860
+ targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
2861
+ targetScroll = clampScrollOffset(this.ctx, targetScroll);
2862
+ } else {
2863
+ targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
2864
+ }
2865
+ const adjustment = targetScroll - state.scroll;
2866
+ if (Math.abs(adjustment) > 0.1 || Math.abs(pending) > 0.1) {
2867
+ this.appliedAdjust += adjustment;
2868
+ state.scroll = targetScroll;
2869
+ state.scrollForNextCalculateItemsInView = void 0;
2870
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
2871
+ }
2829
2872
  set$(this.ctx, "scrollAdjustPending", 0);
2830
- set$(this.ctx, "scrollAdjust", this.appliedAdjust);
2831
2873
  calculateItemsInView(this.ctx);
2832
2874
  }
2833
2875
  }
@@ -2968,6 +3010,12 @@ function updateOneItemSize(ctx, itemKey, sizeObj) {
2968
3010
  }
2969
3011
  return 0;
2970
3012
  }
3013
+ function useWrapIfItem(fn) {
3014
+ return useMemo(
3015
+ () => fn ? (arg1, arg2, arg3) => arg1 !== void 0 && arg2 !== void 0 ? fn(arg1, arg2, arg3) : void 0 : void 0,
3016
+ [fn]
3017
+ );
3018
+ }
2971
3019
  var useCombinedRef = (...refs) => {
2972
3020
  const callback = useCallback((element) => {
2973
3021
  for (const ref of refs) {
@@ -3149,18 +3197,18 @@ function getRenderedItem(ctx, key) {
3149
3197
  function normalizeMaintainVisibleContentPosition(value) {
3150
3198
  var _a3, _b;
3151
3199
  if (value === true) {
3152
- return { dataChanged: true, scroll: true };
3200
+ return { data: true, size: true };
3153
3201
  }
3154
3202
  if (value && typeof value === "object") {
3155
3203
  return {
3156
- dataChanged: (_a3 = value.dataChanged) != null ? _a3 : false,
3157
- scroll: (_b = value.scroll) != null ? _b : true
3204
+ data: (_a3 = value.data) != null ? _a3 : false,
3205
+ size: (_b = value.size) != null ? _b : true
3158
3206
  };
3159
3207
  }
3160
3208
  if (value === false) {
3161
- return { dataChanged: false, scroll: false };
3209
+ return { data: false, size: false };
3162
3210
  }
3163
- return { dataChanged: false, scroll: true };
3211
+ return { data: false, size: true };
3164
3212
  }
3165
3213
  function useThrottleDebounce(mode) {
3166
3214
  const timeoutRef = useRef(null);
@@ -3286,6 +3334,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3286
3334
  viewabilityConfig,
3287
3335
  viewabilityConfigCallbackPairs,
3288
3336
  waitForInitialLayout = true,
3337
+ stickyHeaderConfig,
3289
3338
  ...rest
3290
3339
  } = props;
3291
3340
  const animatedPropsInternal = props.animatedPropsInternal;
@@ -3403,13 +3452,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3403
3452
  data: dataProp,
3404
3453
  dataVersion,
3405
3454
  estimatedItemSize,
3406
- getEstimatedItemSize,
3407
- getFixedItemSize,
3408
- getItemType,
3455
+ getEstimatedItemSize: useWrapIfItem(getEstimatedItemSize),
3456
+ getFixedItemSize: useWrapIfItem(getFixedItemSize),
3457
+ getItemType: useWrapIfItem(getItemType),
3409
3458
  horizontal: !!horizontal,
3410
3459
  initialContainerPoolRatio,
3411
3460
  itemsAreEqual,
3412
- keyExtractor,
3461
+ keyExtractor: useWrapIfItem(keyExtractor),
3413
3462
  maintainScrollAtEnd,
3414
3463
  maintainScrollAtEndThreshold,
3415
3464
  maintainVisibleContentPosition: maintainVisibleContentPositionConfig,
@@ -3447,7 +3496,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3447
3496
  setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3448
3497
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3449
3498
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3450
- if (maintainVisibleContentPositionConfig.scroll && paddingDiff && prevPaddingTop !== void 0 && Platform2.OS === "ios") {
3499
+ if (maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform2.OS === "ios") {
3451
3500
  if (state.scroll < 0) {
3452
3501
  paddingDiff += state.scroll;
3453
3502
  }
@@ -3640,6 +3689,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3640
3689
  scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3641
3690
  scrollEventThrottle: 0,
3642
3691
  snapToIndices,
3692
+ stickyHeaderConfig,
3643
3693
  stickyHeaderIndices,
3644
3694
  style,
3645
3695
  updateItemSize: fns.updateItemSize,