@legendapp/list 1.0.0-beta.2 → 1.0.0-beta.3

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,11 +1,11 @@
1
- import * as React4 from 'react';
2
- import React4__default, { useMemo, forwardRef, useRef, useCallback, useEffect, useImperativeHandle, useSyncExternalStore, useState } from 'react';
1
+ import * as React5 from 'react';
2
+ import React5__default, { createContext, useMemo, forwardRef, useRef, useCallback, useEffect, useImperativeHandle, useSyncExternalStore, useContext, useState, useLayoutEffect } from 'react';
3
3
  import { Animated, ScrollView, View, Dimensions, StyleSheet, Platform, useAnimatedValue as useAnimatedValue$1 } from 'react-native';
4
4
 
5
5
  // src/LegendList.tsx
6
- var ContextState = React4.createContext(null);
6
+ var ContextState = React5.createContext(null);
7
7
  function StateProvider({ children }) {
8
- const [value] = React4.useState(() => ({
8
+ const [value] = React5.useState(() => ({
9
9
  listeners: /* @__PURE__ */ new Map(),
10
10
  values: /* @__PURE__ */ new Map(),
11
11
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
@@ -13,10 +13,10 @@ function StateProvider({ children }) {
13
13
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
14
14
  mapViewabilityAmountValues: /* @__PURE__ */ new Map()
15
15
  }));
16
- return /* @__PURE__ */ React4.createElement(ContextState.Provider, { value }, children);
16
+ return /* @__PURE__ */ React5.createElement(ContextState.Provider, { value }, children);
17
17
  }
18
18
  function useStateContext() {
19
- return React4.useContext(ContextState);
19
+ return React5.useContext(ContextState);
20
20
  }
21
21
  function createSelectorFunctions(ctx, signalName) {
22
22
  return {
@@ -25,8 +25,8 @@ function createSelectorFunctions(ctx, signalName) {
25
25
  };
26
26
  }
27
27
  function use$(signalName) {
28
- const ctx = React4.useContext(ContextState);
29
- const { subscribe, get } = React4.useMemo(() => createSelectorFunctions(ctx, signalName), []);
28
+ const ctx = React5.useContext(ContextState);
29
+ const { subscribe, get } = React5.useMemo(() => createSelectorFunctions(ctx, signalName), []);
30
30
  const value = useSyncExternalStore(subscribe, get);
31
31
  return value;
32
32
  }
@@ -56,60 +56,186 @@ function set$(ctx, signalName, value) {
56
56
  }
57
57
  }
58
58
  }
59
+ var symbolFirst = Symbol();
60
+ function useInit(cb) {
61
+ const refValue = useRef(symbolFirst);
62
+ if (refValue.current === symbolFirst) {
63
+ refValue.current = cb();
64
+ }
65
+ return refValue.current;
66
+ }
67
+
68
+ // src/ContextContainer.ts
69
+ var ContextContainer = createContext(null);
70
+ function useViewability(configId, callback) {
71
+ const ctx = useStateContext();
72
+ const { containerId } = useContext(ContextContainer);
73
+ const key = containerId + configId;
74
+ useInit(() => {
75
+ const value = ctx.mapViewabilityValues.get(key);
76
+ if (value) {
77
+ callback(value);
78
+ }
79
+ });
80
+ ctx.mapViewabilityCallbacks.set(key, callback);
81
+ useEffect(
82
+ () => () => {
83
+ ctx.mapViewabilityCallbacks.delete(key);
84
+ },
85
+ []
86
+ );
87
+ }
88
+ function useViewabilityAmount(callback) {
89
+ const ctx = useStateContext();
90
+ const { containerId } = useContext(ContextContainer);
91
+ useInit(() => {
92
+ const value = ctx.mapViewabilityAmountValues.get(containerId);
93
+ if (value) {
94
+ callback(value);
95
+ }
96
+ });
97
+ ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
98
+ useEffect(
99
+ () => () => {
100
+ ctx.mapViewabilityAmountCallbacks.delete(containerId);
101
+ },
102
+ []
103
+ );
104
+ }
105
+ function useRecyclingEffect(effect) {
106
+ const { index, value } = useContext(ContextContainer);
107
+ const prevValues = useRef({
108
+ prevIndex: void 0,
109
+ prevItem: void 0
110
+ });
111
+ useEffect(() => {
112
+ let ret = void 0;
113
+ if (prevValues.current.prevIndex !== void 0 && prevValues.current.prevItem !== void 0) {
114
+ ret = effect({
115
+ index,
116
+ item: value,
117
+ prevIndex: prevValues.current.prevIndex,
118
+ prevItem: prevValues.current.prevItem
119
+ });
120
+ }
121
+ prevValues.current = {
122
+ prevIndex: index,
123
+ prevItem: value
124
+ };
125
+ return ret;
126
+ }, [index, value]);
127
+ }
128
+ function useRecyclingState(valueOrFun) {
129
+ const { index, value } = useContext(ContextContainer);
130
+ const stateInfo = useState(
131
+ () => typeof valueOrFun === "function" ? valueOrFun({
132
+ index,
133
+ item: value,
134
+ prevIndex: void 0,
135
+ prevItem: void 0
136
+ }) : valueOrFun
137
+ );
138
+ useRecyclingEffect((state) => {
139
+ const newState = typeof valueOrFun === "function" ? valueOrFun(state) : valueOrFun;
140
+ stateInfo[1](newState);
141
+ });
142
+ return stateInfo;
143
+ }
144
+ var LeanView = React5.forwardRef((props, ref) => {
145
+ return React5.createElement("RCTView", { ...props, ref });
146
+ });
147
+ LeanView.displayName = "RCTView";
148
+
149
+ // src/constants.ts
150
+ var POSITION_OUT_OF_VIEW = -1e7;
151
+ var ANCHORED_POSITION_OUT_OF_VIEW = {
152
+ type: "top",
153
+ relativeCoordinate: POSITION_OUT_OF_VIEW,
154
+ top: POSITION_OUT_OF_VIEW
155
+ };
59
156
 
60
157
  // src/Container.tsx
61
158
  var Container = ({
62
159
  id,
63
160
  recycleItems,
64
161
  horizontal,
65
- waitForInitialLayout,
66
162
  getRenderedItem,
67
163
  updateItemSize,
68
164
  ItemSeparatorComponent
69
165
  }) => {
70
166
  const ctx = useStateContext();
71
- const position = use$(`containerPosition${id}`);
167
+ const maintainVisibleContentPosition = use$("maintainVisibleContentPosition");
168
+ const position = use$(`containerPosition${id}`) || ANCHORED_POSITION_OUT_OF_VIEW;
72
169
  const column = use$(`containerColumn${id}`) || 0;
73
170
  const numColumns = use$("numColumns");
74
171
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
75
172
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
76
173
  const style = horizontal ? {
77
- flexDirection: "row",
174
+ flexDirection: ItemSeparatorComponent ? "row" : void 0,
78
175
  position: "absolute",
79
176
  top: otherAxisPos,
80
177
  bottom: numColumns > 1 ? null : 0,
81
178
  height: otherAxisSize,
82
- left: position
179
+ left: position.relativeCoordinate
83
180
  } : {
84
181
  position: "absolute",
85
182
  left: otherAxisPos,
86
183
  right: numColumns > 1 ? null : 0,
87
184
  width: otherAxisSize,
88
- top: position
185
+ top: position.relativeCoordinate
89
186
  };
90
- if (waitForInitialLayout) {
91
- const visible = use$(`containerDidLayout${id}`);
92
- style.opacity = visible ? 1 : 0;
93
- }
94
187
  const lastItemKey = use$("lastItemKey");
95
188
  const itemKey = use$(`containerItemKey${id}`);
96
189
  const data = use$(`containerItemData${id}`);
97
190
  const extraData = use$("extraData");
98
- const renderedItem = useMemo(() => itemKey !== void 0 && getRenderedItem(itemKey, id), [itemKey, data, extraData]);
99
- return /* @__PURE__ */ React4__default.createElement(
100
- View,
101
- {
102
- style,
103
- onLayout: (event) => {
104
- const key = peek$(ctx, `containerItemKey${id}`);
105
- if (key !== void 0) {
106
- const size = Math.floor(event.nativeEvent.layout[horizontal ? "width" : "height"] * 8) / 8;
107
- updateItemSize(id, key, size);
191
+ const refLastSize = useRef();
192
+ const renderedItemInfo = useMemo(
193
+ () => itemKey !== void 0 && getRenderedItem(itemKey),
194
+ [itemKey, data, extraData]
195
+ );
196
+ const { index, renderedItem } = renderedItemInfo || {};
197
+ useEffect(() => {
198
+ if (itemKey) {
199
+ const timeout = setTimeout(() => {
200
+ if (refLastSize.current) {
201
+ updateItemSize(id, itemKey, refLastSize.current);
202
+ }
203
+ }, 16);
204
+ return () => {
205
+ clearTimeout(timeout);
206
+ };
207
+ }
208
+ }, [itemKey]);
209
+ const onLayout = (event) => {
210
+ const key = peek$(ctx, `containerItemKey${id}`);
211
+ if (key !== void 0) {
212
+ const size = Math.floor(event.nativeEvent.layout[horizontal ? "width" : "height"] * 8) / 8;
213
+ updateItemSize(id, key, size);
214
+ }
215
+ };
216
+ const ref = useRef(null);
217
+ useLayoutEffect(() => {
218
+ var _a, _b;
219
+ if (itemKey) {
220
+ const measured = (_b = (_a = ref.current) == null ? void 0 : _a.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a);
221
+ if (measured) {
222
+ const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
223
+ if (size) {
224
+ updateItemSize(id, itemKey, size);
108
225
  }
109
226
  }
110
- },
111
- /* @__PURE__ */ React4__default.createElement(React4__default.Fragment, { key: recycleItems ? void 0 : itemKey }, renderedItem, renderedItem && ItemSeparatorComponent && itemKey !== lastItemKey && ItemSeparatorComponent)
227
+ }
228
+ }, [itemKey]);
229
+ const contextValue = useMemo(
230
+ () => ({ containerId: id, itemKey, index, value: data }),
231
+ [id, itemKey, index, data]
112
232
  );
233
+ const contentFragment = /* @__PURE__ */ React5__default.createElement(React5__default.Fragment, { key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React5__default.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItem && ItemSeparatorComponent && itemKey !== lastItemKey && ItemSeparatorComponent));
234
+ if (maintainVisibleContentPosition) {
235
+ const anchorStyle = position.type === "top" ? { position: "absolute", top: 0, left: 0, right: 0 } : { position: "absolute", bottom: 0, left: 0, right: 0 };
236
+ return /* @__PURE__ */ React5__default.createElement(LeanView, { style, ref }, /* @__PURE__ */ React5__default.createElement(LeanView, { style: anchorStyle, onLayout }, contentFragment));
237
+ }
238
+ return /* @__PURE__ */ React5__default.createElement(LeanView, { style, onLayout, ref }, contentFragment);
113
239
  };
114
240
  var useAnimatedValue = useAnimatedValue$1 || ((initialValue) => {
115
241
  return useRef(new Animated.Value(initialValue)).current;
@@ -117,15 +243,15 @@ var useAnimatedValue = useAnimatedValue$1 || ((initialValue) => {
117
243
  function useValue$(key, getValue, key2) {
118
244
  var _a;
119
245
  const ctx = useStateContext();
120
- const animValue = useAnimatedValue((_a = peek$(ctx, key)) != null ? _a : 0);
246
+ const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
121
247
  useMemo(() => {
122
- listen$(ctx, key, (v) => animValue.setValue(v));
248
+ listen$(ctx, key, (v) => animValue.setValue(getValue ? getValue(v) : v));
123
249
  }, []);
124
250
  return animValue;
125
251
  }
126
252
 
127
253
  // src/Containers.tsx
128
- var Containers = React4.memo(function Containers2({
254
+ var Containers = React5.memo(function Containers2({
129
255
  horizontal,
130
256
  recycleItems,
131
257
  ItemSeparatorComponent,
@@ -135,17 +261,17 @@ var Containers = React4.memo(function Containers2({
135
261
  }) {
136
262
  const numContainers = use$("numContainersPooled");
137
263
  const animSize = useValue$("totalSize");
264
+ const animOpacity = waitForInitialLayout ? useValue$("containersDidLayout", (value) => value ? 1 : 0) : void 0;
138
265
  const containers = [];
139
266
  for (let i = 0; i < numContainers; i++) {
140
267
  containers.push(
141
- /* @__PURE__ */ React4.createElement(
268
+ /* @__PURE__ */ React5.createElement(
142
269
  Container,
143
270
  {
144
271
  id: i,
145
272
  key: i,
146
273
  recycleItems,
147
274
  horizontal,
148
- waitForInitialLayout,
149
275
  getRenderedItem,
150
276
  updateItemSize,
151
277
  ItemSeparatorComponent
@@ -153,21 +279,21 @@ var Containers = React4.memo(function Containers2({
153
279
  )
154
280
  );
155
281
  }
156
- const style = horizontal ? { width: animSize } : { height: animSize };
157
- return /* @__PURE__ */ React4.createElement(Animated.View, { style }, containers);
282
+ const style = horizontal ? { width: animSize, opacity: animOpacity } : { height: animSize, opacity: animOpacity };
283
+ return /* @__PURE__ */ React5.createElement(Animated.View, { style }, containers);
158
284
  });
159
285
 
160
286
  // src/ListComponent.tsx
161
287
  var getComponent = (Component) => {
162
- if (React4.isValidElement(Component)) {
288
+ if (React5.isValidElement(Component)) {
163
289
  return Component;
164
290
  }
165
291
  if (Component) {
166
- return /* @__PURE__ */ React4.createElement(Component, null);
292
+ return /* @__PURE__ */ React5.createElement(Component, null);
167
293
  }
168
294
  return null;
169
295
  };
170
- var ListComponent = React4.memo(function ListComponent2({
296
+ var ListComponent = React5.memo(function ListComponent2({
171
297
  style,
172
298
  contentContainerStyle,
173
299
  horizontal,
@@ -195,11 +321,11 @@ var ListComponent = React4.memo(function ListComponent2({
195
321
  const animPaddingTop = useValue$("paddingTop");
196
322
  const animScrollAdjust = useValue$("scrollAdjust");
197
323
  const ScrollComponent = renderScrollComponent ? useMemo(
198
- () => React4.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
324
+ () => React5.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
199
325
  [renderScrollComponent]
200
326
  ) : ScrollView;
201
327
  const additionalSize = { marginTop: animScrollAdjust, paddingTop: animPaddingTop };
202
- return /* @__PURE__ */ React4.createElement(
328
+ return /* @__PURE__ */ React5.createElement(
203
329
  ScrollComponent,
204
330
  {
205
331
  ...rest,
@@ -217,8 +343,8 @@ var ListComponent = React4.memo(function ListComponent2({
217
343
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
218
344
  ref: refScrollView
219
345
  },
220
- /* @__PURE__ */ React4.createElement(Animated.View, { style: additionalSize }),
221
- ListHeaderComponent && /* @__PURE__ */ React4.createElement(
346
+ /* @__PURE__ */ React5.createElement(Animated.View, { style: additionalSize }),
347
+ ListHeaderComponent && /* @__PURE__ */ React5.createElement(
222
348
  Animated.View,
223
349
  {
224
350
  style: ListHeaderComponentStyle,
@@ -232,8 +358,8 @@ var ListComponent = React4.memo(function ListComponent2({
232
358
  },
233
359
  getComponent(ListHeaderComponent)
234
360
  ),
235
- ListEmptyComponent && /* @__PURE__ */ React4.createElement(Animated.View, { style: ListEmptyComponentStyle }, getComponent(ListEmptyComponent)),
236
- /* @__PURE__ */ React4.createElement(
361
+ ListEmptyComponent && /* @__PURE__ */ React5.createElement(Animated.View, { style: ListEmptyComponentStyle }, getComponent(ListEmptyComponent)),
362
+ /* @__PURE__ */ React5.createElement(
237
363
  Containers,
238
364
  {
239
365
  horizontal,
@@ -244,7 +370,7 @@ var ListComponent = React4.memo(function ListComponent2({
244
370
  updateItemSize
245
371
  }
246
372
  ),
247
- ListFooterComponent && /* @__PURE__ */ React4.createElement(View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
373
+ ListFooterComponent && /* @__PURE__ */ React5.createElement(View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
248
374
  );
249
375
  });
250
376
 
@@ -284,14 +410,6 @@ var ScrollAdjustHandler = class {
284
410
  return this.appliedAdjust;
285
411
  }
286
412
  };
287
- var symbolFirst = Symbol();
288
- function useInit(cb) {
289
- const refValue = useRef(symbolFirst);
290
- if (refValue.current === symbolFirst) {
291
- refValue.current = cb();
292
- }
293
- return refValue.current;
294
- }
295
413
 
296
414
  // src/viewability.ts
297
415
  var mapViewabilityConfigCallbackPairs = /* @__PURE__ */ new Map();
@@ -442,13 +560,12 @@ function maybeUpdateViewabilityCallback(ctx, configId, viewToken) {
442
560
 
443
561
  // src/LegendList.tsx
444
562
  var DEFAULT_DRAW_DISTANCE = 250;
445
- var POSITION_OUT_OF_VIEW = -1e7;
446
563
  var DEFAULT_ITEM_SIZE = 100;
447
564
  var LegendList = forwardRef(function LegendList2(props, forwardedRef) {
448
- return /* @__PURE__ */ React4.createElement(StateProvider, null, /* @__PURE__ */ React4.createElement(LegendListInner, { ...props, ref: forwardedRef }));
565
+ return /* @__PURE__ */ React5.createElement(StateProvider, null, /* @__PURE__ */ React5.createElement(LegendListInner, { ...props, ref: forwardedRef }));
449
566
  });
450
567
  var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef) {
451
- var _a, _b, _c, _d;
568
+ var _a, _b, _c, _d, _e;
452
569
  const {
453
570
  data,
454
571
  initialScrollIndex,
@@ -474,6 +591,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
474
591
  onItemSizeChanged,
475
592
  scrollEventThrottle,
476
593
  refScrollView,
594
+ waitForInitialLayout = true,
477
595
  extraData,
478
596
  ...rest
479
597
  } = props;
@@ -524,7 +642,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
524
642
  positions: /* @__PURE__ */ new Map(),
525
643
  columns: /* @__PURE__ */ new Map(),
526
644
  pendingAdjust: 0,
527
- animFrameLayout: null,
645
+ waitingForMicrotask: false,
528
646
  isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
529
647
  isEndReached: false,
530
648
  isAtBottom: false,
@@ -557,7 +675,6 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
557
675
  belowAnchorElementPositions: void 0,
558
676
  rowHeights: /* @__PURE__ */ new Map(),
559
677
  startReachedBlockedByTimer: false,
560
- layoutsPending: /* @__PURE__ */ new Set(),
561
678
  scrollForNextCalculateItemsInView: void 0,
562
679
  enableScrollForNextCalculateItemsInView: true
563
680
  };
@@ -578,6 +695,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
578
695
  }
579
696
  }
580
697
  set$(ctx, "scrollAdjust", 0);
698
+ set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
581
699
  set$(ctx, "extraData", extraData);
582
700
  }
583
701
  const getAnchorElementIndex = () => {
@@ -687,12 +805,10 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
687
805
  startBufferedId: startBufferedIdOrig,
688
806
  positions,
689
807
  columns,
690
- scrollAdjustHandler,
691
- layoutsPending
808
+ scrollAdjustHandler
692
809
  } = state;
693
- if (state.animFrameLayout) {
694
- cancelAnimationFrame(state.animFrameLayout);
695
- state.animFrameLayout = null;
810
+ if (state.waitingForMicrotask) {
811
+ state.waitingForMicrotask = false;
696
812
  }
697
813
  if (!data2) {
698
814
  return;
@@ -834,7 +950,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
834
950
  break;
835
951
  }
836
952
  const index = state.indexByKey.get(key);
837
- const pos = peek$(ctx, `containerPosition${u}`);
953
+ const pos = peek$(ctx, `containerPosition${u}`).top;
838
954
  if (index < startBuffered || index > endBuffered) {
839
955
  const distance = Math.abs(pos - top2);
840
956
  if (index < 0 || distance > furthestDistance) {
@@ -853,7 +969,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
853
969
  set$(ctx, `containerItemKey${containerId}`, id);
854
970
  const index = state.indexByKey.get(id);
855
971
  set$(ctx, `containerItemData${containerId}`, data2[index]);
856
- set$(ctx, `containerPosition${containerId}`, POSITION_OUT_OF_VIEW);
972
+ set$(ctx, `containerPosition${containerId}`, ANCHORED_POSITION_OUT_OF_VIEW);
857
973
  set$(ctx, `containerColumn${containerId}`, -1);
858
974
  if (__DEV__ && numContainers > peek$(ctx, "numContainersPooled")) {
859
975
  console.warn(
@@ -877,19 +993,31 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
877
993
  if (item) {
878
994
  const id = getId(itemIndex);
879
995
  if (itemKey !== id || itemIndex < startBuffered || itemIndex > endBuffered) {
880
- const prevPos = peek$(ctx, `containerPosition${i}`);
996
+ const prevPos = peek$(ctx, `containerPosition${i}`).top;
881
997
  const pos = positions.get(id) || 0;
882
998
  const size = getItemSize(id, itemIndex, data2[i]);
883
999
  if (pos + size >= scroll && pos <= scrollBottom || prevPos + size >= scroll && prevPos <= scrollBottom) {
884
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1000
+ set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
885
1001
  }
886
1002
  } else {
887
- const pos = positions.get(id) || 0;
1003
+ const pos = {
1004
+ type: "top",
1005
+ relativeCoordinate: positions.get(id) || 0,
1006
+ top: positions.get(id) || 0
1007
+ };
888
1008
  const column2 = columns.get(id) || 1;
1009
+ if (maintainVisibleContentPosition && itemIndex < anchorElementIndex) {
1010
+ const currentRow = Math.floor(itemIndex / numColumnsProp);
1011
+ const rowHeight = getRowHeight(currentRow);
1012
+ const elementHeight = getItemSize(id, itemIndex, data2[i]);
1013
+ const diff = rowHeight - elementHeight;
1014
+ pos.relativeCoordinate = pos.top + getRowHeight(currentRow) - diff;
1015
+ pos.type = "bottom";
1016
+ }
889
1017
  const prevPos = peek$(ctx, `containerPosition${i}`);
890
1018
  const prevColumn = peek$(ctx, `containerColumn${i}`);
891
1019
  const prevData = peek$(ctx, `containerItemData${i}`);
892
- if (pos > POSITION_OUT_OF_VIEW && pos !== prevPos) {
1020
+ if (pos.relativeCoordinate > POSITION_OUT_OF_VIEW && pos.top !== prevPos.top) {
893
1021
  set$(ctx, `containerPosition${i}`, pos);
894
1022
  }
895
1023
  if (column2 >= 0 && column2 !== prevColumn) {
@@ -902,12 +1030,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
902
1030
  }
903
1031
  }
904
1032
  }
905
- if (layoutsPending.size > 0) {
906
- for (const containerId of layoutsPending) {
907
- set$(ctx, `containerDidLayout${containerId}`, true);
908
- }
909
- layoutsPending.clear();
910
- }
1033
+ set$(ctx, "containersDidLayout", true);
911
1034
  if (state.viewabilityConfigCallbackPairs) {
912
1035
  updateViewableItems(
913
1036
  state,
@@ -1000,13 +1123,13 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1000
1123
  const itemKey = peek$(ctx, `containerItemKey${i}`);
1001
1124
  if (!keyExtractorProp || itemKey && state.indexByKey.get(itemKey) === void 0) {
1002
1125
  set$(ctx, `containerItemKey${i}`, void 0);
1003
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1126
+ set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1004
1127
  set$(ctx, `containerColumn${i}`, -1);
1005
1128
  }
1006
1129
  }
1007
1130
  if (!keyExtractorProp) {
1008
1131
  state.sizes.clear();
1009
- state.positions;
1132
+ state.positions.clear();
1010
1133
  }
1011
1134
  calculateItemsInView(state.scrollVelocity);
1012
1135
  }
@@ -1028,13 +1151,48 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1028
1151
  let totalSize = 0;
1029
1152
  let totalSizeBelowIndex = 0;
1030
1153
  const indexByKey = /* @__PURE__ */ new Map();
1154
+ const newPositions = /* @__PURE__ */ new Map();
1031
1155
  let column = 1;
1032
1156
  let maxSizeInRow = 0;
1033
1157
  for (let i = 0; i < data.length; i++) {
1034
1158
  const key = getId(i);
1035
1159
  indexByKey.set(key, i);
1160
+ if (refState.current.positions.get(key) != null && refState.current.indexByKey.get(key) === i) {
1161
+ newPositions.set(key, refState.current.positions.get(key));
1162
+ }
1036
1163
  }
1037
1164
  refState.current.indexByKey = indexByKey;
1165
+ refState.current.positions = newPositions;
1166
+ if (maintainVisibleContentPosition) {
1167
+ if (refState.current.anchorElement == null || indexByKey.get(refState.current.anchorElement.id) == null) {
1168
+ if (data.length) {
1169
+ const newAnchorElement = {
1170
+ coordinate: 0,
1171
+ id: getId(0)
1172
+ };
1173
+ refState.current.anchorElement = newAnchorElement;
1174
+ (_a = refState.current.belowAnchorElementPositions) == null ? void 0 : _a.clear();
1175
+ refScroller.current.scrollTo({ x: 0, y: 0, animated: false });
1176
+ setTimeout(() => {
1177
+ calculateItemsInView(0);
1178
+ }, 0);
1179
+ } else {
1180
+ refState.current.startBufferedId = void 0;
1181
+ }
1182
+ }
1183
+ } else {
1184
+ if (refState.current.startBufferedId != null && newPositions.get(refState.current.startBufferedId) == null) {
1185
+ if (data.length) {
1186
+ refState.current.startBufferedId = getId(0);
1187
+ } else {
1188
+ refState.current.startBufferedId = void 0;
1189
+ }
1190
+ refScroller.current.scrollTo({ x: 0, y: 0, animated: false });
1191
+ setTimeout(() => {
1192
+ calculateItemsInView(0);
1193
+ }, 0);
1194
+ }
1195
+ }
1038
1196
  const anchorElementIndex = getAnchorElementIndex();
1039
1197
  for (let i = 0; i < data.length; i++) {
1040
1198
  const key = getId(i);
@@ -1066,7 +1224,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1066
1224
  }, [extraData]);
1067
1225
  refState.current.renderItem = renderItem;
1068
1226
  const lastItemKey = getId(data[data.length - 1]);
1069
- const stylePaddingTop = (_d = (_c = (_a = StyleSheet.flatten(style)) == null ? void 0 : _a.paddingTop) != null ? _c : (_b = StyleSheet.flatten(contentContainerStyle)) == null ? void 0 : _b.paddingTop) != null ? _d : 0;
1227
+ const stylePaddingTop = (_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;
1070
1228
  const initalizeStateVars = () => {
1071
1229
  set$(ctx, "lastItemKey", lastItemKey);
1072
1230
  set$(ctx, "numColumns", numColumnsProp);
@@ -1076,7 +1234,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1076
1234
  initalizeStateVars();
1077
1235
  }
1078
1236
  useEffect(initalizeStateVars, [lastItemKey, numColumnsProp, stylePaddingTop]);
1079
- const getRenderedItem = useCallback((key, containerId) => {
1237
+ const getRenderedItem = useCallback((key) => {
1080
1238
  var _a2, _b2;
1081
1239
  const state = refState.current;
1082
1240
  if (!state) {
@@ -1087,89 +1245,27 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1087
1245
  if (index === void 0) {
1088
1246
  return null;
1089
1247
  }
1090
- const useViewability = (configId, callback) => {
1091
- const key2 = containerId + configId;
1092
- useInit(() => {
1093
- const value = ctx.mapViewabilityValues.get(key2);
1094
- if (value) {
1095
- callback(value);
1096
- }
1097
- });
1098
- ctx.mapViewabilityCallbacks.set(key2, callback);
1099
- useEffect(
1100
- () => () => {
1101
- ctx.mapViewabilityCallbacks.delete(key2);
1102
- },
1103
- []
1104
- );
1248
+ const useViewability2 = (configId, callback) => {
1249
+ useViewability(configId, callback);
1105
1250
  };
1106
- const useViewabilityAmount = (callback) => {
1107
- useInit(() => {
1108
- const value = ctx.mapViewabilityAmountValues.get(containerId);
1109
- if (value) {
1110
- callback(value);
1111
- }
1112
- });
1113
- ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
1114
- useEffect(
1115
- () => () => {
1116
- ctx.mapViewabilityAmountCallbacks.delete(containerId);
1117
- },
1118
- []
1119
- );
1251
+ const useViewabilityAmount2 = (callback) => {
1252
+ useViewabilityAmount(callback);
1120
1253
  };
1121
- const useRecyclingEffect = (effect) => {
1122
- useEffect(() => {
1123
- const state2 = refState.current;
1124
- let prevIndex = index;
1125
- let prevItem = state2.data[index];
1126
- const signal = `containerItemKey${containerId}`;
1127
- const run = () => {
1128
- const data3 = state2.data;
1129
- if (data3) {
1130
- const newKey = peek$(ctx, signal);
1131
- const newIndex = state2.indexByKey.get(newKey);
1132
- const newItem = data3[newIndex];
1133
- if (newItem) {
1134
- effect({
1135
- index: newIndex,
1136
- item: newItem,
1137
- prevIndex,
1138
- prevItem
1139
- });
1140
- }
1141
- prevIndex = newIndex;
1142
- prevItem = newItem;
1143
- }
1144
- };
1145
- run();
1146
- return listen$(ctx, signal, run);
1147
- }, []);
1254
+ const useRecyclingEffect2 = (effect) => {
1255
+ useRecyclingEffect(effect);
1148
1256
  };
1149
- const useRecyclingState = (valueOrFun) => {
1150
- const stateInfo = useState(
1151
- () => typeof valueOrFun === "function" ? valueOrFun({
1152
- index,
1153
- item: refState.current.data[index],
1154
- prevIndex: void 0,
1155
- prevItem: void 0
1156
- }) : valueOrFun
1157
- );
1158
- useRecyclingEffect((state2) => {
1159
- const newState = typeof valueOrFun === "function" ? valueOrFun(state2) : valueOrFun;
1160
- stateInfo[1](newState);
1161
- });
1162
- return stateInfo;
1257
+ const useRecyclingState2 = (valueOrFun) => {
1258
+ return useRecyclingState(valueOrFun);
1163
1259
  };
1164
1260
  const renderedItem = (_b2 = (_a2 = refState.current).renderItem) == null ? void 0 : _b2.call(_a2, {
1165
1261
  item: data2[index],
1166
1262
  index,
1167
- useViewability,
1168
- useViewabilityAmount,
1169
- useRecyclingEffect,
1170
- useRecyclingState
1263
+ useViewability: useViewability2,
1264
+ useViewabilityAmount: useViewabilityAmount2,
1265
+ useRecyclingEffect: useRecyclingEffect2,
1266
+ useRecyclingState: useRecyclingState2
1171
1267
  });
1172
- return renderedItem;
1268
+ return { index, renderedItem };
1173
1269
  }, []);
1174
1270
  useInit(() => {
1175
1271
  var _a2;
@@ -1181,7 +1277,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1181
1277
  const averageItemSize = (_a2 = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, data[0])) != null ? _a2 : DEFAULT_ITEM_SIZE;
1182
1278
  const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) * numColumnsProp;
1183
1279
  for (let i = 0; i < numContainers; i++) {
1184
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1280
+ set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1185
1281
  set$(ctx, `containerColumn${i}`, -1);
1186
1282
  }
1187
1283
  set$(ctx, "numContainers", numContainers);
@@ -1195,15 +1291,11 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1195
1291
  return;
1196
1292
  }
1197
1293
  const state = refState.current;
1198
- const { sizes, indexByKey, idsInFirstRender, columns, sizesLaidOut } = state;
1294
+ const { sizes, indexByKey, columns, sizesLaidOut } = state;
1199
1295
  const index = indexByKey.get(itemKey);
1200
1296
  const numColumns = peek$(ctx, "numColumns");
1201
1297
  const row = Math.floor(index / numColumns);
1202
1298
  const prevSize = getRowHeight(row);
1203
- const measured = peek$(ctx, `containerDidLayout${containerId}`);
1204
- if (!measured) {
1205
- state.layoutsPending.add(containerId);
1206
- }
1207
1299
  if (!prevSize || Math.abs(prevSize - size) > 0.5) {
1208
1300
  let diff;
1209
1301
  if (numColumns > 1) {
@@ -1245,11 +1337,14 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1245
1337
  addTotalSize(itemKey, diff, 0);
1246
1338
  doMaintainScrollAtEnd(true);
1247
1339
  const scrollVelocity = state.scrollVelocity;
1248
- if (!state.animFrameLayout && (Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1)) {
1249
- if (!peek$(ctx, `containerDidLayout${containerId}`)) {
1250
- state.animFrameLayout = requestAnimationFrame(() => {
1251
- state.animFrameLayout = null;
1252
- calculateItemsInView(state.scrollVelocity);
1340
+ if (!state.waitingForMicrotask && (Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1)) {
1341
+ if (!peek$(ctx, "containersDidLayout")) {
1342
+ state.waitingForMicrotask = true;
1343
+ queueMicrotask(() => {
1344
+ if (state.waitingForMicrotask) {
1345
+ state.waitingForMicrotask = false;
1346
+ calculateItemsInView(state.scrollVelocity);
1347
+ }
1253
1348
  });
1254
1349
  } else {
1255
1350
  calculateItemsInView(state.scrollVelocity);
@@ -1258,8 +1353,6 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1258
1353
  if (onItemSizeChanged) {
1259
1354
  onItemSizeChanged({ size, previous: prevSize, index, itemKey, itemData: data2[index] });
1260
1355
  }
1261
- } else {
1262
- set$(ctx, `containerDidLayout${containerId}`, true);
1263
1356
  }
1264
1357
  }, []);
1265
1358
  const handleScrollDebounced = useCallback((velocity) => {
@@ -1355,7 +1448,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1355
1448
  },
1356
1449
  []
1357
1450
  );
1358
- return /* @__PURE__ */ React4.createElement(
1451
+ return /* @__PURE__ */ React5.createElement(
1359
1452
  ListComponent,
1360
1453
  {
1361
1454
  ...rest,
@@ -1380,9 +1473,10 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1380
1473
  ListEmptyComponent: data.length === 0 ? ListEmptyComponent : void 0,
1381
1474
  maintainVisibleContentPosition,
1382
1475
  scrollEventThrottle: scrollEventThrottle != null ? scrollEventThrottle : Platform.OS === "web" ? 16 : void 0,
1476
+ waitForInitialLayout,
1383
1477
  style
1384
1478
  }
1385
1479
  );
1386
1480
  });
1387
1481
 
1388
- export { LegendList };
1482
+ export { LegendList, useRecyclingEffect, useRecyclingState, useViewability, useViewabilityAmount };