@legendapp/list 1.1.4 → 2.0.0-next.0

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 +59 -52
  2. package/index.d.ts +59 -52
  3. package/index.js +686 -949
  4. package/index.mjs +687 -950
  5. package/package.json +1 -1
package/index.mjs CHANGED
@@ -1,8 +1,7 @@
1
1
  import * as React2 from 'react';
2
- import React2__default, { useReducer, useEffect, createContext, useMemo, useRef, useCallback, useLayoutEffect, useImperativeHandle, useContext, useState, forwardRef, memo } from 'react';
2
+ import { useReducer, useEffect, createContext, useMemo, useState, useRef, useCallback, useLayoutEffect, 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
- import { LegendList as LegendList$1 } from '@legendapp/list';
6
5
 
7
6
  // src/LegendList.tsx
8
7
  var ContextState = React2.createContext(null);
@@ -10,7 +9,6 @@ function StateProvider({ children }) {
10
9
  const [value] = React2.useState(() => ({
11
10
  listeners: /* @__PURE__ */ new Map(),
12
11
  values: /* @__PURE__ */ new Map([
13
- ["paddingTop", 0],
14
12
  ["alignItemsPaddingTop", 0],
15
13
  ["stylePaddingTop", 0],
16
14
  ["headerSize", 0]
@@ -113,17 +111,8 @@ var DebugRow = ({ children }) => {
113
111
  };
114
112
  var DebugView = React2.memo(function DebugView2({ state }) {
115
113
  const ctx = useStateContext();
116
- const [
117
- totalSize = 0,
118
- totalSizeWithScrollAdjust = 0,
119
- scrollAdjust = 0,
120
- rawScroll = 0,
121
- scroll = 0,
122
- numContainers = 0,
123
- numContainersPooled = 0
124
- ] = useArr$([
114
+ const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, numContainers = 0, numContainersPooled = 0] = useArr$([
125
115
  "totalSize",
126
- "totalSizeWithScrollAdjust",
127
116
  "scrollAdjust",
128
117
  "debugRawScroll",
129
118
  "debugComputedScroll",
@@ -156,7 +145,6 @@ var DebugView = React2.memo(function DebugView2({ state }) {
156
145
  /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "At end:"), /* @__PURE__ */ React2.createElement(Text, null, String(state.isAtEnd))),
157
146
  /* @__PURE__ */ React2.createElement(Text, null),
158
147
  /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React2.createElement(Text, null, scrollAdjust.toFixed(2))),
159
- /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "TotalSizeReal: "), /* @__PURE__ */ React2.createElement(Text, null, totalSizeWithScrollAdjust.toFixed(2))),
160
148
  /* @__PURE__ */ React2.createElement(Text, null),
161
149
  /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "RawScroll: "), /* @__PURE__ */ React2.createElement(Text, null, rawScroll.toFixed(2))),
162
150
  /* @__PURE__ */ React2.createElement(DebugRow, null, /* @__PURE__ */ React2.createElement(Text, null, "ComputedScroll: "), /* @__PURE__ */ React2.createElement(Text, null, scroll.toFixed(2)))
@@ -311,11 +299,6 @@ var LeanView = Platform.OS === "android" || Platform.OS === "ios" ? LeanViewComp
311
299
 
312
300
  // src/constants.ts
313
301
  var POSITION_OUT_OF_VIEW = -1e7;
314
- var ANCHORED_POSITION_OUT_OF_VIEW = {
315
- type: "top",
316
- relativeCoordinate: POSITION_OUT_OF_VIEW,
317
- top: POSITION_OUT_OF_VIEW
318
- };
319
302
  var ENABLE_DEVMODE = __DEV__ && false;
320
303
  var ENABLE_DEBUG_VIEW = __DEV__ && false;
321
304
  var IsNewArchitecture = global.nativeFabricUIManager != null;
@@ -331,23 +314,13 @@ var Container = ({
331
314
  }) => {
332
315
  const ctx = useStateContext();
333
316
  const columnWrapperStyle = ctx.columnWrapperStyle;
334
- const [
335
- maintainVisibleContentPosition,
336
- position = ANCHORED_POSITION_OUT_OF_VIEW,
337
- column = 0,
338
- numColumns,
339
- lastItemKeys,
340
- itemKey,
341
- data,
342
- extraData
343
- ] = useArr$([
344
- "maintainVisibleContentPosition",
345
- `containerPosition${id}`,
317
+ const [column = 0, data, itemKey, position = POSITION_OUT_OF_VIEW, numColumns, lastItemKeys, extraData] = useArr$([
346
318
  `containerColumn${id}`,
319
+ `containerItemData${id}`,
320
+ `containerItemKey${id}`,
321
+ `containerPosition${id}`,
347
322
  "numColumns",
348
323
  "lastItemKeys",
349
- `containerItemKey${id}`,
350
- `containerItemData${id}`,
351
324
  "extraData"
352
325
  ]);
353
326
  const refLastSize = useRef();
@@ -356,6 +329,7 @@ var Container = ({
356
329
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
357
330
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
358
331
  const isALastItem = lastItemKeys.includes(itemKey);
332
+ let didLayout = false;
359
333
  let paddingStyles;
360
334
  if (columnWrapperStyle) {
361
335
  const { columnGap, rowGap, gap } = columnWrapperStyle;
@@ -376,14 +350,14 @@ var Container = ({
376
350
  position: "absolute",
377
351
  top: otherAxisPos,
378
352
  height: otherAxisSize,
379
- left: position.relativeCoordinate,
353
+ left: position,
380
354
  ...paddingStyles || {}
381
355
  } : {
382
356
  position: "absolute",
383
357
  left: otherAxisPos,
384
358
  right: numColumns > 1 ? null : 0,
385
359
  width: otherAxisSize,
386
- top: position.relativeCoordinate,
360
+ top: position,
387
361
  ...paddingStyles || {}
388
362
  };
389
363
  const renderedItemInfo = useMemo(
@@ -394,9 +368,14 @@ var Container = ({
394
368
  const triggerLayout = useCallback(() => {
395
369
  forceLayoutRender((v) => v + 1);
396
370
  }, []);
371
+ const contextValue = useMemo(() => {
372
+ ctx.viewRefs.set(id, ref);
373
+ return { containerId: id, itemKey, index, value: data, triggerLayout };
374
+ }, [id, itemKey, index, data]);
397
375
  const onLayout = (event) => {
398
376
  var _a, _b;
399
377
  if (!isNullOrUndefined(itemKey)) {
378
+ didLayout = true;
400
379
  let layout = event.nativeEvent.layout;
401
380
  const size = layout[horizontal ? "width" : "height"];
402
381
  const doUpdate = () => {
@@ -430,7 +409,7 @@ var Container = ({
430
409
  useEffect(() => {
431
410
  if (!isNullOrUndefined(itemKey)) {
432
411
  const timeout = setTimeout(() => {
433
- if (refLastSize.current) {
412
+ if (!didLayout && refLastSize.current) {
434
413
  updateItemSize(itemKey, refLastSize.current);
435
414
  }
436
415
  }, 16);
@@ -440,20 +419,7 @@ var Container = ({
440
419
  }
441
420
  }, [itemKey]);
442
421
  }
443
- const contextValue = useMemo(() => {
444
- ctx.viewRefs.set(id, ref);
445
- return { containerId: id, itemKey, index, value: data, triggerLayout };
446
- }, [id, itemKey, index, data]);
447
- const contentFragment = /* @__PURE__ */ React2__default.createElement(React2__default.Fragment, { key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React2__default.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && !isALastItem && /* @__PURE__ */ React2__default.createElement(ItemSeparatorComponent, { leadingItem: renderedItemInfo.item })));
448
- if (maintainVisibleContentPosition) {
449
- const anchorStyle = horizontal ? position.type === "top" ? { position: "absolute", left: 0, top: 0, bottom: 0, flexDirection: "row", alignItems: "stretch" } : { position: "absolute", right: 0, top: 0, bottom: 0, flexDirection: "row", alignItems: "stretch" } : position.type === "top" ? { position: "absolute", top: 0, left: 0, right: 0 } : { position: "absolute", bottom: 0, left: 0, right: 0 };
450
- if (__DEV__ && ENABLE_DEVMODE) {
451
- anchorStyle.borderColor = position.type === "top" ? "red" : "blue";
452
- anchorStyle.borderWidth = 1;
453
- }
454
- return /* @__PURE__ */ React2__default.createElement(LeanView, { style }, /* @__PURE__ */ React2__default.createElement(LeanView, { style: [anchorStyle, paddingStyles], onLayout, ref }, contentFragment, __DEV__ && ENABLE_DEVMODE && /* @__PURE__ */ React2__default.createElement(Text, { style: { position: "absolute", top: 0, left: 0, zIndex: 1e3 } }, position.top)));
455
- }
456
- return /* @__PURE__ */ React2__default.createElement(LeanView, { style, onLayout, ref }, contentFragment);
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 })));
457
423
  };
458
424
  var typedForwardRef = forwardRef;
459
425
  var typedMemo = memo;
@@ -462,21 +428,35 @@ var useAnimatedValue = (initialValue) => {
462
428
  };
463
429
 
464
430
  // src/useValue$.ts
465
- function useValue$(key, getValue, useMicrotask) {
431
+ function useValue$(key, params) {
466
432
  var _a;
433
+ const { getValue, delay } = params || {};
467
434
  const ctx = useStateContext();
468
435
  const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
469
436
  useMemo(() => {
470
437
  let newValue = void 0;
438
+ let prevValue = void 0;
439
+ let didQueueTask = false;
471
440
  listen$(ctx, key, (v) => {
472
- if (useMicrotask && newValue === void 0) {
473
- queueMicrotask(() => {
474
- animValue.setValue(newValue);
475
- newValue = void 0;
476
- });
477
- }
478
441
  newValue = getValue ? getValue(v) : v;
479
- if (!useMicrotask) {
442
+ if (delay !== void 0) {
443
+ const fn = () => {
444
+ didQueueTask = false;
445
+ if (newValue !== void 0) {
446
+ animValue.setValue(newValue);
447
+ }
448
+ };
449
+ const delayValue = typeof delay === "function" ? delay(newValue, prevValue) : delay;
450
+ prevValue = newValue;
451
+ if (!didQueueTask) {
452
+ didQueueTask = true;
453
+ if (delayValue === 0) {
454
+ queueMicrotask(fn);
455
+ } else {
456
+ setTimeout(fn, delayValue);
457
+ }
458
+ }
459
+ } else {
480
460
  animValue.setValue(newValue);
481
461
  }
482
462
  });
@@ -496,19 +476,12 @@ var Containers = typedMemo(function Containers2({
496
476
  const ctx = useStateContext();
497
477
  const columnWrapperStyle = ctx.columnWrapperStyle;
498
478
  const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
499
- const animSize = useValue$(
500
- "totalSizeWithScrollAdjust",
501
- void 0,
502
- /*useMicrotask*/
503
- true
504
- );
505
- const animOpacity = waitForInitialLayout ? useValue$("containersDidLayout", (value) => value ? 1 : 0) : void 0;
506
- const otherAxisSize = useValue$(
507
- "otherAxisSize",
508
- void 0,
509
- /*useMicrotask*/
510
- true
511
- );
479
+ const animSize = useValue$("totalSize", {
480
+ // Use a microtask if increasing the size significantly, otherwise use a timeout
481
+ delay: (value, prevValue) => !prevValue || value - prevValue > 20 ? 0 : 200
482
+ });
483
+ const animOpacity = waitForInitialLayout && !IsNewArchitecture ? useValue$("containersDidLayout", { getValue: (value) => value ? 1 : 0 }) : void 0;
484
+ const otherAxisSize = useValue$("otherAxisSize", { delay: 0 });
512
485
  const containers = [];
513
486
  for (let i = 0; i < numContainers; i++) {
514
487
  containers.push(
@@ -543,33 +516,41 @@ var Containers = typedMemo(function Containers2({
543
516
  }
544
517
  return /* @__PURE__ */ React2.createElement(Animated.View, { style }, containers);
545
518
  });
546
- function ListHeaderComponentContainer({
547
- children,
548
- style,
549
- ctx,
550
- horizontal,
551
- waitForInitialLayout
552
- }) {
553
- var _a;
554
- const hasData = ((_a = peek$(ctx, "lastItemKeys")) == null ? void 0 : _a.length) > 0;
555
- const scrollAdjust = useValue$("scrollAdjust", (v) => v != null ? v : 0, true);
556
- const animOpacity = waitForInitialLayout ? useValue$("containersDidLayout", (value) => value ? 1 : 0) : void 0;
557
- const additionalSize = {
558
- transform: [{ translateY: Animated.multiply(scrollAdjust, -1) }],
559
- // Header should show if there's no data yet, but containersDidLayout will be false until it has some data
560
- opacity: hasData ? animOpacity : 1
561
- };
519
+ function ScrollAdjust() {
520
+ const bias = 1e7;
521
+ const [scrollAdjust, scrollAdjustUserOffset] = useArr$(["scrollAdjust", "scrollAdjustUserOffset"]);
522
+ const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0) + bias;
562
523
  return /* @__PURE__ */ React2.createElement(
563
- Animated.View,
524
+ View,
564
525
  {
565
- style: [style, additionalSize],
566
- onLayout: (event) => {
567
- const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
568
- set$(ctx, "headerSize", size);
526
+ style: {
527
+ position: "absolute",
528
+ height: 0,
529
+ width: 0,
530
+ top: scrollOffset,
531
+ left: 0
569
532
  }
533
+ }
534
+ );
535
+ }
536
+ function useSyncLayout({
537
+ onChange
538
+ }) {
539
+ const ref = useRef(null);
540
+ const onLayout = useCallback(
541
+ (event) => {
542
+ onChange(event.nativeEvent.layout, false);
570
543
  },
571
- children
544
+ [onChange]
572
545
  );
546
+ useLayoutEffect(() => {
547
+ if (ref.current) {
548
+ ref.current.measure((x, y, width, height) => {
549
+ onChange({ x, y, width, height }, true);
550
+ });
551
+ }
552
+ }, []);
553
+ return { onLayout, ref };
573
554
  }
574
555
 
575
556
  // src/ListComponent.tsx
@@ -582,58 +563,28 @@ var getComponent = (Component) => {
582
563
  }
583
564
  return null;
584
565
  };
585
- var PaddingAndAdjust = () => {
586
- const animPaddingTop = useValue$("paddingTop", (v) => v, true);
587
- const animScrollAdjust = useValue$("scrollAdjust", (v) => v, true);
588
- const additionalSize = { marginTop: animScrollAdjust, paddingTop: animPaddingTop };
589
- return /* @__PURE__ */ React2.createElement(Animated.View, { style: additionalSize });
566
+ var Padding = () => {
567
+ const animPaddingTop = useValue$("alignItemsPaddingTop", { delay: 0 });
568
+ return /* @__PURE__ */ React2.createElement(Animated.View, { style: { paddingTop: animPaddingTop } });
590
569
  };
591
- var PaddingAndAdjustDevMode = () => {
592
- const animPaddingTop = useValue$("paddingTop", (v) => v, true);
593
- const animScrollAdjust = useValue$("scrollAdjust", (v) => v, true);
594
- return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Animated.View, { style: { marginTop: animScrollAdjust } }), /* @__PURE__ */ React2.createElement(Animated.View, { style: { paddingTop: animPaddingTop } }), /* @__PURE__ */ React2.createElement(
570
+ var PaddingDevMode = () => {
571
+ 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(
595
573
  Animated.View,
596
574
  {
597
575
  style: {
598
576
  position: "absolute",
599
- top: Animated.add(animScrollAdjust, Animated.multiply(animScrollAdjust, -1)),
577
+ top: 0,
600
578
  height: animPaddingTop,
601
579
  left: 0,
602
580
  right: 0,
603
581
  backgroundColor: "green"
604
582
  }
605
583
  }
606
- ), /* @__PURE__ */ React2.createElement(
607
- Animated.View,
608
- {
609
- style: {
610
- position: "absolute",
611
- top: animPaddingTop,
612
- height: animScrollAdjust,
613
- left: -16,
614
- right: -16,
615
- backgroundColor: "lightblue"
616
- }
617
- }
618
- ), /* @__PURE__ */ React2.createElement(
619
- Animated.View,
620
- {
621
- style: {
622
- position: "absolute",
623
- top: animPaddingTop,
624
- height: Animated.multiply(animScrollAdjust, -1),
625
- width: 8,
626
- right: 4,
627
- borderStyle: "dashed",
628
- borderColor: "blue",
629
- borderWidth: 1,
630
- backgroundColor: "lightblue"
631
- //backgroundColor: "blue",
632
- }
633
- }
634
584
  ));
635
585
  };
636
586
  var ListComponent = typedMemo(function ListComponent2({
587
+ canRender,
637
588
  style,
638
589
  contentContainerStyle,
639
590
  horizontal,
@@ -654,13 +605,25 @@ var ListComponent = typedMemo(function ListComponent2({
654
605
  refScrollView,
655
606
  maintainVisibleContentPosition,
656
607
  renderScrollComponent,
608
+ scrollAdjustHandler,
609
+ onLayoutHeader,
657
610
  ...rest
658
611
  }) {
659
612
  const ctx = useStateContext();
613
+ const { onLayout: onLayoutHeaderSync, ref: refHeader } = useSyncLayout({
614
+ onChange: onLayoutHeader
615
+ });
660
616
  const ScrollComponent = renderScrollComponent ? useMemo(
661
617
  () => React2.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
662
618
  [renderScrollComponent]
663
619
  ) : ScrollView;
620
+ React2.useEffect(() => {
621
+ if (canRender) {
622
+ setTimeout(() => {
623
+ scrollAdjustHandler.setMounted();
624
+ }, 0);
625
+ }
626
+ }, [canRender]);
664
627
  return /* @__PURE__ */ React2.createElement(
665
628
  ScrollComponent,
666
629
  {
@@ -679,19 +642,11 @@ var ListComponent = typedMemo(function ListComponent2({
679
642
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
680
643
  ref: refScrollView
681
644
  },
682
- ENABLE_DEVMODE ? /* @__PURE__ */ React2.createElement(PaddingAndAdjustDevMode, null) : /* @__PURE__ */ React2.createElement(PaddingAndAdjust, null),
683
- ListHeaderComponent && /* @__PURE__ */ React2.createElement(
684
- ListHeaderComponentContainer,
685
- {
686
- style: ListHeaderComponentStyle,
687
- ctx,
688
- horizontal,
689
- waitForInitialLayout
690
- },
691
- getComponent(ListHeaderComponent)
692
- ),
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)),
693
648
  ListEmptyComponent && getComponent(ListEmptyComponent),
694
- /* @__PURE__ */ React2.createElement(
649
+ canRender && /* @__PURE__ */ React2.createElement(
695
650
  Containers,
696
651
  {
697
652
  horizontal,
@@ -719,49 +674,22 @@ var ListComponent = typedMemo(function ListComponent2({
719
674
  // src/ScrollAdjustHandler.ts
720
675
  var ScrollAdjustHandler = class {
721
676
  constructor(ctx) {
722
- this.ctx = ctx;
723
677
  this.appliedAdjust = 0;
724
- this.busy = false;
725
- this.isPaused = false;
726
- this.isDisabled = false;
678
+ this.mounted = false;
727
679
  this.context = ctx;
728
680
  }
729
- doAjdust() {
730
- set$(this.context, "scrollAdjust", this.appliedAdjust);
731
- this.busy = false;
732
- }
733
- requestAdjust(adjust, onAdjusted) {
734
- if (this.isDisabled) {
735
- return;
736
- }
737
- const oldAdjustTop = peek$(this.context, "scrollAdjust");
738
- if (oldAdjustTop === adjust) {
739
- return;
740
- }
741
- this.appliedAdjust = adjust;
742
- if (!this.busy && !this.isPaused) {
743
- this.busy = true;
744
- this.doAjdust();
745
- onAdjusted(oldAdjustTop - adjust);
681
+ requestAdjust(add) {
682
+ const oldAdjustTop = peek$(this.context, "scrollAdjust") || 0;
683
+ this.appliedAdjust = add + oldAdjustTop;
684
+ const set = () => set$(this.context, "scrollAdjust", this.appliedAdjust);
685
+ if (this.mounted) {
686
+ set();
687
+ } else {
688
+ requestAnimationFrame(set);
746
689
  }
747
690
  }
748
- getAppliedAdjust() {
749
- return this.appliedAdjust;
750
- }
751
- pauseAdjust() {
752
- this.isPaused = true;
753
- }
754
- setDisableAdjust(disable) {
755
- this.isDisabled = disable;
756
- }
757
- // return true if it was paused
758
- unPauseAdjust() {
759
- if (this.isPaused) {
760
- this.isPaused = false;
761
- this.doAjdust();
762
- return true;
763
- }
764
- return false;
691
+ setMounted() {
692
+ this.mounted = true;
765
693
  }
766
694
  };
767
695
  var useCombinedRef = (...refs) => {
@@ -909,13 +837,12 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getI
909
837
  }
910
838
  }
911
839
  function computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
912
- const { sizes, positions, scroll: scrollState, scrollAdjustHandler } = state;
840
+ const { sizes, positions, scroll: scrollState } = state;
913
841
  const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
914
842
  const { itemVisiblePercentThreshold, viewAreaCoveragePercentThreshold } = viewabilityConfig;
915
843
  const viewAreaMode = viewAreaCoveragePercentThreshold != null;
916
844
  const viewablePercentThreshold = viewAreaMode ? viewAreaCoveragePercentThreshold : itemVisiblePercentThreshold;
917
- const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
918
- const scroll = scrollState - previousScrollAdjust - topPad;
845
+ const scroll = scrollState - topPad;
919
846
  const top = positions.get(key) - scroll;
920
847
  const size = sizes.get(key) || 0;
921
848
  const bottom = top + size;
@@ -987,6 +914,7 @@ var LegendList = typedForwardRef(function LegendList2(props, forwardedRef) {
987
914
  return /* @__PURE__ */ React2.createElement(StateProvider, null, /* @__PURE__ */ React2.createElement(LegendListInner, { ...props, ref: forwardedRef }));
988
915
  });
989
916
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
917
+ var _a;
990
918
  const {
991
919
  data: dataProp = [],
992
920
  initialScrollIndex: initialScrollIndexProp,
@@ -1029,9 +957,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1029
957
  onViewableItemsChanged,
1030
958
  ...rest
1031
959
  } = props;
960
+ const [renderNum, setRenderNum] = useState(0);
1032
961
  const initialScroll = typeof initialScrollIndexProp === "number" ? { index: initialScrollIndexProp } : initialScrollIndexProp;
1033
962
  const initialScrollIndex = initialScroll == null ? void 0 : initialScroll.index;
1034
963
  const refLoadStartTime = useRef(Date.now());
964
+ const [canRender, setCanRender] = React2.useState(!IsNewArchitecture);
1035
965
  const callbacks = useRef({
1036
966
  onStartReached: rest.onStartReached,
1037
967
  onEndReached: rest.onEndReached
@@ -1042,12 +972,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1042
972
  const style = { ...StyleSheet.flatten(styleProp) };
1043
973
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
1044
974
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
1045
- if (style == null ? void 0 : style.paddingTop) {
1046
- style.paddingTop = void 0;
1047
- }
1048
- if (contentContainerStyle == null ? void 0 : contentContainerStyle.paddingTop) {
1049
- contentContainerStyle.paddingTop = void 0;
1050
- }
1051
975
  const ctx = useStateContext();
1052
976
  ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
1053
977
  const refScroller = useRef(null);
@@ -1057,56 +981,45 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1057
981
  const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (item, index) => index.toString();
1058
982
  const refState = useRef();
1059
983
  const getId = (index) => {
1060
- var _a;
1061
- const data = (_a = refState.current) == null ? void 0 : _a.data;
1062
- if (!data) {
984
+ const state = refState.current;
985
+ if (!(state == null ? void 0 : state.data)) {
1063
986
  return "";
1064
987
  }
988
+ const data = state.data;
1065
989
  const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
1066
- return `${ret}`;
990
+ const id = ret;
991
+ state.idCache.set(index, id);
992
+ return id;
1067
993
  };
1068
994
  const getItemSize = (key, index, data, useAverageSize = false) => {
1069
995
  const state = refState.current;
1070
- state.sizesKnown.get(key);
996
+ const sizeKnown = state.sizesKnown.get(key);
997
+ if (sizeKnown !== void 0) {
998
+ return sizeKnown;
999
+ }
1071
1000
  const sizePrevious = state.sizes.get(key);
1072
- let size;
1073
- peek$(ctx, "numColumns");
1074
- if (size === void 0 && sizePrevious !== void 0) {
1001
+ if (sizePrevious !== void 0) {
1075
1002
  return sizePrevious;
1076
1003
  }
1077
- if (size === void 0) {
1078
- size = getEstimatedItemSize ? getEstimatedItemSize(index, data) : estimatedItemSize;
1079
- }
1004
+ const size = getEstimatedItemSize ? getEstimatedItemSize(index, data) : estimatedItemSize;
1080
1005
  state.sizes.set(key, size);
1081
1006
  return size;
1082
1007
  };
1083
- const calculateOffsetForIndex = (indexParam) => {
1084
- var _a;
1085
- const isFromInit = indexParam === void 0;
1086
- const index = isFromInit ? initialScrollIndex : indexParam;
1087
- const data = dataProp;
1008
+ const calculateOffsetForIndex = (index) => {
1009
+ var _a2;
1010
+ let position = 0;
1088
1011
  if (index !== void 0) {
1089
- let offset = 0;
1090
- const canGetSize = !!refState.current;
1091
- if (canGetSize || getEstimatedItemSize) {
1092
- const sizeFn = (index2) => {
1093
- if (canGetSize) {
1094
- return getItemSize(getId(index2), index2, data[index2], true);
1095
- }
1096
- return getEstimatedItemSize(index2, data[index2]);
1097
- };
1098
- for (let i = 0; i < index; i++) {
1099
- offset += sizeFn(i);
1100
- }
1101
- } else {
1102
- offset = index * estimatedItemSize;
1103
- }
1104
- const adjust = peek$(ctx, "containersDidLayout") ? ((_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler.getAppliedAdjust()) || 0 : 0;
1105
- const stylePaddingTop = isFromInit ? stylePaddingTopState : peek$(ctx, "stylePaddingTop");
1106
- const topPad = (stylePaddingTop != null ? stylePaddingTop : 0) + peek$(ctx, "headerSize");
1107
- return offset / numColumnsProp - adjust + topPad;
1012
+ position = ((_a2 = refState.current) == null ? void 0 : _a2.positions.get(getId(index))) || 0;
1108
1013
  }
1109
- return 0;
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;
1110
1023
  };
1111
1024
  const calculateOffsetWithOffsetPosition = (offsetParam, params) => {
1112
1025
  const { index, viewOffset, viewPosition } = params;
@@ -1120,15 +1033,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1120
1033
  }
1121
1034
  return offset;
1122
1035
  };
1123
- const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : useMemo(() => calculateOffsetForIndex(void 0), []);
1124
1036
  if (!refState.current) {
1125
- const initialScrollLength = (estimatedListSize != null ? estimatedListSize : Dimensions.get("window"))[horizontal ? "width" : "height"];
1037
+ const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { width: 0, height: 0 } : Dimensions.get("window"))[horizontal ? "width" : "height"];
1126
1038
  refState.current = {
1127
1039
  sizes: /* @__PURE__ */ new Map(),
1128
1040
  positions: /* @__PURE__ */ new Map(),
1129
1041
  columns: /* @__PURE__ */ new Map(),
1130
1042
  pendingAdjust: 0,
1131
- isStartReached: initialContentOffset < initialScrollLength * onStartReachedThreshold,
1043
+ isStartReached: false,
1132
1044
  isEndReached: false,
1133
1045
  isAtEnd: false,
1134
1046
  isAtStart: false,
@@ -1138,9 +1050,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1138
1050
  startNoBuffer: -1,
1139
1051
  endBuffered: -1,
1140
1052
  endNoBuffer: -1,
1141
- scroll: initialContentOffset || 0,
1053
+ firstFullyOnScreenIndex: -1,
1054
+ scroll: 0,
1142
1055
  totalSize: 0,
1143
- totalSizeBelowAnchor: 0,
1144
1056
  timeouts: /* @__PURE__ */ new Set(),
1145
1057
  viewabilityConfigCallbackPairs: void 0,
1146
1058
  renderItem: void 0,
@@ -1152,12 +1064,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1152
1064
  scrollPending: 0,
1153
1065
  indexByKey: /* @__PURE__ */ new Map(),
1154
1066
  scrollHistory: [],
1155
- scrollVelocity: 0,
1156
1067
  sizesKnown: /* @__PURE__ */ new Map(),
1157
1068
  timeoutSizeMessage: 0,
1158
- scrollTimer: void 0,
1159
- belowAnchorElementPositions: void 0,
1160
- rowHeights: /* @__PURE__ */ new Map(),
1161
1069
  startReachedBlockedByTimer: false,
1162
1070
  endReachedBlockedByTimer: false,
1163
1071
  scrollForNextCalculateItemsInView: void 0,
@@ -1166,41 +1074,126 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1166
1074
  queuedCalculateItemsInView: 0,
1167
1075
  lastBatchingAction: Date.now(),
1168
1076
  averageSizes: {},
1169
- onScroll: onScrollProp
1077
+ onScroll: onScrollProp,
1078
+ idsInView: [],
1079
+ containerItemKeys: /* @__PURE__ */ new Set(),
1080
+ idCache: /* @__PURE__ */ new Map()
1170
1081
  };
1171
- const dataLength = dataProp.length;
1172
- if (maintainVisibleContentPosition && dataLength > 0) {
1173
- if (initialScrollIndex && initialScrollIndex < dataLength) {
1174
- refState.current.anchorElement = {
1175
- coordinate: initialContentOffset,
1176
- id: getId(initialScrollIndex)
1177
- };
1178
- } else if (dataLength > 0) {
1179
- refState.current.anchorElement = {
1180
- coordinate: initialContentOffset,
1181
- id: getId(0)
1182
- };
1183
- } else {
1184
- __DEV__ && warnDevOnce(
1185
- "maintainVisibleContentPosition",
1186
- "[legend-list] maintainVisibleContentPosition was not able to find an anchor element"
1187
- );
1188
- }
1189
- }
1190
- set$(ctx, "scrollAdjust", 0);
1191
1082
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPosition);
1192
1083
  set$(ctx, "extraData", extraData);
1193
1084
  }
1194
1085
  const didDataChange = refState.current.data !== dataProp;
1195
1086
  refState.current.data = dataProp;
1196
1087
  refState.current.onScroll = onScrollProp;
1197
- const getAnchorElementIndex = () => {
1198
- const state = refState.current;
1199
- if (state.anchorElement) {
1200
- const el = state.indexByKey.get(state.anchorElement.id);
1201
- return el;
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
+ }
1202
1195
  }
1203
- return void 0;
1196
+ updateTotalSize();
1204
1197
  };
1205
1198
  const scrollToIndex = ({
1206
1199
  index,
@@ -1208,7 +1201,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1208
1201
  animated = true,
1209
1202
  viewPosition
1210
1203
  }) => {
1211
- var _a;
1212
1204
  const state = refState.current;
1213
1205
  if (index >= state.data.length) {
1214
1206
  index = state.data.length - 1;
@@ -1217,220 +1209,33 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1217
1209
  }
1218
1210
  const firstIndexOffset = calculateOffsetForIndex(index);
1219
1211
  const isLast = index === state.data.length - 1;
1220
- if (isLast && viewPosition !== void 0) {
1212
+ if (isLast && viewPosition === void 0) {
1221
1213
  viewPosition = 1;
1222
1214
  }
1223
- let firstIndexScrollPostion = firstIndexOffset - viewOffset;
1224
- const diff = Math.abs(state.scroll - firstIndexScrollPostion);
1225
- const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
1226
- const needsReanchoring = maintainVisibleContentPosition && diff > 100;
1215
+ const firstIndexScrollPostion = firstIndexOffset - viewOffset;
1227
1216
  state.scrollForNextCalculateItemsInView = void 0;
1228
- if (needsReanchoring) {
1229
- const id = getId(index);
1230
- state.anchorElement = { id, coordinate: firstIndexOffset - topPad };
1231
- (_a = state.belowAnchorElementPositions) == null ? void 0 : _a.clear();
1232
- state.positions.clear();
1233
- calcTotalSizesAndPositions({ forgetPositions: true });
1234
- state.startBufferedId = id;
1235
- state.minIndexSizeChanged = index;
1236
- firstIndexScrollPostion = firstIndexOffset - viewOffset + state.scrollAdjustHandler.getAppliedAdjust();
1237
- }
1238
1217
  scrollTo({ offset: firstIndexScrollPostion, animated, index, viewPosition: viewPosition != null ? viewPosition : 0, viewOffset });
1239
1218
  };
1240
1219
  const setDidLayout = () => {
1241
1220
  refState.current.queuedInitialLayout = true;
1242
1221
  checkAtBottom();
1243
- const setIt = () => {
1244
- set$(ctx, "containersDidLayout", true);
1245
- if (props.onLoad) {
1246
- props.onLoad({ elapsedTimeInMs: Date.now() - refLoadStartTime.current });
1247
- }
1248
- };
1249
- if (initialScroll) {
1250
- queueMicrotask(() => {
1251
- scrollToIndex({ ...initialScroll, animated: false });
1252
- requestAnimationFrame(() => {
1253
- if (!IsNewArchitecture) {
1254
- scrollToIndex({ ...initialScroll, animated: false });
1255
- }
1256
- setIt();
1257
- });
1258
- });
1259
- } else {
1260
- queueMicrotask(setIt);
1222
+ set$(ctx, "containersDidLayout", true);
1223
+ if (props.onLoad) {
1224
+ props.onLoad({ elapsedTimeInMs: Date.now() - refLoadStartTime.current });
1261
1225
  }
1262
1226
  };
1263
- const addTotalSize = useCallback((key, add, totalSizeBelowAnchor) => {
1227
+ const addTotalSize = useCallback((key, add) => {
1264
1228
  const state = refState.current;
1265
- const { indexByKey, anchorElement } = state;
1266
- const index = key === null ? 0 : indexByKey.get(key);
1267
- let isAboveAnchor = false;
1268
- if (maintainVisibleContentPosition) {
1269
- if (anchorElement && index < getAnchorElementIndex()) {
1270
- isAboveAnchor = true;
1271
- }
1272
- }
1273
1229
  if (key === null) {
1274
1230
  state.totalSize = add;
1275
- state.totalSizeBelowAnchor = totalSizeBelowAnchor;
1276
1231
  } else {
1277
1232
  state.totalSize += add;
1278
- if (isAboveAnchor) {
1279
- state.totalSizeBelowAnchor += add;
1280
- }
1281
- }
1282
- let applyAdjustValue = 0;
1283
- let resultSize = state.totalSize;
1284
- if (maintainVisibleContentPosition && anchorElement !== void 0) {
1285
- const newAdjust = anchorElement.coordinate - state.totalSizeBelowAnchor;
1286
- applyAdjustValue = -newAdjust;
1287
- state.belowAnchorElementPositions = buildElementPositionsBelowAnchor();
1288
- state.rowHeights.clear();
1289
- if (applyAdjustValue !== void 0) {
1290
- resultSize -= applyAdjustValue;
1291
- state.scrollAdjustHandler.requestAdjust(applyAdjustValue, (diff) => {
1292
- state.scroll -= diff;
1293
- });
1294
- }
1295
1233
  }
1296
1234
  set$(ctx, "totalSize", state.totalSize);
1297
- set$(ctx, "totalSizeWithScrollAdjust", resultSize);
1298
1235
  if (alignItemsAtEnd) {
1299
1236
  updateAlignItemsPaddingTop();
1300
1237
  }
1301
1238
  }, []);
1302
- const getRowHeight = (n) => {
1303
- const { rowHeights, data } = refState.current;
1304
- const numColumns = peek$(ctx, "numColumns");
1305
- if (numColumns === 1) {
1306
- const id = getId(n);
1307
- return getItemSize(id, n, data[n]);
1308
- }
1309
- if (rowHeights.has(n)) {
1310
- return rowHeights.get(n) || 0;
1311
- }
1312
- let rowHeight = 0;
1313
- const startEl = n * numColumns;
1314
- for (let i = startEl; i < startEl + numColumns && i < data.length; i++) {
1315
- const id = getId(i);
1316
- const size = getItemSize(id, i, data[i]);
1317
- rowHeight = Math.max(rowHeight, size);
1318
- }
1319
- rowHeights.set(n, rowHeight);
1320
- return rowHeight;
1321
- };
1322
- const buildElementPositionsBelowAnchor = () => {
1323
- const state = refState.current;
1324
- if (!state.anchorElement) {
1325
- return /* @__PURE__ */ new Map();
1326
- }
1327
- const anchorIndex = state.indexByKey.get(state.anchorElement.id);
1328
- if (anchorIndex === 0) {
1329
- return /* @__PURE__ */ new Map();
1330
- }
1331
- const map = state.belowAnchorElementPositions || /* @__PURE__ */ new Map();
1332
- const numColumns = peek$(ctx, "numColumns");
1333
- let top = state.anchorElement.coordinate;
1334
- for (let i = anchorIndex - 1; i >= 0; i--) {
1335
- const id = getId(i);
1336
- const rowNumber = Math.floor(i / numColumns);
1337
- if (i % numColumns === 0) {
1338
- top -= getRowHeight(rowNumber);
1339
- }
1340
- map.set(id, top);
1341
- }
1342
- return map;
1343
- };
1344
- const disableScrollJumps = (timeout) => {
1345
- const state = refState.current;
1346
- if (state.scrollingTo === void 0) {
1347
- state.disableScrollJumpsFrom = state.scroll - state.scrollAdjustHandler.getAppliedAdjust();
1348
- state.scrollHistory.length = 0;
1349
- setTimeout(() => {
1350
- state.disableScrollJumpsFrom = void 0;
1351
- if (state.scrollPending !== void 0 && state.scrollPending !== state.scroll) {
1352
- updateScroll(state.scrollPending);
1353
- }
1354
- }, timeout);
1355
- }
1356
- };
1357
- const getElementPositionBelowAchor = (id) => {
1358
- var _a;
1359
- const state = refState.current;
1360
- if (!refState.current.belowAnchorElementPositions) {
1361
- state.belowAnchorElementPositions = buildElementPositionsBelowAnchor();
1362
- }
1363
- const res = state.belowAnchorElementPositions.get(id);
1364
- if (res === void 0) {
1365
- console.warn(`Undefined position below anchor ${id} ${(_a = state.anchorElement) == null ? void 0 : _a.id}`);
1366
- return 0;
1367
- }
1368
- return res;
1369
- };
1370
- const fixGaps = useCallback(() => {
1371
- var _a;
1372
- const state = refState.current;
1373
- const { data, scrollLength, positions, startBuffered, endBuffered } = state;
1374
- const numColumns = peek$(ctx, "numColumns");
1375
- if (!data || scrollLength === 0 || numColumns > 1) {
1376
- return;
1377
- }
1378
- const numContainers = ctx.values.get("numContainers");
1379
- let numMeasurements = 0;
1380
- for (let i = 0; i < numContainers; i++) {
1381
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1382
- const isSizeKnown = state.sizesKnown.get(itemKey);
1383
- if (itemKey && !isSizeKnown) {
1384
- const containerRef = ctx.viewRefs.get(i);
1385
- if (containerRef) {
1386
- let measured;
1387
- (_a = containerRef.current) == null ? void 0 : _a.measure((x, y, width, height) => {
1388
- measured = { width, height };
1389
- });
1390
- numMeasurements++;
1391
- if (measured) {
1392
- updateItemSize(
1393
- itemKey,
1394
- measured,
1395
- /*fromFixGaps*/
1396
- true
1397
- );
1398
- }
1399
- }
1400
- }
1401
- }
1402
- if (numMeasurements > 0) {
1403
- let top;
1404
- const diffs = /* @__PURE__ */ new Map();
1405
- for (let i = startBuffered; i <= endBuffered; i++) {
1406
- const id = getId(i);
1407
- if (top === void 0) {
1408
- top = positions.get(id);
1409
- }
1410
- if (positions.get(id) !== top) {
1411
- diffs.set(id, top - positions.get(id));
1412
- positions.set(id, top);
1413
- }
1414
- const size = getItemSize(id, i, data[i]);
1415
- const bottom = top + size;
1416
- top = bottom;
1417
- }
1418
- for (let i = 0; i < numContainers; i++) {
1419
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1420
- const diff = diffs.get(itemKey);
1421
- if (diff) {
1422
- const prevPos = peek$(ctx, `containerPosition${i}`);
1423
- const newPos = prevPos.top + diff;
1424
- if (prevPos.top !== newPos) {
1425
- const pos = { ...prevPos };
1426
- pos.relativeCoordinate += diff;
1427
- pos.top += diff;
1428
- set$(ctx, `containerPosition${i}`, pos);
1429
- }
1430
- }
1431
- }
1432
- }
1433
- }, []);
1434
1239
  const checkAllSizesKnown = useCallback(() => {
1435
1240
  const { startBuffered, endBuffered, sizesKnown } = refState.current;
1436
1241
  if (endBuffered !== null) {
@@ -1443,8 +1248,70 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1443
1248
  }
1444
1249
  return false;
1445
1250
  }, []);
1446
- const calculateItemsInView = useCallback((isReset) => {
1447
- var _a;
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;
1448
1315
  const state = refState.current;
1449
1316
  const {
1450
1317
  data,
@@ -1452,20 +1319,33 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1452
1319
  startBufferedId: startBufferedIdOrig,
1453
1320
  positions,
1454
1321
  columns,
1455
- scrollAdjustHandler,
1456
- scrollVelocity: speed
1322
+ containerItemKeys,
1323
+ idCache,
1324
+ sizes,
1325
+ indexByKey,
1326
+ scrollForNextCalculateItemsInView,
1327
+ enableScrollForNextCalculateItemsInView,
1328
+ minIndexSizeChanged
1457
1329
  } = state;
1458
1330
  if (!data || scrollLength === 0) {
1459
1331
  return;
1460
1332
  }
1461
- const totalSize = peek$(ctx, "totalSizeWithScrollAdjust");
1333
+ const totalSize = peek$(ctx, "totalSize");
1462
1334
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
1463
1335
  const numColumns = peek$(ctx, "numColumns");
1464
- const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
1465
- let scrollState = state.scroll;
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
+ }
1466
1344
  const scrollExtra = 0;
1467
- const useAverageSize = !state.disableScrollJumpsFrom && speed >= 0 && peek$(ctx, "containersDidLayout");
1468
- if (!state.queuedInitialLayout && initialScroll) {
1345
+ const useAverageSize = false;
1346
+ const { queuedInitialLayout } = state;
1347
+ let { scroll: scrollState } = state;
1348
+ if (!queuedInitialLayout && initialScroll) {
1469
1349
  const updatedOffset = calculateOffsetWithOffsetPosition(
1470
1350
  calculateOffsetForIndex(initialScroll.index),
1471
1351
  initialScroll
@@ -1483,21 +1363,19 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1483
1363
  }
1484
1364
  let scrollBufferTop = scrollBuffer;
1485
1365
  let scrollBufferBottom = scrollBuffer;
1486
- if (Math.abs(speed) > 4) {
1487
- if (speed > 0) {
1488
- scrollBufferTop = scrollBuffer * 0.1;
1489
- scrollBufferBottom = scrollBuffer * 1.9;
1490
- } else {
1491
- scrollBufferTop = scrollBuffer * 1.9;
1492
- scrollBufferBottom = scrollBuffer * 0.1;
1493
- }
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;
1494
1372
  }
1495
1373
  const scrollTopBuffered = scroll - scrollBufferTop;
1496
1374
  const scrollBottom = scroll + scrollLength;
1497
1375
  const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
1498
- if (state.scrollForNextCalculateItemsInView) {
1499
- const { top: top2, bottom } = state.scrollForNextCalculateItemsInView;
1500
- if (scrollTopBuffered > top2 && scrollBottomBuffered < bottom) {
1376
+ if (scrollForNextCalculateItemsInView) {
1377
+ const { top, bottom } = scrollForNextCalculateItemsInView;
1378
+ if (scrollTopBuffered > top && scrollBottomBuffered < bottom) {
1501
1379
  return;
1502
1380
  }
1503
1381
  }
@@ -1506,51 +1384,26 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1506
1384
  let startBufferedId = null;
1507
1385
  let endNoBuffer = null;
1508
1386
  let endBuffered = null;
1509
- let loopStart = startBufferedIdOrig ? state.indexByKey.get(startBufferedIdOrig) || 0 : 0;
1510
- if (state.minIndexSizeChanged !== void 0) {
1511
- loopStart = Math.min(state.minIndexSizeChanged, loopStart);
1387
+ let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
1388
+ if (minIndexSizeChanged !== void 0) {
1389
+ loopStart = Math.min(minIndexSizeChanged, loopStart);
1512
1390
  state.minIndexSizeChanged = void 0;
1513
1391
  }
1514
- const anchorElementIndex = getAnchorElementIndex();
1515
1392
  for (let i = loopStart; i >= 0; i--) {
1516
- const id = getId(i);
1517
- let newPosition;
1518
- if (maintainVisibleContentPosition && anchorElementIndex && i < anchorElementIndex) {
1519
- newPosition = getElementPositionBelowAchor(id);
1520
- if (newPosition !== void 0) {
1521
- positions.set(id, newPosition);
1522
- }
1523
- }
1524
- const top2 = newPosition || positions.get(id);
1525
- if (top2 !== void 0) {
1526
- const size = getItemSize(id, i, data[i], useAverageSize);
1527
- const bottom = top2 + size;
1528
- if (bottom > scroll - scrollBuffer) {
1529
- loopStart = i;
1530
- } else {
1531
- break;
1532
- }
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;
1533
1401
  }
1534
1402
  }
1535
1403
  const loopStartMod = loopStart % numColumns;
1536
1404
  if (loopStartMod > 0) {
1537
1405
  loopStart -= loopStartMod;
1538
1406
  }
1539
- let top = void 0;
1540
- let column = 1;
1541
- let maxSizeInRow = 0;
1542
- const getInitialTop = (i) => {
1543
- var _a2;
1544
- const id = getId(i);
1545
- let topOffset = 0;
1546
- if (positions.get(id)) {
1547
- topOffset = positions.get(id);
1548
- }
1549
- if (id === ((_a2 = state.anchorElement) == null ? void 0 : _a2.id)) {
1550
- topOffset = state.anchorElement.coordinate;
1551
- }
1552
- return topOffset;
1553
- };
1554
1407
  let foundEnd = false;
1555
1408
  let nextTop;
1556
1409
  let nextBottom;
@@ -1559,27 +1412,23 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1559
1412
  for (let i = 0; i < prevNumContainers; i++) {
1560
1413
  const key = peek$(ctx, `containerItemKey${i}`);
1561
1414
  if (key !== void 0) {
1562
- const index = state.indexByKey.get(key);
1415
+ const index = indexByKey.get(key);
1563
1416
  maxIndexRendered = Math.max(maxIndexRendered, index);
1564
1417
  }
1565
1418
  }
1566
- for (let i = Math.max(0, loopStart); i < data.length && (!foundEnd || i <= maxIndexRendered); i++) {
1567
- const id = getId(i);
1568
- const size = getItemSize(id, i, data[i], useAverageSize);
1569
- maxSizeInRow = Math.max(maxSizeInRow, size);
1570
- if (top === void 0 || id === ((_a = state.anchorElement) == null ? void 0 : _a.id)) {
1571
- top = getInitialTop(i);
1572
- }
1573
- if (positions.get(id) !== top) {
1574
- positions.set(id, top);
1575
- }
1576
- if (columns.get(id) !== column) {
1577
- columns.set(id, column);
1578
- }
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);
1579
1425
  if (!foundEnd) {
1580
1426
  if (startNoBuffer === null && top + size > scroll) {
1581
1427
  startNoBuffer = i;
1582
1428
  }
1429
+ if (firstFullyOnScreenIndex === void 0 && top >= scroll - 10) {
1430
+ firstFullyOnScreenIndex = i;
1431
+ }
1583
1432
  if (startBuffered === null && top + size > scrollTopBuffered) {
1584
1433
  startBuffered = i;
1585
1434
  startBufferedId = id;
@@ -1591,46 +1440,49 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1591
1440
  }
1592
1441
  if (top <= scrollBottomBuffered) {
1593
1442
  endBuffered = i;
1594
- nextBottom = top + maxSizeInRow - scrollLength;
1443
+ nextBottom = top + size;
1595
1444
  } else {
1596
1445
  foundEnd = true;
1597
1446
  }
1598
1447
  }
1599
1448
  }
1600
- column++;
1601
- if (column > numColumns) {
1602
- top += maxSizeInRow;
1603
- column = 1;
1604
- maxSizeInRow = 0;
1605
- }
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);
1606
1454
  }
1607
1455
  Object.assign(state, {
1608
1456
  startBuffered,
1609
1457
  startBufferedId,
1610
1458
  startNoBuffer,
1611
1459
  endBuffered,
1612
- endNoBuffer
1460
+ endNoBuffer,
1461
+ idsInView,
1462
+ firstFullyOnScreenIndex
1613
1463
  });
1614
- if (state.enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0 && state.disableScrollJumpsFrom === void 0) {
1464
+ if (enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0) {
1615
1465
  state.scrollForNextCalculateItemsInView = nextTop !== void 0 && nextBottom !== void 0 ? {
1616
1466
  top: nextTop,
1617
1467
  bottom: nextBottom
1618
1468
  } : void 0;
1619
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
+ }
1620
1480
  if (startBuffered !== null && endBuffered !== null) {
1621
- let numContainers = prevNumContainers;
1481
+ let numContainers2 = prevNumContainers;
1622
1482
  const needNewContainers = [];
1623
- const isContained = (i) => {
1624
- const id = getId(i);
1625
- for (let j = 0; j < numContainers; j++) {
1626
- const key = peek$(ctx, `containerItemKey${j}`);
1627
- if (key === id) {
1628
- return true;
1629
- }
1630
- }
1631
- };
1632
1483
  for (let i = startBuffered; i <= endBuffered; i++) {
1633
- if (!isContained(i)) {
1484
+ const id = (_f = idCache.get(i)) != null ? _f : getId(i);
1485
+ if (!containerItemKeys.has(id)) {
1634
1486
  needNewContainers.push(i);
1635
1487
  }
1636
1488
  }
@@ -1638,75 +1490,79 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1638
1490
  const availableContainers = findAvailableContainers(
1639
1491
  needNewContainers.length,
1640
1492
  startBuffered,
1641
- endBuffered
1493
+ endBuffered,
1494
+ pendingRemoval
1642
1495
  );
1643
1496
  for (let idx = 0; idx < needNewContainers.length; idx++) {
1644
1497
  const i = needNewContainers[idx];
1645
1498
  const containerIndex = availableContainers[idx];
1646
- const id = getId(i);
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
+ }
1647
1504
  set$(ctx, `containerItemKey${containerIndex}`, id);
1648
1505
  set$(ctx, `containerItemData${containerIndex}`, data[i]);
1649
- if (containerIndex >= numContainers) {
1650
- numContainers = containerIndex + 1;
1506
+ containerItemKeys.add(id);
1507
+ if (containerIndex >= numContainers2) {
1508
+ numContainers2 = containerIndex + 1;
1651
1509
  }
1652
1510
  }
1653
- if (numContainers !== prevNumContainers) {
1654
- set$(ctx, "numContainers", numContainers);
1655
- if (numContainers > peek$(ctx, "numContainersPooled")) {
1656
- set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
1511
+ if (numContainers2 !== prevNumContainers) {
1512
+ set$(ctx, "numContainers", numContainers2);
1513
+ if (numContainers2 > peek$(ctx, "numContainersPooled")) {
1514
+ set$(ctx, "numContainersPooled", Math.ceil(numContainers2 * 1.5));
1657
1515
  }
1658
1516
  }
1659
1517
  }
1660
- for (let i = 0; i < numContainers; i++) {
1518
+ for (let i = 0; i < numContainers2; i++) {
1661
1519
  const itemKey = peek$(ctx, `containerItemKey${i}`);
1662
- const itemIndex = state.indexByKey.get(itemKey);
1663
- const item = data[itemIndex];
1664
- if (item !== void 0) {
1665
- const id = getId(itemIndex);
1666
- const position = positions.get(id);
1667
- if (position === void 0) {
1668
- set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1669
- } else {
1670
- const pos = {
1671
- type: "top",
1672
- relativeCoordinate: positions.get(id),
1673
- top: positions.get(id)
1674
- };
1675
- const column2 = columns.get(id) || 1;
1676
- if (maintainVisibleContentPosition && itemIndex < anchorElementIndex) {
1677
- const currentRow = Math.floor(itemIndex / numColumns);
1678
- const rowHeight = getRowHeight(currentRow);
1679
- const elementHeight = getItemSize(id, itemIndex, data[i]);
1680
- const diff = rowHeight - elementHeight;
1681
- pos.relativeCoordinate = pos.top + getRowHeight(currentRow) - diff;
1682
- pos.type = "bottom";
1683
- }
1684
- const prevPos = peek$(ctx, `containerPosition${i}`);
1685
- const prevColumn = peek$(ctx, `containerColumn${i}`);
1686
- const prevData = peek$(ctx, `containerItemData${i}`);
1687
- if (!prevPos || pos.relativeCoordinate > POSITION_OUT_OF_VIEW && pos.top !== prevPos.top) {
1688
- set$(ctx, `containerPosition${i}`, pos);
1689
- }
1690
- if (column2 >= 0 && column2 !== prevColumn) {
1691
- set$(ctx, `containerColumn${i}`, column2);
1692
- }
1693
- if (prevData !== item) {
1694
- set$(ctx, `containerItemData${i}`, data[itemIndex]);
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
+ }
1695
1551
  }
1696
1552
  }
1697
1553
  }
1698
1554
  }
1699
1555
  }
1700
- if (!state.queuedInitialLayout && endBuffered !== null) {
1556
+ if (!queuedInitialLayout && endBuffered !== null) {
1701
1557
  if (checkAllSizesKnown()) {
1702
1558
  setDidLayout();
1703
1559
  }
1704
1560
  }
1705
- if (state.viewabilityConfigCallbackPairs) {
1561
+ if (viewabilityConfigCallbackPairs) {
1706
1562
  updateViewableItems(
1707
1563
  state,
1708
1564
  ctx,
1709
- state.viewabilityConfigCallbackPairs,
1565
+ viewabilityConfigCallbackPairs,
1710
1566
  getId,
1711
1567
  scrollLength,
1712
1568
  startNoBuffer,
@@ -1721,10 +1577,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1721
1577
  if (stylePaddingTop !== void 0) {
1722
1578
  const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1723
1579
  if (stylePaddingTop < prevStylePaddingTop) {
1724
- const prevTotalSize = peek$(ctx, "totalSizeWithScrollAdjust") || 0;
1725
- set$(ctx, "totalSizeWithScrollAdjust", prevTotalSize + prevStylePaddingTop);
1580
+ const prevTotalSize = peek$(ctx, "totalSize") || 0;
1581
+ set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1726
1582
  setTimeout(() => {
1727
- set$(ctx, "totalSizeWithScrollAdjust", prevTotalSize);
1583
+ set$(ctx, "totalSize", prevTotalSize);
1728
1584
  }, 16);
1729
1585
  }
1730
1586
  set$(ctx, "stylePaddingTop", stylePaddingTop);
@@ -1732,11 +1588,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1732
1588
  if (alignItemsPaddingTop !== void 0) {
1733
1589
  set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1734
1590
  }
1735
- set$(
1736
- ctx,
1737
- "paddingTop",
1738
- (stylePaddingTop != null ? stylePaddingTop : peek$(ctx, "stylePaddingTop")) + (alignItemsPaddingTop != null ? alignItemsPaddingTop : peek$(ctx, "alignItemsPaddingTop"))
1739
- );
1740
1591
  };
1741
1592
  const updateAlignItemsPaddingTop = () => {
1742
1593
  if (alignItemsAtEnd) {
@@ -1753,27 +1604,25 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1753
1604
  const state = refState.current;
1754
1605
  if (state) {
1755
1606
  state.scrollingTo = void 0;
1756
- state.scrollAdjustHandler.setDisableAdjust(false);
1757
1607
  state.scrollHistory.length = 0;
1758
- calculateItemsInView();
1759
1608
  }
1760
1609
  };
1761
1610
  const scrollTo = (params = {}) => {
1762
- var _a;
1611
+ var _a2;
1763
1612
  const state = refState.current;
1764
1613
  const { animated } = params;
1765
1614
  const offset = calculateOffsetWithOffsetPosition(params.offset, params);
1766
- state.scrollAdjustHandler.setDisableAdjust(true);
1767
1615
  state.scrollHistory.length = 0;
1768
1616
  state.scrollingTo = params;
1769
1617
  state.scrollPending = offset;
1770
- (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
1618
+ (_a2 = refScroller.current) == null ? void 0 : _a2.scrollTo({
1771
1619
  x: horizontal ? offset : 0,
1772
1620
  y: horizontal ? 0 : offset,
1773
1621
  animated: !!animated
1774
1622
  });
1775
1623
  if (!animated) {
1776
- requestAnimationFrame(finishScrollTo);
1624
+ refState.current.scroll = offset;
1625
+ setTimeout(finishScrollTo, 100);
1777
1626
  }
1778
1627
  };
1779
1628
  const doMaintainScrollAtEnd = (animated) => {
@@ -1783,11 +1632,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1783
1632
  if (paddingTop > 0) {
1784
1633
  state.scroll = 0;
1785
1634
  }
1786
- state.disableScrollJumpsFrom = void 0;
1787
1635
  requestAnimationFrame(() => {
1788
- var _a;
1636
+ var _a2;
1789
1637
  state.maintainingScrollAtEnd = true;
1790
- (_a = refScroller.current) == null ? void 0 : _a.scrollToEnd({
1638
+ (_a2 = refScroller.current) == null ? void 0 : _a2.scrollToEnd({
1791
1639
  animated
1792
1640
  });
1793
1641
  setTimeout(
@@ -1836,8 +1684,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1836
1684
  refState.current.isEndReached,
1837
1685
  refState.current.endReachedBlockedByTimer,
1838
1686
  (distance) => {
1839
- var _a, _b;
1840
- return (_b = (_a = callbacks.current).onEndReached) == null ? void 0 : _b.call(_a, { distanceFromEnd: distance });
1687
+ var _a2, _b;
1688
+ return (_b = (_a2 = callbacks.current).onEndReached) == null ? void 0 : _b.call(_a2, { distanceFromEnd: distance });
1841
1689
  },
1842
1690
  (block) => {
1843
1691
  refState.current.endReachedBlockedByTimer = block;
@@ -1859,8 +1707,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1859
1707
  refState.current.isStartReached,
1860
1708
  refState.current.startReachedBlockedByTimer,
1861
1709
  (distance) => {
1862
- var _a, _b;
1863
- return (_b = (_a = callbacks.current).onStartReached) == null ? void 0 : _b.call(_a, { distanceFromStart: distance });
1710
+ var _a2, _b;
1711
+ return (_b = (_a2 = callbacks.current).onStartReached) == null ? void 0 : _b.call(_a2, { distanceFromStart: distance });
1864
1712
  },
1865
1713
  (block) => {
1866
1714
  refState.current.startReachedBlockedByTimer = block;
@@ -1872,30 +1720,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1872
1720
  if (state) {
1873
1721
  state.data = dataProp;
1874
1722
  if (!isFirst2) {
1875
- const totalSizeBefore = state.previousTotalSize;
1876
- const totalSizeAfter = state.totalSize;
1877
- const scrollDiff = state.scroll - state.scrollPrev;
1878
- const sizeDiff = totalSizeAfter - totalSizeBefore;
1879
- if (Math.abs(scrollDiff - sizeDiff) < 10) {
1880
- disableScrollJumps(1e3);
1881
- }
1882
- const numContainers = peek$(ctx, "numContainers");
1883
- for (let i = 0; i < numContainers; i++) {
1884
- const itemKey = peek$(ctx, `containerItemKey${i}`);
1885
- if (!keyExtractorProp || itemKey && state.indexByKey.get(itemKey) === void 0) {
1886
- set$(ctx, `containerItemKey${i}`, void 0);
1887
- set$(ctx, `containerItemData${i}`, void 0);
1888
- set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1889
- set$(ctx, `containerColumn${i}`, -1);
1890
- }
1891
- }
1892
- if (!keyExtractorProp) {
1893
- state.positions.clear();
1894
- }
1895
- calculateItemsInView(
1896
- /*isReset*/
1897
- true
1898
- );
1723
+ calculateItemsInView({ dataChanged: true, doMVCP: true });
1899
1724
  const didMaintainScrollAtEnd = doMaintainScrollAtEnd(false);
1900
1725
  if (!didMaintainScrollAtEnd && dataProp.length > state.data.length) {
1901
1726
  state.isEndReached = false;
@@ -1907,106 +1732,40 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
1907
1732
  }
1908
1733
  }
1909
1734
  };
1910
- const calcTotalSizesAndPositions = ({ forgetPositions = false }) => {
1911
- var _a, _b;
1912
- const state = refState.current;
1913
- let totalSize = 0;
1914
- let totalSizeBelowIndex = 0;
1915
- const indexByKey = /* @__PURE__ */ new Map();
1916
- const newPositions = /* @__PURE__ */ new Map();
1917
- let column = 1;
1918
- let maxSizeInRow = 0;
1919
- const numColumns = (_a = peek$(ctx, "numColumns")) != null ? _a : numColumnsProp;
1920
- if (!state) {
1921
- return;
1922
- }
1923
- for (let i = 0; i < dataProp.length; i++) {
1924
- const key = getId(i);
1925
- if (__DEV__) {
1926
- if (indexByKey.has(key)) {
1927
- console.error(
1928
- `[legend-list] Error: Detected overlapping key (${key}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
1929
- );
1930
- }
1931
- }
1932
- indexByKey.set(key, i);
1933
- if (!forgetPositions && state.positions.get(key) != null && state.indexByKey.get(key) === i) {
1934
- newPositions.set(key, state.positions.get(key));
1935
- }
1936
- }
1937
- state.indexByKey = indexByKey;
1938
- state.positions = newPositions;
1939
- if (!forgetPositions && !isFirst) {
1940
- if (maintainVisibleContentPosition) {
1941
- if (state.anchorElement == null || indexByKey.get(state.anchorElement.id) == null) {
1942
- if (dataProp.length) {
1943
- const newAnchorElement = {
1944
- coordinate: 0,
1945
- id: getId(0)
1946
- };
1947
- state.anchorElement = newAnchorElement;
1948
- (_b = state.belowAnchorElementPositions) == null ? void 0 : _b.clear();
1949
- scrollTo({ offset: 0, animated: false });
1950
- setTimeout(() => {
1951
- calculateItemsInView(
1952
- /*reset*/
1953
- true
1954
- );
1955
- }, 0);
1956
- } else {
1957
- state.startBufferedId = void 0;
1958
- }
1959
- }
1960
- } else {
1961
- if (state.startBufferedId != null && newPositions.get(state.startBufferedId) == null) {
1962
- if (dataProp.length) {
1963
- state.startBufferedId = getId(0);
1964
- } else {
1965
- state.startBufferedId = void 0;
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);
1966
1748
  }
1967
- scrollTo({ offset: 0, animated: false });
1968
- setTimeout(() => {
1969
- calculateItemsInView(
1970
- /*reset*/
1971
- true
1972
- );
1973
- }, 0);
1974
1749
  }
1975
1750
  }
1976
1751
  }
1977
- const anchorElementIndex = getAnchorElementIndex();
1978
- for (let i = 0; i < dataProp.length; i++) {
1979
- const key = getId(i);
1980
- const size = getItemSize(key, i, dataProp[i]);
1981
- maxSizeInRow = Math.max(maxSizeInRow, size);
1982
- column++;
1983
- if (column > numColumns) {
1984
- if (maintainVisibleContentPosition && anchorElementIndex !== void 0 && i < anchorElementIndex) {
1985
- totalSizeBelowIndex += maxSizeInRow;
1986
- }
1987
- totalSize += maxSizeInRow;
1988
- column = 1;
1989
- maxSizeInRow = 0;
1990
- }
1991
- }
1992
- if (maxSizeInRow > 0) {
1993
- totalSize += maxSizeInRow;
1994
- }
1995
- state.ignoreScrollFromCalcTotal = true;
1996
- requestAnimationFrame(() => {
1997
- state.ignoreScrollFromCalcTotal = false;
1998
- });
1999
- addTotalSize(null, totalSize, totalSizeBelowIndex);
2000
1752
  };
2001
- const findAvailableContainers = (numNeeded, startBuffered, endBuffered) => {
1753
+ const findAvailableContainers = (numNeeded, startBuffered, endBuffered, pendingRemoval) => {
2002
1754
  const state = refState.current;
2003
1755
  const numContainers = peek$(ctx, "numContainers");
2004
- if (numNeeded === 0) return [];
2005
1756
  const result = [];
2006
1757
  const availableContainers = [];
2007
1758
  for (let u = 0; u < numContainers; u++) {
2008
1759
  const key = peek$(ctx, `containerItemKey${u}`);
2009
- if (key === void 0) {
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) {
2010
1769
  result.push(u);
2011
1770
  if (result.length >= numNeeded) {
2012
1771
  return result;
@@ -2072,14 +1831,21 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2072
1831
  refState.current.stylePaddingBottom = stylePaddingBottomState;
2073
1832
  const paddingDiff = stylePaddingTopState - prevPaddingTop;
2074
1833
  if (paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") {
2075
- queueMicrotask(() => {
2076
- scrollTo({ offset: refState.current.scrollPending + paddingDiff, animated: false });
2077
- });
1834
+ requestAdjust(paddingDiff);
2078
1835
  }
2079
1836
  };
2080
1837
  if (isFirst) {
2081
1838
  initalizeStateVars();
1839
+ updateAllPositions();
2082
1840
  }
1841
+ const initialContentOffset = useMemo(() => {
1842
+ const initialContentOffset2 = initialScrollOffset || calculateOffsetForIndex(initialScrollIndex);
1843
+ refState.current.isStartReached = initialContentOffset2 < refState.current.scrollLength * onStartReachedThreshold;
1844
+ if (initialContentOffset2 > 0) {
1845
+ scrollTo({ offset: initialContentOffset2, animated: false, index: initialScrollIndex });
1846
+ }
1847
+ return initialContentOffset2;
1848
+ }, [renderNum]);
2083
1849
  if (isFirst || didDataChange || numColumnsProp !== peek$(ctx, "numColumns")) {
2084
1850
  refState.current.lastBatchingAction = Date.now();
2085
1851
  if (!keyExtractorProp && !isFirst && didDataChange) {
@@ -2090,22 +1856,38 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2090
1856
  refState.current.sizes.clear();
2091
1857
  refState.current.positions.clear();
2092
1858
  }
2093
- refState.current.previousTotalSize = peek$(ctx, "totalSize");
2094
- calcTotalSizesAndPositions({ forgetPositions: false });
2095
1859
  }
2096
- useEffect(() => {
2097
- if (initialScroll && ListHeaderComponent) {
2098
- const dispose = listen$(ctx, "headerSize", (size) => {
2099
- if (size > 0) {
2100
- scrollToIndex({ ...initialScroll, animated: false });
2101
- dispose == null ? void 0 : dispose();
1860
+ useLayoutEffect(() => {
1861
+ var _a2, _b;
1862
+ if (IsNewArchitecture) {
1863
+ const measured = (_b = (_a2 = refScroller.current) == null ? void 0 : _a2.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a2);
1864
+ if (measured) {
1865
+ const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
1866
+ if (size) {
1867
+ handleLayout(measured);
2102
1868
  }
2103
- });
2104
- setTimeout(dispose, 0);
2105
- return dispose;
1869
+ }
1870
+ }
1871
+ if (!isFirst) {
1872
+ calculateItemsInView({ doMVCP: true });
1873
+ }
1874
+ }, [dataProp]);
1875
+ const onLayoutHeader = useCallback((rect, fromLayoutEffect) => {
1876
+ const size = rect[horizontal ? "width" : "height"];
1877
+ set$(ctx, "headerSize", size);
1878
+ if (initialScroll) {
1879
+ if (IsNewArchitecture && Platform.OS !== "android") {
1880
+ if (fromLayoutEffect) {
1881
+ setRenderNum((v) => v + 1);
1882
+ }
1883
+ } else {
1884
+ setTimeout(() => {
1885
+ scrollToIndex({ ...initialScroll, animated: false });
1886
+ }, 17);
1887
+ }
2106
1888
  }
2107
1889
  }, []);
2108
- useEffect(() => {
1890
+ useLayoutEffect(() => {
2109
1891
  const didAllocateContainers = doInitialAllocateContainers();
2110
1892
  if (!didAllocateContainers) {
2111
1893
  checkResetContainers(
@@ -2114,11 +1896,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2114
1896
  );
2115
1897
  }
2116
1898
  }, [dataProp, numColumnsProp]);
2117
- useEffect(() => {
1899
+ useLayoutEffect(() => {
2118
1900
  set$(ctx, "extraData", extraData);
2119
1901
  }, [extraData]);
2120
1902
  refState.current.renderItem = renderItem2;
2121
- useEffect(initalizeStateVars, [
1903
+ useLayoutEffect(initalizeStateVars, [
2122
1904
  memoizedLastItemKeys.join(","),
2123
1905
  numColumnsProp,
2124
1906
  stylePaddingTopState,
@@ -2151,25 +1933,24 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2151
1933
  const { scrollLength, data } = state;
2152
1934
  if (scrollLength > 0 && data.length > 0 && !peek$(ctx, "numContainers")) {
2153
1935
  const averageItemSize = getEstimatedItemSize ? getEstimatedItemSize(0, data[0]) : estimatedItemSize;
2154
- const numContainers = Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) * numColumnsProp;
1936
+ const Extra = 1.5;
1937
+ const numContainers = Math.ceil(
1938
+ (scrollLength + scrollBuffer * 2) / averageItemSize * numColumnsProp * Extra
1939
+ );
2155
1940
  for (let i = 0; i < numContainers; i++) {
2156
- set$(ctx, `containerPosition${i}`, ANCHORED_POSITION_OUT_OF_VIEW);
1941
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2157
1942
  set$(ctx, `containerColumn${i}`, -1);
2158
1943
  }
2159
1944
  set$(ctx, "numContainers", numContainers);
2160
1945
  set$(ctx, "numContainersPooled", numContainers * initialContainerPoolRatio);
2161
- if (initialScroll) {
2162
- requestAnimationFrame(() => {
2163
- calculateItemsInView(
2164
- /*isReset*/
2165
- true
2166
- );
2167
- });
2168
- } else {
2169
- calculateItemsInView(
2170
- /*isReset*/
2171
- true
2172
- );
1946
+ if (!IsNewArchitecture) {
1947
+ if (initialScroll) {
1948
+ requestAnimationFrame(() => {
1949
+ calculateItemsInView();
1950
+ });
1951
+ } else {
1952
+ calculateItemsInView();
1953
+ }
2173
1954
  }
2174
1955
  return true;
2175
1956
  }
@@ -2184,131 +1965,137 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2184
1965
  state.viewabilityConfigCallbackPairs = viewability;
2185
1966
  state.enableScrollForNextCalculateItemsInView = !viewability;
2186
1967
  }, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
2187
- useInit(() => {
2188
- doInitialAllocateContainers();
2189
- });
2190
- const updateItemSize = useCallback(
2191
- (itemKey, sizeObj, fromFixGaps) => {
1968
+ if (!IsNewArchitecture) {
1969
+ useInit(() => {
1970
+ doInitialAllocateContainers();
1971
+ });
1972
+ }
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;
2192
1997
  const state = refState.current;
2193
- const {
2194
- sizes,
2195
- indexByKey,
2196
- sizesKnown,
2197
- data,
2198
- rowHeights,
2199
- startBuffered,
2200
- endBuffered,
2201
- averageSizes,
2202
- queuedInitialLayout
2203
- } = state;
2204
- if (!data) {
2205
- return;
2206
- }
2207
- const index = indexByKey.get(itemKey);
2208
- const numColumns = peek$(ctx, "numColumns");
2209
- state.scrollForNextCalculateItemsInView = void 0;
2210
- state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, index) : index;
2211
- const prevSize = getItemSize(itemKey, index, data);
2212
- const prevSizeKnown = sizesKnown.get(itemKey);
2213
- let needsCalculate = false;
2214
- let needsUpdateContainersDidLayout = false;
2215
- const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2216
- sizesKnown.set(itemKey, size);
2217
- const itemType = "";
2218
- let averages = averageSizes[itemType];
2219
- if (!averages) {
2220
- averages = averageSizes[itemType] = {
2221
- num: 0,
2222
- avg: 0
2223
- };
2224
- }
2225
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2226
- averages.num++;
2227
- if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2228
- let diff;
2229
- needsCalculate = true;
2230
- if (numColumns > 1) {
2231
- const rowNumber = Math.floor(index / numColumnsProp);
2232
- const prevSizeInRow = getRowHeight(rowNumber);
2233
- sizes.set(itemKey, size);
2234
- rowHeights.delete(rowNumber);
2235
- const sizeInRow = getRowHeight(rowNumber);
2236
- diff = sizeInRow - prevSizeInRow;
2237
- } else {
2238
- sizes.set(itemKey, size);
2239
- diff = size - prevSize;
2240
- }
2241
- if (__DEV__ && suggestEstimatedItemSize) {
2242
- if (state.timeoutSizeMessage) {
2243
- clearTimeout(state.timeoutSizeMessage);
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);
2244
2012
  }
2245
- state.timeoutSizeMessage = setTimeout(() => {
2246
- state.timeoutSizeMessage = void 0;
2247
- const num = sizesKnown.size;
2248
- const avg = state.averageSizes[""].avg;
2249
- console.warn(
2250
- `[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
2251
- );
2252
- }, 1e3);
2253
- }
2254
- state.scrollForNextCalculateItemsInView = void 0;
2255
- addTotalSize(itemKey, diff, 0);
2256
- if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
2257
- doMaintainScrollAtEnd(false);
2258
- }
2259
- if (onItemSizeChanged) {
2260
- onItemSizeChanged({
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({
2261
2032
  size,
2262
- previous: prevSize,
2033
+ previous: size - diff,
2263
2034
  index,
2264
2035
  itemKey,
2265
- itemData: data[index]
2036
+ itemData: state.data[index]
2266
2037
  });
2267
2038
  }
2268
2039
  }
2269
- if (!queuedInitialLayout && checkAllSizesKnown()) {
2270
- needsUpdateContainersDidLayout = true;
2040
+ if (minIndexSizeChanged !== void 0) {
2041
+ state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
2271
2042
  }
2272
- let isInView = index >= startBuffered && index <= endBuffered;
2273
- if (!isInView) {
2274
- const numContainers = ctx.values.get("numContainers");
2275
- for (let i = 0; i < numContainers; i++) {
2276
- if (peek$(ctx, `containerItemKey${i}`) === itemKey) {
2277
- isInView = true;
2278
- break;
2279
- }
2280
- }
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);
2281
2054
  }
2282
- if (needsUpdateContainersDidLayout || !fromFixGaps && needsCalculate && (isInView || !queuedInitialLayout)) {
2283
- const scrollVelocity = state.scrollVelocity;
2284
- let didCalculate = false;
2285
- if ((Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1 || state.scrollingTo !== void 0) && (!waitForInitialLayout || needsUpdateContainersDidLayout || queuedInitialLayout)) {
2286
- if (Date.now() - state.lastBatchingAction < 500) {
2287
- if (!state.queuedCalculateItemsInView) {
2288
- state.queuedCalculateItemsInView = requestAnimationFrame(() => {
2289
- state.queuedCalculateItemsInView = void 0;
2290
- calculateItemsInView();
2291
- });
2292
- }
2293
- } else {
2294
- calculateItemsInView();
2295
- didCalculate = true;
2296
- }
2297
- }
2298
- if (!didCalculate && !needsUpdateContainersDidLayout && IsNewArchitecture) {
2299
- fixGaps();
2300
- }
2055
+ const cur = peek$(ctx, "otherAxisSize");
2056
+ if (!cur || maxOtherAxisSize > cur) {
2057
+ set$(ctx, "otherAxisSize", maxOtherAxisSize);
2301
2058
  }
2302
- if (state.needsOtherAxisSize) {
2303
- const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
2304
- const cur = peek$(ctx, "otherAxisSize");
2305
- if (!cur || otherAxisSize > cur) {
2306
- set$(ctx, "otherAxisSize", otherAxisSize);
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);
2307
2067
  }
2308
2068
  }
2309
2069
  },
2310
2070
  []
2311
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
+ }, []);
2312
2099
  const handleLayout = useCallback((size) => {
2313
2100
  const scrollLength = size[horizontal ? "width" : "height"];
2314
2101
  const otherAxisSize = size[horizontal ? "height" : "width"];
@@ -2320,16 +2107,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2320
2107
  state.lastBatchingAction = Date.now();
2321
2108
  state.scrollForNextCalculateItemsInView = void 0;
2322
2109
  doInitialAllocateContainers();
2323
- doMaintainScrollAtEnd(false);
2324
- updateAlignItemsPaddingTop();
2325
- checkAtBottom();
2326
- checkAtTop();
2327
2110
  if (didChange) {
2328
- calculateItemsInView();
2111
+ calculateItemsInView({ doMVCP: true });
2329
2112
  }
2330
2113
  if (didChange || otherAxisSize !== prevOtherAxisSize) {
2331
2114
  set$(ctx, "scrollSize", { width: size.width, height: size.height });
2332
2115
  }
2116
+ doMaintainScrollAtEnd(false);
2117
+ updateAlignItemsPaddingTop();
2118
+ checkAtBottom();
2119
+ checkAtTop();
2333
2120
  if (refState.current) {
2334
2121
  refState.current.needsOtherAxisSize = otherAxisSize - (stylePaddingTopState || 0) < 10;
2335
2122
  }
@@ -2339,40 +2126,32 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2339
2126
  `List ${horizontal ? "width" : "height"} is 0. You may need to set a style or \`flex: \` for the list, because children are absolutely positioned.`
2340
2127
  );
2341
2128
  }
2129
+ calculateItemsInView({ doMVCP: true });
2130
+ setCanRender(true);
2342
2131
  }, []);
2343
2132
  const onLayout = useCallback((event) => {
2344
2133
  const layout = event.nativeEvent.layout;
2345
2134
  handleLayout(layout);
2346
- layout[horizontal ? "width" : "height"];
2347
- layout[horizontal ? "height" : "width"];
2348
2135
  if (onLayoutProp) {
2349
2136
  onLayoutProp(event);
2350
2137
  }
2351
2138
  }, []);
2352
- if (IsNewArchitecture) {
2353
- useLayoutEffect(() => {
2354
- var _a, _b;
2355
- const measured = (_b = (_a = refScroller.current) == null ? void 0 : _a.unstable_getBoundingClientRect) == null ? void 0 : _b.call(_a);
2356
- if (measured) {
2357
- const size = Math.floor(measured[horizontal ? "width" : "height"] * 8) / 8;
2358
- if (size) {
2359
- handleLayout(measured);
2360
- }
2361
- }
2362
- }, []);
2363
- }
2364
2139
  const handleScroll = useCallback(
2365
2140
  (event) => {
2366
- var _a, _b, _c, _d;
2367
- 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) {
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) {
2368
2143
  return;
2369
2144
  }
2370
2145
  const state = refState.current;
2371
2146
  const newScroll = event.nativeEvent.contentOffset[horizontal ? "x" : "y"];
2372
- state.scrollPending = newScroll;
2373
- if (state.ignoreScrollFromCalcTotal && newScroll !== 0) {
2374
- return;
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
+ }
2375
2153
  }
2154
+ state.scrollPending = newScroll;
2376
2155
  updateScroll(newScroll);
2377
2156
  (_d = state.onScroll) == null ? void 0 : _d.call(state, event);
2378
2157
  },
@@ -2381,53 +2160,19 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2381
2160
  const updateScroll = useCallback((newScroll) => {
2382
2161
  const state = refState.current;
2383
2162
  const scrollingTo = state.scrollingTo;
2384
- if (scrollingTo !== void 0 && Math.abs(newScroll - scrollingTo.offset) < 10) {
2385
- finishScrollTo();
2386
- }
2387
- if (state.disableScrollJumpsFrom !== void 0) {
2388
- const scrollMinusAdjust = newScroll - state.scrollAdjustHandler.getAppliedAdjust();
2389
- if (Math.abs(scrollMinusAdjust - state.disableScrollJumpsFrom) > 200) {
2390
- return;
2391
- }
2392
- state.disableScrollJumpsFrom = void 0;
2393
- }
2394
2163
  state.hasScrolled = true;
2395
2164
  state.lastBatchingAction = Date.now();
2396
2165
  const currentTime = performance.now();
2397
- if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === initialContentOffset)) {
2166
+ if (scrollingTo === void 0 && !(state.scrollHistory.length === 0 && newScroll === state.scroll)) {
2398
2167
  state.scrollHistory.push({ scroll: newScroll, time: currentTime });
2399
2168
  }
2400
2169
  if (state.scrollHistory.length > 5) {
2401
2170
  state.scrollHistory.shift();
2402
2171
  }
2403
- if (state.scrollTimer !== void 0) {
2404
- clearTimeout(state.scrollTimer);
2405
- }
2406
- state.scrollTimer = setTimeout(() => {
2407
- state.scrollVelocity = 0;
2408
- }, 500);
2409
- let velocity = 0;
2410
- if (state.scrollHistory.length >= 2) {
2411
- const newest = state.scrollHistory[state.scrollHistory.length - 1];
2412
- let oldest;
2413
- for (let i = 0; i < state.scrollHistory.length - 1; i++) {
2414
- const entry = state.scrollHistory[i];
2415
- if (newest.time - entry.time <= 100) {
2416
- oldest = entry;
2417
- break;
2418
- }
2419
- }
2420
- if (oldest) {
2421
- const scrollDiff = newest.scroll - oldest.scroll;
2422
- const timeDiff = newest.time - oldest.time;
2423
- velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
2424
- }
2425
- }
2426
2172
  state.scrollPrev = state.scroll;
2427
2173
  state.scrollPrevTime = state.scrollTime;
2428
2174
  state.scroll = newScroll;
2429
2175
  state.scrollTime = currentTime;
2430
- state.scrollVelocity = velocity;
2431
2176
  calculateItemsInView();
2432
2177
  checkAtBottom();
2433
2178
  checkAtTop();
@@ -2493,8 +2238,17 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2493
2238
  if (index !== -1) {
2494
2239
  const paddingBottom = stylePaddingBottom || 0;
2495
2240
  const footerSize = peek$(ctx, "footerSize") || 0;
2496
- scrollToIndex({ index, viewPosition: 1, viewOffset: -paddingBottom - footerSize, ...options });
2241
+ scrollToIndex({
2242
+ index,
2243
+ viewPosition: 1,
2244
+ viewOffset: -paddingBottom - footerSize,
2245
+ ...options
2246
+ });
2497
2247
  }
2248
+ },
2249
+ setVisibleContentAnchorOffset: (value) => {
2250
+ const val = typeof value === "function" ? value(peek$(ctx, "scrollAdjustUserOffset") || 0) : value;
2251
+ set$(ctx, "scrollAdjustUserOffset", val);
2498
2252
  }
2499
2253
  };
2500
2254
  },
@@ -2502,14 +2256,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2502
2256
  );
2503
2257
  if (Platform.OS === "web") {
2504
2258
  useEffect(() => {
2505
- var _a;
2506
2259
  if (initialContentOffset) {
2507
- (_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler.setDisableAdjust(true);
2508
2260
  scrollTo({ offset: initialContentOffset, animated: false });
2509
- setTimeout(() => {
2510
- var _a2;
2511
- (_a2 = refState.current) == null ? void 0 : _a2.scrollAdjustHandler.setDisableAdjust(false);
2512
- }, 0);
2513
2261
  }
2514
2262
  }, []);
2515
2263
  }
@@ -2517,6 +2265,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2517
2265
  ListComponent,
2518
2266
  {
2519
2267
  ...rest,
2268
+ canRender,
2520
2269
  horizontal,
2521
2270
  refScrollView: combinedRef,
2522
2271
  initialContentOffset,
@@ -2524,23 +2273,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2524
2273
  updateItemSize,
2525
2274
  handleScroll,
2526
2275
  onMomentumScrollEnd: (event) => {
2527
- var _a;
2528
- const scrollingTo = (_a = refState.current) == null ? void 0 : _a.scrollingTo;
2529
- if (scrollingTo !== void 0) {
2530
- requestAnimationFrame(() => {
2531
- scrollTo({ ...scrollingTo, animated: false });
2532
- refState.current.scrollingTo = void 0;
2533
- requestAnimationFrame(() => {
2534
- refState.current.scrollAdjustHandler.setDisableAdjust(false);
2535
- });
2536
- });
2537
- }
2538
- const wasPaused = refState.current.scrollAdjustHandler.unPauseAdjust();
2539
- if (wasPaused) {
2540
- refState.current.scrollVelocity = 0;
2541
- refState.current.scrollHistory = [];
2542
- calculateItemsInView();
2543
- }
2276
+ requestAnimationFrame(() => {
2277
+ finishScrollTo();
2278
+ });
2544
2279
  if (onMomentumScrollEnd) {
2545
2280
  onMomentumScrollEnd(event);
2546
2281
  }
@@ -2564,7 +2299,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2564
2299
  }
2565
2300
  ),
2566
2301
  style,
2567
- contentContainerStyle
2302
+ contentContainerStyle,
2303
+ scrollAdjustHandler: (_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler,
2304
+ onLayoutHeader
2568
2305
  }
2569
2306
  ), __DEV__ && ENABLE_DEBUG_VIEW && /* @__PURE__ */ React2.createElement(DebugView, { state: refState.current }));
2570
2307
  });
@@ -2572,7 +2309,7 @@ var typedForwardRef2 = forwardRef;
2572
2309
  var renderItem = ({ item }) => item;
2573
2310
  var LazyLegendList = typedForwardRef2(function LazyLegendList2(props, forwardedRef) {
2574
2311
  const { LegendList: LegendListProp, children, ...rest } = props;
2575
- const LegendListComponent = LegendListProp != null ? LegendListProp : LegendList$1;
2312
+ const LegendListComponent = LegendListProp != null ? LegendListProp : LegendList;
2576
2313
  const data = (isArray(children) ? children : React2.Children.toArray(children)).flat(1);
2577
2314
  return (
2578
2315
  // @ts-expect-error TODO: Fix this type