@legendapp/list 3.3.1 → 3.3.3

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