@legendapp/list 3.0.0-beta.21 → 3.0.0-beta.22

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.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as React$1 from 'react';
2
2
  import { ComponentProps, Key, ReactNode, Dispatch, SetStateAction } from 'react';
3
- import { View, ScrollView, Animated, LayoutRectangle, ScrollViewProps, Insets, ScrollViewComponent, ScrollResponderMixin, StyleProp, ViewStyle, NativeSyntheticEvent, NativeScrollEvent } from 'react-native';
3
+ import { View, ScrollView, Animated, LayoutRectangle, Insets, ScrollViewProps, ScrollViewComponent, ScrollResponderMixin, StyleProp, ViewStyle, NativeSyntheticEvent, NativeScrollEvent } from 'react-native';
4
4
  import Reanimated from 'react-native-reanimated';
5
5
 
6
6
  type AnimatedValue = number;
@@ -466,6 +466,8 @@ interface InternalState {
466
466
  loadStartTime: number;
467
467
  maintainingScrollAtEnd?: boolean;
468
468
  minIndexSizeChanged: number | undefined;
469
+ contentInsetOverride?: Partial<Insets> | null;
470
+ nativeContentInset?: Insets;
469
471
  nativeMarginTop: number;
470
472
  needsOtherAxisSize?: boolean;
471
473
  otherAxisSize?: number;
@@ -581,6 +583,7 @@ type LegendListState = {
581
583
  positions: Map<string, number>;
582
584
  scroll: number;
583
585
  scrollLength: number;
586
+ scrollVelocity: number;
584
587
  sizeAtIndex: (index: number) => number;
585
588
  sizes: Map<string, number>;
586
589
  start: number;
@@ -686,6 +689,11 @@ type LegendListRef = {
686
689
  * @param enabled - If true, scroll processing is enabled.
687
690
  */
688
691
  setScrollProcessingEnabled(enabled: boolean): void;
692
+ /**
693
+ * Reports an externally measured content inset. Pass null/undefined to clear.
694
+ * Values are merged on top of props/animated/native insets.
695
+ */
696
+ reportContentInset(inset?: Partial<Insets> | null): void;
689
697
  };
690
698
  interface ViewToken<ItemT = any> {
691
699
  containerId: number;
package/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as React$1 from 'react';
2
2
  import { ComponentProps, Key, ReactNode, Dispatch, SetStateAction } from 'react';
3
- import { View, ScrollView, Animated, LayoutRectangle, ScrollViewProps, Insets, ScrollViewComponent, ScrollResponderMixin, StyleProp, ViewStyle, NativeSyntheticEvent, NativeScrollEvent } from 'react-native';
3
+ import { View, ScrollView, Animated, LayoutRectangle, Insets, ScrollViewProps, ScrollViewComponent, ScrollResponderMixin, StyleProp, ViewStyle, NativeSyntheticEvent, NativeScrollEvent } from 'react-native';
4
4
  import Reanimated from 'react-native-reanimated';
5
5
 
6
6
  type AnimatedValue = number;
@@ -466,6 +466,8 @@ interface InternalState {
466
466
  loadStartTime: number;
467
467
  maintainingScrollAtEnd?: boolean;
468
468
  minIndexSizeChanged: number | undefined;
469
+ contentInsetOverride?: Partial<Insets> | null;
470
+ nativeContentInset?: Insets;
469
471
  nativeMarginTop: number;
470
472
  needsOtherAxisSize?: boolean;
471
473
  otherAxisSize?: number;
@@ -581,6 +583,7 @@ type LegendListState = {
581
583
  positions: Map<string, number>;
582
584
  scroll: number;
583
585
  scrollLength: number;
586
+ scrollVelocity: number;
584
587
  sizeAtIndex: (index: number) => number;
585
588
  sizes: Map<string, number>;
586
589
  start: number;
@@ -686,6 +689,11 @@ type LegendListRef = {
686
689
  * @param enabled - If true, scroll processing is enabled.
687
690
  */
688
691
  setScrollProcessingEnabled(enabled: boolean): void;
692
+ /**
693
+ * Reports an externally measured content inset. Pass null/undefined to clear.
694
+ * Values are merged on top of props/animated/native insets.
695
+ */
696
+ reportContentInset(inset?: Partial<Insets> | null): void;
689
697
  };
690
698
  interface ViewToken<ItemT = any> {
691
699
  containerId: number;
package/index.js CHANGED
@@ -35,7 +35,7 @@ var Text = View;
35
35
 
36
36
  // src/state/getContentInsetEnd.ts
37
37
  function getContentInsetEnd(state) {
38
- var _a3;
38
+ var _a3, _b;
39
39
  const { props } = state;
40
40
  const horizontal = props.horizontal;
41
41
  let contentInset = props.contentInset;
@@ -49,7 +49,16 @@ function getContentInsetEnd(state) {
49
49
  }
50
50
  }
51
51
  }
52
- return (horizontal ? contentInset == null ? void 0 : contentInset.right : contentInset == null ? void 0 : contentInset.bottom) || 0;
52
+ const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
53
+ const overrideInset = (_b = state.contentInsetOverride) != null ? _b : void 0;
54
+ if (overrideInset) {
55
+ const mergedInset = { top: 0, left: 0, right: 0, bottom: 0, ...baseInset, ...overrideInset };
56
+ return (horizontal ? mergedInset.right : mergedInset.bottom) || 0;
57
+ }
58
+ if (baseInset) {
59
+ return (horizontal ? baseInset.right : baseInset.bottom) || 0;
60
+ }
61
+ return 0;
53
62
  }
54
63
 
55
64
  // src/state/getContentSize.ts
@@ -1753,7 +1762,7 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1753
1762
  const scrollDelta = Math.abs(newScroll - prevScroll);
1754
1763
  const scrollLength = state.scrollLength;
1755
1764
  const lastCalculated = state.scrollLastCalculate;
1756
- const shouldUpdate = state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1765
+ const shouldUpdate = forceUpdate || state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1757
1766
  if (shouldUpdate) {
1758
1767
  state.scrollLastCalculate = state.scroll;
1759
1768
  state.ignoreScrollFromMVCPIgnored = false;
@@ -3243,7 +3252,7 @@ function handleLayout(ctx, layout, setCanRender) {
3243
3252
 
3244
3253
  // src/core/onScroll.ts
3245
3254
  function onScroll(ctx, event) {
3246
- var _a3, _b, _c;
3255
+ var _a3, _b, _c, _d;
3247
3256
  const state = ctx.state;
3248
3257
  const {
3249
3258
  scrollProcessingEnabled,
@@ -3255,6 +3264,15 @@ function onScroll(ctx, event) {
3255
3264
  if (((_b = (_a3 = event.nativeEvent) == null ? void 0 : _a3.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
3256
3265
  return;
3257
3266
  }
3267
+ let insetChanged = false;
3268
+ if ((_d = event.nativeEvent) == null ? void 0 : _d.contentInset) {
3269
+ const { contentInset } = event.nativeEvent;
3270
+ const prevInset = state.nativeContentInset;
3271
+ if (!prevInset || prevInset.top !== contentInset.top || prevInset.bottom !== contentInset.bottom || prevInset.left !== contentInset.left || prevInset.right !== contentInset.right) {
3272
+ state.nativeContentInset = contentInset;
3273
+ insetChanged = true;
3274
+ }
3275
+ }
3258
3276
  let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3259
3277
  if (state.scrollingTo) {
3260
3278
  const maxOffset = clampScrollOffset(ctx, newScroll);
@@ -3270,7 +3288,7 @@ function onScroll(ctx, event) {
3270
3288
  }
3271
3289
  }
3272
3290
  state.scrollPending = newScroll;
3273
- updateScroll(ctx, newScroll);
3291
+ updateScroll(ctx, newScroll, insetChanged);
3274
3292
  if (state.scrollingTo) {
3275
3293
  checkFinishedScroll(ctx);
3276
3294
  }
@@ -3443,7 +3461,10 @@ function updateOneItemSize(ctx, itemKey, sizeObj) {
3443
3461
  if (!averages) {
3444
3462
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
3445
3463
  }
3446
- if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3464
+ if (averages.num === 0) {
3465
+ averages.avg = size;
3466
+ averages.num++;
3467
+ } else if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3447
3468
  averages.avg += (size - prevSizeKnown) / averages.num;
3448
3469
  } else {
3449
3470
  averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
@@ -3528,7 +3549,7 @@ function createImperativeHandle(ctx) {
3528
3549
  getScrollResponder: () => refScroller.current.getScrollResponder(),
3529
3550
  getState: () => ({
3530
3551
  activeStickyIndex: peek$(ctx, "activeStickyIndex"),
3531
- contentLength: state.totalSize,
3552
+ contentLength: getContentSize(ctx),
3532
3553
  data: state.props.data,
3533
3554
  elementAtIndex: (index) => {
3534
3555
  var _a3;
@@ -3544,6 +3565,7 @@ function createImperativeHandle(ctx) {
3544
3565
  positions: state.positions,
3545
3566
  scroll: state.scroll,
3546
3567
  scrollLength: state.scrollLength,
3568
+ scrollVelocity: getScrollVelocity(state),
3547
3569
  sizeAtIndex: (index) => state.sizesKnown.get(getId(state, index)),
3548
3570
  sizes: state.sizesKnown,
3549
3571
  start: state.startNoBuffer,
@@ -3581,6 +3603,10 @@ function createImperativeHandle(ctx) {
3581
3603
  }
3582
3604
  },
3583
3605
  scrollToOffset: (params) => scrollTo(ctx, params),
3606
+ reportContentInset: (inset) => {
3607
+ state.contentInsetOverride = inset != null ? inset : void 0;
3608
+ updateScroll(ctx, state.scroll, true);
3609
+ },
3584
3610
  setScrollProcessingEnabled: (enabled) => {
3585
3611
  state.scrollProcessingEnabled = enabled;
3586
3612
  },
@@ -3892,6 +3918,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3892
3918
  lastScrollDelta: 0,
3893
3919
  loadStartTime: Date.now(),
3894
3920
  minIndexSizeChanged: 0,
3921
+ contentInsetOverride: void 0,
3922
+ nativeContentInset: void 0,
3895
3923
  nativeMarginTop: 0,
3896
3924
  positions: /* @__PURE__ */ new Map(),
3897
3925
  props: {},
package/index.mjs CHANGED
@@ -14,7 +14,7 @@ var Text = View;
14
14
 
15
15
  // src/state/getContentInsetEnd.ts
16
16
  function getContentInsetEnd(state) {
17
- var _a3;
17
+ var _a3, _b;
18
18
  const { props } = state;
19
19
  const horizontal = props.horizontal;
20
20
  let contentInset = props.contentInset;
@@ -28,7 +28,16 @@ function getContentInsetEnd(state) {
28
28
  }
29
29
  }
30
30
  }
31
- return (horizontal ? contentInset == null ? void 0 : contentInset.right : contentInset == null ? void 0 : contentInset.bottom) || 0;
31
+ const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
32
+ const overrideInset = (_b = state.contentInsetOverride) != null ? _b : void 0;
33
+ if (overrideInset) {
34
+ const mergedInset = { top: 0, left: 0, right: 0, bottom: 0, ...baseInset, ...overrideInset };
35
+ return (horizontal ? mergedInset.right : mergedInset.bottom) || 0;
36
+ }
37
+ if (baseInset) {
38
+ return (horizontal ? baseInset.right : baseInset.bottom) || 0;
39
+ }
40
+ return 0;
32
41
  }
33
42
 
34
43
  // src/state/getContentSize.ts
@@ -1732,7 +1741,7 @@ function updateScroll(ctx, newScroll, forceUpdate) {
1732
1741
  const scrollDelta = Math.abs(newScroll - prevScroll);
1733
1742
  const scrollLength = state.scrollLength;
1734
1743
  const lastCalculated = state.scrollLastCalculate;
1735
- const shouldUpdate = state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1744
+ const shouldUpdate = forceUpdate || state.dataChangeNeedsScrollUpdate || state.scrollLastCalculate === void 0 || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1736
1745
  if (shouldUpdate) {
1737
1746
  state.scrollLastCalculate = state.scroll;
1738
1747
  state.ignoreScrollFromMVCPIgnored = false;
@@ -3222,7 +3231,7 @@ function handleLayout(ctx, layout, setCanRender) {
3222
3231
 
3223
3232
  // src/core/onScroll.ts
3224
3233
  function onScroll(ctx, event) {
3225
- var _a3, _b, _c;
3234
+ var _a3, _b, _c, _d;
3226
3235
  const state = ctx.state;
3227
3236
  const {
3228
3237
  scrollProcessingEnabled,
@@ -3234,6 +3243,15 @@ function onScroll(ctx, event) {
3234
3243
  if (((_b = (_a3 = event.nativeEvent) == null ? void 0 : _a3.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
3235
3244
  return;
3236
3245
  }
3246
+ let insetChanged = false;
3247
+ if ((_d = event.nativeEvent) == null ? void 0 : _d.contentInset) {
3248
+ const { contentInset } = event.nativeEvent;
3249
+ const prevInset = state.nativeContentInset;
3250
+ if (!prevInset || prevInset.top !== contentInset.top || prevInset.bottom !== contentInset.bottom || prevInset.left !== contentInset.left || prevInset.right !== contentInset.right) {
3251
+ state.nativeContentInset = contentInset;
3252
+ insetChanged = true;
3253
+ }
3254
+ }
3237
3255
  let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3238
3256
  if (state.scrollingTo) {
3239
3257
  const maxOffset = clampScrollOffset(ctx, newScroll);
@@ -3249,7 +3267,7 @@ function onScroll(ctx, event) {
3249
3267
  }
3250
3268
  }
3251
3269
  state.scrollPending = newScroll;
3252
- updateScroll(ctx, newScroll);
3270
+ updateScroll(ctx, newScroll, insetChanged);
3253
3271
  if (state.scrollingTo) {
3254
3272
  checkFinishedScroll(ctx);
3255
3273
  }
@@ -3422,7 +3440,10 @@ function updateOneItemSize(ctx, itemKey, sizeObj) {
3422
3440
  if (!averages) {
3423
3441
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
3424
3442
  }
3425
- if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3443
+ if (averages.num === 0) {
3444
+ averages.avg = size;
3445
+ averages.num++;
3446
+ } else if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3426
3447
  averages.avg += (size - prevSizeKnown) / averages.num;
3427
3448
  } else {
3428
3449
  averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
@@ -3507,7 +3528,7 @@ function createImperativeHandle(ctx) {
3507
3528
  getScrollResponder: () => refScroller.current.getScrollResponder(),
3508
3529
  getState: () => ({
3509
3530
  activeStickyIndex: peek$(ctx, "activeStickyIndex"),
3510
- contentLength: state.totalSize,
3531
+ contentLength: getContentSize(ctx),
3511
3532
  data: state.props.data,
3512
3533
  elementAtIndex: (index) => {
3513
3534
  var _a3;
@@ -3523,6 +3544,7 @@ function createImperativeHandle(ctx) {
3523
3544
  positions: state.positions,
3524
3545
  scroll: state.scroll,
3525
3546
  scrollLength: state.scrollLength,
3547
+ scrollVelocity: getScrollVelocity(state),
3526
3548
  sizeAtIndex: (index) => state.sizesKnown.get(getId(state, index)),
3527
3549
  sizes: state.sizesKnown,
3528
3550
  start: state.startNoBuffer,
@@ -3560,6 +3582,10 @@ function createImperativeHandle(ctx) {
3560
3582
  }
3561
3583
  },
3562
3584
  scrollToOffset: (params) => scrollTo(ctx, params),
3585
+ reportContentInset: (inset) => {
3586
+ state.contentInsetOverride = inset != null ? inset : void 0;
3587
+ updateScroll(ctx, state.scroll, true);
3588
+ },
3563
3589
  setScrollProcessingEnabled: (enabled) => {
3564
3590
  state.scrollProcessingEnabled = enabled;
3565
3591
  },
@@ -3871,6 +3897,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3871
3897
  lastScrollDelta: 0,
3872
3898
  loadStartTime: Date.now(),
3873
3899
  minIndexSizeChanged: 0,
3900
+ contentInsetOverride: void 0,
3901
+ nativeContentInset: void 0,
3874
3902
  nativeMarginTop: 0,
3875
3903
  positions: /* @__PURE__ */ new Map(),
3876
3904
  props: {},
@@ -1,6 +1,6 @@
1
1
  import * as React$1 from 'react';
2
2
  import { ComponentProps, Key, ReactNode, Dispatch, SetStateAction } from 'react';
3
- import { View, ScrollView, Animated, LayoutRectangle, ScrollViewProps, Insets, ScrollViewComponent, ScrollResponderMixin, StyleProp, ViewStyle, NativeSyntheticEvent, NativeScrollEvent } from 'react-native';
3
+ import { View, ScrollView, Animated, LayoutRectangle, Insets, ScrollViewProps, ScrollViewComponent, ScrollResponderMixin, StyleProp, ViewStyle, NativeSyntheticEvent, NativeScrollEvent } from 'react-native';
4
4
  import Reanimated from 'react-native-reanimated';
5
5
 
6
6
  type AnimatedValue = number;
@@ -466,6 +466,8 @@ interface InternalState {
466
466
  loadStartTime: number;
467
467
  maintainingScrollAtEnd?: boolean;
468
468
  minIndexSizeChanged: number | undefined;
469
+ contentInsetOverride?: Partial<Insets> | null;
470
+ nativeContentInset?: Insets;
469
471
  nativeMarginTop: number;
470
472
  needsOtherAxisSize?: boolean;
471
473
  otherAxisSize?: number;
@@ -581,6 +583,7 @@ type LegendListState = {
581
583
  positions: Map<string, number>;
582
584
  scroll: number;
583
585
  scrollLength: number;
586
+ scrollVelocity: number;
584
587
  sizeAtIndex: (index: number) => number;
585
588
  sizes: Map<string, number>;
586
589
  start: number;
@@ -686,6 +689,11 @@ type LegendListRef = {
686
689
  * @param enabled - If true, scroll processing is enabled.
687
690
  */
688
691
  setScrollProcessingEnabled(enabled: boolean): void;
692
+ /**
693
+ * Reports an externally measured content inset. Pass null/undefined to clear.
694
+ * Values are merged on top of props/animated/native insets.
695
+ */
696
+ reportContentInset(inset?: Partial<Insets> | null): void;
689
697
  };
690
698
  interface ViewToken<ItemT = any> {
691
699
  containerId: number;
package/index.native.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as React$1 from 'react';
2
2
  import { ComponentProps, Key, ReactNode, Dispatch, SetStateAction } from 'react';
3
- import { View, ScrollView, Animated, LayoutRectangle, ScrollViewProps, Insets, ScrollViewComponent, ScrollResponderMixin, StyleProp, ViewStyle, NativeSyntheticEvent, NativeScrollEvent } from 'react-native';
3
+ import { View, ScrollView, Animated, LayoutRectangle, Insets, ScrollViewProps, ScrollViewComponent, ScrollResponderMixin, StyleProp, ViewStyle, NativeSyntheticEvent, NativeScrollEvent } from 'react-native';
4
4
  import Reanimated from 'react-native-reanimated';
5
5
 
6
6
  type AnimatedValue = number;
@@ -466,6 +466,8 @@ interface InternalState {
466
466
  loadStartTime: number;
467
467
  maintainingScrollAtEnd?: boolean;
468
468
  minIndexSizeChanged: number | undefined;
469
+ contentInsetOverride?: Partial<Insets> | null;
470
+ nativeContentInset?: Insets;
469
471
  nativeMarginTop: number;
470
472
  needsOtherAxisSize?: boolean;
471
473
  otherAxisSize?: number;
@@ -581,6 +583,7 @@ type LegendListState = {
581
583
  positions: Map<string, number>;
582
584
  scroll: number;
583
585
  scrollLength: number;
586
+ scrollVelocity: number;
584
587
  sizeAtIndex: (index: number) => number;
585
588
  sizes: Map<string, number>;
586
589
  start: number;
@@ -686,6 +689,11 @@ type LegendListRef = {
686
689
  * @param enabled - If true, scroll processing is enabled.
687
690
  */
688
691
  setScrollProcessingEnabled(enabled: boolean): void;
692
+ /**
693
+ * Reports an externally measured content inset. Pass null/undefined to clear.
694
+ * Values are merged on top of props/animated/native insets.
695
+ */
696
+ reportContentInset(inset?: Partial<Insets> | null): void;
689
697
  };
690
698
  interface ViewToken<ItemT = any> {
691
699
  containerId: number;
package/index.native.js CHANGED
@@ -31,7 +31,7 @@ var Text = reactNative.Text;
31
31
 
32
32
  // src/state/getContentInsetEnd.ts
33
33
  function getContentInsetEnd(state) {
34
- var _a3;
34
+ var _a3, _b;
35
35
  const { props } = state;
36
36
  const horizontal = props.horizontal;
37
37
  let contentInset = props.contentInset;
@@ -45,7 +45,16 @@ function getContentInsetEnd(state) {
45
45
  }
46
46
  }
47
47
  }
48
- return (horizontal ? contentInset == null ? void 0 : contentInset.right : contentInset == null ? void 0 : contentInset.bottom) || 0;
48
+ const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
49
+ const overrideInset = (_b = state.contentInsetOverride) != null ? _b : void 0;
50
+ if (overrideInset) {
51
+ const mergedInset = { top: 0, left: 0, right: 0, bottom: 0, ...baseInset, ...overrideInset };
52
+ return (horizontal ? mergedInset.right : mergedInset.bottom) || 0;
53
+ }
54
+ if (baseInset) {
55
+ return (horizontal ? baseInset.right : baseInset.bottom) || 0;
56
+ }
57
+ return 0;
49
58
  }
50
59
 
51
60
  // src/state/getContentSize.ts
@@ -3027,7 +3036,7 @@ function handleLayout(ctx, layout, setCanRender) {
3027
3036
 
3028
3037
  // src/core/onScroll.ts
3029
3038
  function onScroll(ctx, event) {
3030
- var _a3, _b, _c;
3039
+ var _a3, _b, _c, _d;
3031
3040
  const state = ctx.state;
3032
3041
  const {
3033
3042
  scrollProcessingEnabled,
@@ -3039,6 +3048,15 @@ function onScroll(ctx, event) {
3039
3048
  if (((_b = (_a3 = event.nativeEvent) == null ? void 0 : _a3.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
3040
3049
  return;
3041
3050
  }
3051
+ let insetChanged = false;
3052
+ if ((_d = event.nativeEvent) == null ? void 0 : _d.contentInset) {
3053
+ const { contentInset } = event.nativeEvent;
3054
+ const prevInset = state.nativeContentInset;
3055
+ if (!prevInset || prevInset.top !== contentInset.top || prevInset.bottom !== contentInset.bottom || prevInset.left !== contentInset.left || prevInset.right !== contentInset.right) {
3056
+ state.nativeContentInset = contentInset;
3057
+ insetChanged = true;
3058
+ }
3059
+ }
3042
3060
  let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3043
3061
  if (state.scrollingTo) {
3044
3062
  const maxOffset = clampScrollOffset(ctx, newScroll);
@@ -3054,7 +3072,7 @@ function onScroll(ctx, event) {
3054
3072
  }
3055
3073
  }
3056
3074
  state.scrollPending = newScroll;
3057
- updateScroll(ctx, newScroll);
3075
+ updateScroll(ctx, newScroll, insetChanged);
3058
3076
  if (state.scrollingTo) {
3059
3077
  checkFinishedScroll(ctx);
3060
3078
  }
@@ -3227,7 +3245,10 @@ function updateOneItemSize(ctx, itemKey, sizeObj) {
3227
3245
  if (!averages) {
3228
3246
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
3229
3247
  }
3230
- if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3248
+ if (averages.num === 0) {
3249
+ averages.avg = size;
3250
+ averages.num++;
3251
+ } else if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3231
3252
  averages.avg += (size - prevSizeKnown) / averages.num;
3232
3253
  } else {
3233
3254
  averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
@@ -3331,7 +3352,7 @@ function createImperativeHandle(ctx) {
3331
3352
  getScrollResponder: () => refScroller.current.getScrollResponder(),
3332
3353
  getState: () => ({
3333
3354
  activeStickyIndex: peek$(ctx, "activeStickyIndex"),
3334
- contentLength: state.totalSize,
3355
+ contentLength: getContentSize(ctx),
3335
3356
  data: state.props.data,
3336
3357
  elementAtIndex: (index) => {
3337
3358
  var _a3;
@@ -3347,6 +3368,7 @@ function createImperativeHandle(ctx) {
3347
3368
  positions: state.positions,
3348
3369
  scroll: state.scroll,
3349
3370
  scrollLength: state.scrollLength,
3371
+ scrollVelocity: getScrollVelocity(state),
3350
3372
  sizeAtIndex: (index) => state.sizesKnown.get(getId(state, index)),
3351
3373
  sizes: state.sizesKnown,
3352
3374
  start: state.startNoBuffer,
@@ -3384,6 +3406,10 @@ function createImperativeHandle(ctx) {
3384
3406
  }
3385
3407
  },
3386
3408
  scrollToOffset: (params) => scrollTo(ctx, params),
3409
+ reportContentInset: (inset) => {
3410
+ state.contentInsetOverride = inset != null ? inset : void 0;
3411
+ updateScroll(ctx, state.scroll, true);
3412
+ },
3387
3413
  setScrollProcessingEnabled: (enabled) => {
3388
3414
  state.scrollProcessingEnabled = enabled;
3389
3415
  },
@@ -3695,6 +3721,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3695
3721
  lastScrollDelta: 0,
3696
3722
  loadStartTime: Date.now(),
3697
3723
  minIndexSizeChanged: 0,
3724
+ contentInsetOverride: void 0,
3725
+ nativeContentInset: void 0,
3698
3726
  nativeMarginTop: 0,
3699
3727
  positions: /* @__PURE__ */ new Map(),
3700
3728
  props: {},
package/index.native.mjs CHANGED
@@ -10,7 +10,7 @@ var Text = Text$1;
10
10
 
11
11
  // src/state/getContentInsetEnd.ts
12
12
  function getContentInsetEnd(state) {
13
- var _a3;
13
+ var _a3, _b;
14
14
  const { props } = state;
15
15
  const horizontal = props.horizontal;
16
16
  let contentInset = props.contentInset;
@@ -24,7 +24,16 @@ function getContentInsetEnd(state) {
24
24
  }
25
25
  }
26
26
  }
27
- return (horizontal ? contentInset == null ? void 0 : contentInset.right : contentInset == null ? void 0 : contentInset.bottom) || 0;
27
+ const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
28
+ const overrideInset = (_b = state.contentInsetOverride) != null ? _b : void 0;
29
+ if (overrideInset) {
30
+ const mergedInset = { top: 0, left: 0, right: 0, bottom: 0, ...baseInset, ...overrideInset };
31
+ return (horizontal ? mergedInset.right : mergedInset.bottom) || 0;
32
+ }
33
+ if (baseInset) {
34
+ return (horizontal ? baseInset.right : baseInset.bottom) || 0;
35
+ }
36
+ return 0;
28
37
  }
29
38
 
30
39
  // src/state/getContentSize.ts
@@ -3006,7 +3015,7 @@ function handleLayout(ctx, layout, setCanRender) {
3006
3015
 
3007
3016
  // src/core/onScroll.ts
3008
3017
  function onScroll(ctx, event) {
3009
- var _a3, _b, _c;
3018
+ var _a3, _b, _c, _d;
3010
3019
  const state = ctx.state;
3011
3020
  const {
3012
3021
  scrollProcessingEnabled,
@@ -3018,6 +3027,15 @@ function onScroll(ctx, event) {
3018
3027
  if (((_b = (_a3 = event.nativeEvent) == null ? void 0 : _a3.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
3019
3028
  return;
3020
3029
  }
3030
+ let insetChanged = false;
3031
+ if ((_d = event.nativeEvent) == null ? void 0 : _d.contentInset) {
3032
+ const { contentInset } = event.nativeEvent;
3033
+ const prevInset = state.nativeContentInset;
3034
+ if (!prevInset || prevInset.top !== contentInset.top || prevInset.bottom !== contentInset.bottom || prevInset.left !== contentInset.left || prevInset.right !== contentInset.right) {
3035
+ state.nativeContentInset = contentInset;
3036
+ insetChanged = true;
3037
+ }
3038
+ }
3021
3039
  let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
3022
3040
  if (state.scrollingTo) {
3023
3041
  const maxOffset = clampScrollOffset(ctx, newScroll);
@@ -3033,7 +3051,7 @@ function onScroll(ctx, event) {
3033
3051
  }
3034
3052
  }
3035
3053
  state.scrollPending = newScroll;
3036
- updateScroll(ctx, newScroll);
3054
+ updateScroll(ctx, newScroll, insetChanged);
3037
3055
  if (state.scrollingTo) {
3038
3056
  checkFinishedScroll(ctx);
3039
3057
  }
@@ -3206,7 +3224,10 @@ function updateOneItemSize(ctx, itemKey, sizeObj) {
3206
3224
  if (!averages) {
3207
3225
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
3208
3226
  }
3209
- if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3227
+ if (averages.num === 0) {
3228
+ averages.avg = size;
3229
+ averages.num++;
3230
+ } else if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
3210
3231
  averages.avg += (size - prevSizeKnown) / averages.num;
3211
3232
  } else {
3212
3233
  averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
@@ -3310,7 +3331,7 @@ function createImperativeHandle(ctx) {
3310
3331
  getScrollResponder: () => refScroller.current.getScrollResponder(),
3311
3332
  getState: () => ({
3312
3333
  activeStickyIndex: peek$(ctx, "activeStickyIndex"),
3313
- contentLength: state.totalSize,
3334
+ contentLength: getContentSize(ctx),
3314
3335
  data: state.props.data,
3315
3336
  elementAtIndex: (index) => {
3316
3337
  var _a3;
@@ -3326,6 +3347,7 @@ function createImperativeHandle(ctx) {
3326
3347
  positions: state.positions,
3327
3348
  scroll: state.scroll,
3328
3349
  scrollLength: state.scrollLength,
3350
+ scrollVelocity: getScrollVelocity(state),
3329
3351
  sizeAtIndex: (index) => state.sizesKnown.get(getId(state, index)),
3330
3352
  sizes: state.sizesKnown,
3331
3353
  start: state.startNoBuffer,
@@ -3363,6 +3385,10 @@ function createImperativeHandle(ctx) {
3363
3385
  }
3364
3386
  },
3365
3387
  scrollToOffset: (params) => scrollTo(ctx, params),
3388
+ reportContentInset: (inset) => {
3389
+ state.contentInsetOverride = inset != null ? inset : void 0;
3390
+ updateScroll(ctx, state.scroll, true);
3391
+ },
3366
3392
  setScrollProcessingEnabled: (enabled) => {
3367
3393
  state.scrollProcessingEnabled = enabled;
3368
3394
  },
@@ -3674,6 +3700,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3674
3700
  lastScrollDelta: 0,
3675
3701
  loadStartTime: Date.now(),
3676
3702
  minIndexSizeChanged: 0,
3703
+ contentInsetOverride: void 0,
3704
+ nativeContentInset: void 0,
3677
3705
  nativeMarginTop: 0,
3678
3706
  positions: /* @__PURE__ */ new Map(),
3679
3707
  props: {},
package/keyboard.js CHANGED
@@ -62,6 +62,15 @@ var calculateKeyboardInset = (height, safeAreaInsetBottom, isNewArchitecture) =>
62
62
  "worklet";
63
63
  return Math.max(0, height - safeAreaInsetBottom) ;
64
64
  };
65
+ var calculateEffectiveKeyboardHeight = (keyboardHeight, contentLength, scrollLength, alignItemsAtEnd) => {
66
+ "worklet";
67
+ if (alignItemsAtEnd) {
68
+ return keyboardHeight;
69
+ } else {
70
+ const availableSpace = Math.max(0, scrollLength - contentLength);
71
+ return Math.max(0, keyboardHeight - availableSpace);
72
+ }
73
+ };
65
74
  var calculateEndPaddingInset = (keyboardHeight, alignItemsAtEndPadding) => {
66
75
  "worklet";
67
76
  return Math.min(keyboardHeight, alignItemsAtEndPadding);
@@ -86,6 +95,7 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
86
95
  style: styleProp,
87
96
  ...rest
88
97
  } = props;
98
+ const { alignItemsAtEnd } = props;
89
99
  const styleFlattened = reactNative.StyleSheet.flatten(styleProp);
90
100
  const refLegendList = React.useRef(null);
91
101
  const combinedRef = useCombinedRef(forwardedRef, refLegendList);
@@ -98,6 +108,8 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
98
108
  const mode = reactNativeReanimated.useSharedValue("idle");
99
109
  const keyboardInset = reactNativeReanimated.useSharedValue({ bottom: 0, top: 0 });
100
110
  const keyboardHeight = reactNativeReanimated.useSharedValue(0);
111
+ const contentLength = reactNativeReanimated.useSharedValue(0);
112
+ const scrollLength = reactNativeReanimated.useSharedValue(0);
101
113
  const alignItemsAtEndPadding = reactNativeReanimated.useSharedValue(0);
102
114
  const isOpening = reactNativeReanimated.useSharedValue(false);
103
115
  const didInteractive = reactNativeReanimated.useSharedValue(false);
@@ -105,7 +117,9 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
105
117
  const isKeyboardOpen = reactNativeReanimated.useSharedValue(false);
106
118
  const scrollHandler = reactNativeReanimated.useAnimatedScrollHandler(
107
119
  (event) => {
108
- scrollOffsetY.set(event.contentOffset[horizontal ? "x" : "y"]);
120
+ if (mode.get() !== "running" || didInteractive.get()) {
121
+ scrollOffsetY.set(event.contentOffset[horizontal ? "x" : "y"]);
122
+ }
109
123
  if (onScrollProp) {
110
124
  reactNativeReanimated.runOnJS(onScrollProp)(event);
111
125
  }
@@ -119,8 +133,18 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
119
133
  },
120
134
  [refLegendList]
121
135
  );
136
+ const updateScrollMetrics = React.useCallback(() => {
137
+ var _a;
138
+ const state = (_a = refLegendList.current) == null ? void 0 : _a.getState();
139
+ if (!state) {
140
+ return;
141
+ }
142
+ contentLength.set(state.contentLength);
143
+ scrollLength.set(state.scrollLength);
144
+ }, [contentLength, scrollLength]);
122
145
  const handleMetricsChange = React.useCallback(
123
146
  (metrics) => {
147
+ updateScrollMetrics();
124
148
  const nextPadding = metrics.alignItemsAtEndPadding || 0;
125
149
  alignItemsAtEndPadding.set(nextPadding);
126
150
  if (!horizontal) {
@@ -130,7 +154,13 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
130
154
  return;
131
155
  }
132
156
  const vKeyboardHeight = keyboardHeight.get();
133
- const vTopInset = calculateEndPaddingInset(vKeyboardHeight, padding);
157
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
158
+ vKeyboardHeight,
159
+ contentLength.get(),
160
+ scrollLength.get(),
161
+ alignItemsAtEnd
162
+ );
163
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, padding);
134
164
  const topInset = calculateTopInset(safeInsetTop, isNewArchitecture, vTopInset);
135
165
  keyboardInset.set({
136
166
  bottom: keyboardInset.get().bottom,
@@ -147,7 +177,8 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
147
177
  keyboardHeight,
148
178
  keyboardInset,
149
179
  onMetricsChangeProp,
150
- safeAreaInsetTop
180
+ safeAreaInsetTop,
181
+ updateScrollMetrics
151
182
  ]
152
183
  );
153
184
  reactNativeKeyboardController.useKeyboardHandler(
@@ -197,11 +228,17 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
197
228
  const progress = clampProgress(event.progress);
198
229
  const vIsOpening = isOpening.get();
199
230
  const vKeyboardHeight = keyboardHeight.get();
231
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
232
+ vKeyboardHeight,
233
+ contentLength.get(),
234
+ scrollLength.get(),
235
+ alignItemsAtEnd
236
+ );
200
237
  const vAlignItemsPadding = alignItemsAtEndPadding.get();
201
- const vTopInset = calculateEndPaddingInset(vKeyboardHeight, vAlignItemsPadding);
238
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, vAlignItemsPadding);
202
239
  const targetOffset = calculateKeyboardTargetOffset(
203
240
  scrollOffsetAtKeyboardStart.get(),
204
- vKeyboardHeight,
241
+ vEffectiveKeyboardHeight,
205
242
  vIsOpening,
206
243
  progress
207
244
  );
@@ -230,13 +267,19 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
230
267
  if (vMode === "running") {
231
268
  const progress = clampProgress(event.progress);
232
269
  const vKeyboardHeight = keyboardHeight.get();
270
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
271
+ vKeyboardHeight,
272
+ contentLength.get(),
273
+ scrollLength.get(),
274
+ alignItemsAtEnd
275
+ );
233
276
  const vAlignItemsPadding = alignItemsAtEndPadding.get();
234
- const vTopInset = calculateEndPaddingInset(vKeyboardHeight, vAlignItemsPadding);
277
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, vAlignItemsPadding);
235
278
  const vIsOpening = isOpening.get();
236
279
  if (!wasInteractive) {
237
280
  const targetOffset = calculateKeyboardTargetOffset(
238
281
  scrollOffsetAtKeyboardStart.get(),
239
- vKeyboardHeight,
282
+ vEffectiveKeyboardHeight,
240
283
  vIsOpening,
241
284
  progress
242
285
  );
@@ -265,7 +308,7 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
265
308
  }
266
309
  }
267
310
  },
268
- [scrollViewRef, safeAreaInsetBottom]
311
+ [alignItemsAtEnd, safeAreaInsetBottom, scrollViewRef]
269
312
  );
270
313
  const animatedProps = reactNativeReanimated.useAnimatedProps(() => {
271
314
  "worklet";
package/keyboard.mjs CHANGED
@@ -41,6 +41,15 @@ var calculateKeyboardInset = (height, safeAreaInsetBottom, isNewArchitecture) =>
41
41
  "worklet";
42
42
  return Math.max(0, height - safeAreaInsetBottom) ;
43
43
  };
44
+ var calculateEffectiveKeyboardHeight = (keyboardHeight, contentLength, scrollLength, alignItemsAtEnd) => {
45
+ "worklet";
46
+ if (alignItemsAtEnd) {
47
+ return keyboardHeight;
48
+ } else {
49
+ const availableSpace = Math.max(0, scrollLength - contentLength);
50
+ return Math.max(0, keyboardHeight - availableSpace);
51
+ }
52
+ };
44
53
  var calculateEndPaddingInset = (keyboardHeight, alignItemsAtEndPadding) => {
45
54
  "worklet";
46
55
  return Math.min(keyboardHeight, alignItemsAtEndPadding);
@@ -65,6 +74,7 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
65
74
  style: styleProp,
66
75
  ...rest
67
76
  } = props;
77
+ const { alignItemsAtEnd } = props;
68
78
  const styleFlattened = StyleSheet.flatten(styleProp);
69
79
  const refLegendList = useRef(null);
70
80
  const combinedRef = useCombinedRef(forwardedRef, refLegendList);
@@ -77,6 +87,8 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
77
87
  const mode = useSharedValue("idle");
78
88
  const keyboardInset = useSharedValue({ bottom: 0, top: 0 });
79
89
  const keyboardHeight = useSharedValue(0);
90
+ const contentLength = useSharedValue(0);
91
+ const scrollLength = useSharedValue(0);
80
92
  const alignItemsAtEndPadding = useSharedValue(0);
81
93
  const isOpening = useSharedValue(false);
82
94
  const didInteractive = useSharedValue(false);
@@ -84,7 +96,9 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
84
96
  const isKeyboardOpen = useSharedValue(false);
85
97
  const scrollHandler = useAnimatedScrollHandler(
86
98
  (event) => {
87
- scrollOffsetY.set(event.contentOffset[horizontal ? "x" : "y"]);
99
+ if (mode.get() !== "running" || didInteractive.get()) {
100
+ scrollOffsetY.set(event.contentOffset[horizontal ? "x" : "y"]);
101
+ }
88
102
  if (onScrollProp) {
89
103
  runOnJS(onScrollProp)(event);
90
104
  }
@@ -98,8 +112,18 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
98
112
  },
99
113
  [refLegendList]
100
114
  );
115
+ const updateScrollMetrics = useCallback(() => {
116
+ var _a;
117
+ const state = (_a = refLegendList.current) == null ? void 0 : _a.getState();
118
+ if (!state) {
119
+ return;
120
+ }
121
+ contentLength.set(state.contentLength);
122
+ scrollLength.set(state.scrollLength);
123
+ }, [contentLength, scrollLength]);
101
124
  const handleMetricsChange = useCallback(
102
125
  (metrics) => {
126
+ updateScrollMetrics();
103
127
  const nextPadding = metrics.alignItemsAtEndPadding || 0;
104
128
  alignItemsAtEndPadding.set(nextPadding);
105
129
  if (!horizontal) {
@@ -109,7 +133,13 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
109
133
  return;
110
134
  }
111
135
  const vKeyboardHeight = keyboardHeight.get();
112
- const vTopInset = calculateEndPaddingInset(vKeyboardHeight, padding);
136
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
137
+ vKeyboardHeight,
138
+ contentLength.get(),
139
+ scrollLength.get(),
140
+ alignItemsAtEnd
141
+ );
142
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, padding);
113
143
  const topInset = calculateTopInset(safeInsetTop, isNewArchitecture, vTopInset);
114
144
  keyboardInset.set({
115
145
  bottom: keyboardInset.get().bottom,
@@ -126,7 +156,8 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
126
156
  keyboardHeight,
127
157
  keyboardInset,
128
158
  onMetricsChangeProp,
129
- safeAreaInsetTop
159
+ safeAreaInsetTop,
160
+ updateScrollMetrics
130
161
  ]
131
162
  );
132
163
  useKeyboardHandler(
@@ -176,11 +207,17 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
176
207
  const progress = clampProgress(event.progress);
177
208
  const vIsOpening = isOpening.get();
178
209
  const vKeyboardHeight = keyboardHeight.get();
210
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
211
+ vKeyboardHeight,
212
+ contentLength.get(),
213
+ scrollLength.get(),
214
+ alignItemsAtEnd
215
+ );
179
216
  const vAlignItemsPadding = alignItemsAtEndPadding.get();
180
- const vTopInset = calculateEndPaddingInset(vKeyboardHeight, vAlignItemsPadding);
217
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, vAlignItemsPadding);
181
218
  const targetOffset = calculateKeyboardTargetOffset(
182
219
  scrollOffsetAtKeyboardStart.get(),
183
- vKeyboardHeight,
220
+ vEffectiveKeyboardHeight,
184
221
  vIsOpening,
185
222
  progress
186
223
  );
@@ -209,13 +246,19 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
209
246
  if (vMode === "running") {
210
247
  const progress = clampProgress(event.progress);
211
248
  const vKeyboardHeight = keyboardHeight.get();
249
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
250
+ vKeyboardHeight,
251
+ contentLength.get(),
252
+ scrollLength.get(),
253
+ alignItemsAtEnd
254
+ );
212
255
  const vAlignItemsPadding = alignItemsAtEndPadding.get();
213
- const vTopInset = calculateEndPaddingInset(vKeyboardHeight, vAlignItemsPadding);
256
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, vAlignItemsPadding);
214
257
  const vIsOpening = isOpening.get();
215
258
  if (!wasInteractive) {
216
259
  const targetOffset = calculateKeyboardTargetOffset(
217
260
  scrollOffsetAtKeyboardStart.get(),
218
- vKeyboardHeight,
261
+ vEffectiveKeyboardHeight,
219
262
  vIsOpening,
220
263
  progress
221
264
  );
@@ -244,7 +287,7 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
244
287
  }
245
288
  }
246
289
  },
247
- [scrollViewRef, safeAreaInsetBottom]
290
+ [alignItemsAtEnd, safeAreaInsetBottom, scrollViewRef]
248
291
  );
249
292
  const animatedProps = useAnimatedProps(() => {
250
293
  "worklet";
@@ -63,6 +63,15 @@ var calculateKeyboardInset = (height, safeAreaInsetBottom, isNewArchitecture) =>
63
63
  "worklet";
64
64
  return isNewArchitecture ? Math.max(0, height - safeAreaInsetBottom) : Math.max(isNewArchitecture ? 0 : -safeAreaInsetBottom, height - safeAreaInsetBottom * 2);
65
65
  };
66
+ var calculateEffectiveKeyboardHeight = (keyboardHeight, contentLength, scrollLength, alignItemsAtEnd) => {
67
+ "worklet";
68
+ if (alignItemsAtEnd) {
69
+ return keyboardHeight;
70
+ } else {
71
+ const availableSpace = Math.max(0, scrollLength - contentLength);
72
+ return Math.max(0, keyboardHeight - availableSpace);
73
+ }
74
+ };
66
75
  var calculateEndPaddingInset = (keyboardHeight, alignItemsAtEndPadding) => {
67
76
  "worklet";
68
77
  return Math.min(keyboardHeight, alignItemsAtEndPadding);
@@ -87,6 +96,7 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
87
96
  style: styleProp,
88
97
  ...rest
89
98
  } = props;
99
+ const { alignItemsAtEnd } = props;
90
100
  const styleFlattened = reactNative.StyleSheet.flatten(styleProp);
91
101
  const refLegendList = React.useRef(null);
92
102
  const combinedRef = useCombinedRef(forwardedRef, refLegendList);
@@ -99,6 +109,8 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
99
109
  const mode = reactNativeReanimated.useSharedValue("idle");
100
110
  const keyboardInset = reactNativeReanimated.useSharedValue({ bottom: 0, top: 0 });
101
111
  const keyboardHeight = reactNativeReanimated.useSharedValue(0);
112
+ const contentLength = reactNativeReanimated.useSharedValue(0);
113
+ const scrollLength = reactNativeReanimated.useSharedValue(0);
102
114
  const alignItemsAtEndPadding = reactNativeReanimated.useSharedValue(0);
103
115
  const isOpening = reactNativeReanimated.useSharedValue(false);
104
116
  const didInteractive = reactNativeReanimated.useSharedValue(false);
@@ -106,7 +118,9 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
106
118
  const isKeyboardOpen = reactNativeReanimated.useSharedValue(false);
107
119
  const scrollHandler = reactNativeReanimated.useAnimatedScrollHandler(
108
120
  (event) => {
109
- scrollOffsetY.set(event.contentOffset[horizontal ? "x" : "y"]);
121
+ if (mode.get() !== "running" || didInteractive.get()) {
122
+ scrollOffsetY.set(event.contentOffset[horizontal ? "x" : "y"]);
123
+ }
110
124
  if (onScrollProp) {
111
125
  reactNativeReanimated.runOnJS(onScrollProp)(event);
112
126
  }
@@ -120,8 +134,18 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
120
134
  },
121
135
  [refLegendList]
122
136
  );
137
+ const updateScrollMetrics = React.useCallback(() => {
138
+ var _a;
139
+ const state = (_a = refLegendList.current) == null ? void 0 : _a.getState();
140
+ if (!state) {
141
+ return;
142
+ }
143
+ contentLength.set(state.contentLength);
144
+ scrollLength.set(state.scrollLength);
145
+ }, [contentLength, scrollLength]);
123
146
  const handleMetricsChange = React.useCallback(
124
147
  (metrics) => {
148
+ updateScrollMetrics();
125
149
  const nextPadding = metrics.alignItemsAtEndPadding || 0;
126
150
  alignItemsAtEndPadding.set(nextPadding);
127
151
  if (!horizontal) {
@@ -131,7 +155,13 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
131
155
  return;
132
156
  }
133
157
  const vKeyboardHeight = keyboardHeight.get();
134
- const vTopInset = calculateEndPaddingInset(vKeyboardHeight, padding);
158
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
159
+ vKeyboardHeight,
160
+ contentLength.get(),
161
+ scrollLength.get(),
162
+ alignItemsAtEnd
163
+ );
164
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, padding);
135
165
  const topInset = calculateTopInset(safeInsetTop, isNewArchitecture, vTopInset);
136
166
  keyboardInset.set({
137
167
  bottom: keyboardInset.get().bottom,
@@ -148,7 +178,8 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
148
178
  keyboardHeight,
149
179
  keyboardInset,
150
180
  onMetricsChangeProp,
151
- safeAreaInsetTop
181
+ safeAreaInsetTop,
182
+ updateScrollMetrics
152
183
  ]
153
184
  );
154
185
  reactNativeKeyboardController.useKeyboardHandler(
@@ -198,11 +229,17 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
198
229
  const progress = clampProgress(event.progress);
199
230
  const vIsOpening = isOpening.get();
200
231
  const vKeyboardHeight = keyboardHeight.get();
232
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
233
+ vKeyboardHeight,
234
+ contentLength.get(),
235
+ scrollLength.get(),
236
+ alignItemsAtEnd
237
+ );
201
238
  const vAlignItemsPadding = alignItemsAtEndPadding.get();
202
- const vTopInset = calculateEndPaddingInset(vKeyboardHeight, vAlignItemsPadding);
239
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, vAlignItemsPadding);
203
240
  const targetOffset = calculateKeyboardTargetOffset(
204
241
  scrollOffsetAtKeyboardStart.get(),
205
- vKeyboardHeight,
242
+ vEffectiveKeyboardHeight,
206
243
  vIsOpening,
207
244
  progress
208
245
  );
@@ -231,13 +268,19 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
231
268
  if (vMode === "running") {
232
269
  const progress = clampProgress(event.progress);
233
270
  const vKeyboardHeight = keyboardHeight.get();
271
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
272
+ vKeyboardHeight,
273
+ contentLength.get(),
274
+ scrollLength.get(),
275
+ alignItemsAtEnd
276
+ );
234
277
  const vAlignItemsPadding = alignItemsAtEndPadding.get();
235
- const vTopInset = calculateEndPaddingInset(vKeyboardHeight, vAlignItemsPadding);
278
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, vAlignItemsPadding);
236
279
  const vIsOpening = isOpening.get();
237
280
  if (!wasInteractive) {
238
281
  const targetOffset = calculateKeyboardTargetOffset(
239
282
  scrollOffsetAtKeyboardStart.get(),
240
- vKeyboardHeight,
283
+ vEffectiveKeyboardHeight,
241
284
  vIsOpening,
242
285
  progress
243
286
  );
@@ -266,7 +309,7 @@ var KeyboardAvoidingLegendList = React.forwardRef(function KeyboardAvoidingLegen
266
309
  }
267
310
  }
268
311
  },
269
- [scrollViewRef, safeAreaInsetBottom]
312
+ [alignItemsAtEnd, safeAreaInsetBottom, scrollViewRef]
270
313
  );
271
314
  const animatedProps = reactNativeReanimated.useAnimatedProps(() => {
272
315
  "worklet";
@@ -42,6 +42,15 @@ var calculateKeyboardInset = (height, safeAreaInsetBottom, isNewArchitecture) =>
42
42
  "worklet";
43
43
  return isNewArchitecture ? Math.max(0, height - safeAreaInsetBottom) : Math.max(isNewArchitecture ? 0 : -safeAreaInsetBottom, height - safeAreaInsetBottom * 2);
44
44
  };
45
+ var calculateEffectiveKeyboardHeight = (keyboardHeight, contentLength, scrollLength, alignItemsAtEnd) => {
46
+ "worklet";
47
+ if (alignItemsAtEnd) {
48
+ return keyboardHeight;
49
+ } else {
50
+ const availableSpace = Math.max(0, scrollLength - contentLength);
51
+ return Math.max(0, keyboardHeight - availableSpace);
52
+ }
53
+ };
45
54
  var calculateEndPaddingInset = (keyboardHeight, alignItemsAtEndPadding) => {
46
55
  "worklet";
47
56
  return Math.min(keyboardHeight, alignItemsAtEndPadding);
@@ -66,6 +75,7 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
66
75
  style: styleProp,
67
76
  ...rest
68
77
  } = props;
78
+ const { alignItemsAtEnd } = props;
69
79
  const styleFlattened = StyleSheet.flatten(styleProp);
70
80
  const refLegendList = useRef(null);
71
81
  const combinedRef = useCombinedRef(forwardedRef, refLegendList);
@@ -78,6 +88,8 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
78
88
  const mode = useSharedValue("idle");
79
89
  const keyboardInset = useSharedValue({ bottom: 0, top: 0 });
80
90
  const keyboardHeight = useSharedValue(0);
91
+ const contentLength = useSharedValue(0);
92
+ const scrollLength = useSharedValue(0);
81
93
  const alignItemsAtEndPadding = useSharedValue(0);
82
94
  const isOpening = useSharedValue(false);
83
95
  const didInteractive = useSharedValue(false);
@@ -85,7 +97,9 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
85
97
  const isKeyboardOpen = useSharedValue(false);
86
98
  const scrollHandler = useAnimatedScrollHandler(
87
99
  (event) => {
88
- scrollOffsetY.set(event.contentOffset[horizontal ? "x" : "y"]);
100
+ if (mode.get() !== "running" || didInteractive.get()) {
101
+ scrollOffsetY.set(event.contentOffset[horizontal ? "x" : "y"]);
102
+ }
89
103
  if (onScrollProp) {
90
104
  runOnJS(onScrollProp)(event);
91
105
  }
@@ -99,8 +113,18 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
99
113
  },
100
114
  [refLegendList]
101
115
  );
116
+ const updateScrollMetrics = useCallback(() => {
117
+ var _a;
118
+ const state = (_a = refLegendList.current) == null ? void 0 : _a.getState();
119
+ if (!state) {
120
+ return;
121
+ }
122
+ contentLength.set(state.contentLength);
123
+ scrollLength.set(state.scrollLength);
124
+ }, [contentLength, scrollLength]);
102
125
  const handleMetricsChange = useCallback(
103
126
  (metrics) => {
127
+ updateScrollMetrics();
104
128
  const nextPadding = metrics.alignItemsAtEndPadding || 0;
105
129
  alignItemsAtEndPadding.set(nextPadding);
106
130
  if (!horizontal) {
@@ -110,7 +134,13 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
110
134
  return;
111
135
  }
112
136
  const vKeyboardHeight = keyboardHeight.get();
113
- const vTopInset = calculateEndPaddingInset(vKeyboardHeight, padding);
137
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
138
+ vKeyboardHeight,
139
+ contentLength.get(),
140
+ scrollLength.get(),
141
+ alignItemsAtEnd
142
+ );
143
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, padding);
114
144
  const topInset = calculateTopInset(safeInsetTop, isNewArchitecture, vTopInset);
115
145
  keyboardInset.set({
116
146
  bottom: keyboardInset.get().bottom,
@@ -127,7 +157,8 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
127
157
  keyboardHeight,
128
158
  keyboardInset,
129
159
  onMetricsChangeProp,
130
- safeAreaInsetTop
160
+ safeAreaInsetTop,
161
+ updateScrollMetrics
131
162
  ]
132
163
  );
133
164
  useKeyboardHandler(
@@ -177,11 +208,17 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
177
208
  const progress = clampProgress(event.progress);
178
209
  const vIsOpening = isOpening.get();
179
210
  const vKeyboardHeight = keyboardHeight.get();
211
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
212
+ vKeyboardHeight,
213
+ contentLength.get(),
214
+ scrollLength.get(),
215
+ alignItemsAtEnd
216
+ );
180
217
  const vAlignItemsPadding = alignItemsAtEndPadding.get();
181
- const vTopInset = calculateEndPaddingInset(vKeyboardHeight, vAlignItemsPadding);
218
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, vAlignItemsPadding);
182
219
  const targetOffset = calculateKeyboardTargetOffset(
183
220
  scrollOffsetAtKeyboardStart.get(),
184
- vKeyboardHeight,
221
+ vEffectiveKeyboardHeight,
185
222
  vIsOpening,
186
223
  progress
187
224
  );
@@ -210,13 +247,19 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
210
247
  if (vMode === "running") {
211
248
  const progress = clampProgress(event.progress);
212
249
  const vKeyboardHeight = keyboardHeight.get();
250
+ const vEffectiveKeyboardHeight = calculateEffectiveKeyboardHeight(
251
+ vKeyboardHeight,
252
+ contentLength.get(),
253
+ scrollLength.get(),
254
+ alignItemsAtEnd
255
+ );
213
256
  const vAlignItemsPadding = alignItemsAtEndPadding.get();
214
- const vTopInset = calculateEndPaddingInset(vKeyboardHeight, vAlignItemsPadding);
257
+ const vTopInset = calculateEndPaddingInset(vEffectiveKeyboardHeight, vAlignItemsPadding);
215
258
  const vIsOpening = isOpening.get();
216
259
  if (!wasInteractive) {
217
260
  const targetOffset = calculateKeyboardTargetOffset(
218
261
  scrollOffsetAtKeyboardStart.get(),
219
- vKeyboardHeight,
262
+ vEffectiveKeyboardHeight,
220
263
  vIsOpening,
221
264
  progress
222
265
  );
@@ -245,7 +288,7 @@ var KeyboardAvoidingLegendList = forwardRef(function KeyboardAvoidingLegendList2
245
288
  }
246
289
  }
247
290
  },
248
- [scrollViewRef, safeAreaInsetBottom]
291
+ [alignItemsAtEnd, safeAreaInsetBottom, scrollViewRef]
249
292
  );
250
293
  const animatedProps = useAnimatedProps(() => {
251
294
  "worklet";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "3.0.0-beta.21",
3
+ "version": "3.0.0-beta.22",
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,