@legendapp/list 0.5.9 → 0.6.0

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.
Files changed (5) hide show
  1. package/index.d.mts +22 -2
  2. package/index.d.ts +22 -2
  3. package/index.js +294 -187
  4. package/index.mjs +275 -168
  5. package/package.json +1 -1
package/index.mjs CHANGED
@@ -1,12 +1,11 @@
1
- import * as React5 from 'react';
2
- import React5__default, { forwardRef, useRef, useMemo, useCallback, useImperativeHandle, useSyncExternalStore, useEffect, useState } from 'react';
3
- import { Platform, StyleSheet, ScrollView, Animated, View, Dimensions, useAnimatedValue as useAnimatedValue$1 } from 'react-native';
1
+ import * as React4 from 'react';
2
+ import React4__default, { forwardRef, useRef, useMemo, useCallback, useImperativeHandle, useSyncExternalStore, useEffect, useState } from 'react';
3
+ import { Animated, ScrollView, View, Dimensions, StyleSheet, useAnimatedValue as useAnimatedValue$1 } from 'react-native';
4
4
 
5
5
  // src/LegendList.tsx
6
- var USE_CONTENT_INSET = Platform.OS === "ios";
7
- var ContextState = React5.createContext(null);
6
+ var ContextState = React4.createContext(null);
8
7
  function StateProvider({ children }) {
9
- const [value] = React5.useState(() => ({
8
+ const [value] = React4.useState(() => ({
10
9
  listeners: /* @__PURE__ */ new Map(),
11
10
  values: /* @__PURE__ */ new Map(),
12
11
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
@@ -14,13 +13,13 @@ function StateProvider({ children }) {
14
13
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
15
14
  mapViewabilityAmountValues: /* @__PURE__ */ new Map()
16
15
  }));
17
- return /* @__PURE__ */ React5.createElement(ContextState.Provider, { value }, children);
16
+ return /* @__PURE__ */ React4.createElement(ContextState.Provider, { value }, children);
18
17
  }
19
18
  function useStateContext() {
20
- return React5.useContext(ContextState);
19
+ return React4.useContext(ContextState);
21
20
  }
22
21
  function use$(signalName) {
23
- const ctx = React5.useContext(ContextState);
22
+ const ctx = React4.useContext(ContextState);
24
23
  const value = useSyncExternalStore(
25
24
  (onStoreChange) => listen$(ctx, signalName, onStoreChange),
26
25
  () => ctx.values.get(signalName)
@@ -53,25 +52,6 @@ function set$(ctx, signalName, value) {
53
52
  }
54
53
  }
55
54
  }
56
-
57
- // src/$ScrollView.tsx
58
- var OFFSET_TEST = 0;
59
- var $ScrollView = React5.forwardRef(function $ScrollView2(props, ref) {
60
- const { style, horizontal, ...rest } = props;
61
- const scrollAdjust = use$("scrollAdjust");
62
- const adjustProps = {};
63
- if (scrollAdjust !== 0) {
64
- if (USE_CONTENT_INSET) {
65
- adjustProps.contentInset = horizontal ? { left: -scrollAdjust } : { top: -scrollAdjust + OFFSET_TEST };
66
- } else {
67
- adjustProps.style = horizontal ? { marginLeft: -scrollAdjust } : { marginTop: -scrollAdjust };
68
- if (style) {
69
- adjustProps.style = StyleSheet.compose(style, adjustProps.style);
70
- }
71
- }
72
- }
73
- return /* @__PURE__ */ React5.createElement(ScrollView, { ...rest, style, horizontal, ...adjustProps, ref });
74
- });
75
55
  var Container = ({
76
56
  id,
77
57
  recycleItems,
@@ -87,31 +67,34 @@ var Container = ({
87
67
  const numColumns = use$("numColumns");
88
68
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
89
69
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
90
- const style = horizontal ? {
70
+ let style = horizontal ? {
91
71
  flexDirection: "row",
92
72
  position: "absolute",
93
- top: visible ? otherAxisPos : -1e7,
73
+ top: otherAxisPos,
94
74
  bottom: numColumns > 1 ? null : 0,
95
75
  height: otherAxisSize,
96
76
  left: position
97
77
  } : {
98
78
  position: "absolute",
99
- left: visible ? otherAxisPos : -1e7,
79
+ left: otherAxisPos,
100
80
  right: numColumns > 1 ? null : 0,
101
81
  width: otherAxisSize,
102
82
  top: position
103
83
  };
84
+ {
85
+ style.opacity = visible ? 1 : 0;
86
+ }
104
87
  const lastItemKey = use$("lastItemKey");
105
88
  const itemKey = use$(`containerItemKey${id}`);
106
89
  const renderedItem = useMemo(() => itemKey !== void 0 && getRenderedItem(itemKey, id), [itemKey]);
107
- return /* @__PURE__ */ React5__default.createElement(
90
+ return /* @__PURE__ */ React4__default.createElement(
108
91
  View,
109
92
  {
110
93
  style,
111
94
  onLayout: (event) => {
112
95
  const key = peek$(ctx, `containerItemKey${id}`);
113
96
  if (key !== void 0) {
114
- const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
97
+ const size = Math.floor(event.nativeEvent.layout[horizontal ? "width" : "height"] * 8) / 8;
115
98
  updateItemSize(id, key, size);
116
99
  const otherAxisSize2 = horizontal ? event.nativeEvent.layout.width : event.nativeEvent.layout.height;
117
100
  set$(ctx, "otherAxisSize", Math.max(otherAxisSize2, peek$(ctx, "otherAxisSize") || 0));
@@ -124,7 +107,7 @@ var Container = ({
124
107
  }
125
108
  }
126
109
  },
127
- /* @__PURE__ */ React5__default.createElement(React5__default.Fragment, { key: recycleItems ? void 0 : itemKey }, renderedItem, renderedItem && ItemSeparatorComponent && itemKey !== lastItemKey && ItemSeparatorComponent)
110
+ /* @__PURE__ */ React4__default.createElement(React4__default.Fragment, { key: recycleItems ? void 0 : itemKey }, renderedItem, renderedItem && ItemSeparatorComponent && itemKey !== lastItemKey && ItemSeparatorComponent)
128
111
  );
129
112
  };
130
113
  var useAnimatedValue = useAnimatedValue$1 || ((initialValue) => {
@@ -133,28 +116,27 @@ var useAnimatedValue = useAnimatedValue$1 || ((initialValue) => {
133
116
  function useValue$(key, getValue, key2) {
134
117
  var _a;
135
118
  const ctx = useStateContext();
136
- const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
119
+ const animValue = useAnimatedValue((_a = peek$(ctx, key)) != null ? _a : 0);
137
120
  useMemo(() => {
138
- listen$(ctx, key, (v) => animValue.setValue(getValue ? getValue(v) : v));
121
+ listen$(ctx, key, (v) => animValue.setValue(v));
139
122
  }, []);
140
123
  return animValue;
141
124
  }
142
125
 
143
126
  // src/Containers.tsx
144
- var Containers = React5.memo(function Containers2({
127
+ var Containers = React4.memo(function Containers2({
145
128
  horizontal,
146
129
  recycleItems,
147
130
  ItemSeparatorComponent,
148
131
  updateItemSize,
149
132
  getRenderedItem
150
133
  }) {
151
- const ctx = useStateContext();
152
134
  const numContainers = use$("numContainersPooled");
153
- const animSize = useValue$("totalSize", (v) => v + peek$(ctx, "scrollAdjust"));
135
+ const animSize = useValue$("totalSize");
154
136
  const containers = [];
155
137
  for (let i = 0; i < numContainers; i++) {
156
138
  containers.push(
157
- /* @__PURE__ */ React5.createElement(
139
+ /* @__PURE__ */ React4.createElement(
158
140
  Container,
159
141
  {
160
142
  id: i,
@@ -169,20 +151,20 @@ var Containers = React5.memo(function Containers2({
169
151
  );
170
152
  }
171
153
  const style = horizontal ? { width: animSize } : { height: animSize };
172
- return /* @__PURE__ */ React5.createElement(Animated.View, { style }, containers);
154
+ return /* @__PURE__ */ React4.createElement(Animated.View, { style }, containers);
173
155
  });
174
156
 
175
157
  // src/ListComponent.tsx
176
158
  var getComponent = (Component) => {
177
- if (React5.isValidElement(Component)) {
159
+ if (React4.isValidElement(Component)) {
178
160
  return Component;
179
161
  }
180
162
  if (Component) {
181
- return /* @__PURE__ */ React5.createElement(Component, null);
163
+ return /* @__PURE__ */ React4.createElement(Component, null);
182
164
  }
183
165
  return null;
184
166
  };
185
- var ListComponent = React5.memo(function ListComponent2({
167
+ var ListComponent = React4.memo(function ListComponent2({
186
168
  style,
187
169
  contentContainerStyle,
188
170
  horizontal,
@@ -200,18 +182,20 @@ var ListComponent = React5.memo(function ListComponent2({
200
182
  ListEmptyComponentStyle,
201
183
  getRenderedItem,
202
184
  updateItemSize,
203
- addTotalSize,
204
185
  refScroller,
186
+ maintainVisibleContentPosition,
205
187
  ...rest
206
188
  }) {
207
189
  const ctx = useStateContext();
208
190
  const animPaddingTop = useValue$("paddingTop");
209
191
  const animScrollAdjust = useValue$("scrollAdjust");
210
- return /* @__PURE__ */ React5.createElement(
211
- $ScrollView,
192
+ const additionalSize = { marginTop: animScrollAdjust, paddingTop: animPaddingTop };
193
+ return /* @__PURE__ */ React4.createElement(
194
+ ScrollView,
212
195
  {
213
196
  ...rest,
214
197
  style,
198
+ maintainVisibleContentPosition: maintainVisibleContentPosition ? { minIndexForVisible: 0 } : void 0,
215
199
  contentContainerStyle: [
216
200
  contentContainerStyle,
217
201
  horizontal ? {
@@ -224,13 +208,11 @@ var ListComponent = React5.memo(function ListComponent2({
224
208
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
225
209
  ref: refScroller
226
210
  },
227
- alignItemsAtEnd && /* @__PURE__ */ React5.createElement(Animated.View, { style: { height: animPaddingTop } }),
228
- ListHeaderComponent && /* @__PURE__ */ React5.createElement(
211
+ /* @__PURE__ */ React4.createElement(Animated.View, { style: additionalSize }),
212
+ ListHeaderComponent && /* @__PURE__ */ React4.createElement(
229
213
  Animated.View,
230
214
  {
231
- style: StyleSheet.compose(ListHeaderComponentStyle, {
232
- top: animScrollAdjust
233
- }),
215
+ style: ListHeaderComponentStyle,
234
216
  onLayout: (event) => {
235
217
  const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
236
218
  const prevSize = peek$(ctx, "headerSize") || 0;
@@ -241,16 +223,8 @@ var ListComponent = React5.memo(function ListComponent2({
241
223
  },
242
224
  getComponent(ListHeaderComponent)
243
225
  ),
244
- ListEmptyComponent && /* @__PURE__ */ React5.createElement(
245
- Animated.View,
246
- {
247
- style: StyleSheet.compose(ListEmptyComponentStyle, {
248
- top: animScrollAdjust
249
- })
250
- },
251
- getComponent(ListEmptyComponent)
252
- ),
253
- /* @__PURE__ */ React5.createElement(
226
+ ListEmptyComponent && /* @__PURE__ */ React4.createElement(Animated.View, { style: ListEmptyComponentStyle }, getComponent(ListEmptyComponent)),
227
+ /* @__PURE__ */ React4.createElement(
254
228
  Containers,
255
229
  {
256
230
  horizontal,
@@ -260,9 +234,46 @@ var ListComponent = React5.memo(function ListComponent2({
260
234
  updateItemSize
261
235
  }
262
236
  ),
263
- ListFooterComponent && /* @__PURE__ */ React5.createElement(View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
237
+ ListFooterComponent && /* @__PURE__ */ React4.createElement(View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
264
238
  );
265
239
  });
240
+
241
+ // src/ScrollAdjustHandler.ts
242
+ var ScrollAdjustHandler = class {
243
+ constructor(ctx) {
244
+ this.ctx = ctx;
245
+ this.appliedAdjust = 0;
246
+ this.pendingAdjust = 0;
247
+ this.busy = false;
248
+ this.firstAdjust = true;
249
+ this.context = ctx;
250
+ }
251
+ requestAdjust(adjust, onAdjusted) {
252
+ const oldAdjustTop = peek$(this.context, "scrollAdjust");
253
+ if (oldAdjustTop === adjust) {
254
+ return;
255
+ }
256
+ this.appliedAdjust = adjust;
257
+ this.pendingAdjust = adjust;
258
+ const doAjdust = () => {
259
+ set$(this.context, "scrollAdjust", this.pendingAdjust);
260
+ onAdjusted(oldAdjustTop - this.pendingAdjust);
261
+ this.busy = false;
262
+ };
263
+ if (!this.busy) {
264
+ this.busy = true;
265
+ if (this.firstAdjust) {
266
+ this.firstAdjust = false;
267
+ setTimeout(doAjdust, 50);
268
+ } else {
269
+ doAjdust();
270
+ }
271
+ }
272
+ }
273
+ getAppliedAdjust() {
274
+ return this.appliedAdjust;
275
+ }
276
+ };
266
277
  var symbolFirst = Symbol();
267
278
  function useInit(cb) {
268
279
  const refValue = useRef(symbolFirst);
@@ -421,14 +432,13 @@ function maybeUpdateViewabilityCallback(ctx, configId, viewToken) {
421
432
 
422
433
  // src/LegendList.tsx
423
434
  var DEFAULT_DRAW_DISTANCE = 250;
424
- var INITIAL_SCROLL_ADJUST = 1e4;
425
435
  var POSITION_OUT_OF_VIEW = -1e7;
426
436
  var DEFAULT_ITEM_SIZE = 100;
427
437
  var LegendList = forwardRef(function LegendList2(props, forwardedRef) {
428
- return /* @__PURE__ */ React5.createElement(StateProvider, null, /* @__PURE__ */ React5.createElement(LegendListInner, { ...props, ref: forwardedRef }));
438
+ return /* @__PURE__ */ React4.createElement(StateProvider, null, /* @__PURE__ */ React4.createElement(LegendListInner, { ...props, ref: forwardedRef }));
429
439
  });
430
440
  var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef) {
431
- var _a, _b, _c, _d, _e, _f;
441
+ var _a, _b, _c, _d, _e;
432
442
  const {
433
443
  data,
434
444
  initialScrollIndex,
@@ -490,37 +500,38 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
490
500
  } else if (estimatedItemSize) {
491
501
  offset = index * estimatedItemSize;
492
502
  }
493
- return offset + (maintainVisibleContentPosition ? INITIAL_SCROLL_ADJUST : 0);
503
+ return offset / numColumnsProp;
494
504
  }
495
- return void 0;
505
+ return 0;
496
506
  };
497
507
  const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : useMemo(calculateInitialOffset, []);
498
508
  if (!refState.current) {
509
+ const initialScrollLength = Dimensions.get("window")[horizontal ? "width" : "height"];
499
510
  refState.current = {
500
511
  sizes: /* @__PURE__ */ new Map(),
501
512
  positions: /* @__PURE__ */ new Map(),
502
513
  columns: /* @__PURE__ */ new Map(),
503
514
  pendingAdjust: 0,
504
515
  animFrameLayout: null,
505
- animFrameTotalSize: null,
506
- isStartReached: true,
516
+ isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
507
517
  isEndReached: false,
508
518
  isAtBottom: false,
509
519
  isAtTop: false,
510
520
  data,
511
521
  idsInFirstRender: void 0,
512
522
  hasScrolled: false,
513
- scrollLength: Dimensions.get("window")[horizontal ? "width" : "height"],
523
+ scrollLength: initialScrollLength,
514
524
  startBuffered: 0,
515
525
  startNoBuffer: 0,
516
526
  endBuffered: 0,
517
527
  endNoBuffer: 0,
518
528
  scroll: initialContentOffset || 0,
519
529
  totalSize: 0,
530
+ totalSizeBelowAnchor: 0,
520
531
  timeouts: /* @__PURE__ */ new Set(),
521
532
  viewabilityConfigCallbackPairs: void 0,
522
533
  renderItem: void 0,
523
- scrollAdjustPending: maintainVisibleContentPosition ? INITIAL_SCROLL_ADJUST : 0,
534
+ scrollAdjustHandler: new ScrollAdjustHandler(ctx),
524
535
  nativeMarginTop: 0,
525
536
  scrollPrev: 0,
526
537
  scrollPrevTime: 0,
@@ -531,54 +542,141 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
531
542
  contentSize: { width: 0, height: 0 },
532
543
  sizesLaidOut: __DEV__ ? /* @__PURE__ */ new Map() : void 0,
533
544
  timeoutSizeMessage: 0,
534
- scrollTimer: void 0
545
+ scrollTimer: void 0,
546
+ belowAnchorElementPositions: void 0,
547
+ rowHeights: /* @__PURE__ */ new Map(),
548
+ startReachedBlockedByTimer: false
535
549
  };
536
550
  refState.current.idsInFirstRender = new Set(data.map((_, i) => getId(i)));
537
- set$(ctx, "scrollAdjust", refState.current.scrollAdjustPending);
551
+ if (maintainVisibleContentPosition) {
552
+ if (initialScrollIndex) {
553
+ refState.current.anchorElement = {
554
+ coordinate: initialContentOffset,
555
+ id: getId(initialScrollIndex)
556
+ };
557
+ } else if (data.length) {
558
+ refState.current.anchorElement = {
559
+ coordinate: initialContentOffset,
560
+ id: getId(0)
561
+ };
562
+ } else {
563
+ console.warn("[legend-list] maintainVisibleContentPosition was not able to find an anchor element");
564
+ }
565
+ }
566
+ set$(ctx, "scrollAdjust", 0);
538
567
  }
539
- const adjustScroll = (diff) => {
540
- if (maintainVisibleContentPosition && refScroller.current) {
541
- refState.current.scrollAdjustPending -= diff;
568
+ const getAnchorElementIndex = () => {
569
+ const state = refState.current;
570
+ if (state.anchorElement) {
571
+ const el = state.indexByKey.get(state.anchorElement.id);
572
+ return el;
542
573
  }
574
+ return void 0;
543
575
  };
544
- const addTotalSize = useCallback((key, add) => {
576
+ const addTotalSize = useCallback((key, add, totalSizeBelowAnchor) => {
545
577
  const state = refState.current;
546
578
  const index = key === null ? 0 : state.indexByKey.get(key);
547
- const isAbove = key !== null && index < (state.startNoBuffer || 0);
548
- const prev = state.totalSize;
579
+ let isAboveAnchor = false;
580
+ if (maintainVisibleContentPosition) {
581
+ if (state.anchorElement && index < getAnchorElementIndex()) {
582
+ isAboveAnchor = true;
583
+ }
584
+ }
585
+ state.totalSize;
549
586
  if (key === null) {
550
587
  state.totalSize = add;
588
+ state.totalSizeBelowAnchor = totalSizeBelowAnchor;
551
589
  } else {
552
590
  state.totalSize += add;
591
+ if (isAboveAnchor) {
592
+ state.totalSizeBelowAnchor += add;
593
+ }
594
+ }
595
+ let applyAdjustValue = void 0;
596
+ if (maintainVisibleContentPosition) {
597
+ const newAdjust = state.anchorElement.coordinate - state.totalSizeBelowAnchor;
598
+ applyAdjustValue = -newAdjust;
599
+ state.belowAnchorElementPositions = buildElementPositionsBelowAnchor();
600
+ state.rowHeights.clear();
553
601
  }
554
602
  const doAdd = () => {
555
603
  const totalSize = state.totalSize;
556
- state.animFrameTotalSize = null;
557
- set$(ctx, "totalSize", totalSize);
604
+ let resultSize = totalSize;
605
+ if (applyAdjustValue !== void 0) {
606
+ resultSize -= applyAdjustValue;
607
+ refState.current.scrollAdjustHandler.requestAdjust(applyAdjustValue, (diff) => {
608
+ state.scroll -= diff;
609
+ });
610
+ }
611
+ set$(ctx, "totalSize", resultSize);
558
612
  if (alignItemsAtEnd) {
559
613
  doUpdatePaddingTop();
560
614
  }
561
615
  };
562
- if (isAbove) {
563
- adjustScroll(add);
616
+ doAdd();
617
+ }, []);
618
+ const getRowHeight = (n) => {
619
+ const { rowHeights } = refState.current;
620
+ if (numColumnsProp === 1) {
621
+ const id = getId(n);
622
+ return getItemSize(id, n, data[n]);
564
623
  }
565
- if (!prev || key === null) {
566
- doAdd();
567
- } else if (!state.animFrameTotalSize) {
568
- state.animFrameTotalSize = requestAnimationFrame(doAdd);
624
+ if (rowHeights.has(n)) {
625
+ return rowHeights.get(n) || 0;
569
626
  }
570
- }, []);
571
- const calculateItemsInView = useCallback((speed = 0) => {
572
- var _a2, _b2, _c2;
627
+ let rowHeight = 0;
628
+ const startEl = n * numColumnsProp;
629
+ for (let i = startEl; i < startEl + numColumnsProp; i++) {
630
+ const id = getId(i);
631
+ const size = getItemSize(id, i, data[i]);
632
+ rowHeight = Math.max(rowHeight, size);
633
+ }
634
+ rowHeights.set(n, rowHeight);
635
+ return rowHeight;
636
+ };
637
+ const buildElementPositionsBelowAnchor = () => {
638
+ const state = refState.current;
639
+ if (!state.anchorElement) {
640
+ return /* @__PURE__ */ new Map();
641
+ }
642
+ let top = state.anchorElement.coordinate;
643
+ const anchorIndex = state.indexByKey.get(state.anchorElement.id);
644
+ if (anchorIndex === 0) {
645
+ return /* @__PURE__ */ new Map();
646
+ }
647
+ const map = state.belowAnchorElementPositions || /* @__PURE__ */ new Map();
648
+ for (let i = anchorIndex - 1; i >= 0; i--) {
649
+ const id = getId(i);
650
+ const rowNumber = Math.floor(i / numColumnsProp);
651
+ if (i % numColumnsProp === 0) {
652
+ top -= getRowHeight(rowNumber);
653
+ }
654
+ map.set(id, top);
655
+ }
656
+ return map;
657
+ };
658
+ const getElementPositionBelowAchor = (id) => {
659
+ const state = refState.current;
660
+ if (!refState.current.belowAnchorElementPositions) {
661
+ state.belowAnchorElementPositions = buildElementPositionsBelowAnchor();
662
+ }
663
+ const res = state.belowAnchorElementPositions.get(id);
664
+ if (res === void 0) {
665
+ throw new Error("Undefined position below achor");
666
+ }
667
+ return res;
668
+ };
669
+ const calculateItemsInView = useCallback((speed) => {
670
+ var _a2, _b2;
573
671
  const state = refState.current;
574
672
  const {
575
673
  data: data2,
576
674
  scrollLength,
577
675
  scroll: scrollState,
578
- startBuffered: startBufferedState,
676
+ startBufferedId: startBufferedIdOrig,
579
677
  positions,
580
- sizes,
581
- columns
678
+ columns,
679
+ scrollAdjustHandler
582
680
  } = state;
583
681
  if (state.animFrameLayout) {
584
682
  cancelAnimationFrame(state.animFrameLayout);
@@ -588,30 +686,35 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
588
686
  return;
589
687
  }
590
688
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
591
- const scrollAdjustPending = (_a2 = state.scrollAdjustPending) != null ? _a2 : 0;
689
+ const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
592
690
  const scrollExtra = Math.max(-16, Math.min(16, speed)) * 16;
593
- const scroll = Math.max(
594
- 0,
595
- scrollState - topPad - (USE_CONTENT_INSET ? scrollAdjustPending : 0) + scrollExtra
596
- );
691
+ const scroll = scrollState - previousScrollAdjust - topPad - scrollExtra;
597
692
  const scrollBottom = scroll + scrollLength;
598
693
  let startNoBuffer = null;
599
694
  let startBuffered = null;
695
+ let startBufferedId = null;
600
696
  let endNoBuffer = null;
601
697
  let endBuffered = null;
602
- let loopStart = startBufferedState || 0;
603
- if (startBufferedState) {
604
- for (let i = startBufferedState; i >= 0; i--) {
605
- const id = getId(i);
606
- const top2 = positions.get(id);
607
- if (top2 !== void 0) {
608
- const size = getItemSize(id, i, data2[i]);
609
- const bottom = top2 + size;
610
- if (bottom > scroll - scrollBuffer) {
611
- loopStart = i;
612
- } else {
613
- break;
614
- }
698
+ const originalStartId = startBufferedIdOrig && state.indexByKey.get(startBufferedIdOrig);
699
+ let loopStart = originalStartId || 0;
700
+ const anchorElementIndex = getAnchorElementIndex();
701
+ for (let i = loopStart; i >= 0; i--) {
702
+ const id = getId(i);
703
+ let newPosition;
704
+ if (maintainVisibleContentPosition && anchorElementIndex && i < anchorElementIndex) {
705
+ newPosition = getElementPositionBelowAchor(id);
706
+ if (newPosition !== void 0) {
707
+ positions.set(id, newPosition);
708
+ }
709
+ }
710
+ const top2 = newPosition || positions.get(id);
711
+ if (top2 !== void 0) {
712
+ const size = getItemSize(id, i, data2[i]);
713
+ const bottom = top2 + size;
714
+ if (bottom > scroll - scrollBuffer) {
715
+ loopStart = i;
716
+ } else {
717
+ break;
615
718
  }
616
719
  }
617
720
  }
@@ -620,13 +723,28 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
620
723
  if (loopStartMod > 0) {
621
724
  loopStart -= loopStartMod;
622
725
  }
623
- let top = loopStart > 0 ? positions.get(getId(loopStart)) : 0;
726
+ let top = void 0;
624
727
  let column = 1;
625
728
  let maxSizeInRow = 0;
729
+ const getInitialTop = (i) => {
730
+ var _a3;
731
+ const id = getId(i);
732
+ let topOffset = 0;
733
+ if (positions.get(id)) {
734
+ topOffset = positions.get(id);
735
+ }
736
+ if (id === ((_a3 = state.anchorElement) == null ? void 0 : _a3.id)) {
737
+ topOffset = initialContentOffset || 0;
738
+ }
739
+ return topOffset;
740
+ };
626
741
  for (let i = loopStart; i < data2.length; i++) {
627
742
  const id = getId(i);
628
743
  const size = getItemSize(id, i, data2[i]);
629
744
  maxSizeInRow = Math.max(maxSizeInRow, size);
745
+ if (top === void 0) {
746
+ top = getInitialTop(i);
747
+ }
630
748
  if (positions.get(id) !== top) {
631
749
  positions.set(id, top);
632
750
  }
@@ -638,6 +756,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
638
756
  }
639
757
  if (startBuffered === null && top + size > scroll - scrollBuffer) {
640
758
  startBuffered = i;
759
+ startBufferedId = id;
641
760
  }
642
761
  if (startNoBuffer !== null) {
643
762
  if (top <= scrollBottom) {
@@ -658,6 +777,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
658
777
  }
659
778
  Object.assign(refState.current, {
660
779
  startBuffered,
780
+ startBufferedId,
661
781
  startNoBuffer,
662
782
  endBuffered,
663
783
  endNoBuffer
@@ -676,7 +796,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
676
796
  }
677
797
  }
678
798
  if (!isContained) {
679
- const top2 = (positions.get(id) || 0) + scrollAdjustPending;
799
+ const top2 = positions.get(id) || 0;
680
800
  let furthestIndex = -1;
681
801
  let furthestDistance = 0;
682
802
  for (let u = 0; u < numContainers; u++) {
@@ -685,7 +805,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
685
805
  furthestIndex = u;
686
806
  break;
687
807
  }
688
- const index = (_b2 = refState.current) == null ? void 0 : _b2.indexByKey.get(key);
808
+ const index = (_a2 = refState.current) == null ? void 0 : _a2.indexByKey.get(key);
689
809
  const pos = peek$(ctx, `containerPosition${u}`);
690
810
  if (index < startBuffered || index > endBuffered) {
691
811
  const distance = Math.abs(pos - top2);
@@ -720,23 +840,23 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
720
840
  }
721
841
  for (let i = 0; i < numContainers; i++) {
722
842
  const itemKey = peek$(ctx, `containerItemKey${i}`);
723
- const itemIndex = (_c2 = refState.current) == null ? void 0 : _c2.indexByKey.get(itemKey);
843
+ const itemIndex = (_b2 = refState.current) == null ? void 0 : _b2.indexByKey.get(itemKey);
724
844
  const item = data2[itemIndex];
725
845
  if (item) {
726
846
  const id = getId(itemIndex);
727
847
  if (itemKey !== id || itemIndex < startBuffered || itemIndex > endBuffered) {
728
- const prevPos = peek$(ctx, `containerPosition${i}`) - scrollAdjustPending;
848
+ const prevPos = peek$(ctx, `containerPosition${i}`);
729
849
  const pos = positions.get(id) || 0;
730
- const size = sizes.get(id) || 0;
850
+ const size = getItemSize(id, itemIndex, data2[i]);
731
851
  if (pos + size >= scroll && pos <= scrollBottom || prevPos + size >= scroll && prevPos <= scrollBottom) {
732
852
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
733
853
  }
734
854
  } else {
735
- const pos = (positions.get(id) || 0) + scrollAdjustPending;
855
+ const pos = positions.get(id) || 0;
736
856
  const column2 = columns.get(id) || 1;
737
857
  const prevPos = peek$(ctx, `containerPosition${i}`);
738
858
  const prevColumn = peek$(ctx, `containerColumn${i}`);
739
- if (pos >= 0 && pos !== prevPos) {
859
+ if (pos > POSITION_OUT_OF_VIEW && pos !== prevPos) {
740
860
  set$(ctx, `containerPosition${i}`, pos);
741
861
  }
742
862
  if (column2 >= 0 && column2 !== prevColumn) {
@@ -808,17 +928,20 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
808
928
  return;
809
929
  }
810
930
  const { scrollLength, scroll } = refState.current;
811
- const scrollAdjust = peek$(ctx, "scrollAdjust") || 0;
812
- const distanceFromTop = scroll - scrollAdjust;
931
+ const distanceFromTop = scroll;
813
932
  refState.current.isAtTop = distanceFromTop < 0;
814
933
  if (onStartReached) {
815
- if (!refState.current.isStartReached) {
934
+ if (!refState.current.isStartReached && !refState.current.startReachedBlockedByTimer) {
816
935
  if (distanceFromTop < onStartReachedThreshold * scrollLength) {
817
936
  refState.current.isStartReached = true;
818
937
  onStartReached({ distanceFromStart: scroll });
938
+ refState.current.startReachedBlockedByTimer = true;
939
+ setTimeout(() => {
940
+ refState.current.startReachedBlockedByTimer = false;
941
+ }, 700);
819
942
  }
820
943
  } else {
821
- if (distanceFromTop >= onStartReachedThreshold * scrollLength) {
944
+ if (distanceFromTop >= 1.3 * onStartReachedThreshold * scrollLength) {
822
945
  refState.current.isStartReached = false;
823
946
  }
824
947
  }
@@ -832,43 +955,36 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
832
955
  }
833
956
  refState.current.data = data;
834
957
  let totalSize = 0;
958
+ let totalSizeBelowIndex = 0;
835
959
  const indexByKey = /* @__PURE__ */ new Map();
836
960
  let column = 1;
837
961
  let maxSizeInRow = 0;
838
962
  for (let i = 0; i < data.length; i++) {
839
963
  const key = getId(i);
840
964
  indexByKey.set(key, i);
965
+ }
966
+ refState.current.indexByKey = indexByKey;
967
+ const anchorElementIndex = getAnchorElementIndex();
968
+ for (let i = 0; i < data.length; i++) {
969
+ const key = getId(i);
841
970
  const size = getItemSize(key, i, data[i]);
842
971
  maxSizeInRow = Math.max(maxSizeInRow, size);
843
- if (maintainVisibleContentPosition && i < refState.current.startNoBuffer && !refState.current.indexByKey.has(key)) {
844
- const size2 = getItemSize(key, i, data[i]);
845
- adjustScroll(size2);
846
- }
847
972
  column++;
848
973
  if (column > numColumnsProp) {
974
+ if (maintainVisibleContentPosition && anchorElementIndex !== void 0 && i < anchorElementIndex) {
975
+ totalSizeBelowIndex += maxSizeInRow;
976
+ }
849
977
  totalSize += maxSizeInRow;
850
978
  column = 1;
851
979
  maxSizeInRow = 0;
852
980
  }
853
981
  }
854
- addTotalSize(null, totalSize);
855
- if (maintainVisibleContentPosition) {
856
- for (const [key, index] of refState.current.indexByKey) {
857
- if (index < refState.current.startNoBuffer && !indexByKey.has(key)) {
858
- const size = (_a = refState.current.sizes.get(key)) != null ? _a : 0;
859
- if (size) {
860
- adjustScroll(-size);
861
- }
862
- }
863
- }
864
- }
865
- refState.current.indexByKey = indexByKey;
982
+ addTotalSize(null, totalSize, totalSizeBelowIndex);
866
983
  if (!isFirst) {
867
- refState.current.isEndReached = false;
868
984
  const numContainers = peek$(ctx, "numContainers");
869
985
  for (let i = 0; i < numContainers; i++) {
870
986
  const itemKey = peek$(ctx, `containerItemKey${i}`);
871
- if (!keyExtractorProp || itemKey && ((_b = refState.current) == null ? void 0 : _b.indexByKey.get(itemKey)) === void 0) {
987
+ if (!keyExtractorProp || itemKey && ((_a = refState.current) == null ? void 0 : _a.indexByKey.get(itemKey)) === void 0) {
872
988
  set$(ctx, `containerItemKey${i}`, void 0);
873
989
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
874
990
  set$(ctx, `containerColumn${i}`, -1);
@@ -878,10 +994,12 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
878
994
  refState.current.sizes.clear();
879
995
  refState.current.positions;
880
996
  }
881
- calculateItemsInView();
882
- doMaintainScrollAtEnd(false);
883
- checkAtTop();
884
- checkAtBottom();
997
+ setTimeout(() => {
998
+ calculateItemsInView(refState.current.scrollVelocity);
999
+ doMaintainScrollAtEnd(false);
1000
+ checkAtTop();
1001
+ checkAtBottom();
1002
+ }, 0);
885
1003
  }
886
1004
  }
887
1005
  refState.current.renderItem = renderItem;
@@ -890,7 +1008,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
890
1008
  set$(
891
1009
  ctx,
892
1010
  "stylePaddingTop",
893
- (_f = (_e = (_c = StyleSheet.flatten(style)) == null ? void 0 : _c.paddingTop) != null ? _e : (_d = StyleSheet.flatten(contentContainerStyle)) == null ? void 0 : _d.paddingTop) != null ? _f : 0
1011
+ (_e = (_d = (_b = StyleSheet.flatten(style)) == null ? void 0 : _b.paddingTop) != null ? _d : (_c = StyleSheet.flatten(contentContainerStyle)) == null ? void 0 : _c.paddingTop) != null ? _e : 0
894
1012
  );
895
1013
  const getRenderedItem = useCallback((key, containerId) => {
896
1014
  var _a2, _b2;
@@ -999,7 +1117,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
999
1117
  }
1000
1118
  set$(ctx, "numContainers", numContainers);
1001
1119
  set$(ctx, "numContainersPooled", numContainers * 2);
1002
- calculateItemsInView();
1120
+ calculateItemsInView(refState.current.scrollVelocity);
1003
1121
  });
1004
1122
  const updateItemSize = useCallback((containerId, itemKey, size) => {
1005
1123
  var _a2;
@@ -1010,21 +1128,16 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1010
1128
  const state = refState.current;
1011
1129
  const { sizes, indexByKey, idsInFirstRender, columns, sizesLaidOut } = state;
1012
1130
  const index = indexByKey.get(itemKey);
1013
- const wasInFirstRender = idsInFirstRender.has(itemKey);
1014
- const prevSize = sizes.get(itemKey) || (wasInFirstRender ? getItemSize(itemKey, index, data2[index]) : 0);
1131
+ const numColumns = peek$(ctx, "numColumns");
1132
+ const row = Math.floor(index / numColumns);
1133
+ const prevSize = getRowHeight(row);
1015
1134
  if (!prevSize || Math.abs(prevSize - size) > 0.5) {
1016
1135
  let diff;
1017
- const numColumns = peek$(ctx, "numColumns");
1018
1136
  if (numColumns > 1) {
1137
+ const prevMaxSizeInRow = getRowHeight(row);
1138
+ sizes.set(itemKey, size);
1019
1139
  const column = columns.get(itemKey);
1020
1140
  const loopStart = index - (column - 1);
1021
- let prevMaxSizeInRow = 0;
1022
- for (let i = loopStart; i < loopStart + numColumns; i++) {
1023
- const id = getId(i);
1024
- const size2 = getItemSize(id, i, data2[i]);
1025
- prevMaxSizeInRow = Math.max(prevMaxSizeInRow, size2);
1026
- }
1027
- sizes.set(itemKey, size);
1028
1141
  let nextMaxSizeInRow = 0;
1029
1142
  for (let i = loopStart; i < loopStart + numColumns; i++) {
1030
1143
  const id = getId(i);
@@ -1055,7 +1168,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1055
1168
  );
1056
1169
  }, 1e3);
1057
1170
  }
1058
- addTotalSize(itemKey, diff);
1171
+ addTotalSize(itemKey, diff, 0);
1059
1172
  doMaintainScrollAtEnd(true);
1060
1173
  const scrollVelocity = state.scrollVelocity;
1061
1174
  if (!state.animFrameLayout && (Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1)) {
@@ -1071,18 +1184,12 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1071
1184
  }
1072
1185
  }, []);
1073
1186
  const handleScrollDebounced = useCallback((velocity) => {
1074
- var _a2, _b2;
1075
- const scrollAdjustPending = (_b2 = (_a2 = refState.current) == null ? void 0 : _a2.scrollAdjustPending) != null ? _b2 : 0;
1076
- set$(ctx, "scrollAdjust", scrollAdjustPending);
1077
1187
  calculateItemsInView(velocity);
1078
1188
  checkAtBottom();
1079
1189
  checkAtTop();
1080
1190
  }, []);
1081
1191
  const onLayout = useCallback((event) => {
1082
- let scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
1083
- if (!USE_CONTENT_INSET) {
1084
- scrollLength += event.nativeEvent.layout[horizontal ? "x" : "y"];
1085
- }
1192
+ const scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
1086
1193
  refState.current.scrollLength = scrollLength;
1087
1194
  if (refState.current.hasScrolled) {
1088
1195
  doMaintainScrollAtEnd(false);
@@ -1172,7 +1279,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1172
1279
  },
1173
1280
  []
1174
1281
  );
1175
- return /* @__PURE__ */ React5.createElement(
1282
+ return /* @__PURE__ */ React4.createElement(
1176
1283
  ListComponent,
1177
1284
  {
1178
1285
  ...rest,
@@ -1185,8 +1292,8 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1185
1292
  onLayout,
1186
1293
  recycleItems,
1187
1294
  alignItemsAtEnd,
1188
- addTotalSize,
1189
1295
  ListEmptyComponent: data.length === 0 ? ListEmptyComponent : void 0,
1296
+ maintainVisibleContentPosition,
1190
1297
  style
1191
1298
  }
1192
1299
  );