@legendapp/list 1.0.0-beta.1 → 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,59 +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
- const renderedItem = useMemo(() => itemKey !== void 0 && getRenderedItem(itemKey, id), [itemKey, data]);
98
- return /* @__PURE__ */ React4__default.createElement(
99
- View,
100
- {
101
- style,
102
- onLayout: (event) => {
103
- const key = peek$(ctx, `containerItemKey${id}`);
104
- if (key !== void 0) {
105
- const size = Math.floor(event.nativeEvent.layout[horizontal ? "width" : "height"] * 8) / 8;
106
- updateItemSize(id, key, size);
190
+ const extraData = use$("extraData");
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);
107
225
  }
108
226
  }
109
- },
110
- /* @__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]
111
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);
112
239
  };
113
240
  var useAnimatedValue = useAnimatedValue$1 || ((initialValue) => {
114
241
  return useRef(new Animated.Value(initialValue)).current;
@@ -116,15 +243,15 @@ var useAnimatedValue = useAnimatedValue$1 || ((initialValue) => {
116
243
  function useValue$(key, getValue, key2) {
117
244
  var _a;
118
245
  const ctx = useStateContext();
119
- 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);
120
247
  useMemo(() => {
121
- listen$(ctx, key, (v) => animValue.setValue(v));
248
+ listen$(ctx, key, (v) => animValue.setValue(getValue ? getValue(v) : v));
122
249
  }, []);
123
250
  return animValue;
124
251
  }
125
252
 
126
253
  // src/Containers.tsx
127
- var Containers = React4.memo(function Containers2({
254
+ var Containers = React5.memo(function Containers2({
128
255
  horizontal,
129
256
  recycleItems,
130
257
  ItemSeparatorComponent,
@@ -134,17 +261,17 @@ var Containers = React4.memo(function Containers2({
134
261
  }) {
135
262
  const numContainers = use$("numContainersPooled");
136
263
  const animSize = useValue$("totalSize");
264
+ const animOpacity = waitForInitialLayout ? useValue$("containersDidLayout", (value) => value ? 1 : 0) : void 0;
137
265
  const containers = [];
138
266
  for (let i = 0; i < numContainers; i++) {
139
267
  containers.push(
140
- /* @__PURE__ */ React4.createElement(
268
+ /* @__PURE__ */ React5.createElement(
141
269
  Container,
142
270
  {
143
271
  id: i,
144
272
  key: i,
145
273
  recycleItems,
146
274
  horizontal,
147
- waitForInitialLayout,
148
275
  getRenderedItem,
149
276
  updateItemSize,
150
277
  ItemSeparatorComponent
@@ -152,21 +279,21 @@ var Containers = React4.memo(function Containers2({
152
279
  )
153
280
  );
154
281
  }
155
- const style = horizontal ? { width: animSize } : { height: animSize };
156
- 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);
157
284
  });
158
285
 
159
286
  // src/ListComponent.tsx
160
287
  var getComponent = (Component) => {
161
- if (React4.isValidElement(Component)) {
288
+ if (React5.isValidElement(Component)) {
162
289
  return Component;
163
290
  }
164
291
  if (Component) {
165
- return /* @__PURE__ */ React4.createElement(Component, null);
292
+ return /* @__PURE__ */ React5.createElement(Component, null);
166
293
  }
167
294
  return null;
168
295
  };
169
- var ListComponent = React4.memo(function ListComponent2({
296
+ var ListComponent = React5.memo(function ListComponent2({
170
297
  style,
171
298
  contentContainerStyle,
172
299
  horizontal,
@@ -194,11 +321,11 @@ var ListComponent = React4.memo(function ListComponent2({
194
321
  const animPaddingTop = useValue$("paddingTop");
195
322
  const animScrollAdjust = useValue$("scrollAdjust");
196
323
  const ScrollComponent = renderScrollComponent ? useMemo(
197
- () => React4.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
324
+ () => React5.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
198
325
  [renderScrollComponent]
199
326
  ) : ScrollView;
200
327
  const additionalSize = { marginTop: animScrollAdjust, paddingTop: animPaddingTop };
201
- return /* @__PURE__ */ React4.createElement(
328
+ return /* @__PURE__ */ React5.createElement(
202
329
  ScrollComponent,
203
330
  {
204
331
  ...rest,
@@ -216,8 +343,8 @@ var ListComponent = React4.memo(function ListComponent2({
216
343
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
217
344
  ref: refScrollView
218
345
  },
219
- /* @__PURE__ */ React4.createElement(Animated.View, { style: additionalSize }),
220
- ListHeaderComponent && /* @__PURE__ */ React4.createElement(
346
+ /* @__PURE__ */ React5.createElement(Animated.View, { style: additionalSize }),
347
+ ListHeaderComponent && /* @__PURE__ */ React5.createElement(
221
348
  Animated.View,
222
349
  {
223
350
  style: ListHeaderComponentStyle,
@@ -231,8 +358,8 @@ var ListComponent = React4.memo(function ListComponent2({
231
358
  },
232
359
  getComponent(ListHeaderComponent)
233
360
  ),
234
- ListEmptyComponent && /* @__PURE__ */ React4.createElement(Animated.View, { style: ListEmptyComponentStyle }, getComponent(ListEmptyComponent)),
235
- /* @__PURE__ */ React4.createElement(
361
+ ListEmptyComponent && /* @__PURE__ */ React5.createElement(Animated.View, { style: ListEmptyComponentStyle }, getComponent(ListEmptyComponent)),
362
+ /* @__PURE__ */ React5.createElement(
236
363
  Containers,
237
364
  {
238
365
  horizontal,
@@ -243,7 +370,7 @@ var ListComponent = React4.memo(function ListComponent2({
243
370
  updateItemSize
244
371
  }
245
372
  ),
246
- ListFooterComponent && /* @__PURE__ */ React4.createElement(View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
373
+ ListFooterComponent && /* @__PURE__ */ React5.createElement(View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
247
374
  );
248
375
  });
249
376
 
@@ -283,14 +410,6 @@ var ScrollAdjustHandler = class {
283
410
  return this.appliedAdjust;
284
411
  }
285
412
  };
286
- var symbolFirst = Symbol();
287
- function useInit(cb) {
288
- const refValue = useRef(symbolFirst);
289
- if (refValue.current === symbolFirst) {
290
- refValue.current = cb();
291
- }
292
- return refValue.current;
293
- }
294
413
 
295
414
  // src/viewability.ts
296
415
  var mapViewabilityConfigCallbackPairs = /* @__PURE__ */ new Map();
@@ -441,13 +560,12 @@ function maybeUpdateViewabilityCallback(ctx, configId, viewToken) {
441
560
 
442
561
  // src/LegendList.tsx
443
562
  var DEFAULT_DRAW_DISTANCE = 250;
444
- var POSITION_OUT_OF_VIEW = -1e7;
445
563
  var DEFAULT_ITEM_SIZE = 100;
446
564
  var LegendList = forwardRef(function LegendList2(props, forwardedRef) {
447
- 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 }));
448
566
  });
449
567
  var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef) {
450
- var _a, _b, _c, _d;
568
+ var _a, _b, _c, _d, _e;
451
569
  const {
452
570
  data,
453
571
  initialScrollIndex,
@@ -473,6 +591,8 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
473
591
  onItemSizeChanged,
474
592
  scrollEventThrottle,
475
593
  refScrollView,
594
+ waitForInitialLayout = true,
595
+ extraData,
476
596
  ...rest
477
597
  } = props;
478
598
  const { style, contentContainerStyle } = props;
@@ -522,7 +642,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
522
642
  positions: /* @__PURE__ */ new Map(),
523
643
  columns: /* @__PURE__ */ new Map(),
524
644
  pendingAdjust: 0,
525
- animFrameLayout: null,
645
+ waitingForMicrotask: false,
526
646
  isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
527
647
  isEndReached: false,
528
648
  isAtBottom: false,
@@ -555,7 +675,6 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
555
675
  belowAnchorElementPositions: void 0,
556
676
  rowHeights: /* @__PURE__ */ new Map(),
557
677
  startReachedBlockedByTimer: false,
558
- layoutsPending: /* @__PURE__ */ new Set(),
559
678
  scrollForNextCalculateItemsInView: void 0,
560
679
  enableScrollForNextCalculateItemsInView: true
561
680
  };
@@ -576,6 +695,8 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
576
695
  }
577
696
  }
578
697
  set$(ctx, "scrollAdjust", 0);
698
+ set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
699
+ set$(ctx, "extraData", extraData);
579
700
  }
580
701
  const getAnchorElementIndex = () => {
581
702
  const state = refState.current;
@@ -684,12 +805,10 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
684
805
  startBufferedId: startBufferedIdOrig,
685
806
  positions,
686
807
  columns,
687
- scrollAdjustHandler,
688
- layoutsPending
808
+ scrollAdjustHandler
689
809
  } = state;
690
- if (state.animFrameLayout) {
691
- cancelAnimationFrame(state.animFrameLayout);
692
- state.animFrameLayout = null;
810
+ if (state.waitingForMicrotask) {
811
+ state.waitingForMicrotask = false;
693
812
  }
694
813
  if (!data2) {
695
814
  return;
@@ -797,9 +916,9 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
797
916
  endBuffered,
798
917
  endNoBuffer
799
918
  });
800
- const nextTop = Math.ceil(startBuffered ? positions.get(startBufferedId) + scrollBuffer : 0);
919
+ const nextTop = Math.ceil(startBuffered !== null ? positions.get(startBufferedId) + scrollBuffer : 0);
801
920
  const nextBottom = Math.floor(
802
- endBuffered ? (positions.get(getId(endBuffered + 1)) || 0) - scrollLength - scrollBuffer : 0
921
+ endBuffered !== null ? (positions.get(getId(endBuffered + 1)) || 0) - scrollLength - scrollBuffer : 0
803
922
  );
804
923
  if (state.enableScrollForNextCalculateItemsInView) {
805
924
  state.scrollForNextCalculateItemsInView = nextTop >= 0 && nextBottom >= 0 ? {
@@ -831,7 +950,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
831
950
  break;
832
951
  }
833
952
  const index = state.indexByKey.get(key);
834
- const pos = peek$(ctx, `containerPosition${u}`);
953
+ const pos = peek$(ctx, `containerPosition${u}`).top;
835
954
  if (index < startBuffered || index > endBuffered) {
836
955
  const distance = Math.abs(pos - top2);
837
956
  if (index < 0 || distance > furthestDistance) {
@@ -850,7 +969,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
850
969
  set$(ctx, `containerItemKey${containerId}`, id);
851
970
  const index = state.indexByKey.get(id);
852
971
  set$(ctx, `containerItemData${containerId}`, data2[index]);
853
- set$(ctx, `containerPosition${containerId}`, POSITION_OUT_OF_VIEW);
972
+ set$(ctx, `containerPosition${containerId}`, ANCHORED_POSITION_OUT_OF_VIEW);
854
973
  set$(ctx, `containerColumn${containerId}`, -1);
855
974
  if (__DEV__ && numContainers > peek$(ctx, "numContainersPooled")) {
856
975
  console.warn(
@@ -874,19 +993,31 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
874
993
  if (item) {
875
994
  const id = getId(itemIndex);
876
995
  if (itemKey !== id || itemIndex < startBuffered || itemIndex > endBuffered) {
877
- const prevPos = peek$(ctx, `containerPosition${i}`);
996
+ const prevPos = peek$(ctx, `containerPosition${i}`).top;
878
997
  const pos = positions.get(id) || 0;
879
998
  const size = getItemSize(id, itemIndex, data2[i]);
880
999
  if (pos + size >= scroll && pos <= scrollBottom || prevPos + size >= scroll && prevPos <= scrollBottom) {
881
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1000
+ set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
882
1001
  }
883
1002
  } else {
884
- 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
+ };
885
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
+ }
886
1017
  const prevPos = peek$(ctx, `containerPosition${i}`);
887
1018
  const prevColumn = peek$(ctx, `containerColumn${i}`);
888
1019
  const prevData = peek$(ctx, `containerItemData${i}`);
889
- if (pos > POSITION_OUT_OF_VIEW && pos !== prevPos) {
1020
+ if (pos.relativeCoordinate > POSITION_OUT_OF_VIEW && pos.top !== prevPos.top) {
890
1021
  set$(ctx, `containerPosition${i}`, pos);
891
1022
  }
892
1023
  if (column2 >= 0 && column2 !== prevColumn) {
@@ -899,12 +1030,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
899
1030
  }
900
1031
  }
901
1032
  }
902
- if (layoutsPending.size > 0) {
903
- for (const containerId of layoutsPending) {
904
- set$(ctx, `containerDidLayout${containerId}`, true);
905
- }
906
- layoutsPending.clear();
907
- }
1033
+ set$(ctx, "containersDidLayout", true);
908
1034
  if (state.viewabilityConfigCallbackPairs) {
909
1035
  updateViewableItems(
910
1036
  state,
@@ -997,13 +1123,13 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
997
1123
  const itemKey = peek$(ctx, `containerItemKey${i}`);
998
1124
  if (!keyExtractorProp || itemKey && state.indexByKey.get(itemKey) === void 0) {
999
1125
  set$(ctx, `containerItemKey${i}`, void 0);
1000
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1126
+ set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1001
1127
  set$(ctx, `containerColumn${i}`, -1);
1002
1128
  }
1003
1129
  }
1004
1130
  if (!keyExtractorProp) {
1005
1131
  state.sizes.clear();
1006
- state.positions;
1132
+ state.positions.clear();
1007
1133
  }
1008
1134
  calculateItemsInView(state.scrollVelocity);
1009
1135
  }
@@ -1025,13 +1151,48 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1025
1151
  let totalSize = 0;
1026
1152
  let totalSizeBelowIndex = 0;
1027
1153
  const indexByKey = /* @__PURE__ */ new Map();
1154
+ const newPositions = /* @__PURE__ */ new Map();
1028
1155
  let column = 1;
1029
1156
  let maxSizeInRow = 0;
1030
1157
  for (let i = 0; i < data.length; i++) {
1031
1158
  const key = getId(i);
1032
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
+ }
1033
1163
  }
1034
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
+ }
1035
1196
  const anchorElementIndex = getAnchorElementIndex();
1036
1197
  for (let i = 0; i < data.length; i++) {
1037
1198
  const key = getId(i);
@@ -1058,9 +1219,12 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1058
1219
  !isFirst
1059
1220
  );
1060
1221
  }, [isFirst, data, numColumnsProp]);
1222
+ useEffect(() => {
1223
+ set$(ctx, "extraData", extraData);
1224
+ }, [extraData]);
1061
1225
  refState.current.renderItem = renderItem;
1062
1226
  const lastItemKey = getId(data[data.length - 1]);
1063
- 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;
1064
1228
  const initalizeStateVars = () => {
1065
1229
  set$(ctx, "lastItemKey", lastItemKey);
1066
1230
  set$(ctx, "numColumns", numColumnsProp);
@@ -1070,7 +1234,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1070
1234
  initalizeStateVars();
1071
1235
  }
1072
1236
  useEffect(initalizeStateVars, [lastItemKey, numColumnsProp, stylePaddingTop]);
1073
- const getRenderedItem = useCallback((key, containerId) => {
1237
+ const getRenderedItem = useCallback((key) => {
1074
1238
  var _a2, _b2;
1075
1239
  const state = refState.current;
1076
1240
  if (!state) {
@@ -1081,89 +1245,27 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1081
1245
  if (index === void 0) {
1082
1246
  return null;
1083
1247
  }
1084
- const useViewability = (configId, callback) => {
1085
- const key2 = containerId + configId;
1086
- useInit(() => {
1087
- const value = ctx.mapViewabilityValues.get(key2);
1088
- if (value) {
1089
- callback(value);
1090
- }
1091
- });
1092
- ctx.mapViewabilityCallbacks.set(key2, callback);
1093
- useEffect(
1094
- () => () => {
1095
- ctx.mapViewabilityCallbacks.delete(key2);
1096
- },
1097
- []
1098
- );
1248
+ const useViewability2 = (configId, callback) => {
1249
+ useViewability(configId, callback);
1099
1250
  };
1100
- const useViewabilityAmount = (callback) => {
1101
- useInit(() => {
1102
- const value = ctx.mapViewabilityAmountValues.get(containerId);
1103
- if (value) {
1104
- callback(value);
1105
- }
1106
- });
1107
- ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
1108
- useEffect(
1109
- () => () => {
1110
- ctx.mapViewabilityAmountCallbacks.delete(containerId);
1111
- },
1112
- []
1113
- );
1251
+ const useViewabilityAmount2 = (callback) => {
1252
+ useViewabilityAmount(callback);
1114
1253
  };
1115
- const useRecyclingEffect = (effect) => {
1116
- useEffect(() => {
1117
- const state2 = refState.current;
1118
- let prevIndex = index;
1119
- let prevItem = state2.data[index];
1120
- const signal = `containerItemKey${containerId}`;
1121
- const run = () => {
1122
- const data3 = state2.data;
1123
- if (data3) {
1124
- const newKey = peek$(ctx, signal);
1125
- const newIndex = state2.indexByKey.get(newKey);
1126
- const newItem = data3[newIndex];
1127
- if (newItem) {
1128
- effect({
1129
- index: newIndex,
1130
- item: newItem,
1131
- prevIndex,
1132
- prevItem
1133
- });
1134
- }
1135
- prevIndex = newIndex;
1136
- prevItem = newItem;
1137
- }
1138
- };
1139
- run();
1140
- return listen$(ctx, signal, run);
1141
- }, []);
1254
+ const useRecyclingEffect2 = (effect) => {
1255
+ useRecyclingEffect(effect);
1142
1256
  };
1143
- const useRecyclingState = (valueOrFun) => {
1144
- const stateInfo = useState(
1145
- () => typeof valueOrFun === "function" ? valueOrFun({
1146
- index,
1147
- item: refState.current.data[index],
1148
- prevIndex: void 0,
1149
- prevItem: void 0
1150
- }) : valueOrFun
1151
- );
1152
- useRecyclingEffect((state2) => {
1153
- const newState = typeof valueOrFun === "function" ? valueOrFun(state2) : valueOrFun;
1154
- stateInfo[1](newState);
1155
- });
1156
- return stateInfo;
1257
+ const useRecyclingState2 = (valueOrFun) => {
1258
+ return useRecyclingState(valueOrFun);
1157
1259
  };
1158
1260
  const renderedItem = (_b2 = (_a2 = refState.current).renderItem) == null ? void 0 : _b2.call(_a2, {
1159
1261
  item: data2[index],
1160
1262
  index,
1161
- useViewability,
1162
- useViewabilityAmount,
1163
- useRecyclingEffect,
1164
- useRecyclingState
1263
+ useViewability: useViewability2,
1264
+ useViewabilityAmount: useViewabilityAmount2,
1265
+ useRecyclingEffect: useRecyclingEffect2,
1266
+ useRecyclingState: useRecyclingState2
1165
1267
  });
1166
- return renderedItem;
1268
+ return { index, renderedItem };
1167
1269
  }, []);
1168
1270
  useInit(() => {
1169
1271
  var _a2;
@@ -1175,7 +1277,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1175
1277
  const averageItemSize = (_a2 = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, data[0])) != null ? _a2 : DEFAULT_ITEM_SIZE;
1176
1278
  const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) * numColumnsProp;
1177
1279
  for (let i = 0; i < numContainers; i++) {
1178
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1280
+ set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1179
1281
  set$(ctx, `containerColumn${i}`, -1);
1180
1282
  }
1181
1283
  set$(ctx, "numContainers", numContainers);
@@ -1189,15 +1291,11 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1189
1291
  return;
1190
1292
  }
1191
1293
  const state = refState.current;
1192
- const { sizes, indexByKey, idsInFirstRender, columns, sizesLaidOut } = state;
1294
+ const { sizes, indexByKey, columns, sizesLaidOut } = state;
1193
1295
  const index = indexByKey.get(itemKey);
1194
1296
  const numColumns = peek$(ctx, "numColumns");
1195
1297
  const row = Math.floor(index / numColumns);
1196
1298
  const prevSize = getRowHeight(row);
1197
- const measured = peek$(ctx, `containerDidLayout${containerId}`);
1198
- if (!measured) {
1199
- state.layoutsPending.add(containerId);
1200
- }
1201
1299
  if (!prevSize || Math.abs(prevSize - size) > 0.5) {
1202
1300
  let diff;
1203
1301
  if (numColumns > 1) {
@@ -1239,11 +1337,14 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1239
1337
  addTotalSize(itemKey, diff, 0);
1240
1338
  doMaintainScrollAtEnd(true);
1241
1339
  const scrollVelocity = state.scrollVelocity;
1242
- if (!state.animFrameLayout && (Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1)) {
1243
- if (!peek$(ctx, `containerDidLayout${containerId}`)) {
1244
- state.animFrameLayout = requestAnimationFrame(() => {
1245
- state.animFrameLayout = null;
1246
- 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
+ }
1247
1348
  });
1248
1349
  } else {
1249
1350
  calculateItemsInView(state.scrollVelocity);
@@ -1252,8 +1353,6 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1252
1353
  if (onItemSizeChanged) {
1253
1354
  onItemSizeChanged({ size, previous: prevSize, index, itemKey, itemData: data2[index] });
1254
1355
  }
1255
- } else {
1256
- set$(ctx, `containerDidLayout${containerId}`, true);
1257
1356
  }
1258
1357
  }, []);
1259
1358
  const handleScrollDebounced = useCallback((velocity) => {
@@ -1349,7 +1448,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1349
1448
  },
1350
1449
  []
1351
1450
  );
1352
- return /* @__PURE__ */ React4.createElement(
1451
+ return /* @__PURE__ */ React5.createElement(
1353
1452
  ListComponent,
1354
1453
  {
1355
1454
  ...rest,
@@ -1374,9 +1473,10 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1374
1473
  ListEmptyComponent: data.length === 0 ? ListEmptyComponent : void 0,
1375
1474
  maintainVisibleContentPosition,
1376
1475
  scrollEventThrottle: scrollEventThrottle != null ? scrollEventThrottle : Platform.OS === "web" ? 16 : void 0,
1476
+ waitForInitialLayout,
1377
1477
  style
1378
1478
  }
1379
1479
  );
1380
1480
  });
1381
1481
 
1382
- export { LegendList };
1482
+ export { LegendList, useRecyclingEffect, useRecyclingState, useViewability, useViewabilityAmount };