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

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 React5 from 'react';
2
- import React5__default, { createContext, useMemo, forwardRef, useRef, useCallback, useEffect, useImperativeHandle, useSyncExternalStore, useContext, useState, useLayoutEffect } 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, { memo, useReducer, useEffect, createContext, useMemo, useRef, useCallback, useImperativeHandle, useSyncExternalStore, useContext, useState, forwardRef, useLayoutEffect } from 'react';
3
+ import { View, Text, Platform, Animated, ScrollView, StyleSheet, Dimensions, RefreshControl } from 'react-native';
4
4
 
5
5
  // src/LegendList.tsx
6
- var ContextState = React5.createContext(null);
6
+ var ContextState = React6.createContext(null);
7
7
  function StateProvider({ children }) {
8
- const [value] = React5.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__ */ React5.createElement(ContextState.Provider, { value }, children);
17
+ return /* @__PURE__ */ React6.createElement(ContextState.Provider, { value }, children);
17
18
  }
18
19
  function useStateContext() {
19
- return React5.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 = React5.useContext(ContextState);
29
- const { subscribe, get } = React5.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,6 +57,66 @@ 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
+
69
+ // src/DebugView.tsx
70
+ var DebugRow = ({ children }) => {
71
+ return /* @__PURE__ */ React.createElement(View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" } }, children);
72
+ };
73
+ var DebugView = memo(function DebugView2({ state }) {
74
+ const ctx = useStateContext();
75
+ const totalSize = use$("totalSize") || 0;
76
+ const totalSizeWithScrollAdjust = use$("totalSizeWithScrollAdjust") || 0;
77
+ const scrollAdjust = use$("scrollAdjust") || 0;
78
+ const rawScroll = use$("debugRawScroll") || 0;
79
+ const scroll = use$("debugComputedScroll") || 0;
80
+ const contentSize = getContentSize(ctx);
81
+ const [, forceUpdate] = useReducer((x) => x + 1, 0);
82
+ use$("numContainers");
83
+ use$("numContainersPooled");
84
+ useInterval(() => {
85
+ forceUpdate();
86
+ }, 100);
87
+ return /* @__PURE__ */ React.createElement(
88
+ View,
89
+ {
90
+ style: {
91
+ position: "absolute",
92
+ top: 0,
93
+ right: 0,
94
+ paddingLeft: 4,
95
+ paddingBottom: 4,
96
+ // height: 100,
97
+ backgroundColor: "#FFFFFFCC",
98
+ padding: 4,
99
+ borderRadius: 4
100
+ },
101
+ pointerEvents: "none"
102
+ },
103
+ /* @__PURE__ */ React.createElement(DebugRow, null, /* @__PURE__ */ React.createElement(Text, null, "TotalSize:"), /* @__PURE__ */ React.createElement(Text, null, totalSize.toFixed(2))),
104
+ /* @__PURE__ */ React.createElement(DebugRow, null, /* @__PURE__ */ React.createElement(Text, null, "ContentSize:"), /* @__PURE__ */ React.createElement(Text, null, contentSize.toFixed(2))),
105
+ /* @__PURE__ */ React.createElement(DebugRow, null, /* @__PURE__ */ React.createElement(Text, null, "At end:"), /* @__PURE__ */ React.createElement(Text, null, String(state.isAtBottom))),
106
+ /* @__PURE__ */ React.createElement(Text, null),
107
+ /* @__PURE__ */ React.createElement(DebugRow, null, /* @__PURE__ */ React.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React.createElement(Text, null, scrollAdjust.toFixed(2))),
108
+ /* @__PURE__ */ React.createElement(DebugRow, null, /* @__PURE__ */ React.createElement(Text, null, "TotalSizeReal: "), /* @__PURE__ */ React.createElement(Text, null, totalSizeWithScrollAdjust.toFixed(2))),
109
+ /* @__PURE__ */ React.createElement(Text, null),
110
+ /* @__PURE__ */ React.createElement(DebugRow, null, /* @__PURE__ */ React.createElement(Text, null, "RawScroll: "), /* @__PURE__ */ React.createElement(Text, null, rawScroll.toFixed(2))),
111
+ /* @__PURE__ */ React.createElement(DebugRow, null, /* @__PURE__ */ React.createElement(Text, null, "ComputedScroll: "), /* @__PURE__ */ React.createElement(Text, null, scroll.toFixed(2)))
112
+ );
113
+ });
114
+ function useInterval(callback, delay) {
115
+ useEffect(() => {
116
+ const interval = setInterval(callback, delay);
117
+ return () => clearInterval(interval);
118
+ }, [delay]);
119
+ }
59
120
  var symbolFirst = Symbol();
60
121
  function useInit(cb) {
61
122
  const refValue = useRef(symbolFirst);
@@ -141,10 +202,11 @@ function useRecyclingState(valueOrFun) {
141
202
  });
142
203
  return stateInfo;
143
204
  }
144
- var LeanView = React5.forwardRef((props, ref) => {
145
- return React5.createElement("RCTView", { ...props, ref });
205
+ var LeanViewComponent = React6.forwardRef((props, ref) => {
206
+ return React6.createElement("RCTView", { ...props, ref });
146
207
  });
147
- LeanView.displayName = "RCTView";
208
+ LeanViewComponent.displayName = "RCTView";
209
+ var LeanView = Platform.OS === "android" || Platform.OS === "ios" ? LeanViewComponent : View;
148
210
 
149
211
  // src/constants.ts
150
212
  var POSITION_OUT_OF_VIEW = -1e7;
@@ -153,6 +215,8 @@ var ANCHORED_POSITION_OUT_OF_VIEW = {
153
215
  relativeCoordinate: POSITION_OUT_OF_VIEW,
154
216
  top: POSITION_OUT_OF_VIEW
155
217
  };
218
+ var ENABLE_DEVMODE = __DEV__ && false;
219
+ var ENABLE_DEBUG_VIEW = __DEV__ && false;
156
220
 
157
221
  // src/Container.tsx
158
222
  var isNewArchitecture = global.nativeFabricUIManager != null;
@@ -164,13 +228,27 @@ var Container = ({
164
228
  updateItemSize,
165
229
  ItemSeparatorComponent
166
230
  }) => {
167
- useStateContext();
231
+ const ctx = useStateContext();
232
+ const columnWrapperStyle = ctx.columnWrapperStyle;
168
233
  const maintainVisibleContentPosition = use$("maintainVisibleContentPosition");
169
234
  const position = use$(`containerPosition${id}`) || ANCHORED_POSITION_OUT_OF_VIEW;
170
235
  const column = use$(`containerColumn${id}`) || 0;
171
236
  const numColumns = use$("numColumns");
237
+ const lastItemKeys = use$("lastItemKeys");
238
+ const itemKey = use$(`containerItemKey${id}`);
239
+ const data = use$(`containerItemData${id}`);
240
+ const extraData = use$("extraData");
241
+ const refLastSize = useRef();
172
242
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
173
243
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
244
+ let verticalPaddingStyles;
245
+ if (columnWrapperStyle) {
246
+ const { columnGap, rowGap, gap } = columnWrapperStyle;
247
+ verticalPaddingStyles = {
248
+ paddingBottom: !lastItemKeys.includes(itemKey) ? rowGap || gap || void 0 : void 0,
249
+ paddingHorizontal: (columnGap || gap || 0) / 2
250
+ };
251
+ }
174
252
  const style = horizontal ? {
175
253
  flexDirection: ItemSeparatorComponent ? "row" : void 0,
176
254
  position: "absolute",
@@ -183,68 +261,96 @@ var Container = ({
183
261
  left: otherAxisPos,
184
262
  right: numColumns > 1 ? null : 0,
185
263
  width: otherAxisSize,
186
- top: position.relativeCoordinate
264
+ top: position.relativeCoordinate,
265
+ ...verticalPaddingStyles || {}
187
266
  };
188
- const lastItemKey = use$("lastItemKey");
189
- const itemKey = use$(`containerItemKey${id}`);
190
- const data = use$(`containerItemData${id}`);
191
- const extraData = use$("extraData");
192
267
  const renderedItemInfo = useMemo(
193
- () => itemKey !== void 0 && getRenderedItem(itemKey),
268
+ () => itemKey !== void 0 ? getRenderedItem(itemKey) : null,
194
269
  [itemKey, data, extraData]
195
270
  );
196
271
  const { index, renderedItem } = renderedItemInfo || {};
197
272
  const onLayout = (event) => {
198
273
  if (itemKey !== void 0) {
199
- const size = Math.floor(event.nativeEvent.layout[horizontal ? "width" : "height"] * 8) / 8;
200
- if (size === 0) {
201
- console.log("[WARN] Container 0 height reported, possible bug in LegendList", id, itemKey);
202
- return;
203
- }
204
- updateItemSize(id, itemKey, size);
274
+ const layout = event.nativeEvent.layout;
275
+ const size = Math.floor(layout[horizontal ? "width" : "height"] * 8) / 8;
276
+ refLastSize.current = size;
277
+ updateItemSize(itemKey, size);
205
278
  }
206
279
  };
207
280
  const ref = useRef(null);
208
281
  if (isNewArchitecture) {
209
282
  useLayoutEffect(() => {
210
283
  var _a, _b;
211
- if (itemKey) {
284
+ if (itemKey !== void 0) {
212
285
  const measured = (_b = (_a = ref.current) == null ? void 0 : _a.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a);
213
286
  if (measured) {
214
287
  const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
215
288
  if (size) {
216
- updateItemSize(id, itemKey, size);
289
+ updateItemSize(itemKey, size);
217
290
  }
218
291
  }
219
292
  }
220
293
  }, [itemKey]);
294
+ } else {
295
+ useEffect(() => {
296
+ if (itemKey) {
297
+ const timeout = setTimeout(() => {
298
+ if (refLastSize.current) {
299
+ updateItemSize(itemKey, refLastSize.current);
300
+ }
301
+ }, 16);
302
+ return () => {
303
+ clearTimeout(timeout);
304
+ };
305
+ }
306
+ }, [itemKey]);
221
307
  }
222
308
  const contextValue = useMemo(
223
309
  () => ({ containerId: id, itemKey, index, value: data }),
224
310
  [id, itemKey, index, data]
225
311
  );
226
- const contentFragment = /* @__PURE__ */ React5__default.createElement(React5__default.Fragment, { key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React5__default.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItem && ItemSeparatorComponent && itemKey !== lastItemKey && ItemSeparatorComponent));
312
+ 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.includes(itemKey) && /* @__PURE__ */ React6__default.createElement(ItemSeparatorComponent, { leadingItem: renderedItemInfo.item })));
227
313
  if (maintainVisibleContentPosition) {
228
314
  const anchorStyle = position.type === "top" ? { position: "absolute", top: 0, left: 0, right: 0 } : { position: "absolute", bottom: 0, left: 0, right: 0 };
229
- return /* @__PURE__ */ React5__default.createElement(LeanView, { style }, /* @__PURE__ */ React5__default.createElement(LeanView, { style: anchorStyle, onLayout, ref }, contentFragment));
315
+ if (ENABLE_DEVMODE) {
316
+ anchorStyle.borderColor = position.type === "top" ? "red" : "blue";
317
+ anchorStyle.borderWidth = 1;
318
+ }
319
+ 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)));
230
320
  }
231
- return /* @__PURE__ */ React5__default.createElement(LeanView, { style, onLayout, ref }, contentFragment);
321
+ return /* @__PURE__ */ React6__default.createElement(LeanView, { style, onLayout, ref }, contentFragment);
232
322
  };
233
- var useAnimatedValue = useAnimatedValue$1 || ((initialValue) => {
323
+ var typedForwardRef = forwardRef;
324
+ var typedMemo = memo;
325
+ var useAnimatedValue = (initialValue) => {
234
326
  return useRef(new Animated.Value(initialValue)).current;
235
- });
236
- function useValue$(key, getValue, key2) {
327
+ };
328
+
329
+ // src/useValue$.ts
330
+ function useValue$(key, getValue, useMicrotask) {
237
331
  var _a;
238
332
  const ctx = useStateContext();
239
333
  const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
240
334
  useMemo(() => {
241
- listen$(ctx, key, (v) => animValue.setValue(getValue ? getValue(v) : v));
335
+ let newValue = void 0;
336
+ listen$(ctx, key, (v) => {
337
+ if (useMicrotask && newValue === void 0) {
338
+ queueMicrotask(() => {
339
+ animValue.setValue(newValue);
340
+ newValue = void 0;
341
+ });
342
+ }
343
+ newValue = getValue ? getValue(v) : v;
344
+ if (!useMicrotask) {
345
+ animValue.setValue(newValue);
346
+ }
347
+ });
242
348
  }, []);
243
349
  return animValue;
244
350
  }
245
351
 
246
352
  // src/Containers.tsx
247
- var Containers = React5.memo(function Containers2({
353
+ var Containers = typedMemo(function Containers2({
248
354
  horizontal,
249
355
  recycleItems,
250
356
  ItemSeparatorComponent,
@@ -252,13 +358,21 @@ var Containers = React5.memo(function Containers2({
252
358
  updateItemSize,
253
359
  getRenderedItem
254
360
  }) {
361
+ const ctx = useStateContext();
362
+ const columnWrapperStyle = ctx.columnWrapperStyle;
363
+ const numColumns = use$("numColumns");
255
364
  const numContainers = use$("numContainersPooled");
256
- const animSize = useValue$("totalSize");
365
+ const animSize = useValue$(
366
+ "totalSizeWithScrollAdjust",
367
+ void 0,
368
+ /*useMicrotask*/
369
+ true
370
+ );
257
371
  const animOpacity = waitForInitialLayout ? useValue$("containersDidLayout", (value) => value ? 1 : 0) : void 0;
258
372
  const containers = [];
259
373
  for (let i = 0; i < numContainers; i++) {
260
374
  containers.push(
261
- /* @__PURE__ */ React5.createElement(
375
+ /* @__PURE__ */ React6.createElement(
262
376
  Container,
263
377
  {
264
378
  id: i,
@@ -273,20 +387,78 @@ var Containers = React5.memo(function Containers2({
273
387
  );
274
388
  }
275
389
  const style = horizontal ? { width: animSize, opacity: animOpacity } : { height: animSize, opacity: animOpacity };
276
- return /* @__PURE__ */ React5.createElement(Animated.View, { style }, containers);
390
+ if (columnWrapperStyle && !horizontal && numColumns > 1) {
391
+ const { columnGap, rowGap, gap } = columnWrapperStyle;
392
+ const mx = (columnGap || gap || 0) / 2;
393
+ if (mx) {
394
+ style.marginHorizontal = -mx;
395
+ }
396
+ }
397
+ return /* @__PURE__ */ React6.createElement(Animated.View, { style }, containers);
277
398
  });
278
399
 
279
400
  // src/ListComponent.tsx
280
401
  var getComponent = (Component) => {
281
- if (React5.isValidElement(Component)) {
402
+ if (React6.isValidElement(Component)) {
282
403
  return Component;
283
404
  }
284
405
  if (Component) {
285
- return /* @__PURE__ */ React5.createElement(Component, null);
406
+ return /* @__PURE__ */ React6.createElement(Component, null);
286
407
  }
287
408
  return null;
288
409
  };
289
- var ListComponent = React5.memo(function ListComponent2({
410
+ var PaddingAndAdjust = () => {
411
+ const animPaddingTop = useValue$("paddingTop", (v) => v, true);
412
+ const animScrollAdjust = useValue$("scrollAdjust", (v) => v, true);
413
+ const additionalSize = { marginTop: animScrollAdjust, paddingTop: animPaddingTop };
414
+ return /* @__PURE__ */ React6.createElement(Animated.View, { style: additionalSize });
415
+ };
416
+ var PaddingAndAdjustDevMode = () => {
417
+ const animPaddingTop = useValue$("paddingTop", (v) => v, true);
418
+ const animScrollAdjust = useValue$("scrollAdjust", (v) => v, true);
419
+ 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(
420
+ Animated.View,
421
+ {
422
+ style: {
423
+ position: "absolute",
424
+ top: Animated.add(animScrollAdjust, Animated.multiply(animScrollAdjust, -1)),
425
+ height: animPaddingTop,
426
+ left: 0,
427
+ right: 0,
428
+ backgroundColor: "green"
429
+ }
430
+ }
431
+ ), /* @__PURE__ */ React6.createElement(
432
+ Animated.View,
433
+ {
434
+ style: {
435
+ position: "absolute",
436
+ top: animPaddingTop,
437
+ height: animScrollAdjust,
438
+ left: -16,
439
+ right: -16,
440
+ backgroundColor: "lightblue"
441
+ }
442
+ }
443
+ ), /* @__PURE__ */ React6.createElement(
444
+ Animated.View,
445
+ {
446
+ style: {
447
+ position: "absolute",
448
+ top: animPaddingTop,
449
+ height: Animated.multiply(animScrollAdjust, -1),
450
+ width: 8,
451
+ right: 4,
452
+ borderStyle: "dashed",
453
+ borderColor: "blue",
454
+ borderWidth: 1,
455
+ backgroundColor: "lightblue"
456
+ //backgroundColor: "blue",
457
+ }
458
+ }
459
+ ));
460
+ };
461
+ var ListComponent = typedMemo(function ListComponent2({
290
462
  style,
291
463
  contentContainerStyle,
292
464
  horizontal,
@@ -307,22 +479,22 @@ var ListComponent = React5.memo(function ListComponent2({
307
479
  refScrollView,
308
480
  maintainVisibleContentPosition,
309
481
  renderScrollComponent,
482
+ onRefresh,
483
+ refreshing,
484
+ progressViewOffset,
310
485
  ...rest
311
486
  }) {
312
487
  const ctx = useStateContext();
313
- const animPaddingTop = useValue$("paddingTop");
314
- const animScrollAdjust = useValue$("scrollAdjust");
315
488
  const ScrollComponent = renderScrollComponent ? useMemo(
316
- () => React5.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
489
+ () => React6.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
317
490
  [renderScrollComponent]
318
491
  ) : ScrollView;
319
- const additionalSize = { marginTop: animScrollAdjust, paddingTop: animPaddingTop };
320
- return /* @__PURE__ */ React5.createElement(
492
+ return /* @__PURE__ */ React6.createElement(
321
493
  ScrollComponent,
322
494
  {
323
495
  ...rest,
324
496
  style,
325
- maintainVisibleContentPosition: maintainVisibleContentPosition ? { minIndexForVisible: 0 } : void 0,
497
+ maintainVisibleContentPosition: maintainVisibleContentPosition && !ListEmptyComponent ? { minIndexForVisible: 0 } : void 0,
326
498
  contentContainerStyle: [
327
499
  contentContainerStyle,
328
500
  horizontal ? {
@@ -335,34 +507,41 @@ var ListComponent = React5.memo(function ListComponent2({
335
507
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
336
508
  ref: refScrollView
337
509
  },
338
- /* @__PURE__ */ React5.createElement(Animated.View, { style: additionalSize }),
339
- ListHeaderComponent && /* @__PURE__ */ React5.createElement(
340
- Animated.View,
510
+ !ListEmptyComponent && (ENABLE_DEVMODE ? /* @__PURE__ */ React6.createElement(PaddingAndAdjustDevMode, null) : /* @__PURE__ */ React6.createElement(PaddingAndAdjust, null)),
511
+ ListHeaderComponent && /* @__PURE__ */ React6.createElement(
512
+ View,
341
513
  {
342
514
  style: ListHeaderComponentStyle,
343
515
  onLayout: (event) => {
344
516
  const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
345
- const prevSize = peek$(ctx, "headerSize") || 0;
346
- if (size !== prevSize) {
347
- set$(ctx, "headerSize", size);
348
- }
517
+ set$(ctx, "headerSize", size);
349
518
  }
350
519
  },
351
520
  getComponent(ListHeaderComponent)
352
521
  ),
353
522
  ListEmptyComponent && getComponent(ListEmptyComponent),
354
- /* @__PURE__ */ React5.createElement(
523
+ /* @__PURE__ */ React6.createElement(
355
524
  Containers,
356
525
  {
357
526
  horizontal,
358
527
  recycleItems,
359
528
  waitForInitialLayout,
360
529
  getRenderedItem,
361
- ItemSeparatorComponent: ItemSeparatorComponent && getComponent(ItemSeparatorComponent),
530
+ ItemSeparatorComponent,
362
531
  updateItemSize
363
532
  }
364
533
  ),
365
- ListFooterComponent && /* @__PURE__ */ React5.createElement(View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
534
+ ListFooterComponent && /* @__PURE__ */ React6.createElement(
535
+ View,
536
+ {
537
+ style: ListFooterComponentStyle,
538
+ onLayout: (event) => {
539
+ const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
540
+ set$(ctx, "footerSize", size);
541
+ }
542
+ },
543
+ getComponent(ListFooterComponent)
544
+ )
366
545
  );
367
546
  });
368
547
 
@@ -371,36 +550,63 @@ var ScrollAdjustHandler = class {
371
550
  constructor(ctx) {
372
551
  this.ctx = ctx;
373
552
  this.appliedAdjust = 0;
374
- this.pendingAdjust = 0;
375
553
  this.busy = false;
376
- this.firstAdjust = true;
554
+ this.isPaused = false;
555
+ this.isDisabled = false;
377
556
  this.context = ctx;
378
557
  }
558
+ doAjdust() {
559
+ set$(this.context, "scrollAdjust", this.appliedAdjust);
560
+ this.busy = false;
561
+ }
379
562
  requestAdjust(adjust, onAdjusted) {
563
+ if (this.isDisabled) {
564
+ return;
565
+ }
380
566
  const oldAdjustTop = peek$(this.context, "scrollAdjust");
381
567
  if (oldAdjustTop === adjust) {
382
568
  return;
383
569
  }
384
570
  this.appliedAdjust = adjust;
385
- this.pendingAdjust = adjust;
386
- const doAjdust = () => {
387
- set$(this.context, "scrollAdjust", this.pendingAdjust);
388
- onAdjusted(oldAdjustTop - this.pendingAdjust);
389
- this.busy = false;
390
- };
391
- if (!this.busy) {
571
+ if (!this.busy && !this.isPaused) {
392
572
  this.busy = true;
393
- if (this.firstAdjust) {
394
- this.firstAdjust = false;
395
- setTimeout(doAjdust, 50);
396
- } else {
397
- doAjdust();
398
- }
573
+ this.doAjdust();
574
+ onAdjusted(oldAdjustTop - adjust);
399
575
  }
400
576
  }
401
577
  getAppliedAdjust() {
402
578
  return this.appliedAdjust;
403
579
  }
580
+ pauseAdjust() {
581
+ this.isPaused = true;
582
+ }
583
+ setDisableAdjust(disable) {
584
+ this.isDisabled = disable;
585
+ }
586
+ // return true if it was paused
587
+ unPauseAdjust() {
588
+ if (this.isPaused) {
589
+ this.isPaused = false;
590
+ this.doAjdust();
591
+ return true;
592
+ }
593
+ return false;
594
+ }
595
+ };
596
+ var useCombinedRef = (...refs) => {
597
+ const callback = useCallback((element) => {
598
+ for (const ref of refs) {
599
+ if (!ref) {
600
+ continue;
601
+ }
602
+ if (typeof ref === "function") {
603
+ ref(element);
604
+ } else {
605
+ ref.current = element;
606
+ }
607
+ }
608
+ }, refs);
609
+ return callback;
404
610
  };
405
611
 
406
612
  // src/viewability.ts
@@ -453,11 +659,37 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getI
453
659
  const { viewabilityConfig, onViewableItemsChanged } = viewabilityConfigCallbackPair;
454
660
  const configId = viewabilityConfig.id;
455
661
  const viewabilityState = mapViewabilityConfigCallbackPairs.get(configId);
456
- const { viewableItems: previousViewableItems, start, previousStart, end, previousEnd } = viewabilityState;
662
+ const { viewableItems: previousViewableItems, start, end } = viewabilityState;
663
+ const viewabilityTokens = /* @__PURE__ */ new Map();
664
+ for (const [containerId, value] of ctx.mapViewabilityAmountValues) {
665
+ viewabilityTokens.set(
666
+ containerId,
667
+ computeViewability(
668
+ state,
669
+ ctx,
670
+ viewabilityConfig,
671
+ containerId,
672
+ value.key,
673
+ scrollSize,
674
+ value.item,
675
+ value.index
676
+ )
677
+ );
678
+ }
457
679
  const changed = [];
458
680
  if (previousViewableItems) {
459
681
  for (const viewToken of previousViewableItems) {
460
- if (!isViewable(state, ctx, viewabilityConfig, viewToken.key, scrollSize, viewToken.item, viewToken.index)) {
682
+ const containerId = findContainerId(ctx, viewToken.key);
683
+ if (!isViewable(
684
+ state,
685
+ ctx,
686
+ viewabilityConfig,
687
+ containerId,
688
+ viewToken.key,
689
+ scrollSize,
690
+ viewToken.item,
691
+ viewToken.index
692
+ )) {
461
693
  viewToken.isViewable = false;
462
694
  changed.push(viewToken);
463
695
  }
@@ -468,12 +700,14 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getI
468
700
  const item = data[i];
469
701
  if (item) {
470
702
  const key = getId(i);
471
- if (isViewable(state, ctx, viewabilityConfig, key, scrollSize, item, i)) {
703
+ const containerId = findContainerId(ctx, key);
704
+ if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
472
705
  const viewToken = {
473
706
  item,
474
707
  key,
475
708
  index: i,
476
- isViewable: true
709
+ isViewable: true,
710
+ containerId
477
711
  };
478
712
  viewableItems.push(viewToken);
479
713
  if (!(previousViewableItems == null ? void 0 : previousViewableItems.find((v) => v.key === viewToken.key))) {
@@ -491,20 +725,27 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getI
491
725
  viewabilityState.viewableItems = viewableItems;
492
726
  for (let i = 0; i < changed.length; i++) {
493
727
  const change = changed[i];
494
- maybeUpdateViewabilityCallback(ctx, configId, change);
728
+ maybeUpdateViewabilityCallback(ctx, configId, change.containerId, change);
495
729
  }
496
730
  if (onViewableItemsChanged) {
497
731
  onViewableItemsChanged({ viewableItems, changed });
498
732
  }
499
733
  }
734
+ for (const [containerId, value] of ctx.mapViewabilityAmountValues) {
735
+ if (value.sizeVisible < 0) {
736
+ ctx.mapViewabilityAmountValues.delete(containerId);
737
+ }
738
+ }
500
739
  }
501
- function isViewable(state, ctx, viewabilityConfig, key, scrollSize, item, index) {
502
- const { sizes, positions, scroll } = state;
740
+ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
741
+ const { sizes, positions, scroll: scrollState, scrollAdjustHandler } = state;
503
742
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
504
743
  const { itemVisiblePercentThreshold, viewAreaCoveragePercentThreshold } = viewabilityConfig;
505
744
  const viewAreaMode = viewAreaCoveragePercentThreshold != null;
506
745
  const viewablePercentThreshold = viewAreaMode ? viewAreaCoveragePercentThreshold : itemVisiblePercentThreshold;
507
- const top = positions.get(key) - scroll + topPad;
746
+ const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
747
+ const scroll = scrollState - previousScrollAdjust - topPad;
748
+ const top = positions.get(key) - scroll;
508
749
  const size = sizes.get(key) || 0;
509
750
  const bottom = top + size;
510
751
  const isEntirelyVisible = top >= 0 && bottom <= scrollSize && bottom > top;
@@ -513,7 +754,6 @@ function isViewable(state, ctx, viewabilityConfig, key, scrollSize, item, index)
513
754
  const percentOfScroller = size ? 100 * (sizeVisible / scrollSize) : 0;
514
755
  const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
515
756
  const isViewable2 = percent >= viewablePercentThreshold;
516
- const containerId = findContainerId(ctx, key);
517
757
  const value = {
518
758
  index,
519
759
  isViewable: isViewable2,
@@ -523,15 +763,21 @@ function isViewable(state, ctx, viewabilityConfig, key, scrollSize, item, index)
523
763
  percentOfScroller,
524
764
  sizeVisible,
525
765
  size,
526
- position: top,
527
- scrollSize
766
+ scrollSize,
767
+ containerId
528
768
  };
529
- ctx.mapViewabilityAmountValues.set(containerId, value);
530
- const cb = ctx.mapViewabilityAmountCallbacks.get(containerId);
531
- if (cb) {
532
- cb(value);
769
+ if (JSON.stringify(value) !== JSON.stringify(ctx.mapViewabilityAmountValues.get(containerId))) {
770
+ ctx.mapViewabilityAmountValues.set(containerId, value);
771
+ const cb = ctx.mapViewabilityAmountCallbacks.get(containerId);
772
+ if (cb) {
773
+ cb(value);
774
+ }
533
775
  }
534
- return isViewable2;
776
+ return value;
777
+ }
778
+ function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
779
+ const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
780
+ return value.isViewable;
535
781
  }
536
782
  function findContainerId(ctx, key) {
537
783
  const numContainers = peek$(ctx, "numContainers");
@@ -543,8 +789,8 @@ function findContainerId(ctx, key) {
543
789
  }
544
790
  return -1;
545
791
  }
546
- function maybeUpdateViewabilityCallback(ctx, configId, viewToken) {
547
- const key = viewToken.key + configId;
792
+ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
793
+ const key = containerId + configId;
548
794
  ctx.mapViewabilityValues.set(key, viewToken);
549
795
  const cb = ctx.mapViewabilityCallbacks.get(key);
550
796
  cb == null ? void 0 : cb(viewToken);
@@ -553,13 +799,26 @@ function maybeUpdateViewabilityCallback(ctx, configId, viewToken) {
553
799
  // src/LegendList.tsx
554
800
  var DEFAULT_DRAW_DISTANCE = 250;
555
801
  var DEFAULT_ITEM_SIZE = 100;
556
- var LegendList = forwardRef(function LegendList2(props, forwardedRef) {
557
- return /* @__PURE__ */ React5.createElement(StateProvider, null, /* @__PURE__ */ React5.createElement(LegendListInner, { ...props, ref: forwardedRef }));
802
+ function createColumnWrapperStyle(contentContainerStyle) {
803
+ const { gap, columnGap, rowGap } = contentContainerStyle;
804
+ if (gap || columnGap || rowGap) {
805
+ contentContainerStyle.gap = void 0;
806
+ contentContainerStyle.columnGap = void 0;
807
+ contentContainerStyle.rowGap = void 0;
808
+ return {
809
+ gap,
810
+ columnGap,
811
+ rowGap
812
+ };
813
+ }
814
+ }
815
+ var LegendList = typedForwardRef(function LegendList2(props, forwardedRef) {
816
+ return /* @__PURE__ */ React6.createElement(StateProvider, null, /* @__PURE__ */ React6.createElement(LegendListInner, { ...props, ref: forwardedRef }));
558
817
  });
559
- var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef) {
560
- var _a, _b, _c, _d, _e;
818
+ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
819
+ var _a, _b, _c, _d;
561
820
  const {
562
- data,
821
+ data: dataProp = [],
563
822
  initialScrollIndex,
564
823
  initialScrollOffset,
565
824
  horizontal,
@@ -572,61 +831,97 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
572
831
  alignItemsAtEnd = false,
573
832
  maintainVisibleContentPosition = false,
574
833
  onScroll: onScrollProp,
834
+ onMomentumScrollEnd,
575
835
  numColumns: numColumnsProp = 1,
836
+ columnWrapperStyle,
576
837
  keyExtractor: keyExtractorProp,
577
838
  renderItem,
578
839
  estimatedItemSize,
579
840
  getEstimatedItemSize,
580
- onEndReached,
581
- onStartReached,
582
841
  ListEmptyComponent,
583
842
  onItemSizeChanged,
584
843
  scrollEventThrottle,
585
844
  refScrollView,
586
845
  waitForInitialLayout = true,
587
846
  extraData,
847
+ contentContainerStyle: contentContainerStyleProp,
848
+ style: styleProp,
849
+ onLayout: onLayoutProp,
850
+ onRefresh,
851
+ refreshing,
852
+ progressViewOffset,
853
+ refreshControl,
854
+ initialContainerPoolRatio = 2,
855
+ viewabilityConfig,
856
+ viewabilityConfigCallbackPairs,
857
+ onViewableItemsChanged,
588
858
  ...rest
589
859
  } = props;
590
- const { style, contentContainerStyle } = props;
860
+ const callbacks = useRef({
861
+ onStartReached: rest.onStartReached,
862
+ onEndReached: rest.onEndReached
863
+ });
864
+ callbacks.current.onStartReached = rest.onStartReached;
865
+ callbacks.current.onEndReached = rest.onEndReached;
866
+ const contentContainerStyle = StyleSheet.flatten(contentContainerStyleProp);
867
+ const style = StyleSheet.flatten(styleProp);
868
+ 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;
869
+ if (style == null ? void 0 : style.paddingTop) {
870
+ style.paddingTop = void 0;
871
+ }
872
+ if (contentContainerStyle == null ? void 0 : contentContainerStyle.paddingTop) {
873
+ contentContainerStyle.paddingTop = void 0;
874
+ }
591
875
  const ctx = useStateContext();
876
+ ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
592
877
  const refScroller = useRef(null);
593
- const scrollBuffer = drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE;
878
+ const combinedRef = useCombinedRef(refScroller, refScrollView);
879
+ const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
594
880
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (item, index) => index.toString();
595
881
  const refState = useRef();
596
882
  const getId = (index) => {
597
883
  var _a2;
598
- const data2 = (_a2 = refState.current) == null ? void 0 : _a2.data;
599
- if (!data2) {
884
+ const data = (_a2 = refState.current) == null ? void 0 : _a2.data;
885
+ if (!data) {
600
886
  return "";
601
887
  }
602
- const ret = index < data2.length ? keyExtractor ? keyExtractor(data2[index], index) : index : null;
888
+ const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
603
889
  return `${ret}`;
604
890
  };
605
- const getItemSize = (key, index, data2) => {
891
+ const getItemSize = (key, index, data) => {
606
892
  var _a2;
607
893
  const sizeKnown = refState.current.sizes.get(key);
608
894
  if (sizeKnown !== void 0) {
609
895
  return sizeKnown;
610
896
  }
611
- const size = (_a2 = getEstimatedItemSize ? getEstimatedItemSize(index, data2) : estimatedItemSize) != null ? _a2 : DEFAULT_ITEM_SIZE;
897
+ const size = (_a2 = getEstimatedItemSize ? getEstimatedItemSize(index, data) : estimatedItemSize) != null ? _a2 : DEFAULT_ITEM_SIZE;
612
898
  refState.current.sizes.set(key, size);
613
899
  return size;
614
900
  };
615
- const calculateInitialOffset = (index = initialScrollIndex) => {
616
- if (index) {
901
+ const calculateOffsetForIndex = (index = initialScrollIndex) => {
902
+ var _a2;
903
+ const data = dataProp;
904
+ if (index !== void 0) {
617
905
  let offset = 0;
618
- if (getEstimatedItemSize) {
906
+ const canGetSize = !!refState.current;
907
+ if (canGetSize || getEstimatedItemSize) {
908
+ const sizeFn = (index2) => {
909
+ if (canGetSize) {
910
+ return getItemSize(getId(index2), index2, data[index2]);
911
+ }
912
+ return getEstimatedItemSize(index2, data[index2]);
913
+ };
619
914
  for (let i = 0; i < index; i++) {
620
- offset += getEstimatedItemSize(i, data[i]);
915
+ offset += sizeFn(i);
621
916
  }
622
917
  } else if (estimatedItemSize) {
623
918
  offset = index * estimatedItemSize;
624
919
  }
625
- return offset / numColumnsProp;
920
+ return offset / numColumnsProp - (((_a2 = refState.current) == null ? void 0 : _a2.scrollAdjustHandler.getAppliedAdjust()) || 0);
626
921
  }
627
922
  return 0;
628
923
  };
629
- const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : useMemo(calculateInitialOffset, []);
924
+ const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : useMemo(calculateOffsetForIndex, []);
630
925
  if (!refState.current) {
631
926
  const initialScrollLength = Dimensions.get("window")[horizontal ? "width" : "height"];
632
927
  refState.current = {
@@ -634,14 +929,11 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
634
929
  positions: /* @__PURE__ */ new Map(),
635
930
  columns: /* @__PURE__ */ new Map(),
636
931
  pendingAdjust: 0,
637
- waitingForMicrotask: false,
638
932
  isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
639
933
  isEndReached: false,
640
934
  isAtBottom: false,
641
935
  isAtTop: false,
642
- data,
643
- idsInFirstRender: void 0,
644
- hasScrolled: false,
936
+ data: dataProp,
645
937
  scrollLength: initialScrollLength,
646
938
  startBuffered: 0,
647
939
  startNoBuffer: 0,
@@ -661,23 +953,29 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
661
953
  indexByKey: /* @__PURE__ */ new Map(),
662
954
  scrollHistory: [],
663
955
  scrollVelocity: 0,
664
- sizesLaidOut: __DEV__ ? /* @__PURE__ */ new Map() : void 0,
956
+ sizesKnown: /* @__PURE__ */ new Map(),
665
957
  timeoutSizeMessage: 0,
666
958
  scrollTimer: void 0,
667
959
  belowAnchorElementPositions: void 0,
668
960
  rowHeights: /* @__PURE__ */ new Map(),
669
961
  startReachedBlockedByTimer: false,
962
+ endReachedBlockedByTimer: false,
670
963
  scrollForNextCalculateItemsInView: void 0,
671
- enableScrollForNextCalculateItemsInView: true
964
+ enableScrollForNextCalculateItemsInView: true,
965
+ minIndexSizeChanged: 0,
966
+ numPendingInitialLayout: 0,
967
+ queuedCalculateItemsInView: 0,
968
+ lastBatchingAction: Date.now(),
969
+ onScroll: onScrollProp
672
970
  };
673
- refState.current.idsInFirstRender = new Set(data.map((_, i) => getId(i)));
674
- if (maintainVisibleContentPosition) {
675
- if (initialScrollIndex) {
971
+ const dataLength = dataProp.length;
972
+ if (maintainVisibleContentPosition && dataLength > 0) {
973
+ if (initialScrollIndex && initialScrollIndex < dataLength) {
676
974
  refState.current.anchorElement = {
677
975
  coordinate: initialContentOffset,
678
976
  id: getId(initialScrollIndex)
679
977
  };
680
- } else if (data.length) {
978
+ } else if (dataLength > 0) {
681
979
  refState.current.anchorElement = {
682
980
  coordinate: initialContentOffset,
683
981
  id: getId(0)
@@ -690,6 +988,9 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
690
988
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
691
989
  set$(ctx, "extraData", extraData);
692
990
  }
991
+ const didDataChange = refState.current.data !== dataProp;
992
+ refState.current.data = dataProp;
993
+ refState.current.onScroll = onScrollProp;
693
994
  const getAnchorElementIndex = () => {
694
995
  const state = refState.current;
695
996
  if (state.anchorElement) {
@@ -698,12 +999,34 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
698
999
  }
699
1000
  return void 0;
700
1001
  };
1002
+ const setDidLayout = () => {
1003
+ var _a2;
1004
+ refState.current.queuedInitialLayout = true;
1005
+ checkAtBottom();
1006
+ if (initialScrollIndex) {
1007
+ const updatedOffset = calculateOffsetForIndex(initialScrollIndex);
1008
+ (_a2 = refState.current) == null ? void 0 : _a2.scrollAdjustHandler.setDisableAdjust(true);
1009
+ queueMicrotask(() => {
1010
+ scrollTo(updatedOffset, false);
1011
+ requestAnimationFrame(() => {
1012
+ var _a3;
1013
+ set$(ctx, "containersDidLayout", true);
1014
+ (_a3 = refState.current) == null ? void 0 : _a3.scrollAdjustHandler.setDisableAdjust(false);
1015
+ });
1016
+ });
1017
+ } else {
1018
+ queueMicrotask(() => {
1019
+ set$(ctx, "containersDidLayout", true);
1020
+ });
1021
+ }
1022
+ };
701
1023
  const addTotalSize = useCallback((key, add, totalSizeBelowAnchor) => {
702
1024
  const state = refState.current;
703
- const index = key === null ? 0 : state.indexByKey.get(key);
1025
+ const { indexByKey, anchorElement } = state;
1026
+ const index = key === null ? 0 : indexByKey.get(key);
704
1027
  let isAboveAnchor = false;
705
1028
  if (maintainVisibleContentPosition) {
706
- if (state.anchorElement && index < getAnchorElementIndex()) {
1029
+ if (anchorElement && index < getAnchorElementIndex()) {
707
1030
  isAboveAnchor = true;
708
1031
  }
709
1032
  }
@@ -716,29 +1039,30 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
716
1039
  state.totalSizeBelowAnchor += add;
717
1040
  }
718
1041
  }
719
- let applyAdjustValue = void 0;
720
- if (maintainVisibleContentPosition) {
721
- const newAdjust = state.anchorElement.coordinate - state.totalSizeBelowAnchor;
1042
+ let applyAdjustValue = 0;
1043
+ let resultSize = state.totalSize;
1044
+ if (maintainVisibleContentPosition && anchorElement !== void 0) {
1045
+ const newAdjust = anchorElement.coordinate - state.totalSizeBelowAnchor;
722
1046
  applyAdjustValue = -newAdjust;
723
1047
  state.belowAnchorElementPositions = buildElementPositionsBelowAnchor();
724
1048
  state.rowHeights.clear();
1049
+ if (applyAdjustValue !== void 0) {
1050
+ resultSize -= applyAdjustValue;
1051
+ state.scrollAdjustHandler.requestAdjust(applyAdjustValue, (diff) => {
1052
+ state.scroll -= diff;
1053
+ });
1054
+ }
725
1055
  }
726
- const totalSize = state.totalSize;
727
- let resultSize = totalSize;
728
- if (applyAdjustValue !== void 0) {
729
- resultSize -= applyAdjustValue;
730
- refState.current.scrollAdjustHandler.requestAdjust(applyAdjustValue, (diff) => {
731
- state.scroll -= diff;
732
- });
733
- }
734
- set$(ctx, "totalSize", resultSize);
1056
+ set$(ctx, "totalSize", state.totalSize);
1057
+ set$(ctx, "totalSizeWithScrollAdjust", resultSize);
735
1058
  if (alignItemsAtEnd) {
736
1059
  doUpdatePaddingTop();
737
1060
  }
738
1061
  }, []);
739
1062
  const getRowHeight = (n) => {
740
- const { rowHeights } = refState.current;
741
- if (numColumnsProp === 1) {
1063
+ const { rowHeights, data } = refState.current;
1064
+ const numColumns = peek$(ctx, "numColumns");
1065
+ if (numColumns === 1) {
742
1066
  const id = getId(n);
743
1067
  return getItemSize(id, n, data[n]);
744
1068
  }
@@ -746,8 +1070,8 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
746
1070
  return rowHeights.get(n) || 0;
747
1071
  }
748
1072
  let rowHeight = 0;
749
- const startEl = n * numColumnsProp;
750
- for (let i = startEl; i < startEl + numColumnsProp && i < data.length; i++) {
1073
+ const startEl = n * numColumns;
1074
+ for (let i = startEl; i < startEl + numColumns && i < data.length; i++) {
751
1075
  const id = getId(i);
752
1076
  const size = getItemSize(id, i, data[i]);
753
1077
  rowHeight = Math.max(rowHeight, size);
@@ -766,10 +1090,11 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
766
1090
  return /* @__PURE__ */ new Map();
767
1091
  }
768
1092
  const map = state.belowAnchorElementPositions || /* @__PURE__ */ new Map();
1093
+ const numColumns = peek$(ctx, "numColumns");
769
1094
  for (let i = anchorIndex - 1; i >= 0; i--) {
770
1095
  const id = getId(i);
771
- const rowNumber = Math.floor(i / numColumnsProp);
772
- if (i % numColumnsProp === 0) {
1096
+ const rowNumber = Math.floor(i / numColumns);
1097
+ if (i % numColumns === 0) {
773
1098
  top -= getRowHeight(rowNumber);
774
1099
  }
775
1100
  map.set(id, top);
@@ -777,37 +1102,51 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
777
1102
  return map;
778
1103
  };
779
1104
  const getElementPositionBelowAchor = (id) => {
1105
+ var _a2;
780
1106
  const state = refState.current;
781
1107
  if (!refState.current.belowAnchorElementPositions) {
782
1108
  state.belowAnchorElementPositions = buildElementPositionsBelowAnchor();
783
1109
  }
784
1110
  const res = state.belowAnchorElementPositions.get(id);
785
1111
  if (res === void 0) {
786
- throw new Error("Undefined position below achor");
1112
+ console.warn(`Undefined position below achor ${id} ${(_a2 = state.anchorElement) == null ? void 0 : _a2.id}`);
1113
+ return 0;
787
1114
  }
788
1115
  return res;
789
1116
  };
790
- const calculateItemsInView = useCallback((speed) => {
1117
+ const calculateItemsInView = useCallback(() => {
1118
+ var _a2;
791
1119
  const state = refState.current;
792
1120
  const {
793
- data: data2,
1121
+ data,
794
1122
  scrollLength,
795
- scroll: scrollState,
796
1123
  startBufferedId: startBufferedIdOrig,
797
1124
  positions,
798
1125
  columns,
799
- scrollAdjustHandler
1126
+ scrollAdjustHandler,
1127
+ scrollVelocity: speed
800
1128
  } = state;
801
- if (state.waitingForMicrotask) {
802
- state.waitingForMicrotask = false;
803
- }
804
- if (!data2) {
1129
+ if (!data || scrollLength === 0) {
805
1130
  return;
806
1131
  }
1132
+ const totalSize = peek$(ctx, "totalSizeWithScrollAdjust");
807
1133
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
1134
+ const numColumns = peek$(ctx, "numColumns");
808
1135
  const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
809
1136
  const scrollExtra = Math.max(-16, Math.min(16, speed)) * 16;
810
- const scroll = scrollState - previousScrollAdjust - topPad;
1137
+ let scrollState = state.scroll;
1138
+ if (!state.queuedInitialLayout && initialScrollIndex) {
1139
+ const updatedOffset = calculateOffsetForIndex(initialScrollIndex);
1140
+ scrollState = updatedOffset;
1141
+ }
1142
+ let scroll = scrollState - previousScrollAdjust - topPad;
1143
+ if (scroll + scrollLength > totalSize) {
1144
+ scroll = totalSize - scrollLength;
1145
+ }
1146
+ if (ENABLE_DEBUG_VIEW) {
1147
+ set$(ctx, "debugRawScroll", scrollState);
1148
+ set$(ctx, "debugComputedScroll", scroll);
1149
+ }
811
1150
  let scrollBufferTop = scrollBuffer;
812
1151
  let scrollBufferBottom = scrollBuffer;
813
1152
  if (scrollExtra > 8) {
@@ -830,8 +1169,11 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
830
1169
  let startBufferedId = null;
831
1170
  let endNoBuffer = null;
832
1171
  let endBuffered = null;
833
- const originalStartId = startBufferedIdOrig && state.indexByKey.get(startBufferedIdOrig);
834
- let loopStart = originalStartId || 0;
1172
+ let loopStart = startBufferedIdOrig ? state.indexByKey.get(startBufferedIdOrig) || 0 : 0;
1173
+ if (state.minIndexSizeChanged !== void 0) {
1174
+ loopStart = Math.min(state.minIndexSizeChanged, loopStart);
1175
+ state.minIndexSizeChanged = void 0;
1176
+ }
835
1177
  const anchorElementIndex = getAnchorElementIndex();
836
1178
  for (let i = loopStart; i >= 0; i--) {
837
1179
  const id = getId(i);
@@ -844,7 +1186,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
844
1186
  }
845
1187
  const top2 = newPosition || positions.get(id);
846
1188
  if (top2 !== void 0) {
847
- const size = getItemSize(id, i, data2[i]);
1189
+ const size = getItemSize(id, i, data[i]);
848
1190
  const bottom = top2 + size;
849
1191
  if (bottom > scroll - scrollBuffer) {
850
1192
  loopStart = i;
@@ -853,7 +1195,6 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
853
1195
  }
854
1196
  }
855
1197
  }
856
- const numColumns = peek$(ctx, "numColumns");
857
1198
  const loopStartMod = loopStart % numColumns;
858
1199
  if (loopStartMod > 0) {
859
1200
  loopStart -= loopStartMod;
@@ -862,22 +1203,22 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
862
1203
  let column = 1;
863
1204
  let maxSizeInRow = 0;
864
1205
  const getInitialTop = (i) => {
865
- var _a2;
1206
+ var _a3;
866
1207
  const id = getId(i);
867
1208
  let topOffset = 0;
868
1209
  if (positions.get(id)) {
869
1210
  topOffset = positions.get(id);
870
1211
  }
871
- if (id === ((_a2 = state.anchorElement) == null ? void 0 : _a2.id)) {
872
- topOffset = initialContentOffset || 0;
1212
+ if (id === ((_a3 = state.anchorElement) == null ? void 0 : _a3.id)) {
1213
+ topOffset = state.anchorElement.coordinate;
873
1214
  }
874
1215
  return topOffset;
875
1216
  };
876
- for (let i = loopStart; i < data2.length; i++) {
1217
+ for (let i = loopStart; i < data.length; i++) {
877
1218
  const id = getId(i);
878
- const size = getItemSize(id, i, data2[i]);
1219
+ const size = getItemSize(id, i, data[i]);
879
1220
  maxSizeInRow = Math.max(maxSizeInRow, size);
880
- if (top === void 0) {
1221
+ if (top === void 0 || id === ((_a2 = state.anchorElement) == null ? void 0 : _a2.id)) {
881
1222
  top = getInitialTop(i);
882
1223
  }
883
1224
  if (positions.get(id) !== top) {
@@ -930,6 +1271,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
930
1271
  if (startBuffered !== null && endBuffered !== null) {
931
1272
  const prevNumContainers = ctx.values.get("numContainers");
932
1273
  let numContainers = prevNumContainers;
1274
+ let didWarnMoreContainers = false;
933
1275
  for (let i = startBuffered; i <= endBuffered; i++) {
934
1276
  let isContained = false;
935
1277
  const id = getId(i);
@@ -963,18 +1305,19 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
963
1305
  if (furthestIndex >= 0) {
964
1306
  set$(ctx, `containerItemKey${furthestIndex}`, id);
965
1307
  const index = state.indexByKey.get(id);
966
- set$(ctx, `containerItemData${furthestIndex}`, data2[index]);
1308
+ set$(ctx, `containerItemData${furthestIndex}`, data[index]);
967
1309
  } else {
968
1310
  const containerId = numContainers;
969
1311
  numContainers++;
970
1312
  set$(ctx, `containerItemKey${containerId}`, id);
971
1313
  const index = state.indexByKey.get(id);
972
- set$(ctx, `containerItemData${containerId}`, data2[index]);
1314
+ set$(ctx, `containerItemData${containerId}`, data[index]);
973
1315
  set$(ctx, `containerPosition${containerId}`, ANCHORED_POSITION_OUT_OF_VIEW);
974
1316
  set$(ctx, `containerColumn${containerId}`, -1);
975
- if (__DEV__ && numContainers > peek$(ctx, "numContainersPooled")) {
1317
+ if (__DEV__ && !didWarnMoreContainers && numContainers > peek$(ctx, "numContainersPooled")) {
1318
+ didWarnMoreContainers = true;
976
1319
  console.warn(
977
- "[legend-list] No container to recycle, so creating one on demand. This can be a performance issue and is likely caused by the estimatedItemSize being too small. Consider increasing estimatedItemSize. numContainers:",
1320
+ "[legend-list] No container to recycle, so creating one on demand. This can be a minor performance issue and is likely caused by the estimatedItemSize being too large. Consider decreasing estimatedItemSize. numContainers:",
978
1321
  numContainers
979
1322
  );
980
1323
  }
@@ -984,19 +1327,19 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
984
1327
  if (numContainers !== prevNumContainers) {
985
1328
  set$(ctx, "numContainers", numContainers);
986
1329
  if (numContainers > peek$(ctx, "numContainersPooled")) {
987
- set$(ctx, "numContainersPooled", numContainers);
1330
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
988
1331
  }
989
1332
  }
990
1333
  for (let i = 0; i < numContainers; i++) {
991
1334
  const itemKey = peek$(ctx, `containerItemKey${i}`);
992
1335
  const itemIndex = state.indexByKey.get(itemKey);
993
- const item = data2[itemIndex];
994
- if (item) {
1336
+ const item = data[itemIndex];
1337
+ if (item !== void 0) {
995
1338
  const id = getId(itemIndex);
996
1339
  if (itemKey !== id || itemIndex < startBuffered || itemIndex > endBuffered) {
997
1340
  const prevPos = peek$(ctx, `containerPosition${i}`).top;
998
1341
  const pos = positions.get(id) || 0;
999
- const size = getItemSize(id, itemIndex, data2[i]);
1342
+ const size = getItemSize(id, itemIndex, data[i]);
1000
1343
  if (pos + size >= scroll && pos <= scrollBottom || prevPos + size >= scroll && prevPos <= scrollBottom) {
1001
1344
  set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1002
1345
  }
@@ -1008,9 +1351,9 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1008
1351
  };
1009
1352
  const column2 = columns.get(id) || 1;
1010
1353
  if (maintainVisibleContentPosition && itemIndex < anchorElementIndex) {
1011
- const currentRow = Math.floor(itemIndex / numColumnsProp);
1354
+ const currentRow = Math.floor(itemIndex / numColumns);
1012
1355
  const rowHeight = getRowHeight(currentRow);
1013
- const elementHeight = getItemSize(id, itemIndex, data2[i]);
1356
+ const elementHeight = getItemSize(id, itemIndex, data[i]);
1014
1357
  const diff = rowHeight - elementHeight;
1015
1358
  pos.relativeCoordinate = pos.top + getRowHeight(currentRow) - diff;
1016
1359
  pos.type = "bottom";
@@ -1025,13 +1368,25 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1025
1368
  set$(ctx, `containerColumn${i}`, column2);
1026
1369
  }
1027
1370
  if (prevData !== item) {
1028
- set$(ctx, `containerItemData${i}`, data2[itemIndex]);
1371
+ set$(ctx, `containerItemData${i}`, data[itemIndex]);
1029
1372
  }
1030
1373
  }
1031
1374
  }
1032
1375
  }
1033
1376
  }
1034
- set$(ctx, "containersDidLayout", true);
1377
+ if (state.numPendingInitialLayout === 0) {
1378
+ state.numPendingInitialLayout = state.endBuffered - state.startBuffered + 1;
1379
+ }
1380
+ if (!state.queuedInitialLayout && endBuffered !== null) {
1381
+ let areAllKnown = true;
1382
+ for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
1383
+ const key = getId(i);
1384
+ areAllKnown && (areAllKnown = state.sizesKnown.has(key));
1385
+ }
1386
+ if (areAllKnown) {
1387
+ setDidLayout();
1388
+ }
1389
+ }
1035
1390
  if (state.viewabilityConfigCallbackPairs) {
1036
1391
  updateViewableItems(
1037
1392
  state,
@@ -1046,16 +1401,27 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1046
1401
  }, []);
1047
1402
  const doUpdatePaddingTop = () => {
1048
1403
  if (alignItemsAtEnd) {
1049
- const { scrollLength, totalSize } = refState.current;
1050
- const listPaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1051
- const paddingTop = Math.max(0, Math.floor(scrollLength - totalSize - listPaddingTop));
1404
+ const { scrollLength } = refState.current;
1405
+ const contentSize = getContentSize(ctx);
1406
+ const paddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1052
1407
  set$(ctx, "paddingTop", paddingTop);
1053
1408
  }
1054
1409
  };
1410
+ const scrollTo = (offset, animated) => {
1411
+ var _a2;
1412
+ (_a2 = refScroller.current) == null ? void 0 : _a2.scrollTo({
1413
+ x: horizontal ? offset : 0,
1414
+ y: horizontal ? 0 : offset,
1415
+ animated: !!animated
1416
+ });
1417
+ };
1055
1418
  const doMaintainScrollAtEnd = (animated) => {
1056
1419
  const state = refState.current;
1057
- if ((state == null ? void 0 : state.isAtBottom) && maintainScrollAtEnd) {
1058
- state.scroll = state.totalSize - state.scrollLength + peek$(ctx, "paddingTop");
1420
+ if ((state == null ? void 0 : state.isAtBottom) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
1421
+ const paddingTop = peek$(ctx, "paddingTop") || 0;
1422
+ if (paddingTop > 0) {
1423
+ state.scroll = 0;
1424
+ }
1059
1425
  requestAnimationFrame(() => {
1060
1426
  var _a2;
1061
1427
  (_a2 = refScroller.current) == null ? void 0 : _a2.scrollToEnd({
@@ -1065,28 +1431,50 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1065
1431
  return true;
1066
1432
  }
1067
1433
  };
1434
+ const checkThreshold = (distance, atThreshold, threshold, isReached, isBlockedByTimer, onReached, blockTimer) => {
1435
+ const distanceAbs = Math.abs(distance);
1436
+ const isAtThreshold = atThreshold || distanceAbs < threshold;
1437
+ if (!isReached && !isBlockedByTimer) {
1438
+ if (isAtThreshold) {
1439
+ onReached == null ? void 0 : onReached(distance);
1440
+ blockTimer == null ? void 0 : blockTimer(true);
1441
+ setTimeout(() => {
1442
+ blockTimer == null ? void 0 : blockTimer(false);
1443
+ }, 700);
1444
+ return true;
1445
+ }
1446
+ } else {
1447
+ if (distance >= 1.3 * threshold) {
1448
+ return false;
1449
+ }
1450
+ }
1451
+ return isReached;
1452
+ };
1068
1453
  const checkAtBottom = () => {
1069
1454
  if (!refState.current) {
1070
1455
  return;
1071
1456
  }
1072
- const { scrollLength, scroll, totalSize } = refState.current;
1073
- if (totalSize > 0) {
1074
- const distanceFromEnd = totalSize - scroll - scrollLength;
1075
- if (refState.current) {
1076
- refState.current.isAtBottom = distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1077
- }
1078
- if (onEndReached) {
1079
- if (!refState.current.isEndReached) {
1080
- if (distanceFromEnd < onEndReachedThreshold * scrollLength) {
1081
- refState.current.isEndReached = true;
1082
- onEndReached({ distanceFromEnd });
1083
- }
1084
- } else {
1085
- if (distanceFromEnd >= onEndReachedThreshold * scrollLength) {
1086
- refState.current.isEndReached = false;
1087
- }
1457
+ const { queuedInitialLayout, scrollLength, scroll } = refState.current;
1458
+ const contentSize = getContentSize(ctx);
1459
+ if (contentSize > 0 && queuedInitialLayout) {
1460
+ const distanceFromEnd = contentSize - scroll - scrollLength;
1461
+ const distanceFromEndAbs = Math.abs(distanceFromEnd);
1462
+ const isContentLess = contentSize < scrollLength;
1463
+ refState.current.isAtBottom = isContentLess || distanceFromEndAbs < scrollLength * maintainScrollAtEndThreshold;
1464
+ refState.current.isEndReached = checkThreshold(
1465
+ distanceFromEnd,
1466
+ isContentLess,
1467
+ onEndReachedThreshold * scrollLength,
1468
+ refState.current.isEndReached,
1469
+ refState.current.endReachedBlockedByTimer,
1470
+ (distance) => {
1471
+ var _a2, _b2;
1472
+ return (_b2 = (_a2 = callbacks.current).onEndReached) == null ? void 0 : _b2.call(_a2, { distanceFromEnd: distance });
1473
+ },
1474
+ (block) => {
1475
+ refState.current.endReachedBlockedByTimer = block;
1088
1476
  }
1089
- }
1477
+ );
1090
1478
  }
1091
1479
  };
1092
1480
  const checkAtTop = () => {
@@ -1095,112 +1483,119 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1095
1483
  }
1096
1484
  const { scrollLength, scroll } = refState.current;
1097
1485
  const distanceFromTop = scroll;
1098
- refState.current.isAtTop = distanceFromTop < 0;
1099
- if (onStartReached) {
1100
- if (!refState.current.isStartReached && !refState.current.startReachedBlockedByTimer) {
1101
- if (distanceFromTop < onStartReachedThreshold * scrollLength) {
1102
- refState.current.isStartReached = true;
1103
- onStartReached({ distanceFromStart: scroll });
1104
- refState.current.startReachedBlockedByTimer = true;
1105
- setTimeout(() => {
1106
- refState.current.startReachedBlockedByTimer = false;
1107
- }, 700);
1108
- }
1109
- } else {
1110
- if (distanceFromTop >= 1.3 * onStartReachedThreshold * scrollLength) {
1111
- refState.current.isStartReached = false;
1112
- }
1486
+ const distanceFromTopAbs = Math.abs(distanceFromTop);
1487
+ refState.current.isAtTop = distanceFromTopAbs < 0;
1488
+ refState.current.isStartReached = checkThreshold(
1489
+ distanceFromTop,
1490
+ false,
1491
+ onStartReachedThreshold * scrollLength,
1492
+ refState.current.isStartReached,
1493
+ refState.current.startReachedBlockedByTimer,
1494
+ (distance) => {
1495
+ var _a2, _b2;
1496
+ return (_b2 = (_a2 = callbacks.current).onStartReached) == null ? void 0 : _b2.call(_a2, { distanceFromStart: distance });
1497
+ },
1498
+ (block) => {
1499
+ refState.current.startReachedBlockedByTimer = block;
1113
1500
  }
1114
- }
1501
+ );
1115
1502
  };
1116
- const checkResetContainers = (reset) => {
1503
+ const checkResetContainers = (isFirst2) => {
1117
1504
  const state = refState.current;
1118
1505
  if (state) {
1119
- state.data = data;
1120
- if (reset) {
1506
+ state.data = dataProp;
1507
+ if (!isFirst2) {
1121
1508
  refState.current.scrollForNextCalculateItemsInView = void 0;
1122
1509
  const numContainers = peek$(ctx, "numContainers");
1123
1510
  for (let i = 0; i < numContainers; i++) {
1124
1511
  const itemKey = peek$(ctx, `containerItemKey${i}`);
1125
1512
  if (!keyExtractorProp || itemKey && state.indexByKey.get(itemKey) === void 0) {
1126
1513
  set$(ctx, `containerItemKey${i}`, void 0);
1514
+ set$(ctx, `containerItemData${i}`, void 0);
1127
1515
  set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1128
1516
  set$(ctx, `containerColumn${i}`, -1);
1129
1517
  }
1130
1518
  }
1131
1519
  if (!keyExtractorProp) {
1132
- state.sizes.clear();
1133
1520
  state.positions.clear();
1134
1521
  }
1135
- calculateItemsInView(state.scrollVelocity);
1136
- }
1137
- const didMaintainScrollAtEnd = doMaintainScrollAtEnd(false);
1138
- if (!didMaintainScrollAtEnd && data.length > state.data.length) {
1139
- state.isEndReached = false;
1522
+ calculateItemsInView();
1523
+ const didMaintainScrollAtEnd = doMaintainScrollAtEnd(false);
1524
+ if (!didMaintainScrollAtEnd && dataProp.length > state.data.length) {
1525
+ state.isEndReached = false;
1526
+ }
1527
+ checkAtTop();
1528
+ checkAtBottom();
1140
1529
  }
1141
- checkAtTop();
1142
- checkAtBottom();
1143
1530
  }
1144
1531
  };
1145
- const isFirst = !refState.current.renderItem;
1146
- if (isFirst || data !== refState.current.data || numColumnsProp !== peek$(ctx, "numColumns")) {
1147
- if (!keyExtractorProp && !isFirst && data !== refState.current.data) {
1148
- refState.current.sizes.clear();
1149
- refState.current.positions.clear();
1150
- }
1151
- refState.current.data = data;
1532
+ const calcTotalSizesAndPositions = ({ forgetPositions = false }) => {
1533
+ var _a2, _b2;
1152
1534
  let totalSize = 0;
1153
1535
  let totalSizeBelowIndex = 0;
1154
1536
  const indexByKey = /* @__PURE__ */ new Map();
1155
1537
  const newPositions = /* @__PURE__ */ new Map();
1156
1538
  let column = 1;
1157
1539
  let maxSizeInRow = 0;
1158
- for (let i = 0; i < data.length; i++) {
1540
+ const numColumns = (_a2 = peek$(ctx, "numColumns")) != null ? _a2 : numColumnsProp;
1541
+ if (!refState.current) {
1542
+ return;
1543
+ }
1544
+ for (let i = 0; i < dataProp.length; i++) {
1159
1545
  const key = getId(i);
1546
+ if (__DEV__) {
1547
+ if (indexByKey.has(key)) {
1548
+ console.error(
1549
+ `[legend-list] Error: Detected overlapping key (${key}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
1550
+ );
1551
+ }
1552
+ }
1160
1553
  indexByKey.set(key, i);
1161
- if (refState.current.positions.get(key) != null && refState.current.indexByKey.get(key) === i) {
1554
+ if (!forgetPositions && refState.current.positions.get(key) != null && refState.current.indexByKey.get(key) === i) {
1162
1555
  newPositions.set(key, refState.current.positions.get(key));
1163
1556
  }
1164
1557
  }
1165
1558
  refState.current.indexByKey = indexByKey;
1166
1559
  refState.current.positions = newPositions;
1167
- if (maintainVisibleContentPosition) {
1168
- if (refState.current.anchorElement == null || indexByKey.get(refState.current.anchorElement.id) == null) {
1169
- if (data.length) {
1170
- const newAnchorElement = {
1171
- coordinate: 0,
1172
- id: getId(0)
1173
- };
1174
- refState.current.anchorElement = newAnchorElement;
1175
- (_a = refState.current.belowAnchorElementPositions) == null ? void 0 : _a.clear();
1176
- refScroller.current.scrollTo({ x: 0, y: 0, animated: false });
1560
+ if (!forgetPositions && !isFirst) {
1561
+ if (maintainVisibleContentPosition) {
1562
+ if (refState.current.anchorElement == null || indexByKey.get(refState.current.anchorElement.id) == null) {
1563
+ if (dataProp.length) {
1564
+ const newAnchorElement = {
1565
+ coordinate: 0,
1566
+ id: getId(0)
1567
+ };
1568
+ refState.current.anchorElement = newAnchorElement;
1569
+ (_b2 = refState.current.belowAnchorElementPositions) == null ? void 0 : _b2.clear();
1570
+ scrollTo(0, false);
1571
+ setTimeout(() => {
1572
+ calculateItemsInView();
1573
+ }, 0);
1574
+ } else {
1575
+ refState.current.startBufferedId = void 0;
1576
+ }
1577
+ }
1578
+ } else {
1579
+ if (refState.current.startBufferedId != null && newPositions.get(refState.current.startBufferedId) == null) {
1580
+ if (dataProp.length) {
1581
+ refState.current.startBufferedId = getId(0);
1582
+ } else {
1583
+ refState.current.startBufferedId = void 0;
1584
+ }
1585
+ scrollTo(0, false);
1177
1586
  setTimeout(() => {
1178
- calculateItemsInView(0);
1587
+ calculateItemsInView();
1179
1588
  }, 0);
1180
- } else {
1181
- refState.current.startBufferedId = void 0;
1182
1589
  }
1183
1590
  }
1184
- } else {
1185
- if (refState.current.startBufferedId != null && newPositions.get(refState.current.startBufferedId) == null) {
1186
- if (data.length) {
1187
- refState.current.startBufferedId = getId(0);
1188
- } else {
1189
- refState.current.startBufferedId = void 0;
1190
- }
1191
- refScroller.current.scrollTo({ x: 0, y: 0, animated: false });
1192
- setTimeout(() => {
1193
- calculateItemsInView(0);
1194
- }, 0);
1195
- }
1196
1591
  }
1197
1592
  const anchorElementIndex = getAnchorElementIndex();
1198
- for (let i = 0; i < data.length; i++) {
1593
+ for (let i = 0; i < dataProp.length; i++) {
1199
1594
  const key = getId(i);
1200
- const size = getItemSize(key, i, data[i]);
1595
+ const size = getItemSize(key, i, dataProp[i]);
1201
1596
  maxSizeInRow = Math.max(maxSizeInRow, size);
1202
1597
  column++;
1203
- if (column > numColumnsProp) {
1598
+ if (column > numColumns) {
1204
1599
  if (maintainVisibleContentPosition && anchorElementIndex !== void 0 && i < anchorElementIndex) {
1205
1600
  totalSizeBelowIndex += maxSizeInRow;
1206
1601
  }
@@ -1212,111 +1607,178 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1212
1607
  if (maxSizeInRow > 0) {
1213
1608
  totalSize += maxSizeInRow;
1214
1609
  }
1610
+ const state = refState.current;
1611
+ state.ignoreScrollFromCalcTotal = true;
1612
+ requestAnimationFrame(() => {
1613
+ state.ignoreScrollFromCalcTotal = false;
1614
+ });
1215
1615
  addTotalSize(null, totalSize, totalSizeBelowIndex);
1216
- }
1217
- useEffect(() => {
1218
- checkResetContainers(
1219
- /*reset*/
1220
- !isFirst
1616
+ };
1617
+ const isFirst = !refState.current.renderItem;
1618
+ const memoizedLastItemKeys = useMemo(() => {
1619
+ if (!dataProp.length) return [];
1620
+ return Array.from(
1621
+ { length: Math.min(numColumnsProp, dataProp.length) },
1622
+ (_, i) => getId(dataProp.length - 1 - i)
1221
1623
  );
1222
- }, [isFirst, data, numColumnsProp]);
1223
- useEffect(() => {
1224
- set$(ctx, "extraData", extraData);
1225
- }, [extraData]);
1226
- refState.current.renderItem = renderItem;
1227
- const lastItemKey = data.length > 0 ? getId(data.length - 1) : void 0;
1228
- const stylePaddingTop = (_e = (_d = (_b = StyleSheet.flatten(style)) == null ? void 0 : _b.paddingTop) != null ? _d : (_c = StyleSheet.flatten(contentContainerStyle)) == null ? void 0 : _c.paddingTop) != null ? _e : 0;
1624
+ }, [dataProp, numColumnsProp]);
1229
1625
  const initalizeStateVars = () => {
1230
- set$(ctx, "lastItemKey", lastItemKey);
1626
+ set$(ctx, "lastItemKeys", memoizedLastItemKeys);
1231
1627
  set$(ctx, "numColumns", numColumnsProp);
1232
- set$(ctx, "stylePaddingTop", stylePaddingTop);
1628
+ if (maintainVisibleContentPosition) {
1629
+ const prevPaddingTop = peek$(ctx, "stylePaddingTop");
1630
+ set$(ctx, "stylePaddingTop", stylePaddingTop);
1631
+ if (prevPaddingTop !== void 0) {
1632
+ const paddingDiff = stylePaddingTop - prevPaddingTop;
1633
+ if (paddingDiff) {
1634
+ set$(ctx, "paddingTop", peek$(ctx, "paddingTop") + paddingDiff);
1635
+ if (Platform.OS === "ios") {
1636
+ queueMicrotask(() => {
1637
+ scrollTo(refState.current.scroll + paddingDiff, false);
1638
+ });
1639
+ }
1640
+ }
1641
+ }
1642
+ }
1233
1643
  };
1234
1644
  if (isFirst) {
1235
1645
  initalizeStateVars();
1236
1646
  }
1237
- useEffect(initalizeStateVars, [lastItemKey, numColumnsProp, stylePaddingTop]);
1647
+ if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
1648
+ refState.current.lastBatchingAction = Date.now();
1649
+ if (!keyExtractorProp && !isFirst && didDataChange) {
1650
+ refState.current.sizes.clear();
1651
+ refState.current.positions.clear();
1652
+ }
1653
+ calcTotalSizesAndPositions({ forgetPositions: false });
1654
+ }
1655
+ useEffect(() => {
1656
+ const didAllocateContainers = doInitialAllocateContainers();
1657
+ if (!didAllocateContainers) {
1658
+ checkResetContainers(
1659
+ /*isFirst*/
1660
+ isFirst
1661
+ );
1662
+ }
1663
+ }, [isFirst, dataProp, numColumnsProp]);
1664
+ useEffect(() => {
1665
+ set$(ctx, "extraData", extraData);
1666
+ }, [extraData]);
1667
+ refState.current.renderItem = renderItem;
1668
+ useEffect(initalizeStateVars, [memoizedLastItemKeys.join(","), numColumnsProp, stylePaddingTop]);
1238
1669
  const getRenderedItem = useCallback((key) => {
1239
1670
  var _a2, _b2;
1240
1671
  const state = refState.current;
1241
1672
  if (!state) {
1242
1673
  return null;
1243
1674
  }
1244
- const { data: data2, indexByKey } = state;
1675
+ const { data, indexByKey } = state;
1245
1676
  const index = indexByKey.get(key);
1246
1677
  if (index === void 0) {
1247
1678
  return null;
1248
1679
  }
1249
- const useViewability2 = (configId, callback) => {
1250
- useViewability(configId, callback);
1251
- };
1252
- const useViewabilityAmount2 = (callback) => {
1253
- useViewabilityAmount(callback);
1254
- };
1255
- const useRecyclingEffect2 = (effect) => {
1256
- useRecyclingEffect(effect);
1257
- };
1258
- const useRecyclingState2 = (valueOrFun) => {
1259
- return useRecyclingState(valueOrFun);
1260
- };
1680
+ const useViewability2 = __DEV__ ? (configId, callback) => {
1681
+ console.warn(
1682
+ `[legend-list] useViewability has been moved from a render prop to a regular import: import { useViewability } from "@legendapp/list";`
1683
+ );
1684
+ } : void 0;
1685
+ const useViewabilityAmount2 = __DEV__ ? (callback) => {
1686
+ console.warn(
1687
+ `[legend-list] useViewabilityAmount has been moved from a render prop to a regular import: import { useViewabilityAmount } from "@legendapp/list";`
1688
+ );
1689
+ } : void 0;
1690
+ const useRecyclingEffect2 = __DEV__ ? (effect) => {
1691
+ console.warn(
1692
+ `[legend-list] useRecyclingEffect has been moved from a render prop to a regular import: import { useRecyclingEffect } from "@legendapp/list";`
1693
+ );
1694
+ } : void 0;
1695
+ const useRecyclingState2 = __DEV__ ? (valueOrFun) => {
1696
+ console.warn(
1697
+ `[legend-list] useRecyclingState has been moved from a render prop to a regular import: import { useRecyclingState } from "@legendapp/list";`
1698
+ );
1699
+ } : void 0;
1261
1700
  const renderedItem = (_b2 = (_a2 = refState.current).renderItem) == null ? void 0 : _b2.call(_a2, {
1262
- item: data2[index],
1701
+ item: data[index],
1263
1702
  index,
1703
+ extraData: peek$(ctx, "extraData"),
1704
+ // @ts-expect-error TODO: Remove these before 1.0
1264
1705
  useViewability: useViewability2,
1265
1706
  useViewabilityAmount: useViewabilityAmount2,
1266
1707
  useRecyclingEffect: useRecyclingEffect2,
1267
1708
  useRecyclingState: useRecyclingState2
1268
1709
  });
1269
- return { index, renderedItem };
1710
+ return { index, item: data[index], renderedItem };
1270
1711
  }, []);
1271
- useInit(() => {
1712
+ const doInitialAllocateContainers = () => {
1272
1713
  var _a2;
1273
1714
  const state = refState.current;
1274
- const viewability = setupViewability(props);
1715
+ const { scrollLength, data } = state;
1716
+ if (scrollLength > 0 && data.length > 0 && !peek$(ctx, "numContainers")) {
1717
+ const averageItemSize = (_a2 = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, data[0])) != null ? _a2 : DEFAULT_ITEM_SIZE;
1718
+ const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) * numColumnsProp;
1719
+ for (let i = 0; i < numContainers; i++) {
1720
+ set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1721
+ set$(ctx, `containerColumn${i}`, -1);
1722
+ }
1723
+ set$(ctx, "numContainers", numContainers);
1724
+ set$(ctx, "numContainersPooled", numContainers * initialContainerPoolRatio);
1725
+ if (initialScrollIndex) {
1726
+ requestAnimationFrame(() => {
1727
+ calculateItemsInView();
1728
+ });
1729
+ } else {
1730
+ calculateItemsInView();
1731
+ }
1732
+ return true;
1733
+ }
1734
+ };
1735
+ useEffect(() => {
1736
+ const state = refState.current;
1737
+ const viewability = setupViewability({
1738
+ viewabilityConfig,
1739
+ viewabilityConfigCallbackPairs,
1740
+ onViewableItemsChanged
1741
+ });
1275
1742
  state.viewabilityConfigCallbackPairs = viewability;
1276
1743
  state.enableScrollForNextCalculateItemsInView = !viewability;
1277
- const scrollLength = state.scrollLength;
1278
- const averageItemSize = (_a2 = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, data[0])) != null ? _a2 : DEFAULT_ITEM_SIZE;
1279
- const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) * numColumnsProp;
1280
- for (let i = 0; i < numContainers; i++) {
1281
- set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1282
- set$(ctx, `containerColumn${i}`, -1);
1283
- }
1284
- set$(ctx, "numContainers", numContainers);
1285
- set$(ctx, "numContainersPooled", numContainers * 2);
1286
- calculateItemsInView(state.scrollVelocity);
1744
+ }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
1745
+ useInit(() => {
1746
+ doInitialAllocateContainers();
1287
1747
  });
1288
- const updateItemSize = useCallback((containerId, itemKey, size) => {
1289
- var _a2;
1290
- const data2 = (_a2 = refState.current) == null ? void 0 : _a2.data;
1291
- if (!data2) {
1748
+ const updateItemSize = useCallback((itemKey, size) => {
1749
+ const state = refState.current;
1750
+ const { sizes, indexByKey, sizesKnown, data, rowHeights } = state;
1751
+ if (!data) {
1292
1752
  return;
1293
1753
  }
1294
- const state = refState.current;
1295
- const { sizes, indexByKey, columns, sizesLaidOut } = state;
1296
1754
  const index = indexByKey.get(itemKey);
1297
1755
  const numColumns = peek$(ctx, "numColumns");
1298
- const row = Math.floor(index / numColumns);
1299
- const prevSize = getRowHeight(row);
1756
+ state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, index) : index;
1757
+ const prevSize = getItemSize(itemKey, index, data);
1758
+ let needsCalculate = false;
1759
+ if (state.numPendingInitialLayout > 0) {
1760
+ state.numPendingInitialLayout--;
1761
+ if (state.numPendingInitialLayout === 0) {
1762
+ needsCalculate = true;
1763
+ state.numPendingInitialLayout = -1;
1764
+ }
1765
+ }
1766
+ sizesKnown == null ? void 0 : sizesKnown.set(itemKey, size);
1300
1767
  if (!prevSize || Math.abs(prevSize - size) > 0.5) {
1301
1768
  let diff;
1769
+ needsCalculate = true;
1302
1770
  if (numColumns > 1) {
1303
- const prevMaxSizeInRow = getRowHeight(row);
1771
+ const rowNumber = Math.floor(index / numColumnsProp);
1772
+ const prevSizeInRow = getRowHeight(rowNumber);
1304
1773
  sizes.set(itemKey, size);
1305
- const column = columns.get(itemKey);
1306
- const loopStart = index - (column - 1);
1307
- let nextMaxSizeInRow = 0;
1308
- for (let i = loopStart; i < loopStart + numColumns && i < data2.length; i++) {
1309
- const id = getId(i);
1310
- const size2 = getItemSize(id, i, data2[i]);
1311
- nextMaxSizeInRow = Math.max(nextMaxSizeInRow, size2);
1312
- }
1313
- diff = nextMaxSizeInRow - prevMaxSizeInRow;
1774
+ rowHeights.delete(rowNumber);
1775
+ const sizeInRow = getRowHeight(rowNumber);
1776
+ diff = sizeInRow - prevSizeInRow;
1314
1777
  } else {
1315
1778
  sizes.set(itemKey, size);
1316
1779
  diff = size - prevSize;
1317
1780
  }
1318
1781
  if (__DEV__ && !estimatedItemSize && !getEstimatedItemSize) {
1319
- sizesLaidOut.set(itemKey, size);
1320
1782
  if (state.timeoutSizeMessage) {
1321
1783
  clearTimeout(state.timeoutSizeMessage);
1322
1784
  }
@@ -1324,7 +1786,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1324
1786
  state.timeoutSizeMessage = void 0;
1325
1787
  let total = 0;
1326
1788
  let num = 0;
1327
- for (const [key, size2] of sizesLaidOut) {
1789
+ for (const [_, size2] of sizesKnown) {
1328
1790
  num++;
1329
1791
  total += size2;
1330
1792
  }
@@ -1336,38 +1798,48 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1336
1798
  }
1337
1799
  refState.current.scrollForNextCalculateItemsInView = void 0;
1338
1800
  addTotalSize(itemKey, diff, 0);
1339
- doMaintainScrollAtEnd(true);
1801
+ doMaintainScrollAtEnd(false);
1802
+ if (onItemSizeChanged) {
1803
+ onItemSizeChanged({
1804
+ size,
1805
+ previous: prevSize,
1806
+ index,
1807
+ itemKey,
1808
+ itemData: data[index]
1809
+ });
1810
+ }
1811
+ }
1812
+ if (needsCalculate) {
1340
1813
  const scrollVelocity = state.scrollVelocity;
1341
- if (!state.waitingForMicrotask && (Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1)) {
1342
- if (!peek$(ctx, "containersDidLayout")) {
1343
- state.waitingForMicrotask = true;
1344
- queueMicrotask(() => {
1345
- if (state.waitingForMicrotask) {
1346
- state.waitingForMicrotask = false;
1347
- calculateItemsInView(state.scrollVelocity);
1348
- }
1349
- });
1814
+ if ((Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1) && (!waitForInitialLayout || state.numPendingInitialLayout < 0)) {
1815
+ if (Date.now() - state.lastBatchingAction < 500) {
1816
+ if (!state.queuedCalculateItemsInView) {
1817
+ state.queuedCalculateItemsInView = requestAnimationFrame(() => {
1818
+ state.queuedCalculateItemsInView = void 0;
1819
+ calculateItemsInView();
1820
+ });
1821
+ }
1350
1822
  } else {
1351
- calculateItemsInView(state.scrollVelocity);
1823
+ calculateItemsInView();
1352
1824
  }
1353
1825
  }
1354
- if (onItemSizeChanged) {
1355
- onItemSizeChanged({ size, previous: prevSize, index, itemKey, itemData: data2[index] });
1356
- }
1357
1826
  }
1358
1827
  }, []);
1359
- const handleScrollDebounced = useCallback((velocity) => {
1360
- calculateItemsInView(velocity);
1361
- checkAtBottom();
1362
- checkAtTop();
1363
- }, []);
1364
1828
  const onLayout = useCallback((event) => {
1829
+ const state = refState.current;
1365
1830
  const scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
1366
- refState.current.scrollLength = scrollLength;
1831
+ const didChange = scrollLength !== state.scrollLength;
1832
+ state.scrollLength = scrollLength;
1833
+ state.lastBatchingAction = Date.now();
1834
+ state.scrollForNextCalculateItemsInView = void 0;
1835
+ doInitialAllocateContainers();
1367
1836
  doMaintainScrollAtEnd(false);
1368
1837
  doUpdatePaddingTop();
1369
1838
  checkAtBottom();
1370
1839
  checkAtTop();
1840
+ if (didChange) {
1841
+ calculateItemsInView();
1842
+ }
1371
1843
  if (__DEV__) {
1372
1844
  const isWidthZero = event.nativeEvent.layout.width === 0;
1373
1845
  const isHeightZero = event.nativeEvent.layout.height === 0;
@@ -1377,17 +1849,24 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1377
1849
  );
1378
1850
  }
1379
1851
  }
1852
+ if (onLayoutProp) {
1853
+ onLayoutProp(event);
1854
+ }
1380
1855
  }, []);
1381
1856
  const handleScroll = useCallback(
1382
1857
  (event, fromSelf) => {
1383
- var _a2, _b2, _c2;
1858
+ var _a2, _b2, _c2, _d2;
1384
1859
  if (((_b2 = (_a2 = event.nativeEvent) == null ? void 0 : _a2.contentSize) == null ? void 0 : _b2.height) === 0 && ((_c2 = event.nativeEvent.contentSize) == null ? void 0 : _c2.width) === 0) {
1385
1860
  return;
1386
1861
  }
1387
1862
  const state = refState.current;
1863
+ const newScroll = event.nativeEvent.contentOffset[horizontal ? "x" : "y"];
1864
+ if (state.ignoreScrollFromCalcTotal && newScroll !== 0) {
1865
+ return;
1866
+ }
1388
1867
  state.hasScrolled = true;
1868
+ state.lastBatchingAction = Date.now();
1389
1869
  const currentTime = performance.now();
1390
- const newScroll = event.nativeEvent.contentOffset[horizontal ? "x" : "y"];
1391
1870
  if (!(state.scrollHistory.length === 0 && newScroll === initialContentOffset)) {
1392
1871
  state.scrollHistory.push({ scroll: newScroll, time: currentTime });
1393
1872
  }
@@ -1413,9 +1892,11 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1413
1892
  state.scroll = newScroll;
1414
1893
  state.scrollTime = currentTime;
1415
1894
  state.scrollVelocity = velocity;
1416
- handleScrollDebounced(velocity);
1895
+ calculateItemsInView();
1896
+ checkAtBottom();
1897
+ checkAtTop();
1417
1898
  if (!fromSelf) {
1418
- onScrollProp == null ? void 0 : onScrollProp(event);
1899
+ (_d2 = state.onScroll) == null ? void 0 : _d2.call(state, event);
1419
1900
  }
1420
1901
  },
1421
1902
  []
@@ -1423,61 +1904,157 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1423
1904
  useImperativeHandle(
1424
1905
  forwardedRef,
1425
1906
  () => {
1426
- const scrollToIndex = ({ index, animated }) => {
1427
- const offsetObj = calculateInitialOffset(index);
1428
- const offset = horizontal ? { x: offsetObj, y: 0 } : { x: 0, y: offsetObj };
1429
- refScroller.current.scrollTo({ ...offset, animated });
1907
+ const scrollToIndex = ({
1908
+ index,
1909
+ viewOffset = 0,
1910
+ animated = true,
1911
+ viewPosition = 0
1912
+ }) => {
1913
+ var _a2;
1914
+ const state = refState.current;
1915
+ const firstIndexOffset = calculateOffsetForIndex(index);
1916
+ let firstIndexScrollPostion = firstIndexOffset - viewOffset;
1917
+ const diff = Math.abs(state.scroll - firstIndexScrollPostion);
1918
+ const needsReanchoring = maintainVisibleContentPosition && diff > 100;
1919
+ state.scrollForNextCalculateItemsInView = void 0;
1920
+ if (needsReanchoring) {
1921
+ const id = getId(index);
1922
+ state.anchorElement = { id, coordinate: firstIndexOffset };
1923
+ (_a2 = state.belowAnchorElementPositions) == null ? void 0 : _a2.clear();
1924
+ state.positions.clear();
1925
+ calcTotalSizesAndPositions({ forgetPositions: true });
1926
+ state.startBufferedId = id;
1927
+ state.minIndexSizeChanged = index;
1928
+ firstIndexScrollPostion = firstIndexOffset - viewOffset + state.scrollAdjustHandler.getAppliedAdjust();
1929
+ }
1930
+ if (viewPosition) {
1931
+ firstIndexScrollPostion -= viewPosition * (state.scrollLength - getItemSize(getId(index), index, state.data[index]));
1932
+ }
1933
+ state.scrollAdjustHandler.setDisableAdjust(true);
1934
+ state.scrollingToOffset = firstIndexScrollPostion;
1935
+ scrollTo(firstIndexScrollPostion, animated);
1936
+ };
1937
+ const scrollIndexIntoView = (options) => {
1938
+ if (refState.current) {
1939
+ const { index, ...rest2 } = options;
1940
+ const { startNoBuffer, endNoBuffer } = refState.current;
1941
+ if (index < startNoBuffer || index > endNoBuffer) {
1942
+ const viewPosition = index < startNoBuffer ? 0 : 1;
1943
+ scrollToIndex({
1944
+ ...rest2,
1945
+ viewPosition,
1946
+ index
1947
+ });
1948
+ }
1949
+ }
1430
1950
  };
1431
1951
  return {
1952
+ flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
1432
1953
  getNativeScrollRef: () => refScroller.current,
1433
- getScrollableNode: refScroller.current.getScrollableNode,
1434
- getScrollResponder: refScroller.current.getScrollResponder,
1435
- flashScrollIndicators: refScroller.current.flashScrollIndicators,
1436
- scrollToIndex,
1437
- scrollToOffset: ({ offset, animated }) => {
1438
- const offsetObj = horizontal ? { x: offset, y: 0 } : { x: 0, y: offset };
1439
- refScroller.current.scrollTo({ ...offsetObj, animated });
1954
+ getScrollableNode: () => refScroller.current.getScrollableNode(),
1955
+ getScrollResponder: () => refScroller.current.getScrollResponder(),
1956
+ getState: () => {
1957
+ const state = refState.current;
1958
+ return state ? {
1959
+ contentLength: state.totalSize,
1960
+ end: state.endNoBuffer,
1961
+ endBuffered: state.endBuffered,
1962
+ isAtEnd: state.isAtBottom,
1963
+ isAtStart: state.isAtTop,
1964
+ scroll: state.scroll,
1965
+ scrollLength: state.scrollLength,
1966
+ start: state.startNoBuffer,
1967
+ startBuffered: state.startBuffered
1968
+ } : {};
1440
1969
  },
1441
- scrollToItem: ({ item, animated }) => {
1970
+ scrollIndexIntoView,
1971
+ scrollItemIntoView: ({ item, ...props2 }) => {
1972
+ const { data } = refState.current;
1442
1973
  const index = data.indexOf(item);
1443
1974
  if (index !== -1) {
1444
- scrollToIndex({ index, animated });
1975
+ scrollIndexIntoView({ index, ...props2 });
1445
1976
  }
1446
1977
  },
1447
- scrollToEnd: refScroller.current.scrollToEnd
1978
+ scrollToIndex,
1979
+ scrollToItem: ({ item, ...props2 }) => {
1980
+ const { data } = refState.current;
1981
+ const index = data.indexOf(item);
1982
+ if (index !== -1) {
1983
+ scrollToIndex({ index, ...props2 });
1984
+ }
1985
+ },
1986
+ scrollToOffset: ({ offset, animated }) => {
1987
+ scrollTo(offset, animated);
1988
+ },
1989
+ scrollToEnd: (options) => refScroller.current.scrollToEnd(options)
1448
1990
  };
1449
1991
  },
1450
1992
  []
1451
1993
  );
1452
- return /* @__PURE__ */ React5.createElement(
1994
+ if (Platform.OS === "web") {
1995
+ useEffect(() => {
1996
+ var _a2;
1997
+ if (initialContentOffset) {
1998
+ (_a2 = refState.current) == null ? void 0 : _a2.scrollAdjustHandler.setDisableAdjust(true);
1999
+ scrollTo(initialContentOffset, false);
2000
+ setTimeout(() => {
2001
+ var _a3;
2002
+ (_a3 = refState.current) == null ? void 0 : _a3.scrollAdjustHandler.setDisableAdjust(false);
2003
+ }, 0);
2004
+ }
2005
+ }, []);
2006
+ }
2007
+ return /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(
1453
2008
  ListComponent,
1454
2009
  {
1455
2010
  ...rest,
1456
2011
  horizontal,
1457
- refScrollView: (r) => {
1458
- refScroller.current = r;
1459
- if (refScrollView) {
1460
- if (typeof refScrollView === "function") {
1461
- refScrollView(r);
1462
- } else {
1463
- refScrollView.current = r;
1464
- }
1465
- }
1466
- },
2012
+ refScrollView: combinedRef,
1467
2013
  initialContentOffset,
1468
2014
  getRenderedItem,
1469
2015
  updateItemSize,
1470
2016
  handleScroll,
2017
+ onMomentumScrollEnd: (event) => {
2018
+ var _a2;
2019
+ const scrollingToOffset = (_a2 = refState.current) == null ? void 0 : _a2.scrollingToOffset;
2020
+ if (scrollingToOffset !== void 0) {
2021
+ requestAnimationFrame(() => {
2022
+ scrollTo(scrollingToOffset, false);
2023
+ refState.current.scrollingToOffset = void 0;
2024
+ requestAnimationFrame(() => {
2025
+ refState.current.scrollAdjustHandler.setDisableAdjust(false);
2026
+ });
2027
+ });
2028
+ }
2029
+ const wasPaused = refState.current.scrollAdjustHandler.unPauseAdjust();
2030
+ if (wasPaused) {
2031
+ refState.current.scrollVelocity = 0;
2032
+ refState.current.scrollHistory = [];
2033
+ calculateItemsInView();
2034
+ }
2035
+ if (onMomentumScrollEnd) {
2036
+ onMomentumScrollEnd(event);
2037
+ }
2038
+ },
1471
2039
  onLayout,
1472
2040
  recycleItems,
1473
2041
  alignItemsAtEnd,
1474
- ListEmptyComponent: data.length === 0 ? ListEmptyComponent : void 0,
2042
+ ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
1475
2043
  maintainVisibleContentPosition,
1476
2044
  scrollEventThrottle: scrollEventThrottle != null ? scrollEventThrottle : Platform.OS === "web" ? 16 : void 0,
1477
2045
  waitForInitialLayout,
1478
- style
2046
+ refreshControl: refreshControl != null ? refreshControl : onRefresh && /* @__PURE__ */ React6.createElement(
2047
+ RefreshControl,
2048
+ {
2049
+ refreshing: !!refreshing,
2050
+ onRefresh,
2051
+ progressViewOffset
2052
+ }
2053
+ ),
2054
+ style,
2055
+ contentContainerStyle
1479
2056
  }
1480
- );
2057
+ ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React6.createElement(DebugView, { state: refState.current }));
1481
2058
  });
1482
2059
 
1483
2060
  export { LegendList, useRecyclingEffect, useRecyclingState, useViewability, useViewabilityAmount };