@legendapp/list 2.0.0-next.1 → 2.0.0-next.11

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