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

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,22 +1,23 @@
1
- import * as React4 from 'react';
2
- import React4__default, { useMemo, forwardRef, useRef, useCallback, useEffect, useImperativeHandle, useSyncExternalStore, useState } from 'react';
3
- import { Animated, ScrollView, View, Dimensions, StyleSheet, Platform, useAnimatedValue as useAnimatedValue$1 } from 'react-native';
1
+ import * as React6 from 'react';
2
+ import React6__default, { createContext, memo, useReducer, useEffect, useMemo, useRef, useCallback, useImperativeHandle, useSyncExternalStore, useContext, useState, forwardRef, useLayoutEffect } from 'react';
3
+ import { View, Text, Platform, Animated, ScrollView, Dimensions, StyleSheet, RefreshControl } from 'react-native';
4
4
 
5
5
  // src/LegendList.tsx
6
- var ContextState = React4.createContext(null);
6
+ var ContextState = React6.createContext(null);
7
7
  function StateProvider({ children }) {
8
- const [value] = React4.useState(() => ({
8
+ const [value] = React6.useState(() => ({
9
9
  listeners: /* @__PURE__ */ new Map(),
10
10
  values: /* @__PURE__ */ new Map(),
11
11
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
12
12
  mapViewabilityValues: /* @__PURE__ */ new Map(),
13
13
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
14
- mapViewabilityAmountValues: /* @__PURE__ */ new Map()
14
+ mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
15
+ columnWrapperStyle: void 0
15
16
  }));
16
- return /* @__PURE__ */ React4.createElement(ContextState.Provider, { value }, children);
17
+ return /* @__PURE__ */ React6.createElement(ContextState.Provider, { value }, children);
17
18
  }
18
19
  function useStateContext() {
19
- return React4.useContext(ContextState);
20
+ return React6.useContext(ContextState);
20
21
  }
21
22
  function createSelectorFunctions(ctx, signalName) {
22
23
  return {
@@ -25,8 +26,8 @@ function createSelectorFunctions(ctx, signalName) {
25
26
  };
26
27
  }
27
28
  function use$(signalName) {
28
- const ctx = React4.useContext(ContextState);
29
- const { subscribe, get } = React4.useMemo(() => createSelectorFunctions(ctx, signalName), []);
29
+ const ctx = React6.useContext(ContextState);
30
+ const { subscribe, get } = React6.useMemo(() => createSelectorFunctions(ctx, signalName), []);
30
31
  const value = useSyncExternalStore(subscribe, get);
31
32
  return value;
32
33
  }
@@ -56,76 +57,278 @@ function set$(ctx, signalName, value) {
56
57
  }
57
58
  }
58
59
  }
60
+ function getContentSize(ctx) {
61
+ const { values } = ctx;
62
+ const stylePaddingTop = values.get("stylePaddingTop") || 0;
63
+ const headerSize = values.get("headerSize") || 0;
64
+ const footerSize = values.get("footerSize") || 0;
65
+ const totalSize = values.get("totalSize") || 0;
66
+ return headerSize + footerSize + totalSize + stylePaddingTop;
67
+ }
68
+ var symbolFirst = Symbol();
69
+ function useInit(cb) {
70
+ const refValue = useRef(symbolFirst);
71
+ if (refValue.current === symbolFirst) {
72
+ refValue.current = cb();
73
+ }
74
+ return refValue.current;
75
+ }
76
+
77
+ // src/ContextContainer.ts
78
+ var ContextContainer = createContext(null);
79
+ function useViewability(configId, callback) {
80
+ const ctx = useStateContext();
81
+ const { containerId } = useContext(ContextContainer);
82
+ const key = containerId + configId;
83
+ useInit(() => {
84
+ const value = ctx.mapViewabilityValues.get(key);
85
+ if (value) {
86
+ callback(value);
87
+ }
88
+ });
89
+ ctx.mapViewabilityCallbacks.set(key, callback);
90
+ useEffect(
91
+ () => () => {
92
+ ctx.mapViewabilityCallbacks.delete(key);
93
+ },
94
+ []
95
+ );
96
+ }
97
+ function useViewabilityAmount(callback) {
98
+ const ctx = useStateContext();
99
+ const { containerId } = useContext(ContextContainer);
100
+ useInit(() => {
101
+ const value = ctx.mapViewabilityAmountValues.get(containerId);
102
+ if (value) {
103
+ callback(value);
104
+ }
105
+ });
106
+ ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
107
+ useEffect(
108
+ () => () => {
109
+ ctx.mapViewabilityAmountCallbacks.delete(containerId);
110
+ },
111
+ []
112
+ );
113
+ }
114
+ function useRecyclingEffect(effect) {
115
+ const { index, value } = useContext(ContextContainer);
116
+ const prevValues = useRef({
117
+ prevIndex: void 0,
118
+ prevItem: void 0
119
+ });
120
+ useEffect(() => {
121
+ let ret = void 0;
122
+ if (prevValues.current.prevIndex !== void 0 && prevValues.current.prevItem !== void 0) {
123
+ ret = effect({
124
+ index,
125
+ item: value,
126
+ prevIndex: prevValues.current.prevIndex,
127
+ prevItem: prevValues.current.prevItem
128
+ });
129
+ }
130
+ prevValues.current = {
131
+ prevIndex: index,
132
+ prevItem: value
133
+ };
134
+ return ret;
135
+ }, [index, value]);
136
+ }
137
+ function useRecyclingState(valueOrFun) {
138
+ const { index, value } = useContext(ContextContainer);
139
+ const stateInfo = useState(
140
+ () => typeof valueOrFun === "function" ? valueOrFun({
141
+ index,
142
+ item: value,
143
+ prevIndex: void 0,
144
+ prevItem: void 0
145
+ }) : valueOrFun
146
+ );
147
+ useRecyclingEffect((state) => {
148
+ const newState = typeof valueOrFun === "function" ? valueOrFun(state) : valueOrFun;
149
+ stateInfo[1](newState);
150
+ });
151
+ return stateInfo;
152
+ }
153
+ var DebugView = memo(function DebugView2({ state }) {
154
+ const ctx = useStateContext();
155
+ const totalSize = use$("totalSize");
156
+ const contentSize = getContentSize(ctx);
157
+ const [, forceUpdate] = useReducer((x) => x + 1, 0);
158
+ useInterval(() => {
159
+ forceUpdate();
160
+ }, 100);
161
+ return /* @__PURE__ */ React6.createElement(
162
+ View,
163
+ {
164
+ style: {
165
+ position: "absolute",
166
+ top: 0,
167
+ right: 0,
168
+ paddingLeft: 4,
169
+ paddingBottom: 4,
170
+ // height: 100,
171
+ backgroundColor: "#FFFFFFCC"
172
+ }
173
+ },
174
+ /* @__PURE__ */ React6.createElement(Text, null, "TotalSize: ", totalSize),
175
+ /* @__PURE__ */ React6.createElement(Text, null, "ContentSize: ", contentSize),
176
+ /* @__PURE__ */ React6.createElement(Text, null, "At end: ", String(state.isAtBottom))
177
+ );
178
+ });
179
+ function useInterval(callback, delay) {
180
+ useEffect(() => {
181
+ const interval = setInterval(callback, delay);
182
+ return () => clearInterval(interval);
183
+ }, [delay]);
184
+ }
185
+ var LeanViewComponent = React6.forwardRef((props, ref) => {
186
+ return React6.createElement("RCTView", { ...props, ref });
187
+ });
188
+ LeanViewComponent.displayName = "RCTView";
189
+ var LeanView = Platform.OS === "android" || Platform.OS === "ios" ? LeanViewComponent : View;
190
+
191
+ // src/constants.ts
192
+ var POSITION_OUT_OF_VIEW = -1e7;
193
+ var ANCHORED_POSITION_OUT_OF_VIEW = {
194
+ type: "top",
195
+ relativeCoordinate: POSITION_OUT_OF_VIEW,
196
+ top: POSITION_OUT_OF_VIEW
197
+ };
198
+ var ENABLE_DEVMODE = __DEV__ && false;
199
+ var ENABLE_DEBUG_VIEW = __DEV__ && false;
59
200
 
60
201
  // src/Container.tsx
202
+ var isNewArchitecture = global.nativeFabricUIManager != null;
61
203
  var Container = ({
62
204
  id,
63
205
  recycleItems,
64
206
  horizontal,
65
- waitForInitialLayout,
66
207
  getRenderedItem,
67
208
  updateItemSize,
68
209
  ItemSeparatorComponent
69
210
  }) => {
70
211
  const ctx = useStateContext();
71
- const position = use$(`containerPosition${id}`);
212
+ const columnWrapperStyle = ctx.columnWrapperStyle;
213
+ const maintainVisibleContentPosition = use$("maintainVisibleContentPosition");
214
+ const position = use$(`containerPosition${id}`) || ANCHORED_POSITION_OUT_OF_VIEW;
72
215
  const column = use$(`containerColumn${id}`) || 0;
73
216
  const numColumns = use$("numColumns");
217
+ const lastItemKeys = use$("lastItemKeys");
218
+ const itemKey = use$(`containerItemKey${id}`);
219
+ const data = use$(`containerItemData${id}`);
220
+ const extraData = use$("extraData");
74
221
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
75
222
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
223
+ let verticalPaddingStyles;
224
+ if (columnWrapperStyle && !horizontal && numColumns > 1) {
225
+ const { columnGap, rowGap, gap } = columnWrapperStyle;
226
+ verticalPaddingStyles = {
227
+ paddingBottom: !lastItemKeys.has(itemKey) ? rowGap || gap || void 0 : void 0,
228
+ // Apply horizontal padding based on column position (first, middle, or last)
229
+ paddingLeft: column > 1 ? (columnGap || gap || 0) / 2 : void 0,
230
+ paddingRight: column < numColumns ? (columnGap || gap || 0) / 2 : void 0
231
+ };
232
+ }
76
233
  const style = horizontal ? {
77
- flexDirection: "row",
234
+ flexDirection: ItemSeparatorComponent ? "row" : void 0,
78
235
  position: "absolute",
79
236
  top: otherAxisPos,
80
237
  bottom: numColumns > 1 ? null : 0,
81
238
  height: otherAxisSize,
82
- left: position
239
+ left: position.relativeCoordinate
83
240
  } : {
84
241
  position: "absolute",
85
242
  left: otherAxisPos,
86
243
  right: numColumns > 1 ? null : 0,
87
244
  width: otherAxisSize,
88
- top: position
245
+ top: position.relativeCoordinate,
246
+ ...verticalPaddingStyles || {}
89
247
  };
90
- if (waitForInitialLayout) {
91
- const visible = use$(`containerDidLayout${id}`);
92
- style.opacity = visible ? 1 : 0;
93
- }
94
- const lastItemKey = use$("lastItemKey");
95
- const itemKey = use$(`containerItemKey${id}`);
96
- const data = use$(`containerItemData${id}`);
97
- 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);
248
+ const renderedItemInfo = useMemo(
249
+ () => itemKey !== void 0 ? getRenderedItem(itemKey) : null,
250
+ [itemKey, data, extraData]
251
+ );
252
+ const { index, renderedItem } = renderedItemInfo || {};
253
+ const onLayout = (event) => {
254
+ if (itemKey !== void 0) {
255
+ const layout = event.nativeEvent.layout;
256
+ const size = Math.floor(layout[horizontal ? "width" : "height"] * 8) / 8;
257
+ if (size === 0) {
258
+ if (layout.x !== POSITION_OUT_OF_VIEW && layout.y !== POSITION_OUT_OF_VIEW) {
259
+ console.log(
260
+ "[WARN] Container 0 height reported, possible bug in LegendList",
261
+ id,
262
+ itemKey,
263
+ event.nativeEvent
264
+ );
108
265
  }
266
+ return;
109
267
  }
110
- },
111
- /* @__PURE__ */ React4__default.createElement(React4__default.Fragment, { key: recycleItems ? void 0 : itemKey }, renderedItem, renderedItem && ItemSeparatorComponent && itemKey !== lastItemKey && ItemSeparatorComponent)
268
+ updateItemSize(id, itemKey, size);
269
+ }
270
+ };
271
+ const ref = useRef(null);
272
+ if (isNewArchitecture) {
273
+ useLayoutEffect(() => {
274
+ var _a, _b;
275
+ if (itemKey !== void 0) {
276
+ const measured = (_b = (_a = ref.current) == null ? void 0 : _a.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a);
277
+ if (measured) {
278
+ const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
279
+ if (size) {
280
+ updateItemSize(id, itemKey, size);
281
+ }
282
+ }
283
+ }
284
+ }, [itemKey]);
285
+ }
286
+ const contextValue = useMemo(
287
+ () => ({ containerId: id, itemKey, index, value: data }),
288
+ [id, itemKey, index, data]
112
289
  );
290
+ const contentFragment = /* @__PURE__ */ React6__default.createElement(React6__default.Fragment, { key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React6__default.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && !lastItemKeys.has(itemKey) && /* @__PURE__ */ React6__default.createElement(ItemSeparatorComponent, { leadingItem: renderedItemInfo.item })));
291
+ if (maintainVisibleContentPosition) {
292
+ const anchorStyle = position.type === "top" ? { position: "absolute", top: 0, left: 0, right: 0 } : { position: "absolute", bottom: 0, left: 0, right: 0 };
293
+ if (ENABLE_DEVMODE) {
294
+ anchorStyle.borderColor = position.type === "top" ? "red" : "blue";
295
+ anchorStyle.borderWidth = 1;
296
+ }
297
+ return /* @__PURE__ */ React6__default.createElement(LeanView, { style }, /* @__PURE__ */ React6__default.createElement(LeanView, { style: anchorStyle, onLayout, ref }, contentFragment, ENABLE_DEVMODE && /* @__PURE__ */ React6__default.createElement(Text, { style: { position: "absolute", top: 0, left: 0, zIndex: 1e3 } }, position.top)));
298
+ }
299
+ return /* @__PURE__ */ React6__default.createElement(LeanView, { style, onLayout, ref }, contentFragment);
113
300
  };
114
- var useAnimatedValue = useAnimatedValue$1 || ((initialValue) => {
301
+ var typedForwardRef = forwardRef;
302
+ var typedMemo = memo;
303
+ var useAnimatedValue = (initialValue) => {
115
304
  return useRef(new Animated.Value(initialValue)).current;
116
- });
117
- function useValue$(key, getValue, key2) {
305
+ };
306
+
307
+ // src/useValue$.ts
308
+ function useValue$(key, getValue, useMicrotask) {
118
309
  var _a;
119
310
  const ctx = useStateContext();
120
- const animValue = useAnimatedValue((_a = peek$(ctx, key)) != null ? _a : 0);
311
+ const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
121
312
  useMemo(() => {
122
- listen$(ctx, key, (v) => animValue.setValue(v));
313
+ let newValue = void 0;
314
+ listen$(ctx, key, (v) => {
315
+ if (useMicrotask && newValue === void 0) {
316
+ queueMicrotask(() => {
317
+ animValue.setValue(newValue);
318
+ newValue = void 0;
319
+ });
320
+ }
321
+ newValue = getValue ? getValue(v) : v;
322
+ if (!useMicrotask) {
323
+ animValue.setValue(newValue);
324
+ }
325
+ });
123
326
  }, []);
124
327
  return animValue;
125
328
  }
126
329
 
127
330
  // src/Containers.tsx
128
- var Containers = React4.memo(function Containers2({
331
+ var Containers = typedMemo(function Containers2({
129
332
  horizontal,
130
333
  recycleItems,
131
334
  ItemSeparatorComponent,
@@ -134,18 +337,23 @@ var Containers = React4.memo(function Containers2({
134
337
  getRenderedItem
135
338
  }) {
136
339
  const numContainers = use$("numContainersPooled");
137
- const animSize = useValue$("totalSize");
340
+ const animSize = useValue$(
341
+ "totalSizeWithScrollAdjust",
342
+ void 0,
343
+ /*useMicrotask*/
344
+ true
345
+ );
346
+ const animOpacity = waitForInitialLayout ? useValue$("containersDidLayout", (value) => value ? 1 : 0) : void 0;
138
347
  const containers = [];
139
348
  for (let i = 0; i < numContainers; i++) {
140
349
  containers.push(
141
- /* @__PURE__ */ React4.createElement(
350
+ /* @__PURE__ */ React6.createElement(
142
351
  Container,
143
352
  {
144
353
  id: i,
145
354
  key: i,
146
355
  recycleItems,
147
356
  horizontal,
148
- waitForInitialLayout,
149
357
  getRenderedItem,
150
358
  updateItemSize,
151
359
  ItemSeparatorComponent
@@ -153,21 +361,72 @@ var Containers = React4.memo(function Containers2({
153
361
  )
154
362
  );
155
363
  }
156
- const style = horizontal ? { width: animSize } : { height: animSize };
157
- return /* @__PURE__ */ React4.createElement(Animated.View, { style }, containers);
364
+ const style = horizontal ? { width: animSize, opacity: animOpacity } : { height: animSize, opacity: animOpacity };
365
+ return /* @__PURE__ */ React6.createElement(Animated.View, { style }, containers);
158
366
  });
159
367
 
160
368
  // src/ListComponent.tsx
161
369
  var getComponent = (Component) => {
162
- if (React4.isValidElement(Component)) {
370
+ if (React6.isValidElement(Component)) {
163
371
  return Component;
164
372
  }
165
373
  if (Component) {
166
- return /* @__PURE__ */ React4.createElement(Component, null);
374
+ return /* @__PURE__ */ React6.createElement(Component, null);
167
375
  }
168
376
  return null;
169
377
  };
170
- var ListComponent = React4.memo(function ListComponent2({
378
+ var PaddingAndAdjust = () => {
379
+ const animPaddingTop = useValue$("paddingTop", (v) => v, true);
380
+ const animScrollAdjust = useValue$("scrollAdjust", (v) => v, true);
381
+ const additionalSize = { marginTop: animScrollAdjust, paddingTop: animPaddingTop };
382
+ return /* @__PURE__ */ React6.createElement(Animated.View, { style: additionalSize });
383
+ };
384
+ var PaddingAndAdjustDevMode = () => {
385
+ const animPaddingTop = useValue$("paddingTop", (v) => v, true);
386
+ const animScrollAdjust = useValue$("scrollAdjust", (v) => v, true);
387
+ return /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Animated.View, { style: { marginTop: animScrollAdjust } }), /* @__PURE__ */ React6.createElement(Animated.View, { style: { paddingTop: animPaddingTop } }), /* @__PURE__ */ React6.createElement(
388
+ Animated.View,
389
+ {
390
+ style: {
391
+ position: "absolute",
392
+ top: Animated.add(animScrollAdjust, Animated.multiply(animScrollAdjust, -1)),
393
+ height: animPaddingTop,
394
+ left: 0,
395
+ right: 0,
396
+ backgroundColor: "green"
397
+ }
398
+ }
399
+ ), /* @__PURE__ */ React6.createElement(
400
+ Animated.View,
401
+ {
402
+ style: {
403
+ position: "absolute",
404
+ top: animPaddingTop,
405
+ height: animScrollAdjust,
406
+ left: -16,
407
+ right: -16,
408
+ backgroundColor: "lightblue"
409
+ }
410
+ }
411
+ ), /* @__PURE__ */ React6.createElement(
412
+ Animated.View,
413
+ {
414
+ style: {
415
+ position: "absolute",
416
+ top: animPaddingTop,
417
+ height: Animated.multiply(animScrollAdjust, -1),
418
+ width: 8,
419
+ right: 4,
420
+ borderStyle: "dashed",
421
+ borderColor: "blue",
422
+ borderWidth: 1,
423
+ backgroundColor: "lightblue"
424
+ //backgroundColor: "blue",
425
+ }
426
+ }
427
+ ));
428
+ };
429
+ var ListComponent = typedMemo(function ListComponent2({
171
430
  style,
172
431
  contentContainerStyle,
173
432
  horizontal,
@@ -183,28 +442,27 @@ var ListComponent = React4.memo(function ListComponent2({
183
442
  ListFooterComponent,
184
443
  ListFooterComponentStyle,
185
444
  ListEmptyComponent,
186
- ListEmptyComponentStyle,
187
445
  getRenderedItem,
188
446
  updateItemSize,
189
447
  refScrollView,
190
448
  maintainVisibleContentPosition,
191
449
  renderScrollComponent,
450
+ onRefresh,
451
+ refreshing,
452
+ progressViewOffset,
192
453
  ...rest
193
454
  }) {
194
455
  const ctx = useStateContext();
195
- const animPaddingTop = useValue$("paddingTop");
196
- const animScrollAdjust = useValue$("scrollAdjust");
197
456
  const ScrollComponent = renderScrollComponent ? useMemo(
198
- () => React4.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
457
+ () => React6.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
199
458
  [renderScrollComponent]
200
459
  ) : ScrollView;
201
- const additionalSize = { marginTop: animScrollAdjust, paddingTop: animPaddingTop };
202
- return /* @__PURE__ */ React4.createElement(
460
+ return /* @__PURE__ */ React6.createElement(
203
461
  ScrollComponent,
204
462
  {
205
463
  ...rest,
206
464
  style,
207
- maintainVisibleContentPosition: maintainVisibleContentPosition ? { minIndexForVisible: 0 } : void 0,
465
+ maintainVisibleContentPosition: maintainVisibleContentPosition && !ListEmptyComponent ? { minIndexForVisible: 0 } : void 0,
208
466
  contentContainerStyle: [
209
467
  contentContainerStyle,
210
468
  horizontal ? {
@@ -217,34 +475,41 @@ var ListComponent = React4.memo(function ListComponent2({
217
475
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
218
476
  ref: refScrollView
219
477
  },
220
- /* @__PURE__ */ React4.createElement(Animated.View, { style: additionalSize }),
221
- ListHeaderComponent && /* @__PURE__ */ React4.createElement(
222
- Animated.View,
478
+ ENABLE_DEVMODE ? /* @__PURE__ */ React6.createElement(PaddingAndAdjustDevMode, null) : /* @__PURE__ */ React6.createElement(PaddingAndAdjust, null),
479
+ ListHeaderComponent && /* @__PURE__ */ React6.createElement(
480
+ View,
223
481
  {
224
482
  style: ListHeaderComponentStyle,
225
483
  onLayout: (event) => {
226
484
  const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
227
- const prevSize = peek$(ctx, "headerSize") || 0;
228
- if (size !== prevSize) {
229
- set$(ctx, "headerSize", size);
230
- }
485
+ set$(ctx, "headerSize", size);
231
486
  }
232
487
  },
233
488
  getComponent(ListHeaderComponent)
234
489
  ),
235
- ListEmptyComponent && /* @__PURE__ */ React4.createElement(Animated.View, { style: ListEmptyComponentStyle }, getComponent(ListEmptyComponent)),
236
- /* @__PURE__ */ React4.createElement(
490
+ ListEmptyComponent && getComponent(ListEmptyComponent),
491
+ /* @__PURE__ */ React6.createElement(
237
492
  Containers,
238
493
  {
239
494
  horizontal,
240
495
  recycleItems,
241
496
  waitForInitialLayout,
242
497
  getRenderedItem,
243
- ItemSeparatorComponent: ItemSeparatorComponent && getComponent(ItemSeparatorComponent),
498
+ ItemSeparatorComponent,
244
499
  updateItemSize
245
500
  }
246
501
  ),
247
- ListFooterComponent && /* @__PURE__ */ React4.createElement(View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
502
+ ListFooterComponent && /* @__PURE__ */ React6.createElement(
503
+ View,
504
+ {
505
+ style: ListFooterComponentStyle,
506
+ onLayout: (event) => {
507
+ const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
508
+ set$(ctx, "footerSize", size);
509
+ }
510
+ },
511
+ getComponent(ListFooterComponent)
512
+ )
248
513
  );
249
514
  });
250
515
 
@@ -253,45 +518,57 @@ var ScrollAdjustHandler = class {
253
518
  constructor(ctx) {
254
519
  this.ctx = ctx;
255
520
  this.appliedAdjust = 0;
256
- this.pendingAdjust = 0;
257
521
  this.busy = false;
258
- this.firstAdjust = true;
522
+ this.isPaused = false;
259
523
  this.context = ctx;
260
524
  }
525
+ doAjdust() {
526
+ set$(this.context, "scrollAdjust", this.appliedAdjust);
527
+ this.busy = false;
528
+ }
261
529
  requestAdjust(adjust, onAdjusted) {
262
530
  const oldAdjustTop = peek$(this.context, "scrollAdjust");
263
531
  if (oldAdjustTop === adjust) {
264
532
  return;
265
533
  }
266
534
  this.appliedAdjust = adjust;
267
- this.pendingAdjust = adjust;
268
- const doAjdust = () => {
269
- set$(this.context, "scrollAdjust", this.pendingAdjust);
270
- onAdjusted(oldAdjustTop - this.pendingAdjust);
271
- this.busy = false;
272
- };
273
- if (!this.busy) {
535
+ if (!this.busy && !this.isPaused) {
274
536
  this.busy = true;
275
- if (this.firstAdjust) {
276
- this.firstAdjust = false;
277
- setTimeout(doAjdust, 50);
278
- } else {
279
- doAjdust();
280
- }
537
+ this.doAjdust();
538
+ onAdjusted(oldAdjustTop - adjust);
281
539
  }
282
540
  }
283
541
  getAppliedAdjust() {
284
542
  return this.appliedAdjust;
285
543
  }
286
- };
287
- var symbolFirst = Symbol();
288
- function useInit(cb) {
289
- const refValue = useRef(symbolFirst);
290
- if (refValue.current === symbolFirst) {
291
- refValue.current = cb();
544
+ pauseAdjust() {
545
+ this.isPaused = true;
292
546
  }
293
- return refValue.current;
294
- }
547
+ // return true if it was paused
548
+ unPauseAdjust() {
549
+ if (this.isPaused) {
550
+ this.isPaused = false;
551
+ this.doAjdust();
552
+ return true;
553
+ }
554
+ return false;
555
+ }
556
+ };
557
+ var useCombinedRef = (...refs) => {
558
+ const callback = useCallback((element) => {
559
+ for (const ref of refs) {
560
+ if (!ref) {
561
+ continue;
562
+ }
563
+ if (typeof ref === "function") {
564
+ ref(element);
565
+ } else {
566
+ ref.current = element;
567
+ }
568
+ }
569
+ }, refs);
570
+ return callback;
571
+ };
295
572
 
296
573
  // src/viewability.ts
297
574
  var mapViewabilityConfigCallbackPairs = /* @__PURE__ */ new Map();
@@ -442,15 +719,14 @@ function maybeUpdateViewabilityCallback(ctx, configId, viewToken) {
442
719
 
443
720
  // src/LegendList.tsx
444
721
  var DEFAULT_DRAW_DISTANCE = 250;
445
- var POSITION_OUT_OF_VIEW = -1e7;
446
722
  var DEFAULT_ITEM_SIZE = 100;
447
- var LegendList = forwardRef(function LegendList2(props, forwardedRef) {
448
- return /* @__PURE__ */ React4.createElement(StateProvider, null, /* @__PURE__ */ React4.createElement(LegendListInner, { ...props, ref: forwardedRef }));
723
+ var LegendList = typedForwardRef(function LegendList2(props, forwardedRef) {
724
+ return /* @__PURE__ */ React6.createElement(StateProvider, null, /* @__PURE__ */ React6.createElement(LegendListInner, { ...props, ref: forwardedRef }));
449
725
  });
450
- var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef) {
726
+ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
451
727
  var _a, _b, _c, _d;
452
728
  const {
453
- data,
729
+ data: dataProp,
454
730
  initialScrollIndex,
455
731
  initialScrollOffset,
456
732
  horizontal,
@@ -463,51 +739,73 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
463
739
  alignItemsAtEnd = false,
464
740
  maintainVisibleContentPosition = false,
465
741
  onScroll: onScrollProp,
742
+ onMomentumScrollEnd,
466
743
  numColumns: numColumnsProp = 1,
744
+ columnWrapperStyle,
467
745
  keyExtractor: keyExtractorProp,
468
746
  renderItem,
469
747
  estimatedItemSize,
470
748
  getEstimatedItemSize,
471
- onEndReached,
472
- onStartReached,
473
749
  ListEmptyComponent,
474
750
  onItemSizeChanged,
475
751
  scrollEventThrottle,
476
752
  refScrollView,
753
+ waitForInitialLayout = true,
477
754
  extraData,
755
+ onLayout: onLayoutProp,
756
+ onRefresh,
757
+ refreshing,
758
+ progressViewOffset,
759
+ refreshControl,
478
760
  ...rest
479
761
  } = props;
480
762
  const { style, contentContainerStyle } = props;
763
+ const callbacks = useRef({
764
+ onStartReached: rest.onStartReached,
765
+ onEndReached: rest.onEndReached
766
+ });
767
+ callbacks.current.onStartReached = rest.onStartReached;
768
+ callbacks.current.onEndReached = rest.onEndReached;
481
769
  const ctx = useStateContext();
770
+ ctx.columnWrapperStyle = columnWrapperStyle;
482
771
  const refScroller = useRef(null);
772
+ const combinedRef = useCombinedRef(refScroller, refScrollView);
483
773
  const scrollBuffer = drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE;
484
774
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (item, index) => index.toString();
485
775
  const refState = useRef();
486
776
  const getId = (index) => {
487
777
  var _a2;
488
- const data2 = (_a2 = refState.current) == null ? void 0 : _a2.data;
489
- if (!data2) {
778
+ const data = (_a2 = refState.current) == null ? void 0 : _a2.data;
779
+ if (!data) {
490
780
  return "";
491
781
  }
492
- const ret = index < data2.length ? keyExtractor ? keyExtractor(data2[index], index) : index : null;
782
+ const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
493
783
  return `${ret}`;
494
784
  };
495
- const getItemSize = (key, index, data2) => {
785
+ const getItemSize = (key, index, data) => {
496
786
  var _a2;
497
787
  const sizeKnown = refState.current.sizes.get(key);
498
788
  if (sizeKnown !== void 0) {
499
789
  return sizeKnown;
500
790
  }
501
- const size = (_a2 = getEstimatedItemSize ? getEstimatedItemSize(index, data2) : estimatedItemSize) != null ? _a2 : DEFAULT_ITEM_SIZE;
791
+ const size = (_a2 = getEstimatedItemSize ? getEstimatedItemSize(index, data) : estimatedItemSize) != null ? _a2 : DEFAULT_ITEM_SIZE;
502
792
  refState.current.sizes.set(key, size);
503
793
  return size;
504
794
  };
505
- const calculateInitialOffset = (index = initialScrollIndex) => {
795
+ const calculateOffsetForIndex = (index = initialScrollIndex) => {
796
+ const data = dataProp;
506
797
  if (index) {
507
798
  let offset = 0;
508
- if (getEstimatedItemSize) {
799
+ const canGetSize = !!refState.current;
800
+ if (canGetSize || getEstimatedItemSize) {
801
+ const sizeFn = (index2) => {
802
+ if (canGetSize) {
803
+ return getItemSize(getId(index2), index2, data[index2]);
804
+ }
805
+ return getEstimatedItemSize(index2, data[index2]);
806
+ };
509
807
  for (let i = 0; i < index; i++) {
510
- offset += getEstimatedItemSize(i, data[i]);
808
+ offset += sizeFn(i);
511
809
  }
512
810
  } else if (estimatedItemSize) {
513
811
  offset = index * estimatedItemSize;
@@ -516,7 +814,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
516
814
  }
517
815
  return 0;
518
816
  };
519
- const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : useMemo(calculateInitialOffset, []);
817
+ const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : useMemo(calculateOffsetForIndex, []);
520
818
  if (!refState.current) {
521
819
  const initialScrollLength = Dimensions.get("window")[horizontal ? "width" : "height"];
522
820
  refState.current = {
@@ -524,13 +822,11 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
524
822
  positions: /* @__PURE__ */ new Map(),
525
823
  columns: /* @__PURE__ */ new Map(),
526
824
  pendingAdjust: 0,
527
- animFrameLayout: null,
528
825
  isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
529
826
  isEndReached: false,
530
827
  isAtBottom: false,
531
828
  isAtTop: false,
532
- data,
533
- idsInFirstRender: void 0,
829
+ data: dataProp,
534
830
  hasScrolled: false,
535
831
  scrollLength: initialScrollLength,
536
832
  startBuffered: 0,
@@ -557,18 +853,19 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
557
853
  belowAnchorElementPositions: void 0,
558
854
  rowHeights: /* @__PURE__ */ new Map(),
559
855
  startReachedBlockedByTimer: false,
560
- layoutsPending: /* @__PURE__ */ new Set(),
856
+ endReachedBlockedByTimer: false,
561
857
  scrollForNextCalculateItemsInView: void 0,
562
- enableScrollForNextCalculateItemsInView: true
858
+ enableScrollForNextCalculateItemsInView: true,
859
+ minIndexSizeChanged: 0,
860
+ numPendingInitialLayout: 0
563
861
  };
564
- refState.current.idsInFirstRender = new Set(data.map((_, i) => getId(i)));
565
862
  if (maintainVisibleContentPosition) {
566
863
  if (initialScrollIndex) {
567
864
  refState.current.anchorElement = {
568
865
  coordinate: initialContentOffset,
569
866
  id: getId(initialScrollIndex)
570
867
  };
571
- } else if (data.length) {
868
+ } else if (dataProp.length) {
572
869
  refState.current.anchorElement = {
573
870
  coordinate: initialContentOffset,
574
871
  id: getId(0)
@@ -578,8 +875,11 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
578
875
  }
579
876
  }
580
877
  set$(ctx, "scrollAdjust", 0);
878
+ set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
581
879
  set$(ctx, "extraData", extraData);
582
880
  }
881
+ const didDataChange = refState.current.data !== dataProp;
882
+ refState.current.data = dataProp;
583
883
  const getAnchorElementIndex = () => {
584
884
  const state = refState.current;
585
885
  if (state.anchorElement) {
@@ -590,14 +890,14 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
590
890
  };
591
891
  const addTotalSize = useCallback((key, add, totalSizeBelowAnchor) => {
592
892
  const state = refState.current;
593
- const index = key === null ? 0 : state.indexByKey.get(key);
893
+ const { indexByKey, anchorElement } = state;
894
+ const index = key === null ? 0 : indexByKey.get(key);
594
895
  let isAboveAnchor = false;
595
896
  if (maintainVisibleContentPosition) {
596
- if (state.anchorElement && index < getAnchorElementIndex()) {
897
+ if (anchorElement && index < getAnchorElementIndex()) {
597
898
  isAboveAnchor = true;
598
899
  }
599
900
  }
600
- state.totalSize;
601
901
  if (key === null) {
602
902
  state.totalSize = add;
603
903
  state.totalSizeBelowAnchor = totalSizeBelowAnchor;
@@ -607,28 +907,28 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
607
907
  state.totalSizeBelowAnchor += add;
608
908
  }
609
909
  }
610
- let applyAdjustValue = void 0;
611
- if (maintainVisibleContentPosition) {
612
- const newAdjust = state.anchorElement.coordinate - state.totalSizeBelowAnchor;
910
+ let applyAdjustValue = 0;
911
+ let resultSize = state.totalSize;
912
+ if (maintainVisibleContentPosition && anchorElement !== void 0) {
913
+ const newAdjust = anchorElement.coordinate - state.totalSizeBelowAnchor;
613
914
  applyAdjustValue = -newAdjust;
614
915
  state.belowAnchorElementPositions = buildElementPositionsBelowAnchor();
615
916
  state.rowHeights.clear();
917
+ if (applyAdjustValue !== void 0) {
918
+ resultSize -= applyAdjustValue;
919
+ refState.current.scrollAdjustHandler.requestAdjust(applyAdjustValue, (diff) => {
920
+ state.scroll -= diff;
921
+ });
922
+ }
616
923
  }
617
- const totalSize = state.totalSize;
618
- let resultSize = totalSize;
619
- if (applyAdjustValue !== void 0) {
620
- resultSize -= applyAdjustValue;
621
- refState.current.scrollAdjustHandler.requestAdjust(applyAdjustValue, (diff) => {
622
- state.scroll -= diff;
623
- });
624
- }
625
- set$(ctx, "totalSize", resultSize);
924
+ set$(ctx, "totalSize", state.totalSize);
925
+ set$(ctx, "totalSizeWithScrollAdjust", resultSize);
626
926
  if (alignItemsAtEnd) {
627
927
  doUpdatePaddingTop();
628
928
  }
629
929
  }, []);
630
930
  const getRowHeight = (n) => {
631
- const { rowHeights } = refState.current;
931
+ const { rowHeights, data } = refState.current;
632
932
  if (numColumnsProp === 1) {
633
933
  const id = getId(n);
634
934
  return getItemSize(id, n, data[n]);
@@ -668,39 +968,47 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
668
968
  return map;
669
969
  };
670
970
  const getElementPositionBelowAchor = (id) => {
971
+ var _a2;
671
972
  const state = refState.current;
672
973
  if (!refState.current.belowAnchorElementPositions) {
673
974
  state.belowAnchorElementPositions = buildElementPositionsBelowAnchor();
674
975
  }
675
976
  const res = state.belowAnchorElementPositions.get(id);
676
977
  if (res === void 0) {
677
- throw new Error("Undefined position below achor");
978
+ console.warn(`Undefined position below achor ${id} ${(_a2 = state.anchorElement) == null ? void 0 : _a2.id}`);
979
+ return 0;
678
980
  }
679
981
  return res;
680
982
  };
681
983
  const calculateItemsInView = useCallback((speed) => {
984
+ var _a2;
682
985
  const state = refState.current;
683
986
  const {
684
- data: data2,
987
+ data,
685
988
  scrollLength,
686
989
  scroll: scrollState,
687
990
  startBufferedId: startBufferedIdOrig,
688
991
  positions,
689
992
  columns,
690
- scrollAdjustHandler,
691
- layoutsPending
993
+ scrollAdjustHandler
692
994
  } = state;
693
- if (state.animFrameLayout) {
694
- cancelAnimationFrame(state.animFrameLayout);
695
- state.animFrameLayout = null;
696
- }
697
- if (!data2) {
995
+ if (!data || scrollLength === 0) {
698
996
  return;
699
997
  }
700
998
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
701
999
  const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
702
1000
  const scrollExtra = Math.max(-16, Math.min(16, speed)) * 16;
703
- const scroll = scrollState - previousScrollAdjust - topPad - scrollExtra;
1001
+ const scroll = scrollState - previousScrollAdjust - topPad;
1002
+ let scrollBufferTop = scrollBuffer;
1003
+ let scrollBufferBottom = scrollBuffer;
1004
+ if (scrollExtra > 8) {
1005
+ scrollBufferTop = 0;
1006
+ scrollBufferBottom = scrollBuffer + scrollExtra;
1007
+ }
1008
+ if (scrollExtra < -8) {
1009
+ scrollBufferTop = scrollBuffer - scrollExtra;
1010
+ scrollBufferBottom = 0;
1011
+ }
704
1012
  if (state.scrollForNextCalculateItemsInView) {
705
1013
  const { top: top2, bottom } = state.scrollForNextCalculateItemsInView;
706
1014
  if (scroll > top2 && scroll < bottom) {
@@ -713,8 +1021,11 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
713
1021
  let startBufferedId = null;
714
1022
  let endNoBuffer = null;
715
1023
  let endBuffered = null;
716
- const originalStartId = startBufferedIdOrig && state.indexByKey.get(startBufferedIdOrig);
717
- let loopStart = originalStartId || 0;
1024
+ let loopStart = startBufferedIdOrig ? state.indexByKey.get(startBufferedIdOrig) || 0 : 0;
1025
+ if (state.minIndexSizeChanged !== void 0) {
1026
+ loopStart = Math.min(state.minIndexSizeChanged, loopStart);
1027
+ state.minIndexSizeChanged = void 0;
1028
+ }
718
1029
  const anchorElementIndex = getAnchorElementIndex();
719
1030
  for (let i = loopStart; i >= 0; i--) {
720
1031
  const id = getId(i);
@@ -727,7 +1038,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
727
1038
  }
728
1039
  const top2 = newPosition || positions.get(id);
729
1040
  if (top2 !== void 0) {
730
- const size = getItemSize(id, i, data2[i]);
1041
+ const size = getItemSize(id, i, data[i]);
731
1042
  const bottom = top2 + size;
732
1043
  if (bottom > scroll - scrollBuffer) {
733
1044
  loopStart = i;
@@ -745,22 +1056,22 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
745
1056
  let column = 1;
746
1057
  let maxSizeInRow = 0;
747
1058
  const getInitialTop = (i) => {
748
- var _a2;
1059
+ var _a3;
749
1060
  const id = getId(i);
750
1061
  let topOffset = 0;
751
1062
  if (positions.get(id)) {
752
1063
  topOffset = positions.get(id);
753
1064
  }
754
- if (id === ((_a2 = state.anchorElement) == null ? void 0 : _a2.id)) {
755
- topOffset = initialContentOffset || 0;
1065
+ if (id === ((_a3 = state.anchorElement) == null ? void 0 : _a3.id)) {
1066
+ topOffset = state.anchorElement.coordinate;
756
1067
  }
757
1068
  return topOffset;
758
1069
  };
759
- for (let i = loopStart; i < data2.length; i++) {
1070
+ for (let i = loopStart; i < data.length; i++) {
760
1071
  const id = getId(i);
761
- const size = getItemSize(id, i, data2[i]);
1072
+ const size = getItemSize(id, i, data[i]);
762
1073
  maxSizeInRow = Math.max(maxSizeInRow, size);
763
- if (top === void 0) {
1074
+ if (top === void 0 || id === ((_a2 = state.anchorElement) == null ? void 0 : _a2.id)) {
764
1075
  top = getInitialTop(i);
765
1076
  }
766
1077
  if (positions.get(id) !== top) {
@@ -772,7 +1083,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
772
1083
  if (startNoBuffer === null && top + size > scroll) {
773
1084
  startNoBuffer = i;
774
1085
  }
775
- if (startBuffered === null && top + size > scroll - scrollBuffer) {
1086
+ if (startBuffered === null && top + size > scroll - scrollBufferTop) {
776
1087
  startBuffered = i;
777
1088
  startBufferedId = id;
778
1089
  }
@@ -780,7 +1091,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
780
1091
  if (top <= scrollBottom) {
781
1092
  endNoBuffer = i;
782
1093
  }
783
- if (top <= scrollBottom + scrollBuffer) {
1094
+ if (top <= scrollBottom + scrollBufferBottom) {
784
1095
  endBuffered = i;
785
1096
  } else {
786
1097
  break;
@@ -834,7 +1145,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
834
1145
  break;
835
1146
  }
836
1147
  const index = state.indexByKey.get(key);
837
- const pos = peek$(ctx, `containerPosition${u}`);
1148
+ const pos = peek$(ctx, `containerPosition${u}`).top;
838
1149
  if (index < startBuffered || index > endBuffered) {
839
1150
  const distance = Math.abs(pos - top2);
840
1151
  if (index < 0 || distance > furthestDistance) {
@@ -846,14 +1157,14 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
846
1157
  if (furthestIndex >= 0) {
847
1158
  set$(ctx, `containerItemKey${furthestIndex}`, id);
848
1159
  const index = state.indexByKey.get(id);
849
- set$(ctx, `containerItemData${furthestIndex}`, data2[index]);
1160
+ set$(ctx, `containerItemData${furthestIndex}`, data[index]);
850
1161
  } else {
851
1162
  const containerId = numContainers;
852
1163
  numContainers++;
853
1164
  set$(ctx, `containerItemKey${containerId}`, id);
854
1165
  const index = state.indexByKey.get(id);
855
- set$(ctx, `containerItemData${containerId}`, data2[index]);
856
- set$(ctx, `containerPosition${containerId}`, POSITION_OUT_OF_VIEW);
1166
+ set$(ctx, `containerItemData${containerId}`, data[index]);
1167
+ set$(ctx, `containerPosition${containerId}`, ANCHORED_POSITION_OUT_OF_VIEW);
857
1168
  set$(ctx, `containerColumn${containerId}`, -1);
858
1169
  if (__DEV__ && numContainers > peek$(ctx, "numContainersPooled")) {
859
1170
  console.warn(
@@ -873,40 +1184,49 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
873
1184
  for (let i = 0; i < numContainers; i++) {
874
1185
  const itemKey = peek$(ctx, `containerItemKey${i}`);
875
1186
  const itemIndex = state.indexByKey.get(itemKey);
876
- const item = data2[itemIndex];
1187
+ const item = data[itemIndex];
877
1188
  if (item) {
878
1189
  const id = getId(itemIndex);
879
1190
  if (itemKey !== id || itemIndex < startBuffered || itemIndex > endBuffered) {
880
- const prevPos = peek$(ctx, `containerPosition${i}`);
1191
+ const prevPos = peek$(ctx, `containerPosition${i}`).top;
881
1192
  const pos = positions.get(id) || 0;
882
- const size = getItemSize(id, itemIndex, data2[i]);
1193
+ const size = getItemSize(id, itemIndex, data[i]);
883
1194
  if (pos + size >= scroll && pos <= scrollBottom || prevPos + size >= scroll && prevPos <= scrollBottom) {
884
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1195
+ set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
885
1196
  }
886
1197
  } else {
887
- const pos = positions.get(id) || 0;
1198
+ const pos = {
1199
+ type: "top",
1200
+ relativeCoordinate: positions.get(id) || 0,
1201
+ top: positions.get(id) || 0
1202
+ };
888
1203
  const column2 = columns.get(id) || 1;
1204
+ if (maintainVisibleContentPosition && itemIndex < anchorElementIndex) {
1205
+ const currentRow = Math.floor(itemIndex / numColumnsProp);
1206
+ const rowHeight = getRowHeight(currentRow);
1207
+ const elementHeight = getItemSize(id, itemIndex, data[i]);
1208
+ const diff = rowHeight - elementHeight;
1209
+ pos.relativeCoordinate = pos.top + getRowHeight(currentRow) - diff;
1210
+ pos.type = "bottom";
1211
+ }
889
1212
  const prevPos = peek$(ctx, `containerPosition${i}`);
890
1213
  const prevColumn = peek$(ctx, `containerColumn${i}`);
891
1214
  const prevData = peek$(ctx, `containerItemData${i}`);
892
- if (pos > POSITION_OUT_OF_VIEW && pos !== prevPos) {
1215
+ if (pos.relativeCoordinate > POSITION_OUT_OF_VIEW && pos.top !== prevPos.top) {
893
1216
  set$(ctx, `containerPosition${i}`, pos);
894
1217
  }
895
1218
  if (column2 >= 0 && column2 !== prevColumn) {
896
1219
  set$(ctx, `containerColumn${i}`, column2);
897
1220
  }
898
1221
  if (prevData !== item) {
899
- set$(ctx, `containerItemData${i}`, data2[itemIndex]);
1222
+ set$(ctx, `containerItemData${i}`, data[itemIndex]);
900
1223
  }
901
1224
  }
902
1225
  }
903
1226
  }
904
1227
  }
905
- if (layoutsPending.size > 0) {
906
- for (const containerId of layoutsPending) {
907
- set$(ctx, `containerDidLayout${containerId}`, true);
908
- }
909
- layoutsPending.clear();
1228
+ if (state.numPendingInitialLayout === 0) {
1229
+ state.numPendingInitialLayout = state.endBuffered - state.startBuffered + 1;
910
1230
  }
911
1231
  if (state.viewabilityConfigCallbackPairs) {
912
1232
  updateViewableItems(
@@ -922,16 +1242,19 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
922
1242
  }, []);
923
1243
  const doUpdatePaddingTop = () => {
924
1244
  if (alignItemsAtEnd) {
925
- const { scrollLength, totalSize } = refState.current;
926
- const listPaddingTop = peek$(ctx, "stylePaddingTop") || 0;
927
- const paddingTop = Math.max(0, Math.floor(scrollLength - totalSize - listPaddingTop));
1245
+ const { scrollLength } = refState.current;
1246
+ const contentSize = getContentSize(ctx);
1247
+ const paddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
928
1248
  set$(ctx, "paddingTop", paddingTop);
929
1249
  }
930
1250
  };
931
1251
  const doMaintainScrollAtEnd = (animated) => {
932
1252
  const state = refState.current;
933
1253
  if ((state == null ? void 0 : state.isAtBottom) && maintainScrollAtEnd) {
934
- state.scroll = state.totalSize - state.scrollLength + peek$(ctx, "paddingTop");
1254
+ const paddingTop = peek$(ctx, "paddingTop") || 0;
1255
+ if (paddingTop > 0) {
1256
+ state.scroll = 0;
1257
+ }
935
1258
  requestAnimationFrame(() => {
936
1259
  var _a2;
937
1260
  (_a2 = refScroller.current) == null ? void 0 : _a2.scrollToEnd({
@@ -941,28 +1264,48 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
941
1264
  return true;
942
1265
  }
943
1266
  };
1267
+ const checkThreshold = (distance, threshold, isReached, isBlockedByTimer, onReached, blockTimer) => {
1268
+ const distanceAbs = Math.abs(distance);
1269
+ const isAtThreshold = distanceAbs < threshold;
1270
+ if (!isReached && !isBlockedByTimer) {
1271
+ if (isAtThreshold) {
1272
+ onReached == null ? void 0 : onReached(distance);
1273
+ blockTimer == null ? void 0 : blockTimer(true);
1274
+ setTimeout(() => {
1275
+ blockTimer == null ? void 0 : blockTimer(false);
1276
+ }, 700);
1277
+ return true;
1278
+ }
1279
+ } else {
1280
+ if (distance >= 1.3 * threshold) {
1281
+ return false;
1282
+ }
1283
+ }
1284
+ return isReached;
1285
+ };
944
1286
  const checkAtBottom = () => {
945
1287
  if (!refState.current) {
946
1288
  return;
947
1289
  }
948
- const { scrollLength, scroll, totalSize } = refState.current;
949
- if (totalSize > 0) {
950
- const distanceFromEnd = totalSize - scroll - scrollLength;
951
- if (refState.current) {
952
- refState.current.isAtBottom = distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
953
- }
954
- if (onEndReached) {
955
- if (!refState.current.isEndReached) {
956
- if (distanceFromEnd < onEndReachedThreshold * scrollLength) {
957
- refState.current.isEndReached = true;
958
- onEndReached({ distanceFromEnd });
959
- }
960
- } else {
961
- if (distanceFromEnd >= onEndReachedThreshold * scrollLength) {
962
- refState.current.isEndReached = false;
963
- }
1290
+ const { scrollLength, scroll, hasScrolled } = refState.current;
1291
+ const contentSize = getContentSize(ctx);
1292
+ if (contentSize > 0 && hasScrolled) {
1293
+ const distanceFromEnd = contentSize - scroll - scrollLength;
1294
+ const distanceFromEndAbs = Math.abs(distanceFromEnd);
1295
+ refState.current.isAtBottom = distanceFromEndAbs < scrollLength * maintainScrollAtEndThreshold;
1296
+ refState.current.isEndReached = checkThreshold(
1297
+ distanceFromEnd,
1298
+ onEndReachedThreshold * scrollLength,
1299
+ refState.current.isEndReached,
1300
+ refState.current.endReachedBlockedByTimer,
1301
+ (distance) => {
1302
+ var _a2, _b2;
1303
+ return (_b2 = (_a2 = callbacks.current).onEndReached) == null ? void 0 : _b2.call(_a2, { distanceFromEnd: distance });
1304
+ },
1305
+ (block) => {
1306
+ refState.current.endReachedBlockedByTimer = block;
964
1307
  }
965
- }
1308
+ );
966
1309
  }
967
1310
  };
968
1311
  const checkAtTop = () => {
@@ -971,74 +1314,114 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
971
1314
  }
972
1315
  const { scrollLength, scroll } = refState.current;
973
1316
  const distanceFromTop = scroll;
974
- refState.current.isAtTop = distanceFromTop < 0;
975
- if (onStartReached) {
976
- if (!refState.current.isStartReached && !refState.current.startReachedBlockedByTimer) {
977
- if (distanceFromTop < onStartReachedThreshold * scrollLength) {
978
- refState.current.isStartReached = true;
979
- onStartReached({ distanceFromStart: scroll });
980
- refState.current.startReachedBlockedByTimer = true;
981
- setTimeout(() => {
982
- refState.current.startReachedBlockedByTimer = false;
983
- }, 700);
984
- }
985
- } else {
986
- if (distanceFromTop >= 1.3 * onStartReachedThreshold * scrollLength) {
987
- refState.current.isStartReached = false;
988
- }
1317
+ const distanceFromTopAbs = Math.abs(distanceFromTop);
1318
+ refState.current.isAtTop = distanceFromTopAbs < 0;
1319
+ refState.current.isStartReached = checkThreshold(
1320
+ distanceFromTop,
1321
+ onStartReachedThreshold * scrollLength,
1322
+ refState.current.isStartReached,
1323
+ refState.current.startReachedBlockedByTimer,
1324
+ (distance) => {
1325
+ var _a2, _b2;
1326
+ return (_b2 = (_a2 = callbacks.current).onStartReached) == null ? void 0 : _b2.call(_a2, { distanceFromStart: distance });
1327
+ },
1328
+ (block) => {
1329
+ refState.current.startReachedBlockedByTimer = block;
989
1330
  }
990
- }
1331
+ );
991
1332
  };
992
- const checkResetContainers = (reset) => {
1333
+ const checkResetContainers = (isFirst2) => {
993
1334
  const state = refState.current;
994
1335
  if (state) {
995
- state.data = data;
996
- if (reset) {
1336
+ state.data = dataProp;
1337
+ if (!isFirst2) {
997
1338
  refState.current.scrollForNextCalculateItemsInView = void 0;
998
1339
  const numContainers = peek$(ctx, "numContainers");
999
1340
  for (let i = 0; i < numContainers; i++) {
1000
1341
  const itemKey = peek$(ctx, `containerItemKey${i}`);
1001
1342
  if (!keyExtractorProp || itemKey && state.indexByKey.get(itemKey) === void 0) {
1002
1343
  set$(ctx, `containerItemKey${i}`, void 0);
1003
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1344
+ set$(ctx, `containerItemData${i}`, void 0);
1345
+ set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1004
1346
  set$(ctx, `containerColumn${i}`, -1);
1005
1347
  }
1006
1348
  }
1007
1349
  if (!keyExtractorProp) {
1008
- state.sizes.clear();
1009
- state.positions;
1350
+ state.positions.clear();
1010
1351
  }
1011
1352
  calculateItemsInView(state.scrollVelocity);
1353
+ const didMaintainScrollAtEnd = doMaintainScrollAtEnd(false);
1354
+ if (!didMaintainScrollAtEnd && dataProp.length > state.data.length) {
1355
+ state.isEndReached = false;
1356
+ }
1357
+ checkAtTop();
1358
+ checkAtBottom();
1012
1359
  }
1013
- const didMaintainScrollAtEnd = doMaintainScrollAtEnd(false);
1014
- if (!didMaintainScrollAtEnd && data.length > state.data.length) {
1015
- state.isEndReached = false;
1016
- }
1017
- checkAtTop();
1018
- checkAtBottom();
1019
1360
  }
1020
1361
  };
1021
- const isFirst = !refState.current.renderItem;
1022
- if (isFirst || data !== refState.current.data || numColumnsProp !== peek$(ctx, "numColumns")) {
1023
- if (!keyExtractorProp && !isFirst && data !== refState.current.data) {
1024
- refState.current.sizes.clear();
1025
- refState.current.positions.clear();
1026
- }
1027
- refState.current.data = data;
1362
+ const calcTotalSizesAndPositions = ({ forgetPositions = false }) => {
1363
+ var _a2, _b2, _c2;
1028
1364
  let totalSize = 0;
1029
1365
  let totalSizeBelowIndex = 0;
1030
1366
  const indexByKey = /* @__PURE__ */ new Map();
1367
+ const newPositions = /* @__PURE__ */ new Map();
1031
1368
  let column = 1;
1032
1369
  let maxSizeInRow = 0;
1033
- for (let i = 0; i < data.length; i++) {
1370
+ if (!refState.current) {
1371
+ return;
1372
+ }
1373
+ for (let i = 0; i < dataProp.length; i++) {
1034
1374
  const key = getId(i);
1375
+ if (__DEV__) {
1376
+ if (indexByKey.has(key)) {
1377
+ console.error(
1378
+ `[legend-list] Error: Detected overlapping key (${key}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
1379
+ );
1380
+ }
1381
+ }
1035
1382
  indexByKey.set(key, i);
1383
+ if (!forgetPositions && refState.current.positions.get(key) != null && refState.current.indexByKey.get(key) === i) {
1384
+ newPositions.set(key, refState.current.positions.get(key));
1385
+ }
1036
1386
  }
1037
1387
  refState.current.indexByKey = indexByKey;
1388
+ refState.current.positions = newPositions;
1389
+ if (!forgetPositions && !isFirst) {
1390
+ if (maintainVisibleContentPosition) {
1391
+ if (refState.current.anchorElement == null || indexByKey.get(refState.current.anchorElement.id) == null) {
1392
+ if (dataProp.length) {
1393
+ const newAnchorElement = {
1394
+ coordinate: 0,
1395
+ id: getId(0)
1396
+ };
1397
+ refState.current.anchorElement = newAnchorElement;
1398
+ (_a2 = refState.current.belowAnchorElementPositions) == null ? void 0 : _a2.clear();
1399
+ (_b2 = refScroller.current) == null ? void 0 : _b2.scrollTo({ x: 0, y: 0, animated: false });
1400
+ setTimeout(() => {
1401
+ calculateItemsInView(0);
1402
+ }, 0);
1403
+ } else {
1404
+ refState.current.startBufferedId = void 0;
1405
+ }
1406
+ }
1407
+ } else {
1408
+ if (refState.current.startBufferedId != null && newPositions.get(refState.current.startBufferedId) == null) {
1409
+ if (dataProp.length) {
1410
+ refState.current.startBufferedId = getId(0);
1411
+ } else {
1412
+ refState.current.startBufferedId = void 0;
1413
+ }
1414
+ (_c2 = refScroller.current) == null ? void 0 : _c2.scrollTo({ x: 0, y: 0, animated: false });
1415
+ setTimeout(() => {
1416
+ calculateItemsInView(0);
1417
+ }, 0);
1418
+ }
1419
+ }
1420
+ }
1038
1421
  const anchorElementIndex = getAnchorElementIndex();
1039
- for (let i = 0; i < data.length; i++) {
1422
+ for (let i = 0; i < dataProp.length; i++) {
1040
1423
  const key = getId(i);
1041
- const size = getItemSize(key, i, data[i]);
1424
+ const size = getItemSize(key, i, dataProp[i]);
1042
1425
  maxSizeInRow = Math.max(maxSizeInRow, size);
1043
1426
  column++;
1044
1427
  if (column > numColumnsProp) {
@@ -1054,170 +1437,134 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1054
1437
  totalSize += maxSizeInRow;
1055
1438
  }
1056
1439
  addTotalSize(null, totalSize, totalSizeBelowIndex);
1440
+ };
1441
+ const isFirst = !refState.current.renderItem;
1442
+ if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
1443
+ if (!keyExtractorProp && !isFirst && didDataChange) {
1444
+ refState.current.sizes.clear();
1445
+ refState.current.positions.clear();
1446
+ }
1447
+ calcTotalSizesAndPositions({ forgetPositions: false });
1057
1448
  }
1058
1449
  useEffect(() => {
1059
1450
  checkResetContainers(
1060
- /*reset*/
1061
- !isFirst
1451
+ /*isFirst*/
1452
+ isFirst
1062
1453
  );
1063
- }, [isFirst, data, numColumnsProp]);
1454
+ }, [isFirst, dataProp, numColumnsProp]);
1064
1455
  useEffect(() => {
1065
1456
  set$(ctx, "extraData", extraData);
1066
1457
  }, [extraData]);
1067
1458
  refState.current.renderItem = renderItem;
1068
- const lastItemKey = getId(data[data.length - 1]);
1459
+ const memoizedLastItemKeys = useMemo(() => {
1460
+ if (!dataProp.length) return [];
1461
+ return new Set(
1462
+ Array.from({ length: Math.min(numColumnsProp, dataProp.length) }, (_, i) => getId(dataProp.length - 1 - i))
1463
+ );
1464
+ }, [dataProp.length, numColumnsProp, dataProp.slice(-numColumnsProp).toString()]);
1069
1465
  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;
1070
1466
  const initalizeStateVars = () => {
1071
- set$(ctx, "lastItemKey", lastItemKey);
1467
+ set$(ctx, "lastItemKeys", memoizedLastItemKeys);
1072
1468
  set$(ctx, "numColumns", numColumnsProp);
1073
1469
  set$(ctx, "stylePaddingTop", stylePaddingTop);
1074
1470
  };
1075
1471
  if (isFirst) {
1076
1472
  initalizeStateVars();
1077
1473
  }
1078
- useEffect(initalizeStateVars, [lastItemKey, numColumnsProp, stylePaddingTop]);
1079
- const getRenderedItem = useCallback((key, containerId) => {
1474
+ useEffect(initalizeStateVars, [memoizedLastItemKeys, numColumnsProp, stylePaddingTop]);
1475
+ const getRenderedItem = useCallback((key) => {
1080
1476
  var _a2, _b2;
1081
1477
  const state = refState.current;
1082
1478
  if (!state) {
1083
1479
  return null;
1084
1480
  }
1085
- const { data: data2, indexByKey } = state;
1481
+ const { data, indexByKey } = state;
1086
1482
  const index = indexByKey.get(key);
1087
1483
  if (index === void 0) {
1088
1484
  return null;
1089
1485
  }
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
- );
1486
+ const useViewability2 = (configId, callback) => {
1487
+ useViewability(configId, callback);
1105
1488
  };
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
- );
1489
+ const useViewabilityAmount2 = (callback) => {
1490
+ useViewabilityAmount(callback);
1120
1491
  };
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
- }, []);
1492
+ const useRecyclingEffect2 = (effect) => {
1493
+ useRecyclingEffect(effect);
1148
1494
  };
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;
1495
+ const useRecyclingState2 = (valueOrFun) => {
1496
+ return useRecyclingState(valueOrFun);
1163
1497
  };
1164
1498
  const renderedItem = (_b2 = (_a2 = refState.current).renderItem) == null ? void 0 : _b2.call(_a2, {
1165
- item: data2[index],
1499
+ item: data[index],
1166
1500
  index,
1167
- useViewability,
1168
- useViewabilityAmount,
1169
- useRecyclingEffect,
1170
- useRecyclingState
1501
+ useViewability: useViewability2,
1502
+ useViewabilityAmount: useViewabilityAmount2,
1503
+ useRecyclingEffect: useRecyclingEffect2,
1504
+ useRecyclingState: useRecyclingState2
1171
1505
  });
1172
- return renderedItem;
1506
+ return { index, item: data[index], renderedItem };
1173
1507
  }, []);
1174
- useInit(() => {
1508
+ const doInitialAllocateContainers = () => {
1175
1509
  var _a2;
1510
+ const state = refState.current;
1511
+ const scrollLength = state.scrollLength;
1512
+ if (scrollLength > 0 && !peek$(ctx, "numContainers")) {
1513
+ const averageItemSize = (_a2 = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, dataProp[0])) != null ? _a2 : DEFAULT_ITEM_SIZE;
1514
+ const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) * numColumnsProp;
1515
+ for (let i = 0; i < numContainers; i++) {
1516
+ set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1517
+ set$(ctx, `containerColumn${i}`, -1);
1518
+ }
1519
+ set$(ctx, "numContainers", numContainers);
1520
+ set$(ctx, "numContainersPooled", numContainers * 2);
1521
+ if (initialScrollIndex) {
1522
+ requestAnimationFrame(() => {
1523
+ calculateItemsInView(state.scrollVelocity);
1524
+ });
1525
+ } else {
1526
+ calculateItemsInView(state.scrollVelocity);
1527
+ }
1528
+ }
1529
+ };
1530
+ useInit(() => {
1176
1531
  const state = refState.current;
1177
1532
  const viewability = setupViewability(props);
1178
1533
  state.viewabilityConfigCallbackPairs = viewability;
1179
1534
  state.enableScrollForNextCalculateItemsInView = !viewability;
1180
- const scrollLength = state.scrollLength;
1181
- const averageItemSize = (_a2 = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, data[0])) != null ? _a2 : DEFAULT_ITEM_SIZE;
1182
- const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) * numColumnsProp;
1183
- for (let i = 0; i < numContainers; i++) {
1184
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1185
- set$(ctx, `containerColumn${i}`, -1);
1186
- }
1187
- set$(ctx, "numContainers", numContainers);
1188
- set$(ctx, "numContainersPooled", numContainers * 2);
1189
- calculateItemsInView(state.scrollVelocity);
1535
+ doInitialAllocateContainers();
1190
1536
  });
1191
1537
  const updateItemSize = useCallback((containerId, itemKey, size) => {
1192
- var _a2;
1193
- const data2 = (_a2 = refState.current) == null ? void 0 : _a2.data;
1194
- if (!data2) {
1538
+ const state = refState.current;
1539
+ const { sizes, indexByKey, sizesLaidOut, data, rowHeights } = state;
1540
+ if (!data) {
1195
1541
  return;
1196
1542
  }
1197
- const state = refState.current;
1198
- const { sizes, indexByKey, idsInFirstRender, columns, sizesLaidOut } = state;
1199
1543
  const index = indexByKey.get(itemKey);
1200
1544
  const numColumns = peek$(ctx, "numColumns");
1201
- const row = Math.floor(index / numColumns);
1202
- const prevSize = getRowHeight(row);
1203
- const measured = peek$(ctx, `containerDidLayout${containerId}`);
1204
- if (!measured) {
1205
- state.layoutsPending.add(containerId);
1545
+ state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, index) : index;
1546
+ const prevSize = getItemSize(itemKey, index, data);
1547
+ let needsCalculate = false;
1548
+ if (state.numPendingInitialLayout > 0) {
1549
+ state.numPendingInitialLayout--;
1550
+ if (state.numPendingInitialLayout === 0) {
1551
+ needsCalculate = true;
1552
+ state.numPendingInitialLayout = -1;
1553
+ queueMicrotask(() => {
1554
+ set$(ctx, "containersDidLayout", true);
1555
+ });
1556
+ }
1206
1557
  }
1207
1558
  if (!prevSize || Math.abs(prevSize - size) > 0.5) {
1208
1559
  let diff;
1560
+ needsCalculate = true;
1209
1561
  if (numColumns > 1) {
1210
- const prevMaxSizeInRow = getRowHeight(row);
1562
+ const rowNumber = Math.floor(index / numColumnsProp);
1563
+ const prevSizeInRow = getRowHeight(rowNumber);
1211
1564
  sizes.set(itemKey, size);
1212
- const column = columns.get(itemKey);
1213
- const loopStart = index - (column - 1);
1214
- let nextMaxSizeInRow = 0;
1215
- for (let i = loopStart; i < loopStart + numColumns && i < data2.length; i++) {
1216
- const id = getId(i);
1217
- const size2 = getItemSize(id, i, data2[i]);
1218
- nextMaxSizeInRow = Math.max(nextMaxSizeInRow, size2);
1219
- }
1220
- diff = nextMaxSizeInRow - prevMaxSizeInRow;
1565
+ rowHeights.delete(rowNumber);
1566
+ const sizeInRow = getRowHeight(rowNumber);
1567
+ diff = sizeInRow - prevSizeInRow;
1221
1568
  } else {
1222
1569
  sizes.set(itemKey, size);
1223
1570
  diff = size - prevSize;
@@ -1244,22 +1591,21 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1244
1591
  refState.current.scrollForNextCalculateItemsInView = void 0;
1245
1592
  addTotalSize(itemKey, diff, 0);
1246
1593
  doMaintainScrollAtEnd(true);
1247
- 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);
1253
- });
1254
- } else {
1255
- calculateItemsInView(state.scrollVelocity);
1256
- }
1257
- }
1258
1594
  if (onItemSizeChanged) {
1259
- onItemSizeChanged({ size, previous: prevSize, index, itemKey, itemData: data2[index] });
1595
+ onItemSizeChanged({
1596
+ size,
1597
+ previous: prevSize,
1598
+ index,
1599
+ itemKey,
1600
+ itemData: data[index]
1601
+ });
1602
+ }
1603
+ }
1604
+ if (needsCalculate) {
1605
+ const scrollVelocity = state.scrollVelocity;
1606
+ if ((Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1) && (!waitForInitialLayout || state.numPendingInitialLayout < 0)) {
1607
+ calculateItemsInView(state.scrollVelocity);
1260
1608
  }
1261
- } else {
1262
- set$(ctx, `containerDidLayout${containerId}`, true);
1263
1609
  }
1264
1610
  }, []);
1265
1611
  const handleScrollDebounced = useCallback((velocity) => {
@@ -1269,11 +1615,17 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1269
1615
  }, []);
1270
1616
  const onLayout = useCallback((event) => {
1271
1617
  const scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
1618
+ const didChange = scrollLength !== refState.current.scrollLength;
1619
+ refState.current.scrollLength;
1272
1620
  refState.current.scrollLength = scrollLength;
1621
+ doInitialAllocateContainers();
1273
1622
  doMaintainScrollAtEnd(false);
1274
1623
  doUpdatePaddingTop();
1275
1624
  checkAtBottom();
1276
1625
  checkAtTop();
1626
+ if (didChange) {
1627
+ calculateItemsInView(0);
1628
+ }
1277
1629
  if (__DEV__) {
1278
1630
  const isWidthZero = event.nativeEvent.layout.width === 0;
1279
1631
  const isHeightZero = event.nativeEvent.layout.height === 0;
@@ -1283,6 +1635,9 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1283
1635
  );
1284
1636
  }
1285
1637
  }
1638
+ if (onLayoutProp) {
1639
+ onLayoutProp(event);
1640
+ }
1286
1641
  }, []);
1287
1642
  const handleScroll = useCallback(
1288
1643
  (event, fromSelf) => {
@@ -1329,60 +1684,110 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1329
1684
  useImperativeHandle(
1330
1685
  forwardedRef,
1331
1686
  () => {
1332
- const scrollToIndex = ({ index, animated }) => {
1333
- const offsetObj = calculateInitialOffset(index);
1334
- const offset = horizontal ? { x: offsetObj, y: 0 } : { x: 0, y: offsetObj };
1335
- refScroller.current.scrollTo({ ...offset, animated });
1687
+ const scrollToIndex = ({
1688
+ index,
1689
+ viewOffset = 0,
1690
+ animated = true
1691
+ }) => {
1692
+ var _a2;
1693
+ const state = refState.current;
1694
+ const firstIndexOffset = calculateOffsetForIndex(index);
1695
+ let firstIndexScrollPostion = firstIndexOffset - viewOffset;
1696
+ const diff = Math.abs(state.scroll - firstIndexScrollPostion);
1697
+ const needsReanchoring = maintainVisibleContentPosition && diff > 100;
1698
+ if (needsReanchoring) {
1699
+ const id = getId(index);
1700
+ state.anchorElement = { id, coordinate: firstIndexOffset };
1701
+ (_a2 = state.belowAnchorElementPositions) == null ? void 0 : _a2.clear();
1702
+ state.positions.clear();
1703
+ calcTotalSizesAndPositions({ forgetPositions: true });
1704
+ state.scrollForNextCalculateItemsInView = void 0;
1705
+ state.startBufferedId = id;
1706
+ state.minIndexSizeChanged = index;
1707
+ firstIndexScrollPostion = firstIndexOffset - viewOffset + state.scrollAdjustHandler.getAppliedAdjust();
1708
+ }
1709
+ state.scrollAdjustHandler.pauseAdjust();
1710
+ setTimeout(
1711
+ () => {
1712
+ const wasAdjusted = state.scrollAdjustHandler.unPauseAdjust();
1713
+ if (wasAdjusted) {
1714
+ refState.current.scrollVelocity = 0;
1715
+ refState.current.scrollHistory = [];
1716
+ calculateItemsInView(0);
1717
+ }
1718
+ },
1719
+ animated ? 1e3 : 50
1720
+ );
1721
+ const offset = horizontal ? { x: firstIndexScrollPostion, y: 0 } : { x: 0, y: firstIndexScrollPostion };
1722
+ if (maintainVisibleContentPosition) {
1723
+ setTimeout(() => {
1724
+ refScroller.current.scrollTo({ ...offset, animated });
1725
+ }, 50);
1726
+ } else {
1727
+ refScroller.current.scrollTo({ ...offset, animated });
1728
+ }
1336
1729
  };
1337
1730
  return {
1338
1731
  getNativeScrollRef: () => refScroller.current,
1339
- getScrollableNode: refScroller.current.getScrollableNode,
1340
- getScrollResponder: refScroller.current.getScrollResponder,
1341
- flashScrollIndicators: refScroller.current.flashScrollIndicators,
1732
+ getScrollableNode: () => refScroller.current.getScrollableNode(),
1733
+ getScrollResponder: () => refScroller.current.getScrollResponder(),
1734
+ flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
1342
1735
  scrollToIndex,
1343
1736
  scrollToOffset: ({ offset, animated }) => {
1344
1737
  const offsetObj = horizontal ? { x: offset, y: 0 } : { x: 0, y: offset };
1345
1738
  refScroller.current.scrollTo({ ...offsetObj, animated });
1346
1739
  },
1347
1740
  scrollToItem: ({ item, animated }) => {
1741
+ const { data } = refState.current;
1348
1742
  const index = data.indexOf(item);
1349
1743
  if (index !== -1) {
1350
1744
  scrollToIndex({ index, animated });
1351
1745
  }
1352
1746
  },
1353
- scrollToEnd: refScroller.current.scrollToEnd
1747
+ scrollToEnd: (options) => refScroller.current.scrollToEnd(options)
1354
1748
  };
1355
1749
  },
1356
1750
  []
1357
1751
  );
1358
- return /* @__PURE__ */ React4.createElement(
1752
+ return /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(
1359
1753
  ListComponent,
1360
1754
  {
1361
1755
  ...rest,
1362
1756
  horizontal,
1363
- refScrollView: (r) => {
1364
- refScroller.current = r;
1365
- if (refScrollView) {
1366
- if (typeof refScrollView === "function") {
1367
- refScrollView(r);
1368
- } else {
1369
- refScrollView.current = r;
1370
- }
1371
- }
1372
- },
1757
+ refScrollView: combinedRef,
1373
1758
  initialContentOffset,
1374
1759
  getRenderedItem,
1375
1760
  updateItemSize,
1376
1761
  handleScroll,
1762
+ onMomentumScrollEnd: (event) => {
1763
+ const wasPaused = refState.current.scrollAdjustHandler.unPauseAdjust();
1764
+ if (wasPaused) {
1765
+ refState.current.scrollVelocity = 0;
1766
+ refState.current.scrollHistory = [];
1767
+ calculateItemsInView(0);
1768
+ }
1769
+ if (onMomentumScrollEnd) {
1770
+ onMomentumScrollEnd(event);
1771
+ }
1772
+ },
1377
1773
  onLayout,
1378
1774
  recycleItems,
1379
1775
  alignItemsAtEnd,
1380
- ListEmptyComponent: data.length === 0 ? ListEmptyComponent : void 0,
1776
+ ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
1381
1777
  maintainVisibleContentPosition,
1382
1778
  scrollEventThrottle: scrollEventThrottle != null ? scrollEventThrottle : Platform.OS === "web" ? 16 : void 0,
1779
+ waitForInitialLayout,
1780
+ refreshControl: refreshControl != null ? refreshControl : onRefresh && /* @__PURE__ */ React6.createElement(
1781
+ RefreshControl,
1782
+ {
1783
+ refreshing: !!refreshing,
1784
+ onRefresh,
1785
+ progressViewOffset
1786
+ }
1787
+ ),
1383
1788
  style
1384
1789
  }
1385
- );
1790
+ ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React6.createElement(DebugView, { state: refState.current }));
1386
1791
  });
1387
1792
 
1388
- export { LegendList };
1793
+ export { LegendList, useRecyclingEffect, useRecyclingState, useViewability, useViewabilityAmount };