@legendapp/list 2.0.0-next.0 → 2.0.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.
Files changed (5) hide show
  1. package/index.d.mts +48 -6
  2. package/index.d.ts +48 -6
  3. package/index.js +1395 -1238
  4. package/index.mjs +1347 -1190
  5. package/package.json +1 -1
package/index.mjs CHANGED
@@ -1,12 +1,12 @@
1
- import * as React2 from 'react';
2
- import { useReducer, useEffect, createContext, useMemo, useState, useRef, useCallback, useLayoutEffect, useImperativeHandle, useContext, forwardRef, memo } from 'react';
1
+ import * as React3 from 'react';
2
+ import React3__default, { useReducer, useEffect, createContext, useMemo, useState, useRef, useLayoutEffect, useCallback, useImperativeHandle, useContext, forwardRef, memo } from 'react';
3
3
  import { View, Text, Platform, Animated, ScrollView, StyleSheet, Dimensions, RefreshControl } from 'react-native';
4
4
  import { useSyncExternalStore } from 'use-sync-external-store/shim';
5
5
 
6
6
  // src/LegendList.tsx
7
- var ContextState = React2.createContext(null);
7
+ var ContextState = React3.createContext(null);
8
8
  function StateProvider({ children }) {
9
- const [value] = React2.useState(() => ({
9
+ const [value] = React3.useState(() => ({
10
10
  listeners: /* @__PURE__ */ new Map(),
11
11
  values: /* @__PURE__ */ new Map([
12
12
  ["alignItemsPaddingTop", 0],
@@ -20,10 +20,10 @@ function StateProvider({ children }) {
20
20
  columnWrapperStyle: void 0,
21
21
  viewRefs: /* @__PURE__ */ new Map()
22
22
  }));
23
- return /* @__PURE__ */ React2.createElement(ContextState.Provider, { value }, children);
23
+ return /* @__PURE__ */ React3.createElement(ContextState.Provider, { value }, children);
24
24
  }
25
25
  function useStateContext() {
26
- return React2.useContext(ContextState);
26
+ return React3.useContext(ContextState);
27
27
  }
28
28
  function createSelectorFunctionsArr(ctx, signalNames) {
29
29
  let lastValues = [];
@@ -93,23 +93,23 @@ function getContentSize(ctx) {
93
93
  return headerSize + footerSize + totalSize + stylePaddingTop;
94
94
  }
95
95
  function useArr$(signalNames) {
96
- const ctx = React2.useContext(ContextState);
97
- const { subscribe, get } = React2.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
96
+ const ctx = React3.useContext(ContextState);
97
+ const { subscribe, get } = React3.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
98
98
  const value = useSyncExternalStore(subscribe, get);
99
99
  return value;
100
100
  }
101
101
  function useSelector$(signalName, selector) {
102
- const ctx = React2.useContext(ContextState);
103
- const { subscribe, get } = React2.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
102
+ const ctx = React3.useContext(ContextState);
103
+ const { subscribe, get } = React3.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
104
104
  const value = useSyncExternalStore(subscribe, () => selector(get()[0]));
105
105
  return value;
106
106
  }
107
107
 
108
108
  // src/DebugView.tsx
109
109
  var DebugRow = ({ children }) => {
110
- return /* @__PURE__ */ React2.createElement(View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" } }, children);
110
+ return /* @__PURE__ */ React3.createElement(View, { style: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" } }, children);
111
111
  };
112
- var DebugView = React2.memo(function DebugView2({ state }) {
112
+ var DebugView = React3.memo(function DebugView2({ state }) {
113
113
  const ctx = useStateContext();
114
114
  const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, numContainers = 0, numContainersPooled = 0] = useArr$([
115
115
  "totalSize",
@@ -124,7 +124,7 @@ var DebugView = React2.memo(function DebugView2({ state }) {
124
124
  useInterval(() => {
125
125
  forceUpdate();
126
126
  }, 100);
127
- return /* @__PURE__ */ React2.createElement(
127
+ return /* @__PURE__ */ React3.createElement(
128
128
  View,
129
129
  {
130
130
  style: {
@@ -140,14 +140,14 @@ var DebugView = React2.memo(function DebugView2({ state }) {
140
140
  },
141
141
  pointerEvents: "none"
142
142
  },
143
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "TotalSize:"), /* @__PURE__ */ React2.createElement(Text, null, totalSize.toFixed(2))),
144
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ContentSize:"), /* @__PURE__ */ React2.createElement(Text, null, contentSize.toFixed(2))),
145
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "At end:"), /* @__PURE__ */ React2.createElement(Text, null, String(state.isAtEnd))),
146
- /* @__PURE__ */ React2.createElement(Text, null),
147
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React2.createElement(Text, null, scrollAdjust.toFixed(2))),
148
- /* @__PURE__ */ React2.createElement(Text, null),
149
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "RawScroll: "), /* @__PURE__ */ React2.createElement(Text, null, rawScroll.toFixed(2))),
150
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ComputedScroll: "), /* @__PURE__ */ React2.createElement(Text, null, scroll.toFixed(2)))
143
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "TotalSize:"), /* @__PURE__ */ React3.createElement(Text, null, totalSize.toFixed(2))),
144
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "ContentSize:"), /* @__PURE__ */ React3.createElement(Text, null, contentSize.toFixed(2))),
145
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "At end:"), /* @__PURE__ */ React3.createElement(Text, null, String(state.isAtEnd))),
146
+ /* @__PURE__ */ React3.createElement(Text, null),
147
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React3.createElement(Text, null, scrollAdjust.toFixed(2))),
148
+ /* @__PURE__ */ React3.createElement(Text, null),
149
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "RawScroll: "), /* @__PURE__ */ React3.createElement(Text, null, rawScroll.toFixed(2))),
150
+ /* @__PURE__ */ React3.createElement(DebugRow, null, /* @__PURE__ */ React3.createElement(Text, null, "ComputedScroll: "), /* @__PURE__ */ React3.createElement(Text, null, scroll.toFixed(2)))
151
151
  );
152
152
  });
153
153
  function useInterval(callback, delay) {
@@ -171,12 +171,12 @@ function warnDevOnce(id, text) {
171
171
  console.warn(`[legend-list] ${text}`);
172
172
  }
173
173
  }
174
+ function roundSize(size) {
175
+ return Math.floor(size * 8) / 8;
176
+ }
174
177
  function isNullOrUndefined(value) {
175
178
  return value === null || value === void 0;
176
179
  }
177
- function comparatorByDistance(a, b) {
178
- return b.distance - a.distance;
179
- }
180
180
  function comparatorDefault(a, b) {
181
181
  return a - b;
182
182
  }
@@ -263,9 +263,10 @@ function useRecyclingState(valueOrFun) {
263
263
  value: null
264
264
  });
265
265
  const [_, setRenderNum] = useState(0);
266
- if (refState.current.itemKey !== itemKey) {
267
- refState.current.itemKey = itemKey;
268
- refState.current.value = isFunction(valueOrFun) ? valueOrFun({
266
+ const state = refState.current;
267
+ if (state.itemKey !== itemKey) {
268
+ state.itemKey = itemKey;
269
+ state.value = isFunction(valueOrFun) ? valueOrFun({
269
270
  index,
270
271
  item: value,
271
272
  prevIndex: void 0,
@@ -274,13 +275,13 @@ function useRecyclingState(valueOrFun) {
274
275
  }
275
276
  const setState = useCallback(
276
277
  (newState) => {
277
- refState.current.value = isFunction(newState) ? newState(refState.current.value) : newState;
278
+ state.value = isFunction(newState) ? newState(state.value) : newState;
278
279
  setRenderNum((v) => v + 1);
279
280
  triggerLayout();
280
281
  },
281
- [triggerLayout]
282
+ [triggerLayout, state]
282
283
  );
283
- return [refState.current.value, setState];
284
+ return [state.value, setState];
284
285
  }
285
286
  function useIsLastItem() {
286
287
  const { itemKey } = useContext(ContextContainer);
@@ -291,12 +292,19 @@ function useListScrollSize() {
291
292
  const [scrollSize] = useArr$(["scrollSize"]);
292
293
  return scrollSize;
293
294
  }
294
- var LeanViewComponent = React2.forwardRef((props, ref) => {
295
- return React2.createElement("RCTView", { ...props, ref });
295
+ var LeanViewComponent = React3.forwardRef((props, ref) => {
296
+ return React3.createElement("RCTView", { ...props, ref });
296
297
  });
297
298
  LeanViewComponent.displayName = "RCTView";
298
299
  var LeanView = Platform.OS === "android" || Platform.OS === "ios" ? LeanViewComponent : View;
299
300
 
301
+ // src/Separator.tsx
302
+ function Separator({ ItemSeparatorComponent, itemKey, leadingItem }) {
303
+ const [lastItemKeys] = useArr$(["lastItemKeys"]);
304
+ const isALastItem = lastItemKeys.includes(itemKey);
305
+ return isALastItem ? null : /* @__PURE__ */ React.createElement(ItemSeparatorComponent, { leadingItem });
306
+ }
307
+
300
308
  // src/constants.ts
301
309
  var POSITION_OUT_OF_VIEW = -1e7;
302
310
  var ENABLE_DEVMODE = __DEV__ && false;
@@ -308,19 +316,18 @@ var Container = ({
308
316
  id,
309
317
  recycleItems,
310
318
  horizontal,
311
- getRenderedItem,
312
- updateItemSize,
319
+ getRenderedItem: getRenderedItem2,
320
+ updateItemSize: updateItemSize2,
313
321
  ItemSeparatorComponent
314
322
  }) => {
315
323
  const ctx = useStateContext();
316
324
  const columnWrapperStyle = ctx.columnWrapperStyle;
317
- const [column = 0, data, itemKey, position = POSITION_OUT_OF_VIEW, numColumns, lastItemKeys, extraData] = useArr$([
325
+ const [column = 0, data, itemKey, position = POSITION_OUT_OF_VIEW, numColumns, extraData] = useArr$([
318
326
  `containerColumn${id}`,
319
327
  `containerItemData${id}`,
320
328
  `containerItemKey${id}`,
321
329
  `containerPosition${id}`,
322
330
  "numColumns",
323
- "lastItemKeys",
324
331
  "extraData"
325
332
  ]);
326
333
  const refLastSize = useRef();
@@ -328,19 +335,18 @@ var Container = ({
328
335
  const [layoutRenderCount, forceLayoutRender] = useState(0);
329
336
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
330
337
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
331
- const isALastItem = lastItemKeys.includes(itemKey);
332
338
  let didLayout = false;
333
339
  let paddingStyles;
334
340
  if (columnWrapperStyle) {
335
341
  const { columnGap, rowGap, gap } = columnWrapperStyle;
336
342
  if (horizontal) {
337
343
  paddingStyles = {
338
- paddingRight: !isALastItem ? columnGap || gap || void 0 : void 0,
344
+ paddingRight: columnGap || gap || void 0,
339
345
  paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
340
346
  };
341
347
  } else {
342
348
  paddingStyles = {
343
- paddingBottom: !isALastItem ? rowGap || gap || void 0 : void 0,
349
+ paddingBottom: rowGap || gap || void 0,
344
350
  paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
345
351
  };
346
352
  }
@@ -361,7 +367,7 @@ var Container = ({
361
367
  ...paddingStyles || {}
362
368
  };
363
369
  const renderedItemInfo = useMemo(
364
- () => itemKey !== void 0 ? getRenderedItem(itemKey) : null,
370
+ () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
365
371
  [itemKey, data, extraData]
366
372
  );
367
373
  const { index, renderedItem } = renderedItemInfo || {};
@@ -380,7 +386,7 @@ var Container = ({
380
386
  const size = layout[horizontal ? "width" : "height"];
381
387
  const doUpdate = () => {
382
388
  refLastSize.current = { width: layout.width, height: layout.height };
383
- updateItemSize(itemKey, layout);
389
+ updateItemSize2(itemKey, layout);
384
390
  };
385
391
  if (IsNewArchitecture || size > 0) {
386
392
  doUpdate();
@@ -400,17 +406,17 @@ var Container = ({
400
406
  if (measured) {
401
407
  const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
402
408
  if (size) {
403
- updateItemSize(itemKey, measured);
409
+ updateItemSize2(itemKey, measured);
404
410
  }
405
411
  }
406
412
  }
407
- }, [itemKey, layoutRenderCount, isALastItem]);
413
+ }, [itemKey, layoutRenderCount]);
408
414
  } else {
409
415
  useEffect(() => {
410
416
  if (!isNullOrUndefined(itemKey)) {
411
417
  const timeout = setTimeout(() => {
412
418
  if (!didLayout && refLastSize.current) {
413
- updateItemSize(itemKey, refLastSize.current);
419
+ updateItemSize2(itemKey, refLastSize.current);
414
420
  }
415
421
  }, 16);
416
422
  return () => {
@@ -419,7 +425,14 @@ var Container = ({
419
425
  }
420
426
  }, [itemKey]);
421
427
  }
422
- return /* @__PURE__ */ React2.createElement(LeanView, { style, onLayout, ref, key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React2.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && !isALastItem && /* @__PURE__ */ React2.createElement(ItemSeparatorComponent, { leadingItem: renderedItemInfo.item })));
428
+ return /* @__PURE__ */ React3.createElement(LeanView, { style, onLayout, ref, key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React3.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React3.createElement(
429
+ Separator,
430
+ {
431
+ itemKey,
432
+ ItemSeparatorComponent,
433
+ leadingItem: renderedItemInfo.item
434
+ }
435
+ )));
423
436
  };
424
437
  var typedForwardRef = forwardRef;
425
438
  var typedMemo = memo;
@@ -470,8 +483,8 @@ var Containers = typedMemo(function Containers2({
470
483
  recycleItems,
471
484
  ItemSeparatorComponent,
472
485
  waitForInitialLayout,
473
- updateItemSize,
474
- getRenderedItem
486
+ updateItemSize: updateItemSize2,
487
+ getRenderedItem: getRenderedItem2
475
488
  }) {
476
489
  const ctx = useStateContext();
477
490
  const columnWrapperStyle = ctx.columnWrapperStyle;
@@ -485,15 +498,15 @@ var Containers = typedMemo(function Containers2({
485
498
  const containers = [];
486
499
  for (let i = 0; i < numContainers; i++) {
487
500
  containers.push(
488
- /* @__PURE__ */ React2.createElement(
501
+ /* @__PURE__ */ React3.createElement(
489
502
  Container,
490
503
  {
491
504
  id: i,
492
505
  key: i,
493
506
  recycleItems,
494
507
  horizontal,
495
- getRenderedItem,
496
- updateItemSize,
508
+ getRenderedItem: getRenderedItem2,
509
+ updateItemSize: updateItemSize2,
497
510
  ItemSeparatorComponent
498
511
  }
499
512
  )
@@ -502,25 +515,31 @@ var Containers = typedMemo(function Containers2({
502
515
  const style = horizontal ? { width: animSize, opacity: animOpacity, minHeight: otherAxisSize } : { height: animSize, opacity: animOpacity, minWidth: otherAxisSize };
503
516
  if (columnWrapperStyle && numColumns > 1) {
504
517
  const { columnGap, rowGap, gap } = columnWrapperStyle;
518
+ const gapX = columnGap || gap || 0;
519
+ const gapY = rowGap || gap || 0;
505
520
  if (horizontal) {
506
- const my = (rowGap || gap || 0) / 2;
507
- if (my) {
508
- style.marginVertical = -my;
521
+ if (gapY) {
522
+ style.marginVertical = -gapY / 2;
523
+ }
524
+ if (gapX) {
525
+ style.marginRight = -gapX;
509
526
  }
510
527
  } else {
511
- const mx = (columnGap || gap || 0) / 2;
512
- if (mx) {
513
- style.marginHorizontal = -mx;
528
+ if (gapX) {
529
+ style.marginHorizontal = -gapX;
530
+ }
531
+ if (gapY) {
532
+ style.marginBottom = -gapY;
514
533
  }
515
534
  }
516
535
  }
517
- return /* @__PURE__ */ React2.createElement(Animated.View, { style }, containers);
536
+ return /* @__PURE__ */ React3.createElement(Animated.View, { style }, containers);
518
537
  });
519
538
  function ScrollAdjust() {
520
539
  const bias = 1e7;
521
540
  const [scrollAdjust, scrollAdjustUserOffset] = useArr$(["scrollAdjust", "scrollAdjustUserOffset"]);
522
541
  const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0) + bias;
523
- return /* @__PURE__ */ React2.createElement(
542
+ return /* @__PURE__ */ React3.createElement(
524
543
  View,
525
544
  {
526
545
  style: {
@@ -555,21 +574,21 @@ function useSyncLayout({
555
574
 
556
575
  // src/ListComponent.tsx
557
576
  var getComponent = (Component) => {
558
- if (React2.isValidElement(Component)) {
577
+ if (React3.isValidElement(Component)) {
559
578
  return Component;
560
579
  }
561
580
  if (Component) {
562
- return /* @__PURE__ */ React2.createElement(Component, null);
581
+ return /* @__PURE__ */ React3.createElement(Component, null);
563
582
  }
564
583
  return null;
565
584
  };
566
585
  var Padding = () => {
567
586
  const animPaddingTop = useValue$("alignItemsPaddingTop", { delay: 0 });
568
- return /* @__PURE__ */ React2.createElement(Animated.View, { style: { paddingTop: animPaddingTop } });
587
+ return /* @__PURE__ */ React3.createElement(Animated.View, { style: { paddingTop: animPaddingTop } });
569
588
  };
570
589
  var PaddingDevMode = () => {
571
590
  const animPaddingTop = useValue$("alignItemsPaddingTop", { delay: 0 });
572
- return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Animated.View, { style: { paddingTop: animPaddingTop } }), /* @__PURE__ */ React2.createElement(
591
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(Animated.View, { style: { paddingTop: animPaddingTop } }), /* @__PURE__ */ React3.createElement(
573
592
  Animated.View,
574
593
  {
575
594
  style: {
@@ -593,15 +612,15 @@ var ListComponent = typedMemo(function ListComponent2({
593
612
  ItemSeparatorComponent,
594
613
  alignItemsAtEnd,
595
614
  waitForInitialLayout,
596
- handleScroll,
615
+ onScroll: onScroll2,
597
616
  onLayout,
598
617
  ListHeaderComponent,
599
618
  ListHeaderComponentStyle,
600
619
  ListFooterComponent,
601
620
  ListFooterComponentStyle,
602
621
  ListEmptyComponent,
603
- getRenderedItem,
604
- updateItemSize,
622
+ getRenderedItem: getRenderedItem2,
623
+ updateItemSize: updateItemSize2,
605
624
  refScrollView,
606
625
  maintainVisibleContentPosition,
607
626
  renderScrollComponent,
@@ -614,17 +633,17 @@ var ListComponent = typedMemo(function ListComponent2({
614
633
  onChange: onLayoutHeader
615
634
  });
616
635
  const ScrollComponent = renderScrollComponent ? useMemo(
617
- () => React2.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
636
+ () => React3.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
618
637
  [renderScrollComponent]
619
638
  ) : ScrollView;
620
- React2.useEffect(() => {
639
+ React3.useEffect(() => {
621
640
  if (canRender) {
622
641
  setTimeout(() => {
623
642
  scrollAdjustHandler.setMounted();
624
643
  }, 0);
625
644
  }
626
645
  }, [canRender]);
627
- return /* @__PURE__ */ React2.createElement(
646
+ return /* @__PURE__ */ React3.createElement(
628
647
  ScrollComponent,
629
648
  {
630
649
  ...rest,
@@ -636,28 +655,28 @@ var ListComponent = typedMemo(function ListComponent2({
636
655
  height: "100%"
637
656
  } : {}
638
657
  ],
639
- onScroll: handleScroll,
658
+ onScroll: onScroll2,
640
659
  onLayout,
641
660
  horizontal,
642
661
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
643
662
  ref: refScrollView
644
663
  },
645
- maintainVisibleContentPosition && /* @__PURE__ */ React2.createElement(ScrollAdjust, null),
646
- ENABLE_DEVMODE ? /* @__PURE__ */ React2.createElement(PaddingDevMode, null) : /* @__PURE__ */ React2.createElement(Padding, null),
647
- ListHeaderComponent && /* @__PURE__ */ React2.createElement(View, { style: ListHeaderComponentStyle, onLayout: onLayoutHeaderSync, ref: refHeader }, getComponent(ListHeaderComponent)),
664
+ maintainVisibleContentPosition && /* @__PURE__ */ React3.createElement(ScrollAdjust, null),
665
+ ENABLE_DEVMODE ? /* @__PURE__ */ React3.createElement(PaddingDevMode, null) : /* @__PURE__ */ React3.createElement(Padding, null),
666
+ ListHeaderComponent && /* @__PURE__ */ React3.createElement(View, { style: ListHeaderComponentStyle, onLayout: onLayoutHeaderSync, ref: refHeader }, getComponent(ListHeaderComponent)),
648
667
  ListEmptyComponent && getComponent(ListEmptyComponent),
649
- canRender && /* @__PURE__ */ React2.createElement(
668
+ canRender && /* @__PURE__ */ React3.createElement(
650
669
  Containers,
651
670
  {
652
671
  horizontal,
653
672
  recycleItems,
654
673
  waitForInitialLayout,
655
- getRenderedItem,
674
+ getRenderedItem: getRenderedItem2,
656
675
  ItemSeparatorComponent,
657
- updateItemSize
676
+ updateItemSize: updateItemSize2
658
677
  }
659
678
  ),
660
- ListFooterComponent && /* @__PURE__ */ React2.createElement(
679
+ ListFooterComponent && /* @__PURE__ */ React3.createElement(
661
680
  View,
662
681
  {
663
682
  style: ListFooterComponentStyle,
@@ -692,22 +711,545 @@ var ScrollAdjustHandler = class {
692
711
  this.mounted = true;
693
712
  }
694
713
  };
695
- var useCombinedRef = (...refs) => {
696
- const callback = useCallback((element) => {
697
- for (const ref of refs) {
698
- if (!ref) {
699
- continue;
714
+
715
+ // src/getId.ts
716
+ function getId(state, index) {
717
+ const { data, keyExtractor } = state.props;
718
+ if (!data) {
719
+ return "";
720
+ }
721
+ const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
722
+ const id = ret;
723
+ state.idCache.set(index, id);
724
+ return id;
725
+ }
726
+
727
+ // src/calculateOffsetForIndex.ts
728
+ function calculateOffsetForIndex(ctx, state, index) {
729
+ let position = 0;
730
+ if (index !== void 0) {
731
+ position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
732
+ }
733
+ const paddingTop = peek$(ctx, "stylePaddingTop");
734
+ if (paddingTop) {
735
+ position += paddingTop;
736
+ }
737
+ const headerSize = peek$(ctx, "headerSize");
738
+ if (headerSize) {
739
+ position += headerSize;
740
+ }
741
+ return position;
742
+ }
743
+
744
+ // src/getItemSize.ts
745
+ function getItemSize(state, key, index, data, useAverageSize) {
746
+ const {
747
+ sizesKnown,
748
+ sizes,
749
+ scrollingTo,
750
+ props: { estimatedItemSize, getEstimatedItemSize }
751
+ } = state;
752
+ const sizeKnown = sizesKnown.get(key);
753
+ if (sizeKnown !== void 0) {
754
+ return sizeKnown;
755
+ }
756
+ let size;
757
+ if (IsNewArchitecture && useAverageSize !== void 0 && sizeKnown === void 0 && !getEstimatedItemSize && !scrollingTo) {
758
+ size = useAverageSize;
759
+ }
760
+ if (size === void 0) {
761
+ size = sizes.get(key);
762
+ if (size !== void 0) {
763
+ return size;
764
+ }
765
+ }
766
+ if (size === void 0) {
767
+ size = getEstimatedItemSize ? getEstimatedItemSize(index, data) : estimatedItemSize;
768
+ }
769
+ sizes.set(key, size);
770
+ return size;
771
+ }
772
+
773
+ // src/calculateOffsetWithOffsetPosition.ts
774
+ function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
775
+ const { index, viewOffset, viewPosition } = params;
776
+ let offset = offsetParam;
777
+ if (viewOffset) {
778
+ offset -= viewOffset;
779
+ }
780
+ if (viewPosition !== void 0 && index !== void 0) {
781
+ offset -= viewPosition * (state.scrollLength - getItemSize(state, getId(state, index), index, state.props.data[index]));
782
+ }
783
+ return offset;
784
+ }
785
+
786
+ // src/checkAllSizesKnown.ts
787
+ function checkAllSizesKnown(state) {
788
+ const { startBuffered, endBuffered, sizesKnown } = state;
789
+ if (endBuffered !== null) {
790
+ let areAllKnown = true;
791
+ for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
792
+ const key = getId(state, i);
793
+ areAllKnown && (areAllKnown = sizesKnown.has(key));
794
+ }
795
+ return areAllKnown;
796
+ }
797
+ return false;
798
+ }
799
+
800
+ // src/findAvailableContainers.ts
801
+ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval) {
802
+ const numContainers = peek$(ctx, "numContainers");
803
+ const result = [];
804
+ const availableContainers = [];
805
+ for (let u = 0; u < numContainers; u++) {
806
+ const key = peek$(ctx, `containerItemKey${u}`);
807
+ let isOk = key === void 0;
808
+ if (!isOk) {
809
+ const index = pendingRemoval.indexOf(u);
810
+ if (index !== -1) {
811
+ pendingRemoval.splice(index, 1);
812
+ isOk = true;
700
813
  }
701
- if (isFunction(ref)) {
702
- ref(element);
703
- } else {
704
- ref.current = element;
814
+ }
815
+ if (isOk) {
816
+ result.push(u);
817
+ if (result.length >= numNeeded) {
818
+ return result;
705
819
  }
706
820
  }
707
- }, refs);
708
- return callback;
821
+ }
822
+ for (let u = 0; u < numContainers; u++) {
823
+ const key = peek$(ctx, `containerItemKey${u}`);
824
+ if (key === void 0) continue;
825
+ const index = state.indexByKey.get(key);
826
+ if (index < startBuffered) {
827
+ availableContainers.push({ index: u, distance: startBuffered - index });
828
+ } else if (index > endBuffered) {
829
+ availableContainers.push({ index: u, distance: index - endBuffered });
830
+ }
831
+ }
832
+ const remaining = numNeeded - result.length;
833
+ if (remaining > 0) {
834
+ if (availableContainers.length > 0) {
835
+ if (availableContainers.length > remaining) {
836
+ availableContainers.sort(comparatorByDistance);
837
+ availableContainers.length = remaining;
838
+ }
839
+ for (const container of availableContainers) {
840
+ result.push(container.index);
841
+ }
842
+ }
843
+ const stillNeeded = numNeeded - result.length;
844
+ if (stillNeeded > 0) {
845
+ for (let i = 0; i < stillNeeded; i++) {
846
+ result.push(numContainers + i);
847
+ }
848
+ if (__DEV__ && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
849
+ console.warn(
850
+ "[legend-list] No unused container available, so creating one on demand. This can be a minor performance issue and is likely caused by the estimatedItemSize being too large. Consider decreasing estimatedItemSize or increasing initialContainerPoolRatio.",
851
+ {
852
+ debugInfo: {
853
+ numContainers,
854
+ numNeeded,
855
+ stillNeeded,
856
+ numContainersPooled: peek$(ctx, "numContainersPooled")
857
+ }
858
+ }
859
+ );
860
+ }
861
+ }
862
+ }
863
+ return result.sort(comparatorDefault);
864
+ }
865
+ function comparatorByDistance(a, b) {
866
+ return b.distance - a.distance;
867
+ }
868
+
869
+ // src/getScrollVelocity.ts
870
+ var getScrollVelocity = (state) => {
871
+ const { scrollHistory } = state;
872
+ let velocity = 0;
873
+ if (scrollHistory.length >= 1) {
874
+ const newest = scrollHistory[scrollHistory.length - 1];
875
+ let oldest;
876
+ let start = 0;
877
+ for (let i = 0; i < scrollHistory.length - 1; i++) {
878
+ const entry = scrollHistory[i];
879
+ const nextEntry = scrollHistory[i + 1];
880
+ if (i > 0) {
881
+ const prevEntry = scrollHistory[i - 1];
882
+ const prevDirection = entry.scroll - prevEntry.scroll;
883
+ const currentDirection = nextEntry.scroll - entry.scroll;
884
+ if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
885
+ start = i;
886
+ break;
887
+ }
888
+ }
889
+ }
890
+ for (let i = start; i < scrollHistory.length - 1; i++) {
891
+ const entry = scrollHistory[i];
892
+ if (newest.time - entry.time <= 1e3) {
893
+ oldest = entry;
894
+ break;
895
+ }
896
+ }
897
+ if (oldest) {
898
+ const scrollDiff = newest.scroll - oldest.scroll;
899
+ const timeDiff = newest.time - oldest.time;
900
+ velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
901
+ }
902
+ }
903
+ return velocity;
904
+ };
905
+
906
+ // src/requestAdjust.ts
907
+ function requestAdjust(ctx, state, positionDiff) {
908
+ if (Math.abs(positionDiff) > 0.1) {
909
+ const doit = () => {
910
+ state.scrollAdjustHandler.requestAdjust(positionDiff);
911
+ };
912
+ state.scroll += positionDiff;
913
+ state.scrollForNextCalculateItemsInView = void 0;
914
+ if (peek$(ctx, "containersDidLayout")) {
915
+ doit();
916
+ } else {
917
+ requestAnimationFrame(doit);
918
+ }
919
+ const threshold = state.scroll - positionDiff / 2;
920
+ if (!state.ignoreScrollFromMVCP) {
921
+ state.ignoreScrollFromMVCP = {};
922
+ }
923
+ if (positionDiff > 0) {
924
+ state.ignoreScrollFromMVCP.lt = threshold;
925
+ } else {
926
+ state.ignoreScrollFromMVCP.gt = threshold;
927
+ }
928
+ if (state.ignoreScrollFromMVCPTimeout) {
929
+ clearTimeout(state.ignoreScrollFromMVCPTimeout);
930
+ }
931
+ state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
932
+ state.ignoreScrollFromMVCP = void 0;
933
+ }, 100);
934
+ }
935
+ }
936
+
937
+ // src/prepareMVCP.ts
938
+ function prepareMVCP(ctx, state) {
939
+ const {
940
+ positions,
941
+ scrollingTo,
942
+ props: { maintainVisibleContentPosition }
943
+ } = state;
944
+ let prevPosition;
945
+ let targetId;
946
+ let targetIndex;
947
+ const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
948
+ if (maintainVisibleContentPosition) {
949
+ const indexByKey = state.indexByKey;
950
+ if (scrollTarget !== void 0) {
951
+ targetId = getId(state, scrollTarget);
952
+ targetIndex = scrollTarget;
953
+ } else if (state.idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
954
+ targetId = state.idsInView.find((id) => indexByKey.get(id) !== void 0);
955
+ targetIndex = indexByKey.get(targetId);
956
+ }
957
+ if (targetId !== void 0 && targetIndex !== void 0) {
958
+ prevPosition = positions.get(targetId);
959
+ }
960
+ }
961
+ return () => {
962
+ if (targetId !== void 0 && prevPosition !== void 0) {
963
+ const newPosition = positions.get(targetId);
964
+ if (newPosition !== void 0) {
965
+ const positionDiff = newPosition - prevPosition;
966
+ if (Math.abs(positionDiff) > 0.1) {
967
+ requestAdjust(ctx, state, positionDiff);
968
+ }
969
+ }
970
+ }
971
+ };
972
+ }
973
+
974
+ // src/checkThreshold.ts
975
+ var checkThreshold = (distance, atThreshold, threshold, isReached, isBlockedByTimer, onReached, blockTimer) => {
976
+ const distanceAbs = Math.abs(distance);
977
+ const isAtThreshold = atThreshold || distanceAbs < threshold;
978
+ if (!isReached && !isBlockedByTimer) {
979
+ if (isAtThreshold) {
980
+ onReached == null ? void 0 : onReached(distance);
981
+ blockTimer == null ? void 0 : blockTimer(true);
982
+ setTimeout(() => {
983
+ blockTimer == null ? void 0 : blockTimer(false);
984
+ }, 700);
985
+ return true;
986
+ }
987
+ } else {
988
+ if (distance >= 1.3 * threshold) {
989
+ return false;
990
+ }
991
+ }
992
+ return isReached;
993
+ };
994
+
995
+ // src/checkAtBottom.ts
996
+ function checkAtBottom(ctx, state) {
997
+ if (!state) {
998
+ return;
999
+ }
1000
+ const {
1001
+ queuedInitialLayout,
1002
+ scrollLength,
1003
+ scroll,
1004
+ maintainingScrollAtEnd,
1005
+ props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
1006
+ } = state;
1007
+ const contentSize = getContentSize(ctx);
1008
+ if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1009
+ const distanceFromEnd = contentSize - scroll - scrollLength;
1010
+ const isContentLess = contentSize < scrollLength;
1011
+ state.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1012
+ state.isEndReached = checkThreshold(
1013
+ distanceFromEnd,
1014
+ isContentLess,
1015
+ onEndReachedThreshold * scrollLength,
1016
+ state.isEndReached,
1017
+ state.endReachedBlockedByTimer,
1018
+ (distance) => {
1019
+ var _a, _b;
1020
+ return (_b = (_a = state.props).onEndReached) == null ? void 0 : _b.call(_a, { distanceFromEnd: distance });
1021
+ },
1022
+ (block) => {
1023
+ state.endReachedBlockedByTimer = block;
1024
+ }
1025
+ );
1026
+ }
1027
+ }
1028
+
1029
+ // src/finishScrollTo.ts
1030
+ var finishScrollTo = (state) => {
1031
+ if (state) {
1032
+ state.scrollingTo = void 0;
1033
+ state.scrollHistory.length = 0;
1034
+ }
709
1035
  };
710
1036
 
1037
+ // src/scrollTo.ts
1038
+ function scrollTo(state, params = {}) {
1039
+ var _a;
1040
+ const { animated } = params;
1041
+ const {
1042
+ refScroller,
1043
+ props: { horizontal }
1044
+ } = state;
1045
+ const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
1046
+ state.scrollHistory.length = 0;
1047
+ state.scrollingTo = params;
1048
+ state.scrollPending = offset;
1049
+ (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
1050
+ x: horizontal ? offset : 0,
1051
+ y: horizontal ? 0 : offset,
1052
+ animated: !!animated
1053
+ });
1054
+ if (!animated) {
1055
+ state.scroll = offset;
1056
+ setTimeout(() => finishScrollTo(state), 100);
1057
+ }
1058
+ }
1059
+
1060
+ // src/scrollToIndex.ts
1061
+ function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
1062
+ if (index >= state.props.data.length) {
1063
+ index = state.props.data.length - 1;
1064
+ } else if (index < 0) {
1065
+ index = 0;
1066
+ }
1067
+ const firstIndexOffset = calculateOffsetForIndex(ctx, state, index);
1068
+ const isLast = index === state.props.data.length - 1;
1069
+ if (isLast && viewPosition === void 0) {
1070
+ viewPosition = 1;
1071
+ }
1072
+ const firstIndexScrollPostion = firstIndexOffset - viewOffset;
1073
+ state.scrollForNextCalculateItemsInView = void 0;
1074
+ scrollTo(state, {
1075
+ offset: firstIndexScrollPostion,
1076
+ animated,
1077
+ index,
1078
+ viewPosition: viewPosition != null ? viewPosition : 0,
1079
+ viewOffset
1080
+ });
1081
+ }
1082
+
1083
+ // src/setDidLayout.ts
1084
+ function setDidLayout(ctx, state) {
1085
+ const {
1086
+ loadStartTime,
1087
+ initialScroll,
1088
+ props: { onLoad }
1089
+ } = state;
1090
+ state.queuedInitialLayout = true;
1091
+ checkAtBottom(ctx, state);
1092
+ if (!IsNewArchitecture && initialScroll) {
1093
+ scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1094
+ }
1095
+ set$(ctx, "containersDidLayout", true);
1096
+ if (onLoad) {
1097
+ onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1098
+ }
1099
+ }
1100
+
1101
+ // src/setPaddingTop.ts
1102
+ function setPaddingTop(ctx, { stylePaddingTop, alignItemsPaddingTop }) {
1103
+ if (stylePaddingTop !== void 0) {
1104
+ const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1105
+ if (stylePaddingTop < prevStylePaddingTop) {
1106
+ const prevTotalSize = peek$(ctx, "totalSize") || 0;
1107
+ set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1108
+ setTimeout(() => {
1109
+ set$(ctx, "totalSize", prevTotalSize);
1110
+ }, 16);
1111
+ }
1112
+ set$(ctx, "stylePaddingTop", stylePaddingTop);
1113
+ }
1114
+ if (alignItemsPaddingTop !== void 0) {
1115
+ set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1116
+ }
1117
+ }
1118
+
1119
+ // src/updateAlignItemsPaddingTop.ts
1120
+ function updateAlignItemsPaddingTop(ctx, state) {
1121
+ const {
1122
+ scrollLength,
1123
+ props: { alignItemsAtEnd, data }
1124
+ } = state;
1125
+ if (alignItemsAtEnd) {
1126
+ let alignItemsPaddingTop = 0;
1127
+ if ((data == null ? void 0 : data.length) > 0) {
1128
+ const contentSize = getContentSize(ctx);
1129
+ alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1130
+ }
1131
+ setPaddingTop(ctx, { alignItemsPaddingTop });
1132
+ }
1133
+ }
1134
+
1135
+ // src/updateTotalSize.ts
1136
+ function updateTotalSize(ctx, state) {
1137
+ const {
1138
+ positions,
1139
+ props: { data }
1140
+ } = state;
1141
+ if (data.length === 0) {
1142
+ addTotalSize(ctx, state, null, 0);
1143
+ } else {
1144
+ const lastId = getId(state, data.length - 1);
1145
+ if (lastId !== void 0) {
1146
+ const lastPosition = positions.get(lastId);
1147
+ if (lastPosition !== void 0) {
1148
+ const lastSize = getItemSize(state, lastId, data.length - 1, data[data.length - 1]);
1149
+ if (lastSize !== void 0) {
1150
+ const totalSize = lastPosition + lastSize;
1151
+ addTotalSize(ctx, state, null, totalSize);
1152
+ }
1153
+ }
1154
+ }
1155
+ }
1156
+ }
1157
+ function addTotalSize(ctx, state, key, add) {
1158
+ const { alignItemsAtEnd } = state.props;
1159
+ {
1160
+ state.totalSize = add;
1161
+ }
1162
+ set$(ctx, "totalSize", state.totalSize);
1163
+ if (alignItemsAtEnd) {
1164
+ updateAlignItemsPaddingTop(ctx, state);
1165
+ }
1166
+ }
1167
+
1168
+ // src/updateAllPositions.ts
1169
+ function updateAllPositions(ctx, state, dataChanged) {
1170
+ var _a, _b, _c, _d, _e;
1171
+ const { averageSizes, columns, indexByKey, positions, firstFullyOnScreenIndex, idCache, sizesKnown } = state;
1172
+ const data = state.props.data;
1173
+ const numColumns = peek$(ctx, "numColumns");
1174
+ const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
1175
+ const scrollVelocity = getScrollVelocity(state);
1176
+ if (dataChanged) {
1177
+ indexByKey.clear();
1178
+ idCache.clear();
1179
+ }
1180
+ const itemType = "";
1181
+ let averageSize = (_a = averageSizes[itemType]) == null ? void 0 : _a.avg;
1182
+ if (averageSize !== void 0) {
1183
+ averageSize = roundSize(averageSize);
1184
+ }
1185
+ const shouldUseBackwards = !dataChanged && scrollVelocity < 0 && firstFullyOnScreenIndex > 5 && firstFullyOnScreenIndex < data.length;
1186
+ if (shouldUseBackwards && firstFullyOnScreenIndex !== void 0) {
1187
+ const anchorId = getId(state, firstFullyOnScreenIndex);
1188
+ const anchorPosition = positions.get(anchorId);
1189
+ if (anchorPosition !== void 0) {
1190
+ let currentRowTop2 = anchorPosition;
1191
+ let maxSizeInRow2 = 0;
1192
+ let bailout = false;
1193
+ for (let i = firstFullyOnScreenIndex - 1; i >= 0; i--) {
1194
+ const id = (_b = idCache.get(i)) != null ? _b : getId(state, i);
1195
+ const size = (_c = sizesKnown.get(id)) != null ? _c : getItemSize(state, id, i, data[i], averageSize);
1196
+ const itemColumn = columns.get(id);
1197
+ maxSizeInRow2 = Math.max(maxSizeInRow2, size);
1198
+ if (itemColumn === 1) {
1199
+ currentRowTop2 -= maxSizeInRow2;
1200
+ maxSizeInRow2 = 0;
1201
+ }
1202
+ if (currentRowTop2 < -2e3) {
1203
+ bailout = true;
1204
+ break;
1205
+ }
1206
+ positions.set(id, currentRowTop2);
1207
+ }
1208
+ if (!bailout) {
1209
+ updateTotalSize(ctx, state);
1210
+ return;
1211
+ }
1212
+ }
1213
+ }
1214
+ let currentRowTop = 0;
1215
+ let column = 1;
1216
+ let maxSizeInRow = 0;
1217
+ const hasColumns = numColumns > 1;
1218
+ const needsIndexByKey = dataChanged || indexByKey.size === 0;
1219
+ const dataLength = data.length;
1220
+ for (let i = 0; i < dataLength; i++) {
1221
+ const id = (_d = idCache.get(i)) != null ? _d : getId(state, i);
1222
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(state, id, i, data[i], averageSize);
1223
+ if (__DEV__ && needsIndexByKey) {
1224
+ if (indexByKeyForChecking.has(id)) {
1225
+ console.error(
1226
+ `[legend-list] Error: Detected overlapping key (${id}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
1227
+ );
1228
+ }
1229
+ indexByKeyForChecking.set(id, i);
1230
+ }
1231
+ positions.set(id, currentRowTop);
1232
+ if (needsIndexByKey) {
1233
+ indexByKey.set(id, i);
1234
+ }
1235
+ columns.set(id, column);
1236
+ if (hasColumns) {
1237
+ if (size > maxSizeInRow) {
1238
+ maxSizeInRow = size;
1239
+ }
1240
+ column++;
1241
+ if (column > numColumns) {
1242
+ currentRowTop += maxSizeInRow;
1243
+ column = 1;
1244
+ maxSizeInRow = 0;
1245
+ }
1246
+ } else {
1247
+ currentRowTop += size;
1248
+ }
1249
+ }
1250
+ updateTotalSize(ctx, state);
1251
+ }
1252
+
711
1253
  // src/viewability.ts
712
1254
  var mapViewabilityConfigCallbackPairs = /* @__PURE__ */ new Map();
713
1255
  function setupViewability(props) {
@@ -736,7 +1278,7 @@ function setupViewability(props) {
736
1278
  }
737
1279
  return viewabilityConfigCallbackPairs;
738
1280
  }
739
- function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, getId, scrollSize, start, end) {
1281
+ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end) {
740
1282
  for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
741
1283
  const viewabilityState = mapViewabilityConfigCallbackPairs.get(
742
1284
  viewabilityConfigCallbackPair.viewabilityConfig.id
@@ -746,15 +1288,15 @@ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, getId,
746
1288
  if (viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime) {
747
1289
  const timer = setTimeout(() => {
748
1290
  state.timeouts.delete(timer);
749
- updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize);
1291
+ updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
750
1292
  }, viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime);
751
1293
  state.timeouts.add(timer);
752
1294
  } else {
753
- updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize);
1295
+ updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
754
1296
  }
755
1297
  }
756
1298
  }
757
- function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize) {
1299
+ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize) {
758
1300
  const { viewabilityConfig, onViewableItemsChanged } = viewabilityConfigCallbackPair;
759
1301
  const configId = viewabilityConfig.id;
760
1302
  const viewabilityState = mapViewabilityConfigCallbackPairs.get(configId);
@@ -798,7 +1340,7 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getI
798
1340
  for (let i = start; i <= end; i++) {
799
1341
  const item = data[i];
800
1342
  if (item) {
801
- const key = getId(i);
1343
+ const key = getId(state, i);
802
1344
  const containerId = findContainerId(ctx, key);
803
1345
  if (isViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
804
1346
  const viewToken = {
@@ -894,9 +1436,299 @@ function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
894
1436
  cb == null ? void 0 : cb(viewToken);
895
1437
  }
896
1438
 
897
- // src/LegendList.tsx
898
- var DEFAULT_DRAW_DISTANCE = 250;
899
- var DEFAULT_ITEM_SIZE = 100;
1439
+ // src/calculateItemsInView.ts
1440
+ function calculateItemsInView(ctx, state, params = {}) {
1441
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1442
+ const {
1443
+ scrollLength,
1444
+ startBufferedId: startBufferedIdOrig,
1445
+ positions,
1446
+ columns,
1447
+ containerItemKeys,
1448
+ idCache,
1449
+ sizes,
1450
+ indexByKey,
1451
+ scrollForNextCalculateItemsInView,
1452
+ enableScrollForNextCalculateItemsInView,
1453
+ minIndexSizeChanged
1454
+ } = state;
1455
+ const data = state.props.data;
1456
+ if (!data || scrollLength === 0) {
1457
+ return;
1458
+ }
1459
+ const totalSize = peek$(ctx, "totalSize");
1460
+ const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
1461
+ const numColumns = peek$(ctx, "numColumns");
1462
+ const previousScrollAdjust = 0;
1463
+ const { dataChanged, doMVCP } = params;
1464
+ const speed = getScrollVelocity(state);
1465
+ if (doMVCP || dataChanged) {
1466
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, state) : void 0;
1467
+ updateAllPositions(ctx, state, dataChanged);
1468
+ checkMVCP == null ? void 0 : checkMVCP();
1469
+ }
1470
+ const scrollExtra = 0;
1471
+ const { queuedInitialLayout } = state;
1472
+ let { scroll: scrollState } = state;
1473
+ const initialScroll = state.props.initialScroll;
1474
+ if (!queuedInitialLayout && initialScroll) {
1475
+ const updatedOffset = calculateOffsetWithOffsetPosition(
1476
+ state,
1477
+ calculateOffsetForIndex(ctx, state, initialScroll.index),
1478
+ initialScroll
1479
+ );
1480
+ scrollState = updatedOffset;
1481
+ }
1482
+ const scrollAdjustPad = -previousScrollAdjust - topPad;
1483
+ let scroll = scrollState + scrollExtra + scrollAdjustPad;
1484
+ if (scroll + scrollLength > totalSize) {
1485
+ scroll = totalSize - scrollLength;
1486
+ }
1487
+ if (ENABLE_DEBUG_VIEW) {
1488
+ set$(ctx, "debugRawScroll", scrollState);
1489
+ set$(ctx, "debugComputedScroll", scroll);
1490
+ }
1491
+ const scrollBuffer = state.props.scrollBuffer;
1492
+ let scrollBufferTop = scrollBuffer;
1493
+ let scrollBufferBottom = scrollBuffer;
1494
+ if (speed > 0) {
1495
+ scrollBufferTop = scrollBuffer * 0.5;
1496
+ scrollBufferBottom = scrollBuffer * 1.5;
1497
+ } else {
1498
+ scrollBufferTop = scrollBuffer * 1.5;
1499
+ scrollBufferBottom = scrollBuffer * 0.5;
1500
+ }
1501
+ const scrollTopBuffered = scroll - scrollBufferTop;
1502
+ const scrollBottom = scroll + scrollLength;
1503
+ const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
1504
+ if (scrollForNextCalculateItemsInView) {
1505
+ const { top, bottom } = scrollForNextCalculateItemsInView;
1506
+ if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
1507
+ return;
1508
+ }
1509
+ }
1510
+ let startNoBuffer = null;
1511
+ let startBuffered = null;
1512
+ let startBufferedId = null;
1513
+ let endNoBuffer = null;
1514
+ let endBuffered = null;
1515
+ let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
1516
+ if (minIndexSizeChanged !== void 0) {
1517
+ loopStart = Math.min(minIndexSizeChanged, loopStart);
1518
+ state.minIndexSizeChanged = void 0;
1519
+ }
1520
+ for (let i = loopStart; i >= 0; i--) {
1521
+ const id = (_a = idCache.get(i)) != null ? _a : getId(state, i);
1522
+ const top = positions.get(id);
1523
+ const size = (_b = sizes.get(id)) != null ? _b : getItemSize(state, id, i, data[i]);
1524
+ const bottom = top + size;
1525
+ if (bottom > scroll - scrollBuffer) {
1526
+ loopStart = i;
1527
+ } else {
1528
+ break;
1529
+ }
1530
+ }
1531
+ const loopStartMod = loopStart % numColumns;
1532
+ if (loopStartMod > 0) {
1533
+ loopStart -= loopStartMod;
1534
+ }
1535
+ let foundEnd = false;
1536
+ let nextTop;
1537
+ let nextBottom;
1538
+ const prevNumContainers = ctx.values.get("numContainers");
1539
+ let maxIndexRendered = 0;
1540
+ for (let i = 0; i < prevNumContainers; i++) {
1541
+ const key = peek$(ctx, `containerItemKey${i}`);
1542
+ if (key !== void 0) {
1543
+ const index = indexByKey.get(key);
1544
+ maxIndexRendered = Math.max(maxIndexRendered, index);
1545
+ }
1546
+ }
1547
+ let firstFullyOnScreenIndex;
1548
+ const dataLength = data.length;
1549
+ for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
1550
+ const id = (_c = idCache.get(i)) != null ? _c : getId(state, i);
1551
+ const size = (_d = sizes.get(id)) != null ? _d : getItemSize(state, id, i, data[i]);
1552
+ const top = positions.get(id);
1553
+ if (!foundEnd) {
1554
+ if (startNoBuffer === null && top + size > scroll) {
1555
+ startNoBuffer = i;
1556
+ }
1557
+ if (firstFullyOnScreenIndex === void 0 && top >= scroll - 10) {
1558
+ firstFullyOnScreenIndex = i;
1559
+ }
1560
+ if (startBuffered === null && top + size > scrollTopBuffered) {
1561
+ startBuffered = i;
1562
+ startBufferedId = id;
1563
+ nextTop = top;
1564
+ }
1565
+ if (startNoBuffer !== null) {
1566
+ if (top <= scrollBottom) {
1567
+ endNoBuffer = i;
1568
+ }
1569
+ if (top <= scrollBottomBuffered) {
1570
+ endBuffered = i;
1571
+ nextBottom = top + size;
1572
+ } else {
1573
+ foundEnd = true;
1574
+ }
1575
+ }
1576
+ }
1577
+ }
1578
+ const idsInView = [];
1579
+ for (let i = firstFullyOnScreenIndex; i <= endNoBuffer; i++) {
1580
+ const id = (_e = idCache.get(i)) != null ? _e : getId(state, i);
1581
+ idsInView.push(id);
1582
+ }
1583
+ Object.assign(state, {
1584
+ startBuffered,
1585
+ startBufferedId,
1586
+ startNoBuffer,
1587
+ endBuffered,
1588
+ endNoBuffer,
1589
+ idsInView,
1590
+ firstFullyOnScreenIndex
1591
+ });
1592
+ if (enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0) {
1593
+ state.scrollForNextCalculateItemsInView = nextTop !== void 0 && nextBottom !== void 0 ? {
1594
+ top: nextTop,
1595
+ bottom: nextBottom
1596
+ } : void 0;
1597
+ }
1598
+ const numContainers = peek$(ctx, "numContainers");
1599
+ const pendingRemoval = [];
1600
+ if (dataChanged) {
1601
+ for (let i = 0; i < numContainers; i++) {
1602
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
1603
+ if (!state.props.keyExtractor || itemKey && indexByKey.get(itemKey) === void 0) {
1604
+ pendingRemoval.push(i);
1605
+ }
1606
+ }
1607
+ }
1608
+ if (startBuffered !== null && endBuffered !== null) {
1609
+ let numContainers2 = prevNumContainers;
1610
+ const needNewContainers = [];
1611
+ for (let i = startBuffered; i <= endBuffered; i++) {
1612
+ const id = (_f = idCache.get(i)) != null ? _f : getId(state, i);
1613
+ if (!containerItemKeys.has(id)) {
1614
+ needNewContainers.push(i);
1615
+ }
1616
+ }
1617
+ if (needNewContainers.length > 0) {
1618
+ const availableContainers = findAvailableContainers(
1619
+ ctx,
1620
+ state,
1621
+ needNewContainers.length,
1622
+ startBuffered,
1623
+ endBuffered,
1624
+ pendingRemoval
1625
+ );
1626
+ for (let idx = 0; idx < needNewContainers.length; idx++) {
1627
+ const i = needNewContainers[idx];
1628
+ const containerIndex = availableContainers[idx];
1629
+ const id = (_g = idCache.get(i)) != null ? _g : getId(state, i);
1630
+ const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
1631
+ if (oldKey && oldKey !== id) {
1632
+ containerItemKeys.delete(oldKey);
1633
+ }
1634
+ set$(ctx, `containerItemKey${containerIndex}`, id);
1635
+ set$(ctx, `containerItemData${containerIndex}`, data[i]);
1636
+ containerItemKeys.add(id);
1637
+ if (containerIndex >= numContainers2) {
1638
+ numContainers2 = containerIndex + 1;
1639
+ }
1640
+ }
1641
+ if (numContainers2 !== prevNumContainers) {
1642
+ set$(ctx, "numContainers", numContainers2);
1643
+ if (numContainers2 > peek$(ctx, "numContainersPooled")) {
1644
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
1645
+ }
1646
+ }
1647
+ }
1648
+ }
1649
+ for (let i = 0; i < numContainers; i++) {
1650
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
1651
+ if (pendingRemoval.includes(i)) {
1652
+ if (itemKey) {
1653
+ containerItemKeys.delete(itemKey);
1654
+ }
1655
+ set$(ctx, `containerItemKey${i}`, void 0);
1656
+ set$(ctx, `containerItemData${i}`, void 0);
1657
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1658
+ set$(ctx, `containerColumn${i}`, -1);
1659
+ } else {
1660
+ const itemIndex = indexByKey.get(itemKey);
1661
+ const item = data[itemIndex];
1662
+ if (item !== void 0) {
1663
+ const id = (_h = idCache.get(itemIndex)) != null ? _h : getId(state, itemIndex);
1664
+ const position = positions.get(id);
1665
+ if (position === void 0) {
1666
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1667
+ } else {
1668
+ const pos = positions.get(id);
1669
+ const column = columns.get(id) || 1;
1670
+ const prevPos = peek$(ctx, `containerPosition${i}`);
1671
+ const prevColumn = peek$(ctx, `containerColumn${i}`);
1672
+ const prevData = peek$(ctx, `containerItemData${i}`);
1673
+ if (!prevPos || pos > POSITION_OUT_OF_VIEW && pos !== prevPos) {
1674
+ set$(ctx, `containerPosition${i}`, pos);
1675
+ }
1676
+ if (column >= 0 && column !== prevColumn) {
1677
+ set$(ctx, `containerColumn${i}`, column);
1678
+ }
1679
+ if (prevData !== item) {
1680
+ set$(ctx, `containerItemData${i}`, data[itemIndex]);
1681
+ }
1682
+ }
1683
+ }
1684
+ }
1685
+ }
1686
+ if (!queuedInitialLayout && endBuffered !== null) {
1687
+ if (checkAllSizesKnown(state)) {
1688
+ setDidLayout(ctx, state);
1689
+ }
1690
+ }
1691
+ if (state.props.viewabilityConfigCallbackPairs) {
1692
+ updateViewableItems(
1693
+ state,
1694
+ ctx,
1695
+ state.props.viewabilityConfigCallbackPairs,
1696
+ scrollLength,
1697
+ startNoBuffer,
1698
+ endNoBuffer
1699
+ );
1700
+ }
1701
+ }
1702
+
1703
+ // src/checkAtTop.ts
1704
+ function checkAtTop(state) {
1705
+ if (!state) {
1706
+ return;
1707
+ }
1708
+ const {
1709
+ scrollLength,
1710
+ scroll,
1711
+ props: { onStartReachedThreshold }
1712
+ } = state;
1713
+ const distanceFromTop = scroll;
1714
+ state.isAtStart = distanceFromTop <= 0;
1715
+ state.isStartReached = checkThreshold(
1716
+ distanceFromTop,
1717
+ false,
1718
+ onStartReachedThreshold * scrollLength,
1719
+ state.isStartReached,
1720
+ state.startReachedBlockedByTimer,
1721
+ (distance) => {
1722
+ var _a, _b;
1723
+ return (_b = (_a = state.props).onStartReached) == null ? void 0 : _b.call(_a, { distanceFromStart: distance });
1724
+ },
1725
+ (block) => {
1726
+ state.startReachedBlockedByTimer = block;
1727
+ }
1728
+ );
1729
+ }
1730
+
1731
+ // src/createColumnWrapperStyle.ts
900
1732
  function createColumnWrapperStyle(contentContainerStyle) {
901
1733
  const { gap, columnGap, rowGap } = contentContainerStyle;
902
1734
  if (gap || columnGap || rowGap) {
@@ -910,14 +1742,317 @@ function createColumnWrapperStyle(contentContainerStyle) {
910
1742
  };
911
1743
  }
912
1744
  }
913
- var LegendList = typedForwardRef(function LegendList2(props, forwardedRef) {
914
- return /* @__PURE__ */ React2.createElement(StateProvider, null, /* @__PURE__ */ React2.createElement(LegendListInner, { ...props, ref: forwardedRef }));
915
- });
916
- var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
917
- var _a;
918
- const {
919
- data: dataProp = [],
920
- initialScrollIndex: initialScrollIndexProp,
1745
+
1746
+ // src/doInitialAllocateContainers.ts
1747
+ function doInitialAllocateContainers(ctx, state) {
1748
+ const { scrollLength } = state;
1749
+ const data = state.props.data;
1750
+ if (scrollLength > 0 && data.length > 0 && !peek$(ctx, "numContainers")) {
1751
+ const averageItemSize = state.props.getEstimatedItemSize ? state.props.getEstimatedItemSize(0, data[0]) : state.props.estimatedItemSize;
1752
+ const Extra = 1.5;
1753
+ const numContainers = Math.ceil(
1754
+ (scrollLength + state.props.scrollBuffer * 2) / averageItemSize * state.props.numColumns * Extra
1755
+ );
1756
+ for (let i = 0; i < numContainers; i++) {
1757
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1758
+ set$(ctx, `containerColumn${i}`, -1);
1759
+ }
1760
+ set$(ctx, "numContainers", numContainers);
1761
+ set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
1762
+ if (!IsNewArchitecture) {
1763
+ if (state.props.initialScroll) {
1764
+ requestAnimationFrame(() => {
1765
+ calculateItemsInView(ctx, state);
1766
+ });
1767
+ } else {
1768
+ calculateItemsInView(ctx, state);
1769
+ }
1770
+ }
1771
+ return true;
1772
+ }
1773
+ }
1774
+
1775
+ // src/doMaintainScrollAtEnd.ts
1776
+ function doMaintainScrollAtEnd(ctx, state, animated) {
1777
+ const {
1778
+ refScroller,
1779
+ props: { maintainScrollAtEnd }
1780
+ } = state;
1781
+ if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
1782
+ const paddingTop = peek$(ctx, "alignItemsPaddingTop");
1783
+ if (paddingTop > 0) {
1784
+ state.scroll = 0;
1785
+ }
1786
+ requestAnimationFrame(() => {
1787
+ var _a;
1788
+ state.maintainingScrollAtEnd = true;
1789
+ (_a = refScroller.current) == null ? void 0 : _a.scrollToEnd({
1790
+ animated
1791
+ });
1792
+ setTimeout(
1793
+ () => {
1794
+ state.maintainingScrollAtEnd = false;
1795
+ },
1796
+ 0
1797
+ );
1798
+ });
1799
+ return true;
1800
+ }
1801
+ }
1802
+ function getRenderedItem(ctx, state, key) {
1803
+ if (!state) {
1804
+ return null;
1805
+ }
1806
+ const {
1807
+ indexByKey,
1808
+ props: { data, renderItem: renderItem2 }
1809
+ } = state;
1810
+ const index = indexByKey.get(key);
1811
+ if (index === void 0) {
1812
+ return null;
1813
+ }
1814
+ let renderedItem = null;
1815
+ if (renderItem2) {
1816
+ const itemProps = {
1817
+ item: data[index],
1818
+ index,
1819
+ extraData: peek$(ctx, "extraData")
1820
+ };
1821
+ renderedItem = React3__default.createElement(renderItem2, itemProps);
1822
+ }
1823
+ return { index, item: data[index], renderedItem };
1824
+ }
1825
+
1826
+ // src/handleLayout.ts
1827
+ function handleLayout(ctx, state, size, setCanRender) {
1828
+ const scrollLength = size[state.props.horizontal ? "width" : "height"];
1829
+ const otherAxisSize = size[state.props.horizontal ? "height" : "width"];
1830
+ const didChange = scrollLength !== state.scrollLength;
1831
+ const prevOtherAxisSize = state.otherAxisSize;
1832
+ state.scrollLength = scrollLength;
1833
+ state.otherAxisSize = otherAxisSize;
1834
+ state.lastBatchingAction = Date.now();
1835
+ state.scrollForNextCalculateItemsInView = void 0;
1836
+ doInitialAllocateContainers(ctx, state);
1837
+ if (didChange) {
1838
+ calculateItemsInView(ctx, state, { doMVCP: true });
1839
+ }
1840
+ if (didChange || otherAxisSize !== prevOtherAxisSize) {
1841
+ set$(ctx, "scrollSize", { width: size.width, height: size.height });
1842
+ }
1843
+ doMaintainScrollAtEnd(ctx, state, false);
1844
+ updateAlignItemsPaddingTop(ctx, state);
1845
+ checkAtBottom(ctx, state);
1846
+ checkAtTop(state);
1847
+ if (state) {
1848
+ state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
1849
+ }
1850
+ if (__DEV__ && scrollLength === 0) {
1851
+ warnDevOnce(
1852
+ "height0",
1853
+ `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.`
1854
+ );
1855
+ }
1856
+ calculateItemsInView(ctx, state, { doMVCP: true });
1857
+ setCanRender(true);
1858
+ }
1859
+
1860
+ // src/onScroll.ts
1861
+ function onScroll(ctx, state, event) {
1862
+ var _a, _b, _c, _d, _e;
1863
+ 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) {
1864
+ return;
1865
+ }
1866
+ const newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
1867
+ const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
1868
+ if (ignoreScrollFromMVCP && !state.scrollingTo) {
1869
+ const { lt, gt } = ignoreScrollFromMVCP;
1870
+ if (lt && newScroll < lt || gt && newScroll > gt) {
1871
+ return;
1872
+ }
1873
+ }
1874
+ state.scrollPending = newScroll;
1875
+ updateScroll(ctx, state, newScroll);
1876
+ (_e = (_d = state.props).onScroll) == null ? void 0 : _e.call(_d, event);
1877
+ }
1878
+ function updateScroll(ctx, state, newScroll) {
1879
+ const scrollingTo = state.scrollingTo;
1880
+ state.hasScrolled = true;
1881
+ state.lastBatchingAction = Date.now();
1882
+ const currentTime = performance.now();
1883
+ if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
1884
+ state.scrollHistory.push({ scroll: newScroll, time: currentTime });
1885
+ }
1886
+ if (state.scrollHistory.length > 5) {
1887
+ state.scrollHistory.shift();
1888
+ }
1889
+ state.scrollPrev = state.scroll;
1890
+ state.scrollPrevTime = state.scrollTime;
1891
+ state.scroll = newScroll;
1892
+ state.scrollTime = currentTime;
1893
+ calculateItemsInView(ctx, state);
1894
+ checkAtBottom(ctx, state);
1895
+ checkAtTop(state);
1896
+ }
1897
+
1898
+ // src/updateItemSize.ts
1899
+ function updateItemSizes(ctx, state, itemUpdates) {
1900
+ var _a;
1901
+ const {
1902
+ props: { horizontal, maintainVisibleContentPosition, suggestEstimatedItemSize, onItemSizeChanged, data }
1903
+ } = state;
1904
+ if (!data) return;
1905
+ let needsRecalculate = false;
1906
+ let shouldMaintainScrollAtEnd = false;
1907
+ let minIndexSizeChanged;
1908
+ let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
1909
+ for (const { itemKey, sizeObj } of itemUpdates) {
1910
+ const index = state.indexByKey.get(itemKey);
1911
+ const prevSizeKnown = state.sizesKnown.get(itemKey);
1912
+ const diff = updateOneItemSize(state, itemKey, sizeObj);
1913
+ const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
1914
+ if (diff !== 0) {
1915
+ minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
1916
+ if (((_a = state.scrollingTo) == null ? void 0 : _a.viewPosition) && maintainVisibleContentPosition && index === state.scrollingTo.index) {
1917
+ requestAdjust(ctx, state, diff * state.scrollingTo.viewPosition);
1918
+ }
1919
+ const { startBuffered, endBuffered } = state;
1920
+ needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
1921
+ if (!needsRecalculate) {
1922
+ const numContainers = ctx.values.get("numContainers");
1923
+ for (let i = 0; i < numContainers; i++) {
1924
+ if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
1925
+ needsRecalculate = true;
1926
+ break;
1927
+ }
1928
+ }
1929
+ }
1930
+ if (state.needsOtherAxisSize) {
1931
+ const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
1932
+ maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
1933
+ }
1934
+ if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
1935
+ shouldMaintainScrollAtEnd = true;
1936
+ }
1937
+ onItemSizeChanged == null ? void 0 : onItemSizeChanged({
1938
+ size,
1939
+ previous: size - diff,
1940
+ index,
1941
+ itemKey,
1942
+ itemData: state.props.data[index]
1943
+ });
1944
+ }
1945
+ }
1946
+ if (minIndexSizeChanged !== void 0) {
1947
+ state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
1948
+ }
1949
+ if (__DEV__ && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
1950
+ if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
1951
+ state.timeoutSizeMessage = setTimeout(() => {
1952
+ var _a2;
1953
+ state.timeoutSizeMessage = void 0;
1954
+ const num = state.sizesKnown.size;
1955
+ const avg = (_a2 = state.averageSizes[""]) == null ? void 0 : _a2.avg;
1956
+ console.warn(
1957
+ `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
1958
+ );
1959
+ }, 1e3);
1960
+ }
1961
+ const cur = peek$(ctx, "otherAxisSize");
1962
+ if (!cur || maxOtherAxisSize > cur) {
1963
+ set$(ctx, "otherAxisSize", maxOtherAxisSize);
1964
+ }
1965
+ const containersDidLayout = peek$(ctx, "containersDidLayout");
1966
+ if (containersDidLayout || checkAllSizesKnown(state)) {
1967
+ if (needsRecalculate) {
1968
+ state.scrollForNextCalculateItemsInView = void 0;
1969
+ calculateItemsInView(ctx, state, { doMVCP: true });
1970
+ }
1971
+ if (shouldMaintainScrollAtEnd) {
1972
+ doMaintainScrollAtEnd(ctx, state, false);
1973
+ }
1974
+ }
1975
+ }
1976
+ function updateItemSize(ctx, state, itemKey, sizeObj) {
1977
+ var _a, _b;
1978
+ if (IsNewArchitecture) {
1979
+ const { sizesKnown } = state;
1980
+ const numContainers = ctx.values.get("numContainers");
1981
+ const changes = [];
1982
+ for (let i = 0; i < numContainers; i++) {
1983
+ const containerItemKey = peek$(ctx, `containerItemKey${i}`);
1984
+ if (itemKey === containerItemKey) {
1985
+ changes.push({ itemKey, sizeObj });
1986
+ } else if (!sizesKnown.has(containerItemKey) && containerItemKey !== void 0) {
1987
+ const containerRef = ctx.viewRefs.get(i);
1988
+ if (containerRef) {
1989
+ const measured = (_b = (_a = containerRef.current) == null ? void 0 : _a.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a);
1990
+ if (measured) {
1991
+ changes.push({ itemKey: containerItemKey, sizeObj: measured });
1992
+ }
1993
+ }
1994
+ }
1995
+ }
1996
+ if (changes.length > 0) {
1997
+ updateItemSizes(ctx, state, changes);
1998
+ }
1999
+ } else {
2000
+ updateItemSizes(ctx, state, [{ itemKey, sizeObj }]);
2001
+ }
2002
+ }
2003
+ function updateOneItemSize(state, itemKey, sizeObj) {
2004
+ const {
2005
+ sizes,
2006
+ indexByKey,
2007
+ sizesKnown,
2008
+ averageSizes,
2009
+ props: { data, horizontal }
2010
+ } = state;
2011
+ if (!data) return 0;
2012
+ const index = indexByKey.get(itemKey);
2013
+ const prevSize = getItemSize(state, itemKey, index, data);
2014
+ const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2015
+ sizesKnown.set(itemKey, size);
2016
+ const itemType = "";
2017
+ let averages = averageSizes[itemType];
2018
+ if (!averages) {
2019
+ averages = averageSizes[itemType] = { num: 0, avg: 0 };
2020
+ }
2021
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2022
+ averages.num++;
2023
+ if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2024
+ sizes.set(itemKey, size);
2025
+ return size - prevSize;
2026
+ }
2027
+ return 0;
2028
+ }
2029
+ var useCombinedRef = (...refs) => {
2030
+ const callback = useCallback((element) => {
2031
+ for (const ref of refs) {
2032
+ if (!ref) {
2033
+ continue;
2034
+ }
2035
+ if (isFunction(ref)) {
2036
+ ref(element);
2037
+ } else {
2038
+ ref.current = element;
2039
+ }
2040
+ }
2041
+ }, refs);
2042
+ return callback;
2043
+ };
2044
+
2045
+ // src/LegendList.tsx
2046
+ var DEFAULT_DRAW_DISTANCE = 250;
2047
+ var DEFAULT_ITEM_SIZE = 100;
2048
+ var LegendList = typedForwardRef(function LegendList2(props, forwardedRef) {
2049
+ return /* @__PURE__ */ React3.createElement(StateProvider, null, /* @__PURE__ */ React3.createElement(LegendListInner, { ...props, ref: forwardedRef }));
2050
+ });
2051
+ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
2052
+ var _a;
2053
+ const {
2054
+ data: dataProp = [],
2055
+ initialScrollIndex: initialScrollIndexProp,
921
2056
  initialScrollOffset,
922
2057
  horizontal,
923
2058
  drawDistance = 250,
@@ -955,19 +2090,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
955
2090
  viewabilityConfig,
956
2091
  viewabilityConfigCallbackPairs,
957
2092
  onViewableItemsChanged,
2093
+ onStartReached,
2094
+ onEndReached,
2095
+ onLoad,
958
2096
  ...rest
959
2097
  } = props;
960
2098
  const [renderNum, setRenderNum] = useState(0);
961
2099
  const initialScroll = typeof initialScrollIndexProp === "number" ? { index: initialScrollIndexProp } : initialScrollIndexProp;
962
2100
  const initialScrollIndex = initialScroll == null ? void 0 : initialScroll.index;
963
- const refLoadStartTime = useRef(Date.now());
964
- const [canRender, setCanRender] = React2.useState(!IsNewArchitecture);
965
- const callbacks = useRef({
966
- onStartReached: rest.onStartReached,
967
- onEndReached: rest.onEndReached
968
- });
969
- callbacks.current.onStartReached = rest.onStartReached;
970
- callbacks.current.onEndReached = rest.onEndReached;
2101
+ const [canRender, setCanRender] = React3.useState(!IsNewArchitecture);
971
2102
  const contentContainerStyle = { ...StyleSheet.flatten(contentContainerStyleProp) };
972
2103
  const style = { ...StyleSheet.flatten(styleProp) };
973
2104
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
@@ -980,59 +2111,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
980
2111
  const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
981
2112
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (item, index) => index.toString();
982
2113
  const refState = useRef();
983
- const getId = (index) => {
984
- const state = refState.current;
985
- if (!(state == null ? void 0 : state.data)) {
986
- return "";
987
- }
988
- const data = state.data;
989
- const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
990
- const id = ret;
991
- state.idCache.set(index, id);
992
- return id;
993
- };
994
- const getItemSize = (key, index, data, useAverageSize = false) => {
995
- const state = refState.current;
996
- const sizeKnown = state.sizesKnown.get(key);
997
- if (sizeKnown !== void 0) {
998
- return sizeKnown;
999
- }
1000
- const sizePrevious = state.sizes.get(key);
1001
- if (sizePrevious !== void 0) {
1002
- return sizePrevious;
1003
- }
1004
- const size = getEstimatedItemSize ? getEstimatedItemSize(index, data) : estimatedItemSize;
1005
- state.sizes.set(key, size);
1006
- return size;
1007
- };
1008
- const calculateOffsetForIndex = (index) => {
1009
- var _a2;
1010
- let position = 0;
1011
- if (index !== void 0) {
1012
- position = ((_a2 = refState.current) == null ? void 0 : _a2.positions.get(getId(index))) || 0;
1013
- }
1014
- const paddingTop = peek$(ctx, "stylePaddingTop");
1015
- if (paddingTop) {
1016
- position += paddingTop;
1017
- }
1018
- const headerSize = peek$(ctx, "headerSize");
1019
- if (headerSize) {
1020
- position += headerSize;
1021
- }
1022
- return position;
1023
- };
1024
- const calculateOffsetWithOffsetPosition = (offsetParam, params) => {
1025
- const { index, viewOffset, viewPosition } = params;
1026
- let offset = offsetParam;
1027
- const state = refState.current;
1028
- if (viewOffset) {
1029
- offset -= viewOffset;
1030
- }
1031
- if (viewPosition !== void 0 && index !== void 0) {
1032
- offset -= viewPosition * (state.scrollLength - getItemSize(getId(index), index, state.data[index]));
1033
- }
1034
- return offset;
1035
- };
1036
2114
  if (!refState.current) {
1037
2115
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { width: 0, height: 0 } : Dimensions.get("window"))[horizontal ? "width" : "height"];
1038
2116
  refState.current = {
@@ -1044,7 +2122,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1044
2122
  isEndReached: false,
1045
2123
  isAtEnd: false,
1046
2124
  isAtStart: false,
1047
- data: dataProp,
1048
2125
  scrollLength: initialScrollLength,
1049
2126
  startBuffered: -1,
1050
2127
  startNoBuffer: -1,
@@ -1055,7 +2132,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1055
2132
  totalSize: 0,
1056
2133
  timeouts: /* @__PURE__ */ new Set(),
1057
2134
  viewabilityConfigCallbackPairs: void 0,
1058
- renderItem: void 0,
1059
2135
  scrollAdjustHandler: new ScrollAdjustHandler(ctx),
1060
2136
  nativeMarginTop: 0,
1061
2137
  scrollPrev: 0,
@@ -1074,775 +2150,93 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1074
2150
  queuedCalculateItemsInView: 0,
1075
2151
  lastBatchingAction: Date.now(),
1076
2152
  averageSizes: {},
1077
- onScroll: onScrollProp,
1078
2153
  idsInView: [],
1079
2154
  containerItemKeys: /* @__PURE__ */ new Set(),
1080
- idCache: /* @__PURE__ */ new Map()
2155
+ idCache: /* @__PURE__ */ new Map(),
2156
+ props: {},
2157
+ refScroller: void 0,
2158
+ loadStartTime: Date.now(),
2159
+ initialScroll
1081
2160
  };
1082
2161
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
1083
2162
  set$(ctx, "extraData", extraData);
1084
2163
  }
1085
- const didDataChange = refState.current.data !== dataProp;
1086
- refState.current.data = dataProp;
1087
- refState.current.onScroll = onScrollProp;
1088
- const getScrollVelocity = () => {
1089
- const { scrollHistory } = refState.current;
1090
- let velocity = 0;
1091
- if (scrollHistory.length >= 1) {
1092
- const newest = scrollHistory[scrollHistory.length - 1];
1093
- let oldest;
1094
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1095
- const entry = scrollHistory[i];
1096
- const nextEntry = scrollHistory[i + 1];
1097
- if (i > 0) {
1098
- const prevEntry = scrollHistory[i - 1];
1099
- const prevDirection = entry.scroll - prevEntry.scroll;
1100
- const currentDirection = nextEntry.scroll - entry.scroll;
1101
- if (prevDirection > 0 && currentDirection < 0 || prevDirection < 0 && currentDirection > 0) {
1102
- break;
1103
- }
1104
- }
1105
- }
1106
- for (let i = 0; i < scrollHistory.length - 1; i++) {
1107
- const entry = scrollHistory[i];
1108
- if (newest.time - entry.time <= 1e3) {
1109
- oldest = entry;
1110
- break;
1111
- }
1112
- }
1113
- if (oldest) {
1114
- const scrollDiff = newest.scroll - oldest.scroll;
1115
- const timeDiff = newest.time - oldest.time;
1116
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
1117
- }
1118
- }
1119
- return velocity;
1120
- };
1121
- const updateAllPositions = (dataChanged) => {
1122
- var _a2, _b, _c;
1123
- const { columns, data, indexByKey, positions, firstFullyOnScreenIndex, idCache, sizes } = refState.current;
1124
- const numColumns = (_a2 = peek$(ctx, "numColumns")) != null ? _a2 : numColumnsProp;
1125
- const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
1126
- const scrollVelocity = getScrollVelocity();
1127
- if (dataChanged) {
1128
- indexByKey.clear();
1129
- idCache.clear();
1130
- }
1131
- const shouldUseBackwards = !dataChanged && scrollVelocity < 0 && firstFullyOnScreenIndex > 5 && firstFullyOnScreenIndex < data.length;
1132
- if (shouldUseBackwards && firstFullyOnScreenIndex !== void 0) {
1133
- const anchorId = getId(firstFullyOnScreenIndex);
1134
- const anchorPosition = positions.get(anchorId);
1135
- if (anchorPosition !== void 0) {
1136
- let currentRowTop2 = anchorPosition;
1137
- let maxSizeInRow2 = 0;
1138
- let bailout = false;
1139
- for (let i = firstFullyOnScreenIndex - 1; i >= 0; i--) {
1140
- const id = getId(i);
1141
- const size = getItemSize(id, i, data[i], false);
1142
- const itemColumn = columns.get(id);
1143
- maxSizeInRow2 = Math.max(maxSizeInRow2, size);
1144
- if (itemColumn === 1) {
1145
- currentRowTop2 -= maxSizeInRow2;
1146
- maxSizeInRow2 = 0;
1147
- }
1148
- if (currentRowTop2 < -2e3) {
1149
- bailout = true;
1150
- break;
1151
- }
1152
- positions.set(id, currentRowTop2);
1153
- }
1154
- if (!bailout) {
1155
- updateTotalSize();
1156
- return;
1157
- }
1158
- }
1159
- }
1160
- let currentRowTop = 0;
1161
- let column = 1;
1162
- let maxSizeInRow = 0;
1163
- const hasColumns = numColumns > 1;
1164
- const needsIndexByKey = dataChanged || indexByKey.size === 0;
1165
- const dataLength = data.length;
1166
- for (let i = 0; i < dataLength; i++) {
1167
- const id = (_b = idCache.get(i)) != null ? _b : getId(i);
1168
- const size = (_c = sizes.get(id)) != null ? _c : getItemSize(id, i, data[i], false);
1169
- if (__DEV__ && needsIndexByKey) {
1170
- if (indexByKeyForChecking.has(id)) {
1171
- console.error(
1172
- `[legend-list] Error: Detected overlapping key (${id}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
1173
- );
1174
- }
1175
- indexByKeyForChecking.set(id, i);
1176
- }
1177
- positions.set(id, currentRowTop);
1178
- if (needsIndexByKey) {
1179
- indexByKey.set(id, i);
1180
- }
1181
- columns.set(id, column);
1182
- if (hasColumns) {
1183
- if (size > maxSizeInRow) {
1184
- maxSizeInRow = size;
1185
- }
1186
- column++;
1187
- if (column > numColumns) {
1188
- currentRowTop += maxSizeInRow;
1189
- column = 1;
1190
- maxSizeInRow = 0;
1191
- }
1192
- } else {
1193
- currentRowTop += size;
1194
- }
1195
- }
1196
- updateTotalSize();
1197
- };
1198
- const scrollToIndex = ({
1199
- index,
1200
- viewOffset = 0,
1201
- animated = true,
1202
- viewPosition
1203
- }) => {
1204
- const state = refState.current;
1205
- if (index >= state.data.length) {
1206
- index = state.data.length - 1;
1207
- } else if (index < 0) {
1208
- index = 0;
1209
- }
1210
- const firstIndexOffset = calculateOffsetForIndex(index);
1211
- const isLast = index === state.data.length - 1;
1212
- if (isLast && viewPosition === void 0) {
1213
- viewPosition = 1;
1214
- }
1215
- const firstIndexScrollPostion = firstIndexOffset - viewOffset;
1216
- state.scrollForNextCalculateItemsInView = void 0;
1217
- scrollTo({ offset: firstIndexScrollPostion, animated, index, viewPosition: viewPosition != null ? viewPosition : 0, viewOffset });
1218
- };
1219
- const setDidLayout = () => {
1220
- refState.current.queuedInitialLayout = true;
1221
- checkAtBottom();
1222
- set$(ctx, "containersDidLayout", true);
1223
- if (props.onLoad) {
1224
- props.onLoad({ elapsedTimeInMs: Date.now() - refLoadStartTime.current });
1225
- }
1226
- };
1227
- const addTotalSize = useCallback((key, add) => {
1228
- const state = refState.current;
1229
- if (key === null) {
1230
- state.totalSize = add;
1231
- } else {
1232
- state.totalSize += add;
1233
- }
1234
- set$(ctx, "totalSize", state.totalSize);
1235
- if (alignItemsAtEnd) {
1236
- updateAlignItemsPaddingTop();
1237
- }
1238
- }, []);
1239
- const checkAllSizesKnown = useCallback(() => {
1240
- const { startBuffered, endBuffered, sizesKnown } = refState.current;
1241
- if (endBuffered !== null) {
1242
- let areAllKnown = true;
1243
- for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
1244
- const key = getId(i);
1245
- areAllKnown && (areAllKnown = sizesKnown.has(key));
1246
- }
1247
- return areAllKnown;
1248
- }
1249
- return false;
1250
- }, []);
1251
- const requestAdjust = (positionDiff) => {
1252
- if (Math.abs(positionDiff) > 0.1) {
1253
- const state = refState.current;
1254
- const doit = () => {
1255
- state.scrollAdjustHandler.requestAdjust(positionDiff);
1256
- };
1257
- state.scroll += positionDiff;
1258
- state.scrollForNextCalculateItemsInView = void 0;
1259
- if (peek$(ctx, "containersDidLayout")) {
1260
- doit();
1261
- } else {
1262
- requestAnimationFrame(doit);
1263
- }
1264
- const threshold = state.scroll - positionDiff / 2;
1265
- if (!state.ignoreScrollFromMVCP) {
1266
- state.ignoreScrollFromMVCP = {};
1267
- }
1268
- if (positionDiff > 0) {
1269
- state.ignoreScrollFromMVCP.lt = threshold;
1270
- } else {
1271
- state.ignoreScrollFromMVCP.gt = threshold;
1272
- }
1273
- if (state.ignoreScrollFromMVCPTimeout) {
1274
- clearTimeout(state.ignoreScrollFromMVCPTimeout);
1275
- }
1276
- state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
1277
- state.ignoreScrollFromMVCP = void 0;
1278
- }, 100);
1279
- }
1280
- };
1281
- const prepareMVCP = useCallback(() => {
1282
- const state = refState.current;
1283
- const { positions, scrollingTo } = state;
1284
- let prevPosition;
1285
- let targetId;
1286
- let targetIndex;
1287
- const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
1288
- if (maintainVisibleContentPosition) {
1289
- const indexByKey = state.indexByKey;
1290
- if (scrollTarget !== void 0) {
1291
- targetId = getId(scrollTarget);
1292
- targetIndex = scrollTarget;
1293
- } else if (state.idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1294
- targetId = state.idsInView.find((id) => indexByKey.get(id) !== void 0);
1295
- targetIndex = indexByKey.get(targetId);
1296
- }
1297
- if (targetId !== void 0 && targetIndex !== void 0) {
1298
- prevPosition = positions.get(targetId);
1299
- }
1300
- }
1301
- return () => {
1302
- if (targetId !== void 0 && prevPosition !== void 0) {
1303
- const newPosition = positions.get(targetId);
1304
- if (newPosition !== void 0) {
1305
- const positionDiff = newPosition - prevPosition;
1306
- if (Math.abs(positionDiff) > 0.1) {
1307
- requestAdjust(positionDiff);
1308
- }
1309
- }
1310
- }
1311
- };
1312
- }, []);
1313
- const calculateItemsInView = useCallback((params = {}) => {
1314
- var _a2, _b, _c, _d, _e, _f, _g, _h;
1315
- const state = refState.current;
1316
- const {
1317
- data,
1318
- scrollLength,
1319
- startBufferedId: startBufferedIdOrig,
1320
- positions,
1321
- columns,
1322
- containerItemKeys,
1323
- idCache,
1324
- sizes,
1325
- indexByKey,
1326
- scrollForNextCalculateItemsInView,
1327
- enableScrollForNextCalculateItemsInView,
1328
- minIndexSizeChanged
1329
- } = state;
1330
- if (!data || scrollLength === 0) {
1331
- return;
1332
- }
1333
- const totalSize = peek$(ctx, "totalSize");
1334
- const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
1335
- const numColumns = peek$(ctx, "numColumns");
1336
- const previousScrollAdjust = 0;
1337
- const { dataChanged, doMVCP } = params;
1338
- const speed = getScrollVelocity();
1339
- if (doMVCP || dataChanged) {
1340
- const checkMVCP = doMVCP ? prepareMVCP() : void 0;
1341
- updateAllPositions(dataChanged);
1342
- checkMVCP == null ? void 0 : checkMVCP();
1343
- }
1344
- const scrollExtra = 0;
1345
- const useAverageSize = false;
1346
- const { queuedInitialLayout } = state;
1347
- let { scroll: scrollState } = state;
1348
- if (!queuedInitialLayout && initialScroll) {
1349
- const updatedOffset = calculateOffsetWithOffsetPosition(
1350
- calculateOffsetForIndex(initialScroll.index),
1351
- initialScroll
1352
- );
1353
- scrollState = updatedOffset;
1354
- }
1355
- const scrollAdjustPad = -previousScrollAdjust - topPad;
1356
- let scroll = scrollState + scrollExtra + scrollAdjustPad;
1357
- if (scroll + scrollLength > totalSize) {
1358
- scroll = totalSize - scrollLength;
1359
- }
1360
- if (ENABLE_DEBUG_VIEW) {
1361
- set$(ctx, "debugRawScroll", scrollState);
1362
- set$(ctx, "debugComputedScroll", scroll);
1363
- }
1364
- let scrollBufferTop = scrollBuffer;
1365
- let scrollBufferBottom = scrollBuffer;
1366
- if (speed > 0) {
1367
- scrollBufferTop = scrollBuffer * 0.5;
1368
- scrollBufferBottom = scrollBuffer * 1.5;
1369
- } else {
1370
- scrollBufferTop = scrollBuffer * 1.5;
1371
- scrollBufferBottom = scrollBuffer * 0.5;
1372
- }
1373
- const scrollTopBuffered = scroll - scrollBufferTop;
1374
- const scrollBottom = scroll + scrollLength;
1375
- const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
1376
- if (scrollForNextCalculateItemsInView) {
1377
- const { top, bottom } = scrollForNextCalculateItemsInView;
1378
- if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
1379
- return;
1380
- }
1381
- }
1382
- let startNoBuffer = null;
1383
- let startBuffered = null;
1384
- let startBufferedId = null;
1385
- let endNoBuffer = null;
1386
- let endBuffered = null;
1387
- let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
1388
- if (minIndexSizeChanged !== void 0) {
1389
- loopStart = Math.min(minIndexSizeChanged, loopStart);
1390
- state.minIndexSizeChanged = void 0;
1391
- }
1392
- for (let i = loopStart; i >= 0; i--) {
1393
- const id = (_a2 = idCache.get(i)) != null ? _a2 : getId(i);
1394
- const top = positions.get(id);
1395
- const size = (_b = sizes.get(id)) != null ? _b : getItemSize(id, i, data[i], useAverageSize);
1396
- const bottom = top + size;
1397
- if (bottom > scroll - scrollBuffer) {
1398
- loopStart = i;
1399
- } else {
1400
- break;
1401
- }
1402
- }
1403
- const loopStartMod = loopStart % numColumns;
1404
- if (loopStartMod > 0) {
1405
- loopStart -= loopStartMod;
1406
- }
1407
- let foundEnd = false;
1408
- let nextTop;
1409
- let nextBottom;
1410
- const prevNumContainers = ctx.values.get("numContainers");
1411
- let maxIndexRendered = 0;
1412
- for (let i = 0; i < prevNumContainers; i++) {
1413
- const key = peek$(ctx, `containerItemKey${i}`);
1414
- if (key !== void 0) {
1415
- const index = indexByKey.get(key);
1416
- maxIndexRendered = Math.max(maxIndexRendered, index);
1417
- }
1418
- }
1419
- let firstFullyOnScreenIndex;
1420
- const dataLength = data.length;
1421
- for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
1422
- const id = (_c = idCache.get(i)) != null ? _c : getId(i);
1423
- const size = (_d = sizes.get(id)) != null ? _d : getItemSize(id, i, data[i], useAverageSize);
1424
- const top = positions.get(id);
1425
- if (!foundEnd) {
1426
- if (startNoBuffer === null && top + size > scroll) {
1427
- startNoBuffer = i;
1428
- }
1429
- if (firstFullyOnScreenIndex === void 0 && top >= scroll - 10) {
1430
- firstFullyOnScreenIndex = i;
1431
- }
1432
- if (startBuffered === null && top + size > scrollTopBuffered) {
1433
- startBuffered = i;
1434
- startBufferedId = id;
1435
- nextTop = top;
1436
- }
1437
- if (startNoBuffer !== null) {
1438
- if (top <= scrollBottom) {
1439
- endNoBuffer = i;
1440
- }
1441
- if (top <= scrollBottomBuffered) {
1442
- endBuffered = i;
1443
- nextBottom = top + size;
1444
- } else {
1445
- foundEnd = true;
1446
- }
1447
- }
1448
- }
1449
- }
1450
- const idsInView = [];
1451
- for (let i = firstFullyOnScreenIndex; i <= endNoBuffer; i++) {
1452
- const id = (_e = idCache.get(i)) != null ? _e : getId(i);
1453
- idsInView.push(id);
1454
- }
1455
- Object.assign(state, {
1456
- startBuffered,
1457
- startBufferedId,
1458
- startNoBuffer,
1459
- endBuffered,
1460
- endNoBuffer,
1461
- idsInView,
1462
- firstFullyOnScreenIndex
1463
- });
1464
- if (enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0) {
1465
- state.scrollForNextCalculateItemsInView = nextTop !== void 0 && nextBottom !== void 0 ? {
1466
- top: nextTop,
1467
- bottom: nextBottom
1468
- } : void 0;
1469
- }
1470
- const numContainers = peek$(ctx, "numContainers");
1471
- const pendingRemoval = [];
1472
- if (dataChanged) {
1473
- for (let i = 0; i < numContainers; i++) {
1474
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1475
- if (!keyExtractorProp || itemKey && indexByKey.get(itemKey) === void 0) {
1476
- pendingRemoval.push(i);
1477
- }
1478
- }
1479
- }
1480
- if (startBuffered !== null && endBuffered !== null) {
1481
- let numContainers2 = prevNumContainers;
1482
- const needNewContainers = [];
1483
- for (let i = startBuffered; i <= endBuffered; i++) {
1484
- const id = (_f = idCache.get(i)) != null ? _f : getId(i);
1485
- if (!containerItemKeys.has(id)) {
1486
- needNewContainers.push(i);
1487
- }
1488
- }
1489
- if (needNewContainers.length > 0) {
1490
- const availableContainers = findAvailableContainers(
1491
- needNewContainers.length,
1492
- startBuffered,
1493
- endBuffered,
1494
- pendingRemoval
1495
- );
1496
- for (let idx = 0; idx < needNewContainers.length; idx++) {
1497
- const i = needNewContainers[idx];
1498
- const containerIndex = availableContainers[idx];
1499
- const id = (_g = idCache.get(i)) != null ? _g : getId(i);
1500
- const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
1501
- if (oldKey && oldKey !== id) {
1502
- containerItemKeys.delete(oldKey);
1503
- }
1504
- set$(ctx, `containerItemKey${containerIndex}`, id);
1505
- set$(ctx, `containerItemData${containerIndex}`, data[i]);
1506
- containerItemKeys.add(id);
1507
- if (containerIndex >= numContainers2) {
1508
- numContainers2 = containerIndex + 1;
1509
- }
1510
- }
1511
- if (numContainers2 !== prevNumContainers) {
1512
- set$(ctx, "numContainers", numContainers2);
1513
- if (numContainers2 > peek$(ctx, "numContainersPooled")) {
1514
- set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
1515
- }
1516
- }
1517
- }
1518
- for (let i = 0; i < numContainers2; i++) {
1519
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1520
- if (pendingRemoval.includes(i)) {
1521
- if (itemKey) {
1522
- containerItemKeys.delete(itemKey);
1523
- }
1524
- set$(ctx, `containerItemKey${i}`, void 0);
1525
- set$(ctx, `containerItemData${i}`, void 0);
1526
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1527
- set$(ctx, `containerColumn${i}`, -1);
1528
- } else {
1529
- const itemIndex = indexByKey.get(itemKey);
1530
- const item = data[itemIndex];
1531
- if (item !== void 0) {
1532
- const id = (_h = idCache.get(itemIndex)) != null ? _h : getId(itemIndex);
1533
- const position = positions.get(id);
1534
- if (position === void 0) {
1535
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1536
- } else {
1537
- const pos = positions.get(id);
1538
- const column = columns.get(id) || 1;
1539
- const prevPos = peek$(ctx, `containerPosition${i}`);
1540
- const prevColumn = peek$(ctx, `containerColumn${i}`);
1541
- const prevData = peek$(ctx, `containerItemData${i}`);
1542
- if (!prevPos || pos > POSITION_OUT_OF_VIEW && pos !== prevPos) {
1543
- set$(ctx, `containerPosition${i}`, pos);
1544
- }
1545
- if (column >= 0 && column !== prevColumn) {
1546
- set$(ctx, `containerColumn${i}`, column);
1547
- }
1548
- if (prevData !== item) {
1549
- set$(ctx, `containerItemData${i}`, data[itemIndex]);
1550
- }
1551
- }
1552
- }
1553
- }
1554
- }
1555
- }
1556
- if (!queuedInitialLayout && endBuffered !== null) {
1557
- if (checkAllSizesKnown()) {
1558
- setDidLayout();
1559
- }
1560
- }
1561
- if (viewabilityConfigCallbackPairs) {
1562
- updateViewableItems(
1563
- state,
1564
- ctx,
1565
- viewabilityConfigCallbackPairs,
1566
- getId,
1567
- scrollLength,
1568
- startNoBuffer,
1569
- endNoBuffer
1570
- );
1571
- }
1572
- }, []);
1573
- const setPaddingTop = ({
1574
- stylePaddingTop,
1575
- alignItemsPaddingTop
1576
- }) => {
1577
- if (stylePaddingTop !== void 0) {
1578
- const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1579
- if (stylePaddingTop < prevStylePaddingTop) {
1580
- const prevTotalSize = peek$(ctx, "totalSize") || 0;
1581
- set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1582
- setTimeout(() => {
1583
- set$(ctx, "totalSize", prevTotalSize);
1584
- }, 16);
1585
- }
1586
- set$(ctx, "stylePaddingTop", stylePaddingTop);
1587
- }
1588
- if (alignItemsPaddingTop !== void 0) {
1589
- set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1590
- }
1591
- };
1592
- const updateAlignItemsPaddingTop = () => {
1593
- if (alignItemsAtEnd) {
1594
- const { data, scrollLength } = refState.current;
1595
- let alignItemsPaddingTop = 0;
1596
- if ((data == null ? void 0 : data.length) > 0) {
1597
- const contentSize = getContentSize(ctx);
1598
- alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1599
- }
1600
- setPaddingTop({ alignItemsPaddingTop });
1601
- }
1602
- };
1603
- const finishScrollTo = () => {
1604
- const state = refState.current;
1605
- if (state) {
1606
- state.scrollingTo = void 0;
1607
- state.scrollHistory.length = 0;
1608
- }
1609
- };
1610
- const scrollTo = (params = {}) => {
1611
- var _a2;
1612
- const state = refState.current;
1613
- const { animated } = params;
1614
- const offset = calculateOffsetWithOffsetPosition(params.offset, params);
1615
- state.scrollHistory.length = 0;
1616
- state.scrollingTo = params;
1617
- state.scrollPending = offset;
1618
- (_a2 = refScroller.current) == null ? void 0 : _a2.scrollTo({
1619
- x: horizontal ? offset : 0,
1620
- y: horizontal ? 0 : offset,
1621
- animated: !!animated
1622
- });
1623
- if (!animated) {
1624
- refState.current.scroll = offset;
1625
- setTimeout(finishScrollTo, 100);
1626
- }
1627
- };
1628
- const doMaintainScrollAtEnd = (animated) => {
1629
- const state = refState.current;
1630
- if ((state == null ? void 0 : state.isAtEnd) && maintainScrollAtEnd && peek$(ctx, "containersDidLayout")) {
1631
- const paddingTop = peek$(ctx, "alignItemsPaddingTop");
1632
- if (paddingTop > 0) {
1633
- state.scroll = 0;
1634
- }
1635
- requestAnimationFrame(() => {
1636
- var _a2;
1637
- state.maintainingScrollAtEnd = true;
1638
- (_a2 = refScroller.current) == null ? void 0 : _a2.scrollToEnd({
1639
- animated
1640
- });
1641
- setTimeout(
1642
- () => {
1643
- state.maintainingScrollAtEnd = false;
1644
- },
1645
- 0
1646
- );
1647
- });
1648
- return true;
1649
- }
1650
- };
1651
- const checkThreshold = (distance, atThreshold, threshold, isReached, isBlockedByTimer, onReached, blockTimer) => {
1652
- const distanceAbs = Math.abs(distance);
1653
- const isAtThreshold = atThreshold || distanceAbs < threshold;
1654
- if (!isReached && !isBlockedByTimer) {
1655
- if (isAtThreshold) {
1656
- onReached == null ? void 0 : onReached(distance);
1657
- blockTimer == null ? void 0 : blockTimer(true);
1658
- setTimeout(() => {
1659
- blockTimer == null ? void 0 : blockTimer(false);
1660
- }, 700);
1661
- return true;
1662
- }
1663
- } else {
1664
- if (distance >= 1.3 * threshold) {
1665
- return false;
1666
- }
1667
- }
1668
- return isReached;
1669
- };
1670
- const checkAtBottom = () => {
1671
- if (!refState.current) {
1672
- return;
1673
- }
1674
- const { queuedInitialLayout, scrollLength, scroll, maintainingScrollAtEnd } = refState.current;
1675
- const contentSize = getContentSize(ctx);
1676
- if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
1677
- const distanceFromEnd = contentSize - scroll - scrollLength;
1678
- const isContentLess = contentSize < scrollLength;
1679
- refState.current.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
1680
- refState.current.isEndReached = checkThreshold(
1681
- distanceFromEnd,
1682
- isContentLess,
1683
- onEndReachedThreshold * scrollLength,
1684
- refState.current.isEndReached,
1685
- refState.current.endReachedBlockedByTimer,
1686
- (distance) => {
1687
- var _a2, _b;
1688
- return (_b = (_a2 = callbacks.current).onEndReached) == null ? void 0 : _b.call(_a2, { distanceFromEnd: distance });
1689
- },
1690
- (block) => {
1691
- refState.current.endReachedBlockedByTimer = block;
1692
- }
1693
- );
1694
- }
1695
- };
1696
- const checkAtTop = () => {
1697
- if (!refState.current) {
1698
- return;
1699
- }
1700
- const { scrollLength, scroll } = refState.current;
1701
- const distanceFromTop = scroll;
1702
- refState.current.isAtStart = distanceFromTop <= 0;
1703
- refState.current.isStartReached = checkThreshold(
1704
- distanceFromTop,
1705
- false,
1706
- onStartReachedThreshold * scrollLength,
1707
- refState.current.isStartReached,
1708
- refState.current.startReachedBlockedByTimer,
1709
- (distance) => {
1710
- var _a2, _b;
1711
- return (_b = (_a2 = callbacks.current).onStartReached) == null ? void 0 : _b.call(_a2, { distanceFromStart: distance });
1712
- },
1713
- (block) => {
1714
- refState.current.startReachedBlockedByTimer = block;
1715
- }
1716
- );
2164
+ const state = refState.current;
2165
+ const isFirst = !state.props.renderItem;
2166
+ const didDataChange = state.props.data !== dataProp;
2167
+ state.props = {
2168
+ alignItemsAtEnd,
2169
+ data: dataProp,
2170
+ estimatedItemSize,
2171
+ maintainScrollAtEnd,
2172
+ maintainScrollAtEndThreshold,
2173
+ onEndReachedThreshold,
2174
+ onStartReachedThreshold,
2175
+ stylePaddingBottom: stylePaddingBottomState,
2176
+ horizontal: !!horizontal,
2177
+ maintainVisibleContentPosition,
2178
+ onItemSizeChanged,
2179
+ suggestEstimatedItemSize: !!suggestEstimatedItemSize,
2180
+ keyExtractor,
2181
+ onScroll: onScrollProp,
2182
+ getEstimatedItemSize,
2183
+ onStartReached,
2184
+ onEndReached,
2185
+ onLoad,
2186
+ renderItem: renderItem2,
2187
+ initialScroll,
2188
+ scrollBuffer,
2189
+ viewabilityConfigCallbackPairs: void 0,
2190
+ numColumns: numColumnsProp,
2191
+ initialContainerPoolRatio,
2192
+ stylePaddingTop: stylePaddingTopState
1717
2193
  };
2194
+ state.refScroller = refScroller;
1718
2195
  const checkResetContainers = (isFirst2) => {
1719
- const state = refState.current;
1720
- if (state) {
1721
- state.data = dataProp;
2196
+ const state2 = refState.current;
2197
+ if (state2) {
2198
+ state2.props.data = dataProp;
1722
2199
  if (!isFirst2) {
1723
- calculateItemsInView({ dataChanged: true, doMVCP: true });
1724
- const didMaintainScrollAtEnd = doMaintainScrollAtEnd(false);
1725
- if (!didMaintainScrollAtEnd && dataProp.length > state.data.length) {
1726
- state.isEndReached = false;
2200
+ calculateItemsInView(ctx, state2, { dataChanged: true, doMVCP: true });
2201
+ const didMaintainScrollAtEnd = doMaintainScrollAtEnd(ctx, state2, false);
2202
+ if (!didMaintainScrollAtEnd && dataProp.length > state2.props.data.length) {
2203
+ state2.isEndReached = false;
1727
2204
  }
1728
2205
  if (!didMaintainScrollAtEnd) {
1729
- checkAtTop();
1730
- checkAtBottom();
1731
- }
1732
- }
1733
- }
1734
- };
1735
- const updateTotalSize = () => {
1736
- const { data, positions } = refState.current;
1737
- if (data.length === 0) {
1738
- addTotalSize(null, 0);
1739
- } else {
1740
- const lastId = getId(data.length - 1);
1741
- if (lastId !== void 0) {
1742
- const lastPosition = positions.get(lastId);
1743
- if (lastPosition !== void 0) {
1744
- const lastSize = getItemSize(lastId, data.length - 1, data[dataProp.length - 1]);
1745
- if (lastSize !== void 0) {
1746
- const totalSize = lastPosition + lastSize;
1747
- addTotalSize(null, totalSize);
1748
- }
2206
+ checkAtTop(state2);
2207
+ checkAtBottom(ctx, state2);
1749
2208
  }
1750
2209
  }
1751
2210
  }
1752
2211
  };
1753
- const findAvailableContainers = (numNeeded, startBuffered, endBuffered, pendingRemoval) => {
1754
- const state = refState.current;
1755
- const numContainers = peek$(ctx, "numContainers");
1756
- const result = [];
1757
- const availableContainers = [];
1758
- for (let u = 0; u < numContainers; u++) {
1759
- const key = peek$(ctx, `containerItemKey${u}`);
1760
- let isOk = key === void 0;
1761
- if (!isOk) {
1762
- const index = pendingRemoval.indexOf(u);
1763
- if (index !== -1) {
1764
- pendingRemoval.splice(index, 1);
1765
- isOk = true;
1766
- }
1767
- }
1768
- if (isOk) {
1769
- result.push(u);
1770
- if (result.length >= numNeeded) {
1771
- return result;
1772
- }
1773
- }
1774
- }
1775
- for (let u = 0; u < numContainers; u++) {
1776
- const key = peek$(ctx, `containerItemKey${u}`);
1777
- if (key === void 0) continue;
1778
- const index = state.indexByKey.get(key);
1779
- if (index < startBuffered) {
1780
- availableContainers.push({ index: u, distance: startBuffered - index });
1781
- } else if (index > endBuffered) {
1782
- availableContainers.push({ index: u, distance: index - endBuffered });
1783
- }
1784
- }
1785
- const remaining = numNeeded - result.length;
1786
- if (remaining > 0) {
1787
- if (availableContainers.length > 0) {
1788
- if (availableContainers.length > remaining) {
1789
- availableContainers.sort(comparatorByDistance);
1790
- availableContainers.length = remaining;
1791
- }
1792
- for (const container of availableContainers) {
1793
- result.push(container.index);
1794
- }
1795
- }
1796
- const stillNeeded = numNeeded - result.length;
1797
- if (stillNeeded > 0) {
1798
- for (let i = 0; i < stillNeeded; i++) {
1799
- result.push(numContainers + i);
1800
- }
1801
- if (__DEV__ && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
1802
- console.warn(
1803
- "[legend-list] No unused container available, so creating one on demand. This can be a minor performance issue and is likely caused by the estimatedItemSize being too large. Consider decreasing estimatedItemSize or increasing initialContainerPoolRatio.",
1804
- {
1805
- debugInfo: {
1806
- numContainers,
1807
- numNeeded,
1808
- stillNeeded,
1809
- numContainersPooled: peek$(ctx, "numContainersPooled")
1810
- }
1811
- }
1812
- );
1813
- }
1814
- }
1815
- }
1816
- return result.sort(comparatorDefault);
1817
- };
1818
- const isFirst = !refState.current.renderItem;
1819
2212
  const memoizedLastItemKeys = useMemo(() => {
1820
2213
  if (!dataProp.length) return [];
1821
2214
  return Array.from(
1822
2215
  { length: Math.min(numColumnsProp, dataProp.length) },
1823
- (_, i) => getId(dataProp.length - 1 - i)
2216
+ (_, i) => getId(state, dataProp.length - 1 - i)
1824
2217
  );
1825
2218
  }, [dataProp, numColumnsProp]);
1826
2219
  const initalizeStateVars = () => {
1827
2220
  set$(ctx, "lastItemKeys", memoizedLastItemKeys);
1828
2221
  set$(ctx, "numColumns", numColumnsProp);
1829
2222
  const prevPaddingTop = peek$(ctx, "stylePaddingTop");
1830
- setPaddingTop({ stylePaddingTop: stylePaddingTopState });
1831
- refState.current.stylePaddingBottom = stylePaddingBottomState;
2223
+ setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
2224
+ refState.current.props.stylePaddingBottom = stylePaddingBottomState;
1832
2225
  const paddingDiff = stylePaddingTopState - prevPaddingTop;
1833
2226
  if (paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
1834
- requestAdjust(paddingDiff);
2227
+ calculateItemsInView(ctx, state, { doMVCP: true });
2228
+ requestAdjust(ctx, state, paddingDiff);
1835
2229
  }
1836
2230
  };
1837
2231
  if (isFirst) {
1838
2232
  initalizeStateVars();
1839
- updateAllPositions();
2233
+ updateAllPositions(ctx, state);
1840
2234
  }
1841
2235
  const initialContentOffset = useMemo(() => {
1842
- const initialContentOffset2 = initialScrollOffset || calculateOffsetForIndex(initialScrollIndex);
2236
+ const initialContentOffset2 = initialScrollOffset || calculateOffsetForIndex(ctx, state, initialScrollIndex);
1843
2237
  refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
1844
2238
  if (initialContentOffset2 > 0) {
1845
- scrollTo({ offset: initialContentOffset2, animated: false, index: initialScrollIndex });
2239
+ scrollTo(state, { offset: initialContentOffset2, animated: false, index: initialScrollIndex });
1846
2240
  }
1847
2241
  return initialContentOffset2;
1848
2242
  }, [renderNum]);
@@ -1864,12 +2258,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1864
2258
  if (measured) {
1865
2259
  const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
1866
2260
  if (size) {
1867
- handleLayout(measured);
2261
+ handleLayout(ctx, state, measured, setCanRender);
1868
2262
  }
1869
2263
  }
1870
2264
  }
1871
2265
  if (!isFirst) {
1872
- calculateItemsInView({ doMVCP: true });
2266
+ calculateItemsInView(ctx, state, { doMVCP: true });
1873
2267
  }
1874
2268
  }, [dataProp]);
1875
2269
  const onLayoutHeader = useCallback((rect, fromLayoutEffect) => {
@@ -1882,13 +2276,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1882
2276
  }
1883
2277
  } else {
1884
2278
  setTimeout(() => {
1885
- scrollToIndex({ ...initialScroll, animated: false });
2279
+ scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1886
2280
  }, 17);
1887
2281
  }
1888
2282
  }
1889
2283
  }, []);
1890
2284
  useLayoutEffect(() => {
1891
- const didAllocateContainers = doInitialAllocateContainers();
2285
+ const didAllocateContainers = doInitialAllocateContainersCallback();
1892
2286
  if (!didAllocateContainers) {
1893
2287
  checkResetContainers(
1894
2288
  /*isFirst*/
@@ -1899,294 +2293,48 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1899
2293
  useLayoutEffect(() => {
1900
2294
  set$(ctx, "extraData", extraData);
1901
2295
  }, [extraData]);
1902
- refState.current.renderItem = renderItem2;
1903
2296
  useLayoutEffect(initalizeStateVars, [
1904
2297
  memoizedLastItemKeys.join(","),
1905
2298
  numColumnsProp,
1906
2299
  stylePaddingTopState,
1907
2300
  stylePaddingBottomState
1908
2301
  ]);
1909
- const getRenderedItem = useCallback((key) => {
1910
- const state = refState.current;
1911
- if (!state) {
1912
- return null;
1913
- }
1914
- const { data, indexByKey } = state;
1915
- const index = indexByKey.get(key);
1916
- if (index === void 0) {
1917
- return null;
1918
- }
1919
- const renderItemProp = refState.current.renderItem;
1920
- let renderedItem = null;
1921
- if (renderItemProp) {
1922
- const itemProps = {
1923
- item: data[index],
1924
- index,
1925
- extraData: peek$(ctx, "extraData")
1926
- };
1927
- renderedItem = React2.createElement(renderItemProp, itemProps);
1928
- }
1929
- return { index, item: data[index], renderedItem };
1930
- }, []);
1931
- const doInitialAllocateContainers = () => {
1932
- const state = refState.current;
1933
- const { scrollLength, data } = state;
1934
- if (scrollLength > 0 && data.length > 0 && !peek$(ctx, "numContainers")) {
1935
- const averageItemSize = getEstimatedItemSize ? getEstimatedItemSize(0, data[0]) : estimatedItemSize;
1936
- const Extra = 1.5;
1937
- const numContainers = Math.ceil(
1938
- (scrollLength + scrollBuffer * 2) / averageItemSize * numColumnsProp * Extra
1939
- );
1940
- for (let i = 0; i < numContainers; i++) {
1941
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1942
- set$(ctx, `containerColumn${i}`, -1);
1943
- }
1944
- set$(ctx, "numContainers", numContainers);
1945
- set$(ctx, "numContainersPooled", numContainers * initialContainerPoolRatio);
1946
- if (!IsNewArchitecture) {
1947
- if (initialScroll) {
1948
- requestAnimationFrame(() => {
1949
- calculateItemsInView();
1950
- });
1951
- } else {
1952
- calculateItemsInView();
1953
- }
1954
- }
1955
- return true;
1956
- }
2302
+ const doInitialAllocateContainersCallback = () => {
2303
+ return doInitialAllocateContainers(ctx, state);
1957
2304
  };
1958
2305
  useEffect(() => {
1959
- const state = refState.current;
1960
2306
  const viewability = setupViewability({
1961
2307
  viewabilityConfig,
1962
2308
  viewabilityConfigCallbackPairs,
1963
2309
  onViewableItemsChanged
1964
2310
  });
1965
2311
  state.viewabilityConfigCallbackPairs = viewability;
2312
+ state.props.viewabilityConfigCallbackPairs = viewability;
1966
2313
  state.enableScrollForNextCalculateItemsInView = !viewability;
1967
2314
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
1968
2315
  if (!IsNewArchitecture) {
1969
2316
  useInit(() => {
1970
- doInitialAllocateContainers();
2317
+ doInitialAllocateContainersCallback();
1971
2318
  });
1972
2319
  }
1973
- const updateOneItemSize = useCallback((itemKey, sizeObj) => {
1974
- const state = refState.current;
1975
- const { sizes, indexByKey, sizesKnown, data, averageSizes } = state;
1976
- if (!data) return 0;
1977
- const index = indexByKey.get(itemKey);
1978
- const prevSize = getItemSize(itemKey, index, data);
1979
- const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
1980
- sizesKnown.set(itemKey, size);
1981
- const itemType = "";
1982
- let averages = averageSizes[itemType];
1983
- if (!averages) {
1984
- averages = averageSizes[itemType] = { num: 0, avg: 0 };
1985
- }
1986
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
1987
- averages.num++;
1988
- if (!prevSize || Math.abs(prevSize - size) > 0.1) {
1989
- sizes.set(itemKey, size);
1990
- return size - prevSize;
1991
- }
1992
- return 0;
1993
- }, []);
1994
- const updateItemSizes = useCallback(
1995
- (itemUpdates) => {
1996
- var _a2;
1997
- const state = refState.current;
1998
- if (!state.data) return;
1999
- let needsRecalculate = false;
2000
- let shouldMaintainScrollAtEnd = false;
2001
- let minIndexSizeChanged;
2002
- let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
2003
- for (const { itemKey, sizeObj } of itemUpdates) {
2004
- const index = state.indexByKey.get(itemKey);
2005
- const prevSizeKnown = state.sizesKnown.get(itemKey);
2006
- const diff = updateOneItemSize(itemKey, sizeObj);
2007
- const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2008
- if (diff !== 0) {
2009
- minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
2010
- if (((_a2 = state.scrollingTo) == null ? void 0 : _a2.viewPosition) && maintainVisibleContentPosition && index === state.scrollingTo.index) {
2011
- requestAdjust(diff * state.scrollingTo.viewPosition);
2012
- }
2013
- const { startBuffered, endBuffered } = state;
2014
- needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
2015
- if (!needsRecalculate) {
2016
- const numContainers = ctx.values.get("numContainers");
2017
- for (let i = 0; i < numContainers; i++) {
2018
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
2019
- needsRecalculate = true;
2020
- break;
2021
- }
2022
- }
2023
- }
2024
- if (state.needsOtherAxisSize) {
2025
- const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
2026
- maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
2027
- }
2028
- if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2029
- shouldMaintainScrollAtEnd = true;
2030
- }
2031
- onItemSizeChanged == null ? void 0 : onItemSizeChanged({
2032
- size,
2033
- previous: size - diff,
2034
- index,
2035
- itemKey,
2036
- itemData: state.data[index]
2037
- });
2038
- }
2039
- }
2040
- if (minIndexSizeChanged !== void 0) {
2041
- state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
2042
- }
2043
- if (__DEV__ && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
2044
- if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
2045
- state.timeoutSizeMessage = setTimeout(() => {
2046
- var _a3;
2047
- state.timeoutSizeMessage = void 0;
2048
- const num = state.sizesKnown.size;
2049
- const avg = (_a3 = state.averageSizes[""]) == null ? void 0 : _a3.avg;
2050
- console.warn(
2051
- `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
2052
- );
2053
- }, 1e3);
2054
- }
2055
- const cur = peek$(ctx, "otherAxisSize");
2056
- if (!cur || maxOtherAxisSize > cur) {
2057
- set$(ctx, "otherAxisSize", maxOtherAxisSize);
2058
- }
2059
- const containersDidLayout = peek$(ctx, "containersDidLayout");
2060
- if (containersDidLayout || checkAllSizesKnown()) {
2061
- if (needsRecalculate) {
2062
- state.scrollForNextCalculateItemsInView = void 0;
2063
- calculateItemsInView({ doMVCP: true });
2064
- }
2065
- if (shouldMaintainScrollAtEnd) {
2066
- doMaintainScrollAtEnd(false);
2067
- }
2068
- }
2069
- },
2070
- []
2071
- );
2072
- const updateItemSize = useCallback((itemKey, sizeObj) => {
2073
- var _a2, _b;
2074
- if (IsNewArchitecture) {
2075
- const { sizesKnown } = refState.current;
2076
- const numContainers = ctx.values.get("numContainers");
2077
- const changes = [];
2078
- for (let i = 0; i < numContainers; i++) {
2079
- const containerItemKey = peek$(ctx, `containerItemKey${i}`);
2080
- if (itemKey === containerItemKey) {
2081
- changes.push({ itemKey, sizeObj });
2082
- } else if (!sizesKnown.has(containerItemKey) && containerItemKey !== void 0) {
2083
- const containerRef = ctx.viewRefs.get(i);
2084
- if (containerRef) {
2085
- const measured = (_b = (_a2 = containerRef.current) == null ? void 0 : _a2.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a2);
2086
- if (measured) {
2087
- changes.push({ itemKey: containerItemKey, sizeObj: measured });
2088
- }
2089
- }
2090
- }
2091
- }
2092
- if (changes.length > 0) {
2093
- updateItemSizes(changes);
2094
- }
2095
- } else {
2096
- updateItemSizes([{ itemKey, sizeObj }]);
2097
- }
2098
- }, []);
2099
- const handleLayout = useCallback((size) => {
2100
- const scrollLength = size[horizontal ? "width" : "height"];
2101
- const otherAxisSize = size[horizontal ? "height" : "width"];
2102
- const state = refState.current;
2103
- const didChange = scrollLength !== state.scrollLength;
2104
- const prevOtherAxisSize = state.otherAxisSize;
2105
- state.scrollLength = scrollLength;
2106
- state.otherAxisSize = otherAxisSize;
2107
- state.lastBatchingAction = Date.now();
2108
- state.scrollForNextCalculateItemsInView = void 0;
2109
- doInitialAllocateContainers();
2110
- if (didChange) {
2111
- calculateItemsInView({ doMVCP: true });
2112
- }
2113
- if (didChange || otherAxisSize !== prevOtherAxisSize) {
2114
- set$(ctx, "scrollSize", { width: size.width, height: size.height });
2115
- }
2116
- doMaintainScrollAtEnd(false);
2117
- updateAlignItemsPaddingTop();
2118
- checkAtBottom();
2119
- checkAtTop();
2120
- if (refState.current) {
2121
- refState.current.needsOtherAxisSize = otherAxisSize - (stylePaddingTopState || 0) < 10;
2122
- }
2123
- if (__DEV__ && scrollLength === 0) {
2124
- warnDevOnce(
2125
- "height0",
2126
- `List ${horizontal ? "width" : "height"} is 0. You may need to set a style or \`flex: \` for the list, because children are absolutely positioned.`
2127
- );
2128
- }
2129
- calculateItemsInView({ doMVCP: true });
2130
- setCanRender(true);
2131
- }, []);
2132
2320
  const onLayout = useCallback((event) => {
2133
2321
  const layout = event.nativeEvent.layout;
2134
- handleLayout(layout);
2322
+ handleLayout(ctx, state, layout, setCanRender);
2135
2323
  if (onLayoutProp) {
2136
2324
  onLayoutProp(event);
2137
2325
  }
2138
2326
  }, []);
2139
- const handleScroll = useCallback(
2140
- (event) => {
2141
- var _a2, _b, _c, _d;
2142
- if (((_b = (_a2 = event.nativeEvent) == null ? void 0 : _a2.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
2143
- return;
2144
- }
2145
- const state = refState.current;
2146
- const newScroll = event.nativeEvent.contentOffset[horizontal ? "x" : "y"];
2147
- const ignoreScrollFromMVCP = state.ignoreScrollFromMVCP;
2148
- if (ignoreScrollFromMVCP && !state.scrollingTo) {
2149
- const { lt, gt } = ignoreScrollFromMVCP;
2150
- if (lt && newScroll < lt || gt && newScroll > gt) {
2151
- return;
2152
- }
2153
- }
2154
- state.scrollPending = newScroll;
2155
- updateScroll(newScroll);
2156
- (_d = state.onScroll) == null ? void 0 : _d.call(state, event);
2157
- },
2158
- []
2159
- );
2160
- const updateScroll = useCallback((newScroll) => {
2161
- const state = refState.current;
2162
- const scrollingTo = state.scrollingTo;
2163
- state.hasScrolled = true;
2164
- state.lastBatchingAction = Date.now();
2165
- const currentTime = performance.now();
2166
- if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
2167
- state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2168
- }
2169
- if (state.scrollHistory.length > 5) {
2170
- state.scrollHistory.shift();
2171
- }
2172
- state.scrollPrev = state.scroll;
2173
- state.scrollPrevTime = state.scrollTime;
2174
- state.scroll = newScroll;
2175
- state.scrollTime = currentTime;
2176
- calculateItemsInView();
2177
- checkAtBottom();
2178
- checkAtTop();
2179
- }, []);
2180
2327
  useImperativeHandle(
2181
2328
  forwardedRef,
2182
2329
  () => {
2183
2330
  const scrollIndexIntoView = (options) => {
2184
- if (refState.current) {
2331
+ const state2 = refState.current;
2332
+ if (state2) {
2185
2333
  const { index, ...rest2 } = options;
2186
- const { startNoBuffer, endNoBuffer } = refState.current;
2334
+ const { startNoBuffer, endNoBuffer } = state2;
2187
2335
  if (index < startNoBuffer || index > endNoBuffer) {
2188
2336
  const viewPosition = index < startNoBuffer ? 0 : 1;
2189
- scrollToIndex({
2337
+ scrollToIndex(ctx, state2, {
2190
2338
  ...rest2,
2191
2339
  viewPosition,
2192
2340
  index
@@ -2200,45 +2348,46 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2200
2348
  getScrollableNode: () => refScroller.current.getScrollableNode(),
2201
2349
  getScrollResponder: () => refScroller.current.getScrollResponder(),
2202
2350
  getState: () => {
2203
- const state = refState.current;
2204
- return state ? {
2205
- contentLength: state.totalSize,
2206
- end: state.endNoBuffer,
2207
- endBuffered: state.endBuffered,
2208
- isAtEnd: state.isAtEnd,
2209
- isAtStart: state.isAtStart,
2210
- scroll: state.scroll,
2211
- scrollLength: state.scrollLength,
2212
- start: state.startNoBuffer,
2213
- startBuffered: state.startBuffered,
2214
- sizes: state.sizesKnown,
2215
- sizeAtIndex: (index) => state.sizesKnown.get(getId(index))
2351
+ const state2 = refState.current;
2352
+ return state2 ? {
2353
+ contentLength: state2.totalSize,
2354
+ end: state2.endNoBuffer,
2355
+ endBuffered: state2.endBuffered,
2356
+ isAtEnd: state2.isAtEnd,
2357
+ isAtStart: state2.isAtStart,
2358
+ scroll: state2.scroll,
2359
+ scrollLength: state2.scrollLength,
2360
+ start: state2.startNoBuffer,
2361
+ startBuffered: state2.startBuffered,
2362
+ sizes: state2.sizesKnown,
2363
+ sizeAtIndex: (index) => state2.sizesKnown.get(getId(state2, index))
2216
2364
  } : {};
2217
2365
  },
2218
2366
  scrollIndexIntoView,
2219
2367
  scrollItemIntoView: ({ item, ...props2 }) => {
2220
- const { data } = refState.current;
2368
+ const data = refState.current.props.data;
2221
2369
  const index = data.indexOf(item);
2222
2370
  if (index !== -1) {
2223
2371
  scrollIndexIntoView({ index, ...props2 });
2224
2372
  }
2225
2373
  },
2226
- scrollToIndex,
2374
+ scrollToIndex: (params) => scrollToIndex(ctx, state, params),
2227
2375
  scrollToItem: ({ item, ...props2 }) => {
2228
- const { data } = refState.current;
2376
+ const data = refState.current.props.data;
2229
2377
  const index = data.indexOf(item);
2230
2378
  if (index !== -1) {
2231
- scrollToIndex({ index, ...props2 });
2379
+ scrollToIndex(ctx, state, { index, ...props2 });
2232
2380
  }
2233
2381
  },
2234
- scrollToOffset: (params) => scrollTo(params),
2382
+ scrollToOffset: (params) => scrollTo(state, params),
2235
2383
  scrollToEnd: (options) => {
2236
- const { data, stylePaddingBottom } = refState.current;
2384
+ const data = refState.current.props.data;
2385
+ const stylePaddingBottom = refState.current.props.stylePaddingBottom;
2237
2386
  const index = data.length - 1;
2238
2387
  if (index !== -1) {
2239
2388
  const paddingBottom = stylePaddingBottom || 0;
2240
2389
  const footerSize = peek$(ctx, "footerSize") || 0;
2241
- scrollToIndex({
2390
+ scrollToIndex(ctx, state, {
2242
2391
  index,
2243
2392
  viewPosition: 1,
2244
2393
  viewOffset: -paddingBottom - footerSize,
@@ -2257,11 +2406,19 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2257
2406
  if (Platform.OS === "web") {
2258
2407
  useEffect(() => {
2259
2408
  if (initialContentOffset) {
2260
- scrollTo({ offset: initialContentOffset, animated: false });
2409
+ scrollTo(state, { offset: initialContentOffset, animated: false });
2261
2410
  }
2262
2411
  }, []);
2263
2412
  }
2264
- return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(
2413
+ const fns = useMemo(
2414
+ () => ({
2415
+ updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, state, itemKey, sizeObj),
2416
+ getRenderedItem: (key) => getRenderedItem(ctx, state, key),
2417
+ onScroll: (event) => onScroll(ctx, state, event)
2418
+ }),
2419
+ []
2420
+ );
2421
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(
2265
2422
  ListComponent,
2266
2423
  {
2267
2424
  ...rest,
@@ -2269,12 +2426,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2269
2426
  horizontal,
2270
2427
  refScrollView: combinedRef,
2271
2428
  initialContentOffset,
2272
- getRenderedItem,
2273
- updateItemSize,
2274
- handleScroll,
2429
+ getRenderedItem: fns.getRenderedItem,
2430
+ updateItemSize: fns.updateItemSize,
2431
+ onScroll: fns.onScroll,
2275
2432
  onMomentumScrollEnd: (event) => {
2276
2433
  requestAnimationFrame(() => {
2277
- finishScrollTo();
2434
+ finishScrollTo(refState.current);
2278
2435
  });
2279
2436
  if (onMomentumScrollEnd) {
2280
2437
  onMomentumScrollEnd(event);
@@ -2288,9 +2445,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2288
2445
  maintainVisibleContentPosition,
2289
2446
  scrollEventThrottle: Platform.OS === "web" ? 16 : void 0,
2290
2447
  waitForInitialLayout,
2291
- refreshControl: refreshControl ? stylePaddingTopState > 0 ? React2.cloneElement(refreshControl, {
2448
+ refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3.cloneElement(refreshControl, {
2292
2449
  progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
2293
- }) : refreshControl : onRefresh && /* @__PURE__ */ React2.createElement(
2450
+ }) : refreshControl : onRefresh && /* @__PURE__ */ React3.createElement(
2294
2451
  RefreshControl,
2295
2452
  {
2296
2453
  refreshing: !!refreshing,
@@ -2303,17 +2460,17 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2303
2460
  scrollAdjustHandler: (_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler,
2304
2461
  onLayoutHeader
2305
2462
  }
2306
- ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React2.createElement(DebugView, { state: refState.current }));
2463
+ ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React3.createElement(DebugView, { state: refState.current }));
2307
2464
  });
2308
2465
  var typedForwardRef2 = forwardRef;
2309
2466
  var renderItem = ({ item }) => item;
2310
2467
  var LazyLegendList = typedForwardRef2(function LazyLegendList2(props, forwardedRef) {
2311
2468
  const { LegendList: LegendListProp, children, ...rest } = props;
2312
2469
  const LegendListComponent = LegendListProp != null ? LegendListProp : LegendList;
2313
- const data = (isArray(children) ? children : React2.Children.toArray(children)).flat(1);
2470
+ const data = (isArray(children) ? children : React3.Children.toArray(children)).flat(1);
2314
2471
  return (
2315
2472
  // @ts-expect-error TODO: Fix this type
2316
- /* @__PURE__ */ React2.createElement(LegendListComponent, { ...rest, data, renderItem, ref: forwardedRef })
2473
+ /* @__PURE__ */ React3.createElement(LegendListComponent, { ...rest, data, renderItem, ref: forwardedRef })
2317
2474
  );
2318
2475
  });
2319
2476