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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var React4 = require('react');
3
+ var React3 = require('react');
4
4
  var shim = require('use-sync-external-store/shim');
5
5
  var reactDom = require('react-dom');
6
6
 
@@ -22,14 +22,14 @@ function _interopNamespace(e) {
22
22
  return Object.freeze(n);
23
23
  }
24
24
 
25
- var React4__namespace = /*#__PURE__*/_interopNamespace(React4);
25
+ var React3__namespace = /*#__PURE__*/_interopNamespace(React3);
26
26
 
27
27
  // src/components/LegendList.tsx
28
- var AnimatedView = React4.forwardRef(function AnimatedView2(props, ref) {
29
- return /* @__PURE__ */ React4__namespace.createElement("div", { ref, ...props });
28
+ React3.forwardRef(function AnimatedView2(props, ref) {
29
+ return /* @__PURE__ */ React3__namespace.createElement("div", { ref, ...props });
30
30
  });
31
- var View = React4.forwardRef(function View2(props, ref) {
32
- return /* @__PURE__ */ React4__namespace.createElement("div", { ref, ...props });
31
+ var View = React3.forwardRef(function View2(props, ref) {
32
+ return /* @__PURE__ */ React3__namespace.createElement("div", { ref, ...props });
33
33
  });
34
34
  var Text = View;
35
35
 
@@ -37,9 +37,9 @@ var Text = View;
37
37
  var createAnimatedValue = (value) => value;
38
38
 
39
39
  // src/state/state.tsx
40
- var ContextState = React4__namespace.createContext(null);
40
+ var ContextState = React3__namespace.createContext(null);
41
41
  function StateProvider({ children }) {
42
- const [value] = React4__namespace.useState(() => ({
42
+ const [value] = React3__namespace.useState(() => ({
43
43
  animatedScrollY: createAnimatedValue(0),
44
44
  columnWrapperStyle: void 0,
45
45
  internalState: void 0,
@@ -54,14 +54,17 @@ function StateProvider({ children }) {
54
54
  ["stylePaddingTop", 0],
55
55
  ["headerSize", 0],
56
56
  ["numContainers", 0],
57
- ["totalSize", 0]
57
+ ["activeStickyIndex", void 0],
58
+ ["totalSize", 0],
59
+ ["scrollAdjustPending", 0],
60
+ ["scrollingTo", void 0]
58
61
  ]),
59
62
  viewRefs: /* @__PURE__ */ new Map()
60
63
  }));
61
- return /* @__PURE__ */ React4__namespace.createElement(ContextState.Provider, { value }, children);
64
+ return /* @__PURE__ */ React3__namespace.createElement(ContextState.Provider, { value }, children);
62
65
  }
63
66
  function useStateContext() {
64
- return React4__namespace.useContext(ContextState);
67
+ return React3__namespace.useContext(ContextState);
65
68
  }
66
69
  function createSelectorFunctionsArr(ctx, signalNames) {
67
70
  let lastValues = [];
@@ -131,23 +134,23 @@ function getContentSize(ctx) {
131
134
  return headerSize + footerSize + totalSize + stylePaddingTop;
132
135
  }
133
136
  function useArr$(signalNames) {
134
- const ctx = React4__namespace.useContext(ContextState);
135
- const { subscribe, get } = React4__namespace.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
137
+ const ctx = React3__namespace.useContext(ContextState);
138
+ const { subscribe, get } = React3__namespace.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
136
139
  const value = shim.useSyncExternalStore(subscribe, get);
137
140
  return value;
138
141
  }
139
142
  function useSelector$(signalName, selector) {
140
- const ctx = React4__namespace.useContext(ContextState);
141
- const { subscribe, get } = React4__namespace.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
143
+ const ctx = React3__namespace.useContext(ContextState);
144
+ const { subscribe, get } = React3__namespace.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
142
145
  const value = shim.useSyncExternalStore(subscribe, () => selector(get()[0]));
143
146
  return value;
144
147
  }
145
148
 
146
149
  // src/components/DebugView.tsx
147
150
  var DebugRow = ({ children }) => {
148
- return /* @__PURE__ */ React4__namespace.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
151
+ return /* @__PURE__ */ React3__namespace.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
149
152
  };
150
- var DebugView = React4__namespace.memo(function DebugView2({ state }) {
153
+ var DebugView = React3__namespace.memo(function DebugView2({ state }) {
151
154
  const ctx = useStateContext();
152
155
  const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, _numContainers = 0, _numContainersPooled = 0] = useArr$([
153
156
  "totalSize",
@@ -158,11 +161,11 @@ var DebugView = React4__namespace.memo(function DebugView2({ state }) {
158
161
  "numContainersPooled"
159
162
  ]);
160
163
  const contentSize = getContentSize(ctx);
161
- const [, forceUpdate] = React4.useReducer((x) => x + 1, 0);
164
+ const [, forceUpdate] = React3.useReducer((x) => x + 1, 0);
162
165
  useInterval(() => {
163
166
  forceUpdate();
164
167
  }, 100);
165
- return /* @__PURE__ */ React4__namespace.createElement(
168
+ return /* @__PURE__ */ React3__namespace.createElement(
166
169
  View,
167
170
  {
168
171
  pointerEvents: "none",
@@ -178,107 +181,77 @@ var DebugView = React4__namespace.memo(function DebugView2({ state }) {
178
181
  top: 0
179
182
  }
180
183
  },
181
- /* @__PURE__ */ React4__namespace.createElement(DebugRow, null, /* @__PURE__ */ React4__namespace.createElement(Text, null, "TotalSize:"), /* @__PURE__ */ React4__namespace.createElement(Text, null, totalSize.toFixed(2))),
182
- /* @__PURE__ */ React4__namespace.createElement(DebugRow, null, /* @__PURE__ */ React4__namespace.createElement(Text, null, "ContentSize:"), /* @__PURE__ */ React4__namespace.createElement(Text, null, contentSize.toFixed(2))),
183
- /* @__PURE__ */ React4__namespace.createElement(DebugRow, null, /* @__PURE__ */ React4__namespace.createElement(Text, null, "At end:"), /* @__PURE__ */ React4__namespace.createElement(Text, null, String(state.isAtEnd))),
184
- /* @__PURE__ */ React4__namespace.createElement(DebugRow, null, /* @__PURE__ */ React4__namespace.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React4__namespace.createElement(Text, null, scrollAdjust.toFixed(2))),
185
- /* @__PURE__ */ React4__namespace.createElement(DebugRow, null, /* @__PURE__ */ React4__namespace.createElement(Text, null, "RawScroll: "), /* @__PURE__ */ React4__namespace.createElement(Text, null, rawScroll.toFixed(2))),
186
- /* @__PURE__ */ React4__namespace.createElement(DebugRow, null, /* @__PURE__ */ React4__namespace.createElement(Text, null, "ComputedScroll: "), /* @__PURE__ */ React4__namespace.createElement(Text, null, scroll.toFixed(2)))
184
+ /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(Text, null, "TotalSize:"), /* @__PURE__ */ React3__namespace.createElement(Text, null, totalSize.toFixed(2))),
185
+ /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(Text, null, "ContentSize:"), /* @__PURE__ */ React3__namespace.createElement(Text, null, contentSize.toFixed(2))),
186
+ /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(Text, null, "At end:"), /* @__PURE__ */ React3__namespace.createElement(Text, null, String(state.isAtEnd))),
187
+ /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React3__namespace.createElement(Text, null, scrollAdjust.toFixed(2))),
188
+ /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(Text, null, "RawScroll: "), /* @__PURE__ */ React3__namespace.createElement(Text, null, rawScroll.toFixed(2))),
189
+ /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(Text, null, "ComputedScroll: "), /* @__PURE__ */ React3__namespace.createElement(Text, null, scroll.toFixed(2)))
187
190
  );
188
191
  });
189
192
  function useInterval(callback, delay) {
190
- React4.useEffect(() => {
193
+ React3.useEffect(() => {
191
194
  const interval = setInterval(callback, delay);
192
195
  return () => clearInterval(interval);
193
196
  }, [delay]);
194
197
  }
195
- var globalResizeObserver = null;
196
- function getGlobalResizeObserver() {
197
- if (!globalResizeObserver) {
198
- globalResizeObserver = new ResizeObserver((entries) => {
199
- for (const entry of entries) {
200
- const callbacks = callbackMap.get(entry.target);
201
- if (callbacks) {
202
- for (const callback of callbacks) {
203
- callback(entry);
204
- }
205
- }
206
- }
207
- });
198
+
199
+ // src/utils/devEnvironment.ts
200
+ var metroDev = typeof __DEV__ !== "undefined" ? __DEV__ : void 0;
201
+ var _a;
202
+ var envMode = typeof process !== "undefined" && typeof process.env === "object" && process.env ? (_a = process.env.NODE_ENV) != null ? _a : process.env.MODE : void 0;
203
+ var processDev = typeof envMode === "string" ? envMode.toLowerCase() !== "production" : void 0;
204
+ var _a2;
205
+ var IS_DEV = (_a2 = metroDev != null ? metroDev : processDev) != null ? _a2 : false;
206
+
207
+ // src/constants.ts
208
+ var POSITION_OUT_OF_VIEW = -1e7;
209
+ var ENABLE_DEVMODE = IS_DEV && false;
210
+ var ENABLE_DEBUG_VIEW = IS_DEV && false;
211
+ var typedForwardRef = React3.forwardRef;
212
+ var typedMemo = React3.memo;
213
+
214
+ // src/utils/helpers.ts
215
+ function isFunction(obj) {
216
+ return typeof obj === "function";
217
+ }
218
+ function isArray(obj) {
219
+ return Array.isArray(obj);
220
+ }
221
+ var warned = /* @__PURE__ */ new Set();
222
+ function warnDevOnce(id, text) {
223
+ if (IS_DEV && !warned.has(id)) {
224
+ warned.add(id);
225
+ console.warn(`[legend-list] ${text}`);
208
226
  }
209
- return globalResizeObserver;
210
227
  }
211
- var callbackMap = /* @__PURE__ */ new WeakMap();
212
- function useResizeObserver(element, callback) {
213
- React4.useEffect(() => {
214
- if (!element) return;
215
- const observer = getGlobalResizeObserver();
216
- let callbacks = callbackMap.get(element);
217
- if (!callbacks) {
218
- callbacks = /* @__PURE__ */ new Set();
219
- callbackMap.set(element, callbacks);
220
- observer.observe(element);
221
- }
222
- callbacks.add(callback);
223
- return () => {
224
- const callbacks2 = callbackMap.get(element);
225
- if (callbacks2) {
226
- callbacks2.delete(callback);
227
- if (callbacks2.size === 0) {
228
- callbackMap.delete(element);
229
- observer.unobserve(element);
230
- }
231
- }
232
- };
233
- }, [element, callback]);
228
+ function roundSize(size) {
229
+ return Math.floor(size * 8) / 8;
234
230
  }
235
-
236
- // src/hooks/useSyncLayout.tsx
237
- function useSyncLayout({
238
- ref,
239
- onLayoutChange
240
- }) {
241
- var _a, _b;
242
- useResizeObserver(
243
- ((_b = (_a = ref.current) == null ? void 0 : _a.getScrollableNode) == null ? void 0 : _b.call(_a)) || ref.current,
244
- React4.useCallback(
245
- (entry) => {
246
- onLayoutChange(entry.contentRect, false);
247
- },
248
- [onLayoutChange]
249
- )
250
- );
251
- React4.useLayoutEffect(() => {
252
- if (ref.current) {
253
- const rect = ref.current.getBoundingClientRect();
254
- onLayoutChange(
255
- {
256
- height: rect.height,
257
- width: rect.width,
258
- x: rect.left,
259
- y: rect.top
260
- },
261
- true
262
- );
231
+ function isNullOrUndefined(value) {
232
+ return value === null || value === void 0;
233
+ }
234
+ function comparatorDefault(a, b) {
235
+ return a - b;
236
+ }
237
+ function getPadding(s, type) {
238
+ var _a3, _b, _c;
239
+ return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : s.paddingVertical) != null ? _b : s.padding) != null ? _c : 0;
240
+ }
241
+ function extractPadding(style, contentContainerStyle, type) {
242
+ return getPadding(style, type) + getPadding(contentContainerStyle, type);
243
+ }
244
+ function findContainerId(ctx, key) {
245
+ const numContainers = peek$(ctx, "numContainers");
246
+ for (let i = 0; i < numContainers; i++) {
247
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
248
+ if (itemKey === key) {
249
+ return i;
263
250
  }
264
- }, []);
265
- return {};
251
+ }
252
+ return -1;
266
253
  }
267
254
 
268
- // src/components/LayoutView.tsx
269
- var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
270
- const ref = refView != null ? refView : React4.useRef();
271
- useSyncLayout({ onLayoutChange, ref });
272
- return /* @__PURE__ */ React4__namespace.createElement("div", { ...rest, ref }, children);
273
- };
274
-
275
- // src/constants.ts
276
- var POSITION_OUT_OF_VIEW = -1e7;
277
- var ENABLE_DEVMODE = __DEV__ && false;
278
- var ENABLE_DEBUG_VIEW = __DEV__ && false;
279
- var typedForwardRef = React4.forwardRef;
280
- var typedMemo = React4.memo;
281
-
282
255
  // src/components/PositionView.tsx
283
256
  var PositionViewState = typedMemo(function PositionView({
284
257
  id,
@@ -288,9 +261,12 @@ var PositionViewState = typedMemo(function PositionView({
288
261
  ...rest
289
262
  }) {
290
263
  const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
291
- const base = Array.isArray(style) ? Object.assign({}, ...style) : style;
292
- const combinedStyle = horizontal ? { ...base, left: position } : { ...base, top: position };
293
- return /* @__PURE__ */ React4__namespace.createElement(LayoutView, { refView, style: combinedStyle, ...rest });
264
+ const base = {
265
+ contain: "paint layout style"
266
+ };
267
+ const composed = isArray(style) ? Object.assign({}, ...style) : style;
268
+ const combinedStyle = horizontal ? { ...base, ...composed, left: position } : { ...base, ...composed, top: position };
269
+ return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, style: combinedStyle, ...rest });
294
270
  });
295
271
  var PositionViewSticky = typedMemo(function PositionViewSticky2({
296
272
  id,
@@ -298,80 +274,61 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
298
274
  style,
299
275
  refView,
300
276
  index,
277
+ stickyOffset,
278
+ animatedScrollY: _animatedScrollY,
279
+ children,
301
280
  ...rest
302
281
  }) {
303
- const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
304
- const viewStyle = React4__namespace.useMemo(() => {
305
- const base = Array.isArray(style) ? Object.assign({}, ...style) : style;
306
- const axisStyle = horizontal ? { transform: `translateX(${position}px)` } : { top: position };
307
- return {
308
- ...base,
309
- zIndex: index + 1e3,
310
- ...axisStyle
311
- };
312
- }, [style, position, horizontal, index]);
313
- return /* @__PURE__ */ React4__namespace.createElement(LayoutView, { refView, style: viewStyle, ...rest });
282
+ const [position = POSITION_OUT_OF_VIEW, headerSize = 0, activeStickyIndex] = useArr$([
283
+ `containerPosition${id}`,
284
+ "headerSize",
285
+ "activeStickyIndex"
286
+ ]);
287
+ const base = {
288
+ contain: "paint layout style"
289
+ };
290
+ const composed = React3__namespace.useMemo(
291
+ () => {
292
+ var _a3;
293
+ return (_a3 = isArray(style) ? Object.assign({}, ...style) : style) != null ? _a3 : {};
294
+ },
295
+ [style]
296
+ );
297
+ const viewStyle = React3__namespace.useMemo(() => {
298
+ var _a3;
299
+ const styleBase = { ...base, ...composed };
300
+ delete styleBase.transform;
301
+ const offset = (_a3 = stickyOffset != null ? stickyOffset : headerSize) != null ? _a3 : 0;
302
+ const isActive = activeStickyIndex === index;
303
+ styleBase.position = isActive ? "sticky" : "absolute";
304
+ styleBase.zIndex = index + 1e3;
305
+ if (horizontal) {
306
+ styleBase.left = isActive ? offset : position;
307
+ } else {
308
+ styleBase.top = isActive ? offset : position;
309
+ }
310
+ return styleBase;
311
+ }, [composed, horizontal, position, index, stickyOffset, headerSize, activeStickyIndex]);
312
+ return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
314
313
  });
315
314
  var PositionView2 = PositionViewState;
316
- function Separator({ ItemSeparatorComponent, itemKey, leadingItem }) {
317
- const [lastItemKeys] = useArr$(["lastItemKeys"]);
318
- const isALastItem = lastItemKeys.includes(itemKey);
319
- return isALastItem ? null : /* @__PURE__ */ React4__namespace.createElement(ItemSeparatorComponent, { leadingItem });
320
- }
321
315
 
322
316
  // src/constants-platform.ts
323
317
  var IsNewArchitecture = true;
324
-
325
- // src/platform/Platform.ts
326
- var Platform = {
327
- // Widen the type to avoid unreachable-branch lints in cross-platform code that compares against other OSes
328
- OS: "web"
329
- };
330
318
  var symbolFirst = Symbol();
331
319
  function useInit(cb) {
332
- const refValue = React4.useRef(symbolFirst);
320
+ const refValue = React3.useRef(symbolFirst);
333
321
  if (refValue.current === symbolFirst) {
334
322
  refValue.current = cb();
335
323
  }
336
324
  return refValue.current;
337
325
  }
338
326
 
339
- // src/utils/helpers.ts
340
- function isFunction(obj) {
341
- return typeof obj === "function";
342
- }
343
- function isArray(obj) {
344
- return Array.isArray(obj);
345
- }
346
- var warned = /* @__PURE__ */ new Set();
347
- function warnDevOnce(id, text) {
348
- if (__DEV__ && !warned.has(id)) {
349
- warned.add(id);
350
- console.warn(`[legend-list] ${text}`);
351
- }
352
- }
353
- function roundSize(size) {
354
- return Math.floor(size * 8) / 8;
355
- }
356
- function isNullOrUndefined(value) {
357
- return value === null || value === void 0;
358
- }
359
- function comparatorDefault(a, b) {
360
- return a - b;
361
- }
362
- function getPadding(s, type) {
363
- var _a, _b, _c;
364
- return (_c = (_b = (_a = s[`padding${type}`]) != null ? _a : s.paddingVertical) != null ? _b : s.padding) != null ? _c : 0;
365
- }
366
- function extractPadding(style, contentContainerStyle, type) {
367
- return getPadding(style, type) + getPadding(contentContainerStyle, type);
368
- }
369
-
370
327
  // src/state/ContextContainer.ts
371
- var ContextContainer = React4.createContext(null);
328
+ var ContextContainer = React3.createContext(null);
372
329
  function useViewability(callback, configId) {
373
330
  const ctx = useStateContext();
374
- const { containerId } = React4.useContext(ContextContainer);
331
+ const { containerId } = React3.useContext(ContextContainer);
375
332
  const key = containerId + (configId != null ? configId : "");
376
333
  useInit(() => {
377
334
  const value = ctx.mapViewabilityValues.get(key);
@@ -380,7 +337,7 @@ function useViewability(callback, configId) {
380
337
  }
381
338
  });
382
339
  ctx.mapViewabilityCallbacks.set(key, callback);
383
- React4.useEffect(
340
+ React3.useEffect(
384
341
  () => () => {
385
342
  ctx.mapViewabilityCallbacks.delete(key);
386
343
  },
@@ -389,7 +346,7 @@ function useViewability(callback, configId) {
389
346
  }
390
347
  function useViewabilityAmount(callback) {
391
348
  const ctx = useStateContext();
392
- const { containerId } = React4.useContext(ContextContainer);
349
+ const { containerId } = React3.useContext(ContextContainer);
393
350
  useInit(() => {
394
351
  const value = ctx.mapViewabilityAmountValues.get(containerId);
395
352
  if (value) {
@@ -397,7 +354,7 @@ function useViewabilityAmount(callback) {
397
354
  }
398
355
  });
399
356
  ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
400
- React4.useEffect(
357
+ React3.useEffect(
401
358
  () => () => {
402
359
  ctx.mapViewabilityAmountCallbacks.delete(containerId);
403
360
  },
@@ -405,12 +362,12 @@ function useViewabilityAmount(callback) {
405
362
  );
406
363
  }
407
364
  function useRecyclingEffect(effect) {
408
- const { index, value } = React4.useContext(ContextContainer);
409
- const prevValues = React4.useRef({
365
+ const { index, value } = React3.useContext(ContextContainer);
366
+ const prevValues = React3.useRef({
410
367
  prevIndex: void 0,
411
368
  prevItem: void 0
412
369
  });
413
- React4.useEffect(() => {
370
+ React3.useEffect(() => {
414
371
  let ret;
415
372
  if (prevValues.current.prevIndex !== void 0 && prevValues.current.prevItem !== void 0) {
416
373
  ret = effect({
@@ -428,12 +385,12 @@ function useRecyclingEffect(effect) {
428
385
  }, [index, value, effect]);
429
386
  }
430
387
  function useRecyclingState(valueOrFun) {
431
- const { index, value, itemKey, triggerLayout } = React4.useContext(ContextContainer);
432
- const refState = React4.useRef({
388
+ const { index, value, itemKey, triggerLayout } = React3.useContext(ContextContainer);
389
+ const refState = React3.useRef({
433
390
  itemKey: null,
434
391
  value: null
435
392
  });
436
- const [_, setRenderNum] = React4.useState(0);
393
+ const [_, setRenderNum] = React3.useState(0);
437
394
  const state = refState.current;
438
395
  if (state.itemKey !== itemKey) {
439
396
  state.itemKey = itemKey;
@@ -444,7 +401,7 @@ function useRecyclingState(valueOrFun) {
444
401
  prevItem: void 0
445
402
  }) : valueOrFun;
446
403
  }
447
- const setState = React4.useCallback(
404
+ const setState = React3.useCallback(
448
405
  (newState) => {
449
406
  state.value = isFunction(newState) ? newState(state.value) : newState;
450
407
  setRenderNum((v) => v + 1);
@@ -455,7 +412,7 @@ function useRecyclingState(valueOrFun) {
455
412
  return [state.value, setState];
456
413
  }
457
414
  function useIsLastItem() {
458
- const { itemKey } = React4.useContext(ContextContainer);
415
+ const { itemKey } = React3.useContext(ContextContainer);
459
416
  const isLast = useSelector$("lastItemKeys", (lastItemKeys) => (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false);
460
417
  return isLast;
461
418
  }
@@ -463,13 +420,110 @@ function useListScrollSize() {
463
420
  const [scrollSize] = useArr$(["scrollSize"]);
464
421
  return scrollSize;
465
422
  }
466
- function useSyncLayout2() {
423
+ function useSyncLayout() {
467
424
  {
468
- const { triggerLayout: syncLayout } = React4.useContext(ContextContainer);
425
+ const { triggerLayout: syncLayout } = React3.useContext(ContextContainer);
469
426
  return syncLayout;
470
427
  }
471
428
  }
472
429
 
430
+ // src/components/Separator.tsx
431
+ function Separator({ ItemSeparatorComponent, leadingItem }) {
432
+ const isLastItem = useIsLastItem();
433
+ return isLastItem ? null : /* @__PURE__ */ React3__namespace.createElement(ItemSeparatorComponent, { leadingItem });
434
+ }
435
+
436
+ // src/hooks/createResizeObserver.ts
437
+ var globalResizeObserver = null;
438
+ function getGlobalResizeObserver() {
439
+ if (!globalResizeObserver) {
440
+ globalResizeObserver = new ResizeObserver((entries) => {
441
+ for (const entry of entries) {
442
+ const callbacks = callbackMap.get(entry.target);
443
+ if (callbacks) {
444
+ for (const callback of callbacks) {
445
+ callback(entry);
446
+ }
447
+ }
448
+ }
449
+ });
450
+ }
451
+ return globalResizeObserver;
452
+ }
453
+ var callbackMap = /* @__PURE__ */ new WeakMap();
454
+ function createResizeObserver(element, callback) {
455
+ if (typeof ResizeObserver === "undefined") {
456
+ return () => {
457
+ };
458
+ }
459
+ if (!element) {
460
+ return () => {
461
+ };
462
+ }
463
+ const observer = getGlobalResizeObserver();
464
+ let callbacks = callbackMap.get(element);
465
+ if (!callbacks) {
466
+ callbacks = /* @__PURE__ */ new Set();
467
+ callbackMap.set(element, callbacks);
468
+ observer.observe(element);
469
+ }
470
+ callbacks.add(callback);
471
+ return () => {
472
+ const callbacks2 = callbackMap.get(element);
473
+ if (callbacks2) {
474
+ callbacks2.delete(callback);
475
+ if (callbacks2.size === 0) {
476
+ callbackMap.delete(element);
477
+ observer.unobserve(element);
478
+ }
479
+ }
480
+ };
481
+ }
482
+
483
+ // src/hooks/useOnLayoutSync.tsx
484
+ function useOnLayoutSync({
485
+ ref,
486
+ onLayoutProp,
487
+ onLayoutChange
488
+ }, deps) {
489
+ React3.useLayoutEffect(() => {
490
+ var _a3, _b;
491
+ const current = ref.current;
492
+ const scrollableNode = (_b = (_a3 = current == null ? void 0 : current.getScrollableNode) == null ? void 0 : _a3.call(current)) != null ? _b : null;
493
+ const element = scrollableNode || current;
494
+ if (!element) {
495
+ return;
496
+ }
497
+ const emit = (layout, fromLayoutEffect) => {
498
+ if (layout.height === 0 && layout.width === 0) {
499
+ return;
500
+ }
501
+ onLayoutChange(layout, fromLayoutEffect);
502
+ onLayoutProp == null ? void 0 : onLayoutProp({ nativeEvent: { layout } });
503
+ };
504
+ const rect = element.getBoundingClientRect();
505
+ emit(toLayout(rect), true);
506
+ return createResizeObserver(element, (entry) => {
507
+ var _a4;
508
+ const target = entry.target instanceof HTMLElement ? entry.target : void 0;
509
+ const rect2 = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
510
+ emit(toLayout(rect2), false);
511
+ });
512
+ }, deps);
513
+ return {};
514
+ }
515
+ function toLayout(rect) {
516
+ if (!rect) {
517
+ return { height: 0, width: 0, x: 0, y: 0 };
518
+ }
519
+ return {
520
+ height: rect.height,
521
+ width: rect.width,
522
+ x: rect.left,
523
+ y: rect.top
524
+ };
525
+ }
526
+
473
527
  // src/components/Container.tsx
474
528
  var Container = typedMemo(function Container2({
475
529
  id,
@@ -480,37 +534,42 @@ var Container = typedMemo(function Container2({
480
534
  ItemSeparatorComponent
481
535
  }) {
482
536
  const ctx = useStateContext();
483
- const { columnWrapperStyle } = ctx;
484
- const [column = 0, data, itemKey, numColumns, extraData, isSticky] = useArr$([
537
+ const { columnWrapperStyle, animatedScrollY } = ctx;
538
+ const [column = 0, data, itemKey, numColumns, extraData, isSticky, stickyOffset] = useArr$([
485
539
  `containerColumn${id}`,
486
540
  `containerItemData${id}`,
487
541
  `containerItemKey${id}`,
488
542
  "numColumns",
489
543
  "extraData",
490
- `containerSticky${id}`
544
+ `containerSticky${id}`,
545
+ `containerStickyOffset${id}`
491
546
  ]);
492
- const refLastSize = React4.useRef();
493
- const ref = React4.useRef(null);
494
- const [_, forceLayoutRender] = React4.useState(0);
547
+ const itemLayoutRef = React3.useRef({
548
+ horizontal,
549
+ itemKey,
550
+ updateItemSize: updateItemSize2
551
+ });
552
+ itemLayoutRef.current.horizontal = horizontal;
553
+ itemLayoutRef.current.itemKey = itemKey;
554
+ itemLayoutRef.current.updateItemSize = updateItemSize2;
555
+ const ref = React3.useRef(null);
556
+ const [layoutRenderCount, forceLayoutRender] = React3.useState(0);
495
557
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
496
558
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
497
- const style = React4.useMemo(() => {
559
+ const didLayoutRef = React3.useRef(false);
560
+ const style = React3.useMemo(() => {
498
561
  let paddingStyles;
499
562
  if (columnWrapperStyle) {
500
563
  const { columnGap, rowGap, gap } = columnWrapperStyle;
501
564
  if (horizontal) {
502
- const py = numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0;
503
565
  paddingStyles = {
504
- paddingBottom: py,
505
566
  paddingRight: columnGap || gap || void 0,
506
- paddingTop: py
567
+ paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
507
568
  };
508
569
  } else {
509
- const px = numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0;
510
570
  paddingStyles = {
511
571
  paddingBottom: rowGap || gap || void 0,
512
- paddingLeft: px,
513
- paddingRight: px
572
+ paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
514
573
  };
515
574
  }
516
575
  }
@@ -524,18 +583,18 @@ var Container = typedMemo(function Container2({
524
583
  } : {
525
584
  left: otherAxisPos,
526
585
  position: "absolute",
527
- right: numColumns > 1 ? void 0 : 0,
586
+ right: numColumns > 1 ? null : 0,
528
587
  top: 0,
529
588
  width: otherAxisSize,
530
589
  ...paddingStyles || {}
531
590
  };
532
591
  }, [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns]);
533
- const renderedItemInfo = React4.useMemo(
592
+ const renderedItemInfo = React3.useMemo(
534
593
  () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
535
594
  [itemKey, data, extraData]
536
595
  );
537
596
  const { index, renderedItem } = renderedItemInfo || {};
538
- const contextValue = React4.useMemo(() => {
597
+ const contextValue = React3.useMemo(() => {
539
598
  ctx.viewRefs.set(id, ref);
540
599
  return {
541
600
  containerId: id,
@@ -547,49 +606,64 @@ var Container = typedMemo(function Container2({
547
606
  value: data
548
607
  };
549
608
  }, [id, itemKey, index, data]);
550
- const onLayoutChange = (rectangle) => {
551
- if (!isNullOrUndefined(itemKey)) {
552
- let layout = rectangle;
553
- layout[horizontal ? "width" : "height"];
554
- const doUpdate = () => {
555
- refLastSize.current = { height: layout.height, width: layout.width };
556
- updateItemSize2(itemKey, layout);
557
- };
558
- {
559
- doUpdate();
560
- }
609
+ const onLayoutChange = React3.useCallback((rectangle) => {
610
+ const {
611
+ horizontal: currentHorizontal,
612
+ itemKey: currentItemKey,
613
+ updateItemSize: updateItemSizeFn
614
+ } = itemLayoutRef.current;
615
+ if (isNullOrUndefined(currentItemKey)) {
616
+ return;
561
617
  }
562
- };
618
+ didLayoutRef.current = true;
619
+ let layout = rectangle;
620
+ roundSize(rectangle[currentHorizontal ? "width" : "height"]);
621
+ const doUpdate = () => {
622
+ itemLayoutRef.current.lastSize = { height: layout.height, width: layout.width };
623
+ updateItemSizeFn(currentItemKey, layout);
624
+ didLayoutRef.current = true;
625
+ };
626
+ {
627
+ doUpdate();
628
+ }
629
+ }, []);
630
+ const { onLayout } = useOnLayoutSync(
631
+ {
632
+ onLayoutChange,
633
+ ref
634
+ },
635
+ [itemKey, layoutRenderCount]
636
+ );
563
637
  const PositionComponent = isSticky ? PositionViewSticky : PositionView2;
564
- return /* @__PURE__ */ React4__namespace.createElement(ContextContainer.Provider, { value: contextValue }, /* @__PURE__ */ React4__namespace.createElement(
638
+ return /* @__PURE__ */ React3__namespace.createElement(
565
639
  PositionComponent,
566
640
  {
641
+ animatedScrollY: isSticky ? animatedScrollY : void 0,
567
642
  horizontal,
568
643
  id,
569
644
  index,
570
645
  key: recycleItems ? void 0 : itemKey,
571
- onLayoutChange,
646
+ onLayout,
572
647
  refView: ref,
648
+ stickyOffset: isSticky ? stickyOffset : void 0,
573
649
  style
574
650
  },
575
- renderedItem,
576
- renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React4__namespace.createElement(
577
- Separator,
578
- {
579
- ItemSeparatorComponent,
580
- itemKey,
581
- leadingItem: renderedItemInfo.item
582
- }
583
- )
584
- ));
651
+ /* @__PURE__ */ React3__namespace.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React3__namespace.createElement(Separator, { ItemSeparatorComponent, leadingItem: renderedItemInfo.item }))
652
+ );
585
653
  });
586
654
 
655
+ // src/platform/Platform.ts
656
+ var Platform = {
657
+ // Widen the type to avoid unreachable-branch lints in cross-platform code that compares against other OSes
658
+ OS: "web"
659
+ };
660
+
587
661
  // src/utils/reordering.ts
588
662
  var mapFn = (element) => {
589
663
  const indexStr = element.getAttribute("index");
590
664
  return [element, indexStr === null ? null : parseInt(indexStr)];
591
665
  };
592
- function sortDOMElementsPatience(container) {
666
+ function sortDOMElements(container) {
593
667
  const elements = Array.from(container.children);
594
668
  if (elements.length <= 1) return elements;
595
669
  const items = elements.map(mapFn);
@@ -671,8 +745,8 @@ function findLIS(arr) {
671
745
  // src/hooks/useDOMOrder.ts
672
746
  function useDOMOrder(ref) {
673
747
  const ctx = useStateContext();
674
- const debounceRef = React4.useRef(void 0);
675
- React4.useEffect(() => {
748
+ const debounceRef = React3.useRef(void 0);
749
+ React3.useEffect(() => {
676
750
  const unsubscribe = listen$(ctx, "lastPositionUpdate", () => {
677
751
  if (debounceRef.current !== void 0) {
678
752
  clearTimeout(debounceRef.current);
@@ -680,7 +754,7 @@ function useDOMOrder(ref) {
680
754
  debounceRef.current = setTimeout(() => {
681
755
  const parent = ref.current;
682
756
  if (parent) {
683
- sortDOMElementsPatience(parent);
757
+ sortDOMElements(parent);
684
758
  }
685
759
  debounceRef.current = void 0;
686
760
  }, 500);
@@ -696,12 +770,12 @@ function useDOMOrder(ref) {
696
770
 
697
771
  // src/components/Containers.tsx
698
772
  var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColumns, children }) {
699
- const ref = React4.useRef(null);
773
+ const ref = React3.useRef(null);
700
774
  const ctx = useStateContext();
701
775
  const columnWrapperStyle = ctx.columnWrapperStyle;
702
776
  const [totalSize, otherAxisSize] = useArr$(["totalSize", "otherAxisSize"]);
703
777
  useDOMOrder(ref);
704
- const style = horizontal ? { minHeight: otherAxisSize, width: totalSize } : { height: totalSize, minWidth: otherAxisSize };
778
+ const style = horizontal ? { minHeight: otherAxisSize, position: "relative", width: totalSize } : { height: totalSize, minWidth: otherAxisSize, position: "relative" };
705
779
  if (columnWrapperStyle && numColumns > 1) {
706
780
  const { columnGap, rowGap, gap } = columnWrapperStyle;
707
781
  const gapX = columnGap || gap || 0;
@@ -722,7 +796,7 @@ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColum
722
796
  }
723
797
  }
724
798
  }
725
- return /* @__PURE__ */ React4__namespace.createElement("div", { ref, style }, children);
799
+ return /* @__PURE__ */ React3__namespace.createElement("div", { ref, style }, children);
726
800
  });
727
801
  var Containers = typedMemo(function Containers2({
728
802
  horizontal,
@@ -736,7 +810,7 @@ var Containers = typedMemo(function Containers2({
736
810
  const containers = [];
737
811
  for (let i = 0; i < numContainers; i++) {
738
812
  containers.push(
739
- /* @__PURE__ */ React4__namespace.createElement(
813
+ /* @__PURE__ */ React3__namespace.createElement(
740
814
  Container,
741
815
  {
742
816
  getRenderedItem: getRenderedItem2,
@@ -750,25 +824,41 @@ var Containers = typedMemo(function Containers2({
750
824
  )
751
825
  );
752
826
  }
753
- return /* @__PURE__ */ React4__namespace.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
754
- });
755
- var DevNumbers = __DEV__ && React4__namespace.memo(function DevNumbers2() {
756
- return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React4__namespace.createElement(
757
- View,
758
- {
759
- key: index,
760
- style: {
761
- height: 100,
762
- pointerEvents: "none",
763
- position: "absolute",
764
- top: index * 100,
765
- width: "100%"
766
- }
767
- },
768
- /* @__PURE__ */ React4__namespace.createElement(Text, { style: { color: "red" } }, index * 100)
769
- ));
827
+ return /* @__PURE__ */ React3__namespace.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
770
828
  });
771
- var ListComponentScrollView = React4.forwardRef(function ListComponentScrollView2({
829
+ function DevNumbers() {
830
+ return IS_DEV && React3__namespace.memo(function DevNumbers2() {
831
+ return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3__namespace.createElement(
832
+ "div",
833
+ {
834
+ key: index,
835
+ style: {
836
+ height: 100,
837
+ pointerEvents: "none",
838
+ position: "absolute",
839
+ top: index * 100,
840
+ width: "100%"
841
+ }
842
+ },
843
+ /* @__PURE__ */ React3__namespace.createElement("div", { style: { color: "red" } }, index * 100)
844
+ ));
845
+ });
846
+ }
847
+
848
+ // src/platform/StyleSheet.tsx
849
+ function flattenStyles(styles) {
850
+ if (isArray(styles)) {
851
+ return Object.assign({}, ...styles.filter(Boolean));
852
+ }
853
+ return styles;
854
+ }
855
+ var StyleSheet = {
856
+ create: (styles) => styles,
857
+ flatten: (style) => flattenStyles(style)
858
+ };
859
+
860
+ // src/components/ListComponentScrollView.tsx
861
+ var ListComponentScrollView = React3.forwardRef(function ListComponentScrollView2({
772
862
  children,
773
863
  style,
774
864
  contentContainerStyle,
@@ -781,25 +871,23 @@ var ListComponentScrollView = React4.forwardRef(function ListComponentScrollView
781
871
  showsVerticalScrollIndicator = true,
782
872
  refreshControl,
783
873
  onLayout,
784
- ScrollComponent,
785
874
  ...props
786
875
  }, ref) {
787
- const scrollRef = React4.useRef(null);
788
- const contentRef = React4.useRef(null);
789
- const momentumTimeout = React4.useRef(null);
790
- React4.useImperativeHandle(ref, () => {
876
+ const scrollRef = React3.useRef(null);
877
+ const contentRef = React3.useRef(null);
878
+ const momentumTimeout = React3.useRef(null);
879
+ React3.useImperativeHandle(ref, () => {
791
880
  const api = {
792
881
  getBoundingClientRect: () => {
793
- var _a;
794
- return (_a = scrollRef.current) == null ? void 0 : _a.getBoundingClientRect();
882
+ var _a3;
883
+ return (_a3 = scrollRef.current) == null ? void 0 : _a3.getBoundingClientRect();
795
884
  },
796
885
  getScrollableNode: () => scrollRef.current,
797
886
  getScrollResponder: () => scrollRef.current,
798
- scrollBy: (options) => {
887
+ scrollBy: (x, y) => {
799
888
  const el = scrollRef.current;
800
889
  if (!el) return;
801
- const { x = 0, y = 0, animated = true } = options;
802
- el.scrollBy({ behavior: animated ? "smooth" : "auto", left: x, top: y });
890
+ el.scrollBy(x, y);
803
891
  },
804
892
  scrollTo: (options) => {
805
893
  const el = scrollRef.current;
@@ -830,7 +918,7 @@ var ListComponentScrollView = React4.forwardRef(function ListComponentScrollView
830
918
  };
831
919
  return api;
832
920
  }, [horizontal]);
833
- const handleScroll = React4.useCallback(
921
+ const handleScroll = React3.useCallback(
834
922
  (event) => {
835
923
  if (!onScroll2 || !(event == null ? void 0 : event.target)) {
836
924
  return;
@@ -866,21 +954,25 @@ var ListComponentScrollView = React4.forwardRef(function ListComponentScrollView
866
954
  },
867
955
  [onScroll2, onMomentumScrollEnd]
868
956
  );
869
- React4.useLayoutEffect(() => {
957
+ React3.useLayoutEffect(() => {
870
958
  const element = scrollRef.current;
871
959
  if (!element) return;
872
- element.addEventListener("scroll", handleScroll, { passive: true });
960
+ element.addEventListener("scroll", handleScroll);
873
961
  return () => {
874
962
  element.removeEventListener("scroll", handleScroll);
875
963
  };
876
964
  }, [handleScroll]);
877
- React4.useLayoutEffect(() => {
878
- if (contentOffset && scrollRef.current) {
879
- scrollRef.current.scrollLeft = contentOffset.x || 0;
880
- scrollRef.current.scrollTop = contentOffset.y || 0;
881
- }
882
- }, [contentOffset]);
883
- React4.useLayoutEffect(() => {
965
+ React3.useEffect(() => {
966
+ const doScroll = () => {
967
+ if (contentOffset && scrollRef.current) {
968
+ scrollRef.current.scrollLeft = contentOffset.x || 0;
969
+ scrollRef.current.scrollTop = contentOffset.y || 0;
970
+ }
971
+ };
972
+ doScroll();
973
+ requestAnimationFrame(doScroll);
974
+ }, [contentOffset == null ? void 0 : contentOffset.x, contentOffset == null ? void 0 : contentOffset.y]);
975
+ React3.useLayoutEffect(() => {
884
976
  if (!onLayout || !scrollRef.current) return;
885
977
  const element = scrollRef.current;
886
978
  const fireLayout = () => {
@@ -911,36 +1003,57 @@ var ListComponentScrollView = React4.forwardRef(function ListComponentScrollView
911
1003
  // Ensure proper positioning context
912
1004
  WebkitOverflowScrolling: "touch",
913
1005
  // iOS momentum scrolling
914
- ...style
1006
+ ...StyleSheet.flatten(style)
915
1007
  };
916
1008
  const contentStyle = {
917
1009
  display: horizontal ? "flex" : "block",
918
1010
  flexDirection: horizontal ? "row" : void 0,
919
1011
  minHeight: horizontal ? void 0 : "100%",
920
1012
  minWidth: horizontal ? "100%" : void 0,
921
- ...contentContainerStyle
1013
+ ...StyleSheet.flatten(contentContainerStyle)
922
1014
  };
923
- return /* @__PURE__ */ React4__namespace.createElement("div", { ref: scrollRef, style: scrollViewStyle, ...props }, refreshControl, /* @__PURE__ */ React4__namespace.createElement("div", { ref: contentRef, style: contentStyle }, children));
1015
+ return /* @__PURE__ */ React3__namespace.createElement("div", { ref: scrollRef, style: scrollViewStyle, ...props }, refreshControl, /* @__PURE__ */ React3__namespace.createElement("div", { ref: contentRef, style: contentStyle }, children));
924
1016
  });
1017
+ function Padding() {
1018
+ const [paddingTop] = useArr$(["alignItemsPaddingTop"]);
1019
+ return /* @__PURE__ */ React3__namespace.createElement("div", { style: { paddingTop } });
1020
+ }
1021
+ function PaddingDevMode() {
1022
+ const [paddingTop] = useArr$(["alignItemsPaddingTop"]);
1023
+ return /* @__PURE__ */ React3__namespace.createElement(React3__namespace.Fragment, null, /* @__PURE__ */ React3__namespace.createElement("div", { style: { paddingTop } }), /* @__PURE__ */ React3__namespace.createElement(
1024
+ "div",
1025
+ {
1026
+ style: {
1027
+ backgroundColor: "green",
1028
+ height: paddingTop,
1029
+ left: 0,
1030
+ position: "absolute",
1031
+ right: 0,
1032
+ top: 0
1033
+ }
1034
+ }
1035
+ ));
1036
+ }
925
1037
  function useValueListener$(key, callback) {
926
1038
  const ctx = useStateContext();
927
- React4.useLayoutEffect(() => {
928
- listen$(ctx, key, (value) => {
1039
+ React3.useLayoutEffect(() => {
1040
+ const unsubscribe = listen$(ctx, key, (value) => {
929
1041
  callback(value);
930
1042
  });
931
- }, []);
1043
+ return unsubscribe;
1044
+ }, [callback, ctx, key]);
932
1045
  }
933
1046
 
934
1047
  // src/components/ScrollAdjust.tsx
935
1048
  function ScrollAdjust() {
936
1049
  const ctx = useStateContext();
937
- const lastScrollOffsetRef = React4__namespace.useRef(0);
938
- const callback = React4__namespace.useCallback(() => {
939
- var _a;
1050
+ const lastScrollOffsetRef = React3__namespace.useRef(0);
1051
+ const callback = React3__namespace.useCallback(() => {
1052
+ var _a3;
940
1053
  const scrollAdjust = peek$(ctx, "scrollAdjust");
941
1054
  const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
942
1055
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
943
- const scrollView = (_a = ctx.internalState) == null ? void 0 : _a.refScroller.current;
1056
+ const scrollView = (_a3 = ctx.internalState) == null ? void 0 : _a3.refScroller.current;
944
1057
  if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
945
1058
  const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
946
1059
  if (scrollDelta !== 0) {
@@ -954,49 +1067,26 @@ function ScrollAdjust() {
954
1067
  useValueListener$("scrollAdjustUserOffset", callback);
955
1068
  return null;
956
1069
  }
957
-
958
- // src/components/SnapWrapper.tsx
959
1070
  function SnapWrapper({ ScrollComponent, ...props }) {
960
1071
  const [snapToOffsets] = useArr$(["snapToOffsets"]);
961
- return /* @__PURE__ */ React.createElement(ScrollComponent, { ...props, snapToOffsets });
962
- }
963
-
964
- // src/hooks/useValue$.ts
965
- function useValue$(key, params) {
966
- const [value] = useArr$([key]);
967
- return value;
1072
+ return /* @__PURE__ */ React3__namespace.createElement(ScrollComponent, { ...props, snapToOffsets });
968
1073
  }
1074
+ var LayoutView = ({ onLayoutChange, refView, children, ...rest }) => {
1075
+ const ref = refView != null ? refView : React3.useRef();
1076
+ useOnLayoutSync({ onLayoutChange, ref });
1077
+ return /* @__PURE__ */ React3__namespace.createElement("div", { ...rest, ref }, children);
1078
+ };
969
1079
 
970
1080
  // src/components/ListComponent.tsx
971
1081
  var getComponent = (Component) => {
972
- if (React4__namespace.isValidElement(Component)) {
1082
+ if (React3__namespace.isValidElement(Component)) {
973
1083
  return Component;
974
1084
  }
975
1085
  if (Component) {
976
- return /* @__PURE__ */ React4__namespace.createElement(Component, null);
1086
+ return /* @__PURE__ */ React3__namespace.createElement(Component, null);
977
1087
  }
978
1088
  return null;
979
1089
  };
980
- var Padding = () => {
981
- const animPaddingTop = useValue$("alignItemsPaddingTop");
982
- return /* @__PURE__ */ React4__namespace.createElement(AnimatedView, { style: { paddingTop: animPaddingTop } });
983
- };
984
- var PaddingDevMode = () => {
985
- const animPaddingTop = useValue$("alignItemsPaddingTop");
986
- return /* @__PURE__ */ React4__namespace.createElement(React4__namespace.Fragment, null, /* @__PURE__ */ React4__namespace.createElement(AnimatedView, { style: { paddingTop: animPaddingTop } }), /* @__PURE__ */ React4__namespace.createElement(
987
- AnimatedView,
988
- {
989
- style: {
990
- backgroundColor: "green",
991
- height: animPaddingTop,
992
- left: 0,
993
- position: "absolute",
994
- right: 0,
995
- top: 0
996
- }
997
- }
998
- ));
999
- };
1000
1090
  var ListComponent = typedMemo(function ListComponent2({
1001
1091
  canRender,
1002
1092
  style,
@@ -1026,12 +1116,11 @@ var ListComponent = typedMemo(function ListComponent2({
1026
1116
  ...rest
1027
1117
  }) {
1028
1118
  const ctx = useStateContext();
1029
- const refHeader = React4__namespace.useRef(null);
1030
- const ScrollComponent = renderScrollComponent ? React4.useMemo(
1031
- () => React4__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1119
+ const ScrollComponent = renderScrollComponent ? React3.useMemo(
1120
+ () => React3__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1032
1121
  [renderScrollComponent]
1033
1122
  ) : ListComponentScrollView;
1034
- React4__namespace.useEffect(() => {
1123
+ React3__namespace.useEffect(() => {
1035
1124
  if (canRender) {
1036
1125
  setTimeout(() => {
1037
1126
  scrollAdjustHandler.setMounted();
@@ -1039,39 +1128,30 @@ var ListComponent = typedMemo(function ListComponent2({
1039
1128
  }
1040
1129
  }, [canRender]);
1041
1130
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
1042
- const contentContainerStyleWeb = React4.useMemo(() => {
1043
- const base = contentContainerStyle || void 0;
1044
- if (!horizontal) return base;
1045
- if (base && base.height === "100%") return base;
1046
- return { ...base || {}, height: "100%" };
1047
- }, [horizontal, (contentContainerStyle == null ? void 0 : contentContainerStyle.height) === "100%" ? 1 : 0]);
1048
- return /* @__PURE__ */ React4__namespace.createElement(
1131
+ return /* @__PURE__ */ React3__namespace.createElement(
1049
1132
  SnapOrScroll,
1050
1133
  {
1051
1134
  ...rest,
1052
- contentContainerStyle: contentContainerStyleWeb,
1135
+ contentContainerStyle: [
1136
+ contentContainerStyle,
1137
+ horizontal ? {
1138
+ height: "100%"
1139
+ } : {}
1140
+ ],
1053
1141
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1054
1142
  horizontal,
1055
- maintainVisibleContentPosition: maintainVisibleContentPosition && !ListEmptyComponent ? { minIndexForVisible: 0 } : void 0,
1143
+ maintainVisibleContentPosition: maintainVisibleContentPosition ? { minIndexForVisible: 0 } : void 0,
1056
1144
  onLayout,
1057
1145
  onScroll: onScroll2,
1058
1146
  ref: refScrollView,
1059
1147
  ScrollComponent: snapToIndices ? ScrollComponent : void 0,
1060
1148
  style
1061
1149
  },
1062
- maintainVisibleContentPosition && /* @__PURE__ */ React4__namespace.createElement(ScrollAdjust, null),
1063
- ENABLE_DEVMODE ? /* @__PURE__ */ React4__namespace.createElement(PaddingDevMode, null) : /* @__PURE__ */ React4__namespace.createElement(Padding, null),
1064
- ListHeaderComponent && /* @__PURE__ */ React4__namespace.createElement(
1065
- LayoutView,
1066
- {
1067
- onLayoutChange: onLayoutHeader,
1068
- refView: refHeader,
1069
- style: ListHeaderComponentStyle
1070
- },
1071
- getComponent(ListHeaderComponent)
1072
- ),
1150
+ maintainVisibleContentPosition && /* @__PURE__ */ React3__namespace.createElement(ScrollAdjust, null),
1151
+ ENABLE_DEVMODE ? /* @__PURE__ */ React3__namespace.createElement(PaddingDevMode, null) : /* @__PURE__ */ React3__namespace.createElement(Padding, null),
1152
+ ListHeaderComponent && /* @__PURE__ */ React3__namespace.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
1073
1153
  ListEmptyComponent && getComponent(ListEmptyComponent),
1074
- canRender && /* @__PURE__ */ React4__namespace.createElement(
1154
+ canRender && !ListEmptyComponent && /* @__PURE__ */ React3__namespace.createElement(
1075
1155
  Containers,
1076
1156
  {
1077
1157
  getRenderedItem: getRenderedItem2,
@@ -1082,7 +1162,7 @@ var ListComponent = typedMemo(function ListComponent2({
1082
1162
  waitForInitialLayout
1083
1163
  }
1084
1164
  ),
1085
- ListFooterComponent && /* @__PURE__ */ React4__namespace.createElement(
1165
+ ListFooterComponent && /* @__PURE__ */ React3__namespace.createElement(
1086
1166
  LayoutView,
1087
1167
  {
1088
1168
  onLayoutChange: (layout) => {
@@ -1093,7 +1173,7 @@ var ListComponent = typedMemo(function ListComponent2({
1093
1173
  },
1094
1174
  getComponent(ListFooterComponent)
1095
1175
  ),
1096
- __DEV__ && ENABLE_DEVMODE && /* @__PURE__ */ React4__namespace.createElement(DevNumbers, null)
1176
+ IS_DEV && ENABLE_DEVMODE && /* @__PURE__ */ React3__namespace.createElement(DevNumbers, null)
1097
1177
  );
1098
1178
  });
1099
1179
 
@@ -1105,7 +1185,7 @@ function getId(state, index) {
1105
1185
  }
1106
1186
  const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
1107
1187
  const id = ret;
1108
- state.idCache.set(index, id);
1188
+ state.idCache[index] = id;
1109
1189
  return id;
1110
1190
  }
1111
1191
 
@@ -1126,13 +1206,100 @@ function calculateOffsetForIndex(ctx, state, index) {
1126
1206
  return position;
1127
1207
  }
1128
1208
 
1209
+ // src/utils/setPaddingTop.ts
1210
+ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1211
+ if (stylePaddingTop !== void 0) {
1212
+ const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1213
+ if (stylePaddingTop < prevStylePaddingTop) {
1214
+ let prevTotalSize = peek$(ctx, "totalSize") || 0;
1215
+ set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1216
+ state.timeoutSetPaddingTop = setTimeout(() => {
1217
+ prevTotalSize = peek$(ctx, "totalSize") || 0;
1218
+ set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
1219
+ }, 16);
1220
+ }
1221
+ set$(ctx, "stylePaddingTop", stylePaddingTop);
1222
+ }
1223
+ if (alignItemsPaddingTop !== void 0) {
1224
+ set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1225
+ }
1226
+ }
1227
+
1228
+ // src/utils/updateAlignItemsPaddingTop.ts
1229
+ function updateAlignItemsPaddingTop(ctx, state) {
1230
+ const {
1231
+ scrollLength,
1232
+ props: { alignItemsAtEnd, data }
1233
+ } = state;
1234
+ if (alignItemsAtEnd) {
1235
+ let alignItemsPaddingTop = 0;
1236
+ if ((data == null ? void 0 : data.length) > 0) {
1237
+ const contentSize = getContentSize(ctx);
1238
+ alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1239
+ }
1240
+ setPaddingTop(ctx, state, { alignItemsPaddingTop });
1241
+ }
1242
+ }
1243
+
1244
+ // src/core/updateTotalSize.ts
1245
+ function updateTotalSize(ctx, state) {
1246
+ const {
1247
+ positions,
1248
+ props: { data }
1249
+ } = state;
1250
+ if (data.length === 0) {
1251
+ addTotalSize(ctx, state, null, 0);
1252
+ } else {
1253
+ const lastId = getId(state, data.length - 1);
1254
+ if (lastId !== void 0) {
1255
+ const lastPosition = positions.get(lastId);
1256
+ if (lastPosition !== void 0) {
1257
+ const lastSize = getItemSize(ctx, state, lastId, data.length - 1, data[data.length - 1]);
1258
+ if (lastSize !== void 0) {
1259
+ const totalSize = lastPosition + lastSize;
1260
+ addTotalSize(ctx, state, null, totalSize);
1261
+ }
1262
+ }
1263
+ }
1264
+ }
1265
+ }
1266
+ function addTotalSize(ctx, state, key, add) {
1267
+ const { alignItemsAtEnd } = state.props;
1268
+ const prevTotalSize = state.totalSize;
1269
+ if (key === null) {
1270
+ state.totalSize = add;
1271
+ if (state.timeoutSetPaddingTop) {
1272
+ clearTimeout(state.timeoutSetPaddingTop);
1273
+ state.timeoutSetPaddingTop = void 0;
1274
+ }
1275
+ } else {
1276
+ state.totalSize += add;
1277
+ }
1278
+ if (prevTotalSize !== state.totalSize) {
1279
+ set$(ctx, "totalSize", state.totalSize);
1280
+ if (alignItemsAtEnd) {
1281
+ updateAlignItemsPaddingTop(ctx, state);
1282
+ }
1283
+ }
1284
+ }
1285
+
1286
+ // src/core/setSize.ts
1287
+ function setSize(ctx, state, itemKey, size) {
1288
+ const { sizes } = state;
1289
+ const previousSize = sizes.get(itemKey);
1290
+ const diff = previousSize !== void 0 ? size - previousSize : size;
1291
+ if (diff !== 0) {
1292
+ addTotalSize(ctx, state, itemKey, diff);
1293
+ }
1294
+ sizes.set(itemKey, size);
1295
+ }
1296
+
1129
1297
  // src/utils/getItemSize.ts
1130
- function getItemSize(state, key, index, data, useAverageSize) {
1131
- var _a, _b;
1298
+ function getItemSize(ctx, state, key, index, data, useAverageSize, preferCachedSize) {
1299
+ var _a3, _b;
1132
1300
  const {
1133
1301
  sizesKnown,
1134
1302
  sizes,
1135
- scrollingTo,
1136
1303
  averageSizes,
1137
1304
  props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
1138
1305
  } = state;
@@ -1141,7 +1308,14 @@ function getItemSize(state, key, index, data, useAverageSize) {
1141
1308
  return sizeKnown;
1142
1309
  }
1143
1310
  let size;
1144
- const itemType = getItemType ? (_a = getItemType(data, index)) != null ? _a : "" : "";
1311
+ const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
1312
+ const scrollingTo = peek$(ctx, "scrollingTo");
1313
+ if (preferCachedSize) {
1314
+ const cachedSize = sizes.get(key);
1315
+ if (cachedSize !== void 0) {
1316
+ return cachedSize;
1317
+ }
1318
+ }
1145
1319
  if (getFixedItemSize) {
1146
1320
  size = getFixedItemSize(index, data, itemType);
1147
1321
  if (size !== void 0) {
@@ -1163,53 +1337,239 @@ function getItemSize(state, key, index, data, useAverageSize) {
1163
1337
  if (size === void 0) {
1164
1338
  size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
1165
1339
  }
1166
- sizes.set(key, size);
1340
+ setSize(ctx, state, key, size);
1167
1341
  return size;
1168
1342
  }
1169
1343
 
1170
1344
  // src/core/calculateOffsetWithOffsetPosition.ts
1171
- function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
1345
+ function calculateOffsetWithOffsetPosition(ctx, state, offsetParam, params) {
1172
1346
  const { index, viewOffset, viewPosition } = params;
1173
1347
  let offset = offsetParam;
1174
1348
  if (viewOffset) {
1175
1349
  offset -= viewOffset;
1176
1350
  }
1177
1351
  if (viewPosition !== void 0 && index !== void 0) {
1178
- offset -= viewPosition * (state.scrollLength - getItemSize(state, getId(state, index), index, state.props.data[index]));
1352
+ offset -= viewPosition * (state.scrollLength - getItemSize(ctx, state, getId(state, index), index, state.props.data[index]));
1179
1353
  }
1180
1354
  return offset;
1181
1355
  }
1182
1356
 
1357
+ // src/utils/checkThreshold.ts
1358
+ var HYSTERESIS_MULTIPLIER = 1.3;
1359
+ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
1360
+ const absDistance = Math.abs(distance);
1361
+ const within = atThreshold || threshold > 0 && absDistance <= threshold;
1362
+ const updateSnapshot = () => {
1363
+ setSnapshot == null ? void 0 : setSnapshot({
1364
+ atThreshold,
1365
+ contentSize: context.contentSize,
1366
+ dataLength: context.dataLength,
1367
+ scrollPosition: context.scrollPosition
1368
+ });
1369
+ };
1370
+ if (!wasReached) {
1371
+ if (!within) {
1372
+ return false;
1373
+ }
1374
+ onReached == null ? void 0 : onReached(distance);
1375
+ updateSnapshot();
1376
+ return true;
1377
+ }
1378
+ const reset = !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
1379
+ if (reset) {
1380
+ setSnapshot == null ? void 0 : setSnapshot(void 0);
1381
+ return false;
1382
+ }
1383
+ if (within) {
1384
+ const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
1385
+ if (changed) {
1386
+ onReached == null ? void 0 : onReached(distance);
1387
+ updateSnapshot();
1388
+ }
1389
+ }
1390
+ return true;
1391
+ };
1392
+
1393
+ // src/utils/checkAtBottom.ts
1394
+ function checkAtBottom(ctx, state) {
1395
+ var _a3;
1396
+ if (!state) {
1397
+ return;
1398
+ }
1399
+ const {
1400
+ queuedInitialLayout,
1401
+ scrollLength,
1402
+ scroll,
1403
+ maintainingScrollAtEnd,
1404
+ props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
1405
+ } = state;
1406
+ const contentSize = getContentSize(ctx);
1407
+ if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1408
+ const distanceFromEnd = contentSize - scroll - scrollLength;
1409
+ const isContentLess = contentSize < scrollLength;
1410
+ state.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1411
+ state.isEndReached = checkThreshold(
1412
+ distanceFromEnd,
1413
+ isContentLess,
1414
+ onEndReachedThreshold * scrollLength,
1415
+ state.isEndReached,
1416
+ state.endReachedSnapshot,
1417
+ {
1418
+ contentSize,
1419
+ dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length,
1420
+ scrollPosition: scroll
1421
+ },
1422
+ (distance) => {
1423
+ var _a4, _b;
1424
+ return (_b = (_a4 = state.props).onEndReached) == null ? void 0 : _b.call(_a4, { distanceFromEnd: distance });
1425
+ },
1426
+ (snapshot) => {
1427
+ state.endReachedSnapshot = snapshot;
1428
+ }
1429
+ );
1430
+ }
1431
+ }
1432
+
1433
+ // src/utils/checkAtTop.ts
1434
+ function checkAtTop(state) {
1435
+ var _a3;
1436
+ if (!state) {
1437
+ return;
1438
+ }
1439
+ const {
1440
+ scrollLength,
1441
+ scroll,
1442
+ props: { onStartReachedThreshold }
1443
+ } = state;
1444
+ const distanceFromTop = scroll;
1445
+ state.isAtStart = distanceFromTop <= 0;
1446
+ state.isStartReached = checkThreshold(
1447
+ distanceFromTop,
1448
+ false,
1449
+ onStartReachedThreshold * scrollLength,
1450
+ state.isStartReached,
1451
+ state.startReachedSnapshot,
1452
+ {
1453
+ contentSize: state.totalSize,
1454
+ dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length,
1455
+ scrollPosition: scroll
1456
+ },
1457
+ (distance) => {
1458
+ var _a4, _b;
1459
+ return (_b = (_a4 = state.props).onStartReached) == null ? void 0 : _b.call(_a4, { distanceFromStart: distance });
1460
+ },
1461
+ (snapshot) => {
1462
+ state.startReachedSnapshot = snapshot;
1463
+ }
1464
+ );
1465
+ }
1466
+
1467
+ // src/core/onScroll.ts
1468
+ function onScroll(ctx, state, event) {
1469
+ var _a3, _b, _c;
1470
+ const {
1471
+ scrollProcessingEnabled,
1472
+ props: { onScroll: onScrollProp }
1473
+ } = state;
1474
+ if (scrollProcessingEnabled === false) {
1475
+ return;
1476
+ }
1477
+ 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) {
1478
+ return;
1479
+ }
1480
+ const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
1481
+ state.scrollPending = newScroll;
1482
+ updateScroll(ctx, state, newScroll);
1483
+ onScrollProp == null ? void 0 : onScrollProp(event);
1484
+ }
1485
+ function updateScroll(ctx, state, newScroll, forceUpdate) {
1486
+ const scrollingTo = peek$(ctx, "scrollingTo");
1487
+ state.hasScrolled = true;
1488
+ state.lastBatchingAction = Date.now();
1489
+ const currentTime = Date.now();
1490
+ const adjust = state.scrollAdjustHandler.getAdjust();
1491
+ const lastHistoryAdjust = state.lastScrollAdjustForHistory;
1492
+ const adjustChanged = lastHistoryAdjust !== void 0 && Math.abs(adjust - lastHistoryAdjust) > 0.1;
1493
+ if (adjustChanged) {
1494
+ state.scrollHistory.length = 0;
1495
+ }
1496
+ state.lastScrollAdjustForHistory = adjust;
1497
+ if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
1498
+ if (!adjustChanged) {
1499
+ state.scrollHistory.push({ scroll: newScroll, time: currentTime });
1500
+ }
1501
+ }
1502
+ if (state.scrollHistory.length > 5) {
1503
+ state.scrollHistory.shift();
1504
+ }
1505
+ state.scrollPrev = state.scroll;
1506
+ state.scrollPrevTime = state.scrollTime;
1507
+ state.scroll = newScroll;
1508
+ state.scrollTime = currentTime;
1509
+ const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
1510
+ if (ignoreScrollFromMVCP && !scrollingTo) {
1511
+ const { lt, gt } = ignoreScrollFromMVCP;
1512
+ if (lt && newScroll < lt || gt && newScroll > gt) {
1513
+ state.ignoreScrollFromMVCPIgnored = true;
1514
+ return;
1515
+ }
1516
+ }
1517
+ if (state.dataChangeNeedsScrollUpdate || Math.abs(state.scroll - state.scrollPrev) > 2) {
1518
+ state.ignoreScrollFromMVCPIgnored = false;
1519
+ calculateItemsInView(ctx, state, { doMVCP: scrollingTo !== void 0 });
1520
+ checkAtBottom(ctx, state);
1521
+ checkAtTop(state);
1522
+ state.dataChangeNeedsScrollUpdate = false;
1523
+ }
1524
+ }
1525
+
1183
1526
  // src/core/finishScrollTo.ts
1184
- var finishScrollTo = (state) => {
1527
+ function finishScrollTo(ctx, state) {
1528
+ var _a3, _b;
1185
1529
  if (state) {
1186
- state.scrollingTo = void 0;
1187
1530
  state.scrollHistory.length = 0;
1531
+ state.initialScroll = void 0;
1532
+ set$(ctx, "scrollingTo", void 0);
1533
+ if ((_a3 = state.props) == null ? void 0 : _a3.data) {
1534
+ (_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
1535
+ }
1188
1536
  }
1189
- };
1537
+ }
1190
1538
 
1191
1539
  // src/core/scrollTo.ts
1192
- function scrollTo(state, params = {}) {
1193
- var _a;
1194
- const { animated, noScrollingTo } = params;
1540
+ function scrollTo(ctx, state, params) {
1541
+ var _a3;
1542
+ const { noScrollingTo, ...scrollTarget } = params;
1543
+ const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
1195
1544
  const {
1196
1545
  refScroller,
1197
1546
  props: { horizontal }
1198
1547
  } = state;
1199
- const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
1548
+ let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, state, scrollTargetOffset, scrollTarget);
1549
+ if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
1550
+ const maxOffset = Math.max(0, getContentSize(ctx) - state.scrollLength);
1551
+ offset = Math.min(offset, maxOffset);
1552
+ }
1200
1553
  state.scrollHistory.length = 0;
1201
1554
  if (!noScrollingTo) {
1202
- state.scrollingTo = params;
1555
+ set$(ctx, "scrollingTo", scrollTarget);
1203
1556
  }
1204
1557
  state.scrollPending = offset;
1205
- (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
1206
- animated: !!animated,
1207
- x: horizontal ? offset : 0,
1208
- y: horizontal ? 0 : offset
1209
- });
1558
+ if (!isInitialScroll || Platform.OS === "android") {
1559
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollTo({
1560
+ animated: !!animated,
1561
+ x: horizontal ? offset : 0,
1562
+ y: horizontal ? 0 : offset
1563
+ });
1564
+ }
1210
1565
  if (!animated) {
1211
1566
  state.scroll = offset;
1212
- setTimeout(() => finishScrollTo(state), 100);
1567
+ setTimeout(() => finishScrollTo(ctx, state), 100);
1568
+ if (isInitialScroll) {
1569
+ setTimeout(() => {
1570
+ state.initialScroll = void 0;
1571
+ }, 500);
1572
+ }
1213
1573
  }
1214
1574
  }
1215
1575
 
@@ -1226,24 +1586,6 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1226
1586
  const didLayout = peek$(ctx, "containersDidLayout");
1227
1587
  if (didLayout) {
1228
1588
  doit();
1229
- const threshold = state.scroll - positionDiff / 2;
1230
- if (!state.ignoreScrollFromMVCP) {
1231
- state.ignoreScrollFromMVCP = {};
1232
- }
1233
- if (positionDiff > 0) {
1234
- state.ignoreScrollFromMVCP.lt = threshold;
1235
- } else {
1236
- state.ignoreScrollFromMVCP.gt = threshold;
1237
- }
1238
- if (state.ignoreScrollFromMVCPTimeout) {
1239
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
1240
- }
1241
- state.ignoreScrollFromMVCPTimeout = setTimeout(
1242
- () => {
1243
- state.ignoreScrollFromMVCP = void 0;
1244
- },
1245
- 100
1246
- );
1247
1589
  } else {
1248
1590
  requestAnimationFrame(doit);
1249
1591
  }
@@ -1255,9 +1597,9 @@ function prepareMVCP(ctx, state, dataChanged) {
1255
1597
  const {
1256
1598
  idsInView,
1257
1599
  positions,
1258
- scrollingTo,
1259
1600
  props: { maintainVisibleContentPosition }
1260
1601
  } = state;
1602
+ const scrollingTo = peek$(ctx, "scrollingTo");
1261
1603
  let prevPosition;
1262
1604
  let targetId;
1263
1605
  const idsInViewWithPositions = [];
@@ -1298,7 +1640,16 @@ function prepareMVCP(ctx, state, dataChanged) {
1298
1640
  if (targetId !== void 0 && prevPosition !== void 0) {
1299
1641
  const newPosition = positions.get(targetId);
1300
1642
  if (newPosition !== void 0) {
1301
- positionDiff = newPosition - prevPosition;
1643
+ const totalSize = peek$(ctx, "totalSize");
1644
+ let diff = newPosition - prevPosition;
1645
+ if (diff !== 0 && state.scroll + state.scrollLength > totalSize) {
1646
+ if (diff > 0) {
1647
+ diff = Math.max(0, totalSize - state.scroll - state.scrollLength);
1648
+ } else {
1649
+ diff = 0;
1650
+ }
1651
+ }
1652
+ positionDiff = diff;
1302
1653
  }
1303
1654
  }
1304
1655
  if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
@@ -1307,77 +1658,105 @@ function prepareMVCP(ctx, state, dataChanged) {
1307
1658
  };
1308
1659
  }
1309
1660
 
1310
- // src/utils/setPaddingTop.ts
1311
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1312
- if (stylePaddingTop !== void 0) {
1313
- const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1314
- if (stylePaddingTop < prevStylePaddingTop) {
1315
- let prevTotalSize = peek$(ctx, "totalSize") || 0;
1316
- set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1317
- state.timeoutSetPaddingTop = setTimeout(() => {
1318
- prevTotalSize = peek$(ctx, "totalSize") || 0;
1319
- set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
1320
- }, 16);
1321
- }
1322
- set$(ctx, "stylePaddingTop", stylePaddingTop);
1661
+ // src/core/prepareColumnStartState.ts
1662
+ function prepareColumnStartState(ctx, state, startIndex, useAverageSize) {
1663
+ var _a3;
1664
+ const numColumns = peek$(ctx, "numColumns");
1665
+ let rowStartIndex = startIndex;
1666
+ const columnAtStart = state.columns.get(state.idCache[startIndex]);
1667
+ if (columnAtStart !== 1) {
1668
+ rowStartIndex = findRowStartIndex(state, numColumns, startIndex);
1323
1669
  }
1324
- if (alignItemsPaddingTop !== void 0) {
1325
- set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1670
+ let currentRowTop = 0;
1671
+ const curId = state.idCache[rowStartIndex];
1672
+ const column = state.columns.get(curId);
1673
+ if (rowStartIndex > 0) {
1674
+ const prevIndex = rowStartIndex - 1;
1675
+ const prevId = state.idCache[prevIndex];
1676
+ const prevPosition = (_a3 = state.positions.get(prevId)) != null ? _a3 : 0;
1677
+ const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
1678
+ const prevRowHeight = calculateRowMaxSize(ctx, state, prevRowStart, prevIndex, useAverageSize);
1679
+ currentRowTop = prevPosition + prevRowHeight;
1326
1680
  }
1681
+ return {
1682
+ column,
1683
+ currentRowTop,
1684
+ startIndex: rowStartIndex
1685
+ };
1327
1686
  }
1328
-
1329
- // src/utils/updateAlignItemsPaddingTop.ts
1330
- function updateAlignItemsPaddingTop(ctx, state) {
1331
- const {
1332
- scrollLength,
1333
- props: { alignItemsAtEnd, data }
1334
- } = state;
1335
- if (alignItemsAtEnd) {
1336
- let alignItemsPaddingTop = 0;
1337
- if ((data == null ? void 0 : data.length) > 0) {
1338
- const contentSize = getContentSize(ctx);
1339
- alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1687
+ function findRowStartIndex(state, numColumns, index) {
1688
+ if (numColumns <= 1) {
1689
+ return Math.max(0, index);
1690
+ }
1691
+ let rowStart = Math.max(0, index);
1692
+ while (rowStart > 0) {
1693
+ const columnForIndex = state.columns.get(state.idCache[rowStart]);
1694
+ if (columnForIndex === 1) {
1695
+ break;
1340
1696
  }
1341
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
1697
+ rowStart--;
1342
1698
  }
1699
+ return rowStart;
1343
1700
  }
1344
-
1345
- // src/core/updateTotalSize.ts
1346
- function updateTotalSize(ctx, state) {
1347
- const {
1348
- positions,
1349
- props: { data }
1350
- } = state;
1351
- if (data.length === 0) {
1352
- addTotalSize(ctx, state, null, 0);
1353
- } else {
1354
- const lastId = getId(state, data.length - 1);
1355
- if (lastId !== void 0) {
1356
- const lastPosition = positions.get(lastId);
1357
- if (lastPosition !== void 0) {
1358
- const lastSize = getItemSize(state, lastId, data.length - 1, data[data.length - 1]);
1359
- if (lastSize !== void 0) {
1360
- const totalSize = lastPosition + lastSize;
1361
- addTotalSize(ctx, state, null, totalSize);
1362
- }
1363
- }
1701
+ function calculateRowMaxSize(ctx, state, startIndex, endIndex, useAverageSize) {
1702
+ if (endIndex < startIndex) {
1703
+ return 0;
1704
+ }
1705
+ const { data } = state.props;
1706
+ if (!data) {
1707
+ return 0;
1708
+ }
1709
+ let maxSize = 0;
1710
+ for (let i = startIndex; i <= endIndex; i++) {
1711
+ if (i < 0 || i >= data.length) {
1712
+ continue;
1713
+ }
1714
+ const id = state.idCache[i];
1715
+ const size = getItemSize(ctx, state, id, i, data[i], useAverageSize);
1716
+ if (size > maxSize) {
1717
+ maxSize = size;
1364
1718
  }
1365
1719
  }
1720
+ return maxSize;
1366
1721
  }
1367
- function addTotalSize(ctx, state, key, add) {
1368
- const { alignItemsAtEnd } = state.props;
1369
- {
1370
- state.totalSize = add;
1371
- if (state.timeoutSetPaddingTop) {
1372
- clearTimeout(state.timeoutSetPaddingTop);
1373
- state.timeoutSetPaddingTop = void 0;
1722
+
1723
+ // src/utils/getScrollVelocity.ts
1724
+ var getScrollVelocity = (state) => {
1725
+ const { scrollHistory } = state;
1726
+ let velocity = 0;
1727
+ if (scrollHistory.length >= 1) {
1728
+ const newest = scrollHistory[scrollHistory.length - 1];
1729
+ let oldest;
1730
+ let start = 0;
1731
+ const now = Date.now();
1732
+ for (let i = 0; i < scrollHistory.length - 1; i++) {
1733
+ const entry = scrollHistory[i];
1734
+ const nextEntry = scrollHistory[i + 1];
1735
+ if (i > 0) {
1736
+ const prevEntry = scrollHistory[i - 1];
1737
+ const prevDirection = entry.scroll - prevEntry.scroll;
1738
+ const currentDirection = nextEntry.scroll - entry.scroll;
1739
+ if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1740
+ start = i;
1741
+ break;
1742
+ }
1743
+ }
1744
+ }
1745
+ for (let i = start; i < scrollHistory.length - 1; i++) {
1746
+ const entry = scrollHistory[i];
1747
+ if (now - entry.time <= 1e3) {
1748
+ oldest = entry;
1749
+ break;
1750
+ }
1751
+ }
1752
+ if (oldest && oldest !== newest) {
1753
+ const scrollDiff = newest.scroll - oldest.scroll;
1754
+ const timeDiff = newest.time - oldest.time;
1755
+ velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1374
1756
  }
1375
1757
  }
1376
- set$(ctx, "totalSize", state.totalSize);
1377
- if (alignItemsAtEnd) {
1378
- updateAlignItemsPaddingTop(ctx, state);
1379
- }
1380
- }
1758
+ return velocity;
1759
+ };
1381
1760
 
1382
1761
  // src/utils/updateSnapToOffsets.ts
1383
1762
  function updateSnapToOffsets(ctx, state) {
@@ -1394,44 +1773,67 @@ function updateSnapToOffsets(ctx, state) {
1394
1773
  set$(ctx, "snapToOffsets", snapToOffsets);
1395
1774
  }
1396
1775
 
1397
- // src/core/updateAllPositions.ts
1398
- function updateAllPositions(ctx, state, dataChanged, startIndex = 0) {
1399
- var _a, _b, _c, _d, _e, _f;
1776
+ // src/core/updateItemPositions.ts
1777
+ function updateItemPositions(ctx, state, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false } = {
1778
+ forceFullUpdate: false,
1779
+ scrollBottomBuffered: -1,
1780
+ startIndex: 0
1781
+ }) {
1782
+ var _a3, _b, _c, _d, _e;
1400
1783
  const {
1401
1784
  columns,
1402
1785
  indexByKey,
1403
1786
  positions,
1404
1787
  idCache,
1405
1788
  sizesKnown,
1406
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
1789
+ props: { getEstimatedItemSize, snapToIndices, enableAverages, maintainVisibleContentPosition }
1407
1790
  } = state;
1408
1791
  const data = state.props.data;
1792
+ const dataLength = data.length;
1409
1793
  const numColumns = peek$(ctx, "numColumns");
1410
- const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
1794
+ const scrollingTo = peek$(ctx, "scrollingTo");
1795
+ const hasColumns = numColumns > 1;
1796
+ const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
1797
+ const shouldOptimize = !forceFullUpdate && !dataChanged && Math.abs(getScrollVelocity(state)) > 0;
1798
+ const maxVisibleArea = scrollBottomBuffered + 1e3;
1411
1799
  const useAverageSize = enableAverages && !getEstimatedItemSize;
1800
+ const preferCachedSize = maintainVisibleContentPosition && (dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0) !== 0);
1412
1801
  let currentRowTop = 0;
1413
1802
  let column = 1;
1414
1803
  let maxSizeInRow = 0;
1415
- const hasColumns = numColumns > 1;
1416
1804
  if (startIndex > 0) {
1417
- const prevIndex = startIndex - 1;
1418
- const prevId = (_a = idCache.get(prevIndex)) != null ? _a : getId(state, prevIndex);
1419
- const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1420
1805
  if (hasColumns) {
1421
- const prevColumn = (_c = columns.get(prevId)) != null ? _c : 1;
1422
- currentRowTop = prevPosition;
1423
- column = prevColumn % numColumns + 1;
1424
- } else {
1425
- const prevSize = (_d = sizesKnown.get(prevId)) != null ? _d : getItemSize(state, prevId, prevIndex, data[prevIndex], useAverageSize);
1806
+ const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
1807
+ ctx,
1808
+ state,
1809
+ startIndex,
1810
+ useAverageSize
1811
+ );
1812
+ startIndex = processedStartIndex;
1813
+ currentRowTop = initialRowTop;
1814
+ } else if (startIndex < dataLength) {
1815
+ const prevIndex = startIndex - 1;
1816
+ const prevId = getId(state, prevIndex);
1817
+ const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1818
+ const prevSize = (_c = sizesKnown.get(prevId)) != null ? _c : getItemSize(ctx, state, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
1426
1819
  currentRowTop = prevPosition + prevSize;
1427
1820
  }
1428
1821
  }
1429
1822
  const needsIndexByKey = dataChanged || indexByKey.size === 0;
1430
- const dataLength = data.length;
1823
+ let didBreakEarly = false;
1824
+ let breakAt;
1431
1825
  for (let i = startIndex; i < dataLength; i++) {
1432
- const id = (_e = idCache.get(i)) != null ? _e : getId(state, i);
1433
- const size = (_f = sizesKnown.get(id)) != null ? _f : getItemSize(state, id, i, data[i], useAverageSize);
1434
- if (__DEV__ && needsIndexByKey) {
1826
+ if (shouldOptimize && breakAt !== void 0 && i > breakAt) {
1827
+ didBreakEarly = true;
1828
+ break;
1829
+ }
1830
+ if (shouldOptimize && breakAt === void 0 && !scrollingTo && !dataChanged && currentRowTop > maxVisibleArea) {
1831
+ const itemsPerRow = hasColumns ? numColumns : 1;
1832
+ breakAt = i + itemsPerRow + 10;
1833
+ }
1834
+ const id = (_d = idCache[i]) != null ? _d : getId(state, i);
1835
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(ctx, state, id, i, data[i], useAverageSize, preferCachedSize);
1836
+ if (IS_DEV && needsIndexByKey) {
1435
1837
  if (indexByKeyForChecking.has(id)) {
1436
1838
  console.error(
1437
1839
  `[legend-list] Error: Detected overlapping key (${id}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
@@ -1458,7 +1860,9 @@ function updateAllPositions(ctx, state, dataChanged, startIndex = 0) {
1458
1860
  currentRowTop += size;
1459
1861
  }
1460
1862
  }
1461
- updateTotalSize(ctx, state);
1863
+ if (!didBreakEarly) {
1864
+ updateTotalSize(ctx, state);
1865
+ }
1462
1866
  if (snapToIndices) {
1463
1867
  updateSnapToOffsets(ctx, state);
1464
1868
  }
@@ -1478,6 +1882,21 @@ function ensureViewabilityState(ctx, configId) {
1478
1882
  }
1479
1883
  return state;
1480
1884
  }
1885
+ function setupViewability(props) {
1886
+ let { viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged } = props;
1887
+ if (viewabilityConfig || onViewableItemsChanged) {
1888
+ viewabilityConfigCallbackPairs = [
1889
+ ...viewabilityConfigCallbackPairs || [],
1890
+ {
1891
+ onViewableItemsChanged,
1892
+ viewabilityConfig: viewabilityConfig || {
1893
+ viewAreaCoveragePercentThreshold: 0
1894
+ }
1895
+ }
1896
+ ];
1897
+ }
1898
+ return viewabilityConfigCallbackPairs;
1899
+ }
1481
1900
  function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end) {
1482
1901
  const {
1483
1902
  timeouts,
@@ -1631,16 +2050,6 @@ function isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize,
1631
2050
  const value = ctx.mapViewabilityAmountValues.get(containerId) || computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
1632
2051
  return value.isViewable;
1633
2052
  }
1634
- function findContainerId(ctx, key) {
1635
- const numContainers = peek$(ctx, "numContainers");
1636
- for (let i = 0; i < numContainers; i++) {
1637
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1638
- if (itemKey === key) {
1639
- return i;
1640
- }
1641
- }
1642
- return -1;
1643
- }
1644
2053
  function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
1645
2054
  const key = containerId + configId;
1646
2055
  ctx.mapViewabilityValues.set(key, viewToken);
@@ -1649,9 +2058,12 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
1649
2058
  }
1650
2059
 
1651
2060
  // src/utils/checkAllSizesKnown.ts
2061
+ function isNullOrUndefined2(value) {
2062
+ return value === null || value === void 0;
2063
+ }
1652
2064
  function checkAllSizesKnown(state) {
1653
2065
  const { startBuffered, endBuffered, sizesKnown } = state;
1654
- if (endBuffered !== null && startBuffered >= 0 && endBuffered >= 0) {
2066
+ if (!isNullOrUndefined2(endBuffered) && !isNullOrUndefined2(startBuffered) && startBuffered >= 0 && endBuffered >= 0) {
1655
2067
  let areAllKnown = true;
1656
2068
  for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
1657
2069
  const key = getId(state, i);
@@ -1668,6 +2080,8 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1668
2080
  const { stickyContainerPool, containerItemTypes } = state;
1669
2081
  const result = [];
1670
2082
  const availableContainers = [];
2083
+ const pendingRemovalSet = new Set(pendingRemoval);
2084
+ let pendingRemovalChanged = false;
1671
2085
  const stickyIndicesSet = state.props.stickyIndicesSet;
1672
2086
  const stickyItemIndices = (needNewContainers == null ? void 0 : needNewContainers.filter((index) => stickyIndicesSet.has(index))) || [];
1673
2087
  const canReuseContainer = (containerIndex, requiredType) => {
@@ -1683,12 +2097,11 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1683
2097
  let foundContainer = false;
1684
2098
  for (const containerIndex of stickyContainerPool) {
1685
2099
  const key = peek$(ctx, `containerItemKey${containerIndex}`);
1686
- const isPendingRemoval = pendingRemoval.includes(containerIndex);
1687
- if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType)) {
2100
+ const isPendingRemoval = pendingRemovalSet.has(containerIndex);
2101
+ if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType) && !result.includes(containerIndex)) {
1688
2102
  result.push(containerIndex);
1689
- if (isPendingRemoval) {
1690
- const index = pendingRemoval.indexOf(containerIndex);
1691
- pendingRemoval.splice(index, 1);
2103
+ if (isPendingRemoval && pendingRemovalSet.delete(containerIndex)) {
2104
+ pendingRemovalChanged = true;
1692
2105
  }
1693
2106
  foundContainer = true;
1694
2107
  if (requiredItemTypes) typeIndex++;
@@ -1708,13 +2121,11 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1708
2121
  }
1709
2122
  const key = peek$(ctx, `containerItemKey${u}`);
1710
2123
  let isOk = key === void 0;
1711
- if (!isOk) {
1712
- const index = pendingRemoval.indexOf(u);
1713
- if (index !== -1) {
1714
- pendingRemoval.splice(index, 1);
1715
- const requiredType = neededTypes[typeIndex];
1716
- isOk = canReuseContainer(u, requiredType);
1717
- }
2124
+ if (!isOk && pendingRemovalSet.has(u)) {
2125
+ pendingRemovalSet.delete(u);
2126
+ pendingRemovalChanged = true;
2127
+ const requiredType = neededTypes[typeIndex];
2128
+ isOk = canReuseContainer(u, requiredType);
1718
2129
  }
1719
2130
  if (isOk) {
1720
2131
  result.push(u);
@@ -1757,7 +2168,7 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1757
2168
  for (let i = 0; i < stillNeeded; i++) {
1758
2169
  result.push(numContainers + i);
1759
2170
  }
1760
- if (__DEV__ && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
2171
+ if (IS_DEV && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
1761
2172
  console.warn(
1762
2173
  "[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.",
1763
2174
  {
@@ -1772,50 +2183,18 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1772
2183
  }
1773
2184
  }
1774
2185
  }
2186
+ if (pendingRemovalChanged) {
2187
+ pendingRemoval.length = 0;
2188
+ for (const value of pendingRemovalSet) {
2189
+ pendingRemoval.push(value);
2190
+ }
2191
+ }
1775
2192
  return result.sort(comparatorDefault);
1776
2193
  }
1777
2194
  function comparatorByDistance(a, b) {
1778
2195
  return b.distance - a.distance;
1779
2196
  }
1780
2197
 
1781
- // src/utils/getScrollVelocity.ts
1782
- var getScrollVelocity = (state) => {
1783
- const { scrollHistory } = state;
1784
- let velocity = 0;
1785
- if (scrollHistory.length >= 1) {
1786
- const newest = scrollHistory[scrollHistory.length - 1];
1787
- let oldest;
1788
- let start = 0;
1789
- const now = Date.now();
1790
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1791
- const entry = scrollHistory[i];
1792
- const nextEntry = scrollHistory[i + 1];
1793
- if (i > 0) {
1794
- const prevEntry = scrollHistory[i - 1];
1795
- const prevDirection = entry.scroll - prevEntry.scroll;
1796
- const currentDirection = nextEntry.scroll - entry.scroll;
1797
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1798
- start = i;
1799
- break;
1800
- }
1801
- }
1802
- }
1803
- for (let i = start; i < scrollHistory.length - 1; i++) {
1804
- const entry = scrollHistory[i];
1805
- if (now - entry.time <= 1e3) {
1806
- oldest = entry;
1807
- break;
1808
- }
1809
- }
1810
- if (oldest && oldest !== newest) {
1811
- const scrollDiff = newest.scroll - oldest.scroll;
1812
- const timeDiff = newest.time - oldest.time;
1813
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1814
- }
1815
- }
1816
- return velocity;
1817
- };
1818
-
1819
2198
  // src/core/scrollToIndex.ts
1820
2199
  function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
1821
2200
  if (index >= state.props.data.length) {
@@ -1828,72 +2207,16 @@ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, vie
1828
2207
  if (isLast && viewPosition === void 0) {
1829
2208
  viewPosition = 1;
1830
2209
  }
1831
- const firstIndexScrollPostion = firstIndexOffset - viewOffset;
1832
2210
  state.scrollForNextCalculateItemsInView = void 0;
1833
- scrollTo(state, {
2211
+ scrollTo(ctx, state, {
1834
2212
  animated,
1835
2213
  index,
1836
- offset: firstIndexScrollPostion,
2214
+ offset: firstIndexOffset,
1837
2215
  viewOffset,
1838
2216
  viewPosition: viewPosition != null ? viewPosition : 0
1839
2217
  });
1840
2218
  }
1841
2219
 
1842
- // src/utils/checkThreshold.ts
1843
- var checkThreshold = (distance, atThreshold, threshold, isReached, isBlockedByTimer, onReached, blockTimer) => {
1844
- const distanceAbs = Math.abs(distance);
1845
- const isAtThreshold = atThreshold || distanceAbs < threshold;
1846
- if (!isReached && !isBlockedByTimer) {
1847
- if (isAtThreshold) {
1848
- onReached == null ? void 0 : onReached(distance);
1849
- blockTimer == null ? void 0 : blockTimer(true);
1850
- setTimeout(() => {
1851
- blockTimer == null ? void 0 : blockTimer(false);
1852
- }, 700);
1853
- return true;
1854
- }
1855
- } else {
1856
- if (distance >= 1.3 * threshold) {
1857
- return false;
1858
- }
1859
- }
1860
- return isReached;
1861
- };
1862
-
1863
- // src/utils/checkAtBottom.ts
1864
- function checkAtBottom(ctx, state) {
1865
- if (!state) {
1866
- return;
1867
- }
1868
- const {
1869
- queuedInitialLayout,
1870
- scrollLength,
1871
- scroll,
1872
- maintainingScrollAtEnd,
1873
- props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
1874
- } = state;
1875
- const contentSize = getContentSize(ctx);
1876
- if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1877
- const distanceFromEnd = contentSize - scroll - scrollLength;
1878
- const isContentLess = contentSize < scrollLength;
1879
- state.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1880
- state.isEndReached = checkThreshold(
1881
- distanceFromEnd,
1882
- isContentLess,
1883
- onEndReachedThreshold * scrollLength,
1884
- state.isEndReached,
1885
- state.endReachedBlockedByTimer,
1886
- (distance) => {
1887
- var _a, _b;
1888
- return (_b = (_a = state.props).onEndReached) == null ? void 0 : _b.call(_a, { distanceFromEnd: distance });
1889
- },
1890
- (block) => {
1891
- state.endReachedBlockedByTimer = block;
1892
- }
1893
- );
1894
- }
1895
- }
1896
-
1897
2220
  // src/utils/setDidLayout.ts
1898
2221
  function setDidLayout(ctx, state) {
1899
2222
  const {
@@ -1916,11 +2239,12 @@ function setDidLayout(ctx, state) {
1916
2239
 
1917
2240
  // src/core/calculateItemsInView.ts
1918
2241
  function findCurrentStickyIndex(stickyArray, scroll, state) {
1919
- var _a;
2242
+ var _a3;
1920
2243
  const idCache = state.idCache;
1921
2244
  const positions = state.positions;
1922
2245
  for (let i = stickyArray.length - 1; i >= 0; i--) {
1923
- const stickyId = (_a = idCache.get(stickyArray[i])) != null ? _a : getId(state, stickyArray[i]);
2246
+ const stickyIndex = stickyArray[i];
2247
+ const stickyId = (_a3 = idCache[stickyIndex]) != null ? _a3 : getId(state, stickyIndex);
1924
2248
  const stickyPos = stickyId ? positions.get(stickyId) : void 0;
1925
2249
  if (stickyPos !== void 0 && scroll >= stickyPos) {
1926
2250
  return i;
@@ -1933,42 +2257,46 @@ function getActiveStickyIndices(ctx, state, stickyIndices) {
1933
2257
  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))
1934
2258
  );
1935
2259
  }
1936
- function handleStickyActivation(ctx, state, stickyIndices, stickyArray, scroll, needNewContainers, startBuffered, endBuffered) {
1937
- var _a;
2260
+ function handleStickyActivation(ctx, state, stickyIndices, stickyArray, currentStickyIdx, needNewContainers, startBuffered, endBuffered) {
2261
+ var _a3;
1938
2262
  const activeIndices = getActiveStickyIndices(ctx, state, stickyIndices);
1939
- const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
2263
+ state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
1940
2264
  for (let offset = 0; offset <= 1; offset++) {
1941
2265
  const idx = currentStickyIdx - offset;
1942
2266
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
1943
2267
  const stickyIndex = stickyArray[idx];
1944
- const stickyId = (_a = state.idCache.get(stickyIndex)) != null ? _a : getId(state, stickyIndex);
2268
+ const stickyId = (_a3 = state.idCache[stickyIndex]) != null ? _a3 : getId(state, stickyIndex);
1945
2269
  if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered)) {
1946
2270
  needNewContainers.push(stickyIndex);
1947
2271
  }
1948
2272
  }
1949
2273
  }
1950
- function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, pendingRemoval) {
1951
- var _a, _b, _c;
1952
- const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
2274
+ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, currentStickyIdx, pendingRemoval) {
2275
+ var _a3, _b, _c;
1953
2276
  for (const containerIndex of state.stickyContainerPool) {
1954
2277
  const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
1955
2278
  const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
1956
2279
  if (itemIndex === void 0) continue;
1957
2280
  const arrayIdx = stickyArray.indexOf(itemIndex);
1958
- if (arrayIdx === -1) continue;
2281
+ if (arrayIdx === -1) {
2282
+ state.stickyContainerPool.delete(containerIndex);
2283
+ set$(ctx, `containerSticky${containerIndex}`, false);
2284
+ set$(ctx, `containerStickyOffset${containerIndex}`, void 0);
2285
+ continue;
2286
+ }
1959
2287
  const isRecentSticky = arrayIdx >= currentStickyIdx - 1 && arrayIdx <= currentStickyIdx + 1;
1960
2288
  if (isRecentSticky) continue;
1961
2289
  const nextIndex = stickyArray[arrayIdx + 1];
1962
2290
  let shouldRecycle = false;
1963
2291
  if (nextIndex) {
1964
- const nextId = (_a = state.idCache.get(nextIndex)) != null ? _a : getId(state, nextIndex);
2292
+ const nextId = (_a3 = state.idCache[nextIndex]) != null ? _a3 : getId(state, nextIndex);
1965
2293
  const nextPos = nextId ? state.positions.get(nextId) : void 0;
1966
2294
  shouldRecycle = nextPos !== void 0 && scroll > nextPos + scrollBuffer * 2;
1967
2295
  } else {
1968
- const currentId = (_b = state.idCache.get(itemIndex)) != null ? _b : getId(state, itemIndex);
2296
+ const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
1969
2297
  if (currentId) {
1970
2298
  const currentPos = state.positions.get(currentId);
1971
- const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(state, currentId, itemIndex, state.props.data[itemIndex]);
2299
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, state, currentId, itemIndex, state.props.data[itemIndex]);
1972
2300
  shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
1973
2301
  }
1974
2302
  }
@@ -1979,21 +2307,22 @@ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, pe
1979
2307
  }
1980
2308
  function calculateItemsInView(ctx, state, params = {}) {
1981
2309
  reactDom.unstable_batchedUpdates(() => {
1982
- var _a, _b, _c, _d, _e, _f, _g, _h;
2310
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1983
2311
  const {
1984
2312
  columns,
1985
2313
  containerItemKeys,
1986
2314
  enableScrollForNextCalculateItemsInView,
1987
2315
  idCache,
1988
2316
  indexByKey,
2317
+ initialScroll,
1989
2318
  minIndexSizeChanged,
1990
2319
  positions,
2320
+ props: { getItemType, itemsAreEqual, keyExtractor, onStickyHeaderChange, scrollBuffer },
1991
2321
  scrollForNextCalculateItemsInView,
1992
2322
  scrollLength,
1993
2323
  sizes,
1994
2324
  startBufferedId: startBufferedIdOrig,
1995
- viewabilityConfigCallbackPairs,
1996
- props: { getItemType, initialScroll, itemsAreEqual, keyExtractor, scrollBuffer }
2325
+ viewabilityConfigCallbackPairs
1997
2326
  } = state;
1998
2327
  const { data } = state.props;
1999
2328
  const stickyIndicesArr = state.props.stickyIndicesArr || [];
@@ -2005,35 +2334,22 @@ function calculateItemsInView(ctx, state, params = {}) {
2005
2334
  const totalSize = peek$(ctx, "totalSize");
2006
2335
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
2007
2336
  const numColumns = peek$(ctx, "numColumns");
2008
- const previousScrollAdjust = 0;
2009
- const { dataChanged, doMVCP } = params;
2337
+ const { dataChanged, doMVCP, forceFullItemPositions } = params;
2010
2338
  const speed = getScrollVelocity(state);
2011
- if (doMVCP || dataChanged) {
2012
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2013
- if (dataChanged) {
2014
- indexByKey.clear();
2015
- idCache.clear();
2016
- positions.clear();
2017
- }
2018
- const startIndex = dataChanged ? 0 : minIndexSizeChanged != null ? minIndexSizeChanged : 0;
2019
- updateAllPositions(ctx, state, dataChanged, startIndex);
2020
- if (minIndexSizeChanged !== void 0) {
2021
- state.minIndexSizeChanged = void 0;
2022
- }
2023
- checkMVCP == null ? void 0 : checkMVCP();
2024
- }
2025
2339
  const scrollExtra = 0;
2026
2340
  const { queuedInitialLayout } = state;
2027
2341
  let { scroll: scrollState } = state;
2028
2342
  if (!queuedInitialLayout && initialScroll) {
2029
2343
  const updatedOffset = calculateOffsetWithOffsetPosition(
2344
+ ctx,
2030
2345
  state,
2031
2346
  calculateOffsetForIndex(ctx, state, initialScroll.index),
2032
2347
  initialScroll
2033
2348
  );
2034
2349
  scrollState = updatedOffset;
2035
2350
  }
2036
- const scrollAdjustPad = -previousScrollAdjust - topPad;
2351
+ const scrollAdjustPending = (_a3 = peek$(ctx, "scrollAdjustPending")) != null ? _a3 : 0;
2352
+ const scrollAdjustPad = scrollAdjustPending - topPad;
2037
2353
  let scroll = scrollState + scrollExtra + scrollAdjustPad;
2038
2354
  if (scroll + scrollLength > totalSize) {
2039
2355
  scroll = Math.max(0, totalSize - scrollLength);
@@ -2042,6 +2358,11 @@ function calculateItemsInView(ctx, state, params = {}) {
2042
2358
  set$(ctx, "debugRawScroll", scrollState);
2043
2359
  set$(ctx, "debugComputedScroll", scroll);
2044
2360
  }
2361
+ const previousStickyIndex = state.activeStickyIndex;
2362
+ const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
2363
+ const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : void 0;
2364
+ state.activeStickyIndex = nextActiveStickyIndex;
2365
+ set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
2045
2366
  let scrollBufferTop = scrollBuffer;
2046
2367
  let scrollBufferBottom = scrollBuffer;
2047
2368
  if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
@@ -2054,22 +2375,38 @@ function calculateItemsInView(ctx, state, params = {}) {
2054
2375
  const scrollTopBuffered = scroll - scrollBufferTop;
2055
2376
  const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
2056
2377
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
2057
- if (scrollForNextCalculateItemsInView) {
2378
+ if (!dataChanged && scrollForNextCalculateItemsInView) {
2058
2379
  const { top, bottom } = scrollForNextCalculateItemsInView;
2059
2380
  if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
2060
2381
  return;
2061
2382
  }
2062
2383
  }
2384
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
2385
+ if (dataChanged) {
2386
+ indexByKey.clear();
2387
+ idCache.length = 0;
2388
+ positions.clear();
2389
+ }
2390
+ const startIndex = dataChanged ? 0 : (_b = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _b : 0;
2391
+ updateItemPositions(ctx, state, dataChanged, {
2392
+ forceFullUpdate: !!forceFullItemPositions,
2393
+ scrollBottomBuffered,
2394
+ startIndex
2395
+ });
2396
+ if (minIndexSizeChanged !== void 0) {
2397
+ state.minIndexSizeChanged = void 0;
2398
+ }
2399
+ checkMVCP == null ? void 0 : checkMVCP();
2063
2400
  let startNoBuffer = null;
2064
2401
  let startBuffered = null;
2065
2402
  let startBufferedId = null;
2066
2403
  let endNoBuffer = null;
2067
2404
  let endBuffered = null;
2068
- let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
2405
+ let loopStart = !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
2069
2406
  for (let i = loopStart; i >= 0; i--) {
2070
- const id = (_a = idCache.get(i)) != null ? _a : getId(state, i);
2407
+ const id = (_c = idCache[i]) != null ? _c : getId(state, i);
2071
2408
  const top = positions.get(id);
2072
- const size = (_b = sizes.get(id)) != null ? _b : getItemSize(state, id, i, data[i]);
2409
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(ctx, state, id, i, data[i]);
2073
2410
  const bottom = top + size;
2074
2411
  if (bottom > scroll - scrollBuffer) {
2075
2412
  loopStart = i;
@@ -2095,8 +2432,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2095
2432
  let firstFullyOnScreenIndex;
2096
2433
  const dataLength = data.length;
2097
2434
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2098
- const id = (_c = idCache.get(i)) != null ? _c : getId(state, i);
2099
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(state, id, i, data[i]);
2435
+ const id = (_e = idCache[i]) != null ? _e : getId(state, i);
2436
+ const size = (_f = sizes.get(id)) != null ? _f : getItemSize(ctx, state, id, i, data[i]);
2100
2437
  const top = positions.get(id);
2101
2438
  if (!foundEnd) {
2102
2439
  if (startNoBuffer === null && top + size > scroll) {
@@ -2125,7 +2462,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2125
2462
  }
2126
2463
  const idsInView = [];
2127
2464
  for (let i = firstFullyOnScreenIndex; i <= endNoBuffer; i++) {
2128
- const id = (_e = idCache.get(i)) != null ? _e : getId(state, i);
2465
+ const id = (_g = idCache[i]) != null ? _g : getId(state, i);
2129
2466
  idsInView.push(id);
2130
2467
  }
2131
2468
  Object.assign(state, {
@@ -2157,7 +2494,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2157
2494
  let numContainers2 = prevNumContainers;
2158
2495
  const needNewContainers = [];
2159
2496
  for (let i = startBuffered; i <= endBuffered; i++) {
2160
- const id = (_f = idCache.get(i)) != null ? _f : getId(state, i);
2497
+ const id = (_h = idCache[i]) != null ? _h : getId(state, i);
2161
2498
  if (!containerItemKeys.has(id)) {
2162
2499
  needNewContainers.push(i);
2163
2500
  }
@@ -2168,11 +2505,14 @@ function calculateItemsInView(ctx, state, params = {}) {
2168
2505
  state,
2169
2506
  stickyIndicesSet,
2170
2507
  stickyIndicesArr,
2171
- scroll,
2508
+ currentStickyIdx,
2172
2509
  needNewContainers,
2173
2510
  startBuffered,
2174
2511
  endBuffered
2175
2512
  );
2513
+ } else {
2514
+ state.activeStickyIndex = void 0;
2515
+ set$(ctx, "activeStickyIndex", void 0);
2176
2516
  }
2177
2517
  if (needNewContainers.length > 0) {
2178
2518
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
@@ -2192,7 +2532,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2192
2532
  for (let idx = 0; idx < needNewContainers.length; idx++) {
2193
2533
  const i = needNewContainers[idx];
2194
2534
  const containerIndex = availableContainers[idx];
2195
- const id = (_g = idCache.get(i)) != null ? _g : getId(state, i);
2535
+ const id = (_i = idCache[i]) != null ? _i : getId(state, i);
2196
2536
  const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
2197
2537
  if (oldKey && oldKey !== id) {
2198
2538
  containerItemKeys.delete(oldKey);
@@ -2206,9 +2546,10 @@ function calculateItemsInView(ctx, state, params = {}) {
2206
2546
  if (stickyIndicesSet.has(i)) {
2207
2547
  set$(ctx, `containerSticky${containerIndex}`, true);
2208
2548
  const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2209
- set$(ctx, `containerStickyOffset${containerIndex}`, createAnimatedValue(topPadding));
2549
+ set$(ctx, `containerStickyOffset${containerIndex}`, topPadding);
2210
2550
  state.stickyContainerPool.add(containerIndex);
2211
2551
  } else {
2552
+ set$(ctx, `containerSticky${containerIndex}`, false);
2212
2553
  state.stickyContainerPool.delete(containerIndex);
2213
2554
  }
2214
2555
  if (containerIndex >= numContainers2) {
@@ -2224,13 +2565,13 @@ function calculateItemsInView(ctx, state, params = {}) {
2224
2565
  }
2225
2566
  }
2226
2567
  if (stickyIndicesArr.length > 0) {
2227
- handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, pendingRemoval);
2568
+ handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, currentStickyIdx, pendingRemoval);
2228
2569
  }
2229
2570
  let didChangePositions = false;
2230
2571
  for (let i = 0; i < numContainers; i++) {
2231
2572
  const itemKey = peek$(ctx, `containerItemKey${i}`);
2232
2573
  if (pendingRemoval.includes(i)) {
2233
- if (itemKey) {
2574
+ if (itemKey !== void 0) {
2234
2575
  containerItemKeys.delete(itemKey);
2235
2576
  }
2236
2577
  state.containerItemTypes.delete(i);
@@ -2247,11 +2588,12 @@ function calculateItemsInView(ctx, state, params = {}) {
2247
2588
  const itemIndex = indexByKey.get(itemKey);
2248
2589
  const item = data[itemIndex];
2249
2590
  if (item !== void 0) {
2250
- const id = (_h = idCache.get(itemIndex)) != null ? _h : getId(state, itemIndex);
2251
- const position = positions.get(id);
2252
- if (position === void 0) {
2591
+ const id = (_j = idCache[itemIndex]) != null ? _j : getId(state, itemIndex);
2592
+ const positionValue = positions.get(id);
2593
+ if (positionValue === void 0) {
2253
2594
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2254
2595
  } else {
2596
+ const position = (positionValue || 0) - scrollAdjustPending;
2255
2597
  const column = columns.get(id) || 1;
2256
2598
  const prevPos = peek$(ctx, `containerPosition${i}`);
2257
2599
  const prevColumn = peek$(ctx, `containerColumn${i}`);
@@ -2264,7 +2606,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2264
2606
  set$(ctx, `containerColumn${i}`, column);
2265
2607
  }
2266
2608
  if (prevData !== item && (itemsAreEqual ? !itemsAreEqual(prevData, item, itemIndex, data) : true)) {
2267
- set$(ctx, `containerItemData${i}`, data[itemIndex]);
2609
+ set$(ctx, `containerItemData${i}`, item);
2268
2610
  }
2269
2611
  }
2270
2612
  }
@@ -2281,12 +2623,140 @@ function calculateItemsInView(ctx, state, params = {}) {
2281
2623
  if (viewabilityConfigCallbackPairs) {
2282
2624
  updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollLength, startNoBuffer, endNoBuffer);
2283
2625
  }
2284
- });
2626
+ if (onStickyHeaderChange && stickyIndicesArr.length > 0 && nextActiveStickyIndex !== void 0 && nextActiveStickyIndex !== previousStickyIndex) {
2627
+ const item = data[nextActiveStickyIndex];
2628
+ if (item !== void 0) {
2629
+ onStickyHeaderChange({ index: nextActiveStickyIndex, item });
2630
+ }
2631
+ }
2632
+ });
2633
+ }
2634
+
2635
+ // src/core/checkActualChange.ts
2636
+ function checkActualChange(state, dataProp, previousData) {
2637
+ if (!previousData || !dataProp || dataProp.length !== previousData.length) {
2638
+ return true;
2639
+ }
2640
+ const {
2641
+ idCache,
2642
+ props: { keyExtractor }
2643
+ } = state;
2644
+ for (let i = 0; i < dataProp.length; i++) {
2645
+ if (dataProp[i] !== previousData[i]) {
2646
+ return true;
2647
+ }
2648
+ if (keyExtractor ? idCache[i] !== keyExtractor(previousData[i], i) : dataProp[i] !== previousData[i]) {
2649
+ return true;
2650
+ }
2651
+ }
2652
+ return false;
2653
+ }
2654
+
2655
+ // src/core/doMaintainScrollAtEnd.ts
2656
+ function doMaintainScrollAtEnd(ctx, state, animated) {
2657
+ const {
2658
+ refScroller,
2659
+ props: { maintainScrollAtEnd }
2660
+ } = state;
2661
+ if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2662
+ const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2663
+ if (paddingTop > 0) {
2664
+ state.scroll = 0;
2665
+ }
2666
+ requestAnimationFrame(() => {
2667
+ var _a3;
2668
+ if (state == null ? void 0 : state.isAtEnd) {
2669
+ state.maintainingScrollAtEnd = true;
2670
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
2671
+ animated
2672
+ });
2673
+ setTimeout(
2674
+ () => {
2675
+ state.maintainingScrollAtEnd = false;
2676
+ },
2677
+ 0
2678
+ );
2679
+ }
2680
+ });
2681
+ return true;
2682
+ }
2683
+ }
2684
+
2685
+ // src/utils/updateAveragesOnDataChange.ts
2686
+ function updateAveragesOnDataChange(state, oldData, newData) {
2687
+ var _a3;
2688
+ const {
2689
+ averageSizes,
2690
+ sizesKnown,
2691
+ indexByKey,
2692
+ props: { itemsAreEqual, getItemType, keyExtractor }
2693
+ } = state;
2694
+ if (!itemsAreEqual || !oldData.length || !newData.length) {
2695
+ for (const key in averageSizes) {
2696
+ delete averageSizes[key];
2697
+ }
2698
+ return;
2699
+ }
2700
+ const itemTypesToPreserve = {};
2701
+ const newDataLength = newData.length;
2702
+ const oldDataLength = oldData.length;
2703
+ for (let newIndex = 0; newIndex < newDataLength; newIndex++) {
2704
+ const newItem = newData[newIndex];
2705
+ const id = keyExtractor ? keyExtractor(newItem, newIndex) : String(newIndex);
2706
+ const oldIndex = indexByKey.get(id);
2707
+ if (oldIndex !== void 0 && oldIndex < oldDataLength) {
2708
+ const knownSize = sizesKnown.get(id);
2709
+ if (knownSize === void 0) continue;
2710
+ const oldItem = oldData[oldIndex];
2711
+ const areEqual = itemsAreEqual(oldItem, newItem, newIndex, newData);
2712
+ if (areEqual) {
2713
+ const itemType = getItemType ? (_a3 = getItemType(newItem, newIndex)) != null ? _a3 : "" : "";
2714
+ let typeData = itemTypesToPreserve[itemType];
2715
+ if (!typeData) {
2716
+ typeData = itemTypesToPreserve[itemType] = { count: 0, totalSize: 0 };
2717
+ }
2718
+ typeData.totalSize += knownSize;
2719
+ typeData.count++;
2720
+ }
2721
+ }
2722
+ }
2723
+ for (const key in averageSizes) {
2724
+ delete averageSizes[key];
2725
+ }
2726
+ for (const itemType in itemTypesToPreserve) {
2727
+ const { totalSize, count } = itemTypesToPreserve[itemType];
2728
+ if (count > 0) {
2729
+ averageSizes[itemType] = {
2730
+ avg: totalSize / count,
2731
+ num: count
2732
+ };
2733
+ }
2734
+ }
2735
+ }
2736
+
2737
+ // src/core/checkResetContainers.ts
2738
+ function checkResetContainers(ctx, state, dataProp) {
2739
+ const { previousData } = state;
2740
+ if (previousData) {
2741
+ updateAveragesOnDataChange(state, previousData, dataProp);
2742
+ }
2743
+ const { maintainScrollAtEnd } = state.props;
2744
+ calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2745
+ const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
2746
+ const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state, false);
2747
+ if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
2748
+ state.isEndReached = false;
2749
+ }
2750
+ if (!didMaintainScrollAtEnd) {
2751
+ checkAtTop(state);
2752
+ checkAtBottom(ctx, state);
2753
+ }
2754
+ delete state.previousData;
2285
2755
  }
2286
2756
 
2287
2757
  // src/core/doInitialAllocateContainers.ts
2288
2758
  function doInitialAllocateContainers(ctx, state) {
2289
- var _a;
2759
+ var _a3, _b, _c;
2290
2760
  const {
2291
2761
  scrollLength,
2292
2762
  props: {
@@ -2302,12 +2772,13 @@ function doInitialAllocateContainers(ctx, state) {
2302
2772
  const hasContainers = peek$(ctx, "numContainers");
2303
2773
  if (scrollLength > 0 && data.length > 0 && !hasContainers) {
2304
2774
  let averageItemSize;
2305
- const fn = getFixedItemSize || getEstimatedItemSize;
2306
- if (fn) {
2775
+ if (getFixedItemSize || getEstimatedItemSize) {
2307
2776
  let totalSize = 0;
2308
2777
  const num = Math.min(20, data.length);
2309
2778
  for (let i = 0; i < num; i++) {
2310
- totalSize += fn(0, data[0], getItemType ? (_a = getItemType(data[0], 0)) != null ? _a : "" : "");
2779
+ const item = data[i];
2780
+ const itemType = getItemType ? (_a3 = getItemType(item, i)) != null ? _a3 : "" : "";
2781
+ totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(i, item, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(i, item, itemType)) != null ? _c : estimatedItemSize;
2311
2782
  }
2312
2783
  averageItemSize = totalSize / num;
2313
2784
  } else {
@@ -2321,76 +2792,18 @@ function doInitialAllocateContainers(ctx, state) {
2321
2792
  set$(ctx, "numContainers", numContainers);
2322
2793
  set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
2323
2794
  if (state.lastLayout) {
2324
- if (state.props.initialScroll) {
2795
+ if (state.initialScroll) {
2325
2796
  requestAnimationFrame(() => {
2326
- calculateItemsInView(ctx, state, { dataChanged: true });
2797
+ calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2327
2798
  });
2328
2799
  } else {
2329
- calculateItemsInView(ctx, state, { dataChanged: true });
2800
+ calculateItemsInView(ctx, state, { dataChanged: true, doMVCP: true });
2330
2801
  }
2331
2802
  }
2332
2803
  return true;
2333
2804
  }
2334
2805
  }
2335
2806
 
2336
- // src/core/doMaintainScrollAtEnd.ts
2337
- function doMaintainScrollAtEnd(ctx, state, animated) {
2338
- const {
2339
- refScroller,
2340
- props: { maintainScrollAtEnd }
2341
- } = state;
2342
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
2343
- const paddingTop = peek$(ctx, "alignItemsPaddingTop");
2344
- if (paddingTop > 0) {
2345
- state.scroll = 0;
2346
- }
2347
- requestAnimationFrame(() => {
2348
- var _a;
2349
- if (state == null ? void 0 : state.isAtEnd) {
2350
- state.maintainingScrollAtEnd = true;
2351
- (_a = refScroller.current) == null ? void 0 : _a.scrollToEnd({
2352
- animated
2353
- });
2354
- setTimeout(
2355
- () => {
2356
- state.maintainingScrollAtEnd = false;
2357
- },
2358
- 0
2359
- );
2360
- }
2361
- });
2362
- return true;
2363
- }
2364
- }
2365
-
2366
- // src/utils/checkAtTop.ts
2367
- function checkAtTop(state) {
2368
- if (!state) {
2369
- return;
2370
- }
2371
- const {
2372
- scrollLength,
2373
- scroll,
2374
- props: { onStartReachedThreshold }
2375
- } = state;
2376
- const distanceFromTop = scroll;
2377
- state.isAtStart = distanceFromTop <= 0;
2378
- state.isStartReached = checkThreshold(
2379
- distanceFromTop,
2380
- false,
2381
- onStartReachedThreshold * scrollLength,
2382
- state.isStartReached,
2383
- state.startReachedBlockedByTimer,
2384
- (distance) => {
2385
- var _a, _b;
2386
- return (_b = (_a = state.props).onStartReached) == null ? void 0 : _b.call(_a, { distanceFromStart: distance });
2387
- },
2388
- (block) => {
2389
- state.startReachedBlockedByTimer = block;
2390
- }
2391
- );
2392
- }
2393
-
2394
2807
  // src/core/handleLayout.ts
2395
2808
  function handleLayout(ctx, state, layout, setCanRender) {
2396
2809
  const { maintainScrollAtEnd } = state.props;
@@ -2425,87 +2838,57 @@ function handleLayout(ctx, state, layout, setCanRender) {
2425
2838
  if (state) {
2426
2839
  state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
2427
2840
  }
2428
- if (__DEV__ && measuredLength === 0) {
2841
+ if (IS_DEV && measuredLength === 0) {
2429
2842
  warnDevOnce(
2430
2843
  "height0",
2431
2844
  `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.`
2432
2845
  );
2433
2846
  }
2434
- setCanRender(true);
2435
- }
2436
- }
2437
-
2438
- // src/core/onScroll.ts
2439
- function onScroll(ctx, state, event) {
2440
- var _a, _b, _c;
2441
- const {
2442
- scrollProcessingEnabled,
2443
- props: { onScroll: onScrollProp }
2444
- } = state;
2445
- if (scrollProcessingEnabled === false) {
2446
- return;
2447
- }
2448
- 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) {
2449
- return;
2450
- }
2451
- const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
2452
- const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
2453
- if (ignoreScrollFromMVCP && !state.scrollingTo) {
2454
- const { lt, gt } = ignoreScrollFromMVCP;
2455
- if (lt && newScroll < lt || gt && newScroll > gt) {
2456
- return;
2457
- }
2458
- }
2459
- state.scrollPending = newScroll;
2460
- {
2461
- if (!state.onScrollRafScheduled) {
2462
- state.onScrollRafScheduled = true;
2463
- requestAnimationFrame(() => {
2464
- state.onScrollRafScheduled = false;
2465
- updateScroll(ctx, state, newScroll);
2466
- });
2467
- }
2468
- }
2469
- onScrollProp == null ? void 0 : onScrollProp(event);
2470
- }
2471
- function updateScroll(ctx, state, newScroll) {
2472
- const scrollingTo = state.scrollingTo;
2473
- state.hasScrolled = true;
2474
- state.lastBatchingAction = Date.now();
2475
- const currentTime = Date.now();
2476
- if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
2477
- const adjust = state.scrollAdjustHandler.getAdjust();
2478
- state.scrollHistory.push({ scroll: newScroll - adjust, time: currentTime });
2479
- }
2480
- if (state.scrollHistory.length > 5) {
2481
- state.scrollHistory.shift();
2482
- }
2483
- state.scrollPrev = state.scroll;
2484
- state.scrollPrevTime = state.scrollTime;
2485
- state.scroll = newScroll;
2486
- state.scrollTime = currentTime;
2487
- if (Math.abs(state.scroll - state.scrollPrev) > 2) {
2488
- calculateItemsInView(ctx, state);
2489
- checkAtBottom(ctx, state);
2490
- checkAtTop(state);
2491
2847
  }
2848
+ setCanRender(true);
2492
2849
  }
2493
2850
 
2494
2851
  // src/core/ScrollAdjustHandler.ts
2495
2852
  var ScrollAdjustHandler = class {
2496
2853
  constructor(ctx) {
2497
2854
  this.appliedAdjust = 0;
2855
+ this.pendingAdjust = 0;
2498
2856
  this.mounted = false;
2499
2857
  this.context = ctx;
2858
+ {
2859
+ const commitPendingAdjust = () => {
2860
+ const state = this.context.internalState;
2861
+ const pending = this.pendingAdjust;
2862
+ if (pending !== 0) {
2863
+ this.pendingAdjust = 0;
2864
+ this.appliedAdjust += pending;
2865
+ state.scroll += pending;
2866
+ state.scrollForNextCalculateItemsInView = void 0;
2867
+ set$(this.context, "scrollAdjustPending", 0);
2868
+ set$(this.context, "scrollAdjust", this.appliedAdjust);
2869
+ calculateItemsInView(this.context, this.context.internalState);
2870
+ }
2871
+ };
2872
+ listen$(this.context, "scrollingTo", (value) => {
2873
+ if (value === void 0) {
2874
+ commitPendingAdjust();
2875
+ }
2876
+ });
2877
+ }
2500
2878
  }
2501
2879
  requestAdjust(add) {
2502
- const oldAdjustTop = peek$(this.context, "scrollAdjust") || 0;
2503
- this.appliedAdjust = add + oldAdjustTop;
2504
- const set = () => set$(this.context, "scrollAdjust", this.appliedAdjust);
2505
- if (this.mounted) {
2506
- set();
2880
+ const scrollingTo = peek$(this.context, "scrollingTo");
2881
+ if ((scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
2882
+ this.pendingAdjust += add;
2883
+ set$(this.context, "scrollAdjustPending", this.pendingAdjust);
2507
2884
  } else {
2508
- requestAnimationFrame(set);
2885
+ this.appliedAdjust += add;
2886
+ const setter = () => set$(this.context, "scrollAdjust", this.appliedAdjust);
2887
+ if (this.mounted) {
2888
+ setter();
2889
+ } else {
2890
+ requestAnimationFrame(setter);
2891
+ }
2509
2892
  }
2510
2893
  }
2511
2894
  setMounted() {
@@ -2518,14 +2901,13 @@ var ScrollAdjustHandler = class {
2518
2901
 
2519
2902
  // src/core/updateItemSize.ts
2520
2903
  function updateItemSize(ctx, state, itemKey, sizeObj) {
2521
- var _a, _b;
2904
+ var _a3;
2522
2905
  const {
2523
2906
  sizesKnown,
2524
2907
  props: {
2525
2908
  getFixedItemSize,
2526
2909
  getItemType,
2527
2910
  horizontal,
2528
- maintainVisibleContentPosition,
2529
2911
  suggestEstimatedItemSize,
2530
2912
  onItemSizeChanged,
2531
2913
  data,
@@ -2533,17 +2915,17 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2533
2915
  }
2534
2916
  } = state;
2535
2917
  if (!data) return;
2918
+ const index = state.indexByKey.get(itemKey);
2536
2919
  if (getFixedItemSize) {
2537
- const index2 = state.indexByKey.get(itemKey);
2538
- if (index2 === void 0) {
2920
+ if (index === void 0) {
2539
2921
  return;
2540
2922
  }
2541
- const itemData = state.props.data[index2];
2923
+ const itemData = state.props.data[index];
2542
2924
  if (itemData === void 0) {
2543
2925
  return;
2544
2926
  }
2545
- const type = getItemType ? (_a = getItemType(itemData, index2)) != null ? _a : "" : "";
2546
- const size2 = getFixedItemSize(index2, itemData, type);
2927
+ const type = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
2928
+ const size2 = getFixedItemSize(index, itemData, type);
2547
2929
  if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
2548
2930
  return;
2549
2931
  }
@@ -2553,15 +2935,11 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2553
2935
  let shouldMaintainScrollAtEnd = false;
2554
2936
  let minIndexSizeChanged;
2555
2937
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2556
- const index = state.indexByKey.get(itemKey);
2557
2938
  const prevSizeKnown = state.sizesKnown.get(itemKey);
2558
- const diff = updateOneItemSize(state, itemKey, sizeObj);
2559
- const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2939
+ const diff = updateOneItemSize(ctx, state, itemKey, sizeObj);
2940
+ const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
2560
2941
  if (diff !== 0) {
2561
2942
  minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
2562
- if (((_b = state.scrollingTo) == null ? void 0 : _b.viewPosition) && maintainVisibleContentPosition && index === state.scrollingTo.index && diff > 0) {
2563
- requestAdjust(ctx, state, diff * state.scrollingTo.viewPosition);
2564
- }
2565
2943
  const { startBuffered, endBuffered } = state;
2566
2944
  needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
2567
2945
  if (!needsRecalculate) {
@@ -2591,13 +2969,13 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2591
2969
  if (minIndexSizeChanged !== void 0) {
2592
2970
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
2593
2971
  }
2594
- if (__DEV__ && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
2972
+ if (IS_DEV && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
2595
2973
  if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
2596
2974
  state.timeoutSizeMessage = setTimeout(() => {
2597
- var _a2;
2975
+ var _a4;
2598
2976
  state.timeoutSizeMessage = void 0;
2599
2977
  const num = state.sizesKnown.size;
2600
- const avg = (_a2 = state.averageSizes[""]) == null ? void 0 : _a2.avg;
2978
+ const avg = (_a4 = state.averageSizes[""]) == null ? void 0 : _a4.avg;
2601
2979
  console.warn(
2602
2980
  `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
2603
2981
  );
@@ -2619,8 +2997,8 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2619
2997
  }
2620
2998
  }
2621
2999
  }
2622
- function updateOneItemSize(state, itemKey, sizeObj) {
2623
- var _a;
3000
+ function updateOneItemSize(ctx, state, itemKey, sizeObj) {
3001
+ var _a3;
2624
3002
  const {
2625
3003
  sizes,
2626
3004
  indexByKey,
@@ -2630,12 +3008,12 @@ function updateOneItemSize(state, itemKey, sizeObj) {
2630
3008
  } = state;
2631
3009
  if (!data) return 0;
2632
3010
  const index = indexByKey.get(itemKey);
2633
- const prevSize = getItemSize(state, itemKey, index, data);
3011
+ const prevSize = getItemSize(ctx, state, itemKey, index, data[index]);
2634
3012
  const rawSize = horizontal ? sizeObj.width : sizeObj.height;
2635
3013
  const size = Math.round(rawSize) ;
2636
3014
  sizesKnown.set(itemKey, size);
2637
3015
  if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
2638
- const itemType = getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : "";
3016
+ const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
2639
3017
  let averages = averageSizes[itemType];
2640
3018
  if (!averages) {
2641
3019
  averages = averageSizes[itemType] = { avg: 0, num: 0 };
@@ -2644,13 +3022,13 @@ function updateOneItemSize(state, itemKey, sizeObj) {
2644
3022
  averages.num++;
2645
3023
  }
2646
3024
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2647
- sizes.set(itemKey, size);
3025
+ setSize(ctx, state, itemKey, size);
2648
3026
  return size - prevSize;
2649
3027
  }
2650
3028
  return 0;
2651
3029
  }
2652
3030
  var useCombinedRef = (...refs) => {
2653
- const callback = React4.useCallback((element) => {
3031
+ const callback = React3.useCallback((element) => {
2654
3032
  for (const ref of refs) {
2655
3033
  if (!ref) {
2656
3034
  continue;
@@ -2666,24 +3044,12 @@ var useCombinedRef = (...refs) => {
2666
3044
  };
2667
3045
 
2668
3046
  // src/platform/RefreshControl.tsx
2669
- function RefreshControl(props) {
3047
+ function RefreshControl(_props) {
2670
3048
  return null;
2671
3049
  }
2672
3050
 
2673
- // src/platform/StyleSheet.tsx
2674
- function flattenStyles(styles) {
2675
- if (Array.isArray(styles)) {
2676
- return Object.assign({}, ...styles.filter(Boolean));
2677
- }
2678
- return styles;
2679
- }
2680
- var StyleSheet = {
2681
- create: (styles) => styles,
2682
- flatten: (style) => flattenStyles(style)
2683
- };
2684
-
2685
3051
  // src/platform/useStickyScrollHandler.ts
2686
- function useStickyScrollHandler(stickyIndices, horizontal, ctx, onScroll2) {
3052
+ function useStickyScrollHandler(_stickyIndices, _horizontal, _ctx, onScroll2) {
2687
3053
  return onScroll2;
2688
3054
  }
2689
3055
 
@@ -2701,8 +3067,93 @@ function createColumnWrapperStyle(contentContainerStyle) {
2701
3067
  };
2702
3068
  }
2703
3069
  }
3070
+
3071
+ // src/utils/createImperativeHandle.ts
3072
+ function createImperativeHandle(ctx, state) {
3073
+ const scrollIndexIntoView = (options) => {
3074
+ if (state) {
3075
+ const { index, ...rest } = options;
3076
+ const { startNoBuffer, endNoBuffer } = state;
3077
+ if (index < startNoBuffer || index > endNoBuffer) {
3078
+ const viewPosition = index < startNoBuffer ? 0 : 1;
3079
+ scrollToIndex(ctx, state, {
3080
+ ...rest,
3081
+ index,
3082
+ viewPosition
3083
+ });
3084
+ }
3085
+ }
3086
+ };
3087
+ const refScroller = state.refScroller;
3088
+ return {
3089
+ flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
3090
+ getNativeScrollRef: () => refScroller.current,
3091
+ getScrollableNode: () => refScroller.current.getScrollableNode(),
3092
+ getScrollResponder: () => refScroller.current.getScrollResponder(),
3093
+ getState: () => ({
3094
+ activeStickyIndex: state.activeStickyIndex,
3095
+ contentLength: state.totalSize,
3096
+ data: state.props.data,
3097
+ elementAtIndex: (index) => {
3098
+ var _a3;
3099
+ return (_a3 = ctx.viewRefs.get(findContainerId(ctx, getId(state, index)))) == null ? void 0 : _a3.current;
3100
+ },
3101
+ end: state.endNoBuffer,
3102
+ endBuffered: state.endBuffered,
3103
+ isAtEnd: state.isAtEnd,
3104
+ isAtStart: state.isAtStart,
3105
+ positionAtIndex: (index) => state.positions.get(getId(state, index)),
3106
+ positions: state.positions,
3107
+ scroll: state.scroll,
3108
+ scrollLength: state.scrollLength,
3109
+ sizeAtIndex: (index) => state.sizesKnown.get(getId(state, index)),
3110
+ sizes: state.sizesKnown,
3111
+ start: state.startNoBuffer,
3112
+ startBuffered: state.startBuffered
3113
+ }),
3114
+ scrollIndexIntoView,
3115
+ scrollItemIntoView: ({ item, ...props }) => {
3116
+ const data = state.props.data;
3117
+ const index = data.indexOf(item);
3118
+ if (index !== -1) {
3119
+ scrollIndexIntoView({ index, ...props });
3120
+ }
3121
+ },
3122
+ scrollToEnd: (options) => {
3123
+ const data = state.props.data;
3124
+ const stylePaddingBottom = state.props.stylePaddingBottom;
3125
+ const index = data.length - 1;
3126
+ if (index !== -1) {
3127
+ const paddingBottom = stylePaddingBottom || 0;
3128
+ const footerSize = peek$(ctx, "footerSize") || 0;
3129
+ scrollToIndex(ctx, state, {
3130
+ index,
3131
+ viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3132
+ viewPosition: 1,
3133
+ ...options
3134
+ });
3135
+ }
3136
+ },
3137
+ scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3138
+ scrollToItem: ({ item, ...props }) => {
3139
+ const data = state.props.data;
3140
+ const index = data.indexOf(item);
3141
+ if (index !== -1) {
3142
+ scrollToIndex(ctx, state, { index, ...props });
3143
+ }
3144
+ },
3145
+ scrollToOffset: (params) => scrollTo(ctx, state, params),
3146
+ setScrollProcessingEnabled: (enabled) => {
3147
+ state.scrollProcessingEnabled = enabled;
3148
+ },
3149
+ setVisibleContentAnchorOffset: (value) => {
3150
+ const val = isFunction(value) ? value(peek$(ctx, "scrollAdjustUserOffset") || 0) : value;
3151
+ set$(ctx, "scrollAdjustUserOffset", val);
3152
+ }
3153
+ };
3154
+ }
2704
3155
  function getRenderedItem(ctx, state, key) {
2705
- var _a;
3156
+ var _a3;
2706
3157
  if (!state) {
2707
3158
  return null;
2708
3159
  }
@@ -2715,29 +3166,31 @@ function getRenderedItem(ctx, state, key) {
2715
3166
  return null;
2716
3167
  }
2717
3168
  let renderedItem = null;
2718
- if (renderItem && data[index]) {
3169
+ const extraData = peek$(ctx, "extraData");
3170
+ const item = data[index];
3171
+ if (renderItem && !isNullOrUndefined(item)) {
2719
3172
  const itemProps = {
2720
3173
  data,
2721
- extraData: peek$(ctx, "extraData"),
3174
+ extraData,
2722
3175
  index,
2723
- item: data[index],
2724
- type: getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : ""
3176
+ item,
3177
+ type: getItemType ? (_a3 = getItemType(item, index)) != null ? _a3 : "" : ""
2725
3178
  };
2726
- renderedItem = isFunction(renderItem) ? renderItem(itemProps) : React4__namespace.default.createElement(renderItem, itemProps);
3179
+ renderedItem = isFunction(renderItem) ? renderItem(itemProps) : React3__namespace.default.createElement(renderItem, itemProps);
2727
3180
  }
2728
3181
  return { index, item: data[index], renderedItem };
2729
3182
  }
2730
3183
  function useThrottleDebounce(mode) {
2731
- const timeoutRef = React4.useRef(null);
2732
- const lastCallTimeRef = React4.useRef(0);
2733
- const lastArgsRef = React4.useRef(null);
3184
+ const timeoutRef = React3.useRef(null);
3185
+ const lastCallTimeRef = React3.useRef(0);
3186
+ const lastArgsRef = React3.useRef(null);
2734
3187
  const clearTimeoutRef = () => {
2735
3188
  if (timeoutRef.current) {
2736
3189
  clearTimeout(timeoutRef.current);
2737
3190
  timeoutRef.current = null;
2738
3191
  }
2739
3192
  };
2740
- const execute = React4.useCallback(
3193
+ const execute = React3.useCallback(
2741
3194
  (callback, delay, ...args) => {
2742
3195
  {
2743
3196
  const now = Date.now();
@@ -2773,58 +3226,6 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
2773
3226
  return (event) => throttle(originalHandler, scrollEventThrottle, { nativeEvent: event.nativeEvent });
2774
3227
  }
2775
3228
 
2776
- // src/utils/updateAveragesOnDataChange.ts
2777
- function updateAveragesOnDataChange(state, oldData, newData) {
2778
- var _a;
2779
- const {
2780
- averageSizes,
2781
- sizesKnown,
2782
- indexByKey,
2783
- props: { itemsAreEqual, getItemType, keyExtractor }
2784
- } = state;
2785
- if (!itemsAreEqual || !oldData.length || !newData.length) {
2786
- for (const key in averageSizes) {
2787
- delete averageSizes[key];
2788
- }
2789
- return;
2790
- }
2791
- const itemTypesToPreserve = {};
2792
- const newDataLength = newData.length;
2793
- const oldDataLength = oldData.length;
2794
- for (let newIndex = 0; newIndex < newDataLength; newIndex++) {
2795
- const newItem = newData[newIndex];
2796
- const id = keyExtractor ? keyExtractor(newItem, newIndex) : String(newIndex);
2797
- const oldIndex = indexByKey.get(id);
2798
- if (oldIndex !== void 0 && oldIndex < oldDataLength) {
2799
- const knownSize = sizesKnown.get(id);
2800
- if (knownSize === void 0) continue;
2801
- const oldItem = oldData[oldIndex];
2802
- const areEqual = itemsAreEqual(oldItem, newItem, newIndex, newData);
2803
- if (areEqual) {
2804
- const itemType = getItemType ? (_a = getItemType(newItem, newIndex)) != null ? _a : "" : "";
2805
- let typeData = itemTypesToPreserve[itemType];
2806
- if (!typeData) {
2807
- typeData = itemTypesToPreserve[itemType] = { count: 0, totalSize: 0 };
2808
- }
2809
- typeData.totalSize += knownSize;
2810
- typeData.count++;
2811
- }
2812
- }
2813
- }
2814
- for (const key in averageSizes) {
2815
- delete averageSizes[key];
2816
- }
2817
- for (const itemType in itemTypesToPreserve) {
2818
- const { totalSize, count } = itemTypesToPreserve[itemType];
2819
- if (count > 0) {
2820
- averageSizes[itemType] = {
2821
- avg: totalSize / count,
2822
- num: count
2823
- };
2824
- }
2825
- }
2826
- }
2827
-
2828
3229
  // src/components/LegendList.tsx
2829
3230
  var DEFAULT_DRAW_DISTANCE = 250;
2830
3231
  var DEFAULT_ITEM_SIZE = 100;
@@ -2834,22 +3235,24 @@ var LegendList = typedMemo(
2834
3235
  const isChildrenMode = children !== void 0 && dataProp === void 0;
2835
3236
  const processedProps = isChildrenMode ? {
2836
3237
  ...restProps,
2837
- data: (isArray(children) ? children : React4__namespace.Children.toArray(children)).flat(1),
3238
+ data: (isArray(children) ? children : React3__namespace.Children.toArray(children)).flat(1),
2838
3239
  renderItem: ({ item }) => item
2839
3240
  } : {
2840
3241
  ...restProps,
2841
3242
  data: dataProp || [],
2842
3243
  renderItem: renderItemProp
2843
3244
  };
2844
- return /* @__PURE__ */ React4__namespace.createElement(StateProvider, null, /* @__PURE__ */ React4__namespace.createElement(LegendListInner, { ...processedProps, ref: forwardedRef }));
3245
+ return /* @__PURE__ */ React3__namespace.createElement(StateProvider, null, /* @__PURE__ */ React3__namespace.createElement(LegendListInner, { ...processedProps, ref: forwardedRef }));
2845
3246
  })
2846
3247
  );
2847
3248
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
3249
+ var _a3;
2848
3250
  const {
2849
3251
  alignItemsAtEnd = false,
2850
3252
  columnWrapperStyle,
2851
3253
  contentContainerStyle: contentContainerStyleProp,
2852
3254
  data: dataProp = [],
3255
+ dataVersion,
2853
3256
  drawDistance = 250,
2854
3257
  enableAverages = true,
2855
3258
  estimatedItemSize: estimatedItemSizeProp,
@@ -2860,6 +3263,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2860
3263
  getItemType,
2861
3264
  horizontal,
2862
3265
  initialContainerPoolRatio = 2,
3266
+ initialScrollAtEnd = false,
2863
3267
  initialScrollIndex: initialScrollIndexProp,
2864
3268
  initialScrollOffset: initialScrollOffsetProp,
2865
3269
  itemsAreEqual,
@@ -2880,6 +3284,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2880
3284
  onScroll: onScrollProp,
2881
3285
  onStartReached,
2882
3286
  onStartReachedThreshold = 0.5,
3287
+ onStickyHeaderChange,
3288
+ onViewableItemsChanged,
2883
3289
  progressViewOffset,
2884
3290
  recycleItems = false,
2885
3291
  refreshControl,
@@ -2891,24 +3297,26 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2891
3297
  stickyIndices,
2892
3298
  style: styleProp,
2893
3299
  suggestEstimatedItemSize,
3300
+ viewabilityConfig,
3301
+ viewabilityConfigCallbackPairs,
2894
3302
  waitForInitialLayout = true,
2895
3303
  ...rest
2896
3304
  } = props;
2897
- const [renderNum, setRenderNum] = React4.useState(0);
2898
- const initialScroll = initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
2899
- const [canRender, setCanRender] = React4__namespace.useState(!IsNewArchitecture);
2900
3305
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
2901
3306
  const style = { ...StyleSheet.flatten(styleProp) };
2902
3307
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
2903
3308
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
3309
+ const [renderNum, setRenderNum] = React3.useState(0);
3310
+ 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;
3311
+ const [canRender, setCanRender] = React3__namespace.useState(!IsNewArchitecture);
2904
3312
  const ctx = useStateContext();
2905
3313
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
2906
- const refScroller = React4.useRef(null);
3314
+ const refScroller = React3.useRef(null);
2907
3315
  const combinedRef = useCombinedRef(refScroller, refScrollView);
2908
3316
  const estimatedItemSize = estimatedItemSizeProp != null ? estimatedItemSizeProp : DEFAULT_ITEM_SIZE;
2909
3317
  const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
2910
3318
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (_item, index) => index.toString();
2911
- const refState = React4.useRef();
3319
+ const refState = React3.useRef();
2912
3320
  if (!refState.current) {
2913
3321
  if (!ctx.internalState) {
2914
3322
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : { height: 0, width: 0 } )[horizontal ? "width" : "height"];
@@ -2918,18 +3326,22 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2918
3326
  columns: /* @__PURE__ */ new Map(),
2919
3327
  containerItemKeys: /* @__PURE__ */ new Set(),
2920
3328
  containerItemTypes: /* @__PURE__ */ new Map(),
3329
+ dataChangeNeedsScrollUpdate: false,
3330
+ didColumnsChange: false,
3331
+ didDataChange: false,
2921
3332
  enableScrollForNextCalculateItemsInView: true,
2922
3333
  endBuffered: -1,
2923
3334
  endNoBuffer: -1,
2924
- endReachedBlockedByTimer: false,
3335
+ endReachedSnapshot: void 0,
2925
3336
  firstFullyOnScreenIndex: -1,
2926
- idCache: /* @__PURE__ */ new Map(),
3337
+ idCache: [],
2927
3338
  idsInView: [],
2928
3339
  indexByKey: /* @__PURE__ */ new Map(),
2929
- initialScroll,
3340
+ initialScroll: initialScrollProp,
2930
3341
  isAtEnd: false,
2931
3342
  isAtStart: false,
2932
3343
  isEndReached: false,
3344
+ isFirst: true,
2933
3345
  isStartReached: false,
2934
3346
  lastBatchingAction: Date.now(),
2935
3347
  lastLayout: void 0,
@@ -2954,7 +3366,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2954
3366
  sizesKnown: /* @__PURE__ */ new Map(),
2955
3367
  startBuffered: -1,
2956
3368
  startNoBuffer: -1,
2957
- startReachedBlockedByTimer: false,
3369
+ startReachedSnapshot: void 0,
2958
3370
  stickyContainerPool: /* @__PURE__ */ new Set(),
2959
3371
  stickyContainers: /* @__PURE__ */ new Map(),
2960
3372
  timeoutSizeMessage: 0,
@@ -2962,21 +3374,27 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2962
3374
  totalSize: 0,
2963
3375
  viewabilityConfigCallbackPairs: void 0
2964
3376
  };
3377
+ const internalState = ctx.internalState;
3378
+ internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, internalState, params);
2965
3379
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
2966
3380
  set$(ctx, "extraData", extraData);
2967
3381
  }
2968
3382
  refState.current = ctx.internalState;
2969
3383
  }
2970
3384
  const state = refState.current;
2971
- const isFirst = !state.props.renderItem;
2972
- const didDataChange = state.props.data !== dataProp;
2973
- const throttleScrollFn = (
2974
- // @ts-expect-error TODO Fix this
2975
- scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp
2976
- );
3385
+ const isFirstLocal = state.isFirst;
3386
+ state.didColumnsChange = numColumnsProp !== state.props.numColumns;
3387
+ const didDataChangeLocal = state.props.dataVersion !== dataVersion || state.props.data !== dataProp && checkActualChange(state, dataProp, state.props.data);
3388
+ if (didDataChangeLocal) {
3389
+ state.dataChangeNeedsScrollUpdate = true;
3390
+ state.didDataChange = true;
3391
+ state.previousData = state.props.data;
3392
+ }
3393
+ const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
2977
3394
  state.props = {
2978
3395
  alignItemsAtEnd,
2979
3396
  data: dataProp,
3397
+ dataVersion,
2980
3398
  enableAverages,
2981
3399
  estimatedItemSize,
2982
3400
  getEstimatedItemSize,
@@ -2984,7 +3402,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2984
3402
  getItemType,
2985
3403
  horizontal: !!horizontal,
2986
3404
  initialContainerPoolRatio,
2987
- initialScroll,
2988
3405
  itemsAreEqual,
2989
3406
  keyExtractor,
2990
3407
  maintainScrollAtEnd,
@@ -2998,45 +3415,25 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2998
3415
  onScroll: throttleScrollFn,
2999
3416
  onStartReached,
3000
3417
  onStartReachedThreshold,
3418
+ onStickyHeaderChange,
3001
3419
  recycleItems: !!recycleItems,
3002
3420
  renderItem,
3003
3421
  scrollBuffer,
3004
3422
  snapToIndices,
3005
3423
  stickyIndicesArr: stickyIndices != null ? stickyIndices : [],
3006
- stickyIndicesSet: React4.useMemo(() => new Set(stickyIndices != null ? stickyIndices : []), [stickyIndices == null ? void 0 : stickyIndices.join(",")]),
3424
+ stickyIndicesSet: React3.useMemo(() => new Set(stickyIndices != null ? stickyIndices : []), [stickyIndices == null ? void 0 : stickyIndices.join(",")]),
3007
3425
  stylePaddingBottom: stylePaddingBottomState,
3008
3426
  stylePaddingTop: stylePaddingTopState,
3009
3427
  suggestEstimatedItemSize: !!suggestEstimatedItemSize
3010
3428
  };
3011
3429
  state.refScroller = refScroller;
3012
- const checkResetContainers = (isFirst2) => {
3013
- const state2 = refState.current;
3014
- if (state2) {
3015
- if (!isFirst2 && state2.props.data !== dataProp) {
3016
- updateAveragesOnDataChange(state2, state2.props.data, dataProp);
3017
- }
3018
- state2.props.data = dataProp;
3019
- if (!isFirst2) {
3020
- calculateItemsInView(ctx, state2, { dataChanged: true, doMVCP: true });
3021
- const shouldMaintainScrollAtEnd = maintainScrollAtEnd === true || maintainScrollAtEnd.onDataChange;
3022
- const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx, state2, false);
3023
- if (!didMaintainScrollAtEnd && dataProp.length > state2.props.data.length) {
3024
- state2.isEndReached = false;
3025
- }
3026
- if (!didMaintainScrollAtEnd) {
3027
- checkAtTop(state2);
3028
- checkAtBottom(ctx, state2);
3029
- }
3030
- }
3031
- }
3032
- };
3033
- const memoizedLastItemKeys = React4.useMemo(() => {
3430
+ const memoizedLastItemKeys = React3.useMemo(() => {
3034
3431
  if (!dataProp.length) return [];
3035
3432
  return Array.from(
3036
3433
  { length: Math.min(numColumnsProp, dataProp.length) },
3037
3434
  (_, i) => getId(state, dataProp.length - 1 - i)
3038
3435
  );
3039
- }, [dataProp, numColumnsProp]);
3436
+ }, [dataProp, dataVersion, numColumnsProp]);
3040
3437
  const initializeStateVars = () => {
3041
3438
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
3042
3439
  set$(ctx, "numColumns", numColumnsProp);
@@ -3051,37 +3448,52 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3051
3448
  requestAdjust(ctx, state, paddingDiff);
3052
3449
  }
3053
3450
  };
3054
- if (isFirst) {
3451
+ if (isFirstLocal) {
3055
3452
  initializeStateVars();
3056
- updateAllPositions(ctx, state);
3453
+ updateItemPositions(
3454
+ ctx,
3455
+ state,
3456
+ /*dataChanged*/
3457
+ true
3458
+ );
3057
3459
  }
3058
- const initialContentOffset = React4.useMemo(() => {
3059
- if (initialScroll) {
3060
- const { index, viewOffset } = initialScroll;
3061
- let initialContentOffset2 = viewOffset || 0;
3062
- if (index !== void 0) {
3063
- initialContentOffset2 += calculateOffsetForIndex(ctx, state, index);
3064
- }
3065
- refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
3066
- if (initialContentOffset2 > 0) {
3067
- scrollTo(state, { animated: false, index, offset: initialContentOffset2 });
3068
- }
3069
- return initialContentOffset2;
3070
- }
3071
- return 0;
3072
- }, [renderNum]);
3073
- if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
3074
- state.lastBatchingAction = Date.now();
3075
- if (!keyExtractorProp && !isFirst && didDataChange) {
3076
- __DEV__ && warnDevOnce(
3460
+ const initialContentOffset = React3.useMemo(() => {
3461
+ const { initialScroll } = refState.current;
3462
+ if (!initialScroll) {
3463
+ return 0;
3464
+ }
3465
+ if (initialScroll.contentOffset !== void 0) {
3466
+ return initialScroll.contentOffset;
3467
+ }
3468
+ const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, state, initialScroll.index) : 0;
3469
+ const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, state, baseOffset, initialScroll);
3470
+ let clampedOffset = resolvedOffset;
3471
+ if (Number.isFinite(state.scrollLength) && Number.isFinite(state.totalSize)) {
3472
+ const maxOffset = Math.max(0, state.totalSize - state.scrollLength);
3473
+ clampedOffset = Math.min(clampedOffset, maxOffset);
3474
+ }
3475
+ clampedOffset = Math.max(0, clampedOffset);
3476
+ const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
3477
+ refState.current.initialScroll = updatedInitialScroll;
3478
+ state.initialScroll = updatedInitialScroll;
3479
+ refState.current.isStartReached = clampedOffset < refState.current.scrollLength * onStartReachedThreshold;
3480
+ return clampedOffset;
3481
+ }, [renderNum, state.initialScroll]);
3482
+ if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
3483
+ refState.current.lastBatchingAction = Date.now();
3484
+ if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
3485
+ IS_DEV && warnDevOnce(
3077
3486
  "keyExtractor",
3078
3487
  "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."
3079
3488
  );
3080
- state.sizes.clear();
3081
- state.positions.clear();
3489
+ refState.current.sizes.clear();
3490
+ refState.current.positions.clear();
3491
+ refState.current.totalSize = 0;
3492
+ set$(ctx, "totalSize", 0);
3082
3493
  }
3083
3494
  }
3084
- const onLayoutHeader = React4.useCallback((rect, fromLayoutEffect) => {
3495
+ const onLayoutHeader = React3.useCallback((rect, fromLayoutEffect) => {
3496
+ const { initialScroll } = refState.current;
3085
3497
  const size = rect[horizontal ? "width" : "height"];
3086
3498
  set$(ctx, "headerSize", size);
3087
3499
  if ((initialScroll == null ? void 0 : initialScroll.index) !== void 0) {
@@ -3092,134 +3504,72 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3092
3504
  }
3093
3505
  }
3094
3506
  }, []);
3095
- React4.useLayoutEffect(() => {
3507
+ const doInitialScroll = React3.useCallback(() => {
3508
+ var _a4;
3509
+ const initialScroll = state.initialScroll;
3510
+ if (initialScroll) {
3511
+ scrollTo(ctx, state, {
3512
+ animated: false,
3513
+ index: (_a4 = state.initialScroll) == null ? void 0 : _a4.index,
3514
+ offset: initialContentOffset,
3515
+ precomputedWithViewOffset: true
3516
+ });
3517
+ }
3518
+ }, [initialContentOffset, state.initialScroll]);
3519
+ const onLayoutChange = React3.useCallback((layout) => {
3520
+ doInitialScroll();
3521
+ handleLayout(ctx, state, layout, setCanRender);
3522
+ }, []);
3523
+ const { onLayout } = useOnLayoutSync({
3524
+ onLayoutChange,
3525
+ onLayoutProp,
3526
+ ref: refScroller
3527
+ // the type of ScrollView doesn't include measure?
3528
+ });
3529
+ React3.useLayoutEffect(() => {
3096
3530
  if (snapToIndices) {
3097
3531
  updateSnapToOffsets(ctx, state);
3098
3532
  }
3099
3533
  }, [snapToIndices]);
3100
- React4.useLayoutEffect(() => {
3101
- const didAllocateContainers = dataProp.length > 0 && doInitialAllocateContainersCallback();
3102
- if (!didAllocateContainers) {
3103
- checkResetContainers(
3104
- /*isFirst*/
3105
- isFirst
3106
- );
3107
- }
3108
- }, [dataProp, numColumnsProp]);
3109
- React4.useLayoutEffect(() => {
3534
+ React3.useLayoutEffect(() => {
3535
+ const {
3536
+ didColumnsChange,
3537
+ didDataChange,
3538
+ isFirst,
3539
+ props: { data }
3540
+ } = state;
3541
+ const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx, state);
3542
+ if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
3543
+ checkResetContainers(ctx, state, data);
3544
+ }
3545
+ state.didColumnsChange = false;
3546
+ state.didDataChange = false;
3547
+ state.isFirst = false;
3548
+ }, [dataProp, dataVersion, numColumnsProp]);
3549
+ React3.useLayoutEffect(() => {
3110
3550
  set$(ctx, "extraData", extraData);
3111
3551
  }, [extraData]);
3112
- const { onLayout } = useSyncLayout({
3113
- onLayout: onLayoutProp,
3114
- onLayoutChange: React4.useCallback(
3115
- (rectangle) => {
3116
- handleLayout(ctx, state, rectangle, setCanRender);
3117
- },
3118
- [ctx, state, setCanRender]
3119
- ),
3120
- ref: refScroller
3121
- });
3122
- React4.useLayoutEffect(initializeStateVars, [
3552
+ React3.useLayoutEffect(initializeStateVars, [
3553
+ dataVersion,
3123
3554
  memoizedLastItemKeys.join(","),
3124
3555
  numColumnsProp,
3125
- stylePaddingTopState,
3126
- stylePaddingBottomState
3556
+ stylePaddingBottomState,
3557
+ stylePaddingTopState
3127
3558
  ]);
3128
- const doInitialAllocateContainersCallback = () => {
3129
- return doInitialAllocateContainers(ctx, state);
3130
- };
3131
- React4.useImperativeHandle(forwardedRef, () => {
3132
- const scrollIndexIntoView = (options) => {
3133
- const state2 = refState.current;
3134
- if (state2) {
3135
- const { index, ...rest2 } = options;
3136
- const { startNoBuffer, endNoBuffer } = state2;
3137
- if (index < startNoBuffer || index > endNoBuffer) {
3138
- const viewPosition = index < startNoBuffer ? 0 : 1;
3139
- scrollToIndex(ctx, state2, {
3140
- ...rest2,
3141
- index,
3142
- viewPosition
3143
- });
3144
- }
3145
- }
3146
- };
3147
- return {
3148
- flashScrollIndicators: () => {
3149
- var _a, _b;
3150
- return (_b = (_a = refScroller.current) == null ? void 0 : _a.flashScrollIndicators) == null ? void 0 : _b.call(_a);
3151
- },
3152
- getNativeScrollRef: () => refScroller.current,
3153
- getScrollableNode: () => refScroller.current,
3154
- getScrollResponder: () => refScroller.current,
3155
- getState: () => {
3156
- const state2 = refState.current;
3157
- return state2 ? {
3158
- contentLength: state2.totalSize,
3159
- data: state2.props.data,
3160
- end: state2.endNoBuffer,
3161
- endBuffered: state2.endBuffered,
3162
- isAtEnd: state2.isAtEnd,
3163
- isAtStart: state2.isAtStart,
3164
- positionAtIndex: (index) => state2.positions.get(getId(state2, index)),
3165
- positions: state2.positions,
3166
- scroll: state2.scroll,
3167
- scrollLength: state2.scrollLength,
3168
- sizeAtIndex: (index) => state2.sizesKnown.get(getId(state2, index)),
3169
- sizes: state2.sizesKnown,
3170
- start: state2.startNoBuffer,
3171
- startBuffered: state2.startBuffered
3172
- } : {};
3173
- },
3174
- scrollIndexIntoView,
3175
- scrollItemIntoView: ({ item, ...props2 }) => {
3176
- const data = refState.current.props.data;
3177
- const index = data.indexOf(item);
3178
- if (index !== -1) {
3179
- scrollIndexIntoView({ index, ...props2 });
3180
- }
3181
- },
3182
- scrollToEnd: (options) => {
3183
- const data = refState.current.props.data;
3184
- const stylePaddingBottom = refState.current.props.stylePaddingBottom;
3185
- const index = data.length - 1;
3186
- if (index !== -1) {
3187
- const paddingBottom = stylePaddingBottom || 0;
3188
- const footerSize = peek$(ctx, "footerSize") || 0;
3189
- scrollToIndex(ctx, state, {
3190
- index,
3191
- viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
3192
- viewPosition: 1,
3193
- ...options
3194
- });
3195
- }
3196
- },
3197
- scrollToIndex: (params) => scrollToIndex(ctx, state, params),
3198
- scrollToItem: ({ item, ...props2 }) => {
3199
- const data = refState.current.props.data;
3200
- const index = data.indexOf(item);
3201
- if (index !== -1) {
3202
- scrollToIndex(ctx, state, { index, ...props2 });
3203
- }
3204
- },
3205
- scrollToOffset: (params) => scrollTo(state, params),
3206
- setScrollProcessingEnabled: (enabled) => {
3207
- refState.current.scrollProcessingEnabled = enabled;
3208
- },
3209
- setVisibleContentAnchorOffset: (value) => {
3210
- const val = typeof value === "function" ? value(peek$(ctx, "scrollAdjustUserOffset") || 0) : value;
3211
- set$(ctx, "scrollAdjustUserOffset", val);
3212
- }
3213
- };
3214
- }, []);
3559
+ React3.useEffect(() => {
3560
+ const viewability = setupViewability({
3561
+ onViewableItemsChanged,
3562
+ viewabilityConfig,
3563
+ viewabilityConfigCallbackPairs
3564
+ });
3565
+ state.viewabilityConfigCallbackPairs = viewability;
3566
+ state.enableScrollForNextCalculateItemsInView = !viewability;
3567
+ }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
3568
+ React3.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx, state), []);
3215
3569
  {
3216
- React4.useEffect(() => {
3217
- if (initialContentOffset) {
3218
- scrollTo(state, { animated: false, offset: initialContentOffset });
3219
- }
3220
- }, []);
3570
+ React3.useEffect(doInitialScroll, []);
3221
3571
  }
3222
- const fns = React4.useMemo(
3572
+ const fns = React3.useMemo(
3223
3573
  () => ({
3224
3574
  getRenderedItem: (key) => getRenderedItem(ctx, state, key),
3225
3575
  onScroll: (event) => onScroll(ctx, state, event),
@@ -3228,7 +3578,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3228
3578
  []
3229
3579
  );
3230
3580
  const onScrollHandler = useStickyScrollHandler(stickyIndices, horizontal, ctx, fns.onScroll);
3231
- return /* @__PURE__ */ React4__namespace.createElement(React4__namespace.Fragment, null, /* @__PURE__ */ React4__namespace.createElement(
3581
+ return /* @__PURE__ */ React3__namespace.createElement(React3__namespace.Fragment, null, /* @__PURE__ */ React3__namespace.createElement(
3232
3582
  ListComponent,
3233
3583
  {
3234
3584
  ...rest,
@@ -3246,7 +3596,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3246
3596
  onMomentumScrollEnd: (event) => {
3247
3597
  {
3248
3598
  requestAnimationFrame(() => {
3249
- finishScrollTo(refState.current);
3599
+ finishScrollTo(ctx, refState.current);
3250
3600
  });
3251
3601
  }
3252
3602
  if (onMomentumScrollEnd) {
@@ -3255,9 +3605,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3255
3605
  },
3256
3606
  onScroll: onScrollHandler,
3257
3607
  recycleItems,
3258
- refreshControl: refreshControl ? stylePaddingTopState > 0 ? React4__namespace.cloneElement(refreshControl, {
3608
+ refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3__namespace.cloneElement(refreshControl, {
3259
3609
  progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
3260
- }) : refreshControl : onRefresh && /* @__PURE__ */ React4__namespace.createElement(
3610
+ }) : refreshControl : onRefresh && /* @__PURE__ */ React3__namespace.createElement(
3261
3611
  RefreshControl,
3262
3612
  {
3263
3613
  onRefresh,
@@ -3266,14 +3616,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3266
3616
  }
3267
3617
  ),
3268
3618
  refScrollView: combinedRef,
3269
- scrollAdjustHandler: state.scrollAdjustHandler,
3619
+ scrollAdjustHandler: (_a3 = refState.current) == null ? void 0 : _a3.scrollAdjustHandler,
3620
+ scrollEventThrottle: 16 ,
3270
3621
  snapToIndices,
3271
3622
  stickyIndices,
3272
3623
  style,
3273
3624
  updateItemSize: fns.updateItemSize,
3274
3625
  waitForInitialLayout
3275
3626
  }
3276
- ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React4__namespace.createElement(DebugView, { state: refState.current }));
3627
+ ), IS_DEV && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React3__namespace.createElement(DebugView, { state: refState.current }));
3277
3628
  });
3278
3629
 
3279
3630
  exports.LegendList = LegendList;
@@ -3281,6 +3632,6 @@ exports.useIsLastItem = useIsLastItem;
3281
3632
  exports.useListScrollSize = useListScrollSize;
3282
3633
  exports.useRecyclingEffect = useRecyclingEffect;
3283
3634
  exports.useRecyclingState = useRecyclingState;
3284
- exports.useSyncLayout = useSyncLayout2;
3635
+ exports.useSyncLayout = useSyncLayout;
3285
3636
  exports.useViewability = useViewability;
3286
3637
  exports.useViewabilityAmount = useViewabilityAmount;