@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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React2 from 'react';
2
- import { useReducer, useEffect, createContext, useRef, useState, useMemo, useCallback, useLayoutEffect, useImperativeHandle, useContext } from 'react';
2
+ import { useReducer, useEffect, createContext, useRef, useMemo, useCallback, useLayoutEffect, useImperativeHandle, useState, useContext } from 'react';
3
3
  import * as ReactNative from 'react-native';
4
4
  import { Animated, Platform as Platform$1, View as View$1, Text as Text$1, PixelRatio as PixelRatio$1, StyleSheet as StyleSheet$1, RefreshControl, Dimensions, I18nManager } from 'react-native';
5
5
  import { useSyncExternalStore } from 'use-sync-external-store/shim';
@@ -131,11 +131,13 @@ function StateProvider({ children }) {
131
131
  mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
132
132
  mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
133
133
  mapViewabilityValues: /* @__PURE__ */ new Map(),
134
+ pendingContainerIds: void 0,
134
135
  positionListeners: /* @__PURE__ */ new Map(),
135
136
  scrollAxisGap: 0,
136
137
  state: void 0,
137
138
  values: /* @__PURE__ */ new Map([
138
139
  ["alignItemsAtEndPadding", 0],
140
+ ["containerLayoutEpoch", 0],
139
141
  ["stylePaddingTop", 0],
140
142
  ["headerSize", 0],
141
143
  ["numContainers", 0],
@@ -360,28 +362,49 @@ function useInterval(callback, delay) {
360
362
  }, [delay]);
361
363
  }
362
364
 
363
- // src/components/stickyPositionUtils.ts
364
- function getStickyPushLimit(state, index, itemKey) {
365
- if (!itemKey) {
366
- return void 0;
367
- }
368
- const currentSize = state.sizes.get(itemKey);
369
- if (!(currentSize && currentSize > 0)) {
370
- return void 0;
365
+ // src/constants-platform.native.ts
366
+ var f = global.nativeFabricUIManager;
367
+ var IsNewArchitecture = f !== void 0 && f != null;
368
+
369
+ // src/core/containerItemMetadata.ts
370
+ function createContainerItemMetadata(state, itemIndex, itemData, itemType) {
371
+ return {
372
+ dataChangeEpoch: state.dataChangeEpoch,
373
+ getFixedItemSize: state.props.getFixedItemSize,
374
+ getItemType: state.props.getItemType,
375
+ itemData,
376
+ itemIndex,
377
+ itemType
378
+ };
379
+ }
380
+ function resolveContainerItemMetadata(state, containerId, itemIndex, itemData) {
381
+ var _a3, _b;
382
+ const { getFixedItemSize, getItemType } = state.props;
383
+ const previousMetadata = state.containerItemMetadata.get(containerId);
384
+ let metadata;
385
+ if ((previousMetadata == null ? void 0 : previousMetadata.dataChangeEpoch) === state.dataChangeEpoch && previousMetadata.getItemType === getItemType && previousMetadata.itemData === itemData && previousMetadata.itemIndex === itemIndex) {
386
+ metadata = previousMetadata;
387
+ } else {
388
+ const itemType = getItemType ? (_a3 = getItemType(itemData, itemIndex)) != null ? _a3 : "" : void 0;
389
+ metadata = createContainerItemMetadata(state, itemIndex, itemData, itemType);
390
+ state.containerItemMetadata.set(containerId, metadata);
371
391
  }
372
- const stickyIndexInArray = state.props.stickyHeaderIndicesArr.indexOf(index);
373
- if (stickyIndexInArray === -1) {
374
- return void 0;
392
+ if (metadata.getFixedItemSize !== getFixedItemSize) {
393
+ metadata.didResolveFixedItemSize = false;
394
+ metadata.fixedItemSize = void 0;
395
+ metadata.getFixedItemSize = getFixedItemSize;
375
396
  }
376
- const nextStickyIndex = state.props.stickyHeaderIndicesArr[stickyIndexInArray + 1];
377
- if (nextStickyIndex === void 0) {
378
- return void 0;
397
+ if (getFixedItemSize && !metadata.didResolveFixedItemSize) {
398
+ metadata.fixedItemSize = getFixedItemSize(itemData, itemIndex, (_b = metadata.itemType) != null ? _b : "");
399
+ metadata.didResolveFixedItemSize = true;
379
400
  }
380
- const nextStickyPosition = state.positions[nextStickyIndex];
381
- if (nextStickyPosition === void 0) {
382
- return void 0;
401
+ return metadata;
402
+ }
403
+ function invalidateContainerFixedItemSizes(state) {
404
+ for (const metadata of state.containerItemMetadata.values()) {
405
+ metadata.didResolveFixedItemSize = false;
406
+ metadata.fixedItemSize = void 0;
383
407
  }
384
- return nextStickyPosition - currentSize;
385
408
  }
386
409
 
387
410
  // src/utils/devEnvironment.ts
@@ -398,445 +421,73 @@ var EDGE_POSITION_EPSILON = 1;
398
421
  var ENABLE_DEVMODE = IS_DEV && false;
399
422
  var ENABLE_DEBUG_VIEW = IS_DEV && false;
400
423
 
401
- // src/constants-platform.native.ts
402
- var f = global.nativeFabricUIManager;
403
- var IsNewArchitecture = f !== void 0 && f != null;
404
- var useAnimatedValue = (initialValue) => {
405
- const [animAnimatedValue] = useState(() => new Animated.Value(initialValue));
406
- return animAnimatedValue;
407
- };
408
-
409
- // src/hooks/useValue$.ts
410
- function useValue$(key, params) {
411
- const { getValue } = params || {};
412
- const ctx = useStateContext();
413
- const getNewValue = () => {
414
- var _a3;
415
- return (_a3 = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a3 : 0;
424
+ // src/core/deferredPublicOnScroll.ts
425
+ function withResolvedContentOffset(state, event, resolvedOffset) {
426
+ return {
427
+ ...event,
428
+ nativeEvent: {
429
+ ...event.nativeEvent,
430
+ contentOffset: state.props.horizontal ? { x: resolvedOffset, y: 0 } : { x: 0, y: resolvedOffset }
431
+ }
416
432
  };
417
- const animValue = useAnimatedValue(getNewValue());
418
- useLayoutEffect(() => {
419
- const syncCurrentValue = () => {
420
- animValue.setValue(getNewValue());
421
- };
422
- const unsubscribe = listen$(ctx, key, syncCurrentValue);
423
- syncCurrentValue();
424
- return unsubscribe;
425
- }, [animValue, ctx, key]);
426
- return animValue;
427
433
  }
428
- var typedForwardRef = React2.forwardRef;
429
- var typedMemo = React2.memo;
430
- var getComponent = (Component) => {
431
- if (React2.isValidElement(Component)) {
432
- return Component;
433
- }
434
- if (Component) {
435
- return /* @__PURE__ */ React2.createElement(Component, null);
436
- }
437
- return null;
438
- };
439
-
440
- // src/components/PositionView.native.tsx
441
- var PositionViewState = typedMemo(function PositionViewState2({
442
- id,
443
- horizontal,
444
- style,
445
- refView,
446
- ...rest
447
- }) {
448
- const [position = POSITION_OUT_OF_VIEW, _itemKey] = useArr$([`containerPosition${id}`, `containerItemKey${id}`]);
449
- return /* @__PURE__ */ React2.createElement(View$1, { ref: refView, style: [style, horizontal ? { left: position } : { top: position }], ...rest });
450
- });
451
- var PositionViewAnimated = typedMemo(function PositionViewAnimated2({
452
- id,
453
- horizontal,
454
- style,
455
- refView,
456
- ...rest
457
- }) {
458
- const position$ = useValue$(`containerPosition${id}`, {
459
- getValue: (v) => v != null ? v : POSITION_OUT_OF_VIEW
460
- });
461
- const position = horizontal ? { left: position$ } : { top: position$ };
462
- return /* @__PURE__ */ React2.createElement(Animated.View, { ref: refView, style: [style, position], ...rest });
463
- });
464
- var PositionViewSticky = typedMemo(function PositionViewSticky2({
465
- id,
466
- horizontal,
467
- style,
468
- refView,
469
- animatedScrollY,
470
- index,
471
- stickyHeaderConfig,
472
- children,
473
- ...rest
474
- }) {
475
- const ctx = useStateContext();
476
- const [
477
- position = POSITION_OUT_OF_VIEW,
478
- alignItemsAtEndPadding = 0,
479
- headerSize = 0,
480
- stylePaddingTop = 0,
481
- itemKey,
482
- _totalSize = 0
483
- ] = useArr$([
484
- `containerPosition${id}`,
485
- "alignItemsAtEndPadding",
486
- "headerSize",
487
- "stylePaddingTop",
488
- `containerItemKey${id}`,
489
- "totalSize"
490
- ]);
491
- const pushLimit = React2.useMemo(
492
- () => getStickyPushLimit(ctx.state, index, itemKey),
493
- [ctx.state, index, itemKey, _totalSize]
494
- );
495
- const transform = React2.useMemo(() => {
496
- var _a3;
497
- if (animatedScrollY) {
498
- const stickyConfigOffset = (_a3 = stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset) != null ? _a3 : 0;
499
- const stickyStart = position + headerSize + stylePaddingTop + alignItemsAtEndPadding - stickyConfigOffset;
500
- let nextStickyPosition;
501
- if (pushLimit !== void 0) {
502
- if (pushLimit <= position) {
503
- nextStickyPosition = pushLimit;
504
- } else {
505
- nextStickyPosition = animatedScrollY.interpolate({
506
- extrapolateLeft: "clamp",
507
- extrapolateRight: "clamp",
508
- inputRange: [stickyStart, stickyStart + (pushLimit - position)],
509
- outputRange: [position, pushLimit]
510
- });
511
- }
512
- } else {
513
- nextStickyPosition = animatedScrollY.interpolate({
514
- extrapolateLeft: "clamp",
515
- extrapolateRight: "extend",
516
- inputRange: [stickyStart, stickyStart + 5e3],
517
- outputRange: [position, position + 5e3]
518
- });
519
- }
520
- return horizontal ? [{ translateX: nextStickyPosition }] : [{ translateY: nextStickyPosition }];
521
- }
522
- }, [
523
- alignItemsAtEndPadding,
524
- animatedScrollY,
525
- headerSize,
526
- position,
527
- pushLimit,
528
- stylePaddingTop,
529
- stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset
530
- ]);
531
- const viewStyle = React2.useMemo(() => [style, { zIndex: index + 1e3 }, { transform }], [style, transform]);
532
- const renderStickyHeaderBackdrop = React2.useMemo(() => {
533
- if (!(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)) {
534
- return null;
535
- }
536
- return /* @__PURE__ */ React2.createElement(
537
- View$1,
538
- {
539
- style: {
540
- inset: 0,
541
- pointerEvents: "none",
542
- position: "absolute"
543
- }
544
- },
545
- getComponent(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)
434
+ function releaseDeferredPublicOnScroll(ctx, resolvedOffset) {
435
+ var _a3, _b, _c, _d;
436
+ const state = ctx.state;
437
+ const deferredEvent = state.deferredPublicOnScrollEvent;
438
+ state.deferredPublicOnScrollEvent = void 0;
439
+ if (deferredEvent) {
440
+ (_d = (_c = state.props).onScroll) == null ? void 0 : _d.call(
441
+ _c,
442
+ withResolvedContentOffset(
443
+ state,
444
+ deferredEvent,
445
+ (_b = (_a3 = resolvedOffset != null ? resolvedOffset : state.scrollPending) != null ? _a3 : state.scroll) != null ? _b : 0
446
+ )
546
447
  );
547
- }, [stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent]);
548
- return /* @__PURE__ */ React2.createElement(Animated.View, { ref: refView, style: viewStyle, ...rest }, renderStickyHeaderBackdrop, children);
549
- });
550
- var PositionView = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
551
- function useInit(cb) {
552
- useState(() => cb());
448
+ }
553
449
  }
554
450
 
555
- // src/utils/helpers.ts
556
- function isFunction(obj) {
557
- return typeof obj === "function";
558
- }
559
- function isArray(obj) {
560
- return Array.isArray(obj);
561
- }
562
- var warned = /* @__PURE__ */ new Set();
563
- function warnDevOnce(id, text) {
564
- if (IS_DEV && !warned.has(id)) {
565
- warned.add(id);
566
- console.warn(`[legend-list] ${text}`);
567
- }
451
+ // src/core/initialScrollSession.ts
452
+ var INITIAL_SCROLL_MIN_TARGET_OFFSET = 1;
453
+ function hasInitialScrollSessionCompletion(completion) {
454
+ return !!((completion == null ? void 0 : completion.didDispatchNativeScroll) || (completion == null ? void 0 : completion.didRetrySilentInitialScroll) || (completion == null ? void 0 : completion.watchdog));
568
455
  }
569
- function roundSize(size) {
570
- return Math.floor(size * 8) / 8;
456
+ function clearInitialScrollSession(state) {
457
+ state.initialScrollSession = void 0;
458
+ return void 0;
571
459
  }
572
- function isNullOrUndefined(value) {
573
- return value === null || value === void 0;
460
+ function createInitialScrollSession(options) {
461
+ const { bootstrap, completion, kind, previousDataLength } = options;
462
+ return kind === "offset" ? {
463
+ completion,
464
+ kind,
465
+ previousDataLength
466
+ } : {
467
+ bootstrap,
468
+ completion,
469
+ kind,
470
+ previousDataLength
471
+ };
574
472
  }
575
- function getPadding(s, type) {
576
- var _a3, _b, _c;
577
- const axisPadding = type === "Left" || type === "Right" ? s.paddingHorizontal : s.paddingVertical;
578
- return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : axisPadding) != null ? _b : s.padding) != null ? _c : 0;
579
- }
580
- function extractPadding(style, contentContainerStyle, type) {
581
- return getPadding(style, type) + getPadding(contentContainerStyle, type);
582
- }
583
- function findContainerId(ctx, key) {
584
- var _a3, _b;
585
- const directMatch = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.containerItemKeys) == null ? void 0 : _b.get(key);
586
- if (directMatch !== void 0) {
587
- return directMatch;
588
- }
589
- const numContainers = peek$(ctx, "numContainers");
590
- for (let i = 0; i < numContainers; i++) {
591
- const itemKey = peek$(ctx, `containerItemKey${i}`);
592
- if (itemKey === key) {
593
- return i;
594
- }
595
- }
596
- return -1;
597
- }
598
-
599
- // src/state/ContextContainer.ts
600
- var ContextContainer = createContext(null);
601
- var NO_CONTAINER_ID = -1;
602
- function useContextContainer() {
603
- return useContext(ContextContainer);
604
- }
605
- function useContainerItemInfo(containerContext) {
606
- var _a3;
607
- const containerId = (_a3 = containerContext == null ? void 0 : containerContext.containerId) != null ? _a3 : NO_CONTAINER_ID;
608
- const [itemInfo] = useArr$([`containerItemInfo${containerId}`]);
609
- return containerContext ? itemInfo : void 0;
610
- }
611
- function useContainerItemKey(containerContext) {
612
- var _a3;
613
- const containerId = (_a3 = containerContext == null ? void 0 : containerContext.containerId) != null ? _a3 : NO_CONTAINER_ID;
614
- const [itemKey] = useArr$([`containerItemKey${containerId}`]);
615
- return containerContext ? itemKey : void 0;
616
- }
617
- function useAdaptiveRender() {
618
- const [mode] = useArr$(["adaptiveRender"]);
619
- return mode;
620
- }
621
- function useAdaptiveRenderChange(callback) {
622
- const ctx = useStateContext();
623
- const callbackRef = useRef(callback);
624
- callbackRef.current = callback;
625
- useLayoutEffect(() => {
626
- let mode = peek$(ctx, "adaptiveRender");
627
- return listen$(ctx, "adaptiveRender", (nextMode) => {
628
- if (mode !== nextMode) {
629
- mode = nextMode;
630
- callbackRef.current(nextMode);
631
- }
632
- });
633
- }, [ctx]);
634
- }
635
- function useViewability(callback, configId) {
636
- const ctx = useStateContext();
637
- const containerContext = useContextContainer();
638
- useInit(() => {
639
- if (!containerContext) {
640
- return;
641
- }
642
- const { containerId } = containerContext;
643
- const key = containerId + (configId != null ? configId : "");
644
- const value = ctx.mapViewabilityValues.get(key);
645
- if (value) {
646
- callback(value);
647
- }
648
- });
649
- useEffect(() => {
650
- if (!containerContext) {
651
- return;
652
- }
653
- const { containerId } = containerContext;
654
- const key = containerId + (configId != null ? configId : "");
655
- ctx.mapViewabilityCallbacks.set(key, callback);
656
- return () => {
657
- ctx.mapViewabilityCallbacks.delete(key);
658
- };
659
- }, [ctx, callback, configId, containerContext]);
660
- }
661
- function useViewabilityAmount(callback) {
662
- const ctx = useStateContext();
663
- const containerContext = useContextContainer();
664
- useInit(() => {
665
- if (!containerContext) {
666
- return;
667
- }
668
- const { containerId } = containerContext;
669
- const value = ctx.mapViewabilityAmountValues.get(containerId);
670
- if (value) {
671
- callback(value);
672
- }
673
- });
674
- useEffect(() => {
675
- if (!containerContext) {
676
- return;
677
- }
678
- const { containerId } = containerContext;
679
- ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
680
- return () => {
681
- ctx.mapViewabilityAmountCallbacks.delete(containerId);
682
- };
683
- }, [ctx, callback, containerContext]);
684
- }
685
- function useRecyclingEffect(effect) {
686
- const containerContext = useContextContainer();
687
- const itemInfo = useContainerItemInfo(containerContext);
688
- const prevInfo = useRef(void 0);
689
- useEffect(() => {
690
- if (!itemInfo) {
691
- return;
692
- }
693
- let ret;
694
- if (prevInfo.current) {
695
- ret = effect({
696
- index: itemInfo.index,
697
- item: itemInfo.value,
698
- prevIndex: prevInfo.current.index,
699
- prevItem: prevInfo.current.value
700
- });
701
- }
702
- prevInfo.current = itemInfo;
703
- return ret;
704
- }, [effect, itemInfo]);
705
- }
706
- function useRecyclingState(valueOrFun) {
707
- var _a3;
708
- const containerContext = useContextContainer();
709
- const itemInfo = useContainerItemInfo(containerContext);
710
- const computeValue = (info) => {
711
- if (isFunction(valueOrFun)) {
712
- const initializer = valueOrFun;
713
- return info ? initializer({
714
- index: info.index,
715
- item: info.value,
716
- prevIndex: void 0,
717
- prevItem: void 0
718
- }) : initializer();
719
- }
720
- return valueOrFun;
721
- };
722
- const [stateValue, setStateValue] = useState(() => {
723
- return computeValue(itemInfo);
724
- });
725
- const prevItemKeyRef = useRef((_a3 = itemInfo == null ? void 0 : itemInfo.itemKey) != null ? _a3 : null);
726
- if (itemInfo && prevItemKeyRef.current !== itemInfo.itemKey) {
727
- prevItemKeyRef.current = itemInfo.itemKey;
728
- setStateValue(computeValue(itemInfo));
729
- }
730
- const triggerLayout = containerContext == null ? void 0 : containerContext.triggerLayout;
731
- const setState = useCallback(
732
- (newState) => {
733
- if (!triggerLayout) {
734
- return;
735
- }
736
- setStateValue((prevValue) => {
737
- return isFunction(newState) ? newState(prevValue) : newState;
738
- });
739
- triggerLayout();
740
- },
741
- [triggerLayout]
742
- );
743
- return [stateValue, setState];
744
- }
745
- function useIsLastItem() {
746
- const containerContext = useContextContainer();
747
- const itemKey = useContainerItemKey(containerContext);
748
- const isLast = useSelector$("lastItemKeys", (lastItemKeys) => {
749
- if (containerContext && !isNullOrUndefined(itemKey)) {
750
- return (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false;
751
- }
752
- return false;
753
- });
754
- return isLast;
755
- }
756
- function useListScrollSize() {
757
- const [scrollSize] = useArr$(["scrollSize"]);
758
- return scrollSize;
759
- }
760
- var noop = () => {
761
- };
762
- function useSyncLayout() {
763
- const containerContext = useContextContainer();
764
- return IsNewArchitecture && containerContext ? containerContext.triggerLayout : noop;
765
- }
766
-
767
- // src/components/Separator.tsx
768
- function Separator({ ItemSeparatorComponent, leadingItem }) {
769
- const isLastItem = useIsLastItem();
770
- return isLastItem ? null : /* @__PURE__ */ React2.createElement(ItemSeparatorComponent, { leadingItem });
771
- }
772
-
773
- // src/core/deferredPublicOnScroll.ts
774
- function withResolvedContentOffset(state, event, resolvedOffset) {
775
- return {
776
- ...event,
777
- nativeEvent: {
778
- ...event.nativeEvent,
779
- contentOffset: state.props.horizontal ? { x: resolvedOffset, y: 0 } : { x: 0, y: resolvedOffset }
780
- }
781
- };
782
- }
783
- function releaseDeferredPublicOnScroll(ctx, resolvedOffset) {
784
- var _a3, _b, _c, _d;
785
- const state = ctx.state;
786
- const deferredEvent = state.deferredPublicOnScrollEvent;
787
- state.deferredPublicOnScrollEvent = void 0;
788
- if (deferredEvent) {
789
- (_d = (_c = state.props).onScroll) == null ? void 0 : _d.call(
790
- _c,
791
- withResolvedContentOffset(
792
- state,
793
- deferredEvent,
794
- (_b = (_a3 = resolvedOffset != null ? resolvedOffset : state.scrollPending) != null ? _a3 : state.scroll) != null ? _b : 0
795
- )
796
- );
797
- }
798
- }
799
-
800
- // src/core/initialScrollSession.ts
801
- var INITIAL_SCROLL_MIN_TARGET_OFFSET = 1;
802
- function hasInitialScrollSessionCompletion(completion) {
803
- return !!((completion == null ? void 0 : completion.didDispatchNativeScroll) || (completion == null ? void 0 : completion.didRetrySilentInitialScroll) || (completion == null ? void 0 : completion.watchdog));
804
- }
805
- function clearInitialScrollSession(state) {
806
- state.initialScrollSession = void 0;
807
- return void 0;
808
- }
809
- function createInitialScrollSession(options) {
810
- const { bootstrap, completion, kind, previousDataLength } = options;
811
- return kind === "offset" ? {
812
- completion,
813
- kind,
814
- previousDataLength
815
- } : {
816
- bootstrap,
817
- completion,
818
- kind,
819
- previousDataLength
820
- };
821
- }
822
- function ensureInitialScrollSessionCompletion(state, kind = ((_b) => (_b = ((_a3) => (_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind)()) != null ? _b : "bootstrap")()) {
823
- var _a4, _b2;
824
- if (!state.initialScrollSession) {
825
- state.initialScrollSession = createInitialScrollSession({
826
- completion: {},
827
- kind,
828
- previousDataLength: 0
829
- });
830
- } else if (state.initialScrollSession.kind !== kind) {
831
- state.initialScrollSession = createInitialScrollSession({
832
- bootstrap: state.initialScrollSession.kind === "bootstrap" ? state.initialScrollSession.bootstrap : void 0,
833
- completion: state.initialScrollSession.completion,
834
- kind,
835
- previousDataLength: state.initialScrollSession.previousDataLength
836
- });
837
- }
838
- (_b2 = (_a4 = state.initialScrollSession).completion) != null ? _b2 : _a4.completion = {};
839
- return state.initialScrollSession.completion;
473
+ function ensureInitialScrollSessionCompletion(state, kind = ((_b) => (_b = ((_a3) => (_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind)()) != null ? _b : "bootstrap")()) {
474
+ var _a4, _b2;
475
+ if (!state.initialScrollSession) {
476
+ state.initialScrollSession = createInitialScrollSession({
477
+ completion: {},
478
+ kind,
479
+ previousDataLength: 0
480
+ });
481
+ } else if (state.initialScrollSession.kind !== kind) {
482
+ state.initialScrollSession = createInitialScrollSession({
483
+ bootstrap: state.initialScrollSession.kind === "bootstrap" ? state.initialScrollSession.bootstrap : void 0,
484
+ completion: state.initialScrollSession.completion,
485
+ kind,
486
+ previousDataLength: state.initialScrollSession.previousDataLength
487
+ });
488
+ }
489
+ (_b2 = (_a4 = state.initialScrollSession).completion) != null ? _b2 : _a4.completion = {};
490
+ return state.initialScrollSession.completion;
840
491
  }
841
492
  var initialScrollCompletion = {
842
493
  didDispatchNativeScroll(state) {
@@ -917,7 +568,11 @@ function setInitialScrollSession(state, options = {}) {
917
568
 
918
569
  // src/utils/checkThreshold.ts
919
570
  var HYSTERESIS_MULTIPLIER = 1.3;
920
- var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot, allowReentryOnChange) => {
571
+ function isOutsideThresholdHysteresis(distance, atThreshold, threshold) {
572
+ const absDistance = Math.abs(distance);
573
+ return !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
574
+ }
575
+ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot) => {
921
576
  const absDistance = Math.abs(distance);
922
577
  const within = atThreshold || threshold > 0 && absDistance <= threshold;
923
578
  const updateSnapshot = () => {
@@ -936,7 +591,7 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
936
591
  updateSnapshot();
937
592
  return true;
938
593
  }
939
- const reset = !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
594
+ const reset = isOutsideThresholdHysteresis(distance, atThreshold, threshold);
940
595
  if (reset) {
941
596
  setSnapshot(void 0);
942
597
  return false;
@@ -944,35 +599,82 @@ var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, co
944
599
  if (within) {
945
600
  const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
946
601
  if (changed) {
947
- if (allowReentryOnChange) {
948
- onReached(distance);
949
- }
950
602
  updateSnapshot();
951
603
  }
952
604
  }
953
605
  return true;
954
606
  };
955
607
 
956
- // src/utils/hasActiveInitialScroll.ts
957
- function hasActiveInitialScroll(state) {
958
- return !!(state == null ? void 0 : state.initialScroll) && !state.didFinishInitialScroll;
608
+ // src/utils/edgeReachedGate.ts
609
+ function resetEdgeLatch(ctx, edge) {
610
+ const state = ctx.state;
611
+ if (edge === "start") {
612
+ state.isStartReached = false;
613
+ state.startReachedSnapshot = void 0;
614
+ } else {
615
+ state.isEndReached = false;
616
+ state.endReachedSnapshot = void 0;
617
+ }
959
618
  }
960
-
961
- // src/utils/checkAtBottom.ts
962
- function checkAtBottom(ctx) {
963
- var _a3;
619
+ function resetSharedEdgeGateIfOutsideHysteresis(ctx) {
964
620
  const state = ctx.state;
965
- if (!state) {
621
+ if (!state.edgeReachedGate) {
966
622
  return;
967
623
  }
968
- const {
969
- queuedInitialLayout,
624
+ const contentSize = getContentSize(ctx);
625
+ const endDistance = contentSize - state.scroll - state.scrollLength - getContentInsetEnd(ctx);
626
+ const isContentLess = contentSize < state.scrollLength;
627
+ const startThreshold = state.props.onStartReachedThreshold * state.scrollLength;
628
+ const endThreshold = state.props.onEndReachedThreshold * state.scrollLength;
629
+ const isOutsideStart = isOutsideThresholdHysteresis(state.scroll, false, startThreshold);
630
+ const isOutsideEnd = isOutsideThresholdHysteresis(endDistance, isContentLess, endThreshold);
631
+ if (isOutsideStart && isOutsideEnd) {
632
+ state.edgeReachedGate = void 0;
633
+ }
634
+ }
635
+ function canDispatchReachedEdge(ctx, edge, allowedEdge, allowGateCreatedInCurrentCheck) {
636
+ return !ctx.state.edgeReachedGate || allowedEdge === edge || !!allowGateCreatedInCurrentCheck;
637
+ }
638
+ function markReachedEdge(ctx) {
639
+ ctx.state.edgeReachedGate = "closed";
640
+ }
641
+ function prepareReachedEdgeForNextUserScroll(ctx) {
642
+ if (ctx.state.edgeReachedGate) {
643
+ ctx.state.edgeReachedGate = "prepared";
644
+ }
645
+ }
646
+ function beginReachedEdgeUserScroll(ctx, scrollDelta) {
647
+ const state = ctx.state;
648
+ if (state.edgeReachedGate !== "prepared") {
649
+ return void 0;
650
+ }
651
+ const allowedEdge = scrollDelta < 0 ? "start" : "end";
652
+ state.edgeReachedGate = "closed";
653
+ resetEdgeLatch(ctx, allowedEdge);
654
+ return allowedEdge;
655
+ }
656
+
657
+ // src/utils/hasActiveInitialScroll.ts
658
+ function hasActiveInitialScroll(state) {
659
+ return !!(state == null ? void 0 : state.initialScroll) && !state.didFinishInitialScroll;
660
+ }
661
+
662
+ // src/utils/checkAtBottom.ts
663
+ function checkAtBottom(ctx, allowedEdge, allowGateCreatedInCurrentCheck) {
664
+ var _a3;
665
+ const state = ctx.state;
666
+ if (!state) {
667
+ return;
668
+ }
669
+ const {
670
+ queuedInitialLayout,
970
671
  scrollLength,
971
672
  scroll,
972
673
  maintainingScrollAtEnd,
973
674
  props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
974
675
  } = state;
975
676
  const contentSize = getContentSize(ctx);
677
+ resetSharedEdgeGateIfOutsideHysteresis(ctx);
976
678
  if (contentSize > 0 && queuedInitialLayout) {
977
679
  const insetEnd = getContentInsetEnd(ctx);
978
680
  const distanceFromEnd = contentSize - scroll - scrollLength - insetEnd;
@@ -999,59 +701,50 @@ function checkAtBottom(ctx) {
999
701
  },
1000
702
  (distance) => {
1001
703
  var _a4, _b;
1002
- return (_b = (_a4 = state.props).onEndReached) == null ? void 0 : _b.call(_a4, { distanceFromEnd: distance });
704
+ if (canDispatchReachedEdge(ctx, "end", allowedEdge, allowGateCreatedInCurrentCheck)) {
705
+ markReachedEdge(ctx);
706
+ (_b = (_a4 = state.props).onEndReached) == null ? void 0 : _b.call(_a4, { distanceFromEnd: distance });
707
+ }
1003
708
  },
1004
709
  (snapshot) => {
1005
710
  state.endReachedSnapshot = snapshot;
1006
- },
1007
- true
711
+ }
1008
712
  );
1009
713
  }
1010
714
  }
1011
715
  }
1012
716
 
1013
- // src/utils/isInMVCPActiveMode.native.ts
1014
- function isInMVCPActiveMode(state) {
1015
- return state.dataChangeNeedsScrollUpdate;
1016
- }
1017
-
1018
717
  // src/utils/checkAtTop.ts
1019
- function checkAtTop(ctx) {
718
+ function checkAtTop(ctx, allowedEdge, allowGateCreatedInCurrentCheck) {
1020
719
  const state = ctx == null ? void 0 : ctx.state;
1021
720
  if (!state) {
1022
721
  return;
1023
722
  }
1024
723
  const {
1025
- dataChangeEpoch,
1026
724
  isStartReached,
1027
725
  props: { data, onStartReachedThreshold },
1028
726
  scroll,
1029
727
  scrollLength,
1030
728
  startReachedSnapshot,
1031
- startReachedSnapshotDataChangeEpoch,
1032
729
  totalSize
1033
730
  } = state;
1034
731
  const dataLength = data.length;
1035
732
  const threshold = onStartReachedThreshold * scrollLength;
1036
- const dataChanged = startReachedSnapshotDataChangeEpoch !== dataChangeEpoch;
1037
- const withinThreshold = threshold > 0 && Math.abs(scroll) <= threshold;
1038
- const allowReentryOnDataChange = !!isStartReached && withinThreshold && !!dataChanged && !isInMVCPActiveMode(state);
1039
- if (isStartReached && threshold > 0 && scroll > threshold && startReachedSnapshot && (dataChanged || startReachedSnapshot.contentSize !== totalSize || startReachedSnapshot.dataLength !== dataLength)) {
733
+ resetSharedEdgeGateIfOutsideHysteresis(ctx);
734
+ if (isStartReached && threshold > 0 && scroll > threshold && startReachedSnapshot && (startReachedSnapshot.contentSize !== totalSize || startReachedSnapshot.dataLength !== dataLength)) {
1040
735
  state.isStartReached = false;
1041
736
  state.startReachedSnapshot = void 0;
1042
- state.startReachedSnapshotDataChangeEpoch = void 0;
1043
737
  }
1044
738
  set$(ctx, "isAtStart", scroll <= EDGE_POSITION_EPSILON);
1045
739
  set$(ctx, "isNearStart", scroll <= threshold);
1046
740
  const shouldSkipThresholdChecks = hasActiveInitialScroll(state) || !!state.scrollingTo;
1047
- const shouldDeferDataChangeRefire = isStartReached && withinThreshold && dataChanged && !allowReentryOnDataChange;
1048
- if (!shouldSkipThresholdChecks && !shouldDeferDataChangeRefire) {
741
+ if (!shouldSkipThresholdChecks) {
1049
742
  state.isStartReached = checkThreshold(
1050
743
  scroll,
1051
744
  false,
1052
745
  threshold,
1053
746
  state.isStartReached,
1054
- allowReentryOnDataChange ? void 0 : startReachedSnapshot,
747
+ startReachedSnapshot,
1055
748
  {
1056
749
  contentSize: totalSize,
1057
750
  dataLength,
@@ -1059,21 +752,23 @@ function checkAtTop(ctx) {
1059
752
  },
1060
753
  (distance) => {
1061
754
  var _a3, _b;
1062
- return (_b = (_a3 = state.props).onStartReached) == null ? void 0 : _b.call(_a3, { distanceFromStart: distance });
755
+ if (canDispatchReachedEdge(ctx, "start", allowedEdge, allowGateCreatedInCurrentCheck)) {
756
+ markReachedEdge(ctx);
757
+ (_b = (_a3 = state.props).onStartReached) == null ? void 0 : _b.call(_a3, { distanceFromStart: distance });
758
+ }
1063
759
  },
1064
760
  (snapshot) => {
1065
761
  state.startReachedSnapshot = snapshot;
1066
- state.startReachedSnapshotDataChangeEpoch = snapshot ? dataChangeEpoch : void 0;
1067
- },
1068
- allowReentryOnDataChange
762
+ }
1069
763
  );
1070
764
  }
1071
765
  }
1072
766
 
1073
767
  // src/utils/checkThresholds.ts
1074
- function checkThresholds(ctx) {
1075
- checkAtBottom(ctx);
1076
- checkAtTop(ctx);
768
+ function checkThresholds(ctx, allowedEdge) {
769
+ const allowGateCreatedInCurrentCheck = !ctx.state.edgeReachedGate;
770
+ checkAtBottom(ctx, allowedEdge, allowGateCreatedInCurrentCheck);
771
+ checkAtTop(ctx, allowedEdge, allowGateCreatedInCurrentCheck);
1077
772
  }
1078
773
 
1079
774
  // src/core/recalculateSettledScroll.ts
@@ -1382,6 +1077,50 @@ function setSize(ctx, itemKey, size, notifyTotalSize = true) {
1382
1077
  sizes.set(itemKey, size);
1383
1078
  }
1384
1079
 
1080
+ // src/utils/helpers.ts
1081
+ function isFunction(obj) {
1082
+ return typeof obj === "function";
1083
+ }
1084
+ function isArray(obj) {
1085
+ return Array.isArray(obj);
1086
+ }
1087
+ var warned = /* @__PURE__ */ new Set();
1088
+ function warnDevOnce(id, text) {
1089
+ if (IS_DEV && !warned.has(id)) {
1090
+ warned.add(id);
1091
+ console.warn(`[legend-list] ${text}`);
1092
+ }
1093
+ }
1094
+ function roundSize(size) {
1095
+ return Math.floor(size * 8) / 8;
1096
+ }
1097
+ function isNullOrUndefined(value) {
1098
+ return value === null || value === void 0;
1099
+ }
1100
+ function getPadding(s, type) {
1101
+ var _a3, _b, _c;
1102
+ const axisPadding = type === "Left" || type === "Right" ? s.paddingHorizontal : s.paddingVertical;
1103
+ return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : axisPadding) != null ? _b : s.padding) != null ? _c : 0;
1104
+ }
1105
+ function extractPadding(style, contentContainerStyle, type) {
1106
+ return getPadding(style, type) + getPadding(contentContainerStyle, type);
1107
+ }
1108
+ function findContainerId(ctx, key) {
1109
+ var _a3, _b;
1110
+ const directMatch = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.containerItemKeys) == null ? void 0 : _b.get(key);
1111
+ if (directMatch !== void 0) {
1112
+ return directMatch;
1113
+ }
1114
+ const numContainers = peek$(ctx, "numContainers");
1115
+ for (let i = 0; i < numContainers; i++) {
1116
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
1117
+ if (itemKey === key) {
1118
+ return i;
1119
+ }
1120
+ }
1121
+ return -1;
1122
+ }
1123
+
1385
1124
  // src/utils/getItemSize.ts
1386
1125
  function getKnownOrFixedSize(ctx, key, index, data, resolved) {
1387
1126
  var _a3, _b;
@@ -2206,6 +1945,11 @@ var getScrollVelocity = (state) => {
2206
1945
  return totalWeight > 0 ? weightedVelocity / totalWeight : 0;
2207
1946
  };
2208
1947
 
1948
+ // src/utils/isInMVCPActiveMode.native.ts
1949
+ function isInMVCPActiveMode(state) {
1950
+ return state.dataChangeNeedsScrollUpdate;
1951
+ }
1952
+
2209
1953
  // src/core/updateScroll.ts
2210
1954
  function updateScroll(ctx, newScroll, forceUpdate, options) {
2211
1955
  var _a3;
@@ -2243,6 +1987,8 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
2243
1987
  state.scroll = newScroll;
2244
1988
  state.scrollTime = currentTime;
2245
1989
  const scrollDelta = Math.abs(newScroll - prevScroll);
1990
+ const isUserScrollEvent = !!(options == null ? void 0 : options.fromNativeScrollEvent) && scrollDelta > 0.1 && !adjustChanged && scrollingTo === void 0 && !state.pendingNativeMVCPAdjust;
1991
+ const allowedEdge = isUserScrollEvent ? beginReachedEdgeUserScroll(ctx, newScroll - prevScroll) : void 0;
2246
1992
  const didResolvePendingNativeMVCPAdjust = resolvePendingNativeMVCPAdjust(ctx, newScroll);
2247
1993
  const scrollLength = state.scrollLength;
2248
1994
  const isLargeUserScrollJump = scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength && !state.pendingNativeMVCPAdjust;
@@ -2250,7 +1996,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
2250
1996
  updateAdaptiveRender(ctx, scrollVelocity, { forceLight: isLargeUserScrollJump });
2251
1997
  const lastCalculated = state.scrollLastCalculate;
2252
1998
  const useAggressiveItemRecalculation = isInMVCPActiveMode(state);
2253
- const shouldUpdate = useAggressiveItemRecalculation || didResolvePendingNativeMVCPAdjust || forceUpdate || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
1999
+ const shouldUpdate = useAggressiveItemRecalculation || didResolvePendingNativeMVCPAdjust || allowedEdge !== void 0 || forceUpdate || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
2254
2000
  if (shouldUpdate) {
2255
2001
  state.scrollLastCalculate = state.scroll;
2256
2002
  state.ignoreScrollFromMVCPIgnored = false;
@@ -2265,7 +2011,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
2265
2011
  calculateItemsParams.drawDistanceMode = "visible-first";
2266
2012
  }
2267
2013
  (_a4 = state.triggerCalculateItemsInView) == null ? void 0 : _a4.call(state, calculateItemsParams);
2268
- checkThresholds(ctx);
2014
+ checkThresholds(ctx, allowedEdge);
2269
2015
  };
2270
2016
  if (isLargeUserScrollJump) {
2271
2017
  state.mvcpAnchorLock = void 0;
@@ -3354,6 +3100,52 @@ function resetLayoutCachesForDataChange(state) {
3354
3100
  state.columnSpans.length = 0;
3355
3101
  }
3356
3102
 
3103
+ // src/core/scheduleContainerLayout.ts
3104
+ function getContainerLayoutEffectScope(ctx) {
3105
+ var _a3;
3106
+ const scheduledIds = ctx.pendingContainerIds;
3107
+ ctx.pendingContainerIds = void 0;
3108
+ if (scheduledIds === void 0) {
3109
+ return void 0;
3110
+ }
3111
+ const state = ctx.state;
3112
+ let targetContainerIds = scheduledIds;
3113
+ if (targetContainerIds && ((_a3 = state.userScrollAnchorReset) == null ? void 0 : _a3.keys.size)) {
3114
+ targetContainerIds = new Set(targetContainerIds);
3115
+ for (const itemKey of state.userScrollAnchorReset.keys) {
3116
+ const containerId = state.containerItemKeys.get(itemKey);
3117
+ if (containerId !== void 0) {
3118
+ targetContainerIds.add(containerId);
3119
+ }
3120
+ }
3121
+ }
3122
+ return targetContainerIds;
3123
+ }
3124
+ function scheduleContainerLayout(ctx, target) {
3125
+ var _a3;
3126
+ const isAlreadyScheduled = ctx.pendingContainerIds !== void 0;
3127
+ const previousIds = ctx.pendingContainerIds;
3128
+ if (target === void 0) {
3129
+ ctx.pendingContainerIds = null;
3130
+ } else if (previousIds !== null) {
3131
+ let nextIds = previousIds;
3132
+ if (!nextIds) {
3133
+ nextIds = typeof target === "number" ? /* @__PURE__ */ new Set([target]) : new Set(target);
3134
+ } else if (typeof target === "number") {
3135
+ nextIds.add(target);
3136
+ } else {
3137
+ for (const containerId of target) {
3138
+ nextIds.add(containerId);
3139
+ }
3140
+ }
3141
+ ctx.pendingContainerIds = nextIds;
3142
+ }
3143
+ if (!isAlreadyScheduled) {
3144
+ const nextEpoch = ((_a3 = peek$(ctx, "containerLayoutEpoch")) != null ? _a3 : 0) + 1;
3145
+ set$(ctx, "containerLayoutEpoch", nextEpoch);
3146
+ }
3147
+ }
3148
+
3357
3149
  // src/core/syncMountedContainer.ts
3358
3150
  function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3359
3151
  var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
@@ -3397,14 +3189,13 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3397
3189
  set$(ctx, `containerSpan${containerIndex}`, span);
3398
3190
  }
3399
3191
  }
3400
- const prevItemInfo = peek$(ctx, `containerItemInfo${containerIndex}`);
3192
+ const prevIndex = peek$(ctx, `containerItemIndex${containerIndex}`);
3193
+ if (prevIndex !== itemIndex) {
3194
+ set$(ctx, `containerItemIndex${containerIndex}`, itemIndex);
3195
+ }
3401
3196
  const prevData = peek$(ctx, `containerItemData${containerIndex}`);
3402
- let itemInfoValue = prevData;
3403
- let didChangeItemInfo = (prevItemInfo == null ? void 0 : prevItemInfo.itemKey) !== itemKey || (prevItemInfo == null ? void 0 : prevItemInfo.index) !== itemIndex || (prevItemInfo == null ? void 0 : prevItemInfo.value) !== prevData;
3404
3197
  const updateData = () => {
3405
3198
  set$(ctx, `containerItemData${containerIndex}`, item);
3406
- itemInfoValue = item;
3407
- didChangeItemInfo = true;
3408
3199
  didRefreshData = true;
3409
3200
  };
3410
3201
  if (prevData !== item) {
@@ -3439,13 +3230,6 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3439
3230
  }
3440
3231
  }
3441
3232
  }
3442
- if (didChangeItemInfo) {
3443
- set$(ctx, `containerItemInfo${containerIndex}`, {
3444
- index: itemIndex,
3445
- itemKey,
3446
- value: itemInfoValue
3447
- });
3448
- }
3449
3233
  return { didChangePosition, didRefreshData };
3450
3234
  }
3451
3235
 
@@ -3810,19 +3594,29 @@ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, stat
3810
3594
  if (previousViewableItems) {
3811
3595
  for (const viewToken of previousViewableItems) {
3812
3596
  previousViewableKeys.add(viewToken.key);
3597
+ const currentIndex = state.indexByKey.get(viewToken.key);
3598
+ const currentItem = currentIndex !== void 0 ? data[currentIndex] : void 0;
3813
3599
  const containerId = findContainerId(ctx, viewToken.key);
3814
- if (!checkIsViewable(
3815
- state,
3816
- ctx,
3817
- viewabilityConfig,
3818
- containerId,
3819
- viewToken.key,
3820
- scrollSize,
3821
- viewToken.item,
3822
- viewToken.index
3823
- )) {
3824
- viewToken.isViewable = false;
3825
- changed.push(viewToken);
3600
+ let isStillViewable = false;
3601
+ if (currentIndex !== void 0 && currentItem !== void 0) {
3602
+ isStillViewable = checkIsViewable(
3603
+ state,
3604
+ ctx,
3605
+ viewabilityConfig,
3606
+ containerId,
3607
+ viewToken.key,
3608
+ scrollSize,
3609
+ currentItem,
3610
+ currentIndex
3611
+ );
3612
+ }
3613
+ if (!isStillViewable) {
3614
+ changed.push({
3615
+ ...viewToken,
3616
+ index: currentIndex != null ? currentIndex : viewToken.index,
3617
+ isViewable: false,
3618
+ item: currentItem != null ? currentItem : viewToken.item
3619
+ });
3826
3620
  }
3827
3621
  }
3828
3622
  }
@@ -3979,128 +3773,102 @@ function getExpandedContainerPoolSize(dataLength, numContainers) {
3979
3773
 
3980
3774
  // src/utils/findAvailableContainers.ts
3981
3775
  function findAvailableContainers(ctx, needNewContainers, startBuffered, endBuffered, pendingRemoval, getRequiredItemType, protectedKeys) {
3776
+ var _a3;
3982
3777
  const numNeeded = needNewContainers.length;
3983
3778
  if (numNeeded === 0) {
3984
3779
  return [];
3985
3780
  }
3986
3781
  const numContainers = peek$(ctx, "numContainers");
3987
3782
  const state = ctx.state;
3988
- const { stickyContainerPool, containerItemTypes } = state;
3783
+ const { containerItemMetadata, stickyContainerPool } = state;
3989
3784
  const shouldAvoidAssignedContainerReuse = state.props.recycleItems && !!state.props.positionComponentInternal;
3990
- const allocations = [];
3991
3785
  const pendingRemovalSet = pendingRemoval.length > 0 ? new Set(pendingRemoval) : void 0;
3992
- let pendingRemovalChanged = false;
3786
+ const requests = needNewContainers.map((itemIndex, order) => ({
3787
+ isSticky: state.props.stickyHeaderIndicesSet.has(itemIndex),
3788
+ itemIndex,
3789
+ itemType: getRequiredItemType == null ? void 0 : getRequiredItemType(itemIndex),
3790
+ order
3791
+ }));
3792
+ const normalRequests = requests.filter((request) => !request.isSticky);
3793
+ const stickyRequests = requests.filter((request) => request.isSticky);
3794
+ const normalCandidates = [];
3795
+ const stickyCandidates = [];
3796
+ for (let containerIndex = 0; containerIndex < numContainers; containerIndex++) {
3797
+ const key = peek$(ctx, `containerItemKey${containerIndex}`);
3798
+ const isPendingRemoval = !!(pendingRemovalSet == null ? void 0 : pendingRemovalSet.has(containerIndex));
3799
+ const isProtected = !!key && !!(protectedKeys == null ? void 0 : protectedKeys.has(key)) && state.indexByKey.has(key);
3800
+ if (isProtected) {
3801
+ continue;
3802
+ }
3803
+ if (stickyContainerPool.has(containerIndex)) {
3804
+ if (key === void 0 || isPendingRemoval) {
3805
+ stickyCandidates.push({ containerIndex, distance: Number.POSITIVE_INFINITY });
3806
+ }
3807
+ } else if (key === void 0 || isPendingRemoval) {
3808
+ normalCandidates.push({ containerIndex, distance: Number.POSITIVE_INFINITY });
3809
+ } else if (!shouldAvoidAssignedContainerReuse) {
3810
+ const index = state.indexByKey.get(key);
3811
+ if (index !== void 0 && (index < startBuffered || index > endBuffered)) {
3812
+ const distance = index < startBuffered ? startBuffered - index : index - endBuffered;
3813
+ normalCandidates.push({ containerIndex, distance });
3814
+ }
3815
+ }
3816
+ }
3817
+ normalCandidates.sort(comparatorByDistance);
3818
+ const allocations = new Array(numNeeded);
3993
3819
  let nextNewContainerIndex = numContainers;
3994
- const usedContainers = /* @__PURE__ */ new Set();
3995
- let availableContainers;
3996
- const stickyHeaderIndicesSet = state.props.stickyHeaderIndicesSet;
3997
- const canReuseContainer = (containerIndex, requiredType) => {
3998
- if (!requiredType) return true;
3999
- const existingType = containerItemTypes.get(containerIndex);
4000
- if (!existingType) return true;
4001
- return existingType === requiredType;
4002
- };
4003
- const pushAllocation = (itemIndex, itemType, containerIndex) => {
4004
- allocations.push({
3820
+ let pendingRemovalChanged = false;
3821
+ const assign = (request, containerIndex) => {
3822
+ allocations[request.order] = {
4005
3823
  containerIndex,
4006
- itemIndex,
4007
- itemType
4008
- });
4009
- usedContainers.add(containerIndex);
3824
+ itemIndex: request.itemIndex,
3825
+ itemType: request.itemType
3826
+ };
4010
3827
  if (pendingRemovalSet == null ? void 0 : pendingRemovalSet.delete(containerIndex)) {
4011
3828
  pendingRemovalChanged = true;
4012
3829
  }
4013
3830
  };
4014
- const pushNewContainer = (itemIndex, itemType, isSticky) => {
4015
- const newContainerIndex = nextNewContainerIndex++;
4016
- pushAllocation(itemIndex, itemType, newContainerIndex);
4017
- if (isSticky) {
4018
- stickyContainerPool.add(newContainerIndex);
4019
- }
4020
- return newContainerIndex;
4021
- };
4022
- const canUseContainer = (containerIndex, itemType) => {
4023
- if (usedContainers.has(containerIndex) || stickyContainerPool.has(containerIndex)) {
4024
- return false;
4025
- }
4026
- const key = peek$(ctx, `containerItemKey${containerIndex}`);
4027
- const isPending = !!(pendingRemovalSet == null ? void 0 : pendingRemovalSet.has(containerIndex));
4028
- return (key === void 0 || isPending) && canReuseContainer(containerIndex, itemType);
4029
- };
4030
- const findStickyContainer = (itemType) => {
4031
- let foundContainer;
4032
- for (const containerIndex of stickyContainerPool) {
4033
- if (!usedContainers.has(containerIndex)) {
4034
- const key = peek$(ctx, `containerItemKey${containerIndex}`);
4035
- const isPendingRemoval = !!(pendingRemovalSet == null ? void 0 : pendingRemovalSet.has(containerIndex));
4036
- if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, itemType)) {
4037
- foundContainer = containerIndex;
4038
- break;
4039
- }
4040
- }
4041
- }
4042
- return foundContainer;
4043
- };
4044
- const findUnassignedOrPendingContainer = (itemType) => {
4045
- let foundContainer;
4046
- for (let containerIndex = 0; containerIndex < numContainers && foundContainer === void 0; containerIndex++) {
4047
- if (canUseContainer(containerIndex, itemType)) {
4048
- foundContainer = containerIndex;
3831
+ const assignMatching = (pendingRequests, candidates, matches) => {
3832
+ for (const request of pendingRequests) {
3833
+ if (allocations[request.order]) {
3834
+ continue;
4049
3835
  }
4050
- }
4051
- return foundContainer;
4052
- };
4053
- const getAvailableContainers = () => {
4054
- if (!availableContainers) {
4055
- availableContainers = [];
4056
- if (!shouldAvoidAssignedContainerReuse) {
4057
- for (let containerIndex = 0; containerIndex < numContainers; containerIndex++) {
4058
- if (usedContainers.has(containerIndex) || stickyContainerPool.has(containerIndex)) {
4059
- continue;
4060
- }
4061
- const key = peek$(ctx, `containerItemKey${containerIndex}`);
4062
- if (key === void 0) continue;
4063
- if ((protectedKeys == null ? void 0 : protectedKeys.has(key)) && state.indexByKey.has(key)) continue;
4064
- const index = state.indexByKey.get(key);
4065
- const isOutOfView = index < startBuffered || index > endBuffered;
4066
- if (isOutOfView) {
4067
- const distance = index < startBuffered ? startBuffered - index : index - endBuffered;
4068
- availableContainers.push({ distance, index: containerIndex });
4069
- }
3836
+ const candidateIndex = candidates.findIndex(
3837
+ (candidate) => {
3838
+ var _a4;
3839
+ return matches((_a4 = containerItemMetadata.get(candidate.containerIndex)) == null ? void 0 : _a4.itemType, request.itemType);
4070
3840
  }
4071
- availableContainers.sort(comparatorByDistance);
3841
+ );
3842
+ if (candidateIndex !== -1) {
3843
+ const [candidate] = candidates.splice(candidateIndex, 1);
3844
+ assign(request, candidate.containerIndex);
4072
3845
  }
4073
3846
  }
4074
- return availableContainers;
4075
3847
  };
4076
- const findAvailableContainer = (itemType) => {
4077
- const containers = getAvailableContainers();
4078
- let matchIndex = -1;
4079
- for (let i = 0; i < containers.length && matchIndex === -1; i++) {
4080
- const containerIndex = containers[i].index;
4081
- if (!usedContainers.has(containerIndex) && canReuseContainer(containerIndex, itemType)) {
4082
- matchIndex = i;
4083
- }
3848
+ const assignFromPool = (pendingRequests, candidates, allowCrossType) => {
3849
+ if (getRequiredItemType) {
3850
+ assignMatching(
3851
+ pendingRequests,
3852
+ candidates,
3853
+ (containerType, requestType) => requestType !== void 0 && containerType === requestType
3854
+ );
3855
+ }
3856
+ assignMatching(pendingRequests, candidates, (containerType) => containerType === void 0);
3857
+ if (allowCrossType) {
3858
+ assignMatching(pendingRequests, candidates, () => true);
4084
3859
  }
4085
- return matchIndex === -1 ? void 0 : containers.splice(matchIndex, 1)[0].index;
4086
3860
  };
4087
- for (const itemIndex of needNewContainers) {
4088
- const itemType = getRequiredItemType == null ? void 0 : getRequiredItemType(itemIndex);
4089
- const isSticky = stickyHeaderIndicesSet.has(itemIndex);
4090
- let containerIndex;
4091
- if (isSticky) {
4092
- containerIndex = findStickyContainer(itemType);
4093
- } else {
4094
- containerIndex = findUnassignedOrPendingContainer(itemType);
4095
- if (containerIndex === void 0) {
4096
- containerIndex = findAvailableContainer(itemType);
4097
- }
3861
+ assignFromPool(normalRequests, normalCandidates, true);
3862
+ assignFromPool(stickyRequests, stickyCandidates, false);
3863
+ for (const request of requests) {
3864
+ if (allocations[request.order]) {
3865
+ continue;
4098
3866
  }
4099
- if (containerIndex !== void 0) {
4100
- pushAllocation(itemIndex, itemType, containerIndex);
4101
- } else {
4102
- pushNewContainer(itemIndex, itemType, isSticky);
3867
+ const containerIndex = nextNewContainerIndex++;
3868
+ if (request.isSticky) {
3869
+ stickyContainerPool.add(containerIndex);
4103
3870
  }
3871
+ assign(request, containerIndex);
4104
3872
  }
4105
3873
  if (pendingRemovalChanged) {
4106
3874
  pendingRemoval.length = 0;
@@ -4110,18 +3878,21 @@ function findAvailableContainers(ctx, needNewContainers, startBuffered, endBuffe
4110
3878
  }
4111
3879
  }
4112
3880
  }
4113
- if (IS_DEV && nextNewContainerIndex > peek$(ctx, "numContainersPooled")) {
4114
- console.warn(
4115
- "[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.",
4116
- {
4117
- debugInfo: {
4118
- numContainers,
4119
- numContainersPooled: peek$(ctx, "numContainersPooled"),
4120
- numNeeded,
4121
- stillNeeded: nextNewContainerIndex - numContainers
3881
+ if (IS_DEV) {
3882
+ const numContainersPooled = (_a3 = peek$(ctx, "numContainersPooled")) != null ? _a3 : Number.POSITIVE_INFINITY;
3883
+ if (nextNewContainerIndex > numContainersPooled) {
3884
+ console.warn(
3885
+ "[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.",
3886
+ {
3887
+ debugInfo: {
3888
+ numContainers,
3889
+ numContainersPooled,
3890
+ numNeeded,
3891
+ stillNeeded: nextNewContainerIndex - numContainers
3892
+ }
4122
3893
  }
4123
- }
4124
- );
3894
+ );
3895
+ }
4125
3896
  }
4126
3897
  return allocations;
4127
3898
  }
@@ -4356,7 +4127,7 @@ function updateViewabilityForCachedRange(ctx, viewabilityConfigCallbackPairs, sc
4356
4127
  function calculateItemsInView(ctx, params = {}) {
4357
4128
  const state = ctx.state;
4358
4129
  batchedUpdates(() => {
4359
- var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t;
4130
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u;
4360
4131
  const {
4361
4132
  columns,
4362
4133
  containerItemKeys,
@@ -4384,6 +4155,7 @@ function calculateItemsInView(ctx, params = {}) {
4384
4155
  return;
4385
4156
  }
4386
4157
  let totalSize = getContentSize(ctx);
4158
+ let changedContainerIds;
4387
4159
  const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "alignItemsAtEndPadding") + peek$(ctx, "headerSize");
4388
4160
  const numColumns = peek$(ctx, "numColumns");
4389
4161
  const speed = (_b = params.scrollVelocity) != null ? _b : getScrollVelocity(state);
@@ -4509,7 +4281,7 @@ function calculateItemsInView(ctx, params = {}) {
4509
4281
  const scrollAdjustPendingBeforeMVCP = (_f = peek$(ctx, "scrollAdjustPending")) != null ? _f : 0;
4510
4282
  checkMVCP == null ? void 0 : checkMVCP();
4511
4283
  const didMVCPAdjustScroll = !!checkMVCP && (state.scroll !== scrollBeforeMVCP || ((_g = peek$(ctx, "scrollAdjustPending")) != null ? _g : 0) !== scrollAdjustPendingBeforeMVCP);
4512
- if (didMVCPAdjustScroll && (initialScroll || state.scrollingTo)) {
4284
+ if (didMVCPAdjustScroll) {
4513
4285
  updateScroll2(state.scroll);
4514
4286
  updateScrollRange();
4515
4287
  }
@@ -4689,22 +4461,20 @@ function calculateItemsInView(ctx, params = {}) {
4689
4461
  if (oldKey && oldKey !== id) {
4690
4462
  containerItemKeys.delete(oldKey);
4691
4463
  }
4464
+ if (oldKey !== id) {
4465
+ changedContainerIds != null ? changedContainerIds : changedContainerIds = /* @__PURE__ */ new Set();
4466
+ changedContainerIds.add(containerIndex);
4467
+ state.containerItemGenerations[containerIndex] = ((_p = state.containerItemGenerations[containerIndex]) != null ? _p : 0) + 1;
4468
+ }
4692
4469
  set$(ctx, `containerItemKey${containerIndex}`, id);
4470
+ set$(ctx, `containerItemIndex${containerIndex}`, i);
4693
4471
  set$(ctx, `containerItemData${containerIndex}`, data[i]);
4694
- set$(ctx, `containerItemInfo${containerIndex}`, {
4695
- index: i,
4696
- itemKey: id,
4697
- value: data[i]
4698
- });
4699
- if (allocation.itemType !== void 0) {
4700
- state.containerItemTypes.set(containerIndex, allocation.itemType);
4701
- }
4472
+ state.containerItemMetadata.set(
4473
+ containerIndex,
4474
+ createContainerItemMetadata(state, i, data[i], allocation.itemType)
4475
+ );
4702
4476
  containerItemKeys.set(id, containerIndex);
4703
- (_p = state.userScrollAnchorReset) == null ? void 0 : _p.keys.add(id);
4704
- if (IsNewArchitecture) {
4705
- (_q = state.pendingLayoutEffectMeasurements) != null ? _q : state.pendingLayoutEffectMeasurements = /* @__PURE__ */ new Set();
4706
- state.pendingLayoutEffectMeasurements.add(id);
4707
- }
4477
+ (_q = state.userScrollAnchorReset) == null ? void 0 : _q.keys.add(id);
4708
4478
  const containerSticky = `containerSticky${containerIndex}`;
4709
4479
  const isSticky = stickyHeaderIndicesSet.has(i);
4710
4480
  const isPinnedRender = isPinnedRenderIndex(i);
@@ -4754,15 +4524,18 @@ function calculateItemsInView(ctx, params = {}) {
4754
4524
  if (pendingRemovalSet == null ? void 0 : pendingRemovalSet.has(i)) {
4755
4525
  if (itemKey !== void 0) {
4756
4526
  containerItemKeys.delete(itemKey);
4527
+ changedContainerIds != null ? changedContainerIds : changedContainerIds = /* @__PURE__ */ new Set();
4528
+ changedContainerIds.add(i);
4529
+ state.containerItemGenerations[i] = ((_t = state.containerItemGenerations[i]) != null ? _t : 0) + 1;
4757
4530
  }
4758
- state.containerItemTypes.delete(i);
4531
+ state.containerItemMetadata.delete(i);
4759
4532
  if (state.stickyContainerPool.has(i)) {
4760
4533
  set$(ctx, `containerSticky${i}`, false);
4761
4534
  state.stickyContainerPool.delete(i);
4762
4535
  }
4763
4536
  set$(ctx, `containerItemKey${i}`, void 0);
4537
+ set$(ctx, `containerItemIndex${i}`, void 0);
4764
4538
  set$(ctx, `containerItemData${i}`, void 0);
4765
- set$(ctx, `containerItemInfo${i}`, void 0);
4766
4539
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
4767
4540
  set$(ctx, `containerColumn${i}`, -1);
4768
4541
  set$(ctx, `containerSpan${i}`, 1);
@@ -4776,6 +4549,9 @@ function calculateItemsInView(ctx, params = {}) {
4776
4549
  }
4777
4550
  }
4778
4551
  }
4552
+ if (changedContainerIds && (IsNewArchitecture || Platform.OS === "web")) {
4553
+ scheduleContainerLayout(ctx, changedContainerIds);
4554
+ }
4779
4555
  if (Platform.OS === "web" && didChangePositions) {
4780
4556
  set$(ctx, "lastPositionUpdate", Date.now());
4781
4557
  }
@@ -4792,20 +4568,18 @@ function calculateItemsInView(ctx, params = {}) {
4792
4568
  }
4793
4569
  }
4794
4570
  if (viewabilityConfigCallbackPairs && visibleRange.startNoBuffer !== null && visibleRange.endNoBuffer !== null) {
4795
- if (!didMVCPAdjustScroll) {
4796
- updateViewableItems(
4797
- ctx.state,
4798
- ctx,
4799
- viewabilityConfigCallbackPairs,
4800
- scrollLength,
4801
- visibleRange.startNoBuffer,
4802
- visibleRange.endNoBuffer,
4803
- startBuffered != null ? startBuffered : visibleRange.startNoBuffer,
4804
- endBuffered != null ? endBuffered : visibleRange.endNoBuffer
4805
- );
4806
- }
4571
+ updateViewableItems(
4572
+ ctx.state,
4573
+ ctx,
4574
+ viewabilityConfigCallbackPairs,
4575
+ scrollLength,
4576
+ visibleRange.startNoBuffer,
4577
+ visibleRange.endNoBuffer,
4578
+ startBuffered != null ? startBuffered : visibleRange.startNoBuffer,
4579
+ endBuffered != null ? endBuffered : visibleRange.endNoBuffer
4580
+ );
4807
4581
  }
4808
- (_t = stickyState == null ? void 0 : stickyState.finishCalculateItemsInView) == null ? void 0 : _t.call(stickyState);
4582
+ (_u = stickyState == null ? void 0 : stickyState.finishCalculateItemsInView) == null ? void 0 : _u.call(stickyState);
4809
4583
  });
4810
4584
  }
4811
4585
 
@@ -4911,42 +4685,28 @@ function updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal) {
4911
4685
  }
4912
4686
  }
4913
4687
  }
4688
+ var activeItemSizeBatches;
4689
+ function batchItemSizeUpdates(runUpdates) {
4690
+ const isOuterBatch = activeItemSizeBatches === void 0;
4691
+ activeItemSizeBatches != null ? activeItemSizeBatches : activeItemSizeBatches = /* @__PURE__ */ new Map();
4692
+ try {
4693
+ runUpdates();
4694
+ } finally {
4695
+ if (isOuterBatch) {
4696
+ const batches = activeItemSizeBatches;
4697
+ activeItemSizeBatches = void 0;
4698
+ for (const [ctx, measurements] of batches) {
4699
+ updateItemSizesBatch(ctx, measurements);
4700
+ }
4701
+ }
4702
+ }
4703
+ }
4914
4704
  function mergeItemSizeUpdateResult(result, next) {
4915
4705
  result.didChange || (result.didChange = next.didChange);
4916
4706
  result.didMeasureUserScrollAnchorResetItem || (result.didMeasureUserScrollAnchorResetItem = next.didMeasureUserScrollAnchorResetItem);
4917
4707
  result.needsRecalculate || (result.needsRecalculate = next.needsRecalculate);
4918
4708
  result.shouldMaintainScrollAtEnd || (result.shouldMaintainScrollAtEnd = next.shouldMaintainScrollAtEnd);
4919
4709
  }
4920
- var batchedItemSizeRecalculates = /* @__PURE__ */ new WeakMap();
4921
- function flushBatchedItemSizeRecalculate(ctx, didFallback = false, expectedResult) {
4922
- const result = batchedItemSizeRecalculates.get(ctx);
4923
- if (!result || expectedResult && result !== expectedResult) {
4924
- return;
4925
- }
4926
- batchedItemSizeRecalculates.delete(ctx);
4927
- if (didFallback) {
4928
- ctx.state.pendingLayoutEffectMeasurements = void 0;
4929
- }
4930
- flushItemSizeUpdates(ctx, result);
4931
- }
4932
- function queueItemSizeRecalculate(ctx, result) {
4933
- var _a3, _b;
4934
- const batch = batchedItemSizeRecalculates.get(ctx);
4935
- if (batch) {
4936
- mergeItemSizeUpdateResult(batch, result);
4937
- } else {
4938
- const nextBatch = { ...result };
4939
- batchedItemSizeRecalculates.set(ctx, nextBatch);
4940
- if ((_a3 = ctx.state.pendingLayoutEffectMeasurements) == null ? void 0 : _a3.size) {
4941
- requestAnimationFrame(() => {
4942
- flushBatchedItemSizeRecalculate(ctx, true, nextBatch);
4943
- });
4944
- }
4945
- }
4946
- if (!((_b = ctx.state.pendingLayoutEffectMeasurements) == null ? void 0 : _b.size)) {
4947
- flushBatchedItemSizeRecalculate(ctx);
4948
- }
4949
- }
4950
4710
  function flushItemSizeUpdates(ctx, result) {
4951
4711
  var _a3;
4952
4712
  const state = ctx.state;
@@ -4961,54 +4721,36 @@ function flushItemSizeUpdates(ctx, result) {
4961
4721
  }
4962
4722
  }
4963
4723
  function updateItemSizes(ctx, measurement) {
4964
- var _a3, _b, _c, _d;
4965
- const state = ctx.state;
4966
- let didDrainLayoutEffectMeasurements = false;
4967
- if (IsNewArchitecture && measurement.fromLayoutEffect) {
4968
- const pendingLayoutEffectMeasurements = state.pendingLayoutEffectMeasurements;
4969
- if ((pendingLayoutEffectMeasurements == null ? void 0 : pendingLayoutEffectMeasurements.delete(measurement.itemKey)) && pendingLayoutEffectMeasurements.size === 0) {
4970
- state.pendingLayoutEffectMeasurements = void 0;
4971
- didDrainLayoutEffectMeasurements = true;
4972
- }
4973
- }
4974
- const pendingKeys = (_a3 = state.userScrollAnchorReset) == null ? void 0 : _a3.keys;
4975
- const shouldBatchPendingMeasurements = IsNewArchitecture && measurement.fromLayoutEffect && !!(pendingKeys == null ? void 0 : pendingKeys.size);
4976
- const shouldQueueRecalculate = IsNewArchitecture && !!measurement.fromLayoutEffect;
4977
- let result;
4978
- if (!shouldBatchPendingMeasurements) {
4979
- result = applyItemSize(ctx, measurement.itemKey, measurement.size);
4980
- } else {
4981
- result = {};
4982
- const updateContainerItemSize = (itemKey, containerId, size) => {
4983
- if (containerId !== void 0 && peek$(ctx, `containerItemKey${containerId}`) === itemKey) {
4984
- mergeItemSizeUpdateResult(result, applyItemSize(ctx, itemKey, size));
4985
- }
4986
- };
4987
- updateContainerItemSize(measurement.itemKey, measurement.containerId, measurement.size);
4988
- const keys = Array.from(pendingKeys);
4989
- for (const itemKey of keys) {
4990
- const containerId = state.containerItemKeys.get(itemKey);
4991
- if (containerId !== void 0) {
4992
- (_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) => {
4993
- if (pendingKeys.has(itemKey)) {
4994
- updateContainerItemSize(itemKey, containerId, { height, width });
4995
- }
4996
- });
4997
- }
4724
+ if (activeItemSizeBatches) {
4725
+ const measurements = activeItemSizeBatches.get(ctx);
4726
+ if (measurements) {
4727
+ measurements.push(measurement);
4728
+ } else {
4729
+ activeItemSizeBatches.set(ctx, [measurement]);
4998
4730
  }
4999
- }
5000
- if (shouldQueueRecalculate && result.needsRecalculate) {
5001
- queueItemSizeRecalculate(ctx, result);
5002
4731
  } else {
5003
- flushItemSizeUpdates(ctx, result);
5004
- }
5005
- if (didDrainLayoutEffectMeasurements) {
5006
- flushBatchedItemSizeRecalculate(ctx);
4732
+ updateItemSizesBatch(ctx, [measurement]);
5007
4733
  }
5008
4734
  }
5009
- function applyItemSize(ctx, itemKey, sizeObj) {
4735
+ function updateItemSizesBatch(ctx, measurements) {
5010
4736
  var _a3;
5011
4737
  const state = ctx.state;
4738
+ const result = {};
4739
+ for (const measurement of measurements) {
4740
+ const ownsMeasuredItem = measurement.containerId === void 0 || peek$(ctx, `containerItemKey${measurement.containerId}`) === measurement.itemKey;
4741
+ if (ownsMeasuredItem) {
4742
+ const index = state.indexByKey.get(measurement.itemKey);
4743
+ const itemData = index === void 0 ? void 0 : (_a3 = state.props.data) == null ? void 0 : _a3[index];
4744
+ const metadata = measurement.containerId !== void 0 && index !== void 0 && itemData !== void 0 ? resolveContainerItemMetadata(state, measurement.containerId, index, itemData) : void 0;
4745
+ const nextResult = applyItemSize(ctx, measurement.itemKey, measurement.size, metadata);
4746
+ mergeItemSizeUpdateResult(result, nextResult);
4747
+ }
4748
+ }
4749
+ flushItemSizeUpdates(ctx, result);
4750
+ }
4751
+ function applyItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
4752
+ var _a3, _b;
4753
+ const state = ctx.state;
5012
4754
  const userScrollAnchorReset = state.userScrollAnchorReset;
5013
4755
  const didMeasureUserScrollAnchorResetItem = !!(userScrollAnchorReset == null ? void 0 : userScrollAnchorReset.keys.delete(itemKey));
5014
4756
  const {
@@ -5018,7 +4760,6 @@ function applyItemSize(ctx, itemKey, sizeObj) {
5018
4760
  } = state;
5019
4761
  if (!data) return { didMeasureUserScrollAnchorResetItem };
5020
4762
  const index = state.indexByKey.get(itemKey);
5021
- let resolvedMeasurementItem;
5022
4763
  if (getFixedItemSize) {
5023
4764
  if (index === void 0) {
5024
4765
  return { didMeasureUserScrollAnchorResetItem };
@@ -5027,14 +4768,15 @@ function applyItemSize(ctx, itemKey, sizeObj) {
5027
4768
  if (itemData === void 0) {
5028
4769
  return { didMeasureUserScrollAnchorResetItem };
5029
4770
  }
5030
- const type = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
5031
- const size2 = getFixedItemSize(itemData, index, type);
5032
- resolvedMeasurementItem = {
5033
- didResolveFixedItemSize: true,
5034
- fixedItemSize: size2,
5035
- itemData,
5036
- itemType: type
5037
- };
4771
+ if (!(resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.didResolveFixedItemSize)) {
4772
+ const type = (_b = resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.itemType) != null ? _b : getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
4773
+ resolvedMeasurementItem = {
4774
+ didResolveFixedItemSize: true,
4775
+ fixedItemSize: getFixedItemSize(itemData, index, type),
4776
+ itemType: type
4777
+ };
4778
+ }
4779
+ const size2 = resolvedMeasurementItem.fixedItemSize;
5038
4780
  if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
5039
4781
  updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
5040
4782
  return { didMeasureUserScrollAnchorResetItem };
@@ -5053,91 +4795,532 @@ function applyItemSize(ctx, itemKey, sizeObj) {
5053
4795
  if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
5054
4796
  needsRecalculate = true;
5055
4797
  }
5056
- if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
5057
- shouldMaintainScrollAtEnd = true;
4798
+ if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
4799
+ shouldMaintainScrollAtEnd = true;
4800
+ }
4801
+ onItemSizeChanged == null ? void 0 : onItemSizeChanged({
4802
+ index,
4803
+ itemData: state.props.data[index],
4804
+ itemKey,
4805
+ previous: size - diff,
4806
+ size
4807
+ });
4808
+ maybeUpdateAnchoredEndSpace(ctx);
4809
+ }
4810
+ if (minIndexSizeChanged !== void 0) {
4811
+ state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
4812
+ }
4813
+ updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
4814
+ if (didContainersLayout || checkAllSizesKnown(state, state.startBuffered, state.endBuffered)) {
4815
+ const canMaintainScrollAtEnd = shouldMaintainScrollAtEnd && !!(maintainScrollAtEnd == null ? void 0 : maintainScrollAtEnd.onItemLayout);
4816
+ return {
4817
+ didChange: diff !== 0,
4818
+ didMeasureUserScrollAnchorResetItem,
4819
+ needsRecalculate,
4820
+ shouldMaintainScrollAtEnd: canMaintainScrollAtEnd
4821
+ };
4822
+ }
4823
+ return {
4824
+ didChange: diff !== 0,
4825
+ didMeasureUserScrollAnchorResetItem
4826
+ };
4827
+ }
4828
+ function updateOneItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
4829
+ var _a3, _b;
4830
+ const state = ctx.state;
4831
+ const {
4832
+ indexByKey,
4833
+ sizesKnown,
4834
+ averageSizes,
4835
+ props: { data, horizontal, getItemType, getFixedItemSize }
4836
+ } = state;
4837
+ if (!data) return 0;
4838
+ const index = indexByKey.get(itemKey);
4839
+ const itemData = data[index];
4840
+ let itemType = resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.itemType;
4841
+ let fixedItemSize = resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.fixedItemSize;
4842
+ if (getFixedItemSize && !(resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.didResolveFixedItemSize)) {
4843
+ itemType = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
4844
+ fixedItemSize = getFixedItemSize(itemData, index, itemType);
4845
+ }
4846
+ const resolvedItemSize = (resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.didResolveFixedItemSize) || itemType !== void 0 || fixedItemSize !== void 0 ? {
4847
+ didResolveFixedItemSize: resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.didResolveFixedItemSize,
4848
+ fixedItemSize,
4849
+ itemType
4850
+ } : void 0;
4851
+ const prevSize = getItemSize(ctx, itemKey, index, itemData, void 0, void 0, void 0, resolvedItemSize);
4852
+ const rawSize = horizontal ? sizeObj.width : sizeObj.height;
4853
+ const prevSizeKnown = sizesKnown.get(itemKey);
4854
+ if (Platform.OS !== "web" && prevSizeKnown !== void 0 && isNativeLayoutNoise(rawSize - prevSizeKnown)) {
4855
+ return 0;
4856
+ }
4857
+ const size = Platform.OS === "web" ? Math.round(rawSize) : roundSize(rawSize);
4858
+ sizesKnown.set(itemKey, size);
4859
+ if (fixedItemSize === void 0 && size > 0) {
4860
+ itemType != null ? itemType : itemType = getItemType ? (_b = getItemType(itemData, index)) != null ? _b : "" : "";
4861
+ let averages = averageSizes[itemType];
4862
+ if (!averages) {
4863
+ averages = averageSizes[itemType] = { avg: 0, num: 0 };
4864
+ }
4865
+ if (averages.num === 0) {
4866
+ averages.avg = size;
4867
+ averages.num++;
4868
+ } else if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
4869
+ averages.avg += (size - prevSizeKnown) / averages.num;
4870
+ } else {
4871
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
4872
+ averages.num++;
4873
+ }
4874
+ }
4875
+ if (!prevSize || Math.abs(prevSize - size) > 0.1) {
4876
+ setSize(ctx, itemKey, size);
4877
+ return size - prevSize;
4878
+ }
4879
+ return 0;
4880
+ }
4881
+
4882
+ // src/core/measureContainersInLayoutEffect.native.ts
4883
+ function resolveFixedItemSize(ctx, containerId, itemKey) {
4884
+ var _a3;
4885
+ const state = ctx.state;
4886
+ const { data, getFixedItemSize } = state.props;
4887
+ const index = state.indexByKey.get(itemKey);
4888
+ let fixedItemSize;
4889
+ if (data && getFixedItemSize && index !== void 0) {
4890
+ const itemData = data[index];
4891
+ if (itemData !== void 0) {
4892
+ fixedItemSize = (_a3 = resolveContainerItemMetadata(state, containerId, index, itemData)) == null ? void 0 : _a3.fixedItemSize;
4893
+ }
4894
+ }
4895
+ return fixedItemSize;
4896
+ }
4897
+ function resolveSkippedAnchorReset(ctx, itemKey) {
4898
+ const state = ctx.state;
4899
+ const anchorReset = state.userScrollAnchorReset;
4900
+ if ((anchorReset == null ? void 0 : anchorReset.keys.delete(itemKey)) && anchorReset.keys.size === 0) {
4901
+ state.userScrollAnchorReset = void 0;
4902
+ }
4903
+ }
4904
+ function measureContainersInLayoutEffect(ctx, targetContainerIds = null) {
4905
+ var _a3, _b, _c;
4906
+ const state = ctx.state;
4907
+ const measurements = [];
4908
+ let isCollectingSynchronousMeasurements = true;
4909
+ const containerIds = targetContainerIds != null ? targetContainerIds : ctx.viewRefs.keys();
4910
+ for (const containerId of containerIds) {
4911
+ const viewRef = ctx.viewRefs.get(containerId);
4912
+ const itemKey = peek$(ctx, `containerItemKey${containerId}`);
4913
+ if (itemKey !== void 0) {
4914
+ const generation = ((_a3 = state.containerItemGenerations[containerId]) != null ? _a3 : 0) + 1;
4915
+ state.containerItemGenerations[containerId] = generation;
4916
+ const fixedItemSize = resolveFixedItemSize(ctx, containerId, itemKey);
4917
+ const canSkipMeasurement = !state.needsOtherAxisSize && fixedItemSize !== void 0 && state.sizesKnown.get(itemKey) === fixedItemSize + ctx.scrollAxisGap;
4918
+ if (canSkipMeasurement) {
4919
+ resolveSkippedAnchorReset(ctx, itemKey);
4920
+ } else if (viewRef) {
4921
+ (_c = (_b = viewRef.current) == null ? void 0 : _b.measure) == null ? void 0 : _c.call(_b, (_x, _y, width, height) => {
4922
+ var _a4;
4923
+ const isCurrentGeneration = ((_a4 = ctx.state.containerItemGenerations[containerId]) != null ? _a4 : 0) === generation;
4924
+ if (isCurrentGeneration) {
4925
+ const measurement = {
4926
+ containerId,
4927
+ itemKey,
4928
+ size: { height, width }
4929
+ };
4930
+ if (isCollectingSynchronousMeasurements) {
4931
+ measurements.push(measurement);
4932
+ } else {
4933
+ updateItemSizes(ctx, measurement);
4934
+ }
4935
+ }
4936
+ });
4937
+ }
4938
+ }
4939
+ }
4940
+ isCollectingSynchronousMeasurements = false;
4941
+ if (measurements.length > 0) {
4942
+ updateItemSizesBatch(ctx, measurements);
4943
+ }
4944
+ }
4945
+ var typedForwardRef = React2.forwardRef;
4946
+ var typedMemo = React2.memo;
4947
+
4948
+ // src/components/ContainerLayoutCoordinator.tsx
4949
+ var ContainerLayoutCoordinator = typedMemo(function ContainerLayoutCoordinatorComponent({
4950
+ children
4951
+ }) {
4952
+ const ctx = useStateContext();
4953
+ const [containerLayoutEpoch] = useArr$(["containerLayoutEpoch"]);
4954
+ React2.useLayoutEffect(() => {
4955
+ if (IsNewArchitecture) {
4956
+ const targetContainerIds = getContainerLayoutEffectScope(ctx);
4957
+ if (targetContainerIds !== void 0) {
4958
+ measureContainersInLayoutEffect(ctx, targetContainerIds);
4959
+ }
4960
+ }
4961
+ }, [ctx, containerLayoutEpoch]);
4962
+ return children;
4963
+ });
4964
+
4965
+ // src/components/stickyPositionUtils.ts
4966
+ function getStickyPushLimit(state, index, itemKey) {
4967
+ if (!itemKey) {
4968
+ return void 0;
4969
+ }
4970
+ const currentSize = state.sizes.get(itemKey);
4971
+ if (!(currentSize && currentSize > 0)) {
4972
+ return void 0;
4973
+ }
4974
+ const stickyIndexInArray = state.props.stickyHeaderIndicesArr.indexOf(index);
4975
+ if (stickyIndexInArray === -1) {
4976
+ return void 0;
4977
+ }
4978
+ const nextStickyIndex = state.props.stickyHeaderIndicesArr[stickyIndexInArray + 1];
4979
+ if (nextStickyIndex === void 0) {
4980
+ return void 0;
4981
+ }
4982
+ const nextStickyPosition = state.positions[nextStickyIndex];
4983
+ if (nextStickyPosition === void 0) {
4984
+ return void 0;
4985
+ }
4986
+ return nextStickyPosition - currentSize;
4987
+ }
4988
+ var useAnimatedValue = (initialValue) => {
4989
+ const [animAnimatedValue] = useState(() => new Animated.Value(initialValue));
4990
+ return animAnimatedValue;
4991
+ };
4992
+
4993
+ // src/hooks/useValue$.ts
4994
+ function useValue$(key, params) {
4995
+ const { getValue } = params || {};
4996
+ const ctx = useStateContext();
4997
+ const getNewValue = () => {
4998
+ var _a3;
4999
+ return (_a3 = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a3 : 0;
5000
+ };
5001
+ const animValue = useAnimatedValue(getNewValue());
5002
+ useLayoutEffect(() => {
5003
+ const syncCurrentValue = () => {
5004
+ animValue.setValue(getNewValue());
5005
+ };
5006
+ const unsubscribe = listen$(ctx, key, syncCurrentValue);
5007
+ syncCurrentValue();
5008
+ return unsubscribe;
5009
+ }, [animValue, ctx, key]);
5010
+ return animValue;
5011
+ }
5012
+ var getComponent = (Component) => {
5013
+ if (React2.isValidElement(Component)) {
5014
+ return Component;
5015
+ }
5016
+ if (Component) {
5017
+ return /* @__PURE__ */ React2.createElement(Component, null);
5018
+ }
5019
+ return null;
5020
+ };
5021
+
5022
+ // src/components/PositionView.native.tsx
5023
+ var PositionViewState = typedMemo(function PositionViewState2({
5024
+ id,
5025
+ horizontal,
5026
+ style,
5027
+ refView,
5028
+ ...rest
5029
+ }) {
5030
+ const [position = POSITION_OUT_OF_VIEW, _itemKey] = useArr$([`containerPosition${id}`, `containerItemKey${id}`]);
5031
+ return /* @__PURE__ */ React2.createElement(View$1, { ref: refView, style: [style, horizontal ? { left: position } : { top: position }], ...rest });
5032
+ });
5033
+ var PositionViewAnimated = typedMemo(function PositionViewAnimated2({
5034
+ id,
5035
+ horizontal,
5036
+ style,
5037
+ refView,
5038
+ ...rest
5039
+ }) {
5040
+ const position$ = useValue$(`containerPosition${id}`, {
5041
+ getValue: (v) => v != null ? v : POSITION_OUT_OF_VIEW
5042
+ });
5043
+ const position = horizontal ? { left: position$ } : { top: position$ };
5044
+ return /* @__PURE__ */ React2.createElement(Animated.View, { ref: refView, style: [style, position], ...rest });
5045
+ });
5046
+ var PositionViewSticky = typedMemo(function PositionViewSticky2({
5047
+ id,
5048
+ horizontal,
5049
+ style,
5050
+ refView,
5051
+ animatedScrollY,
5052
+ stickyHeaderConfig,
5053
+ children,
5054
+ ...rest
5055
+ }) {
5056
+ const ctx = useStateContext();
5057
+ const [
5058
+ position = POSITION_OUT_OF_VIEW,
5059
+ alignItemsAtEndPadding = 0,
5060
+ headerSize = 0,
5061
+ stylePaddingTop = 0,
5062
+ itemKey,
5063
+ itemIndex,
5064
+ _totalSize = 0
5065
+ ] = useArr$([
5066
+ `containerPosition${id}`,
5067
+ "alignItemsAtEndPadding",
5068
+ "headerSize",
5069
+ "stylePaddingTop",
5070
+ `containerItemKey${id}`,
5071
+ `containerItemIndex${id}`,
5072
+ "totalSize"
5073
+ ]);
5074
+ const pushLimit = React2.useMemo(
5075
+ () => getStickyPushLimit(ctx.state, itemIndex, itemKey),
5076
+ [ctx.state, itemIndex, itemKey, _totalSize]
5077
+ );
5078
+ const transform = React2.useMemo(() => {
5079
+ var _a3;
5080
+ if (animatedScrollY) {
5081
+ const stickyConfigOffset = (_a3 = stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset) != null ? _a3 : 0;
5082
+ const stickyStart = position + headerSize + stylePaddingTop + alignItemsAtEndPadding - stickyConfigOffset;
5083
+ let nextStickyPosition;
5084
+ if (pushLimit !== void 0) {
5085
+ if (pushLimit <= position) {
5086
+ nextStickyPosition = pushLimit;
5087
+ } else {
5088
+ nextStickyPosition = animatedScrollY.interpolate({
5089
+ extrapolateLeft: "clamp",
5090
+ extrapolateRight: "clamp",
5091
+ inputRange: [stickyStart, stickyStart + (pushLimit - position)],
5092
+ outputRange: [position, pushLimit]
5093
+ });
5094
+ }
5095
+ } else {
5096
+ nextStickyPosition = animatedScrollY.interpolate({
5097
+ extrapolateLeft: "clamp",
5098
+ extrapolateRight: "extend",
5099
+ inputRange: [stickyStart, stickyStart + 5e3],
5100
+ outputRange: [position, position + 5e3]
5101
+ });
5102
+ }
5103
+ return horizontal ? [{ translateX: nextStickyPosition }] : [{ translateY: nextStickyPosition }];
5104
+ }
5105
+ }, [
5106
+ alignItemsAtEndPadding,
5107
+ animatedScrollY,
5108
+ headerSize,
5109
+ position,
5110
+ pushLimit,
5111
+ stylePaddingTop,
5112
+ stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset
5113
+ ]);
5114
+ const viewStyle = React2.useMemo(
5115
+ () => [style, { zIndex: itemIndex + 1e3 }, { transform }],
5116
+ [style, itemIndex, transform]
5117
+ );
5118
+ const renderStickyHeaderBackdrop = React2.useMemo(() => {
5119
+ if (!(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)) {
5120
+ return null;
5121
+ }
5122
+ return /* @__PURE__ */ React2.createElement(
5123
+ View$1,
5124
+ {
5125
+ style: {
5126
+ inset: 0,
5127
+ pointerEvents: "none",
5128
+ position: "absolute"
5129
+ }
5130
+ },
5131
+ getComponent(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)
5132
+ );
5133
+ }, [stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent]);
5134
+ return /* @__PURE__ */ React2.createElement(Animated.View, { ref: refView, style: viewStyle, ...rest }, renderStickyHeaderBackdrop, children);
5135
+ });
5136
+ var PositionView = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
5137
+ function useInit(cb) {
5138
+ useState(() => cb());
5139
+ }
5140
+
5141
+ // src/state/ContextContainer.ts
5142
+ var ContextContainer = createContext(null);
5143
+ var NO_CONTAINER_ID = -1;
5144
+ function useContextContainer() {
5145
+ return useContext(ContextContainer);
5146
+ }
5147
+ function useContainerItemSignals(containerContext) {
5148
+ var _a3;
5149
+ const containerId = (_a3 = containerContext == null ? void 0 : containerContext.containerId) != null ? _a3 : NO_CONTAINER_ID;
5150
+ const [itemKey, itemIndex, item] = useArr$([
5151
+ `containerItemKey${containerId}`,
5152
+ `containerItemIndex${containerId}`,
5153
+ `containerItemData${containerId}`
5154
+ ]);
5155
+ return {
5156
+ hasItemInfo: !!containerContext && itemKey !== void 0 && itemIndex !== void 0,
5157
+ item,
5158
+ itemIndex,
5159
+ itemKey
5160
+ };
5161
+ }
5162
+ function useAdaptiveRender() {
5163
+ const [mode] = useArr$(["adaptiveRender"]);
5164
+ return mode;
5165
+ }
5166
+ function useAdaptiveRenderChange(callback) {
5167
+ const ctx = useStateContext();
5168
+ const callbackRef = useRef(callback);
5169
+ callbackRef.current = callback;
5170
+ useLayoutEffect(() => {
5171
+ let mode = peek$(ctx, "adaptiveRender");
5172
+ return listen$(ctx, "adaptiveRender", (nextMode) => {
5173
+ if (mode !== nextMode) {
5174
+ mode = nextMode;
5175
+ callbackRef.current(nextMode);
5176
+ }
5177
+ });
5178
+ }, [ctx]);
5179
+ }
5180
+ function useViewability(callback, configId) {
5181
+ const ctx = useStateContext();
5182
+ const containerContext = useContextContainer();
5183
+ useInit(() => {
5184
+ if (!containerContext) {
5185
+ return;
5186
+ }
5187
+ const { containerId } = containerContext;
5188
+ const key = containerId + (configId != null ? configId : "");
5189
+ const value = ctx.mapViewabilityValues.get(key);
5190
+ if (value) {
5191
+ callback(value);
5192
+ }
5193
+ });
5194
+ useEffect(() => {
5195
+ if (!containerContext) {
5196
+ return;
5197
+ }
5198
+ const { containerId } = containerContext;
5199
+ const key = containerId + (configId != null ? configId : "");
5200
+ ctx.mapViewabilityCallbacks.set(key, callback);
5201
+ return () => {
5202
+ ctx.mapViewabilityCallbacks.delete(key);
5203
+ };
5204
+ }, [ctx, callback, configId, containerContext]);
5205
+ }
5206
+ function useViewabilityAmount(callback) {
5207
+ const ctx = useStateContext();
5208
+ const containerContext = useContextContainer();
5209
+ useInit(() => {
5210
+ if (!containerContext) {
5211
+ return;
5212
+ }
5213
+ const { containerId } = containerContext;
5214
+ const value = ctx.mapViewabilityAmountValues.get(containerId);
5215
+ if (value) {
5216
+ callback(value);
5217
+ }
5218
+ });
5219
+ useEffect(() => {
5220
+ if (!containerContext) {
5221
+ return;
5222
+ }
5223
+ const { containerId } = containerContext;
5224
+ ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
5225
+ return () => {
5226
+ ctx.mapViewabilityAmountCallbacks.delete(containerId);
5227
+ };
5228
+ }, [ctx, callback, containerContext]);
5229
+ }
5230
+ function useRecyclingEffect(effect) {
5231
+ const containerContext = useContextContainer();
5232
+ const { hasItemInfo, item, itemIndex, itemKey } = useContainerItemSignals(containerContext);
5233
+ const prevInfo = useRef(void 0);
5234
+ useEffect(() => {
5235
+ if (!hasItemInfo) {
5236
+ return;
5237
+ }
5238
+ let ret;
5239
+ if (prevInfo.current) {
5240
+ ret = effect({
5241
+ index: itemIndex,
5242
+ item,
5243
+ prevIndex: prevInfo.current.index,
5244
+ prevItem: prevInfo.current.item
5245
+ });
5058
5246
  }
5059
- onItemSizeChanged == null ? void 0 : onItemSizeChanged({
5060
- index,
5061
- itemData: state.props.data[index],
5062
- itemKey,
5063
- previous: size - diff,
5064
- size
5065
- });
5066
- maybeUpdateAnchoredEndSpace(ctx);
5067
- }
5068
- if (minIndexSizeChanged !== void 0) {
5069
- state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
5070
- }
5071
- updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
5072
- if (didContainersLayout || checkAllSizesKnown(state, state.startBuffered, state.endBuffered)) {
5073
- const canMaintainScrollAtEnd = shouldMaintainScrollAtEnd && !!(maintainScrollAtEnd == null ? void 0 : maintainScrollAtEnd.onItemLayout);
5074
- return {
5075
- didChange: diff !== 0,
5076
- didMeasureUserScrollAnchorResetItem,
5077
- needsRecalculate,
5078
- shouldMaintainScrollAtEnd: canMaintainScrollAtEnd
5247
+ prevInfo.current = {
5248
+ index: itemIndex,
5249
+ item
5079
5250
  };
5080
- }
5081
- return {
5082
- didChange: diff !== 0,
5083
- didMeasureUserScrollAnchorResetItem
5084
- };
5251
+ return ret;
5252
+ }, [effect, hasItemInfo, itemIndex, item, itemKey]);
5085
5253
  }
5086
- function updateOneItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem) {
5087
- var _a3, _b, _c;
5088
- const state = ctx.state;
5089
- const {
5090
- indexByKey,
5091
- sizesKnown,
5092
- averageSizes,
5093
- props: { data, horizontal, getItemType, getFixedItemSize }
5094
- } = state;
5095
- if (!data) return 0;
5096
- const index = indexByKey.get(itemKey);
5097
- const itemData = (_a3 = resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.itemData) != null ? _a3 : data[index];
5098
- let itemType = resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.itemType;
5099
- let fixedItemSize = resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.fixedItemSize;
5100
- if (getFixedItemSize && !(resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.didResolveFixedItemSize)) {
5101
- itemType = getItemType ? (_b = getItemType(itemData, index)) != null ? _b : "" : "";
5102
- fixedItemSize = getFixedItemSize(itemData, index, itemType);
5103
- }
5104
- const resolvedItemSize = (resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.didResolveFixedItemSize) || itemType !== void 0 || fixedItemSize !== void 0 ? {
5105
- didResolveFixedItemSize: resolvedMeasurementItem == null ? void 0 : resolvedMeasurementItem.didResolveFixedItemSize,
5106
- fixedItemSize,
5107
- itemType
5108
- } : void 0;
5109
- const prevSize = getItemSize(ctx, itemKey, index, itemData, void 0, void 0, void 0, resolvedItemSize);
5110
- const rawSize = horizontal ? sizeObj.width : sizeObj.height;
5111
- const prevSizeKnown = sizesKnown.get(itemKey);
5112
- if (Platform.OS !== "web" && prevSizeKnown !== void 0 && isNativeLayoutNoise(rawSize - prevSizeKnown)) {
5113
- return 0;
5114
- }
5115
- const size = Platform.OS === "web" ? Math.round(rawSize) : roundSize(rawSize);
5116
- sizesKnown.set(itemKey, size);
5117
- if (fixedItemSize === void 0 && size > 0) {
5118
- itemType != null ? itemType : itemType = getItemType ? (_c = getItemType(itemData, index)) != null ? _c : "" : "";
5119
- let averages = averageSizes[itemType];
5120
- if (!averages) {
5121
- averages = averageSizes[itemType] = { avg: 0, num: 0 };
5122
- }
5123
- if (averages.num === 0) {
5124
- averages.avg = size;
5125
- averages.num++;
5126
- } else if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
5127
- averages.avg += (size - prevSizeKnown) / averages.num;
5128
- } else {
5129
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
5130
- averages.num++;
5254
+ function useRecyclingState(valueOrFun) {
5255
+ const containerContext = useContextContainer();
5256
+ const { hasItemInfo, item, itemIndex, itemKey } = useContainerItemSignals(containerContext);
5257
+ const computeValue = () => {
5258
+ if (isFunction(valueOrFun)) {
5259
+ const initializer = valueOrFun;
5260
+ return hasItemInfo ? initializer({
5261
+ index: itemIndex,
5262
+ item,
5263
+ prevIndex: void 0,
5264
+ prevItem: void 0
5265
+ }) : initializer();
5131
5266
  }
5267
+ return valueOrFun;
5268
+ };
5269
+ const [stateValue, setStateValue] = useState(() => {
5270
+ return computeValue();
5271
+ });
5272
+ const prevItemKeyRef = useRef(hasItemInfo ? itemKey : null);
5273
+ if (hasItemInfo && prevItemKeyRef.current !== itemKey) {
5274
+ prevItemKeyRef.current = itemKey;
5275
+ setStateValue(computeValue());
5132
5276
  }
5133
- if (!prevSize || Math.abs(prevSize - size) > 0.1) {
5134
- setSize(ctx, itemKey, size);
5135
- return size - prevSize;
5136
- }
5137
- return 0;
5277
+ const triggerLayout = containerContext == null ? void 0 : containerContext.triggerLayout;
5278
+ const setState = useCallback(
5279
+ (newState) => {
5280
+ if (!triggerLayout) {
5281
+ return;
5282
+ }
5283
+ setStateValue((prevValue) => {
5284
+ return isFunction(newState) ? newState(prevValue) : newState;
5285
+ });
5286
+ triggerLayout();
5287
+ },
5288
+ [triggerLayout]
5289
+ );
5290
+ return [stateValue, setState];
5291
+ }
5292
+ function useIsLastItem() {
5293
+ var _a3;
5294
+ const containerContext = useContextContainer();
5295
+ const containerId = (_a3 = containerContext == null ? void 0 : containerContext.containerId) != null ? _a3 : NO_CONTAINER_ID;
5296
+ const [itemKey] = useArr$([`containerItemKey${containerId}`]);
5297
+ const isLast = useSelector$("lastItemKeys", (lastItemKeys) => {
5298
+ if (containerContext && !isNullOrUndefined(itemKey)) {
5299
+ return (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false;
5300
+ }
5301
+ return false;
5302
+ });
5303
+ return isLast;
5304
+ }
5305
+ function useListScrollSize() {
5306
+ const [scrollSize] = useArr$(["scrollSize"]);
5307
+ return scrollSize;
5308
+ }
5309
+ var noop = () => {
5310
+ };
5311
+ function useSyncLayout() {
5312
+ const containerContext = useContextContainer();
5313
+ return IsNewArchitecture && containerContext ? containerContext.triggerLayout : noop;
5314
+ }
5315
+
5316
+ // src/components/Separator.tsx
5317
+ function Separator({ ItemSeparatorComponent, leadingItem }) {
5318
+ const isLastItem = useIsLastItem();
5319
+ return isLastItem ? null : /* @__PURE__ */ React2.createElement(ItemSeparatorComponent, { leadingItem });
5138
5320
  }
5139
5321
  function useOnLayoutSync({
5140
5322
  ref,
5323
+ measureInLayoutEffect = true,
5141
5324
  onLayoutProp,
5142
5325
  onLayoutChange
5143
5326
  }, deps = []) {
@@ -5151,16 +5334,154 @@ function useOnLayoutSync({
5151
5334
  );
5152
5335
  if (IsNewArchitecture) {
5153
5336
  useLayoutEffect(() => {
5154
- if (ref.current) {
5337
+ if (measureInLayoutEffect && ref.current) {
5155
5338
  ref.current.measure((x, y, width, height) => {
5156
5339
  onLayoutChange({ height, width, x, y }, true);
5157
5340
  });
5158
5341
  }
5159
- }, deps);
5342
+ }, [measureInLayoutEffect, ...deps]);
5160
5343
  }
5161
5344
  return { onLayout };
5162
5345
  }
5163
5346
 
5347
+ // src/hooks/useContainerMeasurement.tsx
5348
+ var pendingWebShrinkMeasurements = /* @__PURE__ */ new Map();
5349
+ var pendingWebShrinkFrame;
5350
+ function cancelWebShrinkMeasurement(state) {
5351
+ pendingWebShrinkMeasurements.delete(state);
5352
+ }
5353
+ function scheduleWebShrinkMeasurement(state, confirmMeasurement) {
5354
+ pendingWebShrinkMeasurements.set(state, confirmMeasurement);
5355
+ if (pendingWebShrinkFrame === void 0) {
5356
+ pendingWebShrinkFrame = requestAnimationFrame(() => {
5357
+ const callbacks = Array.from(pendingWebShrinkMeasurements.values());
5358
+ pendingWebShrinkMeasurements.clear();
5359
+ pendingWebShrinkFrame = void 0;
5360
+ batchItemSizeUpdates(() => {
5361
+ for (const callback of callbacks) {
5362
+ callback();
5363
+ }
5364
+ });
5365
+ });
5366
+ }
5367
+ }
5368
+ function processContainerLayout({ containerId, ctx, rectangle, ref, state }) {
5369
+ var _a3, _b;
5370
+ const listState = ctx.state;
5371
+ const currentItemKey = state.itemKey;
5372
+ state.didLayout = true;
5373
+ let layout = rectangle;
5374
+ const axis = state.horizontal ? "width" : "height";
5375
+ const size = roundSize(rectangle[axis]);
5376
+ const localPreviousSize = state.lastSize ? roundSize(state.lastSize[axis]) : void 0;
5377
+ const coreKnownSize = listState.sizesKnown.get(currentItemKey);
5378
+ const previousSize = Platform.OS === "web" ? coreKnownSize : localPreviousSize;
5379
+ const applyLayout = () => {
5380
+ state.lastSize = layout;
5381
+ updateItemSizes(ctx, {
5382
+ containerId,
5383
+ itemKey: currentItemKey,
5384
+ size: layout
5385
+ });
5386
+ };
5387
+ const shouldDeferWebShrinkLayoutUpdate = Platform.OS === "web" && !isInMVCPActiveMode(listState) && previousSize !== void 0 && size + 1 < previousSize;
5388
+ if (shouldDeferWebShrinkLayoutUpdate) {
5389
+ scheduleWebShrinkMeasurement(state, () => {
5390
+ var _a4;
5391
+ if (state.itemKey === currentItemKey) {
5392
+ const element = ref.current;
5393
+ const rect = (_a4 = element == null ? void 0 : element.getBoundingClientRect) == null ? void 0 : _a4.call(element);
5394
+ if (rect) {
5395
+ layout = { height: rect.height, width: rect.width };
5396
+ }
5397
+ applyLayout();
5398
+ }
5399
+ });
5400
+ } else {
5401
+ if (Platform.OS === "web") {
5402
+ cancelWebShrinkMeasurement(state);
5403
+ }
5404
+ if (IsNewArchitecture || size > 0) {
5405
+ applyLayout();
5406
+ } else {
5407
+ (_b = (_a3 = ref.current) == null ? void 0 : _a3.measure) == null ? void 0 : _b.call(_a3, (_x, _y, width, height) => {
5408
+ layout = { height, width };
5409
+ applyLayout();
5410
+ });
5411
+ }
5412
+ }
5413
+ }
5414
+ function useContainerMeasurement({
5415
+ containerId,
5416
+ ctx,
5417
+ horizontal,
5418
+ itemKey,
5419
+ ref
5420
+ }) {
5421
+ const stateRef = useRef({
5422
+ didLayout: false,
5423
+ horizontal,
5424
+ itemKey
5425
+ });
5426
+ stateRef.current.horizontal = horizontal;
5427
+ stateRef.current.itemKey = itemKey;
5428
+ const [layoutRenderCount, forceLayoutRender] = useState(0);
5429
+ const onLayoutChange = useCallback(
5430
+ (rectangle) => {
5431
+ processContainerLayout({ containerId, ctx, rectangle, ref, state: stateRef.current });
5432
+ },
5433
+ [containerId, ctx, ref]
5434
+ );
5435
+ const triggerLayout = useCallback(() => {
5436
+ if (IsNewArchitecture) {
5437
+ scheduleContainerLayout(ctx, containerId);
5438
+ } else {
5439
+ forceLayoutRender((value) => value + 1);
5440
+ }
5441
+ }, [containerId, ctx]);
5442
+ useLayoutEffect(() => {
5443
+ ctx.containerLayoutTriggers.set(containerId, triggerLayout);
5444
+ return () => {
5445
+ cancelWebShrinkMeasurement(stateRef.current);
5446
+ if (ctx.containerLayoutTriggers.get(containerId) === triggerLayout) {
5447
+ ctx.containerLayoutTriggers.delete(containerId);
5448
+ }
5449
+ };
5450
+ }, [containerId, ctx, triggerLayout]);
5451
+ useLayoutEffect(() => {
5452
+ if (IsNewArchitecture) {
5453
+ scheduleContainerLayout(ctx, containerId);
5454
+ }
5455
+ });
5456
+ const { onLayout } = useOnLayoutSync(
5457
+ {
5458
+ measureInLayoutEffect: !IsNewArchitecture,
5459
+ onLayoutChange,
5460
+ ref},
5461
+ [itemKey, layoutRenderCount]
5462
+ );
5463
+ useEffect(() => {
5464
+ if (!IsNewArchitecture) {
5465
+ stateRef.current.didLayout = false;
5466
+ const timeout = setTimeout(() => {
5467
+ const state = stateRef.current;
5468
+ if (!state.didLayout && state.lastSize) {
5469
+ updateItemSizes(ctx, {
5470
+ containerId,
5471
+ itemKey: state.itemKey,
5472
+ size: state.lastSize
5473
+ });
5474
+ state.didLayout = true;
5475
+ }
5476
+ }, 16);
5477
+ return () => {
5478
+ clearTimeout(timeout);
5479
+ };
5480
+ }
5481
+ }, [containerId, ctx, itemKey]);
5482
+ return { onLayout, triggerLayout };
5483
+ }
5484
+
5164
5485
  // src/components/Container.tsx
5165
5486
  function getContainerPositionStyle({
5166
5487
  columnWrapperStyle,
@@ -5231,16 +5552,14 @@ var Container = typedMemo(function Container2({
5231
5552
  "extraData",
5232
5553
  `containerSticky${id}`
5233
5554
  ]);
5234
- const itemLayoutRef = useRef({
5235
- didLayout: false,
5555
+ const ref = useRef(null);
5556
+ const { onLayout, triggerLayout } = useContainerMeasurement({
5557
+ containerId: id,
5558
+ ctx,
5236
5559
  horizontal,
5237
5560
  itemKey,
5238
- pendingShrinkToken: 0
5561
+ ref
5239
5562
  });
5240
- itemLayoutRef.current.horizontal = horizontal;
5241
- itemLayoutRef.current.itemKey = itemKey;
5242
- const ref = useRef(null);
5243
- const [layoutRenderCount, forceLayoutRender] = useState(0);
5244
5563
  const resolvedColumn = column > 0 ? column : 1;
5245
5564
  const resolvedSpan = Math.min(Math.max(span || 1, 1), numColumns);
5246
5565
  const otherAxisPos = numColumns > 1 ? `${(resolvedColumn - 1) / numColumns * 100}%` : 0;
@@ -5271,63 +5590,7 @@ var Container = typedMemo(function Container2({
5271
5590
  () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
5272
5591
  [itemKey, data, extraData]
5273
5592
  );
5274
- const { index, renderedItem } = renderedItemInfo || {};
5275
- const onLayoutChange = useCallback((rectangle, fromLayoutEffect) => {
5276
- var _a3, _b;
5277
- const {
5278
- horizontal: currentHorizontal,
5279
- itemKey: currentItemKey,
5280
- lastSize,
5281
- pendingShrinkToken
5282
- } = itemLayoutRef.current;
5283
- if (isNullOrUndefined(currentItemKey)) {
5284
- return;
5285
- }
5286
- itemLayoutRef.current.didLayout = true;
5287
- let layout = rectangle;
5288
- const axis = currentHorizontal ? "width" : "height";
5289
- const size = roundSize(rectangle[axis]);
5290
- const prevSize = lastSize ? roundSize(lastSize[axis]) : void 0;
5291
- const doUpdate = () => {
5292
- itemLayoutRef.current.lastSize = layout;
5293
- updateItemSizes(ctx, {
5294
- containerId: id,
5295
- fromLayoutEffect,
5296
- itemKey: currentItemKey,
5297
- size: layout
5298
- });
5299
- itemLayoutRef.current.didLayout = true;
5300
- };
5301
- const shouldDeferWebShrinkLayoutUpdate = Platform.OS === "web" && !isInMVCPActiveMode(ctx.state) && prevSize !== void 0 && size + 1 < prevSize;
5302
- if (shouldDeferWebShrinkLayoutUpdate) {
5303
- const token = pendingShrinkToken + 1;
5304
- itemLayoutRef.current.pendingShrinkToken = token;
5305
- requestAnimationFrame(() => {
5306
- var _a4;
5307
- if (itemLayoutRef.current.pendingShrinkToken !== token) {
5308
- return;
5309
- }
5310
- const element = ref.current;
5311
- const rect = (_a4 = element == null ? void 0 : element.getBoundingClientRect) == null ? void 0 : _a4.call(element);
5312
- if (rect) {
5313
- layout = { height: rect.height, width: rect.width };
5314
- }
5315
- doUpdate();
5316
- });
5317
- return;
5318
- }
5319
- if (IsNewArchitecture || size > 0) {
5320
- doUpdate();
5321
- } else {
5322
- (_b = (_a3 = ref.current) == null ? void 0 : _a3.measure) == null ? void 0 : _b.call(_a3, (_x, _y, width, height) => {
5323
- layout = { height, width };
5324
- doUpdate();
5325
- });
5326
- }
5327
- }, []);
5328
- const triggerLayout = useCallback(() => {
5329
- forceLayoutRender((v) => v + 1);
5330
- }, []);
5593
+ const { renderedItem } = renderedItemInfo || {};
5331
5594
  const contextValue = useMemo(() => {
5332
5595
  ctx.viewRefs.set(id, ref);
5333
5596
  return {
@@ -5335,44 +5598,6 @@ var Container = typedMemo(function Container2({
5335
5598
  triggerLayout
5336
5599
  };
5337
5600
  }, [id, triggerLayout]);
5338
- useLayoutEffect(() => {
5339
- ctx.containerLayoutTriggers.set(id, triggerLayout);
5340
- return () => {
5341
- if (ctx.containerLayoutTriggers.get(id) === triggerLayout) {
5342
- ctx.containerLayoutTriggers.delete(id);
5343
- }
5344
- };
5345
- }, [ctx, id, triggerLayout]);
5346
- const { onLayout } = useOnLayoutSync(
5347
- {
5348
- onLayoutChange,
5349
- ref},
5350
- [itemKey, layoutRenderCount]
5351
- );
5352
- if (!IsNewArchitecture) {
5353
- useEffect(() => {
5354
- if (!isNullOrUndefined(itemKey)) {
5355
- itemLayoutRef.current.didLayout = false;
5356
- const timeout = setTimeout(() => {
5357
- if (!itemLayoutRef.current.didLayout) {
5358
- const { itemKey: currentItemKey, lastSize } = itemLayoutRef.current;
5359
- if (lastSize && !isNullOrUndefined(currentItemKey)) {
5360
- updateItemSizes(ctx, {
5361
- containerId: id,
5362
- fromLayoutEffect: false,
5363
- itemKey: currentItemKey,
5364
- size: lastSize
5365
- });
5366
- itemLayoutRef.current.didLayout = true;
5367
- }
5368
- }
5369
- }, 16);
5370
- return () => {
5371
- clearTimeout(timeout);
5372
- };
5373
- }
5374
- }, [itemKey]);
5375
- }
5376
5601
  const PositionComponent = isSticky ? stickyPositionComponentInternal ? stickyPositionComponentInternal : PositionViewSticky : positionComponentInternal ? positionComponentInternal : PositionView;
5377
5602
  return /* @__PURE__ */ React2.createElement(
5378
5603
  PositionComponent,
@@ -5380,7 +5605,6 @@ var Container = typedMemo(function Container2({
5380
5605
  animatedScrollY: isSticky ? animatedScrollY : void 0,
5381
5606
  horizontal,
5382
5607
  id,
5383
- index,
5384
5608
  key: recycleItems ? void 0 : itemKey,
5385
5609
  onLayout,
5386
5610
  refView: ref,
@@ -5454,7 +5678,7 @@ var ContainersLayer = typedMemo(function ContainersLayer2({ children, horizontal
5454
5678
  }
5455
5679
  }
5456
5680
  }
5457
- return /* @__PURE__ */ React2.createElement(Animated.View, { style }, children);
5681
+ return /* @__PURE__ */ React2.createElement(Animated.View, { style }, /* @__PURE__ */ React2.createElement(ContainerLayoutCoordinator, null, children));
5458
5682
  });
5459
5683
  var Containers = typedMemo(function Containers2({
5460
5684
  horizontal,
@@ -5641,6 +5865,8 @@ var ListComponent = typedMemo(function ListComponent2({
5641
5865
  refScrollView,
5642
5866
  renderScrollComponent,
5643
5867
  onLayoutFooter,
5868
+ onInternalScrollBeginDrag,
5869
+ onInternalScrollEnd,
5644
5870
  scrollAdjustHandler,
5645
5871
  snapToIndices,
5646
5872
  stickyHeaderConfig,
@@ -5702,7 +5928,7 @@ var ListComponent = typedMemo(function ListComponent2({
5702
5928
  SnapOrScroll,
5703
5929
  {
5704
5930
  ...rest,
5705
- ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
5931
+ ...Platform.OS === "web" ? ScrollComponent === ListComponentScrollView ? { onInternalScrollEnd, useWindowScroll } : {} : { onScrollBeginDrag: onInternalScrollBeginDrag },
5706
5932
  contentContainerStyle: [
5707
5933
  horizontal ? {
5708
5934
  height: "100%"
@@ -5808,6 +6034,7 @@ function checkResetContainers(ctx, dataProp, { didColumnsChange = false } = {})
5808
6034
  if (didColumnsChange) {
5809
6035
  state.sizes.clear();
5810
6036
  state.sizesKnown.clear();
6037
+ invalidateContainerFixedItemSizes(state);
5811
6038
  for (const key in state.averageSizes) {
5812
6039
  delete state.averageSizes[key];
5813
6040
  }
@@ -6054,7 +6281,7 @@ function onScroll(ctx, event) {
6054
6281
  }
6055
6282
  }
6056
6283
  state.scrollPending = newScroll;
6057
- updateScroll(ctx, newScroll, insetChanged);
6284
+ updateScroll(ctx, newScroll, insetChanged, { fromNativeScrollEvent: true });
6058
6285
  trackInitialScrollNativeProgress(state, newScroll);
6059
6286
  clearFinishedBootstrapInitialScrollTargetIfMovedAway(ctx);
6060
6287
  if (state.scrollingTo) {
@@ -6230,8 +6457,12 @@ function getAverageItemSizes(state) {
6230
6457
  return averageItemSizes;
6231
6458
  }
6232
6459
  function triggerMountedContainerLayouts(ctx) {
6233
- for (const triggerLayout of ctx.containerLayoutTriggers.values()) {
6234
- triggerLayout();
6460
+ if (IsNewArchitecture) {
6461
+ scheduleContainerLayout(ctx);
6462
+ } else {
6463
+ for (const triggerLayout of ctx.containerLayoutTriggers.values()) {
6464
+ triggerLayout();
6465
+ }
6235
6466
  }
6236
6467
  }
6237
6468
  function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
@@ -6344,6 +6575,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6344
6575
  const mode = (_a3 = options == null ? void 0 : options.mode) != null ? _a3 : "sizes";
6345
6576
  state.sizes.clear();
6346
6577
  state.sizesKnown.clear();
6578
+ invalidateContainerFixedItemSizes(state);
6347
6579
  for (const key in state.averageSizes) {
6348
6580
  delete state.averageSizes[key];
6349
6581
  }
@@ -6365,6 +6597,10 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
6365
6597
  return {
6366
6598
  clearCaches,
6367
6599
  flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
6600
+ getAnimatableRef: () => {
6601
+ var _a3, _b, _c;
6602
+ return (_c = (_b = (_a3 = refScroller.current).getNativeScrollRef) == null ? void 0 : _b.call(_a3)) != null ? _c : refScroller.current;
6603
+ },
6368
6604
  getNativeScrollRef: () => refScroller.current,
6369
6605
  getScrollableNode: () => refScroller.current.getScrollableNode(),
6370
6606
  getScrollResponder: () => refScroller.current.getScrollResponder(),
@@ -6735,6 +6971,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6735
6971
  onMomentumScrollEnd,
6736
6972
  onRefresh,
6737
6973
  onScroll: onScrollProp,
6974
+ onScrollBeginDrag,
6738
6975
  onStartReached,
6739
6976
  onStartReachedThreshold = 0.5,
6740
6977
  onStickyHeaderChange,
@@ -6846,8 +7083,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6846
7083
  averageSizes: {},
6847
7084
  columnSpans: [],
6848
7085
  columns: [],
7086
+ containerItemGenerations: [],
6849
7087
  containerItemKeys: /* @__PURE__ */ new Map(),
6850
- containerItemTypes: /* @__PURE__ */ new Map(),
7088
+ containerItemMetadata: /* @__PURE__ */ new Map(),
6851
7089
  contentInsetOverride: void 0,
6852
7090
  dataChangeEpoch: 0,
6853
7091
  dataChangeNeedsScrollUpdate: false,
@@ -6900,7 +7138,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6900
7138
  startBuffered: -1,
6901
7139
  startNoBuffer: -1,
6902
7140
  startReachedSnapshot: void 0,
6903
- startReachedSnapshotDataChangeEpoch: void 0,
6904
7141
  stickyContainerPool: /* @__PURE__ */ new Set(),
6905
7142
  stickyContainers: /* @__PURE__ */ new Map(),
6906
7143
  timeoutAdaptiveRender: void 0,
@@ -6976,7 +7213,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
6976
7213
  onFirstVisibleItemChanged,
6977
7214
  onItemSizeChanged,
6978
7215
  onLoad,
7216
+ onMomentumScrollEnd,
6979
7217
  onScroll: throttleScrollFn,
7218
+ onScrollBeginDrag,
6980
7219
  onStartReached,
6981
7220
  onStartReachedThreshold,
6982
7221
  onStickyHeaderChange,
@@ -7259,11 +7498,17 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7259
7498
  getRenderedItem: (key) => getRenderedItem(ctx, key),
7260
7499
  onMomentumScrollEnd: (event) => {
7261
7500
  checkFinishedScrollFallback(ctx);
7262
- if (onMomentumScrollEnd) {
7263
- onMomentumScrollEnd(event);
7501
+ if (state.props.onMomentumScrollEnd) {
7502
+ state.props.onMomentumScrollEnd(event);
7264
7503
  }
7265
7504
  },
7266
- onScroll: (event) => onScroll(ctx, event)
7505
+ onScroll: (event) => onScroll(ctx, event),
7506
+ onScrollBeginDrag: (event) => {
7507
+ var _a4, _b2;
7508
+ prepareReachedEdgeForNextUserScroll(ctx);
7509
+ (_b2 = (_a4 = state.props).onScrollBeginDrag) == null ? void 0 : _b2.call(_a4, event);
7510
+ },
7511
+ onScrollEnd: () => prepareReachedEdgeForNextUserScroll(ctx)
7267
7512
  }),
7268
7513
  []
7269
7514
  );
@@ -7284,6 +7529,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
7284
7529
  ListFooterComponent,
7285
7530
  ListFooterComponentStyle,
7286
7531
  ListHeaderComponent,
7532
+ onInternalScrollBeginDrag: fns.onScrollBeginDrag,
7533
+ onInternalScrollEnd: fns.onScrollEnd,
7287
7534
  onLayout,
7288
7535
  onLayoutFooter,
7289
7536
  onMomentumScrollEnd: fns.onMomentumScrollEnd,