@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/index.native.js CHANGED
@@ -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) {
@@ -603,7 +635,8 @@ var Container = typedMemo(function Container2({
603
635
  horizontal,
604
636
  getRenderedItem: getRenderedItem2,
605
637
  updateItemSize: updateItemSize2,
606
- ItemSeparatorComponent
638
+ ItemSeparatorComponent,
639
+ stickyHeaderConfig
607
640
  }) {
608
641
  const ctx = useStateContext();
609
642
  const { columnWrapperStyle, animatedScrollY } = ctx;
@@ -746,6 +779,7 @@ var Container = typedMemo(function Container2({
746
779
  key: recycleItems ? void 0 : itemKey,
747
780
  onLayout,
748
781
  refView: ref,
782
+ stickyHeaderConfig,
749
783
  stickyOffset: isSticky ? stickyOffset : void 0,
750
784
  style
751
785
  },
@@ -883,15 +917,6 @@ var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
883
917
  };
884
918
 
885
919
  // src/components/ListComponent.tsx
886
- var getComponent = (Component) => {
887
- if (React2__namespace.isValidElement(Component)) {
888
- return Component;
889
- }
890
- if (Component) {
891
- return /* @__PURE__ */ React2__namespace.createElement(Component, null);
892
- }
893
- return null;
894
- };
895
920
  var ListComponent = typedMemo(function ListComponent2({
896
921
  canRender,
897
922
  style,
@@ -916,6 +941,7 @@ var ListComponent = typedMemo(function ListComponent2({
916
941
  scrollAdjustHandler,
917
942
  onLayoutHeader,
918
943
  snapToIndices,
944
+ stickyHeaderConfig,
919
945
  stickyHeaderIndices,
920
946
  ...rest
921
947
  }) {
@@ -938,7 +964,7 @@ var ListComponent = typedMemo(function ListComponent2({
938
964
  ],
939
965
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
940
966
  horizontal,
941
- maintainVisibleContentPosition: maintainVisibleContentPosition.scroll || maintainVisibleContentPosition.dataChanged ? { minIndexForVisible: 0 } : void 0,
967
+ maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
942
968
  onLayout,
943
969
  onScroll: onScroll2,
944
970
  ref: refScrollView,
@@ -956,6 +982,7 @@ var ListComponent = typedMemo(function ListComponent2({
956
982
  horizontal,
957
983
  ItemSeparatorComponent,
958
984
  recycleItems,
985
+ stickyHeaderConfig,
959
986
  updateItemSize: updateItemSize2,
960
987
  waitForInitialLayout
961
988
  }
@@ -1152,7 +1179,7 @@ function clampScrollOffset(ctx, offset) {
1152
1179
  const state = ctx.state;
1153
1180
  const contentSize = getContentSize(ctx);
1154
1181
  let clampedOffset = offset;
1155
- if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength)) {
1182
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && state.lastLayout) {
1156
1183
  const maxOffset = Math.max(0, contentSize - state.scrollLength);
1157
1184
  clampedOffset = Math.min(offset, maxOffset);
1158
1185
  }
@@ -1160,6 +1187,7 @@ function clampScrollOffset(ctx, offset) {
1160
1187
  return clampedOffset;
1161
1188
  }
1162
1189
  var Platform2 = reactNative.Platform;
1190
+ var PlatformAdjustBreaksScroll = Platform2.OS === "android";
1163
1191
 
1164
1192
  // src/utils/setInitialRenderState.ts
1165
1193
  function setInitialRenderState(ctx, {
@@ -1183,6 +1211,7 @@ function finishScrollTo(ctx) {
1183
1211
  var _a3, _b;
1184
1212
  const state = ctx.state;
1185
1213
  if (state == null ? void 0 : state.scrollingTo) {
1214
+ const scrollingTo = state.scrollingTo;
1186
1215
  state.scrollHistory.length = 0;
1187
1216
  state.initialScroll = void 0;
1188
1217
  state.initialAnchor = void 0;
@@ -1193,8 +1222,8 @@ function finishScrollTo(ctx) {
1193
1222
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1194
1223
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1195
1224
  }
1196
- if (Platform2.OS === "web") {
1197
- state.scrollAdjustHandler.commitPendingAdjust();
1225
+ if (PlatformAdjustBreaksScroll) {
1226
+ state.scrollAdjustHandler.commitPendingAdjust(scrollingTo);
1198
1227
  }
1199
1228
  setInitialRenderState(ctx, { didInitialScroll: true });
1200
1229
  }
@@ -1565,7 +1594,7 @@ function prepareMVCP(ctx, dataChanged) {
1565
1594
  const state = ctx.state;
1566
1595
  const { idsInView, positions, props } = state;
1567
1596
  const {
1568
- maintainVisibleContentPosition: { dataChanged: mvcpdataChanged, scroll: mvcpScroll }
1597
+ maintainVisibleContentPosition: { data: mvcpData, size: mvcpScroll }
1569
1598
  } = props;
1570
1599
  const scrollingTo = state.scrollingTo;
1571
1600
  let prevPosition;
@@ -1573,7 +1602,7 @@ function prepareMVCP(ctx, dataChanged) {
1573
1602
  const idsInViewWithPositions = [];
1574
1603
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1575
1604
  const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1576
- const shouldMVCP = dataChanged ? mvcpdataChanged : mvcpScroll;
1605
+ const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
1577
1606
  const indexByKey = state.indexByKey;
1578
1607
  if (shouldMVCP) {
1579
1608
  if (scrollTarget !== void 0) {
@@ -1599,7 +1628,7 @@ function prepareMVCP(ctx, dataChanged) {
1599
1628
  }
1600
1629
  return () => {
1601
1630
  let positionDiff = 0;
1602
- if (dataChanged && targetId === void 0 && mvcpdataChanged) {
1631
+ if (dataChanged && targetId === void 0 && mvcpData) {
1603
1632
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1604
1633
  const { id, position } = idsInViewWithPositions[i];
1605
1634
  const newPosition = positions.get(id);
@@ -1636,7 +1665,7 @@ function prepareMVCP(ctx, dataChanged) {
1636
1665
  }
1637
1666
  }
1638
1667
  if (Math.abs(positionDiff) > 0.1) {
1639
- requestAdjust(ctx, positionDiff, dataChanged && mvcpdataChanged);
1668
+ requestAdjust(ctx, positionDiff, dataChanged && mvcpData);
1640
1669
  }
1641
1670
  };
1642
1671
  }
@@ -2569,7 +2598,7 @@ function calculateItemsInView(ctx, params = {}) {
2569
2598
  if (needNewContainers.length > 0) {
2570
2599
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
2571
2600
  const itemType = getItemType(data[i], i);
2572
- return itemType ? String(itemType) : "";
2601
+ return itemType !== void 0 ? String(itemType) : "";
2573
2602
  }) : void 0;
2574
2603
  const availableContainers = findAvailableContainers(
2575
2604
  ctx,
@@ -2838,8 +2867,10 @@ function doInitialAllocateContainers(ctx) {
2838
2867
  const num = Math.min(20, data.length);
2839
2868
  for (let i = 0; i < num; i++) {
2840
2869
  const item = data[i];
2841
- const itemType = getItemType ? (_a3 = getItemType(item, i)) != null ? _a3 : "" : "";
2842
- totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
2870
+ if (item !== void 0) {
2871
+ const itemType = (_a3 = getItemType == null ? void 0 : getItemType(item, i)) != null ? _a3 : "";
2872
+ totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
2873
+ }
2843
2874
  }
2844
2875
  averageItemSize = totalSize / num;
2845
2876
  } else {
@@ -2955,7 +2986,7 @@ var ScrollAdjustHandler = class {
2955
2986
  }
2956
2987
  requestAdjust(add) {
2957
2988
  const scrollingTo = this.ctx.state.scrollingTo;
2958
- if (Platform2.OS === "web" && (scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2989
+ if (PlatformAdjustBreaksScroll && (scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2959
2990
  this.pendingAdjust += add;
2960
2991
  set$(this.ctx, "scrollAdjustPending", this.pendingAdjust);
2961
2992
  } else {
@@ -2969,17 +3000,28 @@ var ScrollAdjustHandler = class {
2969
3000
  getAdjust() {
2970
3001
  return this.appliedAdjust;
2971
3002
  }
2972
- commitPendingAdjust() {
2973
- if (Platform2.OS === "web") {
3003
+ commitPendingAdjust(scrollTarget) {
3004
+ if (PlatformAdjustBreaksScroll) {
2974
3005
  const state = this.ctx.state;
2975
3006
  const pending = this.pendingAdjust;
3007
+ this.pendingAdjust = 0;
2976
3008
  if (pending !== 0) {
2977
- this.pendingAdjust = 0;
2978
- this.appliedAdjust += pending;
2979
- state.scroll += pending;
2980
- state.scrollForNextCalculateItemsInView = void 0;
3009
+ let targetScroll;
3010
+ if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
3011
+ const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
3012
+ targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
3013
+ targetScroll = clampScrollOffset(this.ctx, targetScroll);
3014
+ } else {
3015
+ targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
3016
+ }
3017
+ const adjustment = targetScroll - state.scroll;
3018
+ if (Math.abs(adjustment) > 0.1 || Math.abs(pending) > 0.1) {
3019
+ this.appliedAdjust += adjustment;
3020
+ state.scroll = targetScroll;
3021
+ state.scrollForNextCalculateItemsInView = void 0;
3022
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3023
+ }
2981
3024
  set$(this.ctx, "scrollAdjustPending", 0);
2982
- set$(this.ctx, "scrollAdjust", this.appliedAdjust);
2983
3025
  calculateItemsInView(this.ctx);
2984
3026
  }
2985
3027
  }
@@ -3120,6 +3162,12 @@ function updateOneItemSize(ctx, itemKey, sizeObj) {
3120
3162
  }
3121
3163
  return 0;
3122
3164
  }
3165
+ function useWrapIfItem(fn) {
3166
+ return React2.useMemo(
3167
+ () => fn ? (arg1, arg2, arg3) => arg1 !== void 0 && arg2 !== void 0 ? fn(arg1, arg2, arg3) : void 0 : void 0,
3168
+ [fn]
3169
+ );
3170
+ }
3123
3171
  var useCombinedRef = (...refs) => {
3124
3172
  const callback = React2.useCallback((element) => {
3125
3173
  for (const ref of refs) {
@@ -3301,18 +3349,18 @@ function getRenderedItem(ctx, key) {
3301
3349
  function normalizeMaintainVisibleContentPosition(value) {
3302
3350
  var _a3, _b;
3303
3351
  if (value === true) {
3304
- return { dataChanged: true, scroll: true };
3352
+ return { data: true, size: true };
3305
3353
  }
3306
3354
  if (value && typeof value === "object") {
3307
3355
  return {
3308
- dataChanged: (_a3 = value.dataChanged) != null ? _a3 : false,
3309
- scroll: (_b = value.scroll) != null ? _b : true
3356
+ data: (_a3 = value.data) != null ? _a3 : false,
3357
+ size: (_b = value.size) != null ? _b : true
3310
3358
  };
3311
3359
  }
3312
3360
  if (value === false) {
3313
- return { dataChanged: false, scroll: false };
3361
+ return { data: false, size: false };
3314
3362
  }
3315
- return { dataChanged: false, scroll: true };
3363
+ return { data: false, size: true };
3316
3364
  }
3317
3365
  function useThrottleDebounce(mode) {
3318
3366
  const timeoutRef = React2.useRef(null);
@@ -3438,6 +3486,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3438
3486
  viewabilityConfig,
3439
3487
  viewabilityConfigCallbackPairs,
3440
3488
  waitForInitialLayout = true,
3489
+ stickyHeaderConfig,
3441
3490
  ...rest
3442
3491
  } = props;
3443
3492
  const animatedPropsInternal = props.animatedPropsInternal;
@@ -3555,13 +3604,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3555
3604
  data: dataProp,
3556
3605
  dataVersion,
3557
3606
  estimatedItemSize,
3558
- getEstimatedItemSize,
3559
- getFixedItemSize,
3560
- getItemType,
3607
+ getEstimatedItemSize: useWrapIfItem(getEstimatedItemSize),
3608
+ getFixedItemSize: useWrapIfItem(getFixedItemSize),
3609
+ getItemType: useWrapIfItem(getItemType),
3561
3610
  horizontal: !!horizontal,
3562
3611
  initialContainerPoolRatio,
3563
3612
  itemsAreEqual,
3564
- keyExtractor,
3613
+ keyExtractor: useWrapIfItem(keyExtractor),
3565
3614
  maintainScrollAtEnd,
3566
3615
  maintainScrollAtEndThreshold,
3567
3616
  maintainVisibleContentPosition: maintainVisibleContentPositionConfig,
@@ -3599,7 +3648,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3599
3648
  setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3600
3649
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3601
3650
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3602
- if (maintainVisibleContentPositionConfig.scroll && paddingDiff && prevPaddingTop !== void 0 && Platform2.OS === "ios") {
3651
+ if (maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform2.OS === "ios") {
3603
3652
  if (state.scroll < 0) {
3604
3653
  paddingDiff += state.scroll;
3605
3654
  }
@@ -3792,6 +3841,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3792
3841
  scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3793
3842
  scrollEventThrottle: 0,
3794
3843
  snapToIndices,
3844
+ stickyHeaderConfig,
3795
3845
  stickyHeaderIndices,
3796
3846
  style,
3797
3847
  updateItemSize: fns.updateItemSize,
package/index.native.mjs CHANGED
@@ -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) {
@@ -582,7 +614,8 @@ var Container = typedMemo(function Container2({
582
614
  horizontal,
583
615
  getRenderedItem: getRenderedItem2,
584
616
  updateItemSize: updateItemSize2,
585
- ItemSeparatorComponent
617
+ ItemSeparatorComponent,
618
+ stickyHeaderConfig
586
619
  }) {
587
620
  const ctx = useStateContext();
588
621
  const { columnWrapperStyle, animatedScrollY } = ctx;
@@ -725,6 +758,7 @@ var Container = typedMemo(function Container2({
725
758
  key: recycleItems ? void 0 : itemKey,
726
759
  onLayout,
727
760
  refView: ref,
761
+ stickyHeaderConfig,
728
762
  stickyOffset: isSticky ? stickyOffset : void 0,
729
763
  style
730
764
  },
@@ -862,15 +896,6 @@ var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
862
896
  };
863
897
 
864
898
  // src/components/ListComponent.tsx
865
- var getComponent = (Component) => {
866
- if (React2.isValidElement(Component)) {
867
- return Component;
868
- }
869
- if (Component) {
870
- return /* @__PURE__ */ React2.createElement(Component, null);
871
- }
872
- return null;
873
- };
874
899
  var ListComponent = typedMemo(function ListComponent2({
875
900
  canRender,
876
901
  style,
@@ -895,6 +920,7 @@ var ListComponent = typedMemo(function ListComponent2({
895
920
  scrollAdjustHandler,
896
921
  onLayoutHeader,
897
922
  snapToIndices,
923
+ stickyHeaderConfig,
898
924
  stickyHeaderIndices,
899
925
  ...rest
900
926
  }) {
@@ -917,7 +943,7 @@ var ListComponent = typedMemo(function ListComponent2({
917
943
  ],
918
944
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
919
945
  horizontal,
920
- maintainVisibleContentPosition: maintainVisibleContentPosition.scroll || maintainVisibleContentPosition.dataChanged ? { minIndexForVisible: 0 } : void 0,
946
+ maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
921
947
  onLayout,
922
948
  onScroll: onScroll2,
923
949
  ref: refScrollView,
@@ -935,6 +961,7 @@ var ListComponent = typedMemo(function ListComponent2({
935
961
  horizontal,
936
962
  ItemSeparatorComponent,
937
963
  recycleItems,
964
+ stickyHeaderConfig,
938
965
  updateItemSize: updateItemSize2,
939
966
  waitForInitialLayout
940
967
  }
@@ -1131,7 +1158,7 @@ function clampScrollOffset(ctx, offset) {
1131
1158
  const state = ctx.state;
1132
1159
  const contentSize = getContentSize(ctx);
1133
1160
  let clampedOffset = offset;
1134
- if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength)) {
1161
+ if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && state.lastLayout) {
1135
1162
  const maxOffset = Math.max(0, contentSize - state.scrollLength);
1136
1163
  clampedOffset = Math.min(offset, maxOffset);
1137
1164
  }
@@ -1139,6 +1166,7 @@ function clampScrollOffset(ctx, offset) {
1139
1166
  return clampedOffset;
1140
1167
  }
1141
1168
  var Platform2 = Platform;
1169
+ var PlatformAdjustBreaksScroll = Platform2.OS === "android";
1142
1170
 
1143
1171
  // src/utils/setInitialRenderState.ts
1144
1172
  function setInitialRenderState(ctx, {
@@ -1162,6 +1190,7 @@ function finishScrollTo(ctx) {
1162
1190
  var _a3, _b;
1163
1191
  const state = ctx.state;
1164
1192
  if (state == null ? void 0 : state.scrollingTo) {
1193
+ const scrollingTo = state.scrollingTo;
1165
1194
  state.scrollHistory.length = 0;
1166
1195
  state.initialScroll = void 0;
1167
1196
  state.initialAnchor = void 0;
@@ -1172,8 +1201,8 @@ function finishScrollTo(ctx) {
1172
1201
  if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1173
1202
  (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1174
1203
  }
1175
- if (Platform2.OS === "web") {
1176
- state.scrollAdjustHandler.commitPendingAdjust();
1204
+ if (PlatformAdjustBreaksScroll) {
1205
+ state.scrollAdjustHandler.commitPendingAdjust(scrollingTo);
1177
1206
  }
1178
1207
  setInitialRenderState(ctx, { didInitialScroll: true });
1179
1208
  }
@@ -1544,7 +1573,7 @@ function prepareMVCP(ctx, dataChanged) {
1544
1573
  const state = ctx.state;
1545
1574
  const { idsInView, positions, props } = state;
1546
1575
  const {
1547
- maintainVisibleContentPosition: { dataChanged: mvcpdataChanged, scroll: mvcpScroll }
1576
+ maintainVisibleContentPosition: { data: mvcpData, size: mvcpScroll }
1548
1577
  } = props;
1549
1578
  const scrollingTo = state.scrollingTo;
1550
1579
  let prevPosition;
@@ -1552,7 +1581,7 @@ function prepareMVCP(ctx, dataChanged) {
1552
1581
  const idsInViewWithPositions = [];
1553
1582
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1554
1583
  const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
1555
- const shouldMVCP = dataChanged ? mvcpdataChanged : mvcpScroll;
1584
+ const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
1556
1585
  const indexByKey = state.indexByKey;
1557
1586
  if (shouldMVCP) {
1558
1587
  if (scrollTarget !== void 0) {
@@ -1578,7 +1607,7 @@ function prepareMVCP(ctx, dataChanged) {
1578
1607
  }
1579
1608
  return () => {
1580
1609
  let positionDiff = 0;
1581
- if (dataChanged && targetId === void 0 && mvcpdataChanged) {
1610
+ if (dataChanged && targetId === void 0 && mvcpData) {
1582
1611
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1583
1612
  const { id, position } = idsInViewWithPositions[i];
1584
1613
  const newPosition = positions.get(id);
@@ -1615,7 +1644,7 @@ function prepareMVCP(ctx, dataChanged) {
1615
1644
  }
1616
1645
  }
1617
1646
  if (Math.abs(positionDiff) > 0.1) {
1618
- requestAdjust(ctx, positionDiff, dataChanged && mvcpdataChanged);
1647
+ requestAdjust(ctx, positionDiff, dataChanged && mvcpData);
1619
1648
  }
1620
1649
  };
1621
1650
  }
@@ -2548,7 +2577,7 @@ function calculateItemsInView(ctx, params = {}) {
2548
2577
  if (needNewContainers.length > 0) {
2549
2578
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
2550
2579
  const itemType = getItemType(data[i], i);
2551
- return itemType ? String(itemType) : "";
2580
+ return itemType !== void 0 ? String(itemType) : "";
2552
2581
  }) : void 0;
2553
2582
  const availableContainers = findAvailableContainers(
2554
2583
  ctx,
@@ -2817,8 +2846,10 @@ function doInitialAllocateContainers(ctx) {
2817
2846
  const num = Math.min(20, data.length);
2818
2847
  for (let i = 0; i < num; i++) {
2819
2848
  const item = data[i];
2820
- const itemType = getItemType ? (_a3 = getItemType(item, i)) != null ? _a3 : "" : "";
2821
- totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
2849
+ if (item !== void 0) {
2850
+ const itemType = (_a3 = getItemType == null ? void 0 : getItemType(item, i)) != null ? _a3 : "";
2851
+ totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
2852
+ }
2822
2853
  }
2823
2854
  averageItemSize = totalSize / num;
2824
2855
  } else {
@@ -2934,7 +2965,7 @@ var ScrollAdjustHandler = class {
2934
2965
  }
2935
2966
  requestAdjust(add) {
2936
2967
  const scrollingTo = this.ctx.state.scrollingTo;
2937
- if (Platform2.OS === "web" && (scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2968
+ if (PlatformAdjustBreaksScroll && (scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2938
2969
  this.pendingAdjust += add;
2939
2970
  set$(this.ctx, "scrollAdjustPending", this.pendingAdjust);
2940
2971
  } else {
@@ -2948,17 +2979,28 @@ var ScrollAdjustHandler = class {
2948
2979
  getAdjust() {
2949
2980
  return this.appliedAdjust;
2950
2981
  }
2951
- commitPendingAdjust() {
2952
- if (Platform2.OS === "web") {
2982
+ commitPendingAdjust(scrollTarget) {
2983
+ if (PlatformAdjustBreaksScroll) {
2953
2984
  const state = this.ctx.state;
2954
2985
  const pending = this.pendingAdjust;
2986
+ this.pendingAdjust = 0;
2955
2987
  if (pending !== 0) {
2956
- this.pendingAdjust = 0;
2957
- this.appliedAdjust += pending;
2958
- state.scroll += pending;
2959
- state.scrollForNextCalculateItemsInView = void 0;
2988
+ let targetScroll;
2989
+ if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
2990
+ const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
2991
+ targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
2992
+ targetScroll = clampScrollOffset(this.ctx, targetScroll);
2993
+ } else {
2994
+ targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
2995
+ }
2996
+ const adjustment = targetScroll - state.scroll;
2997
+ if (Math.abs(adjustment) > 0.1 || Math.abs(pending) > 0.1) {
2998
+ this.appliedAdjust += adjustment;
2999
+ state.scroll = targetScroll;
3000
+ state.scrollForNextCalculateItemsInView = void 0;
3001
+ set$(this.ctx, "scrollAdjust", this.appliedAdjust);
3002
+ }
2960
3003
  set$(this.ctx, "scrollAdjustPending", 0);
2961
- set$(this.ctx, "scrollAdjust", this.appliedAdjust);
2962
3004
  calculateItemsInView(this.ctx);
2963
3005
  }
2964
3006
  }
@@ -3099,6 +3141,12 @@ function updateOneItemSize(ctx, itemKey, sizeObj) {
3099
3141
  }
3100
3142
  return 0;
3101
3143
  }
3144
+ function useWrapIfItem(fn) {
3145
+ return useMemo(
3146
+ () => fn ? (arg1, arg2, arg3) => arg1 !== void 0 && arg2 !== void 0 ? fn(arg1, arg2, arg3) : void 0 : void 0,
3147
+ [fn]
3148
+ );
3149
+ }
3102
3150
  var useCombinedRef = (...refs) => {
3103
3151
  const callback = useCallback((element) => {
3104
3152
  for (const ref of refs) {
@@ -3280,18 +3328,18 @@ function getRenderedItem(ctx, key) {
3280
3328
  function normalizeMaintainVisibleContentPosition(value) {
3281
3329
  var _a3, _b;
3282
3330
  if (value === true) {
3283
- return { dataChanged: true, scroll: true };
3331
+ return { data: true, size: true };
3284
3332
  }
3285
3333
  if (value && typeof value === "object") {
3286
3334
  return {
3287
- dataChanged: (_a3 = value.dataChanged) != null ? _a3 : false,
3288
- scroll: (_b = value.scroll) != null ? _b : true
3335
+ data: (_a3 = value.data) != null ? _a3 : false,
3336
+ size: (_b = value.size) != null ? _b : true
3289
3337
  };
3290
3338
  }
3291
3339
  if (value === false) {
3292
- return { dataChanged: false, scroll: false };
3340
+ return { data: false, size: false };
3293
3341
  }
3294
- return { dataChanged: false, scroll: true };
3342
+ return { data: false, size: true };
3295
3343
  }
3296
3344
  function useThrottleDebounce(mode) {
3297
3345
  const timeoutRef = useRef(null);
@@ -3417,6 +3465,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3417
3465
  viewabilityConfig,
3418
3466
  viewabilityConfigCallbackPairs,
3419
3467
  waitForInitialLayout = true,
3468
+ stickyHeaderConfig,
3420
3469
  ...rest
3421
3470
  } = props;
3422
3471
  const animatedPropsInternal = props.animatedPropsInternal;
@@ -3534,13 +3583,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3534
3583
  data: dataProp,
3535
3584
  dataVersion,
3536
3585
  estimatedItemSize,
3537
- getEstimatedItemSize,
3538
- getFixedItemSize,
3539
- getItemType,
3586
+ getEstimatedItemSize: useWrapIfItem(getEstimatedItemSize),
3587
+ getFixedItemSize: useWrapIfItem(getFixedItemSize),
3588
+ getItemType: useWrapIfItem(getItemType),
3540
3589
  horizontal: !!horizontal,
3541
3590
  initialContainerPoolRatio,
3542
3591
  itemsAreEqual,
3543
- keyExtractor,
3592
+ keyExtractor: useWrapIfItem(keyExtractor),
3544
3593
  maintainScrollAtEnd,
3545
3594
  maintainScrollAtEndThreshold,
3546
3595
  maintainVisibleContentPosition: maintainVisibleContentPositionConfig,
@@ -3578,7 +3627,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3578
3627
  setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
3579
3628
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3580
3629
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3581
- if (maintainVisibleContentPositionConfig.scroll && paddingDiff && prevPaddingTop !== void 0 && Platform2.OS === "ios") {
3630
+ if (maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform2.OS === "ios") {
3582
3631
  if (state.scroll < 0) {
3583
3632
  paddingDiff += state.scroll;
3584
3633
  }
@@ -3771,6 +3820,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3771
3820
  scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3772
3821
  scrollEventThrottle: 0,
3773
3822
  snapToIndices,
3823
+ stickyHeaderConfig,
3774
3824
  stickyHeaderIndices,
3775
3825
  style,
3776
3826
  updateItemSize: fns.updateItemSize,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "3.0.0-beta.13",
3
+ "version": "3.0.0-beta.15",
4
4
  "description": "Legend List is a drop-in replacement for FlatList with much better performance and supporting dynamically sized items.",
5
5
  "sideEffects": false,
6
6
  "private": false,