@legendapp/list 2.1.0-next.1 → 3.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.mjs CHANGED
@@ -1,14 +1,14 @@
1
- import * as React4 from 'react';
2
- import React4__default, { forwardRef, useReducer, useEffect, createContext, useRef, useState, useMemo, useImperativeHandle, useCallback, useLayoutEffect, memo, useContext } from 'react';
1
+ import * as React3 from 'react';
2
+ import React3__default, { forwardRef, useReducer, useEffect, createContext, useRef, useState, useMemo, useCallback, useImperativeHandle, useLayoutEffect, memo, useContext } from 'react';
3
3
  import { useSyncExternalStore } from 'use-sync-external-store/shim';
4
4
  import { unstable_batchedUpdates } from 'react-dom';
5
5
 
6
6
  // src/components/LegendList.tsx
7
- var AnimatedView = forwardRef(function AnimatedView2(props, ref) {
8
- return /* @__PURE__ */ React4.createElement("div", { ref, ...props });
7
+ forwardRef(function AnimatedView2(props, ref) {
8
+ return /* @__PURE__ */ React3.createElement("div", { ref, ...props });
9
9
  });
10
10
  var View = forwardRef(function View2(props, ref) {
11
- return /* @__PURE__ */ React4.createElement("div", { ref, ...props });
11
+ return /* @__PURE__ */ React3.createElement("div", { ref, ...props });
12
12
  });
13
13
  var Text = View;
14
14
 
@@ -16,9 +16,9 @@ var Text = View;
16
16
  var createAnimatedValue = (value) => value;
17
17
 
18
18
  // src/state/state.tsx
19
- var ContextState = React4.createContext(null);
19
+ var ContextState = React3.createContext(null);
20
20
  function StateProvider({ children }) {
21
- const [value] = React4.useState(() => ({
21
+ const [value] = React3.useState(() => ({
22
22
  animatedScrollY: createAnimatedValue(0),
23
23
  columnWrapperStyle: void 0,
24
24
  internalState: void 0,
@@ -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 = [];
@@ -102,31 +105,33 @@ function set$(ctx, signalName, value) {
102
105
  }
103
106
  }
104
107
  function getContentSize(ctx) {
105
- const { values } = ctx;
108
+ var _a3, _b;
109
+ const { values, internalState } = ctx;
106
110
  const stylePaddingTop = values.get("stylePaddingTop") || 0;
111
+ const stylePaddingBottom = (internalState == null ? void 0 : internalState.props.stylePaddingBottom) || 0;
107
112
  const headerSize = values.get("headerSize") || 0;
108
113
  const footerSize = values.get("footerSize") || 0;
109
- const totalSize = values.get("totalSize");
110
- return headerSize + footerSize + totalSize + stylePaddingTop;
114
+ const totalSize = (_b = (_a3 = ctx.internalState) == null ? void 0 : _a3.pendingTotalSize) != null ? _b : values.get("totalSize");
115
+ return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom;
111
116
  }
112
117
  function useArr$(signalNames) {
113
- const ctx = React4.useContext(ContextState);
114
- const { subscribe, get } = React4.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
118
+ const ctx = React3.useContext(ContextState);
119
+ const { subscribe, get } = React3.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
115
120
  const value = useSyncExternalStore(subscribe, get);
116
121
  return value;
117
122
  }
118
123
  function useSelector$(signalName, selector) {
119
- const ctx = React4.useContext(ContextState);
120
- const { subscribe, get } = React4.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
124
+ const ctx = React3.useContext(ContextState);
125
+ const { subscribe, get } = React3.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
121
126
  const value = useSyncExternalStore(subscribe, () => selector(get()[0]));
122
127
  return value;
123
128
  }
124
129
 
125
130
  // src/components/DebugView.tsx
126
131
  var DebugRow = ({ children }) => {
127
- return /* @__PURE__ */ React4.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
132
+ return /* @__PURE__ */ React3.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
128
133
  };
129
- var DebugView = React4.memo(function DebugView2({ state }) {
134
+ var DebugView = React3.memo(function DebugView2({ state }) {
130
135
  const ctx = useStateContext();
131
136
  const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, _numContainers = 0, _numContainersPooled = 0] = useArr$([
132
137
  "totalSize",
@@ -141,7 +146,7 @@ var DebugView = React4.memo(function DebugView2({ state }) {
141
146
  useInterval(() => {
142
147
  forceUpdate();
143
148
  }, 100);
144
- return /* @__PURE__ */ React4.createElement(
149
+ return /* @__PURE__ */ React3.createElement(
145
150
  View,
146
151
  {
147
152
  pointerEvents: "none",
@@ -157,12 +162,12 @@ var DebugView = React4.memo(function DebugView2({ state }) {
157
162
  top: 0
158
163
  }
159
164
  },
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)))
165
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "TotalSize:"), /* @__PURE__ */ React3.createElement(Text, null, totalSize.toFixed(2))),
166
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "ContentSize:"), /* @__PURE__ */ React3.createElement(Text, null, contentSize.toFixed(2))),
167
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "At end:"), /* @__PURE__ */ React3.createElement(Text, null, String(state.isAtEnd))),
168
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React3.createElement(Text, null, scrollAdjust.toFixed(2))),
169
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "RawScroll: "), /* @__PURE__ */ React3.createElement(Text, null, rawScroll.toFixed(2))),
170
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "ComputedScroll: "), /* @__PURE__ */ React3.createElement(Text, null, scroll.toFixed(2)))
166
171
  );
167
172
  });
168
173
  function useInterval(callback, delay) {
@@ -171,93 +176,63 @@ function useInterval(callback, delay) {
171
176
  return () => clearInterval(interval);
172
177
  }, [delay]);
173
178
  }
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
179
 
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
- };
180
+ // src/utils/devEnvironment.ts
181
+ var metroDev = typeof __DEV__ !== "undefined" ? __DEV__ : void 0;
182
+ var _a;
183
+ var envMode = typeof process !== "undefined" && typeof process.env === "object" && process.env ? (_a = process.env.NODE_ENV) != null ? _a : process.env.MODE : void 0;
184
+ var processDev = typeof envMode === "string" ? envMode.toLowerCase() !== "production" : void 0;
185
+ var _a2;
186
+ var IS_DEV = (_a2 = metroDev != null ? metroDev : processDev) != null ? _a2 : false;
253
187
 
254
188
  // src/constants.ts
255
189
  var POSITION_OUT_OF_VIEW = -1e7;
256
- var ENABLE_DEVMODE = __DEV__ && false;
257
- var ENABLE_DEBUG_VIEW = __DEV__ && false;
190
+ var ENABLE_DEVMODE = IS_DEV && false;
191
+ var ENABLE_DEBUG_VIEW = IS_DEV && false;
258
192
  var typedForwardRef = forwardRef;
259
193
  var typedMemo = memo;
260
194
 
195
+ // src/utils/helpers.ts
196
+ function isFunction(obj) {
197
+ return typeof obj === "function";
198
+ }
199
+ function isArray(obj) {
200
+ return Array.isArray(obj);
201
+ }
202
+ var warned = /* @__PURE__ */ new Set();
203
+ function warnDevOnce(id, text) {
204
+ if (IS_DEV && !warned.has(id)) {
205
+ warned.add(id);
206
+ console.warn(`[legend-list] ${text}`);
207
+ }
208
+ }
209
+ function roundSize(size) {
210
+ return Math.floor(size * 8) / 8;
211
+ }
212
+ function isNullOrUndefined(value) {
213
+ return value === null || value === void 0;
214
+ }
215
+ function comparatorDefault(a, b) {
216
+ return a - b;
217
+ }
218
+ function getPadding(s, type) {
219
+ var _a3, _b, _c;
220
+ return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : s.paddingVertical) != null ? _b : s.padding) != null ? _c : 0;
221
+ }
222
+ function extractPadding(style, contentContainerStyle, type) {
223
+ return getPadding(style, type) + getPadding(contentContainerStyle, type);
224
+ }
225
+ function findContainerId(ctx, key) {
226
+ const numContainers = peek$(ctx, "numContainers");
227
+ for (let i = 0; i < numContainers; i++) {
228
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
229
+ if (itemKey === key) {
230
+ return i;
231
+ }
232
+ }
233
+ return -1;
234
+ }
235
+
261
236
  // src/components/PositionView.tsx
262
237
  var PositionViewState = typedMemo(function PositionView({
263
238
  id,
@@ -267,9 +242,12 @@ var PositionViewState = typedMemo(function PositionView({
267
242
  ...rest
268
243
  }) {
269
244
  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 });
245
+ const base = {
246
+ contain: "paint layout style"
247
+ };
248
+ const composed = isArray(style) ? Object.assign({}, ...style) : style;
249
+ const combinedStyle = horizontal ? { ...base, ...composed, left: position } : { ...base, ...composed, top: position };
250
+ return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: combinedStyle, ...rest });
273
251
  });
274
252
  var PositionViewSticky = typedMemo(function PositionViewSticky2({
275
253
  id,
@@ -277,35 +255,47 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
277
255
  style,
278
256
  refView,
279
257
  index,
258
+ stickyOffset,
259
+ animatedScrollY: _animatedScrollY,
260
+ children,
280
261
  ...rest
281
262
  }) {
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 });
263
+ const [position = POSITION_OUT_OF_VIEW, headerSize = 0, activeStickyIndex] = useArr$([
264
+ `containerPosition${id}`,
265
+ "headerSize",
266
+ "activeStickyIndex"
267
+ ]);
268
+ const base = {
269
+ contain: "paint layout style"
270
+ };
271
+ const composed = React3.useMemo(
272
+ () => {
273
+ var _a3;
274
+ return (_a3 = isArray(style) ? Object.assign({}, ...style) : style) != null ? _a3 : {};
275
+ },
276
+ [style]
277
+ );
278
+ const viewStyle = React3.useMemo(() => {
279
+ var _a3;
280
+ const styleBase = { ...base, ...composed };
281
+ delete styleBase.transform;
282
+ const offset = (_a3 = stickyOffset != null ? stickyOffset : headerSize) != null ? _a3 : 0;
283
+ const isActive = activeStickyIndex === index;
284
+ styleBase.position = isActive ? "sticky" : "absolute";
285
+ styleBase.zIndex = index + 1e3;
286
+ if (horizontal) {
287
+ styleBase.left = isActive ? offset : position;
288
+ } else {
289
+ styleBase.top = isActive ? offset : position;
290
+ }
291
+ return styleBase;
292
+ }, [composed, horizontal, position, index, stickyOffset, headerSize, activeStickyIndex]);
293
+ return /* @__PURE__ */ React3.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
293
294
  });
294
295
  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
296
 
301
297
  // src/constants-platform.ts
302
298
  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
299
  var symbolFirst = Symbol();
310
300
  function useInit(cb) {
311
301
  const refValue = useRef(symbolFirst);
@@ -315,37 +305,6 @@ function useInit(cb) {
315
305
  return refValue.current;
316
306
  }
317
307
 
318
- // src/utils/helpers.ts
319
- function isFunction(obj) {
320
- return typeof obj === "function";
321
- }
322
- function isArray(obj) {
323
- return Array.isArray(obj);
324
- }
325
- var warned = /* @__PURE__ */ new Set();
326
- function warnDevOnce(id, text) {
327
- if (__DEV__ && !warned.has(id)) {
328
- warned.add(id);
329
- console.warn(`[legend-list] ${text}`);
330
- }
331
- }
332
- function roundSize(size) {
333
- return Math.floor(size * 8) / 8;
334
- }
335
- function isNullOrUndefined(value) {
336
- return value === null || value === void 0;
337
- }
338
- function comparatorDefault(a, b) {
339
- return a - b;
340
- }
341
- 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;
344
- }
345
- function extractPadding(style, contentContainerStyle, type) {
346
- return getPadding(style, type) + getPadding(contentContainerStyle, type);
347
- }
348
-
349
308
  // src/state/ContextContainer.ts
350
309
  var ContextContainer = createContext(null);
351
310
  function useViewability(callback, configId) {
@@ -442,13 +401,114 @@ function useListScrollSize() {
442
401
  const [scrollSize] = useArr$(["scrollSize"]);
443
402
  return scrollSize;
444
403
  }
445
- function useSyncLayout2() {
404
+ function useSyncLayout() {
446
405
  {
447
406
  const { triggerLayout: syncLayout } = useContext(ContextContainer);
448
407
  return syncLayout;
449
408
  }
450
409
  }
451
410
 
411
+ // src/components/Separator.tsx
412
+ function Separator({ ItemSeparatorComponent, leadingItem }) {
413
+ const isLastItem = useIsLastItem();
414
+ return isLastItem ? null : /* @__PURE__ */ React3.createElement(ItemSeparatorComponent, { leadingItem });
415
+ }
416
+
417
+ // src/hooks/createResizeObserver.ts
418
+ var globalResizeObserver = null;
419
+ function getGlobalResizeObserver() {
420
+ if (!globalResizeObserver) {
421
+ globalResizeObserver = new ResizeObserver((entries) => {
422
+ for (const entry of entries) {
423
+ const callbacks = callbackMap.get(entry.target);
424
+ if (callbacks) {
425
+ for (const callback of callbacks) {
426
+ callback(entry);
427
+ }
428
+ }
429
+ }
430
+ });
431
+ }
432
+ return globalResizeObserver;
433
+ }
434
+ var callbackMap = /* @__PURE__ */ new WeakMap();
435
+ function createResizeObserver(element, callback) {
436
+ if (typeof ResizeObserver === "undefined") {
437
+ return () => {
438
+ };
439
+ }
440
+ if (!element) {
441
+ return () => {
442
+ };
443
+ }
444
+ const observer = getGlobalResizeObserver();
445
+ let callbacks = callbackMap.get(element);
446
+ if (!callbacks) {
447
+ callbacks = /* @__PURE__ */ new Set();
448
+ callbackMap.set(element, callbacks);
449
+ observer.observe(element);
450
+ }
451
+ callbacks.add(callback);
452
+ return () => {
453
+ const callbacks2 = callbackMap.get(element);
454
+ if (callbacks2) {
455
+ callbacks2.delete(callback);
456
+ if (callbacks2.size === 0) {
457
+ callbackMap.delete(element);
458
+ observer.unobserve(element);
459
+ }
460
+ }
461
+ };
462
+ }
463
+
464
+ // src/hooks/useOnLayoutSync.tsx
465
+ function useOnLayoutSync({
466
+ ref,
467
+ onLayoutProp,
468
+ onLayoutChange
469
+ }, deps) {
470
+ useLayoutEffect(() => {
471
+ var _a3, _b;
472
+ const current = ref.current;
473
+ const scrollableNode = (_b = (_a3 = current == null ? void 0 : current.getScrollableNode) == null ? void 0 : _a3.call(current)) != null ? _b : null;
474
+ const element = scrollableNode || current;
475
+ if (!element) {
476
+ return;
477
+ }
478
+ const emit = (layout, fromLayoutEffect) => {
479
+ if (layout.height === 0 && layout.width === 0) {
480
+ return;
481
+ }
482
+ onLayoutChange(layout, fromLayoutEffect);
483
+ onLayoutProp == null ? void 0 : onLayoutProp({ nativeEvent: { layout } });
484
+ };
485
+ const rect = element.getBoundingClientRect();
486
+ emit(toLayout(rect), true);
487
+ let prevRect = rect;
488
+ return createResizeObserver(element, (entry) => {
489
+ var _a4;
490
+ const target = entry.target instanceof HTMLElement ? entry.target : void 0;
491
+ const rect2 = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
492
+ if (rect2.width !== prevRect.width || rect2.height !== prevRect.height) {
493
+ prevRect = rect2;
494
+ emit(toLayout(rect2), false);
495
+ }
496
+ });
497
+ }, deps || []);
498
+ return {};
499
+ }
500
+ function toLayout(rect) {
501
+ if (!rect) {
502
+ return { height: 0, width: 0, x: 0, y: 0 };
503
+ }
504
+ return {
505
+ height: rect.height,
506
+ width: rect.width,
507
+ x: rect.left,
508
+ y: rect.top
509
+ };
510
+ }
511
+
452
512
  // src/components/Container.tsx
453
513
  var Container = typedMemo(function Container2({
454
514
  id,
@@ -459,37 +519,42 @@ var Container = typedMemo(function Container2({
459
519
  ItemSeparatorComponent
460
520
  }) {
461
521
  const ctx = useStateContext();
462
- const { columnWrapperStyle } = ctx;
463
- const [column = 0, data, itemKey, numColumns, extraData, isSticky] = useArr$([
522
+ const { columnWrapperStyle, animatedScrollY } = ctx;
523
+ const [column = 0, data, itemKey, numColumns, extraData, isSticky, stickyOffset] = useArr$([
464
524
  `containerColumn${id}`,
465
525
  `containerItemData${id}`,
466
526
  `containerItemKey${id}`,
467
527
  "numColumns",
468
528
  "extraData",
469
- `containerSticky${id}`
529
+ `containerSticky${id}`,
530
+ `containerStickyOffset${id}`
470
531
  ]);
471
- const refLastSize = useRef();
532
+ const itemLayoutRef = useRef({
533
+ horizontal,
534
+ itemKey,
535
+ updateItemSize: updateItemSize2
536
+ });
537
+ itemLayoutRef.current.horizontal = horizontal;
538
+ itemLayoutRef.current.itemKey = itemKey;
539
+ itemLayoutRef.current.updateItemSize = updateItemSize2;
472
540
  const ref = useRef(null);
473
- const [_, forceLayoutRender] = useState(0);
541
+ const [layoutRenderCount, forceLayoutRender] = useState(0);
474
542
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
475
543
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
544
+ const didLayoutRef = useRef(false);
476
545
  const style = useMemo(() => {
477
546
  let paddingStyles;
478
547
  if (columnWrapperStyle) {
479
548
  const { columnGap, rowGap, gap } = columnWrapperStyle;
480
549
  if (horizontal) {
481
- const py = numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0;
482
550
  paddingStyles = {
483
- paddingBottom: py,
484
551
  paddingRight: columnGap || gap || void 0,
485
- paddingTop: py
552
+ paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
486
553
  };
487
554
  } else {
488
- const px = numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0;
489
555
  paddingStyles = {
490
556
  paddingBottom: rowGap || gap || void 0,
491
- paddingLeft: px,
492
- paddingRight: px
557
+ paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
493
558
  };
494
559
  }
495
560
  }
@@ -503,7 +568,7 @@ var Container = typedMemo(function Container2({
503
568
  } : {
504
569
  left: otherAxisPos,
505
570
  position: "absolute",
506
- right: numColumns > 1 ? void 0 : 0,
571
+ right: numColumns > 1 ? null : 0,
507
572
  top: 0,
508
573
  width: otherAxisSize,
509
574
  ...paddingStyles || {}
@@ -526,49 +591,64 @@ var Container = typedMemo(function Container2({
526
591
  value: data
527
592
  };
528
593
  }, [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
- }
594
+ const onLayoutChange = useCallback((rectangle) => {
595
+ const {
596
+ horizontal: currentHorizontal,
597
+ itemKey: currentItemKey,
598
+ updateItemSize: updateItemSizeFn
599
+ } = itemLayoutRef.current;
600
+ if (isNullOrUndefined(currentItemKey)) {
601
+ return;
540
602
  }
541
- };
603
+ didLayoutRef.current = true;
604
+ let layout = rectangle;
605
+ roundSize(rectangle[currentHorizontal ? "width" : "height"]);
606
+ const doUpdate = () => {
607
+ itemLayoutRef.current.lastSize = { height: layout.height, width: layout.width };
608
+ updateItemSizeFn(currentItemKey, layout);
609
+ didLayoutRef.current = true;
610
+ };
611
+ {
612
+ doUpdate();
613
+ }
614
+ }, []);
615
+ const { onLayout } = useOnLayoutSync(
616
+ {
617
+ onLayoutChange,
618
+ ref
619
+ },
620
+ [itemKey, layoutRenderCount]
621
+ );
542
622
  const PositionComponent = isSticky ? PositionViewSticky : PositionView2;
543
- return /* @__PURE__ */ React4.createElement(ContextContainer.Provider, { value: contextValue }, /* @__PURE__ */ React4.createElement(
623
+ return /* @__PURE__ */ React3.createElement(
544
624
  PositionComponent,
545
625
  {
626
+ animatedScrollY: isSticky ? animatedScrollY : void 0,
546
627
  horizontal,
547
628
  id,
548
629
  index,
549
630
  key: recycleItems ? void 0 : itemKey,
550
- onLayoutChange,
631
+ onLayout,
551
632
  refView: ref,
633
+ stickyOffset: isSticky ? stickyOffset : void 0,
552
634
  style
553
635
  },
554
- renderedItem,
555
- renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React4.createElement(
556
- Separator,
557
- {
558
- ItemSeparatorComponent,
559
- itemKey,
560
- leadingItem: renderedItemInfo.item
561
- }
562
- )
563
- ));
636
+ /* @__PURE__ */ React3.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React3.createElement(Separator, { ItemSeparatorComponent, leadingItem: renderedItemInfo.item }))
637
+ );
564
638
  });
565
639
 
640
+ // src/platform/Platform.ts
641
+ var Platform = {
642
+ // Widen the type to avoid unreachable-branch lints in cross-platform code that compares against other OSes
643
+ OS: "web"
644
+ };
645
+
566
646
  // src/utils/reordering.ts
567
647
  var mapFn = (element) => {
568
648
  const indexStr = element.getAttribute("index");
569
649
  return [element, indexStr === null ? null : parseInt(indexStr)];
570
650
  };
571
- function sortDOMElementsPatience(container) {
651
+ function sortDOMElements(container) {
572
652
  const elements = Array.from(container.children);
573
653
  if (elements.length <= 1) return elements;
574
654
  const items = elements.map(mapFn);
@@ -659,7 +739,7 @@ function useDOMOrder(ref) {
659
739
  debounceRef.current = setTimeout(() => {
660
740
  const parent = ref.current;
661
741
  if (parent) {
662
- sortDOMElementsPatience(parent);
742
+ sortDOMElements(parent);
663
743
  }
664
744
  debounceRef.current = void 0;
665
745
  }, 500);
@@ -680,7 +760,7 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
680
760
  const columnWrapperStyle = ctx.columnWrapperStyle;
681
761
  const [totalSize, otherAxisSize] = useArr$(["totalSize", "otherAxisSize"]);
682
762
  useDOMOrder(ref);
683
- const style = horizontal ? { minHeight: otherAxisSize, width: totalSize } : { height: totalSize, minWidth: otherAxisSize };
763
+ const style = horizontal ? { minHeight: otherAxisSize, position: "relative", width: totalSize } : { height: totalSize, minWidth: otherAxisSize, position: "relative" };
684
764
  if (columnWrapperStyle && numColumns > 1) {
685
765
  const { columnGap, rowGap, gap } = columnWrapperStyle;
686
766
  const gapX = columnGap || gap || 0;
@@ -701,7 +781,7 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
701
781
  }
702
782
  }
703
783
  }
704
- return /* @__PURE__ */ React4.createElement("div", { ref, style }, children);
784
+ return /* @__PURE__ */ React3.createElement("div", { ref, style }, children);
705
785
  });
706
786
  var Containers = typedMemo(function Containers2({
707
787
  horizontal,
@@ -715,7 +795,7 @@ var Containers = typedMemo(function Containers2({
715
795
  const containers = [];
716
796
  for (let i = 0; i < numContainers; i++) {
717
797
  containers.push(
718
- /* @__PURE__ */ React4.createElement(
798
+ /* @__PURE__ */ React3.createElement(
719
799
  Container,
720
800
  {
721
801
  getRenderedItem: getRenderedItem2,
@@ -729,24 +809,40 @@ var Containers = typedMemo(function Containers2({
729
809
  )
730
810
  );
731
811
  }
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
- ));
812
+ return /* @__PURE__ */ React3.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
749
813
  });
814
+ function DevNumbers() {
815
+ return IS_DEV && React3.memo(function DevNumbers2() {
816
+ return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3.createElement(
817
+ "div",
818
+ {
819
+ key: index,
820
+ style: {
821
+ height: 100,
822
+ pointerEvents: "none",
823
+ position: "absolute",
824
+ top: index * 100,
825
+ width: "100%"
826
+ }
827
+ },
828
+ /* @__PURE__ */ React3.createElement("div", { style: { color: "red" } }, index * 100)
829
+ ));
830
+ });
831
+ }
832
+
833
+ // src/platform/StyleSheet.tsx
834
+ function flattenStyles(styles) {
835
+ if (isArray(styles)) {
836
+ return Object.assign({}, ...styles.filter(Boolean));
837
+ }
838
+ return styles;
839
+ }
840
+ var StyleSheet = {
841
+ create: (styles) => styles,
842
+ flatten: (style) => flattenStyles(style)
843
+ };
844
+
845
+ // src/components/ListComponentScrollView.tsx
750
846
  var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
751
847
  children,
752
848
  style,
@@ -760,7 +856,6 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
760
856
  showsVerticalScrollIndicator = true,
761
857
  refreshControl,
762
858
  onLayout,
763
- ScrollComponent,
764
859
  ...props
765
860
  }, ref) {
766
861
  const scrollRef = useRef(null);
@@ -769,16 +864,15 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
769
864
  useImperativeHandle(ref, () => {
770
865
  const api = {
771
866
  getBoundingClientRect: () => {
772
- var _a;
773
- return (_a = scrollRef.current) == null ? void 0 : _a.getBoundingClientRect();
867
+ var _a3;
868
+ return (_a3 = scrollRef.current) == null ? void 0 : _a3.getBoundingClientRect();
774
869
  },
775
870
  getScrollableNode: () => scrollRef.current,
776
871
  getScrollResponder: () => scrollRef.current,
777
- scrollBy: (options) => {
872
+ scrollBy: (x, y) => {
778
873
  const el = scrollRef.current;
779
874
  if (!el) return;
780
- const { x = 0, y = 0, animated = true } = options;
781
- el.scrollBy({ behavior: animated ? "smooth" : "auto", left: x, top: y });
875
+ el.scrollBy(x, y);
782
876
  },
783
877
  scrollTo: (options) => {
784
878
  const el = scrollRef.current;
@@ -848,17 +942,21 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
848
942
  useLayoutEffect(() => {
849
943
  const element = scrollRef.current;
850
944
  if (!element) return;
851
- element.addEventListener("scroll", handleScroll, { passive: true });
945
+ element.addEventListener("scroll", handleScroll);
852
946
  return () => {
853
947
  element.removeEventListener("scroll", handleScroll);
854
948
  };
855
949
  }, [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]);
950
+ useEffect(() => {
951
+ const doScroll = () => {
952
+ if (contentOffset && scrollRef.current) {
953
+ scrollRef.current.scrollLeft = contentOffset.x || 0;
954
+ scrollRef.current.scrollTop = contentOffset.y || 0;
955
+ }
956
+ };
957
+ doScroll();
958
+ requestAnimationFrame(doScroll);
959
+ }, [contentOffset == null ? void 0 : contentOffset.x, contentOffset == null ? void 0 : contentOffset.y]);
862
960
  useLayoutEffect(() => {
863
961
  if (!onLayout || !scrollRef.current) return;
864
962
  const element = scrollRef.current;
@@ -890,41 +988,80 @@ var ListComponentScrollView = forwardRef(function ListComponentScrollView2({
890
988
  // Ensure proper positioning context
891
989
  WebkitOverflowScrolling: "touch",
892
990
  // iOS momentum scrolling
893
- ...style
991
+ ...StyleSheet.flatten(style)
894
992
  };
895
993
  const contentStyle = {
896
994
  display: horizontal ? "flex" : "block",
897
995
  flexDirection: horizontal ? "row" : void 0,
898
996
  minHeight: horizontal ? void 0 : "100%",
899
997
  minWidth: horizontal ? "100%" : void 0,
900
- ...contentContainerStyle
998
+ ...StyleSheet.flatten(contentContainerStyle)
901
999
  };
902
- return /* @__PURE__ */ React4.createElement("div", { ref: scrollRef, style: scrollViewStyle, ...props }, refreshControl, /* @__PURE__ */ React4.createElement("div", { ref: contentRef, style: contentStyle }, children));
1000
+ return /* @__PURE__ */ React3.createElement("div", { ref: scrollRef, style: scrollViewStyle, ...props }, refreshControl, /* @__PURE__ */ React3.createElement("div", { ref: contentRef, style: contentStyle }, children));
903
1001
  });
1002
+ function Padding() {
1003
+ const [paddingTop] = useArr$(["alignItemsPaddingTop"]);
1004
+ return /* @__PURE__ */ React3.createElement("div", { style: { paddingTop } });
1005
+ }
1006
+ function PaddingDevMode() {
1007
+ const [paddingTop] = useArr$(["alignItemsPaddingTop"]);
1008
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement("div", { style: { paddingTop } }), /* @__PURE__ */ React3.createElement(
1009
+ "div",
1010
+ {
1011
+ style: {
1012
+ backgroundColor: "green",
1013
+ height: paddingTop,
1014
+ left: 0,
1015
+ position: "absolute",
1016
+ right: 0,
1017
+ top: 0
1018
+ }
1019
+ }
1020
+ ));
1021
+ }
904
1022
  function useValueListener$(key, callback) {
905
1023
  const ctx = useStateContext();
906
1024
  useLayoutEffect(() => {
907
- listen$(ctx, key, (value) => {
1025
+ const unsubscribe = listen$(ctx, key, (value) => {
908
1026
  callback(value);
909
1027
  });
910
- }, []);
1028
+ return unsubscribe;
1029
+ }, [callback, ctx, key]);
911
1030
  }
912
1031
 
913
1032
  // src/components/ScrollAdjust.tsx
914
1033
  function ScrollAdjust() {
915
1034
  const ctx = useStateContext();
916
- const lastScrollOffsetRef = React4.useRef(0);
917
- const callback = React4.useCallback(() => {
918
- var _a;
1035
+ const lastScrollOffsetRef = React3.useRef(0);
1036
+ const callback = React3.useCallback(() => {
1037
+ var _a3;
919
1038
  const scrollAdjust = peek$(ctx, "scrollAdjust");
920
1039
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
921
1040
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
922
- const scrollView = (_a = ctx.internalState) == null ? void 0 : _a.refScroller.current;
1041
+ const scrollView = (_a3 = ctx.internalState) == null ? void 0 : _a3.refScroller.current;
923
1042
  if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
924
1043
  const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
925
1044
  if (scrollDelta !== 0) {
926
- scrollView.scrollBy(0, scrollDelta);
927
- console.log("ScrollAdjust (web scrollBy)", scrollDelta, "total offset:", scrollOffset);
1045
+ const el = scrollView.getScrollableNode();
1046
+ const prevScroll = el.scrollTop;
1047
+ const nextScroll = prevScroll + scrollDelta;
1048
+ const totalSize = el.scrollHeight;
1049
+ if (scrollDelta > 0 && !ctx.internalState.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
1050
+ const child = el.firstElementChild;
1051
+ const prevPaddingBottom = child.style.paddingBottom;
1052
+ const pad = (nextScroll + el.clientHeight - totalSize) * 2;
1053
+ child.style.paddingBottom = `${pad}px`;
1054
+ void el.offsetHeight;
1055
+ scrollView.scrollBy(0, scrollDelta);
1056
+ setTimeout(() => {
1057
+ child.style.paddingBottom = prevPaddingBottom;
1058
+ }, 100);
1059
+ } else {
1060
+ scrollView.scrollBy(0, scrollDelta);
1061
+ }
1062
+ if (IS_DEV) {
1063
+ console.log("ScrollAdjust (web scrollBy)", scrollDelta, "total offset:", scrollOffset);
1064
+ }
928
1065
  }
929
1066
  lastScrollOffsetRef.current = scrollOffset;
930
1067
  }
@@ -933,49 +1070,26 @@ function ScrollAdjust() {
933
1070
  useValueListener$("scrollAdjustUserOffset", callback);
934
1071
  return null;
935
1072
  }
936
-
937
- // src/components/SnapWrapper.tsx
938
1073
  function SnapWrapper({ ScrollComponent, ...props }) {
939
1074
  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;
1075
+ return /* @__PURE__ */ React3.createElement(ScrollComponent, { ...props, snapToOffsets });
947
1076
  }
1077
+ var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
1078
+ const ref = refView != null ? refView : useRef();
1079
+ useOnLayoutSync({ onLayoutChange, ref });
1080
+ return /* @__PURE__ */ React3.createElement("div", { ...rest, ref }, children);
1081
+ };
948
1082
 
949
1083
  // src/components/ListComponent.tsx
950
1084
  var getComponent = (Component) => {
951
- if (React4.isValidElement(Component)) {
1085
+ if (React3.isValidElement(Component)) {
952
1086
  return Component;
953
1087
  }
954
1088
  if (Component) {
955
- return /* @__PURE__ */ React4.createElement(Component, null);
1089
+ return /* @__PURE__ */ React3.createElement(Component, null);
956
1090
  }
957
1091
  return null;
958
1092
  };
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
1093
  var ListComponent = typedMemo(function ListComponent2({
980
1094
  canRender,
981
1095
  style,
@@ -1001,16 +1115,15 @@ var ListComponent = typedMemo(function ListComponent2({
1001
1115
  scrollAdjustHandler,
1002
1116
  onLayoutHeader,
1003
1117
  snapToIndices,
1004
- stickyIndices,
1118
+ stickyHeaderIndices,
1005
1119
  ...rest
1006
1120
  }) {
1007
1121
  const ctx = useStateContext();
1008
- const refHeader = React4.useRef(null);
1009
1122
  const ScrollComponent = renderScrollComponent ? useMemo(
1010
- () => React4.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1123
+ () => React3.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1011
1124
  [renderScrollComponent]
1012
1125
  ) : ListComponentScrollView;
1013
- React4.useEffect(() => {
1126
+ React3.useEffect(() => {
1014
1127
  if (canRender) {
1015
1128
  setTimeout(() => {
1016
1129
  scrollAdjustHandler.setMounted();
@@ -1018,39 +1131,30 @@ var ListComponent = typedMemo(function ListComponent2({
1018
1131
  }
1019
1132
  }, [canRender]);
1020
1133
  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(
1134
+ return /* @__PURE__ */ React3.createElement(
1028
1135
  SnapOrScroll,
1029
1136
  {
1030
1137
  ...rest,
1031
- contentContainerStyle: contentContainerStyleWeb,
1138
+ contentContainerStyle: [
1139
+ contentContainerStyle,
1140
+ horizontal ? {
1141
+ height: "100%"
1142
+ } : {}
1143
+ ],
1032
1144
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1033
1145
  horizontal,
1034
- maintainVisibleContentPosition: maintainVisibleContentPosition && !ListEmptyComponent ? { minIndexForVisible: 0 } : void 0,
1146
+ maintainVisibleContentPosition: maintainVisibleContentPosition ? { minIndexForVisible: 0 } : void 0,
1035
1147
  onLayout,
1036
1148
  onScroll: onScroll2,
1037
1149
  ref: refScrollView,
1038
1150
  ScrollComponent: snapToIndices ? ScrollComponent : void 0,
1039
1151
  style
1040
1152
  },
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
- ),
1153
+ /* @__PURE__ */ React3.createElement(ScrollAdjust, null),
1154
+ ENABLE_DEVMODE ? /* @__PURE__ */ React3.createElement(PaddingDevMode, null) : /* @__PURE__ */ React3.createElement(Padding, null),
1155
+ ListHeaderComponent && /* @__PURE__ */ React3.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
1052
1156
  ListEmptyComponent && getComponent(ListEmptyComponent),
1053
- canRender && /* @__PURE__ */ React4.createElement(
1157
+ canRender && !ListEmptyComponent && /* @__PURE__ */ React3.createElement(
1054
1158
  Containers,
1055
1159
  {
1056
1160
  getRenderedItem: getRenderedItem2,
@@ -1061,7 +1165,7 @@ var ListComponent = typedMemo(function ListComponent2({
1061
1165
  waitForInitialLayout
1062
1166
  }
1063
1167
  ),
1064
- ListFooterComponent && /* @__PURE__ */ React4.createElement(
1168
+ ListFooterComponent && /* @__PURE__ */ React3.createElement(
1065
1169
  LayoutView,
1066
1170
  {
1067
1171
  onLayoutChange: (layout) => {
@@ -1072,7 +1176,7 @@ var ListComponent = typedMemo(function ListComponent2({
1072
1176
  },
1073
1177
  getComponent(ListFooterComponent)
1074
1178
  ),
1075
- __DEV__ && ENABLE_DEVMODE && /* @__PURE__ */ React4.createElement(DevNumbers, null)
1179
+ IS_DEV && ENABLE_DEVMODE && /* @__PURE__ */ React3.createElement(DevNumbers, null)
1076
1180
  );
1077
1181
  });
1078
1182
 
@@ -1084,7 +1188,7 @@ function getId(state, index) {
1084
1188
  }
1085
1189
  const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
1086
1190
  const id = ret;
1087
- state.idCache.set(index, id);
1191
+ state.idCache[index] = id;
1088
1192
  return id;
1089
1193
  }
1090
1194
 
@@ -1105,13 +1209,84 @@ function calculateOffsetForIndex(ctx, state, index) {
1105
1209
  return position;
1106
1210
  }
1107
1211
 
1212
+ // src/utils/setPaddingTop.ts
1213
+ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1214
+ if (stylePaddingTop !== void 0) {
1215
+ const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1216
+ if (stylePaddingTop < prevStylePaddingTop) {
1217
+ let prevTotalSize = peek$(ctx, "totalSize") || 0;
1218
+ set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1219
+ state.timeoutSetPaddingTop = setTimeout(() => {
1220
+ prevTotalSize = peek$(ctx, "totalSize") || 0;
1221
+ set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
1222
+ }, 16);
1223
+ }
1224
+ set$(ctx, "stylePaddingTop", stylePaddingTop);
1225
+ }
1226
+ if (alignItemsPaddingTop !== void 0) {
1227
+ set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1228
+ }
1229
+ }
1230
+
1231
+ // src/utils/updateAlignItemsPaddingTop.ts
1232
+ function updateAlignItemsPaddingTop(ctx, state) {
1233
+ const {
1234
+ scrollLength,
1235
+ props: { alignItemsAtEnd, data }
1236
+ } = state;
1237
+ if (alignItemsAtEnd) {
1238
+ let alignItemsPaddingTop = 0;
1239
+ if ((data == null ? void 0 : data.length) > 0) {
1240
+ const contentSize = getContentSize(ctx);
1241
+ alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1242
+ }
1243
+ setPaddingTop(ctx, state, { alignItemsPaddingTop });
1244
+ }
1245
+ }
1246
+
1247
+ // src/core/addTotalSize.ts
1248
+ function addTotalSize(ctx, state, key, add) {
1249
+ const { alignItemsAtEnd } = state.props;
1250
+ const prevTotalSize = state.totalSize;
1251
+ let totalSize = state.totalSize;
1252
+ if (key === null) {
1253
+ totalSize = add;
1254
+ if (state.timeoutSetPaddingTop) {
1255
+ clearTimeout(state.timeoutSetPaddingTop);
1256
+ state.timeoutSetPaddingTop = void 0;
1257
+ }
1258
+ } else {
1259
+ totalSize += add;
1260
+ }
1261
+ if (prevTotalSize !== totalSize) {
1262
+ {
1263
+ state.pendingTotalSize = void 0;
1264
+ state.totalSize = totalSize;
1265
+ set$(ctx, "totalSize", totalSize);
1266
+ if (alignItemsAtEnd) {
1267
+ updateAlignItemsPaddingTop(ctx, state);
1268
+ }
1269
+ }
1270
+ }
1271
+ }
1272
+
1273
+ // src/core/setSize.ts
1274
+ function setSize(ctx, state, itemKey, size) {
1275
+ const { sizes } = state;
1276
+ const previousSize = sizes.get(itemKey);
1277
+ const diff = previousSize !== void 0 ? size - previousSize : size;
1278
+ if (diff !== 0) {
1279
+ addTotalSize(ctx, state, itemKey, diff);
1280
+ }
1281
+ sizes.set(itemKey, size);
1282
+ }
1283
+
1108
1284
  // src/utils/getItemSize.ts
1109
- function getItemSize(state, key, index, data, useAverageSize) {
1110
- var _a, _b;
1285
+ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedSize) {
1286
+ var _a3, _b;
1111
1287
  const {
1112
1288
  sizesKnown,
1113
1289
  sizes,
1114
- scrollingTo,
1115
1290
  averageSizes,
1116
1291
  props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
1117
1292
  } = state;
@@ -1120,7 +1295,14 @@ function getItemSize(state, key, index, data, useAverageSize) {
1120
1295
  return sizeKnown;
1121
1296
  }
1122
1297
  let size;
1123
- const itemType = getItemType ? (_a = getItemType(data, index)) != null ? _a : "" : "";
1298
+ const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1299
+ const scrollingTo = peek$(ctx, "scrollingTo");
1300
+ if (preferCachedSize) {
1301
+ const cachedSize = sizes.get(key);
1302
+ if (cachedSize !== void 0) {
1303
+ return cachedSize;
1304
+ }
1305
+ }
1124
1306
  if (getFixedItemSize) {
1125
1307
  size = getFixedItemSize(index, data, itemType);
1126
1308
  if (size !== void 0) {
@@ -1142,53 +1324,234 @@ function getItemSize(state, key, index, data, useAverageSize) {
1142
1324
  if (size === void 0) {
1143
1325
  size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
1144
1326
  }
1145
- sizes.set(key, size);
1327
+ setSize(ctx, state, key, size);
1146
1328
  return size;
1147
1329
  }
1148
1330
 
1149
1331
  // src/core/calculateOffsetWithOffsetPosition.ts
1150
- function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
1332
+ function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
1151
1333
  const { index, viewOffset, viewPosition } = params;
1152
1334
  let offset = offsetParam;
1153
1335
  if (viewOffset) {
1154
1336
  offset -= viewOffset;
1155
1337
  }
1156
1338
  if (viewPosition !== void 0 && index !== void 0) {
1157
- offset -= viewPosition * (state.scrollLength - getItemSize(state, getId(state, index), index, state.props.data[index]));
1339
+ offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
1158
1340
  }
1159
1341
  return offset;
1160
1342
  }
1161
1343
 
1162
1344
  // src/core/finishScrollTo.ts
1163
- var finishScrollTo = (state) => {
1345
+ function finishScrollTo(ctx, state) {
1346
+ var _a3, _b;
1164
1347
  if (state) {
1165
- state.scrollingTo = void 0;
1166
1348
  state.scrollHistory.length = 0;
1349
+ state.initialScroll = void 0;
1350
+ state.initialAnchor = void 0;
1351
+ set$(ctx, "scrollingTo", void 0);
1352
+ if (state.pendingTotalSize !== void 0) {
1353
+ addTotalSize(ctx, state, null, state.pendingTotalSize);
1354
+ }
1355
+ if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1356
+ (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1357
+ }
1167
1358
  }
1168
- };
1359
+ }
1169
1360
 
1170
1361
  // src/core/scrollTo.ts
1171
- function scrollTo(state, params = {}) {
1172
- var _a;
1173
- const { animated, noScrollingTo } = params;
1362
+ function scrollTo(ctx, state, params) {
1363
+ var _a3;
1364
+ const { noScrollingTo, ...scrollTarget } = params;
1365
+ const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1174
1366
  const {
1175
1367
  refScroller,
1176
1368
  props: { horizontal }
1177
1369
  } = state;
1178
- const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
1370
+ let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1371
+ if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1372
+ const maxOffset = Math.max(0, getContentSize(ctx) - state.scrollLength);
1373
+ offset = Math.min(offset, maxOffset);
1374
+ }
1179
1375
  state.scrollHistory.length = 0;
1180
1376
  if (!noScrollingTo) {
1181
- state.scrollingTo = params;
1377
+ set$(ctx, "scrollingTo", scrollTarget);
1182
1378
  }
1183
1379
  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
- });
1380
+ if (!isInitialScroll || Platform.OS === "android") {
1381
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1382
+ animated: !!animated,
1383
+ x: horizontal ? offset : 0,
1384
+ y: horizontal ? 0 : offset
1385
+ });
1386
+ }
1189
1387
  if (!animated) {
1190
1388
  state.scroll = offset;
1191
- setTimeout(() => finishScrollTo(state), 100);
1389
+ {
1390
+ const unlisten = listen$(ctx, "containersDidLayout", (value) => {
1391
+ if (value && peek$(ctx, "scrollingTo")) {
1392
+ finishScrollTo(ctx, state);
1393
+ unlisten();
1394
+ }
1395
+ });
1396
+ }
1397
+ if (isInitialScroll) {
1398
+ setTimeout(() => {
1399
+ state.initialScroll = void 0;
1400
+ }, 500);
1401
+ }
1402
+ }
1403
+ }
1404
+
1405
+ // src/utils/checkThreshold.ts
1406
+ var HYSTERESIS_MULTIPLIER = 1.3;
1407
+ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1408
+ const absDistance = Math.abs(distance);
1409
+ const within = atThreshold || threshold > 0 && absDistance <= threshold;
1410
+ const updateSnapshot = () => {
1411
+ setSnapshot == null ? void 0 : setSnapshot({
1412
+ atThreshold,
1413
+ contentSize: context.contentSize,
1414
+ dataLength: context.dataLength,
1415
+ scrollPosition: context.scrollPosition
1416
+ });
1417
+ };
1418
+ if (!wasReached) {
1419
+ if (!within) {
1420
+ return false;
1421
+ }
1422
+ onReached == null ? void 0 : onReached(distance);
1423
+ updateSnapshot();
1424
+ return true;
1425
+ }
1426
+ const reset = !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
1427
+ if (reset) {
1428
+ setSnapshot == null ? void 0 : setSnapshot(void 0);
1429
+ return false;
1430
+ }
1431
+ if (within) {
1432
+ const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
1433
+ if (changed) {
1434
+ onReached == null ? void 0 : onReached(distance);
1435
+ updateSnapshot();
1436
+ }
1437
+ }
1438
+ return true;
1439
+ };
1440
+
1441
+ // src/utils/checkAtBottom.ts
1442
+ function checkAtBottom(ctx, state) {
1443
+ var _a3;
1444
+ if (!state) {
1445
+ return;
1446
+ }
1447
+ const {
1448
+ queuedInitialLayout,
1449
+ scrollLength,
1450
+ scroll,
1451
+ maintainingScrollAtEnd,
1452
+ props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
1453
+ } = state;
1454
+ const contentSize = getContentSize(ctx);
1455
+ if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1456
+ const distanceFromEnd = contentSize - scroll - scrollLength;
1457
+ const isContentLess = contentSize < scrollLength;
1458
+ state.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1459
+ state.isEndReached = checkThreshold(
1460
+ distanceFromEnd,
1461
+ isContentLess,
1462
+ onEndReachedThreshold * scrollLength,
1463
+ state.isEndReached,
1464
+ state.endReachedSnapshot,
1465
+ {
1466
+ contentSize,
1467
+ dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length,
1468
+ scrollPosition: scroll
1469
+ },
1470
+ (distance) => {
1471
+ var _a4, _b;
1472
+ return (_b = (_a4 = state.props).onEndReached) == null ? void 0 : _b.call(_a4, { distanceFromEnd: distance });
1473
+ },
1474
+ (snapshot) => {
1475
+ state.endReachedSnapshot = snapshot;
1476
+ }
1477
+ );
1478
+ }
1479
+ }
1480
+
1481
+ // src/utils/checkAtTop.ts
1482
+ function checkAtTop(state) {
1483
+ var _a3;
1484
+ if (!state) {
1485
+ return;
1486
+ }
1487
+ const {
1488
+ scrollLength,
1489
+ scroll,
1490
+ props: { onStartReachedThreshold }
1491
+ } = state;
1492
+ const distanceFromTop = scroll;
1493
+ state.isAtStart = distanceFromTop <= 0;
1494
+ state.isStartReached = checkThreshold(
1495
+ distanceFromTop,
1496
+ false,
1497
+ onStartReachedThreshold * scrollLength,
1498
+ state.isStartReached,
1499
+ state.startReachedSnapshot,
1500
+ {
1501
+ contentSize: state.totalSize,
1502
+ dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length,
1503
+ scrollPosition: scroll
1504
+ },
1505
+ (distance) => {
1506
+ var _a4, _b;
1507
+ return (_b = (_a4 = state.props).onStartReached) == null ? void 0 : _b.call(_a4, { distanceFromStart: distance });
1508
+ },
1509
+ (snapshot) => {
1510
+ state.startReachedSnapshot = snapshot;
1511
+ }
1512
+ );
1513
+ }
1514
+
1515
+ // src/core/updateScroll.ts
1516
+ function updateScroll(ctx, state, newScroll, forceUpdate) {
1517
+ var _a3;
1518
+ const scrollingTo = peek$(ctx, "scrollingTo");
1519
+ state.hasScrolled = true;
1520
+ state.lastBatchingAction = Date.now();
1521
+ const currentTime = Date.now();
1522
+ const adjust = state.scrollAdjustHandler.getAdjust();
1523
+ const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1524
+ const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1525
+ if (adjustChanged) {
1526
+ state.scrollHistory.length = 0;
1527
+ }
1528
+ state.lastScrollAdjustForHistory = adjust;
1529
+ if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
1530
+ if (!adjustChanged) {
1531
+ state.scrollHistory.push({ scroll: newScroll, time: currentTime });
1532
+ }
1533
+ }
1534
+ if (state.scrollHistory.length > 5) {
1535
+ state.scrollHistory.shift();
1536
+ }
1537
+ state.scrollPrev = state.scroll;
1538
+ state.scrollPrevTime = state.scrollTime;
1539
+ state.scroll = newScroll;
1540
+ state.scrollTime = currentTime;
1541
+ const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
1542
+ if (ignoreScrollFromMVCP && !scrollingTo) {
1543
+ const { lt, gt } = ignoreScrollFromMVCP;
1544
+ if (lt && newScroll < lt || gt && newScroll > gt) {
1545
+ state.ignoreScrollFromMVCPIgnored = true;
1546
+ return;
1547
+ }
1548
+ }
1549
+ if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1550
+ state.ignoreScrollFromMVCPIgnored = false;
1551
+ (_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { doMVCP: scrollingTo !== void 0 });
1552
+ checkAtBottom(ctx, state);
1553
+ checkAtTop(state);
1554
+ state.dataChangeNeedsScrollUpdate = false;
1192
1555
  }
1193
1556
  }
1194
1557
 
@@ -1198,6 +1561,9 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1198
1561
  const doit = () => {
1199
1562
  {
1200
1563
  state.scrollAdjustHandler.requestAdjust(positionDiff);
1564
+ if (state.adjustingFromInitialMount) {
1565
+ state.adjustingFromInitialMount--;
1566
+ }
1201
1567
  }
1202
1568
  };
1203
1569
  state.scroll += positionDiff;
@@ -1205,44 +1571,77 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1205
1571
  const didLayout = peek$(ctx, "containersDidLayout");
1206
1572
  if (didLayout) {
1207
1573
  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
1574
  } else {
1575
+ state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
1227
1576
  requestAnimationFrame(doit);
1228
1577
  }
1229
1578
  }
1230
1579
  }
1231
1580
 
1581
+ // src/core/ensureInitialAnchor.ts
1582
+ var INITIAL_ANCHOR_TOLERANCE = 0.5;
1583
+ var INITIAL_ANCHOR_MAX_ATTEMPTS = 4;
1584
+ var INITIAL_ANCHOR_SETTLED_TICKS = 2;
1585
+ function ensureInitialAnchor(ctx, state) {
1586
+ var _a3, _b, _c, _d, _e;
1587
+ const anchor = state.initialAnchor;
1588
+ const item = state.props.data[anchor.index];
1589
+ const containersDidLayout = peek$(ctx, "containersDidLayout");
1590
+ if (!containersDidLayout) {
1591
+ return;
1592
+ }
1593
+ const id = getId(state, anchor.index);
1594
+ if (state.positions.get(id) === void 0) {
1595
+ return;
1596
+ }
1597
+ const size = getItemSize(ctx, state, id, anchor.index, item, true, true);
1598
+ if (size === void 0) {
1599
+ return;
1600
+ }
1601
+ const availableSpace = Math.max(0, state.scrollLength - size);
1602
+ const desiredOffset = calculateOffsetForIndex(ctx, state, anchor.index) - ((_a3 = anchor.viewOffset) != null ? _a3 : 0) - ((_b = anchor.viewPosition) != null ? _b : 0) * availableSpace;
1603
+ const contentSize = getContentSize(ctx);
1604
+ const maxOffset = Math.max(0, contentSize - state.scrollLength);
1605
+ const clampedDesiredOffset = Math.max(0, Math.min(desiredOffset, maxOffset));
1606
+ const delta = clampedDesiredOffset - state.scroll;
1607
+ if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
1608
+ const settledTicks = ((_c = anchor.settledTicks) != null ? _c : 0) + 1;
1609
+ if (settledTicks >= INITIAL_ANCHOR_SETTLED_TICKS) {
1610
+ state.initialAnchor = void 0;
1611
+ } else {
1612
+ anchor.settledTicks = settledTicks;
1613
+ }
1614
+ return;
1615
+ }
1616
+ if (((_d = anchor.attempts) != null ? _d : 0) >= INITIAL_ANCHOR_MAX_ATTEMPTS) {
1617
+ state.initialAnchor = void 0;
1618
+ return;
1619
+ }
1620
+ const lastDelta = anchor.lastDelta;
1621
+ if (lastDelta !== void 0 && Math.abs(delta) >= Math.abs(lastDelta)) {
1622
+ state.initialAnchor = void 0;
1623
+ return;
1624
+ }
1625
+ Object.assign(anchor, {
1626
+ attempts: ((_e = anchor.attempts) != null ? _e : 0) + 1,
1627
+ lastDelta: delta,
1628
+ settledTicks: 0
1629
+ });
1630
+ requestAdjust(ctx, state, delta);
1631
+ }
1632
+
1232
1633
  // src/core/mvcp.ts
1233
1634
  function prepareMVCP(ctx, state, dataChanged) {
1234
- const {
1235
- idsInView,
1236
- positions,
1237
- scrollingTo,
1238
- props: { maintainVisibleContentPosition }
1239
- } = state;
1635
+ const { idsInView, positions, props } = state;
1636
+ const { maintainVisibleContentPosition } = props;
1637
+ const scrollingTo = peek$(ctx, "scrollingTo");
1240
1638
  let prevPosition;
1241
1639
  let targetId;
1242
1640
  const idsInViewWithPositions = [];
1243
1641
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1244
- if (maintainVisibleContentPosition) {
1245
- const indexByKey = state.indexByKey;
1642
+ const shouldMVCP = !dataChanged || maintainVisibleContentPosition;
1643
+ const indexByKey = state.indexByKey;
1644
+ if (shouldMVCP) {
1246
1645
  if (scrollTarget !== void 0) {
1247
1646
  targetId = getId(state, scrollTarget);
1248
1647
  } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
@@ -1255,70 +1654,106 @@ function prepareMVCP(ctx, state, dataChanged) {
1255
1654
  }
1256
1655
  }
1257
1656
  } else {
1258
- targetId = state.idsInView.find((id) => indexByKey.get(id) !== void 0);
1657
+ targetId = idsInView.find((id) => indexByKey.get(id) !== void 0);
1259
1658
  }
1260
1659
  }
1261
1660
  if (targetId !== void 0) {
1262
1661
  prevPosition = positions.get(targetId);
1263
1662
  }
1264
- }
1265
- return () => {
1266
- let positionDiff;
1267
- if (dataChanged && targetId === void 0) {
1268
- for (let i = 0; i < idsInViewWithPositions.length; i++) {
1269
- const { id, position } = idsInViewWithPositions[i];
1270
- const newPosition = positions.get(id);
1663
+ return () => {
1664
+ let positionDiff;
1665
+ if (dataChanged && targetId === void 0 && maintainVisibleContentPosition) {
1666
+ for (let i = 0; i < idsInViewWithPositions.length; i++) {
1667
+ const { id, position } = idsInViewWithPositions[i];
1668
+ const newPosition = positions.get(id);
1669
+ if (newPosition !== void 0) {
1670
+ positionDiff = newPosition - position;
1671
+ break;
1672
+ }
1673
+ }
1674
+ }
1675
+ if (targetId !== void 0 && prevPosition !== void 0) {
1676
+ const newPosition = positions.get(targetId);
1271
1677
  if (newPosition !== void 0) {
1272
- positionDiff = newPosition - position;
1273
- break;
1678
+ const totalSize = getContentSize(ctx);
1679
+ let diff = newPosition - prevPosition;
1680
+ if (diff !== 0 && state.scroll + state.scrollLength > totalSize) {
1681
+ if (diff > 0) {
1682
+ diff = Math.max(0, totalSize - state.scroll - state.scrollLength);
1683
+ } else {
1684
+ diff = 0;
1685
+ }
1686
+ }
1687
+ positionDiff = diff;
1274
1688
  }
1275
1689
  }
1276
- }
1277
- if (targetId !== void 0 && prevPosition !== void 0) {
1278
- const newPosition = positions.get(targetId);
1279
- if (newPosition !== void 0) {
1280
- positionDiff = newPosition - prevPosition;
1690
+ if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1691
+ requestAdjust(ctx, state, positionDiff);
1281
1692
  }
1282
- }
1283
- if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1284
- requestAdjust(ctx, state, positionDiff);
1285
- }
1286
- };
1693
+ };
1694
+ }
1287
1695
  }
1288
1696
 
1289
- // src/utils/setPaddingTop.ts
1290
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1291
- if (stylePaddingTop !== void 0) {
1292
- const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1293
- if (stylePaddingTop < prevStylePaddingTop) {
1294
- let prevTotalSize = peek$(ctx, "totalSize") || 0;
1295
- set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1296
- state.timeoutSetPaddingTop = setTimeout(() => {
1297
- prevTotalSize = peek$(ctx, "totalSize") || 0;
1298
- set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
1299
- }, 16);
1300
- }
1301
- set$(ctx, "stylePaddingTop", stylePaddingTop);
1697
+ // src/core/prepareColumnStartState.ts
1698
+ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1699
+ var _a3;
1700
+ const numColumns = peek$(ctx, "numColumns");
1701
+ let rowStartIndex = startIndex;
1702
+ const columnAtStart = state.columns.get(state.idCache[startIndex]);
1703
+ if (columnAtStart !== 1) {
1704
+ rowStartIndex = findRowStartIndex(state, numColumns, startIndex);
1302
1705
  }
1303
- if (alignItemsPaddingTop !== void 0) {
1304
- set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1706
+ let currentRowTop = 0;
1707
+ const curId = state.idCache[rowStartIndex];
1708
+ const column = state.columns.get(curId);
1709
+ if (rowStartIndex > 0) {
1710
+ const prevIndex = rowStartIndex - 1;
1711
+ const prevId = state.idCache[prevIndex];
1712
+ const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1713
+ const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1714
+ const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1715
+ currentRowTop = prevPosition + prevRowHeight;
1305
1716
  }
1717
+ return {
1718
+ column,
1719
+ currentRowTop,
1720
+ startIndex: rowStartIndex
1721
+ };
1306
1722
  }
1307
-
1308
- // src/utils/updateAlignItemsPaddingTop.ts
1309
- function updateAlignItemsPaddingTop(ctx, state) {
1310
- const {
1311
- scrollLength,
1312
- props: { alignItemsAtEnd, data }
1313
- } = state;
1314
- if (alignItemsAtEnd) {
1315
- let alignItemsPaddingTop = 0;
1316
- if ((data == null ? void 0 : data.length) > 0) {
1317
- const contentSize = getContentSize(ctx);
1318
- alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1723
+ function findRowStartIndex(state, numColumns, index) {
1724
+ if (numColumns <= 1) {
1725
+ return Math.max(0, index);
1726
+ }
1727
+ let rowStart = Math.max(0, index);
1728
+ while (rowStart > 0) {
1729
+ const columnForIndex = state.columns.get(state.idCache[rowStart]);
1730
+ if (columnForIndex === 1) {
1731
+ break;
1319
1732
  }
1320
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
1733
+ rowStart--;
1321
1734
  }
1735
+ return rowStart;
1736
+ }
1737
+ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1738
+ if (endIndex < startIndex) {
1739
+ return 0;
1740
+ }
1741
+ const { data } = state.props;
1742
+ if (!data) {
1743
+ return 0;
1744
+ }
1745
+ let maxSize = 0;
1746
+ for (let i = startIndex; i <= endIndex; i++) {
1747
+ if (i < 0 || i >= data.length) {
1748
+ continue;
1749
+ }
1750
+ const id = state.idCache[i];
1751
+ const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1752
+ if (size > maxSize) {
1753
+ maxSize = size;
1754
+ }
1755
+ }
1756
+ return maxSize;
1322
1757
  }
1323
1758
 
1324
1759
  // src/core/updateTotalSize.ts
@@ -1334,29 +1769,53 @@ function updateTotalSize(ctx, state) {
1334
1769
  if (lastId !== void 0) {
1335
1770
  const lastPosition = positions.get(lastId);
1336
1771
  if (lastPosition !== void 0) {
1337
- const lastSize = getItemSize(state, lastId, data.length - 1, data[data.length - 1]);
1772
+ const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1338
1773
  if (lastSize !== void 0) {
1339
1774
  const totalSize = lastPosition + lastSize;
1340
1775
  addTotalSize(ctx, state, null, totalSize);
1341
1776
  }
1342
1777
  }
1343
1778
  }
1344
- }
1345
- }
1346
- function addTotalSize(ctx, state, key, add) {
1347
- const { alignItemsAtEnd } = state.props;
1348
- {
1349
- state.totalSize = add;
1350
- if (state.timeoutSetPaddingTop) {
1351
- clearTimeout(state.timeoutSetPaddingTop);
1352
- state.timeoutSetPaddingTop = void 0;
1779
+ }
1780
+ }
1781
+
1782
+ // src/utils/getScrollVelocity.ts
1783
+ var getScrollVelocity = (state) => {
1784
+ const { scrollHistory } = state;
1785
+ let velocity = 0;
1786
+ if (scrollHistory.length >= 1) {
1787
+ const newest = scrollHistory[scrollHistory.length - 1];
1788
+ let oldest;
1789
+ let start = 0;
1790
+ const now = Date.now();
1791
+ for (let i = 0; i < scrollHistory.length - 1; i++) {
1792
+ const entry = scrollHistory[i];
1793
+ const nextEntry = scrollHistory[i + 1];
1794
+ if (i > 0) {
1795
+ const prevEntry = scrollHistory[i - 1];
1796
+ const prevDirection = entry.scroll - prevEntry.scroll;
1797
+ const currentDirection = nextEntry.scroll - entry.scroll;
1798
+ if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1799
+ start = i;
1800
+ break;
1801
+ }
1802
+ }
1803
+ }
1804
+ for (let i = start; i < scrollHistory.length - 1; i++) {
1805
+ const entry = scrollHistory[i];
1806
+ if (now - entry.time <= 1e3) {
1807
+ oldest = entry;
1808
+ break;
1809
+ }
1810
+ }
1811
+ if (oldest && oldest !== newest) {
1812
+ const scrollDiff = newest.scroll - oldest.scroll;
1813
+ const timeDiff = newest.time - oldest.time;
1814
+ velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1353
1815
  }
1354
1816
  }
1355
- set$(ctx, "totalSize", state.totalSize);
1356
- if (alignItemsAtEnd) {
1357
- updateAlignItemsPaddingTop(ctx, state);
1358
- }
1359
- }
1817
+ return velocity;
1818
+ };
1360
1819
 
1361
1820
  // src/utils/updateSnapToOffsets.ts
1362
1821
  function updateSnapToOffsets(ctx, state) {
@@ -1373,9 +1832,14 @@ function updateSnapToOffsets(ctx, state) {
1373
1832
  set$(ctx, "snapToOffsets", snapToOffsets);
1374
1833
  }
1375
1834
 
1376
- // src/core/updateAllPositions.ts
1377
- function updateAllPositions(ctx, state, dataChanged, startIndex = 0) {
1378
- var _a, _b, _c, _d, _e, _f;
1835
+ // src/core/updateItemPositions.ts
1836
+ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
1837
+ doMVCP: false,
1838
+ forceFullUpdate: false,
1839
+ scrollBottomBuffered: -1,
1840
+ startIndex: 0
1841
+ }) {
1842
+ var _a3, _b, _c, _d, _e;
1379
1843
  const {
1380
1844
  columns,
1381
1845
  indexByKey,
@@ -1385,32 +1849,51 @@ function updateAllPositions(ctx, state, dataChanged, startIndex = 0) {
1385
1849
  props: { getEstimatedItemSize, snapToIndices, enableAverages }
1386
1850
  } = state;
1387
1851
  const data = state.props.data;
1852
+ const dataLength = data.length;
1388
1853
  const numColumns = peek$(ctx, "numColumns");
1389
- const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
1854
+ const scrollingTo = peek$(ctx, "scrollingTo");
1855
+ const hasColumns = numColumns > 1;
1856
+ const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1857
+ const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1858
+ const maxVisibleArea = scrollBottomBuffered + 1e3;
1390
1859
  const useAverageSize = enableAverages && !getEstimatedItemSize;
1860
+ const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0;
1391
1861
  let currentRowTop = 0;
1392
1862
  let column = 1;
1393
1863
  let maxSizeInRow = 0;
1394
- const hasColumns = numColumns > 1;
1395
1864
  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
1865
  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);
1866
+ const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
1867
+ ctx,
1868
+ state,
1869
+ startIndex,
1870
+ useAverageSize
1871
+ );
1872
+ startIndex = processedStartIndex;
1873
+ currentRowTop = initialRowTop;
1874
+ } else if (startIndex < dataLength) {
1875
+ const prevIndex = startIndex - 1;
1876
+ const prevId = getId(state, prevIndex);
1877
+ const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1878
+ const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1405
1879
  currentRowTop = prevPosition + prevSize;
1406
1880
  }
1407
1881
  }
1408
1882
  const needsIndexByKey = dataChanged || indexByKey.size === 0;
1409
- const dataLength = data.length;
1883
+ let didBreakEarly = false;
1884
+ let breakAt;
1410
1885
  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) {
1886
+ if (shouldOptimize && breakAt !== void 0 && i > breakAt) {
1887
+ didBreakEarly = true;
1888
+ break;
1889
+ }
1890
+ if (shouldOptimize && breakAt === void 0 && !scrollingTo && !dataChanged && currentRowTop > maxVisibleArea) {
1891
+ const itemsPerRow = hasColumns ? numColumns : 1;
1892
+ breakAt = i + itemsPerRow + 10;
1893
+ }
1894
+ const id = (_d = idCache[i]) != null ? _d : getId(state, i);
1895
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, state, id, i, data[i], useAverageSize, preferCachedSize);
1896
+ if (IS_DEV && needsIndexByKey) {
1414
1897
  if (indexByKeyForChecking.has(id)) {
1415
1898
  console.error(
1416
1899
  `[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 +1920,9 @@ function updateAllPositions(ctx, state, dataChanged, startIndex = 0) {
1437
1920
  currentRowTop += size;
1438
1921
  }
1439
1922
  }
1440
- updateTotalSize(ctx, state);
1923
+ if (!didBreakEarly) {
1924
+ updateTotalSize(ctx, state);
1925
+ }
1441
1926
  if (snapToIndices) {
1442
1927
  updateSnapToOffsets(ctx, state);
1443
1928
  }
@@ -1457,6 +1942,21 @@ function ensureViewabilityState(ctx, configId) {
1457
1942
  }
1458
1943
  return state;
1459
1944
  }
1945
+ function setupViewability(props) {
1946
+ let { viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged } = props;
1947
+ if (viewabilityConfig || onViewableItemsChanged) {
1948
+ viewabilityConfigCallbackPairs = [
1949
+ ...viewabilityConfigCallbackPairs || [],
1950
+ {
1951
+ onViewableItemsChanged,
1952
+ viewabilityConfig: viewabilityConfig || {
1953
+ viewAreaCoveragePercentThreshold: 0
1954
+ }
1955
+ }
1956
+ ];
1957
+ }
1958
+ return viewabilityConfigCallbackPairs;
1959
+ }
1460
1960
  function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end) {
1461
1961
  const {
1462
1962
  timeouts,
@@ -1610,16 +2110,6 @@ function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize,
1610
2110
  const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
1611
2111
  return value.isViewable;
1612
2112
  }
1613
- function findContainerId(ctx, key) {
1614
- const numContainers = peek$(ctx, "numContainers");
1615
- for (let i = 0; i < numContainers; i++) {
1616
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1617
- if (itemKey === key) {
1618
- return i;
1619
- }
1620
- }
1621
- return -1;
1622
- }
1623
2113
  function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
1624
2114
  const key = containerId + configId;
1625
2115
  ctx.mapViewabilityValues.set(key, viewToken);
@@ -1628,9 +2118,12 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
1628
2118
  }
1629
2119
 
1630
2120
  // src/utils/checkAllSizesKnown.ts
2121
+ function isNullOrUndefined2(value) {
2122
+ return value === null || value === void 0;
2123
+ }
1631
2124
  function checkAllSizesKnown(state) {
1632
2125
  const { startBuffered, endBuffered, sizesKnown } = state;
1633
- if (endBuffered !== null && startBuffered >= 0 && endBuffered >= 0) {
2126
+ if (!isNullOrUndefined2(endBuffered) && !isNullOrUndefined2(startBuffered) && startBuffered >= 0 && endBuffered >= 0) {
1634
2127
  let areAllKnown = true;
1635
2128
  for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
1636
2129
  const key = getId(state, i);
@@ -1647,6 +2140,8 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1647
2140
  const { stickyContainerPool, containerItemTypes } = state;
1648
2141
  const result = [];
1649
2142
  const availableContainers = [];
2143
+ const pendingRemovalSet = new Set(pendingRemoval);
2144
+ let pendingRemovalChanged = false;
1650
2145
  const stickyIndicesSet = state.props.stickyIndicesSet;
1651
2146
  const stickyItemIndices = (needNewContainers == null ? void 0 : needNewContainers.filter((index) => stickyIndicesSet.has(index))) || [];
1652
2147
  const canReuseContainer = (containerIndex, requiredType) => {
@@ -1662,12 +2157,11 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1662
2157
  let foundContainer = false;
1663
2158
  for (const containerIndex of stickyContainerPool) {
1664
2159
  const key = peek$(ctx, `containerItemKey${containerIndex}`);
1665
- const isPendingRemoval = pendingRemoval.includes(containerIndex);
1666
- if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType)) {
2160
+ const isPendingRemoval = pendingRemovalSet.has(containerIndex);
2161
+ if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType) && !result.includes(containerIndex)) {
1667
2162
  result.push(containerIndex);
1668
- if (isPendingRemoval) {
1669
- const index = pendingRemoval.indexOf(containerIndex);
1670
- pendingRemoval.splice(index, 1);
2163
+ if (isPendingRemoval && pendingRemovalSet.delete(containerIndex)) {
2164
+ pendingRemovalChanged = true;
1671
2165
  }
1672
2166
  foundContainer = true;
1673
2167
  if (requiredItemTypes) typeIndex++;
@@ -1687,13 +2181,11 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1687
2181
  }
1688
2182
  const key = peek$(ctx, `containerItemKey${u}`);
1689
2183
  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
- }
2184
+ if (!isOk && pendingRemovalSet.has(u)) {
2185
+ pendingRemovalSet.delete(u);
2186
+ pendingRemovalChanged = true;
2187
+ const requiredType = neededTypes[typeIndex];
2188
+ isOk = canReuseContainer(u, requiredType);
1697
2189
  }
1698
2190
  if (isOk) {
1699
2191
  result.push(u);
@@ -1736,7 +2228,7 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1736
2228
  for (let i = 0; i < stillNeeded; i++) {
1737
2229
  result.push(numContainers + i);
1738
2230
  }
1739
- if (__DEV__ && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
2231
+ if (IS_DEV && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
1740
2232
  console.warn(
1741
2233
  "[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
2234
  {
@@ -1751,50 +2243,18 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1751
2243
  }
1752
2244
  }
1753
2245
  }
2246
+ if (pendingRemovalChanged) {
2247
+ pendingRemoval.length = 0;
2248
+ for (const value of pendingRemovalSet) {
2249
+ pendingRemoval.push(value);
2250
+ }
2251
+ }
1754
2252
  return result.sort(comparatorDefault);
1755
2253
  }
1756
2254
  function comparatorByDistance(a, b) {
1757
2255
  return b.distance - a.distance;
1758
2256
  }
1759
2257
 
1760
- // src/utils/getScrollVelocity.ts
1761
- var getScrollVelocity = (state) => {
1762
- const { scrollHistory } = state;
1763
- let velocity = 0;
1764
- if (scrollHistory.length >= 1) {
1765
- const newest = scrollHistory[scrollHistory.length - 1];
1766
- let oldest;
1767
- let start = 0;
1768
- const now = Date.now();
1769
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1770
- const entry = scrollHistory[i];
1771
- const nextEntry = scrollHistory[i + 1];
1772
- if (i > 0) {
1773
- const prevEntry = scrollHistory[i - 1];
1774
- const prevDirection = entry.scroll - prevEntry.scroll;
1775
- const currentDirection = nextEntry.scroll - entry.scroll;
1776
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1777
- start = i;
1778
- break;
1779
- }
1780
- }
1781
- }
1782
- for (let i = start; i < scrollHistory.length - 1; i++) {
1783
- const entry = scrollHistory[i];
1784
- if (now - entry.time <= 1e3) {
1785
- oldest = entry;
1786
- break;
1787
- }
1788
- }
1789
- if (oldest && oldest !== newest) {
1790
- const scrollDiff = newest.scroll - oldest.scroll;
1791
- const timeDiff = newest.time - oldest.time;
1792
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1793
- }
1794
- }
1795
- return velocity;
1796
- };
1797
-
1798
2258
  // src/core/scrollToIndex.ts
1799
2259
  function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
1800
2260
  if (index >= state.props.data.length) {
@@ -1807,72 +2267,16 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
1807
2267
  if (isLast && viewPosition === void 0) {
1808
2268
  viewPosition = 1;
1809
2269
  }
1810
- const firstIndexScrollPostion = firstIndexOffset - viewOffset;
1811
2270
  state.scrollForNextCalculateItemsInView = void 0;
1812
- scrollTo(state, {
2271
+ scrollTo(ctx, state, {
1813
2272
  animated,
1814
2273
  index,
1815
- offset: firstIndexScrollPostion,
2274
+ offset: firstIndexOffset,
1816
2275
  viewOffset,
1817
2276
  viewPosition: viewPosition != null ? viewPosition : 0
1818
2277
  });
1819
2278
  }
1820
2279
 
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
2280
  // src/utils/setDidLayout.ts
1877
2281
  function setDidLayout(ctx, state) {
1878
2282
  const {
@@ -1895,11 +2299,12 @@ function setDidLayout(ctx, state) {
1895
2299
 
1896
2300
  // src/core/calculateItemsInView.ts
1897
2301
  function findCurrentStickyIndex(stickyArray, scroll, state) {
1898
- var _a;
2302
+ var _a3;
1899
2303
  const idCache = state.idCache;
1900
2304
  const positions = state.positions;
1901
2305
  for (let i = stickyArray.length - 1; i >= 0; i--) {
1902
- const stickyId = (_a = idCache.get(stickyArray[i])) != null ? _a : getId(state, stickyArray[i]);
2306
+ const stickyIndex = stickyArray[i];
2307
+ const stickyId = (_a3 = idCache[stickyIndex]) != null ? _a3 : getId(state, stickyIndex);
1903
2308
  const stickyPos = stickyId ? positions.get(stickyId) : void 0;
1904
2309
  if (stickyPos !== void 0 && scroll >= stickyPos) {
1905
2310
  return i;
@@ -1907,47 +2312,51 @@ function findCurrentStickyIndex(stickyArray, scroll, state) {
1907
2312
  }
1908
2313
  return -1;
1909
2314
  }
1910
- function getActiveStickyIndices(ctx, state, stickyIndices) {
2315
+ function getActiveStickyIndices(ctx, state, stickyHeaderIndices) {
1911
2316
  return new Set(
1912
- 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))
2317
+ Array.from(state.stickyContainerPool).map((i) => peek$(ctx, `containerItemKey${i}`)).map((key) => key ? state.indexByKey.get(key) : void 0).filter((idx) => idx !== void 0 && stickyHeaderIndices.has(idx))
1913
2318
  );
1914
2319
  }
1915
- function handleStickyActivation(ctx, state, stickyIndices, stickyArray, scroll, needNewContainers, startBuffered, endBuffered) {
1916
- var _a;
1917
- const activeIndices = getActiveStickyIndices(ctx, state, stickyIndices);
1918
- const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
2320
+ function handleStickyActivation(ctx, state, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2321
+ var _a3;
2322
+ const activeIndices = getActiveStickyIndices(ctx, state, stickyHeaderIndices);
2323
+ state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
1919
2324
  for (let offset = 0; offset <= 1; offset++) {
1920
2325
  const idx = currentStickyIdx - offset;
1921
2326
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
1922
2327
  const stickyIndex = stickyArray[idx];
1923
- const stickyId = (_a = state.idCache.get(stickyIndex)) != null ? _a : getId(state, stickyIndex);
2328
+ const stickyId = (_a3 = state.idCache[stickyIndex]) != null ? _a3 : getId(state, stickyIndex);
1924
2329
  if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered)) {
1925
2330
  needNewContainers.push(stickyIndex);
1926
2331
  }
1927
2332
  }
1928
2333
  }
1929
- function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, pendingRemoval) {
1930
- var _a, _b, _c;
1931
- const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
2334
+ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2335
+ var _a3, _b, _c;
1932
2336
  for (const containerIndex of state.stickyContainerPool) {
1933
2337
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
1934
2338
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
1935
2339
  if (itemIndex === void 0) continue;
1936
2340
  const arrayIdx = stickyArray.indexOf(itemIndex);
1937
- if (arrayIdx === -1) continue;
2341
+ if (arrayIdx === -1) {
2342
+ state.stickyContainerPool.delete(containerIndex);
2343
+ set$(ctx, `containerSticky${containerIndex}`, false);
2344
+ set$(ctx, `containerStickyOffset${containerIndex}`, void 0);
2345
+ continue;
2346
+ }
1938
2347
  const isRecentSticky = arrayIdx >= currentStickyIdx - 1 && arrayIdx <= currentStickyIdx + 1;
1939
2348
  if (isRecentSticky) continue;
1940
2349
  const nextIndex = stickyArray[arrayIdx + 1];
1941
2350
  let shouldRecycle = false;
1942
2351
  if (nextIndex) {
1943
- const nextId = (_a = state.idCache.get(nextIndex)) != null ? _a : getId(state, nextIndex);
2352
+ const nextId = (_a3 = state.idCache[nextIndex]) != null ? _a3 : getId(state, nextIndex);
1944
2353
  const nextPos = nextId ? state.positions.get(nextId) : void 0;
1945
2354
  shouldRecycle = nextPos !== void 0 && scroll > nextPos + scrollBuffer * 2;
1946
2355
  } else {
1947
- const currentId = (_b = state.idCache.get(itemIndex)) != null ? _b : getId(state, itemIndex);
2356
+ const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
1948
2357
  if (currentId) {
1949
2358
  const currentPos = state.positions.get(currentId);
1950
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(state, currentId, itemIndex, state.props.data[itemIndex]);
2359
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
1951
2360
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
1952
2361
  }
1953
2362
  }
@@ -1958,61 +2367,52 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, pe
1958
2367
  }
1959
2368
  function calculateItemsInView(ctx, state, params = {}) {
1960
2369
  unstable_batchedUpdates(() => {
1961
- var _a, _b, _c, _d, _e, _f, _g, _h;
2370
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1962
2371
  const {
1963
2372
  columns,
1964
2373
  containerItemKeys,
1965
2374
  enableScrollForNextCalculateItemsInView,
1966
2375
  idCache,
1967
2376
  indexByKey,
2377
+ initialScroll,
1968
2378
  minIndexSizeChanged,
1969
2379
  positions,
2380
+ props: { getItemType, itemsAreEqual, keyExtractor, onStickyHeaderChange, scrollBuffer },
1970
2381
  scrollForNextCalculateItemsInView,
1971
2382
  scrollLength,
1972
2383
  sizes,
1973
2384
  startBufferedId: startBufferedIdOrig,
1974
- viewabilityConfigCallbackPairs,
1975
- props: { getItemType, initialScroll, itemsAreEqual, keyExtractor, scrollBuffer }
2385
+ viewabilityConfigCallbackPairs
1976
2386
  } = state;
1977
2387
  const { data } = state.props;
1978
2388
  const stickyIndicesArr = state.props.stickyIndicesArr || [];
1979
2389
  const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
1980
2390
  const prevNumContainers = peek$(ctx, "numContainers");
1981
2391
  if (!data || scrollLength === 0 || !prevNumContainers) {
2392
+ if (state.initialAnchor) {
2393
+ ensureInitialAnchor(ctx, state);
2394
+ }
1982
2395
  return;
1983
2396
  }
1984
- const totalSize = peek$(ctx, "totalSize");
2397
+ const totalSize = getContentSize(ctx);
1985
2398
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
1986
2399
  const numColumns = peek$(ctx, "numColumns");
1987
- const previousScrollAdjust = 0;
1988
- const { dataChanged, doMVCP } = params;
2400
+ const { dataChanged, doMVCP, forceFullItemPositions } = params;
1989
2401
  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
2402
  const scrollExtra = 0;
2005
2403
  const { queuedInitialLayout } = state;
2006
2404
  let { scroll: scrollState } = state;
2007
2405
  if (!queuedInitialLayout && initialScroll) {
2008
2406
  const updatedOffset = calculateOffsetWithOffsetPosition(
2407
+ ctx,
2009
2408
  state,
2010
2409
  calculateOffsetForIndex(ctx, state, initialScroll.index),
2011
2410
  initialScroll
2012
2411
  );
2013
2412
  scrollState = updatedOffset;
2014
2413
  }
2015
- const scrollAdjustPad = -previousScrollAdjust - topPad;
2414
+ const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2415
+ const scrollAdjustPad = scrollAdjustPending - topPad;
2016
2416
  let scroll = scrollState + scrollExtra + scrollAdjustPad;
2017
2417
  if (scroll + scrollLength > totalSize) {
2018
2418
  scroll = Math.max(0, totalSize - scrollLength);
@@ -2021,6 +2421,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2021
2421
  set$(ctx, "debugRawScroll", scrollState);
2022
2422
  set$(ctx, "debugComputedScroll", scroll);
2023
2423
  }
2424
+ const previousStickyIndex = state.activeStickyIndex;
2425
+ const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2426
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2427
+ state.activeStickyIndex = nextActiveStickyIndex;
2428
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2024
2429
  let scrollBufferTop = scrollBuffer;
2025
2430
  let scrollBufferBottom = scrollBuffer;
2026
2431
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2033,22 +2438,42 @@ function calculateItemsInView(ctx, state, params = {}) {
2033
2438
  const scrollTopBuffered = scroll - scrollBufferTop;
2034
2439
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
2035
2440
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
2036
- if (scrollForNextCalculateItemsInView) {
2441
+ if (!dataChanged && scrollForNextCalculateItemsInView) {
2037
2442
  const { top, bottom } = scrollForNextCalculateItemsInView;
2038
2443
  if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2444
+ if (state.initialAnchor) {
2445
+ ensureInitialAnchor(ctx, state);
2446
+ }
2039
2447
  return;
2040
2448
  }
2041
2449
  }
2450
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2451
+ if (dataChanged) {
2452
+ indexByKey.clear();
2453
+ idCache.length = 0;
2454
+ positions.clear();
2455
+ }
2456
+ const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2457
+ updateItemPositions(ctx, state, dataChanged, {
2458
+ doMVCP,
2459
+ forceFullUpdate: !!forceFullItemPositions,
2460
+ scrollBottomBuffered,
2461
+ startIndex
2462
+ });
2463
+ if (minIndexSizeChanged !== void 0) {
2464
+ state.minIndexSizeChanged = void 0;
2465
+ }
2466
+ checkMVCP == null ? void 0 : checkMVCP();
2042
2467
  let startNoBuffer = null;
2043
2468
  let startBuffered = null;
2044
2469
  let startBufferedId = null;
2045
2470
  let endNoBuffer = null;
2046
2471
  let endBuffered = null;
2047
- let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
2472
+ let loopStart = !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
2048
2473
  for (let i = loopStart; i >= 0; i--) {
2049
- const id = (_a = idCache.get(i)) != null ? _a : getId(state, i);
2474
+ const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2050
2475
  const top = positions.get(id);
2051
- const size = (_b = sizes.get(id)) != null ? _b : getItemSize(state, id, i, data[i]);
2476
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2052
2477
  const bottom = top + size;
2053
2478
  if (bottom > scroll - scrollBuffer) {
2054
2479
  loopStart = i;
@@ -2074,8 +2499,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2074
2499
  let firstFullyOnScreenIndex;
2075
2500
  const dataLength = data.length;
2076
2501
  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]);
2502
+ const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2503
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2079
2504
  const top = positions.get(id);
2080
2505
  if (!foundEnd) {
2081
2506
  if (startNoBuffer === null && top + size > scroll) {
@@ -2104,7 +2529,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2104
2529
  }
2105
2530
  const idsInView = [];
2106
2531
  for (let i = firstFullyOnScreenIndex; i <= endNoBuffer; i++) {
2107
- const id = (_e = idCache.get(i)) != null ? _e : getId(state, i);
2532
+ const id = (_g = idCache[i]) != null ? _g : getId(state, i);
2108
2533
  idsInView.push(id);
2109
2534
  }
2110
2535
  Object.assign(state, {
@@ -2136,7 +2561,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2136
2561
  let numContainers2 = prevNumContainers;
2137
2562
  const needNewContainers = [];
2138
2563
  for (let i = startBuffered; i <= endBuffered; i++) {
2139
- const id = (_f = idCache.get(i)) != null ? _f : getId(state, i);
2564
+ const id = (_h = idCache[i]) != null ? _h : getId(state, i);
2140
2565
  if (!containerItemKeys.has(id)) {
2141
2566
  needNewContainers.push(i);
2142
2567
  }
@@ -2147,11 +2572,14 @@ function calculateItemsInView(ctx, state, params = {}) {
2147
2572
  state,
2148
2573
  stickyIndicesSet,
2149
2574
  stickyIndicesArr,
2150
- scroll,
2575
+ currentStickyIdx,
2151
2576
  needNewContainers,
2152
2577
  startBuffered,
2153
2578
  endBuffered
2154
2579
  );
2580
+ } else {
2581
+ state.activeStickyIndex = void 0;
2582
+ set$(ctx, "activeStickyIndex", void 0);
2155
2583
  }
2156
2584
  if (needNewContainers.length > 0) {
2157
2585
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
@@ -2171,7 +2599,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2171
2599
  for (let idx = 0; idx < needNewContainers.length; idx++) {
2172
2600
  const i = needNewContainers[idx];
2173
2601
  const containerIndex = availableContainers[idx];
2174
- const id = (_g = idCache.get(i)) != null ? _g : getId(state, i);
2602
+ const id = (_i = idCache[i]) != null ? _i : getId(state, i);
2175
2603
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
2176
2604
  if (oldKey && oldKey !== id) {
2177
2605
  containerItemKeys.delete(oldKey);
@@ -2185,9 +2613,10 @@ function calculateItemsInView(ctx, state, params = {}) {
2185
2613
  if (stickyIndicesSet.has(i)) {
2186
2614
  set$(ctx, `containerSticky${containerIndex}`, true);
2187
2615
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2188
- set$(ctx, `containerStickyOffset${containerIndex}`, createAnimatedValue(topPadding));
2616
+ set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2189
2617
  state.stickyContainerPool.add(containerIndex);
2190
2618
  } else {
2619
+ set$(ctx, `containerSticky${containerIndex}`, false);
2191
2620
  state.stickyContainerPool.delete(containerIndex);
2192
2621
  }
2193
2622
  if (containerIndex >= numContainers2) {
@@ -2203,13 +2632,13 @@ function calculateItemsInView(ctx, state, params = {}) {
2203
2632
  }
2204
2633
  }
2205
2634
  if (stickyIndicesArr.length > 0) {
2206
- handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, pendingRemoval);
2635
+ handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2207
2636
  }
2208
2637
  let didChangePositions = false;
2209
2638
  for (let i = 0; i < numContainers; i++) {
2210
2639
  const itemKey = peek$(ctx, `containerItemKey${i}`);
2211
2640
  if (pendingRemoval.includes(i)) {
2212
- if (itemKey) {
2641
+ if (itemKey !== void 0) {
2213
2642
  containerItemKeys.delete(itemKey);
2214
2643
  }
2215
2644
  state.containerItemTypes.delete(i);
@@ -2226,11 +2655,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2226
2655
  const itemIndex = indexByKey.get(itemKey);
2227
2656
  const item = data[itemIndex];
2228
2657
  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) {
2658
+ const id = (_j = idCache[itemIndex]) != null ? _j : getId(state, itemIndex);
2659
+ const positionValue = positions.get(id);
2660
+ if (positionValue === void 0) {
2232
2661
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2233
2662
  } else {
2663
+ const position = (positionValue || 0) - scrollAdjustPending;
2234
2664
  const column = columns.get(id) || 1;
2235
2665
  const prevPos = peek$(ctx, `containerPosition${i}`);
2236
2666
  const prevColumn = peek$(ctx, `containerColumn${i}`);
@@ -2243,29 +2673,161 @@ function calculateItemsInView(ctx, state, params = {}) {
2243
2673
  set$(ctx, `containerColumn${i}`, column);
2244
2674
  }
2245
2675
  if (prevData !== item && (itemsAreEqual ? !itemsAreEqual(prevData, item, itemIndex, data) : true)) {
2246
- set$(ctx, `containerItemData${i}`, data[itemIndex]);
2676
+ set$(ctx, `containerItemData${i}`, item);
2247
2677
  }
2248
2678
  }
2249
2679
  }
2250
2680
  }
2251
2681
  }
2252
- if (didChangePositions) {
2253
- set$(ctx, "lastPositionUpdate", Date.now());
2254
- }
2255
- if (!queuedInitialLayout && endBuffered !== null) {
2256
- if (checkAllSizesKnown(state)) {
2257
- setDidLayout(ctx, state);
2258
- }
2259
- }
2260
- if (viewabilityConfigCallbackPairs) {
2261
- updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollLength, startNoBuffer, endNoBuffer);
2682
+ if (didChangePositions) {
2683
+ set$(ctx, "lastPositionUpdate", Date.now());
2684
+ }
2685
+ if (!queuedInitialLayout && endBuffered !== null) {
2686
+ if (checkAllSizesKnown(state)) {
2687
+ setDidLayout(ctx, state);
2688
+ }
2689
+ }
2690
+ if (viewabilityConfigCallbackPairs) {
2691
+ updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollLength, startNoBuffer, endNoBuffer);
2692
+ }
2693
+ if (onStickyHeaderChange && stickyIndicesArr.length > 0 && nextActiveStickyIndex !== void 0 && nextActiveStickyIndex !== previousStickyIndex) {
2694
+ const item = data[nextActiveStickyIndex];
2695
+ if (item !== void 0) {
2696
+ onStickyHeaderChange({ index: nextActiveStickyIndex, item });
2697
+ }
2698
+ }
2699
+ });
2700
+ if (state.initialAnchor) {
2701
+ ensureInitialAnchor(ctx, state);
2702
+ }
2703
+ }
2704
+
2705
+ // src/core/checkActualChange.ts
2706
+ function checkActualChange(state, dataProp, previousData) {
2707
+ if (!previousData || !dataProp || dataProp.length !== previousData.length) {
2708
+ return true;
2709
+ }
2710
+ const {
2711
+ idCache,
2712
+ props: { keyExtractor }
2713
+ } = state;
2714
+ for (let i = 0; i < dataProp.length; i++) {
2715
+ if (dataProp[i] !== previousData[i]) {
2716
+ return true;
2717
+ }
2718
+ if (keyExtractor ? idCache[i] !== keyExtractor(previousData[i], i) : dataProp[i] !== previousData[i]) {
2719
+ return true;
2720
+ }
2721
+ }
2722
+ return false;
2723
+ }
2724
+
2725
+ // src/core/doMaintainScrollAtEnd.ts
2726
+ function doMaintainScrollAtEnd(ctx, state, animated) {
2727
+ const {
2728
+ refScroller,
2729
+ props: { maintainScrollAtEnd }
2730
+ } = state;
2731
+ if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2732
+ const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2733
+ if (paddingTop > 0) {
2734
+ state.scroll = 0;
2735
+ }
2736
+ requestAnimationFrame(() => {
2737
+ var _a3;
2738
+ if (state == null ? void 0 : state.isAtEnd) {
2739
+ state.maintainingScrollAtEnd = true;
2740
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2741
+ animated
2742
+ });
2743
+ setTimeout(
2744
+ () => {
2745
+ state.maintainingScrollAtEnd = false;
2746
+ },
2747
+ 0
2748
+ );
2749
+ }
2750
+ });
2751
+ return true;
2752
+ }
2753
+ return false;
2754
+ }
2755
+
2756
+ // src/utils/updateAveragesOnDataChange.ts
2757
+ function updateAveragesOnDataChange(state, oldData, newData) {
2758
+ var _a3;
2759
+ const {
2760
+ averageSizes,
2761
+ sizesKnown,
2762
+ indexByKey,
2763
+ props: { itemsAreEqual, getItemType, keyExtractor }
2764
+ } = state;
2765
+ if (!itemsAreEqual || !oldData.length || !newData.length) {
2766
+ for (const key in averageSizes) {
2767
+ delete averageSizes[key];
2768
+ }
2769
+ return;
2770
+ }
2771
+ const itemTypesToPreserve = {};
2772
+ const newDataLength = newData.length;
2773
+ const oldDataLength = oldData.length;
2774
+ for (let newIndex = 0; newIndex < newDataLength; newIndex++) {
2775
+ const newItem = newData[newIndex];
2776
+ const id = keyExtractor ? keyExtractor(newItem, newIndex) : String(newIndex);
2777
+ const oldIndex = indexByKey.get(id);
2778
+ if (oldIndex !== void 0 && oldIndex < oldDataLength) {
2779
+ const knownSize = sizesKnown.get(id);
2780
+ if (knownSize === void 0) continue;
2781
+ const oldItem = oldData[oldIndex];
2782
+ const areEqual = itemsAreEqual(oldItem, newItem, newIndex, newData);
2783
+ if (areEqual) {
2784
+ const itemType = getItemType ? (_a3 = getItemType(newItem, newIndex)) != null ? _a3 : "" : "";
2785
+ let typeData = itemTypesToPreserve[itemType];
2786
+ if (!typeData) {
2787
+ typeData = itemTypesToPreserve[itemType] = { count: 0, totalSize: 0 };
2788
+ }
2789
+ typeData.totalSize += knownSize;
2790
+ typeData.count++;
2791
+ }
2792
+ }
2793
+ }
2794
+ for (const key in averageSizes) {
2795
+ delete averageSizes[key];
2796
+ }
2797
+ for (const itemType in itemTypesToPreserve) {
2798
+ const { totalSize, count } = itemTypesToPreserve[itemType];
2799
+ if (count > 0) {
2800
+ averageSizes[itemType] = {
2801
+ avg: totalSize / count,
2802
+ num: count
2803
+ };
2262
2804
  }
2263
- });
2805
+ }
2806
+ }
2807
+
2808
+ // src/core/checkResetContainers.ts
2809
+ function checkResetContainers(ctx, state, dataProp) {
2810
+ const { previousData } = state;
2811
+ if (previousData) {
2812
+ updateAveragesOnDataChange(state, previousData, dataProp);
2813
+ }
2814
+ const { maintainScrollAtEnd } = state.props;
2815
+ calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2816
+ const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2817
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2818
+ if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2819
+ state.isEndReached = false;
2820
+ }
2821
+ if (!didMaintainScrollAtEnd) {
2822
+ checkAtTop(state);
2823
+ checkAtBottom(ctx, state);
2824
+ }
2825
+ delete state.previousData;
2264
2826
  }
2265
2827
 
2266
2828
  // src/core/doInitialAllocateContainers.ts
2267
2829
  function doInitialAllocateContainers(ctx, state) {
2268
- var _a;
2830
+ var _a3, _b, _c;
2269
2831
  const {
2270
2832
  scrollLength,
2271
2833
  props: {
@@ -2281,12 +2843,13 @@ function doInitialAllocateContainers(ctx, state) {
2281
2843
  const hasContainers = peek$(ctx, "numContainers");
2282
2844
  if (scrollLength > 0 && data.length > 0 && !hasContainers) {
2283
2845
  let averageItemSize;
2284
- const fn = getFixedItemSize || getEstimatedItemSize;
2285
- if (fn) {
2846
+ if (getFixedItemSize || getEstimatedItemSize) {
2286
2847
  let totalSize = 0;
2287
2848
  const num = Math.min(20, data.length);
2288
2849
  for (let i = 0; i < num; i++) {
2289
- totalSize += fn(0, data[0], getItemType ? (_a = getItemType(data[0], 0)) != null ? _a : "" : "");
2850
+ const item = data[i];
2851
+ const itemType = getItemType ? (_a3 = getItemType(item, i)) != null ? _a3 : "" : "";
2852
+ 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
2853
  }
2291
2854
  averageItemSize = totalSize / num;
2292
2855
  } else {
@@ -2300,76 +2863,18 @@ function doInitialAllocateContainers(ctx, state) {
2300
2863
  set$(ctx, "numContainers", numContainers);
2301
2864
  set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
2302
2865
  if (state.lastLayout) {
2303
- if (state.props.initialScroll) {
2866
+ if (state.initialScroll) {
2304
2867
  requestAnimationFrame(() => {
2305
- calculateItemsInView(ctx, state, { dataChanged: true });
2868
+ calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2306
2869
  });
2307
2870
  } else {
2308
- calculateItemsInView(ctx, state, { dataChanged: true });
2871
+ calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2309
2872
  }
2310
2873
  }
2311
2874
  return true;
2312
2875
  }
2313
2876
  }
2314
2877
 
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
2878
  // src/core/handleLayout.ts
2374
2879
  function handleLayout(ctx, state, layout, setCanRender) {
2375
2880
  const { maintainScrollAtEnd } = state.props;
@@ -2404,19 +2909,19 @@ function handleLayout(ctx, state, layout, setCanRender) {
2404
2909
  if (state) {
2405
2910
  state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
2406
2911
  }
2407
- if (__DEV__ && measuredLength === 0) {
2912
+ if (IS_DEV && measuredLength === 0) {
2408
2913
  warnDevOnce(
2409
2914
  "height0",
2410
2915
  `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
2916
  );
2412
2917
  }
2413
- setCanRender(true);
2414
2918
  }
2919
+ setCanRender(true);
2415
2920
  }
2416
2921
 
2417
2922
  // src/core/onScroll.ts
2418
2923
  function onScroll(ctx, state, event) {
2419
- var _a, _b, _c;
2924
+ var _a3, _b, _c;
2420
2925
  const {
2421
2926
  scrollProcessingEnabled,
2422
2927
  props: { onScroll: onScrollProp }
@@ -2424,67 +2929,51 @@ function onScroll(ctx, state, event) {
2424
2929
  if (scrollProcessingEnabled === false) {
2425
2930
  return;
2426
2931
  }
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) {
2932
+ if (((_b = (_a3 = event.nativeEvent) == null ? void 0 : _a3.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
2428
2933
  return;
2429
2934
  }
2430
2935
  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
2936
  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
- }
2937
+ updateScroll(ctx, state, newScroll);
2448
2938
  onScrollProp == null ? void 0 : onScrollProp(event);
2449
2939
  }
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
- }
2471
- }
2472
2940
 
2473
2941
  // src/core/ScrollAdjustHandler.ts
2474
2942
  var ScrollAdjustHandler = class {
2475
2943
  constructor(ctx) {
2476
2944
  this.appliedAdjust = 0;
2945
+ this.pendingAdjust = 0;
2477
2946
  this.mounted = false;
2478
2947
  this.context = ctx;
2948
+ {
2949
+ const commitPendingAdjust = () => {
2950
+ const state = this.context.internalState;
2951
+ const pending = this.pendingAdjust;
2952
+ if (pending !== 0) {
2953
+ this.pendingAdjust = 0;
2954
+ this.appliedAdjust += pending;
2955
+ state.scroll += pending;
2956
+ state.scrollForNextCalculateItemsInView = void 0;
2957
+ set$(this.context, "scrollAdjustPending", 0);
2958
+ set$(this.context, "scrollAdjust", this.appliedAdjust);
2959
+ calculateItemsInView(this.context, this.context.internalState);
2960
+ }
2961
+ };
2962
+ listen$(this.context, "scrollingTo", (value) => {
2963
+ if (value === void 0) {
2964
+ commitPendingAdjust();
2965
+ }
2966
+ });
2967
+ }
2479
2968
  }
2480
2969
  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();
2970
+ const scrollingTo = peek$(this.context, "scrollingTo");
2971
+ if ((scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2972
+ this.pendingAdjust += add;
2973
+ set$(this.context, "scrollAdjustPending", this.pendingAdjust);
2486
2974
  } else {
2487
- requestAnimationFrame(set);
2975
+ this.appliedAdjust += add;
2976
+ set$(this.context, "scrollAdjust", this.appliedAdjust);
2488
2977
  }
2489
2978
  }
2490
2979
  setMounted() {
@@ -2497,14 +2986,13 @@ var ScrollAdjustHandler = class {
2497
2986
 
2498
2987
  // src/core/updateItemSize.ts
2499
2988
  function updateItemSize(ctx, state, itemKey, sizeObj) {
2500
- var _a, _b;
2989
+ var _a3;
2501
2990
  const {
2502
2991
  sizesKnown,
2503
2992
  props: {
2504
2993
  getFixedItemSize,
2505
2994
  getItemType,
2506
2995
  horizontal,
2507
- maintainVisibleContentPosition,
2508
2996
  suggestEstimatedItemSize,
2509
2997
  onItemSizeChanged,
2510
2998
  data,
@@ -2512,17 +3000,17 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2512
3000
  }
2513
3001
  } = state;
2514
3002
  if (!data) return;
3003
+ const index = state.indexByKey.get(itemKey);
2515
3004
  if (getFixedItemSize) {
2516
- const index2 = state.indexByKey.get(itemKey);
2517
- if (index2 === void 0) {
3005
+ if (index === void 0) {
2518
3006
  return;
2519
3007
  }
2520
- const itemData = state.props.data[index2];
3008
+ const itemData = state.props.data[index];
2521
3009
  if (itemData === void 0) {
2522
3010
  return;
2523
3011
  }
2524
- const type = getItemType ? (_a = getItemType(itemData, index2)) != null ? _a : "" : "";
2525
- const size2 = getFixedItemSize(index2, itemData, type);
3012
+ const type = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
3013
+ const size2 = getFixedItemSize(index, itemData, type);
2526
3014
  if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
2527
3015
  return;
2528
3016
  }
@@ -2532,15 +3020,11 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2532
3020
  let shouldMaintainScrollAtEnd = false;
2533
3021
  let minIndexSizeChanged;
2534
3022
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2535
- const index = state.indexByKey.get(itemKey);
2536
3023
  const prevSizeKnown = state.sizesKnown.get(itemKey);
2537
- const diff = updateOneItemSize(state, itemKey, sizeObj);
2538
- const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
3024
+ const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
3025
+ const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
2539
3026
  if (diff !== 0) {
2540
3027
  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
3028
  const { startBuffered, endBuffered } = state;
2545
3029
  needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
2546
3030
  if (!needsRecalculate) {
@@ -2570,13 +3054,13 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2570
3054
  if (minIndexSizeChanged !== void 0) {
2571
3055
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
2572
3056
  }
2573
- if (__DEV__ && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
3057
+ if (IS_DEV && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
2574
3058
  if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
2575
3059
  state.timeoutSizeMessage = setTimeout(() => {
2576
- var _a2;
3060
+ var _a4;
2577
3061
  state.timeoutSizeMessage = void 0;
2578
3062
  const num = state.sizesKnown.size;
2579
- const avg = (_a2 = state.averageSizes[""]) == null ? void 0 : _a2.avg;
3063
+ const avg = (_a4 = state.averageSizes[""]) == null ? void 0 : _a4.avg;
2580
3064
  console.warn(
2581
3065
  `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
2582
3066
  );
@@ -2598,8 +3082,8 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2598
3082
  }
2599
3083
  }
2600
3084
  }
2601
- function updateOneItemSize(state, itemKey, sizeObj) {
2602
- var _a;
3085
+ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3086
+ var _a3;
2603
3087
  const {
2604
3088
  sizes,
2605
3089
  indexByKey,
@@ -2609,12 +3093,12 @@ function updateOneItemSize(state, itemKey, sizeObj) {
2609
3093
  } = state;
2610
3094
  if (!data) return 0;
2611
3095
  const index = indexByKey.get(itemKey);
2612
- const prevSize = getItemSize(state, itemKey, index, data);
3096
+ const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
2613
3097
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
2614
3098
  const size = Math.round(rawSize) ;
2615
3099
  sizesKnown.set(itemKey, size);
2616
3100
  if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
2617
- const itemType = getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : "";
3101
+ const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
2618
3102
  let averages = averageSizes[itemType];
2619
3103
  if (!averages) {
2620
3104
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
@@ -2623,7 +3107,7 @@ function updateOneItemSize(state, itemKey, sizeObj) {
2623
3107
  averages.num++;
2624
3108
  }
2625
3109
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2626
- sizes.set(itemKey, size);
3110
+ setSize(ctx, state, itemKey, size);
2627
3111
  return size - prevSize;
2628
3112
  }
2629
3113
  return 0;
@@ -2645,18 +3129,12 @@ var useCombinedRef = (...refs) => {
2645
3129
  };
2646
3130
 
2647
3131
  // src/platform/RefreshControl.tsx
2648
- function RefreshControl(props) {
3132
+ function RefreshControl(_props) {
2649
3133
  return null;
2650
3134
  }
2651
3135
 
2652
- // src/platform/StyleSheet.tsx
2653
- var StyleSheet = {
2654
- create: (styles) => styles,
2655
- flatten: (style) => style
2656
- };
2657
-
2658
3136
  // src/platform/useStickyScrollHandler.ts
2659
- function useStickyScrollHandler(stickyIndices, horizontal, ctx, onScroll2) {
3137
+ function useStickyScrollHandler(_stickyHeaderIndices, _horizontal, _ctx, onScroll2) {
2660
3138
  return onScroll2;
2661
3139
  }
2662
3140
 
@@ -2674,8 +3152,93 @@ function createColumnWrapperStyle(contentContainerStyle) {
2674
3152
  };
2675
3153
  }
2676
3154
  }
3155
+
3156
+ // src/utils/createImperativeHandle.ts
3157
+ function createImperativeHandle(ctx, state) {
3158
+ const scrollIndexIntoView = (options) => {
3159
+ if (state) {
3160
+ const { index, ...rest } = options;
3161
+ const { startNoBuffer, endNoBuffer } = state;
3162
+ if (index < startNoBuffer || index > endNoBuffer) {
3163
+ const viewPosition = index < startNoBuffer ? 0 : 1;
3164
+ scrollToIndex(ctx, state, {
3165
+ ...rest,
3166
+ index,
3167
+ viewPosition
3168
+ });
3169
+ }
3170
+ }
3171
+ };
3172
+ const refScroller = state.refScroller;
3173
+ return {
3174
+ flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
3175
+ getNativeScrollRef: () => refScroller.current,
3176
+ getScrollableNode: () => refScroller.current.getScrollableNode(),
3177
+ getScrollResponder: () => refScroller.current.getScrollResponder(),
3178
+ getState: () => ({
3179
+ activeStickyIndex: state.activeStickyIndex,
3180
+ contentLength: state.totalSize,
3181
+ data: state.props.data,
3182
+ elementAtIndex: (index) => {
3183
+ var _a3;
3184
+ return (_a3 = ctx.viewRefs.get(findContainerId(ctx, getId(state, index)))) == null ? void 0 : _a3.current;
3185
+ },
3186
+ end: state.endNoBuffer,
3187
+ endBuffered: state.endBuffered,
3188
+ isAtEnd: state.isAtEnd,
3189
+ isAtStart: state.isAtStart,
3190
+ positionAtIndex: (index) => state.positions.get(getId(state, index)),
3191
+ positions: state.positions,
3192
+ scroll: state.scroll,
3193
+ scrollLength: state.scrollLength,
3194
+ sizeAtIndex: (index) => state.sizesKnown.get(getId(state, index)),
3195
+ sizes: state.sizesKnown,
3196
+ start: state.startNoBuffer,
3197
+ startBuffered: state.startBuffered
3198
+ }),
3199
+ scrollIndexIntoView,
3200
+ scrollItemIntoView: ({ item, ...props }) => {
3201
+ const data = state.props.data;
3202
+ const index = data.indexOf(item);
3203
+ if (index !== -1) {
3204
+ scrollIndexIntoView({ index, ...props });
3205
+ }
3206
+ },
3207
+ scrollToEnd: (options) => {
3208
+ const data = state.props.data;
3209
+ const stylePaddingBottom = state.props.stylePaddingBottom;
3210
+ const index = data.length - 1;
3211
+ if (index !== -1) {
3212
+ const paddingBottom = stylePaddingBottom || 0;
3213
+ const footerSize = peek$(ctx, "footerSize") || 0;
3214
+ scrollToIndex(ctx, state, {
3215
+ index,
3216
+ viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3217
+ viewPosition: 1,
3218
+ ...options
3219
+ });
3220
+ }
3221
+ },
3222
+ scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3223
+ scrollToItem: ({ item, ...props }) => {
3224
+ const data = state.props.data;
3225
+ const index = data.indexOf(item);
3226
+ if (index !== -1) {
3227
+ scrollToIndex(ctx, state, { index, ...props });
3228
+ }
3229
+ },
3230
+ scrollToOffset: (params) => scrollTo(ctx, state, params),
3231
+ setScrollProcessingEnabled: (enabled) => {
3232
+ state.scrollProcessingEnabled = enabled;
3233
+ },
3234
+ setVisibleContentAnchorOffset: (value) => {
3235
+ const val = isFunction(value) ? value(peek$(ctx, "scrollAdjustUserOffset") || 0) : value;
3236
+ set$(ctx, "scrollAdjustUserOffset", val);
3237
+ }
3238
+ };
3239
+ }
2677
3240
  function getRenderedItem(ctx, state, key) {
2678
- var _a;
3241
+ var _a3;
2679
3242
  if (!state) {
2680
3243
  return null;
2681
3244
  }
@@ -2688,15 +3251,17 @@ function getRenderedItem(ctx, state, key) {
2688
3251
  return null;
2689
3252
  }
2690
3253
  let renderedItem = null;
2691
- if (renderItem && data[index]) {
3254
+ const extraData = peek$(ctx, "extraData");
3255
+ const item = data[index];
3256
+ if (renderItem && !isNullOrUndefined(item)) {
2692
3257
  const itemProps = {
2693
3258
  data,
2694
- extraData: peek$(ctx, "extraData"),
3259
+ extraData,
2695
3260
  index,
2696
- item: data[index],
2697
- type: getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : ""
3261
+ item,
3262
+ type: getItemType ? (_a3 = getItemType(item, index)) != null ? _a3 : "" : ""
2698
3263
  };
2699
- renderedItem = isFunction(renderItem) ? renderItem(itemProps) : React4__default.createElement(renderItem, itemProps);
3264
+ renderedItem = isFunction(renderItem) ? renderItem(itemProps) : React3__default.createElement(renderItem, itemProps);
2700
3265
  }
2701
3266
  return { index, item: data[index], renderedItem };
2702
3267
  }
@@ -2746,58 +3311,6 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
2746
3311
  return (event) => throttle(originalHandler, scrollEventThrottle, { nativeEvent: event.nativeEvent });
2747
3312
  }
2748
3313
 
2749
- // src/utils/updateAveragesOnDataChange.ts
2750
- function updateAveragesOnDataChange(state, oldData, newData) {
2751
- var _a;
2752
- const {
2753
- averageSizes,
2754
- sizesKnown,
2755
- indexByKey,
2756
- props: { itemsAreEqual, getItemType, keyExtractor }
2757
- } = state;
2758
- if (!itemsAreEqual || !oldData.length || !newData.length) {
2759
- for (const key in averageSizes) {
2760
- delete averageSizes[key];
2761
- }
2762
- return;
2763
- }
2764
- const itemTypesToPreserve = {};
2765
- const newDataLength = newData.length;
2766
- const oldDataLength = oldData.length;
2767
- for (let newIndex = 0; newIndex < newDataLength; newIndex++) {
2768
- const newItem = newData[newIndex];
2769
- const id = keyExtractor ? keyExtractor(newItem, newIndex) : String(newIndex);
2770
- const oldIndex = indexByKey.get(id);
2771
- if (oldIndex !== void 0 && oldIndex < oldDataLength) {
2772
- const knownSize = sizesKnown.get(id);
2773
- if (knownSize === void 0) continue;
2774
- const oldItem = oldData[oldIndex];
2775
- const areEqual = itemsAreEqual(oldItem, newItem, newIndex, newData);
2776
- if (areEqual) {
2777
- const itemType = getItemType ? (_a = getItemType(newItem, newIndex)) != null ? _a : "" : "";
2778
- let typeData = itemTypesToPreserve[itemType];
2779
- if (!typeData) {
2780
- typeData = itemTypesToPreserve[itemType] = { count: 0, totalSize: 0 };
2781
- }
2782
- typeData.totalSize += knownSize;
2783
- typeData.count++;
2784
- }
2785
- }
2786
- }
2787
- for (const key in averageSizes) {
2788
- delete averageSizes[key];
2789
- }
2790
- for (const itemType in itemTypesToPreserve) {
2791
- const { totalSize, count } = itemTypesToPreserve[itemType];
2792
- if (count > 0) {
2793
- averageSizes[itemType] = {
2794
- avg: totalSize / count,
2795
- num: count
2796
- };
2797
- }
2798
- }
2799
- }
2800
-
2801
3314
  // src/components/LegendList.tsx
2802
3315
  var DEFAULT_DRAW_DISTANCE = 250;
2803
3316
  var DEFAULT_ITEM_SIZE = 100;
@@ -2807,22 +3320,24 @@ var LegendList = typedMemo(
2807
3320
  const isChildrenMode = children !== void 0 && dataProp === void 0;
2808
3321
  const processedProps = isChildrenMode ? {
2809
3322
  ...restProps,
2810
- data: (isArray(children) ? children : React4.Children.toArray(children)).flat(1),
3323
+ data: (isArray(children) ? children : React3.Children.toArray(children)).flat(1),
2811
3324
  renderItem: ({ item }) => item
2812
3325
  } : {
2813
3326
  ...restProps,
2814
3327
  data: dataProp || [],
2815
3328
  renderItem: renderItemProp
2816
3329
  };
2817
- return /* @__PURE__ */ React4.createElement(StateProvider, null, /* @__PURE__ */ React4.createElement(LegendListInner, { ...processedProps, ref: forwardedRef }));
3330
+ return /* @__PURE__ */ React3.createElement(StateProvider, null, /* @__PURE__ */ React3.createElement(LegendListInner, { ...processedProps, ref: forwardedRef }));
2818
3331
  })
2819
3332
  );
2820
3333
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
3334
+ var _a3, _b;
2821
3335
  const {
2822
3336
  alignItemsAtEnd = false,
2823
3337
  columnWrapperStyle,
2824
3338
  contentContainerStyle: contentContainerStyleProp,
2825
3339
  data: dataProp = [],
3340
+ dataVersion,
2826
3341
  drawDistance = 250,
2827
3342
  enableAverages = true,
2828
3343
  estimatedItemSize: estimatedItemSizeProp,
@@ -2833,6 +3348,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2833
3348
  getItemType,
2834
3349
  horizontal,
2835
3350
  initialContainerPoolRatio = 2,
3351
+ initialScrollAtEnd = false,
2836
3352
  initialScrollIndex: initialScrollIndexProp,
2837
3353
  initialScrollOffset: initialScrollOffsetProp,
2838
3354
  itemsAreEqual,
@@ -2841,7 +3357,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2841
3357
  ListHeaderComponent,
2842
3358
  maintainScrollAtEnd = false,
2843
3359
  maintainScrollAtEndThreshold = 0.1,
2844
- maintainVisibleContentPosition = true,
3360
+ maintainVisibleContentPosition = false,
2845
3361
  numColumns: numColumnsProp = 1,
2846
3362
  onEndReached,
2847
3363
  onEndReachedThreshold = 0.5,
@@ -2853,6 +3369,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2853
3369
  onScroll: onScrollProp,
2854
3370
  onStartReached,
2855
3371
  onStartReachedThreshold = 0.5,
3372
+ onStickyHeaderChange,
3373
+ onViewableItemsChanged,
2856
3374
  progressViewOffset,
2857
3375
  recycleItems = false,
2858
3376
  refreshControl,
@@ -2861,19 +3379,22 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2861
3379
  renderItem,
2862
3380
  scrollEventThrottle,
2863
3381
  snapToIndices,
2864
- stickyIndices,
3382
+ stickyHeaderIndices: stickyHeaderIndicesProp,
3383
+ stickyIndices: stickyIndicesDeprecated,
2865
3384
  style: styleProp,
2866
3385
  suggestEstimatedItemSize,
3386
+ viewabilityConfig,
3387
+ viewabilityConfigCallbackPairs,
2867
3388
  waitForInitialLayout = true,
2868
3389
  ...rest
2869
3390
  } = props;
2870
- const [renderNum, setRenderNum] = useState(0);
2871
- const initialScroll = initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
2872
- const [canRender, setCanRender] = React4.useState(!IsNewArchitecture);
2873
3391
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
2874
3392
  const style = { ...StyleSheet.flatten(styleProp) };
2875
3393
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
2876
3394
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
3395
+ const [renderNum, setRenderNum] = useState(0);
3396
+ const initialScrollProp = initialScrollAtEnd ? { index: Math.max(0, dataProp.length - 1), viewOffset: -stylePaddingBottomState } : initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
3397
+ const [canRender, setCanRender] = React3.useState(!IsNewArchitecture);
2877
3398
  const ctx = useStateContext();
2878
3399
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
2879
3400
  const refScroller = useRef(null);
@@ -2881,6 +3402,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2881
3402
  const estimatedItemSize = estimatedItemSizeProp != null ? estimatedItemSizeProp : DEFAULT_ITEM_SIZE;
2882
3403
  const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
2883
3404
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (_item, index) => index.toString();
3405
+ const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
3406
+ if (IS_DEV && stickyIndicesDeprecated && !stickyHeaderIndicesProp) {
3407
+ warnDevOnce(
3408
+ "stickyIndices",
3409
+ "stickyIndices has been renamed to stickyHeaderIndices. Please update your props to use stickyHeaderIndices."
3410
+ );
3411
+ }
2884
3412
  const refState = useRef();
2885
3413
  if (!refState.current) {
2886
3414
  if (!ctx.internalState) {
@@ -2891,18 +3419,29 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2891
3419
  columns: /* @__PURE__ */ new Map(),
2892
3420
  containerItemKeys: /* @__PURE__ */ new Set(),
2893
3421
  containerItemTypes: /* @__PURE__ */ new Map(),
3422
+ dataChangeNeedsScrollUpdate: false,
3423
+ didColumnsChange: false,
3424
+ didDataChange: false,
2894
3425
  enableScrollForNextCalculateItemsInView: true,
2895
3426
  endBuffered: -1,
2896
3427
  endNoBuffer: -1,
2897
- endReachedBlockedByTimer: false,
3428
+ endReachedSnapshot: void 0,
2898
3429
  firstFullyOnScreenIndex: -1,
2899
- idCache: /* @__PURE__ */ new Map(),
3430
+ idCache: [],
2900
3431
  idsInView: [],
2901
3432
  indexByKey: /* @__PURE__ */ new Map(),
2902
- initialScroll,
3433
+ initialAnchor: (initialScrollProp == null ? void 0 : initialScrollProp.index) !== void 0 && (initialScrollProp == null ? void 0 : initialScrollProp.viewPosition) !== void 0 ? {
3434
+ attempts: 0,
3435
+ index: initialScrollProp.index,
3436
+ settledTicks: 0,
3437
+ viewOffset: (_a3 = initialScrollProp.viewOffset) != null ? _a3 : 0,
3438
+ viewPosition: initialScrollProp.viewPosition
3439
+ } : void 0,
3440
+ initialScroll: initialScrollProp,
2903
3441
  isAtEnd: false,
2904
3442
  isAtStart: false,
2905
3443
  isEndReached: false,
3444
+ isFirst: true,
2906
3445
  isStartReached: false,
2907
3446
  lastBatchingAction: Date.now(),
2908
3447
  lastLayout: void 0,
@@ -2927,7 +3466,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2927
3466
  sizesKnown: /* @__PURE__ */ new Map(),
2928
3467
  startBuffered: -1,
2929
3468
  startNoBuffer: -1,
2930
- startReachedBlockedByTimer: false,
3469
+ startReachedSnapshot: void 0,
2931
3470
  stickyContainerPool: /* @__PURE__ */ new Set(),
2932
3471
  stickyContainers: /* @__PURE__ */ new Map(),
2933
3472
  timeoutSizeMessage: 0,
@@ -2935,21 +3474,27 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2935
3474
  totalSize: 0,
2936
3475
  viewabilityConfigCallbackPairs: void 0
2937
3476
  };
3477
+ const internalState = ctx.internalState;
3478
+ internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, internalState, params);
2938
3479
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
2939
3480
  set$(ctx, "extraData", extraData);
2940
3481
  }
2941
3482
  refState.current = ctx.internalState;
2942
3483
  }
2943
3484
  const state = refState.current;
2944
- const isFirst = !state.props.renderItem;
2945
- const didDataChange = state.props.data !== dataProp;
2946
- const throttleScrollFn = (
2947
- // @ts-expect-error TODO Fix this
2948
- scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp
2949
- );
3485
+ const isFirstLocal = state.isFirst;
3486
+ state.didColumnsChange = numColumnsProp !== state.props.numColumns;
3487
+ const didDataChangeLocal = state.props.dataVersion !== dataVersion || state.props.data !== dataProp && checkActualChange(state, dataProp, state.props.data);
3488
+ if (didDataChangeLocal) {
3489
+ state.dataChangeNeedsScrollUpdate = true;
3490
+ state.didDataChange = true;
3491
+ state.previousData = state.props.data;
3492
+ }
3493
+ const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
2950
3494
  state.props = {
2951
3495
  alignItemsAtEnd,
2952
3496
  data: dataProp,
3497
+ dataVersion,
2953
3498
  enableAverages,
2954
3499
  estimatedItemSize,
2955
3500
  getEstimatedItemSize,
@@ -2957,7 +3502,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2957
3502
  getItemType,
2958
3503
  horizontal: !!horizontal,
2959
3504
  initialContainerPoolRatio,
2960
- initialScroll,
2961
3505
  itemsAreEqual,
2962
3506
  keyExtractor,
2963
3507
  maintainScrollAtEnd,
@@ -2971,45 +3515,25 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2971
3515
  onScroll: throttleScrollFn,
2972
3516
  onStartReached,
2973
3517
  onStartReachedThreshold,
3518
+ onStickyHeaderChange,
2974
3519
  recycleItems: !!recycleItems,
2975
3520
  renderItem,
2976
3521
  scrollBuffer,
2977
3522
  snapToIndices,
2978
- stickyIndicesArr: stickyIndices != null ? stickyIndices : [],
2979
- stickyIndicesSet: useMemo(() => new Set(stickyIndices != null ? stickyIndices : []), [stickyIndices == null ? void 0 : stickyIndices.join(",")]),
3523
+ stickyIndicesArr: stickyHeaderIndices != null ? stickyHeaderIndices : [],
3524
+ stickyIndicesSet: useMemo(() => new Set(stickyHeaderIndices != null ? stickyHeaderIndices : []), [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(",")]),
2980
3525
  stylePaddingBottom: stylePaddingBottomState,
2981
3526
  stylePaddingTop: stylePaddingTopState,
2982
3527
  suggestEstimatedItemSize: !!suggestEstimatedItemSize
2983
3528
  };
2984
3529
  state.refScroller = refScroller;
2985
- const checkResetContainers = (isFirst2) => {
2986
- const state2 = refState.current;
2987
- if (state2) {
2988
- if (!isFirst2 && state2.props.data !== dataProp) {
2989
- updateAveragesOnDataChange(state2, state2.props.data, dataProp);
2990
- }
2991
- state2.props.data = dataProp;
2992
- if (!isFirst2) {
2993
- calculateItemsInView(ctx, state2, { dataChanged: true, doMVCP: true });
2994
- const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2995
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state2, false);
2996
- if (!didMaintainScrollAtEnd && dataProp.length > state2.props.data.length) {
2997
- state2.isEndReached = false;
2998
- }
2999
- if (!didMaintainScrollAtEnd) {
3000
- checkAtTop(state2);
3001
- checkAtBottom(ctx, state2);
3002
- }
3003
- }
3004
- }
3005
- };
3006
3530
  const memoizedLastItemKeys = useMemo(() => {
3007
3531
  if (!dataProp.length) return [];
3008
3532
  return Array.from(
3009
3533
  { length: Math.min(numColumnsProp, dataProp.length) },
3010
3534
  (_, i) => getId(state, dataProp.length - 1 - i)
3011
3535
  );
3012
- }, [dataProp, numColumnsProp]);
3536
+ }, [dataProp, dataVersion, numColumnsProp]);
3013
3537
  const initializeStateVars = () => {
3014
3538
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
3015
3539
  set$(ctx, "numColumns", numColumnsProp);
@@ -3017,44 +3541,70 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3017
3541
  setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
3018
3542
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
3019
3543
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
3020
- if (maintainVisibleContentPosition && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3544
+ if (paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
3021
3545
  if (state.scroll < 0) {
3022
3546
  paddingDiff += state.scroll;
3023
3547
  }
3024
3548
  requestAdjust(ctx, state, paddingDiff);
3025
3549
  }
3026
3550
  };
3027
- if (isFirst) {
3551
+ if (isFirstLocal) {
3028
3552
  initializeStateVars();
3029
- updateAllPositions(ctx, state);
3553
+ updateItemPositions(
3554
+ ctx,
3555
+ state,
3556
+ /*dataChanged*/
3557
+ true
3558
+ );
3030
3559
  }
3031
3560
  const initialContentOffset = useMemo(() => {
3032
- if (initialScroll) {
3033
- const { index, viewOffset } = initialScroll;
3034
- let initialContentOffset2 = viewOffset || 0;
3035
- if (index !== void 0) {
3036
- initialContentOffset2 += calculateOffsetForIndex(ctx, state, index);
3037
- }
3038
- refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
3039
- if (initialContentOffset2 > 0) {
3040
- scrollTo(state, { animated: false, index, offset: initialContentOffset2 });
3041
- }
3042
- return initialContentOffset2;
3561
+ var _a4, _b2;
3562
+ const { initialScroll } = refState.current;
3563
+ if (!initialScroll) {
3564
+ refState.current.initialAnchor = void 0;
3565
+ return 0;
3566
+ }
3567
+ if (initialScroll.index !== void 0 && (!refState.current.initialAnchor || ((_a4 = refState.current.initialAnchor) == null ? void 0 : _a4.index) !== initialScroll.index)) {
3568
+ refState.current.initialAnchor = {
3569
+ attempts: 0,
3570
+ index: initialScroll.index,
3571
+ settledTicks: 0,
3572
+ viewOffset: (_b2 = initialScroll.viewOffset) != null ? _b2 : 0,
3573
+ viewPosition: initialScroll.viewPosition
3574
+ };
3043
3575
  }
3044
- return 0;
3576
+ if (initialScroll.contentOffset !== void 0) {
3577
+ return initialScroll.contentOffset;
3578
+ }
3579
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, state, initialScroll.index) : 0;
3580
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, state, baseOffset, initialScroll);
3581
+ let clampedOffset = resolvedOffset;
3582
+ if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
3583
+ const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
3584
+ clampedOffset = Math.min(clampedOffset, maxOffset);
3585
+ }
3586
+ clampedOffset = Math.max(0, clampedOffset);
3587
+ const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3588
+ refState.current.initialScroll = updatedInitialScroll;
3589
+ state.initialScroll = updatedInitialScroll;
3590
+ refState.current.isStartReached = clampedOffset < refState.current.scrollLength * onStartReachedThreshold;
3591
+ return clampedOffset;
3045
3592
  }, [renderNum]);
3046
- if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
3047
- state.lastBatchingAction = Date.now();
3048
- if (!keyExtractorProp && !isFirst && didDataChange) {
3049
- __DEV__ && warnDevOnce(
3593
+ if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3594
+ refState.current.lastBatchingAction = Date.now();
3595
+ if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
3596
+ IS_DEV && warnDevOnce(
3050
3597
  "keyExtractor",
3051
3598
  "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."
3052
3599
  );
3053
- state.sizes.clear();
3054
- state.positions.clear();
3600
+ refState.current.sizes.clear();
3601
+ refState.current.positions.clear();
3602
+ refState.current.totalSize = 0;
3603
+ set$(ctx, "totalSize", 0);
3055
3604
  }
3056
3605
  }
3057
3606
  const onLayoutHeader = useCallback((rect, fromLayoutEffect) => {
3607
+ const { initialScroll } = refState.current;
3058
3608
  const size = rect[horizontal ? "width" : "height"];
3059
3609
  set$(ctx, "headerSize", size);
3060
3610
  if ((initialScroll == null ? void 0 : initialScroll.index) !== void 0) {
@@ -3065,132 +3615,71 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3065
3615
  }
3066
3616
  }
3067
3617
  }, []);
3618
+ const doInitialScroll = useCallback(() => {
3619
+ var _a4;
3620
+ const initialScroll = state.initialScroll;
3621
+ if (initialScroll) {
3622
+ scrollTo(ctx, state, {
3623
+ animated: false,
3624
+ index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3625
+ isInitialScroll: true,
3626
+ offset: initialContentOffset,
3627
+ precomputedWithViewOffset: true
3628
+ });
3629
+ }
3630
+ }, [initialContentOffset]);
3631
+ const onLayoutChange = useCallback((layout) => {
3632
+ doInitialScroll();
3633
+ handleLayout(ctx, state, layout, setCanRender);
3634
+ }, []);
3635
+ const { onLayout } = useOnLayoutSync({
3636
+ onLayoutChange,
3637
+ onLayoutProp,
3638
+ ref: refScroller
3639
+ // the type of ScrollView doesn't include measure?
3640
+ });
3068
3641
  useLayoutEffect(() => {
3069
3642
  if (snapToIndices) {
3070
3643
  updateSnapToOffsets(ctx, state);
3071
3644
  }
3072
3645
  }, [snapToIndices]);
3073
3646
  useLayoutEffect(() => {
3074
- const didAllocateContainers = dataProp.length > 0 && doInitialAllocateContainersCallback();
3075
- if (!didAllocateContainers) {
3076
- checkResetContainers(
3077
- /*isFirst*/
3078
- isFirst
3079
- );
3080
- }
3081
- }, [dataProp, numColumnsProp]);
3647
+ const {
3648
+ didColumnsChange,
3649
+ didDataChange,
3650
+ isFirst,
3651
+ props: { data }
3652
+ } = state;
3653
+ const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3654
+ if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3655
+ checkResetContainers(ctx, state, data);
3656
+ }
3657
+ state.didColumnsChange = false;
3658
+ state.didDataChange = false;
3659
+ state.isFirst = false;
3660
+ }, [dataProp, dataVersion, numColumnsProp]);
3082
3661
  useLayoutEffect(() => {
3083
3662
  set$(ctx, "extraData", extraData);
3084
3663
  }, [extraData]);
3085
- const { onLayout } = useSyncLayout({
3086
- onLayout: onLayoutProp,
3087
- onLayoutChange: useCallback(
3088
- (rectangle) => {
3089
- handleLayout(ctx, state, rectangle, setCanRender);
3090
- },
3091
- [ctx, state, setCanRender]
3092
- ),
3093
- ref: refScroller
3094
- });
3095
3664
  useLayoutEffect(initializeStateVars, [
3665
+ dataVersion,
3096
3666
  memoizedLastItemKeys.join(","),
3097
3667
  numColumnsProp,
3098
- stylePaddingTopState,
3099
- stylePaddingBottomState
3668
+ stylePaddingBottomState,
3669
+ stylePaddingTopState
3100
3670
  ]);
3101
- const doInitialAllocateContainersCallback = () => {
3102
- return doInitialAllocateContainers(ctx, state);
3103
- };
3104
- useImperativeHandle(forwardedRef, () => {
3105
- const scrollIndexIntoView = (options) => {
3106
- const state2 = refState.current;
3107
- if (state2) {
3108
- const { index, ...rest2 } = options;
3109
- const { startNoBuffer, endNoBuffer } = state2;
3110
- if (index < startNoBuffer || index > endNoBuffer) {
3111
- const viewPosition = index < startNoBuffer ? 0 : 1;
3112
- scrollToIndex(ctx, state2, {
3113
- ...rest2,
3114
- index,
3115
- viewPosition
3116
- });
3117
- }
3118
- }
3119
- };
3120
- return {
3121
- flashScrollIndicators: () => {
3122
- var _a, _b;
3123
- return (_b = (_a = refScroller.current) == null ? void 0 : _a.flashScrollIndicators) == null ? void 0 : _b.call(_a);
3124
- },
3125
- getNativeScrollRef: () => refScroller.current,
3126
- getScrollableNode: () => refScroller.current,
3127
- getScrollResponder: () => refScroller.current,
3128
- getState: () => {
3129
- const state2 = refState.current;
3130
- return state2 ? {
3131
- contentLength: state2.totalSize,
3132
- data: state2.props.data,
3133
- end: state2.endNoBuffer,
3134
- endBuffered: state2.endBuffered,
3135
- isAtEnd: state2.isAtEnd,
3136
- isAtStart: state2.isAtStart,
3137
- positionAtIndex: (index) => state2.positions.get(getId(state2, index)),
3138
- positions: state2.positions,
3139
- scroll: state2.scroll,
3140
- scrollLength: state2.scrollLength,
3141
- sizeAtIndex: (index) => state2.sizesKnown.get(getId(state2, index)),
3142
- sizes: state2.sizesKnown,
3143
- start: state2.startNoBuffer,
3144
- startBuffered: state2.startBuffered
3145
- } : {};
3146
- },
3147
- scrollIndexIntoView,
3148
- scrollItemIntoView: ({ item, ...props2 }) => {
3149
- const data = refState.current.props.data;
3150
- const index = data.indexOf(item);
3151
- if (index !== -1) {
3152
- scrollIndexIntoView({ index, ...props2 });
3153
- }
3154
- },
3155
- scrollToEnd: (options) => {
3156
- const data = refState.current.props.data;
3157
- const stylePaddingBottom = refState.current.props.stylePaddingBottom;
3158
- const index = data.length - 1;
3159
- if (index !== -1) {
3160
- const paddingBottom = stylePaddingBottom || 0;
3161
- const footerSize = peek$(ctx, "footerSize") || 0;
3162
- scrollToIndex(ctx, state, {
3163
- index,
3164
- viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3165
- viewPosition: 1,
3166
- ...options
3167
- });
3168
- }
3169
- },
3170
- scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3171
- scrollToItem: ({ item, ...props2 }) => {
3172
- const data = refState.current.props.data;
3173
- const index = data.indexOf(item);
3174
- if (index !== -1) {
3175
- scrollToIndex(ctx, state, { index, ...props2 });
3176
- }
3177
- },
3178
- scrollToOffset: (params) => scrollTo(state, params),
3179
- setScrollProcessingEnabled: (enabled) => {
3180
- refState.current.scrollProcessingEnabled = enabled;
3181
- },
3182
- setVisibleContentAnchorOffset: (value) => {
3183
- const val = typeof value === "function" ? value(peek$(ctx, "scrollAdjustUserOffset") || 0) : value;
3184
- set$(ctx, "scrollAdjustUserOffset", val);
3185
- }
3186
- };
3187
- }, []);
3671
+ useEffect(() => {
3672
+ const viewability = setupViewability({
3673
+ onViewableItemsChanged,
3674
+ viewabilityConfig,
3675
+ viewabilityConfigCallbackPairs
3676
+ });
3677
+ state.viewabilityConfigCallbackPairs = viewability;
3678
+ state.enableScrollForNextCalculateItemsInView = !viewability;
3679
+ }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3680
+ useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, state), []);
3188
3681
  {
3189
- useEffect(() => {
3190
- if (initialContentOffset) {
3191
- scrollTo(state, { animated: false, offset: initialContentOffset });
3192
- }
3193
- }, []);
3682
+ useEffect(doInitialScroll, []);
3194
3683
  }
3195
3684
  const fns = useMemo(
3196
3685
  () => ({
@@ -3200,8 +3689,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3200
3689
  }),
3201
3690
  []
3202
3691
  );
3203
- const onScrollHandler = useStickyScrollHandler(stickyIndices, horizontal, ctx, fns.onScroll);
3204
- return /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(
3692
+ const onScrollHandler = useStickyScrollHandler(stickyHeaderIndices, horizontal, ctx, fns.onScroll);
3693
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(
3205
3694
  ListComponent,
3206
3695
  {
3207
3696
  ...rest,
@@ -3219,7 +3708,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3219
3708
  onMomentumScrollEnd: (event) => {
3220
3709
  {
3221
3710
  requestAnimationFrame(() => {
3222
- finishScrollTo(refState.current);
3711
+ finishScrollTo(ctx, refState.current);
3223
3712
  });
3224
3713
  }
3225
3714
  if (onMomentumScrollEnd) {
@@ -3228,9 +3717,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3228
3717
  },
3229
3718
  onScroll: onScrollHandler,
3230
3719
  recycleItems,
3231
- refreshControl: refreshControl ? stylePaddingTopState > 0 ? React4.cloneElement(refreshControl, {
3720
+ refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3.cloneElement(refreshControl, {
3232
3721
  progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
3233
- }) : refreshControl : onRefresh && /* @__PURE__ */ React4.createElement(
3722
+ }) : refreshControl : onRefresh && /* @__PURE__ */ React3.createElement(
3234
3723
  RefreshControl,
3235
3724
  {
3236
3725
  onRefresh,
@@ -3239,14 +3728,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3239
3728
  }
3240
3729
  ),
3241
3730
  refScrollView: combinedRef,
3242
- scrollAdjustHandler: state.scrollAdjustHandler,
3731
+ scrollAdjustHandler: (_b = refState.current) == null ? void 0 : _b.scrollAdjustHandler,
3732
+ scrollEventThrottle: 16 ,
3243
3733
  snapToIndices,
3244
- stickyIndices,
3734
+ stickyHeaderIndices,
3245
3735
  style,
3246
3736
  updateItemSize: fns.updateItemSize,
3247
3737
  waitForInitialLayout
3248
3738
  }
3249
- ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React4.createElement(DebugView, { state: refState.current }));
3739
+ ), IS_DEV && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React3.createElement(DebugView, { state: refState.current }));
3250
3740
  });
3251
3741
 
3252
- export { LegendList, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout2 as useSyncLayout, useViewability, useViewabilityAmount };
3742
+ export { LegendList, useIsLastItem, useListScrollSize, useRecyclingEffect, useRecyclingState, useSyncLayout, useViewability, useViewabilityAmount };