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