@legendapp/list 1.1.4 → 2.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,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,46 +22,38 @@ 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
- // src/LegendList.tsx
29
- var ContextState = React2__namespace.createContext(null);
27
+ // src/components/LegendList.tsx
28
+ var ContextState = React3__namespace.createContext(null);
30
29
  function StateProvider({ children }) {
31
- const [value] = React2__namespace.useState(() => ({
30
+ const [value] = React3__namespace.useState(() => ({
31
+ animatedScrollY: new reactNative.Animated.Value(0),
32
+ columnWrapperStyle: void 0,
32
33
  listeners: /* @__PURE__ */ new Map(),
34
+ mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
35
+ mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
36
+ mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
37
+ mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
38
+ mapViewabilityValues: /* @__PURE__ */ new Map(),
33
39
  values: /* @__PURE__ */ new Map([
34
- ["paddingTop", 0],
35
40
  ["alignItemsPaddingTop", 0],
36
41
  ["stylePaddingTop", 0],
37
- ["headerSize", 0]
42
+ ["headerSize", 0],
43
+ ["numContainers", 0],
44
+ ["totalSize", 0]
38
45
  ]),
39
- mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
40
- mapViewabilityValues: /* @__PURE__ */ new Map(),
41
- mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
42
- mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
43
- columnWrapperStyle: void 0,
44
46
  viewRefs: /* @__PURE__ */ new Map()
45
47
  }));
46
- return /* @__PURE__ */ React2__namespace.createElement(ContextState.Provider, { value }, children);
48
+ return /* @__PURE__ */ React3__namespace.createElement(ContextState.Provider, { value }, children);
47
49
  }
48
50
  function useStateContext() {
49
- return React2__namespace.useContext(ContextState);
51
+ return React3__namespace.useContext(ContextState);
50
52
  }
51
53
  function createSelectorFunctionsArr(ctx, signalNames) {
52
54
  let lastValues = [];
53
55
  let lastSignalValues = [];
54
56
  return {
55
- subscribe: (cb) => {
56
- const listeners = [];
57
- for (const signalName of signalNames) {
58
- listeners.push(listen$(ctx, signalName, cb));
59
- }
60
- return () => {
61
- for (const listener of listeners) {
62
- listener();
63
- }
64
- };
65
- },
66
57
  get: () => {
67
58
  const currentValues = [];
68
59
  let hasChanged = false;
@@ -78,6 +69,17 @@ function createSelectorFunctionsArr(ctx, signalNames) {
78
69
  lastValues = currentValues;
79
70
  }
80
71
  return lastValues;
72
+ },
73
+ subscribe: (cb) => {
74
+ const listeners = [];
75
+ for (const signalName of signalNames) {
76
+ listeners.push(listen$(ctx, signalName, cb));
77
+ }
78
+ return () => {
79
+ for (const listener of listeners) {
80
+ listener();
81
+ }
82
+ };
81
83
  }
82
84
  };
83
85
  }
@@ -112,39 +114,30 @@ function getContentSize(ctx) {
112
114
  const stylePaddingTop = values.get("stylePaddingTop") || 0;
113
115
  const headerSize = values.get("headerSize") || 0;
114
116
  const footerSize = values.get("footerSize") || 0;
115
- const totalSize = values.get("totalSize") || 0;
117
+ const totalSize = values.get("totalSize");
116
118
  return headerSize + footerSize + totalSize + stylePaddingTop;
117
119
  }
118
120
  function useArr$(signalNames) {
119
- const ctx = React2__namespace.useContext(ContextState);
120
- const { subscribe, get } = React2__namespace.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
121
+ const ctx = React3__namespace.useContext(ContextState);
122
+ const { subscribe, get } = React3__namespace.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
121
123
  const value = shim.useSyncExternalStore(subscribe, get);
122
124
  return value;
123
125
  }
124
126
  function useSelector$(signalName, selector) {
125
- const ctx = React2__namespace.useContext(ContextState);
126
- const { subscribe, get } = React2__namespace.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
127
+ const ctx = React3__namespace.useContext(ContextState);
128
+ const { subscribe, get } = React3__namespace.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
127
129
  const value = shim.useSyncExternalStore(subscribe, () => selector(get()[0]));
128
130
  return value;
129
131
  }
130
132
 
131
- // src/DebugView.tsx
133
+ // src/components/DebugView.tsx
132
134
  var DebugRow = ({ children }) => {
133
- return /* @__PURE__ */ React2__namespace.createElement(reactNative.View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" } }, children);
135
+ return /* @__PURE__ */ React3__namespace.createElement(reactNative.View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
134
136
  };
135
- var DebugView = React2__namespace.memo(function DebugView2({ state }) {
137
+ var DebugView = React3__namespace.memo(function DebugView2({ state }) {
136
138
  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$([
139
+ const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, _numContainers = 0, _numContainersPooled = 0] = useArr$([
146
140
  "totalSize",
147
- "totalSizeWithScrollAdjust",
148
141
  "scrollAdjust",
149
142
  "debugRawScroll",
150
143
  "debugComputedScroll",
@@ -152,45 +145,179 @@ var DebugView = React2__namespace.memo(function DebugView2({ state }) {
152
145
  "numContainersPooled"
153
146
  ]);
154
147
  const contentSize = getContentSize(ctx);
155
- const [, forceUpdate] = React2.useReducer((x) => x + 1, 0);
148
+ const [, forceUpdate] = React3.useReducer((x) => x + 1, 0);
156
149
  useInterval(() => {
157
150
  forceUpdate();
158
151
  }, 100);
159
- return /* @__PURE__ */ React2__namespace.createElement(
152
+ return /* @__PURE__ */ React3__namespace.createElement(
160
153
  reactNative.View,
161
154
  {
155
+ pointerEvents: "none",
162
156
  style: {
163
- position: "absolute",
164
- top: 0,
165
- right: 0,
166
- paddingLeft: 4,
167
- paddingBottom: 4,
168
157
  // height: 100,
169
158
  backgroundColor: "#FFFFFFCC",
159
+ borderRadius: 4,
170
160
  padding: 4,
171
- borderRadius: 4
172
- },
173
- pointerEvents: "none"
161
+ paddingBottom: 4,
162
+ paddingLeft: 4,
163
+ position: "absolute",
164
+ right: 0,
165
+ top: 0
166
+ }
174
167
  },
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)))
168
+ /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "TotalSize:"), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, totalSize.toFixed(2))),
169
+ /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "ContentSize:"), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, contentSize.toFixed(2))),
170
+ /* @__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))),
171
+ /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null),
172
+ /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "ScrollAdjust:"), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, scrollAdjust.toFixed(2))),
173
+ /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null),
174
+ /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "RawScroll: "), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, rawScroll.toFixed(2))),
175
+ /* @__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
176
  );
185
177
  });
186
178
  function useInterval(callback, delay) {
187
- React2.useEffect(() => {
179
+ React3.useEffect(() => {
188
180
  const interval = setInterval(callback, delay);
189
181
  return () => clearInterval(interval);
190
182
  }, [delay]);
191
183
  }
184
+ var LeanViewComponent = React3__namespace.forwardRef((props, ref) => {
185
+ return React3__namespace.createElement("RCTView", { ...props, ref });
186
+ });
187
+ LeanViewComponent.displayName = "RCTView";
188
+ var LeanView = reactNative.Platform.OS === "android" || reactNative.Platform.OS === "ios" ? LeanViewComponent : reactNative.View;
189
+
190
+ // src/constants.ts
191
+ var POSITION_OUT_OF_VIEW = -1e7;
192
+ var ENABLE_DEVMODE = __DEV__ && false;
193
+ var ENABLE_DEBUG_VIEW = __DEV__ && false;
194
+ var IsNewArchitecture = global.nativeFabricUIManager != null;
195
+ var useAnimatedValue = (initialValue) => {
196
+ return React3.useRef(new reactNative.Animated.Value(initialValue)).current;
197
+ };
198
+
199
+ // src/hooks/useValue$.ts
200
+ function useValue$(key, params) {
201
+ var _a;
202
+ const { getValue, delay } = params || {};
203
+ const ctx = useStateContext();
204
+ const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
205
+ React3.useMemo(() => {
206
+ let newValue;
207
+ let prevValue;
208
+ let didQueueTask = false;
209
+ listen$(ctx, key, (v) => {
210
+ newValue = getValue ? getValue(v) : v;
211
+ if (delay !== void 0) {
212
+ const fn = () => {
213
+ didQueueTask = false;
214
+ if (newValue !== void 0) {
215
+ animValue.setValue(newValue);
216
+ }
217
+ };
218
+ const delayValue = typeof delay === "function" ? delay(newValue, prevValue) : delay;
219
+ prevValue = newValue;
220
+ if (!didQueueTask) {
221
+ didQueueTask = true;
222
+ if (delayValue === 0) {
223
+ queueMicrotask(fn);
224
+ } else {
225
+ setTimeout(fn, delayValue);
226
+ }
227
+ }
228
+ } else {
229
+ animValue.setValue(newValue);
230
+ }
231
+ });
232
+ }, []);
233
+ return animValue;
234
+ }
235
+ var typedForwardRef = React3.forwardRef;
236
+ var typedMemo = React3.memo;
237
+
238
+ // src/components/PositionView.tsx
239
+ var PositionViewState = typedMemo(function PositionView({
240
+ id,
241
+ horizontal,
242
+ style,
243
+ refView,
244
+ ...rest
245
+ }) {
246
+ const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
247
+ return /* @__PURE__ */ React3__namespace.createElement(
248
+ LeanView,
249
+ {
250
+ ref: refView,
251
+ style: [
252
+ style,
253
+ horizontal ? { transform: [{ translateX: position }] } : { transform: [{ translateY: position }] }
254
+ ],
255
+ ...rest
256
+ }
257
+ );
258
+ });
259
+ var PositionViewAnimated = typedMemo(function PositionView2({
260
+ id,
261
+ horizontal,
262
+ style,
263
+ refView,
264
+ ...rest
265
+ }) {
266
+ const position$ = useValue$(`containerPosition${id}`, {
267
+ getValue: (v) => v != null ? v : POSITION_OUT_OF_VIEW
268
+ });
269
+ return /* @__PURE__ */ React3__namespace.createElement(
270
+ reactNative.Animated.View,
271
+ {
272
+ ref: refView,
273
+ style: [
274
+ style,
275
+ horizontal ? { transform: [{ translateX: position$ }] } : { transform: [{ translateY: position$ }] }
276
+ ],
277
+ ...rest
278
+ }
279
+ );
280
+ });
281
+ var PositionViewSticky = typedMemo(function PositionViewSticky2({
282
+ id,
283
+ horizontal,
284
+ style,
285
+ refView,
286
+ animatedScrollY,
287
+ stickyOffset,
288
+ index,
289
+ ...rest
290
+ }) {
291
+ const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
292
+ const transform = React3__namespace.useMemo(() => {
293
+ if (animatedScrollY && stickyOffset) {
294
+ const stickyPosition = animatedScrollY.interpolate({
295
+ extrapolate: "clamp",
296
+ inputRange: [position, position + 5e3],
297
+ outputRange: [position, position + 5e3]
298
+ });
299
+ return horizontal ? [{ translateX: stickyPosition }] : [{ translateY: stickyPosition }];
300
+ }
301
+ }, [position, horizontal, animatedScrollY, stickyOffset]);
302
+ const viewStyle = React3__namespace.useMemo(() => [style, { zIndex: index + 1e3 }, { transform }], [style, transform]);
303
+ return /* @__PURE__ */ React3__namespace.createElement(reactNative.Animated.View, { ref: refView, style: viewStyle, ...rest });
304
+ });
305
+ var PositionView3 = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
306
+ function Separator({ ItemSeparatorComponent, itemKey, leadingItem }) {
307
+ const [lastItemKeys] = useArr$(["lastItemKeys"]);
308
+ const isALastItem = lastItemKeys.includes(itemKey);
309
+ return isALastItem ? null : /* @__PURE__ */ React3__namespace.createElement(ItemSeparatorComponent, { leadingItem });
310
+ }
311
+ var symbolFirst = Symbol();
312
+ function useInit(cb) {
313
+ const refValue = React3.useRef(symbolFirst);
314
+ if (refValue.current === symbolFirst) {
315
+ refValue.current = cb();
316
+ }
317
+ return refValue.current;
318
+ }
192
319
 
193
- // src/helpers.ts
320
+ // src/utils/helpers.ts
194
321
  function isFunction(obj) {
195
322
  return typeof obj === "function";
196
323
  }
@@ -204,12 +331,12 @@ function warnDevOnce(id, text) {
204
331
  console.warn(`[legend-list] ${text}`);
205
332
  }
206
333
  }
334
+ function roundSize(size) {
335
+ return Math.floor(size * 8) / 8;
336
+ }
207
337
  function isNullOrUndefined(value) {
208
338
  return value === null || value === void 0;
209
339
  }
210
- function comparatorByDistance(a, b) {
211
- return b.distance - a.distance;
212
- }
213
340
  function comparatorDefault(a, b) {
214
341
  return a - b;
215
342
  }
@@ -220,20 +347,12 @@ function getPadding(s, type) {
220
347
  function extractPadding(style, contentContainerStyle, type) {
221
348
  return getPadding(style, type) + getPadding(contentContainerStyle, type);
222
349
  }
223
- var symbolFirst = Symbol();
224
- function useInit(cb) {
225
- const refValue = React2.useRef(symbolFirst);
226
- if (refValue.current === symbolFirst) {
227
- refValue.current = cb();
228
- }
229
- return refValue.current;
230
- }
231
350
 
232
- // src/ContextContainer.ts
233
- var ContextContainer = React2.createContext(null);
351
+ // src/state/ContextContainer.ts
352
+ var ContextContainer = React3.createContext(null);
234
353
  function useViewability(callback, configId) {
235
354
  const ctx = useStateContext();
236
- const { containerId } = React2.useContext(ContextContainer);
355
+ const { containerId } = React3.useContext(ContextContainer);
237
356
  const key = containerId + (configId != null ? configId : "");
238
357
  useInit(() => {
239
358
  const value = ctx.mapViewabilityValues.get(key);
@@ -242,7 +361,7 @@ function useViewability(callback, configId) {
242
361
  }
243
362
  });
244
363
  ctx.mapViewabilityCallbacks.set(key, callback);
245
- React2.useEffect(
364
+ React3.useEffect(
246
365
  () => () => {
247
366
  ctx.mapViewabilityCallbacks.delete(key);
248
367
  },
@@ -251,7 +370,7 @@ function useViewability(callback, configId) {
251
370
  }
252
371
  function useViewabilityAmount(callback) {
253
372
  const ctx = useStateContext();
254
- const { containerId } = React2.useContext(ContextContainer);
373
+ const { containerId } = React3.useContext(ContextContainer);
255
374
  useInit(() => {
256
375
  const value = ctx.mapViewabilityAmountValues.get(containerId);
257
376
  if (value) {
@@ -259,7 +378,7 @@ function useViewabilityAmount(callback) {
259
378
  }
260
379
  });
261
380
  ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
262
- React2.useEffect(
381
+ React3.useEffect(
263
382
  () => () => {
264
383
  ctx.mapViewabilityAmountCallbacks.delete(containerId);
265
384
  },
@@ -267,13 +386,13 @@ function useViewabilityAmount(callback) {
267
386
  );
268
387
  }
269
388
  function useRecyclingEffect(effect) {
270
- const { index, value } = React2.useContext(ContextContainer);
271
- const prevValues = React2.useRef({
389
+ const { index, value } = React3.useContext(ContextContainer);
390
+ const prevValues = React3.useRef({
272
391
  prevIndex: void 0,
273
392
  prevItem: void 0
274
393
  });
275
- React2.useEffect(() => {
276
- let ret = void 0;
394
+ React3.useEffect(() => {
395
+ let ret;
277
396
  if (prevValues.current.prevIndex !== void 0 && prevValues.current.prevItem !== void 0) {
278
397
  ret = effect({
279
398
  index,
@@ -287,36 +406,37 @@ function useRecyclingEffect(effect) {
287
406
  prevItem: value
288
407
  };
289
408
  return ret;
290
- }, [index, value]);
409
+ }, [index, value, effect]);
291
410
  }
292
411
  function useRecyclingState(valueOrFun) {
293
- const { index, value, itemKey, triggerLayout } = React2.useContext(ContextContainer);
294
- const refState = React2.useRef({
412
+ const { index, value, itemKey, triggerLayout } = React3.useContext(ContextContainer);
413
+ const refState = React3.useRef({
295
414
  itemKey: null,
296
415
  value: null
297
416
  });
298
- const [_, setRenderNum] = React2.useState(0);
299
- if (refState.current.itemKey !== itemKey) {
300
- refState.current.itemKey = itemKey;
301
- refState.current.value = isFunction(valueOrFun) ? valueOrFun({
417
+ const [_, setRenderNum] = React3.useState(0);
418
+ const state = refState.current;
419
+ if (state.itemKey !== itemKey) {
420
+ state.itemKey = itemKey;
421
+ state.value = isFunction(valueOrFun) ? valueOrFun({
302
422
  index,
303
423
  item: value,
304
424
  prevIndex: void 0,
305
425
  prevItem: void 0
306
426
  }) : valueOrFun;
307
427
  }
308
- const setState = React2.useCallback(
428
+ const setState = React3.useCallback(
309
429
  (newState) => {
310
- refState.current.value = isFunction(newState) ? newState(refState.current.value) : newState;
430
+ state.value = isFunction(newState) ? newState(state.value) : newState;
311
431
  setRenderNum((v) => v + 1);
312
432
  triggerLayout();
313
433
  },
314
- [triggerLayout]
434
+ [triggerLayout, state]
315
435
  );
316
- return [refState.current.value, setState];
436
+ return [state.value, setState];
317
437
  }
318
438
  function useIsLastItem() {
319
- const { itemKey } = React2.useContext(ContextContainer);
439
+ const { itemKey } = React3.useContext(ContextContainer);
320
440
  const isLast = useSelector$("lastItemKeys", (lastItemKeys) => (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false);
321
441
  return isLast;
322
442
  }
@@ -324,135 +444,131 @@ function useListScrollSize() {
324
444
  const [scrollSize] = useArr$(["scrollSize"]);
325
445
  return scrollSize;
326
446
  }
327
- var LeanViewComponent = React2__namespace.forwardRef((props, ref) => {
328
- return React2__namespace.createElement("RCTView", { ...props, ref });
329
- });
330
- LeanViewComponent.displayName = "RCTView";
331
- var LeanView = reactNative.Platform.OS === "android" || reactNative.Platform.OS === "ios" ? LeanViewComponent : reactNative.View;
332
-
333
- // src/constants.ts
334
- 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
447
+ var noop = () => {
339
448
  };
340
- var ENABLE_DEVMODE = __DEV__ && false;
341
- var ENABLE_DEBUG_VIEW = __DEV__ && false;
342
- var IsNewArchitecture = global.nativeFabricUIManager != null;
449
+ function useSyncLayout() {
450
+ if (IsNewArchitecture) {
451
+ const { triggerLayout: syncLayout } = React3.useContext(ContextContainer);
452
+ return syncLayout;
453
+ } else {
454
+ return noop;
455
+ }
456
+ }
343
457
 
344
- // src/Container.tsx
345
- var Container = ({
458
+ // src/components/Container.tsx
459
+ var Container = typedMemo(function Container2({
346
460
  id,
347
461
  recycleItems,
348
462
  horizontal,
349
- getRenderedItem,
350
- updateItemSize,
463
+ getRenderedItem: getRenderedItem2,
464
+ updateItemSize: updateItemSize2,
351
465
  ItemSeparatorComponent
352
- }) => {
466
+ }) {
353
467
  const ctx = useStateContext();
354
- 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}`,
468
+ const { columnWrapperStyle, animatedScrollY } = ctx;
469
+ const [column = 0, data, itemKey, numColumns, extraData, isSticky, stickyOffset] = useArr$([
367
470
  `containerColumn${id}`,
368
- "numColumns",
369
- "lastItemKeys",
370
- `containerItemKey${id}`,
371
471
  `containerItemData${id}`,
372
- "extraData"
472
+ `containerItemKey${id}`,
473
+ "numColumns",
474
+ "extraData",
475
+ `containerSticky${id}`,
476
+ `containerStickyOffset${id}`
373
477
  ]);
374
- const refLastSize = React2.useRef();
375
- const ref = React2.useRef(null);
376
- const [layoutRenderCount, forceLayoutRender] = React2.useState(0);
478
+ const refLastSize = React3.useRef();
479
+ const ref = React3.useRef(null);
480
+ const [layoutRenderCount, forceLayoutRender] = React3.useState(0);
377
481
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
378
482
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
379
- const isALastItem = lastItemKeys.includes(itemKey);
380
- let paddingStyles;
381
- if (columnWrapperStyle) {
382
- const { columnGap, rowGap, gap } = columnWrapperStyle;
383
- if (horizontal) {
384
- paddingStyles = {
385
- paddingRight: !isALastItem ? columnGap || gap || void 0 : void 0,
386
- paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
387
- };
388
- } else {
389
- paddingStyles = {
390
- paddingBottom: !isALastItem ? rowGap || gap || void 0 : void 0,
391
- paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
392
- };
483
+ let didLayout = false;
484
+ const style = React3.useMemo(() => {
485
+ let paddingStyles;
486
+ if (columnWrapperStyle) {
487
+ const { columnGap, rowGap, gap } = columnWrapperStyle;
488
+ if (horizontal) {
489
+ paddingStyles = {
490
+ paddingRight: columnGap || gap || void 0,
491
+ paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
492
+ };
493
+ } else {
494
+ paddingStyles = {
495
+ paddingBottom: rowGap || gap || void 0,
496
+ paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
497
+ };
498
+ }
393
499
  }
394
- }
395
- const style = horizontal ? {
396
- flexDirection: ItemSeparatorComponent ? "row" : void 0,
397
- position: "absolute",
398
- top: otherAxisPos,
399
- height: otherAxisSize,
400
- left: position.relativeCoordinate,
401
- ...paddingStyles || {}
402
- } : {
403
- position: "absolute",
404
- left: otherAxisPos,
405
- right: numColumns > 1 ? null : 0,
406
- width: otherAxisSize,
407
- top: position.relativeCoordinate,
408
- ...paddingStyles || {}
409
- };
410
- const renderedItemInfo = React2.useMemo(
411
- () => itemKey !== void 0 ? getRenderedItem(itemKey) : null,
500
+ return horizontal ? {
501
+ flexDirection: ItemSeparatorComponent ? "row" : void 0,
502
+ height: otherAxisSize,
503
+ left: 0,
504
+ position: "absolute",
505
+ top: otherAxisPos,
506
+ ...paddingStyles || {}
507
+ } : {
508
+ left: otherAxisPos,
509
+ position: "absolute",
510
+ right: numColumns > 1 ? null : 0,
511
+ top: 0,
512
+ width: otherAxisSize,
513
+ ...paddingStyles || {}
514
+ };
515
+ }, [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns]);
516
+ const renderedItemInfo = React3.useMemo(
517
+ () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
412
518
  [itemKey, data, extraData]
413
519
  );
414
520
  const { index, renderedItem } = renderedItemInfo || {};
415
- const triggerLayout = React2.useCallback(() => {
416
- forceLayoutRender((v) => v + 1);
417
- }, []);
521
+ const contextValue = React3.useMemo(() => {
522
+ ctx.viewRefs.set(id, ref);
523
+ return {
524
+ containerId: id,
525
+ index,
526
+ itemKey,
527
+ triggerLayout: () => {
528
+ forceLayoutRender((v) => v + 1);
529
+ },
530
+ value: data
531
+ };
532
+ }, [id, itemKey, index, data]);
418
533
  const onLayout = (event) => {
419
534
  var _a, _b;
420
535
  if (!isNullOrUndefined(itemKey)) {
536
+ didLayout = true;
421
537
  let layout = event.nativeEvent.layout;
422
538
  const size = layout[horizontal ? "width" : "height"];
423
539
  const doUpdate = () => {
424
- refLastSize.current = { width: layout.width, height: layout.height };
425
- updateItemSize(itemKey, layout);
540
+ refLastSize.current = { height: layout.height, width: layout.width };
541
+ updateItemSize2(itemKey, layout);
426
542
  };
427
543
  if (IsNewArchitecture || size > 0) {
428
544
  doUpdate();
429
545
  } else {
430
- (_b = (_a = ref.current) == null ? void 0 : _a.measure) == null ? void 0 : _b.call(_a, (x, y, width, height) => {
431
- layout = { width, height };
546
+ (_b = (_a = ref.current) == null ? void 0 : _a.measure) == null ? void 0 : _b.call(_a, (_x, _y, width, height) => {
547
+ layout = { height, width };
432
548
  doUpdate();
433
549
  });
434
550
  }
435
551
  }
436
552
  };
437
553
  if (IsNewArchitecture) {
438
- React2.useLayoutEffect(() => {
554
+ React3.useLayoutEffect(() => {
439
555
  var _a, _b;
440
556
  if (!isNullOrUndefined(itemKey)) {
441
557
  const measured = (_b = (_a = ref.current) == null ? void 0 : _a.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a);
442
558
  if (measured) {
443
559
  const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
444
560
  if (size) {
445
- updateItemSize(itemKey, measured);
561
+ updateItemSize2(itemKey, measured);
446
562
  }
447
563
  }
448
564
  }
449
- }, [itemKey, layoutRenderCount, isALastItem]);
565
+ }, [itemKey, layoutRenderCount]);
450
566
  } else {
451
- React2.useEffect(() => {
567
+ React3.useEffect(() => {
452
568
  if (!isNullOrUndefined(itemKey)) {
453
569
  const timeout = setTimeout(() => {
454
- if (refLastSize.current) {
455
- updateItemSize(itemKey, refLastSize.current);
570
+ if (!didLayout && refLastSize.current) {
571
+ updateItemSize2(itemKey, refLastSize.current);
456
572
  }
457
573
  }, 16);
458
574
  return () => {
@@ -461,200 +577,204 @@ var Container = ({
461
577
  }
462
578
  }, [itemKey]);
463
579
  }
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;
474
- }
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);
478
- };
479
- var typedForwardRef = React2.forwardRef;
480
- var typedMemo = React2.memo;
481
- var useAnimatedValue = (initialValue) => {
482
- return React2.useRef(new reactNative.Animated.Value(initialValue)).current;
483
- };
484
-
485
- // src/useValue$.ts
486
- function useValue$(key, getValue, useMicrotask) {
487
- var _a;
488
- const ctx = useStateContext();
489
- const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
490
- React2.useMemo(() => {
491
- let newValue = void 0;
492
- listen$(ctx, key, (v) => {
493
- if (useMicrotask && newValue === void 0) {
494
- queueMicrotask(() => {
495
- animValue.setValue(newValue);
496
- newValue = void 0;
497
- });
498
- }
499
- newValue = getValue ? getValue(v) : v;
500
- if (!useMicrotask) {
501
- animValue.setValue(newValue);
580
+ const PositionComponent = isSticky ? PositionViewSticky : PositionView3;
581
+ return /* @__PURE__ */ React3__namespace.createElement(
582
+ PositionComponent,
583
+ {
584
+ animatedScrollY: isSticky ? animatedScrollY : void 0,
585
+ horizontal,
586
+ id,
587
+ index,
588
+ key: recycleItems ? void 0 : itemKey,
589
+ onLayout,
590
+ refView: ref,
591
+ stickyOffset: isSticky ? stickyOffset : void 0,
592
+ style
593
+ },
594
+ /* @__PURE__ */ React3__namespace.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React3__namespace.createElement(
595
+ Separator,
596
+ {
597
+ ItemSeparatorComponent,
598
+ itemKey,
599
+ leadingItem: renderedItemInfo.item
502
600
  }
503
- });
504
- }, []);
505
- return animValue;
506
- }
601
+ ))
602
+ );
603
+ });
507
604
 
508
- // src/Containers.tsx
605
+ // src/components/Containers.tsx
509
606
  var Containers = typedMemo(function Containers2({
510
607
  horizontal,
511
608
  recycleItems,
512
609
  ItemSeparatorComponent,
513
610
  waitForInitialLayout,
514
- updateItemSize,
515
- getRenderedItem
611
+ updateItemSize: updateItemSize2,
612
+ getRenderedItem: getRenderedItem2
516
613
  }) {
517
614
  const ctx = useStateContext();
518
615
  const columnWrapperStyle = ctx.columnWrapperStyle;
519
616
  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
- );
617
+ const animSize = useValue$("totalSize", {
618
+ // Use a microtask if increasing the size significantly, otherwise use a timeout
619
+ delay: (value, prevValue) => !prevValue || value - prevValue > 20 ? 0 : 200
620
+ });
621
+ const animOpacity = waitForInitialLayout && !IsNewArchitecture ? useValue$("containersDidLayout", { getValue: (value) => value ? 1 : 0 }) : void 0;
622
+ const otherAxisSize = useValue$("otherAxisSize", { delay: 0 });
533
623
  const containers = [];
534
624
  for (let i = 0; i < numContainers; i++) {
535
625
  containers.push(
536
- /* @__PURE__ */ React2__namespace.createElement(
626
+ /* @__PURE__ */ React3__namespace.createElement(
537
627
  Container,
538
628
  {
629
+ getRenderedItem: getRenderedItem2,
630
+ horizontal,
631
+ ItemSeparatorComponent,
539
632
  id: i,
540
633
  key: i,
541
634
  recycleItems,
542
- horizontal,
543
- getRenderedItem,
544
- updateItemSize,
545
- ItemSeparatorComponent
635
+ updateItemSize: updateItemSize2
546
636
  }
547
637
  )
548
638
  );
549
639
  }
550
- const style = horizontal ? { width: animSize, opacity: animOpacity, minHeight: otherAxisSize } : { height: animSize, opacity: animOpacity, minWidth: otherAxisSize };
640
+ const style = horizontal ? { minHeight: otherAxisSize, opacity: animOpacity, width: animSize } : { height: animSize, minWidth: otherAxisSize, opacity: animOpacity };
551
641
  if (columnWrapperStyle && numColumns > 1) {
552
642
  const { columnGap, rowGap, gap } = columnWrapperStyle;
643
+ const gapX = columnGap || gap || 0;
644
+ const gapY = rowGap || gap || 0;
553
645
  if (horizontal) {
554
- const my = (rowGap || gap || 0) / 2;
555
- if (my) {
556
- style.marginVertical = -my;
646
+ if (gapY) {
647
+ style.marginVertical = -gapY / 2;
648
+ }
649
+ if (gapX) {
650
+ style.marginRight = -gapX;
557
651
  }
558
652
  } else {
559
- const mx = (columnGap || gap || 0) / 2;
560
- if (mx) {
561
- style.marginHorizontal = -mx;
653
+ if (gapX) {
654
+ style.marginHorizontal = -gapX;
655
+ }
656
+ if (gapY) {
657
+ style.marginBottom = -gapY;
562
658
  }
563
659
  }
564
660
  }
565
- return /* @__PURE__ */ React2__namespace.createElement(reactNative.Animated.View, { style }, containers);
661
+ return /* @__PURE__ */ React3__namespace.createElement(reactNative.Animated.View, { style }, containers);
566
662
  });
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
663
+ function ScrollAdjust() {
664
+ const bias = 1e7;
665
+ const [scrollAdjust, scrollAdjustUserOffset] = useArr$(["scrollAdjust", "scrollAdjustUserOffset"]);
666
+ const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0) + bias;
667
+ return /* @__PURE__ */ React3__namespace.createElement(
668
+ reactNative.View,
669
+ {
670
+ style: {
671
+ height: 0,
672
+ left: 0,
673
+ position: "absolute",
674
+ top: scrollOffset,
675
+ width: 0
676
+ }
677
+ }
678
+ );
679
+ }
680
+
681
+ // src/components/SnapWrapper.tsx
682
+ function SnapWrapper({ ScrollComponent, ...props }) {
683
+ const [snapToOffsets] = useArr$(["snapToOffsets"]);
684
+ return /* @__PURE__ */ React.createElement(ScrollComponent, { ...props, snapToOffsets });
685
+ }
686
+ function useThrottleDebounce(mode) {
687
+ const timeoutRef = React3.useRef(null);
688
+ const lastCallTimeRef = React3.useRef(0);
689
+ const lastArgsRef = React3.useRef(null);
690
+ const clearTimeoutRef = () => {
691
+ if (timeoutRef.current) {
692
+ clearTimeout(timeoutRef.current);
693
+ timeoutRef.current = null;
694
+ }
582
695
  };
583
- return /* @__PURE__ */ React2__namespace.createElement(
584
- reactNative.Animated.View,
696
+ const execute = React3.useCallback((callback, delay, ...args) => {
585
697
  {
586
- style: [style, additionalSize],
587
- onLayout: (event) => {
588
- const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
589
- set$(ctx, "headerSize", size);
698
+ const now = Date.now();
699
+ lastArgsRef.current = args;
700
+ if (now - lastCallTimeRef.current >= delay) {
701
+ lastCallTimeRef.current = now;
702
+ callback(...args);
703
+ clearTimeoutRef();
704
+ } else {
705
+ clearTimeoutRef();
706
+ timeoutRef.current = setTimeout(
707
+ () => {
708
+ if (lastArgsRef.current) {
709
+ lastCallTimeRef.current = Date.now();
710
+ callback(...lastArgsRef.current);
711
+ timeoutRef.current = null;
712
+ lastArgsRef.current = null;
713
+ }
714
+ },
715
+ delay - (now - lastCallTimeRef.current)
716
+ );
590
717
  }
718
+ }
719
+ }, [mode]);
720
+ return execute;
721
+ }
722
+
723
+ // src/hooks/useSyncLayout.tsx
724
+ function useSyncLayout2({
725
+ onChange
726
+ }) {
727
+ const ref = React3.useRef(null);
728
+ const onLayout = React3.useCallback(
729
+ (event) => {
730
+ onChange(event.nativeEvent.layout, false);
591
731
  },
592
- children
732
+ [onChange]
593
733
  );
734
+ if (IsNewArchitecture) {
735
+ React3.useLayoutEffect(() => {
736
+ if (ref.current) {
737
+ ref.current.measure((x, y, width, height) => {
738
+ onChange({ height, width, x, y }, true);
739
+ });
740
+ }
741
+ }, []);
742
+ }
743
+ return { onLayout, ref };
594
744
  }
595
745
 
596
- // src/ListComponent.tsx
746
+ // src/components/ListComponent.tsx
597
747
  var getComponent = (Component) => {
598
- if (React2__namespace.isValidElement(Component)) {
748
+ if (React3__namespace.isValidElement(Component)) {
599
749
  return Component;
600
750
  }
601
751
  if (Component) {
602
- return /* @__PURE__ */ React2__namespace.createElement(Component, null);
752
+ return /* @__PURE__ */ React3__namespace.createElement(Component, null);
603
753
  }
604
754
  return null;
605
755
  };
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 });
756
+ var Padding = () => {
757
+ const animPaddingTop = useValue$("alignItemsPaddingTop", { delay: 0 });
758
+ return /* @__PURE__ */ React3__namespace.createElement(reactNative.Animated.View, { style: { paddingTop: animPaddingTop } });
611
759
  };
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(
760
+ var PaddingDevMode = () => {
761
+ const animPaddingTop = useValue$("alignItemsPaddingTop", { delay: 0 });
762
+ return /* @__PURE__ */ React3__namespace.createElement(React3__namespace.Fragment, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Animated.View, { style: { paddingTop: animPaddingTop } }), /* @__PURE__ */ React3__namespace.createElement(
616
763
  reactNative.Animated.View,
617
764
  {
618
765
  style: {
619
- position: "absolute",
620
- top: reactNative.Animated.add(animScrollAdjust, reactNative.Animated.multiply(animScrollAdjust, -1)),
766
+ backgroundColor: "green",
621
767
  height: animPaddingTop,
622
768
  left: 0,
623
- right: 0,
624
- backgroundColor: "green"
625
- }
626
- }
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
769
  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",
770
+ right: 0,
771
+ top: 0
653
772
  }
654
773
  }
655
774
  ));
656
775
  };
657
776
  var ListComponent = typedMemo(function ListComponent2({
777
+ canRender,
658
778
  style,
659
779
  contentContainerStyle,
660
780
  horizontal,
@@ -663,194 +783,616 @@ var ListComponent = typedMemo(function ListComponent2({
663
783
  ItemSeparatorComponent,
664
784
  alignItemsAtEnd,
665
785
  waitForInitialLayout,
666
- handleScroll,
786
+ onScroll: onScroll2,
667
787
  onLayout,
668
788
  ListHeaderComponent,
669
789
  ListHeaderComponentStyle,
670
790
  ListFooterComponent,
671
791
  ListFooterComponentStyle,
672
792
  ListEmptyComponent,
673
- getRenderedItem,
674
- updateItemSize,
793
+ getRenderedItem: getRenderedItem2,
794
+ updateItemSize: updateItemSize2,
675
795
  refScrollView,
676
796
  maintainVisibleContentPosition,
677
797
  renderScrollComponent,
798
+ scrollAdjustHandler,
799
+ onLayoutHeader,
800
+ snapToIndices,
801
+ stickyIndices,
678
802
  ...rest
679
803
  }) {
680
804
  const ctx = useStateContext();
681
- const ScrollComponent = renderScrollComponent ? React2.useMemo(
682
- () => React2__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
805
+ const { onLayout: onLayoutHeaderSync, ref: refHeader } = useSyncLayout2({
806
+ onChange: onLayoutHeader
807
+ });
808
+ const ScrollComponent = renderScrollComponent ? React3.useMemo(
809
+ () => React3__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
683
810
  [renderScrollComponent]
684
- ) : reactNative.ScrollView;
685
- return /* @__PURE__ */ React2__namespace.createElement(
686
- ScrollComponent,
811
+ ) : reactNative.Animated.ScrollView;
812
+ React3__namespace.useEffect(() => {
813
+ if (canRender) {
814
+ setTimeout(() => {
815
+ scrollAdjustHandler.setMounted();
816
+ }, 0);
817
+ }
818
+ }, [canRender]);
819
+ const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
820
+ return /* @__PURE__ */ React3__namespace.createElement(
821
+ SnapOrScroll,
687
822
  {
688
823
  ...rest,
689
- style,
690
- maintainVisibleContentPosition: maintainVisibleContentPosition && !ListEmptyComponent ? { minIndexForVisible: 0 } : void 0,
691
824
  contentContainerStyle: [
692
825
  contentContainerStyle,
693
826
  horizontal ? {
694
827
  height: "100%"
695
828
  } : {}
696
829
  ],
697
- onScroll: handleScroll,
698
- onLayout,
699
- horizontal,
700
830
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
701
- ref: refScrollView
831
+ horizontal,
832
+ maintainVisibleContentPosition: maintainVisibleContentPosition && !ListEmptyComponent ? { minIndexForVisible: 0 } : void 0,
833
+ onLayout,
834
+ onScroll: onScroll2,
835
+ ref: refScrollView,
836
+ ScrollComponent: snapToIndices ? ScrollComponent : void 0,
837
+ style
702
838
  },
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
- ),
839
+ maintainVisibleContentPosition && /* @__PURE__ */ React3__namespace.createElement(ScrollAdjust, null),
840
+ ENABLE_DEVMODE ? /* @__PURE__ */ React3__namespace.createElement(PaddingDevMode, null) : /* @__PURE__ */ React3__namespace.createElement(Padding, null),
841
+ ListHeaderComponent && /* @__PURE__ */ React3__namespace.createElement(reactNative.View, { onLayout: onLayoutHeaderSync, ref: refHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
714
842
  ListEmptyComponent && getComponent(ListEmptyComponent),
715
- /* @__PURE__ */ React2__namespace.createElement(
843
+ canRender && /* @__PURE__ */ React3__namespace.createElement(
716
844
  Containers,
717
845
  {
846
+ getRenderedItem: getRenderedItem2,
718
847
  horizontal,
719
- recycleItems,
720
- waitForInitialLayout,
721
- getRenderedItem,
722
848
  ItemSeparatorComponent,
723
- updateItemSize
849
+ recycleItems,
850
+ updateItemSize: updateItemSize2,
851
+ waitForInitialLayout
724
852
  }
725
853
  ),
726
- ListFooterComponent && /* @__PURE__ */ React2__namespace.createElement(
854
+ ListFooterComponent && /* @__PURE__ */ React3__namespace.createElement(
727
855
  reactNative.View,
728
856
  {
729
- style: ListFooterComponentStyle,
730
857
  onLayout: (event) => {
731
858
  const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
732
859
  set$(ctx, "footerSize", size);
733
- }
860
+ },
861
+ style: ListFooterComponentStyle
734
862
  },
735
863
  getComponent(ListFooterComponent)
736
- )
864
+ ),
865
+ __DEV__ && ENABLE_DEVMODE && /* @__PURE__ */ React3__namespace.createElement(DevNumbers, null)
737
866
  );
738
867
  });
868
+ var DevNumbers = __DEV__ && React3__namespace.memo(function DevNumbers2() {
869
+ return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3__namespace.createElement(
870
+ reactNative.View,
871
+ {
872
+ key: index,
873
+ style: {
874
+ height: 100,
875
+ pointerEvents: "none",
876
+ position: "absolute",
877
+ top: index * 100,
878
+ width: "100%"
879
+ }
880
+ },
881
+ /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, { style: { color: "red" } }, index * 100)
882
+ ));
883
+ });
739
884
 
740
- // src/ScrollAdjustHandler.ts
741
- var ScrollAdjustHandler = class {
742
- constructor(ctx) {
743
- this.ctx = ctx;
744
- this.appliedAdjust = 0;
745
- this.busy = false;
746
- this.isPaused = false;
747
- this.isDisabled = false;
748
- this.context = ctx;
749
- }
750
- doAjdust() {
751
- set$(this.context, "scrollAdjust", this.appliedAdjust);
752
- this.busy = false;
885
+ // src/utils/getId.ts
886
+ function getId(state, index) {
887
+ const { data, keyExtractor } = state.props;
888
+ if (!data) {
889
+ return "";
753
890
  }
754
- requestAdjust(adjust, onAdjusted) {
755
- if (this.isDisabled) {
756
- return;
891
+ const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
892
+ const id = ret;
893
+ state.idCache.set(index, id);
894
+ return id;
895
+ }
896
+
897
+ // src/core/calculateOffsetForIndex.ts
898
+ function calculateOffsetForIndex(ctx, state, index) {
899
+ let position = 0;
900
+ if (index !== void 0) {
901
+ position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
902
+ const paddingTop = peek$(ctx, "stylePaddingTop");
903
+ if (paddingTop) {
904
+ position += paddingTop;
905
+ }
906
+ const headerSize = peek$(ctx, "headerSize");
907
+ if (headerSize) {
908
+ position += headerSize;
757
909
  }
758
- const oldAdjustTop = peek$(this.context, "scrollAdjust");
759
- if (oldAdjustTop === adjust) {
760
- return;
910
+ }
911
+ return position;
912
+ }
913
+
914
+ // src/utils/getItemSize.ts
915
+ function getItemSize(state, key, index, data, useAverageSize, defaultAverageSize, preferRenderedCache) {
916
+ var _a, _b;
917
+ const {
918
+ sizesKnown,
919
+ sizes,
920
+ scrollingTo,
921
+ averageSizes,
922
+ props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
923
+ } = state;
924
+ const sizeKnown = sizesKnown.get(key);
925
+ if (sizeKnown !== void 0) {
926
+ return sizeKnown;
927
+ }
928
+ let size;
929
+ const itemType = getItemType ? (_a = getItemType(data, index)) != null ? _a : "" : "";
930
+ if (getFixedItemSize) {
931
+ size = getFixedItemSize(index, data, itemType);
932
+ if (size !== void 0) {
933
+ sizesKnown.set(key, size);
761
934
  }
762
- this.appliedAdjust = adjust;
763
- if (!this.busy && !this.isPaused) {
764
- this.busy = true;
765
- this.doAjdust();
766
- onAdjusted(oldAdjustTop - adjust);
935
+ }
936
+ const renderedSize = sizes.get(key);
937
+ if (size === void 0 && preferRenderedCache && renderedSize !== void 0) {
938
+ return renderedSize;
939
+ }
940
+ if (size === void 0 && useAverageSize && !scrollingTo) {
941
+ if (itemType === "") {
942
+ size = defaultAverageSize;
943
+ } else {
944
+ const averageSizeForType = (_b = averageSizes[itemType]) == null ? void 0 : _b.avg;
945
+ if (averageSizeForType !== void 0) {
946
+ size = roundSize(averageSizeForType);
947
+ }
767
948
  }
768
949
  }
769
- getAppliedAdjust() {
770
- return this.appliedAdjust;
950
+ if (size === void 0 && renderedSize !== void 0) {
951
+ return renderedSize;
771
952
  }
772
- pauseAdjust() {
773
- this.isPaused = true;
953
+ if (size === void 0) {
954
+ size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
774
955
  }
775
- setDisableAdjust(disable) {
776
- this.isDisabled = disable;
956
+ sizes.set(key, size);
957
+ return size;
958
+ }
959
+
960
+ // src/core/calculateOffsetWithOffsetPosition.ts
961
+ function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
962
+ const { index, viewOffset, viewPosition } = params;
963
+ let offset = offsetParam;
964
+ if (viewOffset) {
965
+ offset -= viewOffset;
777
966
  }
778
- // return true if it was paused
779
- unPauseAdjust() {
780
- if (this.isPaused) {
781
- this.isPaused = false;
782
- this.doAjdust();
783
- return true;
784
- }
785
- return false;
967
+ if (viewPosition !== void 0 && index !== void 0) {
968
+ offset -= viewPosition * (state.scrollLength - getItemSize(state, getId(state, index), index, state.props.data[index]));
969
+ }
970
+ return offset;
971
+ }
972
+
973
+ // src/core/finishScrollTo.ts
974
+ var finishScrollTo = (state) => {
975
+ if (state) {
976
+ state.scrollingTo = void 0;
977
+ state.scrollHistory.length = 0;
786
978
  }
787
979
  };
788
- var useCombinedRef = (...refs) => {
789
- const callback = React2.useCallback((element) => {
790
- for (const ref of refs) {
791
- if (!ref) {
792
- continue;
980
+
981
+ // src/core/scrollTo.ts
982
+ function scrollTo(state, params = {}) {
983
+ var _a;
984
+ const { animated, noScrollingTo } = params;
985
+ const {
986
+ refScroller,
987
+ props: { horizontal }
988
+ } = state;
989
+ const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
990
+ state.scrollHistory.length = 0;
991
+ if (!noScrollingTo) {
992
+ state.scrollingTo = params;
993
+ }
994
+ state.scrollPending = offset;
995
+ (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
996
+ animated: !!animated,
997
+ x: horizontal ? offset : 0,
998
+ y: horizontal ? 0 : offset
999
+ });
1000
+ if (!animated) {
1001
+ state.scroll = offset;
1002
+ setTimeout(() => finishScrollTo(state), 100);
1003
+ }
1004
+ }
1005
+
1006
+ // src/utils/requestAdjust.ts
1007
+ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1008
+ if (Math.abs(positionDiff) > 0.1) {
1009
+ const needsScrollWorkaround = reactNative.Platform.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff;
1010
+ const doit = () => {
1011
+ if (needsScrollWorkaround) {
1012
+ scrollTo(state, {
1013
+ noScrollingTo: true,
1014
+ offset: state.scroll
1015
+ });
1016
+ } else {
1017
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
793
1018
  }
794
- if (isFunction(ref)) {
795
- ref(element);
1019
+ };
1020
+ state.scroll += positionDiff;
1021
+ state.scrollForNextCalculateItemsInView = void 0;
1022
+ const didLayout = peek$(ctx, "containersDidLayout");
1023
+ if (didLayout) {
1024
+ doit();
1025
+ const threshold = state.scroll - positionDiff / 2;
1026
+ if (!state.ignoreScrollFromMVCP) {
1027
+ state.ignoreScrollFromMVCP = {};
1028
+ }
1029
+ if (positionDiff > 0) {
1030
+ state.ignoreScrollFromMVCP.lt = threshold;
796
1031
  } else {
797
- ref.current = element;
1032
+ state.ignoreScrollFromMVCP.gt = threshold;
1033
+ }
1034
+ if (state.ignoreScrollFromMVCPTimeout) {
1035
+ clearTimeout(state.ignoreScrollFromMVCPTimeout);
798
1036
  }
1037
+ state.ignoreScrollFromMVCPTimeout = setTimeout(
1038
+ () => {
1039
+ state.ignoreScrollFromMVCP = void 0;
1040
+ },
1041
+ needsScrollWorkaround ? 250 : 100
1042
+ );
1043
+ } else {
1044
+ requestAnimationFrame(doit);
799
1045
  }
800
- }, refs);
801
- return callback;
1046
+ }
1047
+ }
1048
+
1049
+ // src/core/mvcp.ts
1050
+ function prepareMVCP(ctx, state, dataChanged) {
1051
+ const {
1052
+ idsInView,
1053
+ positions,
1054
+ scrollingTo,
1055
+ props: { maintainVisibleContentPosition }
1056
+ } = state;
1057
+ let prevPosition;
1058
+ let targetId;
1059
+ const idsInViewWithPositions = [];
1060
+ const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1061
+ if (maintainVisibleContentPosition) {
1062
+ const indexByKey = state.indexByKey;
1063
+ if (scrollTarget !== void 0) {
1064
+ targetId = getId(state, scrollTarget);
1065
+ } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1066
+ if (dataChanged) {
1067
+ for (let i = 0; i < idsInView.length; i++) {
1068
+ const id = idsInView[i];
1069
+ const index = indexByKey.get(id);
1070
+ if (index !== void 0) {
1071
+ idsInViewWithPositions.push({ id, position: positions.get(id) });
1072
+ }
1073
+ }
1074
+ } else {
1075
+ targetId = state.idsInView.find((id) => indexByKey.get(id) !== void 0);
1076
+ }
1077
+ }
1078
+ if (targetId !== void 0) {
1079
+ prevPosition = positions.get(targetId);
1080
+ }
1081
+ }
1082
+ return () => {
1083
+ let positionDiff;
1084
+ if (dataChanged && targetId === void 0) {
1085
+ for (let i = 0; i < idsInViewWithPositions.length; i++) {
1086
+ const { id, position } = idsInViewWithPositions[i];
1087
+ const newPosition = positions.get(id);
1088
+ if (newPosition !== void 0) {
1089
+ positionDiff = newPosition - position;
1090
+ break;
1091
+ }
1092
+ }
1093
+ }
1094
+ if (targetId !== void 0 && prevPosition !== void 0) {
1095
+ const newPosition = positions.get(targetId);
1096
+ if (newPosition !== void 0) {
1097
+ positionDiff = newPosition - prevPosition;
1098
+ }
1099
+ }
1100
+ if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1101
+ requestAdjust(ctx, state, positionDiff, dataChanged);
1102
+ }
1103
+ };
1104
+ }
1105
+
1106
+ // src/utils/setPaddingTop.ts
1107
+ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1108
+ if (stylePaddingTop !== void 0) {
1109
+ const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1110
+ if (stylePaddingTop < prevStylePaddingTop) {
1111
+ let prevTotalSize = peek$(ctx, "totalSize") || 0;
1112
+ set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1113
+ state.timeoutSetPaddingTop = setTimeout(() => {
1114
+ prevTotalSize = peek$(ctx, "totalSize") || 0;
1115
+ set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
1116
+ }, 16);
1117
+ }
1118
+ set$(ctx, "stylePaddingTop", stylePaddingTop);
1119
+ }
1120
+ if (alignItemsPaddingTop !== void 0) {
1121
+ set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1122
+ }
1123
+ }
1124
+
1125
+ // src/utils/updateAlignItemsPaddingTop.ts
1126
+ function updateAlignItemsPaddingTop(ctx, state) {
1127
+ const {
1128
+ scrollLength,
1129
+ props: { alignItemsAtEnd, data }
1130
+ } = state;
1131
+ if (alignItemsAtEnd) {
1132
+ let alignItemsPaddingTop = 0;
1133
+ if ((data == null ? void 0 : data.length) > 0) {
1134
+ const contentSize = getContentSize(ctx);
1135
+ alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1136
+ }
1137
+ setPaddingTop(ctx, state, { alignItemsPaddingTop });
1138
+ }
1139
+ }
1140
+
1141
+ // src/core/updateTotalSize.ts
1142
+ function updateTotalSize(ctx, state) {
1143
+ const {
1144
+ positions,
1145
+ props: { data }
1146
+ } = state;
1147
+ if (data.length === 0) {
1148
+ addTotalSize(ctx, state, null, 0);
1149
+ } else {
1150
+ const lastId = getId(state, data.length - 1);
1151
+ if (lastId !== void 0) {
1152
+ const lastPosition = positions.get(lastId);
1153
+ if (lastPosition !== void 0) {
1154
+ const lastSize = getItemSize(state, lastId, data.length - 1, data[data.length - 1]);
1155
+ if (lastSize !== void 0) {
1156
+ const totalSize = lastPosition + lastSize;
1157
+ addTotalSize(ctx, state, null, totalSize);
1158
+ }
1159
+ }
1160
+ }
1161
+ }
1162
+ }
1163
+ function addTotalSize(ctx, state, key, add) {
1164
+ const { alignItemsAtEnd } = state.props;
1165
+ {
1166
+ state.totalSize = add;
1167
+ if (state.timeoutSetPaddingTop) {
1168
+ clearTimeout(state.timeoutSetPaddingTop);
1169
+ state.timeoutSetPaddingTop = void 0;
1170
+ }
1171
+ }
1172
+ set$(ctx, "totalSize", state.totalSize);
1173
+ if (alignItemsAtEnd) {
1174
+ updateAlignItemsPaddingTop(ctx, state);
1175
+ }
1176
+ }
1177
+
1178
+ // src/utils/getScrollVelocity.ts
1179
+ var getScrollVelocity = (state) => {
1180
+ const { scrollHistory } = state;
1181
+ let velocity = 0;
1182
+ if (scrollHistory.length >= 1) {
1183
+ const newest = scrollHistory[scrollHistory.length - 1];
1184
+ let oldest;
1185
+ let start = 0;
1186
+ const now = Date.now();
1187
+ for (let i = 0; i < scrollHistory.length - 1; i++) {
1188
+ const entry = scrollHistory[i];
1189
+ const nextEntry = scrollHistory[i + 1];
1190
+ if (i > 0) {
1191
+ const prevEntry = scrollHistory[i - 1];
1192
+ const prevDirection = entry.scroll - prevEntry.scroll;
1193
+ const currentDirection = nextEntry.scroll - entry.scroll;
1194
+ if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1195
+ start = i;
1196
+ break;
1197
+ }
1198
+ }
1199
+ }
1200
+ for (let i = start; i < scrollHistory.length - 1; i++) {
1201
+ const entry = scrollHistory[i];
1202
+ if (now - entry.time <= 1e3) {
1203
+ oldest = entry;
1204
+ break;
1205
+ }
1206
+ }
1207
+ if (oldest && oldest !== newest) {
1208
+ const scrollDiff = newest.scroll - oldest.scroll;
1209
+ const timeDiff = newest.time - oldest.time;
1210
+ velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1211
+ }
1212
+ }
1213
+ return velocity;
802
1214
  };
803
1215
 
804
- // src/viewability.ts
805
- var mapViewabilityConfigCallbackPairs = /* @__PURE__ */ new Map();
1216
+ // src/utils/updateSnapToOffsets.ts
1217
+ function updateSnapToOffsets(ctx, state) {
1218
+ const {
1219
+ positions,
1220
+ props: { snapToIndices }
1221
+ } = state;
1222
+ const snapToOffsets = Array(snapToIndices.length);
1223
+ for (let i = 0; i < snapToIndices.length; i++) {
1224
+ const idx = snapToIndices[i];
1225
+ const key = getId(state, idx);
1226
+ snapToOffsets[i] = positions.get(key);
1227
+ }
1228
+ set$(ctx, "snapToOffsets", snapToOffsets);
1229
+ }
1230
+
1231
+ // src/core/updateAllPositions.ts
1232
+ function updateAllPositions(ctx, state, dataChanged) {
1233
+ var _a, _b, _c, _d, _e;
1234
+ const {
1235
+ averageSizes,
1236
+ columns,
1237
+ indexByKey,
1238
+ positions,
1239
+ firstFullyOnScreenIndex,
1240
+ idCache,
1241
+ sizesKnown,
1242
+ props: { getEstimatedItemSize, snapToIndices }
1243
+ } = state;
1244
+ const data = state.props.data;
1245
+ const numColumns = peek$(ctx, "numColumns");
1246
+ const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
1247
+ const scrollVelocity = getScrollVelocity(state);
1248
+ const useAverageSize = !getEstimatedItemSize;
1249
+ const itemType = "";
1250
+ let averageSize = (_a = averageSizes[itemType]) == null ? void 0 : _a.avg;
1251
+ if (averageSize !== void 0) {
1252
+ averageSize = roundSize(averageSize);
1253
+ }
1254
+ const shouldUseBackwards = !dataChanged && scrollVelocity < 0 && firstFullyOnScreenIndex > 5 && firstFullyOnScreenIndex < data.length;
1255
+ if (shouldUseBackwards && firstFullyOnScreenIndex !== void 0) {
1256
+ const anchorId = getId(state, firstFullyOnScreenIndex);
1257
+ const anchorPosition = positions.get(anchorId);
1258
+ if (anchorPosition !== void 0) {
1259
+ let currentRowTop2 = anchorPosition;
1260
+ let maxSizeInRow2 = 0;
1261
+ let bailout = false;
1262
+ for (let i = firstFullyOnScreenIndex - 1; i >= 0; i--) {
1263
+ const id = (_b = idCache.get(i)) != null ? _b : getId(state, i);
1264
+ const size = (_c = sizesKnown.get(id)) != null ? _c : getItemSize(
1265
+ state,
1266
+ id,
1267
+ i,
1268
+ data[i],
1269
+ useAverageSize,
1270
+ averageSize,
1271
+ /*preferRenderedCache*/
1272
+ !!dataChanged
1273
+ );
1274
+ const itemColumn = columns.get(id);
1275
+ maxSizeInRow2 = Math.max(maxSizeInRow2, size);
1276
+ if (itemColumn === 1) {
1277
+ currentRowTop2 -= maxSizeInRow2;
1278
+ maxSizeInRow2 = 0;
1279
+ }
1280
+ if (currentRowTop2 < -2e3) {
1281
+ bailout = true;
1282
+ break;
1283
+ }
1284
+ positions.set(id, currentRowTop2);
1285
+ }
1286
+ if (!bailout) {
1287
+ updateTotalSize(ctx, state);
1288
+ return;
1289
+ }
1290
+ }
1291
+ }
1292
+ let currentRowTop = 0;
1293
+ let column = 1;
1294
+ let maxSizeInRow = 0;
1295
+ const hasColumns = numColumns > 1;
1296
+ const needsIndexByKey = dataChanged || indexByKey.size === 0;
1297
+ const dataLength = data.length;
1298
+ for (let i = 0; i < dataLength; i++) {
1299
+ const id = (_d = idCache.get(i)) != null ? _d : getId(state, i);
1300
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(
1301
+ state,
1302
+ id,
1303
+ i,
1304
+ data[i],
1305
+ useAverageSize,
1306
+ averageSize,
1307
+ /*preferRenderedCache*/
1308
+ !!dataChanged
1309
+ );
1310
+ if (__DEV__ && needsIndexByKey) {
1311
+ if (indexByKeyForChecking.has(id)) {
1312
+ console.error(
1313
+ `[legend-list] Error: Detected overlapping key (${id}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
1314
+ );
1315
+ }
1316
+ indexByKeyForChecking.set(id, i);
1317
+ }
1318
+ positions.set(id, currentRowTop);
1319
+ if (needsIndexByKey) {
1320
+ indexByKey.set(id, i);
1321
+ }
1322
+ columns.set(id, column);
1323
+ if (hasColumns) {
1324
+ if (size > maxSizeInRow) {
1325
+ maxSizeInRow = size;
1326
+ }
1327
+ column++;
1328
+ if (column > numColumns) {
1329
+ currentRowTop += maxSizeInRow;
1330
+ column = 1;
1331
+ maxSizeInRow = 0;
1332
+ }
1333
+ } else {
1334
+ currentRowTop += size;
1335
+ }
1336
+ }
1337
+ updateTotalSize(ctx, state);
1338
+ if (snapToIndices) {
1339
+ updateSnapToOffsets(ctx, state);
1340
+ }
1341
+ }
1342
+
1343
+ // src/core/viewability.ts
1344
+ function ensureViewabilityState(ctx, configId) {
1345
+ let map = ctx.mapViewabilityConfigStates;
1346
+ if (!map) {
1347
+ map = /* @__PURE__ */ new Map();
1348
+ ctx.mapViewabilityConfigStates = map;
1349
+ }
1350
+ let state = map.get(configId);
1351
+ if (!state) {
1352
+ state = { end: -1, previousEnd: -1, previousStart: -1, start: -1, viewableItems: [] };
1353
+ map.set(configId, state);
1354
+ }
1355
+ return state;
1356
+ }
806
1357
  function setupViewability(props) {
807
1358
  let { viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged } = props;
808
1359
  if (viewabilityConfig || onViewableItemsChanged) {
809
1360
  viewabilityConfigCallbackPairs = [
810
1361
  ...viewabilityConfigCallbackPairs || [],
811
1362
  {
1363
+ onViewableItemsChanged,
812
1364
  viewabilityConfig: viewabilityConfig || {
813
1365
  viewAreaCoveragePercentThreshold: 0
814
- },
815
- onViewableItemsChanged
1366
+ }
816
1367
  }
817
1368
  ];
818
1369
  }
819
- if (viewabilityConfigCallbackPairs) {
820
- for (const pair of viewabilityConfigCallbackPairs) {
821
- mapViewabilityConfigCallbackPairs.set(pair.viewabilityConfig.id, {
822
- viewableItems: [],
823
- start: -1,
824
- end: -1,
825
- previousStart: -1,
826
- previousEnd: -1
827
- });
828
- }
829
- }
830
1370
  return viewabilityConfigCallbackPairs;
831
1371
  }
832
- function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, getId, scrollSize, start, end) {
1372
+ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end) {
1373
+ const {
1374
+ timeouts,
1375
+ props: { data }
1376
+ } = state;
833
1377
  for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
834
- const viewabilityState = mapViewabilityConfigCallbackPairs.get(
835
- viewabilityConfigCallbackPair.viewabilityConfig.id
836
- );
1378
+ const viewabilityState = ensureViewabilityState(ctx, viewabilityConfigCallbackPair.viewabilityConfig.id);
837
1379
  viewabilityState.start = start;
838
1380
  viewabilityState.end = end;
839
1381
  if (viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime) {
840
1382
  const timer = setTimeout(() => {
841
- state.timeouts.delete(timer);
842
- updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize);
1383
+ timeouts.delete(timer);
1384
+ updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
843
1385
  }, viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime);
844
- state.timeouts.add(timer);
1386
+ timeouts.add(timer);
845
1387
  } else {
846
- updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize);
1388
+ updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
847
1389
  }
848
1390
  }
849
1391
  }
850
- function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize) {
1392
+ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize) {
851
1393
  const { viewabilityConfig, onViewableItemsChanged } = viewabilityConfigCallbackPair;
852
1394
  const configId = viewabilityConfig.id;
853
- const viewabilityState = mapViewabilityConfigCallbackPairs.get(configId);
1395
+ const viewabilityState = ensureViewabilityState(ctx, configId);
854
1396
  const { viewableItems: previousViewableItems, start, end } = viewabilityState;
855
1397
  const viewabilityTokens = /* @__PURE__ */ new Map();
856
1398
  for (const [containerId, value] of ctx.mapViewabilityAmountValues) {
@@ -891,15 +1433,15 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getI
891
1433
  for (let i = start; i <= end; i++) {
892
1434
  const item = data[i];
893
1435
  if (item) {
894
- const key = getId(i);
1436
+ const key = getId(state, i);
895
1437
  const containerId = findContainerId(ctx, key);
896
1438
  if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
897
1439
  const viewToken = {
898
- item,
899
- key,
1440
+ containerId,
900
1441
  index: i,
901
1442
  isViewable: true,
902
- containerId
1443
+ item,
1444
+ key
903
1445
  };
904
1446
  viewableItems.push(viewToken);
905
1447
  if (!(previousViewableItems == null ? void 0 : previousViewableItems.find((v) => v.key === viewToken.key))) {
@@ -909,9 +1451,9 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getI
909
1451
  }
910
1452
  }
911
1453
  Object.assign(viewabilityState, {
912
- viewableItems,
1454
+ previousEnd: end,
913
1455
  previousStart: start,
914
- previousEnd: end
1456
+ viewableItems
915
1457
  });
916
1458
  if (changed.length > 0) {
917
1459
  viewabilityState.viewableItems = viewableItems;
@@ -920,7 +1462,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getI
920
1462
  maybeUpdateViewabilityCallback(ctx, configId, change.containerId, change);
921
1463
  }
922
1464
  if (onViewableItemsChanged) {
923
- onViewableItemsChanged({ viewableItems, changed });
1465
+ onViewableItemsChanged({ changed, viewableItems });
924
1466
  }
925
1467
  }
926
1468
  for (const [containerId, value] of ctx.mapViewabilityAmountValues) {
@@ -929,14 +1471,22 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getI
929
1471
  }
930
1472
  }
931
1473
  }
1474
+ function shallowEqual(prev, next) {
1475
+ if (!prev) return false;
1476
+ const keys = Object.keys(next);
1477
+ for (let i = 0; i < keys.length; i++) {
1478
+ const k = keys[i];
1479
+ if (prev[k] !== next[k]) return false;
1480
+ }
1481
+ return true;
1482
+ }
932
1483
  function computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
933
- const { sizes, positions, scroll: scrollState, scrollAdjustHandler } = state;
1484
+ const { sizes, positions, scroll: scrollState } = state;
934
1485
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
935
1486
  const { itemVisiblePercentThreshold, viewAreaCoveragePercentThreshold } = viewabilityConfig;
936
1487
  const viewAreaMode = viewAreaCoveragePercentThreshold != null;
937
1488
  const viewablePercentThreshold = viewAreaMode ? viewAreaCoveragePercentThreshold : itemVisiblePercentThreshold;
938
- const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
939
- const scroll = scrollState - previousScrollAdjust - topPad;
1489
+ const scroll = scrollState - topPad;
940
1490
  const top = positions.get(key) - scroll;
941
1491
  const size = sizes.get(key) || 0;
942
1492
  const bottom = top + size;
@@ -947,18 +1497,19 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
947
1497
  const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
948
1498
  const isViewable2 = percent >= viewablePercentThreshold;
949
1499
  const value = {
1500
+ containerId,
950
1501
  index,
951
1502
  isViewable: isViewable2,
952
1503
  item,
953
1504
  key,
954
- percentVisible,
955
1505
  percentOfScroller,
956
- sizeVisible,
957
- size,
1506
+ percentVisible,
958
1507
  scrollSize,
959
- containerId
1508
+ size,
1509
+ sizeVisible
960
1510
  };
961
- if (JSON.stringify(value) !== JSON.stringify(ctx.mapViewabilityAmountValues.get(containerId))) {
1511
+ const prev = ctx.mapViewabilityAmountValues.get(containerId);
1512
+ if (!shallowEqual(prev, value)) {
962
1513
  ctx.mapViewabilityAmountValues.set(containerId, value);
963
1514
  const cb = ctx.mapViewabilityAmountCallbacks.get(containerId);
964
1515
  if (cb) {
@@ -988,507 +1539,357 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
988
1539
  cb == null ? void 0 : cb(viewToken);
989
1540
  }
990
1541
 
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
- };
1542
+ // src/utils/checkAllSizesKnown.ts
1543
+ function checkAllSizesKnown(state) {
1544
+ const { startBuffered, endBuffered, sizesKnown } = state;
1545
+ if (endBuffered !== null) {
1546
+ let areAllKnown = true;
1547
+ for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
1548
+ const key = getId(state, i);
1549
+ areAllKnown && (areAllKnown = sizesKnown.has(key));
1550
+ }
1551
+ return areAllKnown;
1005
1552
  }
1553
+ return false;
1006
1554
  }
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;
1068
- }
1069
- if (contentContainerStyle == null ? void 0 : contentContainerStyle.paddingTop) {
1070
- contentContainerStyle.paddingTop = void 0;
1071
- }
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;
1555
+
1556
+ // src/utils/findAvailableContainers.ts
1557
+ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
1558
+ const numContainers = peek$(ctx, "numContainers");
1559
+ const { stickyContainerPool, containerItemTypes } = state;
1560
+ const result = [];
1561
+ const availableContainers = [];
1562
+ const stickyIndicesSet = state.props.stickyIndicesSet;
1563
+ const stickyItemIndices = (needNewContainers == null ? void 0 : needNewContainers.filter((index) => stickyIndicesSet.has(index))) || [];
1564
+ const canReuseContainer = (containerIndex, requiredType) => {
1565
+ if (!requiredType) return true;
1566
+ const existingType = containerItemTypes.get(containerIndex);
1567
+ if (!existingType) return true;
1568
+ return existingType === requiredType;
1103
1569
  };
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);
1570
+ const neededTypes = requiredItemTypes ? [...requiredItemTypes] : [];
1571
+ let typeIndex = 0;
1572
+ for (let i = 0; i < stickyItemIndices.length; i++) {
1573
+ const requiredType = neededTypes[typeIndex];
1574
+ let foundContainer = false;
1575
+ for (const containerIndex of stickyContainerPool) {
1576
+ const key = peek$(ctx, `containerItemKey${containerIndex}`);
1577
+ const isPendingRemoval = pendingRemoval.includes(containerIndex);
1578
+ if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType)) {
1579
+ result.push(containerIndex);
1580
+ if (isPendingRemoval) {
1581
+ const index = pendingRemoval.indexOf(containerIndex);
1582
+ pendingRemoval.splice(index, 1);
1121
1583
  }
1122
- } else {
1123
- offset = index * estimatedItemSize;
1584
+ foundContainer = true;
1585
+ if (requiredItemTypes) typeIndex++;
1586
+ break;
1124
1587
  }
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
1588
  }
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;
1589
+ if (!foundContainer) {
1590
+ const newContainerIndex = numContainers + result.filter((index) => index >= numContainers).length;
1591
+ result.push(newContainerIndex);
1592
+ stickyContainerPool.add(newContainerIndex);
1593
+ if (requiredItemTypes) typeIndex++;
1138
1594
  }
1139
- if (viewPosition !== void 0 && index !== void 0) {
1140
- offset -= viewPosition * (state.scrollLength - getItemSize(getId(index), index, state.data[index]));
1595
+ }
1596
+ for (let u = 0; u < numContainers && result.length < numNeeded; u++) {
1597
+ if (stickyContainerPool.has(u)) {
1598
+ continue;
1141
1599
  }
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
- );
1600
+ const key = peek$(ctx, `containerItemKey${u}`);
1601
+ let isOk = key === void 0;
1602
+ if (!isOk) {
1603
+ const index = pendingRemoval.indexOf(u);
1604
+ if (index !== -1) {
1605
+ pendingRemoval.splice(index, 1);
1606
+ const requiredType = neededTypes[typeIndex];
1607
+ isOk = canReuseContainer(u, requiredType);
1608
+ }
1609
+ }
1610
+ if (isOk) {
1611
+ result.push(u);
1612
+ if (requiredItemTypes) {
1613
+ typeIndex++;
1209
1614
  }
1210
1615
  }
1211
- set$(ctx, "scrollAdjust", 0);
1212
- set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
1213
- set$(ctx, "extraData", extraData);
1214
1616
  }
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;
1617
+ for (let u = 0; u < numContainers && result.length < numNeeded; u++) {
1618
+ if (stickyContainerPool.has(u)) {
1619
+ continue;
1223
1620
  }
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 });
1621
+ const key = peek$(ctx, `containerItemKey${u}`);
1622
+ if (key === void 0) continue;
1623
+ const index = state.indexByKey.get(key);
1624
+ const isOutOfView = index < startBuffered || index > endBuffered;
1625
+ if (isOutOfView) {
1626
+ const distance = index < startBuffered ? startBuffered - index : index - endBuffered;
1627
+ if (!requiredItemTypes || typeIndex < neededTypes.length && canReuseContainer(u, neededTypes[typeIndex])) {
1628
+ availableContainers.push({ distance, index: u });
1268
1629
  }
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
1630
  }
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
- }
1293
- }
1294
- if (key === null) {
1295
- state.totalSize = add;
1296
- state.totalSizeBelowAnchor = totalSizeBelowAnchor;
1297
- } else {
1298
- state.totalSize += add;
1299
- if (isAboveAnchor) {
1300
- state.totalSizeBelowAnchor += add;
1301
- }
1302
- }
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
- });
1631
+ }
1632
+ const remaining = numNeeded - result.length;
1633
+ if (remaining > 0) {
1634
+ if (availableContainers.length > 0) {
1635
+ if (availableContainers.length > remaining) {
1636
+ availableContainers.sort(comparatorByDistance);
1637
+ availableContainers.length = remaining;
1638
+ }
1639
+ for (const container of availableContainers) {
1640
+ result.push(container.index);
1641
+ if (requiredItemTypes) {
1642
+ typeIndex++;
1643
+ }
1315
1644
  }
1316
1645
  }
1317
- set$(ctx, "totalSize", state.totalSize);
1318
- set$(ctx, "totalSizeWithScrollAdjust", resultSize);
1319
- if (alignItemsAtEnd) {
1320
- updateAlignItemsPaddingTop();
1646
+ const stillNeeded = numNeeded - result.length;
1647
+ if (stillNeeded > 0) {
1648
+ for (let i = 0; i < stillNeeded; i++) {
1649
+ result.push(numContainers + i);
1650
+ }
1651
+ if (__DEV__ && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
1652
+ console.warn(
1653
+ "[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.",
1654
+ {
1655
+ debugInfo: {
1656
+ numContainers,
1657
+ numContainersPooled: peek$(ctx, "numContainersPooled"),
1658
+ numNeeded,
1659
+ stillNeeded
1660
+ }
1661
+ }
1662
+ );
1663
+ }
1321
1664
  }
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();
1665
+ }
1666
+ return result.sort(comparatorDefault);
1667
+ }
1668
+ function comparatorByDistance(a, b) {
1669
+ return b.distance - a.distance;
1670
+ }
1671
+
1672
+ // src/core/scrollToIndex.ts
1673
+ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
1674
+ if (index >= state.props.data.length) {
1675
+ index = state.props.data.length - 1;
1676
+ } else if (index < 0) {
1677
+ index = 0;
1678
+ }
1679
+ const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
1680
+ const isLast = index === state.props.data.length - 1;
1681
+ if (isLast && viewPosition === void 0) {
1682
+ viewPosition = 1;
1683
+ }
1684
+ const firstIndexScrollPostion = firstIndexOffset - viewOffset;
1685
+ state.scrollForNextCalculateItemsInView = void 0;
1686
+ scrollTo(state, {
1687
+ animated,
1688
+ index,
1689
+ offset: firstIndexScrollPostion,
1690
+ viewOffset,
1691
+ viewPosition: viewPosition != null ? viewPosition : 0
1692
+ });
1693
+ }
1694
+
1695
+ // src/utils/checkThreshold.ts
1696
+ var checkThreshold = (distance, atThreshold, threshold, isReached, isBlockedByTimer, onReached, blockTimer) => {
1697
+ const distanceAbs = Math.abs(distance);
1698
+ const isAtThreshold = atThreshold || distanceAbs < threshold;
1699
+ if (!isReached && !isBlockedByTimer) {
1700
+ if (isAtThreshold) {
1701
+ onReached == null ? void 0 : onReached(distance);
1702
+ blockTimer == null ? void 0 : blockTimer(true);
1703
+ setTimeout(() => {
1704
+ blockTimer == null ? void 0 : blockTimer(false);
1705
+ }, 700);
1706
+ return true;
1347
1707
  }
1348
- const anchorIndex = state.indexByKey.get(state.anchorElement.id);
1349
- if (anchorIndex === 0) {
1350
- return /* @__PURE__ */ new Map();
1708
+ } else {
1709
+ if (distance >= 1.3 * threshold) {
1710
+ return false;
1351
1711
  }
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);
1712
+ }
1713
+ return isReached;
1714
+ };
1715
+
1716
+ // src/utils/checkAtBottom.ts
1717
+ function checkAtBottom(ctx, state) {
1718
+ if (!state) {
1719
+ return;
1720
+ }
1721
+ const {
1722
+ queuedInitialLayout,
1723
+ scrollLength,
1724
+ scroll,
1725
+ maintainingScrollAtEnd,
1726
+ props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
1727
+ } = state;
1728
+ const contentSize = getContentSize(ctx);
1729
+ if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1730
+ const distanceFromEnd = contentSize - scroll - scrollLength;
1731
+ const isContentLess = contentSize < scrollLength;
1732
+ state.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1733
+ state.isEndReached = checkThreshold(
1734
+ distanceFromEnd,
1735
+ isContentLess,
1736
+ onEndReachedThreshold * scrollLength,
1737
+ state.isEndReached,
1738
+ state.endReachedBlockedByTimer,
1739
+ (distance) => {
1740
+ var _a, _b;
1741
+ return (_b = (_a = state.props).onEndReached) == null ? void 0 : _b.call(_a, { distanceFromEnd: distance });
1742
+ },
1743
+ (block) => {
1744
+ state.endReachedBlockedByTimer = block;
1360
1745
  }
1361
- map.set(id, top);
1746
+ );
1747
+ }
1748
+ }
1749
+
1750
+ // src/utils/setDidLayout.ts
1751
+ function setDidLayout(ctx, state) {
1752
+ const {
1753
+ loadStartTime,
1754
+ initialScroll,
1755
+ props: { onLoad }
1756
+ } = state;
1757
+ state.queuedInitialLayout = true;
1758
+ checkAtBottom(ctx, state);
1759
+ const setIt = () => {
1760
+ set$(ctx, "containersDidLayout", true);
1761
+ if (onLoad) {
1762
+ onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1362
1763
  }
1363
- return map;
1364
1764
  };
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);
1374
- }
1375
- }, timeout);
1765
+ if (reactNative.Platform.OS === "android" || !IsNewArchitecture) {
1766
+ if (initialScroll) {
1767
+ queueMicrotask(() => {
1768
+ scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1769
+ requestAnimationFrame(() => {
1770
+ scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1771
+ setIt();
1772
+ });
1773
+ });
1774
+ } else {
1775
+ queueMicrotask(setIt);
1376
1776
  }
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;
1777
+ } else {
1778
+ setIt();
1779
+ }
1780
+ }
1781
+
1782
+ // src/core/calculateItemsInView.ts
1783
+ function findCurrentStickyIndex(stickyArray, scroll, state) {
1784
+ var _a;
1785
+ const idCache = state.idCache;
1786
+ const positions = state.positions;
1787
+ for (let i = stickyArray.length - 1; i >= 0; i--) {
1788
+ const stickyId = (_a = idCache.get(stickyArray[i])) != null ? _a : getId(state, stickyArray[i]);
1789
+ const stickyPos = stickyId ? positions.get(stickyId) : void 0;
1790
+ if (stickyPos !== void 0 && scroll >= stickyPos) {
1791
+ return i;
1398
1792
  }
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
- }
1420
- }
1421
- }
1793
+ }
1794
+ return -1;
1795
+ }
1796
+ function getActiveStickyIndices(ctx, state, stickyIndices) {
1797
+ return new Set(
1798
+ Array.from(state.stickyContainerPool).map((i) => peek$(ctx, `containerItemKey${i}`)).map((key) => key ? state.indexByKey.get(key) : void 0).filter((idx) => idx !== void 0 && stickyIndices.has(idx))
1799
+ );
1800
+ }
1801
+ function handleStickyActivation(ctx, state, stickyIndices, stickyArray, scroll, needNewContainers, startBuffered, endBuffered) {
1802
+ var _a;
1803
+ const activeIndices = getActiveStickyIndices(ctx, state, stickyIndices);
1804
+ const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
1805
+ for (let offset = 0; offset <= 1; offset++) {
1806
+ const idx = currentStickyIdx - offset;
1807
+ if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
1808
+ const stickyIndex = stickyArray[idx];
1809
+ const stickyId = (_a = state.idCache.get(stickyIndex)) != null ? _a : getId(state, stickyIndex);
1810
+ if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered)) {
1811
+ needNewContainers.push(stickyIndex);
1422
1812
  }
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
- }
1813
+ }
1814
+ }
1815
+ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, pendingRemoval) {
1816
+ var _a, _b, _c;
1817
+ const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
1818
+ for (const containerIndex of state.stickyContainerPool) {
1819
+ const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
1820
+ const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
1821
+ if (itemIndex === void 0) continue;
1822
+ const arrayIdx = stickyArray.indexOf(itemIndex);
1823
+ if (arrayIdx === -1) continue;
1824
+ const isRecentSticky = arrayIdx >= currentStickyIdx - 1 && arrayIdx <= currentStickyIdx + 1;
1825
+ if (isRecentSticky) continue;
1826
+ const nextIndex = stickyArray[arrayIdx + 1];
1827
+ let shouldRecycle = false;
1828
+ if (nextIndex) {
1829
+ const nextId = (_a = state.idCache.get(nextIndex)) != null ? _a : getId(state, nextIndex);
1830
+ const nextPos = nextId ? state.positions.get(nextId) : void 0;
1831
+ shouldRecycle = nextPos !== void 0 && scroll > nextPos + scrollBuffer * 2;
1832
+ } else {
1833
+ const currentId = (_b = state.idCache.get(itemIndex)) != null ? _b : getId(state, itemIndex);
1834
+ if (currentId) {
1835
+ const currentPos = state.positions.get(currentId);
1836
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(state, currentId, itemIndex, state.props.data[itemIndex]);
1837
+ shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
1452
1838
  }
1453
1839
  }
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));
1462
- }
1463
- return areAllKnown;
1840
+ if (shouldRecycle) {
1841
+ pendingRemoval.push(containerIndex);
1464
1842
  }
1465
- return false;
1466
- }, []);
1467
- const calculateItemsInView = React2.useCallback((isReset) => {
1468
- var _a;
1469
- const state = refState.current;
1843
+ }
1844
+ }
1845
+ function calculateItemsInView(ctx, state, params = {}) {
1846
+ reactNative.unstable_batchedUpdates(() => {
1847
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1470
1848
  const {
1471
- data,
1849
+ columns,
1850
+ containerItemKeys,
1851
+ enableScrollForNextCalculateItemsInView,
1852
+ idCache,
1853
+ indexByKey,
1854
+ minIndexSizeChanged,
1855
+ positions,
1856
+ scrollForNextCalculateItemsInView,
1472
1857
  scrollLength,
1858
+ sizes,
1473
1859
  startBufferedId: startBufferedIdOrig,
1474
- positions,
1475
- columns,
1476
- scrollAdjustHandler,
1477
- scrollVelocity: speed
1860
+ viewabilityConfigCallbackPairs,
1861
+ props: { getItemType, initialScroll, itemsAreEqual, keyExtractor, scrollBuffer }
1478
1862
  } = state;
1479
- if (!data || scrollLength === 0) {
1863
+ const { data } = state.props;
1864
+ const stickyIndicesArr = state.props.stickyIndicesArr || [];
1865
+ const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
1866
+ const prevNumContainers = peek$(ctx, "numContainers");
1867
+ if (!data || scrollLength === 0 || !prevNumContainers) {
1480
1868
  return;
1481
1869
  }
1482
- const totalSize = peek$(ctx, "totalSizeWithScrollAdjust");
1870
+ const totalSize = peek$(ctx, "totalSize");
1483
1871
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
1484
1872
  const numColumns = peek$(ctx, "numColumns");
1485
- const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
1486
- let scrollState = state.scroll;
1873
+ const previousScrollAdjust = 0;
1874
+ const { dataChanged, doMVCP } = params;
1875
+ const speed = getScrollVelocity(state);
1876
+ if (doMVCP || dataChanged) {
1877
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
1878
+ if (dataChanged) {
1879
+ indexByKey.clear();
1880
+ idCache.clear();
1881
+ positions.clear();
1882
+ }
1883
+ updateAllPositions(ctx, state, dataChanged);
1884
+ checkMVCP == null ? void 0 : checkMVCP();
1885
+ }
1487
1886
  const scrollExtra = 0;
1488
- const useAverageSize = !state.disableScrollJumpsFrom && speed >= 0 && peek$(ctx, "containersDidLayout");
1489
- if (!state.queuedInitialLayout && initialScroll) {
1887
+ const { queuedInitialLayout } = state;
1888
+ let { scroll: scrollState } = state;
1889
+ if (!queuedInitialLayout && initialScroll) {
1490
1890
  const updatedOffset = calculateOffsetWithOffsetPosition(
1491
- calculateOffsetForIndex(initialScroll.index),
1891
+ state,
1892
+ calculateOffsetForIndex(ctx, state, initialScroll.index),
1492
1893
  initialScroll
1493
1894
  );
1494
1895
  scrollState = updatedOffset;
@@ -1496,7 +1897,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1496
1897
  const scrollAdjustPad = -previousScrollAdjust - topPad;
1497
1898
  let scroll = scrollState + scrollExtra + scrollAdjustPad;
1498
1899
  if (scroll + scrollLength > totalSize) {
1499
- scroll = totalSize - scrollLength;
1900
+ scroll = Math.max(0, totalSize - scrollLength);
1500
1901
  }
1501
1902
  if (ENABLE_DEBUG_VIEW) {
1502
1903
  set$(ctx, "debugRawScroll", scrollState);
@@ -1504,21 +1905,19 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1504
1905
  }
1505
1906
  let scrollBufferTop = scrollBuffer;
1506
1907
  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
- }
1908
+ if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
1909
+ scrollBufferTop = scrollBuffer * 0.5;
1910
+ scrollBufferBottom = scrollBuffer * 1.5;
1911
+ } else {
1912
+ scrollBufferTop = scrollBuffer * 1.5;
1913
+ scrollBufferBottom = scrollBuffer * 0.5;
1515
1914
  }
1516
1915
  const scrollTopBuffered = scroll - scrollBufferTop;
1517
- const scrollBottom = scroll + scrollLength;
1916
+ const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
1518
1917
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
1519
- if (state.scrollForNextCalculateItemsInView) {
1520
- const { top: top2, bottom } = state.scrollForNextCalculateItemsInView;
1521
- if (scrollTopBuffered > top2 && scrollBottomBuffered < bottom) {
1918
+ if (scrollForNextCalculateItemsInView) {
1919
+ const { top, bottom } = scrollForNextCalculateItemsInView;
1920
+ if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
1522
1921
  return;
1523
1922
  }
1524
1923
  }
@@ -1527,80 +1926,50 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1527
1926
  let startBufferedId = null;
1528
1927
  let endNoBuffer = null;
1529
1928
  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);
1929
+ let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
1930
+ if (minIndexSizeChanged !== void 0) {
1931
+ loopStart = Math.min(minIndexSizeChanged, loopStart);
1533
1932
  state.minIndexSizeChanged = void 0;
1534
1933
  }
1535
- const anchorElementIndex = getAnchorElementIndex();
1536
1934
  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);
1543
- }
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;
1553
- }
1935
+ const id = (_a = idCache.get(i)) != null ? _a : getId(state, i);
1936
+ const top = positions.get(id);
1937
+ const size = (_b = sizes.get(id)) != null ? _b : getItemSize(state, id, i, data[i]);
1938
+ const bottom = top + size;
1939
+ if (bottom > scroll - scrollBuffer) {
1940
+ loopStart = i;
1941
+ } else {
1942
+ break;
1554
1943
  }
1555
1944
  }
1556
1945
  const loopStartMod = loopStart % numColumns;
1557
1946
  if (loopStartMod > 0) {
1558
1947
  loopStart -= loopStartMod;
1559
1948
  }
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
1949
  let foundEnd = false;
1576
1950
  let nextTop;
1577
1951
  let nextBottom;
1578
- const prevNumContainers = ctx.values.get("numContainers");
1579
1952
  let maxIndexRendered = 0;
1580
1953
  for (let i = 0; i < prevNumContainers; i++) {
1581
1954
  const key = peek$(ctx, `containerItemKey${i}`);
1582
1955
  if (key !== void 0) {
1583
- const index = state.indexByKey.get(key);
1956
+ const index = indexByKey.get(key);
1584
1957
  maxIndexRendered = Math.max(maxIndexRendered, index);
1585
1958
  }
1586
1959
  }
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
- }
1960
+ let firstFullyOnScreenIndex;
1961
+ const dataLength = data.length;
1962
+ for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
1963
+ const id = (_c = idCache.get(i)) != null ? _c : getId(state, i);
1964
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(state, id, i, data[i]);
1965
+ const top = positions.get(id);
1600
1966
  if (!foundEnd) {
1601
1967
  if (startNoBuffer === null && top + size > scroll) {
1602
1968
  startNoBuffer = i;
1603
1969
  }
1970
+ if (firstFullyOnScreenIndex === void 0 && top >= scroll - 10) {
1971
+ firstFullyOnScreenIndex = i;
1972
+ }
1604
1973
  if (startBuffered === null && top + size > scrollTopBuffered) {
1605
1974
  startBuffered = i;
1606
1975
  startBufferedId = id;
@@ -1612,201 +1981,212 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1612
1981
  }
1613
1982
  if (top <= scrollBottomBuffered) {
1614
1983
  endBuffered = i;
1615
- nextBottom = top + maxSizeInRow - scrollLength;
1984
+ nextBottom = top + size;
1616
1985
  } else {
1617
1986
  foundEnd = true;
1618
1987
  }
1619
1988
  }
1620
1989
  }
1621
- column++;
1622
- if (column > numColumns) {
1623
- top += maxSizeInRow;
1624
- column = 1;
1625
- maxSizeInRow = 0;
1626
- }
1990
+ }
1991
+ const idsInView = [];
1992
+ for (let i = firstFullyOnScreenIndex; i <= endNoBuffer; i++) {
1993
+ const id = (_e = idCache.get(i)) != null ? _e : getId(state, i);
1994
+ idsInView.push(id);
1627
1995
  }
1628
1996
  Object.assign(state, {
1997
+ endBuffered,
1998
+ endNoBuffer,
1999
+ firstFullyOnScreenIndex,
2000
+ idsInView,
1629
2001
  startBuffered,
1630
2002
  startBufferedId,
1631
- startNoBuffer,
1632
- endBuffered,
1633
- endNoBuffer
2003
+ startNoBuffer
1634
2004
  });
1635
- if (state.enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0 && state.disableScrollJumpsFrom === void 0) {
2005
+ if (enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0) {
1636
2006
  state.scrollForNextCalculateItemsInView = nextTop !== void 0 && nextBottom !== void 0 ? {
1637
- top: nextTop,
1638
- bottom: nextBottom
2007
+ bottom: nextBottom,
2008
+ top: nextTop
1639
2009
  } : void 0;
1640
2010
  }
2011
+ const numContainers = peek$(ctx, "numContainers");
2012
+ const pendingRemoval = [];
2013
+ if (dataChanged) {
2014
+ for (let i = 0; i < numContainers; i++) {
2015
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
2016
+ if (!keyExtractor || itemKey && indexByKey.get(itemKey) === void 0) {
2017
+ pendingRemoval.push(i);
2018
+ }
2019
+ }
2020
+ }
1641
2021
  if (startBuffered !== null && endBuffered !== null) {
1642
- let numContainers = prevNumContainers;
2022
+ let numContainers2 = prevNumContainers;
1643
2023
  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
2024
  for (let i = startBuffered; i <= endBuffered; i++) {
1654
- if (!isContained(i)) {
2025
+ const id = (_f = idCache.get(i)) != null ? _f : getId(state, i);
2026
+ if (!containerItemKeys.has(id)) {
1655
2027
  needNewContainers.push(i);
1656
2028
  }
1657
2029
  }
2030
+ if (stickyIndicesArr.length > 0) {
2031
+ handleStickyActivation(
2032
+ ctx,
2033
+ state,
2034
+ stickyIndicesSet,
2035
+ stickyIndicesArr,
2036
+ scroll,
2037
+ needNewContainers,
2038
+ startBuffered,
2039
+ endBuffered
2040
+ );
2041
+ }
1658
2042
  if (needNewContainers.length > 0) {
2043
+ const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
2044
+ const itemType = getItemType(data[i], i);
2045
+ return itemType ? String(itemType) : "";
2046
+ }) : void 0;
1659
2047
  const availableContainers = findAvailableContainers(
2048
+ ctx,
2049
+ state,
1660
2050
  needNewContainers.length,
1661
2051
  startBuffered,
1662
- endBuffered
2052
+ endBuffered,
2053
+ pendingRemoval,
2054
+ requiredItemTypes,
2055
+ needNewContainers
1663
2056
  );
1664
2057
  for (let idx = 0; idx < needNewContainers.length; idx++) {
1665
2058
  const i = needNewContainers[idx];
1666
2059
  const containerIndex = availableContainers[idx];
1667
- const id = getId(i);
2060
+ const id = (_g = idCache.get(i)) != null ? _g : getId(state, i);
2061
+ const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
2062
+ if (oldKey && oldKey !== id) {
2063
+ containerItemKeys.delete(oldKey);
2064
+ }
1668
2065
  set$(ctx, `containerItemKey${containerIndex}`, id);
1669
2066
  set$(ctx, `containerItemData${containerIndex}`, data[i]);
1670
- if (containerIndex >= numContainers) {
1671
- numContainers = containerIndex + 1;
2067
+ if (requiredItemTypes) {
2068
+ state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2069
+ }
2070
+ containerItemKeys.add(id);
2071
+ if (stickyIndicesSet.has(i)) {
2072
+ set$(ctx, `containerSticky${containerIndex}`, true);
2073
+ const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2074
+ set$(ctx, `containerStickyOffset${containerIndex}`, new reactNative.Animated.Value(topPadding));
2075
+ state.stickyContainerPool.add(containerIndex);
2076
+ } else {
2077
+ state.stickyContainerPool.delete(containerIndex);
2078
+ }
2079
+ if (containerIndex >= numContainers2) {
2080
+ numContainers2 = containerIndex + 1;
1672
2081
  }
1673
2082
  }
1674
- if (numContainers !== prevNumContainers) {
1675
- set$(ctx, "numContainers", numContainers);
1676
- if (numContainers > peek$(ctx, "numContainersPooled")) {
1677
- set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
2083
+ if (numContainers2 !== prevNumContainers) {
2084
+ set$(ctx, "numContainers", numContainers2);
2085
+ if (numContainers2 > peek$(ctx, "numContainersPooled")) {
2086
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
1678
2087
  }
1679
2088
  }
1680
2089
  }
1681
- for (let i = 0; i < numContainers; i++) {
1682
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1683
- const itemIndex = state.indexByKey.get(itemKey);
2090
+ }
2091
+ if (stickyIndicesArr.length > 0) {
2092
+ handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, pendingRemoval);
2093
+ }
2094
+ for (let i = 0; i < numContainers; i++) {
2095
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
2096
+ if (pendingRemoval.includes(i)) {
2097
+ if (itemKey) {
2098
+ containerItemKeys.delete(itemKey);
2099
+ }
2100
+ state.containerItemTypes.delete(i);
2101
+ if (state.stickyContainerPool.has(i)) {
2102
+ set$(ctx, `containerSticky${i}`, false);
2103
+ set$(ctx, `containerStickyOffset${i}`, void 0);
2104
+ state.stickyContainerPool.delete(i);
2105
+ }
2106
+ set$(ctx, `containerItemKey${i}`, void 0);
2107
+ set$(ctx, `containerItemData${i}`, void 0);
2108
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2109
+ set$(ctx, `containerColumn${i}`, -1);
2110
+ } else {
2111
+ const itemIndex = indexByKey.get(itemKey);
1684
2112
  const item = data[itemIndex];
1685
2113
  if (item !== void 0) {
1686
- const id = getId(itemIndex);
2114
+ const id = (_h = idCache.get(itemIndex)) != null ? _h : getId(state, itemIndex);
1687
2115
  const position = positions.get(id);
1688
2116
  if (position === void 0) {
1689
- set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
2117
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1690
2118
  } 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
- }
2119
+ const column = columns.get(id) || 1;
1705
2120
  const prevPos = peek$(ctx, `containerPosition${i}`);
1706
2121
  const prevColumn = peek$(ctx, `containerColumn${i}`);
1707
2122
  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);
2123
+ if (position > POSITION_OUT_OF_VIEW && position !== prevPos) {
2124
+ set$(ctx, `containerPosition${i}`, position);
1710
2125
  }
1711
- if (column2 >= 0 && column2 !== prevColumn) {
1712
- set$(ctx, `containerColumn${i}`, column2);
2126
+ if (column >= 0 && column !== prevColumn) {
2127
+ set$(ctx, `containerColumn${i}`, column);
1713
2128
  }
1714
- if (prevData !== item) {
2129
+ if (prevData !== item && (itemsAreEqual ? !itemsAreEqual(prevData, item, itemIndex, data) : true)) {
1715
2130
  set$(ctx, `containerItemData${i}`, data[itemIndex]);
1716
2131
  }
1717
2132
  }
1718
2133
  }
1719
2134
  }
1720
2135
  }
1721
- if (!state.queuedInitialLayout && endBuffered !== null) {
1722
- if (checkAllSizesKnown()) {
1723
- setDidLayout();
2136
+ if (!queuedInitialLayout && endBuffered !== null) {
2137
+ if (checkAllSizesKnown(state)) {
2138
+ setDidLayout(ctx, state);
1724
2139
  }
1725
2140
  }
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);
2141
+ if (viewabilityConfigCallbackPairs) {
2142
+ updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollLength, startNoBuffer, endNoBuffer);
1752
2143
  }
1753
- if (alignItemsPaddingTop !== void 0) {
1754
- set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
2144
+ });
2145
+ }
2146
+
2147
+ // src/core/doInitialAllocateContainers.ts
2148
+ function doInitialAllocateContainers(ctx, state) {
2149
+ var _a;
2150
+ const {
2151
+ scrollLength,
2152
+ props: { data, getEstimatedItemSize, getItemType, scrollBuffer, numColumns, estimatedItemSize }
2153
+ } = state;
2154
+ if (scrollLength > 0 && data.length > 0 && !peek$(ctx, "numContainers")) {
2155
+ const averageItemSize = getEstimatedItemSize ? getEstimatedItemSize(0, data[0], getItemType ? (_a = getItemType(data[0], 0)) != null ? _a : "" : "") : estimatedItemSize;
2156
+ const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize * numColumns);
2157
+ for (let i = 0; i < numContainers; i++) {
2158
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2159
+ set$(ctx, `containerColumn${i}`, -1);
1755
2160
  }
1756
- set$(
1757
- ctx,
1758
- "paddingTop",
1759
- (stylePaddingTop != null ? stylePaddingTop : peek$(ctx, "stylePaddingTop")) + (alignItemsPaddingTop != null ? alignItemsPaddingTop : peek$(ctx, "alignItemsPaddingTop"))
1760
- );
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));
2161
+ set$(ctx, "numContainers", numContainers);
2162
+ set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
2163
+ if (!IsNewArchitecture) {
2164
+ if (state.props.initialScroll) {
2165
+ requestAnimationFrame(() => {
2166
+ calculateItemsInView(ctx, state);
2167
+ });
2168
+ } else {
2169
+ calculateItemsInView(ctx, state);
1769
2170
  }
1770
- setPaddingTop({ alignItemsPaddingTop });
1771
2171
  }
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();
1780
- }
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);
2172
+ return true;
2173
+ }
2174
+ }
2175
+
2176
+ // src/core/doMaintainScrollAtEnd.ts
2177
+ function doMaintainScrollAtEnd(ctx, state, animated) {
2178
+ const {
2179
+ refScroller,
2180
+ props: { maintainScrollAtEnd }
2181
+ } = state;
2182
+ if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2183
+ const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2184
+ if (paddingTop > 0) {
2185
+ state.scroll = 0;
1798
2186
  }
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;
2187
+ requestAnimationFrame(() => {
2188
+ var _a;
2189
+ if (state == null ? void 0 : state.isAtEnd) {
1810
2190
  state.maintainingScrollAtEnd = true;
1811
2191
  (_a = refScroller.current) == null ? void 0 : _a.scrollToEnd({
1812
2192
  animated
@@ -1817,290 +2197,660 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1817
2197
  },
1818
2198
  0
1819
2199
  );
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;
1839
2200
  }
2201
+ });
2202
+ return true;
2203
+ }
2204
+ }
2205
+
2206
+ // src/utils/checkAtTop.ts
2207
+ function checkAtTop(state) {
2208
+ if (!state) {
2209
+ return;
2210
+ }
2211
+ const {
2212
+ scrollLength,
2213
+ scroll,
2214
+ props: { onStartReachedThreshold }
2215
+ } = state;
2216
+ const distanceFromTop = scroll;
2217
+ state.isAtStart = distanceFromTop <= 0;
2218
+ state.isStartReached = checkThreshold(
2219
+ distanceFromTop,
2220
+ false,
2221
+ onStartReachedThreshold * scrollLength,
2222
+ state.isStartReached,
2223
+ state.startReachedBlockedByTimer,
2224
+ (distance) => {
2225
+ var _a, _b;
2226
+ return (_b = (_a = state.props).onStartReached) == null ? void 0 : _b.call(_a, { distanceFromStart: distance });
2227
+ },
2228
+ (block) => {
2229
+ state.startReachedBlockedByTimer = block;
1840
2230
  }
1841
- return isReached;
1842
- };
1843
- const checkAtBottom = () => {
1844
- if (!refState.current) {
1845
- return;
1846
- }
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 });
1862
- },
1863
- (block) => {
1864
- refState.current.endReachedBlockedByTimer = block;
1865
- }
1866
- );
1867
- }
1868
- };
1869
- const checkAtTop = () => {
1870
- if (!refState.current) {
2231
+ );
2232
+ }
2233
+
2234
+ // src/core/handleLayout.ts
2235
+ function handleLayout(ctx, state, layout, setCanRender) {
2236
+ const { maintainScrollAtEnd } = state.props;
2237
+ const scrollLength = layout[state.props.horizontal ? "width" : "height"];
2238
+ const otherAxisSize = layout[state.props.horizontal ? "height" : "width"];
2239
+ const needsCalculate = !state.lastLayout || scrollLength > state.scrollLength || state.lastLayout.x !== layout.x || state.lastLayout.y !== layout.y;
2240
+ state.lastLayout = layout;
2241
+ const didChange = scrollLength !== state.scrollLength;
2242
+ const prevOtherAxisSize = state.otherAxisSize;
2243
+ state.scrollLength = scrollLength;
2244
+ state.otherAxisSize = otherAxisSize;
2245
+ state.lastBatchingAction = Date.now();
2246
+ state.scrollForNextCalculateItemsInView = void 0;
2247
+ doInitialAllocateContainers(ctx, state);
2248
+ if (needsCalculate) {
2249
+ calculateItemsInView(ctx, state, { doMVCP: true });
2250
+ }
2251
+ if (didChange || otherAxisSize !== prevOtherAxisSize) {
2252
+ set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
2253
+ }
2254
+ if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
2255
+ doMaintainScrollAtEnd(ctx, state, false);
2256
+ }
2257
+ updateAlignItemsPaddingTop(ctx, state);
2258
+ checkAtBottom(ctx, state);
2259
+ checkAtTop(state);
2260
+ if (state) {
2261
+ state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
2262
+ }
2263
+ if (__DEV__ && scrollLength === 0) {
2264
+ warnDevOnce(
2265
+ "height0",
2266
+ `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.`
2267
+ );
2268
+ }
2269
+ setCanRender(true);
2270
+ }
2271
+
2272
+ // src/core/onScroll.ts
2273
+ function onScroll(ctx, state, event) {
2274
+ var _a, _b, _c;
2275
+ const {
2276
+ scrollProcessingEnabled,
2277
+ props: { onScroll: onScrollProp }
2278
+ } = state;
2279
+ if (scrollProcessingEnabled === false) {
2280
+ return;
2281
+ }
2282
+ 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) {
2283
+ return;
2284
+ }
2285
+ const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2286
+ const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
2287
+ if (ignoreScrollFromMVCP && !state.scrollingTo) {
2288
+ const { lt, gt } = ignoreScrollFromMVCP;
2289
+ if (lt && newScroll < lt || gt && newScroll > gt) {
1871
2290
  return;
1872
2291
  }
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");
2292
+ }
2293
+ state.scrollPending = newScroll;
2294
+ updateScroll(ctx, state, newScroll);
2295
+ onScrollProp == null ? void 0 : onScrollProp(event);
2296
+ }
2297
+ function updateScroll(ctx, state, newScroll) {
2298
+ const scrollingTo = state.scrollingTo;
2299
+ state.hasScrolled = true;
2300
+ state.lastBatchingAction = Date.now();
2301
+ const currentTime = Date.now();
2302
+ if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
2303
+ state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2304
+ }
2305
+ if (state.scrollHistory.length > 5) {
2306
+ state.scrollHistory.shift();
2307
+ }
2308
+ state.scrollPrev = state.scroll;
2309
+ state.scrollPrevTime = state.scrollTime;
2310
+ state.scroll = newScroll;
2311
+ state.scrollTime = currentTime;
2312
+ if (Math.abs(state.scroll - state.scrollPrev) > 2) {
2313
+ calculateItemsInView(ctx, state);
2314
+ checkAtBottom(ctx, state);
2315
+ checkAtTop(state);
2316
+ }
2317
+ }
2318
+
2319
+ // src/core/ScrollAdjustHandler.ts
2320
+ var ScrollAdjustHandler = class {
2321
+ constructor(ctx) {
2322
+ this.appliedAdjust = 0;
2323
+ this.mounted = false;
2324
+ this.context = ctx;
2325
+ }
2326
+ requestAdjust(add) {
2327
+ const oldAdjustTop = peek$(this.context, "scrollAdjust") || 0;
2328
+ this.appliedAdjust = add + oldAdjustTop;
2329
+ const set = () => set$(this.context, "scrollAdjust", this.appliedAdjust);
2330
+ if (this.mounted) {
2331
+ set();
2332
+ } else {
2333
+ requestAnimationFrame(set);
2334
+ }
2335
+ }
2336
+ setMounted() {
2337
+ this.mounted = true;
2338
+ }
2339
+ };
2340
+
2341
+ // src/core/updateItemSize.ts
2342
+ function updateItemSizes(ctx, state, itemUpdates) {
2343
+ var _a;
2344
+ const {
2345
+ props: {
2346
+ horizontal,
2347
+ maintainVisibleContentPosition,
2348
+ suggestEstimatedItemSize,
2349
+ onItemSizeChanged,
2350
+ data,
2351
+ maintainScrollAtEnd
2352
+ }
2353
+ } = state;
2354
+ if (!data) return;
2355
+ const containersDidLayout = peek$(ctx, "containersDidLayout");
2356
+ let needsRecalculate = !containersDidLayout;
2357
+ let shouldMaintainScrollAtEnd = false;
2358
+ let minIndexSizeChanged;
2359
+ let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2360
+ for (const { itemKey, sizeObj } of itemUpdates) {
2361
+ const index = state.indexByKey.get(itemKey);
2362
+ const prevSizeKnown = state.sizesKnown.get(itemKey);
2363
+ const diff = updateOneItemSize(state, itemKey, sizeObj);
2364
+ const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2365
+ if (diff !== 0) {
2366
+ minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
2367
+ if (((_a = state.scrollingTo) == null ? void 0 : _a.viewPosition) && maintainVisibleContentPosition && index === state.scrollingTo.index && diff > 0) {
2368
+ requestAdjust(ctx, state, diff * state.scrollingTo.viewPosition);
2369
+ }
2370
+ const { startBuffered, endBuffered } = state;
2371
+ needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
2372
+ if (!needsRecalculate) {
2373
+ const numContainers = ctx.values.get("numContainers");
1904
2374
  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);
2375
+ if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
2376
+ needsRecalculate = true;
2377
+ break;
1911
2378
  }
1912
2379
  }
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
2380
  }
2381
+ if (state.needsOtherAxisSize) {
2382
+ const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
2383
+ maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
2384
+ }
2385
+ if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2386
+ shouldMaintainScrollAtEnd = true;
2387
+ }
2388
+ onItemSizeChanged == null ? void 0 : onItemSizeChanged({
2389
+ index,
2390
+ itemData: state.props.data[index],
2391
+ itemKey,
2392
+ previous: size - diff,
2393
+ size
2394
+ });
1929
2395
  }
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) {
2396
+ }
2397
+ if (minIndexSizeChanged !== void 0) {
2398
+ state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
2399
+ }
2400
+ if (__DEV__ && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
2401
+ if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
2402
+ state.timeoutSizeMessage = setTimeout(() => {
2403
+ var _a2;
2404
+ state.timeoutSizeMessage = void 0;
2405
+ const num = state.sizesKnown.size;
2406
+ const avg = (_a2 = state.averageSizes[""]) == null ? void 0 : _a2.avg;
2407
+ console.warn(
2408
+ `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
2409
+ );
2410
+ }, 1e3);
2411
+ }
2412
+ const cur = peek$(ctx, "otherAxisSize");
2413
+ if (!cur || maxOtherAxisSize > cur) {
2414
+ set$(ctx, "otherAxisSize", maxOtherAxisSize);
2415
+ }
2416
+ if (containersDidLayout || checkAllSizesKnown(state)) {
2417
+ if (needsRecalculate) {
2418
+ state.scrollForNextCalculateItemsInView = void 0;
2419
+ calculateItemsInView(ctx, state, { doMVCP: true });
2420
+ }
2421
+ if (shouldMaintainScrollAtEnd) {
2422
+ if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
2423
+ doMaintainScrollAtEnd(ctx, state, false);
2424
+ }
2425
+ }
2426
+ }
2427
+ }
2428
+ function updateItemSize(ctx, state, itemKey, sizeObj) {
2429
+ var _a;
2430
+ const {
2431
+ queuedItemSizeUpdates,
2432
+ queuedItemSizeUpdatesWaiting,
2433
+ sizesKnown,
2434
+ props: { getFixedItemSize, getItemType }
2435
+ } = state;
2436
+ if (getFixedItemSize) {
2437
+ const index = state.indexByKey.get(itemKey);
2438
+ if (index === void 0) {
1942
2439
  return;
1943
2440
  }
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
- }
2441
+ const itemData = state.props.data[index];
2442
+ if (itemData === void 0) {
2443
+ return;
2444
+ }
2445
+ const type = getItemType ? (_a = getItemType(itemData, index)) != null ? _a : "" : "";
2446
+ const size = getFixedItemSize(index, itemData, type);
2447
+ if (size !== void 0 && size === sizesKnown.get(itemKey)) {
2448
+ return;
2449
+ }
2450
+ }
2451
+ const containersDidLayout = peek$(ctx, "containersDidLayout");
2452
+ const speed = getScrollVelocity(state);
2453
+ if (!containersDidLayout || !queuedItemSizeUpdatesWaiting || Math.abs(speed) < 1) {
2454
+ updateItemSizes(ctx, state, [{ itemKey, sizeObj }]);
2455
+ if (containersDidLayout) {
2456
+ state.queuedItemSizeUpdatesWaiting = true;
2457
+ requestAnimationFrame(() => {
2458
+ state.queuedItemSizeUpdatesWaiting = false;
2459
+ updateItemSizes(ctx, state, queuedItemSizeUpdates);
2460
+ queuedItemSizeUpdates.length = 0;
2461
+ });
2462
+ }
2463
+ } else {
2464
+ queuedItemSizeUpdates.push({ itemKey, sizeObj });
2465
+ }
2466
+ }
2467
+ function updateOneItemSize(state, itemKey, sizeObj) {
2468
+ var _a;
2469
+ const {
2470
+ sizes,
2471
+ indexByKey,
2472
+ sizesKnown,
2473
+ averageSizes,
2474
+ props: { data, horizontal, getEstimatedItemSize, getItemType, getFixedItemSize }
2475
+ } = state;
2476
+ if (!data) return 0;
2477
+ const index = indexByKey.get(itemKey);
2478
+ const prevSize = getItemSize(state, itemKey, index, data);
2479
+ const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2480
+ sizesKnown.set(itemKey, size);
2481
+ if (!getEstimatedItemSize && !getFixedItemSize) {
2482
+ const itemType = getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : "";
2483
+ let averages = averageSizes[itemType];
2484
+ if (!averages) {
2485
+ averages = averageSizes[itemType] = { avg: 0, num: 0 };
2486
+ }
2487
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2488
+ averages.num++;
2489
+ }
2490
+ if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2491
+ sizes.set(itemKey, size);
2492
+ return size - prevSize;
2493
+ }
2494
+ return 0;
2495
+ }
2496
+ var useCombinedRef = (...refs) => {
2497
+ const callback = React3.useCallback((element) => {
2498
+ for (const ref of refs) {
2499
+ if (!ref) {
2500
+ continue;
1952
2501
  }
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));
1956
- }
1957
- }
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
- }
2502
+ if (isFunction(ref)) {
2503
+ ref(element);
1981
2504
  } 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
- }
1997
- }
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;
2007
- }
2008
- totalSize += maxSizeInRow;
2009
- column = 1;
2010
- maxSizeInRow = 0;
2505
+ ref.current = element;
2011
2506
  }
2012
2507
  }
2013
- if (maxSizeInRow > 0) {
2014
- totalSize += maxSizeInRow;
2015
- }
2016
- state.ignoreScrollFromCalcTotal = true;
2017
- requestAnimationFrame(() => {
2018
- state.ignoreScrollFromCalcTotal = false;
2019
- });
2020
- addTotalSize(null, totalSize, totalSizeBelowIndex);
2508
+ }, refs);
2509
+ return callback;
2510
+ };
2511
+
2512
+ // src/utils/createColumnWrapperStyle.ts
2513
+ function createColumnWrapperStyle(contentContainerStyle) {
2514
+ const { gap, columnGap, rowGap } = contentContainerStyle;
2515
+ if (gap || columnGap || rowGap) {
2516
+ contentContainerStyle.gap = void 0;
2517
+ contentContainerStyle.columnGap = void 0;
2518
+ contentContainerStyle.rowGap = void 0;
2519
+ return {
2520
+ columnGap,
2521
+ gap,
2522
+ rowGap
2523
+ };
2524
+ }
2525
+ }
2526
+ function getRenderedItem(ctx, state, key) {
2527
+ var _a;
2528
+ if (!state) {
2529
+ return null;
2530
+ }
2531
+ const {
2532
+ indexByKey,
2533
+ props: { data, getItemType, renderItem }
2534
+ } = state;
2535
+ const index = indexByKey.get(key);
2536
+ if (index === void 0) {
2537
+ return null;
2538
+ }
2539
+ let renderedItem = null;
2540
+ if (renderItem && data[index]) {
2541
+ const itemProps = {
2542
+ extraData: peek$(ctx, "extraData"),
2543
+ index,
2544
+ item: data[index],
2545
+ type: getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : ""
2546
+ };
2547
+ renderedItem = isFunction(renderItem) ? renderItem(itemProps) : React3__namespace.default.createElement(renderItem, itemProps);
2548
+ }
2549
+ return { index, item: data[index], renderedItem };
2550
+ }
2551
+
2552
+ // src/utils/throttledOnScroll.ts
2553
+ function throttledOnScroll(originalHandler, scrollEventThrottle) {
2554
+ const throttle = useThrottleDebounce("throttle");
2555
+ return (event) => {
2556
+ throttle(originalHandler, scrollEventThrottle, event);
2021
2557
  };
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;
2558
+ }
2559
+
2560
+ // src/utils/updateAveragesOnDataChange.ts
2561
+ function updateAveragesOnDataChange(state, oldData, newData) {
2562
+ var _a;
2563
+ const {
2564
+ averageSizes,
2565
+ sizesKnown,
2566
+ indexByKey,
2567
+ props: { itemsAreEqual, getItemType, keyExtractor }
2568
+ } = state;
2569
+ if (!itemsAreEqual || !oldData.length || !newData.length) {
2570
+ for (const key in averageSizes) {
2571
+ delete averageSizes[key];
2572
+ }
2573
+ return;
2574
+ }
2575
+ const itemTypesToPreserve = {};
2576
+ const newDataLength = newData.length;
2577
+ const oldDataLength = oldData.length;
2578
+ for (let newIndex = 0; newIndex < newDataLength; newIndex++) {
2579
+ const newItem = newData[newIndex];
2580
+ const id = keyExtractor ? keyExtractor(newItem, newIndex) : String(newIndex);
2581
+ const oldIndex = indexByKey.get(id);
2582
+ if (oldIndex !== void 0 && oldIndex < oldDataLength) {
2583
+ const knownSize = sizesKnown.get(id);
2584
+ if (knownSize === void 0) continue;
2585
+ const oldItem = oldData[oldIndex];
2586
+ const areEqual = itemsAreEqual(oldItem, newItem, newIndex, newData);
2587
+ if (areEqual) {
2588
+ const itemType = getItemType ? (_a = getItemType(newItem, newIndex)) != null ? _a : "" : "";
2589
+ let typeData = itemTypesToPreserve[itemType];
2590
+ if (!typeData) {
2591
+ typeData = itemTypesToPreserve[itemType] = { count: 0, totalSize: 0 };
2034
2592
  }
2593
+ typeData.totalSize += knownSize;
2594
+ typeData.count++;
2035
2595
  }
2036
2596
  }
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 });
2045
- }
2597
+ }
2598
+ for (const key in averageSizes) {
2599
+ delete averageSizes[key];
2600
+ }
2601
+ for (const itemType in itemTypesToPreserve) {
2602
+ const { totalSize, count } = itemTypesToPreserve[itemType];
2603
+ if (count > 0) {
2604
+ averageSizes[itemType] = {
2605
+ avg: totalSize / count,
2606
+ num: count
2607
+ };
2046
2608
  }
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
- }
2609
+ }
2610
+ }
2611
+
2612
+ // src/components/LegendList.tsx
2613
+ var DEFAULT_DRAW_DISTANCE = 250;
2614
+ var DEFAULT_ITEM_SIZE = 100;
2615
+ var LegendList = typedMemo(
2616
+ typedForwardRef(function LegendList2(props, forwardedRef) {
2617
+ const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
2618
+ const isChildrenMode = children !== void 0 && dataProp === void 0;
2619
+ const processedProps = isChildrenMode ? {
2620
+ ...restProps,
2621
+ data: (isArray(children) ? children : React3__namespace.Children.toArray(children)).flat(1),
2622
+ renderItem: ({ item }) => item
2623
+ } : {
2624
+ ...restProps,
2625
+ data: dataProp || [],
2626
+ renderItem: renderItemProp
2627
+ };
2628
+ return /* @__PURE__ */ React3__namespace.createElement(StateProvider, null, /* @__PURE__ */ React3__namespace.createElement(LegendListInner, { ...processedProps, ref: forwardedRef }));
2629
+ })
2630
+ );
2631
+ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
2632
+ var _a;
2633
+ const {
2634
+ alignItemsAtEnd = false,
2635
+ columnWrapperStyle,
2636
+ contentContainerStyle: contentContainerStyleProp,
2637
+ data: dataProp = [],
2638
+ drawDistance = 250,
2639
+ estimatedItemSize: estimatedItemSizeProp,
2640
+ estimatedListSize,
2641
+ extraData,
2642
+ getEstimatedItemSize,
2643
+ getFixedItemSize,
2644
+ getItemType,
2645
+ horizontal,
2646
+ initialContainerPoolRatio = 2,
2647
+ initialScrollIndex: initialScrollIndexProp,
2648
+ initialScrollOffset: initialScrollOffsetProp,
2649
+ itemsAreEqual,
2650
+ keyExtractor: keyExtractorProp,
2651
+ ListEmptyComponent,
2652
+ ListHeaderComponent,
2653
+ maintainScrollAtEnd = false,
2654
+ maintainScrollAtEndThreshold = 0.1,
2655
+ maintainVisibleContentPosition = true,
2656
+ numColumns: numColumnsProp = 1,
2657
+ onEndReached,
2658
+ onEndReachedThreshold = 0.5,
2659
+ onItemSizeChanged,
2660
+ onLayout: onLayoutProp,
2661
+ onLoad,
2662
+ onMomentumScrollEnd,
2663
+ onRefresh,
2664
+ onScroll: onScrollProp,
2665
+ onStartReached,
2666
+ onStartReachedThreshold = 0.5,
2667
+ onViewableItemsChanged,
2668
+ progressViewOffset,
2669
+ recycleItems = false,
2670
+ refreshControl,
2671
+ refreshing,
2672
+ refScrollView,
2673
+ renderItem,
2674
+ scrollEventThrottle,
2675
+ snapToIndices,
2676
+ stickyIndices,
2677
+ style: styleProp,
2678
+ suggestEstimatedItemSize,
2679
+ viewabilityConfig,
2680
+ viewabilityConfigCallbackPairs,
2681
+ waitForInitialLayout = true,
2682
+ ...rest
2683
+ } = props;
2684
+ const [renderNum, setRenderNum] = React3.useState(0);
2685
+ const initialScroll = initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
2686
+ const [canRender, setCanRender] = React3__namespace.useState(!IsNewArchitecture);
2687
+ const contentContainerStyle = { ...reactNative.StyleSheet.flatten(contentContainerStyleProp) };
2688
+ const style = { ...reactNative.StyleSheet.flatten(styleProp) };
2689
+ const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
2690
+ const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
2691
+ const ctx = useStateContext();
2692
+ ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
2693
+ const refScroller = React3.useRef(null);
2694
+ const combinedRef = useCombinedRef(refScroller, refScrollView);
2695
+ const estimatedItemSize = estimatedItemSizeProp != null ? estimatedItemSizeProp : DEFAULT_ITEM_SIZE;
2696
+ const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
2697
+ const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (_item, index) => index.toString();
2698
+ const refState = React3.useRef();
2699
+ if (!refState.current) {
2700
+ const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { height: 0, width: 0 } : reactNative.Dimensions.get("window"))[horizontal ? "width" : "height"];
2701
+ refState.current = {
2702
+ activeStickyIndex: void 0,
2703
+ averageSizes: {},
2704
+ columns: /* @__PURE__ */ new Map(),
2705
+ containerItemKeys: /* @__PURE__ */ new Set(),
2706
+ containerItemTypes: /* @__PURE__ */ new Map(),
2707
+ enableScrollForNextCalculateItemsInView: true,
2708
+ endBuffered: -1,
2709
+ endNoBuffer: -1,
2710
+ endReachedBlockedByTimer: false,
2711
+ firstFullyOnScreenIndex: -1,
2712
+ idCache: /* @__PURE__ */ new Map(),
2713
+ idsInView: [],
2714
+ indexByKey: /* @__PURE__ */ new Map(),
2715
+ initialScroll,
2716
+ isAtEnd: false,
2717
+ isAtStart: false,
2718
+ isEndReached: false,
2719
+ isStartReached: false,
2720
+ lastBatchingAction: Date.now(),
2721
+ lastLayout: void 0,
2722
+ loadStartTime: Date.now(),
2723
+ minIndexSizeChanged: 0,
2724
+ nativeMarginTop: 0,
2725
+ pendingAdjust: 0,
2726
+ positions: /* @__PURE__ */ new Map(),
2727
+ props: {},
2728
+ queuedCalculateItemsInView: 0,
2729
+ queuedItemSizeUpdates: [],
2730
+ refScroller: void 0,
2731
+ scroll: 0,
2732
+ scrollAdjustHandler: new ScrollAdjustHandler(ctx),
2733
+ scrollForNextCalculateItemsInView: void 0,
2734
+ scrollHistory: [],
2735
+ scrollLength: initialScrollLength,
2736
+ scrollPending: 0,
2737
+ scrollPrev: 0,
2738
+ scrollPrevTime: 0,
2739
+ scrollProcessingEnabled: true,
2740
+ scrollTime: 0,
2741
+ sizes: /* @__PURE__ */ new Map(),
2742
+ sizesKnown: /* @__PURE__ */ new Map(),
2743
+ startBuffered: -1,
2744
+ startNoBuffer: -1,
2745
+ startReachedBlockedByTimer: false,
2746
+ stickyContainerPool: /* @__PURE__ */ new Set(),
2747
+ stickyContainers: /* @__PURE__ */ new Map(),
2748
+ timeoutSizeMessage: 0,
2749
+ timeouts: /* @__PURE__ */ new Set(),
2750
+ totalSize: 0,
2751
+ viewabilityConfigCallbackPairs: void 0
2752
+ };
2753
+ set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
2754
+ set$(ctx, "extraData", extraData);
2755
+ }
2756
+ const state = refState.current;
2757
+ const isFirst = !state.props.renderItem;
2758
+ const didDataChange = state.props.data !== dataProp;
2759
+ state.props = {
2760
+ alignItemsAtEnd,
2761
+ data: dataProp,
2762
+ estimatedItemSize,
2763
+ getEstimatedItemSize,
2764
+ getFixedItemSize,
2765
+ getItemType,
2766
+ horizontal: !!horizontal,
2767
+ initialContainerPoolRatio,
2768
+ initialScroll,
2769
+ itemsAreEqual,
2770
+ keyExtractor,
2771
+ maintainScrollAtEnd,
2772
+ maintainScrollAtEndThreshold,
2773
+ maintainVisibleContentPosition,
2774
+ numColumns: numColumnsProp,
2775
+ onEndReached,
2776
+ onEndReachedThreshold,
2777
+ onItemSizeChanged,
2778
+ onLoad,
2779
+ onScroll: onScrollProp,
2780
+ onStartReached,
2781
+ onStartReachedThreshold,
2782
+ recycleItems: !!recycleItems,
2783
+ renderItem,
2784
+ scrollBuffer,
2785
+ snapToIndices,
2786
+ stickyIndicesArr: stickyIndices != null ? stickyIndices : [],
2787
+ stickyIndicesSet: React3.useMemo(() => new Set(stickyIndices != null ? stickyIndices : []), [stickyIndices == null ? void 0 : stickyIndices.join(",")]),
2788
+ stylePaddingBottom: stylePaddingBottomState,
2789
+ stylePaddingTop: stylePaddingTopState,
2790
+ suggestEstimatedItemSize: !!suggestEstimatedItemSize
2791
+ };
2792
+ state.refScroller = refScroller;
2793
+ const checkResetContainers = (isFirst2) => {
2794
+ const state2 = refState.current;
2795
+ if (state2) {
2796
+ if (!isFirst2 && state2.props.data !== dataProp) {
2797
+ updateAveragesOnDataChange(state2, state2.props.data, dataProp);
2057
2798
  }
2058
- const stillNeeded = numNeeded - result.length;
2059
- if (stillNeeded > 0) {
2060
- for (let i = 0; i < stillNeeded; i++) {
2061
- result.push(numContainers + i);
2799
+ state2.props.data = dataProp;
2800
+ if (!isFirst2) {
2801
+ calculateItemsInView(ctx, state2, { dataChanged: true, doMVCP: true });
2802
+ const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2803
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state2, false);
2804
+ if (!didMaintainScrollAtEnd && dataProp.length > state2.props.data.length) {
2805
+ state2.isEndReached = false;
2062
2806
  }
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
- );
2807
+ if (!didMaintainScrollAtEnd) {
2808
+ checkAtTop(state2);
2809
+ checkAtBottom(ctx, state2);
2075
2810
  }
2076
2811
  }
2077
2812
  }
2078
- return result.sort(comparatorDefault);
2079
2813
  };
2080
- const isFirst = !refState.current.renderItem;
2081
- const memoizedLastItemKeys = React2.useMemo(() => {
2814
+ const memoizedLastItemKeys = React3.useMemo(() => {
2082
2815
  if (!dataProp.length) return [];
2083
2816
  return Array.from(
2084
2817
  { length: Math.min(numColumnsProp, dataProp.length) },
2085
- (_, i) => getId(dataProp.length - 1 - i)
2818
+ (_, i) => getId(state, dataProp.length - 1 - i)
2086
2819
  );
2087
2820
  }, [dataProp, numColumnsProp]);
2088
- const initalizeStateVars = () => {
2821
+ const initializeStateVars = () => {
2089
2822
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
2090
2823
  set$(ctx, "numColumns", numColumnsProp);
2091
2824
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
2092
- setPaddingTop({ stylePaddingTop: stylePaddingTopState });
2093
- refState.current.stylePaddingBottom = stylePaddingBottomState;
2094
- const paddingDiff = stylePaddingTopState - prevPaddingTop;
2095
- if (paddingDiff && prevPaddingTop !== void 0 && reactNative.Platform.OS === "ios") {
2096
- queueMicrotask(() => {
2097
- scrollTo({ offset: refState.current.scrollPending + paddingDiff, animated: false });
2098
- });
2825
+ setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
2826
+ refState.current.props.stylePaddingBottom = stylePaddingBottomState;
2827
+ let paddingDiff = stylePaddingTopState - prevPaddingTop;
2828
+ if (maintainVisibleContentPosition && paddingDiff && prevPaddingTop !== void 0 && reactNative.Platform.OS === "ios") {
2829
+ if (state.scroll < 0) {
2830
+ paddingDiff += state.scroll;
2831
+ }
2832
+ requestAdjust(ctx, state, paddingDiff);
2099
2833
  }
2100
2834
  };
2101
2835
  if (isFirst) {
2102
- initalizeStateVars();
2836
+ initializeStateVars();
2837
+ updateAllPositions(ctx, state);
2103
2838
  }
2839
+ const initialContentOffset = React3.useMemo(() => {
2840
+ if (initialScroll) {
2841
+ const { index, viewOffset } = initialScroll;
2842
+ let initialContentOffset2 = viewOffset || 0;
2843
+ if (index !== void 0) {
2844
+ initialContentOffset2 += calculateOffsetForIndex(ctx, state, index);
2845
+ }
2846
+ refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
2847
+ if (initialContentOffset2 > 0) {
2848
+ scrollTo(state, { animated: false, index, offset: initialContentOffset2 });
2849
+ }
2850
+ return initialContentOffset2;
2851
+ }
2852
+ return 0;
2853
+ }, [renderNum]);
2104
2854
  if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
2105
2855
  refState.current.lastBatchingAction = Date.now();
2106
2856
  if (!keyExtractorProp && !isFirst && didDataChange) {
@@ -2111,23 +2861,29 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2111
2861
  refState.current.sizes.clear();
2112
2862
  refState.current.positions.clear();
2113
2863
  }
2114
- refState.current.previousTotalSize = peek$(ctx, "totalSize");
2115
- calcTotalSizesAndPositions({ forgetPositions: false });
2116
2864
  }
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();
2865
+ const onLayoutHeader = React3.useCallback((rect, fromLayoutEffect) => {
2866
+ const size = rect[horizontal ? "width" : "height"];
2867
+ set$(ctx, "headerSize", size);
2868
+ if ((initialScroll == null ? void 0 : initialScroll.index) !== void 0) {
2869
+ if (IsNewArchitecture && reactNative.Platform.OS !== "android") {
2870
+ if (fromLayoutEffect) {
2871
+ setRenderNum((v) => v + 1);
2123
2872
  }
2124
- });
2125
- setTimeout(dispose, 0);
2126
- return dispose;
2873
+ } else {
2874
+ setTimeout(() => {
2875
+ scrollToIndex(ctx, state, { ...initialScroll, animated: false });
2876
+ }, 17);
2877
+ }
2127
2878
  }
2128
2879
  }, []);
2129
- React2.useEffect(() => {
2130
- const didAllocateContainers = doInitialAllocateContainers();
2880
+ React3.useLayoutEffect(() => {
2881
+ if (snapToIndices) {
2882
+ updateSnapToOffsets(ctx, state);
2883
+ }
2884
+ }, [snapToIndices]);
2885
+ React3.useLayoutEffect(() => {
2886
+ const didAllocateContainers = doInitialAllocateContainersCallback();
2131
2887
  if (!didAllocateContainers) {
2132
2888
  checkResetContainers(
2133
2889
  /*isFirst*/
@@ -2135,477 +2891,218 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2135
2891
  );
2136
2892
  }
2137
2893
  }, [dataProp, numColumnsProp]);
2138
- React2.useEffect(() => {
2894
+ React3.useLayoutEffect(() => {
2139
2895
  set$(ctx, "extraData", extraData);
2140
2896
  }, [extraData]);
2141
- refState.current.renderItem = renderItem2;
2142
- React2.useEffect(initalizeStateVars, [
2897
+ React3.useLayoutEffect(() => {
2898
+ if (IsNewArchitecture) {
2899
+ let measured;
2900
+ refScroller.current.measure((x, y, width, height) => {
2901
+ measured = { height, width, x, y };
2902
+ });
2903
+ if (measured) {
2904
+ const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
2905
+ if (size) {
2906
+ handleLayout(ctx, state, measured, setCanRender);
2907
+ }
2908
+ }
2909
+ }
2910
+ }, []);
2911
+ React3.useLayoutEffect(initializeStateVars, [
2143
2912
  memoizedLastItemKeys.join(","),
2144
2913
  numColumnsProp,
2145
2914
  stylePaddingTopState,
2146
2915
  stylePaddingBottomState
2147
2916
  ]);
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
- }
2917
+ const doInitialAllocateContainersCallback = () => {
2918
+ return doInitialAllocateContainers(ctx, state);
2197
2919
  };
2198
- React2.useEffect(() => {
2199
- const state = refState.current;
2920
+ React3.useEffect(() => {
2200
2921
  const viewability = setupViewability({
2922
+ onViewableItemsChanged,
2201
2923
  viewabilityConfig,
2202
- viewabilityConfigCallbackPairs,
2203
- onViewableItemsChanged
2924
+ viewabilityConfigCallbackPairs
2204
2925
  });
2205
2926
  state.viewabilityConfigCallbackPairs = viewability;
2206
2927
  state.enableScrollForNextCalculateItemsInView = !viewability;
2207
2928
  }, [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) => {
2929
+ if (!IsNewArchitecture) {
2930
+ useInit(() => {
2931
+ doInitialAllocateContainersCallback();
2932
+ });
2933
+ }
2934
+ const onLayout = React3.useCallback((event) => {
2365
2935
  const layout = event.nativeEvent.layout;
2366
- handleLayout(layout);
2367
- layout[horizontal ? "width" : "height"];
2368
- layout[horizontal ? "height" : "width"];
2936
+ handleLayout(ctx, state, layout, setCanRender);
2369
2937
  if (onLayoutProp) {
2370
2938
  onLayoutProp(event);
2371
2939
  }
2372
2940
  }, []);
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);
2941
+ React3.useImperativeHandle(forwardedRef, () => {
2942
+ const scrollIndexIntoView = (options) => {
2943
+ const state2 = refState.current;
2944
+ if (state2) {
2945
+ const { index, ...rest2 } = options;
2946
+ const { startNoBuffer, endNoBuffer } = state2;
2947
+ if (index < startNoBuffer || index > endNoBuffer) {
2948
+ const viewPosition = index < startNoBuffer ? 0 : 1;
2949
+ scrollToIndex(ctx, state2, {
2950
+ ...rest2,
2951
+ index,
2952
+ viewPosition
2953
+ });
2381
2954
  }
2382
2955
  }
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;
2956
+ };
2957
+ return {
2958
+ flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
2959
+ getNativeScrollRef: () => refScroller.current,
2960
+ getScrollableNode: () => refScroller.current.getScrollableNode(),
2961
+ getScrollResponder: () => refScroller.current.getScrollResponder(),
2962
+ getState: () => {
2963
+ const state2 = refState.current;
2964
+ return state2 ? {
2965
+ contentLength: state2.totalSize,
2966
+ data: state2.props.data,
2967
+ end: state2.endNoBuffer,
2968
+ endBuffered: state2.endBuffered,
2969
+ isAtEnd: state2.isAtEnd,
2970
+ isAtStart: state2.isAtStart,
2971
+ positionAtIndex: (index) => state2.positions.get(getId(state2, index)),
2972
+ positions: state2.positions,
2973
+ scroll: state2.scroll,
2974
+ scrollLength: state2.scrollLength,
2975
+ sizeAtIndex: (index) => state2.sizesKnown.get(getId(state2, index)),
2976
+ sizes: state2.sizesKnown,
2977
+ start: state2.startNoBuffer,
2978
+ startBuffered: state2.startBuffered
2979
+ } : {};
2980
+ },
2981
+ scrollIndexIntoView,
2982
+ scrollItemIntoView: ({ item, ...props2 }) => {
2983
+ const data = refState.current.props.data;
2984
+ const index = data.indexOf(item);
2985
+ if (index !== -1) {
2986
+ scrollIndexIntoView({ index, ...props2 });
2439
2987
  }
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(
2457
- forwardedRef,
2458
- () => {
2459
- const scrollIndexIntoView = (options) => {
2460
- if (refState.current) {
2461
- const { index, ...rest2 } = options;
2462
- const { startNoBuffer, endNoBuffer } = refState.current;
2463
- if (index < startNoBuffer || index > endNoBuffer) {
2464
- const viewPosition = index < startNoBuffer ? 0 : 1;
2465
- scrollToIndex({
2466
- ...rest2,
2467
- viewPosition,
2468
- index
2469
- });
2470
- }
2988
+ },
2989
+ scrollToEnd: (options) => {
2990
+ const data = refState.current.props.data;
2991
+ const stylePaddingBottom = refState.current.props.stylePaddingBottom;
2992
+ const index = data.length - 1;
2993
+ if (index !== -1) {
2994
+ const paddingBottom = stylePaddingBottom || 0;
2995
+ const footerSize = peek$(ctx, "footerSize") || 0;
2996
+ scrollToIndex(ctx, state, {
2997
+ index,
2998
+ viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
2999
+ viewPosition: 1,
3000
+ ...options
3001
+ });
2471
3002
  }
2472
- };
2473
- return {
2474
- flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
2475
- getNativeScrollRef: () => refScroller.current,
2476
- getScrollableNode: () => refScroller.current.getScrollableNode(),
2477
- getScrollResponder: () => refScroller.current.getScrollResponder(),
2478
- 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))
2492
- } : {};
2493
- },
2494
- scrollIndexIntoView,
2495
- scrollItemIntoView: ({ item, ...props2 }) => {
2496
- const { data } = refState.current;
2497
- const index = data.indexOf(item);
2498
- if (index !== -1) {
2499
- scrollIndexIntoView({ index, ...props2 });
2500
- }
2501
- },
2502
- scrollToIndex,
2503
- scrollToItem: ({ item, ...props2 }) => {
2504
- const { data } = refState.current;
2505
- const index = data.indexOf(item);
2506
- if (index !== -1) {
2507
- scrollToIndex({ index, ...props2 });
2508
- }
2509
- },
2510
- scrollToOffset: (params) => scrollTo(params),
2511
- scrollToEnd: (options) => {
2512
- const { data, stylePaddingBottom } = refState.current;
2513
- const index = data.length - 1;
2514
- if (index !== -1) {
2515
- const paddingBottom = stylePaddingBottom || 0;
2516
- const footerSize = peek$(ctx, "footerSize") || 0;
2517
- scrollToIndex({ index, viewPosition: 1, viewOffset: -paddingBottom - footerSize, ...options });
2518
- }
3003
+ },
3004
+ scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3005
+ scrollToItem: ({ item, ...props2 }) => {
3006
+ const data = refState.current.props.data;
3007
+ const index = data.indexOf(item);
3008
+ if (index !== -1) {
3009
+ scrollToIndex(ctx, state, { index, ...props2 });
2519
3010
  }
2520
- };
2521
- },
2522
- []
2523
- );
3011
+ },
3012
+ scrollToOffset: (params) => scrollTo(state, params),
3013
+ setScrollProcessingEnabled: (enabled) => {
3014
+ refState.current.scrollProcessingEnabled = enabled;
3015
+ },
3016
+ setVisibleContentAnchorOffset: (value) => {
3017
+ const val = typeof value === "function" ? value(peek$(ctx, "scrollAdjustUserOffset") || 0) : value;
3018
+ set$(ctx, "scrollAdjustUserOffset", val);
3019
+ }
3020
+ };
3021
+ }, []);
2524
3022
  if (reactNative.Platform.OS === "web") {
2525
- React2.useEffect(() => {
2526
- var _a;
3023
+ React3.useEffect(() => {
2527
3024
  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);
3025
+ scrollTo(state, { animated: false, offset: initialContentOffset });
2534
3026
  }
2535
3027
  }, []);
2536
3028
  }
2537
- return /* @__PURE__ */ React2__namespace.createElement(React2__namespace.Fragment, null, /* @__PURE__ */ React2__namespace.createElement(
3029
+ const fns = React3.useMemo(
3030
+ () => ({
3031
+ getRenderedItem: (key) => getRenderedItem(ctx, state, key),
3032
+ onScroll: (event) => onScroll(ctx, state, event),
3033
+ updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj)
3034
+ }),
3035
+ []
3036
+ );
3037
+ const animatedScrollHandler = React3.useMemo(() => {
3038
+ const onScrollFn = scrollEventThrottle && scrollEventThrottle > 0 ? throttledOnScroll(fns.onScroll, scrollEventThrottle) : fns.onScroll;
3039
+ if (stickyIndices == null ? void 0 : stickyIndices.length) {
3040
+ const { animatedScrollY } = ctx;
3041
+ return reactNative.Animated.event([{ nativeEvent: { contentOffset: { [horizontal ? "x" : "y"]: animatedScrollY } } }], {
3042
+ listener: onScrollFn,
3043
+ useNativeDriver: true
3044
+ });
3045
+ }
3046
+ return onScrollFn;
3047
+ }, [stickyIndices == null ? void 0 : stickyIndices.length, horizontal, scrollEventThrottle]);
3048
+ return /* @__PURE__ */ React3__namespace.createElement(React3__namespace.Fragment, null, /* @__PURE__ */ React3__namespace.createElement(
2538
3049
  ListComponent,
2539
3050
  {
2540
3051
  ...rest,
3052
+ alignItemsAtEnd,
3053
+ canRender,
3054
+ contentContainerStyle,
3055
+ getRenderedItem: fns.getRenderedItem,
2541
3056
  horizontal,
2542
- refScrollView: combinedRef,
2543
3057
  initialContentOffset,
2544
- getRenderedItem,
2545
- updateItemSize,
2546
- handleScroll,
3058
+ ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
3059
+ ListHeaderComponent,
3060
+ maintainVisibleContentPosition,
3061
+ onLayout,
3062
+ onLayoutHeader,
2547
3063
  onMomentumScrollEnd: (event) => {
2548
- var _a;
2549
- const scrollingTo = (_a = refState.current) == null ? void 0 : _a.scrollingTo;
2550
- if (scrollingTo !== void 0) {
3064
+ if (IsNewArchitecture) {
2551
3065
  requestAnimationFrame(() => {
2552
- scrollTo({ ...scrollingTo, animated: false });
2553
- refState.current.scrollingTo = void 0;
2554
- requestAnimationFrame(() => {
2555
- refState.current.scrollAdjustHandler.setDisableAdjust(false);
2556
- });
3066
+ finishScrollTo(refState.current);
2557
3067
  });
2558
- }
2559
- const wasPaused = refState.current.scrollAdjustHandler.unPauseAdjust();
2560
- if (wasPaused) {
2561
- refState.current.scrollVelocity = 0;
2562
- refState.current.scrollHistory = [];
2563
- calculateItemsInView();
3068
+ } else {
3069
+ setTimeout(() => {
3070
+ finishScrollTo(refState.current);
3071
+ }, 1e3);
2564
3072
  }
2565
3073
  if (onMomentumScrollEnd) {
2566
3074
  onMomentumScrollEnd(event);
2567
3075
  }
2568
3076
  },
2569
- onLayout,
3077
+ onScroll: animatedScrollHandler,
2570
3078
  recycleItems,
2571
- alignItemsAtEnd,
2572
- ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
2573
- ListHeaderComponent,
2574
- maintainVisibleContentPosition,
2575
- scrollEventThrottle: reactNative.Platform.OS === "web" ? 16 : void 0,
2576
- waitForInitialLayout,
2577
- refreshControl: refreshControl ? stylePaddingTopState > 0 ? React2__namespace.cloneElement(refreshControl, {
3079
+ refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3__namespace.cloneElement(refreshControl, {
2578
3080
  progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
2579
- }) : refreshControl : onRefresh && /* @__PURE__ */ React2__namespace.createElement(
3081
+ }) : refreshControl : onRefresh && /* @__PURE__ */ React3__namespace.createElement(
2580
3082
  reactNative.RefreshControl,
2581
3083
  {
2582
- refreshing: !!refreshing,
2583
3084
  onRefresh,
2584
- progressViewOffset: (progressViewOffset || 0) + stylePaddingTopState
3085
+ progressViewOffset: (progressViewOffset || 0) + stylePaddingTopState,
3086
+ refreshing: !!refreshing
2585
3087
  }
2586
3088
  ),
3089
+ refScrollView: combinedRef,
3090
+ scrollAdjustHandler: (_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler,
3091
+ scrollEventThrottle: reactNative.Platform.OS === "web" ? 16 : void 0,
3092
+ snapToIndices,
3093
+ stickyIndices,
2587
3094
  style,
2588
- contentContainerStyle
3095
+ updateItemSize: fns.updateItemSize,
3096
+ waitForInitialLayout
2589
3097
  }
2590
- ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React2__namespace.createElement(DebugView, { state: refState.current }));
2591
- });
2592
- var typedForwardRef2 = React2.forwardRef;
2593
- var renderItem = ({ item }) => item;
2594
- var LazyLegendList = typedForwardRef2(function LazyLegendList2(props, forwardedRef) {
2595
- 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);
2598
- return (
2599
- // @ts-expect-error TODO: Fix this type
2600
- /* @__PURE__ */ React2__namespace.createElement(LegendListComponent, { ...rest, data, renderItem, ref: forwardedRef })
2601
- );
3098
+ ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React3__namespace.createElement(DebugView, { state: refState.current }));
2602
3099
  });
2603
3100
 
2604
- exports.LazyLegendList = LazyLegendList;
2605
3101
  exports.LegendList = LegendList;
2606
3102
  exports.useIsLastItem = useIsLastItem;
2607
3103
  exports.useListScrollSize = useListScrollSize;
2608
3104
  exports.useRecyclingEffect = useRecyclingEffect;
2609
3105
  exports.useRecyclingState = useRecyclingState;
3106
+ exports.useSyncLayout = useSyncLayout;
2610
3107
  exports.useViewability = useViewability;
2611
3108
  exports.useViewabilityAmount = useViewabilityAmount;