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

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,89 @@ 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
+ onLayout: onLayoutProp,
849
+ onRefresh,
850
+ refreshing,
851
+ progressViewOffset,
852
+ refreshControl,
853
+ initialContainerPoolRatio = 2,
854
+ viewabilityConfig,
855
+ viewabilityConfigCallbackPairs,
856
+ onViewableItemsChanged,
588
857
  ...rest
589
858
  } = props;
590
- const { style, contentContainerStyle } = props;
859
+ const { style } = 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);
591
867
  const ctx = useStateContext();
868
+ ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
592
869
  const refScroller = useRef(null);
593
- const scrollBuffer = drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE;
870
+ const combinedRef = useCombinedRef(refScroller, refScrollView);
871
+ const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
594
872
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (item, index) => index.toString();
595
873
  const refState = useRef();
596
874
  const getId = (index) => {
597
875
  var _a2;
598
- const data2 = (_a2 = refState.current) == null ? void 0 : _a2.data;
599
- if (!data2) {
876
+ const data = (_a2 = refState.current) == null ? void 0 : _a2.data;
877
+ if (!data) {
600
878
  return "";
601
879
  }
602
- const ret = index < data2.length ? keyExtractor ? keyExtractor(data2[index], index) : index : null;
880
+ const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
603
881
  return `${ret}`;
604
882
  };
605
- const getItemSize = (key, index, data2) => {
883
+ const getItemSize = (key, index, data) => {
606
884
  var _a2;
607
885
  const sizeKnown = refState.current.sizes.get(key);
608
886
  if (sizeKnown !== void 0) {
609
887
  return sizeKnown;
610
888
  }
611
- const size = (_a2 = getEstimatedItemSize ? getEstimatedItemSize(index, data2) : estimatedItemSize) != null ? _a2 : DEFAULT_ITEM_SIZE;
889
+ const size = (_a2 = getEstimatedItemSize ? getEstimatedItemSize(index, data) : estimatedItemSize) != null ? _a2 : DEFAULT_ITEM_SIZE;
612
890
  refState.current.sizes.set(key, size);
613
891
  return size;
614
892
  };
615
- const calculateInitialOffset = (index = initialScrollIndex) => {
616
- if (index) {
893
+ const calculateOffsetForIndex = (index = initialScrollIndex) => {
894
+ var _a2;
895
+ const data = dataProp;
896
+ if (index !== void 0) {
617
897
  let offset = 0;
618
- if (getEstimatedItemSize) {
898
+ const canGetSize = !!refState.current;
899
+ if (canGetSize || getEstimatedItemSize) {
900
+ const sizeFn = (index2) => {
901
+ if (canGetSize) {
902
+ return getItemSize(getId(index2), index2, data[index2]);
903
+ }
904
+ return getEstimatedItemSize(index2, data[index2]);
905
+ };
619
906
  for (let i = 0; i < index; i++) {
620
- offset += getEstimatedItemSize(i, data[i]);
907
+ offset += sizeFn(i);
621
908
  }
622
909
  } else if (estimatedItemSize) {
623
910
  offset = index * estimatedItemSize;
624
911
  }
625
- return offset / numColumnsProp;
912
+ return offset / numColumnsProp - (((_a2 = refState.current) == null ? void 0 : _a2.scrollAdjustHandler.getAppliedAdjust()) || 0);
626
913
  }
627
914
  return 0;
628
915
  };
629
- const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : useMemo(calculateInitialOffset, []);
916
+ const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : useMemo(calculateOffsetForIndex, []);
630
917
  if (!refState.current) {
631
918
  const initialScrollLength = Dimensions.get("window")[horizontal ? "width" : "height"];
632
919
  refState.current = {
@@ -634,14 +921,11 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
634
921
  positions: /* @__PURE__ */ new Map(),
635
922
  columns: /* @__PURE__ */ new Map(),
636
923
  pendingAdjust: 0,
637
- waitingForMicrotask: false,
638
924
  isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
639
925
  isEndReached: false,
640
926
  isAtBottom: false,
641
927
  isAtTop: false,
642
- data,
643
- idsInFirstRender: void 0,
644
- hasScrolled: false,
928
+ data: dataProp,
645
929
  scrollLength: initialScrollLength,
646
930
  startBuffered: 0,
647
931
  startNoBuffer: 0,
@@ -661,23 +945,29 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
661
945
  indexByKey: /* @__PURE__ */ new Map(),
662
946
  scrollHistory: [],
663
947
  scrollVelocity: 0,
664
- sizesLaidOut: __DEV__ ? /* @__PURE__ */ new Map() : void 0,
948
+ sizesKnown: /* @__PURE__ */ new Map(),
665
949
  timeoutSizeMessage: 0,
666
950
  scrollTimer: void 0,
667
951
  belowAnchorElementPositions: void 0,
668
952
  rowHeights: /* @__PURE__ */ new Map(),
669
953
  startReachedBlockedByTimer: false,
954
+ endReachedBlockedByTimer: false,
670
955
  scrollForNextCalculateItemsInView: void 0,
671
- enableScrollForNextCalculateItemsInView: true
956
+ enableScrollForNextCalculateItemsInView: true,
957
+ minIndexSizeChanged: 0,
958
+ numPendingInitialLayout: 0,
959
+ queuedCalculateItemsInView: 0,
960
+ lastBatchingAction: Date.now(),
961
+ onScroll: onScrollProp
672
962
  };
673
- refState.current.idsInFirstRender = new Set(data.map((_, i) => getId(i)));
674
- if (maintainVisibleContentPosition) {
675
- if (initialScrollIndex) {
963
+ const dataLength = dataProp.length;
964
+ if (maintainVisibleContentPosition && dataLength > 0) {
965
+ if (initialScrollIndex && initialScrollIndex < dataLength) {
676
966
  refState.current.anchorElement = {
677
967
  coordinate: initialContentOffset,
678
968
  id: getId(initialScrollIndex)
679
969
  };
680
- } else if (data.length) {
970
+ } else if (dataLength > 0) {
681
971
  refState.current.anchorElement = {
682
972
  coordinate: initialContentOffset,
683
973
  id: getId(0)
@@ -690,6 +980,9 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
690
980
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
691
981
  set$(ctx, "extraData", extraData);
692
982
  }
983
+ const didDataChange = refState.current.data !== dataProp;
984
+ refState.current.data = dataProp;
985
+ refState.current.onScroll = onScrollProp;
693
986
  const getAnchorElementIndex = () => {
694
987
  const state = refState.current;
695
988
  if (state.anchorElement) {
@@ -698,12 +991,34 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
698
991
  }
699
992
  return void 0;
700
993
  };
994
+ const setDidLayout = () => {
995
+ var _a2;
996
+ refState.current.queuedInitialLayout = true;
997
+ checkAtBottom();
998
+ if (initialScrollIndex) {
999
+ const updatedOffset = calculateOffsetForIndex(initialScrollIndex);
1000
+ (_a2 = refState.current) == null ? void 0 : _a2.scrollAdjustHandler.setDisableAdjust(true);
1001
+ queueMicrotask(() => {
1002
+ scrollTo(updatedOffset, false);
1003
+ requestAnimationFrame(() => {
1004
+ var _a3;
1005
+ set$(ctx, "containersDidLayout", true);
1006
+ (_a3 = refState.current) == null ? void 0 : _a3.scrollAdjustHandler.setDisableAdjust(false);
1007
+ });
1008
+ });
1009
+ } else {
1010
+ queueMicrotask(() => {
1011
+ set$(ctx, "containersDidLayout", true);
1012
+ });
1013
+ }
1014
+ };
701
1015
  const addTotalSize = useCallback((key, add, totalSizeBelowAnchor) => {
702
1016
  const state = refState.current;
703
- const index = key === null ? 0 : state.indexByKey.get(key);
1017
+ const { indexByKey, anchorElement } = state;
1018
+ const index = key === null ? 0 : indexByKey.get(key);
704
1019
  let isAboveAnchor = false;
705
1020
  if (maintainVisibleContentPosition) {
706
- if (state.anchorElement && index < getAnchorElementIndex()) {
1021
+ if (anchorElement && index < getAnchorElementIndex()) {
707
1022
  isAboveAnchor = true;
708
1023
  }
709
1024
  }
@@ -716,29 +1031,30 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
716
1031
  state.totalSizeBelowAnchor += add;
717
1032
  }
718
1033
  }
719
- let applyAdjustValue = void 0;
720
- if (maintainVisibleContentPosition) {
721
- const newAdjust = state.anchorElement.coordinate - state.totalSizeBelowAnchor;
1034
+ let applyAdjustValue = 0;
1035
+ let resultSize = state.totalSize;
1036
+ if (maintainVisibleContentPosition && anchorElement !== void 0) {
1037
+ const newAdjust = anchorElement.coordinate - state.totalSizeBelowAnchor;
722
1038
  applyAdjustValue = -newAdjust;
723
1039
  state.belowAnchorElementPositions = buildElementPositionsBelowAnchor();
724
1040
  state.rowHeights.clear();
1041
+ if (applyAdjustValue !== void 0) {
1042
+ resultSize -= applyAdjustValue;
1043
+ state.scrollAdjustHandler.requestAdjust(applyAdjustValue, (diff) => {
1044
+ state.scroll -= diff;
1045
+ });
1046
+ }
725
1047
  }
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);
1048
+ set$(ctx, "totalSize", state.totalSize);
1049
+ set$(ctx, "totalSizeWithScrollAdjust", resultSize);
735
1050
  if (alignItemsAtEnd) {
736
1051
  doUpdatePaddingTop();
737
1052
  }
738
1053
  }, []);
739
1054
  const getRowHeight = (n) => {
740
- const { rowHeights } = refState.current;
741
- if (numColumnsProp === 1) {
1055
+ const { rowHeights, data } = refState.current;
1056
+ const numColumns = peek$(ctx, "numColumns");
1057
+ if (numColumns === 1) {
742
1058
  const id = getId(n);
743
1059
  return getItemSize(id, n, data[n]);
744
1060
  }
@@ -746,8 +1062,8 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
746
1062
  return rowHeights.get(n) || 0;
747
1063
  }
748
1064
  let rowHeight = 0;
749
- const startEl = n * numColumnsProp;
750
- for (let i = startEl; i < startEl + numColumnsProp && i < data.length; i++) {
1065
+ const startEl = n * numColumns;
1066
+ for (let i = startEl; i < startEl + numColumns && i < data.length; i++) {
751
1067
  const id = getId(i);
752
1068
  const size = getItemSize(id, i, data[i]);
753
1069
  rowHeight = Math.max(rowHeight, size);
@@ -766,10 +1082,11 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
766
1082
  return /* @__PURE__ */ new Map();
767
1083
  }
768
1084
  const map = state.belowAnchorElementPositions || /* @__PURE__ */ new Map();
1085
+ const numColumns = peek$(ctx, "numColumns");
769
1086
  for (let i = anchorIndex - 1; i >= 0; i--) {
770
1087
  const id = getId(i);
771
- const rowNumber = Math.floor(i / numColumnsProp);
772
- if (i % numColumnsProp === 0) {
1088
+ const rowNumber = Math.floor(i / numColumns);
1089
+ if (i % numColumns === 0) {
773
1090
  top -= getRowHeight(rowNumber);
774
1091
  }
775
1092
  map.set(id, top);
@@ -777,37 +1094,51 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
777
1094
  return map;
778
1095
  };
779
1096
  const getElementPositionBelowAchor = (id) => {
1097
+ var _a2;
780
1098
  const state = refState.current;
781
1099
  if (!refState.current.belowAnchorElementPositions) {
782
1100
  state.belowAnchorElementPositions = buildElementPositionsBelowAnchor();
783
1101
  }
784
1102
  const res = state.belowAnchorElementPositions.get(id);
785
1103
  if (res === void 0) {
786
- throw new Error("Undefined position below achor");
1104
+ console.warn(`Undefined position below achor ${id} ${(_a2 = state.anchorElement) == null ? void 0 : _a2.id}`);
1105
+ return 0;
787
1106
  }
788
1107
  return res;
789
1108
  };
790
- const calculateItemsInView = useCallback((speed) => {
1109
+ const calculateItemsInView = useCallback(() => {
1110
+ var _a2;
791
1111
  const state = refState.current;
792
1112
  const {
793
- data: data2,
1113
+ data,
794
1114
  scrollLength,
795
- scroll: scrollState,
796
1115
  startBufferedId: startBufferedIdOrig,
797
1116
  positions,
798
1117
  columns,
799
- scrollAdjustHandler
1118
+ scrollAdjustHandler,
1119
+ scrollVelocity: speed
800
1120
  } = state;
801
- if (state.waitingForMicrotask) {
802
- state.waitingForMicrotask = false;
803
- }
804
- if (!data2) {
1121
+ if (!data || scrollLength === 0) {
805
1122
  return;
806
1123
  }
1124
+ const totalSize = peek$(ctx, "totalSizeWithScrollAdjust");
807
1125
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
1126
+ const numColumns = peek$(ctx, "numColumns");
808
1127
  const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
809
1128
  const scrollExtra = Math.max(-16, Math.min(16, speed)) * 16;
810
- const scroll = scrollState - previousScrollAdjust - topPad;
1129
+ let scrollState = state.scroll;
1130
+ if (!state.queuedInitialLayout && initialScrollIndex) {
1131
+ const updatedOffset = calculateOffsetForIndex(initialScrollIndex);
1132
+ scrollState = updatedOffset;
1133
+ }
1134
+ let scroll = scrollState - previousScrollAdjust - topPad;
1135
+ if (scroll + scrollLength > totalSize) {
1136
+ scroll = totalSize - scrollLength;
1137
+ }
1138
+ if (ENABLE_DEBUG_VIEW) {
1139
+ set$(ctx, "debugRawScroll", scrollState);
1140
+ set$(ctx, "debugComputedScroll", scroll);
1141
+ }
811
1142
  let scrollBufferTop = scrollBuffer;
812
1143
  let scrollBufferBottom = scrollBuffer;
813
1144
  if (scrollExtra > 8) {
@@ -830,8 +1161,11 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
830
1161
  let startBufferedId = null;
831
1162
  let endNoBuffer = null;
832
1163
  let endBuffered = null;
833
- const originalStartId = startBufferedIdOrig && state.indexByKey.get(startBufferedIdOrig);
834
- let loopStart = originalStartId || 0;
1164
+ let loopStart = startBufferedIdOrig ? state.indexByKey.get(startBufferedIdOrig) || 0 : 0;
1165
+ if (state.minIndexSizeChanged !== void 0) {
1166
+ loopStart = Math.min(state.minIndexSizeChanged, loopStart);
1167
+ state.minIndexSizeChanged = void 0;
1168
+ }
835
1169
  const anchorElementIndex = getAnchorElementIndex();
836
1170
  for (let i = loopStart; i >= 0; i--) {
837
1171
  const id = getId(i);
@@ -844,7 +1178,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
844
1178
  }
845
1179
  const top2 = newPosition || positions.get(id);
846
1180
  if (top2 !== void 0) {
847
- const size = getItemSize(id, i, data2[i]);
1181
+ const size = getItemSize(id, i, data[i]);
848
1182
  const bottom = top2 + size;
849
1183
  if (bottom > scroll - scrollBuffer) {
850
1184
  loopStart = i;
@@ -853,7 +1187,6 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
853
1187
  }
854
1188
  }
855
1189
  }
856
- const numColumns = peek$(ctx, "numColumns");
857
1190
  const loopStartMod = loopStart % numColumns;
858
1191
  if (loopStartMod > 0) {
859
1192
  loopStart -= loopStartMod;
@@ -862,22 +1195,22 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
862
1195
  let column = 1;
863
1196
  let maxSizeInRow = 0;
864
1197
  const getInitialTop = (i) => {
865
- var _a2;
1198
+ var _a3;
866
1199
  const id = getId(i);
867
1200
  let topOffset = 0;
868
1201
  if (positions.get(id)) {
869
1202
  topOffset = positions.get(id);
870
1203
  }
871
- if (id === ((_a2 = state.anchorElement) == null ? void 0 : _a2.id)) {
872
- topOffset = initialContentOffset || 0;
1204
+ if (id === ((_a3 = state.anchorElement) == null ? void 0 : _a3.id)) {
1205
+ topOffset = state.anchorElement.coordinate;
873
1206
  }
874
1207
  return topOffset;
875
1208
  };
876
- for (let i = loopStart; i < data2.length; i++) {
1209
+ for (let i = loopStart; i < data.length; i++) {
877
1210
  const id = getId(i);
878
- const size = getItemSize(id, i, data2[i]);
1211
+ const size = getItemSize(id, i, data[i]);
879
1212
  maxSizeInRow = Math.max(maxSizeInRow, size);
880
- if (top === void 0) {
1213
+ if (top === void 0 || id === ((_a2 = state.anchorElement) == null ? void 0 : _a2.id)) {
881
1214
  top = getInitialTop(i);
882
1215
  }
883
1216
  if (positions.get(id) !== top) {
@@ -930,6 +1263,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
930
1263
  if (startBuffered !== null && endBuffered !== null) {
931
1264
  const prevNumContainers = ctx.values.get("numContainers");
932
1265
  let numContainers = prevNumContainers;
1266
+ let didWarnMoreContainers = false;
933
1267
  for (let i = startBuffered; i <= endBuffered; i++) {
934
1268
  let isContained = false;
935
1269
  const id = getId(i);
@@ -963,18 +1297,19 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
963
1297
  if (furthestIndex >= 0) {
964
1298
  set$(ctx, `containerItemKey${furthestIndex}`, id);
965
1299
  const index = state.indexByKey.get(id);
966
- set$(ctx, `containerItemData${furthestIndex}`, data2[index]);
1300
+ set$(ctx, `containerItemData${furthestIndex}`, data[index]);
967
1301
  } else {
968
1302
  const containerId = numContainers;
969
1303
  numContainers++;
970
1304
  set$(ctx, `containerItemKey${containerId}`, id);
971
1305
  const index = state.indexByKey.get(id);
972
- set$(ctx, `containerItemData${containerId}`, data2[index]);
1306
+ set$(ctx, `containerItemData${containerId}`, data[index]);
973
1307
  set$(ctx, `containerPosition${containerId}`, ANCHORED_POSITION_OUT_OF_VIEW);
974
1308
  set$(ctx, `containerColumn${containerId}`, -1);
975
- if (__DEV__ && numContainers > peek$(ctx, "numContainersPooled")) {
1309
+ if (__DEV__ && !didWarnMoreContainers && numContainers > peek$(ctx, "numContainersPooled")) {
1310
+ didWarnMoreContainers = true;
976
1311
  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:",
1312
+ "[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
1313
  numContainers
979
1314
  );
980
1315
  }
@@ -984,19 +1319,19 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
984
1319
  if (numContainers !== prevNumContainers) {
985
1320
  set$(ctx, "numContainers", numContainers);
986
1321
  if (numContainers > peek$(ctx, "numContainersPooled")) {
987
- set$(ctx, "numContainersPooled", numContainers);
1322
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
988
1323
  }
989
1324
  }
990
1325
  for (let i = 0; i < numContainers; i++) {
991
1326
  const itemKey = peek$(ctx, `containerItemKey${i}`);
992
1327
  const itemIndex = state.indexByKey.get(itemKey);
993
- const item = data2[itemIndex];
994
- if (item) {
1328
+ const item = data[itemIndex];
1329
+ if (item !== void 0) {
995
1330
  const id = getId(itemIndex);
996
1331
  if (itemKey !== id || itemIndex < startBuffered || itemIndex > endBuffered) {
997
1332
  const prevPos = peek$(ctx, `containerPosition${i}`).top;
998
1333
  const pos = positions.get(id) || 0;
999
- const size = getItemSize(id, itemIndex, data2[i]);
1334
+ const size = getItemSize(id, itemIndex, data[i]);
1000
1335
  if (pos + size >= scroll && pos <= scrollBottom || prevPos + size >= scroll && prevPos <= scrollBottom) {
1001
1336
  set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1002
1337
  }
@@ -1008,9 +1343,9 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1008
1343
  };
1009
1344
  const column2 = columns.get(id) || 1;
1010
1345
  if (maintainVisibleContentPosition && itemIndex < anchorElementIndex) {
1011
- const currentRow = Math.floor(itemIndex / numColumnsProp);
1346
+ const currentRow = Math.floor(itemIndex / numColumns);
1012
1347
  const rowHeight = getRowHeight(currentRow);
1013
- const elementHeight = getItemSize(id, itemIndex, data2[i]);
1348
+ const elementHeight = getItemSize(id, itemIndex, data[i]);
1014
1349
  const diff = rowHeight - elementHeight;
1015
1350
  pos.relativeCoordinate = pos.top + getRowHeight(currentRow) - diff;
1016
1351
  pos.type = "bottom";
@@ -1025,13 +1360,25 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1025
1360
  set$(ctx, `containerColumn${i}`, column2);
1026
1361
  }
1027
1362
  if (prevData !== item) {
1028
- set$(ctx, `containerItemData${i}`, data2[itemIndex]);
1363
+ set$(ctx, `containerItemData${i}`, data[itemIndex]);
1029
1364
  }
1030
1365
  }
1031
1366
  }
1032
1367
  }
1033
1368
  }
1034
- set$(ctx, "containersDidLayout", true);
1369
+ if (state.numPendingInitialLayout === 0) {
1370
+ state.numPendingInitialLayout = state.endBuffered - state.startBuffered + 1;
1371
+ }
1372
+ if (!state.queuedInitialLayout && endBuffered !== null) {
1373
+ let areAllKnown = true;
1374
+ for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
1375
+ const key = getId(i);
1376
+ areAllKnown && (areAllKnown = state.sizesKnown.has(key));
1377
+ }
1378
+ if (areAllKnown) {
1379
+ setDidLayout();
1380
+ }
1381
+ }
1035
1382
  if (state.viewabilityConfigCallbackPairs) {
1036
1383
  updateViewableItems(
1037
1384
  state,
@@ -1046,16 +1393,27 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1046
1393
  }, []);
1047
1394
  const doUpdatePaddingTop = () => {
1048
1395
  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));
1396
+ const { scrollLength } = refState.current;
1397
+ const contentSize = getContentSize(ctx);
1398
+ const paddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1052
1399
  set$(ctx, "paddingTop", paddingTop);
1053
1400
  }
1054
1401
  };
1402
+ const scrollTo = (offset, animated) => {
1403
+ var _a2;
1404
+ (_a2 = refScroller.current) == null ? void 0 : _a2.scrollTo({
1405
+ x: horizontal ? offset : 0,
1406
+ y: horizontal ? 0 : offset,
1407
+ animated: !!animated
1408
+ });
1409
+ };
1055
1410
  const doMaintainScrollAtEnd = (animated) => {
1056
1411
  const state = refState.current;
1057
- if ((state == null ? void 0 : state.isAtBottom) && maintainScrollAtEnd) {
1058
- state.scroll = state.totalSize - state.scrollLength + peek$(ctx, "paddingTop");
1412
+ if ((state == null ? void 0 : state.isAtBottom) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
1413
+ const paddingTop = peek$(ctx, "paddingTop") || 0;
1414
+ if (paddingTop > 0) {
1415
+ state.scroll = 0;
1416
+ }
1059
1417
  requestAnimationFrame(() => {
1060
1418
  var _a2;
1061
1419
  (_a2 = refScroller.current) == null ? void 0 : _a2.scrollToEnd({
@@ -1065,28 +1423,50 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1065
1423
  return true;
1066
1424
  }
1067
1425
  };
1426
+ const checkThreshold = (distance, atThreshold, threshold, isReached, isBlockedByTimer, onReached, blockTimer) => {
1427
+ const distanceAbs = Math.abs(distance);
1428
+ const isAtThreshold = atThreshold || distanceAbs < threshold;
1429
+ if (!isReached && !isBlockedByTimer) {
1430
+ if (isAtThreshold) {
1431
+ onReached == null ? void 0 : onReached(distance);
1432
+ blockTimer == null ? void 0 : blockTimer(true);
1433
+ setTimeout(() => {
1434
+ blockTimer == null ? void 0 : blockTimer(false);
1435
+ }, 700);
1436
+ return true;
1437
+ }
1438
+ } else {
1439
+ if (distance >= 1.3 * threshold) {
1440
+ return false;
1441
+ }
1442
+ }
1443
+ return isReached;
1444
+ };
1068
1445
  const checkAtBottom = () => {
1069
1446
  if (!refState.current) {
1070
1447
  return;
1071
1448
  }
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
- }
1449
+ const { queuedInitialLayout, scrollLength, scroll } = refState.current;
1450
+ const contentSize = getContentSize(ctx);
1451
+ if (contentSize > 0 && queuedInitialLayout) {
1452
+ const distanceFromEnd = contentSize - scroll - scrollLength;
1453
+ const distanceFromEndAbs = Math.abs(distanceFromEnd);
1454
+ const isContentLess = contentSize < scrollLength;
1455
+ refState.current.isAtBottom = isContentLess || distanceFromEndAbs < scrollLength * maintainScrollAtEndThreshold;
1456
+ refState.current.isEndReached = checkThreshold(
1457
+ distanceFromEnd,
1458
+ isContentLess,
1459
+ onEndReachedThreshold * scrollLength,
1460
+ refState.current.isEndReached,
1461
+ refState.current.endReachedBlockedByTimer,
1462
+ (distance) => {
1463
+ var _a2, _b2;
1464
+ return (_b2 = (_a2 = callbacks.current).onEndReached) == null ? void 0 : _b2.call(_a2, { distanceFromEnd: distance });
1465
+ },
1466
+ (block) => {
1467
+ refState.current.endReachedBlockedByTimer = block;
1088
1468
  }
1089
- }
1469
+ );
1090
1470
  }
1091
1471
  };
1092
1472
  const checkAtTop = () => {
@@ -1095,112 +1475,119 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1095
1475
  }
1096
1476
  const { scrollLength, scroll } = refState.current;
1097
1477
  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
- }
1478
+ const distanceFromTopAbs = Math.abs(distanceFromTop);
1479
+ refState.current.isAtTop = distanceFromTopAbs < 0;
1480
+ refState.current.isStartReached = checkThreshold(
1481
+ distanceFromTop,
1482
+ false,
1483
+ onStartReachedThreshold * scrollLength,
1484
+ refState.current.isStartReached,
1485
+ refState.current.startReachedBlockedByTimer,
1486
+ (distance) => {
1487
+ var _a2, _b2;
1488
+ return (_b2 = (_a2 = callbacks.current).onStartReached) == null ? void 0 : _b2.call(_a2, { distanceFromStart: distance });
1489
+ },
1490
+ (block) => {
1491
+ refState.current.startReachedBlockedByTimer = block;
1113
1492
  }
1114
- }
1493
+ );
1115
1494
  };
1116
- const checkResetContainers = (reset) => {
1495
+ const checkResetContainers = (isFirst2) => {
1117
1496
  const state = refState.current;
1118
1497
  if (state) {
1119
- state.data = data;
1120
- if (reset) {
1498
+ state.data = dataProp;
1499
+ if (!isFirst2) {
1121
1500
  refState.current.scrollForNextCalculateItemsInView = void 0;
1122
1501
  const numContainers = peek$(ctx, "numContainers");
1123
1502
  for (let i = 0; i < numContainers; i++) {
1124
1503
  const itemKey = peek$(ctx, `containerItemKey${i}`);
1125
1504
  if (!keyExtractorProp || itemKey && state.indexByKey.get(itemKey) === void 0) {
1126
1505
  set$(ctx, `containerItemKey${i}`, void 0);
1506
+ set$(ctx, `containerItemData${i}`, void 0);
1127
1507
  set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1128
1508
  set$(ctx, `containerColumn${i}`, -1);
1129
1509
  }
1130
1510
  }
1131
1511
  if (!keyExtractorProp) {
1132
- state.sizes.clear();
1133
1512
  state.positions.clear();
1134
1513
  }
1135
- calculateItemsInView(state.scrollVelocity);
1136
- }
1137
- const didMaintainScrollAtEnd = doMaintainScrollAtEnd(false);
1138
- if (!didMaintainScrollAtEnd && data.length > state.data.length) {
1139
- state.isEndReached = false;
1514
+ calculateItemsInView();
1515
+ const didMaintainScrollAtEnd = doMaintainScrollAtEnd(false);
1516
+ if (!didMaintainScrollAtEnd && dataProp.length > state.data.length) {
1517
+ state.isEndReached = false;
1518
+ }
1519
+ checkAtTop();
1520
+ checkAtBottom();
1140
1521
  }
1141
- checkAtTop();
1142
- checkAtBottom();
1143
1522
  }
1144
1523
  };
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;
1524
+ const calcTotalSizesAndPositions = ({ forgetPositions = false }) => {
1525
+ var _a2, _b2;
1152
1526
  let totalSize = 0;
1153
1527
  let totalSizeBelowIndex = 0;
1154
1528
  const indexByKey = /* @__PURE__ */ new Map();
1155
1529
  const newPositions = /* @__PURE__ */ new Map();
1156
1530
  let column = 1;
1157
1531
  let maxSizeInRow = 0;
1158
- for (let i = 0; i < data.length; i++) {
1532
+ const numColumns = (_a2 = peek$(ctx, "numColumns")) != null ? _a2 : numColumnsProp;
1533
+ if (!refState.current) {
1534
+ return;
1535
+ }
1536
+ for (let i = 0; i < dataProp.length; i++) {
1159
1537
  const key = getId(i);
1538
+ if (__DEV__) {
1539
+ if (indexByKey.has(key)) {
1540
+ console.error(
1541
+ `[legend-list] Error: Detected overlapping key (${key}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
1542
+ );
1543
+ }
1544
+ }
1160
1545
  indexByKey.set(key, i);
1161
- if (refState.current.positions.get(key) != null && refState.current.indexByKey.get(key) === i) {
1546
+ if (!forgetPositions && refState.current.positions.get(key) != null && refState.current.indexByKey.get(key) === i) {
1162
1547
  newPositions.set(key, refState.current.positions.get(key));
1163
1548
  }
1164
1549
  }
1165
1550
  refState.current.indexByKey = indexByKey;
1166
1551
  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 });
1552
+ if (!forgetPositions && !isFirst) {
1553
+ if (maintainVisibleContentPosition) {
1554
+ if (refState.current.anchorElement == null || indexByKey.get(refState.current.anchorElement.id) == null) {
1555
+ if (dataProp.length) {
1556
+ const newAnchorElement = {
1557
+ coordinate: 0,
1558
+ id: getId(0)
1559
+ };
1560
+ refState.current.anchorElement = newAnchorElement;
1561
+ (_b2 = refState.current.belowAnchorElementPositions) == null ? void 0 : _b2.clear();
1562
+ scrollTo(0, false);
1563
+ setTimeout(() => {
1564
+ calculateItemsInView();
1565
+ }, 0);
1566
+ } else {
1567
+ refState.current.startBufferedId = void 0;
1568
+ }
1569
+ }
1570
+ } else {
1571
+ if (refState.current.startBufferedId != null && newPositions.get(refState.current.startBufferedId) == null) {
1572
+ if (dataProp.length) {
1573
+ refState.current.startBufferedId = getId(0);
1574
+ } else {
1575
+ refState.current.startBufferedId = void 0;
1576
+ }
1577
+ scrollTo(0, false);
1177
1578
  setTimeout(() => {
1178
- calculateItemsInView(0);
1579
+ calculateItemsInView();
1179
1580
  }, 0);
1180
- } else {
1181
- refState.current.startBufferedId = void 0;
1182
1581
  }
1183
1582
  }
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
1583
  }
1197
1584
  const anchorElementIndex = getAnchorElementIndex();
1198
- for (let i = 0; i < data.length; i++) {
1585
+ for (let i = 0; i < dataProp.length; i++) {
1199
1586
  const key = getId(i);
1200
- const size = getItemSize(key, i, data[i]);
1587
+ const size = getItemSize(key, i, dataProp[i]);
1201
1588
  maxSizeInRow = Math.max(maxSizeInRow, size);
1202
1589
  column++;
1203
- if (column > numColumnsProp) {
1590
+ if (column > numColumns) {
1204
1591
  if (maintainVisibleContentPosition && anchorElementIndex !== void 0 && i < anchorElementIndex) {
1205
1592
  totalSizeBelowIndex += maxSizeInRow;
1206
1593
  }
@@ -1212,111 +1599,172 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1212
1599
  if (maxSizeInRow > 0) {
1213
1600
  totalSize += maxSizeInRow;
1214
1601
  }
1602
+ const state = refState.current;
1603
+ state.ignoreScrollFromCalcTotal = true;
1604
+ requestAnimationFrame(() => {
1605
+ state.ignoreScrollFromCalcTotal = false;
1606
+ });
1215
1607
  addTotalSize(null, totalSize, totalSizeBelowIndex);
1216
- }
1217
- useEffect(() => {
1218
- checkResetContainers(
1219
- /*reset*/
1220
- !isFirst
1608
+ };
1609
+ const isFirst = !refState.current.renderItem;
1610
+ const memoizedLastItemKeys = useMemo(() => {
1611
+ if (!dataProp.length) return [];
1612
+ return Array.from(
1613
+ { length: Math.min(numColumnsProp, dataProp.length) },
1614
+ (_, i) => getId(dataProp.length - 1 - i)
1221
1615
  );
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;
1616
+ }, [dataProp, numColumnsProp]);
1617
+ 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;
1229
1618
  const initalizeStateVars = () => {
1230
- set$(ctx, "lastItemKey", lastItemKey);
1619
+ set$(ctx, "lastItemKeys", memoizedLastItemKeys);
1231
1620
  set$(ctx, "numColumns", numColumnsProp);
1232
- set$(ctx, "stylePaddingTop", stylePaddingTop);
1621
+ if (maintainVisibleContentPosition) {
1622
+ const prevPaddingTop = peek$(ctx, "stylePaddingTop");
1623
+ const paddingDiff = stylePaddingTop - prevPaddingTop;
1624
+ if (paddingDiff) {
1625
+ scrollTo(refState.current.scroll + paddingDiff, false);
1626
+ }
1627
+ set$(ctx, "stylePaddingTop", stylePaddingTop);
1628
+ }
1233
1629
  };
1234
1630
  if (isFirst) {
1235
1631
  initalizeStateVars();
1236
1632
  }
1237
- useEffect(initalizeStateVars, [lastItemKey, numColumnsProp, stylePaddingTop]);
1633
+ if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
1634
+ refState.current.lastBatchingAction = Date.now();
1635
+ if (!keyExtractorProp && !isFirst && didDataChange) {
1636
+ refState.current.sizes.clear();
1637
+ refState.current.positions.clear();
1638
+ }
1639
+ calcTotalSizesAndPositions({ forgetPositions: false });
1640
+ }
1641
+ useEffect(() => {
1642
+ const didAllocateContainers = doInitialAllocateContainers();
1643
+ if (!didAllocateContainers) {
1644
+ checkResetContainers(
1645
+ /*isFirst*/
1646
+ isFirst
1647
+ );
1648
+ }
1649
+ }, [isFirst, dataProp, numColumnsProp]);
1650
+ useEffect(() => {
1651
+ set$(ctx, "extraData", extraData);
1652
+ }, [extraData]);
1653
+ refState.current.renderItem = renderItem;
1654
+ useEffect(initalizeStateVars, [memoizedLastItemKeys.join(","), numColumnsProp, stylePaddingTop]);
1238
1655
  const getRenderedItem = useCallback((key) => {
1239
1656
  var _a2, _b2;
1240
1657
  const state = refState.current;
1241
1658
  if (!state) {
1242
1659
  return null;
1243
1660
  }
1244
- const { data: data2, indexByKey } = state;
1661
+ const { data, indexByKey } = state;
1245
1662
  const index = indexByKey.get(key);
1246
1663
  if (index === void 0) {
1247
1664
  return null;
1248
1665
  }
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
- };
1666
+ const useViewability2 = __DEV__ ? (configId, callback) => {
1667
+ console.warn(
1668
+ `[legend-list] useViewability has been moved from a render prop to a regular import: import { useViewability } from "@legendapp/list";`
1669
+ );
1670
+ } : void 0;
1671
+ const useViewabilityAmount2 = __DEV__ ? (callback) => {
1672
+ console.warn(
1673
+ `[legend-list] useViewabilityAmount has been moved from a render prop to a regular import: import { useViewabilityAmount } from "@legendapp/list";`
1674
+ );
1675
+ } : void 0;
1676
+ const useRecyclingEffect2 = __DEV__ ? (effect) => {
1677
+ console.warn(
1678
+ `[legend-list] useRecyclingEffect has been moved from a render prop to a regular import: import { useRecyclingEffect } from "@legendapp/list";`
1679
+ );
1680
+ } : void 0;
1681
+ const useRecyclingState2 = __DEV__ ? (valueOrFun) => {
1682
+ console.warn(
1683
+ `[legend-list] useRecyclingState has been moved from a render prop to a regular import: import { useRecyclingState } from "@legendapp/list";`
1684
+ );
1685
+ } : void 0;
1261
1686
  const renderedItem = (_b2 = (_a2 = refState.current).renderItem) == null ? void 0 : _b2.call(_a2, {
1262
- item: data2[index],
1687
+ item: data[index],
1263
1688
  index,
1689
+ extraData: peek$(ctx, "extraData"),
1690
+ // @ts-expect-error TODO: Remove these before 1.0
1264
1691
  useViewability: useViewability2,
1265
1692
  useViewabilityAmount: useViewabilityAmount2,
1266
1693
  useRecyclingEffect: useRecyclingEffect2,
1267
1694
  useRecyclingState: useRecyclingState2
1268
1695
  });
1269
- return { index, renderedItem };
1696
+ return { index, item: data[index], renderedItem };
1270
1697
  }, []);
1271
- useInit(() => {
1698
+ const doInitialAllocateContainers = () => {
1272
1699
  var _a2;
1273
1700
  const state = refState.current;
1274
- const viewability = setupViewability(props);
1701
+ const { scrollLength, data } = state;
1702
+ if (scrollLength > 0 && data.length > 0 && !peek$(ctx, "numContainers")) {
1703
+ const averageItemSize = (_a2 = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, data[0])) != null ? _a2 : DEFAULT_ITEM_SIZE;
1704
+ const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) * numColumnsProp;
1705
+ for (let i = 0; i < numContainers; i++) {
1706
+ set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1707
+ set$(ctx, `containerColumn${i}`, -1);
1708
+ }
1709
+ set$(ctx, "numContainers", numContainers);
1710
+ set$(ctx, "numContainersPooled", numContainers * initialContainerPoolRatio);
1711
+ if (initialScrollIndex) {
1712
+ requestAnimationFrame(() => {
1713
+ calculateItemsInView();
1714
+ });
1715
+ } else {
1716
+ calculateItemsInView();
1717
+ }
1718
+ return true;
1719
+ }
1720
+ };
1721
+ useEffect(() => {
1722
+ const state = refState.current;
1723
+ const viewability = setupViewability({
1724
+ viewabilityConfig,
1725
+ viewabilityConfigCallbackPairs,
1726
+ onViewableItemsChanged
1727
+ });
1275
1728
  state.viewabilityConfigCallbackPairs = viewability;
1276
1729
  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);
1730
+ }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
1731
+ useInit(() => {
1732
+ doInitialAllocateContainers();
1287
1733
  });
1288
- const updateItemSize = useCallback((containerId, itemKey, size) => {
1289
- var _a2;
1290
- const data2 = (_a2 = refState.current) == null ? void 0 : _a2.data;
1291
- if (!data2) {
1734
+ const updateItemSize = useCallback((itemKey, size) => {
1735
+ const state = refState.current;
1736
+ const { sizes, indexByKey, sizesKnown, data, rowHeights } = state;
1737
+ if (!data) {
1292
1738
  return;
1293
1739
  }
1294
- const state = refState.current;
1295
- const { sizes, indexByKey, columns, sizesLaidOut } = state;
1296
1740
  const index = indexByKey.get(itemKey);
1297
1741
  const numColumns = peek$(ctx, "numColumns");
1298
- const row = Math.floor(index / numColumns);
1299
- const prevSize = getRowHeight(row);
1742
+ state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, index) : index;
1743
+ const prevSize = getItemSize(itemKey, index, data);
1744
+ let needsCalculate = false;
1745
+ if (state.numPendingInitialLayout > 0) {
1746
+ state.numPendingInitialLayout--;
1747
+ if (state.numPendingInitialLayout === 0) {
1748
+ needsCalculate = true;
1749
+ state.numPendingInitialLayout = -1;
1750
+ }
1751
+ }
1752
+ sizesKnown == null ? void 0 : sizesKnown.set(itemKey, size);
1300
1753
  if (!prevSize || Math.abs(prevSize - size) > 0.5) {
1301
1754
  let diff;
1755
+ needsCalculate = true;
1302
1756
  if (numColumns > 1) {
1303
- const prevMaxSizeInRow = getRowHeight(row);
1757
+ const rowNumber = Math.floor(index / numColumnsProp);
1758
+ const prevSizeInRow = getRowHeight(rowNumber);
1304
1759
  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;
1760
+ rowHeights.delete(rowNumber);
1761
+ const sizeInRow = getRowHeight(rowNumber);
1762
+ diff = sizeInRow - prevSizeInRow;
1314
1763
  } else {
1315
1764
  sizes.set(itemKey, size);
1316
1765
  diff = size - prevSize;
1317
1766
  }
1318
1767
  if (__DEV__ && !estimatedItemSize && !getEstimatedItemSize) {
1319
- sizesLaidOut.set(itemKey, size);
1320
1768
  if (state.timeoutSizeMessage) {
1321
1769
  clearTimeout(state.timeoutSizeMessage);
1322
1770
  }
@@ -1324,7 +1772,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1324
1772
  state.timeoutSizeMessage = void 0;
1325
1773
  let total = 0;
1326
1774
  let num = 0;
1327
- for (const [key, size2] of sizesLaidOut) {
1775
+ for (const [_, size2] of sizesKnown) {
1328
1776
  num++;
1329
1777
  total += size2;
1330
1778
  }
@@ -1336,38 +1784,48 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1336
1784
  }
1337
1785
  refState.current.scrollForNextCalculateItemsInView = void 0;
1338
1786
  addTotalSize(itemKey, diff, 0);
1339
- doMaintainScrollAtEnd(true);
1787
+ doMaintainScrollAtEnd(false);
1788
+ if (onItemSizeChanged) {
1789
+ onItemSizeChanged({
1790
+ size,
1791
+ previous: prevSize,
1792
+ index,
1793
+ itemKey,
1794
+ itemData: data[index]
1795
+ });
1796
+ }
1797
+ }
1798
+ if (needsCalculate) {
1340
1799
  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
- });
1800
+ if ((Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1) && (!waitForInitialLayout || state.numPendingInitialLayout < 0)) {
1801
+ if (Date.now() - state.lastBatchingAction < 500) {
1802
+ if (!state.queuedCalculateItemsInView) {
1803
+ state.queuedCalculateItemsInView = requestAnimationFrame(() => {
1804
+ state.queuedCalculateItemsInView = void 0;
1805
+ calculateItemsInView();
1806
+ });
1807
+ }
1350
1808
  } else {
1351
- calculateItemsInView(state.scrollVelocity);
1809
+ calculateItemsInView();
1352
1810
  }
1353
1811
  }
1354
- if (onItemSizeChanged) {
1355
- onItemSizeChanged({ size, previous: prevSize, index, itemKey, itemData: data2[index] });
1356
- }
1357
1812
  }
1358
1813
  }, []);
1359
- const handleScrollDebounced = useCallback((velocity) => {
1360
- calculateItemsInView(velocity);
1361
- checkAtBottom();
1362
- checkAtTop();
1363
- }, []);
1364
1814
  const onLayout = useCallback((event) => {
1815
+ const state = refState.current;
1365
1816
  const scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
1366
- refState.current.scrollLength = scrollLength;
1817
+ const didChange = scrollLength !== state.scrollLength;
1818
+ state.scrollLength = scrollLength;
1819
+ state.lastBatchingAction = Date.now();
1820
+ state.scrollForNextCalculateItemsInView = void 0;
1821
+ doInitialAllocateContainers();
1367
1822
  doMaintainScrollAtEnd(false);
1368
1823
  doUpdatePaddingTop();
1369
1824
  checkAtBottom();
1370
1825
  checkAtTop();
1826
+ if (didChange) {
1827
+ calculateItemsInView();
1828
+ }
1371
1829
  if (__DEV__) {
1372
1830
  const isWidthZero = event.nativeEvent.layout.width === 0;
1373
1831
  const isHeightZero = event.nativeEvent.layout.height === 0;
@@ -1377,17 +1835,24 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1377
1835
  );
1378
1836
  }
1379
1837
  }
1838
+ if (onLayoutProp) {
1839
+ onLayoutProp(event);
1840
+ }
1380
1841
  }, []);
1381
1842
  const handleScroll = useCallback(
1382
1843
  (event, fromSelf) => {
1383
- var _a2, _b2, _c2;
1844
+ var _a2, _b2, _c2, _d2;
1384
1845
  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
1846
  return;
1386
1847
  }
1387
1848
  const state = refState.current;
1849
+ const newScroll = event.nativeEvent.contentOffset[horizontal ? "x" : "y"];
1850
+ if (state.ignoreScrollFromCalcTotal && newScroll !== 0) {
1851
+ return;
1852
+ }
1388
1853
  state.hasScrolled = true;
1854
+ state.lastBatchingAction = Date.now();
1389
1855
  const currentTime = performance.now();
1390
- const newScroll = event.nativeEvent.contentOffset[horizontal ? "x" : "y"];
1391
1856
  if (!(state.scrollHistory.length === 0 && newScroll === initialContentOffset)) {
1392
1857
  state.scrollHistory.push({ scroll: newScroll, time: currentTime });
1393
1858
  }
@@ -1413,9 +1878,11 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1413
1878
  state.scroll = newScroll;
1414
1879
  state.scrollTime = currentTime;
1415
1880
  state.scrollVelocity = velocity;
1416
- handleScrollDebounced(velocity);
1881
+ calculateItemsInView();
1882
+ checkAtBottom();
1883
+ checkAtTop();
1417
1884
  if (!fromSelf) {
1418
- onScrollProp == null ? void 0 : onScrollProp(event);
1885
+ (_d2 = state.onScroll) == null ? void 0 : _d2.call(state, event);
1419
1886
  }
1420
1887
  },
1421
1888
  []
@@ -1423,61 +1890,157 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1423
1890
  useImperativeHandle(
1424
1891
  forwardedRef,
1425
1892
  () => {
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 });
1893
+ const scrollToIndex = ({
1894
+ index,
1895
+ viewOffset = 0,
1896
+ animated = true,
1897
+ viewPosition = 0
1898
+ }) => {
1899
+ var _a2;
1900
+ const state = refState.current;
1901
+ const firstIndexOffset = calculateOffsetForIndex(index);
1902
+ let firstIndexScrollPostion = firstIndexOffset - viewOffset;
1903
+ const diff = Math.abs(state.scroll - firstIndexScrollPostion);
1904
+ const needsReanchoring = maintainVisibleContentPosition && diff > 100;
1905
+ state.scrollForNextCalculateItemsInView = void 0;
1906
+ if (needsReanchoring) {
1907
+ const id = getId(index);
1908
+ state.anchorElement = { id, coordinate: firstIndexOffset };
1909
+ (_a2 = state.belowAnchorElementPositions) == null ? void 0 : _a2.clear();
1910
+ state.positions.clear();
1911
+ calcTotalSizesAndPositions({ forgetPositions: true });
1912
+ state.startBufferedId = id;
1913
+ state.minIndexSizeChanged = index;
1914
+ firstIndexScrollPostion = firstIndexOffset - viewOffset + state.scrollAdjustHandler.getAppliedAdjust();
1915
+ }
1916
+ if (viewPosition) {
1917
+ firstIndexScrollPostion -= viewPosition * (state.scrollLength - getItemSize(getId(index), index, state.data[index]));
1918
+ }
1919
+ state.scrollAdjustHandler.setDisableAdjust(true);
1920
+ state.scrollingToOffset = firstIndexScrollPostion;
1921
+ scrollTo(firstIndexScrollPostion, animated);
1922
+ };
1923
+ const scrollIndexIntoView = (options) => {
1924
+ if (refState.current) {
1925
+ const { index, ...rest2 } = options;
1926
+ const { startNoBuffer, endNoBuffer } = refState.current;
1927
+ if (index < startNoBuffer || index > endNoBuffer) {
1928
+ const viewPosition = index < startNoBuffer ? 0 : 1;
1929
+ scrollToIndex({
1930
+ ...rest2,
1931
+ viewPosition,
1932
+ index
1933
+ });
1934
+ }
1935
+ }
1430
1936
  };
1431
1937
  return {
1938
+ flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
1432
1939
  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 });
1940
+ getScrollableNode: () => refScroller.current.getScrollableNode(),
1941
+ getScrollResponder: () => refScroller.current.getScrollResponder(),
1942
+ getState: () => {
1943
+ const state = refState.current;
1944
+ return state ? {
1945
+ contentLength: state.totalSize,
1946
+ end: state.endNoBuffer,
1947
+ endBuffered: state.endBuffered,
1948
+ isAtEnd: state.isAtBottom,
1949
+ isAtStart: state.isAtTop,
1950
+ scroll: state.scroll,
1951
+ scrollLength: state.scrollLength,
1952
+ start: state.startNoBuffer,
1953
+ startBuffered: state.startBuffered
1954
+ } : {};
1440
1955
  },
1441
- scrollToItem: ({ item, animated }) => {
1956
+ scrollIndexIntoView,
1957
+ scrollItemIntoView: ({ item, ...props2 }) => {
1958
+ const { data } = refState.current;
1442
1959
  const index = data.indexOf(item);
1443
1960
  if (index !== -1) {
1444
- scrollToIndex({ index, animated });
1961
+ scrollIndexIntoView({ index, ...props2 });
1445
1962
  }
1446
1963
  },
1447
- scrollToEnd: refScroller.current.scrollToEnd
1964
+ scrollToIndex,
1965
+ scrollToItem: ({ item, ...props2 }) => {
1966
+ const { data } = refState.current;
1967
+ const index = data.indexOf(item);
1968
+ if (index !== -1) {
1969
+ scrollToIndex({ index, ...props2 });
1970
+ }
1971
+ },
1972
+ scrollToOffset: ({ offset, animated }) => {
1973
+ scrollTo(offset, animated);
1974
+ },
1975
+ scrollToEnd: (options) => refScroller.current.scrollToEnd(options)
1448
1976
  };
1449
1977
  },
1450
1978
  []
1451
1979
  );
1452
- return /* @__PURE__ */ React5.createElement(
1980
+ if (Platform.OS === "web") {
1981
+ useEffect(() => {
1982
+ var _a2;
1983
+ if (initialContentOffset) {
1984
+ (_a2 = refState.current) == null ? void 0 : _a2.scrollAdjustHandler.setDisableAdjust(true);
1985
+ scrollTo(initialContentOffset, false);
1986
+ setTimeout(() => {
1987
+ var _a3;
1988
+ (_a3 = refState.current) == null ? void 0 : _a3.scrollAdjustHandler.setDisableAdjust(false);
1989
+ }, 0);
1990
+ }
1991
+ }, []);
1992
+ }
1993
+ return /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(
1453
1994
  ListComponent,
1454
1995
  {
1455
1996
  ...rest,
1456
1997
  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
- },
1998
+ refScrollView: combinedRef,
1467
1999
  initialContentOffset,
1468
2000
  getRenderedItem,
1469
2001
  updateItemSize,
1470
2002
  handleScroll,
2003
+ onMomentumScrollEnd: (event) => {
2004
+ var _a2;
2005
+ const scrollingToOffset = (_a2 = refState.current) == null ? void 0 : _a2.scrollingToOffset;
2006
+ if (scrollingToOffset !== void 0) {
2007
+ requestAnimationFrame(() => {
2008
+ scrollTo(scrollingToOffset, false);
2009
+ refState.current.scrollingToOffset = void 0;
2010
+ requestAnimationFrame(() => {
2011
+ refState.current.scrollAdjustHandler.setDisableAdjust(false);
2012
+ });
2013
+ });
2014
+ }
2015
+ const wasPaused = refState.current.scrollAdjustHandler.unPauseAdjust();
2016
+ if (wasPaused) {
2017
+ refState.current.scrollVelocity = 0;
2018
+ refState.current.scrollHistory = [];
2019
+ calculateItemsInView();
2020
+ }
2021
+ if (onMomentumScrollEnd) {
2022
+ onMomentumScrollEnd(event);
2023
+ }
2024
+ },
1471
2025
  onLayout,
1472
2026
  recycleItems,
1473
2027
  alignItemsAtEnd,
1474
- ListEmptyComponent: data.length === 0 ? ListEmptyComponent : void 0,
2028
+ ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
1475
2029
  maintainVisibleContentPosition,
1476
2030
  scrollEventThrottle: scrollEventThrottle != null ? scrollEventThrottle : Platform.OS === "web" ? 16 : void 0,
1477
2031
  waitForInitialLayout,
1478
- style
2032
+ refreshControl: refreshControl != null ? refreshControl : onRefresh && /* @__PURE__ */ React6.createElement(
2033
+ RefreshControl,
2034
+ {
2035
+ refreshing: !!refreshing,
2036
+ onRefresh,
2037
+ progressViewOffset
2038
+ }
2039
+ ),
2040
+ style,
2041
+ contentContainerStyle
1479
2042
  }
1480
- );
2043
+ ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React6.createElement(DebugView, { state: refState.current }));
1481
2044
  });
1482
2045
 
1483
2046
  export { LegendList, useRecyclingEffect, useRecyclingState, useViewability, useViewabilityAmount };