@legendapp/list 1.1.4 → 2.0.0-next.1

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.
Files changed (5) hide show
  1. package/index.d.mts +107 -58
  2. package/index.d.ts +107 -58
  3. package/index.js +1586 -1692
  4. package/index.mjs +1552 -1658
  5. package/package.json +1 -1
package/index.js CHANGED
@@ -1,9 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var React2 = require('react');
3
+ var React3 = require('react');
4
4
  var reactNative = require('react-native');
5
5
  var shim = require('use-sync-external-store/shim');
6
- var list = require('@legendapp/list');
7
6
 
8
7
  function _interopNamespace(e) {
9
8
  if (e && e.__esModule) return e;
@@ -23,15 +22,14 @@ function _interopNamespace(e) {
23
22
  return Object.freeze(n);
24
23
  }
25
24
 
26
- var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
25
+ var React3__namespace = /*#__PURE__*/_interopNamespace(React3);
27
26
 
28
27
  // src/LegendList.tsx
29
- var ContextState = React2__namespace.createContext(null);
28
+ var ContextState = React3__namespace.createContext(null);
30
29
  function StateProvider({ children }) {
31
- const [value] = React2__namespace.useState(() => ({
30
+ const [value] = React3__namespace.useState(() => ({
32
31
  listeners: /* @__PURE__ */ new Map(),
33
32
  values: /* @__PURE__ */ new Map([
34
- ["paddingTop", 0],
35
33
  ["alignItemsPaddingTop", 0],
36
34
  ["stylePaddingTop", 0],
37
35
  ["headerSize", 0]
@@ -43,10 +41,10 @@ function StateProvider({ children }) {
43
41
  columnWrapperStyle: void 0,
44
42
  viewRefs: /* @__PURE__ */ new Map()
45
43
  }));
46
- return /* @__PURE__ */ React2__namespace.createElement(ContextState.Provider, { value }, children);
44
+ return /* @__PURE__ */ React3__namespace.createElement(ContextState.Provider, { value }, children);
47
45
  }
48
46
  function useStateContext() {
49
- return React2__namespace.useContext(ContextState);
47
+ return React3__namespace.useContext(ContextState);
50
48
  }
51
49
  function createSelectorFunctionsArr(ctx, signalNames) {
52
50
  let lastValues = [];
@@ -116,35 +114,26 @@ function getContentSize(ctx) {
116
114
  return headerSize + footerSize + totalSize + stylePaddingTop;
117
115
  }
118
116
  function useArr$(signalNames) {
119
- const ctx = React2__namespace.useContext(ContextState);
120
- const { subscribe, get } = React2__namespace.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
117
+ const ctx = React3__namespace.useContext(ContextState);
118
+ const { subscribe, get } = React3__namespace.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
121
119
  const value = shim.useSyncExternalStore(subscribe, get);
122
120
  return value;
123
121
  }
124
122
  function useSelector$(signalName, selector) {
125
- const ctx = React2__namespace.useContext(ContextState);
126
- const { subscribe, get } = React2__namespace.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
123
+ const ctx = React3__namespace.useContext(ContextState);
124
+ const { subscribe, get } = React3__namespace.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
127
125
  const value = shim.useSyncExternalStore(subscribe, () => selector(get()[0]));
128
126
  return value;
129
127
  }
130
128
 
131
129
  // src/DebugView.tsx
132
130
  var DebugRow = ({ children }) => {
133
- return /* @__PURE__ */ React2__namespace.createElement(reactNative.View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" } }, children);
131
+ return /* @__PURE__ */ React3__namespace.createElement(reactNative.View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" } }, children);
134
132
  };
135
- var DebugView = React2__namespace.memo(function DebugView2({ state }) {
133
+ var DebugView = React3__namespace.memo(function DebugView2({ state }) {
136
134
  const ctx = useStateContext();
137
- const [
138
- totalSize = 0,
139
- totalSizeWithScrollAdjust = 0,
140
- scrollAdjust = 0,
141
- rawScroll = 0,
142
- scroll = 0,
143
- numContainers = 0,
144
- numContainersPooled = 0
145
- ] = useArr$([
135
+ const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, numContainers = 0, numContainersPooled = 0] = useArr$([
146
136
  "totalSize",
147
- "totalSizeWithScrollAdjust",
148
137
  "scrollAdjust",
149
138
  "debugRawScroll",
150
139
  "debugComputedScroll",
@@ -152,11 +141,11 @@ var DebugView = React2__namespace.memo(function DebugView2({ state }) {
152
141
  "numContainersPooled"
153
142
  ]);
154
143
  const contentSize = getContentSize(ctx);
155
- const [, forceUpdate] = React2.useReducer((x) => x + 1, 0);
144
+ const [, forceUpdate] = React3.useReducer((x) => x + 1, 0);
156
145
  useInterval(() => {
157
146
  forceUpdate();
158
147
  }, 100);
159
- return /* @__PURE__ */ React2__namespace.createElement(
148
+ return /* @__PURE__ */ React3__namespace.createElement(
160
149
  reactNative.View,
161
150
  {
162
151
  style: {
@@ -172,19 +161,18 @@ var DebugView = React2__namespace.memo(function DebugView2({ state }) {
172
161
  },
173
162
  pointerEvents: "none"
174
163
  },
175
- /* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, "TotalSize:"), /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, totalSize.toFixed(2))),
176
- /* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, "ContentSize:"), /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, contentSize.toFixed(2))),
177
- /* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, "At end:"), /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, String(state.isAtEnd))),
178
- /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null),
179
- /* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, "ScrollAdjust:"), /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, scrollAdjust.toFixed(2))),
180
- /* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, "TotalSizeReal: "), /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, totalSizeWithScrollAdjust.toFixed(2))),
181
- /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null),
182
- /* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, "RawScroll: "), /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, rawScroll.toFixed(2))),
183
- /* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, "ComputedScroll: "), /* @__PURE__ */ React2__namespace.createElement(reactNative.Text, null, scroll.toFixed(2)))
164
+ /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "TotalSize:"), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, totalSize.toFixed(2))),
165
+ /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "ContentSize:"), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, contentSize.toFixed(2))),
166
+ /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "At end:"), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, String(state.isAtEnd))),
167
+ /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null),
168
+ /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "ScrollAdjust:"), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, scrollAdjust.toFixed(2))),
169
+ /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null),
170
+ /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "RawScroll: "), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, rawScroll.toFixed(2))),
171
+ /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "ComputedScroll: "), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, scroll.toFixed(2)))
184
172
  );
185
173
  });
186
174
  function useInterval(callback, delay) {
187
- React2.useEffect(() => {
175
+ React3.useEffect(() => {
188
176
  const interval = setInterval(callback, delay);
189
177
  return () => clearInterval(interval);
190
178
  }, [delay]);
@@ -204,12 +192,12 @@ function warnDevOnce(id, text) {
204
192
  console.warn(`[legend-list] ${text}`);
205
193
  }
206
194
  }
195
+ function roundSize(size) {
196
+ return Math.floor(size * 8) / 8;
197
+ }
207
198
  function isNullOrUndefined(value) {
208
199
  return value === null || value === void 0;
209
200
  }
210
- function comparatorByDistance(a, b) {
211
- return b.distance - a.distance;
212
- }
213
201
  function comparatorDefault(a, b) {
214
202
  return a - b;
215
203
  }
@@ -222,7 +210,7 @@ function extractPadding(style, contentContainerStyle, type) {
222
210
  }
223
211
  var symbolFirst = Symbol();
224
212
  function useInit(cb) {
225
- const refValue = React2.useRef(symbolFirst);
213
+ const refValue = React3.useRef(symbolFirst);
226
214
  if (refValue.current === symbolFirst) {
227
215
  refValue.current = cb();
228
216
  }
@@ -230,10 +218,10 @@ function useInit(cb) {
230
218
  }
231
219
 
232
220
  // src/ContextContainer.ts
233
- var ContextContainer = React2.createContext(null);
221
+ var ContextContainer = React3.createContext(null);
234
222
  function useViewability(callback, configId) {
235
223
  const ctx = useStateContext();
236
- const { containerId } = React2.useContext(ContextContainer);
224
+ const { containerId } = React3.useContext(ContextContainer);
237
225
  const key = containerId + (configId != null ? configId : "");
238
226
  useInit(() => {
239
227
  const value = ctx.mapViewabilityValues.get(key);
@@ -242,7 +230,7 @@ function useViewability(callback, configId) {
242
230
  }
243
231
  });
244
232
  ctx.mapViewabilityCallbacks.set(key, callback);
245
- React2.useEffect(
233
+ React3.useEffect(
246
234
  () => () => {
247
235
  ctx.mapViewabilityCallbacks.delete(key);
248
236
  },
@@ -251,7 +239,7 @@ function useViewability(callback, configId) {
251
239
  }
252
240
  function useViewabilityAmount(callback) {
253
241
  const ctx = useStateContext();
254
- const { containerId } = React2.useContext(ContextContainer);
242
+ const { containerId } = React3.useContext(ContextContainer);
255
243
  useInit(() => {
256
244
  const value = ctx.mapViewabilityAmountValues.get(containerId);
257
245
  if (value) {
@@ -259,7 +247,7 @@ function useViewabilityAmount(callback) {
259
247
  }
260
248
  });
261
249
  ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
262
- React2.useEffect(
250
+ React3.useEffect(
263
251
  () => () => {
264
252
  ctx.mapViewabilityAmountCallbacks.delete(containerId);
265
253
  },
@@ -267,12 +255,12 @@ function useViewabilityAmount(callback) {
267
255
  );
268
256
  }
269
257
  function useRecyclingEffect(effect) {
270
- const { index, value } = React2.useContext(ContextContainer);
271
- const prevValues = React2.useRef({
258
+ const { index, value } = React3.useContext(ContextContainer);
259
+ const prevValues = React3.useRef({
272
260
  prevIndex: void 0,
273
261
  prevItem: void 0
274
262
  });
275
- React2.useEffect(() => {
263
+ React3.useEffect(() => {
276
264
  let ret = void 0;
277
265
  if (prevValues.current.prevIndex !== void 0 && prevValues.current.prevItem !== void 0) {
278
266
  ret = effect({
@@ -290,33 +278,34 @@ function useRecyclingEffect(effect) {
290
278
  }, [index, value]);
291
279
  }
292
280
  function useRecyclingState(valueOrFun) {
293
- const { index, value, itemKey, triggerLayout } = React2.useContext(ContextContainer);
294
- const refState = React2.useRef({
281
+ const { index, value, itemKey, triggerLayout } = React3.useContext(ContextContainer);
282
+ const refState = React3.useRef({
295
283
  itemKey: null,
296
284
  value: null
297
285
  });
298
- const [_, setRenderNum] = React2.useState(0);
299
- if (refState.current.itemKey !== itemKey) {
300
- refState.current.itemKey = itemKey;
301
- refState.current.value = isFunction(valueOrFun) ? valueOrFun({
286
+ const [_, setRenderNum] = React3.useState(0);
287
+ const state = refState.current;
288
+ if (state.itemKey !== itemKey) {
289
+ state.itemKey = itemKey;
290
+ state.value = isFunction(valueOrFun) ? valueOrFun({
302
291
  index,
303
292
  item: value,
304
293
  prevIndex: void 0,
305
294
  prevItem: void 0
306
295
  }) : valueOrFun;
307
296
  }
308
- const setState = React2.useCallback(
297
+ const setState = React3.useCallback(
309
298
  (newState) => {
310
- refState.current.value = isFunction(newState) ? newState(refState.current.value) : newState;
299
+ state.value = isFunction(newState) ? newState(state.value) : newState;
311
300
  setRenderNum((v) => v + 1);
312
301
  triggerLayout();
313
302
  },
314
- [triggerLayout]
303
+ [triggerLayout, state]
315
304
  );
316
- return [refState.current.value, setState];
305
+ return [state.value, setState];
317
306
  }
318
307
  function useIsLastItem() {
319
- const { itemKey } = React2.useContext(ContextContainer);
308
+ const { itemKey } = React3.useContext(ContextContainer);
320
309
  const isLast = useSelector$("lastItemKeys", (lastItemKeys) => (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false);
321
310
  return isLast;
322
311
  }
@@ -324,19 +313,21 @@ function useListScrollSize() {
324
313
  const [scrollSize] = useArr$(["scrollSize"]);
325
314
  return scrollSize;
326
315
  }
327
- var LeanViewComponent = React2__namespace.forwardRef((props, ref) => {
328
- return React2__namespace.createElement("RCTView", { ...props, ref });
316
+ var LeanViewComponent = React3__namespace.forwardRef((props, ref) => {
317
+ return React3__namespace.createElement("RCTView", { ...props, ref });
329
318
  });
330
319
  LeanViewComponent.displayName = "RCTView";
331
320
  var LeanView = reactNative.Platform.OS === "android" || reactNative.Platform.OS === "ios" ? LeanViewComponent : reactNative.View;
332
321
 
322
+ // src/Separator.tsx
323
+ function Separator({ ItemSeparatorComponent, itemKey, leadingItem }) {
324
+ const [lastItemKeys] = useArr$(["lastItemKeys"]);
325
+ const isALastItem = lastItemKeys.includes(itemKey);
326
+ return isALastItem ? null : /* @__PURE__ */ React.createElement(ItemSeparatorComponent, { leadingItem });
327
+ }
328
+
333
329
  // src/constants.ts
334
330
  var POSITION_OUT_OF_VIEW = -1e7;
335
- var ANCHORED_POSITION_OUT_OF_VIEW = {
336
- type: "top",
337
- relativeCoordinate: POSITION_OUT_OF_VIEW,
338
- top: POSITION_OUT_OF_VIEW
339
- };
340
331
  var ENABLE_DEVMODE = __DEV__ && false;
341
332
  var ENABLE_DEBUG_VIEW = __DEV__ && false;
342
333
  var IsNewArchitecture = global.nativeFabricUIManager != null;
@@ -346,48 +337,37 @@ var Container = ({
346
337
  id,
347
338
  recycleItems,
348
339
  horizontal,
349
- getRenderedItem,
350
- updateItemSize,
340
+ getRenderedItem: getRenderedItem2,
341
+ updateItemSize: updateItemSize2,
351
342
  ItemSeparatorComponent
352
343
  }) => {
353
344
  const ctx = useStateContext();
354
345
  const columnWrapperStyle = ctx.columnWrapperStyle;
355
- const [
356
- maintainVisibleContentPosition,
357
- position = ANCHORED_POSITION_OUT_OF_VIEW,
358
- column = 0,
359
- numColumns,
360
- lastItemKeys,
361
- itemKey,
362
- data,
363
- extraData
364
- ] = useArr$([
365
- "maintainVisibleContentPosition",
366
- `containerPosition${id}`,
346
+ const [column = 0, data, itemKey, position = POSITION_OUT_OF_VIEW, numColumns, extraData] = useArr$([
367
347
  `containerColumn${id}`,
368
- "numColumns",
369
- "lastItemKeys",
370
- `containerItemKey${id}`,
371
348
  `containerItemData${id}`,
349
+ `containerItemKey${id}`,
350
+ `containerPosition${id}`,
351
+ "numColumns",
372
352
  "extraData"
373
353
  ]);
374
- const refLastSize = React2.useRef();
375
- const ref = React2.useRef(null);
376
- const [layoutRenderCount, forceLayoutRender] = React2.useState(0);
354
+ const refLastSize = React3.useRef();
355
+ const ref = React3.useRef(null);
356
+ const [layoutRenderCount, forceLayoutRender] = React3.useState(0);
377
357
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
378
358
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
379
- const isALastItem = lastItemKeys.includes(itemKey);
359
+ let didLayout = false;
380
360
  let paddingStyles;
381
361
  if (columnWrapperStyle) {
382
362
  const { columnGap, rowGap, gap } = columnWrapperStyle;
383
363
  if (horizontal) {
384
364
  paddingStyles = {
385
- paddingRight: !isALastItem ? columnGap || gap || void 0 : void 0,
365
+ paddingRight: columnGap || gap || void 0,
386
366
  paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
387
367
  };
388
368
  } else {
389
369
  paddingStyles = {
390
- paddingBottom: !isALastItem ? rowGap || gap || void 0 : void 0,
370
+ paddingBottom: rowGap || gap || void 0,
391
371
  paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
392
372
  };
393
373
  }
@@ -397,32 +377,37 @@ var Container = ({
397
377
  position: "absolute",
398
378
  top: otherAxisPos,
399
379
  height: otherAxisSize,
400
- left: position.relativeCoordinate,
380
+ left: position,
401
381
  ...paddingStyles || {}
402
382
  } : {
403
383
  position: "absolute",
404
384
  left: otherAxisPos,
405
385
  right: numColumns > 1 ? null : 0,
406
386
  width: otherAxisSize,
407
- top: position.relativeCoordinate,
387
+ top: position,
408
388
  ...paddingStyles || {}
409
389
  };
410
- const renderedItemInfo = React2.useMemo(
411
- () => itemKey !== void 0 ? getRenderedItem(itemKey) : null,
390
+ const renderedItemInfo = React3.useMemo(
391
+ () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
412
392
  [itemKey, data, extraData]
413
393
  );
414
394
  const { index, renderedItem } = renderedItemInfo || {};
415
- const triggerLayout = React2.useCallback(() => {
395
+ const triggerLayout = React3.useCallback(() => {
416
396
  forceLayoutRender((v) => v + 1);
417
397
  }, []);
398
+ const contextValue = React3.useMemo(() => {
399
+ ctx.viewRefs.set(id, ref);
400
+ return { containerId: id, itemKey, index, value: data, triggerLayout };
401
+ }, [id, itemKey, index, data]);
418
402
  const onLayout = (event) => {
419
403
  var _a, _b;
420
404
  if (!isNullOrUndefined(itemKey)) {
405
+ didLayout = true;
421
406
  let layout = event.nativeEvent.layout;
422
407
  const size = layout[horizontal ? "width" : "height"];
423
408
  const doUpdate = () => {
424
409
  refLastSize.current = { width: layout.width, height: layout.height };
425
- updateItemSize(itemKey, layout);
410
+ updateItemSize2(itemKey, layout);
426
411
  };
427
412
  if (IsNewArchitecture || size > 0) {
428
413
  doUpdate();
@@ -435,24 +420,24 @@ var Container = ({
435
420
  }
436
421
  };
437
422
  if (IsNewArchitecture) {
438
- React2.useLayoutEffect(() => {
423
+ React3.useLayoutEffect(() => {
439
424
  var _a, _b;
440
425
  if (!isNullOrUndefined(itemKey)) {
441
426
  const measured = (_b = (_a = ref.current) == null ? void 0 : _a.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a);
442
427
  if (measured) {
443
428
  const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
444
429
  if (size) {
445
- updateItemSize(itemKey, measured);
430
+ updateItemSize2(itemKey, measured);
446
431
  }
447
432
  }
448
433
  }
449
- }, [itemKey, layoutRenderCount, isALastItem]);
434
+ }, [itemKey, layoutRenderCount]);
450
435
  } else {
451
- React2.useEffect(() => {
436
+ React3.useEffect(() => {
452
437
  if (!isNullOrUndefined(itemKey)) {
453
438
  const timeout = setTimeout(() => {
454
- if (refLastSize.current) {
455
- updateItemSize(itemKey, refLastSize.current);
439
+ if (!didLayout && refLastSize.current) {
440
+ updateItemSize2(itemKey, refLastSize.current);
456
441
  }
457
442
  }, 16);
458
443
  return () => {
@@ -461,43 +446,51 @@ var Container = ({
461
446
  }
462
447
  }, [itemKey]);
463
448
  }
464
- const contextValue = React2.useMemo(() => {
465
- ctx.viewRefs.set(id, ref);
466
- return { containerId: id, itemKey, index, value: data, triggerLayout };
467
- }, [id, itemKey, index, data]);
468
- const contentFragment = /* @__PURE__ */ React2__namespace.default.createElement(React2__namespace.default.Fragment, { key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React2__namespace.default.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && !isALastItem && /* @__PURE__ */ React2__namespace.default.createElement(ItemSeparatorComponent, { leadingItem: renderedItemInfo.item })));
469
- if (maintainVisibleContentPosition) {
470
- const anchorStyle = horizontal ? position.type === "top" ? { position: "absolute", left: 0, top: 0, bottom: 0, flexDirection: "row", alignItems: "stretch" } : { position: "absolute", right: 0, top: 0, bottom: 0, flexDirection: "row", alignItems: "stretch" } : position.type === "top" ? { position: "absolute", top: 0, left: 0, right: 0 } : { position: "absolute", bottom: 0, left: 0, right: 0 };
471
- if (__DEV__ && ENABLE_DEVMODE) {
472
- anchorStyle.borderColor = position.type === "top" ? "red" : "blue";
473
- anchorStyle.borderWidth = 1;
449
+ return /* @__PURE__ */ React3__namespace.createElement(LeanView, { style, onLayout, ref, key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React3__namespace.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React3__namespace.createElement(
450
+ Separator,
451
+ {
452
+ itemKey,
453
+ ItemSeparatorComponent,
454
+ leadingItem: renderedItemInfo.item
474
455
  }
475
- return /* @__PURE__ */ React2__namespace.default.createElement(LeanView, { style }, /* @__PURE__ */ React2__namespace.default.createElement(LeanView, { style: [anchorStyle, paddingStyles], onLayout, ref }, contentFragment, __DEV__ && ENABLE_DEVMODE && /* @__PURE__ */ React2__namespace.default.createElement(reactNative.Text, { style: { position: "absolute", top: 0, left: 0, zIndex: 1e3 } }, position.top)));
476
- }
477
- return /* @__PURE__ */ React2__namespace.default.createElement(LeanView, { style, onLayout, ref }, contentFragment);
456
+ )));
478
457
  };
479
- var typedForwardRef = React2.forwardRef;
480
- var typedMemo = React2.memo;
458
+ var typedForwardRef = React3.forwardRef;
459
+ var typedMemo = React3.memo;
481
460
  var useAnimatedValue = (initialValue) => {
482
- return React2.useRef(new reactNative.Animated.Value(initialValue)).current;
461
+ return React3.useRef(new reactNative.Animated.Value(initialValue)).current;
483
462
  };
484
463
 
485
464
  // src/useValue$.ts
486
- function useValue$(key, getValue, useMicrotask) {
465
+ function useValue$(key, params) {
487
466
  var _a;
467
+ const { getValue, delay } = params || {};
488
468
  const ctx = useStateContext();
489
469
  const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
490
- React2.useMemo(() => {
470
+ React3.useMemo(() => {
491
471
  let newValue = void 0;
472
+ let prevValue = void 0;
473
+ let didQueueTask = false;
492
474
  listen$(ctx, key, (v) => {
493
- if (useMicrotask && newValue === void 0) {
494
- queueMicrotask(() => {
495
- animValue.setValue(newValue);
496
- newValue = void 0;
497
- });
498
- }
499
475
  newValue = getValue ? getValue(v) : v;
500
- if (!useMicrotask) {
476
+ if (delay !== void 0) {
477
+ const fn = () => {
478
+ didQueueTask = false;
479
+ if (newValue !== void 0) {
480
+ animValue.setValue(newValue);
481
+ }
482
+ };
483
+ const delayValue = typeof delay === "function" ? delay(newValue, prevValue) : delay;
484
+ prevValue = newValue;
485
+ if (!didQueueTask) {
486
+ didQueueTask = true;
487
+ if (delayValue === 0) {
488
+ queueMicrotask(fn);
489
+ } else {
490
+ setTimeout(fn, delayValue);
491
+ }
492
+ }
493
+ } else {
501
494
  animValue.setValue(newValue);
502
495
  }
503
496
  });
@@ -511,37 +504,30 @@ var Containers = typedMemo(function Containers2({
511
504
  recycleItems,
512
505
  ItemSeparatorComponent,
513
506
  waitForInitialLayout,
514
- updateItemSize,
515
- getRenderedItem
507
+ updateItemSize: updateItemSize2,
508
+ getRenderedItem: getRenderedItem2
516
509
  }) {
517
510
  const ctx = useStateContext();
518
511
  const columnWrapperStyle = ctx.columnWrapperStyle;
519
512
  const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
520
- const animSize = useValue$(
521
- "totalSizeWithScrollAdjust",
522
- void 0,
523
- /*useMicrotask*/
524
- true
525
- );
526
- const animOpacity = waitForInitialLayout ? useValue$("containersDidLayout", (value) => value ? 1 : 0) : void 0;
527
- const otherAxisSize = useValue$(
528
- "otherAxisSize",
529
- void 0,
530
- /*useMicrotask*/
531
- true
532
- );
513
+ const animSize = useValue$("totalSize", {
514
+ // Use a microtask if increasing the size significantly, otherwise use a timeout
515
+ delay: (value, prevValue) => !prevValue || value - prevValue > 20 ? 0 : 200
516
+ });
517
+ const animOpacity = waitForInitialLayout && !IsNewArchitecture ? useValue$("containersDidLayout", { getValue: (value) => value ? 1 : 0 }) : void 0;
518
+ const otherAxisSize = useValue$("otherAxisSize", { delay: 0 });
533
519
  const containers = [];
534
520
  for (let i = 0; i < numContainers; i++) {
535
521
  containers.push(
536
- /* @__PURE__ */ React2__namespace.createElement(
522
+ /* @__PURE__ */ React3__namespace.createElement(
537
523
  Container,
538
524
  {
539
525
  id: i,
540
526
  key: i,
541
527
  recycleItems,
542
528
  horizontal,
543
- getRenderedItem,
544
- updateItemSize,
529
+ getRenderedItem: getRenderedItem2,
530
+ updateItemSize: updateItemSize2,
545
531
  ItemSeparatorComponent
546
532
  }
547
533
  )
@@ -550,111 +536,95 @@ var Containers = typedMemo(function Containers2({
550
536
  const style = horizontal ? { width: animSize, opacity: animOpacity, minHeight: otherAxisSize } : { height: animSize, opacity: animOpacity, minWidth: otherAxisSize };
551
537
  if (columnWrapperStyle && numColumns > 1) {
552
538
  const { columnGap, rowGap, gap } = columnWrapperStyle;
539
+ const gapX = columnGap || gap || 0;
540
+ const gapY = rowGap || gap || 0;
553
541
  if (horizontal) {
554
- const my = (rowGap || gap || 0) / 2;
555
- if (my) {
556
- style.marginVertical = -my;
542
+ if (gapY) {
543
+ style.marginVertical = -gapY / 2;
544
+ }
545
+ if (gapX) {
546
+ style.marginRight = -gapX;
557
547
  }
558
548
  } else {
559
- const mx = (columnGap || gap || 0) / 2;
560
- if (mx) {
561
- style.marginHorizontal = -mx;
549
+ if (gapX) {
550
+ style.marginHorizontal = -gapX;
551
+ }
552
+ if (gapY) {
553
+ style.marginBottom = -gapY;
562
554
  }
563
555
  }
564
556
  }
565
- return /* @__PURE__ */ React2__namespace.createElement(reactNative.Animated.View, { style }, containers);
557
+ return /* @__PURE__ */ React3__namespace.createElement(reactNative.Animated.View, { style }, containers);
566
558
  });
567
- function ListHeaderComponentContainer({
568
- children,
569
- style,
570
- ctx,
571
- horizontal,
572
- waitForInitialLayout
573
- }) {
574
- var _a;
575
- const hasData = ((_a = peek$(ctx, "lastItemKeys")) == null ? void 0 : _a.length) > 0;
576
- const scrollAdjust = useValue$("scrollAdjust", (v) => v != null ? v : 0, true);
577
- const animOpacity = waitForInitialLayout ? useValue$("containersDidLayout", (value) => value ? 1 : 0) : void 0;
578
- const additionalSize = {
579
- transform: [{ translateY: reactNative.Animated.multiply(scrollAdjust, -1) }],
580
- // Header should show if there's no data yet, but containersDidLayout will be false until it has some data
581
- opacity: hasData ? animOpacity : 1
582
- };
583
- return /* @__PURE__ */ React2__namespace.createElement(
584
- reactNative.Animated.View,
559
+ function ScrollAdjust() {
560
+ const bias = 1e7;
561
+ const [scrollAdjust, scrollAdjustUserOffset] = useArr$(["scrollAdjust", "scrollAdjustUserOffset"]);
562
+ const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0) + bias;
563
+ return /* @__PURE__ */ React3__namespace.createElement(
564
+ reactNative.View,
585
565
  {
586
- style: [style, additionalSize],
587
- onLayout: (event) => {
588
- const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
589
- set$(ctx, "headerSize", size);
566
+ style: {
567
+ position: "absolute",
568
+ height: 0,
569
+ width: 0,
570
+ top: scrollOffset,
571
+ left: 0
590
572
  }
573
+ }
574
+ );
575
+ }
576
+ function useSyncLayout({
577
+ onChange
578
+ }) {
579
+ const ref = React3.useRef(null);
580
+ const onLayout = React3.useCallback(
581
+ (event) => {
582
+ onChange(event.nativeEvent.layout, false);
591
583
  },
592
- children
584
+ [onChange]
593
585
  );
586
+ React3.useLayoutEffect(() => {
587
+ if (ref.current) {
588
+ ref.current.measure((x, y, width, height) => {
589
+ onChange({ x, y, width, height }, true);
590
+ });
591
+ }
592
+ }, []);
593
+ return { onLayout, ref };
594
594
  }
595
595
 
596
596
  // src/ListComponent.tsx
597
597
  var getComponent = (Component) => {
598
- if (React2__namespace.isValidElement(Component)) {
598
+ if (React3__namespace.isValidElement(Component)) {
599
599
  return Component;
600
600
  }
601
601
  if (Component) {
602
- return /* @__PURE__ */ React2__namespace.createElement(Component, null);
602
+ return /* @__PURE__ */ React3__namespace.createElement(Component, null);
603
603
  }
604
604
  return null;
605
605
  };
606
- var PaddingAndAdjust = () => {
607
- const animPaddingTop = useValue$("paddingTop", (v) => v, true);
608
- const animScrollAdjust = useValue$("scrollAdjust", (v) => v, true);
609
- const additionalSize = { marginTop: animScrollAdjust, paddingTop: animPaddingTop };
610
- return /* @__PURE__ */ React2__namespace.createElement(reactNative.Animated.View, { style: additionalSize });
606
+ var Padding = () => {
607
+ const animPaddingTop = useValue$("alignItemsPaddingTop", { delay: 0 });
608
+ return /* @__PURE__ */ React3__namespace.createElement(reactNative.Animated.View, { style: { paddingTop: animPaddingTop } });
611
609
  };
612
- var PaddingAndAdjustDevMode = () => {
613
- const animPaddingTop = useValue$("paddingTop", (v) => v, true);
614
- const animScrollAdjust = useValue$("scrollAdjust", (v) => v, true);
615
- return /* @__PURE__ */ React2__namespace.createElement(React2__namespace.Fragment, null, /* @__PURE__ */ React2__namespace.createElement(reactNative.Animated.View, { style: { marginTop: animScrollAdjust } }), /* @__PURE__ */ React2__namespace.createElement(reactNative.Animated.View, { style: { paddingTop: animPaddingTop } }), /* @__PURE__ */ React2__namespace.createElement(
610
+ var PaddingDevMode = () => {
611
+ const animPaddingTop = useValue$("alignItemsPaddingTop", { delay: 0 });
612
+ return /* @__PURE__ */ React3__namespace.createElement(React3__namespace.Fragment, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Animated.View, { style: { paddingTop: animPaddingTop } }), /* @__PURE__ */ React3__namespace.createElement(
616
613
  reactNative.Animated.View,
617
614
  {
618
615
  style: {
619
616
  position: "absolute",
620
- top: reactNative.Animated.add(animScrollAdjust, reactNative.Animated.multiply(animScrollAdjust, -1)),
617
+ top: 0,
621
618
  height: animPaddingTop,
622
619
  left: 0,
623
620
  right: 0,
624
621
  backgroundColor: "green"
625
622
  }
626
623
  }
627
- ), /* @__PURE__ */ React2__namespace.createElement(
628
- reactNative.Animated.View,
629
- {
630
- style: {
631
- position: "absolute",
632
- top: animPaddingTop,
633
- height: animScrollAdjust,
634
- left: -16,
635
- right: -16,
636
- backgroundColor: "lightblue"
637
- }
638
- }
639
- ), /* @__PURE__ */ React2__namespace.createElement(
640
- reactNative.Animated.View,
641
- {
642
- style: {
643
- position: "absolute",
644
- top: animPaddingTop,
645
- height: reactNative.Animated.multiply(animScrollAdjust, -1),
646
- width: 8,
647
- right: 4,
648
- borderStyle: "dashed",
649
- borderColor: "blue",
650
- borderWidth: 1,
651
- backgroundColor: "lightblue"
652
- //backgroundColor: "blue",
653
- }
654
- }
655
624
  ));
656
625
  };
657
626
  var ListComponent = typedMemo(function ListComponent2({
627
+ canRender,
658
628
  style,
659
629
  contentContainerStyle,
660
630
  horizontal,
@@ -663,26 +633,38 @@ var ListComponent = typedMemo(function ListComponent2({
663
633
  ItemSeparatorComponent,
664
634
  alignItemsAtEnd,
665
635
  waitForInitialLayout,
666
- handleScroll,
636
+ onScroll: onScroll2,
667
637
  onLayout,
668
638
  ListHeaderComponent,
669
639
  ListHeaderComponentStyle,
670
640
  ListFooterComponent,
671
641
  ListFooterComponentStyle,
672
642
  ListEmptyComponent,
673
- getRenderedItem,
674
- updateItemSize,
643
+ getRenderedItem: getRenderedItem2,
644
+ updateItemSize: updateItemSize2,
675
645
  refScrollView,
676
646
  maintainVisibleContentPosition,
677
647
  renderScrollComponent,
648
+ scrollAdjustHandler,
649
+ onLayoutHeader,
678
650
  ...rest
679
651
  }) {
680
652
  const ctx = useStateContext();
681
- const ScrollComponent = renderScrollComponent ? React2.useMemo(
682
- () => React2__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
653
+ const { onLayout: onLayoutHeaderSync, ref: refHeader } = useSyncLayout({
654
+ onChange: onLayoutHeader
655
+ });
656
+ const ScrollComponent = renderScrollComponent ? React3.useMemo(
657
+ () => React3__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
683
658
  [renderScrollComponent]
684
659
  ) : reactNative.ScrollView;
685
- return /* @__PURE__ */ React2__namespace.createElement(
660
+ React3__namespace.useEffect(() => {
661
+ if (canRender) {
662
+ setTimeout(() => {
663
+ scrollAdjustHandler.setMounted();
664
+ }, 0);
665
+ }
666
+ }, [canRender]);
667
+ return /* @__PURE__ */ React3__namespace.createElement(
686
668
  ScrollComponent,
687
669
  {
688
670
  ...rest,
@@ -694,36 +676,28 @@ var ListComponent = typedMemo(function ListComponent2({
694
676
  height: "100%"
695
677
  } : {}
696
678
  ],
697
- onScroll: handleScroll,
679
+ onScroll: onScroll2,
698
680
  onLayout,
699
681
  horizontal,
700
682
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
701
683
  ref: refScrollView
702
684
  },
703
- ENABLE_DEVMODE ? /* @__PURE__ */ React2__namespace.createElement(PaddingAndAdjustDevMode, null) : /* @__PURE__ */ React2__namespace.createElement(PaddingAndAdjust, null),
704
- ListHeaderComponent && /* @__PURE__ */ React2__namespace.createElement(
705
- ListHeaderComponentContainer,
706
- {
707
- style: ListHeaderComponentStyle,
708
- ctx,
709
- horizontal,
710
- waitForInitialLayout
711
- },
712
- getComponent(ListHeaderComponent)
713
- ),
685
+ maintainVisibleContentPosition && /* @__PURE__ */ React3__namespace.createElement(ScrollAdjust, null),
686
+ ENABLE_DEVMODE ? /* @__PURE__ */ React3__namespace.createElement(PaddingDevMode, null) : /* @__PURE__ */ React3__namespace.createElement(Padding, null),
687
+ ListHeaderComponent && /* @__PURE__ */ React3__namespace.createElement(reactNative.View, { style: ListHeaderComponentStyle, onLayout: onLayoutHeaderSync, ref: refHeader }, getComponent(ListHeaderComponent)),
714
688
  ListEmptyComponent && getComponent(ListEmptyComponent),
715
- /* @__PURE__ */ React2__namespace.createElement(
689
+ canRender && /* @__PURE__ */ React3__namespace.createElement(
716
690
  Containers,
717
691
  {
718
692
  horizontal,
719
693
  recycleItems,
720
694
  waitForInitialLayout,
721
- getRenderedItem,
695
+ getRenderedItem: getRenderedItem2,
722
696
  ItemSeparatorComponent,
723
- updateItemSize
697
+ updateItemSize: updateItemSize2
724
698
  }
725
699
  ),
726
- ListFooterComponent && /* @__PURE__ */ React2__namespace.createElement(
700
+ ListFooterComponent && /* @__PURE__ */ React3__namespace.createElement(
727
701
  reactNative.View,
728
702
  {
729
703
  style: ListFooterComponentStyle,
@@ -740,66 +714,562 @@ var ListComponent = typedMemo(function ListComponent2({
740
714
  // src/ScrollAdjustHandler.ts
741
715
  var ScrollAdjustHandler = class {
742
716
  constructor(ctx) {
743
- this.ctx = ctx;
744
717
  this.appliedAdjust = 0;
745
- this.busy = false;
746
- this.isPaused = false;
747
- this.isDisabled = false;
718
+ this.mounted = false;
748
719
  this.context = ctx;
749
720
  }
750
- doAjdust() {
751
- set$(this.context, "scrollAdjust", this.appliedAdjust);
752
- this.busy = false;
721
+ requestAdjust(add) {
722
+ const oldAdjustTop = peek$(this.context, "scrollAdjust") || 0;
723
+ this.appliedAdjust = add + oldAdjustTop;
724
+ const set = () => set$(this.context, "scrollAdjust", this.appliedAdjust);
725
+ if (this.mounted) {
726
+ set();
727
+ } else {
728
+ requestAnimationFrame(set);
729
+ }
753
730
  }
754
- requestAdjust(adjust, onAdjusted) {
755
- if (this.isDisabled) {
756
- return;
731
+ setMounted() {
732
+ this.mounted = true;
733
+ }
734
+ };
735
+
736
+ // src/getId.ts
737
+ function getId(state, index) {
738
+ const { data, keyExtractor } = state.props;
739
+ if (!data) {
740
+ return "";
741
+ }
742
+ const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
743
+ const id = ret;
744
+ state.idCache.set(index, id);
745
+ return id;
746
+ }
747
+
748
+ // src/calculateOffsetForIndex.ts
749
+ function calculateOffsetForIndex(ctx, state, index) {
750
+ let position = 0;
751
+ if (index !== void 0) {
752
+ position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
753
+ }
754
+ const paddingTop = peek$(ctx, "stylePaddingTop");
755
+ if (paddingTop) {
756
+ position += paddingTop;
757
+ }
758
+ const headerSize = peek$(ctx, "headerSize");
759
+ if (headerSize) {
760
+ position += headerSize;
761
+ }
762
+ return position;
763
+ }
764
+
765
+ // src/getItemSize.ts
766
+ function getItemSize(state, key, index, data, useAverageSize) {
767
+ const {
768
+ sizesKnown,
769
+ sizes,
770
+ scrollingTo,
771
+ props: { estimatedItemSize, getEstimatedItemSize }
772
+ } = state;
773
+ const sizeKnown = sizesKnown.get(key);
774
+ if (sizeKnown !== void 0) {
775
+ return sizeKnown;
776
+ }
777
+ let size;
778
+ if (IsNewArchitecture && useAverageSize !== void 0 && sizeKnown === void 0 && !getEstimatedItemSize && !scrollingTo) {
779
+ size = useAverageSize;
780
+ }
781
+ if (size === void 0) {
782
+ size = sizes.get(key);
783
+ if (size !== void 0) {
784
+ return size;
757
785
  }
758
- const oldAdjustTop = peek$(this.context, "scrollAdjust");
759
- if (oldAdjustTop === adjust) {
760
- return;
786
+ }
787
+ if (size === void 0) {
788
+ size = getEstimatedItemSize ? getEstimatedItemSize(index, data) : estimatedItemSize;
789
+ }
790
+ sizes.set(key, size);
791
+ return size;
792
+ }
793
+
794
+ // src/calculateOffsetWithOffsetPosition.ts
795
+ function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
796
+ const { index, viewOffset, viewPosition } = params;
797
+ let offset = offsetParam;
798
+ if (viewOffset) {
799
+ offset -= viewOffset;
800
+ }
801
+ if (viewPosition !== void 0 && index !== void 0) {
802
+ offset -= viewPosition * (state.scrollLength - getItemSize(state, getId(state, index), index, state.props.data[index]));
803
+ }
804
+ return offset;
805
+ }
806
+
807
+ // src/checkAllSizesKnown.ts
808
+ function checkAllSizesKnown(state) {
809
+ const { startBuffered, endBuffered, sizesKnown } = state;
810
+ if (endBuffered !== null) {
811
+ let areAllKnown = true;
812
+ for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
813
+ const key = getId(state, i);
814
+ areAllKnown && (areAllKnown = sizesKnown.has(key));
815
+ }
816
+ return areAllKnown;
817
+ }
818
+ return false;
819
+ }
820
+
821
+ // src/findAvailableContainers.ts
822
+ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval) {
823
+ const numContainers = peek$(ctx, "numContainers");
824
+ const result = [];
825
+ const availableContainers = [];
826
+ for (let u = 0; u < numContainers; u++) {
827
+ const key = peek$(ctx, `containerItemKey${u}`);
828
+ let isOk = key === void 0;
829
+ if (!isOk) {
830
+ const index = pendingRemoval.indexOf(u);
831
+ if (index !== -1) {
832
+ pendingRemoval.splice(index, 1);
833
+ isOk = true;
834
+ }
835
+ }
836
+ if (isOk) {
837
+ result.push(u);
838
+ if (result.length >= numNeeded) {
839
+ return result;
840
+ }
841
+ }
842
+ }
843
+ for (let u = 0; u < numContainers; u++) {
844
+ const key = peek$(ctx, `containerItemKey${u}`);
845
+ if (key === void 0) continue;
846
+ const index = state.indexByKey.get(key);
847
+ if (index < startBuffered) {
848
+ availableContainers.push({ index: u, distance: startBuffered - index });
849
+ } else if (index > endBuffered) {
850
+ availableContainers.push({ index: u, distance: index - endBuffered });
761
851
  }
762
- this.appliedAdjust = adjust;
763
- if (!this.busy && !this.isPaused) {
764
- this.busy = true;
765
- this.doAjdust();
766
- onAdjusted(oldAdjustTop - adjust);
852
+ }
853
+ const remaining = numNeeded - result.length;
854
+ if (remaining > 0) {
855
+ if (availableContainers.length > 0) {
856
+ if (availableContainers.length > remaining) {
857
+ availableContainers.sort(comparatorByDistance);
858
+ availableContainers.length = remaining;
859
+ }
860
+ for (const container of availableContainers) {
861
+ result.push(container.index);
862
+ }
863
+ }
864
+ const stillNeeded = numNeeded - result.length;
865
+ if (stillNeeded > 0) {
866
+ for (let i = 0; i < stillNeeded; i++) {
867
+ result.push(numContainers + i);
868
+ }
869
+ if (__DEV__ && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
870
+ console.warn(
871
+ "[legend-list] No unused container available, 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 or increasing initialContainerPoolRatio.",
872
+ {
873
+ debugInfo: {
874
+ numContainers,
875
+ numNeeded,
876
+ stillNeeded,
877
+ numContainersPooled: peek$(ctx, "numContainersPooled")
878
+ }
879
+ }
880
+ );
881
+ }
767
882
  }
768
883
  }
769
- getAppliedAdjust() {
770
- return this.appliedAdjust;
884
+ return result.sort(comparatorDefault);
885
+ }
886
+ function comparatorByDistance(a, b) {
887
+ return b.distance - a.distance;
888
+ }
889
+
890
+ // src/getScrollVelocity.ts
891
+ var getScrollVelocity = (state) => {
892
+ const { scrollHistory } = state;
893
+ let velocity = 0;
894
+ if (scrollHistory.length >= 1) {
895
+ const newest = scrollHistory[scrollHistory.length - 1];
896
+ let oldest;
897
+ let start = 0;
898
+ for (let i = 0; i < scrollHistory.length - 1; i++) {
899
+ const entry = scrollHistory[i];
900
+ const nextEntry = scrollHistory[i + 1];
901
+ if (i > 0) {
902
+ const prevEntry = scrollHistory[i - 1];
903
+ const prevDirection = entry.scroll - prevEntry.scroll;
904
+ const currentDirection = nextEntry.scroll - entry.scroll;
905
+ if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
906
+ start = i;
907
+ break;
908
+ }
909
+ }
910
+ }
911
+ for (let i = start; i < scrollHistory.length - 1; i++) {
912
+ const entry = scrollHistory[i];
913
+ if (newest.time - entry.time <= 1e3) {
914
+ oldest = entry;
915
+ break;
916
+ }
917
+ }
918
+ if (oldest) {
919
+ const scrollDiff = newest.scroll - oldest.scroll;
920
+ const timeDiff = newest.time - oldest.time;
921
+ velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
922
+ }
771
923
  }
772
- pauseAdjust() {
773
- this.isPaused = true;
924
+ return velocity;
925
+ };
926
+
927
+ // src/requestAdjust.ts
928
+ function requestAdjust(ctx, state, positionDiff) {
929
+ if (Math.abs(positionDiff) > 0.1) {
930
+ const doit = () => {
931
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
932
+ };
933
+ state.scroll += positionDiff;
934
+ state.scrollForNextCalculateItemsInView = void 0;
935
+ if (peek$(ctx, "containersDidLayout")) {
936
+ doit();
937
+ } else {
938
+ requestAnimationFrame(doit);
939
+ }
940
+ const threshold = state.scroll - positionDiff / 2;
941
+ if (!state.ignoreScrollFromMVCP) {
942
+ state.ignoreScrollFromMVCP = {};
943
+ }
944
+ if (positionDiff > 0) {
945
+ state.ignoreScrollFromMVCP.lt = threshold;
946
+ } else {
947
+ state.ignoreScrollFromMVCP.gt = threshold;
948
+ }
949
+ if (state.ignoreScrollFromMVCPTimeout) {
950
+ clearTimeout(state.ignoreScrollFromMVCPTimeout);
951
+ }
952
+ state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
953
+ state.ignoreScrollFromMVCP = void 0;
954
+ }, 100);
774
955
  }
775
- setDisableAdjust(disable) {
776
- this.isDisabled = disable;
956
+ }
957
+
958
+ // src/prepareMVCP.ts
959
+ function prepareMVCP(ctx, state) {
960
+ const {
961
+ positions,
962
+ scrollingTo,
963
+ props: { maintainVisibleContentPosition }
964
+ } = state;
965
+ let prevPosition;
966
+ let targetId;
967
+ let targetIndex;
968
+ const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
969
+ if (maintainVisibleContentPosition) {
970
+ const indexByKey = state.indexByKey;
971
+ if (scrollTarget !== void 0) {
972
+ targetId = getId(state, scrollTarget);
973
+ targetIndex = scrollTarget;
974
+ } else if (state.idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
975
+ targetId = state.idsInView.find((id) => indexByKey.get(id) !== void 0);
976
+ targetIndex = indexByKey.get(targetId);
977
+ }
978
+ if (targetId !== void 0 && targetIndex !== void 0) {
979
+ prevPosition = positions.get(targetId);
980
+ }
777
981
  }
778
- // return true if it was paused
779
- unPauseAdjust() {
780
- if (this.isPaused) {
781
- this.isPaused = false;
782
- this.doAjdust();
982
+ return () => {
983
+ if (targetId !== void 0 && prevPosition !== void 0) {
984
+ const newPosition = positions.get(targetId);
985
+ if (newPosition !== void 0) {
986
+ const positionDiff = newPosition - prevPosition;
987
+ if (Math.abs(positionDiff) > 0.1) {
988
+ requestAdjust(ctx, state, positionDiff);
989
+ }
990
+ }
991
+ }
992
+ };
993
+ }
994
+
995
+ // src/checkThreshold.ts
996
+ var checkThreshold = (distance, atThreshold, threshold, isReached, isBlockedByTimer, onReached, blockTimer) => {
997
+ const distanceAbs = Math.abs(distance);
998
+ const isAtThreshold = atThreshold || distanceAbs < threshold;
999
+ if (!isReached && !isBlockedByTimer) {
1000
+ if (isAtThreshold) {
1001
+ onReached == null ? void 0 : onReached(distance);
1002
+ blockTimer == null ? void 0 : blockTimer(true);
1003
+ setTimeout(() => {
1004
+ blockTimer == null ? void 0 : blockTimer(false);
1005
+ }, 700);
783
1006
  return true;
784
1007
  }
785
- return false;
1008
+ } else {
1009
+ if (distance >= 1.3 * threshold) {
1010
+ return false;
1011
+ }
786
1012
  }
1013
+ return isReached;
787
1014
  };
788
- var useCombinedRef = (...refs) => {
789
- const callback = React2.useCallback((element) => {
790
- for (const ref of refs) {
791
- if (!ref) {
792
- continue;
1015
+
1016
+ // src/checkAtBottom.ts
1017
+ function checkAtBottom(ctx, state) {
1018
+ if (!state) {
1019
+ return;
1020
+ }
1021
+ const {
1022
+ queuedInitialLayout,
1023
+ scrollLength,
1024
+ scroll,
1025
+ maintainingScrollAtEnd,
1026
+ props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
1027
+ } = state;
1028
+ const contentSize = getContentSize(ctx);
1029
+ if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1030
+ const distanceFromEnd = contentSize - scroll - scrollLength;
1031
+ const isContentLess = contentSize < scrollLength;
1032
+ state.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1033
+ state.isEndReached = checkThreshold(
1034
+ distanceFromEnd,
1035
+ isContentLess,
1036
+ onEndReachedThreshold * scrollLength,
1037
+ state.isEndReached,
1038
+ state.endReachedBlockedByTimer,
1039
+ (distance) => {
1040
+ var _a, _b;
1041
+ return (_b = (_a = state.props).onEndReached) == null ? void 0 : _b.call(_a, { distanceFromEnd: distance });
1042
+ },
1043
+ (block) => {
1044
+ state.endReachedBlockedByTimer = block;
793
1045
  }
794
- if (isFunction(ref)) {
795
- ref(element);
796
- } else {
797
- ref.current = element;
1046
+ );
1047
+ }
1048
+ }
1049
+
1050
+ // src/finishScrollTo.ts
1051
+ var finishScrollTo = (state) => {
1052
+ if (state) {
1053
+ state.scrollingTo = void 0;
1054
+ state.scrollHistory.length = 0;
1055
+ }
1056
+ };
1057
+
1058
+ // src/scrollTo.ts
1059
+ function scrollTo(state, params = {}) {
1060
+ var _a;
1061
+ const { animated } = params;
1062
+ const {
1063
+ refScroller,
1064
+ props: { horizontal }
1065
+ } = state;
1066
+ const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
1067
+ state.scrollHistory.length = 0;
1068
+ state.scrollingTo = params;
1069
+ state.scrollPending = offset;
1070
+ (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
1071
+ x: horizontal ? offset : 0,
1072
+ y: horizontal ? 0 : offset,
1073
+ animated: !!animated
1074
+ });
1075
+ if (!animated) {
1076
+ state.scroll = offset;
1077
+ setTimeout(() => finishScrollTo(state), 100);
1078
+ }
1079
+ }
1080
+
1081
+ // src/scrollToIndex.ts
1082
+ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
1083
+ if (index >= state.props.data.length) {
1084
+ index = state.props.data.length - 1;
1085
+ } else if (index < 0) {
1086
+ index = 0;
1087
+ }
1088
+ const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
1089
+ const isLast = index === state.props.data.length - 1;
1090
+ if (isLast && viewPosition === void 0) {
1091
+ viewPosition = 1;
1092
+ }
1093
+ const firstIndexScrollPostion = firstIndexOffset - viewOffset;
1094
+ state.scrollForNextCalculateItemsInView = void 0;
1095
+ scrollTo(state, {
1096
+ offset: firstIndexScrollPostion,
1097
+ animated,
1098
+ index,
1099
+ viewPosition: viewPosition != null ? viewPosition : 0,
1100
+ viewOffset
1101
+ });
1102
+ }
1103
+
1104
+ // src/setDidLayout.ts
1105
+ function setDidLayout(ctx, state) {
1106
+ const {
1107
+ loadStartTime,
1108
+ initialScroll,
1109
+ props: { onLoad }
1110
+ } = state;
1111
+ state.queuedInitialLayout = true;
1112
+ checkAtBottom(ctx, state);
1113
+ if (!IsNewArchitecture && initialScroll) {
1114
+ scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1115
+ }
1116
+ set$(ctx, "containersDidLayout", true);
1117
+ if (onLoad) {
1118
+ onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1119
+ }
1120
+ }
1121
+
1122
+ // src/setPaddingTop.ts
1123
+ function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
1124
+ if (stylePaddingTop !== void 0) {
1125
+ const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1126
+ if (stylePaddingTop < prevStylePaddingTop) {
1127
+ const prevTotalSize = peek$(ctx, "totalSize") || 0;
1128
+ set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1129
+ setTimeout(() => {
1130
+ set$(ctx, "totalSize", prevTotalSize);
1131
+ }, 16);
1132
+ }
1133
+ set$(ctx, "stylePaddingTop", stylePaddingTop);
1134
+ }
1135
+ if (alignItemsPaddingTop !== void 0) {
1136
+ set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1137
+ }
1138
+ }
1139
+
1140
+ // src/updateAlignItemsPaddingTop.ts
1141
+ function updateAlignItemsPaddingTop(ctx, state) {
1142
+ const {
1143
+ scrollLength,
1144
+ props: { alignItemsAtEnd, data }
1145
+ } = state;
1146
+ if (alignItemsAtEnd) {
1147
+ let alignItemsPaddingTop = 0;
1148
+ if ((data == null ? void 0 : data.length) > 0) {
1149
+ const contentSize = getContentSize(ctx);
1150
+ alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1151
+ }
1152
+ setPaddingTop(ctx, { alignItemsPaddingTop });
1153
+ }
1154
+ }
1155
+
1156
+ // src/updateTotalSize.ts
1157
+ function updateTotalSize(ctx, state) {
1158
+ const {
1159
+ positions,
1160
+ props: { data }
1161
+ } = state;
1162
+ if (data.length === 0) {
1163
+ addTotalSize(ctx, state, null, 0);
1164
+ } else {
1165
+ const lastId = getId(state, data.length - 1);
1166
+ if (lastId !== void 0) {
1167
+ const lastPosition = positions.get(lastId);
1168
+ if (lastPosition !== void 0) {
1169
+ const lastSize = getItemSize(state, lastId, data.length - 1, data[data.length - 1]);
1170
+ if (lastSize !== void 0) {
1171
+ const totalSize = lastPosition + lastSize;
1172
+ addTotalSize(ctx, state, null, totalSize);
1173
+ }
798
1174
  }
799
1175
  }
800
- }, refs);
801
- return callback;
802
- };
1176
+ }
1177
+ }
1178
+ function addTotalSize(ctx, state, key, add) {
1179
+ const { alignItemsAtEnd } = state.props;
1180
+ {
1181
+ state.totalSize = add;
1182
+ }
1183
+ set$(ctx, "totalSize", state.totalSize);
1184
+ if (alignItemsAtEnd) {
1185
+ updateAlignItemsPaddingTop(ctx, state);
1186
+ }
1187
+ }
1188
+
1189
+ // src/updateAllPositions.ts
1190
+ function updateAllPositions(ctx, state, dataChanged) {
1191
+ var _a, _b, _c, _d, _e;
1192
+ const { averageSizes, columns, indexByKey, positions, firstFullyOnScreenIndex, idCache, sizesKnown } = state;
1193
+ const data = state.props.data;
1194
+ const numColumns = peek$(ctx, "numColumns");
1195
+ const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
1196
+ const scrollVelocity = getScrollVelocity(state);
1197
+ if (dataChanged) {
1198
+ indexByKey.clear();
1199
+ idCache.clear();
1200
+ }
1201
+ const itemType = "";
1202
+ let averageSize = (_a = averageSizes[itemType]) == null ? void 0 : _a.avg;
1203
+ if (averageSize !== void 0) {
1204
+ averageSize = roundSize(averageSize);
1205
+ }
1206
+ const shouldUseBackwards = !dataChanged && scrollVelocity < 0 && firstFullyOnScreenIndex > 5 && firstFullyOnScreenIndex < data.length;
1207
+ if (shouldUseBackwards && firstFullyOnScreenIndex !== void 0) {
1208
+ const anchorId = getId(state, firstFullyOnScreenIndex);
1209
+ const anchorPosition = positions.get(anchorId);
1210
+ if (anchorPosition !== void 0) {
1211
+ let currentRowTop2 = anchorPosition;
1212
+ let maxSizeInRow2 = 0;
1213
+ let bailout = false;
1214
+ for (let i = firstFullyOnScreenIndex - 1; i >= 0; i--) {
1215
+ const id = (_b = idCache.get(i)) != null ? _b : getId(state, i);
1216
+ const size = (_c = sizesKnown.get(id)) != null ? _c : getItemSize(state, id, i, data[i], averageSize);
1217
+ const itemColumn = columns.get(id);
1218
+ maxSizeInRow2 = Math.max(maxSizeInRow2, size);
1219
+ if (itemColumn === 1) {
1220
+ currentRowTop2 -= maxSizeInRow2;
1221
+ maxSizeInRow2 = 0;
1222
+ }
1223
+ if (currentRowTop2 < -2e3) {
1224
+ bailout = true;
1225
+ break;
1226
+ }
1227
+ positions.set(id, currentRowTop2);
1228
+ }
1229
+ if (!bailout) {
1230
+ updateTotalSize(ctx, state);
1231
+ return;
1232
+ }
1233
+ }
1234
+ }
1235
+ let currentRowTop = 0;
1236
+ let column = 1;
1237
+ let maxSizeInRow = 0;
1238
+ const hasColumns = numColumns > 1;
1239
+ const needsIndexByKey = dataChanged || indexByKey.size === 0;
1240
+ const dataLength = data.length;
1241
+ for (let i = 0; i < dataLength; i++) {
1242
+ const id = (_d = idCache.get(i)) != null ? _d : getId(state, i);
1243
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(state, id, i, data[i], averageSize);
1244
+ if (__DEV__ && needsIndexByKey) {
1245
+ if (indexByKeyForChecking.has(id)) {
1246
+ console.error(
1247
+ `[legend-list] Error: Detected overlapping key (${id}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
1248
+ );
1249
+ }
1250
+ indexByKeyForChecking.set(id, i);
1251
+ }
1252
+ positions.set(id, currentRowTop);
1253
+ if (needsIndexByKey) {
1254
+ indexByKey.set(id, i);
1255
+ }
1256
+ columns.set(id, column);
1257
+ if (hasColumns) {
1258
+ if (size > maxSizeInRow) {
1259
+ maxSizeInRow = size;
1260
+ }
1261
+ column++;
1262
+ if (column > numColumns) {
1263
+ currentRowTop += maxSizeInRow;
1264
+ column = 1;
1265
+ maxSizeInRow = 0;
1266
+ }
1267
+ } else {
1268
+ currentRowTop += size;
1269
+ }
1270
+ }
1271
+ updateTotalSize(ctx, state);
1272
+ }
803
1273
 
804
1274
  // src/viewability.ts
805
1275
  var mapViewabilityConfigCallbackPairs = /* @__PURE__ */ new Map();
@@ -829,7 +1299,7 @@ function setupViewability(props) {
829
1299
  }
830
1300
  return viewabilityConfigCallbackPairs;
831
1301
  }
832
- function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, getId, scrollSize, start, end) {
1302
+ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end) {
833
1303
  for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
834
1304
  const viewabilityState = mapViewabilityConfigCallbackPairs.get(
835
1305
  viewabilityConfigCallbackPair.viewabilityConfig.id
@@ -839,15 +1309,15 @@ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, getId,
839
1309
  if (viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime) {
840
1310
  const timer = setTimeout(() => {
841
1311
  state.timeouts.delete(timer);
842
- updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize);
1312
+ updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
843
1313
  }, viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime);
844
1314
  state.timeouts.add(timer);
845
1315
  } else {
846
- updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize);
1316
+ updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
847
1317
  }
848
1318
  }
849
1319
  }
850
- function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize) {
1320
+ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize) {
851
1321
  const { viewabilityConfig, onViewableItemsChanged } = viewabilityConfigCallbackPair;
852
1322
  const configId = viewabilityConfig.id;
853
1323
  const viewabilityState = mapViewabilityConfigCallbackPairs.get(configId);
@@ -891,7 +1361,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getI
891
1361
  for (let i = start; i <= end; i++) {
892
1362
  const item = data[i];
893
1363
  if (item) {
894
- const key = getId(i);
1364
+ const key = getId(state, i);
895
1365
  const containerId = findContainerId(ctx, key);
896
1366
  if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
897
1367
  const viewToken = {
@@ -930,13 +1400,12 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getI
930
1400
  }
931
1401
  }
932
1402
  function computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
933
- const { sizes, positions, scroll: scrollState, scrollAdjustHandler } = state;
1403
+ const { sizes, positions, scroll: scrollState } = state;
934
1404
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
935
1405
  const { itemVisiblePercentThreshold, viewAreaCoveragePercentThreshold } = viewabilityConfig;
936
1406
  const viewAreaMode = viewAreaCoveragePercentThreshold != null;
937
1407
  const viewablePercentThreshold = viewAreaMode ? viewAreaCoveragePercentThreshold : itemVisiblePercentThreshold;
938
- const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
939
- const scroll = scrollState - previousScrollAdjust - topPad;
1408
+ const scroll = scrollState - topPad;
940
1409
  const top = positions.get(key) - scroll;
941
1410
  const size = sizes.get(key) || 0;
942
1411
  const bottom = top + size;
@@ -988,1119 +1457,810 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
988
1457
  cb == null ? void 0 : cb(viewToken);
989
1458
  }
990
1459
 
991
- // src/LegendList.tsx
992
- var DEFAULT_DRAW_DISTANCE = 250;
993
- var DEFAULT_ITEM_SIZE = 100;
994
- function createColumnWrapperStyle(contentContainerStyle) {
995
- const { gap, columnGap, rowGap } = contentContainerStyle;
996
- if (gap || columnGap || rowGap) {
997
- contentContainerStyle.gap = void 0;
998
- contentContainerStyle.columnGap = void 0;
999
- contentContainerStyle.rowGap = void 0;
1000
- return {
1001
- gap,
1002
- columnGap,
1003
- rowGap
1004
- };
1460
+ // src/calculateItemsInView.ts
1461
+ function calculateItemsInView(ctx, state, params = {}) {
1462
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1463
+ const {
1464
+ scrollLength,
1465
+ startBufferedId: startBufferedIdOrig,
1466
+ positions,
1467
+ columns,
1468
+ containerItemKeys,
1469
+ idCache,
1470
+ sizes,
1471
+ indexByKey,
1472
+ scrollForNextCalculateItemsInView,
1473
+ enableScrollForNextCalculateItemsInView,
1474
+ minIndexSizeChanged
1475
+ } = state;
1476
+ const data = state.props.data;
1477
+ if (!data || scrollLength === 0) {
1478
+ return;
1005
1479
  }
1006
- }
1007
- var LegendList = typedForwardRef(function LegendList2(props, forwardedRef) {
1008
- return /* @__PURE__ */ React2__namespace.createElement(StateProvider, null, /* @__PURE__ */ React2__namespace.createElement(LegendListInner, { ...props, ref: forwardedRef }));
1009
- });
1010
- var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
1011
- const {
1012
- data: dataProp = [],
1013
- initialScrollIndex: initialScrollIndexProp,
1014
- initialScrollOffset,
1015
- horizontal,
1016
- drawDistance = 250,
1017
- recycleItems = false,
1018
- onEndReachedThreshold = 0.5,
1019
- onStartReachedThreshold = 0.5,
1020
- maintainScrollAtEnd = false,
1021
- maintainScrollAtEndThreshold = 0.1,
1022
- alignItemsAtEnd = false,
1023
- maintainVisibleContentPosition = false,
1024
- onScroll: onScrollProp,
1025
- onMomentumScrollEnd,
1026
- numColumns: numColumnsProp = 1,
1027
- columnWrapperStyle,
1028
- keyExtractor: keyExtractorProp,
1029
- renderItem: renderItem2,
1030
- estimatedListSize,
1031
- estimatedItemSize: estimatedItemSizeProp,
1032
- getEstimatedItemSize,
1033
- suggestEstimatedItemSize,
1034
- ListHeaderComponent,
1035
- ListEmptyComponent,
1036
- onItemSizeChanged,
1037
- refScrollView,
1038
- waitForInitialLayout = true,
1039
- extraData,
1040
- contentContainerStyle: contentContainerStyleProp,
1041
- style: styleProp,
1042
- onLayout: onLayoutProp,
1043
- onRefresh,
1044
- refreshing,
1045
- progressViewOffset,
1046
- refreshControl,
1047
- initialContainerPoolRatio = 2,
1048
- viewabilityConfig,
1049
- viewabilityConfigCallbackPairs,
1050
- onViewableItemsChanged,
1051
- ...rest
1052
- } = props;
1053
- const initialScroll = typeof initialScrollIndexProp === "number" ? { index: initialScrollIndexProp } : initialScrollIndexProp;
1054
- const initialScrollIndex = initialScroll == null ? void 0 : initialScroll.index;
1055
- const refLoadStartTime = React2.useRef(Date.now());
1056
- const callbacks = React2.useRef({
1057
- onStartReached: rest.onStartReached,
1058
- onEndReached: rest.onEndReached
1059
- });
1060
- callbacks.current.onStartReached = rest.onStartReached;
1061
- callbacks.current.onEndReached = rest.onEndReached;
1062
- const contentContainerStyle = { ...reactNative.StyleSheet.flatten(contentContainerStyleProp) };
1063
- const style = { ...reactNative.StyleSheet.flatten(styleProp) };
1064
- const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
1065
- const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
1066
- if (style == null ? void 0 : style.paddingTop) {
1067
- style.paddingTop = void 0;
1480
+ const totalSize = peek$(ctx, "totalSize");
1481
+ const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
1482
+ const numColumns = peek$(ctx, "numColumns");
1483
+ const previousScrollAdjust = 0;
1484
+ const { dataChanged, doMVCP } = params;
1485
+ const speed = getScrollVelocity(state);
1486
+ if (doMVCP || dataChanged) {
1487
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, state) : void 0;
1488
+ updateAllPositions(ctx, state, dataChanged);
1489
+ checkMVCP == null ? void 0 : checkMVCP();
1068
1490
  }
1069
- if (contentContainerStyle == null ? void 0 : contentContainerStyle.paddingTop) {
1070
- contentContainerStyle.paddingTop = void 0;
1491
+ const scrollExtra = 0;
1492
+ const { queuedInitialLayout } = state;
1493
+ let { scroll: scrollState } = state;
1494
+ const initialScroll = state.props.initialScroll;
1495
+ if (!queuedInitialLayout && initialScroll) {
1496
+ const updatedOffset = calculateOffsetWithOffsetPosition(
1497
+ state,
1498
+ calculateOffsetForIndex(ctx, state, initialScroll.index),
1499
+ initialScroll
1500
+ );
1501
+ scrollState = updatedOffset;
1071
1502
  }
1072
- const ctx = useStateContext();
1073
- ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
1074
- const refScroller = React2.useRef(null);
1075
- const combinedRef = useCombinedRef(refScroller, refScrollView);
1076
- const estimatedItemSize = estimatedItemSizeProp != null ? estimatedItemSizeProp : DEFAULT_ITEM_SIZE;
1077
- const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
1078
- const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (item, index) => index.toString();
1079
- const refState = React2.useRef();
1080
- const getId = (index) => {
1081
- var _a;
1082
- const data = (_a = refState.current) == null ? void 0 : _a.data;
1083
- if (!data) {
1084
- return "";
1085
- }
1086
- const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
1087
- return `${ret}`;
1088
- };
1089
- const getItemSize = (key, index, data, useAverageSize = false) => {
1090
- const state = refState.current;
1091
- state.sizesKnown.get(key);
1092
- const sizePrevious = state.sizes.get(key);
1093
- let size;
1094
- peek$(ctx, "numColumns");
1095
- if (size === void 0 && sizePrevious !== void 0) {
1096
- return sizePrevious;
1097
- }
1098
- if (size === void 0) {
1099
- size = getEstimatedItemSize ? getEstimatedItemSize(index, data) : estimatedItemSize;
1100
- }
1101
- state.sizes.set(key, size);
1102
- return size;
1103
- };
1104
- const calculateOffsetForIndex = (indexParam) => {
1105
- var _a;
1106
- const isFromInit = indexParam === void 0;
1107
- const index = isFromInit ? initialScrollIndex : indexParam;
1108
- const data = dataProp;
1109
- if (index !== void 0) {
1110
- let offset = 0;
1111
- const canGetSize = !!refState.current;
1112
- if (canGetSize || getEstimatedItemSize) {
1113
- const sizeFn = (index2) => {
1114
- if (canGetSize) {
1115
- return getItemSize(getId(index2), index2, data[index2], true);
1116
- }
1117
- return getEstimatedItemSize(index2, data[index2]);
1118
- };
1119
- for (let i = 0; i < index; i++) {
1120
- offset += sizeFn(i);
1121
- }
1122
- } else {
1123
- offset = index * estimatedItemSize;
1124
- }
1125
- const adjust = peek$(ctx, "containersDidLayout") ? ((_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler.getAppliedAdjust()) || 0 : 0;
1126
- const stylePaddingTop = isFromInit ? stylePaddingTopState : peek$(ctx, "stylePaddingTop");
1127
- const topPad = (stylePaddingTop != null ? stylePaddingTop : 0) + peek$(ctx, "headerSize");
1128
- return offset / numColumnsProp - adjust + topPad;
1129
- }
1130
- return 0;
1131
- };
1132
- const calculateOffsetWithOffsetPosition = (offsetParam, params) => {
1133
- const { index, viewOffset, viewPosition } = params;
1134
- let offset = offsetParam;
1135
- const state = refState.current;
1136
- if (viewOffset) {
1137
- offset -= viewOffset;
1138
- }
1139
- if (viewPosition !== void 0 && index !== void 0) {
1140
- offset -= viewPosition * (state.scrollLength - getItemSize(getId(index), index, state.data[index]));
1141
- }
1142
- return offset;
1143
- };
1144
- const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : React2.useMemo(() => calculateOffsetForIndex(void 0), []);
1145
- if (!refState.current) {
1146
- const initialScrollLength = (estimatedListSize != null ? estimatedListSize : reactNative.Dimensions.get("window"))[horizontal ? "width" : "height"];
1147
- refState.current = {
1148
- sizes: /* @__PURE__ */ new Map(),
1149
- positions: /* @__PURE__ */ new Map(),
1150
- columns: /* @__PURE__ */ new Map(),
1151
- pendingAdjust: 0,
1152
- isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
1153
- isEndReached: false,
1154
- isAtEnd: false,
1155
- isAtStart: false,
1156
- data: dataProp,
1157
- scrollLength: initialScrollLength,
1158
- startBuffered: -1,
1159
- startNoBuffer: -1,
1160
- endBuffered: -1,
1161
- endNoBuffer: -1,
1162
- scroll: initialContentOffset || 0,
1163
- totalSize: 0,
1164
- totalSizeBelowAnchor: 0,
1165
- timeouts: /* @__PURE__ */ new Set(),
1166
- viewabilityConfigCallbackPairs: void 0,
1167
- renderItem: void 0,
1168
- scrollAdjustHandler: new ScrollAdjustHandler(ctx),
1169
- nativeMarginTop: 0,
1170
- scrollPrev: 0,
1171
- scrollPrevTime: 0,
1172
- scrollTime: 0,
1173
- scrollPending: 0,
1174
- indexByKey: /* @__PURE__ */ new Map(),
1175
- scrollHistory: [],
1176
- scrollVelocity: 0,
1177
- sizesKnown: /* @__PURE__ */ new Map(),
1178
- timeoutSizeMessage: 0,
1179
- scrollTimer: void 0,
1180
- belowAnchorElementPositions: void 0,
1181
- rowHeights: /* @__PURE__ */ new Map(),
1182
- startReachedBlockedByTimer: false,
1183
- endReachedBlockedByTimer: false,
1184
- scrollForNextCalculateItemsInView: void 0,
1185
- enableScrollForNextCalculateItemsInView: true,
1186
- minIndexSizeChanged: 0,
1187
- queuedCalculateItemsInView: 0,
1188
- lastBatchingAction: Date.now(),
1189
- averageSizes: {},
1190
- onScroll: onScrollProp
1191
- };
1192
- const dataLength = dataProp.length;
1193
- if (maintainVisibleContentPosition && dataLength > 0) {
1194
- if (initialScrollIndex && initialScrollIndex < dataLength) {
1195
- refState.current.anchorElement = {
1196
- coordinate: initialContentOffset,
1197
- id: getId(initialScrollIndex)
1198
- };
1199
- } else if (dataLength > 0) {
1200
- refState.current.anchorElement = {
1201
- coordinate: initialContentOffset,
1202
- id: getId(0)
1203
- };
1204
- } else {
1205
- __DEV__ && warnDevOnce(
1206
- "maintainVisibleContentPosition",
1207
- "[legend-list] maintainVisibleContentPosition was not able to find an anchor element"
1208
- );
1209
- }
1210
- }
1211
- set$(ctx, "scrollAdjust", 0);
1212
- set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
1213
- set$(ctx, "extraData", extraData);
1503
+ const scrollAdjustPad = -previousScrollAdjust - topPad;
1504
+ let scroll = scrollState + scrollExtra + scrollAdjustPad;
1505
+ if (scroll + scrollLength > totalSize) {
1506
+ scroll = totalSize - scrollLength;
1214
1507
  }
1215
- const didDataChange = refState.current.data !== dataProp;
1216
- refState.current.data = dataProp;
1217
- refState.current.onScroll = onScrollProp;
1218
- const getAnchorElementIndex = () => {
1219
- const state = refState.current;
1220
- if (state.anchorElement) {
1221
- const el = state.indexByKey.get(state.anchorElement.id);
1222
- return el;
1223
- }
1224
- return void 0;
1225
- };
1226
- const scrollToIndex = ({
1227
- index,
1228
- viewOffset = 0,
1229
- animated = true,
1230
- viewPosition
1231
- }) => {
1232
- var _a;
1233
- const state = refState.current;
1234
- if (index >= state.data.length) {
1235
- index = state.data.length - 1;
1236
- } else if (index < 0) {
1237
- index = 0;
1238
- }
1239
- const firstIndexOffset = calculateOffsetForIndex(index);
1240
- const isLast = index === state.data.length - 1;
1241
- if (isLast && viewPosition !== void 0) {
1242
- viewPosition = 1;
1243
- }
1244
- let firstIndexScrollPostion = firstIndexOffset - viewOffset;
1245
- const diff = Math.abs(state.scroll - firstIndexScrollPostion);
1246
- const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
1247
- const needsReanchoring = maintainVisibleContentPosition && diff > 100;
1248
- state.scrollForNextCalculateItemsInView = void 0;
1249
- if (needsReanchoring) {
1250
- const id = getId(index);
1251
- state.anchorElement = { id, coordinate: firstIndexOffset - topPad };
1252
- (_a = state.belowAnchorElementPositions) == null ? void 0 : _a.clear();
1253
- state.positions.clear();
1254
- calcTotalSizesAndPositions({ forgetPositions: true });
1255
- state.startBufferedId = id;
1256
- state.minIndexSizeChanged = index;
1257
- firstIndexScrollPostion = firstIndexOffset - viewOffset + state.scrollAdjustHandler.getAppliedAdjust();
1258
- }
1259
- scrollTo({ offset: firstIndexScrollPostion, animated, index, viewPosition: viewPosition != null ? viewPosition : 0, viewOffset });
1260
- };
1261
- const setDidLayout = () => {
1262
- refState.current.queuedInitialLayout = true;
1263
- checkAtBottom();
1264
- const setIt = () => {
1265
- set$(ctx, "containersDidLayout", true);
1266
- if (props.onLoad) {
1267
- props.onLoad({ elapsedTimeInMs: Date.now() - refLoadStartTime.current });
1268
- }
1269
- };
1270
- if (initialScroll) {
1271
- queueMicrotask(() => {
1272
- scrollToIndex({ ...initialScroll, animated: false });
1273
- requestAnimationFrame(() => {
1274
- if (!IsNewArchitecture) {
1275
- scrollToIndex({ ...initialScroll, animated: false });
1276
- }
1277
- setIt();
1278
- });
1279
- });
1280
- } else {
1281
- queueMicrotask(setIt);
1282
- }
1283
- };
1284
- const addTotalSize = React2.useCallback((key, add, totalSizeBelowAnchor) => {
1285
- const state = refState.current;
1286
- const { indexByKey, anchorElement } = state;
1287
- const index = key === null ? 0 : indexByKey.get(key);
1288
- let isAboveAnchor = false;
1289
- if (maintainVisibleContentPosition) {
1290
- if (anchorElement && index < getAnchorElementIndex()) {
1291
- isAboveAnchor = true;
1292
- }
1508
+ if (ENABLE_DEBUG_VIEW) {
1509
+ set$(ctx, "debugRawScroll", scrollState);
1510
+ set$(ctx, "debugComputedScroll", scroll);
1511
+ }
1512
+ const scrollBuffer = state.props.scrollBuffer;
1513
+ let scrollBufferTop = scrollBuffer;
1514
+ let scrollBufferBottom = scrollBuffer;
1515
+ if (speed > 0) {
1516
+ scrollBufferTop = scrollBuffer * 0.5;
1517
+ scrollBufferBottom = scrollBuffer * 1.5;
1518
+ } else {
1519
+ scrollBufferTop = scrollBuffer * 1.5;
1520
+ scrollBufferBottom = scrollBuffer * 0.5;
1521
+ }
1522
+ const scrollTopBuffered = scroll - scrollBufferTop;
1523
+ const scrollBottom = scroll + scrollLength;
1524
+ const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
1525
+ if (scrollForNextCalculateItemsInView) {
1526
+ const { top, bottom } = scrollForNextCalculateItemsInView;
1527
+ if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
1528
+ return;
1293
1529
  }
1294
- if (key === null) {
1295
- state.totalSize = add;
1296
- state.totalSizeBelowAnchor = totalSizeBelowAnchor;
1530
+ }
1531
+ let startNoBuffer = null;
1532
+ let startBuffered = null;
1533
+ let startBufferedId = null;
1534
+ let endNoBuffer = null;
1535
+ let endBuffered = null;
1536
+ let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
1537
+ if (minIndexSizeChanged !== void 0) {
1538
+ loopStart = Math.min(minIndexSizeChanged, loopStart);
1539
+ state.minIndexSizeChanged = void 0;
1540
+ }
1541
+ for (let i = loopStart; i >= 0; i--) {
1542
+ const id = (_a = idCache.get(i)) != null ? _a : getId(state, i);
1543
+ const top = positions.get(id);
1544
+ const size = (_b = sizes.get(id)) != null ? _b : getItemSize(state, id, i, data[i]);
1545
+ const bottom = top + size;
1546
+ if (bottom > scroll - scrollBuffer) {
1547
+ loopStart = i;
1297
1548
  } else {
1298
- state.totalSize += add;
1299
- if (isAboveAnchor) {
1300
- state.totalSizeBelowAnchor += add;
1301
- }
1549
+ break;
1302
1550
  }
1303
- let applyAdjustValue = 0;
1304
- let resultSize = state.totalSize;
1305
- if (maintainVisibleContentPosition && anchorElement !== void 0) {
1306
- const newAdjust = anchorElement.coordinate - state.totalSizeBelowAnchor;
1307
- applyAdjustValue = -newAdjust;
1308
- state.belowAnchorElementPositions = buildElementPositionsBelowAnchor();
1309
- state.rowHeights.clear();
1310
- if (applyAdjustValue !== void 0) {
1311
- resultSize -= applyAdjustValue;
1312
- state.scrollAdjustHandler.requestAdjust(applyAdjustValue, (diff) => {
1313
- state.scroll -= diff;
1314
- });
1315
- }
1316
- }
1317
- set$(ctx, "totalSize", state.totalSize);
1318
- set$(ctx, "totalSizeWithScrollAdjust", resultSize);
1319
- if (alignItemsAtEnd) {
1320
- updateAlignItemsPaddingTop();
1321
- }
1322
- }, []);
1323
- const getRowHeight = (n) => {
1324
- const { rowHeights, data } = refState.current;
1325
- const numColumns = peek$(ctx, "numColumns");
1326
- if (numColumns === 1) {
1327
- const id = getId(n);
1328
- return getItemSize(id, n, data[n]);
1329
- }
1330
- if (rowHeights.has(n)) {
1331
- return rowHeights.get(n) || 0;
1332
- }
1333
- let rowHeight = 0;
1334
- const startEl = n * numColumns;
1335
- for (let i = startEl; i < startEl + numColumns && i < data.length; i++) {
1336
- const id = getId(i);
1337
- const size = getItemSize(id, i, data[i]);
1338
- rowHeight = Math.max(rowHeight, size);
1339
- }
1340
- rowHeights.set(n, rowHeight);
1341
- return rowHeight;
1342
- };
1343
- const buildElementPositionsBelowAnchor = () => {
1344
- const state = refState.current;
1345
- if (!state.anchorElement) {
1346
- return /* @__PURE__ */ new Map();
1347
- }
1348
- const anchorIndex = state.indexByKey.get(state.anchorElement.id);
1349
- if (anchorIndex === 0) {
1350
- return /* @__PURE__ */ new Map();
1351
- }
1352
- const map = state.belowAnchorElementPositions || /* @__PURE__ */ new Map();
1353
- const numColumns = peek$(ctx, "numColumns");
1354
- let top = state.anchorElement.coordinate;
1355
- for (let i = anchorIndex - 1; i >= 0; i--) {
1356
- const id = getId(i);
1357
- const rowNumber = Math.floor(i / numColumns);
1358
- if (i % numColumns === 0) {
1359
- top -= getRowHeight(rowNumber);
1360
- }
1361
- map.set(id, top);
1551
+ }
1552
+ const loopStartMod = loopStart % numColumns;
1553
+ if (loopStartMod > 0) {
1554
+ loopStart -= loopStartMod;
1555
+ }
1556
+ let foundEnd = false;
1557
+ let nextTop;
1558
+ let nextBottom;
1559
+ const prevNumContainers = ctx.values.get("numContainers");
1560
+ let maxIndexRendered = 0;
1561
+ for (let i = 0; i < prevNumContainers; i++) {
1562
+ const key = peek$(ctx, `containerItemKey${i}`);
1563
+ if (key !== void 0) {
1564
+ const index = indexByKey.get(key);
1565
+ maxIndexRendered = Math.max(maxIndexRendered, index);
1362
1566
  }
1363
- return map;
1364
- };
1365
- const disableScrollJumps = (timeout) => {
1366
- const state = refState.current;
1367
- if (state.scrollingTo === void 0) {
1368
- state.disableScrollJumpsFrom = state.scroll - state.scrollAdjustHandler.getAppliedAdjust();
1369
- state.scrollHistory.length = 0;
1370
- setTimeout(() => {
1371
- state.disableScrollJumpsFrom = void 0;
1372
- if (state.scrollPending !== void 0 && state.scrollPending !== state.scroll) {
1373
- updateScroll(state.scrollPending);
1567
+ }
1568
+ let firstFullyOnScreenIndex;
1569
+ const dataLength = data.length;
1570
+ for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
1571
+ const id = (_c = idCache.get(i)) != null ? _c : getId(state, i);
1572
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(state, id, i, data[i]);
1573
+ const top = positions.get(id);
1574
+ if (!foundEnd) {
1575
+ if (startNoBuffer === null && top + size > scroll) {
1576
+ startNoBuffer = i;
1577
+ }
1578
+ if (firstFullyOnScreenIndex === void 0 && top >= scroll - 10) {
1579
+ firstFullyOnScreenIndex = i;
1580
+ }
1581
+ if (startBuffered === null && top + size > scrollTopBuffered) {
1582
+ startBuffered = i;
1583
+ startBufferedId = id;
1584
+ nextTop = top;
1585
+ }
1586
+ if (startNoBuffer !== null) {
1587
+ if (top <= scrollBottom) {
1588
+ endNoBuffer = i;
1374
1589
  }
1375
- }, timeout);
1376
- }
1377
- };
1378
- const getElementPositionBelowAchor = (id) => {
1379
- var _a;
1380
- const state = refState.current;
1381
- if (!refState.current.belowAnchorElementPositions) {
1382
- state.belowAnchorElementPositions = buildElementPositionsBelowAnchor();
1383
- }
1384
- const res = state.belowAnchorElementPositions.get(id);
1385
- if (res === void 0) {
1386
- console.warn(`Undefined position below anchor ${id} ${(_a = state.anchorElement) == null ? void 0 : _a.id}`);
1387
- return 0;
1388
- }
1389
- return res;
1390
- };
1391
- const fixGaps = React2.useCallback(() => {
1392
- var _a;
1393
- const state = refState.current;
1394
- const { data, scrollLength, positions, startBuffered, endBuffered } = state;
1395
- const numColumns = peek$(ctx, "numColumns");
1396
- if (!data || scrollLength === 0 || numColumns > 1) {
1397
- return;
1398
- }
1399
- const numContainers = ctx.values.get("numContainers");
1400
- let numMeasurements = 0;
1401
- for (let i = 0; i < numContainers; i++) {
1402
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1403
- const isSizeKnown = state.sizesKnown.get(itemKey);
1404
- if (itemKey && !isSizeKnown) {
1405
- const containerRef = ctx.viewRefs.get(i);
1406
- if (containerRef) {
1407
- let measured;
1408
- (_a = containerRef.current) == null ? void 0 : _a.measure((x, y, width, height) => {
1409
- measured = { width, height };
1410
- });
1411
- numMeasurements++;
1412
- if (measured) {
1413
- updateItemSize(
1414
- itemKey,
1415
- measured,
1416
- /*fromFixGaps*/
1417
- true
1418
- );
1419
- }
1590
+ if (top <= scrollBottomBuffered) {
1591
+ endBuffered = i;
1592
+ nextBottom = top + size;
1593
+ } else {
1594
+ foundEnd = true;
1420
1595
  }
1421
1596
  }
1422
1597
  }
1423
- if (numMeasurements > 0) {
1424
- let top;
1425
- const diffs = /* @__PURE__ */ new Map();
1426
- for (let i = startBuffered; i <= endBuffered; i++) {
1427
- const id = getId(i);
1428
- if (top === void 0) {
1429
- top = positions.get(id);
1430
- }
1431
- if (positions.get(id) !== top) {
1432
- diffs.set(id, top - positions.get(id));
1433
- positions.set(id, top);
1434
- }
1435
- const size = getItemSize(id, i, data[i]);
1436
- const bottom = top + size;
1437
- top = bottom;
1438
- }
1439
- for (let i = 0; i < numContainers; i++) {
1440
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1441
- const diff = diffs.get(itemKey);
1442
- if (diff) {
1443
- const prevPos = peek$(ctx, `containerPosition${i}`);
1444
- const newPos = prevPos.top + diff;
1445
- if (prevPos.top !== newPos) {
1446
- const pos = { ...prevPos };
1447
- pos.relativeCoordinate += diff;
1448
- pos.top += diff;
1449
- set$(ctx, `containerPosition${i}`, pos);
1450
- }
1451
- }
1598
+ }
1599
+ const idsInView = [];
1600
+ for (let i = firstFullyOnScreenIndex; i <= endNoBuffer; i++) {
1601
+ const id = (_e = idCache.get(i)) != null ? _e : getId(state, i);
1602
+ idsInView.push(id);
1603
+ }
1604
+ Object.assign(state, {
1605
+ startBuffered,
1606
+ startBufferedId,
1607
+ startNoBuffer,
1608
+ endBuffered,
1609
+ endNoBuffer,
1610
+ idsInView,
1611
+ firstFullyOnScreenIndex
1612
+ });
1613
+ if (enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0) {
1614
+ state.scrollForNextCalculateItemsInView = nextTop !== void 0 && nextBottom !== void 0 ? {
1615
+ top: nextTop,
1616
+ bottom: nextBottom
1617
+ } : void 0;
1618
+ }
1619
+ const numContainers = peek$(ctx, "numContainers");
1620
+ const pendingRemoval = [];
1621
+ if (dataChanged) {
1622
+ for (let i = 0; i < numContainers; i++) {
1623
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
1624
+ if (!state.props.keyExtractor || itemKey && indexByKey.get(itemKey) === void 0) {
1625
+ pendingRemoval.push(i);
1452
1626
  }
1453
1627
  }
1454
- }, []);
1455
- const checkAllSizesKnown = React2.useCallback(() => {
1456
- const { startBuffered, endBuffered, sizesKnown } = refState.current;
1457
- if (endBuffered !== null) {
1458
- let areAllKnown = true;
1459
- for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
1460
- const key = getId(i);
1461
- areAllKnown && (areAllKnown = sizesKnown.has(key));
1628
+ }
1629
+ if (startBuffered !== null && endBuffered !== null) {
1630
+ let numContainers2 = prevNumContainers;
1631
+ const needNewContainers = [];
1632
+ for (let i = startBuffered; i <= endBuffered; i++) {
1633
+ const id = (_f = idCache.get(i)) != null ? _f : getId(state, i);
1634
+ if (!containerItemKeys.has(id)) {
1635
+ needNewContainers.push(i);
1462
1636
  }
1463
- return areAllKnown;
1464
- }
1465
- return false;
1466
- }, []);
1467
- const calculateItemsInView = React2.useCallback((isReset) => {
1468
- var _a;
1469
- const state = refState.current;
1470
- const {
1471
- data,
1472
- scrollLength,
1473
- startBufferedId: startBufferedIdOrig,
1474
- positions,
1475
- columns,
1476
- scrollAdjustHandler,
1477
- scrollVelocity: speed
1478
- } = state;
1479
- if (!data || scrollLength === 0) {
1480
- return;
1481
1637
  }
1482
- const totalSize = peek$(ctx, "totalSizeWithScrollAdjust");
1483
- const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
1484
- const numColumns = peek$(ctx, "numColumns");
1485
- const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
1486
- let scrollState = state.scroll;
1487
- const scrollExtra = 0;
1488
- const useAverageSize = !state.disableScrollJumpsFrom && speed >= 0 && peek$(ctx, "containersDidLayout");
1489
- if (!state.queuedInitialLayout && initialScroll) {
1490
- const updatedOffset = calculateOffsetWithOffsetPosition(
1491
- calculateOffsetForIndex(initialScroll.index),
1492
- initialScroll
1638
+ if (needNewContainers.length > 0) {
1639
+ const availableContainers = findAvailableContainers(
1640
+ ctx,
1641
+ state,
1642
+ needNewContainers.length,
1643
+ startBuffered,
1644
+ endBuffered,
1645
+ pendingRemoval
1493
1646
  );
1494
- scrollState = updatedOffset;
1495
- }
1496
- const scrollAdjustPad = -previousScrollAdjust - topPad;
1497
- let scroll = scrollState + scrollExtra + scrollAdjustPad;
1498
- if (scroll + scrollLength > totalSize) {
1499
- scroll = totalSize - scrollLength;
1500
- }
1501
- if (ENABLE_DEBUG_VIEW) {
1502
- set$(ctx, "debugRawScroll", scrollState);
1503
- set$(ctx, "debugComputedScroll", scroll);
1504
- }
1505
- let scrollBufferTop = scrollBuffer;
1506
- let scrollBufferBottom = scrollBuffer;
1507
- if (Math.abs(speed) > 4) {
1508
- if (speed > 0) {
1509
- scrollBufferTop = scrollBuffer * 0.1;
1510
- scrollBufferBottom = scrollBuffer * 1.9;
1511
- } else {
1512
- scrollBufferTop = scrollBuffer * 1.9;
1513
- scrollBufferBottom = scrollBuffer * 0.1;
1514
- }
1515
- }
1516
- const scrollTopBuffered = scroll - scrollBufferTop;
1517
- const scrollBottom = scroll + scrollLength;
1518
- const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
1519
- if (state.scrollForNextCalculateItemsInView) {
1520
- const { top: top2, bottom } = state.scrollForNextCalculateItemsInView;
1521
- if (scrollTopBuffered > top2 && scrollBottomBuffered < bottom) {
1522
- return;
1523
- }
1524
- }
1525
- let startNoBuffer = null;
1526
- let startBuffered = null;
1527
- let startBufferedId = null;
1528
- let endNoBuffer = null;
1529
- let endBuffered = null;
1530
- let loopStart = startBufferedIdOrig ? state.indexByKey.get(startBufferedIdOrig) || 0 : 0;
1531
- if (state.minIndexSizeChanged !== void 0) {
1532
- loopStart = Math.min(state.minIndexSizeChanged, loopStart);
1533
- state.minIndexSizeChanged = void 0;
1534
- }
1535
- const anchorElementIndex = getAnchorElementIndex();
1536
- for (let i = loopStart; i >= 0; i--) {
1537
- const id = getId(i);
1538
- let newPosition;
1539
- if (maintainVisibleContentPosition && anchorElementIndex && i < anchorElementIndex) {
1540
- newPosition = getElementPositionBelowAchor(id);
1541
- if (newPosition !== void 0) {
1542
- positions.set(id, newPosition);
1647
+ for (let idx = 0; idx < needNewContainers.length; idx++) {
1648
+ const i = needNewContainers[idx];
1649
+ const containerIndex = availableContainers[idx];
1650
+ const id = (_g = idCache.get(i)) != null ? _g : getId(state, i);
1651
+ const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
1652
+ if (oldKey && oldKey !== id) {
1653
+ containerItemKeys.delete(oldKey);
1543
1654
  }
1544
- }
1545
- const top2 = newPosition || positions.get(id);
1546
- if (top2 !== void 0) {
1547
- const size = getItemSize(id, i, data[i], useAverageSize);
1548
- const bottom = top2 + size;
1549
- if (bottom > scroll - scrollBuffer) {
1550
- loopStart = i;
1551
- } else {
1552
- break;
1655
+ set$(ctx, `containerItemKey${containerIndex}`, id);
1656
+ set$(ctx, `containerItemData${containerIndex}`, data[i]);
1657
+ containerItemKeys.add(id);
1658
+ if (containerIndex >= numContainers2) {
1659
+ numContainers2 = containerIndex + 1;
1553
1660
  }
1554
1661
  }
1555
- }
1556
- const loopStartMod = loopStart % numColumns;
1557
- if (loopStartMod > 0) {
1558
- loopStart -= loopStartMod;
1559
- }
1560
- let top = void 0;
1561
- let column = 1;
1562
- let maxSizeInRow = 0;
1563
- const getInitialTop = (i) => {
1564
- var _a2;
1565
- const id = getId(i);
1566
- let topOffset = 0;
1567
- if (positions.get(id)) {
1568
- topOffset = positions.get(id);
1569
- }
1570
- if (id === ((_a2 = state.anchorElement) == null ? void 0 : _a2.id)) {
1571
- topOffset = state.anchorElement.coordinate;
1572
- }
1573
- return topOffset;
1574
- };
1575
- let foundEnd = false;
1576
- let nextTop;
1577
- let nextBottom;
1578
- const prevNumContainers = ctx.values.get("numContainers");
1579
- let maxIndexRendered = 0;
1580
- for (let i = 0; i < prevNumContainers; i++) {
1581
- const key = peek$(ctx, `containerItemKey${i}`);
1582
- if (key !== void 0) {
1583
- const index = state.indexByKey.get(key);
1584
- maxIndexRendered = Math.max(maxIndexRendered, index);
1585
- }
1586
- }
1587
- for (let i = Math.max(0, loopStart); i < data.length && (!foundEnd || i <= maxIndexRendered); i++) {
1588
- const id = getId(i);
1589
- const size = getItemSize(id, i, data[i], useAverageSize);
1590
- maxSizeInRow = Math.max(maxSizeInRow, size);
1591
- if (top === void 0 || id === ((_a = state.anchorElement) == null ? void 0 : _a.id)) {
1592
- top = getInitialTop(i);
1593
- }
1594
- if (positions.get(id) !== top) {
1595
- positions.set(id, top);
1596
- }
1597
- if (columns.get(id) !== column) {
1598
- columns.set(id, column);
1599
- }
1600
- if (!foundEnd) {
1601
- if (startNoBuffer === null && top + size > scroll) {
1602
- startNoBuffer = i;
1603
- }
1604
- if (startBuffered === null && top + size > scrollTopBuffered) {
1605
- startBuffered = i;
1606
- startBufferedId = id;
1607
- nextTop = top;
1608
- }
1609
- if (startNoBuffer !== null) {
1610
- if (top <= scrollBottom) {
1611
- endNoBuffer = i;
1612
- }
1613
- if (top <= scrollBottomBuffered) {
1614
- endBuffered = i;
1615
- nextBottom = top + maxSizeInRow - scrollLength;
1616
- } else {
1617
- foundEnd = true;
1618
- }
1662
+ if (numContainers2 !== prevNumContainers) {
1663
+ set$(ctx, "numContainers", numContainers2);
1664
+ if (numContainers2 > peek$(ctx, "numContainersPooled")) {
1665
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
1619
1666
  }
1620
1667
  }
1621
- column++;
1622
- if (column > numColumns) {
1623
- top += maxSizeInRow;
1624
- column = 1;
1625
- maxSizeInRow = 0;
1626
- }
1627
1668
  }
1628
- Object.assign(state, {
1629
- startBuffered,
1630
- startBufferedId,
1631
- startNoBuffer,
1632
- endBuffered,
1633
- endNoBuffer
1634
- });
1635
- if (state.enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0 && state.disableScrollJumpsFrom === void 0) {
1636
- state.scrollForNextCalculateItemsInView = nextTop !== void 0 && nextBottom !== void 0 ? {
1637
- top: nextTop,
1638
- bottom: nextBottom
1639
- } : void 0;
1640
- }
1641
- if (startBuffered !== null && endBuffered !== null) {
1642
- let numContainers = prevNumContainers;
1643
- const needNewContainers = [];
1644
- const isContained = (i) => {
1645
- const id = getId(i);
1646
- for (let j = 0; j < numContainers; j++) {
1647
- const key = peek$(ctx, `containerItemKey${j}`);
1648
- if (key === id) {
1649
- return true;
1650
- }
1651
- }
1652
- };
1653
- for (let i = startBuffered; i <= endBuffered; i++) {
1654
- if (!isContained(i)) {
1655
- needNewContainers.push(i);
1656
- }
1657
- }
1658
- if (needNewContainers.length > 0) {
1659
- const availableContainers = findAvailableContainers(
1660
- needNewContainers.length,
1661
- startBuffered,
1662
- endBuffered
1663
- );
1664
- for (let idx = 0; idx < needNewContainers.length; idx++) {
1665
- const i = needNewContainers[idx];
1666
- const containerIndex = availableContainers[idx];
1667
- const id = getId(i);
1668
- set$(ctx, `containerItemKey${containerIndex}`, id);
1669
- set$(ctx, `containerItemData${containerIndex}`, data[i]);
1670
- if (containerIndex >= numContainers) {
1671
- numContainers = containerIndex + 1;
1669
+ }
1670
+ for (let i = 0; i < numContainers; i++) {
1671
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
1672
+ if (pendingRemoval.includes(i)) {
1673
+ if (itemKey) {
1674
+ containerItemKeys.delete(itemKey);
1675
+ }
1676
+ set$(ctx, `containerItemKey${i}`, void 0);
1677
+ set$(ctx, `containerItemData${i}`, void 0);
1678
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1679
+ set$(ctx, `containerColumn${i}`, -1);
1680
+ } else {
1681
+ const itemIndex = indexByKey.get(itemKey);
1682
+ const item = data[itemIndex];
1683
+ if (item !== void 0) {
1684
+ const id = (_h = idCache.get(itemIndex)) != null ? _h : getId(state, itemIndex);
1685
+ const position = positions.get(id);
1686
+ if (position === void 0) {
1687
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1688
+ } else {
1689
+ const pos = positions.get(id);
1690
+ const column = columns.get(id) || 1;
1691
+ const prevPos = peek$(ctx, `containerPosition${i}`);
1692
+ const prevColumn = peek$(ctx, `containerColumn${i}`);
1693
+ const prevData = peek$(ctx, `containerItemData${i}`);
1694
+ if (!prevPos || pos > POSITION_OUT_OF_VIEW && pos !== prevPos) {
1695
+ set$(ctx, `containerPosition${i}`, pos);
1672
1696
  }
1673
- }
1674
- if (numContainers !== prevNumContainers) {
1675
- set$(ctx, "numContainers", numContainers);
1676
- if (numContainers > peek$(ctx, "numContainersPooled")) {
1677
- set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
1697
+ if (column >= 0 && column !== prevColumn) {
1698
+ set$(ctx, `containerColumn${i}`, column);
1678
1699
  }
1679
- }
1680
- }
1681
- for (let i = 0; i < numContainers; i++) {
1682
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1683
- const itemIndex = state.indexByKey.get(itemKey);
1684
- const item = data[itemIndex];
1685
- if (item !== void 0) {
1686
- const id = getId(itemIndex);
1687
- const position = positions.get(id);
1688
- if (position === void 0) {
1689
- set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1690
- } else {
1691
- const pos = {
1692
- type: "top",
1693
- relativeCoordinate: positions.get(id),
1694
- top: positions.get(id)
1695
- };
1696
- const column2 = columns.get(id) || 1;
1697
- if (maintainVisibleContentPosition && itemIndex < anchorElementIndex) {
1698
- const currentRow = Math.floor(itemIndex / numColumns);
1699
- const rowHeight = getRowHeight(currentRow);
1700
- const elementHeight = getItemSize(id, itemIndex, data[i]);
1701
- const diff = rowHeight - elementHeight;
1702
- pos.relativeCoordinate = pos.top + getRowHeight(currentRow) - diff;
1703
- pos.type = "bottom";
1704
- }
1705
- const prevPos = peek$(ctx, `containerPosition${i}`);
1706
- const prevColumn = peek$(ctx, `containerColumn${i}`);
1707
- const prevData = peek$(ctx, `containerItemData${i}`);
1708
- if (!prevPos || pos.relativeCoordinate > POSITION_OUT_OF_VIEW && pos.top !== prevPos.top) {
1709
- set$(ctx, `containerPosition${i}`, pos);
1710
- }
1711
- if (column2 >= 0 && column2 !== prevColumn) {
1712
- set$(ctx, `containerColumn${i}`, column2);
1713
- }
1714
- if (prevData !== item) {
1715
- set$(ctx, `containerItemData${i}`, data[itemIndex]);
1716
- }
1700
+ if (prevData !== item) {
1701
+ set$(ctx, `containerItemData${i}`, data[itemIndex]);
1717
1702
  }
1718
1703
  }
1719
1704
  }
1720
1705
  }
1721
- if (!state.queuedInitialLayout && endBuffered !== null) {
1722
- if (checkAllSizesKnown()) {
1723
- setDidLayout();
1724
- }
1725
- }
1726
- if (state.viewabilityConfigCallbackPairs) {
1727
- updateViewableItems(
1728
- state,
1729
- ctx,
1730
- state.viewabilityConfigCallbackPairs,
1731
- getId,
1732
- scrollLength,
1733
- startNoBuffer,
1734
- endNoBuffer
1735
- );
1736
- }
1737
- }, []);
1738
- const setPaddingTop = ({
1739
- stylePaddingTop,
1740
- alignItemsPaddingTop
1741
- }) => {
1742
- if (stylePaddingTop !== void 0) {
1743
- const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1744
- if (stylePaddingTop < prevStylePaddingTop) {
1745
- const prevTotalSize = peek$(ctx, "totalSizeWithScrollAdjust") || 0;
1746
- set$(ctx, "totalSizeWithScrollAdjust", prevTotalSize + prevStylePaddingTop);
1747
- setTimeout(() => {
1748
- set$(ctx, "totalSizeWithScrollAdjust", prevTotalSize);
1749
- }, 16);
1750
- }
1751
- set$(ctx, "stylePaddingTop", stylePaddingTop);
1752
- }
1753
- if (alignItemsPaddingTop !== void 0) {
1754
- set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1706
+ }
1707
+ if (!queuedInitialLayout && endBuffered !== null) {
1708
+ if (checkAllSizesKnown(state)) {
1709
+ setDidLayout(ctx, state);
1755
1710
  }
1756
- set$(
1711
+ }
1712
+ if (state.props.viewabilityConfigCallbackPairs) {
1713
+ updateViewableItems(
1714
+ state,
1757
1715
  ctx,
1758
- "paddingTop",
1759
- (stylePaddingTop != null ? stylePaddingTop : peek$(ctx, "stylePaddingTop")) + (alignItemsPaddingTop != null ? alignItemsPaddingTop : peek$(ctx, "alignItemsPaddingTop"))
1716
+ state.props.viewabilityConfigCallbackPairs,
1717
+ scrollLength,
1718
+ startNoBuffer,
1719
+ endNoBuffer
1760
1720
  );
1761
- };
1762
- const updateAlignItemsPaddingTop = () => {
1763
- if (alignItemsAtEnd) {
1764
- const { data, scrollLength } = refState.current;
1765
- let alignItemsPaddingTop = 0;
1766
- if ((data == null ? void 0 : data.length) > 0) {
1767
- const contentSize = getContentSize(ctx);
1768
- alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1769
- }
1770
- setPaddingTop({ alignItemsPaddingTop });
1771
- }
1772
- };
1773
- const finishScrollTo = () => {
1774
- const state = refState.current;
1775
- if (state) {
1776
- state.scrollingTo = void 0;
1777
- state.scrollAdjustHandler.setDisableAdjust(false);
1778
- state.scrollHistory.length = 0;
1779
- calculateItemsInView();
1721
+ }
1722
+ }
1723
+
1724
+ // src/checkAtTop.ts
1725
+ function checkAtTop(state) {
1726
+ if (!state) {
1727
+ return;
1728
+ }
1729
+ const {
1730
+ scrollLength,
1731
+ scroll,
1732
+ props: { onStartReachedThreshold }
1733
+ } = state;
1734
+ const distanceFromTop = scroll;
1735
+ state.isAtStart = distanceFromTop <= 0;
1736
+ state.isStartReached = checkThreshold(
1737
+ distanceFromTop,
1738
+ false,
1739
+ onStartReachedThreshold * scrollLength,
1740
+ state.isStartReached,
1741
+ state.startReachedBlockedByTimer,
1742
+ (distance) => {
1743
+ var _a, _b;
1744
+ return (_b = (_a = state.props).onStartReached) == null ? void 0 : _b.call(_a, { distanceFromStart: distance });
1745
+ },
1746
+ (block) => {
1747
+ state.startReachedBlockedByTimer = block;
1780
1748
  }
1781
- };
1782
- const scrollTo = (params = {}) => {
1783
- var _a;
1784
- const state = refState.current;
1785
- const { animated } = params;
1786
- const offset = calculateOffsetWithOffsetPosition(params.offset, params);
1787
- state.scrollAdjustHandler.setDisableAdjust(true);
1788
- state.scrollHistory.length = 0;
1789
- state.scrollingTo = params;
1790
- state.scrollPending = offset;
1791
- (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
1792
- x: horizontal ? offset : 0,
1793
- y: horizontal ? 0 : offset,
1794
- animated: !!animated
1795
- });
1796
- if (!animated) {
1797
- requestAnimationFrame(finishScrollTo);
1749
+ );
1750
+ }
1751
+
1752
+ // src/createColumnWrapperStyle.ts
1753
+ function createColumnWrapperStyle(contentContainerStyle) {
1754
+ const { gap, columnGap, rowGap } = contentContainerStyle;
1755
+ if (gap || columnGap || rowGap) {
1756
+ contentContainerStyle.gap = void 0;
1757
+ contentContainerStyle.columnGap = void 0;
1758
+ contentContainerStyle.rowGap = void 0;
1759
+ return {
1760
+ gap,
1761
+ columnGap,
1762
+ rowGap
1763
+ };
1764
+ }
1765
+ }
1766
+
1767
+ // src/doInitialAllocateContainers.ts
1768
+ function doInitialAllocateContainers(ctx, state) {
1769
+ const { scrollLength } = state;
1770
+ const data = state.props.data;
1771
+ if (scrollLength > 0 && data.length > 0 && !peek$(ctx, "numContainers")) {
1772
+ const averageItemSize = state.props.getEstimatedItemSize ? state.props.getEstimatedItemSize(0, data[0]) : state.props.estimatedItemSize;
1773
+ const Extra = 1.5;
1774
+ const numContainers = Math.ceil(
1775
+ (scrollLength + state.props.scrollBuffer * 2) / averageItemSize * state.props.numColumns * Extra
1776
+ );
1777
+ for (let i = 0; i < numContainers; i++) {
1778
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1779
+ set$(ctx, `containerColumn${i}`, -1);
1798
1780
  }
1799
- };
1800
- const doMaintainScrollAtEnd = (animated) => {
1801
- const state = refState.current;
1802
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
1803
- const paddingTop = peek$(ctx, "alignItemsPaddingTop");
1804
- if (paddingTop > 0) {
1805
- state.scroll = 0;
1806
- }
1807
- state.disableScrollJumpsFrom = void 0;
1808
- requestAnimationFrame(() => {
1809
- var _a;
1810
- state.maintainingScrollAtEnd = true;
1811
- (_a = refScroller.current) == null ? void 0 : _a.scrollToEnd({
1812
- animated
1781
+ set$(ctx, "numContainers", numContainers);
1782
+ set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
1783
+ if (!IsNewArchitecture) {
1784
+ if (state.props.initialScroll) {
1785
+ requestAnimationFrame(() => {
1786
+ calculateItemsInView(ctx, state);
1813
1787
  });
1814
- setTimeout(
1815
- () => {
1816
- state.maintainingScrollAtEnd = false;
1817
- },
1818
- 0
1819
- );
1820
- });
1821
- return true;
1822
- }
1823
- };
1824
- const checkThreshold = (distance, atThreshold, threshold, isReached, isBlockedByTimer, onReached, blockTimer) => {
1825
- const distanceAbs = Math.abs(distance);
1826
- const isAtThreshold = atThreshold || distanceAbs < threshold;
1827
- if (!isReached && !isBlockedByTimer) {
1828
- if (isAtThreshold) {
1829
- onReached == null ? void 0 : onReached(distance);
1830
- blockTimer == null ? void 0 : blockTimer(true);
1831
- setTimeout(() => {
1832
- blockTimer == null ? void 0 : blockTimer(false);
1833
- }, 700);
1834
- return true;
1835
- }
1836
- } else {
1837
- if (distance >= 1.3 * threshold) {
1838
- return false;
1788
+ } else {
1789
+ calculateItemsInView(ctx, state);
1839
1790
  }
1840
1791
  }
1841
- return isReached;
1842
- };
1843
- const checkAtBottom = () => {
1844
- if (!refState.current) {
1845
- return;
1792
+ return true;
1793
+ }
1794
+ }
1795
+
1796
+ // src/doMaintainScrollAtEnd.ts
1797
+ function doMaintainScrollAtEnd(ctx, state, animated) {
1798
+ const {
1799
+ refScroller,
1800
+ props: { maintainScrollAtEnd }
1801
+ } = state;
1802
+ if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
1803
+ const paddingTop = peek$(ctx, "alignItemsPaddingTop");
1804
+ if (paddingTop > 0) {
1805
+ state.scroll = 0;
1846
1806
  }
1847
- const { queuedInitialLayout, scrollLength, scroll, maintainingScrollAtEnd } = refState.current;
1848
- const contentSize = getContentSize(ctx);
1849
- if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1850
- const distanceFromEnd = contentSize - scroll - scrollLength;
1851
- const isContentLess = contentSize < scrollLength;
1852
- refState.current.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1853
- refState.current.isEndReached = checkThreshold(
1854
- distanceFromEnd,
1855
- isContentLess,
1856
- onEndReachedThreshold * scrollLength,
1857
- refState.current.isEndReached,
1858
- refState.current.endReachedBlockedByTimer,
1859
- (distance) => {
1860
- var _a, _b;
1861
- return (_b = (_a = callbacks.current).onEndReached) == null ? void 0 : _b.call(_a, { distanceFromEnd: distance });
1807
+ requestAnimationFrame(() => {
1808
+ var _a;
1809
+ state.maintainingScrollAtEnd = true;
1810
+ (_a = refScroller.current) == null ? void 0 : _a.scrollToEnd({
1811
+ animated
1812
+ });
1813
+ setTimeout(
1814
+ () => {
1815
+ state.maintainingScrollAtEnd = false;
1862
1816
  },
1863
- (block) => {
1864
- refState.current.endReachedBlockedByTimer = block;
1865
- }
1817
+ 0
1866
1818
  );
1867
- }
1868
- };
1869
- const checkAtTop = () => {
1870
- if (!refState.current) {
1819
+ });
1820
+ return true;
1821
+ }
1822
+ }
1823
+ function getRenderedItem(ctx, state, key) {
1824
+ if (!state) {
1825
+ return null;
1826
+ }
1827
+ const {
1828
+ indexByKey,
1829
+ props: { data, renderItem: renderItem2 }
1830
+ } = state;
1831
+ const index = indexByKey.get(key);
1832
+ if (index === void 0) {
1833
+ return null;
1834
+ }
1835
+ let renderedItem = null;
1836
+ if (renderItem2) {
1837
+ const itemProps = {
1838
+ item: data[index],
1839
+ index,
1840
+ extraData: peek$(ctx, "extraData")
1841
+ };
1842
+ renderedItem = React3__namespace.default.createElement(renderItem2, itemProps);
1843
+ }
1844
+ return { index, item: data[index], renderedItem };
1845
+ }
1846
+
1847
+ // src/handleLayout.ts
1848
+ function handleLayout(ctx, state, size, setCanRender) {
1849
+ const scrollLength = size[state.props.horizontal ? "width" : "height"];
1850
+ const otherAxisSize = size[state.props.horizontal ? "height" : "width"];
1851
+ const didChange = scrollLength !== state.scrollLength;
1852
+ const prevOtherAxisSize = state.otherAxisSize;
1853
+ state.scrollLength = scrollLength;
1854
+ state.otherAxisSize = otherAxisSize;
1855
+ state.lastBatchingAction = Date.now();
1856
+ state.scrollForNextCalculateItemsInView = void 0;
1857
+ doInitialAllocateContainers(ctx, state);
1858
+ if (didChange) {
1859
+ calculateItemsInView(ctx, state, { doMVCP: true });
1860
+ }
1861
+ if (didChange || otherAxisSize !== prevOtherAxisSize) {
1862
+ set$(ctx, "scrollSize", { width: size.width, height: size.height });
1863
+ }
1864
+ doMaintainScrollAtEnd(ctx, state, false);
1865
+ updateAlignItemsPaddingTop(ctx, state);
1866
+ checkAtBottom(ctx, state);
1867
+ checkAtTop(state);
1868
+ if (state) {
1869
+ state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
1870
+ }
1871
+ if (__DEV__ && scrollLength === 0) {
1872
+ warnDevOnce(
1873
+ "height0",
1874
+ `List ${state.props.horizontal ? "width" : "height"} is 0. You may need to set a style or \`flex: \` for the list, because children are absolutely positioned.`
1875
+ );
1876
+ }
1877
+ calculateItemsInView(ctx, state, { doMVCP: true });
1878
+ setCanRender(true);
1879
+ }
1880
+
1881
+ // src/onScroll.ts
1882
+ function onScroll(ctx, state, event) {
1883
+ var _a, _b, _c, _d, _e;
1884
+ 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) {
1885
+ return;
1886
+ }
1887
+ const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
1888
+ const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
1889
+ if (ignoreScrollFromMVCP && !state.scrollingTo) {
1890
+ const { lt, gt } = ignoreScrollFromMVCP;
1891
+ if (lt && newScroll < lt || gt && newScroll > gt) {
1871
1892
  return;
1872
1893
  }
1873
- const { scrollLength, scroll } = refState.current;
1874
- const distanceFromTop = scroll;
1875
- refState.current.isAtStart = distanceFromTop <= 0;
1876
- refState.current.isStartReached = checkThreshold(
1877
- distanceFromTop,
1878
- false,
1879
- onStartReachedThreshold * scrollLength,
1880
- refState.current.isStartReached,
1881
- refState.current.startReachedBlockedByTimer,
1882
- (distance) => {
1883
- var _a, _b;
1884
- return (_b = (_a = callbacks.current).onStartReached) == null ? void 0 : _b.call(_a, { distanceFromStart: distance });
1885
- },
1886
- (block) => {
1887
- refState.current.startReachedBlockedByTimer = block;
1888
- }
1889
- );
1890
- };
1891
- const checkResetContainers = (isFirst2) => {
1892
- const state = refState.current;
1893
- if (state) {
1894
- state.data = dataProp;
1895
- if (!isFirst2) {
1896
- const totalSizeBefore = state.previousTotalSize;
1897
- const totalSizeAfter = state.totalSize;
1898
- const scrollDiff = state.scroll - state.scrollPrev;
1899
- const sizeDiff = totalSizeAfter - totalSizeBefore;
1900
- if (Math.abs(scrollDiff - sizeDiff) < 10) {
1901
- disableScrollJumps(1e3);
1902
- }
1903
- const numContainers = peek$(ctx, "numContainers");
1894
+ }
1895
+ state.scrollPending = newScroll;
1896
+ updateScroll(ctx, state, newScroll);
1897
+ (_e = (_d = state.props).onScroll) == null ? void 0 : _e.call(_d, event);
1898
+ }
1899
+ function updateScroll(ctx, state, newScroll) {
1900
+ const scrollingTo = state.scrollingTo;
1901
+ state.hasScrolled = true;
1902
+ state.lastBatchingAction = Date.now();
1903
+ const currentTime = performance.now();
1904
+ if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
1905
+ state.scrollHistory.push({ scroll: newScroll, time: currentTime });
1906
+ }
1907
+ if (state.scrollHistory.length > 5) {
1908
+ state.scrollHistory.shift();
1909
+ }
1910
+ state.scrollPrev = state.scroll;
1911
+ state.scrollPrevTime = state.scrollTime;
1912
+ state.scroll = newScroll;
1913
+ state.scrollTime = currentTime;
1914
+ calculateItemsInView(ctx, state);
1915
+ checkAtBottom(ctx, state);
1916
+ checkAtTop(state);
1917
+ }
1918
+
1919
+ // src/updateItemSize.ts
1920
+ function updateItemSizes(ctx, state, itemUpdates) {
1921
+ var _a;
1922
+ const {
1923
+ props: { horizontal, maintainVisibleContentPosition, suggestEstimatedItemSize, onItemSizeChanged, data }
1924
+ } = state;
1925
+ if (!data) return;
1926
+ let needsRecalculate = false;
1927
+ let shouldMaintainScrollAtEnd = false;
1928
+ let minIndexSizeChanged;
1929
+ let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
1930
+ for (const { itemKey, sizeObj } of itemUpdates) {
1931
+ const index = state.indexByKey.get(itemKey);
1932
+ const prevSizeKnown = state.sizesKnown.get(itemKey);
1933
+ const diff = updateOneItemSize(state, itemKey, sizeObj);
1934
+ const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
1935
+ if (diff !== 0) {
1936
+ minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
1937
+ if (((_a = state.scrollingTo) == null ? void 0 : _a.viewPosition) && maintainVisibleContentPosition && index === state.scrollingTo.index) {
1938
+ requestAdjust(ctx, state, diff * state.scrollingTo.viewPosition);
1939
+ }
1940
+ const { startBuffered, endBuffered } = state;
1941
+ needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
1942
+ if (!needsRecalculate) {
1943
+ const numContainers = ctx.values.get("numContainers");
1904
1944
  for (let i = 0; i < numContainers; i++) {
1905
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1906
- if (!keyExtractorProp || itemKey && state.indexByKey.get(itemKey) === void 0) {
1907
- set$(ctx, `containerItemKey${i}`, void 0);
1908
- set$(ctx, `containerItemData${i}`, void 0);
1909
- set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1910
- set$(ctx, `containerColumn${i}`, -1);
1945
+ if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
1946
+ needsRecalculate = true;
1947
+ break;
1911
1948
  }
1912
1949
  }
1913
- if (!keyExtractorProp) {
1914
- state.positions.clear();
1915
- }
1916
- calculateItemsInView(
1917
- /*isReset*/
1918
- true
1919
- );
1920
- const didMaintainScrollAtEnd = doMaintainScrollAtEnd(false);
1921
- if (!didMaintainScrollAtEnd && dataProp.length > state.data.length) {
1922
- state.isEndReached = false;
1923
- }
1924
- if (!didMaintainScrollAtEnd) {
1925
- checkAtTop();
1926
- checkAtBottom();
1927
- }
1928
1950
  }
1929
- }
1930
- };
1931
- const calcTotalSizesAndPositions = ({ forgetPositions = false }) => {
1932
- var _a, _b;
1933
- const state = refState.current;
1934
- let totalSize = 0;
1935
- let totalSizeBelowIndex = 0;
1936
- const indexByKey = /* @__PURE__ */ new Map();
1937
- const newPositions = /* @__PURE__ */ new Map();
1938
- let column = 1;
1939
- let maxSizeInRow = 0;
1940
- const numColumns = (_a = peek$(ctx, "numColumns")) != null ? _a : numColumnsProp;
1941
- if (!state) {
1942
- return;
1943
- }
1944
- for (let i = 0; i < dataProp.length; i++) {
1945
- const key = getId(i);
1946
- if (__DEV__) {
1947
- if (indexByKey.has(key)) {
1948
- console.error(
1949
- `[legend-list] Error: Detected overlapping key (${key}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
1950
- );
1951
- }
1951
+ if (state.needsOtherAxisSize) {
1952
+ const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
1953
+ maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
1952
1954
  }
1953
- indexByKey.set(key, i);
1954
- if (!forgetPositions && state.positions.get(key) != null && state.indexByKey.get(key) === i) {
1955
- newPositions.set(key, state.positions.get(key));
1955
+ if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
1956
+ shouldMaintainScrollAtEnd = true;
1956
1957
  }
1958
+ onItemSizeChanged == null ? void 0 : onItemSizeChanged({
1959
+ size,
1960
+ previous: size - diff,
1961
+ index,
1962
+ itemKey,
1963
+ itemData: state.props.data[index]
1964
+ });
1957
1965
  }
1958
- state.indexByKey = indexByKey;
1959
- state.positions = newPositions;
1960
- if (!forgetPositions && !isFirst) {
1961
- if (maintainVisibleContentPosition) {
1962
- if (state.anchorElement == null || indexByKey.get(state.anchorElement.id) == null) {
1963
- if (dataProp.length) {
1964
- const newAnchorElement = {
1965
- coordinate: 0,
1966
- id: getId(0)
1967
- };
1968
- state.anchorElement = newAnchorElement;
1969
- (_b = state.belowAnchorElementPositions) == null ? void 0 : _b.clear();
1970
- scrollTo({ offset: 0, animated: false });
1971
- setTimeout(() => {
1972
- calculateItemsInView(
1973
- /*reset*/
1974
- true
1975
- );
1976
- }, 0);
1977
- } else {
1978
- state.startBufferedId = void 0;
1979
- }
1980
- }
1981
- } else {
1982
- if (state.startBufferedId != null && newPositions.get(state.startBufferedId) == null) {
1983
- if (dataProp.length) {
1984
- state.startBufferedId = getId(0);
1985
- } else {
1986
- state.startBufferedId = void 0;
1987
- }
1988
- scrollTo({ offset: 0, animated: false });
1989
- setTimeout(() => {
1990
- calculateItemsInView(
1991
- /*reset*/
1992
- true
1993
- );
1994
- }, 0);
1995
- }
1996
- }
1966
+ }
1967
+ if (minIndexSizeChanged !== void 0) {
1968
+ state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
1969
+ }
1970
+ if (__DEV__ && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
1971
+ if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
1972
+ state.timeoutSizeMessage = setTimeout(() => {
1973
+ var _a2;
1974
+ state.timeoutSizeMessage = void 0;
1975
+ const num = state.sizesKnown.size;
1976
+ const avg = (_a2 = state.averageSizes[""]) == null ? void 0 : _a2.avg;
1977
+ console.warn(
1978
+ `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
1979
+ );
1980
+ }, 1e3);
1981
+ }
1982
+ const cur = peek$(ctx, "otherAxisSize");
1983
+ if (!cur || maxOtherAxisSize > cur) {
1984
+ set$(ctx, "otherAxisSize", maxOtherAxisSize);
1985
+ }
1986
+ const containersDidLayout = peek$(ctx, "containersDidLayout");
1987
+ if (containersDidLayout || checkAllSizesKnown(state)) {
1988
+ if (needsRecalculate) {
1989
+ state.scrollForNextCalculateItemsInView = void 0;
1990
+ calculateItemsInView(ctx, state, { doMVCP: true });
1997
1991
  }
1998
- const anchorElementIndex = getAnchorElementIndex();
1999
- for (let i = 0; i < dataProp.length; i++) {
2000
- const key = getId(i);
2001
- const size = getItemSize(key, i, dataProp[i]);
2002
- maxSizeInRow = Math.max(maxSizeInRow, size);
2003
- column++;
2004
- if (column > numColumns) {
2005
- if (maintainVisibleContentPosition && anchorElementIndex !== void 0 && i < anchorElementIndex) {
2006
- totalSizeBelowIndex += maxSizeInRow;
1992
+ if (shouldMaintainScrollAtEnd) {
1993
+ doMaintainScrollAtEnd(ctx, state, false);
1994
+ }
1995
+ }
1996
+ }
1997
+ function updateItemSize(ctx, state, itemKey, sizeObj) {
1998
+ var _a, _b;
1999
+ if (IsNewArchitecture) {
2000
+ const { sizesKnown } = state;
2001
+ const numContainers = ctx.values.get("numContainers");
2002
+ const changes = [];
2003
+ for (let i = 0; i < numContainers; i++) {
2004
+ const containerItemKey = peek$(ctx, `containerItemKey${i}`);
2005
+ if (itemKey === containerItemKey) {
2006
+ changes.push({ itemKey, sizeObj });
2007
+ } else if (!sizesKnown.has(containerItemKey) && containerItemKey !== void 0) {
2008
+ const containerRef = ctx.viewRefs.get(i);
2009
+ if (containerRef) {
2010
+ const measured = (_b = (_a = containerRef.current) == null ? void 0 : _a.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a);
2011
+ if (measured) {
2012
+ changes.push({ itemKey: containerItemKey, sizeObj: measured });
2013
+ }
2007
2014
  }
2008
- totalSize += maxSizeInRow;
2009
- column = 1;
2010
- maxSizeInRow = 0;
2011
2015
  }
2012
2016
  }
2013
- if (maxSizeInRow > 0) {
2014
- totalSize += maxSizeInRow;
2017
+ if (changes.length > 0) {
2018
+ updateItemSizes(ctx, state, changes);
2015
2019
  }
2016
- state.ignoreScrollFromCalcTotal = true;
2017
- requestAnimationFrame(() => {
2018
- state.ignoreScrollFromCalcTotal = false;
2019
- });
2020
- addTotalSize(null, totalSize, totalSizeBelowIndex);
2021
- };
2022
- const findAvailableContainers = (numNeeded, startBuffered, endBuffered) => {
2023
- const state = refState.current;
2024
- const numContainers = peek$(ctx, "numContainers");
2025
- if (numNeeded === 0) return [];
2026
- const result = [];
2027
- const availableContainers = [];
2028
- for (let u = 0; u < numContainers; u++) {
2029
- const key = peek$(ctx, `containerItemKey${u}`);
2030
- if (key === void 0) {
2031
- result.push(u);
2032
- if (result.length >= numNeeded) {
2033
- return result;
2034
- }
2020
+ } else {
2021
+ updateItemSizes(ctx, state, [{ itemKey, sizeObj }]);
2022
+ }
2023
+ }
2024
+ function updateOneItemSize(state, itemKey, sizeObj) {
2025
+ const {
2026
+ sizes,
2027
+ indexByKey,
2028
+ sizesKnown,
2029
+ averageSizes,
2030
+ props: { data, horizontal }
2031
+ } = state;
2032
+ if (!data) return 0;
2033
+ const index = indexByKey.get(itemKey);
2034
+ const prevSize = getItemSize(state, itemKey, index, data);
2035
+ const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2036
+ sizesKnown.set(itemKey, size);
2037
+ const itemType = "";
2038
+ let averages = averageSizes[itemType];
2039
+ if (!averages) {
2040
+ averages = averageSizes[itemType] = { num: 0, avg: 0 };
2041
+ }
2042
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2043
+ averages.num++;
2044
+ if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2045
+ sizes.set(itemKey, size);
2046
+ return size - prevSize;
2047
+ }
2048
+ return 0;
2049
+ }
2050
+ var useCombinedRef = (...refs) => {
2051
+ const callback = React3.useCallback((element) => {
2052
+ for (const ref of refs) {
2053
+ if (!ref) {
2054
+ continue;
2035
2055
  }
2036
- }
2037
- for (let u = 0; u < numContainers; u++) {
2038
- const key = peek$(ctx, `containerItemKey${u}`);
2039
- if (key === void 0) continue;
2040
- const index = state.indexByKey.get(key);
2041
- if (index < startBuffered) {
2042
- availableContainers.push({ index: u, distance: startBuffered - index });
2043
- } else if (index > endBuffered) {
2044
- availableContainers.push({ index: u, distance: index - endBuffered });
2056
+ if (isFunction(ref)) {
2057
+ ref(element);
2058
+ } else {
2059
+ ref.current = element;
2045
2060
  }
2046
2061
  }
2047
- const remaining = numNeeded - result.length;
2048
- if (remaining > 0) {
2049
- if (availableContainers.length > 0) {
2050
- if (availableContainers.length > remaining) {
2051
- availableContainers.sort(comparatorByDistance);
2052
- availableContainers.length = remaining;
2053
- }
2054
- for (const container of availableContainers) {
2055
- result.push(container.index);
2056
- }
2057
- }
2058
- const stillNeeded = numNeeded - result.length;
2059
- if (stillNeeded > 0) {
2060
- for (let i = 0; i < stillNeeded; i++) {
2061
- result.push(numContainers + i);
2062
+ }, refs);
2063
+ return callback;
2064
+ };
2065
+
2066
+ // src/LegendList.tsx
2067
+ var DEFAULT_DRAW_DISTANCE = 250;
2068
+ var DEFAULT_ITEM_SIZE = 100;
2069
+ var LegendList = typedForwardRef(function LegendList2(props, forwardedRef) {
2070
+ return /* @__PURE__ */ React3__namespace.createElement(StateProvider, null, /* @__PURE__ */ React3__namespace.createElement(LegendListInner, { ...props, ref: forwardedRef }));
2071
+ });
2072
+ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
2073
+ var _a;
2074
+ const {
2075
+ data: dataProp = [],
2076
+ initialScrollIndex: initialScrollIndexProp,
2077
+ initialScrollOffset,
2078
+ horizontal,
2079
+ drawDistance = 250,
2080
+ recycleItems = false,
2081
+ onEndReachedThreshold = 0.5,
2082
+ onStartReachedThreshold = 0.5,
2083
+ maintainScrollAtEnd = false,
2084
+ maintainScrollAtEndThreshold = 0.1,
2085
+ alignItemsAtEnd = false,
2086
+ maintainVisibleContentPosition = false,
2087
+ onScroll: onScrollProp,
2088
+ onMomentumScrollEnd,
2089
+ numColumns: numColumnsProp = 1,
2090
+ columnWrapperStyle,
2091
+ keyExtractor: keyExtractorProp,
2092
+ renderItem: renderItem2,
2093
+ estimatedListSize,
2094
+ estimatedItemSize: estimatedItemSizeProp,
2095
+ getEstimatedItemSize,
2096
+ suggestEstimatedItemSize,
2097
+ ListHeaderComponent,
2098
+ ListEmptyComponent,
2099
+ onItemSizeChanged,
2100
+ refScrollView,
2101
+ waitForInitialLayout = true,
2102
+ extraData,
2103
+ contentContainerStyle: contentContainerStyleProp,
2104
+ style: styleProp,
2105
+ onLayout: onLayoutProp,
2106
+ onRefresh,
2107
+ refreshing,
2108
+ progressViewOffset,
2109
+ refreshControl,
2110
+ initialContainerPoolRatio = 2,
2111
+ viewabilityConfig,
2112
+ viewabilityConfigCallbackPairs,
2113
+ onViewableItemsChanged,
2114
+ onStartReached,
2115
+ onEndReached,
2116
+ onLoad,
2117
+ ...rest
2118
+ } = props;
2119
+ const [renderNum, setRenderNum] = React3.useState(0);
2120
+ const initialScroll = typeof initialScrollIndexProp === "number" ? { index: initialScrollIndexProp } : initialScrollIndexProp;
2121
+ const initialScrollIndex = initialScroll == null ? void 0 : initialScroll.index;
2122
+ const [canRender, setCanRender] = React3__namespace.useState(!IsNewArchitecture);
2123
+ const contentContainerStyle = { ...reactNative.StyleSheet.flatten(contentContainerStyleProp) };
2124
+ const style = { ...reactNative.StyleSheet.flatten(styleProp) };
2125
+ const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
2126
+ const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
2127
+ const ctx = useStateContext();
2128
+ ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
2129
+ const refScroller = React3.useRef(null);
2130
+ const combinedRef = useCombinedRef(refScroller, refScrollView);
2131
+ const estimatedItemSize = estimatedItemSizeProp != null ? estimatedItemSizeProp : DEFAULT_ITEM_SIZE;
2132
+ const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
2133
+ const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (item, index) => index.toString();
2134
+ const refState = React3.useRef();
2135
+ if (!refState.current) {
2136
+ const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { width: 0, height: 0 } : reactNative.Dimensions.get("window"))[horizontal ? "width" : "height"];
2137
+ refState.current = {
2138
+ sizes: /* @__PURE__ */ new Map(),
2139
+ positions: /* @__PURE__ */ new Map(),
2140
+ columns: /* @__PURE__ */ new Map(),
2141
+ pendingAdjust: 0,
2142
+ isStartReached: false,
2143
+ isEndReached: false,
2144
+ isAtEnd: false,
2145
+ isAtStart: false,
2146
+ scrollLength: initialScrollLength,
2147
+ startBuffered: -1,
2148
+ startNoBuffer: -1,
2149
+ endBuffered: -1,
2150
+ endNoBuffer: -1,
2151
+ firstFullyOnScreenIndex: -1,
2152
+ scroll: 0,
2153
+ totalSize: 0,
2154
+ timeouts: /* @__PURE__ */ new Set(),
2155
+ viewabilityConfigCallbackPairs: void 0,
2156
+ scrollAdjustHandler: new ScrollAdjustHandler(ctx),
2157
+ nativeMarginTop: 0,
2158
+ scrollPrev: 0,
2159
+ scrollPrevTime: 0,
2160
+ scrollTime: 0,
2161
+ scrollPending: 0,
2162
+ indexByKey: /* @__PURE__ */ new Map(),
2163
+ scrollHistory: [],
2164
+ sizesKnown: /* @__PURE__ */ new Map(),
2165
+ timeoutSizeMessage: 0,
2166
+ startReachedBlockedByTimer: false,
2167
+ endReachedBlockedByTimer: false,
2168
+ scrollForNextCalculateItemsInView: void 0,
2169
+ enableScrollForNextCalculateItemsInView: true,
2170
+ minIndexSizeChanged: 0,
2171
+ queuedCalculateItemsInView: 0,
2172
+ lastBatchingAction: Date.now(),
2173
+ averageSizes: {},
2174
+ idsInView: [],
2175
+ containerItemKeys: /* @__PURE__ */ new Set(),
2176
+ idCache: /* @__PURE__ */ new Map(),
2177
+ props: {},
2178
+ refScroller: void 0,
2179
+ loadStartTime: Date.now(),
2180
+ initialScroll
2181
+ };
2182
+ set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
2183
+ set$(ctx, "extraData", extraData);
2184
+ }
2185
+ const state = refState.current;
2186
+ const isFirst = !state.props.renderItem;
2187
+ const didDataChange = state.props.data !== dataProp;
2188
+ state.props = {
2189
+ alignItemsAtEnd,
2190
+ data: dataProp,
2191
+ estimatedItemSize,
2192
+ maintainScrollAtEnd,
2193
+ maintainScrollAtEndThreshold,
2194
+ onEndReachedThreshold,
2195
+ onStartReachedThreshold,
2196
+ stylePaddingBottom: stylePaddingBottomState,
2197
+ horizontal: !!horizontal,
2198
+ maintainVisibleContentPosition,
2199
+ onItemSizeChanged,
2200
+ suggestEstimatedItemSize: !!suggestEstimatedItemSize,
2201
+ keyExtractor,
2202
+ onScroll: onScrollProp,
2203
+ getEstimatedItemSize,
2204
+ onStartReached,
2205
+ onEndReached,
2206
+ onLoad,
2207
+ renderItem: renderItem2,
2208
+ initialScroll,
2209
+ scrollBuffer,
2210
+ viewabilityConfigCallbackPairs: void 0,
2211
+ numColumns: numColumnsProp,
2212
+ initialContainerPoolRatio,
2213
+ stylePaddingTop: stylePaddingTopState
2214
+ };
2215
+ state.refScroller = refScroller;
2216
+ const checkResetContainers = (isFirst2) => {
2217
+ const state2 = refState.current;
2218
+ if (state2) {
2219
+ state2.props.data = dataProp;
2220
+ if (!isFirst2) {
2221
+ calculateItemsInView(ctx, state2, { dataChanged: true, doMVCP: true });
2222
+ const didMaintainScrollAtEnd = doMaintainScrollAtEnd(ctx, state2, false);
2223
+ if (!didMaintainScrollAtEnd && dataProp.length > state2.props.data.length) {
2224
+ state2.isEndReached = false;
2062
2225
  }
2063
- if (__DEV__ && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
2064
- console.warn(
2065
- "[legend-list] No unused container available, 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 or increasing initialContainerPoolRatio.",
2066
- {
2067
- debugInfo: {
2068
- numContainers,
2069
- numNeeded,
2070
- stillNeeded,
2071
- numContainersPooled: peek$(ctx, "numContainersPooled")
2072
- }
2073
- }
2074
- );
2226
+ if (!didMaintainScrollAtEnd) {
2227
+ checkAtTop(state2);
2228
+ checkAtBottom(ctx, state2);
2075
2229
  }
2076
2230
  }
2077
2231
  }
2078
- return result.sort(comparatorDefault);
2079
2232
  };
2080
- const isFirst = !refState.current.renderItem;
2081
- const memoizedLastItemKeys = React2.useMemo(() => {
2233
+ const memoizedLastItemKeys = React3.useMemo(() => {
2082
2234
  if (!dataProp.length) return [];
2083
2235
  return Array.from(
2084
2236
  { length: Math.min(numColumnsProp, dataProp.length) },
2085
- (_, i) => getId(dataProp.length - 1 - i)
2237
+ (_, i) => getId(state, dataProp.length - 1 - i)
2086
2238
  );
2087
2239
  }, [dataProp, numColumnsProp]);
2088
2240
  const initalizeStateVars = () => {
2089
2241
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
2090
2242
  set$(ctx, "numColumns", numColumnsProp);
2091
2243
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
2092
- setPaddingTop({ stylePaddingTop: stylePaddingTopState });
2093
- refState.current.stylePaddingBottom = stylePaddingBottomState;
2244
+ setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
2245
+ refState.current.props.stylePaddingBottom = stylePaddingBottomState;
2094
2246
  const paddingDiff = stylePaddingTopState - prevPaddingTop;
2095
2247
  if (paddingDiff && prevPaddingTop !== void 0 && reactNative.Platform.OS === "ios") {
2096
- queueMicrotask(() => {
2097
- scrollTo({ offset: refState.current.scrollPending + paddingDiff, animated: false });
2098
- });
2248
+ calculateItemsInView(ctx, state, { doMVCP: true });
2249
+ requestAdjust(ctx, state, paddingDiff);
2099
2250
  }
2100
2251
  };
2101
2252
  if (isFirst) {
2102
2253
  initalizeStateVars();
2254
+ updateAllPositions(ctx, state);
2103
2255
  }
2256
+ const initialContentOffset = React3.useMemo(() => {
2257
+ const initialContentOffset2 = initialScrollOffset || calculateOffsetForIndex(ctx, state, initialScrollIndex);
2258
+ refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
2259
+ if (initialContentOffset2 > 0) {
2260
+ scrollTo(state, { offset: initialContentOffset2, animated: false, index: initialScrollIndex });
2261
+ }
2262
+ return initialContentOffset2;
2263
+ }, [renderNum]);
2104
2264
  if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
2105
2265
  refState.current.lastBatchingAction = Date.now();
2106
2266
  if (!keyExtractorProp && !isFirst && didDataChange) {
@@ -2111,23 +2271,39 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2111
2271
  refState.current.sizes.clear();
2112
2272
  refState.current.positions.clear();
2113
2273
  }
2114
- refState.current.previousTotalSize = peek$(ctx, "totalSize");
2115
- calcTotalSizesAndPositions({ forgetPositions: false });
2116
2274
  }
2117
- React2.useEffect(() => {
2118
- if (initialScroll && ListHeaderComponent) {
2119
- const dispose = listen$(ctx, "headerSize", (size) => {
2120
- if (size > 0) {
2121
- scrollToIndex({ ...initialScroll, animated: false });
2122
- dispose == null ? void 0 : dispose();
2275
+ React3.useLayoutEffect(() => {
2276
+ var _a2, _b;
2277
+ if (IsNewArchitecture) {
2278
+ const measured = (_b = (_a2 = refScroller.current) == null ? void 0 : _a2.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a2);
2279
+ if (measured) {
2280
+ const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
2281
+ if (size) {
2282
+ handleLayout(ctx, state, measured, setCanRender);
2123
2283
  }
2124
- });
2125
- setTimeout(dispose, 0);
2126
- return dispose;
2284
+ }
2285
+ }
2286
+ if (!isFirst) {
2287
+ calculateItemsInView(ctx, state, { doMVCP: true });
2288
+ }
2289
+ }, [dataProp]);
2290
+ const onLayoutHeader = React3.useCallback((rect, fromLayoutEffect) => {
2291
+ const size = rect[horizontal ? "width" : "height"];
2292
+ set$(ctx, "headerSize", size);
2293
+ if (initialScroll) {
2294
+ if (IsNewArchitecture && reactNative.Platform.OS !== "android") {
2295
+ if (fromLayoutEffect) {
2296
+ setRenderNum((v) => v + 1);
2297
+ }
2298
+ } else {
2299
+ setTimeout(() => {
2300
+ scrollToIndex(ctx, state, { ...initialScroll, animated: false });
2301
+ }, 17);
2302
+ }
2127
2303
  }
2128
2304
  }, []);
2129
- React2.useEffect(() => {
2130
- const didAllocateContainers = doInitialAllocateContainers();
2305
+ React3.useLayoutEffect(() => {
2306
+ const didAllocateContainers = doInitialAllocateContainersCallback();
2131
2307
  if (!didAllocateContainers) {
2132
2308
  checkResetContainers(
2133
2309
  /*isFirst*/
@@ -2135,334 +2311,51 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2135
2311
  );
2136
2312
  }
2137
2313
  }, [dataProp, numColumnsProp]);
2138
- React2.useEffect(() => {
2314
+ React3.useLayoutEffect(() => {
2139
2315
  set$(ctx, "extraData", extraData);
2140
2316
  }, [extraData]);
2141
- refState.current.renderItem = renderItem2;
2142
- React2.useEffect(initalizeStateVars, [
2317
+ React3.useLayoutEffect(initalizeStateVars, [
2143
2318
  memoizedLastItemKeys.join(","),
2144
2319
  numColumnsProp,
2145
2320
  stylePaddingTopState,
2146
2321
  stylePaddingBottomState
2147
2322
  ]);
2148
- const getRenderedItem = React2.useCallback((key) => {
2149
- const state = refState.current;
2150
- if (!state) {
2151
- return null;
2152
- }
2153
- const { data, indexByKey } = state;
2154
- const index = indexByKey.get(key);
2155
- if (index === void 0) {
2156
- return null;
2157
- }
2158
- const renderItemProp = refState.current.renderItem;
2159
- let renderedItem = null;
2160
- if (renderItemProp) {
2161
- const itemProps = {
2162
- item: data[index],
2163
- index,
2164
- extraData: peek$(ctx, "extraData")
2165
- };
2166
- renderedItem = React2__namespace.createElement(renderItemProp, itemProps);
2167
- }
2168
- return { index, item: data[index], renderedItem };
2169
- }, []);
2170
- const doInitialAllocateContainers = () => {
2171
- const state = refState.current;
2172
- const { scrollLength, data } = state;
2173
- if (scrollLength > 0 && data.length > 0 && !peek$(ctx, "numContainers")) {
2174
- const averageItemSize = getEstimatedItemSize ? getEstimatedItemSize(0, data[0]) : estimatedItemSize;
2175
- const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) * numColumnsProp;
2176
- for (let i = 0; i < numContainers; i++) {
2177
- set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
2178
- set$(ctx, `containerColumn${i}`, -1);
2179
- }
2180
- set$(ctx, "numContainers", numContainers);
2181
- set$(ctx, "numContainersPooled", numContainers * initialContainerPoolRatio);
2182
- if (initialScroll) {
2183
- requestAnimationFrame(() => {
2184
- calculateItemsInView(
2185
- /*isReset*/
2186
- true
2187
- );
2188
- });
2189
- } else {
2190
- calculateItemsInView(
2191
- /*isReset*/
2192
- true
2193
- );
2194
- }
2195
- return true;
2196
- }
2323
+ const doInitialAllocateContainersCallback = () => {
2324
+ return doInitialAllocateContainers(ctx, state);
2197
2325
  };
2198
- React2.useEffect(() => {
2199
- const state = refState.current;
2326
+ React3.useEffect(() => {
2200
2327
  const viewability = setupViewability({
2201
2328
  viewabilityConfig,
2202
2329
  viewabilityConfigCallbackPairs,
2203
2330
  onViewableItemsChanged
2204
2331
  });
2205
2332
  state.viewabilityConfigCallbackPairs = viewability;
2333
+ state.props.viewabilityConfigCallbackPairs = viewability;
2206
2334
  state.enableScrollForNextCalculateItemsInView = !viewability;
2207
2335
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
2208
- useInit(() => {
2209
- doInitialAllocateContainers();
2210
- });
2211
- const updateItemSize = React2.useCallback(
2212
- (itemKey, sizeObj, fromFixGaps) => {
2213
- const state = refState.current;
2214
- const {
2215
- sizes,
2216
- indexByKey,
2217
- sizesKnown,
2218
- data,
2219
- rowHeights,
2220
- startBuffered,
2221
- endBuffered,
2222
- averageSizes,
2223
- queuedInitialLayout
2224
- } = state;
2225
- if (!data) {
2226
- return;
2227
- }
2228
- const index = indexByKey.get(itemKey);
2229
- const numColumns = peek$(ctx, "numColumns");
2230
- state.scrollForNextCalculateItemsInView = void 0;
2231
- state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, index) : index;
2232
- const prevSize = getItemSize(itemKey, index, data);
2233
- const prevSizeKnown = sizesKnown.get(itemKey);
2234
- let needsCalculate = false;
2235
- let needsUpdateContainersDidLayout = false;
2236
- const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2237
- sizesKnown.set(itemKey, size);
2238
- const itemType = "";
2239
- let averages = averageSizes[itemType];
2240
- if (!averages) {
2241
- averages = averageSizes[itemType] = {
2242
- num: 0,
2243
- avg: 0
2244
- };
2245
- }
2246
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2247
- averages.num++;
2248
- if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2249
- let diff;
2250
- needsCalculate = true;
2251
- if (numColumns > 1) {
2252
- const rowNumber = Math.floor(index / numColumnsProp);
2253
- const prevSizeInRow = getRowHeight(rowNumber);
2254
- sizes.set(itemKey, size);
2255
- rowHeights.delete(rowNumber);
2256
- const sizeInRow = getRowHeight(rowNumber);
2257
- diff = sizeInRow - prevSizeInRow;
2258
- } else {
2259
- sizes.set(itemKey, size);
2260
- diff = size - prevSize;
2261
- }
2262
- if (__DEV__ && suggestEstimatedItemSize) {
2263
- if (state.timeoutSizeMessage) {
2264
- clearTimeout(state.timeoutSizeMessage);
2265
- }
2266
- state.timeoutSizeMessage = setTimeout(() => {
2267
- state.timeoutSizeMessage = void 0;
2268
- const num = sizesKnown.size;
2269
- const avg = state.averageSizes[""].avg;
2270
- console.warn(
2271
- `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
2272
- );
2273
- }, 1e3);
2274
- }
2275
- state.scrollForNextCalculateItemsInView = void 0;
2276
- addTotalSize(itemKey, diff, 0);
2277
- if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2278
- doMaintainScrollAtEnd(false);
2279
- }
2280
- if (onItemSizeChanged) {
2281
- onItemSizeChanged({
2282
- size,
2283
- previous: prevSize,
2284
- index,
2285
- itemKey,
2286
- itemData: data[index]
2287
- });
2288
- }
2289
- }
2290
- if (!queuedInitialLayout && checkAllSizesKnown()) {
2291
- needsUpdateContainersDidLayout = true;
2292
- }
2293
- let isInView = index >= startBuffered && index <= endBuffered;
2294
- if (!isInView) {
2295
- const numContainers = ctx.values.get("numContainers");
2296
- for (let i = 0; i < numContainers; i++) {
2297
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
2298
- isInView = true;
2299
- break;
2300
- }
2301
- }
2302
- }
2303
- if (needsUpdateContainersDidLayout || !fromFixGaps && needsCalculate && (isInView || !queuedInitialLayout)) {
2304
- const scrollVelocity = state.scrollVelocity;
2305
- let didCalculate = false;
2306
- if ((Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1 || state.scrollingTo !== void 0) && (!waitForInitialLayout || needsUpdateContainersDidLayout || queuedInitialLayout)) {
2307
- if (Date.now() - state.lastBatchingAction < 500) {
2308
- if (!state.queuedCalculateItemsInView) {
2309
- state.queuedCalculateItemsInView = requestAnimationFrame(() => {
2310
- state.queuedCalculateItemsInView = void 0;
2311
- calculateItemsInView();
2312
- });
2313
- }
2314
- } else {
2315
- calculateItemsInView();
2316
- didCalculate = true;
2317
- }
2318
- }
2319
- if (!didCalculate && !needsUpdateContainersDidLayout && IsNewArchitecture) {
2320
- fixGaps();
2321
- }
2322
- }
2323
- if (state.needsOtherAxisSize) {
2324
- const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
2325
- const cur = peek$(ctx, "otherAxisSize");
2326
- if (!cur || otherAxisSize > cur) {
2327
- set$(ctx, "otherAxisSize", otherAxisSize);
2328
- }
2329
- }
2330
- },
2331
- []
2332
- );
2333
- const handleLayout = React2.useCallback((size) => {
2334
- const scrollLength = size[horizontal ? "width" : "height"];
2335
- const otherAxisSize = size[horizontal ? "height" : "width"];
2336
- const state = refState.current;
2337
- const didChange = scrollLength !== state.scrollLength;
2338
- const prevOtherAxisSize = state.otherAxisSize;
2339
- state.scrollLength = scrollLength;
2340
- state.otherAxisSize = otherAxisSize;
2341
- state.lastBatchingAction = Date.now();
2342
- state.scrollForNextCalculateItemsInView = void 0;
2343
- doInitialAllocateContainers();
2344
- doMaintainScrollAtEnd(false);
2345
- updateAlignItemsPaddingTop();
2346
- checkAtBottom();
2347
- checkAtTop();
2348
- if (didChange) {
2349
- calculateItemsInView();
2350
- }
2351
- if (didChange || otherAxisSize !== prevOtherAxisSize) {
2352
- set$(ctx, "scrollSize", { width: size.width, height: size.height });
2353
- }
2354
- if (refState.current) {
2355
- refState.current.needsOtherAxisSize = otherAxisSize - (stylePaddingTopState || 0) < 10;
2356
- }
2357
- if (__DEV__ && scrollLength === 0) {
2358
- warnDevOnce(
2359
- "height0",
2360
- `List ${horizontal ? "width" : "height"} is 0. You may need to set a style or \`flex: \` for the list, because children are absolutely positioned.`
2361
- );
2362
- }
2363
- }, []);
2364
- const onLayout = React2.useCallback((event) => {
2336
+ if (!IsNewArchitecture) {
2337
+ useInit(() => {
2338
+ doInitialAllocateContainersCallback();
2339
+ });
2340
+ }
2341
+ const onLayout = React3.useCallback((event) => {
2365
2342
  const layout = event.nativeEvent.layout;
2366
- handleLayout(layout);
2367
- layout[horizontal ? "width" : "height"];
2368
- layout[horizontal ? "height" : "width"];
2343
+ handleLayout(ctx, state, layout, setCanRender);
2369
2344
  if (onLayoutProp) {
2370
2345
  onLayoutProp(event);
2371
2346
  }
2372
2347
  }, []);
2373
- if (IsNewArchitecture) {
2374
- React2.useLayoutEffect(() => {
2375
- var _a, _b;
2376
- const measured = (_b = (_a = refScroller.current) == null ? void 0 : _a.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a);
2377
- if (measured) {
2378
- const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
2379
- if (size) {
2380
- handleLayout(measured);
2381
- }
2382
- }
2383
- }, []);
2384
- }
2385
- const handleScroll = React2.useCallback(
2386
- (event) => {
2387
- var _a, _b, _c, _d;
2388
- 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) {
2389
- return;
2390
- }
2391
- const state = refState.current;
2392
- const newScroll = event.nativeEvent.contentOffset[horizontal ? "x" : "y"];
2393
- state.scrollPending = newScroll;
2394
- if (state.ignoreScrollFromCalcTotal && newScroll !== 0) {
2395
- return;
2396
- }
2397
- updateScroll(newScroll);
2398
- (_d = state.onScroll) == null ? void 0 : _d.call(state, event);
2399
- },
2400
- []
2401
- );
2402
- const updateScroll = React2.useCallback((newScroll) => {
2403
- const state = refState.current;
2404
- const scrollingTo = state.scrollingTo;
2405
- if (scrollingTo !== void 0 && Math.abs(newScroll - scrollingTo.offset) < 10) {
2406
- finishScrollTo();
2407
- }
2408
- if (state.disableScrollJumpsFrom !== void 0) {
2409
- const scrollMinusAdjust = newScroll - state.scrollAdjustHandler.getAppliedAdjust();
2410
- if (Math.abs(scrollMinusAdjust - state.disableScrollJumpsFrom) > 200) {
2411
- return;
2412
- }
2413
- state.disableScrollJumpsFrom = void 0;
2414
- }
2415
- state.hasScrolled = true;
2416
- state.lastBatchingAction = Date.now();
2417
- const currentTime = performance.now();
2418
- if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === initialContentOffset)) {
2419
- state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2420
- }
2421
- if (state.scrollHistory.length > 5) {
2422
- state.scrollHistory.shift();
2423
- }
2424
- if (state.scrollTimer !== void 0) {
2425
- clearTimeout(state.scrollTimer);
2426
- }
2427
- state.scrollTimer = setTimeout(() => {
2428
- state.scrollVelocity = 0;
2429
- }, 500);
2430
- let velocity = 0;
2431
- if (state.scrollHistory.length >= 2) {
2432
- const newest = state.scrollHistory[state.scrollHistory.length - 1];
2433
- let oldest;
2434
- for (let i = 0; i < state.scrollHistory.length - 1; i++) {
2435
- const entry = state.scrollHistory[i];
2436
- if (newest.time - entry.time <= 100) {
2437
- oldest = entry;
2438
- break;
2439
- }
2440
- }
2441
- if (oldest) {
2442
- const scrollDiff = newest.scroll - oldest.scroll;
2443
- const timeDiff = newest.time - oldest.time;
2444
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
2445
- }
2446
- }
2447
- state.scrollPrev = state.scroll;
2448
- state.scrollPrevTime = state.scrollTime;
2449
- state.scroll = newScroll;
2450
- state.scrollTime = currentTime;
2451
- state.scrollVelocity = velocity;
2452
- calculateItemsInView();
2453
- checkAtBottom();
2454
- checkAtTop();
2455
- }, []);
2456
- React2.useImperativeHandle(
2348
+ React3.useImperativeHandle(
2457
2349
  forwardedRef,
2458
2350
  () => {
2459
2351
  const scrollIndexIntoView = (options) => {
2460
- if (refState.current) {
2352
+ const state2 = refState.current;
2353
+ if (state2) {
2461
2354
  const { index, ...rest2 } = options;
2462
- const { startNoBuffer, endNoBuffer } = refState.current;
2355
+ const { startNoBuffer, endNoBuffer } = state2;
2463
2356
  if (index < startNoBuffer || index > endNoBuffer) {
2464
2357
  const viewPosition = index < startNoBuffer ? 0 : 1;
2465
- scrollToIndex({
2358
+ scrollToIndex(ctx, state2, {
2466
2359
  ...rest2,
2467
2360
  viewPosition,
2468
2361
  index
@@ -2476,92 +2369,91 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2476
2369
  getScrollableNode: () => refScroller.current.getScrollableNode(),
2477
2370
  getScrollResponder: () => refScroller.current.getScrollResponder(),
2478
2371
  getState: () => {
2479
- const state = refState.current;
2480
- return state ? {
2481
- contentLength: state.totalSize,
2482
- end: state.endNoBuffer,
2483
- endBuffered: state.endBuffered,
2484
- isAtEnd: state.isAtEnd,
2485
- isAtStart: state.isAtStart,
2486
- scroll: state.scroll,
2487
- scrollLength: state.scrollLength,
2488
- start: state.startNoBuffer,
2489
- startBuffered: state.startBuffered,
2490
- sizes: state.sizesKnown,
2491
- sizeAtIndex: (index) => state.sizesKnown.get(getId(index))
2372
+ const state2 = refState.current;
2373
+ return state2 ? {
2374
+ contentLength: state2.totalSize,
2375
+ end: state2.endNoBuffer,
2376
+ endBuffered: state2.endBuffered,
2377
+ isAtEnd: state2.isAtEnd,
2378
+ isAtStart: state2.isAtStart,
2379
+ scroll: state2.scroll,
2380
+ scrollLength: state2.scrollLength,
2381
+ start: state2.startNoBuffer,
2382
+ startBuffered: state2.startBuffered,
2383
+ sizes: state2.sizesKnown,
2384
+ sizeAtIndex: (index) => state2.sizesKnown.get(getId(state2, index))
2492
2385
  } : {};
2493
2386
  },
2494
2387
  scrollIndexIntoView,
2495
2388
  scrollItemIntoView: ({ item, ...props2 }) => {
2496
- const { data } = refState.current;
2389
+ const data = refState.current.props.data;
2497
2390
  const index = data.indexOf(item);
2498
2391
  if (index !== -1) {
2499
2392
  scrollIndexIntoView({ index, ...props2 });
2500
2393
  }
2501
2394
  },
2502
- scrollToIndex,
2395
+ scrollToIndex: (params) => scrollToIndex(ctx, state, params),
2503
2396
  scrollToItem: ({ item, ...props2 }) => {
2504
- const { data } = refState.current;
2397
+ const data = refState.current.props.data;
2505
2398
  const index = data.indexOf(item);
2506
2399
  if (index !== -1) {
2507
- scrollToIndex({ index, ...props2 });
2400
+ scrollToIndex(ctx, state, { index, ...props2 });
2508
2401
  }
2509
2402
  },
2510
- scrollToOffset: (params) => scrollTo(params),
2403
+ scrollToOffset: (params) => scrollTo(state, params),
2511
2404
  scrollToEnd: (options) => {
2512
- const { data, stylePaddingBottom } = refState.current;
2405
+ const data = refState.current.props.data;
2406
+ const stylePaddingBottom = refState.current.props.stylePaddingBottom;
2513
2407
  const index = data.length - 1;
2514
2408
  if (index !== -1) {
2515
2409
  const paddingBottom = stylePaddingBottom || 0;
2516
2410
  const footerSize = peek$(ctx, "footerSize") || 0;
2517
- scrollToIndex({ index, viewPosition: 1, viewOffset: -paddingBottom - footerSize, ...options });
2411
+ scrollToIndex(ctx, state, {
2412
+ index,
2413
+ viewPosition: 1,
2414
+ viewOffset: -paddingBottom - footerSize,
2415
+ ...options
2416
+ });
2518
2417
  }
2418
+ },
2419
+ setVisibleContentAnchorOffset: (value) => {
2420
+ const val = typeof value === "function" ? value(peek$(ctx, "scrollAdjustUserOffset") || 0) : value;
2421
+ set$(ctx, "scrollAdjustUserOffset", val);
2519
2422
  }
2520
2423
  };
2521
2424
  },
2522
2425
  []
2523
2426
  );
2524
2427
  if (reactNative.Platform.OS === "web") {
2525
- React2.useEffect(() => {
2526
- var _a;
2428
+ React3.useEffect(() => {
2527
2429
  if (initialContentOffset) {
2528
- (_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler.setDisableAdjust(true);
2529
- scrollTo({ offset: initialContentOffset, animated: false });
2530
- setTimeout(() => {
2531
- var _a2;
2532
- (_a2 = refState.current) == null ? void 0 : _a2.scrollAdjustHandler.setDisableAdjust(false);
2533
- }, 0);
2430
+ scrollTo(state, { offset: initialContentOffset, animated: false });
2534
2431
  }
2535
2432
  }, []);
2536
2433
  }
2537
- return /* @__PURE__ */ React2__namespace.createElement(React2__namespace.Fragment, null, /* @__PURE__ */ React2__namespace.createElement(
2434
+ const fns = React3.useMemo(
2435
+ () => ({
2436
+ updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj),
2437
+ getRenderedItem: (key) => getRenderedItem(ctx, state, key),
2438
+ onScroll: (event) => onScroll(ctx, state, event)
2439
+ }),
2440
+ []
2441
+ );
2442
+ return /* @__PURE__ */ React3__namespace.createElement(React3__namespace.Fragment, null, /* @__PURE__ */ React3__namespace.createElement(
2538
2443
  ListComponent,
2539
2444
  {
2540
2445
  ...rest,
2446
+ canRender,
2541
2447
  horizontal,
2542
2448
  refScrollView: combinedRef,
2543
2449
  initialContentOffset,
2544
- getRenderedItem,
2545
- updateItemSize,
2546
- handleScroll,
2450
+ getRenderedItem: fns.getRenderedItem,
2451
+ updateItemSize: fns.updateItemSize,
2452
+ onScroll: fns.onScroll,
2547
2453
  onMomentumScrollEnd: (event) => {
2548
- var _a;
2549
- const scrollingTo = (_a = refState.current) == null ? void 0 : _a.scrollingTo;
2550
- if (scrollingTo !== void 0) {
2551
- requestAnimationFrame(() => {
2552
- scrollTo({ ...scrollingTo, animated: false });
2553
- refState.current.scrollingTo = void 0;
2554
- requestAnimationFrame(() => {
2555
- refState.current.scrollAdjustHandler.setDisableAdjust(false);
2556
- });
2557
- });
2558
- }
2559
- const wasPaused = refState.current.scrollAdjustHandler.unPauseAdjust();
2560
- if (wasPaused) {
2561
- refState.current.scrollVelocity = 0;
2562
- refState.current.scrollHistory = [];
2563
- calculateItemsInView();
2564
- }
2454
+ requestAnimationFrame(() => {
2455
+ finishScrollTo(refState.current);
2456
+ });
2565
2457
  if (onMomentumScrollEnd) {
2566
2458
  onMomentumScrollEnd(event);
2567
2459
  }
@@ -2574,9 +2466,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2574
2466
  maintainVisibleContentPosition,
2575
2467
  scrollEventThrottle: reactNative.Platform.OS === "web" ? 16 : void 0,
2576
2468
  waitForInitialLayout,
2577
- refreshControl: refreshControl ? stylePaddingTopState > 0 ? React2__namespace.cloneElement(refreshControl, {
2469
+ refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3__namespace.cloneElement(refreshControl, {
2578
2470
  progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
2579
- }) : refreshControl : onRefresh && /* @__PURE__ */ React2__namespace.createElement(
2471
+ }) : refreshControl : onRefresh && /* @__PURE__ */ React3__namespace.createElement(
2580
2472
  reactNative.RefreshControl,
2581
2473
  {
2582
2474
  refreshing: !!refreshing,
@@ -2585,19 +2477,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2585
2477
  }
2586
2478
  ),
2587
2479
  style,
2588
- contentContainerStyle
2480
+ contentContainerStyle,
2481
+ scrollAdjustHandler: (_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler,
2482
+ onLayoutHeader
2589
2483
  }
2590
- ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React2__namespace.createElement(DebugView, { state: refState.current }));
2484
+ ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React3__namespace.createElement(DebugView, { state: refState.current }));
2591
2485
  });
2592
- var typedForwardRef2 = React2.forwardRef;
2486
+ var typedForwardRef2 = React3.forwardRef;
2593
2487
  var renderItem = ({ item }) => item;
2594
2488
  var LazyLegendList = typedForwardRef2(function LazyLegendList2(props, forwardedRef) {
2595
2489
  const { LegendList: LegendListProp, children, ...rest } = props;
2596
- const LegendListComponent = LegendListProp != null ? LegendListProp : list.LegendList;
2597
- const data = (isArray(children) ? children : React2__namespace.Children.toArray(children)).flat(1);
2490
+ const LegendListComponent = LegendListProp != null ? LegendListProp : LegendList;
2491
+ const data = (isArray(children) ? children : React3__namespace.Children.toArray(children)).flat(1);
2598
2492
  return (
2599
2493
  // @ts-expect-error TODO: Fix this type
2600
- /* @__PURE__ */ React2__namespace.createElement(LegendListComponent, { ...rest, data, renderItem, ref: forwardedRef })
2494
+ /* @__PURE__ */ React3__namespace.createElement(LegendListComponent, { ...rest, data, renderItem, ref: forwardedRef })
2601
2495
  );
2602
2496
  });
2603
2497