@legendapp/list 0.5.8 → 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 +23 -2
  2. package/index.d.ts +23 -2
  3. package/index.js +310 -191
  4. package/index.mjs +293 -174
  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, useEffect, useState } from 'react';
3
- import { Platform, StyleSheet, ScrollView, Animated, View, Dimensions, useAnimatedValue } 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,18 +13,18 @@ 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);
24
- const [, forceUpdate] = React5.useReducer((x) => x + 1, 0);
25
- useMemo(() => {
26
- listen$(ctx, signalName, forceUpdate);
27
- }, []);
28
- return ctx.values.get(signalName);
22
+ const ctx = React4.useContext(ContextState);
23
+ const value = useSyncExternalStore(
24
+ (onStoreChange) => listen$(ctx, signalName, onStoreChange),
25
+ () => ctx.values.get(signalName)
26
+ );
27
+ return value;
29
28
  }
30
29
  function listen$(ctx, signalName, cb) {
31
30
  const { listeners } = ctx;
@@ -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,34 +107,36 @@ 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
  };
113
+ var useAnimatedValue = useAnimatedValue$1 || ((initialValue) => {
114
+ return useRef(new Animated.Value(initialValue)).current;
115
+ });
130
116
  function useValue$(key, getValue, key2) {
131
117
  var _a;
132
118
  const ctx = useStateContext();
133
- 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);
134
120
  useMemo(() => {
135
- listen$(ctx, key, (v) => animValue.setValue(getValue ? getValue(v) : v));
121
+ listen$(ctx, key, (v) => animValue.setValue(v));
136
122
  }, []);
137
123
  return animValue;
138
124
  }
139
125
 
140
126
  // src/Containers.tsx
141
- var Containers = React5.memo(function Containers2({
127
+ var Containers = React4.memo(function Containers2({
142
128
  horizontal,
143
129
  recycleItems,
144
130
  ItemSeparatorComponent,
145
131
  updateItemSize,
146
132
  getRenderedItem
147
133
  }) {
148
- const ctx = useStateContext();
149
134
  const numContainers = use$("numContainersPooled");
150
- const animSize = useValue$("totalSize", (v) => v + peek$(ctx, "scrollAdjust"));
135
+ const animSize = useValue$("totalSize");
151
136
  const containers = [];
152
137
  for (let i = 0; i < numContainers; i++) {
153
138
  containers.push(
154
- /* @__PURE__ */ React5.createElement(
139
+ /* @__PURE__ */ React4.createElement(
155
140
  Container,
156
141
  {
157
142
  id: i,
@@ -166,20 +151,20 @@ var Containers = React5.memo(function Containers2({
166
151
  );
167
152
  }
168
153
  const style = horizontal ? { width: animSize } : { height: animSize };
169
- return /* @__PURE__ */ React5.createElement(Animated.View, { style }, containers);
154
+ return /* @__PURE__ */ React4.createElement(Animated.View, { style }, containers);
170
155
  });
171
156
 
172
157
  // src/ListComponent.tsx
173
158
  var getComponent = (Component) => {
174
- if (React5.isValidElement(Component)) {
159
+ if (React4.isValidElement(Component)) {
175
160
  return Component;
176
161
  }
177
162
  if (Component) {
178
- return /* @__PURE__ */ React5.createElement(Component, null);
163
+ return /* @__PURE__ */ React4.createElement(Component, null);
179
164
  }
180
165
  return null;
181
166
  };
182
- var ListComponent = React5.memo(function ListComponent2({
167
+ var ListComponent = React4.memo(function ListComponent2({
183
168
  style,
184
169
  contentContainerStyle,
185
170
  horizontal,
@@ -197,18 +182,20 @@ var ListComponent = React5.memo(function ListComponent2({
197
182
  ListEmptyComponentStyle,
198
183
  getRenderedItem,
199
184
  updateItemSize,
200
- addTotalSize,
201
185
  refScroller,
186
+ maintainVisibleContentPosition,
202
187
  ...rest
203
188
  }) {
204
189
  const ctx = useStateContext();
205
190
  const animPaddingTop = useValue$("paddingTop");
206
191
  const animScrollAdjust = useValue$("scrollAdjust");
207
- return /* @__PURE__ */ React5.createElement(
208
- $ScrollView,
192
+ const additionalSize = { marginTop: animScrollAdjust, paddingTop: animPaddingTop };
193
+ return /* @__PURE__ */ React4.createElement(
194
+ ScrollView,
209
195
  {
210
196
  ...rest,
211
197
  style,
198
+ maintainVisibleContentPosition: maintainVisibleContentPosition ? { minIndexForVisible: 0 } : void 0,
212
199
  contentContainerStyle: [
213
200
  contentContainerStyle,
214
201
  horizontal ? {
@@ -221,13 +208,11 @@ var ListComponent = React5.memo(function ListComponent2({
221
208
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
222
209
  ref: refScroller
223
210
  },
224
- alignItemsAtEnd && /* @__PURE__ */ React5.createElement(Animated.View, { style: { height: animPaddingTop } }),
225
- ListHeaderComponent && /* @__PURE__ */ React5.createElement(
211
+ /* @__PURE__ */ React4.createElement(Animated.View, { style: additionalSize }),
212
+ ListHeaderComponent && /* @__PURE__ */ React4.createElement(
226
213
  Animated.View,
227
214
  {
228
- style: StyleSheet.compose(ListHeaderComponentStyle, {
229
- top: animScrollAdjust
230
- }),
215
+ style: ListHeaderComponentStyle,
231
216
  onLayout: (event) => {
232
217
  const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
233
218
  const prevSize = peek$(ctx, "headerSize") || 0;
@@ -238,16 +223,8 @@ var ListComponent = React5.memo(function ListComponent2({
238
223
  },
239
224
  getComponent(ListHeaderComponent)
240
225
  ),
241
- ListEmptyComponent && /* @__PURE__ */ React5.createElement(
242
- Animated.View,
243
- {
244
- style: StyleSheet.compose(ListEmptyComponentStyle, {
245
- top: animScrollAdjust
246
- })
247
- },
248
- getComponent(ListEmptyComponent)
249
- ),
250
- /* @__PURE__ */ React5.createElement(
226
+ ListEmptyComponent && /* @__PURE__ */ React4.createElement(Animated.View, { style: ListEmptyComponentStyle }, getComponent(ListEmptyComponent)),
227
+ /* @__PURE__ */ React4.createElement(
251
228
  Containers,
252
229
  {
253
230
  horizontal,
@@ -257,9 +234,46 @@ var ListComponent = React5.memo(function ListComponent2({
257
234
  updateItemSize
258
235
  }
259
236
  ),
260
- ListFooterComponent && /* @__PURE__ */ React5.createElement(View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
237
+ ListFooterComponent && /* @__PURE__ */ React4.createElement(View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
261
238
  );
262
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
+ };
263
277
  var symbolFirst = Symbol();
264
278
  function useInit(cb) {
265
279
  const refValue = useRef(symbolFirst);
@@ -418,14 +432,13 @@ function maybeUpdateViewabilityCallback(ctx, configId, viewToken) {
418
432
 
419
433
  // src/LegendList.tsx
420
434
  var DEFAULT_DRAW_DISTANCE = 250;
421
- var INITIAL_SCROLL_ADJUST = 1e4;
422
435
  var POSITION_OUT_OF_VIEW = -1e7;
423
436
  var DEFAULT_ITEM_SIZE = 100;
424
437
  var LegendList = forwardRef(function LegendList2(props, forwardedRef) {
425
- 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 }));
426
439
  });
427
440
  var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef) {
428
- var _a, _b, _c, _d, _e, _f;
441
+ var _a, _b, _c, _d, _e;
429
442
  const {
430
443
  data,
431
444
  initialScrollIndex,
@@ -487,37 +500,38 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
487
500
  } else if (estimatedItemSize) {
488
501
  offset = index * estimatedItemSize;
489
502
  }
490
- return offset + (maintainVisibleContentPosition ? INITIAL_SCROLL_ADJUST : 0);
503
+ return offset / numColumnsProp;
491
504
  }
492
- return void 0;
505
+ return 0;
493
506
  };
494
507
  const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : useMemo(calculateInitialOffset, []);
495
508
  if (!refState.current) {
509
+ const initialScrollLength = Dimensions.get("window")[horizontal ? "width" : "height"];
496
510
  refState.current = {
497
511
  sizes: /* @__PURE__ */ new Map(),
498
512
  positions: /* @__PURE__ */ new Map(),
499
513
  columns: /* @__PURE__ */ new Map(),
500
514
  pendingAdjust: 0,
501
515
  animFrameLayout: null,
502
- animFrameTotalSize: null,
503
- isStartReached: true,
516
+ isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
504
517
  isEndReached: false,
505
518
  isAtBottom: false,
506
519
  isAtTop: false,
507
520
  data,
508
521
  idsInFirstRender: void 0,
509
522
  hasScrolled: false,
510
- scrollLength: Dimensions.get("window")[horizontal ? "width" : "height"],
523
+ scrollLength: initialScrollLength,
511
524
  startBuffered: 0,
512
525
  startNoBuffer: 0,
513
526
  endBuffered: 0,
514
527
  endNoBuffer: 0,
515
528
  scroll: initialContentOffset || 0,
516
529
  totalSize: 0,
530
+ totalSizeBelowAnchor: 0,
517
531
  timeouts: /* @__PURE__ */ new Set(),
518
532
  viewabilityConfigCallbackPairs: void 0,
519
533
  renderItem: void 0,
520
- scrollAdjustPending: maintainVisibleContentPosition ? INITIAL_SCROLL_ADJUST : 0,
534
+ scrollAdjustHandler: new ScrollAdjustHandler(ctx),
521
535
  nativeMarginTop: 0,
522
536
  scrollPrev: 0,
523
537
  scrollPrevTime: 0,
@@ -527,54 +541,142 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
527
541
  scrollVelocity: 0,
528
542
  contentSize: { width: 0, height: 0 },
529
543
  sizesLaidOut: __DEV__ ? /* @__PURE__ */ new Map() : void 0,
530
- timeoutSizeMessage: 0
544
+ timeoutSizeMessage: 0,
545
+ scrollTimer: void 0,
546
+ belowAnchorElementPositions: void 0,
547
+ rowHeights: /* @__PURE__ */ new Map(),
548
+ startReachedBlockedByTimer: false
531
549
  };
532
550
  refState.current.idsInFirstRender = new Set(data.map((_, i) => getId(i)));
533
- 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);
534
567
  }
535
- const adjustScroll = (diff) => {
536
- if (maintainVisibleContentPosition && refScroller.current) {
537
- 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;
538
573
  }
574
+ return void 0;
539
575
  };
540
- const addTotalSize = useCallback((key, add) => {
576
+ const addTotalSize = useCallback((key, add, totalSizeBelowAnchor) => {
541
577
  const state = refState.current;
542
578
  const index = key === null ? 0 : state.indexByKey.get(key);
543
- const isAbove = key !== null && index < (state.startNoBuffer || 0);
544
- 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;
545
586
  if (key === null) {
546
587
  state.totalSize = add;
588
+ state.totalSizeBelowAnchor = totalSizeBelowAnchor;
547
589
  } else {
548
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();
549
601
  }
550
602
  const doAdd = () => {
551
603
  const totalSize = state.totalSize;
552
- state.animFrameTotalSize = null;
553
- 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);
554
612
  if (alignItemsAtEnd) {
555
613
  doUpdatePaddingTop();
556
614
  }
557
615
  };
558
- if (isAbove) {
559
- 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]);
560
623
  }
561
- if (!prev || key === null) {
562
- doAdd();
563
- } else if (!state.animFrameTotalSize) {
564
- state.animFrameTotalSize = requestAnimationFrame(doAdd);
624
+ if (rowHeights.has(n)) {
625
+ return rowHeights.get(n) || 0;
565
626
  }
566
- }, []);
567
- const calculateItemsInView = useCallback((speed = 0) => {
568
- 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;
569
671
  const state = refState.current;
570
672
  const {
571
673
  data: data2,
572
674
  scrollLength,
573
675
  scroll: scrollState,
574
- startBuffered: startBufferedState,
676
+ startBufferedId: startBufferedIdOrig,
575
677
  positions,
576
- sizes,
577
- columns
678
+ columns,
679
+ scrollAdjustHandler
578
680
  } = state;
579
681
  if (state.animFrameLayout) {
580
682
  cancelAnimationFrame(state.animFrameLayout);
@@ -584,30 +686,35 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
584
686
  return;
585
687
  }
586
688
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
587
- const scrollAdjustPending = (_a2 = state.scrollAdjustPending) != null ? _a2 : 0;
689
+ const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
588
690
  const scrollExtra = Math.max(-16, Math.min(16, speed)) * 16;
589
- const scroll = Math.max(
590
- 0,
591
- scrollState - topPad - (USE_CONTENT_INSET ? scrollAdjustPending : 0) + scrollExtra
592
- );
691
+ const scroll = scrollState - previousScrollAdjust - topPad - scrollExtra;
593
692
  const scrollBottom = scroll + scrollLength;
594
693
  let startNoBuffer = null;
595
694
  let startBuffered = null;
695
+ let startBufferedId = null;
596
696
  let endNoBuffer = null;
597
697
  let endBuffered = null;
598
- let loopStart = startBufferedState || 0;
599
- if (startBufferedState) {
600
- for (let i = startBufferedState; i >= 0; i--) {
601
- const id = getId(i);
602
- const top2 = positions.get(id);
603
- if (top2 !== void 0) {
604
- const size = getItemSize(id, i, data2[i]);
605
- const bottom = top2 + size;
606
- if (bottom > scroll - scrollBuffer) {
607
- loopStart = i;
608
- } else {
609
- break;
610
- }
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;
611
718
  }
612
719
  }
613
720
  }
@@ -616,13 +723,28 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
616
723
  if (loopStartMod > 0) {
617
724
  loopStart -= loopStartMod;
618
725
  }
619
- let top = loopStart > 0 ? positions.get(getId(loopStart)) : 0;
726
+ let top = void 0;
620
727
  let column = 1;
621
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
+ };
622
741
  for (let i = loopStart; i < data2.length; i++) {
623
742
  const id = getId(i);
624
743
  const size = getItemSize(id, i, data2[i]);
625
744
  maxSizeInRow = Math.max(maxSizeInRow, size);
745
+ if (top === void 0) {
746
+ top = getInitialTop(i);
747
+ }
626
748
  if (positions.get(id) !== top) {
627
749
  positions.set(id, top);
628
750
  }
@@ -634,6 +756,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
634
756
  }
635
757
  if (startBuffered === null && top + size > scroll - scrollBuffer) {
636
758
  startBuffered = i;
759
+ startBufferedId = id;
637
760
  }
638
761
  if (startNoBuffer !== null) {
639
762
  if (top <= scrollBottom) {
@@ -654,6 +777,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
654
777
  }
655
778
  Object.assign(refState.current, {
656
779
  startBuffered,
780
+ startBufferedId,
657
781
  startNoBuffer,
658
782
  endBuffered,
659
783
  endNoBuffer
@@ -672,7 +796,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
672
796
  }
673
797
  }
674
798
  if (!isContained) {
675
- const top2 = (positions.get(id) || 0) + scrollAdjustPending;
799
+ const top2 = positions.get(id) || 0;
676
800
  let furthestIndex = -1;
677
801
  let furthestDistance = 0;
678
802
  for (let u = 0; u < numContainers; u++) {
@@ -681,7 +805,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
681
805
  furthestIndex = u;
682
806
  break;
683
807
  }
684
- 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);
685
809
  const pos = peek$(ctx, `containerPosition${u}`);
686
810
  if (index < startBuffered || index > endBuffered) {
687
811
  const distance = Math.abs(pos - top2);
@@ -716,23 +840,23 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
716
840
  }
717
841
  for (let i = 0; i < numContainers; i++) {
718
842
  const itemKey = peek$(ctx, `containerItemKey${i}`);
719
- 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);
720
844
  const item = data2[itemIndex];
721
845
  if (item) {
722
846
  const id = getId(itemIndex);
723
847
  if (itemKey !== id || itemIndex < startBuffered || itemIndex > endBuffered) {
724
- const prevPos = peek$(ctx, `containerPosition${i}`) - scrollAdjustPending;
848
+ const prevPos = peek$(ctx, `containerPosition${i}`);
725
849
  const pos = positions.get(id) || 0;
726
- const size = sizes.get(id) || 0;
850
+ const size = getItemSize(id, itemIndex, data2[i]);
727
851
  if (pos + size >= scroll && pos <= scrollBottom || prevPos + size >= scroll && prevPos <= scrollBottom) {
728
852
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
729
853
  }
730
854
  } else {
731
- const pos = (positions.get(id) || 0) + scrollAdjustPending;
855
+ const pos = positions.get(id) || 0;
732
856
  const column2 = columns.get(id) || 1;
733
857
  const prevPos = peek$(ctx, `containerPosition${i}`);
734
858
  const prevColumn = peek$(ctx, `containerColumn${i}`);
735
- if (pos >= 0 && pos !== prevPos) {
859
+ if (pos > POSITION_OUT_OF_VIEW && pos !== prevPos) {
736
860
  set$(ctx, `containerPosition${i}`, pos);
737
861
  }
738
862
  if (column2 >= 0 && column2 !== prevColumn) {
@@ -804,17 +928,20 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
804
928
  return;
805
929
  }
806
930
  const { scrollLength, scroll } = refState.current;
807
- const scrollAdjust = peek$(ctx, "scrollAdjust") || 0;
808
- const distanceFromTop = scroll - scrollAdjust;
931
+ const distanceFromTop = scroll;
809
932
  refState.current.isAtTop = distanceFromTop < 0;
810
933
  if (onStartReached) {
811
- if (!refState.current.isStartReached) {
934
+ if (!refState.current.isStartReached && !refState.current.startReachedBlockedByTimer) {
812
935
  if (distanceFromTop < onStartReachedThreshold * scrollLength) {
813
936
  refState.current.isStartReached = true;
814
937
  onStartReached({ distanceFromStart: scroll });
938
+ refState.current.startReachedBlockedByTimer = true;
939
+ setTimeout(() => {
940
+ refState.current.startReachedBlockedByTimer = false;
941
+ }, 700);
815
942
  }
816
943
  } else {
817
- if (distanceFromTop >= onStartReachedThreshold * scrollLength) {
944
+ if (distanceFromTop >= 1.3 * onStartReachedThreshold * scrollLength) {
818
945
  refState.current.isStartReached = false;
819
946
  }
820
947
  }
@@ -828,43 +955,36 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
828
955
  }
829
956
  refState.current.data = data;
830
957
  let totalSize = 0;
958
+ let totalSizeBelowIndex = 0;
831
959
  const indexByKey = /* @__PURE__ */ new Map();
832
960
  let column = 1;
833
961
  let maxSizeInRow = 0;
834
962
  for (let i = 0; i < data.length; i++) {
835
963
  const key = getId(i);
836
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);
837
970
  const size = getItemSize(key, i, data[i]);
838
971
  maxSizeInRow = Math.max(maxSizeInRow, size);
839
- if (maintainVisibleContentPosition && i < refState.current.startNoBuffer && !refState.current.indexByKey.has(key)) {
840
- const size2 = getItemSize(key, i, data[i]);
841
- adjustScroll(size2);
842
- }
843
972
  column++;
844
973
  if (column > numColumnsProp) {
974
+ if (maintainVisibleContentPosition && anchorElementIndex !== void 0 && i < anchorElementIndex) {
975
+ totalSizeBelowIndex += maxSizeInRow;
976
+ }
845
977
  totalSize += maxSizeInRow;
846
978
  column = 1;
847
979
  maxSizeInRow = 0;
848
980
  }
849
981
  }
850
- addTotalSize(null, totalSize);
851
- if (maintainVisibleContentPosition) {
852
- for (const [key, index] of refState.current.indexByKey) {
853
- if (index < refState.current.startNoBuffer && !indexByKey.has(key)) {
854
- const size = (_a = refState.current.sizes.get(key)) != null ? _a : 0;
855
- if (size) {
856
- adjustScroll(-size);
857
- }
858
- }
859
- }
860
- }
861
- refState.current.indexByKey = indexByKey;
982
+ addTotalSize(null, totalSize, totalSizeBelowIndex);
862
983
  if (!isFirst) {
863
- refState.current.isEndReached = false;
864
984
  const numContainers = peek$(ctx, "numContainers");
865
985
  for (let i = 0; i < numContainers; i++) {
866
986
  const itemKey = peek$(ctx, `containerItemKey${i}`);
867
- 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) {
868
988
  set$(ctx, `containerItemKey${i}`, void 0);
869
989
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
870
990
  set$(ctx, `containerColumn${i}`, -1);
@@ -874,10 +994,12 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
874
994
  refState.current.sizes.clear();
875
995
  refState.current.positions;
876
996
  }
877
- calculateItemsInView();
878
- doMaintainScrollAtEnd(false);
879
- checkAtTop();
880
- checkAtBottom();
997
+ setTimeout(() => {
998
+ calculateItemsInView(refState.current.scrollVelocity);
999
+ doMaintainScrollAtEnd(false);
1000
+ checkAtTop();
1001
+ checkAtBottom();
1002
+ }, 0);
881
1003
  }
882
1004
  }
883
1005
  refState.current.renderItem = renderItem;
@@ -886,7 +1008,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
886
1008
  set$(
887
1009
  ctx,
888
1010
  "stylePaddingTop",
889
- (_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
890
1012
  );
891
1013
  const getRenderedItem = useCallback((key, containerId) => {
892
1014
  var _a2, _b2;
@@ -995,7 +1117,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
995
1117
  }
996
1118
  set$(ctx, "numContainers", numContainers);
997
1119
  set$(ctx, "numContainersPooled", numContainers * 2);
998
- calculateItemsInView();
1120
+ calculateItemsInView(refState.current.scrollVelocity);
999
1121
  });
1000
1122
  const updateItemSize = useCallback((containerId, itemKey, size) => {
1001
1123
  var _a2;
@@ -1006,21 +1128,16 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1006
1128
  const state = refState.current;
1007
1129
  const { sizes, indexByKey, idsInFirstRender, columns, sizesLaidOut } = state;
1008
1130
  const index = indexByKey.get(itemKey);
1009
- const wasInFirstRender = idsInFirstRender.has(itemKey);
1010
- 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);
1011
1134
  if (!prevSize || Math.abs(prevSize - size) > 0.5) {
1012
1135
  let diff;
1013
- const numColumns = peek$(ctx, "numColumns");
1014
1136
  if (numColumns > 1) {
1137
+ const prevMaxSizeInRow = getRowHeight(row);
1138
+ sizes.set(itemKey, size);
1015
1139
  const column = columns.get(itemKey);
1016
1140
  const loopStart = index - (column - 1);
1017
- let prevMaxSizeInRow = 0;
1018
- for (let i = loopStart; i < loopStart + numColumns; i++) {
1019
- const id = getId(i);
1020
- const size2 = getItemSize(id, i, data2[i]);
1021
- prevMaxSizeInRow = Math.max(prevMaxSizeInRow, size2);
1022
- }
1023
- sizes.set(itemKey, size);
1024
1141
  let nextMaxSizeInRow = 0;
1025
1142
  for (let i = loopStart; i < loopStart + numColumns; i++) {
1026
1143
  const id = getId(i);
@@ -1051,7 +1168,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1051
1168
  );
1052
1169
  }, 1e3);
1053
1170
  }
1054
- addTotalSize(itemKey, diff);
1171
+ addTotalSize(itemKey, diff, 0);
1055
1172
  doMaintainScrollAtEnd(true);
1056
1173
  const scrollVelocity = state.scrollVelocity;
1057
1174
  if (!state.animFrameLayout && (Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1)) {
@@ -1067,18 +1184,12 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1067
1184
  }
1068
1185
  }, []);
1069
1186
  const handleScrollDebounced = useCallback((velocity) => {
1070
- var _a2, _b2;
1071
- const scrollAdjustPending = (_b2 = (_a2 = refState.current) == null ? void 0 : _a2.scrollAdjustPending) != null ? _b2 : 0;
1072
- set$(ctx, "scrollAdjust", scrollAdjustPending);
1073
1187
  calculateItemsInView(velocity);
1074
1188
  checkAtBottom();
1075
1189
  checkAtTop();
1076
1190
  }, []);
1077
1191
  const onLayout = useCallback((event) => {
1078
- let scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
1079
- if (!USE_CONTENT_INSET) {
1080
- scrollLength += event.nativeEvent.layout[horizontal ? "x" : "y"];
1081
- }
1192
+ const scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
1082
1193
  refState.current.scrollLength = scrollLength;
1083
1194
  if (refState.current.hasScrolled) {
1084
1195
  doMaintainScrollAtEnd(false);
@@ -1107,10 +1218,18 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1107
1218
  state.contentSize = event.nativeEvent.contentSize;
1108
1219
  const currentTime = performance.now();
1109
1220
  const newScroll = event.nativeEvent.contentOffset[horizontal ? "x" : "y"];
1110
- state.scrollHistory.push({ scroll: newScroll, time: currentTime });
1221
+ if (!(state.scrollHistory.length === 0 && newScroll === initialContentOffset)) {
1222
+ state.scrollHistory.push({ scroll: newScroll, time: currentTime });
1223
+ }
1111
1224
  if (state.scrollHistory.length > 5) {
1112
1225
  state.scrollHistory.shift();
1113
1226
  }
1227
+ if (state.scrollTimer !== void 0) {
1228
+ clearTimeout(state.scrollTimer);
1229
+ }
1230
+ state.scrollTimer = setTimeout(() => {
1231
+ state.scrollVelocity = 0;
1232
+ }, 500);
1114
1233
  let velocity = 0;
1115
1234
  if (state.scrollHistory.length >= 2) {
1116
1235
  const newest = state.scrollHistory[state.scrollHistory.length - 1];
@@ -1160,7 +1279,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1160
1279
  },
1161
1280
  []
1162
1281
  );
1163
- return /* @__PURE__ */ React5.createElement(
1282
+ return /* @__PURE__ */ React4.createElement(
1164
1283
  ListComponent,
1165
1284
  {
1166
1285
  ...rest,
@@ -1173,8 +1292,8 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1173
1292
  onLayout,
1174
1293
  recycleItems,
1175
1294
  alignItemsAtEnd,
1176
- addTotalSize,
1177
1295
  ListEmptyComponent: data.length === 0 ? ListEmptyComponent : void 0,
1296
+ maintainVisibleContentPosition,
1178
1297
  style
1179
1298
  }
1180
1299
  );