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