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

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,
@@ -33,14 +33,17 @@ function StateProvider({ children }) {
33
33
  ["stylePaddingTop", 0],
34
34
  ["headerSize", 0],
35
35
  ["numContainers", 0],
36
- ["totalSize", 0]
36
+ ["activeStickyIndex", void 0],
37
+ ["totalSize", 0],
38
+ ["scrollAdjustPending", 0],
39
+ ["scrollingTo", void 0]
37
40
  ]),
38
41
  viewRefs: /* @__PURE__ */ new Map()
39
42
  }));
40
- return /* @__PURE__ */ React4.createElement(ContextState.Provider, { value }, children);
43
+ return /* @__PURE__ */ React3.createElement(ContextState.Provider, { value }, children);
41
44
  }
42
45
  function useStateContext() {
43
- return React4.useContext(ContextState);
46
+ return React3.useContext(ContextState);
44
47
  }
45
48
  function createSelectorFunctionsArr(ctx, signalNames) {
46
49
  let lastValues = [];
@@ -110,23 +113,23 @@ function getContentSize(ctx) {
110
113
  return headerSize + footerSize + totalSize + stylePaddingTop;
111
114
  }
112
115
  function useArr$(signalNames) {
113
- const ctx = React4.useContext(ContextState);
114
- const { subscribe, get } = React4.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
116
+ const ctx = React3.useContext(ContextState);
117
+ const { subscribe, get } = React3.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
115
118
  const value = useSyncExternalStore(subscribe, get);
116
119
  return value;
117
120
  }
118
121
  function useSelector$(signalName, selector) {
119
- const ctx = React4.useContext(ContextState);
120
- const { subscribe, get } = React4.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
122
+ const ctx = React3.useContext(ContextState);
123
+ const { subscribe, get } = React3.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
121
124
  const value = useSyncExternalStore(subscribe, () => selector(get()[0]));
122
125
  return value;
123
126
  }
124
127
 
125
128
  // src/components/DebugView.tsx
126
129
  var DebugRow = ({ children }) => {
127
- return /* @__PURE__ */ React4.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
130
+ return /* @__PURE__ */ React3.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
128
131
  };
129
- var DebugView = React4.memo(function DebugView2({ state }) {
132
+ var DebugView = React3.memo(function DebugView2({ state }) {
130
133
  const ctx = useStateContext();
131
134
  const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, _numContainers = 0, _numContainersPooled = 0] = useArr$([
132
135
  "totalSize",
@@ -141,7 +144,7 @@ var DebugView = React4.memo(function DebugView2({ state }) {
141
144
  useInterval(() => {
142
145
  forceUpdate();
143
146
  }, 100);
144
- return /* @__PURE__ */ React4.createElement(
147
+ return /* @__PURE__ */ React3.createElement(
145
148
  View,
146
149
  {
147
150
  pointerEvents: "none",
@@ -157,12 +160,12 @@ var DebugView = React4.memo(function DebugView2({ state }) {
157
160
  top: 0
158
161
  }
159
162
  },
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)))
163
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "TotalSize:"), /* @__PURE__ */ React3.createElement(Text, null, totalSize.toFixed(2))),
164
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "ContentSize:"), /* @__PURE__ */ React3.createElement(Text, null, contentSize.toFixed(2))),
165
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "At end:"), /* @__PURE__ */ React3.createElement(Text, null, String(state.isAtEnd))),
166
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React3.createElement(Text, null, scrollAdjust.toFixed(2))),
167
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "RawScroll: "), /* @__PURE__ */ React3.createElement(Text, null, rawScroll.toFixed(2))),
168
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "ComputedScroll: "), /* @__PURE__ */ React3.createElement(Text, null, scroll.toFixed(2)))
166
169
  );
167
170
  });
168
171
  function useInterval(callback, delay) {
@@ -171,90 +174,19 @@ function useInterval(callback, delay) {
171
174
  return () => clearInterval(interval);
172
175
  }, [delay]);
173
176
  }
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
177
 
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
- };
178
+ // src/utils/devEnvironment.ts
179
+ var metroDev = typeof __DEV__ !== "undefined" ? __DEV__ : void 0;
180
+ var _a;
181
+ var envMode = typeof process !== "undefined" && typeof process.env === "object" && process.env ? (_a = process.env.NODE_ENV) != null ? _a : process.env.MODE : void 0;
182
+ var processDev = typeof envMode === "string" ? envMode.toLowerCase() !== "production" : void 0;
183
+ var _a2;
184
+ var IS_DEV = (_a2 = metroDev != null ? metroDev : processDev) != null ? _a2 : false;
253
185
 
254
186
  // src/constants.ts
255
187
  var POSITION_OUT_OF_VIEW = -1e7;
256
- var ENABLE_DEVMODE = __DEV__ && false;
257
- var ENABLE_DEBUG_VIEW = __DEV__ && false;
188
+ var ENABLE_DEVMODE = IS_DEV && false;
189
+ var ENABLE_DEBUG_VIEW = IS_DEV && false;
258
190
  var typedForwardRef = forwardRef;
259
191
  var typedMemo = memo;
260
192
 
@@ -267,9 +199,12 @@ var PositionViewState = typedMemo(function PositionView({
267
199
  ...rest
268
200
  }) {
269
201
  const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
270
- const base = Array.isArray(style) ? Object.assign({}, ...style) : style;
271
- const combinedStyle = horizontal ? { ...base, left: position } : { ...base, top: position };
272
- return /* @__PURE__ */ React4.createElement(LayoutView, { refView, style: combinedStyle, ...rest });
202
+ const base = {
203
+ contain: "paint layout style"
204
+ };
205
+ const composed = Array.isArray(style) ? Object.assign({}, ...style) : style;
206
+ const combinedStyle = horizontal ? { ...base, ...composed, left: position } : { ...base, ...composed, top: position };
207
+ return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: combinedStyle, ...rest });
273
208
  });
274
209
  var PositionViewSticky = typedMemo(function PositionViewSticky2({
275
210
  id,
@@ -277,35 +212,47 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
277
212
  style,
278
213
  refView,
279
214
  index,
215
+ stickyOffset,
216
+ animatedScrollY: _animatedScrollY,
217
+ children,
280
218
  ...rest
281
219
  }) {
282
- const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
283
- const viewStyle = React4.useMemo(() => {
284
- const base = Array.isArray(style) ? Object.assign({}, ...style) : style;
285
- const axisStyle = horizontal ? { transform: `translateX(${position}px)` } : { top: position };
286
- return {
287
- ...base,
288
- zIndex: index + 1e3,
289
- ...axisStyle
290
- };
291
- }, [style, position, horizontal, index]);
292
- return /* @__PURE__ */ React4.createElement(LayoutView, { refView, style: viewStyle, ...rest });
220
+ const [position = POSITION_OUT_OF_VIEW, headerSize = 0, activeStickyIndex] = useArr$([
221
+ `containerPosition${id}`,
222
+ "headerSize",
223
+ "activeStickyIndex"
224
+ ]);
225
+ const base = {
226
+ contain: "paint layout style"
227
+ };
228
+ const composed = React3.useMemo(
229
+ () => {
230
+ var _a3;
231
+ return (_a3 = Array.isArray(style) ? Object.assign({}, ...style) : style) != null ? _a3 : {};
232
+ },
233
+ [style]
234
+ );
235
+ const viewStyle = React3.useMemo(() => {
236
+ var _a3;
237
+ const styleBase = { ...base, ...composed };
238
+ delete styleBase.transform;
239
+ const offset = (_a3 = stickyOffset != null ? stickyOffset : headerSize) != null ? _a3 : 0;
240
+ const isActive = activeStickyIndex === index;
241
+ styleBase.position = isActive ? "sticky" : "absolute";
242
+ styleBase.zIndex = index + 1e3;
243
+ if (horizontal) {
244
+ styleBase.left = isActive ? offset : position;
245
+ } else {
246
+ styleBase.top = isActive ? offset : position;
247
+ }
248
+ return styleBase;
249
+ }, [composed, horizontal, position, index, stickyOffset, headerSize, activeStickyIndex]);
250
+ return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
293
251
  });
294
252
  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
253
 
301
254
  // src/constants-platform.ts
302
255
  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
256
  var symbolFirst = Symbol();
310
257
  function useInit(cb) {
311
258
  const refValue = useRef(symbolFirst);
@@ -324,7 +271,7 @@ function isArray(obj) {
324
271
  }
325
272
  var warned = /* @__PURE__ */ new Set();
326
273
  function warnDevOnce(id, text) {
327
- if (__DEV__ && !warned.has(id)) {
274
+ if (IS_DEV && !warned.has(id)) {
328
275
  warned.add(id);
329
276
  console.warn(`[legend-list] ${text}`);
330
277
  }
@@ -339,8 +286,8 @@ function comparatorDefault(a, b) {
339
286
  return a - b;
340
287
  }
341
288
  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;
289
+ var _a3, _b, _c;
290
+ return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : s.paddingVertical) != null ? _b : s.padding) != null ? _c : 0;
344
291
  }
345
292
  function extractPadding(style, contentContainerStyle, type) {
346
293
  return getPadding(style, type) + getPadding(contentContainerStyle, type);
@@ -442,13 +389,103 @@ function useListScrollSize() {
442
389
  const [scrollSize] = useArr$(["scrollSize"]);
443
390
  return scrollSize;
444
391
  }
445
- function useSyncLayout2() {
392
+ function useSyncLayout() {
446
393
  {
447
394
  const { triggerLayout: syncLayout } = useContext(ContextContainer);
448
395
  return syncLayout;
449
396
  }
450
397
  }
451
398
 
399
+ // src/components/Separator.tsx
400
+ function Separator({ ItemSeparatorComponent, leadingItem }) {
401
+ const isLastItem = useIsLastItem();
402
+ return isLastItem ? null : /* @__PURE__ */ React3.createElement(ItemSeparatorComponent, { leadingItem });
403
+ }
404
+
405
+ // src/hooks/createResizeObserver.ts
406
+ var globalResizeObserver = null;
407
+ function getGlobalResizeObserver() {
408
+ if (!globalResizeObserver) {
409
+ globalResizeObserver = new ResizeObserver((entries) => {
410
+ for (const entry of entries) {
411
+ const callbacks = callbackMap.get(entry.target);
412
+ if (callbacks) {
413
+ for (const callback of callbacks) {
414
+ callback(entry);
415
+ }
416
+ }
417
+ }
418
+ });
419
+ }
420
+ return globalResizeObserver;
421
+ }
422
+ var callbackMap = /* @__PURE__ */ new WeakMap();
423
+ function createResizeObserver(element, callback) {
424
+ if (!element) {
425
+ return () => {
426
+ };
427
+ }
428
+ const observer = getGlobalResizeObserver();
429
+ let callbacks = callbackMap.get(element);
430
+ if (!callbacks) {
431
+ callbacks = /* @__PURE__ */ new Set();
432
+ callbackMap.set(element, callbacks);
433
+ observer.observe(element);
434
+ }
435
+ callbacks.add(callback);
436
+ return () => {
437
+ const callbacks2 = callbackMap.get(element);
438
+ if (callbacks2) {
439
+ callbacks2.delete(callback);
440
+ if (callbacks2.size === 0) {
441
+ callbackMap.delete(element);
442
+ observer.unobserve(element);
443
+ }
444
+ }
445
+ };
446
+ }
447
+
448
+ // src/hooks/useOnLayoutSync.tsx
449
+ function useOnLayoutSync({
450
+ ref,
451
+ onLayoutProp,
452
+ onLayoutChange
453
+ }, deps) {
454
+ useLayoutEffect(() => {
455
+ var _a3, _b;
456
+ const current = ref.current;
457
+ const scrollableNode = (_b = (_a3 = current == null ? void 0 : current.getScrollableNode) == null ? void 0 : _a3.call(current)) != null ? _b : null;
458
+ const element = scrollableNode || current;
459
+ if (!element || !(element instanceof HTMLElement)) {
460
+ return;
461
+ }
462
+ const emit = (layout, fromLayoutEffect) => {
463
+ if (layout.height === 0 && layout.width === 0) {
464
+ return;
465
+ }
466
+ onLayoutChange(layout, fromLayoutEffect);
467
+ onLayoutProp == null ? void 0 : onLayoutProp({ nativeEvent: { layout } });
468
+ };
469
+ const rect = element.getBoundingClientRect();
470
+ emit(toLayout(rect), true);
471
+ return createResizeObserver(element, (entry) => {
472
+ var _a4;
473
+ const target = entry.target instanceof HTMLElement ? entry.target : void 0;
474
+ const rect2 = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
475
+ emit(toLayout(rect2), false);
476
+ });
477
+ }, deps);
478
+ return {};
479
+ }
480
+ function toLayout(rect) {
481
+ return {
482
+ height: rect.height,
483
+ width: rect.width,
484
+ x: rect.left,
485
+ y: rect.top
486
+ };
487
+ }
488
+
452
489
  // src/components/Container.tsx
453
490
  var Container = typedMemo(function Container2({
454
491
  id,
@@ -459,37 +496,42 @@ var Container = typedMemo(function Container2({
459
496
  ItemSeparatorComponent
460
497
  }) {
461
498
  const ctx = useStateContext();
462
- const { columnWrapperStyle } = ctx;
463
- const [column = 0, data, itemKey, numColumns, extraData, isSticky] = useArr$([
499
+ const { columnWrapperStyle, animatedScrollY } = ctx;
500
+ const [column = 0, data, itemKey, numColumns, extraData, isSticky, stickyOffset] = useArr$([
464
501
  `containerColumn${id}`,
465
502
  `containerItemData${id}`,
466
503
  `containerItemKey${id}`,
467
504
  "numColumns",
468
505
  "extraData",
469
- `containerSticky${id}`
506
+ `containerSticky${id}`,
507
+ `containerStickyOffset${id}`
470
508
  ]);
471
- const refLastSize = useRef();
509
+ const itemLayoutRef = useRef({
510
+ horizontal,
511
+ itemKey,
512
+ updateItemSize: updateItemSize2
513
+ });
514
+ itemLayoutRef.current.horizontal = horizontal;
515
+ itemLayoutRef.current.itemKey = itemKey;
516
+ itemLayoutRef.current.updateItemSize = updateItemSize2;
472
517
  const ref = useRef(null);
473
- const [_, forceLayoutRender] = useState(0);
518
+ const [layoutRenderCount, forceLayoutRender] = useState(0);
474
519
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
475
520
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
521
+ const didLayoutRef = useRef(false);
476
522
  const style = useMemo(() => {
477
523
  let paddingStyles;
478
524
  if (columnWrapperStyle) {
479
525
  const { columnGap, rowGap, gap } = columnWrapperStyle;
480
526
  if (horizontal) {
481
- const py = numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0;
482
527
  paddingStyles = {
483
- paddingBottom: py,
484
528
  paddingRight: columnGap || gap || void 0,
485
- paddingTop: py
529
+ paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
486
530
  };
487
531
  } else {
488
- const px = numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0;
489
532
  paddingStyles = {
490
533
  paddingBottom: rowGap || gap || void 0,
491
- paddingLeft: px,
492
- paddingRight: px
534
+ paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
493
535
  };
494
536
  }
495
537
  }
@@ -503,7 +545,7 @@ var Container = typedMemo(function Container2({
503
545
  } : {
504
546
  left: otherAxisPos,
505
547
  position: "absolute",
506
- right: numColumns > 1 ? void 0 : 0,
548
+ right: numColumns > 1 ? null : 0,
507
549
  top: 0,
508
550
  width: otherAxisSize,
509
551
  ...paddingStyles || {}
@@ -526,49 +568,64 @@ var Container = typedMemo(function Container2({
526
568
  value: data
527
569
  };
528
570
  }, [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
- }
571
+ const onLayoutChange = useCallback((rectangle) => {
572
+ const {
573
+ horizontal: currentHorizontal,
574
+ itemKey: currentItemKey,
575
+ updateItemSize: updateItemSizeFn
576
+ } = itemLayoutRef.current;
577
+ if (isNullOrUndefined(currentItemKey)) {
578
+ return;
540
579
  }
541
- };
580
+ didLayoutRef.current = true;
581
+ let layout = rectangle;
582
+ Math.floor(rectangle[currentHorizontal ? "width" : "height"] * 8) / 8;
583
+ const doUpdate = () => {
584
+ itemLayoutRef.current.lastSize = { height: layout.height, width: layout.width };
585
+ updateItemSizeFn(currentItemKey, layout);
586
+ didLayoutRef.current = true;
587
+ };
588
+ {
589
+ doUpdate();
590
+ }
591
+ }, []);
592
+ const { onLayout } = useOnLayoutSync(
593
+ {
594
+ onLayoutChange,
595
+ ref
596
+ },
597
+ [itemKey, layoutRenderCount]
598
+ );
542
599
  const PositionComponent = isSticky ? PositionViewSticky : PositionView2;
543
- return /* @__PURE__ */ React4.createElement(ContextContainer.Provider, { value: contextValue }, /* @__PURE__ */ React4.createElement(
600
+ return /* @__PURE__ */ React3.createElement(
544
601
  PositionComponent,
545
602
  {
603
+ animatedScrollY: isSticky ? animatedScrollY : void 0,
546
604
  horizontal,
547
605
  id,
548
606
  index,
549
607
  key: recycleItems ? void 0 : itemKey,
550
- onLayoutChange,
608
+ onLayout,
551
609
  refView: ref,
610
+ stickyOffset: isSticky ? stickyOffset : void 0,
552
611
  style
553
612
  },
554
- renderedItem,
555
- renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React4.createElement(
556
- Separator,
557
- {
558
- ItemSeparatorComponent,
559
- itemKey,
560
- leadingItem: renderedItemInfo.item
561
- }
562
- )
563
- ));
613
+ /* @__PURE__ */ React3.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React3.createElement(Separator, { ItemSeparatorComponent, leadingItem: renderedItemInfo.item }))
614
+ );
564
615
  });
565
616
 
617
+ // src/platform/Platform.ts
618
+ var Platform = {
619
+ // Widen the type to avoid unreachable-branch lints in cross-platform code that compares against other OSes
620
+ OS: "web"
621
+ };
622
+
566
623
  // src/utils/reordering.ts
567
624
  var mapFn = (element) => {
568
625
  const indexStr = element.getAttribute("index");
569
626
  return [element, indexStr === null ? null : parseInt(indexStr)];
570
627
  };
571
- function sortDOMElementsPatience(container) {
628
+ function sortDOMElements(container) {
572
629
  const elements = Array.from(container.children);
573
630
  if (elements.length <= 1) return elements;
574
631
  const items = elements.map(mapFn);
@@ -659,7 +716,7 @@ function useDOMOrder(ref) {
659
716
  debounceRef.current = setTimeout(() => {
660
717
  const parent = ref.current;
661
718
  if (parent) {
662
- sortDOMElementsPatience(parent);
719
+ sortDOMElements(parent);
663
720
  }
664
721
  debounceRef.current = void 0;
665
722
  }, 500);
@@ -701,7 +758,7 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
701
758
  }
702
759
  }
703
760
  }
704
- return /* @__PURE__ */ React4.createElement("div", { ref, style }, children);
761
+ return /* @__PURE__ */ React3.createElement("div", { ref, style }, children);
705
762
  });
706
763
  var Containers = typedMemo(function Containers2({
707
764
  horizontal,
@@ -715,7 +772,7 @@ var Containers = typedMemo(function Containers2({
715
772
  const containers = [];
716
773
  for (let i = 0; i < numContainers; i++) {
717
774
  containers.push(
718
- /* @__PURE__ */ React4.createElement(
775
+ /* @__PURE__ */ React3.createElement(
719
776
  Container,
720
777
  {
721
778
  getRenderedItem: getRenderedItem2,
@@ -729,24 +786,40 @@ var Containers = typedMemo(function Containers2({
729
786
  )
730
787
  );
731
788
  }
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
- ));
789
+ return /* @__PURE__ */ React3.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
749
790
  });
791
+ function DevNumbers() {
792
+ return IS_DEV && React3.memo(function DevNumbers2() {
793
+ return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3.createElement(
794
+ "div",
795
+ {
796
+ key: index,
797
+ style: {
798
+ height: 100,
799
+ pointerEvents: "none",
800
+ position: "absolute",
801
+ top: index * 100,
802
+ width: "100%"
803
+ }
804
+ },
805
+ /* @__PURE__ */ React3.createElement("div", { style: { color: "red" } }, index * 100)
806
+ ));
807
+ });
808
+ }
809
+
810
+ // src/platform/StyleSheet.tsx
811
+ function flattenStyles(styles) {
812
+ if (Array.isArray(styles)) {
813
+ return Object.assign({}, ...styles.filter(Boolean));
814
+ }
815
+ return styles;
816
+ }
817
+ var StyleSheet = {
818
+ create: (styles) => styles,
819
+ flatten: (style) => flattenStyles(style)
820
+ };
821
+
822
+ // src/components/ListComponentScrollView.tsx
750
823
  var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
751
824
  children,
752
825
  style,
@@ -760,7 +833,6 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
760
833
  showsVerticalScrollIndicator = true,
761
834
  refreshControl,
762
835
  onLayout,
763
- ScrollComponent,
764
836
  ...props
765
837
  }, ref) {
766
838
  const scrollRef = useRef(null);
@@ -769,16 +841,15 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
769
841
  useImperativeHandle(ref, () => {
770
842
  const api = {
771
843
  getBoundingClientRect: () => {
772
- var _a;
773
- return (_a = scrollRef.current) == null ? void 0 : _a.getBoundingClientRect();
844
+ var _a3;
845
+ return (_a3 = scrollRef.current) == null ? void 0 : _a3.getBoundingClientRect();
774
846
  },
775
847
  getScrollableNode: () => scrollRef.current,
776
848
  getScrollResponder: () => scrollRef.current,
777
- scrollBy: (options) => {
849
+ scrollBy: (x, y) => {
778
850
  const el = scrollRef.current;
779
851
  if (!el) return;
780
- const { x = 0, y = 0, animated = true } = options;
781
- el.scrollBy({ behavior: animated ? "smooth" : "auto", left: x, top: y });
852
+ el.scrollBy(x, y);
782
853
  },
783
854
  scrollTo: (options) => {
784
855
  const el = scrollRef.current;
@@ -848,17 +919,21 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
848
919
  useLayoutEffect(() => {
849
920
  const element = scrollRef.current;
850
921
  if (!element) return;
851
- element.addEventListener("scroll", handleScroll, { passive: true });
922
+ element.addEventListener("scroll", handleScroll);
852
923
  return () => {
853
924
  element.removeEventListener("scroll", handleScroll);
854
925
  };
855
926
  }, [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]);
927
+ useEffect(() => {
928
+ const doScroll = () => {
929
+ if (contentOffset && scrollRef.current) {
930
+ scrollRef.current.scrollLeft = contentOffset.x || 0;
931
+ scrollRef.current.scrollTop = contentOffset.y || 0;
932
+ }
933
+ };
934
+ doScroll();
935
+ requestAnimationFrame(doScroll);
936
+ }, [contentOffset == null ? void 0 : contentOffset.x, contentOffset == null ? void 0 : contentOffset.y]);
862
937
  useLayoutEffect(() => {
863
938
  if (!onLayout || !scrollRef.current) return;
864
939
  const element = scrollRef.current;
@@ -890,36 +965,57 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
890
965
  // Ensure proper positioning context
891
966
  WebkitOverflowScrolling: "touch",
892
967
  // iOS momentum scrolling
893
- ...style
968
+ ...StyleSheet.flatten(style)
894
969
  };
895
970
  const contentStyle = {
896
971
  display: horizontal ? "flex" : "block",
897
972
  flexDirection: horizontal ? "row" : void 0,
898
973
  minHeight: horizontal ? void 0 : "100%",
899
974
  minWidth: horizontal ? "100%" : void 0,
900
- ...contentContainerStyle
975
+ ...StyleSheet.flatten(contentContainerStyle)
901
976
  };
902
- return /* @__PURE__ */ React4.createElement("div", { ref: scrollRef, style: scrollViewStyle, ...props }, refreshControl, /* @__PURE__ */ React4.createElement("div", { ref: contentRef, style: contentStyle }, children));
977
+ return /* @__PURE__ */ React3.createElement("div", { ref: scrollRef, style: scrollViewStyle, ...props }, refreshControl, /* @__PURE__ */ React3.createElement("div", { ref: contentRef, style: contentStyle }, children));
903
978
  });
979
+ function Padding() {
980
+ const [paddingTop] = useArr$(["alignItemsPaddingTop"]);
981
+ return /* @__PURE__ */ React3.createElement("div", { style: { paddingTop } });
982
+ }
983
+ function PaddingDevMode() {
984
+ const [paddingTop] = useArr$(["alignItemsPaddingTop"]);
985
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement("div", { style: { paddingTop } }), /* @__PURE__ */ React3.createElement(
986
+ "div",
987
+ {
988
+ style: {
989
+ backgroundColor: "green",
990
+ height: paddingTop,
991
+ left: 0,
992
+ position: "absolute",
993
+ right: 0,
994
+ top: 0
995
+ }
996
+ }
997
+ ));
998
+ }
904
999
  function useValueListener$(key, callback) {
905
1000
  const ctx = useStateContext();
906
1001
  useLayoutEffect(() => {
907
- listen$(ctx, key, (value) => {
1002
+ const unsubscribe = listen$(ctx, key, (value) => {
908
1003
  callback(value);
909
1004
  });
910
- }, []);
1005
+ return unsubscribe;
1006
+ }, [callback, ctx, key]);
911
1007
  }
912
1008
 
913
1009
  // src/components/ScrollAdjust.tsx
914
1010
  function ScrollAdjust() {
915
1011
  const ctx = useStateContext();
916
- const lastScrollOffsetRef = React4.useRef(0);
917
- const callback = React4.useCallback(() => {
918
- var _a;
1012
+ const lastScrollOffsetRef = React3.useRef(0);
1013
+ const callback = React3.useCallback(() => {
1014
+ var _a3;
919
1015
  const scrollAdjust = peek$(ctx, "scrollAdjust");
920
1016
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
921
1017
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
922
- const scrollView = (_a = ctx.internalState) == null ? void 0 : _a.refScroller.current;
1018
+ const scrollView = (_a3 = ctx.internalState) == null ? void 0 : _a3.refScroller.current;
923
1019
  if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
924
1020
  const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
925
1021
  if (scrollDelta !== 0) {
@@ -933,49 +1029,26 @@ function ScrollAdjust() {
933
1029
  useValueListener$("scrollAdjustUserOffset", callback);
934
1030
  return null;
935
1031
  }
936
-
937
- // src/components/SnapWrapper.tsx
938
1032
  function SnapWrapper({ ScrollComponent, ...props }) {
939
1033
  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;
1034
+ return /* @__PURE__ */ React3.createElement(ScrollComponent, { ...props, snapToOffsets });
947
1035
  }
1036
+ var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
1037
+ const ref = refView != null ? refView : useRef();
1038
+ useOnLayoutSync({ onLayoutChange, ref });
1039
+ return /* @__PURE__ */ React3.createElement("div", { ...rest, ref }, children);
1040
+ };
948
1041
 
949
1042
  // src/components/ListComponent.tsx
950
1043
  var getComponent = (Component) => {
951
- if (React4.isValidElement(Component)) {
1044
+ if (React3.isValidElement(Component)) {
952
1045
  return Component;
953
1046
  }
954
1047
  if (Component) {
955
- return /* @__PURE__ */ React4.createElement(Component, null);
1048
+ return /* @__PURE__ */ React3.createElement(Component, null);
956
1049
  }
957
1050
  return null;
958
1051
  };
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
1052
  var ListComponent = typedMemo(function ListComponent2({
980
1053
  canRender,
981
1054
  style,
@@ -1005,12 +1078,11 @@ var ListComponent = typedMemo(function ListComponent2({
1005
1078
  ...rest
1006
1079
  }) {
1007
1080
  const ctx = useStateContext();
1008
- const refHeader = React4.useRef(null);
1009
1081
  const ScrollComponent = renderScrollComponent ? useMemo(
1010
- () => React4.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1082
+ () => React3.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1011
1083
  [renderScrollComponent]
1012
1084
  ) : ListComponentScrollView;
1013
- React4.useEffect(() => {
1085
+ React3.useEffect(() => {
1014
1086
  if (canRender) {
1015
1087
  setTimeout(() => {
1016
1088
  scrollAdjustHandler.setMounted();
@@ -1018,39 +1090,30 @@ var ListComponent = typedMemo(function ListComponent2({
1018
1090
  }
1019
1091
  }, [canRender]);
1020
1092
  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(
1093
+ return /* @__PURE__ */ React3.createElement(
1028
1094
  SnapOrScroll,
1029
1095
  {
1030
1096
  ...rest,
1031
- contentContainerStyle: contentContainerStyleWeb,
1097
+ contentContainerStyle: [
1098
+ contentContainerStyle,
1099
+ horizontal ? {
1100
+ height: "100%"
1101
+ } : {}
1102
+ ],
1032
1103
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1033
1104
  horizontal,
1034
- maintainVisibleContentPosition: maintainVisibleContentPosition && !ListEmptyComponent ? { minIndexForVisible: 0 } : void 0,
1105
+ maintainVisibleContentPosition: maintainVisibleContentPosition ? { minIndexForVisible: 0 } : void 0,
1035
1106
  onLayout,
1036
1107
  onScroll: onScroll2,
1037
1108
  ref: refScrollView,
1038
1109
  ScrollComponent: snapToIndices ? ScrollComponent : void 0,
1039
1110
  style
1040
1111
  },
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
- ),
1112
+ maintainVisibleContentPosition && /* @__PURE__ */ React3.createElement(ScrollAdjust, null),
1113
+ ENABLE_DEVMODE ? /* @__PURE__ */ React3.createElement(PaddingDevMode, null) : /* @__PURE__ */ React3.createElement(Padding, null),
1114
+ ListHeaderComponent && /* @__PURE__ */ React3.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
1052
1115
  ListEmptyComponent && getComponent(ListEmptyComponent),
1053
- canRender && /* @__PURE__ */ React4.createElement(
1116
+ canRender && !ListEmptyComponent && /* @__PURE__ */ React3.createElement(
1054
1117
  Containers,
1055
1118
  {
1056
1119
  getRenderedItem: getRenderedItem2,
@@ -1061,7 +1124,7 @@ var ListComponent = typedMemo(function ListComponent2({
1061
1124
  waitForInitialLayout
1062
1125
  }
1063
1126
  ),
1064
- ListFooterComponent && /* @__PURE__ */ React4.createElement(
1127
+ ListFooterComponent && /* @__PURE__ */ React3.createElement(
1065
1128
  LayoutView,
1066
1129
  {
1067
1130
  onLayoutChange: (layout) => {
@@ -1072,7 +1135,7 @@ var ListComponent = typedMemo(function ListComponent2({
1072
1135
  },
1073
1136
  getComponent(ListFooterComponent)
1074
1137
  ),
1075
- __DEV__ && ENABLE_DEVMODE && /* @__PURE__ */ React4.createElement(DevNumbers, null)
1138
+ IS_DEV && ENABLE_DEVMODE && /* @__PURE__ */ React3.createElement(DevNumbers, null)
1076
1139
  );
1077
1140
  });
1078
1141
 
@@ -1084,7 +1147,7 @@ function getId(state, index) {
1084
1147
  }
1085
1148
  const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
1086
1149
  const id = ret;
1087
- state.idCache.set(index, id);
1150
+ state.idCache[index] = id;
1088
1151
  return id;
1089
1152
  }
1090
1153
 
@@ -1106,12 +1169,11 @@ function calculateOffsetForIndex(ctx, state, index) {
1106
1169
  }
1107
1170
 
1108
1171
  // src/utils/getItemSize.ts
1109
- function getItemSize(state, key, index, data, useAverageSize) {
1110
- var _a, _b;
1172
+ function getItemSize(ctx, state, key, index, data, useAverageSize) {
1173
+ var _a3, _b;
1111
1174
  const {
1112
1175
  sizesKnown,
1113
1176
  sizes,
1114
- scrollingTo,
1115
1177
  averageSizes,
1116
1178
  props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
1117
1179
  } = state;
@@ -1120,7 +1182,8 @@ function getItemSize(state, key, index, data, useAverageSize) {
1120
1182
  return sizeKnown;
1121
1183
  }
1122
1184
  let size;
1123
- const itemType = getItemType ? (_a = getItemType(data, index)) != null ? _a : "" : "";
1185
+ const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1186
+ const scrollingTo = peek$(ctx, "scrollingTo");
1124
1187
  if (getFixedItemSize) {
1125
1188
  size = getFixedItemSize(index, data, itemType);
1126
1189
  if (size !== void 0) {
@@ -1147,57 +1210,234 @@ function getItemSize(state, key, index, data, useAverageSize) {
1147
1210
  }
1148
1211
 
1149
1212
  // src/core/calculateOffsetWithOffsetPosition.ts
1150
- function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
1213
+ function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
1151
1214
  const { index, viewOffset, viewPosition } = params;
1152
1215
  let offset = offsetParam;
1153
1216
  if (viewOffset) {
1154
1217
  offset -= viewOffset;
1155
1218
  }
1156
1219
  if (viewPosition !== void 0 && index !== void 0) {
1157
- offset -= viewPosition * (state.scrollLength - getItemSize(state, getId(state, index), index, state.props.data[index]));
1220
+ offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
1158
1221
  }
1159
1222
  return offset;
1160
1223
  }
1161
1224
 
1162
- // src/core/finishScrollTo.ts
1163
- var finishScrollTo = (state) => {
1164
- if (state) {
1165
- state.scrollingTo = void 0;
1166
- state.scrollHistory.length = 0;
1225
+ // src/utils/checkThreshold.ts
1226
+ var HYSTERESIS_MULTIPLIER = 1.3;
1227
+ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1228
+ const absDistance = Math.abs(distance);
1229
+ const within = atThreshold || threshold > 0 && absDistance <= threshold;
1230
+ const updateSnapshot = () => {
1231
+ setSnapshot == null ? void 0 : setSnapshot({
1232
+ atThreshold,
1233
+ contentSize: context.contentSize,
1234
+ dataLength: context.dataLength,
1235
+ scrollPosition: context.scrollPosition
1236
+ });
1237
+ };
1238
+ if (!wasReached) {
1239
+ if (!within) {
1240
+ return false;
1241
+ }
1242
+ onReached == null ? void 0 : onReached(distance);
1243
+ updateSnapshot();
1244
+ return true;
1245
+ }
1246
+ const reset = !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
1247
+ if (reset) {
1248
+ setSnapshot == null ? void 0 : setSnapshot(void 0);
1249
+ return false;
1250
+ }
1251
+ if (within) {
1252
+ const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
1253
+ if (changed) {
1254
+ onReached == null ? void 0 : onReached(distance);
1255
+ updateSnapshot();
1256
+ }
1167
1257
  }
1258
+ return true;
1168
1259
  };
1169
1260
 
1170
- // src/core/scrollTo.ts
1171
- function scrollTo(state, params = {}) {
1172
- var _a;
1173
- const { animated, noScrollingTo } = params;
1261
+ // src/utils/checkAtBottom.ts
1262
+ function checkAtBottom(ctx, state) {
1263
+ var _a3;
1264
+ if (!state) {
1265
+ return;
1266
+ }
1174
1267
  const {
1175
- refScroller,
1176
- props: { horizontal }
1268
+ queuedInitialLayout,
1269
+ scrollLength,
1270
+ scroll,
1271
+ maintainingScrollAtEnd,
1272
+ props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
1177
1273
  } = state;
1178
- const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
1179
- state.scrollHistory.length = 0;
1180
- if (!noScrollingTo) {
1181
- state.scrollingTo = params;
1182
- }
1183
- 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
- });
1189
- if (!animated) {
1190
- state.scroll = offset;
1191
- setTimeout(() => finishScrollTo(state), 100);
1274
+ const contentSize = getContentSize(ctx);
1275
+ if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1276
+ const distanceFromEnd = contentSize - scroll - scrollLength;
1277
+ const isContentLess = contentSize < scrollLength;
1278
+ state.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1279
+ state.isEndReached = checkThreshold(
1280
+ distanceFromEnd,
1281
+ isContentLess,
1282
+ onEndReachedThreshold * scrollLength,
1283
+ state.isEndReached,
1284
+ state.endReachedSnapshot,
1285
+ {
1286
+ contentSize,
1287
+ dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length,
1288
+ scrollPosition: scroll
1289
+ },
1290
+ (distance) => {
1291
+ var _a4, _b;
1292
+ return (_b = (_a4 = state.props).onEndReached) == null ? void 0 : _b.call(_a4, { distanceFromEnd: distance });
1293
+ },
1294
+ (snapshot) => {
1295
+ state.endReachedSnapshot = snapshot;
1296
+ }
1297
+ );
1192
1298
  }
1193
1299
  }
1194
1300
 
1195
- // src/utils/requestAdjust.ts
1196
- function requestAdjust(ctx, state, positionDiff, dataChanged) {
1197
- if (Math.abs(positionDiff) > 0.1) {
1198
- const doit = () => {
1199
- {
1200
- state.scrollAdjustHandler.requestAdjust(positionDiff);
1301
+ // src/utils/checkAtTop.ts
1302
+ function checkAtTop(state) {
1303
+ var _a3;
1304
+ if (!state) {
1305
+ return;
1306
+ }
1307
+ const {
1308
+ scrollLength,
1309
+ scroll,
1310
+ props: { onStartReachedThreshold }
1311
+ } = state;
1312
+ const distanceFromTop = scroll;
1313
+ state.isAtStart = distanceFromTop <= 0;
1314
+ state.isStartReached = checkThreshold(
1315
+ distanceFromTop,
1316
+ false,
1317
+ onStartReachedThreshold * scrollLength,
1318
+ state.isStartReached,
1319
+ state.startReachedSnapshot,
1320
+ {
1321
+ contentSize: state.totalSize,
1322
+ dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length,
1323
+ scrollPosition: scroll
1324
+ },
1325
+ (distance) => {
1326
+ var _a4, _b;
1327
+ return (_b = (_a4 = state.props).onStartReached) == null ? void 0 : _b.call(_a4, { distanceFromStart: distance });
1328
+ },
1329
+ (snapshot) => {
1330
+ state.startReachedSnapshot = snapshot;
1331
+ }
1332
+ );
1333
+ }
1334
+
1335
+ // src/core/onScroll.ts
1336
+ function onScroll(ctx, state, event) {
1337
+ var _a3, _b, _c;
1338
+ const {
1339
+ scrollProcessingEnabled,
1340
+ props: { onScroll: onScrollProp }
1341
+ } = state;
1342
+ if (scrollProcessingEnabled === false) {
1343
+ return;
1344
+ }
1345
+ 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) {
1346
+ return;
1347
+ }
1348
+ const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
1349
+ state.scrollPending = newScroll;
1350
+ updateScroll(ctx, state, newScroll);
1351
+ onScrollProp == null ? void 0 : onScrollProp(event);
1352
+ }
1353
+ function updateScroll(ctx, state, newScroll, forceUpdate) {
1354
+ const scrollingTo = peek$(ctx, "scrollingTo");
1355
+ state.hasScrolled = true;
1356
+ state.lastBatchingAction = Date.now();
1357
+ const currentTime = Date.now();
1358
+ const adjust = state.scrollAdjustHandler.getAdjust();
1359
+ const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1360
+ const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1361
+ if (adjustChanged) {
1362
+ state.scrollHistory.length = 0;
1363
+ }
1364
+ state.lastScrollAdjustForHistory = adjust;
1365
+ if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
1366
+ if (!adjustChanged) {
1367
+ state.scrollHistory.push({ scroll: newScroll, time: currentTime });
1368
+ }
1369
+ }
1370
+ if (state.scrollHistory.length > 5) {
1371
+ state.scrollHistory.shift();
1372
+ }
1373
+ state.scrollPrev = state.scroll;
1374
+ state.scrollPrevTime = state.scrollTime;
1375
+ state.scroll = newScroll;
1376
+ state.scrollTime = currentTime;
1377
+ const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
1378
+ if (ignoreScrollFromMVCP && !scrollingTo) {
1379
+ const { lt, gt } = ignoreScrollFromMVCP;
1380
+ if (lt && newScroll < lt || gt && newScroll > gt) {
1381
+ state.ignoreScrollFromMVCPIgnored = true;
1382
+ return;
1383
+ }
1384
+ }
1385
+ if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1386
+ state.ignoreScrollFromMVCPIgnored = false;
1387
+ calculateItemsInView(ctx, state, { doMVCP: scrollingTo !== void 0 });
1388
+ checkAtBottom(ctx, state);
1389
+ checkAtTop(state);
1390
+ state.dataChangeNeedsScrollUpdate = false;
1391
+ }
1392
+ }
1393
+
1394
+ // src/core/finishScrollTo.ts
1395
+ function finishScrollTo(ctx, state) {
1396
+ if (state) {
1397
+ set$(ctx, "scrollingTo", void 0);
1398
+ state.scrollHistory.length = 0;
1399
+ }
1400
+ }
1401
+
1402
+ // src/core/scrollTo.ts
1403
+ function scrollTo(ctx, state, params) {
1404
+ var _a3;
1405
+ const { noScrollingTo, ...scrollTarget } = params;
1406
+ const { animated, isInitialScroll, offset: scrollTargetOffset } = scrollTarget;
1407
+ const {
1408
+ refScroller,
1409
+ props: { horizontal }
1410
+ } = state;
1411
+ const offset = calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1412
+ state.scrollHistory.length = 0;
1413
+ if (!noScrollingTo) {
1414
+ set$(ctx, "scrollingTo", scrollTarget);
1415
+ }
1416
+ state.scrollPending = offset;
1417
+ if (!isInitialScroll || Platform.OS === "android") {
1418
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1419
+ animated: !!animated,
1420
+ x: horizontal ? offset : 0,
1421
+ y: horizontal ? 0 : offset
1422
+ });
1423
+ }
1424
+ if (!animated) {
1425
+ state.scroll = offset;
1426
+ setTimeout(() => finishScrollTo(ctx, state), 100);
1427
+ if (isInitialScroll) {
1428
+ setTimeout(() => {
1429
+ state.initialScroll = void 0;
1430
+ }, 500);
1431
+ }
1432
+ }
1433
+ }
1434
+
1435
+ // src/utils/requestAdjust.ts
1436
+ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1437
+ if (Math.abs(positionDiff) > 0.1) {
1438
+ const doit = () => {
1439
+ {
1440
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
1201
1441
  }
1202
1442
  };
1203
1443
  state.scroll += positionDiff;
@@ -1205,24 +1445,6 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1205
1445
  const didLayout = peek$(ctx, "containersDidLayout");
1206
1446
  if (didLayout) {
1207
1447
  doit();
1208
- const threshold = state.scroll - positionDiff / 2;
1209
- if (!state.ignoreScrollFromMVCP) {
1210
- state.ignoreScrollFromMVCP = {};
1211
- }
1212
- if (positionDiff > 0) {
1213
- state.ignoreScrollFromMVCP.lt = threshold;
1214
- } else {
1215
- state.ignoreScrollFromMVCP.gt = threshold;
1216
- }
1217
- if (state.ignoreScrollFromMVCPTimeout) {
1218
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
1219
- }
1220
- state.ignoreScrollFromMVCPTimeout = setTimeout(
1221
- () => {
1222
- state.ignoreScrollFromMVCP = void 0;
1223
- },
1224
- 100
1225
- );
1226
1448
  } else {
1227
1449
  requestAnimationFrame(doit);
1228
1450
  }
@@ -1234,9 +1456,9 @@ function prepareMVCP(ctx, state, dataChanged) {
1234
1456
  const {
1235
1457
  idsInView,
1236
1458
  positions,
1237
- scrollingTo,
1238
1459
  props: { maintainVisibleContentPosition }
1239
1460
  } = state;
1461
+ const scrollingTo = peek$(ctx, "scrollingTo");
1240
1462
  let prevPosition;
1241
1463
  let targetId;
1242
1464
  const idsInViewWithPositions = [];
@@ -1277,7 +1499,16 @@ function prepareMVCP(ctx, state, dataChanged) {
1277
1499
  if (targetId !== void 0 && prevPosition !== void 0) {
1278
1500
  const newPosition = positions.get(targetId);
1279
1501
  if (newPosition !== void 0) {
1280
- positionDiff = newPosition - prevPosition;
1502
+ const totalSize = peek$(ctx, "totalSize");
1503
+ let diff = newPosition - prevPosition;
1504
+ if (diff !== 0 && state.scroll + state.scrollLength > totalSize) {
1505
+ if (diff > 0) {
1506
+ diff = Math.max(0, totalSize - state.scroll - state.scrollLength);
1507
+ } else {
1508
+ diff = 0;
1509
+ }
1510
+ }
1511
+ positionDiff = diff;
1281
1512
  }
1282
1513
  }
1283
1514
  if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
@@ -1286,6 +1517,68 @@ function prepareMVCP(ctx, state, dataChanged) {
1286
1517
  };
1287
1518
  }
1288
1519
 
1520
+ // src/core/prepareColumnStartState.ts
1521
+ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1522
+ var _a3;
1523
+ const numColumns = peek$(ctx, "numColumns");
1524
+ let rowStartIndex = startIndex;
1525
+ const columnAtStart = state.columns.get(state.idCache[startIndex]);
1526
+ if (columnAtStart !== 1) {
1527
+ rowStartIndex = findRowStartIndex(state, numColumns, startIndex);
1528
+ }
1529
+ let currentRowTop = 0;
1530
+ const curId = state.idCache[rowStartIndex];
1531
+ const column = state.columns.get(curId);
1532
+ if (rowStartIndex > 0) {
1533
+ const prevIndex = rowStartIndex - 1;
1534
+ const prevId = state.idCache[prevIndex];
1535
+ const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1536
+ const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1537
+ const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1538
+ currentRowTop = prevPosition + prevRowHeight;
1539
+ }
1540
+ return {
1541
+ column,
1542
+ currentRowTop,
1543
+ startIndex: rowStartIndex
1544
+ };
1545
+ }
1546
+ function findRowStartIndex(state, numColumns, index) {
1547
+ if (numColumns <= 1) {
1548
+ return Math.max(0, index);
1549
+ }
1550
+ let rowStart = Math.max(0, index);
1551
+ while (rowStart > 0) {
1552
+ const columnForIndex = state.columns.get(state.idCache[rowStart]);
1553
+ if (columnForIndex === 1) {
1554
+ break;
1555
+ }
1556
+ rowStart--;
1557
+ }
1558
+ return rowStart;
1559
+ }
1560
+ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1561
+ if (endIndex < startIndex) {
1562
+ return 0;
1563
+ }
1564
+ const { data } = state.props;
1565
+ if (!data) {
1566
+ return 0;
1567
+ }
1568
+ let maxSize = 0;
1569
+ for (let i = startIndex; i <= endIndex; i++) {
1570
+ if (i < 0 || i >= data.length) {
1571
+ continue;
1572
+ }
1573
+ const id = state.idCache[i];
1574
+ const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1575
+ if (size > maxSize) {
1576
+ maxSize = size;
1577
+ }
1578
+ }
1579
+ return maxSize;
1580
+ }
1581
+
1289
1582
  // src/utils/setPaddingTop.ts
1290
1583
  function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1291
1584
  if (stylePaddingTop !== void 0) {
@@ -1334,7 +1627,7 @@ function updateTotalSize(ctx, state) {
1334
1627
  if (lastId !== void 0) {
1335
1628
  const lastPosition = positions.get(lastId);
1336
1629
  if (lastPosition !== void 0) {
1337
- const lastSize = getItemSize(state, lastId, data.length - 1, data[data.length - 1]);
1630
+ const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1338
1631
  if (lastSize !== void 0) {
1339
1632
  const totalSize = lastPosition + lastSize;
1340
1633
  addTotalSize(ctx, state, null, totalSize);
@@ -1345,16 +1638,21 @@ function updateTotalSize(ctx, state) {
1345
1638
  }
1346
1639
  function addTotalSize(ctx, state, key, add) {
1347
1640
  const { alignItemsAtEnd } = state.props;
1348
- {
1641
+ const prevTotalSize = state.totalSize;
1642
+ if (key === null) {
1349
1643
  state.totalSize = add;
1350
1644
  if (state.timeoutSetPaddingTop) {
1351
1645
  clearTimeout(state.timeoutSetPaddingTop);
1352
1646
  state.timeoutSetPaddingTop = void 0;
1353
1647
  }
1648
+ } else {
1649
+ state.totalSize += add;
1354
1650
  }
1355
- set$(ctx, "totalSize", state.totalSize);
1356
- if (alignItemsAtEnd) {
1357
- updateAlignItemsPaddingTop(ctx, state);
1651
+ if (prevTotalSize !== state.totalSize) {
1652
+ set$(ctx, "totalSize", state.totalSize);
1653
+ if (alignItemsAtEnd) {
1654
+ updateAlignItemsPaddingTop(ctx, state);
1655
+ }
1358
1656
  }
1359
1657
  }
1360
1658
 
@@ -1373,9 +1671,9 @@ function updateSnapToOffsets(ctx, state) {
1373
1671
  set$(ctx, "snapToOffsets", snapToOffsets);
1374
1672
  }
1375
1673
 
1376
- // src/core/updateAllPositions.ts
1377
- function updateAllPositions(ctx, state, dataChanged, startIndex = 0) {
1378
- var _a, _b, _c, _d, _e, _f;
1674
+ // src/core/updateItemPositions.ts
1675
+ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered } = { scrollBottomBuffered: -1, startIndex: 0 }) {
1676
+ var _a3, _b, _c, _d;
1379
1677
  const {
1380
1678
  columns,
1381
1679
  indexByKey,
@@ -1385,32 +1683,49 @@ function updateAllPositions(ctx, state, dataChanged, startIndex = 0) {
1385
1683
  props: { getEstimatedItemSize, snapToIndices, enableAverages }
1386
1684
  } = state;
1387
1685
  const data = state.props.data;
1686
+ const dataLength = data.length;
1388
1687
  const numColumns = peek$(ctx, "numColumns");
1389
- const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
1688
+ const scrollingTo = peek$(ctx, "scrollingTo");
1689
+ const hasColumns = numColumns > 1;
1690
+ const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1691
+ const maxVisibleArea = scrollBottomBuffered + 1e3;
1390
1692
  const useAverageSize = enableAverages && !getEstimatedItemSize;
1391
1693
  let currentRowTop = 0;
1392
1694
  let column = 1;
1393
1695
  let maxSizeInRow = 0;
1394
- const hasColumns = numColumns > 1;
1395
1696
  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
1697
  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);
1698
+ const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
1699
+ ctx,
1700
+ state,
1701
+ startIndex,
1702
+ useAverageSize
1703
+ );
1704
+ startIndex = processedStartIndex;
1705
+ currentRowTop = initialRowTop;
1706
+ } else if (startIndex < dataLength) {
1707
+ const prevIndex = startIndex - 1;
1708
+ const prevId = getId(state, prevIndex);
1709
+ const prevPosition = (_a3 = positions.get(prevId)) != null ? _a3 : 0;
1710
+ const prevSize = (_b = sizesKnown.get(prevId)) != null ? _b : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize);
1405
1711
  currentRowTop = prevPosition + prevSize;
1406
1712
  }
1407
1713
  }
1408
1714
  const needsIndexByKey = dataChanged || indexByKey.size === 0;
1409
- const dataLength = data.length;
1715
+ let didBreakEarly = false;
1716
+ let breakAt;
1410
1717
  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) {
1718
+ if (breakAt && i > breakAt) {
1719
+ didBreakEarly = true;
1720
+ break;
1721
+ }
1722
+ if (breakAt === void 0 && !scrollingTo && !dataChanged && currentRowTop > maxVisibleArea) {
1723
+ const itemsPerRow = hasColumns ? numColumns : 1;
1724
+ breakAt = i + itemsPerRow + 10;
1725
+ }
1726
+ const id = (_c = idCache[i]) != null ? _c : getId(state, i);
1727
+ const size = (_d = sizesKnown.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i], useAverageSize);
1728
+ if (IS_DEV && needsIndexByKey) {
1414
1729
  if (indexByKeyForChecking.has(id)) {
1415
1730
  console.error(
1416
1731
  `[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 +1752,9 @@ function updateAllPositions(ctx, state, dataChanged, startIndex = 0) {
1437
1752
  currentRowTop += size;
1438
1753
  }
1439
1754
  }
1440
- updateTotalSize(ctx, state);
1755
+ if (!didBreakEarly) {
1756
+ updateTotalSize(ctx, state);
1757
+ }
1441
1758
  if (snapToIndices) {
1442
1759
  updateSnapToOffsets(ctx, state);
1443
1760
  }
@@ -1457,6 +1774,21 @@ function ensureViewabilityState(ctx, configId) {
1457
1774
  }
1458
1775
  return state;
1459
1776
  }
1777
+ function setupViewability(props) {
1778
+ let { viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged } = props;
1779
+ if (viewabilityConfig || onViewableItemsChanged) {
1780
+ viewabilityConfigCallbackPairs = [
1781
+ ...viewabilityConfigCallbackPairs || [],
1782
+ {
1783
+ onViewableItemsChanged,
1784
+ viewabilityConfig: viewabilityConfig || {
1785
+ viewAreaCoveragePercentThreshold: 0
1786
+ }
1787
+ }
1788
+ ];
1789
+ }
1790
+ return viewabilityConfigCallbackPairs;
1791
+ }
1460
1792
  function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end) {
1461
1793
  const {
1462
1794
  timeouts,
@@ -1628,9 +1960,12 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
1628
1960
  }
1629
1961
 
1630
1962
  // src/utils/checkAllSizesKnown.ts
1963
+ function isNullOrUndefined2(value) {
1964
+ return value === null || value === void 0;
1965
+ }
1631
1966
  function checkAllSizesKnown(state) {
1632
1967
  const { startBuffered, endBuffered, sizesKnown } = state;
1633
- if (endBuffered !== null && startBuffered >= 0 && endBuffered >= 0) {
1968
+ if (!isNullOrUndefined2(endBuffered) && !isNullOrUndefined2(startBuffered) && startBuffered >= 0 && endBuffered >= 0) {
1634
1969
  let areAllKnown = true;
1635
1970
  for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
1636
1971
  const key = getId(state, i);
@@ -1647,6 +1982,8 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1647
1982
  const { stickyContainerPool, containerItemTypes } = state;
1648
1983
  const result = [];
1649
1984
  const availableContainers = [];
1985
+ const pendingRemovalSet = new Set(pendingRemoval);
1986
+ let pendingRemovalChanged = false;
1650
1987
  const stickyIndicesSet = state.props.stickyIndicesSet;
1651
1988
  const stickyItemIndices = (needNewContainers == null ? void 0 : needNewContainers.filter((index) => stickyIndicesSet.has(index))) || [];
1652
1989
  const canReuseContainer = (containerIndex, requiredType) => {
@@ -1662,12 +1999,11 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1662
1999
  let foundContainer = false;
1663
2000
  for (const containerIndex of stickyContainerPool) {
1664
2001
  const key = peek$(ctx, `containerItemKey${containerIndex}`);
1665
- const isPendingRemoval = pendingRemoval.includes(containerIndex);
2002
+ const isPendingRemoval = pendingRemovalSet.has(containerIndex);
1666
2003
  if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType)) {
1667
2004
  result.push(containerIndex);
1668
- if (isPendingRemoval) {
1669
- const index = pendingRemoval.indexOf(containerIndex);
1670
- pendingRemoval.splice(index, 1);
2005
+ if (isPendingRemoval && pendingRemovalSet.delete(containerIndex)) {
2006
+ pendingRemovalChanged = true;
1671
2007
  }
1672
2008
  foundContainer = true;
1673
2009
  if (requiredItemTypes) typeIndex++;
@@ -1687,13 +2023,11 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1687
2023
  }
1688
2024
  const key = peek$(ctx, `containerItemKey${u}`);
1689
2025
  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
- }
2026
+ if (!isOk && pendingRemovalSet.has(u)) {
2027
+ pendingRemovalSet.delete(u);
2028
+ pendingRemovalChanged = true;
2029
+ const requiredType = neededTypes[typeIndex];
2030
+ isOk = canReuseContainer(u, requiredType);
1697
2031
  }
1698
2032
  if (isOk) {
1699
2033
  result.push(u);
@@ -1736,7 +2070,7 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1736
2070
  for (let i = 0; i < stillNeeded; i++) {
1737
2071
  result.push(numContainers + i);
1738
2072
  }
1739
- if (__DEV__ && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
2073
+ if (IS_DEV && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
1740
2074
  console.warn(
1741
2075
  "[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
2076
  {
@@ -1751,6 +2085,12 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1751
2085
  }
1752
2086
  }
1753
2087
  }
2088
+ if (pendingRemovalChanged) {
2089
+ pendingRemoval.length = 0;
2090
+ for (const value of pendingRemovalSet) {
2091
+ pendingRemoval.push(value);
2092
+ }
2093
+ }
1754
2094
  return result.sort(comparatorDefault);
1755
2095
  }
1756
2096
  function comparatorByDistance(a, b) {
@@ -1807,72 +2147,16 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
1807
2147
  if (isLast && viewPosition === void 0) {
1808
2148
  viewPosition = 1;
1809
2149
  }
1810
- const firstIndexScrollPostion = firstIndexOffset - viewOffset;
1811
2150
  state.scrollForNextCalculateItemsInView = void 0;
1812
- scrollTo(state, {
2151
+ scrollTo(ctx, state, {
1813
2152
  animated,
1814
2153
  index,
1815
- offset: firstIndexScrollPostion,
2154
+ offset: firstIndexOffset,
1816
2155
  viewOffset,
1817
2156
  viewPosition: viewPosition != null ? viewPosition : 0
1818
2157
  });
1819
2158
  }
1820
2159
 
1821
- // 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) {
1836
- return false;
1837
- }
1838
- }
1839
- return isReached;
1840
- };
1841
-
1842
- // src/utils/checkAtBottom.ts
1843
- function checkAtBottom(ctx, state) {
1844
- if (!state) {
1845
- return;
1846
- }
1847
- const {
1848
- queuedInitialLayout,
1849
- scrollLength,
1850
- scroll,
1851
- maintainingScrollAtEnd,
1852
- props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
1853
- } = state;
1854
- const contentSize = getContentSize(ctx);
1855
- if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1856
- const distanceFromEnd = contentSize - scroll - scrollLength;
1857
- const isContentLess = contentSize < scrollLength;
1858
- state.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1859
- state.isEndReached = checkThreshold(
1860
- distanceFromEnd,
1861
- isContentLess,
1862
- onEndReachedThreshold * scrollLength,
1863
- state.isEndReached,
1864
- state.endReachedBlockedByTimer,
1865
- (distance) => {
1866
- var _a, _b;
1867
- return (_b = (_a = state.props).onEndReached) == null ? void 0 : _b.call(_a, { distanceFromEnd: distance });
1868
- },
1869
- (block) => {
1870
- state.endReachedBlockedByTimer = block;
1871
- }
1872
- );
1873
- }
1874
- }
1875
-
1876
2160
  // src/utils/setDidLayout.ts
1877
2161
  function setDidLayout(ctx, state) {
1878
2162
  const {
@@ -1895,11 +2179,12 @@ function setDidLayout(ctx, state) {
1895
2179
 
1896
2180
  // src/core/calculateItemsInView.ts
1897
2181
  function findCurrentStickyIndex(stickyArray, scroll, state) {
1898
- var _a;
2182
+ var _a3;
1899
2183
  const idCache = state.idCache;
1900
2184
  const positions = state.positions;
1901
2185
  for (let i = stickyArray.length - 1; i >= 0; i--) {
1902
- const stickyId = (_a = idCache.get(stickyArray[i])) != null ? _a : getId(state, stickyArray[i]);
2186
+ const stickyIndex = stickyArray[i];
2187
+ const stickyId = (_a3 = idCache[stickyIndex]) != null ? _a3 : getId(state, stickyIndex);
1903
2188
  const stickyPos = stickyId ? positions.get(stickyId) : void 0;
1904
2189
  if (stickyPos !== void 0 && scroll >= stickyPos) {
1905
2190
  return i;
@@ -1912,42 +2197,46 @@ function getActiveStickyIndices(ctx, state, stickyIndices) {
1912
2197
  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
2198
  );
1914
2199
  }
1915
- function handleStickyActivation(ctx, state, stickyIndices, stickyArray, scroll, needNewContainers, startBuffered, endBuffered) {
1916
- var _a;
2200
+ function handleStickyActivation(ctx, state, stickyIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2201
+ var _a3;
1917
2202
  const activeIndices = getActiveStickyIndices(ctx, state, stickyIndices);
1918
- const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
2203
+ state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
1919
2204
  for (let offset = 0; offset <= 1; offset++) {
1920
2205
  const idx = currentStickyIdx - offset;
1921
2206
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
1922
2207
  const stickyIndex = stickyArray[idx];
1923
- const stickyId = (_a = state.idCache.get(stickyIndex)) != null ? _a : getId(state, stickyIndex);
2208
+ const stickyId = (_a3 = state.idCache[stickyIndex]) != null ? _a3 : getId(state, stickyIndex);
1924
2209
  if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered)) {
1925
2210
  needNewContainers.push(stickyIndex);
1926
2211
  }
1927
2212
  }
1928
2213
  }
1929
- function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, pendingRemoval) {
1930
- var _a, _b, _c;
1931
- const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
2214
+ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2215
+ var _a3, _b, _c;
1932
2216
  for (const containerIndex of state.stickyContainerPool) {
1933
2217
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
1934
2218
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
1935
2219
  if (itemIndex === void 0) continue;
1936
2220
  const arrayIdx = stickyArray.indexOf(itemIndex);
1937
- if (arrayIdx === -1) continue;
2221
+ if (arrayIdx === -1) {
2222
+ state.stickyContainerPool.delete(containerIndex);
2223
+ set$(ctx, `containerSticky${containerIndex}`, false);
2224
+ set$(ctx, `containerStickyOffset${containerIndex}`, void 0);
2225
+ continue;
2226
+ }
1938
2227
  const isRecentSticky = arrayIdx >= currentStickyIdx - 1 && arrayIdx <= currentStickyIdx + 1;
1939
2228
  if (isRecentSticky) continue;
1940
2229
  const nextIndex = stickyArray[arrayIdx + 1];
1941
2230
  let shouldRecycle = false;
1942
2231
  if (nextIndex) {
1943
- const nextId = (_a = state.idCache.get(nextIndex)) != null ? _a : getId(state, nextIndex);
2232
+ const nextId = (_a3 = state.idCache[nextIndex]) != null ? _a3 : getId(state, nextIndex);
1944
2233
  const nextPos = nextId ? state.positions.get(nextId) : void 0;
1945
2234
  shouldRecycle = nextPos !== void 0 && scroll > nextPos + scrollBuffer * 2;
1946
2235
  } else {
1947
- const currentId = (_b = state.idCache.get(itemIndex)) != null ? _b : getId(state, itemIndex);
2236
+ const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
1948
2237
  if (currentId) {
1949
2238
  const currentPos = state.positions.get(currentId);
1950
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(state, currentId, itemIndex, state.props.data[itemIndex]);
2239
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
1951
2240
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
1952
2241
  }
1953
2242
  }
@@ -1958,7 +2247,7 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, pe
1958
2247
  }
1959
2248
  function calculateItemsInView(ctx, state, params = {}) {
1960
2249
  unstable_batchedUpdates(() => {
1961
- var _a, _b, _c, _d, _e, _f, _g, _h;
2250
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1962
2251
  const {
1963
2252
  columns,
1964
2253
  containerItemKeys,
@@ -1972,7 +2261,7 @@ function calculateItemsInView(ctx, state, params = {}) {
1972
2261
  sizes,
1973
2262
  startBufferedId: startBufferedIdOrig,
1974
2263
  viewabilityConfigCallbackPairs,
1975
- props: { getItemType, initialScroll, itemsAreEqual, keyExtractor, scrollBuffer }
2264
+ props: { getItemType, initialScroll, itemsAreEqual, keyExtractor, onStickyHeaderChange, scrollBuffer }
1976
2265
  } = state;
1977
2266
  const { data } = state.props;
1978
2267
  const stickyIndicesArr = state.props.stickyIndicesArr || [];
@@ -1984,35 +2273,22 @@ function calculateItemsInView(ctx, state, params = {}) {
1984
2273
  const totalSize = peek$(ctx, "totalSize");
1985
2274
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
1986
2275
  const numColumns = peek$(ctx, "numColumns");
1987
- const previousScrollAdjust = 0;
1988
2276
  const { dataChanged, doMVCP } = params;
1989
2277
  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
2278
  const scrollExtra = 0;
2005
2279
  const { queuedInitialLayout } = state;
2006
2280
  let { scroll: scrollState } = state;
2007
2281
  if (!queuedInitialLayout && initialScroll) {
2008
2282
  const updatedOffset = calculateOffsetWithOffsetPosition(
2283
+ ctx,
2009
2284
  state,
2010
2285
  calculateOffsetForIndex(ctx, state, initialScroll.index),
2011
2286
  initialScroll
2012
2287
  );
2013
2288
  scrollState = updatedOffset;
2014
2289
  }
2015
- const scrollAdjustPad = -previousScrollAdjust - topPad;
2290
+ const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2291
+ const scrollAdjustPad = scrollAdjustPending - topPad;
2016
2292
  let scroll = scrollState + scrollExtra + scrollAdjustPad;
2017
2293
  if (scroll + scrollLength > totalSize) {
2018
2294
  scroll = Math.max(0, totalSize - scrollLength);
@@ -2021,6 +2297,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2021
2297
  set$(ctx, "debugRawScroll", scrollState);
2022
2298
  set$(ctx, "debugComputedScroll", scroll);
2023
2299
  }
2300
+ const previousStickyIndex = state.activeStickyIndex;
2301
+ const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2302
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2303
+ state.activeStickyIndex = nextActiveStickyIndex;
2304
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2024
2305
  let scrollBufferTop = scrollBuffer;
2025
2306
  let scrollBufferBottom = scrollBuffer;
2026
2307
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2033,22 +2314,34 @@ function calculateItemsInView(ctx, state, params = {}) {
2033
2314
  const scrollTopBuffered = scroll - scrollBufferTop;
2034
2315
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
2035
2316
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
2036
- if (scrollForNextCalculateItemsInView) {
2317
+ if (!dataChanged && scrollForNextCalculateItemsInView) {
2037
2318
  const { top, bottom } = scrollForNextCalculateItemsInView;
2038
2319
  if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2039
2320
  return;
2040
2321
  }
2041
2322
  }
2323
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2324
+ if (dataChanged) {
2325
+ indexByKey.clear();
2326
+ idCache.length = 0;
2327
+ positions.clear();
2328
+ }
2329
+ const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2330
+ updateItemPositions(ctx, state, dataChanged, { scrollBottomBuffered, startIndex });
2331
+ if (minIndexSizeChanged !== void 0) {
2332
+ state.minIndexSizeChanged = void 0;
2333
+ }
2334
+ checkMVCP == null ? void 0 : checkMVCP();
2042
2335
  let startNoBuffer = null;
2043
2336
  let startBuffered = null;
2044
2337
  let startBufferedId = null;
2045
2338
  let endNoBuffer = null;
2046
2339
  let endBuffered = null;
2047
- let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
2340
+ let loopStart = !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
2048
2341
  for (let i = loopStart; i >= 0; i--) {
2049
- const id = (_a = idCache.get(i)) != null ? _a : getId(state, i);
2342
+ const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2050
2343
  const top = positions.get(id);
2051
- const size = (_b = sizes.get(id)) != null ? _b : getItemSize(state, id, i, data[i]);
2344
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2052
2345
  const bottom = top + size;
2053
2346
  if (bottom > scroll - scrollBuffer) {
2054
2347
  loopStart = i;
@@ -2074,8 +2367,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2074
2367
  let firstFullyOnScreenIndex;
2075
2368
  const dataLength = data.length;
2076
2369
  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]);
2370
+ const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2371
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2079
2372
  const top = positions.get(id);
2080
2373
  if (!foundEnd) {
2081
2374
  if (startNoBuffer === null && top + size > scroll) {
@@ -2104,7 +2397,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2104
2397
  }
2105
2398
  const idsInView = [];
2106
2399
  for (let i = firstFullyOnScreenIndex; i <= endNoBuffer; i++) {
2107
- const id = (_e = idCache.get(i)) != null ? _e : getId(state, i);
2400
+ const id = (_g = idCache[i]) != null ? _g : getId(state, i);
2108
2401
  idsInView.push(id);
2109
2402
  }
2110
2403
  Object.assign(state, {
@@ -2136,7 +2429,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2136
2429
  let numContainers2 = prevNumContainers;
2137
2430
  const needNewContainers = [];
2138
2431
  for (let i = startBuffered; i <= endBuffered; i++) {
2139
- const id = (_f = idCache.get(i)) != null ? _f : getId(state, i);
2432
+ const id = (_h = idCache[i]) != null ? _h : getId(state, i);
2140
2433
  if (!containerItemKeys.has(id)) {
2141
2434
  needNewContainers.push(i);
2142
2435
  }
@@ -2147,11 +2440,14 @@ function calculateItemsInView(ctx, state, params = {}) {
2147
2440
  state,
2148
2441
  stickyIndicesSet,
2149
2442
  stickyIndicesArr,
2150
- scroll,
2443
+ currentStickyIdx,
2151
2444
  needNewContainers,
2152
2445
  startBuffered,
2153
2446
  endBuffered
2154
2447
  );
2448
+ } else {
2449
+ state.activeStickyIndex = void 0;
2450
+ set$(ctx, "activeStickyIndex", void 0);
2155
2451
  }
2156
2452
  if (needNewContainers.length > 0) {
2157
2453
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
@@ -2171,7 +2467,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2171
2467
  for (let idx = 0; idx < needNewContainers.length; idx++) {
2172
2468
  const i = needNewContainers[idx];
2173
2469
  const containerIndex = availableContainers[idx];
2174
- const id = (_g = idCache.get(i)) != null ? _g : getId(state, i);
2470
+ const id = (_i = idCache[i]) != null ? _i : getId(state, i);
2175
2471
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
2176
2472
  if (oldKey && oldKey !== id) {
2177
2473
  containerItemKeys.delete(oldKey);
@@ -2185,9 +2481,10 @@ function calculateItemsInView(ctx, state, params = {}) {
2185
2481
  if (stickyIndicesSet.has(i)) {
2186
2482
  set$(ctx, `containerSticky${containerIndex}`, true);
2187
2483
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2188
- set$(ctx, `containerStickyOffset${containerIndex}`, createAnimatedValue(topPadding));
2484
+ set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2189
2485
  state.stickyContainerPool.add(containerIndex);
2190
2486
  } else {
2487
+ set$(ctx, `containerSticky${containerIndex}`, false);
2191
2488
  state.stickyContainerPool.delete(containerIndex);
2192
2489
  }
2193
2490
  if (containerIndex >= numContainers2) {
@@ -2203,7 +2500,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2203
2500
  }
2204
2501
  }
2205
2502
  if (stickyIndicesArr.length > 0) {
2206
- handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, pendingRemoval);
2503
+ handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2207
2504
  }
2208
2505
  let didChangePositions = false;
2209
2506
  for (let i = 0; i < numContainers; i++) {
@@ -2226,11 +2523,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2226
2523
  const itemIndex = indexByKey.get(itemKey);
2227
2524
  const item = data[itemIndex];
2228
2525
  if (item !== void 0) {
2229
- const id = (_h = idCache.get(itemIndex)) != null ? _h : getId(state, itemIndex);
2230
- const position = positions.get(id);
2231
- if (position === void 0) {
2526
+ const id = (_j = idCache[itemIndex]) != null ? _j : getId(state, itemIndex);
2527
+ const positionValue = positions.get(id);
2528
+ if (positionValue === void 0) {
2232
2529
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2233
2530
  } else {
2531
+ const position = (positionValue || 0) - scrollAdjustPending;
2234
2532
  const column = columns.get(id) || 1;
2235
2533
  const prevPos = peek$(ctx, `containerPosition${i}`);
2236
2534
  const prevColumn = peek$(ctx, `containerColumn${i}`);
@@ -2243,7 +2541,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2243
2541
  set$(ctx, `containerColumn${i}`, column);
2244
2542
  }
2245
2543
  if (prevData !== item && (itemsAreEqual ? !itemsAreEqual(prevData, item, itemIndex, data) : true)) {
2246
- set$(ctx, `containerItemData${i}`, data[itemIndex]);
2544
+ set$(ctx, `containerItemData${i}`, item);
2247
2545
  }
2248
2546
  }
2249
2547
  }
@@ -2260,12 +2558,122 @@ function calculateItemsInView(ctx, state, params = {}) {
2260
2558
  if (viewabilityConfigCallbackPairs) {
2261
2559
  updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollLength, startNoBuffer, endNoBuffer);
2262
2560
  }
2561
+ if (onStickyHeaderChange && stickyIndicesArr.length > 0 && nextActiveStickyIndex !== void 0 && nextActiveStickyIndex !== previousStickyIndex) {
2562
+ const item = data[nextActiveStickyIndex];
2563
+ if (item !== void 0) {
2564
+ onStickyHeaderChange({ index: nextActiveStickyIndex, item });
2565
+ }
2566
+ }
2263
2567
  });
2264
2568
  }
2265
2569
 
2570
+ // src/core/doMaintainScrollAtEnd.ts
2571
+ function doMaintainScrollAtEnd(ctx, state, animated) {
2572
+ const {
2573
+ refScroller,
2574
+ props: { maintainScrollAtEnd }
2575
+ } = state;
2576
+ if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2577
+ const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2578
+ if (paddingTop > 0) {
2579
+ state.scroll = 0;
2580
+ }
2581
+ requestAnimationFrame(() => {
2582
+ var _a3;
2583
+ if (state == null ? void 0 : state.isAtEnd) {
2584
+ state.maintainingScrollAtEnd = true;
2585
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2586
+ animated
2587
+ });
2588
+ setTimeout(
2589
+ () => {
2590
+ state.maintainingScrollAtEnd = false;
2591
+ },
2592
+ 0
2593
+ );
2594
+ }
2595
+ });
2596
+ return true;
2597
+ }
2598
+ }
2599
+
2600
+ // src/utils/updateAveragesOnDataChange.ts
2601
+ function updateAveragesOnDataChange(state, oldData, newData) {
2602
+ var _a3;
2603
+ const {
2604
+ averageSizes,
2605
+ sizesKnown,
2606
+ indexByKey,
2607
+ props: { itemsAreEqual, getItemType, keyExtractor }
2608
+ } = state;
2609
+ if (!itemsAreEqual || !oldData.length || !newData.length) {
2610
+ for (const key in averageSizes) {
2611
+ delete averageSizes[key];
2612
+ }
2613
+ return;
2614
+ }
2615
+ const itemTypesToPreserve = {};
2616
+ const newDataLength = newData.length;
2617
+ const oldDataLength = oldData.length;
2618
+ for (let newIndex = 0; newIndex < newDataLength; newIndex++) {
2619
+ const newItem = newData[newIndex];
2620
+ const id = keyExtractor ? keyExtractor(newItem, newIndex) : String(newIndex);
2621
+ const oldIndex = indexByKey.get(id);
2622
+ if (oldIndex !== void 0 && oldIndex < oldDataLength) {
2623
+ const knownSize = sizesKnown.get(id);
2624
+ if (knownSize === void 0) continue;
2625
+ const oldItem = oldData[oldIndex];
2626
+ const areEqual = itemsAreEqual(oldItem, newItem, newIndex, newData);
2627
+ if (areEqual) {
2628
+ const itemType = getItemType ? (_a3 = getItemType(newItem, newIndex)) != null ? _a3 : "" : "";
2629
+ let typeData = itemTypesToPreserve[itemType];
2630
+ if (!typeData) {
2631
+ typeData = itemTypesToPreserve[itemType] = { count: 0, totalSize: 0 };
2632
+ }
2633
+ typeData.totalSize += knownSize;
2634
+ typeData.count++;
2635
+ }
2636
+ }
2637
+ }
2638
+ for (const key in averageSizes) {
2639
+ delete averageSizes[key];
2640
+ }
2641
+ for (const itemType in itemTypesToPreserve) {
2642
+ const { totalSize, count } = itemTypesToPreserve[itemType];
2643
+ if (count > 0) {
2644
+ averageSizes[itemType] = {
2645
+ avg: totalSize / count,
2646
+ num: count
2647
+ };
2648
+ }
2649
+ }
2650
+ }
2651
+
2652
+ // src/core/checkResetContainers.ts
2653
+ function checkResetContainers(ctx, state, isFirst, dataProp) {
2654
+ if (state) {
2655
+ if (!isFirst && state.props.data !== dataProp) {
2656
+ updateAveragesOnDataChange(state, state.props.data, dataProp);
2657
+ }
2658
+ const { maintainScrollAtEnd } = state.props;
2659
+ if (!isFirst) {
2660
+ calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2661
+ const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2662
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2663
+ if (!didMaintainScrollAtEnd && dataProp.length > state.props.data.length) {
2664
+ state.isEndReached = false;
2665
+ }
2666
+ if (!didMaintainScrollAtEnd) {
2667
+ checkAtTop(state);
2668
+ checkAtBottom(ctx, state);
2669
+ }
2670
+ }
2671
+ }
2672
+ }
2673
+
2266
2674
  // src/core/doInitialAllocateContainers.ts
2267
2675
  function doInitialAllocateContainers(ctx, state) {
2268
- var _a;
2676
+ var _a3, _b, _c;
2269
2677
  const {
2270
2678
  scrollLength,
2271
2679
  props: {
@@ -2281,12 +2689,13 @@ function doInitialAllocateContainers(ctx, state) {
2281
2689
  const hasContainers = peek$(ctx, "numContainers");
2282
2690
  if (scrollLength > 0 && data.length > 0 && !hasContainers) {
2283
2691
  let averageItemSize;
2284
- const fn = getFixedItemSize || getEstimatedItemSize;
2285
- if (fn) {
2692
+ if (getFixedItemSize || getEstimatedItemSize) {
2286
2693
  let totalSize = 0;
2287
2694
  const num = Math.min(20, data.length);
2288
2695
  for (let i = 0; i < num; i++) {
2289
- totalSize += fn(0, data[0], getItemType ? (_a = getItemType(data[0], 0)) != null ? _a : "" : "");
2696
+ const item = data[i];
2697
+ const itemType = getItemType ? (_a3 = getItemType(item, i)) != null ? _a3 : "" : "";
2698
+ totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
2290
2699
  }
2291
2700
  averageItemSize = totalSize / num;
2292
2701
  } else {
@@ -2302,74 +2711,16 @@ function doInitialAllocateContainers(ctx, state) {
2302
2711
  if (state.lastLayout) {
2303
2712
  if (state.props.initialScroll) {
2304
2713
  requestAnimationFrame(() => {
2305
- calculateItemsInView(ctx, state, { dataChanged: true });
2714
+ calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2306
2715
  });
2307
2716
  } else {
2308
- calculateItemsInView(ctx, state, { dataChanged: true });
2717
+ calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2309
2718
  }
2310
2719
  }
2311
2720
  return true;
2312
2721
  }
2313
2722
  }
2314
2723
 
2315
- // src/core/doMaintainScrollAtEnd.ts
2316
- function doMaintainScrollAtEnd(ctx, state, animated) {
2317
- const {
2318
- refScroller,
2319
- props: { maintainScrollAtEnd }
2320
- } = state;
2321
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2322
- const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2323
- if (paddingTop > 0) {
2324
- state.scroll = 0;
2325
- }
2326
- requestAnimationFrame(() => {
2327
- var _a;
2328
- if (state == null ? void 0 : state.isAtEnd) {
2329
- state.maintainingScrollAtEnd = true;
2330
- (_a = refScroller.current) == null ? void 0 : _a.scrollToEnd({
2331
- animated
2332
- });
2333
- setTimeout(
2334
- () => {
2335
- state.maintainingScrollAtEnd = false;
2336
- },
2337
- 0
2338
- );
2339
- }
2340
- });
2341
- return true;
2342
- }
2343
- }
2344
-
2345
- // src/utils/checkAtTop.ts
2346
- function checkAtTop(state) {
2347
- if (!state) {
2348
- return;
2349
- }
2350
- const {
2351
- scrollLength,
2352
- scroll,
2353
- props: { onStartReachedThreshold }
2354
- } = state;
2355
- const distanceFromTop = scroll;
2356
- state.isAtStart = distanceFromTop <= 0;
2357
- state.isStartReached = checkThreshold(
2358
- distanceFromTop,
2359
- false,
2360
- onStartReachedThreshold * scrollLength,
2361
- state.isStartReached,
2362
- state.startReachedBlockedByTimer,
2363
- (distance) => {
2364
- var _a, _b;
2365
- return (_b = (_a = state.props).onStartReached) == null ? void 0 : _b.call(_a, { distanceFromStart: distance });
2366
- },
2367
- (block) => {
2368
- state.startReachedBlockedByTimer = block;
2369
- }
2370
- );
2371
- }
2372
-
2373
2724
  // src/core/handleLayout.ts
2374
2725
  function handleLayout(ctx, state, layout, setCanRender) {
2375
2726
  const { maintainScrollAtEnd } = state.props;
@@ -2404,87 +2755,55 @@ function handleLayout(ctx, state, layout, setCanRender) {
2404
2755
  if (state) {
2405
2756
  state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
2406
2757
  }
2407
- if (__DEV__ && measuredLength === 0) {
2758
+ if (IS_DEV && measuredLength === 0) {
2408
2759
  warnDevOnce(
2409
2760
  "height0",
2410
2761
  `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
2762
  );
2412
2763
  }
2413
- setCanRender(true);
2414
- }
2415
- }
2416
-
2417
- // src/core/onScroll.ts
2418
- function onScroll(ctx, state, event) {
2419
- var _a, _b, _c;
2420
- const {
2421
- scrollProcessingEnabled,
2422
- props: { onScroll: onScrollProp }
2423
- } = state;
2424
- if (scrollProcessingEnabled === false) {
2425
- return;
2426
- }
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) {
2428
- return;
2429
- }
2430
- 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
- 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
- }
2448
- onScrollProp == null ? void 0 : onScrollProp(event);
2449
- }
2450
- function updateScroll(ctx, state, newScroll) {
2451
- const scrollingTo = state.scrollingTo;
2452
- state.hasScrolled = true;
2453
- state.lastBatchingAction = Date.now();
2454
- const currentTime = Date.now();
2455
- 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 });
2458
- }
2459
- if (state.scrollHistory.length > 5) {
2460
- state.scrollHistory.shift();
2461
- }
2462
- state.scrollPrev = state.scroll;
2463
- state.scrollPrevTime = state.scrollTime;
2464
- state.scroll = newScroll;
2465
- state.scrollTime = currentTime;
2466
- if (Math.abs(state.scroll - state.scrollPrev) > 2) {
2467
- calculateItemsInView(ctx, state);
2468
- checkAtBottom(ctx, state);
2469
- checkAtTop(state);
2470
2764
  }
2765
+ setCanRender(true);
2471
2766
  }
2472
2767
 
2473
2768
  // src/core/ScrollAdjustHandler.ts
2474
2769
  var ScrollAdjustHandler = class {
2475
2770
  constructor(ctx) {
2476
2771
  this.appliedAdjust = 0;
2772
+ this.pendingAdjust = 0;
2477
2773
  this.mounted = false;
2478
2774
  this.context = ctx;
2775
+ {
2776
+ const commitPendingAdjust = () => {
2777
+ const state = this.context.internalState;
2778
+ const pending = this.pendingAdjust;
2779
+ this.pendingAdjust = 0;
2780
+ this.appliedAdjust += pending;
2781
+ state.scroll += pending;
2782
+ state.scrollForNextCalculateItemsInView = void 0;
2783
+ set$(this.context, "scrollAdjustPending", 0);
2784
+ set$(this.context, "scrollAdjust", this.appliedAdjust);
2785
+ calculateItemsInView(this.context, this.context.internalState);
2786
+ };
2787
+ listen$(this.context, "scrollingTo", (value) => {
2788
+ if (value === void 0) {
2789
+ commitPendingAdjust();
2790
+ }
2791
+ });
2792
+ }
2479
2793
  }
2480
2794
  requestAdjust(add) {
2481
- const oldAdjustTop = peek$(this.context, "scrollAdjust") || 0;
2482
- this.appliedAdjust = add + oldAdjustTop;
2483
- const set = () => set$(this.context, "scrollAdjust", this.appliedAdjust);
2484
- if (this.mounted) {
2485
- set();
2795
+ const scrollingTo = peek$(this.context, "scrollingTo");
2796
+ if ((scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2797
+ this.pendingAdjust += add;
2798
+ set$(this.context, "scrollAdjustPending", this.pendingAdjust);
2486
2799
  } else {
2487
- requestAnimationFrame(set);
2800
+ this.appliedAdjust += add;
2801
+ const setter = () => set$(this.context, "scrollAdjust", this.appliedAdjust);
2802
+ if (this.mounted) {
2803
+ setter();
2804
+ } else {
2805
+ requestAnimationFrame(setter);
2806
+ }
2488
2807
  }
2489
2808
  }
2490
2809
  setMounted() {
@@ -2497,14 +2816,13 @@ var ScrollAdjustHandler = class {
2497
2816
 
2498
2817
  // src/core/updateItemSize.ts
2499
2818
  function updateItemSize(ctx, state, itemKey, sizeObj) {
2500
- var _a, _b;
2819
+ var _a3;
2501
2820
  const {
2502
2821
  sizesKnown,
2503
2822
  props: {
2504
2823
  getFixedItemSize,
2505
2824
  getItemType,
2506
2825
  horizontal,
2507
- maintainVisibleContentPosition,
2508
2826
  suggestEstimatedItemSize,
2509
2827
  onItemSizeChanged,
2510
2828
  data,
@@ -2512,17 +2830,17 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2512
2830
  }
2513
2831
  } = state;
2514
2832
  if (!data) return;
2833
+ const index = state.indexByKey.get(itemKey);
2515
2834
  if (getFixedItemSize) {
2516
- const index2 = state.indexByKey.get(itemKey);
2517
- if (index2 === void 0) {
2835
+ if (index === void 0) {
2518
2836
  return;
2519
2837
  }
2520
- const itemData = state.props.data[index2];
2838
+ const itemData = state.props.data[index];
2521
2839
  if (itemData === void 0) {
2522
2840
  return;
2523
2841
  }
2524
- const type = getItemType ? (_a = getItemType(itemData, index2)) != null ? _a : "" : "";
2525
- const size2 = getFixedItemSize(index2, itemData, type);
2842
+ const type = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
2843
+ const size2 = getFixedItemSize(index, itemData, type);
2526
2844
  if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
2527
2845
  return;
2528
2846
  }
@@ -2532,15 +2850,11 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2532
2850
  let shouldMaintainScrollAtEnd = false;
2533
2851
  let minIndexSizeChanged;
2534
2852
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2535
- const index = state.indexByKey.get(itemKey);
2536
2853
  const prevSizeKnown = state.sizesKnown.get(itemKey);
2537
- const diff = updateOneItemSize(state, itemKey, sizeObj);
2854
+ const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
2538
2855
  const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2539
2856
  if (diff !== 0) {
2540
2857
  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
2858
  const { startBuffered, endBuffered } = state;
2545
2859
  needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
2546
2860
  if (!needsRecalculate) {
@@ -2559,6 +2873,7 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2559
2873
  if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2560
2874
  shouldMaintainScrollAtEnd = true;
2561
2875
  }
2876
+ addTotalSize(ctx, state, itemKey, diff);
2562
2877
  onItemSizeChanged == null ? void 0 : onItemSizeChanged({
2563
2878
  index,
2564
2879
  itemData: state.props.data[index],
@@ -2570,13 +2885,13 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2570
2885
  if (minIndexSizeChanged !== void 0) {
2571
2886
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
2572
2887
  }
2573
- if (__DEV__ && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
2888
+ if (IS_DEV && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
2574
2889
  if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
2575
2890
  state.timeoutSizeMessage = setTimeout(() => {
2576
- var _a2;
2891
+ var _a4;
2577
2892
  state.timeoutSizeMessage = void 0;
2578
2893
  const num = state.sizesKnown.size;
2579
- const avg = (_a2 = state.averageSizes[""]) == null ? void 0 : _a2.avg;
2894
+ const avg = (_a4 = state.averageSizes[""]) == null ? void 0 : _a4.avg;
2580
2895
  console.warn(
2581
2896
  `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
2582
2897
  );
@@ -2598,8 +2913,8 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2598
2913
  }
2599
2914
  }
2600
2915
  }
2601
- function updateOneItemSize(state, itemKey, sizeObj) {
2602
- var _a;
2916
+ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
2917
+ var _a3;
2603
2918
  const {
2604
2919
  sizes,
2605
2920
  indexByKey,
@@ -2609,12 +2924,12 @@ function updateOneItemSize(state, itemKey, sizeObj) {
2609
2924
  } = state;
2610
2925
  if (!data) return 0;
2611
2926
  const index = indexByKey.get(itemKey);
2612
- const prevSize = getItemSize(state, itemKey, index, data);
2927
+ const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
2613
2928
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
2614
2929
  const size = Math.round(rawSize) ;
2615
2930
  sizesKnown.set(itemKey, size);
2616
2931
  if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
2617
- const itemType = getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : "";
2932
+ const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
2618
2933
  let averages = averageSizes[itemType];
2619
2934
  if (!averages) {
2620
2935
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
@@ -2645,24 +2960,12 @@ var useCombinedRef = (...refs) => {
2645
2960
  };
2646
2961
 
2647
2962
  // src/platform/RefreshControl.tsx
2648
- function RefreshControl(props) {
2963
+ function RefreshControl(_props) {
2649
2964
  return null;
2650
2965
  }
2651
2966
 
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
2967
  // src/platform/useStickyScrollHandler.ts
2665
- function useStickyScrollHandler(stickyIndices, horizontal, ctx, onScroll2) {
2968
+ function useStickyScrollHandler(_stickyIndices, _horizontal, _ctx, onScroll2) {
2666
2969
  return onScroll2;
2667
2970
  }
2668
2971
 
@@ -2681,7 +2984,7 @@ function createColumnWrapperStyle(contentContainerStyle) {
2681
2984
  }
2682
2985
  }
2683
2986
  function getRenderedItem(ctx, state, key) {
2684
- var _a;
2987
+ var _a3;
2685
2988
  if (!state) {
2686
2989
  return null;
2687
2990
  }
@@ -2694,15 +2997,17 @@ function getRenderedItem(ctx, state, key) {
2694
2997
  return null;
2695
2998
  }
2696
2999
  let renderedItem = null;
2697
- if (renderItem && data[index]) {
3000
+ const extraData = peek$(ctx, "extraData");
3001
+ const item = data[index];
3002
+ if (renderItem && !isNullOrUndefined(item)) {
2698
3003
  const itemProps = {
2699
3004
  data,
2700
- extraData: peek$(ctx, "extraData"),
3005
+ extraData,
2701
3006
  index,
2702
- item: data[index],
2703
- type: getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : ""
3007
+ item,
3008
+ type: getItemType ? (_a3 = getItemType(item, index)) != null ? _a3 : "" : ""
2704
3009
  };
2705
- renderedItem = isFunction(renderItem) ? renderItem(itemProps) : React4__default.createElement(renderItem, itemProps);
3010
+ renderedItem = isFunction(renderItem) ? renderItem(itemProps) : React3__default.createElement(renderItem, itemProps);
2706
3011
  }
2707
3012
  return { index, item: data[index], renderedItem };
2708
3013
  }
@@ -2752,58 +3057,6 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
2752
3057
  return (event) => throttle(originalHandler, scrollEventThrottle, { nativeEvent: event.nativeEvent });
2753
3058
  }
2754
3059
 
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
3060
  // src/components/LegendList.tsx
2808
3061
  var DEFAULT_DRAW_DISTANCE = 250;
2809
3062
  var DEFAULT_ITEM_SIZE = 100;
@@ -2813,17 +3066,18 @@ var LegendList = typedMemo(
2813
3066
  const isChildrenMode = children !== void 0 && dataProp === void 0;
2814
3067
  const processedProps = isChildrenMode ? {
2815
3068
  ...restProps,
2816
- data: (isArray(children) ? children : React4.Children.toArray(children)).flat(1),
3069
+ data: (isArray(children) ? children : React3.Children.toArray(children)).flat(1),
2817
3070
  renderItem: ({ item }) => item
2818
3071
  } : {
2819
3072
  ...restProps,
2820
3073
  data: dataProp || [],
2821
3074
  renderItem: renderItemProp
2822
3075
  };
2823
- return /* @__PURE__ */ React4.createElement(StateProvider, null, /* @__PURE__ */ React4.createElement(LegendListInner, { ...processedProps, ref: forwardedRef }));
3076
+ return /* @__PURE__ */ React3.createElement(StateProvider, null, /* @__PURE__ */ React3.createElement(LegendListInner, { ...processedProps, ref: forwardedRef }));
2824
3077
  })
2825
3078
  );
2826
3079
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
3080
+ var _a3;
2827
3081
  const {
2828
3082
  alignItemsAtEnd = false,
2829
3083
  columnWrapperStyle,
@@ -2859,6 +3113,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2859
3113
  onScroll: onScrollProp,
2860
3114
  onStartReached,
2861
3115
  onStartReachedThreshold = 0.5,
3116
+ onStickyHeaderChange,
3117
+ onViewableItemsChanged,
2862
3118
  progressViewOffset,
2863
3119
  recycleItems = false,
2864
3120
  refreshControl,
@@ -2870,12 +3126,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2870
3126
  stickyIndices,
2871
3127
  style: styleProp,
2872
3128
  suggestEstimatedItemSize,
3129
+ viewabilityConfig,
3130
+ viewabilityConfigCallbackPairs,
2873
3131
  waitForInitialLayout = true,
2874
3132
  ...rest
2875
3133
  } = props;
2876
3134
  const [renderNum, setRenderNum] = useState(0);
2877
3135
  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);
3136
+ const [canRender, setCanRender] = React3.useState(!IsNewArchitecture);
2879
3137
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
2880
3138
  const style = { ...StyleSheet.flatten(styleProp) };
2881
3139
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
@@ -2897,12 +3155,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2897
3155
  columns: /* @__PURE__ */ new Map(),
2898
3156
  containerItemKeys: /* @__PURE__ */ new Set(),
2899
3157
  containerItemTypes: /* @__PURE__ */ new Map(),
3158
+ dataChangeNeedsScrollUpdate: false,
2900
3159
  enableScrollForNextCalculateItemsInView: true,
2901
3160
  endBuffered: -1,
2902
3161
  endNoBuffer: -1,
2903
- endReachedBlockedByTimer: false,
3162
+ endReachedSnapshot: void 0,
2904
3163
  firstFullyOnScreenIndex: -1,
2905
- idCache: /* @__PURE__ */ new Map(),
3164
+ idCache: [],
2906
3165
  idsInView: [],
2907
3166
  indexByKey: /* @__PURE__ */ new Map(),
2908
3167
  initialScroll,
@@ -2933,7 +3192,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2933
3192
  sizesKnown: /* @__PURE__ */ new Map(),
2934
3193
  startBuffered: -1,
2935
3194
  startNoBuffer: -1,
2936
- startReachedBlockedByTimer: false,
3195
+ startReachedSnapshot: void 0,
2937
3196
  stickyContainerPool: /* @__PURE__ */ new Set(),
2938
3197
  stickyContainers: /* @__PURE__ */ new Map(),
2939
3198
  timeoutSizeMessage: 0,
@@ -2949,10 +3208,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2949
3208
  const state = refState.current;
2950
3209
  const isFirst = !state.props.renderItem;
2951
3210
  const didDataChange = state.props.data !== dataProp;
2952
- const throttleScrollFn = (
2953
- // @ts-expect-error TODO Fix this
2954
- scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp
2955
- );
3211
+ if (didDataChange) {
3212
+ state.dataChangeNeedsScrollUpdate = true;
3213
+ }
3214
+ const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
2956
3215
  state.props = {
2957
3216
  alignItemsAtEnd,
2958
3217
  data: dataProp,
@@ -2977,6 +3236,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2977
3236
  onScroll: throttleScrollFn,
2978
3237
  onStartReached,
2979
3238
  onStartReachedThreshold,
3239
+ onStickyHeaderChange,
2980
3240
  recycleItems: !!recycleItems,
2981
3241
  renderItem,
2982
3242
  scrollBuffer,
@@ -2988,27 +3248,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2988
3248
  suggestEstimatedItemSize: !!suggestEstimatedItemSize
2989
3249
  };
2990
3250
  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
3251
  const memoizedLastItemKeys = useMemo(() => {
3013
3252
  if (!dataProp.length) return [];
3014
3253
  return Array.from(
@@ -3032,7 +3271,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3032
3271
  };
3033
3272
  if (isFirst) {
3034
3273
  initializeStateVars();
3035
- updateAllPositions(ctx, state);
3274
+ updateItemPositions(
3275
+ ctx,
3276
+ state,
3277
+ /*dataChanged*/
3278
+ true
3279
+ );
3036
3280
  }
3037
3281
  const initialContentOffset = useMemo(() => {
3038
3282
  if (initialScroll) {
@@ -3043,21 +3287,27 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3043
3287
  }
3044
3288
  refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
3045
3289
  if (initialContentOffset2 > 0) {
3046
- scrollTo(state, { animated: false, index, offset: initialContentOffset2 });
3290
+ scrollTo(ctx, state, {
3291
+ animated: false,
3292
+ index,
3293
+ isInitialScroll: true,
3294
+ offset: initialContentOffset2,
3295
+ viewPosition: index === dataProp.length - 1 ? 1 : 0
3296
+ });
3047
3297
  }
3048
3298
  return initialContentOffset2;
3049
3299
  }
3050
3300
  return 0;
3051
3301
  }, [renderNum]);
3052
3302
  if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
3053
- state.lastBatchingAction = Date.now();
3303
+ refState.current.lastBatchingAction = Date.now();
3054
3304
  if (!keyExtractorProp && !isFirst && didDataChange) {
3055
- __DEV__ && warnDevOnce(
3305
+ IS_DEV && warnDevOnce(
3056
3306
  "keyExtractor",
3057
3307
  "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
3308
  );
3059
- state.sizes.clear();
3060
- state.positions.clear();
3309
+ refState.current.sizes.clear();
3310
+ refState.current.positions.clear();
3061
3311
  }
3062
3312
  }
3063
3313
  const onLayoutHeader = useCallback((rect, fromLayoutEffect) => {
@@ -3077,36 +3327,44 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3077
3327
  }
3078
3328
  }, [snapToIndices]);
3079
3329
  useLayoutEffect(() => {
3080
- const didAllocateContainers = dataProp.length > 0 && doInitialAllocateContainersCallback();
3330
+ const didAllocateContainers = dataProp.length > 0 && doInitialAllocateContainers(ctx, state);
3081
3331
  if (!didAllocateContainers) {
3082
3332
  checkResetContainers(
3333
+ ctx,
3334
+ state,
3083
3335
  /*isFirst*/
3084
- isFirst
3336
+ isFirst,
3337
+ dataProp
3085
3338
  );
3086
3339
  }
3087
3340
  }, [dataProp, numColumnsProp]);
3088
3341
  useLayoutEffect(() => {
3089
3342
  set$(ctx, "extraData", extraData);
3090
3343
  }, [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
3344
  useLayoutEffect(initializeStateVars, [
3102
3345
  memoizedLastItemKeys.join(","),
3103
3346
  numColumnsProp,
3104
3347
  stylePaddingTopState,
3105
3348
  stylePaddingBottomState
3106
3349
  ]);
3107
- const doInitialAllocateContainersCallback = () => {
3108
- return doInitialAllocateContainers(ctx, state);
3109
- };
3350
+ useEffect(() => {
3351
+ const viewability = setupViewability({
3352
+ onViewableItemsChanged,
3353
+ viewabilityConfig,
3354
+ viewabilityConfigCallbackPairs
3355
+ });
3356
+ state.viewabilityConfigCallbackPairs = viewability;
3357
+ state.enableScrollForNextCalculateItemsInView = !viewability;
3358
+ }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3359
+ const onLayoutChange = useCallback((layout) => {
3360
+ handleLayout(ctx, state, layout, setCanRender);
3361
+ }, []);
3362
+ const { onLayout } = useOnLayoutSync({
3363
+ onLayoutChange,
3364
+ onLayoutProp,
3365
+ ref: refScroller
3366
+ // the type of ScrollView doesn't include measure?
3367
+ });
3110
3368
  useImperativeHandle(forwardedRef, () => {
3111
3369
  const scrollIndexIntoView = (options) => {
3112
3370
  const state2 = refState.current;
@@ -3124,16 +3382,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3124
3382
  }
3125
3383
  };
3126
3384
  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
- },
3385
+ flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
3131
3386
  getNativeScrollRef: () => refScroller.current,
3132
- getScrollableNode: () => refScroller.current,
3133
- getScrollResponder: () => refScroller.current,
3387
+ getScrollableNode: () => refScroller.current.getScrollableNode(),
3388
+ getScrollResponder: () => refScroller.current.getScrollResponder(),
3134
3389
  getState: () => {
3135
3390
  const state2 = refState.current;
3136
3391
  return state2 ? {
3392
+ activeStickyIndex: state2.activeStickyIndex,
3137
3393
  contentLength: state2.totalSize,
3138
3394
  data: state2.props.data,
3139
3395
  end: state2.endNoBuffer,
@@ -3181,7 +3437,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3181
3437
  scrollToIndex(ctx, state, { index, ...props2 });
3182
3438
  }
3183
3439
  },
3184
- scrollToOffset: (params) => scrollTo(state, params),
3440
+ scrollToOffset: (params) => scrollTo(ctx, state, params),
3185
3441
  setScrollProcessingEnabled: (enabled) => {
3186
3442
  refState.current.scrollProcessingEnabled = enabled;
3187
3443
  },
@@ -3194,7 +3450,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3194
3450
  {
3195
3451
  useEffect(() => {
3196
3452
  if (initialContentOffset) {
3197
- scrollTo(state, { animated: false, offset: initialContentOffset });
3453
+ scrollTo(ctx, state, { animated: false, offset: initialContentOffset, ...initialScroll || {} });
3198
3454
  }
3199
3455
  }, []);
3200
3456
  }
@@ -3207,7 +3463,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3207
3463
  []
3208
3464
  );
3209
3465
  const onScrollHandler = useStickyScrollHandler(stickyIndices, horizontal, ctx, fns.onScroll);
3210
- return /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(
3466
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(
3211
3467
  ListComponent,
3212
3468
  {
3213
3469
  ...rest,
@@ -3225,7 +3481,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3225
3481
  onMomentumScrollEnd: (event) => {
3226
3482
  {
3227
3483
  requestAnimationFrame(() => {
3228
- finishScrollTo(refState.current);
3484
+ finishScrollTo(ctx, refState.current);
3229
3485
  });
3230
3486
  }
3231
3487
  if (onMomentumScrollEnd) {
@@ -3234,9 +3490,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3234
3490
  },
3235
3491
  onScroll: onScrollHandler,
3236
3492
  recycleItems,
3237
- refreshControl: refreshControl ? stylePaddingTopState > 0 ? React4.cloneElement(refreshControl, {
3493
+ refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3.cloneElement(refreshControl, {
3238
3494
  progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
3239
- }) : refreshControl : onRefresh && /* @__PURE__ */ React4.createElement(
3495
+ }) : refreshControl : onRefresh && /* @__PURE__ */ React3.createElement(
3240
3496
  RefreshControl,
3241
3497
  {
3242
3498
  onRefresh,
@@ -3245,14 +3501,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3245
3501
  }
3246
3502
  ),
3247
3503
  refScrollView: combinedRef,
3248
- scrollAdjustHandler: state.scrollAdjustHandler,
3504
+ scrollAdjustHandler: (_a3 = refState.current) == null ? void 0 : _a3.scrollAdjustHandler,
3505
+ scrollEventThrottle: 16 ,
3249
3506
  snapToIndices,
3250
3507
  stickyIndices,
3251
3508
  style,
3252
3509
  updateItemSize: fns.updateItemSize,
3253
3510
  waitForInitialLayout
3254
3511
  }
3255
- ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React4.createElement(DebugView, { state: refState.current }));
3512
+ ), IS_DEV && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React3.createElement(DebugView, { state: refState.current }));
3256
3513
  });
3257
3514
 
3258
- export { LegendList, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout2 as useSyncLayout, useViewability, useViewabilityAmount };
3515
+ export { LegendList, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };