@legendapp/list 2.0.0-next.9 → 2.1.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var React3 = require('react');
4
- var reactNative = require('react-native');
3
+ var React4 = require('react');
5
4
  var shim = require('use-sync-external-store/shim');
5
+ var reactDom = require('react-dom');
6
6
 
7
7
  function _interopNamespace(e) {
8
8
  if (e && e.__esModule) return e;
@@ -22,17 +22,32 @@ function _interopNamespace(e) {
22
22
  return Object.freeze(n);
23
23
  }
24
24
 
25
- var React3__namespace = /*#__PURE__*/_interopNamespace(React3);
25
+ var React4__namespace = /*#__PURE__*/_interopNamespace(React4);
26
26
 
27
- // src/components/LazyLegendList.tsx
28
- var ContextState = React3__namespace.createContext(null);
27
+ // src/components/LegendList.tsx
28
+ var AnimatedView = React4.forwardRef(function AnimatedView2(props, ref) {
29
+ return /* @__PURE__ */ React4__namespace.createElement("div", { ref, ...props });
30
+ });
31
+ var View = React4.forwardRef(function View2(props, ref) {
32
+ return /* @__PURE__ */ React4__namespace.createElement("div", { ref, ...props });
33
+ });
34
+ var Text = View;
35
+
36
+ // src/platform/Animated.tsx
37
+ var createAnimatedValue = (value) => value;
38
+
39
+ // src/state/state.tsx
40
+ var ContextState = React4__namespace.createContext(null);
29
41
  function StateProvider({ children }) {
30
- const [value] = React3__namespace.useState(() => ({
42
+ const [value] = React4__namespace.useState(() => ({
43
+ animatedScrollY: createAnimatedValue(0),
31
44
  columnWrapperStyle: void 0,
45
+ internalState: void 0,
32
46
  listeners: /* @__PURE__ */ new Map(),
33
47
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
34
48
  mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
35
49
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
50
+ mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
36
51
  mapViewabilityValues: /* @__PURE__ */ new Map(),
37
52
  values: /* @__PURE__ */ new Map([
38
53
  ["alignItemsPaddingTop", 0],
@@ -43,10 +58,10 @@ function StateProvider({ children }) {
43
58
  ]),
44
59
  viewRefs: /* @__PURE__ */ new Map()
45
60
  }));
46
- return /* @__PURE__ */ React3__namespace.createElement(ContextState.Provider, { value }, children);
61
+ return /* @__PURE__ */ React4__namespace.createElement(ContextState.Provider, { value }, children);
47
62
  }
48
63
  function useStateContext() {
49
- return React3__namespace.useContext(ContextState);
64
+ return React4__namespace.useContext(ContextState);
50
65
  }
51
66
  function createSelectorFunctionsArr(ctx, signalNames) {
52
67
  let lastValues = [];
@@ -116,23 +131,23 @@ function getContentSize(ctx) {
116
131
  return headerSize + footerSize + totalSize + stylePaddingTop;
117
132
  }
118
133
  function useArr$(signalNames) {
119
- const ctx = React3__namespace.useContext(ContextState);
120
- const { subscribe, get } = React3__namespace.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
134
+ const ctx = React4__namespace.useContext(ContextState);
135
+ const { subscribe, get } = React4__namespace.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
121
136
  const value = shim.useSyncExternalStore(subscribe, get);
122
137
  return value;
123
138
  }
124
139
  function useSelector$(signalName, selector) {
125
- const ctx = React3__namespace.useContext(ContextState);
126
- const { subscribe, get } = React3__namespace.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
140
+ const ctx = React4__namespace.useContext(ContextState);
141
+ const { subscribe, get } = React4__namespace.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
127
142
  const value = shim.useSyncExternalStore(subscribe, () => selector(get()[0]));
128
143
  return value;
129
144
  }
130
145
 
131
146
  // src/components/DebugView.tsx
132
147
  var DebugRow = ({ children }) => {
133
- return /* @__PURE__ */ React3__namespace.createElement(reactNative.View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
148
+ return /* @__PURE__ */ React4__namespace.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
134
149
  };
135
- var DebugView = React3__namespace.memo(function DebugView2({ state }) {
150
+ var DebugView = React4__namespace.memo(function DebugView2({ state }) {
136
151
  const ctx = useStateContext();
137
152
  const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, _numContainers = 0, _numContainersPooled = 0] = useArr$([
138
153
  "totalSize",
@@ -143,12 +158,12 @@ var DebugView = React3__namespace.memo(function DebugView2({ state }) {
143
158
  "numContainersPooled"
144
159
  ]);
145
160
  const contentSize = getContentSize(ctx);
146
- const [, forceUpdate] = React3.useReducer((x) => x + 1, 0);
161
+ const [, forceUpdate] = React4.useReducer((x) => x + 1, 0);
147
162
  useInterval(() => {
148
163
  forceUpdate();
149
164
  }, 100);
150
- return /* @__PURE__ */ React3__namespace.createElement(
151
- reactNative.View,
165
+ return /* @__PURE__ */ React4__namespace.createElement(
166
+ View,
152
167
  {
153
168
  pointerEvents: "none",
154
169
  style: {
@@ -163,43 +178,158 @@ var DebugView = React3__namespace.memo(function DebugView2({ state }) {
163
178
  top: 0
164
179
  }
165
180
  },
166
- /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "TotalSize:"), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, totalSize.toFixed(2))),
167
- /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "ContentSize:"), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, contentSize.toFixed(2))),
168
- /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "At end:"), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, String(state.isAtEnd))),
169
- /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null),
170
- /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "ScrollAdjust:"), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, scrollAdjust.toFixed(2))),
171
- /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null),
172
- /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "RawScroll: "), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, rawScroll.toFixed(2))),
173
- /* @__PURE__ */ React3__namespace.createElement(DebugRow, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, "ComputedScroll: "), /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, null, scroll.toFixed(2)))
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)))
174
187
  );
175
188
  });
176
189
  function useInterval(callback, delay) {
177
- React3.useEffect(() => {
190
+ React4.useEffect(() => {
178
191
  const interval = setInterval(callback, delay);
179
192
  return () => clearInterval(interval);
180
193
  }, [delay]);
181
194
  }
182
- var LeanViewComponent = React3__namespace.forwardRef((props, ref) => {
183
- return React3__namespace.createElement("RCTView", { ...props, ref });
184
- });
185
- LeanViewComponent.displayName = "RCTView";
186
- var LeanView = reactNative.Platform.OS === "android" || reactNative.Platform.OS === "ios" ? LeanViewComponent : reactNative.View;
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
+ });
208
+ }
209
+ return globalResizeObserver;
210
+ }
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]);
234
+ }
187
235
 
188
- // src/components/Separator.tsx
189
- function Separator({ ItemSeparatorComponent, itemKey, leadingItem }) {
190
- const [lastItemKeys] = useArr$(["lastItemKeys"]);
191
- const isALastItem = lastItemKeys.includes(itemKey);
192
- return isALastItem ? null : /* @__PURE__ */ React.createElement(ItemSeparatorComponent, { leadingItem });
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
+ );
263
+ }
264
+ }, []);
265
+ return {};
193
266
  }
194
267
 
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
+
195
275
  // src/constants.ts
196
276
  var POSITION_OUT_OF_VIEW = -1e7;
197
277
  var ENABLE_DEVMODE = __DEV__ && false;
198
278
  var ENABLE_DEBUG_VIEW = __DEV__ && false;
199
- var IsNewArchitecture = global.nativeFabricUIManager != null;
279
+ var typedForwardRef = React4.forwardRef;
280
+ var typedMemo = React4.memo;
281
+
282
+ // src/components/PositionView.tsx
283
+ var PositionViewState = typedMemo(function PositionView({
284
+ id,
285
+ horizontal,
286
+ style,
287
+ refView,
288
+ ...rest
289
+ }) {
290
+ 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 });
294
+ });
295
+ var PositionViewSticky = typedMemo(function PositionViewSticky2({
296
+ id,
297
+ horizontal,
298
+ style,
299
+ refView,
300
+ index,
301
+ ...rest
302
+ }) {
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 });
314
+ });
315
+ 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
+
322
+ // src/constants-platform.ts
323
+ 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
+ };
200
330
  var symbolFirst = Symbol();
201
331
  function useInit(cb) {
202
- const refValue = React3.useRef(symbolFirst);
332
+ const refValue = React4.useRef(symbolFirst);
203
333
  if (refValue.current === symbolFirst) {
204
334
  refValue.current = cb();
205
335
  }
@@ -238,10 +368,10 @@ function extractPadding(style, contentContainerStyle, type) {
238
368
  }
239
369
 
240
370
  // src/state/ContextContainer.ts
241
- var ContextContainer = React3.createContext(null);
371
+ var ContextContainer = React4.createContext(null);
242
372
  function useViewability(callback, configId) {
243
373
  const ctx = useStateContext();
244
- const { containerId } = React3.useContext(ContextContainer);
374
+ const { containerId } = React4.useContext(ContextContainer);
245
375
  const key = containerId + (configId != null ? configId : "");
246
376
  useInit(() => {
247
377
  const value = ctx.mapViewabilityValues.get(key);
@@ -250,7 +380,7 @@ function useViewability(callback, configId) {
250
380
  }
251
381
  });
252
382
  ctx.mapViewabilityCallbacks.set(key, callback);
253
- React3.useEffect(
383
+ React4.useEffect(
254
384
  () => () => {
255
385
  ctx.mapViewabilityCallbacks.delete(key);
256
386
  },
@@ -259,7 +389,7 @@ function useViewability(callback, configId) {
259
389
  }
260
390
  function useViewabilityAmount(callback) {
261
391
  const ctx = useStateContext();
262
- const { containerId } = React3.useContext(ContextContainer);
392
+ const { containerId } = React4.useContext(ContextContainer);
263
393
  useInit(() => {
264
394
  const value = ctx.mapViewabilityAmountValues.get(containerId);
265
395
  if (value) {
@@ -267,7 +397,7 @@ function useViewabilityAmount(callback) {
267
397
  }
268
398
  });
269
399
  ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
270
- React3.useEffect(
400
+ React4.useEffect(
271
401
  () => () => {
272
402
  ctx.mapViewabilityAmountCallbacks.delete(containerId);
273
403
  },
@@ -275,12 +405,12 @@ function useViewabilityAmount(callback) {
275
405
  );
276
406
  }
277
407
  function useRecyclingEffect(effect) {
278
- const { index, value } = React3.useContext(ContextContainer);
279
- const prevValues = React3.useRef({
408
+ const { index, value } = React4.useContext(ContextContainer);
409
+ const prevValues = React4.useRef({
280
410
  prevIndex: void 0,
281
411
  prevItem: void 0
282
412
  });
283
- React3.useEffect(() => {
413
+ React4.useEffect(() => {
284
414
  let ret;
285
415
  if (prevValues.current.prevIndex !== void 0 && prevValues.current.prevItem !== void 0) {
286
416
  ret = effect({
@@ -298,12 +428,12 @@ function useRecyclingEffect(effect) {
298
428
  }, [index, value, effect]);
299
429
  }
300
430
  function useRecyclingState(valueOrFun) {
301
- const { index, value, itemKey, triggerLayout } = React3.useContext(ContextContainer);
302
- const refState = React3.useRef({
431
+ const { index, value, itemKey, triggerLayout } = React4.useContext(ContextContainer);
432
+ const refState = React4.useRef({
303
433
  itemKey: null,
304
434
  value: null
305
435
  });
306
- const [_, setRenderNum] = React3.useState(0);
436
+ const [_, setRenderNum] = React4.useState(0);
307
437
  const state = refState.current;
308
438
  if (state.itemKey !== itemKey) {
309
439
  state.itemKey = itemKey;
@@ -314,7 +444,7 @@ function useRecyclingState(valueOrFun) {
314
444
  prevItem: void 0
315
445
  }) : valueOrFun;
316
446
  }
317
- const setState = React3.useCallback(
447
+ const setState = React4.useCallback(
318
448
  (newState) => {
319
449
  state.value = isFunction(newState) ? newState(state.value) : newState;
320
450
  setRenderNum((v) => v + 1);
@@ -325,7 +455,7 @@ function useRecyclingState(valueOrFun) {
325
455
  return [state.value, setState];
326
456
  }
327
457
  function useIsLastItem() {
328
- const { itemKey } = React3.useContext(ContextContainer);
458
+ const { itemKey } = React4.useContext(ContextContainer);
329
459
  const isLast = useSelector$("lastItemKeys", (lastItemKeys) => (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false);
330
460
  return isLast;
331
461
  }
@@ -333,8 +463,12 @@ function useListScrollSize() {
333
463
  const [scrollSize] = useArr$(["scrollSize"]);
334
464
  return scrollSize;
335
465
  }
336
- var typedForwardRef = React3.forwardRef;
337
- var typedMemo = React3.memo;
466
+ function useSyncLayout2() {
467
+ {
468
+ const { triggerLayout: syncLayout } = React4.useContext(ContextContainer);
469
+ return syncLayout;
470
+ }
471
+ }
338
472
 
339
473
  // src/components/Container.tsx
340
474
  var Container = typedMemo(function Container2({
@@ -346,57 +480,62 @@ var Container = typedMemo(function Container2({
346
480
  ItemSeparatorComponent
347
481
  }) {
348
482
  const ctx = useStateContext();
349
- const columnWrapperStyle = ctx.columnWrapperStyle;
350
- const [column = 0, data, itemKey, position = POSITION_OUT_OF_VIEW, numColumns, extraData] = useArr$([
483
+ const { columnWrapperStyle } = ctx;
484
+ const [column = 0, data, itemKey, numColumns, extraData, isSticky] = useArr$([
351
485
  `containerColumn${id}`,
352
486
  `containerItemData${id}`,
353
487
  `containerItemKey${id}`,
354
- `containerPosition${id}`,
355
488
  "numColumns",
356
- "extraData"
489
+ "extraData",
490
+ `containerSticky${id}`
357
491
  ]);
358
- const refLastSize = React3.useRef();
359
- const ref = React3.useRef(null);
360
- const [layoutRenderCount, forceLayoutRender] = React3.useState(0);
492
+ const refLastSize = React4.useRef();
493
+ const ref = React4.useRef(null);
494
+ const [_, forceLayoutRender] = React4.useState(0);
361
495
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
362
496
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
363
- let didLayout = false;
364
- let paddingStyles;
365
- if (columnWrapperStyle) {
366
- const { columnGap, rowGap, gap } = columnWrapperStyle;
367
- if (horizontal) {
368
- paddingStyles = {
369
- paddingRight: columnGap || gap || void 0,
370
- paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
371
- };
372
- } else {
373
- paddingStyles = {
374
- paddingBottom: rowGap || gap || void 0,
375
- paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
376
- };
497
+ const style = React4.useMemo(() => {
498
+ let paddingStyles;
499
+ if (columnWrapperStyle) {
500
+ const { columnGap, rowGap, gap } = columnWrapperStyle;
501
+ if (horizontal) {
502
+ const py = numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0;
503
+ paddingStyles = {
504
+ paddingBottom: py,
505
+ paddingRight: columnGap || gap || void 0,
506
+ paddingTop: py
507
+ };
508
+ } else {
509
+ const px = numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0;
510
+ paddingStyles = {
511
+ paddingBottom: rowGap || gap || void 0,
512
+ paddingLeft: px,
513
+ paddingRight: px
514
+ };
515
+ }
377
516
  }
378
- }
379
- const style = horizontal ? {
380
- flexDirection: ItemSeparatorComponent ? "row" : void 0,
381
- height: otherAxisSize,
382
- left: position,
383
- position: "absolute",
384
- top: otherAxisPos,
385
- ...paddingStyles || {}
386
- } : {
387
- left: otherAxisPos,
388
- position: "absolute",
389
- right: numColumns > 1 ? null : 0,
390
- top: position,
391
- width: otherAxisSize,
392
- ...paddingStyles || {}
393
- };
394
- const renderedItemInfo = React3.useMemo(
517
+ return horizontal ? {
518
+ flexDirection: ItemSeparatorComponent ? "row" : void 0,
519
+ height: otherAxisSize,
520
+ left: 0,
521
+ position: "absolute",
522
+ top: otherAxisPos,
523
+ ...paddingStyles || {}
524
+ } : {
525
+ left: otherAxisPos,
526
+ position: "absolute",
527
+ right: numColumns > 1 ? void 0 : 0,
528
+ top: 0,
529
+ width: otherAxisSize,
530
+ ...paddingStyles || {}
531
+ };
532
+ }, [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns]);
533
+ const renderedItemInfo = React4.useMemo(
395
534
  () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
396
535
  [itemKey, data, extraData]
397
536
  );
398
537
  const { index, renderedItem } = renderedItemInfo || {};
399
- const contextValue = React3.useMemo(() => {
538
+ const contextValue = React4.useMemo(() => {
400
539
  ctx.viewRefs.set(id, ref);
401
540
  return {
402
541
  containerId: id,
@@ -408,104 +547,183 @@ var Container = typedMemo(function Container2({
408
547
  value: data
409
548
  };
410
549
  }, [id, itemKey, index, data]);
411
- const onLayout = (event) => {
412
- var _a, _b;
550
+ const onLayoutChange = (rectangle) => {
413
551
  if (!isNullOrUndefined(itemKey)) {
414
- didLayout = true;
415
- let layout = event.nativeEvent.layout;
416
- const size = layout[horizontal ? "width" : "height"];
552
+ let layout = rectangle;
553
+ layout[horizontal ? "width" : "height"];
417
554
  const doUpdate = () => {
418
555
  refLastSize.current = { height: layout.height, width: layout.width };
419
556
  updateItemSize2(itemKey, layout);
420
557
  };
421
- if (IsNewArchitecture || size > 0) {
558
+ {
422
559
  doUpdate();
423
- } else {
424
- (_b = (_a = ref.current) == null ? void 0 : _a.measure) == null ? void 0 : _b.call(_a, (_x, _y, width, height) => {
425
- layout = { height, width };
426
- doUpdate();
427
- });
428
560
  }
429
561
  }
430
562
  };
431
- if (IsNewArchitecture) {
432
- React3.useLayoutEffect(() => {
433
- var _a, _b;
434
- if (!isNullOrUndefined(itemKey)) {
435
- const measured = (_b = (_a = ref.current) == null ? void 0 : _a.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a);
436
- if (measured) {
437
- const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
438
- if (size) {
439
- updateItemSize2(itemKey, measured);
440
- }
563
+ const PositionComponent = isSticky ? PositionViewSticky : PositionView2;
564
+ return /* @__PURE__ */ React4__namespace.createElement(ContextContainer.Provider, { value: contextValue }, /* @__PURE__ */ React4__namespace.createElement(
565
+ PositionComponent,
566
+ {
567
+ horizontal,
568
+ id,
569
+ index,
570
+ key: recycleItems ? void 0 : itemKey,
571
+ onLayoutChange,
572
+ refView: ref,
573
+ style
574
+ },
575
+ renderedItem,
576
+ renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React4__namespace.createElement(
577
+ Separator,
578
+ {
579
+ ItemSeparatorComponent,
580
+ itemKey,
581
+ leadingItem: renderedItemInfo.item
582
+ }
583
+ )
584
+ ));
585
+ });
586
+
587
+ // src/utils/reordering.ts
588
+ var mapFn = (element) => {
589
+ const indexStr = element.getAttribute("index");
590
+ return [element, indexStr === null ? null : parseInt(indexStr)];
591
+ };
592
+ function sortDOMElementsPatience(container) {
593
+ const elements = Array.from(container.children);
594
+ if (elements.length <= 1) return elements;
595
+ const items = elements.map(mapFn);
596
+ items.sort((a, b) => {
597
+ const aKey = a[1];
598
+ const bKey = b[1];
599
+ if (aKey === null) {
600
+ return 1;
601
+ }
602
+ if (bKey === null) {
603
+ return -1;
604
+ }
605
+ return aKey - bKey;
606
+ });
607
+ const targetPositions = /* @__PURE__ */ new Map();
608
+ items.forEach((item, index) => {
609
+ targetPositions.set(item[0], index);
610
+ });
611
+ const currentPositions = elements.map((el) => targetPositions.get(el));
612
+ const lis = findLIS(currentPositions);
613
+ const stableIndices = new Set(lis);
614
+ for (let targetPos = 0; targetPos < items.length; targetPos++) {
615
+ const element = items[targetPos][0];
616
+ const currentPos = elements.indexOf(element);
617
+ if (!stableIndices.has(currentPos)) {
618
+ let nextStableElement = null;
619
+ for (let i = targetPos + 1; i < items.length; i++) {
620
+ const nextEl = items[i][0];
621
+ const nextCurrentPos = elements.indexOf(nextEl);
622
+ if (stableIndices.has(nextCurrentPos)) {
623
+ nextStableElement = nextEl;
624
+ break;
441
625
  }
442
626
  }
443
- }, [itemKey, layoutRenderCount]);
444
- } else {
445
- React3.useEffect(() => {
446
- if (!isNullOrUndefined(itemKey)) {
447
- const timeout = setTimeout(() => {
448
- if (!didLayout && refLastSize.current) {
449
- updateItemSize2(itemKey, refLastSize.current);
450
- }
451
- }, 16);
452
- return () => {
453
- clearTimeout(timeout);
454
- };
627
+ if (nextStableElement) {
628
+ container.insertBefore(element, nextStableElement);
629
+ } else {
630
+ container.appendChild(element);
455
631
  }
456
- }, [itemKey]);
632
+ }
457
633
  }
458
- return /* @__PURE__ */ React3__namespace.createElement(LeanView, { key: recycleItems ? void 0 : itemKey, onLayout, ref, style }, /* @__PURE__ */ React3__namespace.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React3__namespace.createElement(
459
- Separator,
460
- {
461
- ItemSeparatorComponent,
462
- itemKey,
463
- leadingItem: renderedItemInfo.item
634
+ }
635
+ function findLIS(arr) {
636
+ const n = arr.length;
637
+ const tails = [];
638
+ const predecessors = new Array(n).fill(-1);
639
+ const indices = [];
640
+ for (let i = 0; i < n; i++) {
641
+ const num = arr[i];
642
+ let left = 0, right = tails.length;
643
+ while (left < right) {
644
+ const mid = Math.floor((left + right) / 2);
645
+ if (arr[indices[mid]] < num) {
646
+ left = mid + 1;
647
+ } else {
648
+ right = mid;
649
+ }
464
650
  }
465
- )));
466
- });
467
- var useAnimatedValue = (initialValue) => {
468
- return React3.useRef(new reactNative.Animated.Value(initialValue)).current;
469
- };
651
+ if (left === tails.length) {
652
+ tails.push(num);
653
+ indices.push(i);
654
+ } else {
655
+ tails[left] = num;
656
+ indices[left] = i;
657
+ }
658
+ if (left > 0) {
659
+ predecessors[i] = indices[left - 1];
660
+ }
661
+ }
662
+ const result = [];
663
+ let k = indices[indices.length - 1];
664
+ while (k !== -1) {
665
+ result.unshift(k);
666
+ k = predecessors[k];
667
+ }
668
+ return result;
669
+ }
470
670
 
471
- // src/hooks/useValue$.ts
472
- function useValue$(key, params) {
473
- var _a;
474
- const { getValue, delay } = params || {};
671
+ // src/hooks/useDOMOrder.ts
672
+ function useDOMOrder(ref) {
475
673
  const ctx = useStateContext();
476
- const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
477
- React3.useMemo(() => {
478
- let newValue;
479
- let prevValue;
480
- let didQueueTask = false;
481
- listen$(ctx, key, (v) => {
482
- newValue = getValue ? getValue(v) : v;
483
- if (delay !== void 0) {
484
- const fn = () => {
485
- didQueueTask = false;
486
- if (newValue !== void 0) {
487
- animValue.setValue(newValue);
488
- }
489
- };
490
- const delayValue = typeof delay === "function" ? delay(newValue, prevValue) : delay;
491
- prevValue = newValue;
492
- if (!didQueueTask) {
493
- didQueueTask = true;
494
- if (delayValue === 0) {
495
- queueMicrotask(fn);
496
- } else {
497
- setTimeout(fn, delayValue);
498
- }
674
+ const debounceRef = React4.useRef(void 0);
675
+ React4.useEffect(() => {
676
+ const unsubscribe = listen$(ctx, "lastPositionUpdate", () => {
677
+ if (debounceRef.current !== void 0) {
678
+ clearTimeout(debounceRef.current);
679
+ }
680
+ debounceRef.current = setTimeout(() => {
681
+ const parent = ref.current;
682
+ if (parent) {
683
+ sortDOMElementsPatience(parent);
499
684
  }
500
- } else {
501
- animValue.setValue(newValue);
502
- }
685
+ debounceRef.current = void 0;
686
+ }, 500);
503
687
  });
504
- }, []);
505
- return animValue;
688
+ return () => {
689
+ unsubscribe();
690
+ if (debounceRef.current !== void 0) {
691
+ clearTimeout(debounceRef.current);
692
+ }
693
+ };
694
+ }, [ctx]);
506
695
  }
507
696
 
508
697
  // src/components/Containers.tsx
698
+ var ContainersInner = typedMemo(function ContainersInner2({ horizontal, numColumns, children }) {
699
+ const ref = React4.useRef(null);
700
+ const ctx = useStateContext();
701
+ const columnWrapperStyle = ctx.columnWrapperStyle;
702
+ const [totalSize, otherAxisSize] = useArr$(["totalSize", "otherAxisSize"]);
703
+ useDOMOrder(ref);
704
+ const style = horizontal ? { minHeight: otherAxisSize, width: totalSize } : { height: totalSize, minWidth: otherAxisSize };
705
+ if (columnWrapperStyle && numColumns > 1) {
706
+ const { columnGap, rowGap, gap } = columnWrapperStyle;
707
+ const gapX = columnGap || gap || 0;
708
+ const gapY = rowGap || gap || 0;
709
+ if (horizontal) {
710
+ if (gapY) {
711
+ style.marginTop = style.marginBottom = -gapY / 2;
712
+ }
713
+ if (gapX) {
714
+ style.marginRight = -gapX;
715
+ }
716
+ } else {
717
+ if (gapX) {
718
+ style.marginLeft = style.marginRight = -gapX;
719
+ }
720
+ if (gapY) {
721
+ style.marginBottom = -gapY;
722
+ }
723
+ }
724
+ }
725
+ return /* @__PURE__ */ React4__namespace.createElement("div", { ref, style }, children);
726
+ });
509
727
  var Containers = typedMemo(function Containers2({
510
728
  horizontal,
511
729
  recycleItems,
@@ -514,19 +732,11 @@ var Containers = typedMemo(function Containers2({
514
732
  updateItemSize: updateItemSize2,
515
733
  getRenderedItem: getRenderedItem2
516
734
  }) {
517
- const ctx = useStateContext();
518
- const columnWrapperStyle = ctx.columnWrapperStyle;
519
735
  const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
520
- const animSize = useValue$("totalSize", {
521
- // Use a microtask if increasing the size significantly, otherwise use a timeout
522
- delay: (value, prevValue) => !prevValue || value - prevValue > 20 ? 0 : 200
523
- });
524
- const animOpacity = waitForInitialLayout && !IsNewArchitecture ? useValue$("containersDidLayout", { getValue: (value) => value ? 1 : 0 }) : void 0;
525
- const otherAxisSize = useValue$("otherAxisSize", { delay: 0 });
526
736
  const containers = [];
527
737
  for (let i = 0; i < numContainers; i++) {
528
738
  containers.push(
529
- /* @__PURE__ */ React3__namespace.createElement(
739
+ /* @__PURE__ */ React4__namespace.createElement(
530
740
  Container,
531
741
  {
532
742
  getRenderedItem: getRenderedItem2,
@@ -540,45 +750,209 @@ var Containers = typedMemo(function Containers2({
540
750
  )
541
751
  );
542
752
  }
543
- const style = horizontal ? { minHeight: otherAxisSize, opacity: animOpacity, width: animSize } : { height: animSize, minWidth: otherAxisSize, opacity: animOpacity };
544
- if (columnWrapperStyle && numColumns > 1) {
545
- const { columnGap, rowGap, gap } = columnWrapperStyle;
546
- const gapX = columnGap || gap || 0;
547
- const gapY = rowGap || gap || 0;
548
- if (horizontal) {
549
- if (gapY) {
550
- style.marginVertical = -gapY / 2;
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%"
551
766
  }
552
- if (gapX) {
553
- style.marginRight = -gapX;
767
+ },
768
+ /* @__PURE__ */ React4__namespace.createElement(Text, { style: { color: "red" } }, index * 100)
769
+ ));
770
+ });
771
+ var ListComponentScrollView = React4.forwardRef(function ListComponentScrollView2({
772
+ children,
773
+ style,
774
+ contentContainerStyle,
775
+ horizontal = false,
776
+ contentOffset,
777
+ maintainVisibleContentPosition,
778
+ onScroll: onScroll2,
779
+ onMomentumScrollEnd,
780
+ showsHorizontalScrollIndicator = true,
781
+ showsVerticalScrollIndicator = true,
782
+ refreshControl,
783
+ onLayout,
784
+ ScrollComponent,
785
+ ...props
786
+ }, ref) {
787
+ const scrollRef = React4.useRef(null);
788
+ const contentRef = React4.useRef(null);
789
+ const momentumTimeout = React4.useRef(null);
790
+ React4.useImperativeHandle(ref, () => {
791
+ const api = {
792
+ getBoundingClientRect: () => {
793
+ var _a;
794
+ return (_a = scrollRef.current) == null ? void 0 : _a.getBoundingClientRect();
795
+ },
796
+ getScrollableNode: () => scrollRef.current,
797
+ getScrollResponder: () => scrollRef.current,
798
+ scrollBy: (options) => {
799
+ const el = scrollRef.current;
800
+ if (!el) return;
801
+ const { x = 0, y = 0, animated = true } = options;
802
+ el.scrollBy({ behavior: animated ? "smooth" : "auto", left: x, top: y });
803
+ },
804
+ scrollTo: (options) => {
805
+ const el = scrollRef.current;
806
+ if (!el) return;
807
+ const { x = 0, y = 0, animated = true } = options;
808
+ el.scrollTo({ behavior: animated ? "smooth" : "auto", left: x, top: y });
809
+ },
810
+ scrollToEnd: (options = {}) => {
811
+ const el = scrollRef.current;
812
+ if (!el) return;
813
+ const { animated = true } = options;
814
+ if (horizontal) {
815
+ el.scrollTo({ behavior: animated ? "smooth" : "auto", left: el.scrollWidth });
816
+ } else {
817
+ el.scrollTo({ behavior: animated ? "smooth" : "auto", top: el.scrollHeight });
818
+ }
819
+ },
820
+ scrollToOffset: (params) => {
821
+ const el = scrollRef.current;
822
+ if (!el) return;
823
+ const { offset, animated = true } = params;
824
+ if (horizontal) {
825
+ el.scrollTo({ behavior: animated ? "smooth" : "auto", left: offset });
826
+ } else {
827
+ el.scrollTo({ behavior: animated ? "smooth" : "auto", top: offset });
828
+ }
554
829
  }
555
- } else {
556
- if (gapX) {
557
- style.marginHorizontal = -gapX;
830
+ };
831
+ return api;
832
+ }, [horizontal]);
833
+ const handleScroll = React4.useCallback(
834
+ (event) => {
835
+ if (!onScroll2 || !(event == null ? void 0 : event.target)) {
836
+ return;
558
837
  }
559
- if (gapY) {
560
- style.marginBottom = -gapY;
838
+ const target = event.target;
839
+ const scrollEvent = {
840
+ nativeEvent: {
841
+ contentOffset: {
842
+ x: target.scrollLeft,
843
+ y: target.scrollTop
844
+ },
845
+ contentSize: {
846
+ height: target.scrollHeight,
847
+ width: target.scrollWidth
848
+ },
849
+ layoutMeasurement: {
850
+ height: target.clientHeight,
851
+ width: target.clientWidth
852
+ }
853
+ }
854
+ };
855
+ onScroll2(scrollEvent);
856
+ if (onMomentumScrollEnd) {
857
+ if (momentumTimeout.current != null) clearTimeout(momentumTimeout.current);
858
+ momentumTimeout.current = setTimeout(() => {
859
+ onMomentumScrollEnd({
860
+ nativeEvent: {
861
+ contentOffset: scrollEvent.nativeEvent.contentOffset
862
+ }
863
+ });
864
+ }, 100);
561
865
  }
562
- }
563
- }
564
- return /* @__PURE__ */ React3__namespace.createElement(reactNative.Animated.View, { style }, containers);
866
+ },
867
+ [onScroll2, onMomentumScrollEnd]
868
+ );
869
+ React4.useLayoutEffect(() => {
870
+ const element = scrollRef.current;
871
+ if (!element) return;
872
+ element.addEventListener("scroll", handleScroll, { passive: true });
873
+ return () => {
874
+ element.removeEventListener("scroll", handleScroll);
875
+ };
876
+ }, [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(() => {
884
+ if (!onLayout || !scrollRef.current) return;
885
+ const element = scrollRef.current;
886
+ const fireLayout = () => {
887
+ const rect = element.getBoundingClientRect();
888
+ onLayout({
889
+ nativeEvent: {
890
+ layout: {
891
+ height: rect.height,
892
+ width: rect.width,
893
+ x: rect.left,
894
+ y: rect.top
895
+ }
896
+ }
897
+ });
898
+ };
899
+ fireLayout();
900
+ const resizeObserver = new ResizeObserver(() => {
901
+ fireLayout();
902
+ });
903
+ resizeObserver.observe(element);
904
+ return () => resizeObserver.disconnect();
905
+ }, [onLayout]);
906
+ const scrollViewStyle = {
907
+ overflow: "auto",
908
+ overflowX: horizontal ? "auto" : showsHorizontalScrollIndicator ? "auto" : "hidden",
909
+ overflowY: horizontal ? showsVerticalScrollIndicator ? "auto" : "hidden" : "auto",
910
+ position: "relative",
911
+ // Ensure proper positioning context
912
+ WebkitOverflowScrolling: "touch",
913
+ // iOS momentum scrolling
914
+ ...style
915
+ };
916
+ const contentStyle = {
917
+ display: horizontal ? "flex" : "block",
918
+ flexDirection: horizontal ? "row" : void 0,
919
+ minHeight: horizontal ? void 0 : "100%",
920
+ minWidth: horizontal ? "100%" : void 0,
921
+ ...contentContainerStyle
922
+ };
923
+ return /* @__PURE__ */ React4__namespace.createElement("div", { ref: scrollRef, style: scrollViewStyle, ...props }, refreshControl, /* @__PURE__ */ React4__namespace.createElement("div", { ref: contentRef, style: contentStyle }, children));
565
924
  });
925
+ function useValueListener$(key, callback) {
926
+ const ctx = useStateContext();
927
+ React4.useLayoutEffect(() => {
928
+ listen$(ctx, key, (value) => {
929
+ callback(value);
930
+ });
931
+ }, []);
932
+ }
933
+
934
+ // src/components/ScrollAdjust.tsx
566
935
  function ScrollAdjust() {
567
- const bias = 1e7;
568
- const [scrollAdjust, scrollAdjustUserOffset] = useArr$(["scrollAdjust", "scrollAdjustUserOffset"]);
569
- const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0) + bias;
570
- return /* @__PURE__ */ React3__namespace.createElement(
571
- reactNative.View,
572
- {
573
- style: {
574
- height: 0,
575
- left: 0,
576
- position: "absolute",
577
- top: scrollOffset,
578
- width: 0
579
- }
936
+ const ctx = useStateContext();
937
+ const lastScrollOffsetRef = React4__namespace.useRef(0);
938
+ const callback = React4__namespace.useCallback(() => {
939
+ var _a;
940
+ const scrollAdjust = peek$(ctx, "scrollAdjust");
941
+ const scrollAdjustUserOffset = peek$(ctx, "scrollAdjustUserOffset");
942
+ const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0);
943
+ const scrollView = (_a = ctx.internalState) == null ? void 0 : _a.refScroller.current;
944
+ if (scrollView && scrollOffset !== lastScrollOffsetRef.current) {
945
+ const scrollDelta = scrollOffset - lastScrollOffsetRef.current;
946
+ if (scrollDelta !== 0) {
947
+ scrollView.scrollBy(0, scrollDelta);
948
+ console.log("ScrollAdjust (web scrollBy)", scrollDelta, "total offset:", scrollOffset);
949
+ }
950
+ lastScrollOffsetRef.current = scrollOffset;
580
951
  }
581
- );
952
+ }, []);
953
+ useValueListener$("scrollAdjust", callback);
954
+ useValueListener$("scrollAdjustUserOffset", callback);
955
+ return null;
582
956
  }
583
957
 
584
958
  // src/components/SnapWrapper.tsx
@@ -586,46 +960,31 @@ function SnapWrapper({ ScrollComponent, ...props }) {
586
960
  const [snapToOffsets] = useArr$(["snapToOffsets"]);
587
961
  return /* @__PURE__ */ React.createElement(ScrollComponent, { ...props, snapToOffsets });
588
962
  }
589
- function useSyncLayout({
590
- onChange
591
- }) {
592
- const ref = React3.useRef(null);
593
- const onLayout = React3.useCallback(
594
- (event) => {
595
- onChange(event.nativeEvent.layout, false);
596
- },
597
- [onChange]
598
- );
599
- if (IsNewArchitecture) {
600
- React3.useLayoutEffect(() => {
601
- if (ref.current) {
602
- ref.current.measure((x, y, width, height) => {
603
- onChange({ height, width, x, y }, true);
604
- });
605
- }
606
- }, []);
607
- }
608
- return { onLayout, ref };
963
+
964
+ // src/hooks/useValue$.ts
965
+ function useValue$(key, params) {
966
+ const [value] = useArr$([key]);
967
+ return value;
609
968
  }
610
969
 
611
970
  // src/components/ListComponent.tsx
612
971
  var getComponent = (Component) => {
613
- if (React3__namespace.isValidElement(Component)) {
972
+ if (React4__namespace.isValidElement(Component)) {
614
973
  return Component;
615
974
  }
616
975
  if (Component) {
617
- return /* @__PURE__ */ React3__namespace.createElement(Component, null);
976
+ return /* @__PURE__ */ React4__namespace.createElement(Component, null);
618
977
  }
619
978
  return null;
620
979
  };
621
980
  var Padding = () => {
622
- const animPaddingTop = useValue$("alignItemsPaddingTop", { delay: 0 });
623
- return /* @__PURE__ */ React3__namespace.createElement(reactNative.Animated.View, { style: { paddingTop: animPaddingTop } });
981
+ const animPaddingTop = useValue$("alignItemsPaddingTop");
982
+ return /* @__PURE__ */ React4__namespace.createElement(AnimatedView, { style: { paddingTop: animPaddingTop } });
624
983
  };
625
984
  var PaddingDevMode = () => {
626
- const animPaddingTop = useValue$("alignItemsPaddingTop", { delay: 0 });
627
- return /* @__PURE__ */ React3__namespace.createElement(React3__namespace.Fragment, null, /* @__PURE__ */ React3__namespace.createElement(reactNative.Animated.View, { style: { paddingTop: animPaddingTop } }), /* @__PURE__ */ React3__namespace.createElement(
628
- reactNative.Animated.View,
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,
629
988
  {
630
989
  style: {
631
990
  backgroundColor: "green",
@@ -663,17 +1022,16 @@ var ListComponent = typedMemo(function ListComponent2({
663
1022
  scrollAdjustHandler,
664
1023
  onLayoutHeader,
665
1024
  snapToIndices,
1025
+ stickyIndices,
666
1026
  ...rest
667
1027
  }) {
668
1028
  const ctx = useStateContext();
669
- const { onLayout: onLayoutHeaderSync, ref: refHeader } = useSyncLayout({
670
- onChange: onLayoutHeader
671
- });
672
- const ScrollComponent = renderScrollComponent ? React3.useMemo(
673
- () => React3__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
1029
+ const refHeader = React4__namespace.useRef(null);
1030
+ const ScrollComponent = renderScrollComponent ? React4.useMemo(
1031
+ () => React4__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
674
1032
  [renderScrollComponent]
675
- ) : reactNative.ScrollView;
676
- React3__namespace.useEffect(() => {
1033
+ ) : ListComponentScrollView;
1034
+ React4__namespace.useEffect(() => {
677
1035
  if (canRender) {
678
1036
  setTimeout(() => {
679
1037
  scrollAdjustHandler.setMounted();
@@ -681,16 +1039,17 @@ var ListComponent = typedMemo(function ListComponent2({
681
1039
  }
682
1040
  }, [canRender]);
683
1041
  const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
684
- return /* @__PURE__ */ React3__namespace.createElement(
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(
685
1049
  SnapOrScroll,
686
1050
  {
687
1051
  ...rest,
688
- contentContainerStyle: [
689
- contentContainerStyle,
690
- horizontal ? {
691
- height: "100%"
692
- } : {}
693
- ],
1052
+ contentContainerStyle: contentContainerStyleWeb,
694
1053
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
695
1054
  horizontal,
696
1055
  maintainVisibleContentPosition: maintainVisibleContentPosition && !ListEmptyComponent ? { minIndexForVisible: 0 } : void 0,
@@ -700,11 +1059,19 @@ var ListComponent = typedMemo(function ListComponent2({
700
1059
  ScrollComponent: snapToIndices ? ScrollComponent : void 0,
701
1060
  style
702
1061
  },
703
- maintainVisibleContentPosition && /* @__PURE__ */ React3__namespace.createElement(ScrollAdjust, null),
704
- ENABLE_DEVMODE ? /* @__PURE__ */ React3__namespace.createElement(PaddingDevMode, null) : /* @__PURE__ */ React3__namespace.createElement(Padding, null),
705
- ListHeaderComponent && /* @__PURE__ */ React3__namespace.createElement(reactNative.View, { onLayout: onLayoutHeaderSync, ref: refHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
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
+ ),
706
1073
  ListEmptyComponent && getComponent(ListEmptyComponent),
707
- canRender && /* @__PURE__ */ React3__namespace.createElement(
1074
+ canRender && /* @__PURE__ */ React4__namespace.createElement(
708
1075
  Containers,
709
1076
  {
710
1077
  getRenderedItem: getRenderedItem2,
@@ -715,17 +1082,18 @@ var ListComponent = typedMemo(function ListComponent2({
715
1082
  waitForInitialLayout
716
1083
  }
717
1084
  ),
718
- ListFooterComponent && /* @__PURE__ */ React3__namespace.createElement(
719
- reactNative.View,
1085
+ ListFooterComponent && /* @__PURE__ */ React4__namespace.createElement(
1086
+ LayoutView,
720
1087
  {
721
- onLayout: (event) => {
722
- const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
1088
+ onLayoutChange: (layout) => {
1089
+ const size = layout[horizontal ? "width" : "height"];
723
1090
  set$(ctx, "footerSize", size);
724
1091
  },
725
1092
  style: ListFooterComponentStyle
726
1093
  },
727
1094
  getComponent(ListFooterComponent)
728
- )
1095
+ ),
1096
+ __DEV__ && ENABLE_DEVMODE && /* @__PURE__ */ React4__namespace.createElement(DevNumbers, null)
729
1097
  );
730
1098
  });
731
1099
 
@@ -746,33 +1114,45 @@ function calculateOffsetForIndex(ctx, state, index) {
746
1114
  let position = 0;
747
1115
  if (index !== void 0) {
748
1116
  position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
749
- }
750
- const paddingTop = peek$(ctx, "stylePaddingTop");
751
- if (paddingTop) {
752
- position += paddingTop;
753
- }
754
- const headerSize = peek$(ctx, "headerSize");
755
- if (headerSize) {
756
- position += headerSize;
1117
+ const paddingTop = peek$(ctx, "stylePaddingTop");
1118
+ if (paddingTop) {
1119
+ position += paddingTop;
1120
+ }
1121
+ const headerSize = peek$(ctx, "headerSize");
1122
+ if (headerSize) {
1123
+ position += headerSize;
1124
+ }
757
1125
  }
758
1126
  return position;
759
1127
  }
760
1128
 
761
1129
  // src/utils/getItemSize.ts
762
1130
  function getItemSize(state, key, index, data, useAverageSize) {
1131
+ var _a, _b;
763
1132
  const {
764
1133
  sizesKnown,
765
1134
  sizes,
766
1135
  scrollingTo,
767
- props: { estimatedItemSize, getEstimatedItemSize }
1136
+ averageSizes,
1137
+ props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
768
1138
  } = state;
769
1139
  const sizeKnown = sizesKnown.get(key);
770
1140
  if (sizeKnown !== void 0) {
771
1141
  return sizeKnown;
772
1142
  }
773
1143
  let size;
774
- if (useAverageSize !== void 0 && sizeKnown === void 0 && !getEstimatedItemSize && !scrollingTo) {
775
- size = useAverageSize;
1144
+ const itemType = getItemType ? (_a = getItemType(data, index)) != null ? _a : "" : "";
1145
+ if (getFixedItemSize) {
1146
+ size = getFixedItemSize(index, data, itemType);
1147
+ if (size !== void 0) {
1148
+ sizesKnown.set(key, size);
1149
+ }
1150
+ }
1151
+ if (size === void 0 && useAverageSize && sizeKnown === void 0 && !scrollingTo) {
1152
+ const averageSizeForType = (_b = averageSizes[itemType]) == null ? void 0 : _b.avg;
1153
+ if (averageSizeForType !== void 0) {
1154
+ size = roundSize(averageSizeForType);
1155
+ }
776
1156
  }
777
1157
  if (size === void 0) {
778
1158
  size = sizes.get(key);
@@ -781,7 +1161,7 @@ function getItemSize(state, key, index, data, useAverageSize) {
781
1161
  }
782
1162
  }
783
1163
  if (size === void 0) {
784
- size = getEstimatedItemSize ? getEstimatedItemSize(index, data) : estimatedItemSize;
1164
+ size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
785
1165
  }
786
1166
  sizes.set(key, size);
787
1167
  return size;
@@ -800,11 +1180,46 @@ function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
800
1180
  return offset;
801
1181
  }
802
1182
 
1183
+ // src/core/finishScrollTo.ts
1184
+ var finishScrollTo = (state) => {
1185
+ if (state) {
1186
+ state.scrollingTo = void 0;
1187
+ state.scrollHistory.length = 0;
1188
+ }
1189
+ };
1190
+
1191
+ // src/core/scrollTo.ts
1192
+ function scrollTo(state, params = {}) {
1193
+ var _a;
1194
+ const { animated, noScrollingTo } = params;
1195
+ const {
1196
+ refScroller,
1197
+ props: { horizontal }
1198
+ } = state;
1199
+ const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
1200
+ state.scrollHistory.length = 0;
1201
+ if (!noScrollingTo) {
1202
+ state.scrollingTo = params;
1203
+ }
1204
+ 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
+ });
1210
+ if (!animated) {
1211
+ state.scroll = offset;
1212
+ setTimeout(() => finishScrollTo(state), 100);
1213
+ }
1214
+ }
1215
+
803
1216
  // src/utils/requestAdjust.ts
804
- function requestAdjust(ctx, state, positionDiff) {
1217
+ function requestAdjust(ctx, state, positionDiff, dataChanged) {
805
1218
  if (Math.abs(positionDiff) > 0.1) {
806
1219
  const doit = () => {
807
- state.scrollAdjustHandler.requestAdjust(positionDiff);
1220
+ {
1221
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
1222
+ }
808
1223
  };
809
1224
  state.scroll += positionDiff;
810
1225
  state.scrollForNextCalculateItemsInView = void 0;
@@ -823,49 +1238,72 @@ function requestAdjust(ctx, state, positionDiff) {
823
1238
  if (state.ignoreScrollFromMVCPTimeout) {
824
1239
  clearTimeout(state.ignoreScrollFromMVCPTimeout);
825
1240
  }
826
- state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
827
- state.ignoreScrollFromMVCP = void 0;
828
- }, 100);
1241
+ state.ignoreScrollFromMVCPTimeout = setTimeout(
1242
+ () => {
1243
+ state.ignoreScrollFromMVCP = void 0;
1244
+ },
1245
+ 100
1246
+ );
829
1247
  } else {
830
1248
  requestAnimationFrame(doit);
831
1249
  }
832
1250
  }
833
1251
  }
834
1252
 
835
- // src/core/prepareMVCP.ts
836
- function prepareMVCP(ctx, state) {
1253
+ // src/core/mvcp.ts
1254
+ function prepareMVCP(ctx, state, dataChanged) {
837
1255
  const {
1256
+ idsInView,
838
1257
  positions,
839
1258
  scrollingTo,
840
1259
  props: { maintainVisibleContentPosition }
841
1260
  } = state;
842
1261
  let prevPosition;
843
1262
  let targetId;
844
- let targetIndex;
1263
+ const idsInViewWithPositions = [];
845
1264
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
846
1265
  if (maintainVisibleContentPosition) {
847
1266
  const indexByKey = state.indexByKey;
848
1267
  if (scrollTarget !== void 0) {
849
1268
  targetId = getId(state, scrollTarget);
850
- targetIndex = scrollTarget;
851
- } else if (state.idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
852
- targetId = state.idsInView.find((id) => indexByKey.get(id) !== void 0);
853
- targetIndex = indexByKey.get(targetId);
1269
+ } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1270
+ if (dataChanged) {
1271
+ for (let i = 0; i < idsInView.length; i++) {
1272
+ const id = idsInView[i];
1273
+ const index = indexByKey.get(id);
1274
+ if (index !== void 0) {
1275
+ idsInViewWithPositions.push({ id, position: positions.get(id) });
1276
+ }
1277
+ }
1278
+ } else {
1279
+ targetId = state.idsInView.find((id) => indexByKey.get(id) !== void 0);
1280
+ }
854
1281
  }
855
- if (targetId !== void 0 && targetIndex !== void 0) {
1282
+ if (targetId !== void 0) {
856
1283
  prevPosition = positions.get(targetId);
857
1284
  }
858
1285
  }
859
1286
  return () => {
1287
+ let positionDiff;
1288
+ if (dataChanged && targetId === void 0) {
1289
+ for (let i = 0; i < idsInViewWithPositions.length; i++) {
1290
+ const { id, position } = idsInViewWithPositions[i];
1291
+ const newPosition = positions.get(id);
1292
+ if (newPosition !== void 0) {
1293
+ positionDiff = newPosition - position;
1294
+ break;
1295
+ }
1296
+ }
1297
+ }
860
1298
  if (targetId !== void 0 && prevPosition !== void 0) {
861
1299
  const newPosition = positions.get(targetId);
862
1300
  if (newPosition !== void 0) {
863
- const positionDiff = newPosition - prevPosition;
864
- if (Math.abs(positionDiff) > 0.1) {
865
- requestAdjust(ctx, state, positionDiff);
866
- }
1301
+ positionDiff = newPosition - prevPosition;
867
1302
  }
868
1303
  }
1304
+ if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1305
+ requestAdjust(ctx, state, positionDiff);
1306
+ }
869
1307
  };
870
1308
  }
871
1309
 
@@ -874,10 +1312,10 @@ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
874
1312
  if (stylePaddingTop !== void 0) {
875
1313
  const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
876
1314
  if (stylePaddingTop < prevStylePaddingTop) {
877
- let prevTotalSize = peek$(ctx, "totalSize");
1315
+ let prevTotalSize = peek$(ctx, "totalSize") || 0;
878
1316
  set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
879
1317
  state.timeoutSetPaddingTop = setTimeout(() => {
880
- prevTotalSize = peek$(ctx, "totalSize");
1318
+ prevTotalSize = peek$(ctx, "totalSize") || 0;
881
1319
  set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
882
1320
  }, 16);
883
1321
  }
@@ -941,43 +1379,6 @@ function addTotalSize(ctx, state, key, add) {
941
1379
  }
942
1380
  }
943
1381
 
944
- // src/utils/getScrollVelocity.ts
945
- var getScrollVelocity = (state) => {
946
- const { scrollHistory } = state;
947
- let velocity = 0;
948
- if (scrollHistory.length >= 1) {
949
- const newest = scrollHistory[scrollHistory.length - 1];
950
- let oldest;
951
- let start = 0;
952
- for (let i = 0; i < scrollHistory.length - 1; i++) {
953
- const entry = scrollHistory[i];
954
- const nextEntry = scrollHistory[i + 1];
955
- if (i > 0) {
956
- const prevEntry = scrollHistory[i - 1];
957
- const prevDirection = entry.scroll - prevEntry.scroll;
958
- const currentDirection = nextEntry.scroll - entry.scroll;
959
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
960
- start = i;
961
- break;
962
- }
963
- }
964
- }
965
- for (let i = start; i < scrollHistory.length - 1; i++) {
966
- const entry = scrollHistory[i];
967
- if (newest.time - entry.time <= 1e3) {
968
- oldest = entry;
969
- break;
970
- }
971
- }
972
- if (oldest) {
973
- const scrollDiff = newest.scroll - oldest.scroll;
974
- const timeDiff = newest.time - oldest.time;
975
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
976
- }
977
- }
978
- return velocity;
979
- };
980
-
981
1382
  // src/utils/updateSnapToOffsets.ts
982
1383
  function updateSnapToOffsets(ctx, state) {
983
1384
  const {
@@ -994,69 +1395,42 @@ function updateSnapToOffsets(ctx, state) {
994
1395
  }
995
1396
 
996
1397
  // src/core/updateAllPositions.ts
997
- function updateAllPositions(ctx, state, dataChanged) {
998
- var _a, _b, _c, _d, _e;
1398
+ function updateAllPositions(ctx, state, dataChanged, startIndex = 0) {
1399
+ var _a, _b, _c, _d, _e, _f;
999
1400
  const {
1000
- averageSizes,
1001
1401
  columns,
1002
1402
  indexByKey,
1003
1403
  positions,
1004
- firstFullyOnScreenIndex,
1005
1404
  idCache,
1006
1405
  sizesKnown,
1007
- props: { snapToIndices }
1406
+ props: { getEstimatedItemSize, snapToIndices, enableAverages }
1008
1407
  } = state;
1009
1408
  const data = state.props.data;
1010
1409
  const numColumns = peek$(ctx, "numColumns");
1011
1410
  const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
1012
- const scrollVelocity = getScrollVelocity(state);
1013
- if (dataChanged) {
1014
- indexByKey.clear();
1015
- idCache.clear();
1016
- }
1017
- const itemType = "";
1018
- let averageSize = (_a = averageSizes[itemType]) == null ? void 0 : _a.avg;
1019
- if (averageSize !== void 0) {
1020
- averageSize = roundSize(averageSize);
1021
- }
1022
- const shouldUseBackwards = !dataChanged && scrollVelocity < 0 && firstFullyOnScreenIndex > 5 && firstFullyOnScreenIndex < data.length;
1023
- if (shouldUseBackwards && firstFullyOnScreenIndex !== void 0) {
1024
- const anchorId = getId(state, firstFullyOnScreenIndex);
1025
- const anchorPosition = positions.get(anchorId);
1026
- if (anchorPosition !== void 0) {
1027
- let currentRowTop2 = anchorPosition;
1028
- let maxSizeInRow2 = 0;
1029
- let bailout = false;
1030
- for (let i = firstFullyOnScreenIndex - 1; i >= 0; i--) {
1031
- const id = (_b = idCache.get(i)) != null ? _b : getId(state, i);
1032
- const size = (_c = sizesKnown.get(id)) != null ? _c : getItemSize(state, id, i, data[i], averageSize);
1033
- const itemColumn = columns.get(id);
1034
- maxSizeInRow2 = Math.max(maxSizeInRow2, size);
1035
- if (itemColumn === 1) {
1036
- currentRowTop2 -= maxSizeInRow2;
1037
- maxSizeInRow2 = 0;
1038
- }
1039
- if (currentRowTop2 < -2e3) {
1040
- bailout = true;
1041
- break;
1042
- }
1043
- positions.set(id, currentRowTop2);
1044
- }
1045
- if (!bailout) {
1046
- updateTotalSize(ctx, state);
1047
- return;
1048
- }
1049
- }
1050
- }
1411
+ const useAverageSize = enableAverages && !getEstimatedItemSize;
1051
1412
  let currentRowTop = 0;
1052
1413
  let column = 1;
1053
1414
  let maxSizeInRow = 0;
1054
1415
  const hasColumns = numColumns > 1;
1416
+ 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
+ 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);
1426
+ currentRowTop = prevPosition + prevSize;
1427
+ }
1428
+ }
1055
1429
  const needsIndexByKey = dataChanged || indexByKey.size === 0;
1056
1430
  const dataLength = data.length;
1057
- for (let i = 0; i < dataLength; i++) {
1058
- const id = (_d = idCache.get(i)) != null ? _d : getId(state, i);
1059
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(state, id, i, data[i], averageSize);
1431
+ 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);
1060
1434
  if (__DEV__ && needsIndexByKey) {
1061
1435
  if (indexByKeyForChecking.has(id)) {
1062
1436
  console.error(
@@ -1091,32 +1465,18 @@ function updateAllPositions(ctx, state, dataChanged) {
1091
1465
  }
1092
1466
 
1093
1467
  // src/core/viewability.ts
1094
- var mapViewabilityConfigCallbackPairs = /* @__PURE__ */ new Map();
1095
- function setupViewability(props) {
1096
- let { viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged } = props;
1097
- if (viewabilityConfig || onViewableItemsChanged) {
1098
- viewabilityConfigCallbackPairs = [
1099
- ...viewabilityConfigCallbackPairs || [],
1100
- {
1101
- onViewableItemsChanged,
1102
- viewabilityConfig: viewabilityConfig || {
1103
- viewAreaCoveragePercentThreshold: 0
1104
- }
1105
- }
1106
- ];
1468
+ function ensureViewabilityState(ctx, configId) {
1469
+ let map = ctx.mapViewabilityConfigStates;
1470
+ if (!map) {
1471
+ map = /* @__PURE__ */ new Map();
1472
+ ctx.mapViewabilityConfigStates = map;
1107
1473
  }
1108
- if (viewabilityConfigCallbackPairs) {
1109
- for (const pair of viewabilityConfigCallbackPairs) {
1110
- mapViewabilityConfigCallbackPairs.set(pair.viewabilityConfig.id, {
1111
- end: -1,
1112
- previousEnd: -1,
1113
- previousStart: -1,
1114
- start: -1,
1115
- viewableItems: []
1116
- });
1117
- }
1474
+ let state = map.get(configId);
1475
+ if (!state) {
1476
+ state = { end: -1, previousEnd: -1, previousStart: -1, start: -1, viewableItems: [] };
1477
+ map.set(configId, state);
1118
1478
  }
1119
- return viewabilityConfigCallbackPairs;
1479
+ return state;
1120
1480
  }
1121
1481
  function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end) {
1122
1482
  const {
@@ -1124,9 +1484,7 @@ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollS
1124
1484
  props: { data }
1125
1485
  } = state;
1126
1486
  for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
1127
- const viewabilityState = mapViewabilityConfigCallbackPairs.get(
1128
- viewabilityConfigCallbackPair.viewabilityConfig.id
1129
- );
1487
+ const viewabilityState = ensureViewabilityState(ctx, viewabilityConfigCallbackPair.viewabilityConfig.id);
1130
1488
  viewabilityState.start = start;
1131
1489
  viewabilityState.end = end;
1132
1490
  if (viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime) {
@@ -1143,7 +1501,7 @@ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollS
1143
1501
  function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize) {
1144
1502
  const { viewabilityConfig, onViewableItemsChanged } = viewabilityConfigCallbackPair;
1145
1503
  const configId = viewabilityConfig.id;
1146
- const viewabilityState = mapViewabilityConfigCallbackPairs.get(configId);
1504
+ const viewabilityState = ensureViewabilityState(ctx, configId);
1147
1505
  const { viewableItems: previousViewableItems, start, end } = viewabilityState;
1148
1506
  const viewabilityTokens = /* @__PURE__ */ new Map();
1149
1507
  for (const [containerId, value] of ctx.mapViewabilityAmountValues) {
@@ -1222,6 +1580,15 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
1222
1580
  }
1223
1581
  }
1224
1582
  }
1583
+ function shallowEqual(prev, next) {
1584
+ if (!prev) return false;
1585
+ const keys = Object.keys(next);
1586
+ for (let i = 0; i < keys.length; i++) {
1587
+ const k = keys[i];
1588
+ if (prev[k] !== next[k]) return false;
1589
+ }
1590
+ return true;
1591
+ }
1225
1592
  function computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
1226
1593
  const { sizes, positions, scroll: scrollState } = state;
1227
1594
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
@@ -1250,7 +1617,8 @@ function computeViewability(state, ctx, viewabilityConfig, containerId, key, scr
1250
1617
  size,
1251
1618
  sizeVisible
1252
1619
  };
1253
- if (JSON.stringify(value) !== JSON.stringify(ctx.mapViewabilityAmountValues.get(containerId))) {
1620
+ const prev = ctx.mapViewabilityAmountValues.get(containerId);
1621
+ if (!shallowEqual(prev, value)) {
1254
1622
  ctx.mapViewabilityAmountValues.set(containerId, value);
1255
1623
  const cb = ctx.mapViewabilityAmountCallbacks.get(containerId);
1256
1624
  if (cb) {
@@ -1283,7 +1651,7 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
1283
1651
  // src/utils/checkAllSizesKnown.ts
1284
1652
  function checkAllSizesKnown(state) {
1285
1653
  const { startBuffered, endBuffered, sizesKnown } = state;
1286
- if (endBuffered !== null) {
1654
+ if (endBuffered !== null && startBuffered >= 0 && endBuffered >= 0) {
1287
1655
  let areAllKnown = true;
1288
1656
  for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
1289
1657
  const key = getId(state, i);
@@ -1295,35 +1663,79 @@ function checkAllSizesKnown(state) {
1295
1663
  }
1296
1664
 
1297
1665
  // src/utils/findAvailableContainers.ts
1298
- function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval) {
1666
+ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
1299
1667
  const numContainers = peek$(ctx, "numContainers");
1668
+ const { stickyContainerPool, containerItemTypes } = state;
1300
1669
  const result = [];
1301
1670
  const availableContainers = [];
1302
- for (let u = 0; u < numContainers; u++) {
1671
+ const stickyIndicesSet = state.props.stickyIndicesSet;
1672
+ const stickyItemIndices = (needNewContainers == null ? void 0 : needNewContainers.filter((index) => stickyIndicesSet.has(index))) || [];
1673
+ const canReuseContainer = (containerIndex, requiredType) => {
1674
+ if (!requiredType) return true;
1675
+ const existingType = containerItemTypes.get(containerIndex);
1676
+ if (!existingType) return true;
1677
+ return existingType === requiredType;
1678
+ };
1679
+ const neededTypes = requiredItemTypes ? [...requiredItemTypes] : [];
1680
+ let typeIndex = 0;
1681
+ for (let i = 0; i < stickyItemIndices.length; i++) {
1682
+ const requiredType = neededTypes[typeIndex];
1683
+ let foundContainer = false;
1684
+ for (const containerIndex of stickyContainerPool) {
1685
+ const key = peek$(ctx, `containerItemKey${containerIndex}`);
1686
+ const isPendingRemoval = pendingRemoval.includes(containerIndex);
1687
+ if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType)) {
1688
+ result.push(containerIndex);
1689
+ if (isPendingRemoval) {
1690
+ const index = pendingRemoval.indexOf(containerIndex);
1691
+ pendingRemoval.splice(index, 1);
1692
+ }
1693
+ foundContainer = true;
1694
+ if (requiredItemTypes) typeIndex++;
1695
+ break;
1696
+ }
1697
+ }
1698
+ if (!foundContainer) {
1699
+ const newContainerIndex = numContainers + result.filter((index) => index >= numContainers).length;
1700
+ result.push(newContainerIndex);
1701
+ stickyContainerPool.add(newContainerIndex);
1702
+ if (requiredItemTypes) typeIndex++;
1703
+ }
1704
+ }
1705
+ for (let u = 0; u < numContainers && result.length < numNeeded; u++) {
1706
+ if (stickyContainerPool.has(u)) {
1707
+ continue;
1708
+ }
1303
1709
  const key = peek$(ctx, `containerItemKey${u}`);
1304
1710
  let isOk = key === void 0;
1305
1711
  if (!isOk) {
1306
1712
  const index = pendingRemoval.indexOf(u);
1307
1713
  if (index !== -1) {
1308
1714
  pendingRemoval.splice(index, 1);
1309
- isOk = true;
1715
+ const requiredType = neededTypes[typeIndex];
1716
+ isOk = canReuseContainer(u, requiredType);
1310
1717
  }
1311
1718
  }
1312
1719
  if (isOk) {
1313
1720
  result.push(u);
1314
- if (result.length >= numNeeded) {
1315
- return result;
1721
+ if (requiredItemTypes) {
1722
+ typeIndex++;
1316
1723
  }
1317
1724
  }
1318
1725
  }
1319
- for (let u = 0; u < numContainers; u++) {
1726
+ for (let u = 0; u < numContainers && result.length < numNeeded; u++) {
1727
+ if (stickyContainerPool.has(u)) {
1728
+ continue;
1729
+ }
1320
1730
  const key = peek$(ctx, `containerItemKey${u}`);
1321
1731
  if (key === void 0) continue;
1322
1732
  const index = state.indexByKey.get(key);
1323
- if (index < startBuffered) {
1324
- availableContainers.push({ distance: startBuffered - index, index: u });
1325
- } else if (index > endBuffered) {
1326
- availableContainers.push({ distance: index - endBuffered, index: u });
1733
+ const isOutOfView = index < startBuffered || index > endBuffered;
1734
+ if (isOutOfView) {
1735
+ const distance = index < startBuffered ? startBuffered - index : index - endBuffered;
1736
+ if (!requiredItemTypes || typeIndex < neededTypes.length && canReuseContainer(u, neededTypes[typeIndex])) {
1737
+ availableContainers.push({ distance, index: u });
1738
+ }
1327
1739
  }
1328
1740
  }
1329
1741
  const remaining = numNeeded - result.length;
@@ -1335,6 +1747,9 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1335
1747
  }
1336
1748
  for (const container of availableContainers) {
1337
1749
  result.push(container.index);
1750
+ if (requiredItemTypes) {
1751
+ typeIndex++;
1752
+ }
1338
1753
  }
1339
1754
  }
1340
1755
  const stillNeeded = numNeeded - result.length;
@@ -1363,37 +1778,44 @@ function comparatorByDistance(a, b) {
1363
1778
  return b.distance - a.distance;
1364
1779
  }
1365
1780
 
1366
- // src/core/finishScrollTo.ts
1367
- var finishScrollTo = (state) => {
1368
- if (state) {
1369
- state.scrollingTo = void 0;
1370
- state.scrollHistory.length = 0;
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
+ }
1371
1815
  }
1816
+ return velocity;
1372
1817
  };
1373
1818
 
1374
- // src/core/scrollTo.ts
1375
- function scrollTo(state, params = {}) {
1376
- var _a;
1377
- const { animated } = params;
1378
- const {
1379
- refScroller,
1380
- props: { horizontal }
1381
- } = state;
1382
- const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
1383
- state.scrollHistory.length = 0;
1384
- state.scrollingTo = params;
1385
- state.scrollPending = offset;
1386
- (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
1387
- animated: !!animated,
1388
- x: horizontal ? offset : 0,
1389
- y: horizontal ? 0 : offset
1390
- });
1391
- if (!animated) {
1392
- state.scroll = offset;
1393
- setTimeout(() => finishScrollTo(state), 100);
1394
- }
1395
- }
1396
-
1397
1819
  // src/core/scrollToIndex.ts
1398
1820
  function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
1399
1821
  if (index >= state.props.data.length) {
@@ -1481,33 +1903,101 @@ function setDidLayout(ctx, state) {
1481
1903
  } = state;
1482
1904
  state.queuedInitialLayout = true;
1483
1905
  checkAtBottom(ctx, state);
1484
- if (!IsNewArchitecture && initialScroll) {
1485
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1906
+ const setIt = () => {
1907
+ set$(ctx, "containersDidLayout", true);
1908
+ if (onLoad) {
1909
+ onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1910
+ }
1911
+ };
1912
+ {
1913
+ setIt();
1914
+ }
1915
+ }
1916
+
1917
+ // src/core/calculateItemsInView.ts
1918
+ function findCurrentStickyIndex(stickyArray, scroll, state) {
1919
+ var _a;
1920
+ const idCache = state.idCache;
1921
+ const positions = state.positions;
1922
+ for (let i = stickyArray.length - 1; i >= 0; i--) {
1923
+ const stickyId = (_a = idCache.get(stickyArray[i])) != null ? _a : getId(state, stickyArray[i]);
1924
+ const stickyPos = stickyId ? positions.get(stickyId) : void 0;
1925
+ if (stickyPos !== void 0 && scroll >= stickyPos) {
1926
+ return i;
1927
+ }
1928
+ }
1929
+ return -1;
1930
+ }
1931
+ function getActiveStickyIndices(ctx, state, stickyIndices) {
1932
+ return new Set(
1933
+ 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
+ );
1935
+ }
1936
+ function handleStickyActivation(ctx, state, stickyIndices, stickyArray, scroll, needNewContainers, startBuffered, endBuffered) {
1937
+ var _a;
1938
+ const activeIndices = getActiveStickyIndices(ctx, state, stickyIndices);
1939
+ const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
1940
+ for (let offset = 0; offset <= 1; offset++) {
1941
+ const idx = currentStickyIdx - offset;
1942
+ if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
1943
+ const stickyIndex = stickyArray[idx];
1944
+ const stickyId = (_a = state.idCache.get(stickyIndex)) != null ? _a : getId(state, stickyIndex);
1945
+ if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered)) {
1946
+ needNewContainers.push(stickyIndex);
1947
+ }
1486
1948
  }
1487
- set$(ctx, "containersDidLayout", true);
1488
- if (onLoad) {
1489
- onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1949
+ }
1950
+ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, pendingRemoval) {
1951
+ var _a, _b, _c;
1952
+ const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
1953
+ for (const containerIndex of state.stickyContainerPool) {
1954
+ const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
1955
+ const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
1956
+ if (itemIndex === void 0) continue;
1957
+ const arrayIdx = stickyArray.indexOf(itemIndex);
1958
+ if (arrayIdx === -1) continue;
1959
+ const isRecentSticky = arrayIdx >= currentStickyIdx - 1 && arrayIdx <= currentStickyIdx + 1;
1960
+ if (isRecentSticky) continue;
1961
+ const nextIndex = stickyArray[arrayIdx + 1];
1962
+ let shouldRecycle = false;
1963
+ if (nextIndex) {
1964
+ const nextId = (_a = state.idCache.get(nextIndex)) != null ? _a : getId(state, nextIndex);
1965
+ const nextPos = nextId ? state.positions.get(nextId) : void 0;
1966
+ shouldRecycle = nextPos !== void 0 && scroll > nextPos + scrollBuffer * 2;
1967
+ } else {
1968
+ const currentId = (_b = state.idCache.get(itemIndex)) != null ? _b : getId(state, itemIndex);
1969
+ if (currentId) {
1970
+ const currentPos = state.positions.get(currentId);
1971
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(state, currentId, itemIndex, state.props.data[itemIndex]);
1972
+ shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
1973
+ }
1974
+ }
1975
+ if (shouldRecycle) {
1976
+ pendingRemoval.push(containerIndex);
1977
+ }
1490
1978
  }
1491
1979
  }
1492
-
1493
- // src/core/calculateItemsInView.ts
1494
1980
  function calculateItemsInView(ctx, state, params = {}) {
1495
- reactNative.unstable_batchedUpdates(() => {
1981
+ reactDom.unstable_batchedUpdates(() => {
1496
1982
  var _a, _b, _c, _d, _e, _f, _g, _h;
1497
1983
  const {
1498
- scrollLength,
1499
- startBufferedId: startBufferedIdOrig,
1500
- positions,
1501
1984
  columns,
1502
1985
  containerItemKeys,
1986
+ enableScrollForNextCalculateItemsInView,
1503
1987
  idCache,
1504
- sizes,
1505
1988
  indexByKey,
1989
+ minIndexSizeChanged,
1990
+ positions,
1506
1991
  scrollForNextCalculateItemsInView,
1507
- enableScrollForNextCalculateItemsInView,
1508
- minIndexSizeChanged
1992
+ scrollLength,
1993
+ sizes,
1994
+ startBufferedId: startBufferedIdOrig,
1995
+ viewabilityConfigCallbackPairs,
1996
+ props: { getItemType, initialScroll, itemsAreEqual, keyExtractor, scrollBuffer }
1509
1997
  } = state;
1510
- const data = state.props.data;
1998
+ const { data } = state.props;
1999
+ const stickyIndicesArr = state.props.stickyIndicesArr || [];
2000
+ const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
1511
2001
  const prevNumContainers = peek$(ctx, "numContainers");
1512
2002
  if (!data || scrollLength === 0 || !prevNumContainers) {
1513
2003
  return;
@@ -1519,14 +2009,22 @@ function calculateItemsInView(ctx, state, params = {}) {
1519
2009
  const { dataChanged, doMVCP } = params;
1520
2010
  const speed = getScrollVelocity(state);
1521
2011
  if (doMVCP || dataChanged) {
1522
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state) : void 0;
1523
- updateAllPositions(ctx, state, 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
+ }
1524
2023
  checkMVCP == null ? void 0 : checkMVCP();
1525
2024
  }
1526
2025
  const scrollExtra = 0;
1527
2026
  const { queuedInitialLayout } = state;
1528
2027
  let { scroll: scrollState } = state;
1529
- const initialScroll = state.props.initialScroll;
1530
2028
  if (!queuedInitialLayout && initialScroll) {
1531
2029
  const updatedOffset = calculateOffsetWithOffsetPosition(
1532
2030
  state,
@@ -1538,16 +2036,15 @@ function calculateItemsInView(ctx, state, params = {}) {
1538
2036
  const scrollAdjustPad = -previousScrollAdjust - topPad;
1539
2037
  let scroll = scrollState + scrollExtra + scrollAdjustPad;
1540
2038
  if (scroll + scrollLength > totalSize) {
1541
- scroll = totalSize - scrollLength;
2039
+ scroll = Math.max(0, totalSize - scrollLength);
1542
2040
  }
1543
2041
  if (ENABLE_DEBUG_VIEW) {
1544
2042
  set$(ctx, "debugRawScroll", scrollState);
1545
2043
  set$(ctx, "debugComputedScroll", scroll);
1546
2044
  }
1547
- const scrollBuffer = state.props.scrollBuffer;
1548
2045
  let scrollBufferTop = scrollBuffer;
1549
2046
  let scrollBufferBottom = scrollBuffer;
1550
- if (speed > 0) {
2047
+ if (speed > 0 || speed === 0 && scroll < Math.max(50, scrollBuffer)) {
1551
2048
  scrollBufferTop = scrollBuffer * 0.5;
1552
2049
  scrollBufferBottom = scrollBuffer * 1.5;
1553
2050
  } else {
@@ -1555,7 +2052,7 @@ function calculateItemsInView(ctx, state, params = {}) {
1555
2052
  scrollBufferBottom = scrollBuffer * 0.5;
1556
2053
  }
1557
2054
  const scrollTopBuffered = scroll - scrollBufferTop;
1558
- const scrollBottom = scroll + scrollLength;
2055
+ const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
1559
2056
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
1560
2057
  if (scrollForNextCalculateItemsInView) {
1561
2058
  const { top, bottom } = scrollForNextCalculateItemsInView;
@@ -1569,10 +2066,6 @@ function calculateItemsInView(ctx, state, params = {}) {
1569
2066
  let endNoBuffer = null;
1570
2067
  let endBuffered = null;
1571
2068
  let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
1572
- if (minIndexSizeChanged !== void 0) {
1573
- loopStart = Math.min(minIndexSizeChanged, loopStart);
1574
- state.minIndexSizeChanged = void 0;
1575
- }
1576
2069
  for (let i = loopStart; i >= 0; i--) {
1577
2070
  const id = (_a = idCache.get(i)) != null ? _a : getId(state, i);
1578
2071
  const top = positions.get(id);
@@ -1655,7 +2148,7 @@ function calculateItemsInView(ctx, state, params = {}) {
1655
2148
  if (dataChanged) {
1656
2149
  for (let i = 0; i < numContainers; i++) {
1657
2150
  const itemKey = peek$(ctx, `containerItemKey${i}`);
1658
- if (!state.props.keyExtractor || itemKey && indexByKey.get(itemKey) === void 0) {
2151
+ if (!keyExtractor || itemKey && indexByKey.get(itemKey) === void 0) {
1659
2152
  pendingRemoval.push(i);
1660
2153
  }
1661
2154
  }
@@ -1669,14 +2162,32 @@ function calculateItemsInView(ctx, state, params = {}) {
1669
2162
  needNewContainers.push(i);
1670
2163
  }
1671
2164
  }
2165
+ if (stickyIndicesArr.length > 0) {
2166
+ handleStickyActivation(
2167
+ ctx,
2168
+ state,
2169
+ stickyIndicesSet,
2170
+ stickyIndicesArr,
2171
+ scroll,
2172
+ needNewContainers,
2173
+ startBuffered,
2174
+ endBuffered
2175
+ );
2176
+ }
1672
2177
  if (needNewContainers.length > 0) {
2178
+ const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
2179
+ const itemType = getItemType(data[i], i);
2180
+ return itemType ? String(itemType) : "";
2181
+ }) : void 0;
1673
2182
  const availableContainers = findAvailableContainers(
1674
2183
  ctx,
1675
2184
  state,
1676
2185
  needNewContainers.length,
1677
2186
  startBuffered,
1678
2187
  endBuffered,
1679
- pendingRemoval
2188
+ pendingRemoval,
2189
+ requiredItemTypes,
2190
+ needNewContainers
1680
2191
  );
1681
2192
  for (let idx = 0; idx < needNewContainers.length; idx++) {
1682
2193
  const i = needNewContainers[idx];
@@ -1688,7 +2199,18 @@ function calculateItemsInView(ctx, state, params = {}) {
1688
2199
  }
1689
2200
  set$(ctx, `containerItemKey${containerIndex}`, id);
1690
2201
  set$(ctx, `containerItemData${containerIndex}`, data[i]);
2202
+ if (requiredItemTypes) {
2203
+ state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
2204
+ }
1691
2205
  containerItemKeys.add(id);
2206
+ if (stickyIndicesSet.has(i)) {
2207
+ set$(ctx, `containerSticky${containerIndex}`, true);
2208
+ const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
2209
+ set$(ctx, `containerStickyOffset${containerIndex}`, createAnimatedValue(topPadding));
2210
+ state.stickyContainerPool.add(containerIndex);
2211
+ } else {
2212
+ state.stickyContainerPool.delete(containerIndex);
2213
+ }
1692
2214
  if (containerIndex >= numContainers2) {
1693
2215
  numContainers2 = containerIndex + 1;
1694
2216
  }
@@ -1701,12 +2223,22 @@ function calculateItemsInView(ctx, state, params = {}) {
1701
2223
  }
1702
2224
  }
1703
2225
  }
2226
+ if (stickyIndicesArr.length > 0) {
2227
+ handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, pendingRemoval);
2228
+ }
2229
+ let didChangePositions = false;
1704
2230
  for (let i = 0; i < numContainers; i++) {
1705
2231
  const itemKey = peek$(ctx, `containerItemKey${i}`);
1706
2232
  if (pendingRemoval.includes(i)) {
1707
2233
  if (itemKey) {
1708
2234
  containerItemKeys.delete(itemKey);
1709
2235
  }
2236
+ state.containerItemTypes.delete(i);
2237
+ if (state.stickyContainerPool.has(i)) {
2238
+ set$(ctx, `containerSticky${i}`, false);
2239
+ set$(ctx, `containerStickyOffset${i}`, void 0);
2240
+ state.stickyContainerPool.delete(i);
2241
+ }
1710
2242
  set$(ctx, `containerItemKey${i}`, void 0);
1711
2243
  set$(ctx, `containerItemData${i}`, void 0);
1712
2244
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
@@ -1726,58 +2258,75 @@ function calculateItemsInView(ctx, state, params = {}) {
1726
2258
  const prevData = peek$(ctx, `containerItemData${i}`);
1727
2259
  if (position > POSITION_OUT_OF_VIEW && position !== prevPos) {
1728
2260
  set$(ctx, `containerPosition${i}`, position);
2261
+ didChangePositions = true;
1729
2262
  }
1730
2263
  if (column >= 0 && column !== prevColumn) {
1731
2264
  set$(ctx, `containerColumn${i}`, column);
1732
2265
  }
1733
- if (prevData !== item) {
2266
+ if (prevData !== item && (itemsAreEqual ? !itemsAreEqual(prevData, item, itemIndex, data) : true)) {
1734
2267
  set$(ctx, `containerItemData${i}`, data[itemIndex]);
1735
2268
  }
1736
2269
  }
1737
2270
  }
1738
2271
  }
1739
2272
  }
2273
+ if (didChangePositions) {
2274
+ set$(ctx, "lastPositionUpdate", Date.now());
2275
+ }
1740
2276
  if (!queuedInitialLayout && endBuffered !== null) {
1741
2277
  if (checkAllSizesKnown(state)) {
1742
2278
  setDidLayout(ctx, state);
1743
2279
  }
1744
2280
  }
1745
- if (state.viewabilityConfigCallbackPairs) {
1746
- updateViewableItems(
1747
- state,
1748
- ctx,
1749
- state.viewabilityConfigCallbackPairs,
1750
- scrollLength,
1751
- startNoBuffer,
1752
- endNoBuffer
1753
- );
2281
+ if (viewabilityConfigCallbackPairs) {
2282
+ updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollLength, startNoBuffer, endNoBuffer);
1754
2283
  }
1755
2284
  });
1756
2285
  }
1757
2286
 
1758
2287
  // src/core/doInitialAllocateContainers.ts
1759
2288
  function doInitialAllocateContainers(ctx, state) {
1760
- const { scrollLength } = state;
1761
- const data = state.props.data;
1762
- if (scrollLength > 0 && data.length > 0 && !peek$(ctx, "numContainers")) {
1763
- const averageItemSize = state.props.getEstimatedItemSize ? state.props.getEstimatedItemSize(0, data[0]) : state.props.estimatedItemSize;
1764
- const Extra = 1.5;
1765
- const numContainers = Math.ceil(
1766
- (scrollLength + state.props.scrollBuffer * 2) / averageItemSize * state.props.numColumns * Extra
1767
- );
2289
+ var _a;
2290
+ const {
2291
+ scrollLength,
2292
+ props: {
2293
+ data,
2294
+ getEstimatedItemSize,
2295
+ getFixedItemSize,
2296
+ getItemType,
2297
+ scrollBuffer,
2298
+ numColumns,
2299
+ estimatedItemSize
2300
+ }
2301
+ } = state;
2302
+ const hasContainers = peek$(ctx, "numContainers");
2303
+ if (scrollLength > 0 && data.length > 0 && !hasContainers) {
2304
+ let averageItemSize;
2305
+ const fn = getFixedItemSize || getEstimatedItemSize;
2306
+ if (fn) {
2307
+ let totalSize = 0;
2308
+ const num = Math.min(20, data.length);
2309
+ for (let i = 0; i < num; i++) {
2310
+ totalSize += fn(0, data[0], getItemType ? (_a = getItemType(data[0], 0)) != null ? _a : "" : "");
2311
+ }
2312
+ averageItemSize = totalSize / num;
2313
+ } else {
2314
+ averageItemSize = estimatedItemSize;
2315
+ }
2316
+ const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize * numColumns);
1768
2317
  for (let i = 0; i < numContainers; i++) {
1769
2318
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1770
2319
  set$(ctx, `containerColumn${i}`, -1);
1771
2320
  }
1772
2321
  set$(ctx, "numContainers", numContainers);
1773
2322
  set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
1774
- if (!IsNewArchitecture) {
2323
+ if (state.lastLayout) {
1775
2324
  if (state.props.initialScroll) {
1776
2325
  requestAnimationFrame(() => {
1777
- calculateItemsInView(ctx, state);
2326
+ calculateItemsInView(ctx, state, { dataChanged: true });
1778
2327
  });
1779
2328
  } else {
1780
- calculateItemsInView(ctx, state);
2329
+ calculateItemsInView(ctx, state, { dataChanged: true });
1781
2330
  }
1782
2331
  }
1783
2332
  return true;
@@ -1797,16 +2346,18 @@ function doMaintainScrollAtEnd(ctx, state, animated) {
1797
2346
  }
1798
2347
  requestAnimationFrame(() => {
1799
2348
  var _a;
1800
- state.maintainingScrollAtEnd = true;
1801
- (_a = refScroller.current) == null ? void 0 : _a.scrollToEnd({
1802
- animated
1803
- });
1804
- setTimeout(
1805
- () => {
1806
- state.maintainingScrollAtEnd = false;
1807
- },
1808
- 0
1809
- );
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
+ }
1810
2361
  });
1811
2362
  return true;
1812
2363
  }
@@ -1843,44 +2394,57 @@ function checkAtTop(state) {
1843
2394
  // src/core/handleLayout.ts
1844
2395
  function handleLayout(ctx, state, layout, setCanRender) {
1845
2396
  const { maintainScrollAtEnd } = state.props;
1846
- const scrollLength = layout[state.props.horizontal ? "width" : "height"];
2397
+ const measuredLength = layout[state.props.horizontal ? "width" : "height"];
2398
+ const previousLength = state.scrollLength;
2399
+ const scrollLength = measuredLength > 0 ? measuredLength : previousLength;
1847
2400
  const otherAxisSize = layout[state.props.horizontal ? "height" : "width"];
1848
2401
  const needsCalculate = !state.lastLayout || scrollLength > state.scrollLength || state.lastLayout.x !== layout.x || state.lastLayout.y !== layout.y;
1849
2402
  state.lastLayout = layout;
1850
- const didChange = scrollLength !== state.scrollLength;
1851
2403
  const prevOtherAxisSize = state.otherAxisSize;
1852
- state.scrollLength = scrollLength;
1853
- state.otherAxisSize = otherAxisSize;
1854
- state.lastBatchingAction = Date.now();
1855
- state.scrollForNextCalculateItemsInView = void 0;
1856
- doInitialAllocateContainers(ctx, state);
1857
- if (needsCalculate) {
1858
- calculateItemsInView(ctx, state, { doMVCP: true });
1859
- }
1860
- if (didChange || otherAxisSize !== prevOtherAxisSize) {
1861
- set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
1862
- }
1863
- if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
1864
- doMaintainScrollAtEnd(ctx, state, false);
1865
- }
1866
- updateAlignItemsPaddingTop(ctx, state);
1867
- checkAtBottom(ctx, state);
1868
- checkAtTop(state);
1869
- if (state) {
1870
- state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
1871
- }
1872
- if (__DEV__ && scrollLength === 0) {
1873
- warnDevOnce(
1874
- "height0",
1875
- `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.`
1876
- );
2404
+ const didChange = scrollLength !== state.scrollLength || otherAxisSize !== prevOtherAxisSize;
2405
+ if (didChange) {
2406
+ state.scrollLength = scrollLength;
2407
+ state.otherAxisSize = otherAxisSize;
2408
+ state.lastBatchingAction = Date.now();
2409
+ state.scrollForNextCalculateItemsInView = void 0;
2410
+ if (scrollLength > 0) {
2411
+ doInitialAllocateContainers(ctx, state);
2412
+ }
2413
+ if (needsCalculate) {
2414
+ calculateItemsInView(ctx, state, { doMVCP: true });
2415
+ }
2416
+ if (didChange || otherAxisSize !== prevOtherAxisSize) {
2417
+ set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
2418
+ }
2419
+ if (maintainScrollAtEnd === true || maintainScrollAtEnd.onLayout) {
2420
+ doMaintainScrollAtEnd(ctx, state, false);
2421
+ }
2422
+ updateAlignItemsPaddingTop(ctx, state);
2423
+ checkAtBottom(ctx, state);
2424
+ checkAtTop(state);
2425
+ if (state) {
2426
+ state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
2427
+ }
2428
+ if (__DEV__ && measuredLength === 0) {
2429
+ warnDevOnce(
2430
+ "height0",
2431
+ `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
+ );
2433
+ }
2434
+ setCanRender(true);
1877
2435
  }
1878
- setCanRender(true);
1879
2436
  }
1880
2437
 
1881
2438
  // src/core/onScroll.ts
1882
2439
  function onScroll(ctx, state, event) {
1883
- var _a, _b, _c, _d, _e;
2440
+ var _a, _b, _c;
2441
+ const {
2442
+ scrollProcessingEnabled,
2443
+ props: { onScroll: onScrollProp }
2444
+ } = state;
2445
+ if (scrollProcessingEnabled === false) {
2446
+ return;
2447
+ }
1884
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) {
1885
2449
  return;
1886
2450
  }
@@ -1893,16 +2457,25 @@ function onScroll(ctx, state, event) {
1893
2457
  }
1894
2458
  }
1895
2459
  state.scrollPending = newScroll;
1896
- updateScroll(ctx, state, newScroll);
1897
- (_e = (_d = state.props).onScroll) == null ? void 0 : _e.call(_d, event);
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);
1898
2470
  }
1899
2471
  function updateScroll(ctx, state, newScroll) {
1900
2472
  const scrollingTo = state.scrollingTo;
1901
2473
  state.hasScrolled = true;
1902
2474
  state.lastBatchingAction = Date.now();
1903
- const currentTime = performance.now();
2475
+ const currentTime = Date.now();
1904
2476
  if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
1905
- state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2477
+ const adjust = state.scrollAdjustHandler.getAdjust();
2478
+ state.scrollHistory.push({ scroll: newScroll - adjust, time: currentTime });
1906
2479
  }
1907
2480
  if (state.scrollHistory.length > 5) {
1908
2481
  state.scrollHistory.shift();
@@ -1911,9 +2484,11 @@ function updateScroll(ctx, state, newScroll) {
1911
2484
  state.scrollPrevTime = state.scrollTime;
1912
2485
  state.scroll = newScroll;
1913
2486
  state.scrollTime = currentTime;
1914
- calculateItemsInView(ctx, state);
1915
- checkAtBottom(ctx, state);
1916
- checkAtTop(state);
2487
+ if (Math.abs(state.scroll - state.scrollPrev) > 2) {
2488
+ calculateItemsInView(ctx, state);
2489
+ checkAtBottom(ctx, state);
2490
+ checkAtTop(state);
2491
+ }
1917
2492
  }
1918
2493
 
1919
2494
  // src/core/ScrollAdjustHandler.ts
@@ -1936,13 +2511,19 @@ var ScrollAdjustHandler = class {
1936
2511
  setMounted() {
1937
2512
  this.mounted = true;
1938
2513
  }
2514
+ getAdjust() {
2515
+ return this.appliedAdjust;
2516
+ }
1939
2517
  };
1940
2518
 
1941
2519
  // src/core/updateItemSize.ts
1942
- function updateItemSizes(ctx, state, itemUpdates) {
1943
- var _a;
2520
+ function updateItemSize(ctx, state, itemKey, sizeObj) {
2521
+ var _a, _b;
1944
2522
  const {
2523
+ sizesKnown,
1945
2524
  props: {
2525
+ getFixedItemSize,
2526
+ getItemType,
1946
2527
  horizontal,
1947
2528
  maintainVisibleContentPosition,
1948
2529
  suggestEstimatedItemSize,
@@ -1952,47 +2533,60 @@ function updateItemSizes(ctx, state, itemUpdates) {
1952
2533
  }
1953
2534
  } = state;
1954
2535
  if (!data) return;
2536
+ if (getFixedItemSize) {
2537
+ const index2 = state.indexByKey.get(itemKey);
2538
+ if (index2 === void 0) {
2539
+ return;
2540
+ }
2541
+ const itemData = state.props.data[index2];
2542
+ if (itemData === void 0) {
2543
+ return;
2544
+ }
2545
+ const type = getItemType ? (_a = getItemType(itemData, index2)) != null ? _a : "" : "";
2546
+ const size2 = getFixedItemSize(index2, itemData, type);
2547
+ if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
2548
+ return;
2549
+ }
2550
+ }
1955
2551
  const containersDidLayout = peek$(ctx, "containersDidLayout");
1956
2552
  let needsRecalculate = !containersDidLayout;
1957
2553
  let shouldMaintainScrollAtEnd = false;
1958
2554
  let minIndexSizeChanged;
1959
2555
  let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
1960
- for (const { itemKey, sizeObj } of itemUpdates) {
1961
- const index = state.indexByKey.get(itemKey);
1962
- const prevSizeKnown = state.sizesKnown.get(itemKey);
1963
- const diff = updateOneItemSize(state, itemKey, sizeObj);
1964
- const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
1965
- if (diff !== 0) {
1966
- minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
1967
- if (((_a = state.scrollingTo) == null ? void 0 : _a.viewPosition) && maintainVisibleContentPosition && index === state.scrollingTo.index && diff > 0) {
1968
- requestAdjust(ctx, state, diff * state.scrollingTo.viewPosition);
1969
- }
1970
- const { startBuffered, endBuffered } = state;
1971
- needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
1972
- if (!needsRecalculate) {
1973
- const numContainers = ctx.values.get("numContainers");
1974
- for (let i = 0; i < numContainers; i++) {
1975
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
1976
- needsRecalculate = true;
1977
- break;
1978
- }
2556
+ const index = state.indexByKey.get(itemKey);
2557
+ 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;
2560
+ if (diff !== 0) {
2561
+ 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
+ const { startBuffered, endBuffered } = state;
2566
+ needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
2567
+ if (!needsRecalculate) {
2568
+ const numContainers = ctx.values.get("numContainers");
2569
+ for (let i = 0; i < numContainers; i++) {
2570
+ if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
2571
+ needsRecalculate = true;
2572
+ break;
1979
2573
  }
1980
2574
  }
1981
- if (state.needsOtherAxisSize) {
1982
- const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
1983
- maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
1984
- }
1985
- if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
1986
- shouldMaintainScrollAtEnd = true;
1987
- }
1988
- onItemSizeChanged == null ? void 0 : onItemSizeChanged({
1989
- index,
1990
- itemData: state.props.data[index],
1991
- itemKey,
1992
- previous: size - diff,
1993
- size
1994
- });
1995
2575
  }
2576
+ if (state.needsOtherAxisSize) {
2577
+ const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
2578
+ maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
2579
+ }
2580
+ if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2581
+ shouldMaintainScrollAtEnd = true;
2582
+ }
2583
+ onItemSizeChanged == null ? void 0 : onItemSizeChanged({
2584
+ index,
2585
+ itemData: state.props.data[index],
2586
+ itemKey,
2587
+ previous: size - diff,
2588
+ size
2589
+ });
1996
2590
  }
1997
2591
  if (minIndexSizeChanged !== void 0) {
1998
2592
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
@@ -2025,43 +2619,30 @@ function updateItemSizes(ctx, state, itemUpdates) {
2025
2619
  }
2026
2620
  }
2027
2621
  }
2028
- function updateItemSize(ctx, state, itemKey, sizeObj) {
2029
- const { queuedItemSizeUpdates, queuedItemSizeUpdatesWaiting } = state;
2030
- const containersDidLayout = peek$(ctx, "containersDidLayout");
2031
- if (!containersDidLayout || !queuedItemSizeUpdatesWaiting) {
2032
- updateItemSizes(ctx, state, [{ itemKey, sizeObj }]);
2033
- if (containersDidLayout) {
2034
- state.queuedItemSizeUpdatesWaiting = true;
2035
- requestAnimationFrame(() => {
2036
- state.queuedItemSizeUpdatesWaiting = false;
2037
- updateItemSizes(ctx, state, queuedItemSizeUpdates);
2038
- queuedItemSizeUpdates.length = 0;
2039
- });
2040
- }
2041
- } else {
2042
- queuedItemSizeUpdates.push({ itemKey, sizeObj });
2043
- }
2044
- }
2045
2622
  function updateOneItemSize(state, itemKey, sizeObj) {
2623
+ var _a;
2046
2624
  const {
2047
2625
  sizes,
2048
2626
  indexByKey,
2049
2627
  sizesKnown,
2050
2628
  averageSizes,
2051
- props: { data, horizontal }
2629
+ props: { data, horizontal, getEstimatedItemSize, getItemType, getFixedItemSize }
2052
2630
  } = state;
2053
2631
  if (!data) return 0;
2054
2632
  const index = indexByKey.get(itemKey);
2055
2633
  const prevSize = getItemSize(state, itemKey, index, data);
2056
- const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2634
+ const rawSize = horizontal ? sizeObj.width : sizeObj.height;
2635
+ const size = Math.round(rawSize) ;
2057
2636
  sizesKnown.set(itemKey, size);
2058
- const itemType = "";
2059
- let averages = averageSizes[itemType];
2060
- if (!averages) {
2061
- averages = averageSizes[itemType] = { avg: 0, num: 0 };
2637
+ if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
2638
+ const itemType = getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : "";
2639
+ let averages = averageSizes[itemType];
2640
+ if (!averages) {
2641
+ averages = averageSizes[itemType] = { avg: 0, num: 0 };
2642
+ }
2643
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2644
+ averages.num++;
2062
2645
  }
2063
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2064
- averages.num++;
2065
2646
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2066
2647
  sizes.set(itemKey, size);
2067
2648
  return size - prevSize;
@@ -2069,7 +2650,7 @@ function updateOneItemSize(state, itemKey, sizeObj) {
2069
2650
  return 0;
2070
2651
  }
2071
2652
  var useCombinedRef = (...refs) => {
2072
- const callback = React3.useCallback((element) => {
2653
+ const callback = React4.useCallback((element) => {
2073
2654
  for (const ref of refs) {
2074
2655
  if (!ref) {
2075
2656
  continue;
@@ -2084,6 +2665,22 @@ var useCombinedRef = (...refs) => {
2084
2665
  return callback;
2085
2666
  };
2086
2667
 
2668
+ // src/platform/RefreshControl.tsx
2669
+ function RefreshControl(props) {
2670
+ return null;
2671
+ }
2672
+
2673
+ // src/platform/StyleSheet.tsx
2674
+ var StyleSheet = {
2675
+ create: (styles) => styles,
2676
+ flatten: (style) => style
2677
+ };
2678
+
2679
+ // src/platform/useStickyScrollHandler.ts
2680
+ function useStickyScrollHandler(stickyIndices, horizontal, ctx, onScroll2) {
2681
+ return onScroll2;
2682
+ }
2683
+
2087
2684
  // src/utils/createColumnWrapperStyle.ts
2088
2685
  function createColumnWrapperStyle(contentContainerStyle) {
2089
2686
  const { gap, columnGap, rowGap } = contentContainerStyle;
@@ -2099,162 +2696,290 @@ function createColumnWrapperStyle(contentContainerStyle) {
2099
2696
  }
2100
2697
  }
2101
2698
  function getRenderedItem(ctx, state, key) {
2699
+ var _a;
2102
2700
  if (!state) {
2103
2701
  return null;
2104
2702
  }
2105
2703
  const {
2106
2704
  indexByKey,
2107
- props: { data, renderItem: renderItem2 }
2705
+ props: { data, getItemType, renderItem }
2108
2706
  } = state;
2109
2707
  const index = indexByKey.get(key);
2110
2708
  if (index === void 0) {
2111
2709
  return null;
2112
2710
  }
2113
2711
  let renderedItem = null;
2114
- if (renderItem2) {
2712
+ if (renderItem && data[index]) {
2115
2713
  const itemProps = {
2714
+ data,
2116
2715
  extraData: peek$(ctx, "extraData"),
2117
2716
  index,
2118
- item: data[index]
2717
+ item: data[index],
2718
+ type: getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : ""
2119
2719
  };
2120
- renderedItem = React3__namespace.default.createElement(renderItem2, itemProps);
2720
+ renderedItem = isFunction(renderItem) ? renderItem(itemProps) : React4__namespace.default.createElement(renderItem, itemProps);
2121
2721
  }
2122
2722
  return { index, item: data[index], renderedItem };
2123
2723
  }
2724
+ function useThrottleDebounce(mode) {
2725
+ const timeoutRef = React4.useRef(null);
2726
+ const lastCallTimeRef = React4.useRef(0);
2727
+ const lastArgsRef = React4.useRef(null);
2728
+ const clearTimeoutRef = () => {
2729
+ if (timeoutRef.current) {
2730
+ clearTimeout(timeoutRef.current);
2731
+ timeoutRef.current = null;
2732
+ }
2733
+ };
2734
+ const execute = React4.useCallback(
2735
+ (callback, delay, ...args) => {
2736
+ {
2737
+ const now = Date.now();
2738
+ lastArgsRef.current = args;
2739
+ if (now - lastCallTimeRef.current >= delay) {
2740
+ lastCallTimeRef.current = now;
2741
+ callback(...args);
2742
+ clearTimeoutRef();
2743
+ } else {
2744
+ clearTimeoutRef();
2745
+ timeoutRef.current = setTimeout(
2746
+ () => {
2747
+ if (lastArgsRef.current) {
2748
+ lastCallTimeRef.current = Date.now();
2749
+ callback(...lastArgsRef.current);
2750
+ timeoutRef.current = null;
2751
+ lastArgsRef.current = null;
2752
+ }
2753
+ },
2754
+ delay - (now - lastCallTimeRef.current)
2755
+ );
2756
+ }
2757
+ }
2758
+ },
2759
+ [mode]
2760
+ );
2761
+ return execute;
2762
+ }
2763
+
2764
+ // src/utils/throttledOnScroll.ts
2765
+ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
2766
+ const throttle = useThrottleDebounce("throttle");
2767
+ return (event) => throttle(originalHandler, scrollEventThrottle, { nativeEvent: event.nativeEvent });
2768
+ }
2769
+
2770
+ // src/utils/updateAveragesOnDataChange.ts
2771
+ function updateAveragesOnDataChange(state, oldData, newData) {
2772
+ var _a;
2773
+ const {
2774
+ averageSizes,
2775
+ sizesKnown,
2776
+ indexByKey,
2777
+ props: { itemsAreEqual, getItemType, keyExtractor }
2778
+ } = state;
2779
+ if (!itemsAreEqual || !oldData.length || !newData.length) {
2780
+ for (const key in averageSizes) {
2781
+ delete averageSizes[key];
2782
+ }
2783
+ return;
2784
+ }
2785
+ const itemTypesToPreserve = {};
2786
+ const newDataLength = newData.length;
2787
+ const oldDataLength = oldData.length;
2788
+ for (let newIndex = 0; newIndex < newDataLength; newIndex++) {
2789
+ const newItem = newData[newIndex];
2790
+ const id = keyExtractor ? keyExtractor(newItem, newIndex) : String(newIndex);
2791
+ const oldIndex = indexByKey.get(id);
2792
+ if (oldIndex !== void 0 && oldIndex < oldDataLength) {
2793
+ const knownSize = sizesKnown.get(id);
2794
+ if (knownSize === void 0) continue;
2795
+ const oldItem = oldData[oldIndex];
2796
+ const areEqual = itemsAreEqual(oldItem, newItem, newIndex, newData);
2797
+ if (areEqual) {
2798
+ const itemType = getItemType ? (_a = getItemType(newItem, newIndex)) != null ? _a : "" : "";
2799
+ let typeData = itemTypesToPreserve[itemType];
2800
+ if (!typeData) {
2801
+ typeData = itemTypesToPreserve[itemType] = { count: 0, totalSize: 0 };
2802
+ }
2803
+ typeData.totalSize += knownSize;
2804
+ typeData.count++;
2805
+ }
2806
+ }
2807
+ }
2808
+ for (const key in averageSizes) {
2809
+ delete averageSizes[key];
2810
+ }
2811
+ for (const itemType in itemTypesToPreserve) {
2812
+ const { totalSize, count } = itemTypesToPreserve[itemType];
2813
+ if (count > 0) {
2814
+ averageSizes[itemType] = {
2815
+ avg: totalSize / count,
2816
+ num: count
2817
+ };
2818
+ }
2819
+ }
2820
+ }
2124
2821
 
2125
2822
  // src/components/LegendList.tsx
2126
2823
  var DEFAULT_DRAW_DISTANCE = 250;
2127
2824
  var DEFAULT_ITEM_SIZE = 100;
2128
- var LegendList = typedForwardRef(function LegendList2(props, forwardedRef) {
2129
- return /* @__PURE__ */ React3__namespace.createElement(StateProvider, null, /* @__PURE__ */ React3__namespace.createElement(LegendListInner, { ...props, ref: forwardedRef }));
2130
- });
2825
+ var LegendList = typedMemo(
2826
+ typedForwardRef(function LegendList2(props, forwardedRef) {
2827
+ const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
2828
+ const isChildrenMode = children !== void 0 && dataProp === void 0;
2829
+ const processedProps = isChildrenMode ? {
2830
+ ...restProps,
2831
+ data: (isArray(children) ? children : React4__namespace.Children.toArray(children)).flat(1),
2832
+ renderItem: ({ item }) => item
2833
+ } : {
2834
+ ...restProps,
2835
+ data: dataProp || [],
2836
+ renderItem: renderItemProp
2837
+ };
2838
+ return /* @__PURE__ */ React4__namespace.createElement(StateProvider, null, /* @__PURE__ */ React4__namespace.createElement(LegendListInner, { ...processedProps, ref: forwardedRef }));
2839
+ })
2840
+ );
2131
2841
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
2132
- var _a;
2133
2842
  const {
2134
- data: dataProp = [],
2135
- initialScrollIndex: initialScrollIndexProp,
2136
- initialScrollOffset,
2137
- horizontal,
2138
- drawDistance = 250,
2139
- recycleItems = false,
2140
- onEndReachedThreshold = 0.5,
2141
- onStartReachedThreshold = 0.5,
2142
- maintainScrollAtEnd = false,
2143
- maintainScrollAtEndThreshold = 0.1,
2144
2843
  alignItemsAtEnd = false,
2145
- maintainVisibleContentPosition = false,
2146
- onScroll: onScrollProp,
2147
- onMomentumScrollEnd,
2148
- numColumns: numColumnsProp = 1,
2149
2844
  columnWrapperStyle,
2150
- keyExtractor: keyExtractorProp,
2151
- renderItem: renderItem2,
2152
- estimatedListSize,
2845
+ contentContainerStyle: contentContainerStyleProp,
2846
+ data: dataProp = [],
2847
+ drawDistance = 250,
2848
+ enableAverages = true,
2153
2849
  estimatedItemSize: estimatedItemSizeProp,
2850
+ estimatedListSize,
2851
+ extraData,
2154
2852
  getEstimatedItemSize,
2155
- suggestEstimatedItemSize,
2156
- ListHeaderComponent,
2853
+ getFixedItemSize,
2854
+ getItemType,
2855
+ horizontal,
2856
+ initialContainerPoolRatio = 2,
2857
+ initialScrollIndex: initialScrollIndexProp,
2858
+ initialScrollOffset: initialScrollOffsetProp,
2859
+ itemsAreEqual,
2860
+ keyExtractor: keyExtractorProp,
2157
2861
  ListEmptyComponent,
2862
+ ListHeaderComponent,
2863
+ maintainScrollAtEnd = false,
2864
+ maintainScrollAtEndThreshold = 0.1,
2865
+ maintainVisibleContentPosition = true,
2866
+ numColumns: numColumnsProp = 1,
2867
+ onEndReached,
2868
+ onEndReachedThreshold = 0.5,
2158
2869
  onItemSizeChanged,
2159
- refScrollView,
2160
- waitForInitialLayout = true,
2161
- extraData,
2162
- contentContainerStyle: contentContainerStyleProp,
2163
- style: styleProp,
2164
2870
  onLayout: onLayoutProp,
2871
+ onLoad,
2872
+ onMomentumScrollEnd,
2165
2873
  onRefresh,
2166
- refreshing,
2874
+ onScroll: onScrollProp,
2875
+ onStartReached,
2876
+ onStartReachedThreshold = 0.5,
2167
2877
  progressViewOffset,
2878
+ recycleItems = false,
2168
2879
  refreshControl,
2169
- initialContainerPoolRatio = 2,
2170
- viewabilityConfig,
2171
- viewabilityConfigCallbackPairs,
2880
+ refreshing,
2881
+ refScrollView,
2882
+ renderItem,
2883
+ scrollEventThrottle,
2172
2884
  snapToIndices,
2173
- onViewableItemsChanged,
2174
- onStartReached,
2175
- onEndReached,
2176
- onLoad,
2885
+ stickyIndices,
2886
+ style: styleProp,
2887
+ suggestEstimatedItemSize,
2888
+ waitForInitialLayout = true,
2177
2889
  ...rest
2178
2890
  } = props;
2179
- const [renderNum, setRenderNum] = React3.useState(0);
2180
- const initialScroll = typeof initialScrollIndexProp === "number" ? { index: initialScrollIndexProp } : initialScrollIndexProp;
2181
- const initialScrollIndex = initialScroll == null ? void 0 : initialScroll.index;
2182
- const [canRender, setCanRender] = React3__namespace.useState(!IsNewArchitecture);
2183
- const contentContainerStyle = { ...reactNative.StyleSheet.flatten(contentContainerStyleProp) };
2184
- const style = { ...reactNative.StyleSheet.flatten(styleProp) };
2891
+ const [renderNum, setRenderNum] = React4.useState(0);
2892
+ const initialScroll = initialScrollIndexProp || initialScrollOffsetProp ? typeof initialScrollIndexProp === "object" ? { index: initialScrollIndexProp.index || 0, viewOffset: initialScrollIndexProp.viewOffset || 0 } : { index: initialScrollIndexProp || 0, viewOffset: initialScrollOffsetProp || 0 } : void 0;
2893
+ const [canRender, setCanRender] = React4__namespace.useState(!IsNewArchitecture);
2894
+ const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
2895
+ const style = { ...StyleSheet.flatten(styleProp) };
2185
2896
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
2186
2897
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
2187
2898
  const ctx = useStateContext();
2188
2899
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
2189
- const refScroller = React3.useRef(null);
2900
+ const refScroller = React4.useRef(null);
2190
2901
  const combinedRef = useCombinedRef(refScroller, refScrollView);
2191
2902
  const estimatedItemSize = estimatedItemSizeProp != null ? estimatedItemSizeProp : DEFAULT_ITEM_SIZE;
2192
2903
  const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
2193
2904
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (_item, index) => index.toString();
2194
- const refState = React3.useRef();
2905
+ const refState = React4.useRef();
2195
2906
  if (!refState.current) {
2196
- const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { height: 0, width: 0 } : reactNative.Dimensions.get("window"))[horizontal ? "width" : "height"];
2197
- refState.current = {
2198
- averageSizes: {},
2199
- columns: /* @__PURE__ */ new Map(),
2200
- containerItemKeys: /* @__PURE__ */ new Set(),
2201
- enableScrollForNextCalculateItemsInView: true,
2202
- endBuffered: -1,
2203
- endNoBuffer: -1,
2204
- endReachedBlockedByTimer: false,
2205
- firstFullyOnScreenIndex: -1,
2206
- idCache: /* @__PURE__ */ new Map(),
2207
- idsInView: [],
2208
- indexByKey: /* @__PURE__ */ new Map(),
2209
- initialScroll,
2210
- isAtEnd: false,
2211
- isAtStart: false,
2212
- isEndReached: false,
2213
- isStartReached: false,
2214
- lastBatchingAction: Date.now(),
2215
- lastLayout: void 0,
2216
- loadStartTime: Date.now(),
2217
- minIndexSizeChanged: 0,
2218
- nativeMarginTop: 0,
2219
- pendingAdjust: 0,
2220
- positions: /* @__PURE__ */ new Map(),
2221
- props: {},
2222
- queuedCalculateItemsInView: 0,
2223
- queuedItemSizeUpdates: [],
2224
- refScroller: void 0,
2225
- scroll: 0,
2226
- scrollAdjustHandler: new ScrollAdjustHandler(ctx),
2227
- scrollForNextCalculateItemsInView: void 0,
2228
- scrollHistory: [],
2229
- scrollLength: initialScrollLength,
2230
- scrollPending: 0,
2231
- scrollPrev: 0,
2232
- scrollPrevTime: 0,
2233
- scrollTime: 0,
2234
- sizes: /* @__PURE__ */ new Map(),
2235
- sizesKnown: /* @__PURE__ */ new Map(),
2236
- startBuffered: -1,
2237
- startNoBuffer: -1,
2238
- startReachedBlockedByTimer: false,
2239
- timeoutSizeMessage: 0,
2240
- timeouts: /* @__PURE__ */ new Set(),
2241
- totalSize: 0,
2242
- viewabilityConfigCallbackPairs: void 0
2243
- };
2244
- set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
2245
- set$(ctx, "extraData", extraData);
2907
+ if (!ctx.internalState) {
2908
+ const initialScrollLength = (estimatedListSize != null ? estimatedListSize : { height: 0, width: 0 } )[horizontal ? "width" : "height"];
2909
+ ctx.internalState = {
2910
+ activeStickyIndex: void 0,
2911
+ averageSizes: {},
2912
+ columns: /* @__PURE__ */ new Map(),
2913
+ containerItemKeys: /* @__PURE__ */ new Set(),
2914
+ containerItemTypes: /* @__PURE__ */ new Map(),
2915
+ enableScrollForNextCalculateItemsInView: true,
2916
+ endBuffered: -1,
2917
+ endNoBuffer: -1,
2918
+ endReachedBlockedByTimer: false,
2919
+ firstFullyOnScreenIndex: -1,
2920
+ idCache: /* @__PURE__ */ new Map(),
2921
+ idsInView: [],
2922
+ indexByKey: /* @__PURE__ */ new Map(),
2923
+ initialScroll,
2924
+ isAtEnd: false,
2925
+ isAtStart: false,
2926
+ isEndReached: false,
2927
+ isStartReached: false,
2928
+ lastBatchingAction: Date.now(),
2929
+ lastLayout: void 0,
2930
+ loadStartTime: Date.now(),
2931
+ minIndexSizeChanged: 0,
2932
+ nativeMarginTop: 0,
2933
+ positions: /* @__PURE__ */ new Map(),
2934
+ props: {},
2935
+ queuedCalculateItemsInView: 0,
2936
+ refScroller: void 0,
2937
+ scroll: 0,
2938
+ scrollAdjustHandler: new ScrollAdjustHandler(ctx),
2939
+ scrollForNextCalculateItemsInView: void 0,
2940
+ scrollHistory: [],
2941
+ scrollLength: initialScrollLength,
2942
+ scrollPending: 0,
2943
+ scrollPrev: 0,
2944
+ scrollPrevTime: 0,
2945
+ scrollProcessingEnabled: true,
2946
+ scrollTime: 0,
2947
+ sizes: /* @__PURE__ */ new Map(),
2948
+ sizesKnown: /* @__PURE__ */ new Map(),
2949
+ startBuffered: -1,
2950
+ startNoBuffer: -1,
2951
+ startReachedBlockedByTimer: false,
2952
+ stickyContainerPool: /* @__PURE__ */ new Set(),
2953
+ stickyContainers: /* @__PURE__ */ new Map(),
2954
+ timeoutSizeMessage: 0,
2955
+ timeouts: /* @__PURE__ */ new Set(),
2956
+ totalSize: 0,
2957
+ viewabilityConfigCallbackPairs: void 0
2958
+ };
2959
+ set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
2960
+ set$(ctx, "extraData", extraData);
2961
+ }
2962
+ refState.current = ctx.internalState;
2246
2963
  }
2247
2964
  const state = refState.current;
2248
2965
  const isFirst = !state.props.renderItem;
2249
2966
  const didDataChange = state.props.data !== dataProp;
2967
+ const throttleScrollFn = (
2968
+ // @ts-expect-error TODO Fix this
2969
+ scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp
2970
+ );
2250
2971
  state.props = {
2251
2972
  alignItemsAtEnd,
2252
2973
  data: dataProp,
2974
+ enableAverages,
2253
2975
  estimatedItemSize,
2254
2976
  getEstimatedItemSize,
2977
+ getFixedItemSize,
2978
+ getItemType,
2255
2979
  horizontal: !!horizontal,
2256
2980
  initialContainerPoolRatio,
2257
2981
  initialScroll,
2982
+ itemsAreEqual,
2258
2983
  keyExtractor,
2259
2984
  maintainScrollAtEnd,
2260
2985
  maintainScrollAtEndThreshold,
@@ -2264,12 +2989,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2264
2989
  onEndReachedThreshold,
2265
2990
  onItemSizeChanged,
2266
2991
  onLoad,
2267
- onScroll: onScrollProp,
2992
+ onScroll: throttleScrollFn,
2268
2993
  onStartReached,
2269
2994
  onStartReachedThreshold,
2270
- renderItem: renderItem2,
2995
+ recycleItems: !!recycleItems,
2996
+ renderItem,
2271
2997
  scrollBuffer,
2272
2998
  snapToIndices,
2999
+ stickyIndicesArr: stickyIndices != null ? stickyIndices : [],
3000
+ stickyIndicesSet: React4.useMemo(() => new Set(stickyIndices != null ? stickyIndices : []), [stickyIndices == null ? void 0 : stickyIndices.join(",")]),
2273
3001
  stylePaddingBottom: stylePaddingBottomState,
2274
3002
  stylePaddingTop: stylePaddingTopState,
2275
3003
  suggestEstimatedItemSize: !!suggestEstimatedItemSize
@@ -2278,6 +3006,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2278
3006
  const checkResetContainers = (isFirst2) => {
2279
3007
  const state2 = refState.current;
2280
3008
  if (state2) {
3009
+ if (!isFirst2 && state2.props.data !== dataProp) {
3010
+ updateAveragesOnDataChange(state2, state2.props.data, dataProp);
3011
+ }
2281
3012
  state2.props.data = dataProp;
2282
3013
  if (!isFirst2) {
2283
3014
  calculateItemsInView(ctx, state2, { dataChanged: true, doMVCP: true });
@@ -2293,7 +3024,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2293
3024
  }
2294
3025
  }
2295
3026
  };
2296
- const memoizedLastItemKeys = React3.useMemo(() => {
3027
+ const memoizedLastItemKeys = React4.useMemo(() => {
2297
3028
  if (!dataProp.length) return [];
2298
3029
  return Array.from(
2299
3030
  { length: Math.min(numColumnsProp, dataProp.length) },
@@ -2307,7 +3038,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2307
3038
  setPaddingTop(ctx, state, { stylePaddingTop: stylePaddingTopState });
2308
3039
  refState.current.props.stylePaddingBottom = stylePaddingBottomState;
2309
3040
  let paddingDiff = stylePaddingTopState - prevPaddingTop;
2310
- if (maintainVisibleContentPosition && paddingDiff && prevPaddingTop !== void 0 && reactNative.Platform.OS === "ios") {
3041
+ if (maintainVisibleContentPosition && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
2311
3042
  if (state.scroll < 0) {
2312
3043
  paddingDiff += state.scroll;
2313
3044
  }
@@ -2318,64 +3049,50 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2318
3049
  initializeStateVars();
2319
3050
  updateAllPositions(ctx, state);
2320
3051
  }
2321
- const initialContentOffset = React3.useMemo(() => {
2322
- const initialContentOffset2 = initialScrollOffset || calculateOffsetForIndex(ctx, state, initialScrollIndex);
2323
- refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
2324
- if (initialContentOffset2 > 0) {
2325
- scrollTo(state, { animated: false, index: initialScrollIndex, offset: initialContentOffset2 });
3052
+ const initialContentOffset = React4.useMemo(() => {
3053
+ if (initialScroll) {
3054
+ const { index, viewOffset } = initialScroll;
3055
+ let initialContentOffset2 = viewOffset || 0;
3056
+ if (index !== void 0) {
3057
+ initialContentOffset2 += calculateOffsetForIndex(ctx, state, index);
3058
+ }
3059
+ refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
3060
+ if (initialContentOffset2 > 0) {
3061
+ scrollTo(state, { animated: false, index, offset: initialContentOffset2 });
3062
+ }
3063
+ return initialContentOffset2;
2326
3064
  }
2327
- return initialContentOffset2;
3065
+ return 0;
2328
3066
  }, [renderNum]);
2329
3067
  if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
2330
- refState.current.lastBatchingAction = Date.now();
3068
+ state.lastBatchingAction = Date.now();
2331
3069
  if (!keyExtractorProp && !isFirst && didDataChange) {
2332
3070
  __DEV__ && warnDevOnce(
2333
3071
  "keyExtractor",
2334
3072
  "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."
2335
3073
  );
2336
- refState.current.sizes.clear();
2337
- refState.current.positions.clear();
3074
+ state.sizes.clear();
3075
+ state.positions.clear();
2338
3076
  }
2339
3077
  }
2340
- React3.useLayoutEffect(() => {
2341
- if (IsNewArchitecture) {
2342
- let measured;
2343
- refScroller.current.measure((x, y, width, height) => {
2344
- measured = { height, width, x, y };
2345
- });
2346
- if (measured) {
2347
- const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
2348
- if (size) {
2349
- handleLayout(ctx, state, measured, setCanRender);
2350
- }
2351
- }
2352
- }
2353
- if (!isFirst) {
2354
- calculateItemsInView(ctx, state, { doMVCP: true });
2355
- }
2356
- }, [dataProp]);
2357
- const onLayoutHeader = React3.useCallback((rect, fromLayoutEffect) => {
3078
+ const onLayoutHeader = React4.useCallback((rect, fromLayoutEffect) => {
2358
3079
  const size = rect[horizontal ? "width" : "height"];
2359
3080
  set$(ctx, "headerSize", size);
2360
- if (initialScroll) {
2361
- if (IsNewArchitecture && reactNative.Platform.OS !== "android") {
3081
+ if ((initialScroll == null ? void 0 : initialScroll.index) !== void 0) {
3082
+ {
2362
3083
  if (fromLayoutEffect) {
2363
3084
  setRenderNum((v) => v + 1);
2364
3085
  }
2365
- } else {
2366
- setTimeout(() => {
2367
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
2368
- }, 17);
2369
3086
  }
2370
3087
  }
2371
3088
  }, []);
2372
- React3.useLayoutEffect(() => {
3089
+ React4.useLayoutEffect(() => {
2373
3090
  if (snapToIndices) {
2374
3091
  updateSnapToOffsets(ctx, state);
2375
3092
  }
2376
3093
  }, [snapToIndices]);
2377
- React3.useLayoutEffect(() => {
2378
- const didAllocateContainers = doInitialAllocateContainersCallback();
3094
+ React4.useLayoutEffect(() => {
3095
+ const didAllocateContainers = dataProp.length > 0 && doInitialAllocateContainersCallback();
2379
3096
  if (!didAllocateContainers) {
2380
3097
  checkResetContainers(
2381
3098
  /*isFirst*/
@@ -2383,10 +3100,20 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2383
3100
  );
2384
3101
  }
2385
3102
  }, [dataProp, numColumnsProp]);
2386
- React3.useLayoutEffect(() => {
3103
+ React4.useLayoutEffect(() => {
2387
3104
  set$(ctx, "extraData", extraData);
2388
3105
  }, [extraData]);
2389
- React3.useLayoutEffect(initializeStateVars, [
3106
+ const { onLayout } = useSyncLayout({
3107
+ onLayout: onLayoutProp,
3108
+ onLayoutChange: React4.useCallback(
3109
+ (rectangle) => {
3110
+ handleLayout(ctx, state, rectangle, setCanRender);
3111
+ },
3112
+ [ctx, state, setCanRender]
3113
+ ),
3114
+ ref: refScroller
3115
+ });
3116
+ React4.useLayoutEffect(initializeStateVars, [
2390
3117
  memoizedLastItemKeys.join(","),
2391
3118
  numColumnsProp,
2392
3119
  stylePaddingTopState,
@@ -2395,28 +3122,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2395
3122
  const doInitialAllocateContainersCallback = () => {
2396
3123
  return doInitialAllocateContainers(ctx, state);
2397
3124
  };
2398
- React3.useEffect(() => {
2399
- const viewability = setupViewability({
2400
- onViewableItemsChanged,
2401
- viewabilityConfig,
2402
- viewabilityConfigCallbackPairs
2403
- });
2404
- state.viewabilityConfigCallbackPairs = viewability;
2405
- state.enableScrollForNextCalculateItemsInView = !viewability;
2406
- }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
2407
- if (!IsNewArchitecture) {
2408
- useInit(() => {
2409
- doInitialAllocateContainersCallback();
2410
- });
2411
- }
2412
- const onLayout = React3.useCallback((event) => {
2413
- const layout = event.nativeEvent.layout;
2414
- handleLayout(ctx, state, layout, setCanRender);
2415
- if (onLayoutProp) {
2416
- onLayoutProp(event);
2417
- }
2418
- }, []);
2419
- React3.useImperativeHandle(forwardedRef, () => {
3125
+ React4.useImperativeHandle(forwardedRef, () => {
2420
3126
  const scrollIndexIntoView = (options) => {
2421
3127
  const state2 = refState.current;
2422
3128
  if (state2) {
@@ -2433,18 +3139,23 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2433
3139
  }
2434
3140
  };
2435
3141
  return {
2436
- flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
3142
+ flashScrollIndicators: () => {
3143
+ var _a, _b;
3144
+ return (_b = (_a = refScroller.current) == null ? void 0 : _a.flashScrollIndicators) == null ? void 0 : _b.call(_a);
3145
+ },
2437
3146
  getNativeScrollRef: () => refScroller.current,
2438
- getScrollableNode: () => refScroller.current.getScrollableNode(),
2439
- getScrollResponder: () => refScroller.current.getScrollResponder(),
3147
+ getScrollableNode: () => refScroller.current,
3148
+ getScrollResponder: () => refScroller.current,
2440
3149
  getState: () => {
2441
3150
  const state2 = refState.current;
2442
3151
  return state2 ? {
2443
3152
  contentLength: state2.totalSize,
3153
+ data: state2.props.data,
2444
3154
  end: state2.endNoBuffer,
2445
3155
  endBuffered: state2.endBuffered,
2446
3156
  isAtEnd: state2.isAtEnd,
2447
3157
  isAtStart: state2.isAtStart,
3158
+ positionAtIndex: (index) => state2.positions.get(getId(state2, index)),
2448
3159
  positions: state2.positions,
2449
3160
  scroll: state2.scroll,
2450
3161
  scrollLength: state2.scrollLength,
@@ -2471,7 +3182,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2471
3182
  const footerSize = peek$(ctx, "footerSize") || 0;
2472
3183
  scrollToIndex(ctx, state, {
2473
3184
  index,
2474
- viewOffset: -paddingBottom - footerSize,
3185
+ viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
2475
3186
  viewPosition: 1,
2476
3187
  ...options
2477
3188
  });
@@ -2486,20 +3197,23 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2486
3197
  }
2487
3198
  },
2488
3199
  scrollToOffset: (params) => scrollTo(state, params),
3200
+ setScrollProcessingEnabled: (enabled) => {
3201
+ refState.current.scrollProcessingEnabled = enabled;
3202
+ },
2489
3203
  setVisibleContentAnchorOffset: (value) => {
2490
3204
  const val = typeof value === "function" ? value(peek$(ctx, "scrollAdjustUserOffset") || 0) : value;
2491
3205
  set$(ctx, "scrollAdjustUserOffset", val);
2492
3206
  }
2493
3207
  };
2494
3208
  }, []);
2495
- if (reactNative.Platform.OS === "web") {
2496
- React3.useEffect(() => {
3209
+ {
3210
+ React4.useEffect(() => {
2497
3211
  if (initialContentOffset) {
2498
3212
  scrollTo(state, { animated: false, offset: initialContentOffset });
2499
3213
  }
2500
3214
  }, []);
2501
3215
  }
2502
- const fns = React3.useMemo(
3216
+ const fns = React4.useMemo(
2503
3217
  () => ({
2504
3218
  getRenderedItem: (key) => getRenderedItem(ctx, state, key),
2505
3219
  onScroll: (event) => onScroll(ctx, state, event),
@@ -2507,7 +3221,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2507
3221
  }),
2508
3222
  []
2509
3223
  );
2510
- return /* @__PURE__ */ React3__namespace.createElement(React3__namespace.Fragment, null, /* @__PURE__ */ React3__namespace.createElement(
3224
+ const onScrollHandler = useStickyScrollHandler(stickyIndices, horizontal, ctx, fns.onScroll);
3225
+ return /* @__PURE__ */ React4__namespace.createElement(React4__namespace.Fragment, null, /* @__PURE__ */ React4__namespace.createElement(
2511
3226
  ListComponent,
2512
3227
  {
2513
3228
  ...rest,
@@ -2523,19 +3238,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2523
3238
  onLayout,
2524
3239
  onLayoutHeader,
2525
3240
  onMomentumScrollEnd: (event) => {
2526
- requestAnimationFrame(() => {
2527
- finishScrollTo(refState.current);
2528
- });
3241
+ {
3242
+ requestAnimationFrame(() => {
3243
+ finishScrollTo(refState.current);
3244
+ });
3245
+ }
2529
3246
  if (onMomentumScrollEnd) {
2530
3247
  onMomentumScrollEnd(event);
2531
3248
  }
2532
3249
  },
2533
- onScroll: fns.onScroll,
3250
+ onScroll: onScrollHandler,
2534
3251
  recycleItems,
2535
- refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3__namespace.cloneElement(refreshControl, {
3252
+ refreshControl: refreshControl ? stylePaddingTopState > 0 ? React4__namespace.cloneElement(refreshControl, {
2536
3253
  progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
2537
- }) : refreshControl : onRefresh && /* @__PURE__ */ React3__namespace.createElement(
2538
- reactNative.RefreshControl,
3254
+ }) : refreshControl : onRefresh && /* @__PURE__ */ React4__namespace.createElement(
3255
+ RefreshControl,
2539
3256
  {
2540
3257
  onRefresh,
2541
3258
  progressViewOffset: (progressViewOffset || 0) + stylePaddingTopState,
@@ -2543,34 +3260,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2543
3260
  }
2544
3261
  ),
2545
3262
  refScrollView: combinedRef,
2546
- scrollAdjustHandler: (_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler,
2547
- scrollEventThrottle: reactNative.Platform.OS === "web" ? 16 : void 0,
3263
+ scrollAdjustHandler: state.scrollAdjustHandler,
2548
3264
  snapToIndices,
3265
+ stickyIndices,
2549
3266
  style,
2550
3267
  updateItemSize: fns.updateItemSize,
2551
3268
  waitForInitialLayout
2552
3269
  }
2553
- ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React3__namespace.createElement(DebugView, { state: refState.current }));
2554
- });
2555
-
2556
- // src/components/LazyLegendList.tsx
2557
- var typedForwardRef2 = React3.forwardRef;
2558
- var renderItem = ({ item }) => item;
2559
- var LazyLegendList = typedForwardRef2(function LazyLegendList2(props, forwardedRef) {
2560
- const { LegendList: LegendListProp, children, ...rest } = props;
2561
- const LegendListComponent = LegendListProp != null ? LegendListProp : LegendList;
2562
- const data = (isArray(children) ? children : React3__namespace.Children.toArray(children)).flat(1);
2563
- return (
2564
- // @ts-expect-error TODO: Fix this type
2565
- /* @__PURE__ */ React3__namespace.createElement(LegendListComponent, { ...rest, data, ref: forwardedRef, renderItem })
2566
- );
3270
+ ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React4__namespace.createElement(DebugView, { state: refState.current }));
2567
3271
  });
2568
3272
 
2569
- exports.LazyLegendList = LazyLegendList;
2570
3273
  exports.LegendList = LegendList;
2571
3274
  exports.useIsLastItem = useIsLastItem;
2572
3275
  exports.useListScrollSize = useListScrollSize;
2573
3276
  exports.useRecyclingEffect = useRecyclingEffect;
2574
3277
  exports.useRecyclingState = useRecyclingState;
3278
+ exports.useSyncLayout = useSyncLayout2;
2575
3279
  exports.useViewability = useViewability;
2576
3280
  exports.useViewabilityAmount = useViewabilityAmount;