@legendapp/list 3.0.0-beta.51 → 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.
@@ -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
  import { AnimatedLegendListProps } from '@legendapp/list/reanimated';
5
6
 
6
7
  interface MaintainVisibleContentPositionNormalized<ItemT = any> {
@@ -220,9 +221,29 @@ type LegendListRef = Omit<LegendListRef$1, "getNativeScrollRef" | "getScrollResp
220
221
  reportContentInset(inset?: Partial<Insets$1> | null): void;
221
222
  };
222
223
 
223
- type KeyboardChatScrollViewPropsUnique = Omit<KeyboardChatScrollViewProps, keyof ScrollViewProps | "inverted" | "ScrollViewComponent" | "blankSpace" | "onContentInsetChange">;
224
- declare const KeyboardChatLegendList: <ItemT>(props: Omit<AnimatedLegendListProps<ItemT>, "anchoredEndSpace" | "renderScrollComponent"> & KeyboardChatScrollViewPropsUnique & {
224
+ type KeyboardChatScrollViewPropsUnique = Omit<KeyboardChatScrollViewProps, keyof ScrollViewProps | "inverted" | "ScrollViewComponent" | "blankSpace" | "extraContentPadding" | "onContentInsetChange">;
225
+ type ScrollMessageToEndOptions = {
226
+ animated: boolean;
227
+ closeKeyboard: boolean;
228
+ };
229
+ type KeyboardScrollToEndListRef = {
230
+ current: {
231
+ scrollToEnd(params?: {
232
+ animated?: boolean;
233
+ }): Promise<void>;
234
+ } | null;
235
+ };
236
+ type UseKeyboardScrollToEndOptions = {
237
+ freeze?: SharedValue<boolean>;
238
+ listRef: KeyboardScrollToEndListRef;
239
+ };
240
+ declare function useKeyboardScrollToEnd({ freeze: freezeProp, listRef }: UseKeyboardScrollToEndOptions): {
241
+ freeze: SharedValue<boolean>;
242
+ scrollMessageToEnd: ({ animated, closeKeyboard }: ScrollMessageToEndOptions) => Promise<void>;
243
+ };
244
+ declare const KeyboardChatLegendList: <ItemT>(props: Omit<AnimatedLegendListProps<ItemT>, "anchoredEndSpace" | "contentInsetEndAdjustment" | "renderScrollComponent"> & KeyboardChatScrollViewPropsUnique & {
225
245
  anchoredEndSpace?: AnchoredEndSpaceConfig;
246
+ contentInsetEndAdjustment?: SharedValue<number>;
226
247
  } & React.RefAttributes<LegendListRef>) => React.ReactElement | null;
227
248
 
228
- export { KeyboardChatLegendList };
249
+ export { KeyboardChatLegendList, useKeyboardScrollToEnd };
package/keyboard-chat.js CHANGED
@@ -28,11 +28,32 @@ var React__namespace = /*#__PURE__*/_interopNamespace(React);
28
28
 
29
29
  // src/integrations/keyboard-chat.tsx
30
30
  var { typedForwardRef, useCombinedRef } = reactNative.internal;
31
+ function useKeyboardScrollToEnd({ freeze: freezeProp, listRef }) {
32
+ const internalFreeze = reactNativeReanimated.useSharedValue(false);
33
+ const freeze = freezeProp != null ? freezeProp : internalFreeze;
34
+ const scrollMessageToEnd = React.useCallback(
35
+ async ({ animated, closeKeyboard }) => {
36
+ const listRefCurrent = listRef.current;
37
+ if (listRefCurrent) {
38
+ freeze.set(true);
39
+ const dismissPromise = closeKeyboard && reactNativeKeyboardController.KeyboardController.dismiss();
40
+ const scrollPromise = listRefCurrent.scrollToEnd({ animated });
41
+ await Promise.all([scrollPromise, dismissPromise]);
42
+ freeze.set(false);
43
+ }
44
+ },
45
+ [freeze, listRef]
46
+ );
47
+ return {
48
+ freeze,
49
+ scrollMessageToEnd
50
+ };
51
+ }
31
52
  var KeyboardChatLegendList = typedForwardRef(function KeyboardChatLegendList2(props, forwardedRef) {
32
53
  const {
33
54
  anchoredEndSpace,
34
55
  applyWorkaroundForContentInsetHitTestBug,
35
- extraContentPadding,
56
+ contentInsetEndAdjustment,
36
57
  freeze,
37
58
  keyboardLiftBehavior,
38
59
  offset,
@@ -72,8 +93,7 @@ var KeyboardChatLegendList = typedForwardRef(function KeyboardChatLegendList2(pr
72
93
  ...scrollProps,
73
94
  applyWorkaroundForContentInsetHitTestBug,
74
95
  blankSpace,
75
- extraContentPadding,
76
- freeze,
96
+ extraContentPadding: contentInsetEndAdjustment,
77
97
  keyboardLiftBehavior,
78
98
  offset,
79
99
  onContentInsetChange
@@ -83,7 +103,7 @@ var KeyboardChatLegendList = typedForwardRef(function KeyboardChatLegendList2(pr
83
103
  [
84
104
  applyWorkaroundForContentInsetHitTestBug,
85
105
  blankSpace,
86
- extraContentPadding,
106
+ contentInsetEndAdjustment,
87
107
  freeze,
88
108
  keyboardLiftBehavior,
89
109
  onContentInsetChange,
@@ -103,3 +123,4 @@ var KeyboardChatLegendList = typedForwardRef(function KeyboardChatLegendList2(pr
103
123
  });
104
124
 
105
125
  exports.KeyboardChatLegendList = KeyboardChatLegendList;
126
+ exports.useKeyboardScrollToEnd = useKeyboardScrollToEnd;
package/keyboard-chat.mjs CHANGED
@@ -1,17 +1,38 @@
1
1
  import * as React from 'react';
2
2
  import { useRef, useEffect, useMemo, useCallback } from 'react';
3
- import { KeyboardChatScrollView } from 'react-native-keyboard-controller';
3
+ import { KeyboardChatScrollView, KeyboardController } from 'react-native-keyboard-controller';
4
4
  import { useSharedValue } from 'react-native-reanimated';
5
5
  import { internal } from '@legendapp/list/react-native';
6
6
  import { AnimatedLegendList } from '@legendapp/list/reanimated';
7
7
 
8
8
  // src/integrations/keyboard-chat.tsx
9
9
  var { typedForwardRef, useCombinedRef } = internal;
10
+ function useKeyboardScrollToEnd({ freeze: freezeProp, listRef }) {
11
+ const internalFreeze = useSharedValue(false);
12
+ const freeze = freezeProp != null ? freezeProp : internalFreeze;
13
+ const scrollMessageToEnd = useCallback(
14
+ async ({ animated, closeKeyboard }) => {
15
+ const listRefCurrent = listRef.current;
16
+ if (listRefCurrent) {
17
+ freeze.set(true);
18
+ const dismissPromise = closeKeyboard && KeyboardController.dismiss();
19
+ const scrollPromise = listRefCurrent.scrollToEnd({ animated });
20
+ await Promise.all([scrollPromise, dismissPromise]);
21
+ freeze.set(false);
22
+ }
23
+ },
24
+ [freeze, listRef]
25
+ );
26
+ return {
27
+ freeze,
28
+ scrollMessageToEnd
29
+ };
30
+ }
10
31
  var KeyboardChatLegendList = typedForwardRef(function KeyboardChatLegendList2(props, forwardedRef) {
11
32
  const {
12
33
  anchoredEndSpace,
13
34
  applyWorkaroundForContentInsetHitTestBug,
14
- extraContentPadding,
35
+ contentInsetEndAdjustment,
15
36
  freeze,
16
37
  keyboardLiftBehavior,
17
38
  offset,
@@ -51,8 +72,7 @@ var KeyboardChatLegendList = typedForwardRef(function KeyboardChatLegendList2(pr
51
72
  ...scrollProps,
52
73
  applyWorkaroundForContentInsetHitTestBug,
53
74
  blankSpace,
54
- extraContentPadding,
55
- freeze,
75
+ extraContentPadding: contentInsetEndAdjustment,
56
76
  keyboardLiftBehavior,
57
77
  offset,
58
78
  onContentInsetChange
@@ -62,7 +82,7 @@ var KeyboardChatLegendList = typedForwardRef(function KeyboardChatLegendList2(pr
62
82
  [
63
83
  applyWorkaroundForContentInsetHitTestBug,
64
84
  blankSpace,
65
- extraContentPadding,
85
+ contentInsetEndAdjustment,
66
86
  freeze,
67
87
  keyboardLiftBehavior,
68
88
  onContentInsetChange,
@@ -81,4 +101,4 @@ var KeyboardChatLegendList = typedForwardRef(function KeyboardChatLegendList2(pr
81
101
  );
82
102
  });
83
103
 
84
- export { KeyboardChatLegendList };
104
+ export { KeyboardChatLegendList, useKeyboardScrollToEnd };
@@ -1,6 +1,8 @@
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';
5
+ export { useKeyboardScrollToEnd } from '@legendapp/list/keyboard-chat';
4
6
  import { AnimatedLegendListProps } from '@legendapp/list/reanimated';
5
7
 
6
8
  interface MaintainVisibleContentPositionNormalized<ItemT = any> {
@@ -210,7 +212,9 @@ type LegendListRef = Omit<LegendListRef$1, "getNativeScrollRef" | "getScrollResp
210
212
  reportContentInset(inset?: Partial<Insets$1> | null): void;
211
213
  };
212
214
 
213
- type KeyboardChatScrollViewPropsUnique = Omit<KeyboardChatScrollViewProps, keyof ScrollViewProps | "inverted" | "ScrollViewComponent" | "onContentInsetChange">;
214
- 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;
215
219
 
216
220
  export { KeyboardAvoidingLegendList };
package/keyboard-test.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  var React = require('react');
4
4
  var reactNativeKeyboardController = require('react-native-keyboard-controller');
5
+ var keyboardChat = require('@legendapp/list/keyboard-chat');
5
6
  var reactNative = require('@legendapp/list/react-native');
6
7
  var reanimated = require('@legendapp/list/reanimated');
7
8
 
@@ -28,7 +29,7 @@ var React__namespace = /*#__PURE__*/_interopNamespace(React);
28
29
  // src/integrations/keyboard-test.tsx
29
30
  var { typedForwardRef, useCombinedRef } = reactNative.internal;
30
31
  var KeyboardAvoidingLegendList = typedForwardRef(function KeyboardAvoidingLegendList2(props, forwardedRef) {
31
- const { extraContentPadding, ...rest } = props;
32
+ const { contentInsetEndAdjustment, ...rest } = props;
32
33
  const refLegendList = React.useRef(null);
33
34
  const combinedRef = useCombinedRef(forwardedRef, refLegendList);
34
35
  const onContentInsetChange = React.useCallback((insets) => {
@@ -40,13 +41,17 @@ var KeyboardAvoidingLegendList = typedForwardRef(function KeyboardAvoidingLegend
40
41
  reactNativeKeyboardController.KeyboardChatScrollView,
41
42
  {
42
43
  ...listProps,
43
- extraContentPadding,
44
+ extraContentPadding: contentInsetEndAdjustment,
44
45
  onContentInsetChange
45
46
  }
46
47
  ),
47
- [extraContentPadding, onContentInsetChange]
48
+ [contentInsetEndAdjustment, onContentInsetChange]
48
49
  );
49
50
  return /* @__PURE__ */ React__namespace.createElement(reanimated.AnimatedLegendList, { ref: combinedRef, renderScrollComponent: memoList, ...rest });
50
51
  });
51
52
 
53
+ Object.defineProperty(exports, "useKeyboardScrollToEnd", {
54
+ enumerable: true,
55
+ get: function () { return keyboardChat.useKeyboardScrollToEnd; }
56
+ });
52
57
  exports.KeyboardAvoidingLegendList = KeyboardAvoidingLegendList;
package/keyboard-test.mjs CHANGED
@@ -1,13 +1,14 @@
1
1
  import * as React from 'react';
2
2
  import { useRef, useCallback } from 'react';
3
3
  import { KeyboardChatScrollView } from 'react-native-keyboard-controller';
4
+ export { useKeyboardScrollToEnd } from '@legendapp/list/keyboard-chat';
4
5
  import { internal } from '@legendapp/list/react-native';
5
6
  import { AnimatedLegendList } from '@legendapp/list/reanimated';
6
7
 
7
8
  // src/integrations/keyboard-test.tsx
8
9
  var { typedForwardRef, useCombinedRef } = internal;
9
10
  var KeyboardAvoidingLegendList = typedForwardRef(function KeyboardAvoidingLegendList2(props, forwardedRef) {
10
- const { extraContentPadding, ...rest } = props;
11
+ const { contentInsetEndAdjustment, ...rest } = props;
11
12
  const refLegendList = useRef(null);
12
13
  const combinedRef = useCombinedRef(forwardedRef, refLegendList);
13
14
  const onContentInsetChange = useCallback((insets) => {
@@ -19,11 +20,11 @@ var KeyboardAvoidingLegendList = typedForwardRef(function KeyboardAvoidingLegend
19
20
  KeyboardChatScrollView,
20
21
  {
21
22
  ...listProps,
22
- extraContentPadding,
23
+ extraContentPadding: contentInsetEndAdjustment,
23
24
  onContentInsetChange
24
25
  }
25
26
  ),
26
- [extraContentPadding, onContentInsetChange]
27
+ [contentInsetEndAdjustment, onContentInsetChange]
27
28
  );
28
29
  return /* @__PURE__ */ React.createElement(AnimatedLegendList, { ref: combinedRef, renderScrollComponent: memoList, ...rest });
29
30
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "3.0.0-beta.51",
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) {
@@ -4796,17 +4833,32 @@ function maybeUpdateAnchoredEndSpace(ctx) {
4796
4833
  nextSize = Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
4797
4834
  }
4798
4835
  }
4799
- if (previousSize === nextSize) {
4800
- return nextSize;
4801
- }
4802
- set$(ctx, "anchoredEndSpaceSize", nextSize);
4803
- (_a3 = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onSizeChanged) == null ? void 0 : _a3.call(anchoredEndSpace, nextSize);
4804
- if (anchoredEndSpace == null ? void 0 : anchoredEndSpace.includeInEndInset) {
4805
- updateScroll(ctx, state.scroll, true);
4836
+ if (previousSize !== nextSize) {
4837
+ set$(ctx, "anchoredEndSpaceSize", nextSize);
4838
+ (_a3 = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onSizeChanged) == null ? void 0 : _a3.call(anchoredEndSpace, nextSize);
4839
+ if (anchoredEndSpace == null ? void 0 : anchoredEndSpace.includeInEndInset) {
4840
+ updateScroll(ctx, state.scroll, true);
4841
+ }
4806
4842
  }
4807
4843
  return nextSize;
4808
4844
  }
4809
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
+
4810
4862
  // src/core/updateItemSize.ts
4811
4863
  function runOrScheduleMVCPRecalculate(ctx) {
4812
4864
  const state = ctx.state;
@@ -5046,14 +5098,14 @@ function createImperativeHandle(ctx) {
5046
5098
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
5047
5099
  let imperativeScrollToken = 0;
5048
5100
  const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0;
5049
- const runWhenSettled = (token, run) => {
5101
+ const runWhenReady = (token, run, isReady) => {
5050
5102
  const startedAt = Date.now();
5051
5103
  let stableFrames = 0;
5052
5104
  const check = () => {
5053
5105
  if (token !== imperativeScrollToken) {
5054
5106
  return;
5055
5107
  }
5056
- if (isSettlingAfterDataChange()) {
5108
+ if (isSettlingAfterDataChange() || !isReady()) {
5057
5109
  stableFrames = 0;
5058
5110
  } else {
5059
5111
  stableFrames += 1;
@@ -5068,10 +5120,10 @@ function createImperativeHandle(ctx) {
5068
5120
  requestAnimationFrame(check);
5069
5121
  };
5070
5122
  const runScrollWithPromise = (run, options) => new Promise((resolve) => {
5071
- var _a3;
5123
+ var _a3, _b;
5072
5124
  const token = ++imperativeScrollToken;
5073
- const shouldWaitOneFrame = !!(options == null ? void 0 : options.shouldWaitOneFrame);
5074
- (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
5125
+ const isReady = (_a3 = options == null ? void 0 : options.isReady) != null ? _a3 : (() => true);
5126
+ (_b = state.pendingScrollResolve) == null ? void 0 : _b.call(state);
5075
5127
  state.pendingScrollResolve = resolve;
5076
5128
  const runNow = () => {
5077
5129
  if (token !== imperativeScrollToken) {
@@ -5085,11 +5137,10 @@ function createImperativeHandle(ctx) {
5085
5137
  resolve();
5086
5138
  }
5087
5139
  };
5088
- const execute = shouldWaitOneFrame ? () => requestAnimationFrame(runNow) : runNow;
5089
- if (isSettlingAfterDataChange()) {
5090
- runWhenSettled(token, execute);
5140
+ if (isSettlingAfterDataChange() || !isReady()) {
5141
+ runWhenReady(token, runNow, isReady);
5091
5142
  } else {
5092
- execute();
5143
+ runNow();
5093
5144
  }
5094
5145
  });
5095
5146
  const scrollIndexIntoView = (options) => {
@@ -5170,8 +5221,14 @@ function createImperativeHandle(ctx) {
5170
5221
  startBuffered: state.startBuffered
5171
5222
  }),
5172
5223
  reportContentInset: (inset) => {
5224
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
5225
+ const previousInset = state.contentInsetOverride;
5173
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);
5174
5228
  updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
5229
+ if (didChange) {
5230
+ retargetActiveInitialScrollAtEnd(ctx);
5231
+ }
5175
5232
  },
5176
5233
  scrollIndexIntoView: (options) => runScrollWithPromise(() => scrollIndexIntoView(options)),
5177
5234
  scrollItemIntoView: ({ item, ...props }) => runScrollWithPromise(() => {
@@ -5200,15 +5257,24 @@ function createImperativeHandle(ctx) {
5200
5257
  }
5201
5258
  return false;
5202
5259
  }),
5203
- scrollToIndex: (params) => runScrollWithPromise(
5204
- () => {
5260
+ scrollToIndex: (params) => {
5261
+ const shouldWaitForOutOfRangeTarget = params.index >= 0 && params.index >= state.props.data.length;
5262
+ const options = shouldWaitForOutOfRangeTarget ? {
5263
+ isReady: () => {
5264
+ var _a3;
5265
+ const props = state.props;
5266
+ const anchorIndex = (_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.anchorIndex;
5267
+ const lastIndex = props.data.length - 1;
5268
+ const isInRange = params.index < props.data.length;
5269
+ const shouldWaitForAnchorSize = isInRange && anchorIndex !== void 0 && anchorIndex >= 0 && params.index >= anchorIndex && !props.getFixedItemSize && !state.sizesKnown.has(getId(state, lastIndex));
5270
+ return isInRange && !shouldWaitForAnchorSize;
5271
+ }
5272
+ } : void 0;
5273
+ return runScrollWithPromise(() => {
5205
5274
  scrollToIndex(ctx, params);
5206
5275
  return true;
5207
- },
5208
- {
5209
- shouldWaitOneFrame: params.index >= 0 && params.index >= state.props.data.length
5210
- }
5211
- ),
5276
+ }, options);
5277
+ },
5212
5278
  scrollToItem: ({ item, ...props }) => runScrollWithPromise(() => {
5213
5279
  const data = state.props.data;
5214
5280
  const index = data.indexOf(item);
@@ -5463,6 +5529,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5463
5529
  data: dataProp = [],
5464
5530
  dataVersion,
5465
5531
  drawDistance = 250,
5532
+ contentInsetEndAdjustment,
5466
5533
  estimatedItemSize = 100,
5467
5534
  estimatedListSize,
5468
5535
  extraData,
@@ -5572,6 +5639,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5572
5639
  const combinedRef = useCombinedRef(refScroller, refScrollView);
5573
5640
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : ((_item, index) => index.toString());
5574
5641
  const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
5642
+ const contentInsetEndAdjustmentResolved = Platform.OS === "web" ? contentInsetEndAdjustment : void 0;
5643
+ const previousContentInsetEndAdjustmentRef = React2.useRef(contentInsetEndAdjustmentResolved);
5575
5644
  const alwaysRenderIndices = React2.useMemo(() => {
5576
5645
  const indices = getAlwaysRenderIndices(alwaysRender, dataProp, keyExtractor, anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex);
5577
5646
  return { arr: indices, set: new Set(indices) };
@@ -5691,6 +5760,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5691
5760
  anchoredEndSpace: anchoredEndSpaceResolved,
5692
5761
  animatedProps: animatedPropsInternal,
5693
5762
  contentInset,
5763
+ contentInsetEndAdjustment: contentInsetEndAdjustmentResolved,
5694
5764
  data: dataProp,
5695
5765
  dataVersion,
5696
5766
  drawDistance,
@@ -5813,6 +5883,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5813
5883
  didAnchoredEndSpaceAnchorIndexChange,
5814
5884
  numColumnsProp
5815
5885
  ]);
5886
+ React2.useLayoutEffect(() => {
5887
+ const previousContentInsetEndAdjustment = previousContentInsetEndAdjustmentRef.current;
5888
+ previousContentInsetEndAdjustmentRef.current = contentInsetEndAdjustmentResolved;
5889
+ updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment);
5890
+ }, [ctx, contentInsetEndAdjustmentResolved]);
5816
5891
  const onLayoutFooter = React2.useCallback(
5817
5892
  (layout) => {
5818
5893
  if (!usesBootstrapInitialScroll) {