@legendapp/list 3.3.2 → 3.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/react-native.js CHANGED
@@ -152,11 +152,13 @@ function StateProvider({ children }) {
152
152
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
153
153
  mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
154
154
  mapViewabilityValues: /* @__PURE__ */ new Map(),
155
+ pendingContainerIds: void 0,
155
156
  positionListeners: /* @__PURE__ */ new Map(),
156
157
  scrollAxisGap: 0,
157
158
  state: void 0,
158
159
  values: /* @__PURE__ */ new Map([
159
160
  ["alignItemsAtEndPadding", 0],
161
+ ["containerLayoutEpoch", 0],
160
162
  ["stylePaddingTop", 0],
161
163
  ["headerSize", 0],
162
164
  ["numContainers", 0],
@@ -381,28 +383,49 @@ function useInterval(callback, delay) {
381
383
  }, [delay]);
382
384
  }
383
385
 
384
- // src/components/stickyPositionUtils.ts
385
- function getStickyPushLimit(state, index, itemKey) {
386
- if (!itemKey) {
387
- return void 0;
388
- }
389
- const currentSize = state.sizes.get(itemKey);
390
- if (!(currentSize && currentSize > 0)) {
391
- return void 0;
386
+ // src/constants-platform.native.ts
387
+ var f = global.nativeFabricUIManager;
388
+ var IsNewArchitecture = f !== void 0 && f != null;
389
+
390
+ // src/core/containerItemMetadata.ts
391
+ function createContainerItemMetadata(state, itemIndex, itemData, itemType) {
392
+ return {
393
+ dataChangeEpoch: state.dataChangeEpoch,
394
+ getFixedItemSize: state.props.getFixedItemSize,
395
+ getItemType: state.props.getItemType,
396
+ itemData,
397
+ itemIndex,
398
+ itemType
399
+ };
400
+ }
401
+ function resolveContainerItemMetadata(state, containerId, itemIndex, itemData) {
402
+ var _a3, _b;
403
+ const { getFixedItemSize, getItemType } = state.props;
404
+ const previousMetadata = state.containerItemMetadata.get(containerId);
405
+ let metadata;
406
+ if ((previousMetadata == null ? void 0 : previousMetadata.dataChangeEpoch) === state.dataChangeEpoch && previousMetadata.getItemType === getItemType && previousMetadata.itemData === itemData && previousMetadata.itemIndex === itemIndex) {
407
+ metadata = previousMetadata;
408
+ } else {
409
+ const itemType = getItemType ? (_a3 = getItemType(itemData, itemIndex)) != null ? _a3 : "" : void 0;
410
+ metadata = createContainerItemMetadata(state, itemIndex, itemData, itemType);
411
+ state.containerItemMetadata.set(containerId, metadata);
392
412
  }
393
- const stickyIndexInArray = state.props.stickyHeaderIndicesArr.indexOf(index);
394
- if (stickyIndexInArray === -1) {
395
- return void 0;
413
+ if (metadata.getFixedItemSize !== getFixedItemSize) {
414
+ metadata.didResolveFixedItemSize = false;
415
+ metadata.fixedItemSize = void 0;
416
+ metadata.getFixedItemSize = getFixedItemSize;
396
417
  }
397
- const nextStickyIndex = state.props.stickyHeaderIndicesArr[stickyIndexInArray + 1];
398
- if (nextStickyIndex === void 0) {
399
- return void 0;
418
+ if (getFixedItemSize && !metadata.didResolveFixedItemSize) {
419
+ metadata.fixedItemSize = getFixedItemSize(itemData, itemIndex, (_b = metadata.itemType) != null ? _b : "");
420
+ metadata.didResolveFixedItemSize = true;
400
421
  }
401
- const nextStickyPosition = state.positions[nextStickyIndex];
402
- if (nextStickyPosition === void 0) {
403
- return void 0;
422
+ return metadata;
423
+ }
424
+ function invalidateContainerFixedItemSizes(state) {
425
+ for (const metadata of state.containerItemMetadata.values()) {
426
+ metadata.didResolveFixedItemSize = false;
427
+ metadata.fixedItemSize = void 0;
404
428
  }
405
- return nextStickyPosition - currentSize;
406
429
  }
407
430
 
408
431
  // src/utils/devEnvironment.ts
@@ -419,445 +442,73 @@ var EDGE_POSITION_EPSILON = 1;
419
442
  var ENABLE_DEVMODE = IS_DEV && false;
420
443
  var ENABLE_DEBUG_VIEW = IS_DEV && false;
421
444
 
422
- // src/constants-platform.native.ts
423
- var f = global.nativeFabricUIManager;
424
- var IsNewArchitecture = f !== void 0 && f != null;
425
- var useAnimatedValue = (initialValue) => {
426
- const [animAnimatedValue] = React2.useState(() => new ReactNative.Animated.Value(initialValue));
427
- return animAnimatedValue;
428
- };
429
-
430
- // src/hooks/useValue$.ts
431
- function useValue$(key, params) {
432
- const { getValue } = params || {};
433
- const ctx = useStateContext();
434
- const getNewValue = () => {
435
- var _a3;
436
- return (_a3 = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a3 : 0;
445
+ // src/core/deferredPublicOnScroll.ts
446
+ function withResolvedContentOffset(state, event, resolvedOffset) {
447
+ return {
448
+ ...event,
449
+ nativeEvent: {
450
+ ...event.nativeEvent,
451
+ contentOffset: state.props.horizontal ? { x: resolvedOffset, y: 0 } : { x: 0, y: resolvedOffset }
452
+ }
437
453
  };
438
- const animValue = useAnimatedValue(getNewValue());
439
- React2.useLayoutEffect(() => {
440
- const syncCurrentValue = () => {
441
- animValue.setValue(getNewValue());
442
- };
443
- const unsubscribe = listen$(ctx, key, syncCurrentValue);
444
- syncCurrentValue();
445
- return unsubscribe;
446
- }, [animValue, ctx, key]);
447
- return animValue;
448
454
  }
449
- var typedForwardRef = React2__namespace.forwardRef;
450
- var typedMemo = React2__namespace.memo;
451
- var getComponent = (Component) => {
452
- if (React2__namespace.isValidElement(Component)) {
453
- return Component;
454
- }
455
- if (Component) {
456
- return /* @__PURE__ */ React2__namespace.createElement(Component, null);
457
- }
458
- return null;
459
- };
460
-
461
- // src/components/PositionView.native.tsx
462
- var PositionViewState = typedMemo(function PositionViewState2({
463
- id,
464
- horizontal,
465
- style,
466
- refView,
467
- ...rest
468
- }) {
469
- const [position = POSITION_OUT_OF_VIEW, _itemKey] = useArr$([`containerPosition${id}`, `containerItemKey${id}`]);
470
- return /* @__PURE__ */ React2__namespace.createElement(ReactNative.View, { ref: refView, style: [style, horizontal ? { left: position } : { top: position }], ...rest });
471
- });
472
- var PositionViewAnimated = typedMemo(function PositionViewAnimated2({
473
- id,
474
- horizontal,
475
- style,
476
- refView,
477
- ...rest
478
- }) {
479
- const position$ = useValue$(`containerPosition${id}`, {
480
- getValue: (v) => v != null ? v : POSITION_OUT_OF_VIEW
481
- });
482
- const position = horizontal ? { left: position$ } : { top: position$ };
483
- return /* @__PURE__ */ React2__namespace.createElement(ReactNative.Animated.View, { ref: refView, style: [style, position], ...rest });
484
- });
485
- var PositionViewSticky = typedMemo(function PositionViewSticky2({
486
- id,
487
- horizontal,
488
- style,
489
- refView,
490
- animatedScrollY,
491
- index,
492
- stickyHeaderConfig,
493
- children,
494
- ...rest
495
- }) {
496
- const ctx = useStateContext();
497
- const [
498
- position = POSITION_OUT_OF_VIEW,
499
- alignItemsAtEndPadding = 0,
500
- headerSize = 0,
501
- stylePaddingTop = 0,
502
- itemKey,
503
- _totalSize = 0
504
- ] = useArr$([
505
- `containerPosition${id}`,
506
- "alignItemsAtEndPadding",
507
- "headerSize",
508
- "stylePaddingTop",
509
- `containerItemKey${id}`,
510
- "totalSize"
511
- ]);
512
- const pushLimit = React2__namespace.useMemo(
513
- () => getStickyPushLimit(ctx.state, index, itemKey),
514
- [ctx.state, index, itemKey, _totalSize]
515
- );
516
- const transform = React2__namespace.useMemo(() => {
517
- var _a3;
518
- if (animatedScrollY) {
519
- const stickyConfigOffset = (_a3 = stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset) != null ? _a3 : 0;
520
- const stickyStart = position + headerSize + stylePaddingTop + alignItemsAtEndPadding - stickyConfigOffset;
521
- let nextStickyPosition;
522
- if (pushLimit !== void 0) {
523
- if (pushLimit <= position) {
524
- nextStickyPosition = pushLimit;
525
- } else {
526
- nextStickyPosition = animatedScrollY.interpolate({
527
- extrapolateLeft: "clamp",
528
- extrapolateRight: "clamp",
529
- inputRange: [stickyStart, stickyStart + (pushLimit - position)],
530
- outputRange: [position, pushLimit]
531
- });
532
- }
533
- } else {
534
- nextStickyPosition = animatedScrollY.interpolate({
535
- extrapolateLeft: "clamp",
536
- extrapolateRight: "extend",
537
- inputRange: [stickyStart, stickyStart + 5e3],
538
- outputRange: [position, position + 5e3]
539
- });
540
- }
541
- return horizontal ? [{ translateX: nextStickyPosition }] : [{ translateY: nextStickyPosition }];
542
- }
543
- }, [
544
- alignItemsAtEndPadding,
545
- animatedScrollY,
546
- headerSize,
547
- position,
548
- pushLimit,
549
- stylePaddingTop,
550
- stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset
551
- ]);
552
- const viewStyle = React2__namespace.useMemo(() => [style, { zIndex: index + 1e3 }, { transform }], [style, transform]);
553
- const renderStickyHeaderBackdrop = React2__namespace.useMemo(() => {
554
- if (!(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)) {
555
- return null;
556
- }
557
- return /* @__PURE__ */ React2__namespace.createElement(
558
- ReactNative.View,
559
- {
560
- style: {
561
- inset: 0,
562
- pointerEvents: "none",
563
- position: "absolute"
564
- }
565
- },
566
- getComponent(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)
455
+ function releaseDeferredPublicOnScroll(ctx, resolvedOffset) {
456
+ var _a3, _b, _c, _d;
457
+ const state = ctx.state;
458
+ const deferredEvent = state.deferredPublicOnScrollEvent;
459
+ state.deferredPublicOnScrollEvent = void 0;
460
+ if (deferredEvent) {
461
+ (_d = (_c = state.props).onScroll) == null ? void 0 : _d.call(
462
+ _c,
463
+ withResolvedContentOffset(
464
+ state,
465
+ deferredEvent,
466
+ (_b = (_a3 = resolvedOffset != null ? resolvedOffset : state.scrollPending) != null ? _a3 : state.scroll) != null ? _b : 0
467
+ )
567
468
  );
568
- }, [stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent]);
569
- return /* @__PURE__ */ React2__namespace.createElement(ReactNative.Animated.View, { ref: refView, style: viewStyle, ...rest }, renderStickyHeaderBackdrop, children);
570
- });
571
- var PositionView = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
572
- function useInit(cb) {
573
- React2.useState(() => cb());
469
+ }
574
470
  }
575
471
 
576
- // src/utils/helpers.ts
577
- function isFunction(obj) {
578
- return typeof obj === "function";
579
- }
580
- function isArray(obj) {
581
- return Array.isArray(obj);
582
- }
583
- var warned = /* @__PURE__ */ new Set();
584
- function warnDevOnce(id, text) {
585
- if (IS_DEV && !warned.has(id)) {
586
- warned.add(id);
587
- console.warn(`[legend-list] ${text}`);
588
- }
472
+ // src/core/initialScrollSession.ts
473
+ var INITIAL_SCROLL_MIN_TARGET_OFFSET = 1;
474
+ function hasInitialScrollSessionCompletion(completion) {
475
+ return !!((completion == null ? void 0 : completion.didDispatchNativeScroll) || (completion == null ? void 0 : completion.didRetrySilentInitialScroll) || (completion == null ? void 0 : completion.watchdog));
589
476
  }
590
- function roundSize(size) {
591
- return Math.floor(size * 8) / 8;
477
+ function clearInitialScrollSession(state) {
478
+ state.initialScrollSession = void 0;
479
+ return void 0;
592
480
  }
593
- function isNullOrUndefined(value) {
594
- return value === null || value === void 0;
481
+ function createInitialScrollSession(options) {
482
+ const { bootstrap, completion, kind, previousDataLength } = options;
483
+ return kind === "offset" ? {
484
+ completion,
485
+ kind,
486
+ previousDataLength
487
+ } : {
488
+ bootstrap,
489
+ completion,
490
+ kind,
491
+ previousDataLength
492
+ };
595
493
  }
596
- function getPadding(s, type) {
597
- var _a3, _b, _c;
598
- const axisPadding = type === "Left" || type === "Right" ? s.paddingHorizontal : s.paddingVertical;
599
- return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : axisPadding) != null ? _b : s.padding) != null ? _c : 0;
600
- }
601
- function extractPadding(style, contentContainerStyle, type) {
602
- return getPadding(style, type) + getPadding(contentContainerStyle, type);
603
- }
604
- function findContainerId(ctx, key) {
605
- var _a3, _b;
606
- const directMatch = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.containerItemKeys) == null ? void 0 : _b.get(key);
607
- if (directMatch !== void 0) {
608
- return directMatch;
609
- }
610
- const numContainers = peek$(ctx, "numContainers");
611
- for (let i = 0; i < numContainers; i++) {
612
- const itemKey = peek$(ctx, `containerItemKey${i}`);
613
- if (itemKey === key) {
614
- return i;
615
- }
616
- }
617
- return -1;
618
- }
619
-
620
- // src/state/ContextContainer.ts
621
- var ContextContainer = React2.createContext(null);
622
- var NO_CONTAINER_ID = -1;
623
- function useContextContainer() {
624
- return React2.useContext(ContextContainer);
625
- }
626
- function useContainerItemInfo(containerContext) {
627
- var _a3;
628
- const containerId = (_a3 = containerContext == null ? void 0 : containerContext.containerId) != null ? _a3 : NO_CONTAINER_ID;
629
- const [itemInfo] = useArr$([`containerItemInfo${containerId}`]);
630
- return containerContext ? itemInfo : void 0;
631
- }
632
- function useContainerItemKey(containerContext) {
633
- var _a3;
634
- const containerId = (_a3 = containerContext == null ? void 0 : containerContext.containerId) != null ? _a3 : NO_CONTAINER_ID;
635
- const [itemKey] = useArr$([`containerItemKey${containerId}`]);
636
- return containerContext ? itemKey : void 0;
637
- }
638
- function useAdaptiveRender() {
639
- const [mode] = useArr$(["adaptiveRender"]);
640
- return mode;
641
- }
642
- function useAdaptiveRenderChange(callback) {
643
- const ctx = useStateContext();
644
- const callbackRef = React2.useRef(callback);
645
- callbackRef.current = callback;
646
- React2.useLayoutEffect(() => {
647
- let mode = peek$(ctx, "adaptiveRender");
648
- return listen$(ctx, "adaptiveRender", (nextMode) => {
649
- if (mode !== nextMode) {
650
- mode = nextMode;
651
- callbackRef.current(nextMode);
652
- }
653
- });
654
- }, [ctx]);
655
- }
656
- function useViewability(callback, configId) {
657
- const ctx = useStateContext();
658
- const containerContext = useContextContainer();
659
- useInit(() => {
660
- if (!containerContext) {
661
- return;
662
- }
663
- const { containerId } = containerContext;
664
- const key = containerId + (configId != null ? configId : "");
665
- const value = ctx.mapViewabilityValues.get(key);
666
- if (value) {
667
- callback(value);
668
- }
669
- });
670
- React2.useEffect(() => {
671
- if (!containerContext) {
672
- return;
673
- }
674
- const { containerId } = containerContext;
675
- const key = containerId + (configId != null ? configId : "");
676
- ctx.mapViewabilityCallbacks.set(key, callback);
677
- return () => {
678
- ctx.mapViewabilityCallbacks.delete(key);
679
- };
680
- }, [ctx, callback, configId, containerContext]);
681
- }
682
- function useViewabilityAmount(callback) {
683
- const ctx = useStateContext();
684
- const containerContext = useContextContainer();
685
- useInit(() => {
686
- if (!containerContext) {
687
- return;
688
- }
689
- const { containerId } = containerContext;
690
- const value = ctx.mapViewabilityAmountValues.get(containerId);
691
- if (value) {
692
- callback(value);
693
- }
694
- });
695
- React2.useEffect(() => {
696
- if (!containerContext) {
697
- return;
698
- }
699
- const { containerId } = containerContext;
700
- ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
701
- return () => {
702
- ctx.mapViewabilityAmountCallbacks.delete(containerId);
703
- };
704
- }, [ctx, callback, containerContext]);
705
- }
706
- function useRecyclingEffect(effect) {
707
- const containerContext = useContextContainer();
708
- const itemInfo = useContainerItemInfo(containerContext);
709
- const prevInfo = React2.useRef(void 0);
710
- React2.useEffect(() => {
711
- if (!itemInfo) {
712
- return;
713
- }
714
- let ret;
715
- if (prevInfo.current) {
716
- ret = effect({
717
- index: itemInfo.index,
718
- item: itemInfo.value,
719
- prevIndex: prevInfo.current.index,
720
- prevItem: prevInfo.current.value
721
- });
722
- }
723
- prevInfo.current = itemInfo;
724
- return ret;
725
- }, [effect, itemInfo]);
726
- }
727
- function useRecyclingState(valueOrFun) {
728
- var _a3;
729
- const containerContext = useContextContainer();
730
- const itemInfo = useContainerItemInfo(containerContext);
731
- const computeValue = (info) => {
732
- if (isFunction(valueOrFun)) {
733
- const initializer = valueOrFun;
734
- return info ? initializer({
735
- index: info.index,
736
- item: info.value,
737
- prevIndex: void 0,
738
- prevItem: void 0
739
- }) : initializer();
740
- }
741
- return valueOrFun;
742
- };
743
- const [stateValue, setStateValue] = React2.useState(() => {
744
- return computeValue(itemInfo);
745
- });
746
- const prevItemKeyRef = React2.useRef((_a3 = itemInfo == null ? void 0 : itemInfo.itemKey) != null ? _a3 : null);
747
- if (itemInfo && prevItemKeyRef.current !== itemInfo.itemKey) {
748
- prevItemKeyRef.current = itemInfo.itemKey;
749
- setStateValue(computeValue(itemInfo));
750
- }
751
- const triggerLayout = containerContext == null ? void 0 : containerContext.triggerLayout;
752
- const setState = React2.useCallback(
753
- (newState) => {
754
- if (!triggerLayout) {
755
- return;
756
- }
757
- setStateValue((prevValue) => {
758
- return isFunction(newState) ? newState(prevValue) : newState;
759
- });
760
- triggerLayout();
761
- },
762
- [triggerLayout]
763
- );
764
- return [stateValue, setState];
765
- }
766
- function useIsLastItem() {
767
- const containerContext = useContextContainer();
768
- const itemKey = useContainerItemKey(containerContext);
769
- const isLast = useSelector$("lastItemKeys", (lastItemKeys) => {
770
- if (containerContext && !isNullOrUndefined(itemKey)) {
771
- return (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false;
772
- }
773
- return false;
774
- });
775
- return isLast;
776
- }
777
- function useListScrollSize() {
778
- const [scrollSize] = useArr$(["scrollSize"]);
779
- return scrollSize;
780
- }
781
- var noop = () => {
782
- };
783
- function useSyncLayout() {
784
- const containerContext = useContextContainer();
785
- return IsNewArchitecture && containerContext ? containerContext.triggerLayout : noop;
786
- }
787
-
788
- // src/components/Separator.tsx
789
- function Separator({ ItemSeparatorComponent, leadingItem }) {
790
- const isLastItem = useIsLastItem();
791
- return isLastItem ? null : /* @__PURE__ */ React2__namespace.createElement(ItemSeparatorComponent, { leadingItem });
792
- }
793
-
794
- // src/core/deferredPublicOnScroll.ts
795
- function withResolvedContentOffset(state, event, resolvedOffset) {
796
- return {
797
- ...event,
798
- nativeEvent: {
799
- ...event.nativeEvent,
800
- contentOffset: state.props.horizontal ? { x: resolvedOffset, y: 0 } : { x: 0, y: resolvedOffset }
801
- }
802
- };
803
- }
804
- function releaseDeferredPublicOnScroll(ctx, resolvedOffset) {
805
- var _a3, _b, _c, _d;
806
- const state = ctx.state;
807
- const deferredEvent = state.deferredPublicOnScrollEvent;
808
- state.deferredPublicOnScrollEvent = void 0;
809
- if (deferredEvent) {
810
- (_d = (_c = state.props).onScroll) == null ? void 0 : _d.call(
811
- _c,
812
- withResolvedContentOffset(
813
- state,
814
- deferredEvent,
815
- (_b = (_a3 = resolvedOffset != null ? resolvedOffset : state.scrollPending) != null ? _a3 : state.scroll) != null ? _b : 0
816
- )
817
- );
818
- }
819
- }
820
-
821
- // src/core/initialScrollSession.ts
822
- var INITIAL_SCROLL_MIN_TARGET_OFFSET = 1;
823
- function hasInitialScrollSessionCompletion(completion) {
824
- return !!((completion == null ? void 0 : completion.didDispatchNativeScroll) || (completion == null ? void 0 : completion.didRetrySilentInitialScroll) || (completion == null ? void 0 : completion.watchdog));
825
- }
826
- function clearInitialScrollSession(state) {
827
- state.initialScrollSession = void 0;
828
- return void 0;
829
- }
830
- function createInitialScrollSession(options) {
831
- const { bootstrap, completion, kind, previousDataLength } = options;
832
- return kind === "offset" ? {
833
- completion,
834
- kind,
835
- previousDataLength
836
- } : {
837
- bootstrap,
838
- completion,
839
- kind,
840
- previousDataLength
841
- };
842
- }
843
- function ensureInitialScrollSessionCompletion(state, kind = ((_b) => (_b = ((_a3) => (_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind)()) != null ? _b : "bootstrap")()) {
844
- var _a4, _b2;
845
- if (!state.initialScrollSession) {
846
- state.initialScrollSession = createInitialScrollSession({
847
- completion: {},
848
- kind,
849
- previousDataLength: 0
850
- });
851
- } else if (state.initialScrollSession.kind !== kind) {
852
- state.initialScrollSession = createInitialScrollSession({
853
- bootstrap: state.initialScrollSession.kind === "bootstrap" ? state.initialScrollSession.bootstrap : void 0,
854
- completion: state.initialScrollSession.completion,
855
- kind,
856
- previousDataLength: state.initialScrollSession.previousDataLength
857
- });
858
- }
859
- (_b2 = (_a4 = state.initialScrollSession).completion) != null ? _b2 : _a4.completion = {};
860
- return state.initialScrollSession.completion;
494
+ function ensureInitialScrollSessionCompletion(state, kind = ((_b) => (_b = ((_a3) => (_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind)()) != null ? _b : "bootstrap")()) {
495
+ var _a4, _b2;
496
+ if (!state.initialScrollSession) {
497
+ state.initialScrollSession = createInitialScrollSession({
498
+ completion: {},
499
+ kind,
500
+ previousDataLength: 0
501
+ });
502
+ } else if (state.initialScrollSession.kind !== kind) {
503
+ state.initialScrollSession = createInitialScrollSession({
504
+ bootstrap: state.initialScrollSession.kind === "bootstrap" ? state.initialScrollSession.bootstrap : void 0,
505
+ completion: state.initialScrollSession.completion,
506
+ kind,
507
+ previousDataLength: state.initialScrollSession.previousDataLength
508
+ });
509
+ }
510
+ (_b2 = (_a4 = state.initialScrollSession).completion) != null ? _b2 : _a4.completion = {};
511
+ return state.initialScrollSession.completion;
861
512
  }
862
513
  var initialScrollCompletion = {
863
514
  didDispatchNativeScroll(state) {
@@ -938,7 +589,11 @@ function setInitialScrollSession(state, options = {}) {
938
589
 
939
590
  // src/utils/checkThreshold.ts
940
591
  var HYSTERESIS_MULTIPLIER = 1.3;
941
- var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot, allowReentryOnChange) => {
592
+ function isOutsideThresholdHysteresis(distance, atThreshold, threshold) {
593
+ const absDistance = Math.abs(distance);
594
+ return !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
595
+ }
596
+ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
942
597
  const absDistance = Math.abs(distance);
943
598
  const within = atThreshold || threshold > 0 && absDistance <= threshold;
944
599
  const updateSnapshot = () => {
@@ -957,7 +612,7 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
957
612
  updateSnapshot();
958
613
  return true;
959
614
  }
960
- const reset = !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
615
+ const reset = isOutsideThresholdHysteresis(distance, atThreshold, threshold);
961
616
  if (reset) {
962
617
  setSnapshot(void 0);
963
618
  return false;
@@ -965,35 +620,82 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
965
620
  if (within) {
966
621
  const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
967
622
  if (changed) {
968
- if (allowReentryOnChange) {
969
- onReached(distance);
970
- }
971
623
  updateSnapshot();
972
624
  }
973
625
  }
974
626
  return true;
975
627
  };
976
628
 
977
- // src/utils/hasActiveInitialScroll.ts
978
- function hasActiveInitialScroll(state) {
979
- return !!(state == null ? void 0 : state.initialScroll) && !state.didFinishInitialScroll;
629
+ // src/utils/edgeReachedGate.ts
630
+ function resetEdgeLatch(ctx, edge) {
631
+ const state = ctx.state;
632
+ if (edge === "start") {
633
+ state.isStartReached = false;
634
+ state.startReachedSnapshot = void 0;
635
+ } else {
636
+ state.isEndReached = false;
637
+ state.endReachedSnapshot = void 0;
638
+ }
980
639
  }
981
-
982
- // src/utils/checkAtBottom.ts
983
- function checkAtBottom(ctx) {
984
- var _a3;
640
+ function resetSharedEdgeGateIfOutsideHysteresis(ctx) {
985
641
  const state = ctx.state;
986
- if (!state) {
642
+ if (!state.edgeReachedGate) {
987
643
  return;
988
644
  }
989
- const {
990
- queuedInitialLayout,
645
+ const contentSize = getContentSize(ctx);
646
+ const endDistance = contentSize - state.scroll - state.scrollLength - getContentInsetEnd(ctx);
647
+ const isContentLess = contentSize < state.scrollLength;
648
+ const startThreshold = state.props.onStartReachedThreshold * state.scrollLength;
649
+ const endThreshold = state.props.onEndReachedThreshold * state.scrollLength;
650
+ const isOutsideStart = isOutsideThresholdHysteresis(state.scroll, false, startThreshold);
651
+ const isOutsideEnd = isOutsideThresholdHysteresis(endDistance, isContentLess, endThreshold);
652
+ if (isOutsideStart && isOutsideEnd) {
653
+ state.edgeReachedGate = void 0;
654
+ }
655
+ }
656
+ function canDispatchReachedEdge(ctx, edge, allowedEdge, allowGateCreatedInCurrentCheck) {
657
+ return !ctx.state.edgeReachedGate || allowedEdge === edge || !!allowGateCreatedInCurrentCheck;
658
+ }
659
+ function markReachedEdge(ctx) {
660
+ ctx.state.edgeReachedGate = "closed";
661
+ }
662
+ function prepareReachedEdgeForNextUserScroll(ctx) {
663
+ if (ctx.state.edgeReachedGate) {
664
+ ctx.state.edgeReachedGate = "prepared";
665
+ }
666
+ }
667
+ function beginReachedEdgeUserScroll(ctx, scrollDelta) {
668
+ const state = ctx.state;
669
+ if (state.edgeReachedGate !== "prepared") {
670
+ return void 0;
671
+ }
672
+ const allowedEdge = scrollDelta < 0 ? "start" : "end";
673
+ state.edgeReachedGate = "closed";
674
+ resetEdgeLatch(ctx, allowedEdge);
675
+ return allowedEdge;
676
+ }
677
+
678
+ // src/utils/hasActiveInitialScroll.ts
679
+ function hasActiveInitialScroll(state) {
680
+ return !!(state == null ? void 0 : state.initialScroll) && !state.didFinishInitialScroll;
681
+ }
682
+
683
+ // src/utils/checkAtBottom.ts
684
+ function checkAtBottom(ctx, allowedEdge, allowGateCreatedInCurrentCheck) {
685
+ var _a3;
686
+ const state = ctx.state;
687
+ if (!state) {
688
+ return;
689
+ }
690
+ const {
691
+ queuedInitialLayout,
991
692
  scrollLength,
992
693
  scroll,
993
694
  maintainingScrollAtEnd,
994
695
  props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
995
696
  } = state;
996
697
  const contentSize = getContentSize(ctx);
698
+ resetSharedEdgeGateIfOutsideHysteresis(ctx);
997
699
  if (contentSize > 0 && queuedInitialLayout) {
998
700
  const insetEnd = getContentInsetEnd(ctx);
999
701
  const distanceFromEnd = contentSize - scroll - scrollLength - insetEnd;
@@ -1020,59 +722,50 @@ function checkAtBottom(ctx) {
1020
722
  },
1021
723
  (distance) => {
1022
724
  var _a4, _b;
1023
- return (_b = (_a4 = state.props).onEndReached) == null ? void 0 : _b.call(_a4, { distanceFromEnd: distance });
725
+ if (canDispatchReachedEdge(ctx, "end", allowedEdge, allowGateCreatedInCurrentCheck)) {
726
+ markReachedEdge(ctx);
727
+ (_b = (_a4 = state.props).onEndReached) == null ? void 0 : _b.call(_a4, { distanceFromEnd: distance });
728
+ }
1024
729
  },
1025
730
  (snapshot) => {
1026
731
  state.endReachedSnapshot = snapshot;
1027
- },
1028
- true
732
+ }
1029
733
  );
1030
734
  }
1031
735
  }
1032
736
  }
1033
737
 
1034
- // src/utils/isInMVCPActiveMode.native.ts
1035
- function isInMVCPActiveMode(state) {
1036
- return state.dataChangeNeedsScrollUpdate;
1037
- }
1038
-
1039
738
  // src/utils/checkAtTop.ts
1040
- function checkAtTop(ctx) {
739
+ function checkAtTop(ctx, allowedEdge, allowGateCreatedInCurrentCheck) {
1041
740
  const state = ctx == null ? void 0 : ctx.state;
1042
741
  if (!state) {
1043
742
  return;
1044
743
  }
1045
744
  const {
1046
- dataChangeEpoch,
1047
745
  isStartReached,
1048
746
  props: { data, onStartReachedThreshold },
1049
747
  scroll,
1050
748
  scrollLength,
1051
749
  startReachedSnapshot,
1052
- startReachedSnapshotDataChangeEpoch,
1053
750
  totalSize
1054
751
  } = state;
1055
752
  const dataLength = data.length;
1056
753
  const threshold = onStartReachedThreshold * scrollLength;
1057
- const dataChanged = startReachedSnapshotDataChangeEpoch !== dataChangeEpoch;
1058
- const withinThreshold = threshold > 0 && Math.abs(scroll) <= threshold;
1059
- const allowReentryOnDataChange = !!isStartReached && withinThreshold && !!dataChanged && !isInMVCPActiveMode(state);
1060
- if (isStartReached && threshold > 0 && scroll > threshold && startReachedSnapshot && (dataChanged || startReachedSnapshot.contentSize !== totalSize || startReachedSnapshot.dataLength !== dataLength)) {
754
+ resetSharedEdgeGateIfOutsideHysteresis(ctx);
755
+ if (isStartReached && threshold > 0 && scroll > threshold && startReachedSnapshot && (startReachedSnapshot.contentSize !== totalSize || startReachedSnapshot.dataLength !== dataLength)) {
1061
756
  state.isStartReached = false;
1062
757
  state.startReachedSnapshot = void 0;
1063
- state.startReachedSnapshotDataChangeEpoch = void 0;
1064
758
  }
1065
759
  set$(ctx, "isAtStart", scroll <= EDGE_POSITION_EPSILON);
1066
760
  set$(ctx, "isNearStart", scroll <= threshold);
1067
761
  const shouldSkipThresholdChecks = hasActiveInitialScroll(state) || !!state.scrollingTo;
1068
- const shouldDeferDataChangeRefire = isStartReached && withinThreshold && dataChanged && !allowReentryOnDataChange;
1069
- if (!shouldSkipThresholdChecks && !shouldDeferDataChangeRefire) {
762
+ if (!shouldSkipThresholdChecks) {
1070
763
  state.isStartReached = checkThreshold(
1071
764
  scroll,
1072
765
  false,
1073
766
  threshold,
1074
767
  state.isStartReached,
1075
- allowReentryOnDataChange ? void 0 : startReachedSnapshot,
768
+ startReachedSnapshot,
1076
769
  {
1077
770
  contentSize: totalSize,
1078
771
  dataLength,
@@ -1080,21 +773,23 @@ function checkAtTop(ctx) {
1080
773
  },
1081
774
  (distance) => {
1082
775
  var _a3, _b;
1083
- return (_b = (_a3 = state.props).onStartReached) == null ? void 0 : _b.call(_a3, { distanceFromStart: distance });
776
+ if (canDispatchReachedEdge(ctx, "start", allowedEdge, allowGateCreatedInCurrentCheck)) {
777
+ markReachedEdge(ctx);
778
+ (_b = (_a3 = state.props).onStartReached) == null ? void 0 : _b.call(_a3, { distanceFromStart: distance });
779
+ }
1084
780
  },
1085
781
  (snapshot) => {
1086
782
  state.startReachedSnapshot = snapshot;
1087
- state.startReachedSnapshotDataChangeEpoch = snapshot ? dataChangeEpoch : void 0;
1088
- },
1089
- allowReentryOnDataChange
783
+ }
1090
784
  );
1091
785
  }
1092
786
  }
1093
787
 
1094
788
  // src/utils/checkThresholds.ts
1095
- function checkThresholds(ctx) {
1096
- checkAtBottom(ctx);
1097
- checkAtTop(ctx);
789
+ function checkThresholds(ctx, allowedEdge) {
790
+ const allowGateCreatedInCurrentCheck = !ctx.state.edgeReachedGate;
791
+ checkAtBottom(ctx, allowedEdge, allowGateCreatedInCurrentCheck);
792
+ checkAtTop(ctx, allowedEdge, allowGateCreatedInCurrentCheck);
1098
793
  }
1099
794
 
1100
795
  // src/core/recalculateSettledScroll.ts
@@ -1403,6 +1098,50 @@ function setSize(ctx, itemKey, size, notifyTotalSize = true) {
1403
1098
  sizes.set(itemKey, size);
1404
1099
  }
1405
1100
 
1101
+ // src/utils/helpers.ts
1102
+ function isFunction(obj) {
1103
+ return typeof obj === "function";
1104
+ }
1105
+ function isArray(obj) {
1106
+ return Array.isArray(obj);
1107
+ }
1108
+ var warned = /* @__PURE__ */ new Set();
1109
+ function warnDevOnce(id, text) {
1110
+ if (IS_DEV && !warned.has(id)) {
1111
+ warned.add(id);
1112
+ console.warn(`[legend-list] ${text}`);
1113
+ }
1114
+ }
1115
+ function roundSize(size) {
1116
+ return Math.floor(size * 8) / 8;
1117
+ }
1118
+ function isNullOrUndefined(value) {
1119
+ return value === null || value === void 0;
1120
+ }
1121
+ function getPadding(s, type) {
1122
+ var _a3, _b, _c;
1123
+ const axisPadding = type === "Left" || type === "Right" ? s.paddingHorizontal : s.paddingVertical;
1124
+ return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : axisPadding) != null ? _b : s.padding) != null ? _c : 0;
1125
+ }
1126
+ function extractPadding(style, contentContainerStyle, type) {
1127
+ return getPadding(style, type) + getPadding(contentContainerStyle, type);
1128
+ }
1129
+ function findContainerId(ctx, key) {
1130
+ var _a3, _b;
1131
+ const directMatch = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.containerItemKeys) == null ? void 0 : _b.get(key);
1132
+ if (directMatch !== void 0) {
1133
+ return directMatch;
1134
+ }
1135
+ const numContainers = peek$(ctx, "numContainers");
1136
+ for (let i = 0; i < numContainers; i++) {
1137
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
1138
+ if (itemKey === key) {
1139
+ return i;
1140
+ }
1141
+ }
1142
+ return -1;
1143
+ }
1144
+
1406
1145
  // src/utils/getItemSize.ts
1407
1146
  function getKnownOrFixedSize(ctx, key, index, data, resolved) {
1408
1147
  var _a3, _b;
@@ -2227,6 +1966,11 @@ var getScrollVelocity = (state) => {
2227
1966
  return totalWeight > 0 ? weightedVelocity / totalWeight : 0;
2228
1967
  };
2229
1968
 
1969
+ // src/utils/isInMVCPActiveMode.native.ts
1970
+ function isInMVCPActiveMode(state) {
1971
+ return state.dataChangeNeedsScrollUpdate;
1972
+ }
1973
+
2230
1974
  // src/core/updateScroll.ts
2231
1975
  function updateScroll(ctx, newScroll, forceUpdate, options) {
2232
1976
  var _a3;
@@ -2264,6 +2008,8 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
2264
2008
  state.scroll = newScroll;
2265
2009
  state.scrollTime = currentTime;
2266
2010
  const scrollDelta = Math.abs(newScroll - prevScroll);
2011
+ const isUserScrollEvent = !!(options == null ? void 0 : options.fromNativeScrollEvent) && scrollDelta > 0.1 && !adjustChanged && scrollingTo === void 0 && !state.pendingNativeMVCPAdjust;
2012
+ const allowedEdge = isUserScrollEvent ? beginReachedEdgeUserScroll(ctx, newScroll - prevScroll) : void 0;
2267
2013
  const didResolvePendingNativeMVCPAdjust = resolvePendingNativeMVCPAdjust(ctx, newScroll);
2268
2014
  const scrollLength = state.scrollLength;
2269
2015
  const isLargeUserScrollJump = scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength && !state.pendingNativeMVCPAdjust;
@@ -2271,7 +2017,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
2271
2017
  updateAdaptiveRender(ctx, scrollVelocity, { forceLight: isLargeUserScrollJump });
2272
2018
  const lastCalculated = state.scrollLastCalculate;
2273
2019
  const useAggressiveItemRecalculation = isInMVCPActiveMode(state);
2274
- const shouldUpdate = useAggressiveItemRecalculation || didResolvePendingNativeMVCPAdjust || forceUpdate || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
2020
+ const shouldUpdate = useAggressiveItemRecalculation || didResolvePendingNativeMVCPAdjust || allowedEdge !== void 0 || forceUpdate || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
2275
2021
  if (shouldUpdate) {
2276
2022
  state.scrollLastCalculate = state.scroll;
2277
2023
  state.ignoreScrollFromMVCPIgnored = false;
@@ -2286,7 +2032,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
2286
2032
  calculateItemsParams.drawDistanceMode = "visible-first";
2287
2033
  }
2288
2034
  (_a4 = state.triggerCalculateItemsInView) == null ? void 0 : _a4.call(state, calculateItemsParams);
2289
- checkThresholds(ctx);
2035
+ checkThresholds(ctx, allowedEdge);
2290
2036
  };
2291
2037
  if (isLargeUserScrollJump) {
2292
2038
  state.mvcpAnchorLock = void 0;
@@ -3375,6 +3121,52 @@ function resetLayoutCachesForDataChange(state) {
3375
3121
  state.columnSpans.length = 0;
3376
3122
  }
3377
3123
 
3124
+ // src/core/scheduleContainerLayout.ts
3125
+ function getContainerLayoutEffectScope(ctx) {
3126
+ var _a3;
3127
+ const scheduledIds = ctx.pendingContainerIds;
3128
+ ctx.pendingContainerIds = void 0;
3129
+ if (scheduledIds === void 0) {
3130
+ return void 0;
3131
+ }
3132
+ const state = ctx.state;
3133
+ let targetContainerIds = scheduledIds;
3134
+ if (targetContainerIds && ((_a3 = state.userScrollAnchorReset) == null ? void 0 : _a3.keys.size)) {
3135
+ targetContainerIds = new Set(targetContainerIds);
3136
+ for (const itemKey of state.userScrollAnchorReset.keys) {
3137
+ const containerId = state.containerItemKeys.get(itemKey);
3138
+ if (containerId !== void 0) {
3139
+ targetContainerIds.add(containerId);
3140
+ }
3141
+ }
3142
+ }
3143
+ return targetContainerIds;
3144
+ }
3145
+ function scheduleContainerLayout(ctx, target) {
3146
+ var _a3;
3147
+ const isAlreadyScheduled = ctx.pendingContainerIds !== void 0;
3148
+ const previousIds = ctx.pendingContainerIds;
3149
+ if (target === void 0) {
3150
+ ctx.pendingContainerIds = null;
3151
+ } else if (previousIds !== null) {
3152
+ let nextIds = previousIds;
3153
+ if (!nextIds) {
3154
+ nextIds = typeof target === "number" ? /* @__PURE__ */ new Set([target]) : new Set(target);
3155
+ } else if (typeof target === "number") {
3156
+ nextIds.add(target);
3157
+ } else {
3158
+ for (const containerId of target) {
3159
+ nextIds.add(containerId);
3160
+ }
3161
+ }
3162
+ ctx.pendingContainerIds = nextIds;
3163
+ }
3164
+ if (!isAlreadyScheduled) {
3165
+ const nextEpoch = ((_a3 = peek$(ctx, "containerLayoutEpoch")) != null ? _a3 : 0) + 1;
3166
+ set$(ctx, "containerLayoutEpoch", nextEpoch);
3167
+ }
3168
+ }
3169
+
3378
3170
  // src/core/syncMountedContainer.ts
3379
3171
  function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3380
3172
  var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
@@ -3418,14 +3210,13 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3418
3210
  set$(ctx, `containerSpan${containerIndex}`, span);
3419
3211
  }
3420
3212
  }
3421
- const prevItemInfo = peek$(ctx, `containerItemInfo${containerIndex}`);
3213
+ const prevIndex = peek$(ctx, `containerItemIndex${containerIndex}`);
3214
+ if (prevIndex !== itemIndex) {
3215
+ set$(ctx, `containerItemIndex${containerIndex}`, itemIndex);
3216
+ }
3422
3217
  const prevData = peek$(ctx, `containerItemData${containerIndex}`);
3423
- let itemInfoValue = prevData;
3424
- let didChangeItemInfo = (prevItemInfo == null ? void 0 : prevItemInfo.itemKey) !== itemKey || (prevItemInfo == null ? void 0 : prevItemInfo.index) !== itemIndex || (prevItemInfo == null ? void 0 : prevItemInfo.value) !== prevData;
3425
3218
  const updateData = () => {
3426
3219
  set$(ctx, `containerItemData${containerIndex}`, item);
3427
- itemInfoValue = item;
3428
- didChangeItemInfo = true;
3429
3220
  didRefreshData = true;
3430
3221
  };
3431
3222
  if (prevData !== item) {
@@ -3460,13 +3251,6 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3460
3251
  }
3461
3252
  }
3462
3253
  }
3463
- if (didChangeItemInfo) {
3464
- set$(ctx, `containerItemInfo${containerIndex}`, {
3465
- index: itemIndex,
3466
- itemKey,
3467
- value: itemInfoValue
3468
- });
3469
- }
3470
3254
  return { didChangePosition, didRefreshData };
3471
3255
  }
3472
3256
 
@@ -3831,19 +3615,29 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
3831
3615
  if (previousViewableItems) {
3832
3616
  for (const viewToken of previousViewableItems) {
3833
3617
  previousViewableKeys.add(viewToken.key);
3618
+ const currentIndex = state.indexByKey.get(viewToken.key);
3619
+ const currentItem = currentIndex !== void 0 ? data[currentIndex] : void 0;
3834
3620
  const containerId = findContainerId(ctx, viewToken.key);
3835
- if (!checkIsViewable(
3836
- state,
3837
- ctx,
3838
- viewabilityConfig,
3839
- containerId,
3840
- viewToken.key,
3841
- scrollSize,
3842
- viewToken.item,
3843
- viewToken.index
3844
- )) {
3845
- viewToken.isViewable = false;
3846
- changed.push(viewToken);
3621
+ let isStillViewable = false;
3622
+ if (currentIndex !== void 0 && currentItem !== void 0) {
3623
+ isStillViewable = checkIsViewable(
3624
+ state,
3625
+ ctx,
3626
+ viewabilityConfig,
3627
+ containerId,
3628
+ viewToken.key,
3629
+ scrollSize,
3630
+ currentItem,
3631
+ currentIndex
3632
+ );
3633
+ }
3634
+ if (!isStillViewable) {
3635
+ changed.push({
3636
+ ...viewToken,
3637
+ index: currentIndex != null ? currentIndex : viewToken.index,
3638
+ isViewable: false,
3639
+ item: currentItem != null ? currentItem : viewToken.item
3640
+ });
3847
3641
  }
3848
3642
  }
3849
3643
  }
@@ -4000,128 +3794,102 @@ function getExpandedContainerPoolSize(dataLength, numContainers) {
4000
3794
 
4001
3795
  // src/utils/findAvailableContainers.ts
4002
3796
  function findAvailableContainers(ctx, needNewContainers, startBuffered, endBuffered, pendingRemoval, getRequiredItemType, protectedKeys) {
3797
+ var _a3;
4003
3798
  const numNeeded = needNewContainers.length;
4004
3799
  if (numNeeded === 0) {
4005
3800
  return [];
4006
3801
  }
4007
3802
  const numContainers = peek$(ctx, "numContainers");
4008
3803
  const state = ctx.state;
4009
- const { stickyContainerPool, containerItemTypes } = state;
3804
+ const { containerItemMetadata, stickyContainerPool } = state;
4010
3805
  const shouldAvoidAssignedContainerReuse = state.props.recycleItems && !!state.props.positionComponentInternal;
4011
- const allocations = [];
4012
3806
  const pendingRemovalSet = pendingRemoval.length > 0 ? new Set(pendingRemoval) : void 0;
4013
- let pendingRemovalChanged = false;
3807
+ const requests = needNewContainers.map((itemIndex, order) => ({
3808
+ isSticky: state.props.stickyHeaderIndicesSet.has(itemIndex),
3809
+ itemIndex,
3810
+ itemType: getRequiredItemType == null ? void 0 : getRequiredItemType(itemIndex),
3811
+ order
3812
+ }));
3813
+ const normalRequests = requests.filter((request) => !request.isSticky);
3814
+ const stickyRequests = requests.filter((request) => request.isSticky);
3815
+ const normalCandidates = [];
3816
+ const stickyCandidates = [];
3817
+ for (let containerIndex = 0; containerIndex < numContainers; containerIndex++) {
3818
+ const key = peek$(ctx, `containerItemKey${containerIndex}`);
3819
+ const isPendingRemoval = !!(pendingRemovalSet == null ? void 0 : pendingRemovalSet.has(containerIndex));
3820
+ const isProtected = !!key && !!(protectedKeys == null ? void 0 : protectedKeys.has(key)) && state.indexByKey.has(key);
3821
+ if (isProtected) {
3822
+ continue;
3823
+ }
3824
+ if (stickyContainerPool.has(containerIndex)) {
3825
+ if (key === void 0 || isPendingRemoval) {
3826
+ stickyCandidates.push({ containerIndex, distance: Number.POSITIVE_INFINITY });
3827
+ }
3828
+ } else if (key === void 0 || isPendingRemoval) {
3829
+ normalCandidates.push({ containerIndex, distance: Number.POSITIVE_INFINITY });
3830
+ } else if (!shouldAvoidAssignedContainerReuse) {
3831
+ const index = state.indexByKey.get(key);
3832
+ if (index !== void 0 && (index < startBuffered || index > endBuffered)) {
3833
+ const distance = index < startBuffered ? startBuffered - index : index - endBuffered;
3834
+ normalCandidates.push({ containerIndex, distance });
3835
+ }
3836
+ }
3837
+ }
3838
+ normalCandidates.sort(comparatorByDistance);
3839
+ const allocations = new Array(numNeeded);
4014
3840
  let nextNewContainerIndex = numContainers;
4015
- const usedContainers = /* @__PURE__ */ new Set();
4016
- let availableContainers;
4017
- const stickyHeaderIndicesSet = state.props.stickyHeaderIndicesSet;
4018
- const canReuseContainer = (containerIndex, requiredType) => {
4019
- if (!requiredType) return true;
4020
- const existingType = containerItemTypes.get(containerIndex);
4021
- if (!existingType) return true;
4022
- return existingType === requiredType;
4023
- };
4024
- const pushAllocation = (itemIndex, itemType, containerIndex) => {
4025
- allocations.push({
3841
+ let pendingRemovalChanged = false;
3842
+ const assign = (request, containerIndex) => {
3843
+ allocations[request.order] = {
4026
3844
  containerIndex,
4027
- itemIndex,
4028
- itemType
4029
- });
4030
- usedContainers.add(containerIndex);
3845
+ itemIndex: request.itemIndex,
3846
+ itemType: request.itemType
3847
+ };
4031
3848
  if (pendingRemovalSet == null ? void 0 : pendingRemovalSet.delete(containerIndex)) {
4032
3849
  pendingRemovalChanged = true;
4033
3850
  }
4034
3851
  };
4035
- const pushNewContainer = (itemIndex, itemType, isSticky) => {
4036
- const newContainerIndex = nextNewContainerIndex++;
4037
- pushAllocation(itemIndex, itemType, newContainerIndex);
4038
- if (isSticky) {
4039
- stickyContainerPool.add(newContainerIndex);
4040
- }
4041
- return newContainerIndex;
4042
- };
4043
- const canUseContainer = (containerIndex, itemType) => {
4044
- if (usedContainers.has(containerIndex) || stickyContainerPool.has(containerIndex)) {
4045
- return false;
4046
- }
4047
- const key = peek$(ctx, `containerItemKey${containerIndex}`);
4048
- const isPending = !!(pendingRemovalSet == null ? void 0 : pendingRemovalSet.has(containerIndex));
4049
- return (key === void 0 || isPending) && canReuseContainer(containerIndex, itemType);
4050
- };
4051
- const findStickyContainer = (itemType) => {
4052
- let foundContainer;
4053
- for (const containerIndex of stickyContainerPool) {
4054
- if (!usedContainers.has(containerIndex)) {
4055
- const key = peek$(ctx, `containerItemKey${containerIndex}`);
4056
- const isPendingRemoval = !!(pendingRemovalSet == null ? void 0 : pendingRemovalSet.has(containerIndex));
4057
- if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, itemType)) {
4058
- foundContainer = containerIndex;
4059
- break;
4060
- }
4061
- }
4062
- }
4063
- return foundContainer;
4064
- };
4065
- const findUnassignedOrPendingContainer = (itemType) => {
4066
- let foundContainer;
4067
- for (let containerIndex = 0; containerIndex < numContainers && foundContainer === void 0; containerIndex++) {
4068
- if (canUseContainer(containerIndex, itemType)) {
4069
- foundContainer = containerIndex;
3852
+ const assignMatching = (pendingRequests, candidates, matches) => {
3853
+ for (const request of pendingRequests) {
3854
+ if (allocations[request.order]) {
3855
+ continue;
4070
3856
  }
4071
- }
4072
- return foundContainer;
4073
- };
4074
- const getAvailableContainers = () => {
4075
- if (!availableContainers) {
4076
- availableContainers = [];
4077
- if (!shouldAvoidAssignedContainerReuse) {
4078
- for (let containerIndex = 0; containerIndex < numContainers; containerIndex++) {
4079
- if (usedContainers.has(containerIndex) || stickyContainerPool.has(containerIndex)) {
4080
- continue;
4081
- }
4082
- const key = peek$(ctx, `containerItemKey${containerIndex}`);
4083
- if (key === void 0) continue;
4084
- if ((protectedKeys == null ? void 0 : protectedKeys.has(key)) && state.indexByKey.has(key)) continue;
4085
- const index = state.indexByKey.get(key);
4086
- const isOutOfView = index < startBuffered || index > endBuffered;
4087
- if (isOutOfView) {
4088
- const distance = index < startBuffered ? startBuffered - index : index - endBuffered;
4089
- availableContainers.push({ distance, index: containerIndex });
4090
- }
3857
+ const candidateIndex = candidates.findIndex(
3858
+ (candidate) => {
3859
+ var _a4;
3860
+ return matches((_a4 = containerItemMetadata.get(candidate.containerIndex)) == null ? void 0 : _a4.itemType, request.itemType);
4091
3861
  }
4092
- availableContainers.sort(comparatorByDistance);
3862
+ );
3863
+ if (candidateIndex !== -1) {
3864
+ const [candidate] = candidates.splice(candidateIndex, 1);
3865
+ assign(request, candidate.containerIndex);
4093
3866
  }
4094
3867
  }
4095
- return availableContainers;
4096
3868
  };
4097
- const findAvailableContainer = (itemType) => {
4098
- const containers = getAvailableContainers();
4099
- let matchIndex = -1;
4100
- for (let i = 0; i < containers.length && matchIndex === -1; i++) {
4101
- const containerIndex = containers[i].index;
4102
- if (!usedContainers.has(containerIndex) && canReuseContainer(containerIndex, itemType)) {
4103
- matchIndex = i;
4104
- }
3869
+ const assignFromPool = (pendingRequests, candidates, allowCrossType) => {
3870
+ if (getRequiredItemType) {
3871
+ assignMatching(
3872
+ pendingRequests,
3873
+ candidates,
3874
+ (containerType, requestType) => requestType !== void 0 && containerType === requestType
3875
+ );
3876
+ }
3877
+ assignMatching(pendingRequests, candidates, (containerType) => containerType === void 0);
3878
+ if (allowCrossType) {
3879
+ assignMatching(pendingRequests, candidates, () => true);
4105
3880
  }
4106
- return matchIndex === -1 ? void 0 : containers.splice(matchIndex, 1)[0].index;
4107
3881
  };
4108
- for (const itemIndex of needNewContainers) {
4109
- const itemType = getRequiredItemType == null ? void 0 : getRequiredItemType(itemIndex);
4110
- const isSticky = stickyHeaderIndicesSet.has(itemIndex);
4111
- let containerIndex;
4112
- if (isSticky) {
4113
- containerIndex = findStickyContainer(itemType);
4114
- } else {
4115
- containerIndex = findUnassignedOrPendingContainer(itemType);
4116
- if (containerIndex === void 0) {
4117
- containerIndex = findAvailableContainer(itemType);
4118
- }
3882
+ assignFromPool(normalRequests, normalCandidates, true);
3883
+ assignFromPool(stickyRequests, stickyCandidates, false);
3884
+ for (const request of requests) {
3885
+ if (allocations[request.order]) {
3886
+ continue;
4119
3887
  }
4120
- if (containerIndex !== void 0) {
4121
- pushAllocation(itemIndex, itemType, containerIndex);
4122
- } else {
4123
- pushNewContainer(itemIndex, itemType, isSticky);
3888
+ const containerIndex = nextNewContainerIndex++;
3889
+ if (request.isSticky) {
3890
+ stickyContainerPool.add(containerIndex);
4124
3891
  }
3892
+ assign(request, containerIndex);
4125
3893
  }
4126
3894
  if (pendingRemovalChanged) {
4127
3895
  pendingRemoval.length = 0;
@@ -4131,18 +3899,21 @@ function findAvailableContainers(ctx, needNewContainers, startBuffered, endBuffe
4131
3899
  }
4132
3900
  }
4133
3901
  }
4134
- if (IS_DEV && nextNewContainerIndex > peek$(ctx, "numContainersPooled")) {
4135
- console.warn(
4136
- "[legend-list] No unused container available, so creating one on demand. This can be a minor performance issue and is likely caused by the estimatedItemSize being too large. Consider decreasing estimatedItemSize.",
4137
- {
4138
- debugInfo: {
4139
- numContainers,
4140
- numContainersPooled: peek$(ctx, "numContainersPooled"),
4141
- numNeeded,
4142
- stillNeeded: nextNewContainerIndex - numContainers
3902
+ if (IS_DEV) {
3903
+ const numContainersPooled = (_a3 = peek$(ctx, "numContainersPooled")) != null ? _a3 : Number.POSITIVE_INFINITY;
3904
+ if (nextNewContainerIndex > numContainersPooled) {
3905
+ console.warn(
3906
+ "[legend-list] No unused container available, so creating one on demand. This can be a minor performance issue and is likely caused by the estimatedItemSize being too large. Consider decreasing estimatedItemSize.",
3907
+ {
3908
+ debugInfo: {
3909
+ numContainers,
3910
+ numContainersPooled,
3911
+ numNeeded,
3912
+ stillNeeded: nextNewContainerIndex - numContainers
3913
+ }
4143
3914
  }
4144
- }
4145
- );
3915
+ );
3916
+ }
4146
3917
  }
4147
3918
  return allocations;
4148
3919
  }
@@ -4377,7 +4148,7 @@ function updateViewabilityForCachedRange(ctx, viewabilityConfigCallbackPairs, sc
4377
4148
  function calculateItemsInView(ctx, params = {}) {
4378
4149
  const state = ctx.state;
4379
4150
  batchedUpdates(() => {
4380
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t;
4151
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u;
4381
4152
  const {
4382
4153
  columns,
4383
4154
  containerItemKeys,
@@ -4405,6 +4176,7 @@ function calculateItemsInView(ctx, params = {}) {
4405
4176
  return;
4406
4177
  }
4407
4178
  let totalSize = getContentSize(ctx);
4179
+ let changedContainerIds;
4408
4180
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "alignItemsAtEndPadding") + peek$(ctx, "headerSize");
4409
4181
  const numColumns = peek$(ctx, "numColumns");
4410
4182
  const speed = (_b = params.scrollVelocity) != null ? _b : getScrollVelocity(state);
@@ -4530,7 +4302,7 @@ function calculateItemsInView(ctx, params = {}) {
4530
4302
  const scrollAdjustPendingBeforeMVCP = (_f = peek$(ctx, "scrollAdjustPending")) != null ? _f : 0;
4531
4303
  checkMVCP == null ? void 0 : checkMVCP();
4532
4304
  const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_g = peek$(ctx, "scrollAdjustPending")) != null ? _g : 0) !== scrollAdjustPendingBeforeMVCP);
4533
- if (didMVCPAdjustScroll && (initialScroll || state.scrollingTo)) {
4305
+ if (didMVCPAdjustScroll) {
4534
4306
  updateScroll2(state.scroll);
4535
4307
  updateScrollRange();
4536
4308
  }
@@ -4710,22 +4482,20 @@ function calculateItemsInView(ctx, params = {}) {
4710
4482
  if (oldKey && oldKey !== id) {
4711
4483
  containerItemKeys.delete(oldKey);
4712
4484
  }
4485
+ if (oldKey !== id) {
4486
+ changedContainerIds != null ? changedContainerIds : changedContainerIds = /* @__PURE__ */ new Set();
4487
+ changedContainerIds.add(containerIndex);
4488
+ state.containerItemGenerations[containerIndex] = ((_p = state.containerItemGenerations[containerIndex]) != null ? _p : 0) + 1;
4489
+ }
4713
4490
  set$(ctx, `containerItemKey${containerIndex}`, id);
4491
+ set$(ctx, `containerItemIndex${containerIndex}`, i);
4714
4492
  set$(ctx, `containerItemData${containerIndex}`, data[i]);
4715
- set$(ctx, `containerItemInfo${containerIndex}`, {
4716
- index: i,
4717
- itemKey: id,
4718
- value: data[i]
4719
- });
4720
- if (allocation.itemType !== void 0) {
4721
- state.containerItemTypes.set(containerIndex, allocation.itemType);
4722
- }
4493
+ state.containerItemMetadata.set(
4494
+ containerIndex,
4495
+ createContainerItemMetadata(state, i, data[i], allocation.itemType)
4496
+ );
4723
4497
  containerItemKeys.set(id, containerIndex);
4724
- (_p = state.userScrollAnchorReset) == null ? void 0 : _p.keys.add(id);
4725
- if (IsNewArchitecture) {
4726
- (_q = state.pendingLayoutEffectMeasurements) != null ? _q : state.pendingLayoutEffectMeasurements = /* @__PURE__ */ new Set();
4727
- state.pendingLayoutEffectMeasurements.add(id);
4728
- }
4498
+ (_q = state.userScrollAnchorReset) == null ? void 0 : _q.keys.add(id);
4729
4499
  const containerSticky = `containerSticky${containerIndex}`;
4730
4500
  const isSticky = stickyHeaderIndicesSet.has(i);
4731
4501
  const isPinnedRender = isPinnedRenderIndex(i);
@@ -4775,15 +4545,18 @@ function calculateItemsInView(ctx, params = {}) {
4775
4545
  if (pendingRemovalSet == null ? void 0 : pendingRemovalSet.has(i)) {
4776
4546
  if (itemKey !== void 0) {
4777
4547
  containerItemKeys.delete(itemKey);
4548
+ changedContainerIds != null ? changedContainerIds : changedContainerIds = /* @__PURE__ */ new Set();
4549
+ changedContainerIds.add(i);
4550
+ state.containerItemGenerations[i] = ((_t = state.containerItemGenerations[i]) != null ? _t : 0) + 1;
4778
4551
  }
4779
- state.containerItemTypes.delete(i);
4552
+ state.containerItemMetadata.delete(i);
4780
4553
  if (state.stickyContainerPool.has(i)) {
4781
4554
  set$(ctx, `containerSticky${i}`, false);
4782
4555
  state.stickyContainerPool.delete(i);
4783
4556
  }
4784
4557
  set$(ctx, `containerItemKey${i}`, void 0);
4558
+ set$(ctx, `containerItemIndex${i}`, void 0);
4785
4559
  set$(ctx, `containerItemData${i}`, void 0);
4786
- set$(ctx, `containerItemInfo${i}`, void 0);
4787
4560
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
4788
4561
  set$(ctx, `containerColumn${i}`, -1);
4789
4562
  set$(ctx, `containerSpan${i}`, 1);
@@ -4797,6 +4570,9 @@ function calculateItemsInView(ctx, params = {}) {
4797
4570
  }
4798
4571
  }
4799
4572
  }
4573
+ if (changedContainerIds && (IsNewArchitecture || Platform.OS === "web")) {
4574
+ scheduleContainerLayout(ctx, changedContainerIds);
4575
+ }
4800
4576
  if (Platform.OS === "web" && didChangePositions) {
4801
4577
  set$(ctx, "lastPositionUpdate", Date.now());
4802
4578
  }
@@ -4813,20 +4589,18 @@ function calculateItemsInView(ctx, params = {}) {
4813
4589
  }
4814
4590
  }
4815
4591
  if (viewabilityConfigCallbackPairs && visibleRange.startNoBuffer !== null && visibleRange.endNoBuffer !== null) {
4816
- if (!didMVCPAdjustScroll) {
4817
- updateViewableItems(
4818
- ctx.state,
4819
- ctx,
4820
- viewabilityConfigCallbackPairs,
4821
- scrollLength,
4822
- visibleRange.startNoBuffer,
4823
- visibleRange.endNoBuffer,
4824
- startBuffered != null ? startBuffered : visibleRange.startNoBuffer,
4825
- endBuffered != null ? endBuffered : visibleRange.endNoBuffer
4826
- );
4827
- }
4592
+ updateViewableItems(
4593
+ ctx.state,
4594
+ ctx,
4595
+ viewabilityConfigCallbackPairs,
4596
+ scrollLength,
4597
+ visibleRange.startNoBuffer,
4598
+ visibleRange.endNoBuffer,
4599
+ startBuffered != null ? startBuffered : visibleRange.startNoBuffer,
4600
+ endBuffered != null ? endBuffered : visibleRange.endNoBuffer
4601
+ );
4828
4602
  }
4829
- (_t = stickyState == null ? void 0 : stickyState.finishCalculateItemsInView) == null ? void 0 : _t.call(stickyState);
4603
+ (_u = stickyState == null ? void 0 : stickyState.finishCalculateItemsInView) == null ? void 0 : _u.call(stickyState);
4830
4604
  });
4831
4605
  }
4832
4606
 
@@ -4932,42 +4706,28 @@ function updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal) {
4932
4706
  }
4933
4707
  }
4934
4708
  }
4709
+ var activeItemSizeBatches;
4710
+ function batchItemSizeUpdates(runUpdates) {
4711
+ const isOuterBatch = activeItemSizeBatches === void 0;
4712
+ activeItemSizeBatches != null ? activeItemSizeBatches : activeItemSizeBatches = /* @__PURE__ */ new Map();
4713
+ try {
4714
+ runUpdates();
4715
+ } finally {
4716
+ if (isOuterBatch) {
4717
+ const batches = activeItemSizeBatches;
4718
+ activeItemSizeBatches = void 0;
4719
+ for (const [ctx, measurements] of batches) {
4720
+ updateItemSizesBatch(ctx, measurements);
4721
+ }
4722
+ }
4723
+ }
4724
+ }
4935
4725
  function mergeItemSizeUpdateResult(result, next) {
4936
4726
  result.didChange || (result.didChange = next.didChange);
4937
4727
  result.didMeasureUserScrollAnchorResetItem || (result.didMeasureUserScrollAnchorResetItem = next.didMeasureUserScrollAnchorResetItem);
4938
4728
  result.needsRecalculate || (result.needsRecalculate = next.needsRecalculate);
4939
4729
  result.shouldMaintainScrollAtEnd || (result.shouldMaintainScrollAtEnd = next.shouldMaintainScrollAtEnd);
4940
4730
  }
4941
- var batchedItemSizeRecalculates = /* @__PURE__ */ new WeakMap();
4942
- function flushBatchedItemSizeRecalculate(ctx, didFallback = false, expectedResult) {
4943
- const result = batchedItemSizeRecalculates.get(ctx);
4944
- if (!result || expectedResult && result !== expectedResult) {
4945
- return;
4946
- }
4947
- batchedItemSizeRecalculates.delete(ctx);
4948
- if (didFallback) {
4949
- ctx.state.pendingLayoutEffectMeasurements = void 0;
4950
- }
4951
- flushItemSizeUpdates(ctx, result);
4952
- }
4953
- function queueItemSizeRecalculate(ctx, result) {
4954
- var _a3, _b;
4955
- const batch = batchedItemSizeRecalculates.get(ctx);
4956
- if (batch) {
4957
- mergeItemSizeUpdateResult(batch, result);
4958
- } else {
4959
- const nextBatch = { ...result };
4960
- batchedItemSizeRecalculates.set(ctx, nextBatch);
4961
- if ((_a3 = ctx.state.pendingLayoutEffectMeasurements) == null ? void 0 : _a3.size) {
4962
- requestAnimationFrame(() => {
4963
- flushBatchedItemSizeRecalculate(ctx, true, nextBatch);
4964
- });
4965
- }
4966
- }
4967
- if (!((_b = ctx.state.pendingLayoutEffectMeasurements) == null ? void 0 : _b.size)) {
4968
- flushBatchedItemSizeRecalculate(ctx);
4969
- }
4970
- }
4971
4731
  function flushItemSizeUpdates(ctx, result) {
4972
4732
  var _a3;
4973
4733
  const state = ctx.state;
@@ -4982,54 +4742,36 @@ function flushItemSizeUpdates(ctx, result) {
4982
4742
  }
4983
4743
  }
4984
4744
  function updateItemSizes(ctx, measurement) {
4985
- var _a3, _b, _c, _d;
4986
- const state = ctx.state;
4987
- let didDrainLayoutEffectMeasurements = false;
4988
- if (IsNewArchitecture && measurement.fromLayoutEffect) {
4989
- const pendingLayoutEffectMeasurements = state.pendingLayoutEffectMeasurements;
4990
- if ((pendingLayoutEffectMeasurements == null ? void 0 : pendingLayoutEffectMeasurements.delete(measurement.itemKey)) && pendingLayoutEffectMeasurements.size === 0) {
4991
- state.pendingLayoutEffectMeasurements = void 0;
4992
- didDrainLayoutEffectMeasurements = true;
4993
- }
4994
- }
4995
- const pendingKeys = (_a3 = state.userScrollAnchorReset) == null ? void 0 : _a3.keys;
4996
- const shouldBatchPendingMeasurements = IsNewArchitecture && measurement.fromLayoutEffect && !!(pendingKeys == null ? void 0 : pendingKeys.size);
4997
- const shouldQueueRecalculate = IsNewArchitecture && !!measurement.fromLayoutEffect;
4998
- let result;
4999
- if (!shouldBatchPendingMeasurements) {
5000
- result = applyItemSize(ctx, measurement.itemKey, measurement.size);
5001
- } else {
5002
- result = {};
5003
- const updateContainerItemSize = (itemKey, containerId, size) => {
5004
- if (containerId !== void 0 && peek$(ctx, `containerItemKey${containerId}`) === itemKey) {
5005
- mergeItemSizeUpdateResult(result, applyItemSize(ctx, itemKey, size));
5006
- }
5007
- };
5008
- updateContainerItemSize(measurement.itemKey, measurement.containerId, measurement.size);
5009
- const keys = Array.from(pendingKeys);
5010
- for (const itemKey of keys) {
5011
- const containerId = state.containerItemKeys.get(itemKey);
5012
- if (containerId !== void 0) {
5013
- (_d = (_c = (_b = ctx.viewRefs.get(containerId)) == null ? void 0 : _b.current) == null ? void 0 : _c.measure) == null ? void 0 : _d.call(_c, (_x, _y, width, height) => {
5014
- if (pendingKeys.has(itemKey)) {
5015
- updateContainerItemSize(itemKey, containerId, { height, width });
5016
- }
5017
- });
5018
- }
4745
+ if (activeItemSizeBatches) {
4746
+ const measurements = activeItemSizeBatches.get(ctx);
4747
+ if (measurements) {
4748
+ measurements.push(measurement);
4749
+ } else {
4750
+ activeItemSizeBatches.set(ctx, [measurement]);
5019
4751
  }
5020
- }
5021
- if (shouldQueueRecalculate && result.needsRecalculate) {
5022
- queueItemSizeRecalculate(ctx, result);
5023
4752
  } else {
5024
- flushItemSizeUpdates(ctx, result);
5025
- }
5026
- if (didDrainLayoutEffectMeasurements) {
5027
- flushBatchedItemSizeRecalculate(ctx);
4753
+ updateItemSizesBatch(ctx, [measurement]);
5028
4754
  }
5029
4755
  }
5030
- function applyItemSize(ctx, itemKey, sizeObj) {
4756
+ function updateItemSizesBatch(ctx, measurements) {
5031
4757
  var _a3;
5032
4758
  const state = ctx.state;
4759
+ const result = {};
4760
+ for (const measurement of measurements) {
4761
+ const ownsMeasuredItem = measurement.containerId === void 0 || peek$(ctx, `containerItemKey${measurement.containerId}`) === measurement.itemKey;
4762
+ if (ownsMeasuredItem) {
4763
+ const index = state.indexByKey.get(measurement.itemKey);
4764
+ const itemData = index === void 0 ? void 0 : (_a3 = state.props.data) == null ? void 0 : _a3[index];
4765
+ const metadata = measurement.containerId !== void 0 && index !== void 0 && itemData !== void 0 ? resolveContainerItemMetadata(state, measurement.containerId, index, itemData) : void 0;
4766
+ const nextResult = applyItemSize(ctx, measurement.itemKey, measurement.size, metadata);
4767
+ mergeItemSizeUpdateResult(result, nextResult);
4768
+ }
4769
+ }
4770
+ flushItemSizeUpdates(ctx, result);
4771
+ }
4772
+ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
4773
+ var _a3, _b;
4774
+ const state = ctx.state;
5033
4775
  const userScrollAnchorReset = state.userScrollAnchorReset;
5034
4776
  const didMeasureUserScrollAnchorResetItem = !!(userScrollAnchorReset == null ? void 0 : userScrollAnchorReset.keys.delete(itemKey));
5035
4777
  const {
@@ -5039,7 +4781,6 @@ function applyItemSize(ctx, itemKey, sizeObj) {
5039
4781
  } = state;
5040
4782
  if (!data) return { didMeasureUserScrollAnchorResetItem };
5041
4783
  const index = state.indexByKey.get(itemKey);
5042
- let resolvedMeasurementItem;
5043
4784
  if (getFixedItemSize) {
5044
4785
  if (index === void 0) {
5045
4786
  return { didMeasureUserScrollAnchorResetItem };
@@ -5048,14 +4789,15 @@ function applyItemSize(ctx, itemKey, sizeObj) {
5048
4789
  if (itemData === void 0) {
5049
4790
  return { didMeasureUserScrollAnchorResetItem };
5050
4791
  }
5051
- const type = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
5052
- const size2 = getFixedItemSize(itemData, index, type);
5053
- resolvedMeasurementItem = {
5054
- didResolveFixedItemSize: true,
5055
- fixedItemSize: size2,
5056
- itemData,
5057
- itemType: type
5058
- };
4792
+ if (!(resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.didResolveFixedItemSize)) {
4793
+ const type = (_b = resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.itemType) != null ? _b : getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
4794
+ resolvedMeasurementItem = {
4795
+ didResolveFixedItemSize: true,
4796
+ fixedItemSize: getFixedItemSize(itemData, index, type),
4797
+ itemType: type
4798
+ };
4799
+ }
4800
+ const size2 = resolvedMeasurementItem.fixedItemSize;
5059
4801
  if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
5060
4802
  updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
5061
4803
  return { didMeasureUserScrollAnchorResetItem };
@@ -5074,91 +4816,532 @@ function applyItemSize(ctx, itemKey, sizeObj) {
5074
4816
  if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
5075
4817
  needsRecalculate = true;
5076
4818
  }
5077
- if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
5078
- shouldMaintainScrollAtEnd = true;
4819
+ if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
4820
+ shouldMaintainScrollAtEnd = true;
4821
+ }
4822
+ onItemSizeChanged == null ? void 0 : onItemSizeChanged({
4823
+ index,
4824
+ itemData: state.props.data[index],
4825
+ itemKey,
4826
+ previous: size - diff,
4827
+ size
4828
+ });
4829
+ maybeUpdateAnchoredEndSpace(ctx);
4830
+ }
4831
+ if (minIndexSizeChanged !== void 0) {
4832
+ state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
4833
+ }
4834
+ updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
4835
+ if (didContainersLayout || checkAllSizesKnown(state, state.startBuffered, state.endBuffered)) {
4836
+ const canMaintainScrollAtEnd = shouldMaintainScrollAtEnd && !!(maintainScrollAtEnd == null ? void 0 : maintainScrollAtEnd.onItemLayout);
4837
+ return {
4838
+ didChange: diff !== 0,
4839
+ didMeasureUserScrollAnchorResetItem,
4840
+ needsRecalculate,
4841
+ shouldMaintainScrollAtEnd: canMaintainScrollAtEnd
4842
+ };
4843
+ }
4844
+ return {
4845
+ didChange: diff !== 0,
4846
+ didMeasureUserScrollAnchorResetItem
4847
+ };
4848
+ }
4849
+ function updateOneItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
4850
+ var _a3, _b;
4851
+ const state = ctx.state;
4852
+ const {
4853
+ indexByKey,
4854
+ sizesKnown,
4855
+ averageSizes,
4856
+ props: { data, horizontal, getItemType, getFixedItemSize }
4857
+ } = state;
4858
+ if (!data) return 0;
4859
+ const index = indexByKey.get(itemKey);
4860
+ const itemData = data[index];
4861
+ let itemType = resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.itemType;
4862
+ let fixedItemSize = resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.fixedItemSize;
4863
+ if (getFixedItemSize && !(resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.didResolveFixedItemSize)) {
4864
+ itemType = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
4865
+ fixedItemSize = getFixedItemSize(itemData, index, itemType);
4866
+ }
4867
+ const resolvedItemSize = (resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.didResolveFixedItemSize) || itemType !== void 0 || fixedItemSize !== void 0 ? {
4868
+ didResolveFixedItemSize: resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.didResolveFixedItemSize,
4869
+ fixedItemSize,
4870
+ itemType
4871
+ } : void 0;
4872
+ const prevSize = getItemSize(ctx, itemKey, index, itemData, void 0, void 0, void 0, resolvedItemSize);
4873
+ const rawSize = horizontal ? sizeObj.width : sizeObj.height;
4874
+ const prevSizeKnown = sizesKnown.get(itemKey);
4875
+ if (Platform.OS !== "web" && prevSizeKnown !== void 0 && isNativeLayoutNoise(rawSize - prevSizeKnown)) {
4876
+ return 0;
4877
+ }
4878
+ const size = Platform.OS === "web" ? Math.round(rawSize) : roundSize(rawSize);
4879
+ sizesKnown.set(itemKey, size);
4880
+ if (fixedItemSize === void 0 && size > 0) {
4881
+ itemType != null ? itemType : itemType = getItemType ? (_b = getItemType(itemData, index)) != null ? _b : "" : "";
4882
+ let averages = averageSizes[itemType];
4883
+ if (!averages) {
4884
+ averages = averageSizes[itemType] = { avg: 0, num: 0 };
4885
+ }
4886
+ if (averages.num === 0) {
4887
+ averages.avg = size;
4888
+ averages.num++;
4889
+ } else if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
4890
+ averages.avg += (size - prevSizeKnown) / averages.num;
4891
+ } else {
4892
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
4893
+ averages.num++;
4894
+ }
4895
+ }
4896
+ if (!prevSize || Math.abs(prevSize - size) > 0.1) {
4897
+ setSize(ctx, itemKey, size);
4898
+ return size - prevSize;
4899
+ }
4900
+ return 0;
4901
+ }
4902
+
4903
+ // src/core/measureContainersInLayoutEffect.native.ts
4904
+ function resolveFixedItemSize(ctx, containerId, itemKey) {
4905
+ var _a3;
4906
+ const state = ctx.state;
4907
+ const { data, getFixedItemSize } = state.props;
4908
+ const index = state.indexByKey.get(itemKey);
4909
+ let fixedItemSize;
4910
+ if (data && getFixedItemSize && index !== void 0) {
4911
+ const itemData = data[index];
4912
+ if (itemData !== void 0) {
4913
+ fixedItemSize = (_a3 = resolveContainerItemMetadata(state, containerId, index, itemData)) == null ? void 0 : _a3.fixedItemSize;
4914
+ }
4915
+ }
4916
+ return fixedItemSize;
4917
+ }
4918
+ function resolveSkippedAnchorReset(ctx, itemKey) {
4919
+ const state = ctx.state;
4920
+ const anchorReset = state.userScrollAnchorReset;
4921
+ if ((anchorReset == null ? void 0 : anchorReset.keys.delete(itemKey)) && anchorReset.keys.size === 0) {
4922
+ state.userScrollAnchorReset = void 0;
4923
+ }
4924
+ }
4925
+ function measureContainersInLayoutEffect(ctx, targetContainerIds = null) {
4926
+ var _a3, _b, _c;
4927
+ const state = ctx.state;
4928
+ const measurements = [];
4929
+ let isCollectingSynchronousMeasurements = true;
4930
+ const containerIds = targetContainerIds != null ? targetContainerIds : ctx.viewRefs.keys();
4931
+ for (const containerId of containerIds) {
4932
+ const viewRef = ctx.viewRefs.get(containerId);
4933
+ const itemKey = peek$(ctx, `containerItemKey${containerId}`);
4934
+ if (itemKey !== void 0) {
4935
+ const generation = ((_a3 = state.containerItemGenerations[containerId]) != null ? _a3 : 0) + 1;
4936
+ state.containerItemGenerations[containerId] = generation;
4937
+ const fixedItemSize = resolveFixedItemSize(ctx, containerId, itemKey);
4938
+ const canSkipMeasurement = !state.needsOtherAxisSize && fixedItemSize !== void 0 && state.sizesKnown.get(itemKey) === fixedItemSize + ctx.scrollAxisGap;
4939
+ if (canSkipMeasurement) {
4940
+ resolveSkippedAnchorReset(ctx, itemKey);
4941
+ } else if (viewRef) {
4942
+ (_c = (_b = viewRef.current) == null ? void 0 : _b.measure) == null ? void 0 : _c.call(_b, (_x, _y, width, height) => {
4943
+ var _a4;
4944
+ const isCurrentGeneration = ((_a4 = ctx.state.containerItemGenerations[containerId]) != null ? _a4 : 0) === generation;
4945
+ if (isCurrentGeneration) {
4946
+ const measurement = {
4947
+ containerId,
4948
+ itemKey,
4949
+ size: { height, width }
4950
+ };
4951
+ if (isCollectingSynchronousMeasurements) {
4952
+ measurements.push(measurement);
4953
+ } else {
4954
+ updateItemSizes(ctx, measurement);
4955
+ }
4956
+ }
4957
+ });
4958
+ }
4959
+ }
4960
+ }
4961
+ isCollectingSynchronousMeasurements = false;
4962
+ if (measurements.length > 0) {
4963
+ updateItemSizesBatch(ctx, measurements);
4964
+ }
4965
+ }
4966
+ var typedForwardRef = React2__namespace.forwardRef;
4967
+ var typedMemo = React2__namespace.memo;
4968
+
4969
+ // src/components/ContainerLayoutCoordinator.tsx
4970
+ var ContainerLayoutCoordinator = typedMemo(function ContainerLayoutCoordinatorComponent({
4971
+ children
4972
+ }) {
4973
+ const ctx = useStateContext();
4974
+ const [containerLayoutEpoch] = useArr$(["containerLayoutEpoch"]);
4975
+ React2__namespace.useLayoutEffect(() => {
4976
+ if (IsNewArchitecture) {
4977
+ const targetContainerIds = getContainerLayoutEffectScope(ctx);
4978
+ if (targetContainerIds !== void 0) {
4979
+ measureContainersInLayoutEffect(ctx, targetContainerIds);
4980
+ }
4981
+ }
4982
+ }, [ctx, containerLayoutEpoch]);
4983
+ return children;
4984
+ });
4985
+
4986
+ // src/components/stickyPositionUtils.ts
4987
+ function getStickyPushLimit(state, index, itemKey) {
4988
+ if (!itemKey) {
4989
+ return void 0;
4990
+ }
4991
+ const currentSize = state.sizes.get(itemKey);
4992
+ if (!(currentSize && currentSize > 0)) {
4993
+ return void 0;
4994
+ }
4995
+ const stickyIndexInArray = state.props.stickyHeaderIndicesArr.indexOf(index);
4996
+ if (stickyIndexInArray === -1) {
4997
+ return void 0;
4998
+ }
4999
+ const nextStickyIndex = state.props.stickyHeaderIndicesArr[stickyIndexInArray + 1];
5000
+ if (nextStickyIndex === void 0) {
5001
+ return void 0;
5002
+ }
5003
+ const nextStickyPosition = state.positions[nextStickyIndex];
5004
+ if (nextStickyPosition === void 0) {
5005
+ return void 0;
5006
+ }
5007
+ return nextStickyPosition - currentSize;
5008
+ }
5009
+ var useAnimatedValue = (initialValue) => {
5010
+ const [animAnimatedValue] = React2.useState(() => new ReactNative.Animated.Value(initialValue));
5011
+ return animAnimatedValue;
5012
+ };
5013
+
5014
+ // src/hooks/useValue$.ts
5015
+ function useValue$(key, params) {
5016
+ const { getValue } = params || {};
5017
+ const ctx = useStateContext();
5018
+ const getNewValue = () => {
5019
+ var _a3;
5020
+ return (_a3 = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a3 : 0;
5021
+ };
5022
+ const animValue = useAnimatedValue(getNewValue());
5023
+ React2.useLayoutEffect(() => {
5024
+ const syncCurrentValue = () => {
5025
+ animValue.setValue(getNewValue());
5026
+ };
5027
+ const unsubscribe = listen$(ctx, key, syncCurrentValue);
5028
+ syncCurrentValue();
5029
+ return unsubscribe;
5030
+ }, [animValue, ctx, key]);
5031
+ return animValue;
5032
+ }
5033
+ var getComponent = (Component) => {
5034
+ if (React2__namespace.isValidElement(Component)) {
5035
+ return Component;
5036
+ }
5037
+ if (Component) {
5038
+ return /* @__PURE__ */ React2__namespace.createElement(Component, null);
5039
+ }
5040
+ return null;
5041
+ };
5042
+
5043
+ // src/components/PositionView.native.tsx
5044
+ var PositionViewState = typedMemo(function PositionViewState2({
5045
+ id,
5046
+ horizontal,
5047
+ style,
5048
+ refView,
5049
+ ...rest
5050
+ }) {
5051
+ const [position = POSITION_OUT_OF_VIEW, _itemKey] = useArr$([`containerPosition${id}`, `containerItemKey${id}`]);
5052
+ return /* @__PURE__ */ React2__namespace.createElement(ReactNative.View, { ref: refView, style: [style, horizontal ? { left: position } : { top: position }], ...rest });
5053
+ });
5054
+ var PositionViewAnimated = typedMemo(function PositionViewAnimated2({
5055
+ id,
5056
+ horizontal,
5057
+ style,
5058
+ refView,
5059
+ ...rest
5060
+ }) {
5061
+ const position$ = useValue$(`containerPosition${id}`, {
5062
+ getValue: (v) => v != null ? v : POSITION_OUT_OF_VIEW
5063
+ });
5064
+ const position = horizontal ? { left: position$ } : { top: position$ };
5065
+ return /* @__PURE__ */ React2__namespace.createElement(ReactNative.Animated.View, { ref: refView, style: [style, position], ...rest });
5066
+ });
5067
+ var PositionViewSticky = typedMemo(function PositionViewSticky2({
5068
+ id,
5069
+ horizontal,
5070
+ style,
5071
+ refView,
5072
+ animatedScrollY,
5073
+ stickyHeaderConfig,
5074
+ children,
5075
+ ...rest
5076
+ }) {
5077
+ const ctx = useStateContext();
5078
+ const [
5079
+ position = POSITION_OUT_OF_VIEW,
5080
+ alignItemsAtEndPadding = 0,
5081
+ headerSize = 0,
5082
+ stylePaddingTop = 0,
5083
+ itemKey,
5084
+ itemIndex,
5085
+ _totalSize = 0
5086
+ ] = useArr$([
5087
+ `containerPosition${id}`,
5088
+ "alignItemsAtEndPadding",
5089
+ "headerSize",
5090
+ "stylePaddingTop",
5091
+ `containerItemKey${id}`,
5092
+ `containerItemIndex${id}`,
5093
+ "totalSize"
5094
+ ]);
5095
+ const pushLimit = React2__namespace.useMemo(
5096
+ () => getStickyPushLimit(ctx.state, itemIndex, itemKey),
5097
+ [ctx.state, itemIndex, itemKey, _totalSize]
5098
+ );
5099
+ const transform = React2__namespace.useMemo(() => {
5100
+ var _a3;
5101
+ if (animatedScrollY) {
5102
+ const stickyConfigOffset = (_a3 = stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset) != null ? _a3 : 0;
5103
+ const stickyStart = position + headerSize + stylePaddingTop + alignItemsAtEndPadding - stickyConfigOffset;
5104
+ let nextStickyPosition;
5105
+ if (pushLimit !== void 0) {
5106
+ if (pushLimit <= position) {
5107
+ nextStickyPosition = pushLimit;
5108
+ } else {
5109
+ nextStickyPosition = animatedScrollY.interpolate({
5110
+ extrapolateLeft: "clamp",
5111
+ extrapolateRight: "clamp",
5112
+ inputRange: [stickyStart, stickyStart + (pushLimit - position)],
5113
+ outputRange: [position, pushLimit]
5114
+ });
5115
+ }
5116
+ } else {
5117
+ nextStickyPosition = animatedScrollY.interpolate({
5118
+ extrapolateLeft: "clamp",
5119
+ extrapolateRight: "extend",
5120
+ inputRange: [stickyStart, stickyStart + 5e3],
5121
+ outputRange: [position, position + 5e3]
5122
+ });
5123
+ }
5124
+ return horizontal ? [{ translateX: nextStickyPosition }] : [{ translateY: nextStickyPosition }];
5125
+ }
5126
+ }, [
5127
+ alignItemsAtEndPadding,
5128
+ animatedScrollY,
5129
+ headerSize,
5130
+ position,
5131
+ pushLimit,
5132
+ stylePaddingTop,
5133
+ stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset
5134
+ ]);
5135
+ const viewStyle = React2__namespace.useMemo(
5136
+ () => [style, { zIndex: itemIndex + 1e3 }, { transform }],
5137
+ [style, itemIndex, transform]
5138
+ );
5139
+ const renderStickyHeaderBackdrop = React2__namespace.useMemo(() => {
5140
+ if (!(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)) {
5141
+ return null;
5142
+ }
5143
+ return /* @__PURE__ */ React2__namespace.createElement(
5144
+ ReactNative.View,
5145
+ {
5146
+ style: {
5147
+ inset: 0,
5148
+ pointerEvents: "none",
5149
+ position: "absolute"
5150
+ }
5151
+ },
5152
+ getComponent(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)
5153
+ );
5154
+ }, [stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent]);
5155
+ return /* @__PURE__ */ React2__namespace.createElement(ReactNative.Animated.View, { ref: refView, style: viewStyle, ...rest }, renderStickyHeaderBackdrop, children);
5156
+ });
5157
+ var PositionView = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
5158
+ function useInit(cb) {
5159
+ React2.useState(() => cb());
5160
+ }
5161
+
5162
+ // src/state/ContextContainer.ts
5163
+ var ContextContainer = React2.createContext(null);
5164
+ var NO_CONTAINER_ID = -1;
5165
+ function useContextContainer() {
5166
+ return React2.useContext(ContextContainer);
5167
+ }
5168
+ function useContainerItemSignals(containerContext) {
5169
+ var _a3;
5170
+ const containerId = (_a3 = containerContext == null ? void 0 : containerContext.containerId) != null ? _a3 : NO_CONTAINER_ID;
5171
+ const [itemKey, itemIndex, item] = useArr$([
5172
+ `containerItemKey${containerId}`,
5173
+ `containerItemIndex${containerId}`,
5174
+ `containerItemData${containerId}`
5175
+ ]);
5176
+ return {
5177
+ hasItemInfo: !!containerContext && itemKey !== void 0 && itemIndex !== void 0,
5178
+ item,
5179
+ itemIndex,
5180
+ itemKey
5181
+ };
5182
+ }
5183
+ function useAdaptiveRender() {
5184
+ const [mode] = useArr$(["adaptiveRender"]);
5185
+ return mode;
5186
+ }
5187
+ function useAdaptiveRenderChange(callback) {
5188
+ const ctx = useStateContext();
5189
+ const callbackRef = React2.useRef(callback);
5190
+ callbackRef.current = callback;
5191
+ React2.useLayoutEffect(() => {
5192
+ let mode = peek$(ctx, "adaptiveRender");
5193
+ return listen$(ctx, "adaptiveRender", (nextMode) => {
5194
+ if (mode !== nextMode) {
5195
+ mode = nextMode;
5196
+ callbackRef.current(nextMode);
5197
+ }
5198
+ });
5199
+ }, [ctx]);
5200
+ }
5201
+ function useViewability(callback, configId) {
5202
+ const ctx = useStateContext();
5203
+ const containerContext = useContextContainer();
5204
+ useInit(() => {
5205
+ if (!containerContext) {
5206
+ return;
5207
+ }
5208
+ const { containerId } = containerContext;
5209
+ const key = containerId + (configId != null ? configId : "");
5210
+ const value = ctx.mapViewabilityValues.get(key);
5211
+ if (value) {
5212
+ callback(value);
5213
+ }
5214
+ });
5215
+ React2.useEffect(() => {
5216
+ if (!containerContext) {
5217
+ return;
5218
+ }
5219
+ const { containerId } = containerContext;
5220
+ const key = containerId + (configId != null ? configId : "");
5221
+ ctx.mapViewabilityCallbacks.set(key, callback);
5222
+ return () => {
5223
+ ctx.mapViewabilityCallbacks.delete(key);
5224
+ };
5225
+ }, [ctx, callback, configId, containerContext]);
5226
+ }
5227
+ function useViewabilityAmount(callback) {
5228
+ const ctx = useStateContext();
5229
+ const containerContext = useContextContainer();
5230
+ useInit(() => {
5231
+ if (!containerContext) {
5232
+ return;
5233
+ }
5234
+ const { containerId } = containerContext;
5235
+ const value = ctx.mapViewabilityAmountValues.get(containerId);
5236
+ if (value) {
5237
+ callback(value);
5238
+ }
5239
+ });
5240
+ React2.useEffect(() => {
5241
+ if (!containerContext) {
5242
+ return;
5243
+ }
5244
+ const { containerId } = containerContext;
5245
+ ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
5246
+ return () => {
5247
+ ctx.mapViewabilityAmountCallbacks.delete(containerId);
5248
+ };
5249
+ }, [ctx, callback, containerContext]);
5250
+ }
5251
+ function useRecyclingEffect(effect) {
5252
+ const containerContext = useContextContainer();
5253
+ const { hasItemInfo, item, itemIndex, itemKey } = useContainerItemSignals(containerContext);
5254
+ const prevInfo = React2.useRef(void 0);
5255
+ React2.useEffect(() => {
5256
+ if (!hasItemInfo) {
5257
+ return;
5258
+ }
5259
+ let ret;
5260
+ if (prevInfo.current) {
5261
+ ret = effect({
5262
+ index: itemIndex,
5263
+ item,
5264
+ prevIndex: prevInfo.current.index,
5265
+ prevItem: prevInfo.current.item
5266
+ });
5079
5267
  }
5080
- onItemSizeChanged == null ? void 0 : onItemSizeChanged({
5081
- index,
5082
- itemData: state.props.data[index],
5083
- itemKey,
5084
- previous: size - diff,
5085
- size
5086
- });
5087
- maybeUpdateAnchoredEndSpace(ctx);
5088
- }
5089
- if (minIndexSizeChanged !== void 0) {
5090
- state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
5091
- }
5092
- updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
5093
- if (didContainersLayout || checkAllSizesKnown(state, state.startBuffered, state.endBuffered)) {
5094
- const canMaintainScrollAtEnd = shouldMaintainScrollAtEnd && !!(maintainScrollAtEnd == null ? void 0 : maintainScrollAtEnd.onItemLayout);
5095
- return {
5096
- didChange: diff !== 0,
5097
- didMeasureUserScrollAnchorResetItem,
5098
- needsRecalculate,
5099
- shouldMaintainScrollAtEnd: canMaintainScrollAtEnd
5268
+ prevInfo.current = {
5269
+ index: itemIndex,
5270
+ item
5100
5271
  };
5101
- }
5102
- return {
5103
- didChange: diff !== 0,
5104
- didMeasureUserScrollAnchorResetItem
5105
- };
5272
+ return ret;
5273
+ }, [effect, hasItemInfo, itemIndex, item, itemKey]);
5106
5274
  }
5107
- function updateOneItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
5108
- var _a3, _b, _c;
5109
- const state = ctx.state;
5110
- const {
5111
- indexByKey,
5112
- sizesKnown,
5113
- averageSizes,
5114
- props: { data, horizontal, getItemType, getFixedItemSize }
5115
- } = state;
5116
- if (!data) return 0;
5117
- const index = indexByKey.get(itemKey);
5118
- const itemData = (_a3 = resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.itemData) != null ? _a3 : data[index];
5119
- let itemType = resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.itemType;
5120
- let fixedItemSize = resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.fixedItemSize;
5121
- if (getFixedItemSize && !(resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.didResolveFixedItemSize)) {
5122
- itemType = getItemType ? (_b = getItemType(itemData, index)) != null ? _b : "" : "";
5123
- fixedItemSize = getFixedItemSize(itemData, index, itemType);
5124
- }
5125
- const resolvedItemSize = (resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.didResolveFixedItemSize) || itemType !== void 0 || fixedItemSize !== void 0 ? {
5126
- didResolveFixedItemSize: resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.didResolveFixedItemSize,
5127
- fixedItemSize,
5128
- itemType
5129
- } : void 0;
5130
- const prevSize = getItemSize(ctx, itemKey, index, itemData, void 0, void 0, void 0, resolvedItemSize);
5131
- const rawSize = horizontal ? sizeObj.width : sizeObj.height;
5132
- const prevSizeKnown = sizesKnown.get(itemKey);
5133
- if (Platform.OS !== "web" && prevSizeKnown !== void 0 && isNativeLayoutNoise(rawSize - prevSizeKnown)) {
5134
- return 0;
5135
- }
5136
- const size = Platform.OS === "web" ? Math.round(rawSize) : roundSize(rawSize);
5137
- sizesKnown.set(itemKey, size);
5138
- if (fixedItemSize === void 0 && size > 0) {
5139
- itemType != null ? itemType : itemType = getItemType ? (_c = getItemType(itemData, index)) != null ? _c : "" : "";
5140
- let averages = averageSizes[itemType];
5141
- if (!averages) {
5142
- averages = averageSizes[itemType] = { avg: 0, num: 0 };
5143
- }
5144
- if (averages.num === 0) {
5145
- averages.avg = size;
5146
- averages.num++;
5147
- } else if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
5148
- averages.avg += (size - prevSizeKnown) / averages.num;
5149
- } else {
5150
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
5151
- averages.num++;
5275
+ function useRecyclingState(valueOrFun) {
5276
+ const containerContext = useContextContainer();
5277
+ const { hasItemInfo, item, itemIndex, itemKey } = useContainerItemSignals(containerContext);
5278
+ const computeValue = () => {
5279
+ if (isFunction(valueOrFun)) {
5280
+ const initializer = valueOrFun;
5281
+ return hasItemInfo ? initializer({
5282
+ index: itemIndex,
5283
+ item,
5284
+ prevIndex: void 0,
5285
+ prevItem: void 0
5286
+ }) : initializer();
5152
5287
  }
5288
+ return valueOrFun;
5289
+ };
5290
+ const [stateValue, setStateValue] = React2.useState(() => {
5291
+ return computeValue();
5292
+ });
5293
+ const prevItemKeyRef = React2.useRef(hasItemInfo ? itemKey : null);
5294
+ if (hasItemInfo && prevItemKeyRef.current !== itemKey) {
5295
+ prevItemKeyRef.current = itemKey;
5296
+ setStateValue(computeValue());
5153
5297
  }
5154
- if (!prevSize || Math.abs(prevSize - size) > 0.1) {
5155
- setSize(ctx, itemKey, size);
5156
- return size - prevSize;
5157
- }
5158
- return 0;
5298
+ const triggerLayout = containerContext == null ? void 0 : containerContext.triggerLayout;
5299
+ const setState = React2.useCallback(
5300
+ (newState) => {
5301
+ if (!triggerLayout) {
5302
+ return;
5303
+ }
5304
+ setStateValue((prevValue) => {
5305
+ return isFunction(newState) ? newState(prevValue) : newState;
5306
+ });
5307
+ triggerLayout();
5308
+ },
5309
+ [triggerLayout]
5310
+ );
5311
+ return [stateValue, setState];
5312
+ }
5313
+ function useIsLastItem() {
5314
+ var _a3;
5315
+ const containerContext = useContextContainer();
5316
+ const containerId = (_a3 = containerContext == null ? void 0 : containerContext.containerId) != null ? _a3 : NO_CONTAINER_ID;
5317
+ const [itemKey] = useArr$([`containerItemKey${containerId}`]);
5318
+ const isLast = useSelector$("lastItemKeys", (lastItemKeys) => {
5319
+ if (containerContext && !isNullOrUndefined(itemKey)) {
5320
+ return (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false;
5321
+ }
5322
+ return false;
5323
+ });
5324
+ return isLast;
5325
+ }
5326
+ function useListScrollSize() {
5327
+ const [scrollSize] = useArr$(["scrollSize"]);
5328
+ return scrollSize;
5329
+ }
5330
+ var noop = () => {
5331
+ };
5332
+ function useSyncLayout() {
5333
+ const containerContext = useContextContainer();
5334
+ return IsNewArchitecture && containerContext ? containerContext.triggerLayout : noop;
5335
+ }
5336
+
5337
+ // src/components/Separator.tsx
5338
+ function Separator({ ItemSeparatorComponent, leadingItem }) {
5339
+ const isLastItem = useIsLastItem();
5340
+ return isLastItem ? null : /* @__PURE__ */ React2__namespace.createElement(ItemSeparatorComponent, { leadingItem });
5159
5341
  }
5160
5342
  function useOnLayoutSync({
5161
5343
  ref,
5344
+ measureInLayoutEffect = true,
5162
5345
  onLayoutProp,
5163
5346
  onLayoutChange
5164
5347
  }, deps = []) {
@@ -5172,16 +5355,154 @@ function useOnLayoutSync({
5172
5355
  );
5173
5356
  if (IsNewArchitecture) {
5174
5357
  React2.useLayoutEffect(() => {
5175
- if (ref.current) {
5358
+ if (measureInLayoutEffect && ref.current) {
5176
5359
  ref.current.measure((x, y, width, height) => {
5177
5360
  onLayoutChange({ height, width, x, y }, true);
5178
5361
  });
5179
5362
  }
5180
- }, deps);
5363
+ }, [measureInLayoutEffect, ...deps]);
5181
5364
  }
5182
5365
  return { onLayout };
5183
5366
  }
5184
5367
 
5368
+ // src/hooks/useContainerMeasurement.tsx
5369
+ var pendingWebShrinkMeasurements = /* @__PURE__ */ new Map();
5370
+ var pendingWebShrinkFrame;
5371
+ function cancelWebShrinkMeasurement(state) {
5372
+ pendingWebShrinkMeasurements.delete(state);
5373
+ }
5374
+ function scheduleWebShrinkMeasurement(state, confirmMeasurement) {
5375
+ pendingWebShrinkMeasurements.set(state, confirmMeasurement);
5376
+ if (pendingWebShrinkFrame === void 0) {
5377
+ pendingWebShrinkFrame = requestAnimationFrame(() => {
5378
+ const callbacks = Array.from(pendingWebShrinkMeasurements.values());
5379
+ pendingWebShrinkMeasurements.clear();
5380
+ pendingWebShrinkFrame = void 0;
5381
+ batchItemSizeUpdates(() => {
5382
+ for (const callback of callbacks) {
5383
+ callback();
5384
+ }
5385
+ });
5386
+ });
5387
+ }
5388
+ }
5389
+ function processContainerLayout({ containerId, ctx, rectangle, ref, state }) {
5390
+ var _a3, _b;
5391
+ const listState = ctx.state;
5392
+ const currentItemKey = state.itemKey;
5393
+ state.didLayout = true;
5394
+ let layout = rectangle;
5395
+ const axis = state.horizontal ? "width" : "height";
5396
+ const size = roundSize(rectangle[axis]);
5397
+ const localPreviousSize = state.lastSize ? roundSize(state.lastSize[axis]) : void 0;
5398
+ const coreKnownSize = listState.sizesKnown.get(currentItemKey);
5399
+ const previousSize = Platform.OS === "web" ? coreKnownSize : localPreviousSize;
5400
+ const applyLayout = () => {
5401
+ state.lastSize = layout;
5402
+ updateItemSizes(ctx, {
5403
+ containerId,
5404
+ itemKey: currentItemKey,
5405
+ size: layout
5406
+ });
5407
+ };
5408
+ const shouldDeferWebShrinkLayoutUpdate = Platform.OS === "web" && !isInMVCPActiveMode(listState) && previousSize !== void 0 && size + 1 < previousSize;
5409
+ if (shouldDeferWebShrinkLayoutUpdate) {
5410
+ scheduleWebShrinkMeasurement(state, () => {
5411
+ var _a4;
5412
+ if (state.itemKey === currentItemKey) {
5413
+ const element = ref.current;
5414
+ const rect = (_a4 = element == null ? void 0 : element.getBoundingClientRect) == null ? void 0 : _a4.call(element);
5415
+ if (rect) {
5416
+ layout = { height: rect.height, width: rect.width };
5417
+ }
5418
+ applyLayout();
5419
+ }
5420
+ });
5421
+ } else {
5422
+ if (Platform.OS === "web") {
5423
+ cancelWebShrinkMeasurement(state);
5424
+ }
5425
+ if (IsNewArchitecture || size > 0) {
5426
+ applyLayout();
5427
+ } else {
5428
+ (_b = (_a3 = ref.current) == null ? void 0 : _a3.measure) == null ? void 0 : _b.call(_a3, (_x, _y, width, height) => {
5429
+ layout = { height, width };
5430
+ applyLayout();
5431
+ });
5432
+ }
5433
+ }
5434
+ }
5435
+ function useContainerMeasurement({
5436
+ containerId,
5437
+ ctx,
5438
+ horizontal,
5439
+ itemKey,
5440
+ ref
5441
+ }) {
5442
+ const stateRef = React2.useRef({
5443
+ didLayout: false,
5444
+ horizontal,
5445
+ itemKey
5446
+ });
5447
+ stateRef.current.horizontal = horizontal;
5448
+ stateRef.current.itemKey = itemKey;
5449
+ const [layoutRenderCount, forceLayoutRender] = React2.useState(0);
5450
+ const onLayoutChange = React2.useCallback(
5451
+ (rectangle) => {
5452
+ processContainerLayout({ containerId, ctx, rectangle, ref, state: stateRef.current });
5453
+ },
5454
+ [containerId, ctx, ref]
5455
+ );
5456
+ const triggerLayout = React2.useCallback(() => {
5457
+ if (IsNewArchitecture) {
5458
+ scheduleContainerLayout(ctx, containerId);
5459
+ } else {
5460
+ forceLayoutRender((value) => value + 1);
5461
+ }
5462
+ }, [containerId, ctx]);
5463
+ React2.useLayoutEffect(() => {
5464
+ ctx.containerLayoutTriggers.set(containerId, triggerLayout);
5465
+ return () => {
5466
+ cancelWebShrinkMeasurement(stateRef.current);
5467
+ if (ctx.containerLayoutTriggers.get(containerId) === triggerLayout) {
5468
+ ctx.containerLayoutTriggers.delete(containerId);
5469
+ }
5470
+ };
5471
+ }, [containerId, ctx, triggerLayout]);
5472
+ React2.useLayoutEffect(() => {
5473
+ if (IsNewArchitecture) {
5474
+ scheduleContainerLayout(ctx, containerId);
5475
+ }
5476
+ });
5477
+ const { onLayout } = useOnLayoutSync(
5478
+ {
5479
+ measureInLayoutEffect: !IsNewArchitecture,
5480
+ onLayoutChange,
5481
+ ref},
5482
+ [itemKey, layoutRenderCount]
5483
+ );
5484
+ React2.useEffect(() => {
5485
+ if (!IsNewArchitecture) {
5486
+ stateRef.current.didLayout = false;
5487
+ const timeout = setTimeout(() => {
5488
+ const state = stateRef.current;
5489
+ if (!state.didLayout && state.lastSize) {
5490
+ updateItemSizes(ctx, {
5491
+ containerId,
5492
+ itemKey: state.itemKey,
5493
+ size: state.lastSize
5494
+ });
5495
+ state.didLayout = true;
5496
+ }
5497
+ }, 16);
5498
+ return () => {
5499
+ clearTimeout(timeout);
5500
+ };
5501
+ }
5502
+ }, [containerId, ctx, itemKey]);
5503
+ return { onLayout, triggerLayout };
5504
+ }
5505
+
5185
5506
  // src/components/Container.tsx
5186
5507
  function getContainerPositionStyle({
5187
5508
  columnWrapperStyle,
@@ -5252,16 +5573,14 @@ var Container = typedMemo(function Container2({
5252
5573
  "extraData",
5253
5574
  `containerSticky${id}`
5254
5575
  ]);
5255
- const itemLayoutRef = React2.useRef({
5256
- didLayout: false,
5576
+ const ref = React2.useRef(null);
5577
+ const { onLayout, triggerLayout } = useContainerMeasurement({
5578
+ containerId: id,
5579
+ ctx,
5257
5580
  horizontal,
5258
5581
  itemKey,
5259
- pendingShrinkToken: 0
5582
+ ref
5260
5583
  });
5261
- itemLayoutRef.current.horizontal = horizontal;
5262
- itemLayoutRef.current.itemKey = itemKey;
5263
- const ref = React2.useRef(null);
5264
- const [layoutRenderCount, forceLayoutRender] = React2.useState(0);
5265
5584
  const resolvedColumn = column > 0 ? column : 1;
5266
5585
  const resolvedSpan = Math.min(Math.max(span || 1, 1), numColumns);
5267
5586
  const otherAxisPos = numColumns > 1 ? `${(resolvedColumn - 1) / numColumns * 100}%` : 0;
@@ -5292,63 +5611,7 @@ var Container = typedMemo(function Container2({
5292
5611
  () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
5293
5612
  [itemKey, data, extraData]
5294
5613
  );
5295
- const { index, renderedItem } = renderedItemInfo || {};
5296
- const onLayoutChange = React2.useCallback((rectangle, fromLayoutEffect) => {
5297
- var _a3, _b;
5298
- const {
5299
- horizontal: currentHorizontal,
5300
- itemKey: currentItemKey,
5301
- lastSize,
5302
- pendingShrinkToken
5303
- } = itemLayoutRef.current;
5304
- if (isNullOrUndefined(currentItemKey)) {
5305
- return;
5306
- }
5307
- itemLayoutRef.current.didLayout = true;
5308
- let layout = rectangle;
5309
- const axis = currentHorizontal ? "width" : "height";
5310
- const size = roundSize(rectangle[axis]);
5311
- const prevSize = lastSize ? roundSize(lastSize[axis]) : void 0;
5312
- const doUpdate = () => {
5313
- itemLayoutRef.current.lastSize = layout;
5314
- updateItemSizes(ctx, {
5315
- containerId: id,
5316
- fromLayoutEffect,
5317
- itemKey: currentItemKey,
5318
- size: layout
5319
- });
5320
- itemLayoutRef.current.didLayout = true;
5321
- };
5322
- const shouldDeferWebShrinkLayoutUpdate = Platform.OS === "web" && !isInMVCPActiveMode(ctx.state) && prevSize !== void 0 && size + 1 < prevSize;
5323
- if (shouldDeferWebShrinkLayoutUpdate) {
5324
- const token = pendingShrinkToken + 1;
5325
- itemLayoutRef.current.pendingShrinkToken = token;
5326
- requestAnimationFrame(() => {
5327
- var _a4;
5328
- if (itemLayoutRef.current.pendingShrinkToken !== token) {
5329
- return;
5330
- }
5331
- const element = ref.current;
5332
- const rect = (_a4 = element == null ? void 0 : element.getBoundingClientRect) == null ? void 0 : _a4.call(element);
5333
- if (rect) {
5334
- layout = { height: rect.height, width: rect.width };
5335
- }
5336
- doUpdate();
5337
- });
5338
- return;
5339
- }
5340
- if (IsNewArchitecture || size > 0) {
5341
- doUpdate();
5342
- } else {
5343
- (_b = (_a3 = ref.current) == null ? void 0 : _a3.measure) == null ? void 0 : _b.call(_a3, (_x, _y, width, height) => {
5344
- layout = { height, width };
5345
- doUpdate();
5346
- });
5347
- }
5348
- }, []);
5349
- const triggerLayout = React2.useCallback(() => {
5350
- forceLayoutRender((v) => v + 1);
5351
- }, []);
5614
+ const { renderedItem } = renderedItemInfo || {};
5352
5615
  const contextValue = React2.useMemo(() => {
5353
5616
  ctx.viewRefs.set(id, ref);
5354
5617
  return {
@@ -5356,44 +5619,6 @@ var Container = typedMemo(function Container2({
5356
5619
  triggerLayout
5357
5620
  };
5358
5621
  }, [id, triggerLayout]);
5359
- React2.useLayoutEffect(() => {
5360
- ctx.containerLayoutTriggers.set(id, triggerLayout);
5361
- return () => {
5362
- if (ctx.containerLayoutTriggers.get(id) === triggerLayout) {
5363
- ctx.containerLayoutTriggers.delete(id);
5364
- }
5365
- };
5366
- }, [ctx, id, triggerLayout]);
5367
- const { onLayout } = useOnLayoutSync(
5368
- {
5369
- onLayoutChange,
5370
- ref},
5371
- [itemKey, layoutRenderCount]
5372
- );
5373
- if (!IsNewArchitecture) {
5374
- React2.useEffect(() => {
5375
- if (!isNullOrUndefined(itemKey)) {
5376
- itemLayoutRef.current.didLayout = false;
5377
- const timeout = setTimeout(() => {
5378
- if (!itemLayoutRef.current.didLayout) {
5379
- const { itemKey: currentItemKey, lastSize } = itemLayoutRef.current;
5380
- if (lastSize && !isNullOrUndefined(currentItemKey)) {
5381
- updateItemSizes(ctx, {
5382
- containerId: id,
5383
- fromLayoutEffect: false,
5384
- itemKey: currentItemKey,
5385
- size: lastSize
5386
- });
5387
- itemLayoutRef.current.didLayout = true;
5388
- }
5389
- }
5390
- }, 16);
5391
- return () => {
5392
- clearTimeout(timeout);
5393
- };
5394
- }
5395
- }, [itemKey]);
5396
- }
5397
5622
  const PositionComponent = isSticky ? stickyPositionComponentInternal ? stickyPositionComponentInternal : PositionViewSticky : positionComponentInternal ? positionComponentInternal : PositionView;
5398
5623
  return /* @__PURE__ */ React2__namespace.createElement(
5399
5624
  PositionComponent,
@@ -5401,7 +5626,6 @@ var Container = typedMemo(function Container2({
5401
5626
  animatedScrollY: isSticky ? animatedScrollY : void 0,
5402
5627
  horizontal,
5403
5628
  id,
5404
- index,
5405
5629
  key: recycleItems ? void 0 : itemKey,
5406
5630
  onLayout,
5407
5631
  refView: ref,
@@ -5475,7 +5699,7 @@ var ContainersLayer = typedMemo(function ContainersLayer2({ children, horizontal
5475
5699
  }
5476
5700
  }
5477
5701
  }
5478
- return /* @__PURE__ */ React2__namespace.createElement(ReactNative.Animated.View, { style }, children);
5702
+ return /* @__PURE__ */ React2__namespace.createElement(ReactNative.Animated.View, { style }, /* @__PURE__ */ React2__namespace.createElement(ContainerLayoutCoordinator, null, children));
5479
5703
  });
5480
5704
  var Containers = typedMemo(function Containers2({
5481
5705
  horizontal,
@@ -5662,6 +5886,8 @@ var ListComponent = typedMemo(function ListComponent2({
5662
5886
  refScrollView,
5663
5887
  renderScrollComponent,
5664
5888
  onLayoutFooter,
5889
+ onInternalScrollBeginDrag,
5890
+ onInternalScrollEnd,
5665
5891
  scrollAdjustHandler,
5666
5892
  snapToIndices,
5667
5893
  stickyHeaderConfig,
@@ -5723,7 +5949,7 @@ var ListComponent = typedMemo(function ListComponent2({
5723
5949
  SnapOrScroll,
5724
5950
  {
5725
5951
  ...rest,
5726
- ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
5952
+ ...Platform.OS === "web" ? ScrollComponent === ListComponentScrollView ? { onInternalScrollEnd, useWindowScroll } : {} : { onScrollBeginDrag: onInternalScrollBeginDrag },
5727
5953
  contentContainerStyle: [
5728
5954
  horizontal ? {
5729
5955
  height: "100%"
@@ -5829,6 +6055,7 @@ function checkResetContainers(ctx, dataProp, { didColumnsChange = false } = {})
5829
6055
  if (didColumnsChange) {
5830
6056
  state.sizes.clear();
5831
6057
  state.sizesKnown.clear();
6058
+ invalidateContainerFixedItemSizes(state);
5832
6059
  for (const key in state.averageSizes) {
5833
6060
  delete state.averageSizes[key];
5834
6061
  }
@@ -6075,7 +6302,7 @@ function onScroll(ctx, event) {
6075
6302
  }
6076
6303
  }
6077
6304
  state.scrollPending = newScroll;
6078
- updateScroll(ctx, newScroll, insetChanged);
6305
+ updateScroll(ctx, newScroll, insetChanged, { fromNativeScrollEvent: true });
6079
6306
  trackInitialScrollNativeProgress(state, newScroll);
6080
6307
  clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx);
6081
6308
  if (state.scrollingTo) {
@@ -6251,8 +6478,12 @@ function getAverageItemSizes(state) {
6251
6478
  return averageItemSizes;
6252
6479
  }
6253
6480
  function triggerMountedContainerLayouts(ctx) {
6254
- for (const triggerLayout of ctx.containerLayoutTriggers.values()) {
6255
- triggerLayout();
6481
+ if (IsNewArchitecture) {
6482
+ scheduleContainerLayout(ctx);
6483
+ } else {
6484
+ for (const triggerLayout of ctx.containerLayoutTriggers.values()) {
6485
+ triggerLayout();
6486
+ }
6256
6487
  }
6257
6488
  }
6258
6489
  function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
@@ -6365,6 +6596,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6365
6596
  const mode = (_a3 = options == null ? void 0 : options.mode) != null ? _a3 : "sizes";
6366
6597
  state.sizes.clear();
6367
6598
  state.sizesKnown.clear();
6599
+ invalidateContainerFixedItemSizes(state);
6368
6600
  for (const key in state.averageSizes) {
6369
6601
  delete state.averageSizes[key];
6370
6602
  }
@@ -6386,6 +6618,10 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6386
6618
  return {
6387
6619
  clearCaches,
6388
6620
  flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
6621
+ getAnimatableRef: () => {
6622
+ var _a3, _b, _c;
6623
+ return (_c = (_b = (_a3 = refScroller.current).getNativeScrollRef) == null ? void 0 : _b.call(_a3)) != null ? _c : refScroller.current;
6624
+ },
6389
6625
  getNativeScrollRef: () => refScroller.current,
6390
6626
  getScrollableNode: () => refScroller.current.getScrollableNode(),
6391
6627
  getScrollResponder: () => refScroller.current.getScrollResponder(),
@@ -6756,6 +6992,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6756
6992
  onMomentumScrollEnd,
6757
6993
  onRefresh,
6758
6994
  onScroll: onScrollProp,
6995
+ onScrollBeginDrag,
6759
6996
  onStartReached,
6760
6997
  onStartReachedThreshold = 0.5,
6761
6998
  onStickyHeaderChange,
@@ -6867,8 +7104,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6867
7104
  averageSizes: {},
6868
7105
  columnSpans: [],
6869
7106
  columns: [],
7107
+ containerItemGenerations: [],
6870
7108
  containerItemKeys: /* @__PURE__ */ new Map(),
6871
- containerItemTypes: /* @__PURE__ */ new Map(),
7109
+ containerItemMetadata: /* @__PURE__ */ new Map(),
6872
7110
  contentInsetOverride: void 0,
6873
7111
  dataChangeEpoch: 0,
6874
7112
  dataChangeNeedsScrollUpdate: false,
@@ -6921,7 +7159,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6921
7159
  startBuffered: -1,
6922
7160
  startNoBuffer: -1,
6923
7161
  startReachedSnapshot: void 0,
6924
- startReachedSnapshotDataChangeEpoch: void 0,
6925
7162
  stickyContainerPool: /* @__PURE__ */ new Set(),
6926
7163
  stickyContainers: /* @__PURE__ */ new Map(),
6927
7164
  timeoutAdaptiveRender: void 0,
@@ -6997,7 +7234,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6997
7234
  onFirstVisibleItemChanged,
6998
7235
  onItemSizeChanged,
6999
7236
  onLoad,
7237
+ onMomentumScrollEnd,
7000
7238
  onScroll: throttleScrollFn,
7239
+ onScrollBeginDrag,
7001
7240
  onStartReached,
7002
7241
  onStartReachedThreshold,
7003
7242
  onStickyHeaderChange,
@@ -7280,11 +7519,17 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7280
7519
  getRenderedItem: (key) => getRenderedItem(ctx, key),
7281
7520
  onMomentumScrollEnd: (event) => {
7282
7521
  checkFinishedScrollFallback(ctx);
7283
- if (onMomentumScrollEnd) {
7284
- onMomentumScrollEnd(event);
7522
+ if (state.props.onMomentumScrollEnd) {
7523
+ state.props.onMomentumScrollEnd(event);
7285
7524
  }
7286
7525
  },
7287
- onScroll: (event) => onScroll(ctx, event)
7526
+ onScroll: (event) => onScroll(ctx, event),
7527
+ onScrollBeginDrag: (event) => {
7528
+ var _a4, _b2;
7529
+ prepareReachedEdgeForNextUserScroll(ctx);
7530
+ (_b2 = (_a4 = state.props).onScrollBeginDrag) == null ? void 0 : _b2.call(_a4, event);
7531
+ },
7532
+ onScrollEnd: () => prepareReachedEdgeForNextUserScroll(ctx)
7288
7533
  }),
7289
7534
  []
7290
7535
  );
@@ -7305,6 +7550,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7305
7550
  ListFooterComponent,
7306
7551
  ListFooterComponentStyle,
7307
7552
  ListHeaderComponent,
7553
+ onInternalScrollBeginDrag: fns.onScrollBeginDrag,
7554
+ onInternalScrollEnd: fns.onScrollEnd,
7308
7555
  onLayout,
7309
7556
  onLayoutFooter,
7310
7557
  onMomentumScrollEnd: fns.onMomentumScrollEnd,