@legendapp/list 1.0.0-beta.5 → 1.0.0-beta.50

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