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

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,179 @@ 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
158
+ var isNewArchitecture = global.nativeFabricUIManager != null;
61
159
  var Container = ({
62
160
  id,
63
161
  recycleItems,
64
162
  horizontal,
65
- waitForInitialLayout,
66
163
  getRenderedItem,
67
164
  updateItemSize,
68
165
  ItemSeparatorComponent
69
166
  }) => {
70
- const ctx = useStateContext();
71
- const position = use$(`containerPosition${id}`);
167
+ useStateContext();
168
+ const maintainVisibleContentPosition = use$("maintainVisibleContentPosition");
169
+ const position = use$(`containerPosition${id}`) || ANCHORED_POSITION_OUT_OF_VIEW;
72
170
  const column = use$(`containerColumn${id}`) || 0;
73
171
  const numColumns = use$("numColumns");
74
172
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
75
173
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
76
174
  const style = horizontal ? {
77
- flexDirection: "row",
175
+ flexDirection: ItemSeparatorComponent ? "row" : void 0,
78
176
  position: "absolute",
79
177
  top: otherAxisPos,
80
178
  bottom: numColumns > 1 ? null : 0,
81
179
  height: otherAxisSize,
82
- left: position
180
+ left: position.relativeCoordinate
83
181
  } : {
84
182
  position: "absolute",
85
183
  left: otherAxisPos,
86
184
  right: numColumns > 1 ? null : 0,
87
185
  width: otherAxisSize,
88
- top: position
186
+ top: position.relativeCoordinate
89
187
  };
90
- if (waitForInitialLayout) {
91
- const visible = use$(`containerDidLayout${id}`);
92
- style.opacity = visible ? 1 : 0;
93
- }
94
188
  const lastItemKey = use$("lastItemKey");
95
189
  const itemKey = use$(`containerItemKey${id}`);
96
190
  const data = use$(`containerItemData${id}`);
97
191
  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);
192
+ const renderedItemInfo = useMemo(
193
+ () => itemKey !== void 0 && getRenderedItem(itemKey),
194
+ [itemKey, data, extraData]
195
+ );
196
+ const { index, renderedItem } = renderedItemInfo || {};
197
+ const onLayout = (event) => {
198
+ if (itemKey !== void 0) {
199
+ const size = Math.floor(event.nativeEvent.layout[horizontal ? "width" : "height"] * 8) / 8;
200
+ if (size === 0) {
201
+ console.log("[WARN] Container 0 height reported, possible bug in LegendList", id, itemKey);
202
+ return;
203
+ }
204
+ updateItemSize(id, itemKey, size);
205
+ }
206
+ };
207
+ const ref = useRef(null);
208
+ if (isNewArchitecture) {
209
+ useLayoutEffect(() => {
210
+ var _a, _b;
211
+ if (itemKey) {
212
+ const measured = (_b = (_a = ref.current) == null ? void 0 : _a.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a);
213
+ if (measured) {
214
+ const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
215
+ if (size) {
216
+ updateItemSize(id, itemKey, size);
217
+ }
108
218
  }
109
219
  }
110
- },
111
- /* @__PURE__ */ React4__default.createElement(React4__default.Fragment, { key: recycleItems ? void 0 : itemKey }, renderedItem, renderedItem && ItemSeparatorComponent && itemKey !== lastItemKey && ItemSeparatorComponent)
220
+ }, [itemKey]);
221
+ }
222
+ const contextValue = useMemo(
223
+ () => ({ containerId: id, itemKey, index, value: data }),
224
+ [id, itemKey, index, data]
112
225
  );
226
+ 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));
227
+ if (maintainVisibleContentPosition) {
228
+ const anchorStyle = position.type === "top" ? { position: "absolute", top: 0, left: 0, right: 0 } : { position: "absolute", bottom: 0, left: 0, right: 0 };
229
+ return /* @__PURE__ */ React5__default.createElement(LeanView, { style }, /* @__PURE__ */ React5__default.createElement(LeanView, { style: anchorStyle, onLayout, ref }, contentFragment));
230
+ }
231
+ return /* @__PURE__ */ React5__default.createElement(LeanView, { style, onLayout, ref }, contentFragment);
113
232
  };
114
233
  var useAnimatedValue = useAnimatedValue$1 || ((initialValue) => {
115
234
  return useRef(new Animated.Value(initialValue)).current;
@@ -117,15 +236,15 @@ var useAnimatedValue = useAnimatedValue$1 || ((initialValue) => {
117
236
  function useValue$(key, getValue, key2) {
118
237
  var _a;
119
238
  const ctx = useStateContext();
120
- const animValue = useAnimatedValue((_a = peek$(ctx, key)) != null ? _a : 0);
239
+ const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
121
240
  useMemo(() => {
122
- listen$(ctx, key, (v) => animValue.setValue(v));
241
+ listen$(ctx, key, (v) => animValue.setValue(getValue ? getValue(v) : v));
123
242
  }, []);
124
243
  return animValue;
125
244
  }
126
245
 
127
246
  // src/Containers.tsx
128
- var Containers = React4.memo(function Containers2({
247
+ var Containers = React5.memo(function Containers2({
129
248
  horizontal,
130
249
  recycleItems,
131
250
  ItemSeparatorComponent,
@@ -135,17 +254,17 @@ var Containers = React4.memo(function Containers2({
135
254
  }) {
136
255
  const numContainers = use$("numContainersPooled");
137
256
  const animSize = useValue$("totalSize");
257
+ const animOpacity = waitForInitialLayout ? useValue$("containersDidLayout", (value) => value ? 1 : 0) : void 0;
138
258
  const containers = [];
139
259
  for (let i = 0; i < numContainers; i++) {
140
260
  containers.push(
141
- /* @__PURE__ */ React4.createElement(
261
+ /* @__PURE__ */ React5.createElement(
142
262
  Container,
143
263
  {
144
264
  id: i,
145
265
  key: i,
146
266
  recycleItems,
147
267
  horizontal,
148
- waitForInitialLayout,
149
268
  getRenderedItem,
150
269
  updateItemSize,
151
270
  ItemSeparatorComponent
@@ -153,21 +272,21 @@ var Containers = React4.memo(function Containers2({
153
272
  )
154
273
  );
155
274
  }
156
- const style = horizontal ? { width: animSize } : { height: animSize };
157
- return /* @__PURE__ */ React4.createElement(Animated.View, { style }, containers);
275
+ const style = horizontal ? { width: animSize, opacity: animOpacity } : { height: animSize, opacity: animOpacity };
276
+ return /* @__PURE__ */ React5.createElement(Animated.View, { style }, containers);
158
277
  });
159
278
 
160
279
  // src/ListComponent.tsx
161
280
  var getComponent = (Component) => {
162
- if (React4.isValidElement(Component)) {
281
+ if (React5.isValidElement(Component)) {
163
282
  return Component;
164
283
  }
165
284
  if (Component) {
166
- return /* @__PURE__ */ React4.createElement(Component, null);
285
+ return /* @__PURE__ */ React5.createElement(Component, null);
167
286
  }
168
287
  return null;
169
288
  };
170
- var ListComponent = React4.memo(function ListComponent2({
289
+ var ListComponent = React5.memo(function ListComponent2({
171
290
  style,
172
291
  contentContainerStyle,
173
292
  horizontal,
@@ -183,7 +302,6 @@ var ListComponent = React4.memo(function ListComponent2({
183
302
  ListFooterComponent,
184
303
  ListFooterComponentStyle,
185
304
  ListEmptyComponent,
186
- ListEmptyComponentStyle,
187
305
  getRenderedItem,
188
306
  updateItemSize,
189
307
  refScrollView,
@@ -195,11 +313,11 @@ var ListComponent = React4.memo(function ListComponent2({
195
313
  const animPaddingTop = useValue$("paddingTop");
196
314
  const animScrollAdjust = useValue$("scrollAdjust");
197
315
  const ScrollComponent = renderScrollComponent ? useMemo(
198
- () => React4.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
316
+ () => React5.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
199
317
  [renderScrollComponent]
200
318
  ) : ScrollView;
201
319
  const additionalSize = { marginTop: animScrollAdjust, paddingTop: animPaddingTop };
202
- return /* @__PURE__ */ React4.createElement(
320
+ return /* @__PURE__ */ React5.createElement(
203
321
  ScrollComponent,
204
322
  {
205
323
  ...rest,
@@ -217,8 +335,8 @@ var ListComponent = React4.memo(function ListComponent2({
217
335
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
218
336
  ref: refScrollView
219
337
  },
220
- /* @__PURE__ */ React4.createElement(Animated.View, { style: additionalSize }),
221
- ListHeaderComponent && /* @__PURE__ */ React4.createElement(
338
+ /* @__PURE__ */ React5.createElement(Animated.View, { style: additionalSize }),
339
+ ListHeaderComponent && /* @__PURE__ */ React5.createElement(
222
340
  Animated.View,
223
341
  {
224
342
  style: ListHeaderComponentStyle,
@@ -232,8 +350,8 @@ var ListComponent = React4.memo(function ListComponent2({
232
350
  },
233
351
  getComponent(ListHeaderComponent)
234
352
  ),
235
- ListEmptyComponent && /* @__PURE__ */ React4.createElement(Animated.View, { style: ListEmptyComponentStyle }, getComponent(ListEmptyComponent)),
236
- /* @__PURE__ */ React4.createElement(
353
+ ListEmptyComponent && getComponent(ListEmptyComponent),
354
+ /* @__PURE__ */ React5.createElement(
237
355
  Containers,
238
356
  {
239
357
  horizontal,
@@ -244,7 +362,7 @@ var ListComponent = React4.memo(function ListComponent2({
244
362
  updateItemSize
245
363
  }
246
364
  ),
247
- ListFooterComponent && /* @__PURE__ */ React4.createElement(View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
365
+ ListFooterComponent && /* @__PURE__ */ React5.createElement(View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
248
366
  );
249
367
  });
250
368
 
@@ -284,14 +402,6 @@ var ScrollAdjustHandler = class {
284
402
  return this.appliedAdjust;
285
403
  }
286
404
  };
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
405
 
296
406
  // src/viewability.ts
297
407
  var mapViewabilityConfigCallbackPairs = /* @__PURE__ */ new Map();
@@ -442,13 +552,12 @@ function maybeUpdateViewabilityCallback(ctx, configId, viewToken) {
442
552
 
443
553
  // src/LegendList.tsx
444
554
  var DEFAULT_DRAW_DISTANCE = 250;
445
- var POSITION_OUT_OF_VIEW = -1e7;
446
555
  var DEFAULT_ITEM_SIZE = 100;
447
556
  var LegendList = forwardRef(function LegendList2(props, forwardedRef) {
448
- return /* @__PURE__ */ React4.createElement(StateProvider, null, /* @__PURE__ */ React4.createElement(LegendListInner, { ...props, ref: forwardedRef }));
557
+ return /* @__PURE__ */ React5.createElement(StateProvider, null, /* @__PURE__ */ React5.createElement(LegendListInner, { ...props, ref: forwardedRef }));
449
558
  });
450
559
  var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef) {
451
- var _a, _b, _c, _d;
560
+ var _a, _b, _c, _d, _e;
452
561
  const {
453
562
  data,
454
563
  initialScrollIndex,
@@ -474,6 +583,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
474
583
  onItemSizeChanged,
475
584
  scrollEventThrottle,
476
585
  refScrollView,
586
+ waitForInitialLayout = true,
477
587
  extraData,
478
588
  ...rest
479
589
  } = props;
@@ -524,7 +634,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
524
634
  positions: /* @__PURE__ */ new Map(),
525
635
  columns: /* @__PURE__ */ new Map(),
526
636
  pendingAdjust: 0,
527
- animFrameLayout: null,
637
+ waitingForMicrotask: false,
528
638
  isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
529
639
  isEndReached: false,
530
640
  isAtBottom: false,
@@ -557,7 +667,6 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
557
667
  belowAnchorElementPositions: void 0,
558
668
  rowHeights: /* @__PURE__ */ new Map(),
559
669
  startReachedBlockedByTimer: false,
560
- layoutsPending: /* @__PURE__ */ new Set(),
561
670
  scrollForNextCalculateItemsInView: void 0,
562
671
  enableScrollForNextCalculateItemsInView: true
563
672
  };
@@ -578,6 +687,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
578
687
  }
579
688
  }
580
689
  set$(ctx, "scrollAdjust", 0);
690
+ set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
581
691
  set$(ctx, "extraData", extraData);
582
692
  }
583
693
  const getAnchorElementIndex = () => {
@@ -597,7 +707,6 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
597
707
  isAboveAnchor = true;
598
708
  }
599
709
  }
600
- state.totalSize;
601
710
  if (key === null) {
602
711
  state.totalSize = add;
603
712
  state.totalSizeBelowAnchor = totalSizeBelowAnchor;
@@ -687,12 +796,10 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
687
796
  startBufferedId: startBufferedIdOrig,
688
797
  positions,
689
798
  columns,
690
- scrollAdjustHandler,
691
- layoutsPending
799
+ scrollAdjustHandler
692
800
  } = state;
693
- if (state.animFrameLayout) {
694
- cancelAnimationFrame(state.animFrameLayout);
695
- state.animFrameLayout = null;
801
+ if (state.waitingForMicrotask) {
802
+ state.waitingForMicrotask = false;
696
803
  }
697
804
  if (!data2) {
698
805
  return;
@@ -700,7 +807,17 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
700
807
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
701
808
  const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
702
809
  const scrollExtra = Math.max(-16, Math.min(16, speed)) * 16;
703
- const scroll = scrollState - previousScrollAdjust - topPad - scrollExtra;
810
+ const scroll = scrollState - previousScrollAdjust - topPad;
811
+ let scrollBufferTop = scrollBuffer;
812
+ let scrollBufferBottom = scrollBuffer;
813
+ if (scrollExtra > 8) {
814
+ scrollBufferTop = 0;
815
+ scrollBufferBottom = scrollBuffer + scrollExtra;
816
+ }
817
+ if (scrollExtra < -8) {
818
+ scrollBufferTop = scrollBuffer - scrollExtra;
819
+ scrollBufferBottom = 0;
820
+ }
704
821
  if (state.scrollForNextCalculateItemsInView) {
705
822
  const { top: top2, bottom } = state.scrollForNextCalculateItemsInView;
706
823
  if (scroll > top2 && scroll < bottom) {
@@ -772,7 +889,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
772
889
  if (startNoBuffer === null && top + size > scroll) {
773
890
  startNoBuffer = i;
774
891
  }
775
- if (startBuffered === null && top + size > scroll - scrollBuffer) {
892
+ if (startBuffered === null && top + size > scroll - scrollBufferTop) {
776
893
  startBuffered = i;
777
894
  startBufferedId = id;
778
895
  }
@@ -780,7 +897,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
780
897
  if (top <= scrollBottom) {
781
898
  endNoBuffer = i;
782
899
  }
783
- if (top <= scrollBottom + scrollBuffer) {
900
+ if (top <= scrollBottom + scrollBufferBottom) {
784
901
  endBuffered = i;
785
902
  } else {
786
903
  break;
@@ -834,7 +951,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
834
951
  break;
835
952
  }
836
953
  const index = state.indexByKey.get(key);
837
- const pos = peek$(ctx, `containerPosition${u}`);
954
+ const pos = peek$(ctx, `containerPosition${u}`).top;
838
955
  if (index < startBuffered || index > endBuffered) {
839
956
  const distance = Math.abs(pos - top2);
840
957
  if (index < 0 || distance > furthestDistance) {
@@ -853,7 +970,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
853
970
  set$(ctx, `containerItemKey${containerId}`, id);
854
971
  const index = state.indexByKey.get(id);
855
972
  set$(ctx, `containerItemData${containerId}`, data2[index]);
856
- set$(ctx, `containerPosition${containerId}`, POSITION_OUT_OF_VIEW);
973
+ set$(ctx, `containerPosition${containerId}`, ANCHORED_POSITION_OUT_OF_VIEW);
857
974
  set$(ctx, `containerColumn${containerId}`, -1);
858
975
  if (__DEV__ && numContainers > peek$(ctx, "numContainersPooled")) {
859
976
  console.warn(
@@ -877,19 +994,31 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
877
994
  if (item) {
878
995
  const id = getId(itemIndex);
879
996
  if (itemKey !== id || itemIndex < startBuffered || itemIndex > endBuffered) {
880
- const prevPos = peek$(ctx, `containerPosition${i}`);
997
+ const prevPos = peek$(ctx, `containerPosition${i}`).top;
881
998
  const pos = positions.get(id) || 0;
882
999
  const size = getItemSize(id, itemIndex, data2[i]);
883
1000
  if (pos + size >= scroll && pos <= scrollBottom || prevPos + size >= scroll && prevPos <= scrollBottom) {
884
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1001
+ set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
885
1002
  }
886
1003
  } else {
887
- const pos = positions.get(id) || 0;
1004
+ const pos = {
1005
+ type: "top",
1006
+ relativeCoordinate: positions.get(id) || 0,
1007
+ top: positions.get(id) || 0
1008
+ };
888
1009
  const column2 = columns.get(id) || 1;
1010
+ if (maintainVisibleContentPosition && itemIndex < anchorElementIndex) {
1011
+ const currentRow = Math.floor(itemIndex / numColumnsProp);
1012
+ const rowHeight = getRowHeight(currentRow);
1013
+ const elementHeight = getItemSize(id, itemIndex, data2[i]);
1014
+ const diff = rowHeight - elementHeight;
1015
+ pos.relativeCoordinate = pos.top + getRowHeight(currentRow) - diff;
1016
+ pos.type = "bottom";
1017
+ }
889
1018
  const prevPos = peek$(ctx, `containerPosition${i}`);
890
1019
  const prevColumn = peek$(ctx, `containerColumn${i}`);
891
1020
  const prevData = peek$(ctx, `containerItemData${i}`);
892
- if (pos > POSITION_OUT_OF_VIEW && pos !== prevPos) {
1021
+ if (pos.relativeCoordinate > POSITION_OUT_OF_VIEW && pos.top !== prevPos.top) {
893
1022
  set$(ctx, `containerPosition${i}`, pos);
894
1023
  }
895
1024
  if (column2 >= 0 && column2 !== prevColumn) {
@@ -902,12 +1031,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
902
1031
  }
903
1032
  }
904
1033
  }
905
- if (layoutsPending.size > 0) {
906
- for (const containerId of layoutsPending) {
907
- set$(ctx, `containerDidLayout${containerId}`, true);
908
- }
909
- layoutsPending.clear();
910
- }
1034
+ set$(ctx, "containersDidLayout", true);
911
1035
  if (state.viewabilityConfigCallbackPairs) {
912
1036
  updateViewableItems(
913
1037
  state,
@@ -1000,13 +1124,13 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1000
1124
  const itemKey = peek$(ctx, `containerItemKey${i}`);
1001
1125
  if (!keyExtractorProp || itemKey && state.indexByKey.get(itemKey) === void 0) {
1002
1126
  set$(ctx, `containerItemKey${i}`, void 0);
1003
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1127
+ set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1004
1128
  set$(ctx, `containerColumn${i}`, -1);
1005
1129
  }
1006
1130
  }
1007
1131
  if (!keyExtractorProp) {
1008
1132
  state.sizes.clear();
1009
- state.positions;
1133
+ state.positions.clear();
1010
1134
  }
1011
1135
  calculateItemsInView(state.scrollVelocity);
1012
1136
  }
@@ -1028,13 +1152,48 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1028
1152
  let totalSize = 0;
1029
1153
  let totalSizeBelowIndex = 0;
1030
1154
  const indexByKey = /* @__PURE__ */ new Map();
1155
+ const newPositions = /* @__PURE__ */ new Map();
1031
1156
  let column = 1;
1032
1157
  let maxSizeInRow = 0;
1033
1158
  for (let i = 0; i < data.length; i++) {
1034
1159
  const key = getId(i);
1035
1160
  indexByKey.set(key, i);
1161
+ if (refState.current.positions.get(key) != null && refState.current.indexByKey.get(key) === i) {
1162
+ newPositions.set(key, refState.current.positions.get(key));
1163
+ }
1036
1164
  }
1037
1165
  refState.current.indexByKey = indexByKey;
1166
+ refState.current.positions = newPositions;
1167
+ if (maintainVisibleContentPosition) {
1168
+ if (refState.current.anchorElement == null || indexByKey.get(refState.current.anchorElement.id) == null) {
1169
+ if (data.length) {
1170
+ const newAnchorElement = {
1171
+ coordinate: 0,
1172
+ id: getId(0)
1173
+ };
1174
+ refState.current.anchorElement = newAnchorElement;
1175
+ (_a = refState.current.belowAnchorElementPositions) == null ? void 0 : _a.clear();
1176
+ refScroller.current.scrollTo({ x: 0, y: 0, animated: false });
1177
+ setTimeout(() => {
1178
+ calculateItemsInView(0);
1179
+ }, 0);
1180
+ } else {
1181
+ refState.current.startBufferedId = void 0;
1182
+ }
1183
+ }
1184
+ } else {
1185
+ if (refState.current.startBufferedId != null && newPositions.get(refState.current.startBufferedId) == null) {
1186
+ if (data.length) {
1187
+ refState.current.startBufferedId = getId(0);
1188
+ } else {
1189
+ refState.current.startBufferedId = void 0;
1190
+ }
1191
+ refScroller.current.scrollTo({ x: 0, y: 0, animated: false });
1192
+ setTimeout(() => {
1193
+ calculateItemsInView(0);
1194
+ }, 0);
1195
+ }
1196
+ }
1038
1197
  const anchorElementIndex = getAnchorElementIndex();
1039
1198
  for (let i = 0; i < data.length; i++) {
1040
1199
  const key = getId(i);
@@ -1065,8 +1224,8 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1065
1224
  set$(ctx, "extraData", extraData);
1066
1225
  }, [extraData]);
1067
1226
  refState.current.renderItem = renderItem;
1068
- 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 lastItemKey = data.length > 0 ? getId(data.length - 1) : void 0;
1228
+ 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
1229
  const initalizeStateVars = () => {
1071
1230
  set$(ctx, "lastItemKey", lastItemKey);
1072
1231
  set$(ctx, "numColumns", numColumnsProp);
@@ -1076,7 +1235,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1076
1235
  initalizeStateVars();
1077
1236
  }
1078
1237
  useEffect(initalizeStateVars, [lastItemKey, numColumnsProp, stylePaddingTop]);
1079
- const getRenderedItem = useCallback((key, containerId) => {
1238
+ const getRenderedItem = useCallback((key) => {
1080
1239
  var _a2, _b2;
1081
1240
  const state = refState.current;
1082
1241
  if (!state) {
@@ -1087,89 +1246,27 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1087
1246
  if (index === void 0) {
1088
1247
  return null;
1089
1248
  }
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
- );
1249
+ const useViewability2 = (configId, callback) => {
1250
+ useViewability(configId, callback);
1105
1251
  };
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
- );
1252
+ const useViewabilityAmount2 = (callback) => {
1253
+ useViewabilityAmount(callback);
1120
1254
  };
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
- }, []);
1255
+ const useRecyclingEffect2 = (effect) => {
1256
+ useRecyclingEffect(effect);
1148
1257
  };
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;
1258
+ const useRecyclingState2 = (valueOrFun) => {
1259
+ return useRecyclingState(valueOrFun);
1163
1260
  };
1164
1261
  const renderedItem = (_b2 = (_a2 = refState.current).renderItem) == null ? void 0 : _b2.call(_a2, {
1165
1262
  item: data2[index],
1166
1263
  index,
1167
- useViewability,
1168
- useViewabilityAmount,
1169
- useRecyclingEffect,
1170
- useRecyclingState
1264
+ useViewability: useViewability2,
1265
+ useViewabilityAmount: useViewabilityAmount2,
1266
+ useRecyclingEffect: useRecyclingEffect2,
1267
+ useRecyclingState: useRecyclingState2
1171
1268
  });
1172
- return renderedItem;
1269
+ return { index, renderedItem };
1173
1270
  }, []);
1174
1271
  useInit(() => {
1175
1272
  var _a2;
@@ -1181,7 +1278,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1181
1278
  const averageItemSize = (_a2 = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, data[0])) != null ? _a2 : DEFAULT_ITEM_SIZE;
1182
1279
  const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) * numColumnsProp;
1183
1280
  for (let i = 0; i < numContainers; i++) {
1184
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1281
+ set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1185
1282
  set$(ctx, `containerColumn${i}`, -1);
1186
1283
  }
1187
1284
  set$(ctx, "numContainers", numContainers);
@@ -1195,15 +1292,11 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1195
1292
  return;
1196
1293
  }
1197
1294
  const state = refState.current;
1198
- const { sizes, indexByKey, idsInFirstRender, columns, sizesLaidOut } = state;
1295
+ const { sizes, indexByKey, columns, sizesLaidOut } = state;
1199
1296
  const index = indexByKey.get(itemKey);
1200
1297
  const numColumns = peek$(ctx, "numColumns");
1201
1298
  const row = Math.floor(index / numColumns);
1202
1299
  const prevSize = getRowHeight(row);
1203
- const measured = peek$(ctx, `containerDidLayout${containerId}`);
1204
- if (!measured) {
1205
- state.layoutsPending.add(containerId);
1206
- }
1207
1300
  if (!prevSize || Math.abs(prevSize - size) > 0.5) {
1208
1301
  let diff;
1209
1302
  if (numColumns > 1) {
@@ -1245,11 +1338,14 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1245
1338
  addTotalSize(itemKey, diff, 0);
1246
1339
  doMaintainScrollAtEnd(true);
1247
1340
  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);
1341
+ if (!state.waitingForMicrotask && (Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1)) {
1342
+ if (!peek$(ctx, "containersDidLayout")) {
1343
+ state.waitingForMicrotask = true;
1344
+ queueMicrotask(() => {
1345
+ if (state.waitingForMicrotask) {
1346
+ state.waitingForMicrotask = false;
1347
+ calculateItemsInView(state.scrollVelocity);
1348
+ }
1253
1349
  });
1254
1350
  } else {
1255
1351
  calculateItemsInView(state.scrollVelocity);
@@ -1258,8 +1354,6 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1258
1354
  if (onItemSizeChanged) {
1259
1355
  onItemSizeChanged({ size, previous: prevSize, index, itemKey, itemData: data2[index] });
1260
1356
  }
1261
- } else {
1262
- set$(ctx, `containerDidLayout${containerId}`, true);
1263
1357
  }
1264
1358
  }, []);
1265
1359
  const handleScrollDebounced = useCallback((velocity) => {
@@ -1355,7 +1449,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1355
1449
  },
1356
1450
  []
1357
1451
  );
1358
- return /* @__PURE__ */ React4.createElement(
1452
+ return /* @__PURE__ */ React5.createElement(
1359
1453
  ListComponent,
1360
1454
  {
1361
1455
  ...rest,
@@ -1380,9 +1474,10 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1380
1474
  ListEmptyComponent: data.length === 0 ? ListEmptyComponent : void 0,
1381
1475
  maintainVisibleContentPosition,
1382
1476
  scrollEventThrottle: scrollEventThrottle != null ? scrollEventThrottle : Platform.OS === "web" ? 16 : void 0,
1477
+ waitForInitialLayout,
1383
1478
  style
1384
1479
  }
1385
1480
  );
1386
1481
  });
1387
1482
 
1388
- export { LegendList };
1483
+ export { LegendList, useRecyclingEffect, useRecyclingState, useViewability, useViewabilityAmount };