@legendapp/list 0.5.9 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.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,35 @@ 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
- const renderedItem = useMemo(() => itemKey !== void 0 && getRenderedItem(itemKey, id), [itemKey]);
107
- return /* @__PURE__ */ React5__default.createElement(
89
+ const data = use$(`containerItemData${id}`);
90
+ const renderedItem = useMemo(() => itemKey !== void 0 && getRenderedItem(itemKey, id), [itemKey, data]);
91
+ return /* @__PURE__ */ React4__default.createElement(
108
92
  View,
109
93
  {
110
94
  style,
111
95
  onLayout: (event) => {
112
96
  const key = peek$(ctx, `containerItemKey${id}`);
113
97
  if (key !== void 0) {
114
- const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
98
+ const size = Math.floor(event.nativeEvent.layout[horizontal ? "width" : "height"] * 8) / 8;
115
99
  updateItemSize(id, key, size);
116
100
  const otherAxisSize2 = horizontal ? event.nativeEvent.layout.width : event.nativeEvent.layout.height;
117
101
  set$(ctx, "otherAxisSize", Math.max(otherAxisSize2, peek$(ctx, "otherAxisSize") || 0));
@@ -124,7 +108,7 @@ var Container = ({
124
108
  }
125
109
  }
126
110
  },
127
- /* @__PURE__ */ React5__default.createElement(React5__default.Fragment, { key: recycleItems ? void 0 : itemKey }, renderedItem, renderedItem && ItemSeparatorComponent && itemKey !== lastItemKey && ItemSeparatorComponent)
111
+ /* @__PURE__ */ React4__default.createElement(React4__default.Fragment, { key: recycleItems ? void 0 : itemKey }, renderedItem, renderedItem && ItemSeparatorComponent && itemKey !== lastItemKey && ItemSeparatorComponent)
128
112
  );
129
113
  };
130
114
  var useAnimatedValue = useAnimatedValue$1 || ((initialValue) => {
@@ -133,28 +117,27 @@ var useAnimatedValue = useAnimatedValue$1 || ((initialValue) => {
133
117
  function useValue$(key, getValue, key2) {
134
118
  var _a;
135
119
  const ctx = useStateContext();
136
- const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
120
+ const animValue = useAnimatedValue((_a = peek$(ctx, key)) != null ? _a : 0);
137
121
  useMemo(() => {
138
- listen$(ctx, key, (v) => animValue.setValue(getValue ? getValue(v) : v));
122
+ listen$(ctx, key, (v) => animValue.setValue(v));
139
123
  }, []);
140
124
  return animValue;
141
125
  }
142
126
 
143
127
  // src/Containers.tsx
144
- var Containers = React5.memo(function Containers2({
128
+ var Containers = React4.memo(function Containers2({
145
129
  horizontal,
146
130
  recycleItems,
147
131
  ItemSeparatorComponent,
148
132
  updateItemSize,
149
133
  getRenderedItem
150
134
  }) {
151
- const ctx = useStateContext();
152
135
  const numContainers = use$("numContainersPooled");
153
- const animSize = useValue$("totalSize", (v) => v + peek$(ctx, "scrollAdjust"));
136
+ const animSize = useValue$("totalSize");
154
137
  const containers = [];
155
138
  for (let i = 0; i < numContainers; i++) {
156
139
  containers.push(
157
- /* @__PURE__ */ React5.createElement(
140
+ /* @__PURE__ */ React4.createElement(
158
141
  Container,
159
142
  {
160
143
  id: i,
@@ -169,20 +152,20 @@ var Containers = React5.memo(function Containers2({
169
152
  );
170
153
  }
171
154
  const style = horizontal ? { width: animSize } : { height: animSize };
172
- return /* @__PURE__ */ React5.createElement(Animated.View, { style }, containers);
155
+ return /* @__PURE__ */ React4.createElement(Animated.View, { style }, containers);
173
156
  });
174
157
 
175
158
  // src/ListComponent.tsx
176
159
  var getComponent = (Component) => {
177
- if (React5.isValidElement(Component)) {
160
+ if (React4.isValidElement(Component)) {
178
161
  return Component;
179
162
  }
180
163
  if (Component) {
181
- return /* @__PURE__ */ React5.createElement(Component, null);
164
+ return /* @__PURE__ */ React4.createElement(Component, null);
182
165
  }
183
166
  return null;
184
167
  };
185
- var ListComponent = React5.memo(function ListComponent2({
168
+ var ListComponent = React4.memo(function ListComponent2({
186
169
  style,
187
170
  contentContainerStyle,
188
171
  horizontal,
@@ -200,18 +183,20 @@ var ListComponent = React5.memo(function ListComponent2({
200
183
  ListEmptyComponentStyle,
201
184
  getRenderedItem,
202
185
  updateItemSize,
203
- addTotalSize,
204
- refScroller,
186
+ refScrollView,
187
+ maintainVisibleContentPosition,
205
188
  ...rest
206
189
  }) {
207
190
  const ctx = useStateContext();
208
191
  const animPaddingTop = useValue$("paddingTop");
209
192
  const animScrollAdjust = useValue$("scrollAdjust");
210
- return /* @__PURE__ */ React5.createElement(
211
- $ScrollView,
193
+ const additionalSize = { marginTop: animScrollAdjust, paddingTop: animPaddingTop };
194
+ return /* @__PURE__ */ React4.createElement(
195
+ ScrollView,
212
196
  {
213
197
  ...rest,
214
198
  style,
199
+ maintainVisibleContentPosition: maintainVisibleContentPosition ? { minIndexForVisible: 0 } : void 0,
215
200
  contentContainerStyle: [
216
201
  contentContainerStyle,
217
202
  horizontal ? {
@@ -222,15 +207,13 @@ var ListComponent = React5.memo(function ListComponent2({
222
207
  onLayout,
223
208
  horizontal,
224
209
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
225
- ref: refScroller
210
+ ref: refScrollView
226
211
  },
227
- alignItemsAtEnd && /* @__PURE__ */ React5.createElement(Animated.View, { style: { height: animPaddingTop } }),
228
- ListHeaderComponent && /* @__PURE__ */ React5.createElement(
212
+ /* @__PURE__ */ React4.createElement(Animated.View, { style: additionalSize }),
213
+ ListHeaderComponent && /* @__PURE__ */ React4.createElement(
229
214
  Animated.View,
230
215
  {
231
- style: StyleSheet.compose(ListHeaderComponentStyle, {
232
- top: animScrollAdjust
233
- }),
216
+ style: ListHeaderComponentStyle,
234
217
  onLayout: (event) => {
235
218
  const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
236
219
  const prevSize = peek$(ctx, "headerSize") || 0;
@@ -241,16 +224,8 @@ var ListComponent = React5.memo(function ListComponent2({
241
224
  },
242
225
  getComponent(ListHeaderComponent)
243
226
  ),
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(
227
+ ListEmptyComponent && /* @__PURE__ */ React4.createElement(Animated.View, { style: ListEmptyComponentStyle }, getComponent(ListEmptyComponent)),
228
+ /* @__PURE__ */ React4.createElement(
254
229
  Containers,
255
230
  {
256
231
  horizontal,
@@ -260,9 +235,46 @@ var ListComponent = React5.memo(function ListComponent2({
260
235
  updateItemSize
261
236
  }
262
237
  ),
263
- ListFooterComponent && /* @__PURE__ */ React5.createElement(View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
238
+ ListFooterComponent && /* @__PURE__ */ React4.createElement(View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
264
239
  );
265
240
  });
241
+
242
+ // src/ScrollAdjustHandler.ts
243
+ var ScrollAdjustHandler = class {
244
+ constructor(ctx) {
245
+ this.ctx = ctx;
246
+ this.appliedAdjust = 0;
247
+ this.pendingAdjust = 0;
248
+ this.busy = false;
249
+ this.firstAdjust = true;
250
+ this.context = ctx;
251
+ }
252
+ requestAdjust(adjust, onAdjusted) {
253
+ const oldAdjustTop = peek$(this.context, "scrollAdjust");
254
+ if (oldAdjustTop === adjust) {
255
+ return;
256
+ }
257
+ this.appliedAdjust = adjust;
258
+ this.pendingAdjust = adjust;
259
+ const doAjdust = () => {
260
+ set$(this.context, "scrollAdjust", this.pendingAdjust);
261
+ onAdjusted(oldAdjustTop - this.pendingAdjust);
262
+ this.busy = false;
263
+ };
264
+ if (!this.busy) {
265
+ this.busy = true;
266
+ if (this.firstAdjust) {
267
+ this.firstAdjust = false;
268
+ setTimeout(doAjdust, 50);
269
+ } else {
270
+ doAjdust();
271
+ }
272
+ }
273
+ }
274
+ getAppliedAdjust() {
275
+ return this.appliedAdjust;
276
+ }
277
+ };
266
278
  var symbolFirst = Symbol();
267
279
  function useInit(cb) {
268
280
  const refValue = useRef(symbolFirst);
@@ -421,14 +433,13 @@ function maybeUpdateViewabilityCallback(ctx, configId, viewToken) {
421
433
 
422
434
  // src/LegendList.tsx
423
435
  var DEFAULT_DRAW_DISTANCE = 250;
424
- var INITIAL_SCROLL_ADJUST = 1e4;
425
436
  var POSITION_OUT_OF_VIEW = -1e7;
426
437
  var DEFAULT_ITEM_SIZE = 100;
427
438
  var LegendList = forwardRef(function LegendList2(props, forwardedRef) {
428
- return /* @__PURE__ */ React5.createElement(StateProvider, null, /* @__PURE__ */ React5.createElement(LegendListInner, { ...props, ref: forwardedRef }));
439
+ return /* @__PURE__ */ React4.createElement(StateProvider, null, /* @__PURE__ */ React4.createElement(LegendListInner, { ...props, ref: forwardedRef }));
429
440
  });
430
441
  var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef) {
431
- var _a, _b, _c, _d, _e, _f;
442
+ var _a, _b, _c, _d, _e;
432
443
  const {
433
444
  data,
434
445
  initialScrollIndex,
@@ -452,12 +463,12 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
452
463
  onEndReached,
453
464
  onStartReached,
454
465
  ListEmptyComponent,
466
+ refScrollView,
455
467
  ...rest
456
468
  } = props;
457
469
  const { style, contentContainerStyle } = props;
458
470
  const ctx = useStateContext();
459
- const internalRef = useRef(null);
460
- const refScroller = internalRef;
471
+ const refScroller = useRef(null);
461
472
  const scrollBuffer = drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE;
462
473
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (item, index) => index.toString();
463
474
  const refState = useRef();
@@ -490,37 +501,38 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
490
501
  } else if (estimatedItemSize) {
491
502
  offset = index * estimatedItemSize;
492
503
  }
493
- return offset + (maintainVisibleContentPosition ? INITIAL_SCROLL_ADJUST : 0);
504
+ return offset / numColumnsProp;
494
505
  }
495
- return void 0;
506
+ return 0;
496
507
  };
497
508
  const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : useMemo(calculateInitialOffset, []);
498
509
  if (!refState.current) {
510
+ const initialScrollLength = Dimensions.get("window")[horizontal ? "width" : "height"];
499
511
  refState.current = {
500
512
  sizes: /* @__PURE__ */ new Map(),
501
513
  positions: /* @__PURE__ */ new Map(),
502
514
  columns: /* @__PURE__ */ new Map(),
503
515
  pendingAdjust: 0,
504
516
  animFrameLayout: null,
505
- animFrameTotalSize: null,
506
- isStartReached: true,
517
+ isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
507
518
  isEndReached: false,
508
519
  isAtBottom: false,
509
520
  isAtTop: false,
510
521
  data,
511
522
  idsInFirstRender: void 0,
512
523
  hasScrolled: false,
513
- scrollLength: Dimensions.get("window")[horizontal ? "width" : "height"],
524
+ scrollLength: initialScrollLength,
514
525
  startBuffered: 0,
515
526
  startNoBuffer: 0,
516
527
  endBuffered: 0,
517
528
  endNoBuffer: 0,
518
529
  scroll: initialContentOffset || 0,
519
530
  totalSize: 0,
531
+ totalSizeBelowAnchor: 0,
520
532
  timeouts: /* @__PURE__ */ new Set(),
521
533
  viewabilityConfigCallbackPairs: void 0,
522
534
  renderItem: void 0,
523
- scrollAdjustPending: maintainVisibleContentPosition ? INITIAL_SCROLL_ADJUST : 0,
535
+ scrollAdjustHandler: new ScrollAdjustHandler(ctx),
524
536
  nativeMarginTop: 0,
525
537
  scrollPrev: 0,
526
538
  scrollPrevTime: 0,
@@ -531,54 +543,141 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
531
543
  contentSize: { width: 0, height: 0 },
532
544
  sizesLaidOut: __DEV__ ? /* @__PURE__ */ new Map() : void 0,
533
545
  timeoutSizeMessage: 0,
534
- scrollTimer: void 0
546
+ scrollTimer: void 0,
547
+ belowAnchorElementPositions: void 0,
548
+ rowHeights: /* @__PURE__ */ new Map(),
549
+ startReachedBlockedByTimer: false
535
550
  };
536
551
  refState.current.idsInFirstRender = new Set(data.map((_, i) => getId(i)));
537
- set$(ctx, "scrollAdjust", refState.current.scrollAdjustPending);
552
+ if (maintainVisibleContentPosition) {
553
+ if (initialScrollIndex) {
554
+ refState.current.anchorElement = {
555
+ coordinate: initialContentOffset,
556
+ id: getId(initialScrollIndex)
557
+ };
558
+ } else if (data.length) {
559
+ refState.current.anchorElement = {
560
+ coordinate: initialContentOffset,
561
+ id: getId(0)
562
+ };
563
+ } else {
564
+ console.warn("[legend-list] maintainVisibleContentPosition was not able to find an anchor element");
565
+ }
566
+ }
567
+ set$(ctx, "scrollAdjust", 0);
538
568
  }
539
- const adjustScroll = (diff) => {
540
- if (maintainVisibleContentPosition && refScroller.current) {
541
- refState.current.scrollAdjustPending -= diff;
569
+ const getAnchorElementIndex = () => {
570
+ const state = refState.current;
571
+ if (state.anchorElement) {
572
+ const el = state.indexByKey.get(state.anchorElement.id);
573
+ return el;
542
574
  }
575
+ return void 0;
543
576
  };
544
- const addTotalSize = useCallback((key, add) => {
577
+ const addTotalSize = useCallback((key, add, totalSizeBelowAnchor) => {
545
578
  const state = refState.current;
546
579
  const index = key === null ? 0 : state.indexByKey.get(key);
547
- const isAbove = key !== null && index < (state.startNoBuffer || 0);
548
- const prev = state.totalSize;
580
+ let isAboveAnchor = false;
581
+ if (maintainVisibleContentPosition) {
582
+ if (state.anchorElement && index < getAnchorElementIndex()) {
583
+ isAboveAnchor = true;
584
+ }
585
+ }
586
+ state.totalSize;
549
587
  if (key === null) {
550
588
  state.totalSize = add;
589
+ state.totalSizeBelowAnchor = totalSizeBelowAnchor;
551
590
  } else {
552
591
  state.totalSize += add;
592
+ if (isAboveAnchor) {
593
+ state.totalSizeBelowAnchor += add;
594
+ }
595
+ }
596
+ let applyAdjustValue = void 0;
597
+ if (maintainVisibleContentPosition) {
598
+ const newAdjust = state.anchorElement.coordinate - state.totalSizeBelowAnchor;
599
+ applyAdjustValue = -newAdjust;
600
+ state.belowAnchorElementPositions = buildElementPositionsBelowAnchor();
601
+ state.rowHeights.clear();
553
602
  }
554
603
  const doAdd = () => {
555
604
  const totalSize = state.totalSize;
556
- state.animFrameTotalSize = null;
557
- set$(ctx, "totalSize", totalSize);
605
+ let resultSize = totalSize;
606
+ if (applyAdjustValue !== void 0) {
607
+ resultSize -= applyAdjustValue;
608
+ refState.current.scrollAdjustHandler.requestAdjust(applyAdjustValue, (diff) => {
609
+ state.scroll -= diff;
610
+ });
611
+ }
612
+ set$(ctx, "totalSize", resultSize);
558
613
  if (alignItemsAtEnd) {
559
614
  doUpdatePaddingTop();
560
615
  }
561
616
  };
562
- if (isAbove) {
563
- adjustScroll(add);
617
+ doAdd();
618
+ }, []);
619
+ const getRowHeight = (n) => {
620
+ const { rowHeights } = refState.current;
621
+ if (numColumnsProp === 1) {
622
+ const id = getId(n);
623
+ return getItemSize(id, n, data[n]);
564
624
  }
565
- if (!prev || key === null) {
566
- doAdd();
567
- } else if (!state.animFrameTotalSize) {
568
- state.animFrameTotalSize = requestAnimationFrame(doAdd);
625
+ if (rowHeights.has(n)) {
626
+ return rowHeights.get(n) || 0;
569
627
  }
570
- }, []);
571
- const calculateItemsInView = useCallback((speed = 0) => {
572
- var _a2, _b2, _c2;
628
+ let rowHeight = 0;
629
+ const startEl = n * numColumnsProp;
630
+ for (let i = startEl; i < startEl + numColumnsProp; i++) {
631
+ const id = getId(i);
632
+ const size = getItemSize(id, i, data[i]);
633
+ rowHeight = Math.max(rowHeight, size);
634
+ }
635
+ rowHeights.set(n, rowHeight);
636
+ return rowHeight;
637
+ };
638
+ const buildElementPositionsBelowAnchor = () => {
639
+ const state = refState.current;
640
+ if (!state.anchorElement) {
641
+ return /* @__PURE__ */ new Map();
642
+ }
643
+ let top = state.anchorElement.coordinate;
644
+ const anchorIndex = state.indexByKey.get(state.anchorElement.id);
645
+ if (anchorIndex === 0) {
646
+ return /* @__PURE__ */ new Map();
647
+ }
648
+ const map = state.belowAnchorElementPositions || /* @__PURE__ */ new Map();
649
+ for (let i = anchorIndex - 1; i >= 0; i--) {
650
+ const id = getId(i);
651
+ const rowNumber = Math.floor(i / numColumnsProp);
652
+ if (i % numColumnsProp === 0) {
653
+ top -= getRowHeight(rowNumber);
654
+ }
655
+ map.set(id, top);
656
+ }
657
+ return map;
658
+ };
659
+ const getElementPositionBelowAchor = (id) => {
660
+ const state = refState.current;
661
+ if (!refState.current.belowAnchorElementPositions) {
662
+ state.belowAnchorElementPositions = buildElementPositionsBelowAnchor();
663
+ }
664
+ const res = state.belowAnchorElementPositions.get(id);
665
+ if (res === void 0) {
666
+ throw new Error("Undefined position below achor");
667
+ }
668
+ return res;
669
+ };
670
+ const calculateItemsInView = useCallback((speed) => {
671
+ var _a2, _b2, _c2, _d2;
573
672
  const state = refState.current;
574
673
  const {
575
674
  data: data2,
576
675
  scrollLength,
577
676
  scroll: scrollState,
578
- startBuffered: startBufferedState,
677
+ startBufferedId: startBufferedIdOrig,
579
678
  positions,
580
- sizes,
581
- columns
679
+ columns,
680
+ scrollAdjustHandler
582
681
  } = state;
583
682
  if (state.animFrameLayout) {
584
683
  cancelAnimationFrame(state.animFrameLayout);
@@ -588,30 +687,35 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
588
687
  return;
589
688
  }
590
689
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
591
- const scrollAdjustPending = (_a2 = state.scrollAdjustPending) != null ? _a2 : 0;
690
+ const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
592
691
  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
- );
692
+ const scroll = scrollState - previousScrollAdjust - topPad - scrollExtra;
597
693
  const scrollBottom = scroll + scrollLength;
598
694
  let startNoBuffer = null;
599
695
  let startBuffered = null;
696
+ let startBufferedId = null;
600
697
  let endNoBuffer = null;
601
698
  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
- }
699
+ const originalStartId = startBufferedIdOrig && state.indexByKey.get(startBufferedIdOrig);
700
+ let loopStart = originalStartId || 0;
701
+ const anchorElementIndex = getAnchorElementIndex();
702
+ for (let i = loopStart; i >= 0; i--) {
703
+ const id = getId(i);
704
+ let newPosition;
705
+ if (maintainVisibleContentPosition && anchorElementIndex && i < anchorElementIndex) {
706
+ newPosition = getElementPositionBelowAchor(id);
707
+ if (newPosition !== void 0) {
708
+ positions.set(id, newPosition);
709
+ }
710
+ }
711
+ const top2 = newPosition || positions.get(id);
712
+ if (top2 !== void 0) {
713
+ const size = getItemSize(id, i, data2[i]);
714
+ const bottom = top2 + size;
715
+ if (bottom > scroll - scrollBuffer) {
716
+ loopStart = i;
717
+ } else {
718
+ break;
615
719
  }
616
720
  }
617
721
  }
@@ -620,13 +724,28 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
620
724
  if (loopStartMod > 0) {
621
725
  loopStart -= loopStartMod;
622
726
  }
623
- let top = loopStart > 0 ? positions.get(getId(loopStart)) : 0;
727
+ let top = void 0;
624
728
  let column = 1;
625
729
  let maxSizeInRow = 0;
730
+ const getInitialTop = (i) => {
731
+ var _a3;
732
+ const id = getId(i);
733
+ let topOffset = 0;
734
+ if (positions.get(id)) {
735
+ topOffset = positions.get(id);
736
+ }
737
+ if (id === ((_a3 = state.anchorElement) == null ? void 0 : _a3.id)) {
738
+ topOffset = initialContentOffset || 0;
739
+ }
740
+ return topOffset;
741
+ };
626
742
  for (let i = loopStart; i < data2.length; i++) {
627
743
  const id = getId(i);
628
744
  const size = getItemSize(id, i, data2[i]);
629
745
  maxSizeInRow = Math.max(maxSizeInRow, size);
746
+ if (top === void 0) {
747
+ top = getInitialTop(i);
748
+ }
630
749
  if (positions.get(id) !== top) {
631
750
  positions.set(id, top);
632
751
  }
@@ -638,6 +757,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
638
757
  }
639
758
  if (startBuffered === null && top + size > scroll - scrollBuffer) {
640
759
  startBuffered = i;
760
+ startBufferedId = id;
641
761
  }
642
762
  if (startNoBuffer !== null) {
643
763
  if (top <= scrollBottom) {
@@ -658,6 +778,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
658
778
  }
659
779
  Object.assign(refState.current, {
660
780
  startBuffered,
781
+ startBufferedId,
661
782
  startNoBuffer,
662
783
  endBuffered,
663
784
  endNoBuffer
@@ -676,7 +797,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
676
797
  }
677
798
  }
678
799
  if (!isContained) {
679
- const top2 = (positions.get(id) || 0) + scrollAdjustPending;
800
+ const top2 = positions.get(id) || 0;
680
801
  let furthestIndex = -1;
681
802
  let furthestDistance = 0;
682
803
  for (let u = 0; u < numContainers; u++) {
@@ -685,7 +806,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
685
806
  furthestIndex = u;
686
807
  break;
687
808
  }
688
- const index = (_b2 = refState.current) == null ? void 0 : _b2.indexByKey.get(key);
809
+ const index = (_a2 = refState.current) == null ? void 0 : _a2.indexByKey.get(key);
689
810
  const pos = peek$(ctx, `containerPosition${u}`);
690
811
  if (index < startBuffered || index > endBuffered) {
691
812
  const distance = Math.abs(pos - top2);
@@ -697,10 +818,14 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
697
818
  }
698
819
  if (furthestIndex >= 0) {
699
820
  set$(ctx, `containerItemKey${furthestIndex}`, id);
821
+ const index = (_b2 = refState.current) == null ? void 0 : _b2.indexByKey.get(id);
822
+ set$(ctx, `containerItemData${furthestIndex}`, data2[index]);
700
823
  } else {
701
824
  const containerId = numContainers;
702
825
  numContainers++;
703
826
  set$(ctx, `containerItemKey${containerId}`, id);
827
+ const index = (_c2 = refState.current) == null ? void 0 : _c2.indexByKey.get(id);
828
+ set$(ctx, `containerItemData${furthestIndex}`, data2[index]);
704
829
  set$(ctx, `containerPosition${containerId}`, POSITION_OUT_OF_VIEW);
705
830
  set$(ctx, `containerColumn${containerId}`, -1);
706
831
  if (__DEV__ && numContainers > peek$(ctx, "numContainersPooled")) {
@@ -720,28 +845,32 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
720
845
  }
721
846
  for (let i = 0; i < numContainers; i++) {
722
847
  const itemKey = peek$(ctx, `containerItemKey${i}`);
723
- const itemIndex = (_c2 = refState.current) == null ? void 0 : _c2.indexByKey.get(itemKey);
848
+ const itemIndex = (_d2 = refState.current) == null ? void 0 : _d2.indexByKey.get(itemKey);
724
849
  const item = data2[itemIndex];
725
850
  if (item) {
726
851
  const id = getId(itemIndex);
727
852
  if (itemKey !== id || itemIndex < startBuffered || itemIndex > endBuffered) {
728
- const prevPos = peek$(ctx, `containerPosition${i}`) - scrollAdjustPending;
853
+ const prevPos = peek$(ctx, `containerPosition${i}`);
729
854
  const pos = positions.get(id) || 0;
730
- const size = sizes.get(id) || 0;
855
+ const size = getItemSize(id, itemIndex, data2[i]);
731
856
  if (pos + size >= scroll && pos <= scrollBottom || prevPos + size >= scroll && prevPos <= scrollBottom) {
732
857
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
733
858
  }
734
859
  } else {
735
- const pos = (positions.get(id) || 0) + scrollAdjustPending;
860
+ const pos = positions.get(id) || 0;
736
861
  const column2 = columns.get(id) || 1;
737
862
  const prevPos = peek$(ctx, `containerPosition${i}`);
738
863
  const prevColumn = peek$(ctx, `containerColumn${i}`);
739
- if (pos >= 0 && pos !== prevPos) {
864
+ const prevData = peek$(ctx, `containerItemData${i}`);
865
+ if (pos > POSITION_OUT_OF_VIEW && pos !== prevPos) {
740
866
  set$(ctx, `containerPosition${i}`, pos);
741
867
  }
742
868
  if (column2 >= 0 && column2 !== prevColumn) {
743
869
  set$(ctx, `containerColumn${i}`, column2);
744
870
  }
871
+ if (prevData !== item) {
872
+ set$(ctx, `containerItemData${i}`, data2[itemIndex]);
873
+ }
745
874
  }
746
875
  }
747
876
  }
@@ -808,17 +937,20 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
808
937
  return;
809
938
  }
810
939
  const { scrollLength, scroll } = refState.current;
811
- const scrollAdjust = peek$(ctx, "scrollAdjust") || 0;
812
- const distanceFromTop = scroll - scrollAdjust;
940
+ const distanceFromTop = scroll;
813
941
  refState.current.isAtTop = distanceFromTop < 0;
814
942
  if (onStartReached) {
815
- if (!refState.current.isStartReached) {
943
+ if (!refState.current.isStartReached && !refState.current.startReachedBlockedByTimer) {
816
944
  if (distanceFromTop < onStartReachedThreshold * scrollLength) {
817
945
  refState.current.isStartReached = true;
818
946
  onStartReached({ distanceFromStart: scroll });
947
+ refState.current.startReachedBlockedByTimer = true;
948
+ setTimeout(() => {
949
+ refState.current.startReachedBlockedByTimer = false;
950
+ }, 700);
819
951
  }
820
952
  } else {
821
- if (distanceFromTop >= onStartReachedThreshold * scrollLength) {
953
+ if (distanceFromTop >= 1.3 * onStartReachedThreshold * scrollLength) {
822
954
  refState.current.isStartReached = false;
823
955
  }
824
956
  }
@@ -832,43 +964,36 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
832
964
  }
833
965
  refState.current.data = data;
834
966
  let totalSize = 0;
967
+ let totalSizeBelowIndex = 0;
835
968
  const indexByKey = /* @__PURE__ */ new Map();
836
969
  let column = 1;
837
970
  let maxSizeInRow = 0;
838
971
  for (let i = 0; i < data.length; i++) {
839
972
  const key = getId(i);
840
973
  indexByKey.set(key, i);
974
+ }
975
+ refState.current.indexByKey = indexByKey;
976
+ const anchorElementIndex = getAnchorElementIndex();
977
+ for (let i = 0; i < data.length; i++) {
978
+ const key = getId(i);
841
979
  const size = getItemSize(key, i, data[i]);
842
980
  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
981
  column++;
848
982
  if (column > numColumnsProp) {
983
+ if (maintainVisibleContentPosition && anchorElementIndex !== void 0 && i < anchorElementIndex) {
984
+ totalSizeBelowIndex += maxSizeInRow;
985
+ }
849
986
  totalSize += maxSizeInRow;
850
987
  column = 1;
851
988
  maxSizeInRow = 0;
852
989
  }
853
990
  }
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;
991
+ addTotalSize(null, totalSize, totalSizeBelowIndex);
866
992
  if (!isFirst) {
867
- refState.current.isEndReached = false;
868
993
  const numContainers = peek$(ctx, "numContainers");
869
994
  for (let i = 0; i < numContainers; i++) {
870
995
  const itemKey = peek$(ctx, `containerItemKey${i}`);
871
- if (!keyExtractorProp || itemKey && ((_b = refState.current) == null ? void 0 : _b.indexByKey.get(itemKey)) === void 0) {
996
+ if (!keyExtractorProp || itemKey && ((_a = refState.current) == null ? void 0 : _a.indexByKey.get(itemKey)) === void 0) {
872
997
  set$(ctx, `containerItemKey${i}`, void 0);
873
998
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
874
999
  set$(ctx, `containerColumn${i}`, -1);
@@ -878,10 +1003,12 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
878
1003
  refState.current.sizes.clear();
879
1004
  refState.current.positions;
880
1005
  }
881
- calculateItemsInView();
882
- doMaintainScrollAtEnd(false);
883
- checkAtTop();
884
- checkAtBottom();
1006
+ setTimeout(() => {
1007
+ calculateItemsInView(refState.current.scrollVelocity);
1008
+ doMaintainScrollAtEnd(false);
1009
+ checkAtTop();
1010
+ checkAtBottom();
1011
+ }, 0);
885
1012
  }
886
1013
  }
887
1014
  refState.current.renderItem = renderItem;
@@ -890,7 +1017,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
890
1017
  set$(
891
1018
  ctx,
892
1019
  "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
1020
+ (_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
1021
  );
895
1022
  const getRenderedItem = useCallback((key, containerId) => {
896
1023
  var _a2, _b2;
@@ -999,7 +1126,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
999
1126
  }
1000
1127
  set$(ctx, "numContainers", numContainers);
1001
1128
  set$(ctx, "numContainersPooled", numContainers * 2);
1002
- calculateItemsInView();
1129
+ calculateItemsInView(refState.current.scrollVelocity);
1003
1130
  });
1004
1131
  const updateItemSize = useCallback((containerId, itemKey, size) => {
1005
1132
  var _a2;
@@ -1010,21 +1137,16 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1010
1137
  const state = refState.current;
1011
1138
  const { sizes, indexByKey, idsInFirstRender, columns, sizesLaidOut } = state;
1012
1139
  const index = indexByKey.get(itemKey);
1013
- const wasInFirstRender = idsInFirstRender.has(itemKey);
1014
- const prevSize = sizes.get(itemKey) || (wasInFirstRender ? getItemSize(itemKey, index, data2[index]) : 0);
1140
+ const numColumns = peek$(ctx, "numColumns");
1141
+ const row = Math.floor(index / numColumns);
1142
+ const prevSize = getRowHeight(row);
1015
1143
  if (!prevSize || Math.abs(prevSize - size) > 0.5) {
1016
1144
  let diff;
1017
- const numColumns = peek$(ctx, "numColumns");
1018
1145
  if (numColumns > 1) {
1146
+ const prevMaxSizeInRow = getRowHeight(row);
1147
+ sizes.set(itemKey, size);
1019
1148
  const column = columns.get(itemKey);
1020
1149
  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
1150
  let nextMaxSizeInRow = 0;
1029
1151
  for (let i = loopStart; i < loopStart + numColumns; i++) {
1030
1152
  const id = getId(i);
@@ -1055,7 +1177,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1055
1177
  );
1056
1178
  }, 1e3);
1057
1179
  }
1058
- addTotalSize(itemKey, diff);
1180
+ addTotalSize(itemKey, diff, 0);
1059
1181
  doMaintainScrollAtEnd(true);
1060
1182
  const scrollVelocity = state.scrollVelocity;
1061
1183
  if (!state.animFrameLayout && (Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1)) {
@@ -1071,18 +1193,12 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1071
1193
  }
1072
1194
  }, []);
1073
1195
  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
1196
  calculateItemsInView(velocity);
1078
1197
  checkAtBottom();
1079
1198
  checkAtTop();
1080
1199
  }, []);
1081
1200
  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
- }
1201
+ const scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
1086
1202
  refState.current.scrollLength = scrollLength;
1087
1203
  if (refState.current.hasScrolled) {
1088
1204
  doMaintainScrollAtEnd(false);
@@ -1172,12 +1288,21 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1172
1288
  },
1173
1289
  []
1174
1290
  );
1175
- return /* @__PURE__ */ React5.createElement(
1291
+ return /* @__PURE__ */ React4.createElement(
1176
1292
  ListComponent,
1177
1293
  {
1178
1294
  ...rest,
1179
1295
  horizontal,
1180
- refScroller,
1296
+ refScrollView: (r) => {
1297
+ refScroller.current = r;
1298
+ if (refScrollView) {
1299
+ if (typeof refScrollView === "function") {
1300
+ refScrollView(r);
1301
+ } else {
1302
+ refScrollView.current = r;
1303
+ }
1304
+ }
1305
+ },
1181
1306
  initialContentOffset,
1182
1307
  getRenderedItem,
1183
1308
  updateItemSize,
@@ -1185,8 +1310,8 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1185
1310
  onLayout,
1186
1311
  recycleItems,
1187
1312
  alignItemsAtEnd,
1188
- addTotalSize,
1189
1313
  ListEmptyComponent: data.length === 0 ? ListEmptyComponent : void 0,
1314
+ maintainVisibleContentPosition,
1190
1315
  style
1191
1316
  }
1192
1317
  );