@legendapp/list 1.0.11 → 1.0.13

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/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## 1.0.13
2
+ - Fix: Missing React import in ListHeaderComponentContainer crashing some environments
3
+ - Fix: `initialScrollIndex` was off by padding if using "padding" or "paddingVertical" props
4
+
5
+ ## 1.0.12
6
+ - Fix: Initial scroll index and scrollTo were not compensating for top padding
7
+ - Fix: Removed an overly aggressive optimization that was sometimes causing blank spaces after scrolling
8
+ - Fix: Adding a lot of items to the end with maintainScrollAtEnd could result in a large blank space
9
+ - Fix: ListHeaderComponent sometimes not positioned correctly with maintainVisibleContentPosition
10
+ - Fix: Gap styles not working with maintainVisibleContentPosition
11
+
12
+ ## 1.0.11
13
+ - Fix: scrollTo was sometimes showing gaps at the bottom or bottom after reaching the destination
14
+
1
15
  ## 1.0.10
2
16
  - Fix: Removed an optimization that only checked newly visible items, which could sometimes cause gaps in lists
3
17
  - Fix: Scroll history resets properly during scroll operations, which was causing gaps after scroll
package/index.d.mts CHANGED
@@ -244,6 +244,7 @@ interface InternalState {
244
244
  startNoBuffer: number;
245
245
  endBuffered: number;
246
246
  endNoBuffer: number;
247
+ scrollPending: number;
247
248
  scroll: number;
248
249
  scrollTime: number;
249
250
  scrollPrev: number;
@@ -278,6 +279,7 @@ interface InternalState {
278
279
  ignoreScrollFromCalcTotal?: boolean;
279
280
  disableScrollJumpsFrom?: number;
280
281
  scrollingToOffset?: number | undefined;
282
+ previousTotalSize?: number;
281
283
  averageSizes: Record<string, {
282
284
  num: number;
283
285
  avg: number;
package/index.d.ts CHANGED
@@ -244,6 +244,7 @@ interface InternalState {
244
244
  startNoBuffer: number;
245
245
  endBuffered: number;
246
246
  endNoBuffer: number;
247
+ scrollPending: number;
247
248
  scroll: number;
248
249
  scrollTime: number;
249
250
  scrollPrev: number;
@@ -278,6 +279,7 @@ interface InternalState {
278
279
  ignoreScrollFromCalcTotal?: boolean;
279
280
  disableScrollJumpsFrom?: number;
280
281
  scrollingToOffset?: number | undefined;
282
+ previousTotalSize?: number;
281
283
  averageSizes: Record<string, {
282
284
  num: number;
283
285
  avg: number;
package/index.js CHANGED
@@ -206,6 +206,13 @@ function comparatorByDistance(a, b) {
206
206
  function comparatorDefault(a, b) {
207
207
  return a - b;
208
208
  }
209
+ function getPadding(s) {
210
+ var _a, _b, _c;
211
+ return (_c = (_b = (_a = s.paddingTop) != null ? _a : s.paddingVertical) != null ? _b : s.padding) != null ? _c : 0;
212
+ }
213
+ function extractPaddingTop(style, contentContainerStyle) {
214
+ return getPadding(style) + getPadding(contentContainerStyle);
215
+ }
209
216
  var symbolFirst = Symbol();
210
217
  function useInit(cb) {
211
218
  const refValue = React2.useRef(symbolFirst);
@@ -449,7 +456,7 @@ var Container = ({
449
456
  anchorStyle.borderColor = position.type === "top" ? "red" : "blue";
450
457
  anchorStyle.borderWidth = 1;
451
458
  }
452
- return /* @__PURE__ */ React2__namespace.default.createElement(LeanView, { style }, /* @__PURE__ */ React2__namespace.default.createElement(LeanView, { style: anchorStyle, onLayout, ref }, contentFragment, __DEV__ && ENABLE_DEVMODE && /* @__PURE__ */ React2__namespace.default.createElement(reactNative.Text, { style: { position: "absolute", top: 0, left: 0, zIndex: 1e3 } }, position.top)));
459
+ return /* @__PURE__ */ React2__namespace.default.createElement(LeanView, { style }, /* @__PURE__ */ React2__namespace.default.createElement(LeanView, { style: [anchorStyle, paddingStyles], onLayout, ref }, contentFragment, __DEV__ && ENABLE_DEVMODE && /* @__PURE__ */ React2__namespace.default.createElement(reactNative.Text, { style: { position: "absolute", top: 0, left: 0, zIndex: 1e3 } }, position.top)));
453
460
  }
454
461
  return /* @__PURE__ */ React2__namespace.default.createElement(LeanView, { style, onLayout, ref }, contentFragment);
455
462
  };
@@ -535,6 +542,31 @@ var Containers = typedMemo(function Containers2({
535
542
  }
536
543
  return /* @__PURE__ */ React2__namespace.createElement(reactNative.Animated.View, { style }, containers);
537
544
  });
545
+ function ListHeaderComponentContainer({
546
+ children,
547
+ style,
548
+ ctx,
549
+ horizontal,
550
+ waitForInitialLayout
551
+ }) {
552
+ const scrollAdjust = useValue$("scrollAdjust", (v) => v, true);
553
+ const animOpacity = waitForInitialLayout ? useValue$("containersDidLayout", (value) => value ? 1 : 0) : void 0;
554
+ const additionalSize = {
555
+ transform: [{ translateY: reactNative.Animated.multiply(scrollAdjust, -1) }],
556
+ opacity: animOpacity
557
+ };
558
+ return /* @__PURE__ */ React2__namespace.createElement(
559
+ reactNative.Animated.View,
560
+ {
561
+ style: [style, additionalSize],
562
+ onLayout: (event) => {
563
+ const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
564
+ set$(ctx, "headerSize", size);
565
+ }
566
+ },
567
+ children
568
+ );
569
+ }
538
570
 
539
571
  // src/ListComponent.tsx
540
572
  var getComponent = (Component) => {
@@ -648,13 +680,12 @@ var ListComponent = typedMemo(function ListComponent2({
648
680
  },
649
681
  !ListEmptyComponent && (ENABLE_DEVMODE ? /* @__PURE__ */ React2__namespace.createElement(PaddingAndAdjustDevMode, null) : /* @__PURE__ */ React2__namespace.createElement(PaddingAndAdjust, null)),
650
682
  ListHeaderComponent && /* @__PURE__ */ React2__namespace.createElement(
651
- reactNative.View,
683
+ ListHeaderComponentContainer,
652
684
  {
653
685
  style: ListHeaderComponentStyle,
654
- onLayout: (event) => {
655
- const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
656
- set$(ctx, "headerSize", size);
657
- }
686
+ ctx,
687
+ horizontal,
688
+ waitForInitialLayout
658
689
  },
659
690
  getComponent(ListHeaderComponent)
660
691
  ),
@@ -1003,7 +1034,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1003
1034
  callbacks.current.onEndReached = rest.onEndReached;
1004
1035
  const contentContainerStyle = { ...reactNative.StyleSheet.flatten(contentContainerStyleProp) };
1005
1036
  const style = { ...reactNative.StyleSheet.flatten(styleProp) };
1006
- const stylePaddingTopState = ((style == null ? void 0 : style.paddingTop) || 0) + ((contentContainerStyle == null ? void 0 : contentContainerStyle.paddingTop) || 0);
1037
+ const stylePaddingTopState = extractPaddingTop(style, contentContainerStyle);
1007
1038
  if (style == null ? void 0 : style.paddingTop) {
1008
1039
  style.paddingTop = void 0;
1009
1040
  }
@@ -1052,8 +1083,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1052
1083
  state.sizes.set(key, size);
1053
1084
  return size;
1054
1085
  };
1055
- const calculateOffsetForIndex = (index = initialScrollIndex) => {
1086
+ const calculateOffsetForIndex = (indexParam) => {
1056
1087
  var _a;
1088
+ const isFromInit = indexParam === void 0;
1089
+ const index = isFromInit ? initialScrollIndex : indexParam;
1057
1090
  const data = dataProp;
1058
1091
  if (index !== void 0) {
1059
1092
  let offset = 0;
@@ -1072,11 +1105,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1072
1105
  offset = index * estimatedItemSize;
1073
1106
  }
1074
1107
  const adjust = peek$(ctx, "containersDidLayout") ? ((_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler.getAppliedAdjust()) || 0 : 0;
1075
- return offset / numColumnsProp - adjust;
1108
+ const stylePaddingTop = isFromInit ? stylePaddingTopState : peek$(ctx, "stylePaddingTop");
1109
+ const topPad = (stylePaddingTop != null ? stylePaddingTop : 0) + peek$(ctx, "headerSize");
1110
+ return offset / numColumnsProp - adjust + topPad;
1076
1111
  }
1077
1112
  return 0;
1078
1113
  };
1079
- const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : React2.useMemo(calculateOffsetForIndex, []);
1114
+ const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : React2.useMemo(() => calculateOffsetForIndex(void 0), []);
1080
1115
  if (!refState.current) {
1081
1116
  const initialScrollLength = reactNative.Dimensions.get("window")[horizontal ? "width" : "height"];
1082
1117
  refState.current = {
@@ -1105,6 +1140,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1105
1140
  scrollPrev: 0,
1106
1141
  scrollPrevTime: 0,
1107
1142
  scrollTime: 0,
1143
+ scrollPending: 0,
1108
1144
  indexByKey: /* @__PURE__ */ new Map(),
1109
1145
  scrollHistory: [],
1110
1146
  scrollVelocity: 0,
@@ -1173,11 +1209,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1173
1209
  const firstIndexOffset = calculateOffsetForIndex(index);
1174
1210
  let firstIndexScrollPostion = firstIndexOffset - viewOffset;
1175
1211
  const diff = Math.abs(state.scroll - firstIndexScrollPostion);
1212
+ const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
1176
1213
  const needsReanchoring = maintainVisibleContentPosition && diff > 100;
1177
1214
  state.scrollForNextCalculateItemsInView = void 0;
1178
1215
  if (needsReanchoring) {
1179
1216
  const id = getId(index);
1180
- state.anchorElement = { id, coordinate: firstIndexOffset };
1217
+ state.anchorElement = { id, coordinate: firstIndexOffset - topPad };
1181
1218
  (_a = state.belowAnchorElementPositions) == null ? void 0 : _a.clear();
1182
1219
  state.positions.clear();
1183
1220
  calcTotalSizesAndPositions({ forgetPositions: true });
@@ -1297,6 +1334,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1297
1334
  state.scrollHistory.length = 0;
1298
1335
  setTimeout(() => {
1299
1336
  state.disableScrollJumpsFrom = void 0;
1337
+ if (state.scrollPending !== void 0 && state.scrollPending !== state.scroll) {
1338
+ updateScroll(state.scrollPending);
1339
+ }
1300
1340
  }, timeout);
1301
1341
  }
1302
1342
  };
@@ -1410,7 +1450,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1410
1450
  const numColumns = peek$(ctx, "numColumns");
1411
1451
  const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
1412
1452
  let scrollState = state.scroll;
1413
- const scrollExtra = Math.max(-16, Math.min(16, speed)) * 24;
1453
+ const scrollExtra = 0;
1414
1454
  const useAverageSize = !state.disableScrollJumpsFrom && speed >= 0 && peek$(ctx, "containersDidLayout");
1415
1455
  if (!state.queuedInitialLayout && initialScrollIndex) {
1416
1456
  const updatedOffset = calculateOffsetForIndex(initialScrollIndex);
@@ -1719,6 +1759,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1719
1759
  if (paddingTop > 0) {
1720
1760
  state.scroll = 0;
1721
1761
  }
1762
+ state.disableScrollJumpsFrom = void 0;
1722
1763
  requestAnimationFrame(() => {
1723
1764
  var _a;
1724
1765
  state.maintainingScrollAtEnd = true;
@@ -1808,8 +1849,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1808
1849
  if (state) {
1809
1850
  state.data = dataProp;
1810
1851
  if (!isFirst2) {
1811
- disableScrollJumps(2e3);
1812
- refState.current.scrollForNextCalculateItemsInView = void 0;
1852
+ const totalSizeBefore = state.previousTotalSize;
1853
+ const totalSizeAfter = state.totalSize;
1854
+ const scrollDiff = state.scroll - state.scrollPrev;
1855
+ const sizeDiff = totalSizeAfter - totalSizeBefore;
1856
+ if (Math.abs(scrollDiff - sizeDiff) < 10) {
1857
+ disableScrollJumps(1e3);
1858
+ }
1813
1859
  const numContainers = peek$(ctx, "numContainers");
1814
1860
  for (let i = 0; i < numContainers; i++) {
1815
1861
  const itemKey = peek$(ctx, `containerItemKey${i}`);
@@ -2020,6 +2066,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2020
2066
  refState.current.sizes.clear();
2021
2067
  refState.current.positions.clear();
2022
2068
  }
2069
+ refState.current.previousTotalSize = peek$(ctx, "totalSize");
2023
2070
  calcTotalSizesAndPositions({ forgetPositions: false });
2024
2071
  }
2025
2072
  React2.useEffect(() => {
@@ -2227,73 +2274,76 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2227
2274
  }
2228
2275
  }, []);
2229
2276
  const handleScroll = React2.useCallback(
2230
- (event, fromSelf) => {
2277
+ (event) => {
2231
2278
  var _a, _b, _c, _d;
2232
2279
  if (((_b = (_a = event.nativeEvent) == null ? void 0 : _a.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
2233
2280
  return;
2234
2281
  }
2235
2282
  const state = refState.current;
2236
- const scrollingToOffset = state.scrollingToOffset;
2237
2283
  const newScroll = event.nativeEvent.contentOffset[horizontal ? "x" : "y"];
2284
+ state.scrollPending = newScroll;
2238
2285
  if (state.ignoreScrollFromCalcTotal && newScroll !== 0) {
2239
2286
  return;
2240
2287
  }
2241
- if (scrollingToOffset !== void 0 && Math.abs(newScroll - scrollingToOffset) < 10) {
2242
- finishScrollTo();
2243
- }
2244
- if (state.disableScrollJumpsFrom !== void 0) {
2245
- const scrollMinusAdjust = newScroll - state.scrollAdjustHandler.getAppliedAdjust();
2246
- if (Math.abs(scrollMinusAdjust - state.disableScrollJumpsFrom) > 200) {
2247
- return;
2248
- }
2249
- state.disableScrollJumpsFrom = void 0;
2288
+ updateScroll(newScroll);
2289
+ (_d = state.onScroll) == null ? void 0 : _d.call(state, event);
2290
+ },
2291
+ []
2292
+ );
2293
+ const updateScroll = React2.useCallback((newScroll) => {
2294
+ const state = refState.current;
2295
+ const scrollingToOffset = state.scrollingToOffset;
2296
+ if (scrollingToOffset !== void 0 && Math.abs(newScroll - scrollingToOffset) < 10) {
2297
+ finishScrollTo();
2298
+ }
2299
+ if (state.disableScrollJumpsFrom !== void 0) {
2300
+ const scrollMinusAdjust = newScroll - state.scrollAdjustHandler.getAppliedAdjust();
2301
+ if (Math.abs(scrollMinusAdjust - state.disableScrollJumpsFrom) > 200) {
2302
+ return;
2250
2303
  }
2251
- state.hasScrolled = true;
2252
- state.lastBatchingAction = Date.now();
2253
- const currentTime = performance.now();
2254
- if (scrollingToOffset === void 0 && !(state.scrollHistory.length === 0 && newScroll === initialContentOffset)) {
2255
- state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2256
- }
2257
- if (state.scrollHistory.length > 5) {
2258
- state.scrollHistory.shift();
2259
- }
2260
- if (state.scrollTimer !== void 0) {
2261
- clearTimeout(state.scrollTimer);
2262
- }
2263
- state.scrollTimer = setTimeout(() => {
2264
- state.scrollVelocity = 0;
2265
- }, 500);
2266
- let velocity = 0;
2267
- if (state.scrollHistory.length >= 2) {
2268
- const newest = state.scrollHistory[state.scrollHistory.length - 1];
2269
- let oldest;
2270
- for (let i = 0; i < state.scrollHistory.length - 1; i++) {
2271
- const entry = state.scrollHistory[i];
2272
- if (newest.time - entry.time <= 100) {
2273
- oldest = entry;
2274
- break;
2275
- }
2276
- }
2277
- if (oldest) {
2278
- const scrollDiff = newest.scroll - oldest.scroll;
2279
- const timeDiff = newest.time - oldest.time;
2280
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
2304
+ state.disableScrollJumpsFrom = void 0;
2305
+ }
2306
+ state.hasScrolled = true;
2307
+ state.lastBatchingAction = Date.now();
2308
+ const currentTime = performance.now();
2309
+ if (scrollingToOffset === void 0 && !(state.scrollHistory.length === 0 && newScroll === initialContentOffset)) {
2310
+ state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2311
+ }
2312
+ if (state.scrollHistory.length > 5) {
2313
+ state.scrollHistory.shift();
2314
+ }
2315
+ if (state.scrollTimer !== void 0) {
2316
+ clearTimeout(state.scrollTimer);
2317
+ }
2318
+ state.scrollTimer = setTimeout(() => {
2319
+ state.scrollVelocity = 0;
2320
+ }, 500);
2321
+ let velocity = 0;
2322
+ if (state.scrollHistory.length >= 2) {
2323
+ const newest = state.scrollHistory[state.scrollHistory.length - 1];
2324
+ let oldest;
2325
+ for (let i = 0; i < state.scrollHistory.length - 1; i++) {
2326
+ const entry = state.scrollHistory[i];
2327
+ if (newest.time - entry.time <= 100) {
2328
+ oldest = entry;
2329
+ break;
2281
2330
  }
2282
2331
  }
2283
- state.scrollPrev = state.scroll;
2284
- state.scrollPrevTime = state.scrollTime;
2285
- state.scroll = newScroll;
2286
- state.scrollTime = currentTime;
2287
- state.scrollVelocity = velocity;
2288
- calculateItemsInView();
2289
- checkAtBottom();
2290
- checkAtTop();
2291
- if (!fromSelf) {
2292
- (_d = state.onScroll) == null ? void 0 : _d.call(state, event);
2332
+ if (oldest) {
2333
+ const scrollDiff = newest.scroll - oldest.scroll;
2334
+ const timeDiff = newest.time - oldest.time;
2335
+ velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
2293
2336
  }
2294
- },
2295
- []
2296
- );
2337
+ }
2338
+ state.scrollPrev = state.scroll;
2339
+ state.scrollPrevTime = state.scrollTime;
2340
+ state.scroll = newScroll;
2341
+ state.scrollTime = currentTime;
2342
+ state.scrollVelocity = velocity;
2343
+ calculateItemsInView();
2344
+ checkAtBottom();
2345
+ checkAtTop();
2346
+ }, []);
2297
2347
  React2.useImperativeHandle(
2298
2348
  forwardedRef,
2299
2349
  () => {
package/index.mjs CHANGED
@@ -185,6 +185,13 @@ function comparatorByDistance(a, b) {
185
185
  function comparatorDefault(a, b) {
186
186
  return a - b;
187
187
  }
188
+ function getPadding(s) {
189
+ var _a, _b, _c;
190
+ return (_c = (_b = (_a = s.paddingTop) != null ? _a : s.paddingVertical) != null ? _b : s.padding) != null ? _c : 0;
191
+ }
192
+ function extractPaddingTop(style, contentContainerStyle) {
193
+ return getPadding(style) + getPadding(contentContainerStyle);
194
+ }
188
195
  var symbolFirst = Symbol();
189
196
  function useInit(cb) {
190
197
  const refValue = useRef(symbolFirst);
@@ -428,7 +435,7 @@ var Container = ({
428
435
  anchorStyle.borderColor = position.type === "top" ? "red" : "blue";
429
436
  anchorStyle.borderWidth = 1;
430
437
  }
431
- return /* @__PURE__ */ React2__default.createElement(LeanView, { style }, /* @__PURE__ */ React2__default.createElement(LeanView, { style: anchorStyle, onLayout, ref }, contentFragment, __DEV__ && ENABLE_DEVMODE && /* @__PURE__ */ React2__default.createElement(Text, { style: { position: "absolute", top: 0, left: 0, zIndex: 1e3 } }, position.top)));
438
+ return /* @__PURE__ */ React2__default.createElement(LeanView, { style }, /* @__PURE__ */ React2__default.createElement(LeanView, { style: [anchorStyle, paddingStyles], onLayout, ref }, contentFragment, __DEV__ && ENABLE_DEVMODE && /* @__PURE__ */ React2__default.createElement(Text, { style: { position: "absolute", top: 0, left: 0, zIndex: 1e3 } }, position.top)));
432
439
  }
433
440
  return /* @__PURE__ */ React2__default.createElement(LeanView, { style, onLayout, ref }, contentFragment);
434
441
  };
@@ -514,6 +521,31 @@ var Containers = typedMemo(function Containers2({
514
521
  }
515
522
  return /* @__PURE__ */ React2.createElement(Animated.View, { style }, containers);
516
523
  });
524
+ function ListHeaderComponentContainer({
525
+ children,
526
+ style,
527
+ ctx,
528
+ horizontal,
529
+ waitForInitialLayout
530
+ }) {
531
+ const scrollAdjust = useValue$("scrollAdjust", (v) => v, true);
532
+ const animOpacity = waitForInitialLayout ? useValue$("containersDidLayout", (value) => value ? 1 : 0) : void 0;
533
+ const additionalSize = {
534
+ transform: [{ translateY: Animated.multiply(scrollAdjust, -1) }],
535
+ opacity: animOpacity
536
+ };
537
+ return /* @__PURE__ */ React2.createElement(
538
+ Animated.View,
539
+ {
540
+ style: [style, additionalSize],
541
+ onLayout: (event) => {
542
+ const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
543
+ set$(ctx, "headerSize", size);
544
+ }
545
+ },
546
+ children
547
+ );
548
+ }
517
549
 
518
550
  // src/ListComponent.tsx
519
551
  var getComponent = (Component) => {
@@ -627,13 +659,12 @@ var ListComponent = typedMemo(function ListComponent2({
627
659
  },
628
660
  !ListEmptyComponent && (ENABLE_DEVMODE ? /* @__PURE__ */ React2.createElement(PaddingAndAdjustDevMode, null) : /* @__PURE__ */ React2.createElement(PaddingAndAdjust, null)),
629
661
  ListHeaderComponent && /* @__PURE__ */ React2.createElement(
630
- View,
662
+ ListHeaderComponentContainer,
631
663
  {
632
664
  style: ListHeaderComponentStyle,
633
- onLayout: (event) => {
634
- const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
635
- set$(ctx, "headerSize", size);
636
- }
665
+ ctx,
666
+ horizontal,
667
+ waitForInitialLayout
637
668
  },
638
669
  getComponent(ListHeaderComponent)
639
670
  ),
@@ -982,7 +1013,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
982
1013
  callbacks.current.onEndReached = rest.onEndReached;
983
1014
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
984
1015
  const style = { ...StyleSheet.flatten(styleProp) };
985
- const stylePaddingTopState = ((style == null ? void 0 : style.paddingTop) || 0) + ((contentContainerStyle == null ? void 0 : contentContainerStyle.paddingTop) || 0);
1016
+ const stylePaddingTopState = extractPaddingTop(style, contentContainerStyle);
986
1017
  if (style == null ? void 0 : style.paddingTop) {
987
1018
  style.paddingTop = void 0;
988
1019
  }
@@ -1031,8 +1062,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1031
1062
  state.sizes.set(key, size);
1032
1063
  return size;
1033
1064
  };
1034
- const calculateOffsetForIndex = (index = initialScrollIndex) => {
1065
+ const calculateOffsetForIndex = (indexParam) => {
1035
1066
  var _a;
1067
+ const isFromInit = indexParam === void 0;
1068
+ const index = isFromInit ? initialScrollIndex : indexParam;
1036
1069
  const data = dataProp;
1037
1070
  if (index !== void 0) {
1038
1071
  let offset = 0;
@@ -1051,11 +1084,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1051
1084
  offset = index * estimatedItemSize;
1052
1085
  }
1053
1086
  const adjust = peek$(ctx, "containersDidLayout") ? ((_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler.getAppliedAdjust()) || 0 : 0;
1054
- return offset / numColumnsProp - adjust;
1087
+ const stylePaddingTop = isFromInit ? stylePaddingTopState : peek$(ctx, "stylePaddingTop");
1088
+ const topPad = (stylePaddingTop != null ? stylePaddingTop : 0) + peek$(ctx, "headerSize");
1089
+ return offset / numColumnsProp - adjust + topPad;
1055
1090
  }
1056
1091
  return 0;
1057
1092
  };
1058
- const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : useMemo(calculateOffsetForIndex, []);
1093
+ const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : useMemo(() => calculateOffsetForIndex(void 0), []);
1059
1094
  if (!refState.current) {
1060
1095
  const initialScrollLength = Dimensions.get("window")[horizontal ? "width" : "height"];
1061
1096
  refState.current = {
@@ -1084,6 +1119,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1084
1119
  scrollPrev: 0,
1085
1120
  scrollPrevTime: 0,
1086
1121
  scrollTime: 0,
1122
+ scrollPending: 0,
1087
1123
  indexByKey: /* @__PURE__ */ new Map(),
1088
1124
  scrollHistory: [],
1089
1125
  scrollVelocity: 0,
@@ -1152,11 +1188,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1152
1188
  const firstIndexOffset = calculateOffsetForIndex(index);
1153
1189
  let firstIndexScrollPostion = firstIndexOffset - viewOffset;
1154
1190
  const diff = Math.abs(state.scroll - firstIndexScrollPostion);
1191
+ const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
1155
1192
  const needsReanchoring = maintainVisibleContentPosition && diff > 100;
1156
1193
  state.scrollForNextCalculateItemsInView = void 0;
1157
1194
  if (needsReanchoring) {
1158
1195
  const id = getId(index);
1159
- state.anchorElement = { id, coordinate: firstIndexOffset };
1196
+ state.anchorElement = { id, coordinate: firstIndexOffset - topPad };
1160
1197
  (_a = state.belowAnchorElementPositions) == null ? void 0 : _a.clear();
1161
1198
  state.positions.clear();
1162
1199
  calcTotalSizesAndPositions({ forgetPositions: true });
@@ -1276,6 +1313,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1276
1313
  state.scrollHistory.length = 0;
1277
1314
  setTimeout(() => {
1278
1315
  state.disableScrollJumpsFrom = void 0;
1316
+ if (state.scrollPending !== void 0 && state.scrollPending !== state.scroll) {
1317
+ updateScroll(state.scrollPending);
1318
+ }
1279
1319
  }, timeout);
1280
1320
  }
1281
1321
  };
@@ -1389,7 +1429,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1389
1429
  const numColumns = peek$(ctx, "numColumns");
1390
1430
  const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
1391
1431
  let scrollState = state.scroll;
1392
- const scrollExtra = Math.max(-16, Math.min(16, speed)) * 24;
1432
+ const scrollExtra = 0;
1393
1433
  const useAverageSize = !state.disableScrollJumpsFrom && speed >= 0 && peek$(ctx, "containersDidLayout");
1394
1434
  if (!state.queuedInitialLayout && initialScrollIndex) {
1395
1435
  const updatedOffset = calculateOffsetForIndex(initialScrollIndex);
@@ -1698,6 +1738,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1698
1738
  if (paddingTop > 0) {
1699
1739
  state.scroll = 0;
1700
1740
  }
1741
+ state.disableScrollJumpsFrom = void 0;
1701
1742
  requestAnimationFrame(() => {
1702
1743
  var _a;
1703
1744
  state.maintainingScrollAtEnd = true;
@@ -1787,8 +1828,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1787
1828
  if (state) {
1788
1829
  state.data = dataProp;
1789
1830
  if (!isFirst2) {
1790
- disableScrollJumps(2e3);
1791
- refState.current.scrollForNextCalculateItemsInView = void 0;
1831
+ const totalSizeBefore = state.previousTotalSize;
1832
+ const totalSizeAfter = state.totalSize;
1833
+ const scrollDiff = state.scroll - state.scrollPrev;
1834
+ const sizeDiff = totalSizeAfter - totalSizeBefore;
1835
+ if (Math.abs(scrollDiff - sizeDiff) < 10) {
1836
+ disableScrollJumps(1e3);
1837
+ }
1792
1838
  const numContainers = peek$(ctx, "numContainers");
1793
1839
  for (let i = 0; i < numContainers; i++) {
1794
1840
  const itemKey = peek$(ctx, `containerItemKey${i}`);
@@ -1999,6 +2045,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1999
2045
  refState.current.sizes.clear();
2000
2046
  refState.current.positions.clear();
2001
2047
  }
2048
+ refState.current.previousTotalSize = peek$(ctx, "totalSize");
2002
2049
  calcTotalSizesAndPositions({ forgetPositions: false });
2003
2050
  }
2004
2051
  useEffect(() => {
@@ -2206,73 +2253,76 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2206
2253
  }
2207
2254
  }, []);
2208
2255
  const handleScroll = useCallback(
2209
- (event, fromSelf) => {
2256
+ (event) => {
2210
2257
  var _a, _b, _c, _d;
2211
2258
  if (((_b = (_a = event.nativeEvent) == null ? void 0 : _a.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
2212
2259
  return;
2213
2260
  }
2214
2261
  const state = refState.current;
2215
- const scrollingToOffset = state.scrollingToOffset;
2216
2262
  const newScroll = event.nativeEvent.contentOffset[horizontal ? "x" : "y"];
2263
+ state.scrollPending = newScroll;
2217
2264
  if (state.ignoreScrollFromCalcTotal && newScroll !== 0) {
2218
2265
  return;
2219
2266
  }
2220
- if (scrollingToOffset !== void 0 && Math.abs(newScroll - scrollingToOffset) < 10) {
2221
- finishScrollTo();
2222
- }
2223
- if (state.disableScrollJumpsFrom !== void 0) {
2224
- const scrollMinusAdjust = newScroll - state.scrollAdjustHandler.getAppliedAdjust();
2225
- if (Math.abs(scrollMinusAdjust - state.disableScrollJumpsFrom) > 200) {
2226
- return;
2227
- }
2228
- state.disableScrollJumpsFrom = void 0;
2267
+ updateScroll(newScroll);
2268
+ (_d = state.onScroll) == null ? void 0 : _d.call(state, event);
2269
+ },
2270
+ []
2271
+ );
2272
+ const updateScroll = useCallback((newScroll) => {
2273
+ const state = refState.current;
2274
+ const scrollingToOffset = state.scrollingToOffset;
2275
+ if (scrollingToOffset !== void 0 && Math.abs(newScroll - scrollingToOffset) < 10) {
2276
+ finishScrollTo();
2277
+ }
2278
+ if (state.disableScrollJumpsFrom !== void 0) {
2279
+ const scrollMinusAdjust = newScroll - state.scrollAdjustHandler.getAppliedAdjust();
2280
+ if (Math.abs(scrollMinusAdjust - state.disableScrollJumpsFrom) > 200) {
2281
+ return;
2229
2282
  }
2230
- state.hasScrolled = true;
2231
- state.lastBatchingAction = Date.now();
2232
- const currentTime = performance.now();
2233
- if (scrollingToOffset === void 0 && !(state.scrollHistory.length === 0 && newScroll === initialContentOffset)) {
2234
- state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2235
- }
2236
- if (state.scrollHistory.length > 5) {
2237
- state.scrollHistory.shift();
2238
- }
2239
- if (state.scrollTimer !== void 0) {
2240
- clearTimeout(state.scrollTimer);
2241
- }
2242
- state.scrollTimer = setTimeout(() => {
2243
- state.scrollVelocity = 0;
2244
- }, 500);
2245
- let velocity = 0;
2246
- if (state.scrollHistory.length >= 2) {
2247
- const newest = state.scrollHistory[state.scrollHistory.length - 1];
2248
- let oldest;
2249
- for (let i = 0; i < state.scrollHistory.length - 1; i++) {
2250
- const entry = state.scrollHistory[i];
2251
- if (newest.time - entry.time <= 100) {
2252
- oldest = entry;
2253
- break;
2254
- }
2255
- }
2256
- if (oldest) {
2257
- const scrollDiff = newest.scroll - oldest.scroll;
2258
- const timeDiff = newest.time - oldest.time;
2259
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
2283
+ state.disableScrollJumpsFrom = void 0;
2284
+ }
2285
+ state.hasScrolled = true;
2286
+ state.lastBatchingAction = Date.now();
2287
+ const currentTime = performance.now();
2288
+ if (scrollingToOffset === void 0 && !(state.scrollHistory.length === 0 && newScroll === initialContentOffset)) {
2289
+ state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2290
+ }
2291
+ if (state.scrollHistory.length > 5) {
2292
+ state.scrollHistory.shift();
2293
+ }
2294
+ if (state.scrollTimer !== void 0) {
2295
+ clearTimeout(state.scrollTimer);
2296
+ }
2297
+ state.scrollTimer = setTimeout(() => {
2298
+ state.scrollVelocity = 0;
2299
+ }, 500);
2300
+ let velocity = 0;
2301
+ if (state.scrollHistory.length >= 2) {
2302
+ const newest = state.scrollHistory[state.scrollHistory.length - 1];
2303
+ let oldest;
2304
+ for (let i = 0; i < state.scrollHistory.length - 1; i++) {
2305
+ const entry = state.scrollHistory[i];
2306
+ if (newest.time - entry.time <= 100) {
2307
+ oldest = entry;
2308
+ break;
2260
2309
  }
2261
2310
  }
2262
- state.scrollPrev = state.scroll;
2263
- state.scrollPrevTime = state.scrollTime;
2264
- state.scroll = newScroll;
2265
- state.scrollTime = currentTime;
2266
- state.scrollVelocity = velocity;
2267
- calculateItemsInView();
2268
- checkAtBottom();
2269
- checkAtTop();
2270
- if (!fromSelf) {
2271
- (_d = state.onScroll) == null ? void 0 : _d.call(state, event);
2311
+ if (oldest) {
2312
+ const scrollDiff = newest.scroll - oldest.scroll;
2313
+ const timeDiff = newest.time - oldest.time;
2314
+ velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
2272
2315
  }
2273
- },
2274
- []
2275
- );
2316
+ }
2317
+ state.scrollPrev = state.scroll;
2318
+ state.scrollPrevTime = state.scrollTime;
2319
+ state.scroll = newScroll;
2320
+ state.scrollTime = currentTime;
2321
+ state.scrollVelocity = velocity;
2322
+ calculateItemsInView();
2323
+ checkAtBottom();
2324
+ checkAtTop();
2325
+ }, []);
2276
2326
  useImperativeHandle(
2277
2327
  forwardedRef,
2278
2328
  () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
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,