@legendapp/list 3.0.0-beta.52 → 3.0.0-beta.53

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.mjs CHANGED
@@ -139,7 +139,10 @@ function useSelector$(signalName, selector) {
139
139
  }
140
140
 
141
141
  // src/state/getContentInsetEnd.ts
142
- function getContentInsetEnd(ctx) {
142
+ function getContentInsetEndAdjustmentEnd(adjustment) {
143
+ return Math.max(0, adjustment != null ? adjustment : 0);
144
+ }
145
+ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
143
146
  var _a3, _b;
144
147
  const state = ctx.state;
145
148
  const { props } = state;
@@ -147,14 +150,21 @@ function getContentInsetEnd(ctx) {
147
150
  const contentInset = props.contentInset;
148
151
  const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
149
152
  const baseEndInset = (horizontal ? baseInset == null ? void 0 : baseInset.right : baseInset == null ? void 0 : baseInset.bottom) || 0;
153
+ const contentInsetEndAdjustment = getContentInsetEndAdjustmentEnd(
154
+ contentInsetEndAdjustmentOverride != null ? contentInsetEndAdjustmentOverride : props.contentInsetEndAdjustment
155
+ );
150
156
  const anchoredEndSpaceSize = peek$(ctx, "anchoredEndSpaceSize");
151
157
  const anchoredEndInset = ((_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.includeInEndInset) && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
152
158
  const overrideInset = (_b = state.contentInsetOverride) != null ? _b : void 0;
159
+ const adjustedBaseEndInset = baseEndInset + contentInsetEndAdjustment;
153
160
  if (overrideInset) {
154
161
  const mergedInset = { bottom: 0, right: 0, ...baseInset, ...overrideInset };
155
- return Math.max((horizontal ? mergedInset.right : mergedInset.bottom) || 0, anchoredEndInset);
162
+ return Math.max(
163
+ ((horizontal ? mergedInset.right : mergedInset.bottom) || 0) + contentInsetEndAdjustment,
164
+ anchoredEndInset
165
+ );
156
166
  }
157
- return Math.max(baseEndInset, anchoredEndInset);
167
+ return Math.max(adjustedBaseEndInset, anchoredEndInset);
158
168
  }
159
169
 
160
170
  // src/state/getContentSize.ts
@@ -646,6 +656,49 @@ function isInMVCPActiveMode(state) {
646
656
  }
647
657
 
648
658
  // src/components/Container.tsx
659
+ function getContainerPositionStyle({
660
+ columnWrapperStyle,
661
+ horizontal,
662
+ hasItemSeparator,
663
+ numColumns,
664
+ otherAxisPos,
665
+ otherAxisSize
666
+ }) {
667
+ let paddingStyles;
668
+ if (columnWrapperStyle) {
669
+ const { columnGap, rowGap, gap } = columnWrapperStyle;
670
+ if (horizontal) {
671
+ paddingStyles = {
672
+ paddingBottom: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0,
673
+ paddingRight: columnGap || gap || void 0,
674
+ paddingTop: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
675
+ };
676
+ } else {
677
+ paddingStyles = {
678
+ paddingBottom: rowGap || gap || void 0,
679
+ paddingLeft: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0,
680
+ paddingRight: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
681
+ };
682
+ }
683
+ }
684
+ return horizontal ? {
685
+ boxSizing: paddingStyles ? "border-box" : void 0,
686
+ flexDirection: hasItemSeparator ? "row" : void 0,
687
+ height: otherAxisSize,
688
+ left: 0,
689
+ position: "absolute",
690
+ top: otherAxisPos,
691
+ ...paddingStyles || {}
692
+ } : {
693
+ boxSizing: paddingStyles ? "border-box" : void 0,
694
+ left: otherAxisPos,
695
+ position: "absolute",
696
+ right: numColumns > 1 ? null : 0,
697
+ top: 0,
698
+ width: otherAxisSize,
699
+ ...paddingStyles || {}
700
+ };
701
+ }
649
702
  var Container = typedMemo(function Container2({
650
703
  id,
651
704
  recycleItems,
@@ -684,42 +737,17 @@ var Container = typedMemo(function Container2({
684
737
  const resolvedSpan = Math.min(Math.max(span || 1, 1), numColumns);
685
738
  const otherAxisPos = numColumns > 1 ? `${(resolvedColumn - 1) / numColumns * 100}%` : 0;
686
739
  const otherAxisSize = numColumns > 1 ? `${resolvedSpan / numColumns * 100}%` : void 0;
687
- const style = useMemo(() => {
688
- let paddingStyles;
689
- if (columnWrapperStyle) {
690
- const { columnGap, rowGap, gap } = columnWrapperStyle;
691
- if (horizontal) {
692
- paddingStyles = {
693
- paddingBottom: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0,
694
- paddingRight: columnGap || gap || void 0,
695
- paddingTop: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
696
- };
697
- } else {
698
- paddingStyles = {
699
- paddingBottom: rowGap || gap || void 0,
700
- paddingLeft: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0,
701
- paddingRight: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
702
- };
703
- }
704
- }
705
- return horizontal ? {
706
- boxSizing: paddingStyles ? "border-box" : void 0,
707
- flexDirection: ItemSeparatorComponent ? "row" : void 0,
708
- height: otherAxisSize,
709
- left: 0,
710
- position: "absolute",
711
- top: otherAxisPos,
712
- ...paddingStyles || {}
713
- } : {
714
- boxSizing: paddingStyles ? "border-box" : void 0,
715
- left: otherAxisPos,
716
- position: "absolute",
717
- right: numColumns > 1 ? null : 0,
718
- top: 0,
719
- width: otherAxisSize,
720
- ...paddingStyles || {}
721
- };
722
- }, [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns]);
740
+ const style = useMemo(
741
+ () => getContainerPositionStyle({
742
+ columnWrapperStyle,
743
+ hasItemSeparator: !!ItemSeparatorComponent,
744
+ horizontal,
745
+ numColumns,
746
+ otherAxisPos,
747
+ otherAxisSize
748
+ }),
749
+ [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns, ItemSeparatorComponent]
750
+ );
723
751
  const renderedItemInfo = useMemo(
724
752
  () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
725
753
  [itemKey, data, extraData]
@@ -2677,6 +2705,15 @@ function abortBootstrapInitialScroll(ctx) {
2677
2705
  }
2678
2706
 
2679
2707
  // src/core/initialScrollLifecycle.ts
2708
+ function retargetActiveInitialScrollAtEnd(ctx) {
2709
+ var _a3;
2710
+ const state = ctx.state;
2711
+ const initialScroll = state.initialScroll;
2712
+ if (!initialScroll || state.didFinishInitialScroll || ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset" || initialScroll.viewPosition !== 1 || state.props.data.length === 0) {
2713
+ return false;
2714
+ }
2715
+ return advanceCurrentInitialScrollSession(ctx, { forceScroll: true });
2716
+ }
2680
2717
  function handleInitialScrollLayoutReady(ctx) {
2681
2718
  var _a3;
2682
2719
  if (!ctx.state.initialScroll) {
@@ -4785,6 +4822,22 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4785
4822
  return nextSize;
4786
4823
  }
4787
4824
 
4825
+ // src/core/updateContentInsetEndAdjustment.ts
4826
+ function updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment) {
4827
+ const state = ctx.state;
4828
+ const previousContentInsetEnd = getContentInsetEnd(ctx, previousContentInsetEndAdjustment);
4829
+ const nextContentInsetEnd = getContentInsetEnd(ctx);
4830
+ const insetDiff = nextContentInsetEnd - previousContentInsetEnd;
4831
+ if (insetDiff !== 0) {
4832
+ const wasWithinEndThreshold = !!peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
4833
+ updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
4834
+ const didRetargetInitialScroll = retargetActiveInitialScrollAtEnd(ctx);
4835
+ if (!didRetargetInitialScroll && wasWithinEndThreshold && (Platform.OS !== "web" || insetDiff > 0)) {
4836
+ requestAdjust(ctx, insetDiff);
4837
+ }
4838
+ }
4839
+ }
4840
+
4788
4841
  // src/core/updateItemSize.ts
4789
4842
  function runOrScheduleMVCPRecalculate(ctx) {
4790
4843
  const state = ctx.state;
@@ -5147,8 +5200,14 @@ function createImperativeHandle(ctx) {
5147
5200
  startBuffered: state.startBuffered
5148
5201
  }),
5149
5202
  reportContentInset: (inset) => {
5203
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
5204
+ const previousInset = state.contentInsetOverride;
5150
5205
  state.contentInsetOverride = inset != null ? inset : void 0;
5206
+ const didChange = ((_a3 = previousInset == null ? void 0 : previousInset.top) != null ? _a3 : 0) !== ((_c = (_b = state.contentInsetOverride) == null ? void 0 : _b.top) != null ? _c : 0) || ((_d = previousInset == null ? void 0 : previousInset.bottom) != null ? _d : 0) !== ((_f = (_e = state.contentInsetOverride) == null ? void 0 : _e.bottom) != null ? _f : 0) || ((_g = previousInset == null ? void 0 : previousInset.left) != null ? _g : 0) !== ((_i = (_h = state.contentInsetOverride) == null ? void 0 : _h.left) != null ? _i : 0) || ((_j = previousInset == null ? void 0 : previousInset.right) != null ? _j : 0) !== ((_l = (_k = state.contentInsetOverride) == null ? void 0 : _k.right) != null ? _l : 0);
5151
5207
  updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
5208
+ if (didChange) {
5209
+ retargetActiveInitialScrollAtEnd(ctx);
5210
+ }
5152
5211
  },
5153
5212
  scrollIndexIntoView: (options) => runScrollWithPromise(() => scrollIndexIntoView(options)),
5154
5213
  scrollItemIntoView: ({ item, ...props }) => runScrollWithPromise(() => {
@@ -5449,6 +5508,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5449
5508
  data: dataProp = [],
5450
5509
  dataVersion,
5451
5510
  drawDistance = 250,
5511
+ contentInsetEndAdjustment,
5452
5512
  estimatedItemSize = 100,
5453
5513
  estimatedListSize,
5454
5514
  extraData,
@@ -5558,6 +5618,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5558
5618
  const combinedRef = useCombinedRef(refScroller, refScrollView);
5559
5619
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : ((_item, index) => index.toString());
5560
5620
  const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
5621
+ const contentInsetEndAdjustmentResolved = Platform.OS === "web" ? contentInsetEndAdjustment : void 0;
5622
+ const previousContentInsetEndAdjustmentRef = useRef(contentInsetEndAdjustmentResolved);
5561
5623
  const alwaysRenderIndices = useMemo(() => {
5562
5624
  const indices = getAlwaysRenderIndices(alwaysRender, dataProp, keyExtractor, anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex);
5563
5625
  return { arr: indices, set: new Set(indices) };
@@ -5677,6 +5739,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5677
5739
  anchoredEndSpace: anchoredEndSpaceResolved,
5678
5740
  animatedProps: animatedPropsInternal,
5679
5741
  contentInset,
5742
+ contentInsetEndAdjustment: contentInsetEndAdjustmentResolved,
5680
5743
  data: dataProp,
5681
5744
  dataVersion,
5682
5745
  drawDistance,
@@ -5799,6 +5862,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5799
5862
  didAnchoredEndSpaceAnchorIndexChange,
5800
5863
  numColumnsProp
5801
5864
  ]);
5865
+ useLayoutEffect(() => {
5866
+ const previousContentInsetEndAdjustment = previousContentInsetEndAdjustmentRef.current;
5867
+ previousContentInsetEndAdjustmentRef.current = contentInsetEndAdjustmentResolved;
5868
+ updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment);
5869
+ }, [ctx, contentInsetEndAdjustmentResolved]);
5802
5870
  const onLayoutFooter = useCallback(
5803
5871
  (layout) => {
5804
5872
  if (!usesBootstrapInitialScroll) {
@@ -221,7 +221,7 @@ type LegendListRef = Omit<LegendListRef$1, "getNativeScrollRef" | "getScrollResp
221
221
  reportContentInset(inset?: Partial<Insets$1> | null): void;
222
222
  };
223
223
 
224
- type KeyboardChatScrollViewPropsUnique = Omit<KeyboardChatScrollViewProps, keyof ScrollViewProps | "inverted" | "ScrollViewComponent" | "blankSpace" | "onContentInsetChange">;
224
+ type KeyboardChatScrollViewPropsUnique = Omit<KeyboardChatScrollViewProps, keyof ScrollViewProps | "inverted" | "ScrollViewComponent" | "blankSpace" | "extraContentPadding" | "onContentInsetChange">;
225
225
  type ScrollMessageToEndOptions = {
226
226
  animated: boolean;
227
227
  closeKeyboard: boolean;
@@ -241,8 +241,9 @@ declare function useKeyboardScrollToEnd({ freeze: freezeProp, listRef }: UseKeyb
241
241
  freeze: SharedValue<boolean>;
242
242
  scrollMessageToEnd: ({ animated, closeKeyboard }: ScrollMessageToEndOptions) => Promise<void>;
243
243
  };
244
- declare const KeyboardChatLegendList: <ItemT>(props: Omit<AnimatedLegendListProps<ItemT>, "anchoredEndSpace" | "renderScrollComponent"> & KeyboardChatScrollViewPropsUnique & {
244
+ declare const KeyboardChatLegendList: <ItemT>(props: Omit<AnimatedLegendListProps<ItemT>, "anchoredEndSpace" | "contentInsetEndAdjustment" | "renderScrollComponent"> & KeyboardChatScrollViewPropsUnique & {
245
245
  anchoredEndSpace?: AnchoredEndSpaceConfig;
246
+ contentInsetEndAdjustment?: SharedValue<number>;
246
247
  } & React.RefAttributes<LegendListRef>) => React.ReactElement | null;
247
248
 
248
249
  export { KeyboardChatLegendList, useKeyboardScrollToEnd };
package/keyboard-chat.js CHANGED
@@ -53,7 +53,7 @@ var KeyboardChatLegendList = typedForwardRef(function KeyboardChatLegendList2(pr
53
53
  const {
54
54
  anchoredEndSpace,
55
55
  applyWorkaroundForContentInsetHitTestBug,
56
- extraContentPadding,
56
+ contentInsetEndAdjustment,
57
57
  freeze,
58
58
  keyboardLiftBehavior,
59
59
  offset,
@@ -93,7 +93,7 @@ var KeyboardChatLegendList = typedForwardRef(function KeyboardChatLegendList2(pr
93
93
  ...scrollProps,
94
94
  applyWorkaroundForContentInsetHitTestBug,
95
95
  blankSpace,
96
- extraContentPadding,
96
+ extraContentPadding: contentInsetEndAdjustment,
97
97
  keyboardLiftBehavior,
98
98
  offset,
99
99
  onContentInsetChange
@@ -103,7 +103,7 @@ var KeyboardChatLegendList = typedForwardRef(function KeyboardChatLegendList2(pr
103
103
  [
104
104
  applyWorkaroundForContentInsetHitTestBug,
105
105
  blankSpace,
106
- extraContentPadding,
106
+ contentInsetEndAdjustment,
107
107
  freeze,
108
108
  keyboardLiftBehavior,
109
109
  onContentInsetChange,
package/keyboard-chat.mjs CHANGED
@@ -32,7 +32,7 @@ var KeyboardChatLegendList = typedForwardRef(function KeyboardChatLegendList2(pr
32
32
  const {
33
33
  anchoredEndSpace,
34
34
  applyWorkaroundForContentInsetHitTestBug,
35
- extraContentPadding,
35
+ contentInsetEndAdjustment,
36
36
  freeze,
37
37
  keyboardLiftBehavior,
38
38
  offset,
@@ -72,7 +72,7 @@ var KeyboardChatLegendList = typedForwardRef(function KeyboardChatLegendList2(pr
72
72
  ...scrollProps,
73
73
  applyWorkaroundForContentInsetHitTestBug,
74
74
  blankSpace,
75
- extraContentPadding,
75
+ extraContentPadding: contentInsetEndAdjustment,
76
76
  keyboardLiftBehavior,
77
77
  offset,
78
78
  onContentInsetChange
@@ -82,7 +82,7 @@ var KeyboardChatLegendList = typedForwardRef(function KeyboardChatLegendList2(pr
82
82
  [
83
83
  applyWorkaroundForContentInsetHitTestBug,
84
84
  blankSpace,
85
- extraContentPadding,
85
+ contentInsetEndAdjustment,
86
86
  freeze,
87
87
  keyboardLiftBehavior,
88
88
  onContentInsetChange,
@@ -1,6 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { ScrollViewComponent, ScrollResponderMixin, Insets as Insets$1, ScrollViewProps } from 'react-native';
3
3
  import { KeyboardChatScrollViewProps } from 'react-native-keyboard-controller';
4
+ import { SharedValue } from 'react-native-reanimated';
4
5
  export { useKeyboardScrollToEnd } from '@legendapp/list/keyboard-chat';
5
6
  import { AnimatedLegendListProps } from '@legendapp/list/reanimated';
6
7
 
@@ -211,7 +212,9 @@ type LegendListRef = Omit<LegendListRef$1, "getNativeScrollRef" | "getScrollResp
211
212
  reportContentInset(inset?: Partial<Insets$1> | null): void;
212
213
  };
213
214
 
214
- type KeyboardChatScrollViewPropsUnique = Omit<KeyboardChatScrollViewProps, keyof ScrollViewProps | "inverted" | "ScrollViewComponent" | "onContentInsetChange">;
215
- declare const KeyboardAvoidingLegendList: <ItemT>(props: Omit<AnimatedLegendListProps<ItemT>, "renderScrollComponent"> & KeyboardChatScrollViewPropsUnique & React.RefAttributes<LegendListRef>) => React.ReactElement | null;
215
+ type KeyboardChatScrollViewPropsUnique = Omit<KeyboardChatScrollViewProps, keyof ScrollViewProps | "inverted" | "ScrollViewComponent" | "extraContentPadding" | "onContentInsetChange">;
216
+ declare const KeyboardAvoidingLegendList: <ItemT>(props: Omit<AnimatedLegendListProps<ItemT>, "contentInsetEndAdjustment" | "renderScrollComponent"> & KeyboardChatScrollViewPropsUnique & {
217
+ contentInsetEndAdjustment?: SharedValue<number>;
218
+ } & React.RefAttributes<LegendListRef>) => React.ReactElement | null;
216
219
 
217
220
  export { KeyboardAvoidingLegendList };
package/keyboard-test.js CHANGED
@@ -29,7 +29,7 @@ var React__namespace = /*#__PURE__*/_interopNamespace(React);
29
29
  // src/integrations/keyboard-test.tsx
30
30
  var { typedForwardRef, useCombinedRef } = reactNative.internal;
31
31
  var KeyboardAvoidingLegendList = typedForwardRef(function KeyboardAvoidingLegendList2(props, forwardedRef) {
32
- const { extraContentPadding, ...rest } = props;
32
+ const { contentInsetEndAdjustment, ...rest } = props;
33
33
  const refLegendList = React.useRef(null);
34
34
  const combinedRef = useCombinedRef(forwardedRef, refLegendList);
35
35
  const onContentInsetChange = React.useCallback((insets) => {
@@ -41,11 +41,11 @@ var KeyboardAvoidingLegendList = typedForwardRef(function KeyboardAvoidingLegend
41
41
  reactNativeKeyboardController.KeyboardChatScrollView,
42
42
  {
43
43
  ...listProps,
44
- extraContentPadding,
44
+ extraContentPadding: contentInsetEndAdjustment,
45
45
  onContentInsetChange
46
46
  }
47
47
  ),
48
- [extraContentPadding, onContentInsetChange]
48
+ [contentInsetEndAdjustment, onContentInsetChange]
49
49
  );
50
50
  return /* @__PURE__ */ React__namespace.createElement(reanimated.AnimatedLegendList, { ref: combinedRef, renderScrollComponent: memoList, ...rest });
51
51
  });
package/keyboard-test.mjs CHANGED
@@ -8,7 +8,7 @@ import { AnimatedLegendList } from '@legendapp/list/reanimated';
8
8
  // src/integrations/keyboard-test.tsx
9
9
  var { typedForwardRef, useCombinedRef } = internal;
10
10
  var KeyboardAvoidingLegendList = typedForwardRef(function KeyboardAvoidingLegendList2(props, forwardedRef) {
11
- const { extraContentPadding, ...rest } = props;
11
+ const { contentInsetEndAdjustment, ...rest } = props;
12
12
  const refLegendList = useRef(null);
13
13
  const combinedRef = useCombinedRef(forwardedRef, refLegendList);
14
14
  const onContentInsetChange = useCallback((insets) => {
@@ -20,11 +20,11 @@ var KeyboardAvoidingLegendList = typedForwardRef(function KeyboardAvoidingLegend
20
20
  KeyboardChatScrollView,
21
21
  {
22
22
  ...listProps,
23
- extraContentPadding,
23
+ extraContentPadding: contentInsetEndAdjustment,
24
24
  onContentInsetChange
25
25
  }
26
26
  ),
27
- [extraContentPadding, onContentInsetChange]
27
+ [contentInsetEndAdjustment, onContentInsetChange]
28
28
  );
29
29
  return /* @__PURE__ */ React.createElement(AnimatedLegendList, { ref: combinedRef, renderScrollComponent: memoList, ...rest });
30
30
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "3.0.0-beta.52",
3
+ "version": "3.0.0-beta.53",
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,
package/react-native.d.ts CHANGED
@@ -254,6 +254,11 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
254
254
  * Keeps an item visually anchored to the start by adding trailing space when the content below it underflows.
255
255
  */
256
256
  anchoredEndSpace?: AnchoredEndSpaceConfig;
257
+ /**
258
+ * Adjusts the effective end content inset for web lists without replacing the base contentInset.
259
+ * The adjustment is also rendered as real content padding so the browser scroll range includes it.
260
+ */
261
+ contentInsetEndAdjustment?: number;
257
262
  /**
258
263
  * Number of columns to render items in.
259
264
  * @default 1
@@ -679,7 +684,7 @@ interface InitialScrollAnchor extends ScrollIndexWithOffsetPosition {
679
684
  settledTicks?: number;
680
685
  }
681
686
 
682
- type LegendListPropsOverrides<ItemT, TItemType extends string | undefined> = Omit<LegendListPropsBase<ItemT, ScrollViewProps, TItemType>, "anchoredEndSpace" | "onScroll" | "refScrollView" | "renderScrollComponent" | "ListHeaderComponentStyle" | "ListFooterComponentStyle"> & {
687
+ type LegendListPropsOverrides<ItemT, TItemType extends string | undefined> = Omit<LegendListPropsBase<ItemT, ScrollViewProps, TItemType>, "anchoredEndSpace" | "contentInsetEndAdjustment" | "onScroll" | "refScrollView" | "renderScrollComponent" | "ListHeaderComponentStyle" | "ListFooterComponentStyle"> & {
683
688
  onScroll?: (event: NativeSyntheticEvent$1<NativeScrollEvent$1>) => void;
684
689
  refScrollView?: React.Ref<ScrollView>;
685
690
  renderScrollComponent?: (props: ScrollViewProps) => React.ReactElement<ScrollViewProps>;
package/react-native.js CHANGED
@@ -160,7 +160,10 @@ function useSelector$(signalName, selector) {
160
160
  }
161
161
 
162
162
  // src/state/getContentInsetEnd.ts
163
- function getContentInsetEnd(ctx) {
163
+ function getContentInsetEndAdjustmentEnd(adjustment) {
164
+ return Math.max(0, adjustment != null ? adjustment : 0);
165
+ }
166
+ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
164
167
  var _a3, _b;
165
168
  const state = ctx.state;
166
169
  const { props } = state;
@@ -168,14 +171,21 @@ function getContentInsetEnd(ctx) {
168
171
  const contentInset = props.contentInset;
169
172
  const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
170
173
  const baseEndInset = (horizontal ? baseInset == null ? void 0 : baseInset.right : baseInset == null ? void 0 : baseInset.bottom) || 0;
174
+ const contentInsetEndAdjustment = getContentInsetEndAdjustmentEnd(
175
+ contentInsetEndAdjustmentOverride != null ? contentInsetEndAdjustmentOverride : props.contentInsetEndAdjustment
176
+ );
171
177
  const anchoredEndSpaceSize = peek$(ctx, "anchoredEndSpaceSize");
172
178
  const anchoredEndInset = ((_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.includeInEndInset) && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
173
179
  const overrideInset = (_b = state.contentInsetOverride) != null ? _b : void 0;
180
+ const adjustedBaseEndInset = baseEndInset + contentInsetEndAdjustment;
174
181
  if (overrideInset) {
175
182
  const mergedInset = { bottom: 0, right: 0, ...baseInset, ...overrideInset };
176
- return Math.max((horizontal ? mergedInset.right : mergedInset.bottom) || 0, anchoredEndInset);
183
+ return Math.max(
184
+ ((horizontal ? mergedInset.right : mergedInset.bottom) || 0) + contentInsetEndAdjustment,
185
+ anchoredEndInset
186
+ );
177
187
  }
178
- return Math.max(baseEndInset, anchoredEndInset);
188
+ return Math.max(adjustedBaseEndInset, anchoredEndInset);
179
189
  }
180
190
 
181
191
  // src/state/getContentSize.ts
@@ -667,6 +677,49 @@ function isInMVCPActiveMode(state) {
667
677
  }
668
678
 
669
679
  // src/components/Container.tsx
680
+ function getContainerPositionStyle({
681
+ columnWrapperStyle,
682
+ horizontal,
683
+ hasItemSeparator,
684
+ numColumns,
685
+ otherAxisPos,
686
+ otherAxisSize
687
+ }) {
688
+ let paddingStyles;
689
+ if (columnWrapperStyle) {
690
+ const { columnGap, rowGap, gap } = columnWrapperStyle;
691
+ if (horizontal) {
692
+ paddingStyles = {
693
+ paddingBottom: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0,
694
+ paddingRight: columnGap || gap || void 0,
695
+ paddingTop: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
696
+ };
697
+ } else {
698
+ paddingStyles = {
699
+ paddingBottom: rowGap || gap || void 0,
700
+ paddingLeft: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0,
701
+ paddingRight: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
702
+ };
703
+ }
704
+ }
705
+ return horizontal ? {
706
+ boxSizing: paddingStyles ? "border-box" : void 0,
707
+ flexDirection: hasItemSeparator ? "row" : void 0,
708
+ height: otherAxisSize,
709
+ left: 0,
710
+ position: "absolute",
711
+ top: otherAxisPos,
712
+ ...paddingStyles || {}
713
+ } : {
714
+ boxSizing: paddingStyles ? "border-box" : void 0,
715
+ left: otherAxisPos,
716
+ position: "absolute",
717
+ right: numColumns > 1 ? null : 0,
718
+ top: 0,
719
+ width: otherAxisSize,
720
+ ...paddingStyles || {}
721
+ };
722
+ }
670
723
  var Container = typedMemo(function Container2({
671
724
  id,
672
725
  recycleItems,
@@ -705,42 +758,17 @@ var Container = typedMemo(function Container2({
705
758
  const resolvedSpan = Math.min(Math.max(span || 1, 1), numColumns);
706
759
  const otherAxisPos = numColumns > 1 ? `${(resolvedColumn - 1) / numColumns * 100}%` : 0;
707
760
  const otherAxisSize = numColumns > 1 ? `${resolvedSpan / numColumns * 100}%` : void 0;
708
- const style = React2.useMemo(() => {
709
- let paddingStyles;
710
- if (columnWrapperStyle) {
711
- const { columnGap, rowGap, gap } = columnWrapperStyle;
712
- if (horizontal) {
713
- paddingStyles = {
714
- paddingBottom: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0,
715
- paddingRight: columnGap || gap || void 0,
716
- paddingTop: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
717
- };
718
- } else {
719
- paddingStyles = {
720
- paddingBottom: rowGap || gap || void 0,
721
- paddingLeft: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0,
722
- paddingRight: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
723
- };
724
- }
725
- }
726
- return horizontal ? {
727
- boxSizing: paddingStyles ? "border-box" : void 0,
728
- flexDirection: ItemSeparatorComponent ? "row" : void 0,
729
- height: otherAxisSize,
730
- left: 0,
731
- position: "absolute",
732
- top: otherAxisPos,
733
- ...paddingStyles || {}
734
- } : {
735
- boxSizing: paddingStyles ? "border-box" : void 0,
736
- left: otherAxisPos,
737
- position: "absolute",
738
- right: numColumns > 1 ? null : 0,
739
- top: 0,
740
- width: otherAxisSize,
741
- ...paddingStyles || {}
742
- };
743
- }, [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns]);
761
+ const style = React2.useMemo(
762
+ () => getContainerPositionStyle({
763
+ columnWrapperStyle,
764
+ hasItemSeparator: !!ItemSeparatorComponent,
765
+ horizontal,
766
+ numColumns,
767
+ otherAxisPos,
768
+ otherAxisSize
769
+ }),
770
+ [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns, ItemSeparatorComponent]
771
+ );
744
772
  const renderedItemInfo = React2.useMemo(
745
773
  () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
746
774
  [itemKey, data, extraData]
@@ -2698,6 +2726,15 @@ function abortBootstrapInitialScroll(ctx) {
2698
2726
  }
2699
2727
 
2700
2728
  // src/core/initialScrollLifecycle.ts
2729
+ function retargetActiveInitialScrollAtEnd(ctx) {
2730
+ var _a3;
2731
+ const state = ctx.state;
2732
+ const initialScroll = state.initialScroll;
2733
+ if (!initialScroll || state.didFinishInitialScroll || ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset" || initialScroll.viewPosition !== 1 || state.props.data.length === 0) {
2734
+ return false;
2735
+ }
2736
+ return advanceCurrentInitialScrollSession(ctx, { forceScroll: true });
2737
+ }
2701
2738
  function handleInitialScrollLayoutReady(ctx) {
2702
2739
  var _a3;
2703
2740
  if (!ctx.state.initialScroll) {
@@ -4806,6 +4843,22 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4806
4843
  return nextSize;
4807
4844
  }
4808
4845
 
4846
+ // src/core/updateContentInsetEndAdjustment.ts
4847
+ function updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment) {
4848
+ const state = ctx.state;
4849
+ const previousContentInsetEnd = getContentInsetEnd(ctx, previousContentInsetEndAdjustment);
4850
+ const nextContentInsetEnd = getContentInsetEnd(ctx);
4851
+ const insetDiff = nextContentInsetEnd - previousContentInsetEnd;
4852
+ if (insetDiff !== 0) {
4853
+ const wasWithinEndThreshold = !!peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
4854
+ updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
4855
+ const didRetargetInitialScroll = retargetActiveInitialScrollAtEnd(ctx);
4856
+ if (!didRetargetInitialScroll && wasWithinEndThreshold && (Platform.OS !== "web" || insetDiff > 0)) {
4857
+ requestAdjust(ctx, insetDiff);
4858
+ }
4859
+ }
4860
+ }
4861
+
4809
4862
  // src/core/updateItemSize.ts
4810
4863
  function runOrScheduleMVCPRecalculate(ctx) {
4811
4864
  const state = ctx.state;
@@ -5168,8 +5221,14 @@ function createImperativeHandle(ctx) {
5168
5221
  startBuffered: state.startBuffered
5169
5222
  }),
5170
5223
  reportContentInset: (inset) => {
5224
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
5225
+ const previousInset = state.contentInsetOverride;
5171
5226
  state.contentInsetOverride = inset != null ? inset : void 0;
5227
+ const didChange = ((_a3 = previousInset == null ? void 0 : previousInset.top) != null ? _a3 : 0) !== ((_c = (_b = state.contentInsetOverride) == null ? void 0 : _b.top) != null ? _c : 0) || ((_d = previousInset == null ? void 0 : previousInset.bottom) != null ? _d : 0) !== ((_f = (_e = state.contentInsetOverride) == null ? void 0 : _e.bottom) != null ? _f : 0) || ((_g = previousInset == null ? void 0 : previousInset.left) != null ? _g : 0) !== ((_i = (_h = state.contentInsetOverride) == null ? void 0 : _h.left) != null ? _i : 0) || ((_j = previousInset == null ? void 0 : previousInset.right) != null ? _j : 0) !== ((_l = (_k = state.contentInsetOverride) == null ? void 0 : _k.right) != null ? _l : 0);
5172
5228
  updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
5229
+ if (didChange) {
5230
+ retargetActiveInitialScrollAtEnd(ctx);
5231
+ }
5173
5232
  },
5174
5233
  scrollIndexIntoView: (options) => runScrollWithPromise(() => scrollIndexIntoView(options)),
5175
5234
  scrollItemIntoView: ({ item, ...props }) => runScrollWithPromise(() => {
@@ -5470,6 +5529,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5470
5529
  data: dataProp = [],
5471
5530
  dataVersion,
5472
5531
  drawDistance = 250,
5532
+ contentInsetEndAdjustment,
5473
5533
  estimatedItemSize = 100,
5474
5534
  estimatedListSize,
5475
5535
  extraData,
@@ -5579,6 +5639,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5579
5639
  const combinedRef = useCombinedRef(refScroller, refScrollView);
5580
5640
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : ((_item, index) => index.toString());
5581
5641
  const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
5642
+ const contentInsetEndAdjustmentResolved = Platform.OS === "web" ? contentInsetEndAdjustment : void 0;
5643
+ const previousContentInsetEndAdjustmentRef = React2.useRef(contentInsetEndAdjustmentResolved);
5582
5644
  const alwaysRenderIndices = React2.useMemo(() => {
5583
5645
  const indices = getAlwaysRenderIndices(alwaysRender, dataProp, keyExtractor, anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex);
5584
5646
  return { arr: indices, set: new Set(indices) };
@@ -5698,6 +5760,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5698
5760
  anchoredEndSpace: anchoredEndSpaceResolved,
5699
5761
  animatedProps: animatedPropsInternal,
5700
5762
  contentInset,
5763
+ contentInsetEndAdjustment: contentInsetEndAdjustmentResolved,
5701
5764
  data: dataProp,
5702
5765
  dataVersion,
5703
5766
  drawDistance,
@@ -5820,6 +5883,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5820
5883
  didAnchoredEndSpaceAnchorIndexChange,
5821
5884
  numColumnsProp
5822
5885
  ]);
5886
+ React2.useLayoutEffect(() => {
5887
+ const previousContentInsetEndAdjustment = previousContentInsetEndAdjustmentRef.current;
5888
+ previousContentInsetEndAdjustmentRef.current = contentInsetEndAdjustmentResolved;
5889
+ updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment);
5890
+ }, [ctx, contentInsetEndAdjustmentResolved]);
5823
5891
  const onLayoutFooter = React2.useCallback(
5824
5892
  (layout) => {
5825
5893
  if (!usesBootstrapInitialScroll) {