@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.
package/react.mjs CHANGED
@@ -145,7 +145,10 @@ function useSelector$(signalName, selector) {
145
145
  }
146
146
 
147
147
  // src/state/getContentInsetEnd.ts
148
- function getContentInsetEnd(ctx) {
148
+ function getContentInsetEndAdjustmentEnd(adjustment) {
149
+ return Math.max(0, adjustment != null ? adjustment : 0);
150
+ }
151
+ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
149
152
  var _a3, _b;
150
153
  const state = ctx.state;
151
154
  const { props } = state;
@@ -153,14 +156,21 @@ function getContentInsetEnd(ctx) {
153
156
  const contentInset = props.contentInset;
154
157
  const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
155
158
  const baseEndInset = (horizontal ? baseInset == null ? void 0 : baseInset.right : baseInset == null ? void 0 : baseInset.bottom) || 0;
159
+ const contentInsetEndAdjustment = getContentInsetEndAdjustmentEnd(
160
+ contentInsetEndAdjustmentOverride != null ? contentInsetEndAdjustmentOverride : props.contentInsetEndAdjustment
161
+ );
156
162
  const anchoredEndSpaceSize = peek$(ctx, "anchoredEndSpaceSize");
157
163
  const anchoredEndInset = ((_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.includeInEndInset) && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
158
164
  const overrideInset = (_b = state.contentInsetOverride) != null ? _b : void 0;
165
+ const adjustedBaseEndInset = baseEndInset + contentInsetEndAdjustment;
159
166
  if (overrideInset) {
160
167
  const mergedInset = { bottom: 0, right: 0, ...baseInset, ...overrideInset };
161
- return Math.max((horizontal ? mergedInset.right : mergedInset.bottom) || 0, anchoredEndInset);
168
+ return Math.max(
169
+ ((horizontal ? mergedInset.right : mergedInset.bottom) || 0) + contentInsetEndAdjustment,
170
+ anchoredEndInset
171
+ );
162
172
  }
163
- return Math.max(baseEndInset, anchoredEndInset);
173
+ return Math.max(adjustedBaseEndInset, anchoredEndInset);
164
174
  }
165
175
 
166
176
  // src/state/getContentSize.ts
@@ -661,6 +671,49 @@ function isInMVCPActiveMode(state) {
661
671
  }
662
672
 
663
673
  // src/components/Container.tsx
674
+ function getContainerPositionStyle({
675
+ columnWrapperStyle,
676
+ horizontal,
677
+ hasItemSeparator,
678
+ numColumns,
679
+ otherAxisPos,
680
+ otherAxisSize
681
+ }) {
682
+ let paddingStyles;
683
+ if (columnWrapperStyle) {
684
+ const { columnGap, rowGap, gap } = columnWrapperStyle;
685
+ if (horizontal) {
686
+ paddingStyles = {
687
+ paddingBottom: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0,
688
+ paddingRight: columnGap || gap || void 0,
689
+ paddingTop: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
690
+ };
691
+ } else {
692
+ paddingStyles = {
693
+ paddingBottom: rowGap || gap || void 0,
694
+ paddingLeft: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0,
695
+ paddingRight: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
696
+ };
697
+ }
698
+ }
699
+ return horizontal ? {
700
+ boxSizing: paddingStyles ? "border-box" : void 0,
701
+ flexDirection: hasItemSeparator ? "row" : void 0,
702
+ height: otherAxisSize,
703
+ left: 0,
704
+ position: "absolute",
705
+ top: otherAxisPos,
706
+ ...paddingStyles || {}
707
+ } : {
708
+ boxSizing: paddingStyles ? "border-box" : void 0,
709
+ left: otherAxisPos,
710
+ position: "absolute",
711
+ right: numColumns > 1 ? null : 0,
712
+ top: 0,
713
+ width: otherAxisSize,
714
+ ...paddingStyles || {}
715
+ };
716
+ }
664
717
  var Container = typedMemo(function Container2({
665
718
  id,
666
719
  recycleItems,
@@ -699,42 +752,17 @@ var Container = typedMemo(function Container2({
699
752
  const resolvedSpan = Math.min(Math.max(span || 1, 1), numColumns);
700
753
  const otherAxisPos = numColumns > 1 ? `${(resolvedColumn - 1) / numColumns * 100}%` : 0;
701
754
  const otherAxisSize = numColumns > 1 ? `${resolvedSpan / numColumns * 100}%` : void 0;
702
- const style = useMemo(() => {
703
- let paddingStyles;
704
- if (columnWrapperStyle) {
705
- const { columnGap, rowGap, gap } = columnWrapperStyle;
706
- if (horizontal) {
707
- paddingStyles = {
708
- paddingBottom: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0,
709
- paddingRight: columnGap || gap || void 0,
710
- paddingTop: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
711
- };
712
- } else {
713
- paddingStyles = {
714
- paddingBottom: rowGap || gap || void 0,
715
- paddingLeft: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0,
716
- paddingRight: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
717
- };
718
- }
719
- }
720
- return horizontal ? {
721
- boxSizing: paddingStyles ? "border-box" : void 0,
722
- flexDirection: ItemSeparatorComponent ? "row" : void 0,
723
- height: otherAxisSize,
724
- left: 0,
725
- position: "absolute",
726
- top: otherAxisPos,
727
- ...paddingStyles || {}
728
- } : {
729
- boxSizing: paddingStyles ? "border-box" : void 0,
730
- left: otherAxisPos,
731
- position: "absolute",
732
- right: numColumns > 1 ? null : 0,
733
- top: 0,
734
- width: otherAxisSize,
735
- ...paddingStyles || {}
736
- };
737
- }, [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns]);
755
+ const style = useMemo(
756
+ () => getContainerPositionStyle({
757
+ columnWrapperStyle,
758
+ hasItemSeparator: !!ItemSeparatorComponent,
759
+ horizontal,
760
+ numColumns,
761
+ otherAxisPos,
762
+ otherAxisSize
763
+ }),
764
+ [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns, ItemSeparatorComponent]
765
+ );
738
766
  const renderedItemInfo = useMemo(
739
767
  () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
740
768
  [itemKey, data, extraData]
@@ -1045,6 +1073,9 @@ function useRafCoalescer(callback) {
1045
1073
  return coalescer;
1046
1074
  }
1047
1075
 
1076
+ // src/components/webConstants.ts
1077
+ var LEGEND_LIST_CONTENT_CONTAINER_CLASS = "legend-list-content-container";
1078
+
1048
1079
  // src/components/webScrollUtils.ts
1049
1080
  function getDocumentScrollerNode() {
1050
1081
  if (typeof document === "undefined") {
@@ -1129,6 +1160,11 @@ function resolveWindowScrollTarget({ clampedOffset, horizontal, listPos, scroll
1129
1160
  }
1130
1161
 
1131
1162
  // src/components/ListComponentScrollView.tsx
1163
+ function getContentInsetEndAdjustmentEnd2(ctx) {
1164
+ var _a3, _b;
1165
+ const adjustment = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.props) == null ? void 0 : _b.contentInsetEndAdjustment;
1166
+ return Math.max(0, adjustment != null ? adjustment : 0);
1167
+ }
1132
1168
  var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1133
1169
  children,
1134
1170
  style,
@@ -1146,7 +1182,9 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1146
1182
  onLayout,
1147
1183
  ...props
1148
1184
  }, ref) {
1185
+ var _a3, _b, _c;
1149
1186
  const ctx = useStateContext();
1187
+ const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
1150
1188
  const scrollRef = useRef(null);
1151
1189
  const contentRef = useRef(null);
1152
1190
  const isWindowScroll = useWindowScroll;
@@ -1208,10 +1246,9 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1208
1246
  useImperativeHandle(ref, () => {
1209
1247
  const api = {
1210
1248
  getBoundingClientRect: () => {
1211
- var _a3;
1212
- return (_a3 = scrollRef.current) == null ? void 0 : _a3.getBoundingClientRect();
1249
+ var _a4;
1250
+ return (_a4 = scrollRef.current) == null ? void 0 : _a4.getBoundingClientRect();
1213
1251
  },
1214
- getContentNode: () => contentRef.current,
1215
1252
  getCurrentScrollOffset,
1216
1253
  getScrollableNode: () => resolveScrollableNode(scrollRef.current, isWindowScroll),
1217
1254
  getScrollEventTarget: () => getScrollTarget(),
@@ -1337,6 +1374,10 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1337
1374
  },
1338
1375
  ...StyleSheet.flatten(style)
1339
1376
  };
1377
+ const contentInsetEndAdjustment = getContentInsetEndAdjustmentEnd2(ctx);
1378
+ const anchoredEndInset = ((_c = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.props) == null ? void 0 : _b.anchoredEndSpace) == null ? void 0 : _c.includeInEndInset) && anchoredEndSpaceSize ? anchoredEndSpaceSize : 0;
1379
+ const renderedContentInsetEndAdjustment = Math.max(0, contentInsetEndAdjustment - anchoredEndInset);
1380
+ const contentInsetEndAdjustmentSpacerStyle = renderedContentInsetEndAdjustment ? horizontal ? { flexShrink: 0, width: renderedContentInsetEndAdjustment } : { height: renderedContentInsetEndAdjustment } : void 0;
1340
1381
  const contentStyle = {
1341
1382
  display: horizontal ? "flex" : "block",
1342
1383
  flexDirection: horizontal ? "row" : void 0,
@@ -1344,6 +1385,7 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1344
1385
  minWidth: horizontal ? "100%" : void 0,
1345
1386
  ...StyleSheet.flatten(contentContainerStyle)
1346
1387
  };
1388
+ const className = contentContainerClassName ? `${LEGEND_LIST_CONTENT_CONTAINER_CLASS} ${contentContainerClassName}` : LEGEND_LIST_CONTENT_CONTAINER_CLASS;
1347
1389
  const {
1348
1390
  contentContainerClassName: _contentContainerClassName,
1349
1391
  contentInset: _contentInset,
@@ -1352,7 +1394,7 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
1352
1394
  useWindowScroll: _useWindowScroll,
1353
1395
  ...webProps
1354
1396
  } = props;
1355
- return /* @__PURE__ */ React3.createElement("div", { ref: scrollRef, ...webProps, style: scrollViewStyle }, refreshControl, /* @__PURE__ */ React3.createElement("div", { className: contentContainerClassName, ref: contentRef, style: contentStyle }, children));
1397
+ return /* @__PURE__ */ React3.createElement("div", { ref: scrollRef, ...webProps, style: scrollViewStyle }, refreshControl, /* @__PURE__ */ React3.createElement("div", { className, ref: contentRef, style: contentStyle }, children, contentInsetEndAdjustmentSpacerStyle ? /* @__PURE__ */ React3.createElement("div", { "aria-hidden": true, style: contentInsetEndAdjustmentSpacerStyle }) : null));
1356
1398
  });
1357
1399
  function useValueListener$(key, callback) {
1358
1400
  const ctx = useStateContext();
@@ -1380,11 +1422,18 @@ function getScrollAdjustAxis(horizontal) {
1380
1422
  y: 1
1381
1423
  };
1382
1424
  }
1425
+ function resolveScrollAdjustContentNode(el, contentNode) {
1426
+ if ((contentNode == null ? void 0 : contentNode.isConnected) && contentNode.parentElement === el) {
1427
+ return contentNode;
1428
+ }
1429
+ return el.querySelector(`:scope > .${LEGEND_LIST_CONTENT_CONTAINER_CLASS}`);
1430
+ }
1383
1431
  function ScrollAdjust() {
1384
1432
  const ctx = useStateContext();
1385
1433
  const lastScrollOffsetRef = React3.useRef(0);
1386
1434
  const resetPaddingRafRef = React3.useRef(void 0);
1387
1435
  const resetPaddingBaselineRef = React3.useRef(void 0);
1436
+ const contentNodeRef = React3.useRef(null);
1388
1437
  const callback = React3.useCallback(() => {
1389
1438
  var _a3, _b;
1390
1439
  const scrollAdjust = peek$(ctx, "scrollAdjust");
@@ -1395,9 +1444,10 @@ function ScrollAdjust() {
1395
1444
  const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
1396
1445
  if (scrollDelta !== 0) {
1397
1446
  const axis = getScrollAdjustAxis(!!ctx.state.props.horizontal);
1398
- const contentNode = scrollView.getContentNode();
1399
1447
  const prevScroll = scrollView.getCurrentScrollOffset();
1400
1448
  const el = scrollView.getScrollableNode();
1449
+ const contentNode = resolveScrollAdjustContentNode(el, contentNodeRef.current);
1450
+ contentNodeRef.current = contentNode;
1401
1451
  const scrollBy = () => scrollView.scrollBy(axis.x * scrollDelta, axis.y * scrollDelta);
1402
1452
  if (!contentNode) {
1403
1453
  scrollBy();
@@ -3252,6 +3302,15 @@ function checkFinishedScrollFallback(ctx) {
3252
3302
  }
3253
3303
 
3254
3304
  // src/core/initialScrollLifecycle.ts
3305
+ function retargetActiveInitialScrollAtEnd(ctx) {
3306
+ var _a3;
3307
+ const state = ctx.state;
3308
+ const initialScroll = state.initialScroll;
3309
+ if (!initialScroll || state.didFinishInitialScroll || ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "offset" || initialScroll.viewPosition !== 1 || state.props.data.length === 0) {
3310
+ return false;
3311
+ }
3312
+ return advanceCurrentInitialScrollSession(ctx, { forceScroll: true });
3313
+ }
3255
3314
  function handleInitialScrollLayoutReady(ctx) {
3256
3315
  var _a3;
3257
3316
  if (!ctx.state.initialScroll) {
@@ -5308,17 +5367,32 @@ function maybeUpdateAnchoredEndSpace(ctx) {
5308
5367
  nextSize = Math.max(0, state.scrollLength - contentBelowAnchor - anchorOffset);
5309
5368
  }
5310
5369
  }
5311
- if (previousSize === nextSize) {
5312
- return nextSize;
5313
- }
5314
- set$(ctx, "anchoredEndSpaceSize", nextSize);
5315
- (_a3 = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onSizeChanged) == null ? void 0 : _a3.call(anchoredEndSpace, nextSize);
5316
- if (anchoredEndSpace == null ? void 0 : anchoredEndSpace.includeInEndInset) {
5317
- updateScroll(ctx, state.scroll, true);
5370
+ if (previousSize !== nextSize) {
5371
+ set$(ctx, "anchoredEndSpaceSize", nextSize);
5372
+ (_a3 = anchoredEndSpace == null ? void 0 : anchoredEndSpace.onSizeChanged) == null ? void 0 : _a3.call(anchoredEndSpace, nextSize);
5373
+ if (anchoredEndSpace == null ? void 0 : anchoredEndSpace.includeInEndInset) {
5374
+ updateScroll(ctx, state.scroll, true);
5375
+ }
5318
5376
  }
5319
5377
  return nextSize;
5320
5378
  }
5321
5379
 
5380
+ // src/core/updateContentInsetEndAdjustment.ts
5381
+ function updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment) {
5382
+ const state = ctx.state;
5383
+ const previousContentInsetEnd = getContentInsetEnd(ctx, previousContentInsetEndAdjustment);
5384
+ const nextContentInsetEnd = getContentInsetEnd(ctx);
5385
+ const insetDiff = nextContentInsetEnd - previousContentInsetEnd;
5386
+ if (insetDiff !== 0) {
5387
+ const wasWithinEndThreshold = !!peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
5388
+ updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
5389
+ const didRetargetInitialScroll = retargetActiveInitialScrollAtEnd(ctx);
5390
+ if (!didRetargetInitialScroll && wasWithinEndThreshold && (insetDiff > 0)) {
5391
+ requestAdjust(ctx, insetDiff);
5392
+ }
5393
+ }
5394
+ }
5395
+
5322
5396
  // src/core/updateItemSize.ts
5323
5397
  function runOrScheduleMVCPRecalculate(ctx) {
5324
5398
  const state = ctx.state;
@@ -5543,14 +5617,14 @@ function createImperativeHandle(ctx) {
5543
5617
  const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
5544
5618
  let imperativeScrollToken = 0;
5545
5619
  const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0;
5546
- const runWhenSettled = (token, run) => {
5620
+ const runWhenReady = (token, run, isReady) => {
5547
5621
  const startedAt = Date.now();
5548
5622
  let stableFrames = 0;
5549
5623
  const check = () => {
5550
5624
  if (token !== imperativeScrollToken) {
5551
5625
  return;
5552
5626
  }
5553
- if (isSettlingAfterDataChange()) {
5627
+ if (isSettlingAfterDataChange() || !isReady()) {
5554
5628
  stableFrames = 0;
5555
5629
  } else {
5556
5630
  stableFrames += 1;
@@ -5565,10 +5639,10 @@ function createImperativeHandle(ctx) {
5565
5639
  requestAnimationFrame(check);
5566
5640
  };
5567
5641
  const runScrollWithPromise = (run, options) => new Promise((resolve) => {
5568
- var _a3;
5642
+ var _a3, _b;
5569
5643
  const token = ++imperativeScrollToken;
5570
- const shouldWaitOneFrame = !!(options == null ? void 0 : options.shouldWaitOneFrame);
5571
- (_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
5644
+ const isReady = (_a3 = options == null ? void 0 : options.isReady) != null ? _a3 : (() => true);
5645
+ (_b = state.pendingScrollResolve) == null ? void 0 : _b.call(state);
5572
5646
  state.pendingScrollResolve = resolve;
5573
5647
  const runNow = () => {
5574
5648
  if (token !== imperativeScrollToken) {
@@ -5582,11 +5656,10 @@ function createImperativeHandle(ctx) {
5582
5656
  resolve();
5583
5657
  }
5584
5658
  };
5585
- const execute = shouldWaitOneFrame ? () => requestAnimationFrame(runNow) : runNow;
5586
- if (isSettlingAfterDataChange()) {
5587
- runWhenSettled(token, execute);
5659
+ if (isSettlingAfterDataChange() || !isReady()) {
5660
+ runWhenReady(token, runNow, isReady);
5588
5661
  } else {
5589
- execute();
5662
+ runNow();
5590
5663
  }
5591
5664
  });
5592
5665
  const scrollIndexIntoView = (options) => {
@@ -5667,8 +5740,14 @@ function createImperativeHandle(ctx) {
5667
5740
  startBuffered: state.startBuffered
5668
5741
  }),
5669
5742
  reportContentInset: (inset) => {
5743
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
5744
+ const previousInset = state.contentInsetOverride;
5670
5745
  state.contentInsetOverride = inset != null ? inset : void 0;
5746
+ 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);
5671
5747
  updateScroll(ctx, state.scroll, true, { markHasScrolled: false });
5748
+ if (didChange) {
5749
+ retargetActiveInitialScrollAtEnd(ctx);
5750
+ }
5672
5751
  },
5673
5752
  scrollIndexIntoView: (options) => runScrollWithPromise(() => scrollIndexIntoView(options)),
5674
5753
  scrollItemIntoView: ({ item, ...props }) => runScrollWithPromise(() => {
@@ -5697,15 +5776,24 @@ function createImperativeHandle(ctx) {
5697
5776
  }
5698
5777
  return false;
5699
5778
  }),
5700
- scrollToIndex: (params) => runScrollWithPromise(
5701
- () => {
5779
+ scrollToIndex: (params) => {
5780
+ const shouldWaitForOutOfRangeTarget = params.index >= 0 && params.index >= state.props.data.length;
5781
+ const options = shouldWaitForOutOfRangeTarget ? {
5782
+ isReady: () => {
5783
+ var _a3;
5784
+ const props = state.props;
5785
+ const anchorIndex = (_a3 = props.anchoredEndSpace) == null ? void 0 : _a3.anchorIndex;
5786
+ const lastIndex = props.data.length - 1;
5787
+ const isInRange = params.index < props.data.length;
5788
+ const shouldWaitForAnchorSize = isInRange && anchorIndex !== void 0 && anchorIndex >= 0 && params.index >= anchorIndex && !props.getFixedItemSize && !state.sizesKnown.has(getId(state, lastIndex));
5789
+ return isInRange && !shouldWaitForAnchorSize;
5790
+ }
5791
+ } : void 0;
5792
+ return runScrollWithPromise(() => {
5702
5793
  scrollToIndex(ctx, params);
5703
5794
  return true;
5704
- },
5705
- {
5706
- shouldWaitOneFrame: params.index >= 0 && params.index >= state.props.data.length
5707
- }
5708
- ),
5795
+ }, options);
5796
+ },
5709
5797
  scrollToItem: ({ item, ...props }) => runScrollWithPromise(() => {
5710
5798
  const data = state.props.data;
5711
5799
  const index = data.indexOf(item);
@@ -5960,6 +6048,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5960
6048
  data: dataProp = [],
5961
6049
  dataVersion,
5962
6050
  drawDistance = 250,
6051
+ contentInsetEndAdjustment,
5963
6052
  estimatedItemSize = 100,
5964
6053
  estimatedListSize,
5965
6054
  extraData,
@@ -6069,6 +6158,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6069
6158
  const combinedRef = useCombinedRef(refScroller, refScrollView);
6070
6159
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : ((_item, index) => index.toString());
6071
6160
  const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
6161
+ const contentInsetEndAdjustmentResolved = contentInsetEndAdjustment ;
6162
+ const previousContentInsetEndAdjustmentRef = useRef(contentInsetEndAdjustmentResolved);
6072
6163
  const alwaysRenderIndices = useMemo(() => {
6073
6164
  const indices = getAlwaysRenderIndices(alwaysRender, dataProp, keyExtractor, anchoredEndSpace == null ? void 0 : anchoredEndSpace.anchorIndex);
6074
6165
  return { arr: indices, set: new Set(indices) };
@@ -6188,6 +6279,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6188
6279
  anchoredEndSpace: anchoredEndSpaceResolved,
6189
6280
  animatedProps: animatedPropsInternal,
6190
6281
  contentInset,
6282
+ contentInsetEndAdjustment: contentInsetEndAdjustmentResolved,
6191
6283
  data: dataProp,
6192
6284
  dataVersion,
6193
6285
  drawDistance,
@@ -6305,6 +6397,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6305
6397
  didAnchoredEndSpaceAnchorIndexChange,
6306
6398
  numColumnsProp
6307
6399
  ]);
6400
+ useLayoutEffect(() => {
6401
+ const previousContentInsetEndAdjustment = previousContentInsetEndAdjustmentRef.current;
6402
+ previousContentInsetEndAdjustmentRef.current = contentInsetEndAdjustmentResolved;
6403
+ updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment);
6404
+ }, [ctx, contentInsetEndAdjustmentResolved]);
6308
6405
  const onLayoutFooter = useCallback(
6309
6406
  (layout) => {
6310
6407
  if (!usesBootstrapInitialScroll) {
package/reanimated.d.ts CHANGED
@@ -249,6 +249,11 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
249
249
  * Keeps an item visually anchored to the start by adding trailing space when the content below it underflows.
250
250
  */
251
251
  anchoredEndSpace?: AnchoredEndSpaceConfig;
252
+ /**
253
+ * Adjusts the effective end content inset for web lists without replacing the base contentInset.
254
+ * The adjustment is also rendered as real content padding so the browser scroll range includes it.
255
+ */
256
+ contentInsetEndAdjustment?: number;
252
257
  /**
253
258
  * Number of columns to render items in.
254
259
  * @default 1
@@ -642,7 +647,7 @@ interface ViewabilityConfig {
642
647
  waitForInteraction?: boolean | undefined;
643
648
  }
644
649
 
645
- type LegendListPropsOverrides<ItemT, TItemType extends string | undefined> = Omit<LegendListPropsBase<ItemT, ScrollViewProps, TItemType>, "anchoredEndSpace" | "onScroll" | "refScrollView" | "renderScrollComponent" | "ListHeaderComponentStyle" | "ListFooterComponentStyle"> & {
650
+ type LegendListPropsOverrides<ItemT, TItemType extends string | undefined> = Omit<LegendListPropsBase<ItemT, ScrollViewProps, TItemType>, "anchoredEndSpace" | "contentInsetEndAdjustment" | "onScroll" | "refScrollView" | "renderScrollComponent" | "ListHeaderComponentStyle" | "ListFooterComponentStyle"> & {
646
651
  onScroll?: (event: NativeSyntheticEvent$1<NativeScrollEvent$1>) => void;
647
652
  refScrollView?: React.Ref<ScrollView>;
648
653
  renderScrollComponent?: (props: ScrollViewProps) => React.ReactElement<ScrollViewProps>;
package/section-list.d.ts CHANGED
@@ -305,6 +305,11 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
305
305
  * Keeps an item visually anchored to the start by adding trailing space when the content below it underflows.
306
306
  */
307
307
  anchoredEndSpace?: AnchoredEndSpaceConfig;
308
+ /**
309
+ * Adjusts the effective end content inset for web lists without replacing the base contentInset.
310
+ * The adjustment is also rendered as real content padding so the browser scroll range includes it.
311
+ */
312
+ contentInsetEndAdjustment?: number;
308
313
  /**
309
314
  * Number of columns to render items in.
310
315
  * @default 1
@@ -698,7 +703,7 @@ interface ViewabilityConfig {
698
703
  waitForInteraction?: boolean | undefined;
699
704
  }
700
705
 
701
- type LegendListPropsOverrides<ItemT, TItemType extends string | undefined> = Omit<LegendListPropsBase<ItemT, ScrollViewProps, TItemType>, "anchoredEndSpace" | "onScroll" | "refScrollView" | "renderScrollComponent" | "ListHeaderComponentStyle" | "ListFooterComponentStyle"> & {
706
+ type LegendListPropsOverrides<ItemT, TItemType extends string | undefined> = Omit<LegendListPropsBase<ItemT, ScrollViewProps, TItemType>, "anchoredEndSpace" | "contentInsetEndAdjustment" | "onScroll" | "refScrollView" | "renderScrollComponent" | "ListHeaderComponentStyle" | "ListFooterComponentStyle"> & {
702
707
  onScroll?: (event: NativeSyntheticEvent$1<NativeScrollEvent$1>) => void;
703
708
  refScrollView?: React.Ref<ScrollView>;
704
709
  renderScrollComponent?: (props: ScrollViewProps) => React.ReactElement<ScrollViewProps>;