@legendapp/list 2.1.0-beta.0 → 2.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.mjs CHANGED
@@ -1,14 +1,14 @@
1
- import * as React4 from 'react';
2
- import React4__default, { forwardRef, useReducer, useEffect, createContext, useRef, useState, useMemo, useImperativeHandle, useCallback, useLayoutEffect, memo, useContext } from 'react';
1
+ import * as React3 from 'react';
2
+ import React3__default, { forwardRef, useReducer, useEffect, createContext, useRef, useState, useMemo, useCallback, useImperativeHandle, useLayoutEffect, memo, useContext } from 'react';
3
3
  import { useSyncExternalStore } from 'use-sync-external-store/shim';
4
4
  import { unstable_batchedUpdates } from 'react-dom';
5
5
 
6
6
  // src/components/LegendList.tsx
7
- var AnimatedView = forwardRef(function AnimatedView2(props, ref) {
8
- return /* @__PURE__ */ React4.createElement("div", { ref, ...props });
7
+ forwardRef(function AnimatedView2(props, ref) {
8
+ return /* @__PURE__ */ React3.createElement("div", { ref, ...props });
9
9
  });
10
10
  var View = forwardRef(function View2(props, ref) {
11
- return /* @__PURE__ */ React4.createElement("div", { ref, ...props });
11
+ return /* @__PURE__ */ React3.createElement("div", { ref, ...props });
12
12
  });
13
13
  var Text = View;
14
14
 
@@ -16,9 +16,9 @@ var Text = View;
16
16
  var createAnimatedValue = (value) => value;
17
17
 
18
18
  // src/state/state.tsx
19
- var ContextState = React4.createContext(null);
19
+ var ContextState = React3.createContext(null);
20
20
  function StateProvider({ children }) {
21
- const [value] = React4.useState(() => ({
21
+ const [value] = React3.useState(() => ({
22
22
  animatedScrollY: createAnimatedValue(0),
23
23
  columnWrapperStyle: void 0,
24
24
  internalState: void 0,
@@ -37,10 +37,10 @@ function StateProvider({ children }) {
37
37
  ]),
38
38
  viewRefs: /* @__PURE__ */ new Map()
39
39
  }));
40
- return /* @__PURE__ */ React4.createElement(ContextState.Provider, { value }, children);
40
+ return /* @__PURE__ */ React3.createElement(ContextState.Provider, { value }, children);
41
41
  }
42
42
  function useStateContext() {
43
- return React4.useContext(ContextState);
43
+ return React3.useContext(ContextState);
44
44
  }
45
45
  function createSelectorFunctionsArr(ctx, signalNames) {
46
46
  let lastValues = [];
@@ -110,23 +110,23 @@ function getContentSize(ctx) {
110
110
  return headerSize + footerSize + totalSize + stylePaddingTop;
111
111
  }
112
112
  function useArr$(signalNames) {
113
- const ctx = React4.useContext(ContextState);
114
- const { subscribe, get } = React4.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
113
+ const ctx = React3.useContext(ContextState);
114
+ const { subscribe, get } = React3.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
115
115
  const value = useSyncExternalStore(subscribe, get);
116
116
  return value;
117
117
  }
118
118
  function useSelector$(signalName, selector) {
119
- const ctx = React4.useContext(ContextState);
120
- const { subscribe, get } = React4.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
119
+ const ctx = React3.useContext(ContextState);
120
+ const { subscribe, get } = React3.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
121
121
  const value = useSyncExternalStore(subscribe, () => selector(get()[0]));
122
122
  return value;
123
123
  }
124
124
 
125
125
  // src/components/DebugView.tsx
126
126
  var DebugRow = ({ children }) => {
127
- return /* @__PURE__ */ React4.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
127
+ return /* @__PURE__ */ React3.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
128
128
  };
129
- var DebugView = React4.memo(function DebugView2({ state }) {
129
+ var DebugView = React3.memo(function DebugView2({ state }) {
130
130
  const ctx = useStateContext();
131
131
  const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, _numContainers = 0, _numContainersPooled = 0] = useArr$([
132
132
  "totalSize",
@@ -141,7 +141,7 @@ var DebugView = React4.memo(function DebugView2({ state }) {
141
141
  useInterval(() => {
142
142
  forceUpdate();
143
143
  }, 100);
144
- return /* @__PURE__ */ React4.createElement(
144
+ return /* @__PURE__ */ React3.createElement(
145
145
  View,
146
146
  {
147
147
  pointerEvents: "none",
@@ -157,12 +157,12 @@ var DebugView = React4.memo(function DebugView2({ state }) {
157
157
  top: 0
158
158
  }
159
159
  },
160
- /* @__PURE__ */ React4.createElement(DebugRow, null, /* @__PURE__ */ React4.createElement(Text, null, "TotalSize:"), /* @__PURE__ */ React4.createElement(Text, null, totalSize.toFixed(2))),
161
- /* @__PURE__ */ React4.createElement(DebugRow, null, /* @__PURE__ */ React4.createElement(Text, null, "ContentSize:"), /* @__PURE__ */ React4.createElement(Text, null, contentSize.toFixed(2))),
162
- /* @__PURE__ */ React4.createElement(DebugRow, null, /* @__PURE__ */ React4.createElement(Text, null, "At end:"), /* @__PURE__ */ React4.createElement(Text, null, String(state.isAtEnd))),
163
- /* @__PURE__ */ React4.createElement(DebugRow, null, /* @__PURE__ */ React4.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React4.createElement(Text, null, scrollAdjust.toFixed(2))),
164
- /* @__PURE__ */ React4.createElement(DebugRow, null, /* @__PURE__ */ React4.createElement(Text, null, "RawScroll: "), /* @__PURE__ */ React4.createElement(Text, null, rawScroll.toFixed(2))),
165
- /* @__PURE__ */ React4.createElement(DebugRow, null, /* @__PURE__ */ React4.createElement(Text, null, "ComputedScroll: "), /* @__PURE__ */ React4.createElement(Text, null, scroll.toFixed(2)))
160
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "TotalSize:"), /* @__PURE__ */ React3.createElement(Text, null, totalSize.toFixed(2))),
161
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "ContentSize:"), /* @__PURE__ */ React3.createElement(Text, null, contentSize.toFixed(2))),
162
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "At end:"), /* @__PURE__ */ React3.createElement(Text, null, String(state.isAtEnd))),
163
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React3.createElement(Text, null, scrollAdjust.toFixed(2))),
164
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "RawScroll: "), /* @__PURE__ */ React3.createElement(Text, null, rawScroll.toFixed(2))),
165
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "ComputedScroll: "), /* @__PURE__ */ React3.createElement(Text, null, scroll.toFixed(2)))
166
166
  );
167
167
  });
168
168
  function useInterval(callback, delay) {
@@ -171,90 +171,19 @@ function useInterval(callback, delay) {
171
171
  return () => clearInterval(interval);
172
172
  }, [delay]);
173
173
  }
174
- var globalResizeObserver = null;
175
- function getGlobalResizeObserver() {
176
- if (!globalResizeObserver) {
177
- globalResizeObserver = new ResizeObserver((entries) => {
178
- for (const entry of entries) {
179
- const callbacks = callbackMap.get(entry.target);
180
- if (callbacks) {
181
- for (const callback of callbacks) {
182
- callback(entry);
183
- }
184
- }
185
- }
186
- });
187
- }
188
- return globalResizeObserver;
189
- }
190
- var callbackMap = /* @__PURE__ */ new WeakMap();
191
- function useResizeObserver(element, callback) {
192
- useEffect(() => {
193
- if (!element) return;
194
- const observer = getGlobalResizeObserver();
195
- let callbacks = callbackMap.get(element);
196
- if (!callbacks) {
197
- callbacks = /* @__PURE__ */ new Set();
198
- callbackMap.set(element, callbacks);
199
- observer.observe(element);
200
- }
201
- callbacks.add(callback);
202
- return () => {
203
- const callbacks2 = callbackMap.get(element);
204
- if (callbacks2) {
205
- callbacks2.delete(callback);
206
- if (callbacks2.size === 0) {
207
- callbackMap.delete(element);
208
- observer.unobserve(element);
209
- }
210
- }
211
- };
212
- }, [element, callback]);
213
- }
214
-
215
- // src/hooks/useSyncLayout.tsx
216
- function useSyncLayout({
217
- ref,
218
- onLayoutChange
219
- }) {
220
- var _a, _b;
221
- useResizeObserver(
222
- ((_b = (_a = ref.current) == null ? void 0 : _a.getScrollableNode) == null ? void 0 : _b.call(_a)) || ref.current,
223
- useCallback(
224
- (entry) => {
225
- onLayoutChange(entry.contentRect, false);
226
- },
227
- [onLayoutChange]
228
- )
229
- );
230
- useLayoutEffect(() => {
231
- if (ref.current) {
232
- const rect = ref.current.getBoundingClientRect();
233
- onLayoutChange(
234
- {
235
- height: rect.height,
236
- width: rect.width,
237
- x: rect.left,
238
- y: rect.top
239
- },
240
- true
241
- );
242
- }
243
- }, []);
244
- return {};
245
- }
246
174
 
247
- // src/components/LayoutView.tsx
248
- var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
249
- const ref = refView != null ? refView : useRef();
250
- useSyncLayout({ onLayoutChange, ref });
251
- return /* @__PURE__ */ React4.createElement("div", { ...rest, ref }, children);
252
- };
175
+ // src/utils/devEnvironment.ts
176
+ var metroDev = typeof __DEV__ !== "undefined" ? __DEV__ : void 0;
177
+ var _a;
178
+ var envMode = typeof process !== "undefined" && typeof process.env === "object" && process.env ? (_a = process.env.NODE_ENV) != null ? _a : process.env.MODE : void 0;
179
+ var processDev = typeof envMode === "string" ? envMode.toLowerCase() !== "production" : void 0;
180
+ var _a2;
181
+ var IS_DEV = (_a2 = metroDev != null ? metroDev : processDev) != null ? _a2 : false;
253
182
 
254
183
  // src/constants.ts
255
184
  var POSITION_OUT_OF_VIEW = -1e7;
256
- var ENABLE_DEVMODE = __DEV__ && false;
257
- var ENABLE_DEBUG_VIEW = __DEV__ && false;
185
+ var ENABLE_DEVMODE = IS_DEV && false;
186
+ var ENABLE_DEBUG_VIEW = IS_DEV && false;
258
187
  var typedForwardRef = forwardRef;
259
188
  var typedMemo = memo;
260
189
 
@@ -269,7 +198,7 @@ var PositionViewState = typedMemo(function PositionView({
269
198
  const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
270
199
  const base = Array.isArray(style) ? Object.assign({}, ...style) : style;
271
200
  const combinedStyle = horizontal ? { ...base, left: position } : { ...base, top: position };
272
- return /* @__PURE__ */ React4.createElement(LayoutView, { refView, style: combinedStyle, ...rest });
201
+ return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: combinedStyle, ...rest });
273
202
  });
274
203
  var PositionViewSticky = typedMemo(function PositionViewSticky2({
275
204
  id,
@@ -279,8 +208,8 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
279
208
  index,
280
209
  ...rest
281
210
  }) {
282
- const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
283
- const viewStyle = React4.useMemo(() => {
211
+ const [position = POSITION_OUT_OF_VIEW, _headerSize] = useArr$([`containerPosition${id}`, "headerSize"]);
212
+ const viewStyle = React3.useMemo(() => {
284
213
  const base = Array.isArray(style) ? Object.assign({}, ...style) : style;
285
214
  const axisStyle = horizontal ? { transform: `translateX(${position}px)` } : { top: position };
286
215
  return {
@@ -289,23 +218,12 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
289
218
  ...axisStyle
290
219
  };
291
220
  }, [style, position, horizontal, index]);
292
- return /* @__PURE__ */ React4.createElement(LayoutView, { refView, style: viewStyle, ...rest });
221
+ return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: viewStyle, ...rest });
293
222
  });
294
223
  var PositionView2 = PositionViewState;
295
- function Separator({ ItemSeparatorComponent, itemKey, leadingItem }) {
296
- const [lastItemKeys] = useArr$(["lastItemKeys"]);
297
- const isALastItem = lastItemKeys.includes(itemKey);
298
- return isALastItem ? null : /* @__PURE__ */ React4.createElement(ItemSeparatorComponent, { leadingItem });
299
- }
300
224
 
301
225
  // src/constants-platform.ts
302
226
  var IsNewArchitecture = true;
303
-
304
- // src/platform/Platform.ts
305
- var Platform = {
306
- // Widen the type to avoid unreachable-branch lints in cross-platform code that compares against other OSes
307
- OS: "web"
308
- };
309
227
  var symbolFirst = Symbol();
310
228
  function useInit(cb) {
311
229
  const refValue = useRef(symbolFirst);
@@ -324,7 +242,7 @@ function isArray(obj) {
324
242
  }
325
243
  var warned = /* @__PURE__ */ new Set();
326
244
  function warnDevOnce(id, text) {
327
- if (__DEV__ && !warned.has(id)) {
245
+ if (IS_DEV && !warned.has(id)) {
328
246
  warned.add(id);
329
247
  console.warn(`[legend-list] ${text}`);
330
248
  }
@@ -339,8 +257,8 @@ function comparatorDefault(a, b) {
339
257
  return a - b;
340
258
  }
341
259
  function getPadding(s, type) {
342
- var _a, _b, _c;
343
- return (_c = (_b = (_a = s[`padding${type}`]) != null ? _a : s.paddingVertical) != null ? _b : s.padding) != null ? _c : 0;
260
+ var _a3, _b, _c;
261
+ return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : s.paddingVertical) != null ? _b : s.padding) != null ? _c : 0;
344
262
  }
345
263
  function extractPadding(style, contentContainerStyle, type) {
346
264
  return getPadding(style, type) + getPadding(contentContainerStyle, type);
@@ -442,13 +360,103 @@ function useListScrollSize() {
442
360
  const [scrollSize] = useArr$(["scrollSize"]);
443
361
  return scrollSize;
444
362
  }
445
- function useSyncLayout2() {
363
+ function useSyncLayout() {
446
364
  {
447
365
  const { triggerLayout: syncLayout } = useContext(ContextContainer);
448
366
  return syncLayout;
449
367
  }
450
368
  }
451
369
 
370
+ // src/components/Separator.tsx
371
+ function Separator({ ItemSeparatorComponent, leadingItem }) {
372
+ const isLastItem = useIsLastItem();
373
+ return isLastItem ? null : /* @__PURE__ */ React3.createElement(ItemSeparatorComponent, { leadingItem });
374
+ }
375
+
376
+ // src/hooks/createResizeObserver.ts
377
+ var globalResizeObserver = null;
378
+ function getGlobalResizeObserver() {
379
+ if (!globalResizeObserver) {
380
+ globalResizeObserver = new ResizeObserver((entries) => {
381
+ for (const entry of entries) {
382
+ const callbacks = callbackMap.get(entry.target);
383
+ if (callbacks) {
384
+ for (const callback of callbacks) {
385
+ callback(entry);
386
+ }
387
+ }
388
+ }
389
+ });
390
+ }
391
+ return globalResizeObserver;
392
+ }
393
+ var callbackMap = /* @__PURE__ */ new WeakMap();
394
+ function createResizeObserver(element, callback) {
395
+ if (!element) {
396
+ return () => {
397
+ };
398
+ }
399
+ const observer = getGlobalResizeObserver();
400
+ let callbacks = callbackMap.get(element);
401
+ if (!callbacks) {
402
+ callbacks = /* @__PURE__ */ new Set();
403
+ callbackMap.set(element, callbacks);
404
+ observer.observe(element);
405
+ }
406
+ callbacks.add(callback);
407
+ return () => {
408
+ const callbacks2 = callbackMap.get(element);
409
+ if (callbacks2) {
410
+ callbacks2.delete(callback);
411
+ if (callbacks2.size === 0) {
412
+ callbackMap.delete(element);
413
+ observer.unobserve(element);
414
+ }
415
+ }
416
+ };
417
+ }
418
+
419
+ // src/hooks/useOnLayoutSync.tsx
420
+ function useOnLayoutSync({
421
+ ref,
422
+ onLayoutProp,
423
+ onLayoutChange
424
+ }, deps) {
425
+ useLayoutEffect(() => {
426
+ var _a3, _b;
427
+ const current = ref.current;
428
+ const scrollableNode = (_b = (_a3 = current == null ? void 0 : current.getScrollableNode) == null ? void 0 : _a3.call(current)) != null ? _b : null;
429
+ const element = scrollableNode || current;
430
+ if (!element || !(element instanceof HTMLElement)) {
431
+ return;
432
+ }
433
+ const emit = (layout, fromLayoutEffect) => {
434
+ if (layout.height === 0 && layout.width === 0) {
435
+ return;
436
+ }
437
+ onLayoutChange(layout, fromLayoutEffect);
438
+ onLayoutProp == null ? void 0 : onLayoutProp({ nativeEvent: { layout } });
439
+ };
440
+ const rect = element.getBoundingClientRect();
441
+ emit(toLayout(rect), true);
442
+ return createResizeObserver(element, (entry) => {
443
+ var _a4;
444
+ const target = entry.target instanceof HTMLElement ? entry.target : void 0;
445
+ const rect2 = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
446
+ emit(toLayout(rect2), false);
447
+ });
448
+ }, deps);
449
+ return {};
450
+ }
451
+ function toLayout(rect) {
452
+ return {
453
+ height: rect.height,
454
+ width: rect.width,
455
+ x: rect.left,
456
+ y: rect.top
457
+ };
458
+ }
459
+
452
460
  // src/components/Container.tsx
453
461
  var Container = typedMemo(function Container2({
454
462
  id,
@@ -459,37 +467,42 @@ var Container = typedMemo(function Container2({
459
467
  ItemSeparatorComponent
460
468
  }) {
461
469
  const ctx = useStateContext();
462
- const { columnWrapperStyle } = ctx;
463
- const [column = 0, data, itemKey, numColumns, extraData, isSticky] = useArr$([
470
+ const { columnWrapperStyle, animatedScrollY } = ctx;
471
+ const [column = 0, data, itemKey, numColumns, extraData, isSticky, stickyOffset] = useArr$([
464
472
  `containerColumn${id}`,
465
473
  `containerItemData${id}`,
466
474
  `containerItemKey${id}`,
467
475
  "numColumns",
468
476
  "extraData",
469
- `containerSticky${id}`
477
+ `containerSticky${id}`,
478
+ `containerStickyOffset${id}`
470
479
  ]);
471
- const refLastSize = useRef();
480
+ const itemLayoutRef = useRef({
481
+ horizontal,
482
+ itemKey,
483
+ updateItemSize: updateItemSize2
484
+ });
485
+ itemLayoutRef.current.horizontal = horizontal;
486
+ itemLayoutRef.current.itemKey = itemKey;
487
+ itemLayoutRef.current.updateItemSize = updateItemSize2;
472
488
  const ref = useRef(null);
473
- const [_, forceLayoutRender] = useState(0);
489
+ const [layoutRenderCount, forceLayoutRender] = useState(0);
474
490
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
475
491
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
492
+ const didLayoutRef = useRef(false);
476
493
  const style = useMemo(() => {
477
494
  let paddingStyles;
478
495
  if (columnWrapperStyle) {
479
496
  const { columnGap, rowGap, gap } = columnWrapperStyle;
480
497
  if (horizontal) {
481
- const py = numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0;
482
498
  paddingStyles = {
483
- paddingBottom: py,
484
499
  paddingRight: columnGap || gap || void 0,
485
- paddingTop: py
500
+ paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
486
501
  };
487
502
  } else {
488
- const px = numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0;
489
503
  paddingStyles = {
490
504
  paddingBottom: rowGap || gap || void 0,
491
- paddingLeft: px,
492
- paddingRight: px
505
+ paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
493
506
  };
494
507
  }
495
508
  }
@@ -503,7 +516,7 @@ var Container = typedMemo(function Container2({
503
516
  } : {
504
517
  left: otherAxisPos,
505
518
  position: "absolute",
506
- right: numColumns > 1 ? void 0 : 0,
519
+ right: numColumns > 1 ? null : 0,
507
520
  top: 0,
508
521
  width: otherAxisSize,
509
522
  ...paddingStyles || {}
@@ -526,49 +539,64 @@ var Container = typedMemo(function Container2({
526
539
  value: data
527
540
  };
528
541
  }, [id, itemKey, index, data]);
529
- const onLayoutChange = (rectangle) => {
530
- if (!isNullOrUndefined(itemKey)) {
531
- let layout = rectangle;
532
- layout[horizontal ? "width" : "height"];
533
- const doUpdate = () => {
534
- refLastSize.current = { height: layout.height, width: layout.width };
535
- updateItemSize2(itemKey, layout);
536
- };
537
- {
538
- doUpdate();
539
- }
542
+ const onLayoutChange = useCallback((rectangle) => {
543
+ const {
544
+ horizontal: currentHorizontal,
545
+ itemKey: currentItemKey,
546
+ updateItemSize: updateItemSizeFn
547
+ } = itemLayoutRef.current;
548
+ if (isNullOrUndefined(currentItemKey)) {
549
+ return;
540
550
  }
541
- };
551
+ didLayoutRef.current = true;
552
+ let layout = rectangle;
553
+ Math.floor(rectangle[currentHorizontal ? "width" : "height"] * 8) / 8;
554
+ const doUpdate = () => {
555
+ itemLayoutRef.current.lastSize = { height: layout.height, width: layout.width };
556
+ updateItemSizeFn(currentItemKey, layout);
557
+ didLayoutRef.current = true;
558
+ };
559
+ {
560
+ doUpdate();
561
+ }
562
+ }, []);
563
+ const { onLayout } = useOnLayoutSync(
564
+ {
565
+ onLayoutChange,
566
+ ref
567
+ },
568
+ [itemKey, layoutRenderCount]
569
+ );
542
570
  const PositionComponent = isSticky ? PositionViewSticky : PositionView2;
543
- return /* @__PURE__ */ React4.createElement(ContextContainer.Provider, { value: contextValue }, /* @__PURE__ */ React4.createElement(
571
+ return /* @__PURE__ */ React3.createElement(
544
572
  PositionComponent,
545
573
  {
574
+ animatedScrollY: isSticky ? animatedScrollY : void 0,
546
575
  horizontal,
547
576
  id,
548
577
  index,
549
578
  key: recycleItems ? void 0 : itemKey,
550
- onLayoutChange,
579
+ onLayout,
551
580
  refView: ref,
581
+ stickyOffset: isSticky ? stickyOffset : void 0,
552
582
  style
553
583
  },
554
- renderedItem,
555
- renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React4.createElement(
556
- Separator,
557
- {
558
- ItemSeparatorComponent,
559
- itemKey,
560
- leadingItem: renderedItemInfo.item
561
- }
562
- )
563
- ));
584
+ /* @__PURE__ */ React3.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React3.createElement(Separator, { ItemSeparatorComponent, leadingItem: renderedItemInfo.item }))
585
+ );
564
586
  });
565
587
 
588
+ // src/platform/Platform.ts
589
+ var Platform = {
590
+ // Widen the type to avoid unreachable-branch lints in cross-platform code that compares against other OSes
591
+ OS: "web"
592
+ };
593
+
566
594
  // src/utils/reordering.ts
567
595
  var mapFn = (element) => {
568
596
  const indexStr = element.getAttribute("index");
569
597
  return [element, indexStr === null ? null : parseInt(indexStr)];
570
598
  };
571
- function sortDOMElementsPatience(container) {
599
+ function sortDOMElements(container) {
572
600
  const elements = Array.from(container.children);
573
601
  if (elements.length <= 1) return elements;
574
602
  const items = elements.map(mapFn);
@@ -659,7 +687,7 @@ function useDOMOrder(ref) {
659
687
  debounceRef.current = setTimeout(() => {
660
688
  const parent = ref.current;
661
689
  if (parent) {
662
- sortDOMElementsPatience(parent);
690
+ sortDOMElements(parent);
663
691
  }
664
692
  debounceRef.current = void 0;
665
693
  }, 500);
@@ -701,7 +729,7 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
701
729
  }
702
730
  }
703
731
  }
704
- return /* @__PURE__ */ React4.createElement("div", { ref, style }, children);
732
+ return /* @__PURE__ */ React3.createElement("div", { ref, style }, children);
705
733
  });
706
734
  var Containers = typedMemo(function Containers2({
707
735
  horizontal,
@@ -715,7 +743,7 @@ var Containers = typedMemo(function Containers2({
715
743
  const containers = [];
716
744
  for (let i = 0; i < numContainers; i++) {
717
745
  containers.push(
718
- /* @__PURE__ */ React4.createElement(
746
+ /* @__PURE__ */ React3.createElement(
719
747
  Container,
720
748
  {
721
749
  getRenderedItem: getRenderedItem2,
@@ -729,24 +757,40 @@ var Containers = typedMemo(function Containers2({
729
757
  )
730
758
  );
731
759
  }
732
- return /* @__PURE__ */ React4.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
733
- });
734
- var DevNumbers = __DEV__ && React4.memo(function DevNumbers2() {
735
- return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React4.createElement(
736
- View,
737
- {
738
- key: index,
739
- style: {
740
- height: 100,
741
- pointerEvents: "none",
742
- position: "absolute",
743
- top: index * 100,
744
- width: "100%"
745
- }
746
- },
747
- /* @__PURE__ */ React4.createElement(Text, { style: { color: "red" } }, index * 100)
748
- ));
760
+ return /* @__PURE__ */ React3.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
749
761
  });
762
+ function DevNumbers() {
763
+ return IS_DEV && React3.memo(function DevNumbers2() {
764
+ return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3.createElement(
765
+ "div",
766
+ {
767
+ key: index,
768
+ style: {
769
+ height: 100,
770
+ pointerEvents: "none",
771
+ position: "absolute",
772
+ top: index * 100,
773
+ width: "100%"
774
+ }
775
+ },
776
+ /* @__PURE__ */ React3.createElement("div", { style: { color: "red" } }, index * 100)
777
+ ));
778
+ });
779
+ }
780
+
781
+ // src/platform/StyleSheet.tsx
782
+ function flattenStyles(styles) {
783
+ if (Array.isArray(styles)) {
784
+ return Object.assign({}, ...styles.filter(Boolean));
785
+ }
786
+ return styles;
787
+ }
788
+ var StyleSheet = {
789
+ create: (styles) => styles,
790
+ flatten: (style) => flattenStyles(style)
791
+ };
792
+
793
+ // src/components/ListComponentScrollView.tsx
750
794
  var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
751
795
  children,
752
796
  style,
@@ -760,7 +804,6 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
760
804
  showsVerticalScrollIndicator = true,
761
805
  refreshControl,
762
806
  onLayout,
763
- ScrollComponent,
764
807
  ...props
765
808
  }, ref) {
766
809
  const scrollRef = useRef(null);
@@ -769,16 +812,15 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
769
812
  useImperativeHandle(ref, () => {
770
813
  const api = {
771
814
  getBoundingClientRect: () => {
772
- var _a;
773
- return (_a = scrollRef.current) == null ? void 0 : _a.getBoundingClientRect();
815
+ var _a3;
816
+ return (_a3 = scrollRef.current) == null ? void 0 : _a3.getBoundingClientRect();
774
817
  },
775
818
  getScrollableNode: () => scrollRef.current,
776
819
  getScrollResponder: () => scrollRef.current,
777
- scrollBy: (options) => {
820
+ scrollBy: (x, y) => {
778
821
  const el = scrollRef.current;
779
822
  if (!el) return;
780
- const { x = 0, y = 0, animated = true } = options;
781
- el.scrollBy({ behavior: animated ? "smooth" : "auto", left: x, top: y });
823
+ el.scrollBy(x, y);
782
824
  },
783
825
  scrollTo: (options) => {
784
826
  const el = scrollRef.current;
@@ -848,17 +890,21 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
848
890
  useLayoutEffect(() => {
849
891
  const element = scrollRef.current;
850
892
  if (!element) return;
851
- element.addEventListener("scroll", handleScroll, { passive: true });
893
+ element.addEventListener("scroll", handleScroll);
852
894
  return () => {
853
895
  element.removeEventListener("scroll", handleScroll);
854
896
  };
855
897
  }, [handleScroll]);
856
- useLayoutEffect(() => {
857
- if (contentOffset && scrollRef.current) {
858
- scrollRef.current.scrollLeft = contentOffset.x || 0;
859
- scrollRef.current.scrollTop = contentOffset.y || 0;
860
- }
861
- }, [contentOffset]);
898
+ useEffect(() => {
899
+ const doScroll = () => {
900
+ if (contentOffset && scrollRef.current) {
901
+ scrollRef.current.scrollLeft = contentOffset.x || 0;
902
+ scrollRef.current.scrollTop = contentOffset.y || 0;
903
+ }
904
+ };
905
+ doScroll();
906
+ requestAnimationFrame(doScroll);
907
+ }, [contentOffset == null ? void 0 : contentOffset.x, contentOffset == null ? void 0 : contentOffset.y]);
862
908
  useLayoutEffect(() => {
863
909
  if (!onLayout || !scrollRef.current) return;
864
910
  const element = scrollRef.current;
@@ -890,17 +936,37 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
890
936
  // Ensure proper positioning context
891
937
  WebkitOverflowScrolling: "touch",
892
938
  // iOS momentum scrolling
893
- ...style
939
+ ...StyleSheet.flatten(style)
894
940
  };
895
941
  const contentStyle = {
896
942
  display: horizontal ? "flex" : "block",
897
943
  flexDirection: horizontal ? "row" : void 0,
898
944
  minHeight: horizontal ? void 0 : "100%",
899
945
  minWidth: horizontal ? "100%" : void 0,
900
- ...contentContainerStyle
946
+ ...StyleSheet.flatten(contentContainerStyle)
901
947
  };
902
- return /* @__PURE__ */ React4.createElement("div", { ref: scrollRef, style: scrollViewStyle, ...props }, refreshControl, /* @__PURE__ */ React4.createElement("div", { ref: contentRef, style: contentStyle }, children));
948
+ return /* @__PURE__ */ React3.createElement("div", { ref: scrollRef, style: scrollViewStyle, ...props }, refreshControl, /* @__PURE__ */ React3.createElement("div", { ref: contentRef, style: contentStyle }, children));
903
949
  });
950
+ function Padding() {
951
+ const [paddingTop] = useArr$(["alignItemsPaddingTop"]);
952
+ return /* @__PURE__ */ React3.createElement("div", { style: { paddingTop } });
953
+ }
954
+ function PaddingDevMode() {
955
+ const [paddingTop] = useArr$(["alignItemsPaddingTop"]);
956
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement("div", { style: { paddingTop } }), /* @__PURE__ */ React3.createElement(
957
+ "div",
958
+ {
959
+ style: {
960
+ backgroundColor: "green",
961
+ height: paddingTop,
962
+ left: 0,
963
+ position: "absolute",
964
+ right: 0,
965
+ top: 0
966
+ }
967
+ }
968
+ ));
969
+ }
904
970
  function useValueListener$(key, callback) {
905
971
  const ctx = useStateContext();
906
972
  useLayoutEffect(() => {
@@ -913,13 +979,13 @@ function useValueListener$(key, callback) {
913
979
  // src/components/ScrollAdjust.tsx
914
980
  function ScrollAdjust() {
915
981
  const ctx = useStateContext();
916
- const lastScrollOffsetRef = React4.useRef(0);
917
- const callback = React4.useCallback(() => {
918
- var _a;
982
+ const lastScrollOffsetRef = React3.useRef(0);
983
+ const callback = React3.useCallback(() => {
984
+ var _a3;
919
985
  const scrollAdjust = peek$(ctx, "scrollAdjust");
920
986
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
921
987
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
922
- const scrollView = (_a = ctx.internalState) == null ? void 0 : _a.refScroller.current;
988
+ const scrollView = (_a3 = ctx.internalState) == null ? void 0 : _a3.refScroller.current;
923
989
  if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
924
990
  const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
925
991
  if (scrollDelta !== 0) {
@@ -933,49 +999,26 @@ function ScrollAdjust() {
933
999
  useValueListener$("scrollAdjustUserOffset", callback);
934
1000
  return null;
935
1001
  }
936
-
937
- // src/components/SnapWrapper.tsx
938
1002
  function SnapWrapper({ ScrollComponent, ...props }) {
939
1003
  const [snapToOffsets] = useArr$(["snapToOffsets"]);
940
- return /* @__PURE__ */ React.createElement(ScrollComponent, { ...props, snapToOffsets });
941
- }
942
-
943
- // src/hooks/useValue$.ts
944
- function useValue$(key, params) {
945
- const [value] = useArr$([key]);
946
- return value;
1004
+ return /* @__PURE__ */ React3.createElement(ScrollComponent, { ...props, snapToOffsets });
947
1005
  }
1006
+ var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
1007
+ const ref = refView != null ? refView : useRef();
1008
+ useOnLayoutSync({ onLayoutChange, ref });
1009
+ return /* @__PURE__ */ React3.createElement("div", { ...rest, ref }, children);
1010
+ };
948
1011
 
949
1012
  // src/components/ListComponent.tsx
950
1013
  var getComponent = (Component) => {
951
- if (React4.isValidElement(Component)) {
1014
+ if (React3.isValidElement(Component)) {
952
1015
  return Component;
953
1016
  }
954
1017
  if (Component) {
955
- return /* @__PURE__ */ React4.createElement(Component, null);
1018
+ return /* @__PURE__ */ React3.createElement(Component, null);
956
1019
  }
957
1020
  return null;
958
1021
  };
959
- var Padding = () => {
960
- const animPaddingTop = useValue$("alignItemsPaddingTop");
961
- return /* @__PURE__ */ React4.createElement(AnimatedView, { style: { paddingTop: animPaddingTop } });
962
- };
963
- var PaddingDevMode = () => {
964
- const animPaddingTop = useValue$("alignItemsPaddingTop");
965
- return /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(AnimatedView, { style: { paddingTop: animPaddingTop } }), /* @__PURE__ */ React4.createElement(
966
- AnimatedView,
967
- {
968
- style: {
969
- backgroundColor: "green",
970
- height: animPaddingTop,
971
- left: 0,
972
- position: "absolute",
973
- right: 0,
974
- top: 0
975
- }
976
- }
977
- ));
978
- };
979
1022
  var ListComponent = typedMemo(function ListComponent2({
980
1023
  canRender,
981
1024
  style,
@@ -1005,12 +1048,11 @@ var ListComponent = typedMemo(function ListComponent2({
1005
1048
  ...rest
1006
1049
  }) {
1007
1050
  const ctx = useStateContext();
1008
- const refHeader = React4.useRef(null);
1009
1051
  const ScrollComponent = renderScrollComponent ? useMemo(
1010
- () => React4.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1052
+ () => React3.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1011
1053
  [renderScrollComponent]
1012
1054
  ) : ListComponentScrollView;
1013
- React4.useEffect(() => {
1055
+ React3.useEffect(() => {
1014
1056
  if (canRender) {
1015
1057
  setTimeout(() => {
1016
1058
  scrollAdjustHandler.setMounted();
@@ -1018,39 +1060,30 @@ var ListComponent = typedMemo(function ListComponent2({
1018
1060
  }
1019
1061
  }, [canRender]);
1020
1062
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
1021
- const contentContainerStyleWeb = useMemo(() => {
1022
- const base = contentContainerStyle || void 0;
1023
- if (!horizontal) return base;
1024
- if (base && base.height === "100%") return base;
1025
- return { ...base || {}, height: "100%" };
1026
- }, [horizontal, (contentContainerStyle == null ? void 0 : contentContainerStyle.height) === "100%" ? 1 : 0]);
1027
- return /* @__PURE__ */ React4.createElement(
1063
+ return /* @__PURE__ */ React3.createElement(
1028
1064
  SnapOrScroll,
1029
1065
  {
1030
1066
  ...rest,
1031
- contentContainerStyle: contentContainerStyleWeb,
1067
+ contentContainerStyle: [
1068
+ contentContainerStyle,
1069
+ horizontal ? {
1070
+ height: "100%"
1071
+ } : {}
1072
+ ],
1032
1073
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1033
1074
  horizontal,
1034
- maintainVisibleContentPosition: maintainVisibleContentPosition && !ListEmptyComponent ? { minIndexForVisible: 0 } : void 0,
1075
+ maintainVisibleContentPosition: maintainVisibleContentPosition ? { minIndexForVisible: 0 } : void 0,
1035
1076
  onLayout,
1036
1077
  onScroll: onScroll2,
1037
1078
  ref: refScrollView,
1038
1079
  ScrollComponent: snapToIndices ? ScrollComponent : void 0,
1039
1080
  style
1040
1081
  },
1041
- maintainVisibleContentPosition && /* @__PURE__ */ React4.createElement(ScrollAdjust, null),
1042
- ENABLE_DEVMODE ? /* @__PURE__ */ React4.createElement(PaddingDevMode, null) : /* @__PURE__ */ React4.createElement(Padding, null),
1043
- ListHeaderComponent && /* @__PURE__ */ React4.createElement(
1044
- LayoutView,
1045
- {
1046
- onLayoutChange: onLayoutHeader,
1047
- refView: refHeader,
1048
- style: ListHeaderComponentStyle
1049
- },
1050
- getComponent(ListHeaderComponent)
1051
- ),
1082
+ maintainVisibleContentPosition && /* @__PURE__ */ React3.createElement(ScrollAdjust, null),
1083
+ ENABLE_DEVMODE ? /* @__PURE__ */ React3.createElement(PaddingDevMode, null) : /* @__PURE__ */ React3.createElement(Padding, null),
1084
+ ListHeaderComponent && /* @__PURE__ */ React3.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
1052
1085
  ListEmptyComponent && getComponent(ListEmptyComponent),
1053
- canRender && /* @__PURE__ */ React4.createElement(
1086
+ canRender && !ListEmptyComponent && /* @__PURE__ */ React3.createElement(
1054
1087
  Containers,
1055
1088
  {
1056
1089
  getRenderedItem: getRenderedItem2,
@@ -1061,7 +1094,7 @@ var ListComponent = typedMemo(function ListComponent2({
1061
1094
  waitForInitialLayout
1062
1095
  }
1063
1096
  ),
1064
- ListFooterComponent && /* @__PURE__ */ React4.createElement(
1097
+ ListFooterComponent && /* @__PURE__ */ React3.createElement(
1065
1098
  LayoutView,
1066
1099
  {
1067
1100
  onLayoutChange: (layout) => {
@@ -1072,7 +1105,7 @@ var ListComponent = typedMemo(function ListComponent2({
1072
1105
  },
1073
1106
  getComponent(ListFooterComponent)
1074
1107
  ),
1075
- __DEV__ && ENABLE_DEVMODE && /* @__PURE__ */ React4.createElement(DevNumbers, null)
1108
+ IS_DEV && ENABLE_DEVMODE && /* @__PURE__ */ React3.createElement(DevNumbers, null)
1076
1109
  );
1077
1110
  });
1078
1111
 
@@ -1084,7 +1117,7 @@ function getId(state, index) {
1084
1117
  }
1085
1118
  const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
1086
1119
  const id = ret;
1087
- state.idCache.set(index, id);
1120
+ state.idCache[index] = id;
1088
1121
  return id;
1089
1122
  }
1090
1123
 
@@ -1107,7 +1140,7 @@ function calculateOffsetForIndex(ctx, state, index) {
1107
1140
 
1108
1141
  // src/utils/getItemSize.ts
1109
1142
  function getItemSize(state, key, index, data, useAverageSize) {
1110
- var _a, _b;
1143
+ var _a3, _b;
1111
1144
  const {
1112
1145
  sizesKnown,
1113
1146
  sizes,
@@ -1120,7 +1153,7 @@ function getItemSize(state, key, index, data, useAverageSize) {
1120
1153
  return sizeKnown;
1121
1154
  }
1122
1155
  let size;
1123
- const itemType = getItemType ? (_a = getItemType(data, index)) != null ? _a : "" : "";
1156
+ const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1124
1157
  if (getFixedItemSize) {
1125
1158
  size = getFixedItemSize(index, data, itemType);
1126
1159
  if (size !== void 0) {
@@ -1169,8 +1202,8 @@ var finishScrollTo = (state) => {
1169
1202
 
1170
1203
  // src/core/scrollTo.ts
1171
1204
  function scrollTo(state, params = {}) {
1172
- var _a;
1173
- const { animated, noScrollingTo } = params;
1205
+ var _a3;
1206
+ const { animated, noScrollingTo, isInitialScroll } = params;
1174
1207
  const {
1175
1208
  refScroller,
1176
1209
  props: { horizontal }
@@ -1181,14 +1214,21 @@ function scrollTo(state, params = {}) {
1181
1214
  state.scrollingTo = params;
1182
1215
  }
1183
1216
  state.scrollPending = offset;
1184
- (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
1185
- animated: !!animated,
1186
- x: horizontal ? offset : 0,
1187
- y: horizontal ? 0 : offset
1188
- });
1217
+ if (!params.isInitialScroll || Platform.OS === "android") {
1218
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1219
+ animated: !!animated,
1220
+ x: horizontal ? offset : 0,
1221
+ y: horizontal ? 0 : offset
1222
+ });
1223
+ }
1189
1224
  if (!animated) {
1190
1225
  state.scroll = offset;
1191
1226
  setTimeout(() => finishScrollTo(state), 100);
1227
+ if (isInitialScroll) {
1228
+ setTimeout(() => {
1229
+ state.initialScroll = void 0;
1230
+ }, 500);
1231
+ }
1192
1232
  }
1193
1233
  }
1194
1234
 
@@ -1277,7 +1317,16 @@ function prepareMVCP(ctx, state, dataChanged) {
1277
1317
  if (targetId !== void 0 && prevPosition !== void 0) {
1278
1318
  const newPosition = positions.get(targetId);
1279
1319
  if (newPosition !== void 0) {
1280
- positionDiff = newPosition - prevPosition;
1320
+ const totalSize = peek$(ctx, "totalSize");
1321
+ let diff = newPosition - prevPosition;
1322
+ if (diff !== 0 && state.scroll + state.scrollLength > totalSize) {
1323
+ if (diff > 0) {
1324
+ diff = Math.max(0, totalSize - state.scroll - state.scrollLength);
1325
+ } else {
1326
+ diff = 0;
1327
+ }
1328
+ }
1329
+ positionDiff = diff;
1281
1330
  }
1282
1331
  }
1283
1332
  if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
@@ -1286,6 +1335,68 @@ function prepareMVCP(ctx, state, dataChanged) {
1286
1335
  };
1287
1336
  }
1288
1337
 
1338
+ // src/core/prepareColumnStartState.ts
1339
+ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1340
+ var _a3;
1341
+ const numColumns = peek$(ctx, "numColumns");
1342
+ let rowStartIndex = startIndex;
1343
+ const columnAtStart = state.columns.get(state.idCache[startIndex]);
1344
+ if (columnAtStart !== 1) {
1345
+ rowStartIndex = findRowStartIndex(state, numColumns, startIndex);
1346
+ }
1347
+ let currentRowTop = 0;
1348
+ const curId = state.idCache[rowStartIndex];
1349
+ const column = state.columns.get(curId);
1350
+ if (rowStartIndex > 0) {
1351
+ const prevIndex = rowStartIndex - 1;
1352
+ const prevId = state.idCache[prevIndex];
1353
+ const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1354
+ const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1355
+ const prevRowHeight = calculateRowMaxSize(state, prevRowStart, prevIndex, useAverageSize);
1356
+ currentRowTop = prevPosition + prevRowHeight;
1357
+ }
1358
+ return {
1359
+ column,
1360
+ currentRowTop,
1361
+ startIndex: rowStartIndex
1362
+ };
1363
+ }
1364
+ function findRowStartIndex(state, numColumns, index) {
1365
+ if (numColumns <= 1) {
1366
+ return Math.max(0, index);
1367
+ }
1368
+ let rowStart = Math.max(0, index);
1369
+ while (rowStart > 0) {
1370
+ const columnForIndex = state.columns.get(state.idCache[rowStart]);
1371
+ if (columnForIndex === 1) {
1372
+ break;
1373
+ }
1374
+ rowStart--;
1375
+ }
1376
+ return rowStart;
1377
+ }
1378
+ function calculateRowMaxSize(state, startIndex, endIndex, useAverageSize) {
1379
+ if (endIndex < startIndex) {
1380
+ return 0;
1381
+ }
1382
+ const { data } = state.props;
1383
+ if (!data) {
1384
+ return 0;
1385
+ }
1386
+ let maxSize = 0;
1387
+ for (let i = startIndex; i <= endIndex; i++) {
1388
+ if (i < 0 || i >= data.length) {
1389
+ continue;
1390
+ }
1391
+ const id = state.idCache[i];
1392
+ const size = getItemSize(state, id, i, data[i], useAverageSize);
1393
+ if (size > maxSize) {
1394
+ maxSize = size;
1395
+ }
1396
+ }
1397
+ return maxSize;
1398
+ }
1399
+
1289
1400
  // src/utils/setPaddingTop.ts
1290
1401
  function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1291
1402
  if (stylePaddingTop !== void 0) {
@@ -1345,16 +1456,21 @@ function updateTotalSize(ctx, state) {
1345
1456
  }
1346
1457
  function addTotalSize(ctx, state, key, add) {
1347
1458
  const { alignItemsAtEnd } = state.props;
1348
- {
1459
+ const prevTotalSize = state.totalSize;
1460
+ if (key === null) {
1349
1461
  state.totalSize = add;
1350
1462
  if (state.timeoutSetPaddingTop) {
1351
1463
  clearTimeout(state.timeoutSetPaddingTop);
1352
1464
  state.timeoutSetPaddingTop = void 0;
1353
1465
  }
1466
+ } else {
1467
+ state.totalSize += add;
1354
1468
  }
1355
- set$(ctx, "totalSize", state.totalSize);
1356
- if (alignItemsAtEnd) {
1357
- updateAlignItemsPaddingTop(ctx, state);
1469
+ if (prevTotalSize !== state.totalSize) {
1470
+ set$(ctx, "totalSize", state.totalSize);
1471
+ if (alignItemsAtEnd) {
1472
+ updateAlignItemsPaddingTop(ctx, state);
1473
+ }
1358
1474
  }
1359
1475
  }
1360
1476
 
@@ -1373,9 +1489,9 @@ function updateSnapToOffsets(ctx, state) {
1373
1489
  set$(ctx, "snapToOffsets", snapToOffsets);
1374
1490
  }
1375
1491
 
1376
- // src/core/updateAllPositions.ts
1377
- function updateAllPositions(ctx, state, dataChanged, startIndex = 0) {
1378
- var _a, _b, _c, _d, _e, _f;
1492
+ // src/core/updateItemPositions.ts
1493
+ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered } = { scrollBottomBuffered: -1, startIndex: 0 }) {
1494
+ var _a3, _b, _c, _d;
1379
1495
  const {
1380
1496
  columns,
1381
1497
  indexByKey,
@@ -1385,32 +1501,48 @@ function updateAllPositions(ctx, state, dataChanged, startIndex = 0) {
1385
1501
  props: { getEstimatedItemSize, snapToIndices, enableAverages }
1386
1502
  } = state;
1387
1503
  const data = state.props.data;
1504
+ const dataLength = data.length;
1388
1505
  const numColumns = peek$(ctx, "numColumns");
1389
- const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
1506
+ const hasColumns = numColumns > 1;
1507
+ const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1508
+ const maxVisibleArea = scrollBottomBuffered + 1e3;
1390
1509
  const useAverageSize = enableAverages && !getEstimatedItemSize;
1391
1510
  let currentRowTop = 0;
1392
1511
  let column = 1;
1393
1512
  let maxSizeInRow = 0;
1394
- const hasColumns = numColumns > 1;
1395
1513
  if (startIndex > 0) {
1396
- const prevIndex = startIndex - 1;
1397
- const prevId = (_a = idCache.get(prevIndex)) != null ? _a : getId(state, prevIndex);
1398
- const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1399
1514
  if (hasColumns) {
1400
- const prevColumn = (_c = columns.get(prevId)) != null ? _c : 1;
1401
- currentRowTop = prevPosition;
1402
- column = prevColumn % numColumns + 1;
1403
- } else {
1404
- const prevSize = (_d = sizesKnown.get(prevId)) != null ? _d : getItemSize(state, prevId, prevIndex, data[prevIndex], useAverageSize);
1515
+ const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
1516
+ ctx,
1517
+ state,
1518
+ startIndex,
1519
+ useAverageSize
1520
+ );
1521
+ startIndex = processedStartIndex;
1522
+ currentRowTop = initialRowTop;
1523
+ } else if (startIndex < dataLength) {
1524
+ const prevIndex = startIndex - 1;
1525
+ const prevId = getId(state, prevIndex);
1526
+ const prevPosition = (_a3 = positions.get(prevId)) != null ? _a3 : 0;
1527
+ const prevSize = (_b = sizesKnown.get(prevId)) != null ? _b : getItemSize(state, prevId, prevIndex, data[prevIndex], useAverageSize);
1405
1528
  currentRowTop = prevPosition + prevSize;
1406
1529
  }
1407
1530
  }
1408
1531
  const needsIndexByKey = dataChanged || indexByKey.size === 0;
1409
- const dataLength = data.length;
1532
+ let didBreakEarly = false;
1533
+ let breakAt;
1410
1534
  for (let i = startIndex; i < dataLength; i++) {
1411
- const id = (_e = idCache.get(i)) != null ? _e : getId(state, i);
1412
- const size = (_f = sizesKnown.get(id)) != null ? _f : getItemSize(state, id, i, data[i], useAverageSize);
1413
- if (__DEV__ && needsIndexByKey) {
1535
+ if (breakAt && i > breakAt) {
1536
+ didBreakEarly = true;
1537
+ break;
1538
+ }
1539
+ if (breakAt === void 0 && !dataChanged && currentRowTop > maxVisibleArea) {
1540
+ const itemsPerRow = hasColumns ? numColumns : 1;
1541
+ breakAt = i + itemsPerRow + 10;
1542
+ }
1543
+ const id = (_c = idCache[i]) != null ? _c : getId(state, i);
1544
+ const size = (_d = sizesKnown.get(id)) != null ? _d : getItemSize(state, id, i, data[i], useAverageSize);
1545
+ if (IS_DEV && needsIndexByKey) {
1414
1546
  if (indexByKeyForChecking.has(id)) {
1415
1547
  console.error(
1416
1548
  `[legend-list] Error: Detected overlapping key (${id}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
@@ -1437,7 +1569,9 @@ function updateAllPositions(ctx, state, dataChanged, startIndex = 0) {
1437
1569
  currentRowTop += size;
1438
1570
  }
1439
1571
  }
1440
- updateTotalSize(ctx, state);
1572
+ if (!didBreakEarly) {
1573
+ updateTotalSize(ctx, state);
1574
+ }
1441
1575
  if (snapToIndices) {
1442
1576
  updateSnapToOffsets(ctx, state);
1443
1577
  }
@@ -1457,6 +1591,21 @@ function ensureViewabilityState(ctx, configId) {
1457
1591
  }
1458
1592
  return state;
1459
1593
  }
1594
+ function setupViewability(props) {
1595
+ let { viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged } = props;
1596
+ if (viewabilityConfig || onViewableItemsChanged) {
1597
+ viewabilityConfigCallbackPairs = [
1598
+ ...viewabilityConfigCallbackPairs || [],
1599
+ {
1600
+ onViewableItemsChanged,
1601
+ viewabilityConfig: viewabilityConfig || {
1602
+ viewAreaCoveragePercentThreshold: 0
1603
+ }
1604
+ }
1605
+ ];
1606
+ }
1607
+ return viewabilityConfigCallbackPairs;
1608
+ }
1460
1609
  function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end) {
1461
1610
  const {
1462
1611
  timeouts,
@@ -1628,9 +1777,12 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
1628
1777
  }
1629
1778
 
1630
1779
  // src/utils/checkAllSizesKnown.ts
1780
+ function isNullOrUndefined2(value) {
1781
+ return value === null || value === void 0;
1782
+ }
1631
1783
  function checkAllSizesKnown(state) {
1632
1784
  const { startBuffered, endBuffered, sizesKnown } = state;
1633
- if (endBuffered !== null && startBuffered >= 0 && endBuffered >= 0) {
1785
+ if (!isNullOrUndefined2(endBuffered) && !isNullOrUndefined2(startBuffered) && startBuffered >= 0 && endBuffered >= 0) {
1634
1786
  let areAllKnown = true;
1635
1787
  for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
1636
1788
  const key = getId(state, i);
@@ -1647,6 +1799,8 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1647
1799
  const { stickyContainerPool, containerItemTypes } = state;
1648
1800
  const result = [];
1649
1801
  const availableContainers = [];
1802
+ const pendingRemovalSet = new Set(pendingRemoval);
1803
+ let pendingRemovalChanged = false;
1650
1804
  const stickyIndicesSet = state.props.stickyIndicesSet;
1651
1805
  const stickyItemIndices = (needNewContainers == null ? void 0 : needNewContainers.filter((index) => stickyIndicesSet.has(index))) || [];
1652
1806
  const canReuseContainer = (containerIndex, requiredType) => {
@@ -1662,12 +1816,11 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1662
1816
  let foundContainer = false;
1663
1817
  for (const containerIndex of stickyContainerPool) {
1664
1818
  const key = peek$(ctx, `containerItemKey${containerIndex}`);
1665
- const isPendingRemoval = pendingRemoval.includes(containerIndex);
1819
+ const isPendingRemoval = pendingRemovalSet.has(containerIndex);
1666
1820
  if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType)) {
1667
1821
  result.push(containerIndex);
1668
- if (isPendingRemoval) {
1669
- const index = pendingRemoval.indexOf(containerIndex);
1670
- pendingRemoval.splice(index, 1);
1822
+ if (isPendingRemoval && pendingRemovalSet.delete(containerIndex)) {
1823
+ pendingRemovalChanged = true;
1671
1824
  }
1672
1825
  foundContainer = true;
1673
1826
  if (requiredItemTypes) typeIndex++;
@@ -1687,13 +1840,11 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1687
1840
  }
1688
1841
  const key = peek$(ctx, `containerItemKey${u}`);
1689
1842
  let isOk = key === void 0;
1690
- if (!isOk) {
1691
- const index = pendingRemoval.indexOf(u);
1692
- if (index !== -1) {
1693
- pendingRemoval.splice(index, 1);
1694
- const requiredType = neededTypes[typeIndex];
1695
- isOk = canReuseContainer(u, requiredType);
1696
- }
1843
+ if (!isOk && pendingRemovalSet.has(u)) {
1844
+ pendingRemovalSet.delete(u);
1845
+ pendingRemovalChanged = true;
1846
+ const requiredType = neededTypes[typeIndex];
1847
+ isOk = canReuseContainer(u, requiredType);
1697
1848
  }
1698
1849
  if (isOk) {
1699
1850
  result.push(u);
@@ -1736,7 +1887,7 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1736
1887
  for (let i = 0; i < stillNeeded; i++) {
1737
1888
  result.push(numContainers + i);
1738
1889
  }
1739
- if (__DEV__ && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
1890
+ if (IS_DEV && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
1740
1891
  console.warn(
1741
1892
  "[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.",
1742
1893
  {
@@ -1751,6 +1902,12 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1751
1902
  }
1752
1903
  }
1753
1904
  }
1905
+ if (pendingRemovalChanged) {
1906
+ pendingRemoval.length = 0;
1907
+ for (const value of pendingRemovalSet) {
1908
+ pendingRemoval.push(value);
1909
+ }
1910
+ }
1754
1911
  return result.sort(comparatorDefault);
1755
1912
  }
1756
1913
  function comparatorByDistance(a, b) {
@@ -1807,40 +1964,55 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
1807
1964
  if (isLast && viewPosition === void 0) {
1808
1965
  viewPosition = 1;
1809
1966
  }
1810
- const firstIndexScrollPostion = firstIndexOffset - viewOffset;
1811
1967
  state.scrollForNextCalculateItemsInView = void 0;
1812
1968
  scrollTo(state, {
1813
1969
  animated,
1814
1970
  index,
1815
- offset: firstIndexScrollPostion,
1971
+ offset: firstIndexOffset,
1816
1972
  viewOffset,
1817
1973
  viewPosition: viewPosition != null ? viewPosition : 0
1818
1974
  });
1819
1975
  }
1820
1976
 
1821
1977
  // src/utils/checkThreshold.ts
1822
- var checkThreshold = (distance, atThreshold, threshold, isReached, isBlockedByTimer, onReached, blockTimer) => {
1823
- const distanceAbs = Math.abs(distance);
1824
- const isAtThreshold = atThreshold || distanceAbs < threshold;
1825
- if (!isReached && !isBlockedByTimer) {
1826
- if (isAtThreshold) {
1827
- onReached == null ? void 0 : onReached(distance);
1828
- blockTimer == null ? void 0 : blockTimer(true);
1829
- setTimeout(() => {
1830
- blockTimer == null ? void 0 : blockTimer(false);
1831
- }, 700);
1832
- return true;
1833
- }
1834
- } else {
1835
- if (distance >= 1.3 * threshold) {
1978
+ var HYSTERESIS_MULTIPLIER = 1.3;
1979
+ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1980
+ const absDistance = Math.abs(distance);
1981
+ const within = atThreshold || threshold > 0 && absDistance <= threshold;
1982
+ const updateSnapshot = () => {
1983
+ setSnapshot == null ? void 0 : setSnapshot({
1984
+ atThreshold,
1985
+ contentSize: context.contentSize,
1986
+ dataLength: context.dataLength,
1987
+ scrollPosition: context.scrollPosition
1988
+ });
1989
+ };
1990
+ if (!wasReached) {
1991
+ if (!within) {
1836
1992
  return false;
1837
1993
  }
1994
+ onReached == null ? void 0 : onReached(distance);
1995
+ updateSnapshot();
1996
+ return true;
1838
1997
  }
1839
- return isReached;
1840
- };
1841
-
1842
- // src/utils/checkAtBottom.ts
1843
- function checkAtBottom(ctx, state) {
1998
+ const reset = !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
1999
+ if (reset) {
2000
+ setSnapshot == null ? void 0 : setSnapshot(void 0);
2001
+ return false;
2002
+ }
2003
+ if (within) {
2004
+ const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
2005
+ if (changed) {
2006
+ onReached == null ? void 0 : onReached(distance);
2007
+ updateSnapshot();
2008
+ }
2009
+ }
2010
+ return true;
2011
+ };
2012
+
2013
+ // src/utils/checkAtBottom.ts
2014
+ function checkAtBottom(ctx, state) {
2015
+ var _a3;
1844
2016
  if (!state) {
1845
2017
  return;
1846
2018
  }
@@ -1861,13 +2033,18 @@ function checkAtBottom(ctx, state) {
1861
2033
  isContentLess,
1862
2034
  onEndReachedThreshold * scrollLength,
1863
2035
  state.isEndReached,
1864
- state.endReachedBlockedByTimer,
2036
+ state.endReachedSnapshot,
2037
+ {
2038
+ scrollPosition: scroll,
2039
+ contentSize,
2040
+ dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length
2041
+ },
1865
2042
  (distance) => {
1866
- var _a, _b;
1867
- return (_b = (_a = state.props).onEndReached) == null ? void 0 : _b.call(_a, { distanceFromEnd: distance });
2043
+ var _a4, _b;
2044
+ return (_b = (_a4 = state.props).onEndReached) == null ? void 0 : _b.call(_a4, { distanceFromEnd: distance });
1868
2045
  },
1869
- (block) => {
1870
- state.endReachedBlockedByTimer = block;
2046
+ (snapshot) => {
2047
+ state.endReachedSnapshot = snapshot;
1871
2048
  }
1872
2049
  );
1873
2050
  }
@@ -1895,11 +2072,12 @@ function setDidLayout(ctx, state) {
1895
2072
 
1896
2073
  // src/core/calculateItemsInView.ts
1897
2074
  function findCurrentStickyIndex(stickyArray, scroll, state) {
1898
- var _a;
2075
+ var _a3;
1899
2076
  const idCache = state.idCache;
1900
2077
  const positions = state.positions;
1901
2078
  for (let i = stickyArray.length - 1; i >= 0; i--) {
1902
- const stickyId = (_a = idCache.get(stickyArray[i])) != null ? _a : getId(state, stickyArray[i]);
2079
+ const stickyIndex = stickyArray[i];
2080
+ const stickyId = (_a3 = idCache[stickyIndex]) != null ? _a3 : getId(state, stickyIndex);
1903
2081
  const stickyPos = stickyId ? positions.get(stickyId) : void 0;
1904
2082
  if (stickyPos !== void 0 && scroll >= stickyPos) {
1905
2083
  return i;
@@ -1912,39 +2090,43 @@ function getActiveStickyIndices(ctx, state, stickyIndices) {
1912
2090
  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))
1913
2091
  );
1914
2092
  }
1915
- function handleStickyActivation(ctx, state, stickyIndices, stickyArray, scroll, needNewContainers, startBuffered, endBuffered) {
1916
- var _a;
2093
+ function handleStickyActivation(ctx, state, stickyIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2094
+ var _a3;
1917
2095
  const activeIndices = getActiveStickyIndices(ctx, state, stickyIndices);
1918
- const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
2096
+ state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
1919
2097
  for (let offset = 0; offset <= 1; offset++) {
1920
2098
  const idx = currentStickyIdx - offset;
1921
2099
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
1922
2100
  const stickyIndex = stickyArray[idx];
1923
- const stickyId = (_a = state.idCache.get(stickyIndex)) != null ? _a : getId(state, stickyIndex);
2101
+ const stickyId = (_a3 = state.idCache[stickyIndex]) != null ? _a3 : getId(state, stickyIndex);
1924
2102
  if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered)) {
1925
2103
  needNewContainers.push(stickyIndex);
1926
2104
  }
1927
2105
  }
1928
2106
  }
1929
- function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, pendingRemoval) {
1930
- var _a, _b, _c;
1931
- const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
2107
+ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2108
+ var _a3, _b, _c;
1932
2109
  for (const containerIndex of state.stickyContainerPool) {
1933
2110
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
1934
2111
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
1935
2112
  if (itemIndex === void 0) continue;
1936
2113
  const arrayIdx = stickyArray.indexOf(itemIndex);
1937
- if (arrayIdx === -1) continue;
2114
+ if (arrayIdx === -1) {
2115
+ state.stickyContainerPool.delete(containerIndex);
2116
+ set$(ctx, `containerSticky${containerIndex}`, false);
2117
+ set$(ctx, `containerStickyOffset${containerIndex}`, void 0);
2118
+ continue;
2119
+ }
1938
2120
  const isRecentSticky = arrayIdx >= currentStickyIdx - 1 && arrayIdx <= currentStickyIdx + 1;
1939
2121
  if (isRecentSticky) continue;
1940
2122
  const nextIndex = stickyArray[arrayIdx + 1];
1941
2123
  let shouldRecycle = false;
1942
2124
  if (nextIndex) {
1943
- const nextId = (_a = state.idCache.get(nextIndex)) != null ? _a : getId(state, nextIndex);
2125
+ const nextId = (_a3 = state.idCache[nextIndex]) != null ? _a3 : getId(state, nextIndex);
1944
2126
  const nextPos = nextId ? state.positions.get(nextId) : void 0;
1945
2127
  shouldRecycle = nextPos !== void 0 && scroll > nextPos + scrollBuffer * 2;
1946
2128
  } else {
1947
- const currentId = (_b = state.idCache.get(itemIndex)) != null ? _b : getId(state, itemIndex);
2129
+ const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
1948
2130
  if (currentId) {
1949
2131
  const currentPos = state.positions.get(currentId);
1950
2132
  const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(state, currentId, itemIndex, state.props.data[itemIndex]);
@@ -1958,7 +2140,7 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, pe
1958
2140
  }
1959
2141
  function calculateItemsInView(ctx, state, params = {}) {
1960
2142
  unstable_batchedUpdates(() => {
1961
- var _a, _b, _c, _d, _e, _f, _g, _h;
2143
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
1962
2144
  const {
1963
2145
  columns,
1964
2146
  containerItemKeys,
@@ -1972,7 +2154,7 @@ function calculateItemsInView(ctx, state, params = {}) {
1972
2154
  sizes,
1973
2155
  startBufferedId: startBufferedIdOrig,
1974
2156
  viewabilityConfigCallbackPairs,
1975
- props: { getItemType, initialScroll, itemsAreEqual, keyExtractor, scrollBuffer }
2157
+ props: { getItemType, initialScroll, itemsAreEqual, keyExtractor, onStickyHeaderChange, scrollBuffer }
1976
2158
  } = state;
1977
2159
  const { data } = state.props;
1978
2160
  const stickyIndicesArr = state.props.stickyIndicesArr || [];
@@ -1984,23 +2166,8 @@ function calculateItemsInView(ctx, state, params = {}) {
1984
2166
  const totalSize = peek$(ctx, "totalSize");
1985
2167
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
1986
2168
  const numColumns = peek$(ctx, "numColumns");
1987
- const previousScrollAdjust = 0;
1988
2169
  const { dataChanged, doMVCP } = params;
1989
2170
  const speed = getScrollVelocity(state);
1990
- if (doMVCP || dataChanged) {
1991
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
1992
- if (dataChanged) {
1993
- indexByKey.clear();
1994
- idCache.clear();
1995
- positions.clear();
1996
- }
1997
- const startIndex = dataChanged ? 0 : minIndexSizeChanged != null ? minIndexSizeChanged : 0;
1998
- updateAllPositions(ctx, state, dataChanged, startIndex);
1999
- if (minIndexSizeChanged !== void 0) {
2000
- state.minIndexSizeChanged = void 0;
2001
- }
2002
- checkMVCP == null ? void 0 : checkMVCP();
2003
- }
2004
2171
  const scrollExtra = 0;
2005
2172
  const { queuedInitialLayout } = state;
2006
2173
  let { scroll: scrollState } = state;
@@ -2012,7 +2179,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2012
2179
  );
2013
2180
  scrollState = updatedOffset;
2014
2181
  }
2015
- const scrollAdjustPad = -previousScrollAdjust - topPad;
2182
+ const scrollAdjustPad = -topPad;
2016
2183
  let scroll = scrollState + scrollExtra + scrollAdjustPad;
2017
2184
  if (scroll + scrollLength > totalSize) {
2018
2185
  scroll = Math.max(0, totalSize - scrollLength);
@@ -2021,6 +2188,10 @@ function calculateItemsInView(ctx, state, params = {}) {
2021
2188
  set$(ctx, "debugRawScroll", scrollState);
2022
2189
  set$(ctx, "debugComputedScroll", scroll);
2023
2190
  }
2191
+ const previousStickyIndex = state.activeStickyIndex;
2192
+ const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2193
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2194
+ state.activeStickyIndex = nextActiveStickyIndex;
2024
2195
  let scrollBufferTop = scrollBuffer;
2025
2196
  let scrollBufferBottom = scrollBuffer;
2026
2197
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2033,22 +2204,34 @@ function calculateItemsInView(ctx, state, params = {}) {
2033
2204
  const scrollTopBuffered = scroll - scrollBufferTop;
2034
2205
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
2035
2206
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
2036
- if (scrollForNextCalculateItemsInView) {
2207
+ if (!dataChanged && scrollForNextCalculateItemsInView) {
2037
2208
  const { top, bottom } = scrollForNextCalculateItemsInView;
2038
2209
  if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2039
2210
  return;
2040
2211
  }
2041
2212
  }
2213
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2214
+ if (dataChanged) {
2215
+ indexByKey.clear();
2216
+ idCache.length = 0;
2217
+ positions.clear();
2218
+ }
2219
+ const startIndex = dataChanged ? 0 : (_a3 = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _a3 : 0;
2220
+ updateItemPositions(ctx, state, dataChanged, { scrollBottomBuffered, startIndex });
2221
+ if (minIndexSizeChanged !== void 0) {
2222
+ state.minIndexSizeChanged = void 0;
2223
+ }
2224
+ checkMVCP == null ? void 0 : checkMVCP();
2042
2225
  let startNoBuffer = null;
2043
2226
  let startBuffered = null;
2044
2227
  let startBufferedId = null;
2045
2228
  let endNoBuffer = null;
2046
2229
  let endBuffered = null;
2047
- let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
2230
+ let loopStart = !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
2048
2231
  for (let i = loopStart; i >= 0; i--) {
2049
- const id = (_a = idCache.get(i)) != null ? _a : getId(state, i);
2232
+ const id = (_b = idCache[i]) != null ? _b : getId(state, i);
2050
2233
  const top = positions.get(id);
2051
- const size = (_b = sizes.get(id)) != null ? _b : getItemSize(state, id, i, data[i]);
2234
+ const size = (_c = sizes.get(id)) != null ? _c : getItemSize(state, id, i, data[i]);
2052
2235
  const bottom = top + size;
2053
2236
  if (bottom > scroll - scrollBuffer) {
2054
2237
  loopStart = i;
@@ -2074,8 +2257,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2074
2257
  let firstFullyOnScreenIndex;
2075
2258
  const dataLength = data.length;
2076
2259
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2077
- const id = (_c = idCache.get(i)) != null ? _c : getId(state, i);
2078
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(state, id, i, data[i]);
2260
+ const id = (_d = idCache[i]) != null ? _d : getId(state, i);
2261
+ const size = (_e = sizes.get(id)) != null ? _e : getItemSize(state, id, i, data[i]);
2079
2262
  const top = positions.get(id);
2080
2263
  if (!foundEnd) {
2081
2264
  if (startNoBuffer === null && top + size > scroll) {
@@ -2104,7 +2287,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2104
2287
  }
2105
2288
  const idsInView = [];
2106
2289
  for (let i = firstFullyOnScreenIndex; i <= endNoBuffer; i++) {
2107
- const id = (_e = idCache.get(i)) != null ? _e : getId(state, i);
2290
+ const id = (_f = idCache[i]) != null ? _f : getId(state, i);
2108
2291
  idsInView.push(id);
2109
2292
  }
2110
2293
  Object.assign(state, {
@@ -2136,7 +2319,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2136
2319
  let numContainers2 = prevNumContainers;
2137
2320
  const needNewContainers = [];
2138
2321
  for (let i = startBuffered; i <= endBuffered; i++) {
2139
- const id = (_f = idCache.get(i)) != null ? _f : getId(state, i);
2322
+ const id = (_g = idCache[i]) != null ? _g : getId(state, i);
2140
2323
  if (!containerItemKeys.has(id)) {
2141
2324
  needNewContainers.push(i);
2142
2325
  }
@@ -2147,11 +2330,13 @@ function calculateItemsInView(ctx, state, params = {}) {
2147
2330
  state,
2148
2331
  stickyIndicesSet,
2149
2332
  stickyIndicesArr,
2150
- scroll,
2333
+ currentStickyIdx,
2151
2334
  needNewContainers,
2152
2335
  startBuffered,
2153
2336
  endBuffered
2154
2337
  );
2338
+ } else {
2339
+ state.activeStickyIndex = void 0;
2155
2340
  }
2156
2341
  if (needNewContainers.length > 0) {
2157
2342
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
@@ -2171,7 +2356,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2171
2356
  for (let idx = 0; idx < needNewContainers.length; idx++) {
2172
2357
  const i = needNewContainers[idx];
2173
2358
  const containerIndex = availableContainers[idx];
2174
- const id = (_g = idCache.get(i)) != null ? _g : getId(state, i);
2359
+ const id = (_h = idCache[i]) != null ? _h : getId(state, i);
2175
2360
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
2176
2361
  if (oldKey && oldKey !== id) {
2177
2362
  containerItemKeys.delete(oldKey);
@@ -2185,9 +2370,10 @@ function calculateItemsInView(ctx, state, params = {}) {
2185
2370
  if (stickyIndicesSet.has(i)) {
2186
2371
  set$(ctx, `containerSticky${containerIndex}`, true);
2187
2372
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2188
- set$(ctx, `containerStickyOffset${containerIndex}`, createAnimatedValue(topPadding));
2373
+ set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2189
2374
  state.stickyContainerPool.add(containerIndex);
2190
2375
  } else {
2376
+ set$(ctx, `containerSticky${containerIndex}`, false);
2191
2377
  state.stickyContainerPool.delete(containerIndex);
2192
2378
  }
2193
2379
  if (containerIndex >= numContainers2) {
@@ -2203,7 +2389,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2203
2389
  }
2204
2390
  }
2205
2391
  if (stickyIndicesArr.length > 0) {
2206
- handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, pendingRemoval);
2392
+ handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2207
2393
  }
2208
2394
  let didChangePositions = false;
2209
2395
  for (let i = 0; i < numContainers; i++) {
@@ -2226,7 +2412,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2226
2412
  const itemIndex = indexByKey.get(itemKey);
2227
2413
  const item = data[itemIndex];
2228
2414
  if (item !== void 0) {
2229
- const id = (_h = idCache.get(itemIndex)) != null ? _h : getId(state, itemIndex);
2415
+ const id = (_i = idCache[itemIndex]) != null ? _i : getId(state, itemIndex);
2230
2416
  const position = positions.get(id);
2231
2417
  if (position === void 0) {
2232
2418
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
@@ -2243,7 +2429,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2243
2429
  set$(ctx, `containerColumn${i}`, column);
2244
2430
  }
2245
2431
  if (prevData !== item && (itemsAreEqual ? !itemsAreEqual(prevData, item, itemIndex, data) : true)) {
2246
- set$(ctx, `containerItemData${i}`, data[itemIndex]);
2432
+ set$(ctx, `containerItemData${i}`, item);
2247
2433
  }
2248
2434
  }
2249
2435
  }
@@ -2260,56 +2446,13 @@ function calculateItemsInView(ctx, state, params = {}) {
2260
2446
  if (viewabilityConfigCallbackPairs) {
2261
2447
  updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollLength, startNoBuffer, endNoBuffer);
2262
2448
  }
2263
- });
2264
- }
2265
-
2266
- // src/core/doInitialAllocateContainers.ts
2267
- function doInitialAllocateContainers(ctx, state) {
2268
- var _a;
2269
- const {
2270
- scrollLength,
2271
- props: {
2272
- data,
2273
- getEstimatedItemSize,
2274
- getFixedItemSize,
2275
- getItemType,
2276
- scrollBuffer,
2277
- numColumns,
2278
- estimatedItemSize
2279
- }
2280
- } = state;
2281
- const hasContainers = peek$(ctx, "numContainers");
2282
- if (scrollLength > 0 && data.length > 0 && !hasContainers) {
2283
- let averageItemSize;
2284
- const fn = getFixedItemSize || getEstimatedItemSize;
2285
- if (fn) {
2286
- let totalSize = 0;
2287
- const num = Math.min(20, data.length);
2288
- for (let i = 0; i < num; i++) {
2289
- totalSize += fn(0, data[0], getItemType ? (_a = getItemType(data[0], 0)) != null ? _a : "" : "");
2449
+ if (onStickyHeaderChange && stickyIndicesArr.length > 0 && nextActiveStickyIndex !== void 0 && nextActiveStickyIndex !== previousStickyIndex) {
2450
+ const item = data[nextActiveStickyIndex];
2451
+ if (item !== void 0) {
2452
+ onStickyHeaderChange({ index: nextActiveStickyIndex, item });
2290
2453
  }
2291
- averageItemSize = totalSize / num;
2292
- } else {
2293
- averageItemSize = estimatedItemSize;
2294
2454
  }
2295
- const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize * numColumns);
2296
- for (let i = 0; i < numContainers; i++) {
2297
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2298
- set$(ctx, `containerColumn${i}`, -1);
2299
- }
2300
- set$(ctx, "numContainers", numContainers);
2301
- set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
2302
- if (state.lastLayout) {
2303
- if (state.props.initialScroll) {
2304
- requestAnimationFrame(() => {
2305
- calculateItemsInView(ctx, state, { dataChanged: true });
2306
- });
2307
- } else {
2308
- calculateItemsInView(ctx, state, { dataChanged: true });
2309
- }
2310
- }
2311
- return true;
2312
- }
2455
+ });
2313
2456
  }
2314
2457
 
2315
2458
  // src/core/doMaintainScrollAtEnd.ts
@@ -2324,10 +2467,10 @@ function doMaintainScrollAtEnd(ctx, state, animated) {
2324
2467
  state.scroll = 0;
2325
2468
  }
2326
2469
  requestAnimationFrame(() => {
2327
- var _a;
2470
+ var _a3;
2328
2471
  if (state == null ? void 0 : state.isAtEnd) {
2329
2472
  state.maintainingScrollAtEnd = true;
2330
- (_a = refScroller.current) == null ? void 0 : _a.scrollToEnd({
2473
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2331
2474
  animated
2332
2475
  });
2333
2476
  setTimeout(
@@ -2344,6 +2487,7 @@ function doMaintainScrollAtEnd(ctx, state, animated) {
2344
2487
 
2345
2488
  // src/utils/checkAtTop.ts
2346
2489
  function checkAtTop(state) {
2490
+ var _a3;
2347
2491
  if (!state) {
2348
2492
  return;
2349
2493
  }
@@ -2359,17 +2503,146 @@ function checkAtTop(state) {
2359
2503
  false,
2360
2504
  onStartReachedThreshold * scrollLength,
2361
2505
  state.isStartReached,
2362
- state.startReachedBlockedByTimer,
2506
+ state.startReachedSnapshot,
2507
+ {
2508
+ scrollPosition: scroll,
2509
+ contentSize: state.totalSize,
2510
+ dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length
2511
+ },
2363
2512
  (distance) => {
2364
- var _a, _b;
2365
- return (_b = (_a = state.props).onStartReached) == null ? void 0 : _b.call(_a, { distanceFromStart: distance });
2513
+ var _a4, _b;
2514
+ return (_b = (_a4 = state.props).onStartReached) == null ? void 0 : _b.call(_a4, { distanceFromStart: distance });
2366
2515
  },
2367
- (block) => {
2368
- state.startReachedBlockedByTimer = block;
2516
+ (snapshot) => {
2517
+ state.startReachedSnapshot = snapshot;
2369
2518
  }
2370
2519
  );
2371
2520
  }
2372
2521
 
2522
+ // src/utils/updateAveragesOnDataChange.ts
2523
+ function updateAveragesOnDataChange(state, oldData, newData) {
2524
+ var _a3;
2525
+ const {
2526
+ averageSizes,
2527
+ sizesKnown,
2528
+ indexByKey,
2529
+ props: { itemsAreEqual, getItemType, keyExtractor }
2530
+ } = state;
2531
+ if (!itemsAreEqual || !oldData.length || !newData.length) {
2532
+ for (const key in averageSizes) {
2533
+ delete averageSizes[key];
2534
+ }
2535
+ return;
2536
+ }
2537
+ const itemTypesToPreserve = {};
2538
+ const newDataLength = newData.length;
2539
+ const oldDataLength = oldData.length;
2540
+ for (let newIndex = 0; newIndex < newDataLength; newIndex++) {
2541
+ const newItem = newData[newIndex];
2542
+ const id = keyExtractor ? keyExtractor(newItem, newIndex) : String(newIndex);
2543
+ const oldIndex = indexByKey.get(id);
2544
+ if (oldIndex !== void 0 && oldIndex < oldDataLength) {
2545
+ const knownSize = sizesKnown.get(id);
2546
+ if (knownSize === void 0) continue;
2547
+ const oldItem = oldData[oldIndex];
2548
+ const areEqual = itemsAreEqual(oldItem, newItem, newIndex, newData);
2549
+ if (areEqual) {
2550
+ const itemType = getItemType ? (_a3 = getItemType(newItem, newIndex)) != null ? _a3 : "" : "";
2551
+ let typeData = itemTypesToPreserve[itemType];
2552
+ if (!typeData) {
2553
+ typeData = itemTypesToPreserve[itemType] = { count: 0, totalSize: 0 };
2554
+ }
2555
+ typeData.totalSize += knownSize;
2556
+ typeData.count++;
2557
+ }
2558
+ }
2559
+ }
2560
+ for (const key in averageSizes) {
2561
+ delete averageSizes[key];
2562
+ }
2563
+ for (const itemType in itemTypesToPreserve) {
2564
+ const { totalSize, count } = itemTypesToPreserve[itemType];
2565
+ if (count > 0) {
2566
+ averageSizes[itemType] = {
2567
+ avg: totalSize / count,
2568
+ num: count
2569
+ };
2570
+ }
2571
+ }
2572
+ }
2573
+
2574
+ // src/core/checkResetContainers.ts
2575
+ function checkResetContainers(ctx, state, isFirst, dataProp) {
2576
+ if (state) {
2577
+ if (!isFirst && state.props.data !== dataProp) {
2578
+ updateAveragesOnDataChange(state, state.props.data, dataProp);
2579
+ }
2580
+ const { maintainScrollAtEnd } = state.props;
2581
+ if (!isFirst) {
2582
+ calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2583
+ const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2584
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2585
+ if (!didMaintainScrollAtEnd && dataProp.length > state.props.data.length) {
2586
+ state.isEndReached = false;
2587
+ }
2588
+ if (!didMaintainScrollAtEnd) {
2589
+ checkAtTop(state);
2590
+ checkAtBottom(ctx, state);
2591
+ }
2592
+ }
2593
+ }
2594
+ }
2595
+
2596
+ // src/core/doInitialAllocateContainers.ts
2597
+ function doInitialAllocateContainers(ctx, state) {
2598
+ var _a3, _b, _c;
2599
+ const {
2600
+ scrollLength,
2601
+ props: {
2602
+ data,
2603
+ getEstimatedItemSize,
2604
+ getFixedItemSize,
2605
+ getItemType,
2606
+ scrollBuffer,
2607
+ numColumns,
2608
+ estimatedItemSize
2609
+ }
2610
+ } = state;
2611
+ const hasContainers = peek$(ctx, "numContainers");
2612
+ if (scrollLength > 0 && data.length > 0 && !hasContainers) {
2613
+ let averageItemSize;
2614
+ if (getFixedItemSize || getEstimatedItemSize) {
2615
+ let totalSize = 0;
2616
+ const num = Math.min(20, data.length);
2617
+ for (let i = 0; i < num; i++) {
2618
+ const item = data[i];
2619
+ const itemType = getItemType ? (_a3 = getItemType(item, i)) != null ? _a3 : "" : "";
2620
+ totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
2621
+ }
2622
+ averageItemSize = totalSize / num;
2623
+ } else {
2624
+ averageItemSize = estimatedItemSize;
2625
+ }
2626
+ const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize * numColumns);
2627
+ for (let i = 0; i < numContainers; i++) {
2628
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2629
+ set$(ctx, `containerColumn${i}`, -1);
2630
+ }
2631
+ set$(ctx, "numContainers", numContainers);
2632
+ set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
2633
+ if (state.lastLayout) {
2634
+ if (state.props.initialScroll) {
2635
+ requestAnimationFrame(() => {
2636
+ calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2637
+ });
2638
+ } else {
2639
+ calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2640
+ }
2641
+ }
2642
+ return true;
2643
+ }
2644
+ }
2645
+
2373
2646
  // src/core/handleLayout.ts
2374
2647
  function handleLayout(ctx, state, layout, setCanRender) {
2375
2648
  const { maintainScrollAtEnd } = state.props;
@@ -2404,19 +2677,19 @@ function handleLayout(ctx, state, layout, setCanRender) {
2404
2677
  if (state) {
2405
2678
  state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
2406
2679
  }
2407
- if (__DEV__ && measuredLength === 0) {
2680
+ if (IS_DEV && measuredLength === 0) {
2408
2681
  warnDevOnce(
2409
2682
  "height0",
2410
2683
  `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.`
2411
2684
  );
2412
2685
  }
2413
- setCanRender(true);
2414
2686
  }
2687
+ setCanRender(true);
2415
2688
  }
2416
2689
 
2417
2690
  // src/core/onScroll.ts
2418
2691
  function onScroll(ctx, state, event) {
2419
- var _a, _b, _c;
2692
+ var _a3, _b, _c;
2420
2693
  const {
2421
2694
  scrollProcessingEnabled,
2422
2695
  props: { onScroll: onScrollProp }
@@ -2424,27 +2697,12 @@ function onScroll(ctx, state, event) {
2424
2697
  if (scrollProcessingEnabled === false) {
2425
2698
  return;
2426
2699
  }
2427
- 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) {
2700
+ if (((_b = (_a3 = event.nativeEvent) == null ? void 0 : _a3.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
2428
2701
  return;
2429
2702
  }
2430
2703
  const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2431
- const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
2432
- if (ignoreScrollFromMVCP && !state.scrollingTo) {
2433
- const { lt, gt } = ignoreScrollFromMVCP;
2434
- if (lt && newScroll < lt || gt && newScroll > gt) {
2435
- return;
2436
- }
2437
- }
2438
2704
  state.scrollPending = newScroll;
2439
- {
2440
- if (!state.onScrollRafScheduled) {
2441
- state.onScrollRafScheduled = true;
2442
- requestAnimationFrame(() => {
2443
- state.onScrollRafScheduled = false;
2444
- updateScroll(ctx, state, newScroll);
2445
- });
2446
- }
2447
- }
2705
+ updateScroll(ctx, state, newScroll);
2448
2706
  onScrollProp == null ? void 0 : onScrollProp(event);
2449
2707
  }
2450
2708
  function updateScroll(ctx, state, newScroll) {
@@ -2452,9 +2710,17 @@ function updateScroll(ctx, state, newScroll) {
2452
2710
  state.hasScrolled = true;
2453
2711
  state.lastBatchingAction = Date.now();
2454
2712
  const currentTime = Date.now();
2713
+ const adjust = state.scrollAdjustHandler.getAdjust();
2714
+ const lastHistoryAdjust = state.lastScrollAdjustForHistory;
2715
+ const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
2716
+ if (adjustChanged) {
2717
+ state.scrollHistory.length = 0;
2718
+ }
2719
+ state.lastScrollAdjustForHistory = adjust;
2455
2720
  if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
2456
- const adjust = state.scrollAdjustHandler.getAdjust();
2457
- state.scrollHistory.push({ scroll: newScroll - adjust, time: currentTime });
2721
+ if (!adjustChanged) {
2722
+ state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2723
+ }
2458
2724
  }
2459
2725
  if (state.scrollHistory.length > 5) {
2460
2726
  state.scrollHistory.shift();
@@ -2463,10 +2729,18 @@ function updateScroll(ctx, state, newScroll) {
2463
2729
  state.scrollPrevTime = state.scrollTime;
2464
2730
  state.scroll = newScroll;
2465
2731
  state.scrollTime = currentTime;
2466
- if (Math.abs(state.scroll - state.scrollPrev) > 2) {
2467
- calculateItemsInView(ctx, state);
2732
+ const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
2733
+ if (ignoreScrollFromMVCP && !state.scrollingTo) {
2734
+ const { lt, gt } = ignoreScrollFromMVCP;
2735
+ if (lt && newScroll < lt || gt && newScroll > gt) {
2736
+ return;
2737
+ }
2738
+ }
2739
+ if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
2740
+ calculateItemsInView(ctx, state, { doMVCP: state.scrollingTo !== void 0 });
2468
2741
  checkAtBottom(ctx, state);
2469
2742
  checkAtTop(state);
2743
+ state.dataChangeNeedsScrollUpdate = false;
2470
2744
  }
2471
2745
  }
2472
2746
 
@@ -2478,7 +2752,7 @@ var ScrollAdjustHandler = class {
2478
2752
  this.context = ctx;
2479
2753
  }
2480
2754
  requestAdjust(add) {
2481
- const oldAdjustTop = peek$(this.context, "scrollAdjust") || 0;
2755
+ const oldAdjustTop = this.appliedAdjust;
2482
2756
  this.appliedAdjust = add + oldAdjustTop;
2483
2757
  const set = () => set$(this.context, "scrollAdjust", this.appliedAdjust);
2484
2758
  if (this.mounted) {
@@ -2497,14 +2771,13 @@ var ScrollAdjustHandler = class {
2497
2771
 
2498
2772
  // src/core/updateItemSize.ts
2499
2773
  function updateItemSize(ctx, state, itemKey, sizeObj) {
2500
- var _a, _b;
2774
+ var _a3;
2501
2775
  const {
2502
2776
  sizesKnown,
2503
2777
  props: {
2504
2778
  getFixedItemSize,
2505
2779
  getItemType,
2506
2780
  horizontal,
2507
- maintainVisibleContentPosition,
2508
2781
  suggestEstimatedItemSize,
2509
2782
  onItemSizeChanged,
2510
2783
  data,
@@ -2512,17 +2785,17 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2512
2785
  }
2513
2786
  } = state;
2514
2787
  if (!data) return;
2788
+ const index = state.indexByKey.get(itemKey);
2515
2789
  if (getFixedItemSize) {
2516
- const index2 = state.indexByKey.get(itemKey);
2517
- if (index2 === void 0) {
2790
+ if (index === void 0) {
2518
2791
  return;
2519
2792
  }
2520
- const itemData = state.props.data[index2];
2793
+ const itemData = state.props.data[index];
2521
2794
  if (itemData === void 0) {
2522
2795
  return;
2523
2796
  }
2524
- const type = getItemType ? (_a = getItemType(itemData, index2)) != null ? _a : "" : "";
2525
- const size2 = getFixedItemSize(index2, itemData, type);
2797
+ const type = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
2798
+ const size2 = getFixedItemSize(index, itemData, type);
2526
2799
  if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
2527
2800
  return;
2528
2801
  }
@@ -2532,15 +2805,11 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2532
2805
  let shouldMaintainScrollAtEnd = false;
2533
2806
  let minIndexSizeChanged;
2534
2807
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2535
- const index = state.indexByKey.get(itemKey);
2536
2808
  const prevSizeKnown = state.sizesKnown.get(itemKey);
2537
2809
  const diff = updateOneItemSize(state, itemKey, sizeObj);
2538
2810
  const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2539
2811
  if (diff !== 0) {
2540
2812
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
2541
- if (((_b = state.scrollingTo) == null ? void 0 : _b.viewPosition) && maintainVisibleContentPosition && index === state.scrollingTo.index && diff > 0) {
2542
- requestAdjust(ctx, state, diff * state.scrollingTo.viewPosition);
2543
- }
2544
2813
  const { startBuffered, endBuffered } = state;
2545
2814
  needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
2546
2815
  if (!needsRecalculate) {
@@ -2559,6 +2828,7 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2559
2828
  if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2560
2829
  shouldMaintainScrollAtEnd = true;
2561
2830
  }
2831
+ addTotalSize(ctx, state, itemKey, diff);
2562
2832
  onItemSizeChanged == null ? void 0 : onItemSizeChanged({
2563
2833
  index,
2564
2834
  itemData: state.props.data[index],
@@ -2570,13 +2840,13 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2570
2840
  if (minIndexSizeChanged !== void 0) {
2571
2841
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
2572
2842
  }
2573
- if (__DEV__ && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
2843
+ if (IS_DEV && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
2574
2844
  if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
2575
2845
  state.timeoutSizeMessage = setTimeout(() => {
2576
- var _a2;
2846
+ var _a4;
2577
2847
  state.timeoutSizeMessage = void 0;
2578
2848
  const num = state.sizesKnown.size;
2579
- const avg = (_a2 = state.averageSizes[""]) == null ? void 0 : _a2.avg;
2849
+ const avg = (_a4 = state.averageSizes[""]) == null ? void 0 : _a4.avg;
2580
2850
  console.warn(
2581
2851
  `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
2582
2852
  );
@@ -2599,7 +2869,7 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2599
2869
  }
2600
2870
  }
2601
2871
  function updateOneItemSize(state, itemKey, sizeObj) {
2602
- var _a;
2872
+ var _a3;
2603
2873
  const {
2604
2874
  sizes,
2605
2875
  indexByKey,
@@ -2609,12 +2879,12 @@ function updateOneItemSize(state, itemKey, sizeObj) {
2609
2879
  } = state;
2610
2880
  if (!data) return 0;
2611
2881
  const index = indexByKey.get(itemKey);
2612
- const prevSize = getItemSize(state, itemKey, index, data);
2882
+ const prevSize = getItemSize(state, itemKey, index, data[index]);
2613
2883
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
2614
2884
  const size = Math.round(rawSize) ;
2615
2885
  sizesKnown.set(itemKey, size);
2616
2886
  if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
2617
- const itemType = getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : "";
2887
+ const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
2618
2888
  let averages = averageSizes[itemType];
2619
2889
  if (!averages) {
2620
2890
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
@@ -2645,24 +2915,12 @@ var useCombinedRef = (...refs) => {
2645
2915
  };
2646
2916
 
2647
2917
  // src/platform/RefreshControl.tsx
2648
- function RefreshControl(props) {
2918
+ function RefreshControl(_props) {
2649
2919
  return null;
2650
2920
  }
2651
2921
 
2652
- // src/platform/StyleSheet.tsx
2653
- function flattenStyles(styles) {
2654
- if (Array.isArray(styles)) {
2655
- return Object.assign({}, ...styles.filter(Boolean));
2656
- }
2657
- return styles;
2658
- }
2659
- var StyleSheet = {
2660
- create: (styles) => styles,
2661
- flatten: (style) => flattenStyles(style)
2662
- };
2663
-
2664
2922
  // src/platform/useStickyScrollHandler.ts
2665
- function useStickyScrollHandler(stickyIndices, horizontal, ctx, onScroll2) {
2923
+ function useStickyScrollHandler(_stickyIndices, _horizontal, _ctx, onScroll2) {
2666
2924
  return onScroll2;
2667
2925
  }
2668
2926
 
@@ -2681,7 +2939,7 @@ function createColumnWrapperStyle(contentContainerStyle) {
2681
2939
  }
2682
2940
  }
2683
2941
  function getRenderedItem(ctx, state, key) {
2684
- var _a;
2942
+ var _a3;
2685
2943
  if (!state) {
2686
2944
  return null;
2687
2945
  }
@@ -2694,15 +2952,17 @@ function getRenderedItem(ctx, state, key) {
2694
2952
  return null;
2695
2953
  }
2696
2954
  let renderedItem = null;
2697
- if (renderItem && data[index]) {
2955
+ const extraData = peek$(ctx, "extraData");
2956
+ const item = data[index];
2957
+ if (renderItem && !isNullOrUndefined(item)) {
2698
2958
  const itemProps = {
2699
2959
  data,
2700
- extraData: peek$(ctx, "extraData"),
2960
+ extraData,
2701
2961
  index,
2702
- item: data[index],
2703
- type: getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : ""
2962
+ item,
2963
+ type: getItemType ? (_a3 = getItemType(item, index)) != null ? _a3 : "" : ""
2704
2964
  };
2705
- renderedItem = isFunction(renderItem) ? renderItem(itemProps) : React4__default.createElement(renderItem, itemProps);
2965
+ renderedItem = isFunction(renderItem) ? renderItem(itemProps) : React3__default.createElement(renderItem, itemProps);
2706
2966
  }
2707
2967
  return { index, item: data[index], renderedItem };
2708
2968
  }
@@ -2752,58 +3012,6 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
2752
3012
  return (event) => throttle(originalHandler, scrollEventThrottle, { nativeEvent: event.nativeEvent });
2753
3013
  }
2754
3014
 
2755
- // src/utils/updateAveragesOnDataChange.ts
2756
- function updateAveragesOnDataChange(state, oldData, newData) {
2757
- var _a;
2758
- const {
2759
- averageSizes,
2760
- sizesKnown,
2761
- indexByKey,
2762
- props: { itemsAreEqual, getItemType, keyExtractor }
2763
- } = state;
2764
- if (!itemsAreEqual || !oldData.length || !newData.length) {
2765
- for (const key in averageSizes) {
2766
- delete averageSizes[key];
2767
- }
2768
- return;
2769
- }
2770
- const itemTypesToPreserve = {};
2771
- const newDataLength = newData.length;
2772
- const oldDataLength = oldData.length;
2773
- for (let newIndex = 0; newIndex < newDataLength; newIndex++) {
2774
- const newItem = newData[newIndex];
2775
- const id = keyExtractor ? keyExtractor(newItem, newIndex) : String(newIndex);
2776
- const oldIndex = indexByKey.get(id);
2777
- if (oldIndex !== void 0 && oldIndex < oldDataLength) {
2778
- const knownSize = sizesKnown.get(id);
2779
- if (knownSize === void 0) continue;
2780
- const oldItem = oldData[oldIndex];
2781
- const areEqual = itemsAreEqual(oldItem, newItem, newIndex, newData);
2782
- if (areEqual) {
2783
- const itemType = getItemType ? (_a = getItemType(newItem, newIndex)) != null ? _a : "" : "";
2784
- let typeData = itemTypesToPreserve[itemType];
2785
- if (!typeData) {
2786
- typeData = itemTypesToPreserve[itemType] = { count: 0, totalSize: 0 };
2787
- }
2788
- typeData.totalSize += knownSize;
2789
- typeData.count++;
2790
- }
2791
- }
2792
- }
2793
- for (const key in averageSizes) {
2794
- delete averageSizes[key];
2795
- }
2796
- for (const itemType in itemTypesToPreserve) {
2797
- const { totalSize, count } = itemTypesToPreserve[itemType];
2798
- if (count > 0) {
2799
- averageSizes[itemType] = {
2800
- avg: totalSize / count,
2801
- num: count
2802
- };
2803
- }
2804
- }
2805
- }
2806
-
2807
3015
  // src/components/LegendList.tsx
2808
3016
  var DEFAULT_DRAW_DISTANCE = 250;
2809
3017
  var DEFAULT_ITEM_SIZE = 100;
@@ -2813,17 +3021,18 @@ var LegendList = typedMemo(
2813
3021
  const isChildrenMode = children !== void 0 && dataProp === void 0;
2814
3022
  const processedProps = isChildrenMode ? {
2815
3023
  ...restProps,
2816
- data: (isArray(children) ? children : React4.Children.toArray(children)).flat(1),
3024
+ data: (isArray(children) ? children : React3.Children.toArray(children)).flat(1),
2817
3025
  renderItem: ({ item }) => item
2818
3026
  } : {
2819
3027
  ...restProps,
2820
3028
  data: dataProp || [],
2821
3029
  renderItem: renderItemProp
2822
3030
  };
2823
- return /* @__PURE__ */ React4.createElement(StateProvider, null, /* @__PURE__ */ React4.createElement(LegendListInner, { ...processedProps, ref: forwardedRef }));
3031
+ return /* @__PURE__ */ React3.createElement(StateProvider, null, /* @__PURE__ */ React3.createElement(LegendListInner, { ...processedProps, ref: forwardedRef }));
2824
3032
  })
2825
3033
  );
2826
3034
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
3035
+ var _a3;
2827
3036
  const {
2828
3037
  alignItemsAtEnd = false,
2829
3038
  columnWrapperStyle,
@@ -2859,6 +3068,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2859
3068
  onScroll: onScrollProp,
2860
3069
  onStartReached,
2861
3070
  onStartReachedThreshold = 0.5,
3071
+ onStickyHeaderChange,
3072
+ onViewableItemsChanged,
2862
3073
  progressViewOffset,
2863
3074
  recycleItems = false,
2864
3075
  refreshControl,
@@ -2870,12 +3081,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2870
3081
  stickyIndices,
2871
3082
  style: styleProp,
2872
3083
  suggestEstimatedItemSize,
3084
+ viewabilityConfig,
3085
+ viewabilityConfigCallbackPairs,
2873
3086
  waitForInitialLayout = true,
2874
3087
  ...rest
2875
3088
  } = props;
2876
3089
  const [renderNum, setRenderNum] = useState(0);
2877
3090
  const initialScroll = initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
2878
- const [canRender, setCanRender] = React4.useState(!IsNewArchitecture);
3091
+ const [canRender, setCanRender] = React3.useState(!IsNewArchitecture);
2879
3092
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
2880
3093
  const style = { ...StyleSheet.flatten(styleProp) };
2881
3094
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
@@ -2897,12 +3110,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2897
3110
  columns: /* @__PURE__ */ new Map(),
2898
3111
  containerItemKeys: /* @__PURE__ */ new Set(),
2899
3112
  containerItemTypes: /* @__PURE__ */ new Map(),
3113
+ dataChangeNeedsScrollUpdate: false,
2900
3114
  enableScrollForNextCalculateItemsInView: true,
2901
3115
  endBuffered: -1,
2902
3116
  endNoBuffer: -1,
2903
- endReachedBlockedByTimer: false,
3117
+ endReachedSnapshot: void 0,
2904
3118
  firstFullyOnScreenIndex: -1,
2905
- idCache: /* @__PURE__ */ new Map(),
3119
+ idCache: [],
2906
3120
  idsInView: [],
2907
3121
  indexByKey: /* @__PURE__ */ new Map(),
2908
3122
  initialScroll,
@@ -2933,7 +3147,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2933
3147
  sizesKnown: /* @__PURE__ */ new Map(),
2934
3148
  startBuffered: -1,
2935
3149
  startNoBuffer: -1,
2936
- startReachedBlockedByTimer: false,
3150
+ startReachedSnapshot: void 0,
2937
3151
  stickyContainerPool: /* @__PURE__ */ new Set(),
2938
3152
  stickyContainers: /* @__PURE__ */ new Map(),
2939
3153
  timeoutSizeMessage: 0,
@@ -2949,10 +3163,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2949
3163
  const state = refState.current;
2950
3164
  const isFirst = !state.props.renderItem;
2951
3165
  const didDataChange = state.props.data !== dataProp;
2952
- const throttleScrollFn = (
2953
- // @ts-expect-error TODO Fix this
2954
- scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp
2955
- );
3166
+ if (didDataChange) {
3167
+ state.dataChangeNeedsScrollUpdate = true;
3168
+ }
3169
+ const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
2956
3170
  state.props = {
2957
3171
  alignItemsAtEnd,
2958
3172
  data: dataProp,
@@ -2977,6 +3191,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2977
3191
  onScroll: throttleScrollFn,
2978
3192
  onStartReached,
2979
3193
  onStartReachedThreshold,
3194
+ onStickyHeaderChange,
2980
3195
  recycleItems: !!recycleItems,
2981
3196
  renderItem,
2982
3197
  scrollBuffer,
@@ -2988,27 +3203,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2988
3203
  suggestEstimatedItemSize: !!suggestEstimatedItemSize
2989
3204
  };
2990
3205
  state.refScroller = refScroller;
2991
- const checkResetContainers = (isFirst2) => {
2992
- const state2 = refState.current;
2993
- if (state2) {
2994
- if (!isFirst2 && state2.props.data !== dataProp) {
2995
- updateAveragesOnDataChange(state2, state2.props.data, dataProp);
2996
- }
2997
- state2.props.data = dataProp;
2998
- if (!isFirst2) {
2999
- calculateItemsInView(ctx, state2, { dataChanged: true, doMVCP: true });
3000
- const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
3001
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state2, false);
3002
- if (!didMaintainScrollAtEnd && dataProp.length > state2.props.data.length) {
3003
- state2.isEndReached = false;
3004
- }
3005
- if (!didMaintainScrollAtEnd) {
3006
- checkAtTop(state2);
3007
- checkAtBottom(ctx, state2);
3008
- }
3009
- }
3010
- }
3011
- };
3012
3206
  const memoizedLastItemKeys = useMemo(() => {
3013
3207
  if (!dataProp.length) return [];
3014
3208
  return Array.from(
@@ -3032,7 +3226,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3032
3226
  };
3033
3227
  if (isFirst) {
3034
3228
  initializeStateVars();
3035
- updateAllPositions(ctx, state);
3229
+ updateItemPositions(
3230
+ ctx,
3231
+ state,
3232
+ /*dataChanged*/
3233
+ true
3234
+ );
3036
3235
  }
3037
3236
  const initialContentOffset = useMemo(() => {
3038
3237
  if (initialScroll) {
@@ -3043,21 +3242,27 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3043
3242
  }
3044
3243
  refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
3045
3244
  if (initialContentOffset2 > 0) {
3046
- scrollTo(state, { animated: false, index, offset: initialContentOffset2 });
3245
+ scrollTo(state, {
3246
+ animated: false,
3247
+ index,
3248
+ isInitialScroll: true,
3249
+ offset: initialContentOffset2,
3250
+ viewPosition: index === dataProp.length - 1 ? 1 : 0
3251
+ });
3047
3252
  }
3048
3253
  return initialContentOffset2;
3049
3254
  }
3050
3255
  return 0;
3051
3256
  }, [renderNum]);
3052
3257
  if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
3053
- state.lastBatchingAction = Date.now();
3258
+ refState.current.lastBatchingAction = Date.now();
3054
3259
  if (!keyExtractorProp && !isFirst && didDataChange) {
3055
- __DEV__ && warnDevOnce(
3260
+ IS_DEV && warnDevOnce(
3056
3261
  "keyExtractor",
3057
3262
  "Changing data without a keyExtractor can cause slow performance and resetting scroll. If your list data can change you should use a keyExtractor with a unique id for best performance and behavior."
3058
3263
  );
3059
- state.sizes.clear();
3060
- state.positions.clear();
3264
+ refState.current.sizes.clear();
3265
+ refState.current.positions.clear();
3061
3266
  }
3062
3267
  }
3063
3268
  const onLayoutHeader = useCallback((rect, fromLayoutEffect) => {
@@ -3077,36 +3282,44 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3077
3282
  }
3078
3283
  }, [snapToIndices]);
3079
3284
  useLayoutEffect(() => {
3080
- const didAllocateContainers = dataProp.length > 0 && doInitialAllocateContainersCallback();
3285
+ const didAllocateContainers = dataProp.length > 0 && doInitialAllocateContainers(ctx, state);
3081
3286
  if (!didAllocateContainers) {
3082
3287
  checkResetContainers(
3288
+ ctx,
3289
+ state,
3083
3290
  /*isFirst*/
3084
- isFirst
3291
+ isFirst,
3292
+ dataProp
3085
3293
  );
3086
3294
  }
3087
3295
  }, [dataProp, numColumnsProp]);
3088
3296
  useLayoutEffect(() => {
3089
3297
  set$(ctx, "extraData", extraData);
3090
3298
  }, [extraData]);
3091
- const { onLayout } = useSyncLayout({
3092
- onLayout: onLayoutProp,
3093
- onLayoutChange: useCallback(
3094
- (rectangle) => {
3095
- handleLayout(ctx, state, rectangle, setCanRender);
3096
- },
3097
- [ctx, state, setCanRender]
3098
- ),
3099
- ref: refScroller
3100
- });
3101
3299
  useLayoutEffect(initializeStateVars, [
3102
3300
  memoizedLastItemKeys.join(","),
3103
3301
  numColumnsProp,
3104
3302
  stylePaddingTopState,
3105
3303
  stylePaddingBottomState
3106
3304
  ]);
3107
- const doInitialAllocateContainersCallback = () => {
3108
- return doInitialAllocateContainers(ctx, state);
3109
- };
3305
+ useEffect(() => {
3306
+ const viewability = setupViewability({
3307
+ onViewableItemsChanged,
3308
+ viewabilityConfig,
3309
+ viewabilityConfigCallbackPairs
3310
+ });
3311
+ state.viewabilityConfigCallbackPairs = viewability;
3312
+ state.enableScrollForNextCalculateItemsInView = !viewability;
3313
+ }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3314
+ const onLayoutChange = useCallback((layout) => {
3315
+ handleLayout(ctx, state, layout, setCanRender);
3316
+ }, []);
3317
+ const { onLayout } = useOnLayoutSync({
3318
+ onLayoutChange,
3319
+ onLayoutProp,
3320
+ ref: refScroller
3321
+ // the type of ScrollView doesn't include measure?
3322
+ });
3110
3323
  useImperativeHandle(forwardedRef, () => {
3111
3324
  const scrollIndexIntoView = (options) => {
3112
3325
  const state2 = refState.current;
@@ -3124,16 +3337,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3124
3337
  }
3125
3338
  };
3126
3339
  return {
3127
- flashScrollIndicators: () => {
3128
- var _a, _b;
3129
- return (_b = (_a = refScroller.current) == null ? void 0 : _a.flashScrollIndicators) == null ? void 0 : _b.call(_a);
3130
- },
3340
+ flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
3131
3341
  getNativeScrollRef: () => refScroller.current,
3132
- getScrollableNode: () => refScroller.current,
3133
- getScrollResponder: () => refScroller.current,
3342
+ getScrollableNode: () => refScroller.current.getScrollableNode(),
3343
+ getScrollResponder: () => refScroller.current.getScrollResponder(),
3134
3344
  getState: () => {
3135
3345
  const state2 = refState.current;
3136
3346
  return state2 ? {
3347
+ activeStickyIndex: state2.activeStickyIndex,
3137
3348
  contentLength: state2.totalSize,
3138
3349
  data: state2.props.data,
3139
3350
  end: state2.endNoBuffer,
@@ -3194,7 +3405,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3194
3405
  {
3195
3406
  useEffect(() => {
3196
3407
  if (initialContentOffset) {
3197
- scrollTo(state, { animated: false, offset: initialContentOffset });
3408
+ scrollTo(state, { animated: false, offset: initialContentOffset, ...initialScroll || {} });
3198
3409
  }
3199
3410
  }, []);
3200
3411
  }
@@ -3207,7 +3418,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3207
3418
  []
3208
3419
  );
3209
3420
  const onScrollHandler = useStickyScrollHandler(stickyIndices, horizontal, ctx, fns.onScroll);
3210
- return /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(
3421
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(
3211
3422
  ListComponent,
3212
3423
  {
3213
3424
  ...rest,
@@ -3234,9 +3445,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3234
3445
  },
3235
3446
  onScroll: onScrollHandler,
3236
3447
  recycleItems,
3237
- refreshControl: refreshControl ? stylePaddingTopState > 0 ? React4.cloneElement(refreshControl, {
3448
+ refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3.cloneElement(refreshControl, {
3238
3449
  progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
3239
- }) : refreshControl : onRefresh && /* @__PURE__ */ React4.createElement(
3450
+ }) : refreshControl : onRefresh && /* @__PURE__ */ React3.createElement(
3240
3451
  RefreshControl,
3241
3452
  {
3242
3453
  onRefresh,
@@ -3245,14 +3456,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3245
3456
  }
3246
3457
  ),
3247
3458
  refScrollView: combinedRef,
3248
- scrollAdjustHandler: state.scrollAdjustHandler,
3459
+ scrollAdjustHandler: (_a3 = refState.current) == null ? void 0 : _a3.scrollAdjustHandler,
3460
+ scrollEventThrottle: 16 ,
3249
3461
  snapToIndices,
3250
3462
  stickyIndices,
3251
3463
  style,
3252
3464
  updateItemSize: fns.updateItemSize,
3253
3465
  waitForInitialLayout
3254
3466
  }
3255
- ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React4.createElement(DebugView, { state: refState.current }));
3467
+ ), IS_DEV && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React3.createElement(DebugView, { state: refState.current }));
3256
3468
  });
3257
3469
 
3258
- export { LegendList, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout2 as useSyncLayout, useViewability, useViewabilityAmount };
3470
+ export { LegendList, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };