@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.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var React5 = require('react');
3
+ var React4 = require('react');
4
4
  var reactNative = require('react-native');
5
5
 
6
6
  function _interopNamespace(e) {
@@ -21,13 +21,12 @@ function _interopNamespace(e) {
21
21
  return Object.freeze(n);
22
22
  }
23
23
 
24
- var React5__namespace = /*#__PURE__*/_interopNamespace(React5);
24
+ var React4__namespace = /*#__PURE__*/_interopNamespace(React4);
25
25
 
26
26
  // src/LegendList.tsx
27
- var USE_CONTENT_INSET = reactNative.Platform.OS === "ios";
28
- var ContextState = React5__namespace.createContext(null);
27
+ var ContextState = React4__namespace.createContext(null);
29
28
  function StateProvider({ children }) {
30
- const [value] = React5__namespace.useState(() => ({
29
+ const [value] = React4__namespace.useState(() => ({
31
30
  listeners: /* @__PURE__ */ new Map(),
32
31
  values: /* @__PURE__ */ new Map(),
33
32
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
@@ -35,14 +34,14 @@ function StateProvider({ children }) {
35
34
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
36
35
  mapViewabilityAmountValues: /* @__PURE__ */ new Map()
37
36
  }));
38
- return /* @__PURE__ */ React5__namespace.createElement(ContextState.Provider, { value }, children);
37
+ return /* @__PURE__ */ React4__namespace.createElement(ContextState.Provider, { value }, children);
39
38
  }
40
39
  function useStateContext() {
41
- return React5__namespace.useContext(ContextState);
40
+ return React4__namespace.useContext(ContextState);
42
41
  }
43
42
  function use$(signalName) {
44
- const ctx = React5__namespace.useContext(ContextState);
45
- const value = React5.useSyncExternalStore(
43
+ const ctx = React4__namespace.useContext(ContextState);
44
+ const value = React4.useSyncExternalStore(
46
45
  (onStoreChange) => listen$(ctx, signalName, onStoreChange),
47
46
  () => ctx.values.get(signalName)
48
47
  );
@@ -74,25 +73,6 @@ function set$(ctx, signalName, value) {
74
73
  }
75
74
  }
76
75
  }
77
-
78
- // src/$ScrollView.tsx
79
- var OFFSET_TEST = 0;
80
- var $ScrollView = React5__namespace.forwardRef(function $ScrollView2(props, ref) {
81
- const { style, horizontal, ...rest } = props;
82
- const scrollAdjust = use$("scrollAdjust");
83
- const adjustProps = {};
84
- if (scrollAdjust !== 0) {
85
- if (USE_CONTENT_INSET) {
86
- adjustProps.contentInset = horizontal ? { left: -scrollAdjust } : { top: -scrollAdjust + OFFSET_TEST };
87
- } else {
88
- adjustProps.style = horizontal ? { marginLeft: -scrollAdjust } : { marginTop: -scrollAdjust };
89
- if (style) {
90
- adjustProps.style = reactNative.StyleSheet.compose(style, adjustProps.style);
91
- }
92
- }
93
- }
94
- return /* @__PURE__ */ React5__namespace.createElement(reactNative.ScrollView, { ...rest, style, horizontal, ...adjustProps, ref });
95
- });
96
76
  var Container = ({
97
77
  id,
98
78
  recycleItems,
@@ -108,31 +88,34 @@ var Container = ({
108
88
  const numColumns = use$("numColumns");
109
89
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
110
90
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
111
- const style = horizontal ? {
91
+ let style = horizontal ? {
112
92
  flexDirection: "row",
113
93
  position: "absolute",
114
- top: visible ? otherAxisPos : -1e7,
94
+ top: otherAxisPos,
115
95
  bottom: numColumns > 1 ? null : 0,
116
96
  height: otherAxisSize,
117
97
  left: position
118
98
  } : {
119
99
  position: "absolute",
120
- left: visible ? otherAxisPos : -1e7,
100
+ left: otherAxisPos,
121
101
  right: numColumns > 1 ? null : 0,
122
102
  width: otherAxisSize,
123
103
  top: position
124
104
  };
105
+ {
106
+ style.opacity = visible ? 1 : 0;
107
+ }
125
108
  const lastItemKey = use$("lastItemKey");
126
109
  const itemKey = use$(`containerItemKey${id}`);
127
- const renderedItem = React5.useMemo(() => itemKey !== void 0 && getRenderedItem(itemKey, id), [itemKey]);
128
- return /* @__PURE__ */ React5__namespace.default.createElement(
110
+ const renderedItem = React4.useMemo(() => itemKey !== void 0 && getRenderedItem(itemKey, id), [itemKey]);
111
+ return /* @__PURE__ */ React4__namespace.default.createElement(
129
112
  reactNative.View,
130
113
  {
131
114
  style,
132
115
  onLayout: (event) => {
133
116
  const key = peek$(ctx, `containerItemKey${id}`);
134
117
  if (key !== void 0) {
135
- const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
118
+ const size = Math.floor(event.nativeEvent.layout[horizontal ? "width" : "height"] * 8) / 8;
136
119
  updateItemSize(id, key, size);
137
120
  const otherAxisSize2 = horizontal ? event.nativeEvent.layout.width : event.nativeEvent.layout.height;
138
121
  set$(ctx, "otherAxisSize", Math.max(otherAxisSize2, peek$(ctx, "otherAxisSize") || 0));
@@ -145,37 +128,36 @@ var Container = ({
145
128
  }
146
129
  }
147
130
  },
148
- /* @__PURE__ */ React5__namespace.default.createElement(React5__namespace.default.Fragment, { key: recycleItems ? void 0 : itemKey }, renderedItem, renderedItem && ItemSeparatorComponent && itemKey !== lastItemKey && ItemSeparatorComponent)
131
+ /* @__PURE__ */ React4__namespace.default.createElement(React4__namespace.default.Fragment, { key: recycleItems ? void 0 : itemKey }, renderedItem, renderedItem && ItemSeparatorComponent && itemKey !== lastItemKey && ItemSeparatorComponent)
149
132
  );
150
133
  };
151
134
  var useAnimatedValue = reactNative.useAnimatedValue || ((initialValue) => {
152
- return React5.useRef(new reactNative.Animated.Value(initialValue)).current;
135
+ return React4.useRef(new reactNative.Animated.Value(initialValue)).current;
153
136
  });
154
137
  function useValue$(key, getValue, key2) {
155
138
  var _a;
156
139
  const ctx = useStateContext();
157
- const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
158
- React5.useMemo(() => {
159
- listen$(ctx, key, (v) => animValue.setValue(getValue ? getValue(v) : v));
140
+ const animValue = useAnimatedValue((_a = peek$(ctx, key)) != null ? _a : 0);
141
+ React4.useMemo(() => {
142
+ listen$(ctx, key, (v) => animValue.setValue(v));
160
143
  }, []);
161
144
  return animValue;
162
145
  }
163
146
 
164
147
  // src/Containers.tsx
165
- var Containers = React5__namespace.memo(function Containers2({
148
+ var Containers = React4__namespace.memo(function Containers2({
166
149
  horizontal,
167
150
  recycleItems,
168
151
  ItemSeparatorComponent,
169
152
  updateItemSize,
170
153
  getRenderedItem
171
154
  }) {
172
- const ctx = useStateContext();
173
155
  const numContainers = use$("numContainersPooled");
174
- const animSize = useValue$("totalSize", (v) => v + peek$(ctx, "scrollAdjust"));
156
+ const animSize = useValue$("totalSize");
175
157
  const containers = [];
176
158
  for (let i = 0; i < numContainers; i++) {
177
159
  containers.push(
178
- /* @__PURE__ */ React5__namespace.createElement(
160
+ /* @__PURE__ */ React4__namespace.createElement(
179
161
  Container,
180
162
  {
181
163
  id: i,
@@ -190,20 +172,20 @@ var Containers = React5__namespace.memo(function Containers2({
190
172
  );
191
173
  }
192
174
  const style = horizontal ? { width: animSize } : { height: animSize };
193
- return /* @__PURE__ */ React5__namespace.createElement(reactNative.Animated.View, { style }, containers);
175
+ return /* @__PURE__ */ React4__namespace.createElement(reactNative.Animated.View, { style }, containers);
194
176
  });
195
177
 
196
178
  // src/ListComponent.tsx
197
179
  var getComponent = (Component) => {
198
- if (React5__namespace.isValidElement(Component)) {
180
+ if (React4__namespace.isValidElement(Component)) {
199
181
  return Component;
200
182
  }
201
183
  if (Component) {
202
- return /* @__PURE__ */ React5__namespace.createElement(Component, null);
184
+ return /* @__PURE__ */ React4__namespace.createElement(Component, null);
203
185
  }
204
186
  return null;
205
187
  };
206
- var ListComponent = React5__namespace.memo(function ListComponent2({
188
+ var ListComponent = React4__namespace.memo(function ListComponent2({
207
189
  style,
208
190
  contentContainerStyle,
209
191
  horizontal,
@@ -221,18 +203,20 @@ var ListComponent = React5__namespace.memo(function ListComponent2({
221
203
  ListEmptyComponentStyle,
222
204
  getRenderedItem,
223
205
  updateItemSize,
224
- addTotalSize,
225
206
  refScroller,
207
+ maintainVisibleContentPosition,
226
208
  ...rest
227
209
  }) {
228
210
  const ctx = useStateContext();
229
211
  const animPaddingTop = useValue$("paddingTop");
230
212
  const animScrollAdjust = useValue$("scrollAdjust");
231
- return /* @__PURE__ */ React5__namespace.createElement(
232
- $ScrollView,
213
+ const additionalSize = { marginTop: animScrollAdjust, paddingTop: animPaddingTop };
214
+ return /* @__PURE__ */ React4__namespace.createElement(
215
+ reactNative.ScrollView,
233
216
  {
234
217
  ...rest,
235
218
  style,
219
+ maintainVisibleContentPosition: maintainVisibleContentPosition ? { minIndexForVisible: 0 } : void 0,
236
220
  contentContainerStyle: [
237
221
  contentContainerStyle,
238
222
  horizontal ? {
@@ -245,13 +229,11 @@ var ListComponent = React5__namespace.memo(function ListComponent2({
245
229
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
246
230
  ref: refScroller
247
231
  },
248
- alignItemsAtEnd && /* @__PURE__ */ React5__namespace.createElement(reactNative.Animated.View, { style: { height: animPaddingTop } }),
249
- ListHeaderComponent && /* @__PURE__ */ React5__namespace.createElement(
232
+ /* @__PURE__ */ React4__namespace.createElement(reactNative.Animated.View, { style: additionalSize }),
233
+ ListHeaderComponent && /* @__PURE__ */ React4__namespace.createElement(
250
234
  reactNative.Animated.View,
251
235
  {
252
- style: reactNative.StyleSheet.compose(ListHeaderComponentStyle, {
253
- top: animScrollAdjust
254
- }),
236
+ style: ListHeaderComponentStyle,
255
237
  onLayout: (event) => {
256
238
  const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
257
239
  const prevSize = peek$(ctx, "headerSize") || 0;
@@ -262,16 +244,8 @@ var ListComponent = React5__namespace.memo(function ListComponent2({
262
244
  },
263
245
  getComponent(ListHeaderComponent)
264
246
  ),
265
- ListEmptyComponent && /* @__PURE__ */ React5__namespace.createElement(
266
- reactNative.Animated.View,
267
- {
268
- style: reactNative.StyleSheet.compose(ListEmptyComponentStyle, {
269
- top: animScrollAdjust
270
- })
271
- },
272
- getComponent(ListEmptyComponent)
273
- ),
274
- /* @__PURE__ */ React5__namespace.createElement(
247
+ ListEmptyComponent && /* @__PURE__ */ React4__namespace.createElement(reactNative.Animated.View, { style: ListEmptyComponentStyle }, getComponent(ListEmptyComponent)),
248
+ /* @__PURE__ */ React4__namespace.createElement(
275
249
  Containers,
276
250
  {
277
251
  horizontal,
@@ -281,12 +255,49 @@ var ListComponent = React5__namespace.memo(function ListComponent2({
281
255
  updateItemSize
282
256
  }
283
257
  ),
284
- ListFooterComponent && /* @__PURE__ */ React5__namespace.createElement(reactNative.View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
258
+ ListFooterComponent && /* @__PURE__ */ React4__namespace.createElement(reactNative.View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
285
259
  );
286
260
  });
261
+
262
+ // src/ScrollAdjustHandler.ts
263
+ var ScrollAdjustHandler = class {
264
+ constructor(ctx) {
265
+ this.ctx = ctx;
266
+ this.appliedAdjust = 0;
267
+ this.pendingAdjust = 0;
268
+ this.busy = false;
269
+ this.firstAdjust = true;
270
+ this.context = ctx;
271
+ }
272
+ requestAdjust(adjust, onAdjusted) {
273
+ const oldAdjustTop = peek$(this.context, "scrollAdjust");
274
+ if (oldAdjustTop === adjust) {
275
+ return;
276
+ }
277
+ this.appliedAdjust = adjust;
278
+ this.pendingAdjust = adjust;
279
+ const doAjdust = () => {
280
+ set$(this.context, "scrollAdjust", this.pendingAdjust);
281
+ onAdjusted(oldAdjustTop - this.pendingAdjust);
282
+ this.busy = false;
283
+ };
284
+ if (!this.busy) {
285
+ this.busy = true;
286
+ if (this.firstAdjust) {
287
+ this.firstAdjust = false;
288
+ setTimeout(doAjdust, 50);
289
+ } else {
290
+ doAjdust();
291
+ }
292
+ }
293
+ }
294
+ getAppliedAdjust() {
295
+ return this.appliedAdjust;
296
+ }
297
+ };
287
298
  var symbolFirst = Symbol();
288
299
  function useInit(cb) {
289
- const refValue = React5.useRef(symbolFirst);
300
+ const refValue = React4.useRef(symbolFirst);
290
301
  if (refValue.current === symbolFirst) {
291
302
  refValue.current = cb();
292
303
  }
@@ -442,14 +453,13 @@ function maybeUpdateViewabilityCallback(ctx, configId, viewToken) {
442
453
 
443
454
  // src/LegendList.tsx
444
455
  var DEFAULT_DRAW_DISTANCE = 250;
445
- var INITIAL_SCROLL_ADJUST = 1e4;
446
456
  var POSITION_OUT_OF_VIEW = -1e7;
447
457
  var DEFAULT_ITEM_SIZE = 100;
448
- var LegendList = React5.forwardRef(function LegendList2(props, forwardedRef) {
449
- return /* @__PURE__ */ React5__namespace.createElement(StateProvider, null, /* @__PURE__ */ React5__namespace.createElement(LegendListInner, { ...props, ref: forwardedRef }));
458
+ var LegendList = React4.forwardRef(function LegendList2(props, forwardedRef) {
459
+ return /* @__PURE__ */ React4__namespace.createElement(StateProvider, null, /* @__PURE__ */ React4__namespace.createElement(LegendListInner, { ...props, ref: forwardedRef }));
450
460
  });
451
- var LegendListInner = React5.forwardRef(function LegendListInner2(props, forwardedRef) {
452
- var _a, _b, _c, _d, _e, _f;
461
+ var LegendListInner = React4.forwardRef(function LegendListInner2(props, forwardedRef) {
462
+ var _a, _b, _c, _d, _e;
453
463
  const {
454
464
  data,
455
465
  initialScrollIndex,
@@ -477,11 +487,11 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
477
487
  } = props;
478
488
  const { style, contentContainerStyle } = props;
479
489
  const ctx = useStateContext();
480
- const internalRef = React5.useRef(null);
490
+ const internalRef = React4.useRef(null);
481
491
  const refScroller = internalRef;
482
492
  const scrollBuffer = drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE;
483
493
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (item, index) => index.toString();
484
- const refState = React5.useRef();
494
+ const refState = React4.useRef();
485
495
  const getId = (index) => {
486
496
  var _a2;
487
497
  const data2 = (_a2 = refState.current) == null ? void 0 : _a2.data;
@@ -511,37 +521,38 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
511
521
  } else if (estimatedItemSize) {
512
522
  offset = index * estimatedItemSize;
513
523
  }
514
- return offset + (maintainVisibleContentPosition ? INITIAL_SCROLL_ADJUST : 0);
524
+ return offset / numColumnsProp;
515
525
  }
516
- return void 0;
526
+ return 0;
517
527
  };
518
- const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : React5.useMemo(calculateInitialOffset, []);
528
+ const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : React4.useMemo(calculateInitialOffset, []);
519
529
  if (!refState.current) {
530
+ const initialScrollLength = reactNative.Dimensions.get("window")[horizontal ? "width" : "height"];
520
531
  refState.current = {
521
532
  sizes: /* @__PURE__ */ new Map(),
522
533
  positions: /* @__PURE__ */ new Map(),
523
534
  columns: /* @__PURE__ */ new Map(),
524
535
  pendingAdjust: 0,
525
536
  animFrameLayout: null,
526
- animFrameTotalSize: null,
527
- isStartReached: true,
537
+ isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
528
538
  isEndReached: false,
529
539
  isAtBottom: false,
530
540
  isAtTop: false,
531
541
  data,
532
542
  idsInFirstRender: void 0,
533
543
  hasScrolled: false,
534
- scrollLength: reactNative.Dimensions.get("window")[horizontal ? "width" : "height"],
544
+ scrollLength: initialScrollLength,
535
545
  startBuffered: 0,
536
546
  startNoBuffer: 0,
537
547
  endBuffered: 0,
538
548
  endNoBuffer: 0,
539
549
  scroll: initialContentOffset || 0,
540
550
  totalSize: 0,
551
+ totalSizeBelowAnchor: 0,
541
552
  timeouts: /* @__PURE__ */ new Set(),
542
553
  viewabilityConfigCallbackPairs: void 0,
543
554
  renderItem: void 0,
544
- scrollAdjustPending: maintainVisibleContentPosition ? INITIAL_SCROLL_ADJUST : 0,
555
+ scrollAdjustHandler: new ScrollAdjustHandler(ctx),
545
556
  nativeMarginTop: 0,
546
557
  scrollPrev: 0,
547
558
  scrollPrevTime: 0,
@@ -552,54 +563,141 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
552
563
  contentSize: { width: 0, height: 0 },
553
564
  sizesLaidOut: __DEV__ ? /* @__PURE__ */ new Map() : void 0,
554
565
  timeoutSizeMessage: 0,
555
- scrollTimer: void 0
566
+ scrollTimer: void 0,
567
+ belowAnchorElementPositions: void 0,
568
+ rowHeights: /* @__PURE__ */ new Map(),
569
+ startReachedBlockedByTimer: false
556
570
  };
557
571
  refState.current.idsInFirstRender = new Set(data.map((_, i) => getId(i)));
558
- set$(ctx, "scrollAdjust", refState.current.scrollAdjustPending);
572
+ if (maintainVisibleContentPosition) {
573
+ if (initialScrollIndex) {
574
+ refState.current.anchorElement = {
575
+ coordinate: initialContentOffset,
576
+ id: getId(initialScrollIndex)
577
+ };
578
+ } else if (data.length) {
579
+ refState.current.anchorElement = {
580
+ coordinate: initialContentOffset,
581
+ id: getId(0)
582
+ };
583
+ } else {
584
+ console.warn("[legend-list] maintainVisibleContentPosition was not able to find an anchor element");
585
+ }
586
+ }
587
+ set$(ctx, "scrollAdjust", 0);
559
588
  }
560
- const adjustScroll = (diff) => {
561
- if (maintainVisibleContentPosition && refScroller.current) {
562
- refState.current.scrollAdjustPending -= diff;
589
+ const getAnchorElementIndex = () => {
590
+ const state = refState.current;
591
+ if (state.anchorElement) {
592
+ const el = state.indexByKey.get(state.anchorElement.id);
593
+ return el;
563
594
  }
595
+ return void 0;
564
596
  };
565
- const addTotalSize = React5.useCallback((key, add) => {
597
+ const addTotalSize = React4.useCallback((key, add, totalSizeBelowAnchor) => {
566
598
  const state = refState.current;
567
599
  const index = key === null ? 0 : state.indexByKey.get(key);
568
- const isAbove = key !== null && index < (state.startNoBuffer || 0);
569
- const prev = state.totalSize;
600
+ let isAboveAnchor = false;
601
+ if (maintainVisibleContentPosition) {
602
+ if (state.anchorElement && index < getAnchorElementIndex()) {
603
+ isAboveAnchor = true;
604
+ }
605
+ }
606
+ state.totalSize;
570
607
  if (key === null) {
571
608
  state.totalSize = add;
609
+ state.totalSizeBelowAnchor = totalSizeBelowAnchor;
572
610
  } else {
573
611
  state.totalSize += add;
612
+ if (isAboveAnchor) {
613
+ state.totalSizeBelowAnchor += add;
614
+ }
615
+ }
616
+ let applyAdjustValue = void 0;
617
+ if (maintainVisibleContentPosition) {
618
+ const newAdjust = state.anchorElement.coordinate - state.totalSizeBelowAnchor;
619
+ applyAdjustValue = -newAdjust;
620
+ state.belowAnchorElementPositions = buildElementPositionsBelowAnchor();
621
+ state.rowHeights.clear();
574
622
  }
575
623
  const doAdd = () => {
576
624
  const totalSize = state.totalSize;
577
- state.animFrameTotalSize = null;
578
- set$(ctx, "totalSize", totalSize);
625
+ let resultSize = totalSize;
626
+ if (applyAdjustValue !== void 0) {
627
+ resultSize -= applyAdjustValue;
628
+ refState.current.scrollAdjustHandler.requestAdjust(applyAdjustValue, (diff) => {
629
+ state.scroll -= diff;
630
+ });
631
+ }
632
+ set$(ctx, "totalSize", resultSize);
579
633
  if (alignItemsAtEnd) {
580
634
  doUpdatePaddingTop();
581
635
  }
582
636
  };
583
- if (isAbove) {
584
- adjustScroll(add);
637
+ doAdd();
638
+ }, []);
639
+ const getRowHeight = (n) => {
640
+ const { rowHeights } = refState.current;
641
+ if (numColumnsProp === 1) {
642
+ const id = getId(n);
643
+ return getItemSize(id, n, data[n]);
585
644
  }
586
- if (!prev || key === null) {
587
- doAdd();
588
- } else if (!state.animFrameTotalSize) {
589
- state.animFrameTotalSize = requestAnimationFrame(doAdd);
645
+ if (rowHeights.has(n)) {
646
+ return rowHeights.get(n) || 0;
590
647
  }
591
- }, []);
592
- const calculateItemsInView = React5.useCallback((speed = 0) => {
593
- var _a2, _b2, _c2;
648
+ let rowHeight = 0;
649
+ const startEl = n * numColumnsProp;
650
+ for (let i = startEl; i < startEl + numColumnsProp; i++) {
651
+ const id = getId(i);
652
+ const size = getItemSize(id, i, data[i]);
653
+ rowHeight = Math.max(rowHeight, size);
654
+ }
655
+ rowHeights.set(n, rowHeight);
656
+ return rowHeight;
657
+ };
658
+ const buildElementPositionsBelowAnchor = () => {
659
+ const state = refState.current;
660
+ if (!state.anchorElement) {
661
+ return /* @__PURE__ */ new Map();
662
+ }
663
+ let top = state.anchorElement.coordinate;
664
+ const anchorIndex = state.indexByKey.get(state.anchorElement.id);
665
+ if (anchorIndex === 0) {
666
+ return /* @__PURE__ */ new Map();
667
+ }
668
+ const map = state.belowAnchorElementPositions || /* @__PURE__ */ new Map();
669
+ for (let i = anchorIndex - 1; i >= 0; i--) {
670
+ const id = getId(i);
671
+ const rowNumber = Math.floor(i / numColumnsProp);
672
+ if (i % numColumnsProp === 0) {
673
+ top -= getRowHeight(rowNumber);
674
+ }
675
+ map.set(id, top);
676
+ }
677
+ return map;
678
+ };
679
+ const getElementPositionBelowAchor = (id) => {
680
+ const state = refState.current;
681
+ if (!refState.current.belowAnchorElementPositions) {
682
+ state.belowAnchorElementPositions = buildElementPositionsBelowAnchor();
683
+ }
684
+ const res = state.belowAnchorElementPositions.get(id);
685
+ if (res === void 0) {
686
+ throw new Error("Undefined position below achor");
687
+ }
688
+ return res;
689
+ };
690
+ const calculateItemsInView = React4.useCallback((speed) => {
691
+ var _a2, _b2;
594
692
  const state = refState.current;
595
693
  const {
596
694
  data: data2,
597
695
  scrollLength,
598
696
  scroll: scrollState,
599
- startBuffered: startBufferedState,
697
+ startBufferedId: startBufferedIdOrig,
600
698
  positions,
601
- sizes,
602
- columns
699
+ columns,
700
+ scrollAdjustHandler
603
701
  } = state;
604
702
  if (state.animFrameLayout) {
605
703
  cancelAnimationFrame(state.animFrameLayout);
@@ -609,30 +707,35 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
609
707
  return;
610
708
  }
611
709
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
612
- const scrollAdjustPending = (_a2 = state.scrollAdjustPending) != null ? _a2 : 0;
710
+ const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
613
711
  const scrollExtra = Math.max(-16, Math.min(16, speed)) * 16;
614
- const scroll = Math.max(
615
- 0,
616
- scrollState - topPad - (USE_CONTENT_INSET ? scrollAdjustPending : 0) + scrollExtra
617
- );
712
+ const scroll = scrollState - previousScrollAdjust - topPad - scrollExtra;
618
713
  const scrollBottom = scroll + scrollLength;
619
714
  let startNoBuffer = null;
620
715
  let startBuffered = null;
716
+ let startBufferedId = null;
621
717
  let endNoBuffer = null;
622
718
  let endBuffered = null;
623
- let loopStart = startBufferedState || 0;
624
- if (startBufferedState) {
625
- for (let i = startBufferedState; i >= 0; i--) {
626
- const id = getId(i);
627
- const top2 = positions.get(id);
628
- if (top2 !== void 0) {
629
- const size = getItemSize(id, i, data2[i]);
630
- const bottom = top2 + size;
631
- if (bottom > scroll - scrollBuffer) {
632
- loopStart = i;
633
- } else {
634
- break;
635
- }
719
+ const originalStartId = startBufferedIdOrig && state.indexByKey.get(startBufferedIdOrig);
720
+ let loopStart = originalStartId || 0;
721
+ const anchorElementIndex = getAnchorElementIndex();
722
+ for (let i = loopStart; i >= 0; i--) {
723
+ const id = getId(i);
724
+ let newPosition;
725
+ if (maintainVisibleContentPosition && anchorElementIndex && i < anchorElementIndex) {
726
+ newPosition = getElementPositionBelowAchor(id);
727
+ if (newPosition !== void 0) {
728
+ positions.set(id, newPosition);
729
+ }
730
+ }
731
+ const top2 = newPosition || positions.get(id);
732
+ if (top2 !== void 0) {
733
+ const size = getItemSize(id, i, data2[i]);
734
+ const bottom = top2 + size;
735
+ if (bottom > scroll - scrollBuffer) {
736
+ loopStart = i;
737
+ } else {
738
+ break;
636
739
  }
637
740
  }
638
741
  }
@@ -641,13 +744,28 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
641
744
  if (loopStartMod > 0) {
642
745
  loopStart -= loopStartMod;
643
746
  }
644
- let top = loopStart > 0 ? positions.get(getId(loopStart)) : 0;
747
+ let top = void 0;
645
748
  let column = 1;
646
749
  let maxSizeInRow = 0;
750
+ const getInitialTop = (i) => {
751
+ var _a3;
752
+ const id = getId(i);
753
+ let topOffset = 0;
754
+ if (positions.get(id)) {
755
+ topOffset = positions.get(id);
756
+ }
757
+ if (id === ((_a3 = state.anchorElement) == null ? void 0 : _a3.id)) {
758
+ topOffset = initialContentOffset || 0;
759
+ }
760
+ return topOffset;
761
+ };
647
762
  for (let i = loopStart; i < data2.length; i++) {
648
763
  const id = getId(i);
649
764
  const size = getItemSize(id, i, data2[i]);
650
765
  maxSizeInRow = Math.max(maxSizeInRow, size);
766
+ if (top === void 0) {
767
+ top = getInitialTop(i);
768
+ }
651
769
  if (positions.get(id) !== top) {
652
770
  positions.set(id, top);
653
771
  }
@@ -659,6 +777,7 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
659
777
  }
660
778
  if (startBuffered === null && top + size > scroll - scrollBuffer) {
661
779
  startBuffered = i;
780
+ startBufferedId = id;
662
781
  }
663
782
  if (startNoBuffer !== null) {
664
783
  if (top <= scrollBottom) {
@@ -679,6 +798,7 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
679
798
  }
680
799
  Object.assign(refState.current, {
681
800
  startBuffered,
801
+ startBufferedId,
682
802
  startNoBuffer,
683
803
  endBuffered,
684
804
  endNoBuffer
@@ -697,7 +817,7 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
697
817
  }
698
818
  }
699
819
  if (!isContained) {
700
- const top2 = (positions.get(id) || 0) + scrollAdjustPending;
820
+ const top2 = positions.get(id) || 0;
701
821
  let furthestIndex = -1;
702
822
  let furthestDistance = 0;
703
823
  for (let u = 0; u < numContainers; u++) {
@@ -706,7 +826,7 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
706
826
  furthestIndex = u;
707
827
  break;
708
828
  }
709
- const index = (_b2 = refState.current) == null ? void 0 : _b2.indexByKey.get(key);
829
+ const index = (_a2 = refState.current) == null ? void 0 : _a2.indexByKey.get(key);
710
830
  const pos = peek$(ctx, `containerPosition${u}`);
711
831
  if (index < startBuffered || index > endBuffered) {
712
832
  const distance = Math.abs(pos - top2);
@@ -741,23 +861,23 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
741
861
  }
742
862
  for (let i = 0; i < numContainers; i++) {
743
863
  const itemKey = peek$(ctx, `containerItemKey${i}`);
744
- const itemIndex = (_c2 = refState.current) == null ? void 0 : _c2.indexByKey.get(itemKey);
864
+ const itemIndex = (_b2 = refState.current) == null ? void 0 : _b2.indexByKey.get(itemKey);
745
865
  const item = data2[itemIndex];
746
866
  if (item) {
747
867
  const id = getId(itemIndex);
748
868
  if (itemKey !== id || itemIndex < startBuffered || itemIndex > endBuffered) {
749
- const prevPos = peek$(ctx, `containerPosition${i}`) - scrollAdjustPending;
869
+ const prevPos = peek$(ctx, `containerPosition${i}`);
750
870
  const pos = positions.get(id) || 0;
751
- const size = sizes.get(id) || 0;
871
+ const size = getItemSize(id, itemIndex, data2[i]);
752
872
  if (pos + size >= scroll && pos <= scrollBottom || prevPos + size >= scroll && prevPos <= scrollBottom) {
753
873
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
754
874
  }
755
875
  } else {
756
- const pos = (positions.get(id) || 0) + scrollAdjustPending;
876
+ const pos = positions.get(id) || 0;
757
877
  const column2 = columns.get(id) || 1;
758
878
  const prevPos = peek$(ctx, `containerPosition${i}`);
759
879
  const prevColumn = peek$(ctx, `containerColumn${i}`);
760
- if (pos >= 0 && pos !== prevPos) {
880
+ if (pos > POSITION_OUT_OF_VIEW && pos !== prevPos) {
761
881
  set$(ctx, `containerPosition${i}`, pos);
762
882
  }
763
883
  if (column2 >= 0 && column2 !== prevColumn) {
@@ -829,17 +949,20 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
829
949
  return;
830
950
  }
831
951
  const { scrollLength, scroll } = refState.current;
832
- const scrollAdjust = peek$(ctx, "scrollAdjust") || 0;
833
- const distanceFromTop = scroll - scrollAdjust;
952
+ const distanceFromTop = scroll;
834
953
  refState.current.isAtTop = distanceFromTop < 0;
835
954
  if (onStartReached) {
836
- if (!refState.current.isStartReached) {
955
+ if (!refState.current.isStartReached && !refState.current.startReachedBlockedByTimer) {
837
956
  if (distanceFromTop < onStartReachedThreshold * scrollLength) {
838
957
  refState.current.isStartReached = true;
839
958
  onStartReached({ distanceFromStart: scroll });
959
+ refState.current.startReachedBlockedByTimer = true;
960
+ setTimeout(() => {
961
+ refState.current.startReachedBlockedByTimer = false;
962
+ }, 700);
840
963
  }
841
964
  } else {
842
- if (distanceFromTop >= onStartReachedThreshold * scrollLength) {
965
+ if (distanceFromTop >= 1.3 * onStartReachedThreshold * scrollLength) {
843
966
  refState.current.isStartReached = false;
844
967
  }
845
968
  }
@@ -853,43 +976,36 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
853
976
  }
854
977
  refState.current.data = data;
855
978
  let totalSize = 0;
979
+ let totalSizeBelowIndex = 0;
856
980
  const indexByKey = /* @__PURE__ */ new Map();
857
981
  let column = 1;
858
982
  let maxSizeInRow = 0;
859
983
  for (let i = 0; i < data.length; i++) {
860
984
  const key = getId(i);
861
985
  indexByKey.set(key, i);
986
+ }
987
+ refState.current.indexByKey = indexByKey;
988
+ const anchorElementIndex = getAnchorElementIndex();
989
+ for (let i = 0; i < data.length; i++) {
990
+ const key = getId(i);
862
991
  const size = getItemSize(key, i, data[i]);
863
992
  maxSizeInRow = Math.max(maxSizeInRow, size);
864
- if (maintainVisibleContentPosition && i < refState.current.startNoBuffer && !refState.current.indexByKey.has(key)) {
865
- const size2 = getItemSize(key, i, data[i]);
866
- adjustScroll(size2);
867
- }
868
993
  column++;
869
994
  if (column > numColumnsProp) {
995
+ if (maintainVisibleContentPosition && anchorElementIndex !== void 0 && i < anchorElementIndex) {
996
+ totalSizeBelowIndex += maxSizeInRow;
997
+ }
870
998
  totalSize += maxSizeInRow;
871
999
  column = 1;
872
1000
  maxSizeInRow = 0;
873
1001
  }
874
1002
  }
875
- addTotalSize(null, totalSize);
876
- if (maintainVisibleContentPosition) {
877
- for (const [key, index] of refState.current.indexByKey) {
878
- if (index < refState.current.startNoBuffer && !indexByKey.has(key)) {
879
- const size = (_a = refState.current.sizes.get(key)) != null ? _a : 0;
880
- if (size) {
881
- adjustScroll(-size);
882
- }
883
- }
884
- }
885
- }
886
- refState.current.indexByKey = indexByKey;
1003
+ addTotalSize(null, totalSize, totalSizeBelowIndex);
887
1004
  if (!isFirst) {
888
- refState.current.isEndReached = false;
889
1005
  const numContainers = peek$(ctx, "numContainers");
890
1006
  for (let i = 0; i < numContainers; i++) {
891
1007
  const itemKey = peek$(ctx, `containerItemKey${i}`);
892
- if (!keyExtractorProp || itemKey && ((_b = refState.current) == null ? void 0 : _b.indexByKey.get(itemKey)) === void 0) {
1008
+ if (!keyExtractorProp || itemKey && ((_a = refState.current) == null ? void 0 : _a.indexByKey.get(itemKey)) === void 0) {
893
1009
  set$(ctx, `containerItemKey${i}`, void 0);
894
1010
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
895
1011
  set$(ctx, `containerColumn${i}`, -1);
@@ -899,10 +1015,12 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
899
1015
  refState.current.sizes.clear();
900
1016
  refState.current.positions;
901
1017
  }
902
- calculateItemsInView();
903
- doMaintainScrollAtEnd(false);
904
- checkAtTop();
905
- checkAtBottom();
1018
+ setTimeout(() => {
1019
+ calculateItemsInView(refState.current.scrollVelocity);
1020
+ doMaintainScrollAtEnd(false);
1021
+ checkAtTop();
1022
+ checkAtBottom();
1023
+ }, 0);
906
1024
  }
907
1025
  }
908
1026
  refState.current.renderItem = renderItem;
@@ -911,9 +1029,9 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
911
1029
  set$(
912
1030
  ctx,
913
1031
  "stylePaddingTop",
914
- (_f = (_e = (_c = reactNative.StyleSheet.flatten(style)) == null ? void 0 : _c.paddingTop) != null ? _e : (_d = reactNative.StyleSheet.flatten(contentContainerStyle)) == null ? void 0 : _d.paddingTop) != null ? _f : 0
1032
+ (_e = (_d = (_b = reactNative.StyleSheet.flatten(style)) == null ? void 0 : _b.paddingTop) != null ? _d : (_c = reactNative.StyleSheet.flatten(contentContainerStyle)) == null ? void 0 : _c.paddingTop) != null ? _e : 0
915
1033
  );
916
- const getRenderedItem = React5.useCallback((key, containerId) => {
1034
+ const getRenderedItem = React4.useCallback((key, containerId) => {
917
1035
  var _a2, _b2;
918
1036
  const state = refState.current;
919
1037
  if (!state) {
@@ -933,7 +1051,7 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
933
1051
  }
934
1052
  });
935
1053
  ctx.mapViewabilityCallbacks.set(key2, callback);
936
- React5.useEffect(
1054
+ React4.useEffect(
937
1055
  () => () => {
938
1056
  ctx.mapViewabilityCallbacks.delete(key2);
939
1057
  },
@@ -948,7 +1066,7 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
948
1066
  }
949
1067
  });
950
1068
  ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
951
- React5.useEffect(
1069
+ React4.useEffect(
952
1070
  () => () => {
953
1071
  ctx.mapViewabilityAmountCallbacks.delete(containerId);
954
1072
  },
@@ -956,7 +1074,7 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
956
1074
  );
957
1075
  };
958
1076
  const useRecyclingEffect = (effect) => {
959
- React5.useEffect(() => {
1077
+ React4.useEffect(() => {
960
1078
  const state2 = refState.current;
961
1079
  let prevIndex = index;
962
1080
  let prevItem = state2.data[index];
@@ -984,7 +1102,7 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
984
1102
  }, []);
985
1103
  };
986
1104
  const useRecyclingState = (valueOrFun) => {
987
- const stateInfo = React5.useState(
1105
+ const stateInfo = React4.useState(
988
1106
  () => typeof valueOrFun === "function" ? valueOrFun({
989
1107
  index,
990
1108
  item: refState.current.data[index],
@@ -1020,9 +1138,9 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
1020
1138
  }
1021
1139
  set$(ctx, "numContainers", numContainers);
1022
1140
  set$(ctx, "numContainersPooled", numContainers * 2);
1023
- calculateItemsInView();
1141
+ calculateItemsInView(refState.current.scrollVelocity);
1024
1142
  });
1025
- const updateItemSize = React5.useCallback((containerId, itemKey, size) => {
1143
+ const updateItemSize = React4.useCallback((containerId, itemKey, size) => {
1026
1144
  var _a2;
1027
1145
  const data2 = (_a2 = refState.current) == null ? void 0 : _a2.data;
1028
1146
  if (!data2) {
@@ -1031,21 +1149,16 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
1031
1149
  const state = refState.current;
1032
1150
  const { sizes, indexByKey, idsInFirstRender, columns, sizesLaidOut } = state;
1033
1151
  const index = indexByKey.get(itemKey);
1034
- const wasInFirstRender = idsInFirstRender.has(itemKey);
1035
- const prevSize = sizes.get(itemKey) || (wasInFirstRender ? getItemSize(itemKey, index, data2[index]) : 0);
1152
+ const numColumns = peek$(ctx, "numColumns");
1153
+ const row = Math.floor(index / numColumns);
1154
+ const prevSize = getRowHeight(row);
1036
1155
  if (!prevSize || Math.abs(prevSize - size) > 0.5) {
1037
1156
  let diff;
1038
- const numColumns = peek$(ctx, "numColumns");
1039
1157
  if (numColumns > 1) {
1158
+ const prevMaxSizeInRow = getRowHeight(row);
1159
+ sizes.set(itemKey, size);
1040
1160
  const column = columns.get(itemKey);
1041
1161
  const loopStart = index - (column - 1);
1042
- let prevMaxSizeInRow = 0;
1043
- for (let i = loopStart; i < loopStart + numColumns; i++) {
1044
- const id = getId(i);
1045
- const size2 = getItemSize(id, i, data2[i]);
1046
- prevMaxSizeInRow = Math.max(prevMaxSizeInRow, size2);
1047
- }
1048
- sizes.set(itemKey, size);
1049
1162
  let nextMaxSizeInRow = 0;
1050
1163
  for (let i = loopStart; i < loopStart + numColumns; i++) {
1051
1164
  const id = getId(i);
@@ -1076,7 +1189,7 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
1076
1189
  );
1077
1190
  }, 1e3);
1078
1191
  }
1079
- addTotalSize(itemKey, diff);
1192
+ addTotalSize(itemKey, diff, 0);
1080
1193
  doMaintainScrollAtEnd(true);
1081
1194
  const scrollVelocity = state.scrollVelocity;
1082
1195
  if (!state.animFrameLayout && (Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1)) {
@@ -1091,19 +1204,13 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
1091
1204
  }
1092
1205
  }
1093
1206
  }, []);
1094
- const handleScrollDebounced = React5.useCallback((velocity) => {
1095
- var _a2, _b2;
1096
- const scrollAdjustPending = (_b2 = (_a2 = refState.current) == null ? void 0 : _a2.scrollAdjustPending) != null ? _b2 : 0;
1097
- set$(ctx, "scrollAdjust", scrollAdjustPending);
1207
+ const handleScrollDebounced = React4.useCallback((velocity) => {
1098
1208
  calculateItemsInView(velocity);
1099
1209
  checkAtBottom();
1100
1210
  checkAtTop();
1101
1211
  }, []);
1102
- const onLayout = React5.useCallback((event) => {
1103
- let scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
1104
- if (!USE_CONTENT_INSET) {
1105
- scrollLength += event.nativeEvent.layout[horizontal ? "x" : "y"];
1106
- }
1212
+ const onLayout = React4.useCallback((event) => {
1213
+ const scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
1107
1214
  refState.current.scrollLength = scrollLength;
1108
1215
  if (refState.current.hasScrolled) {
1109
1216
  doMaintainScrollAtEnd(false);
@@ -1121,7 +1228,7 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
1121
1228
  }
1122
1229
  }
1123
1230
  }, []);
1124
- const handleScroll = React5.useCallback(
1231
+ const handleScroll = React4.useCallback(
1125
1232
  (event, fromSelf) => {
1126
1233
  var _a2, _b2, _c2;
1127
1234
  if (((_b2 = (_a2 = event.nativeEvent) == null ? void 0 : _a2.contentSize) == null ? void 0 : _b2.height) === 0 && ((_c2 = event.nativeEvent.contentSize) == null ? void 0 : _c2.width) === 0) {
@@ -1164,7 +1271,7 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
1164
1271
  },
1165
1272
  []
1166
1273
  );
1167
- React5.useImperativeHandle(
1274
+ React4.useImperativeHandle(
1168
1275
  forwardedRef,
1169
1276
  () => {
1170
1277
  const scrollToIndex = ({ index, animated }) => {
@@ -1193,7 +1300,7 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
1193
1300
  },
1194
1301
  []
1195
1302
  );
1196
- return /* @__PURE__ */ React5__namespace.createElement(
1303
+ return /* @__PURE__ */ React4__namespace.createElement(
1197
1304
  ListComponent,
1198
1305
  {
1199
1306
  ...rest,
@@ -1206,8 +1313,8 @@ var LegendListInner = React5.forwardRef(function LegendListInner2(props, forward
1206
1313
  onLayout,
1207
1314
  recycleItems,
1208
1315
  alignItemsAtEnd,
1209
- addTotalSize,
1210
1316
  ListEmptyComponent: data.length === 0 ? ListEmptyComponent : void 0,
1317
+ maintainVisibleContentPosition,
1211
1318
  style
1212
1319
  }
1213
1320
  );