@legendapp/list 2.0.0-next.10 → 2.0.0-next.12

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/index.js CHANGED
@@ -28,6 +28,7 @@ var React3__namespace = /*#__PURE__*/_interopNamespace(React3);
28
28
  var ContextState = React3__namespace.createContext(null);
29
29
  function StateProvider({ children }) {
30
30
  const [value] = React3__namespace.useState(() => ({
31
+ animatedScrollY: new reactNative.Animated.Value(0),
31
32
  columnWrapperStyle: void 0,
32
33
  listeners: /* @__PURE__ */ new Map(),
33
34
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
@@ -185,18 +186,128 @@ var LeanViewComponent = React3__namespace.forwardRef((props, ref) => {
185
186
  LeanViewComponent.displayName = "RCTView";
186
187
  var LeanView = reactNative.Platform.OS === "android" || reactNative.Platform.OS === "ios" ? LeanViewComponent : reactNative.View;
187
188
 
188
- // src/components/Separator.tsx
189
- function Separator({ ItemSeparatorComponent, itemKey, leadingItem }) {
190
- const [lastItemKeys] = useArr$(["lastItemKeys"]);
191
- const isALastItem = lastItemKeys.includes(itemKey);
192
- return isALastItem ? null : /* @__PURE__ */ React.createElement(ItemSeparatorComponent, { leadingItem });
193
- }
194
-
195
189
  // src/constants.ts
196
190
  var POSITION_OUT_OF_VIEW = -1e7;
197
191
  var ENABLE_DEVMODE = __DEV__ && false;
198
192
  var ENABLE_DEBUG_VIEW = __DEV__ && false;
199
193
  var IsNewArchitecture = global.nativeFabricUIManager != null;
194
+ var useAnimatedValue = (initialValue) => {
195
+ return React3.useRef(new reactNative.Animated.Value(initialValue)).current;
196
+ };
197
+
198
+ // src/hooks/useValue$.ts
199
+ function useValue$(key, params) {
200
+ var _a;
201
+ const { getValue, delay } = params || {};
202
+ const ctx = useStateContext();
203
+ const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
204
+ React3.useMemo(() => {
205
+ let newValue;
206
+ let prevValue;
207
+ let didQueueTask = false;
208
+ listen$(ctx, key, (v) => {
209
+ newValue = getValue ? getValue(v) : v;
210
+ if (delay !== void 0) {
211
+ const fn = () => {
212
+ didQueueTask = false;
213
+ if (newValue !== void 0) {
214
+ animValue.setValue(newValue);
215
+ }
216
+ };
217
+ const delayValue = typeof delay === "function" ? delay(newValue, prevValue) : delay;
218
+ prevValue = newValue;
219
+ if (!didQueueTask) {
220
+ didQueueTask = true;
221
+ if (delayValue === 0) {
222
+ queueMicrotask(fn);
223
+ } else {
224
+ setTimeout(fn, delayValue);
225
+ }
226
+ }
227
+ } else {
228
+ animValue.setValue(newValue);
229
+ }
230
+ });
231
+ }, []);
232
+ return animValue;
233
+ }
234
+ var typedForwardRef = React3.forwardRef;
235
+ var typedMemo = React3.memo;
236
+
237
+ // src/components/PositionView.tsx
238
+ var PositionViewState = typedMemo(function PositionView({
239
+ id,
240
+ horizontal,
241
+ style,
242
+ refView,
243
+ ...rest
244
+ }) {
245
+ const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
246
+ return /* @__PURE__ */ React3__namespace.createElement(
247
+ LeanView,
248
+ {
249
+ ref: refView,
250
+ style: [
251
+ style,
252
+ horizontal ? { transform: [{ translateX: position }] } : { transform: [{ translateY: position }] }
253
+ ],
254
+ ...rest
255
+ }
256
+ );
257
+ });
258
+ var PositionViewAnimated = typedMemo(function PositionView2({
259
+ id,
260
+ horizontal,
261
+ style,
262
+ refView,
263
+ ...rest
264
+ }) {
265
+ const position$ = useValue$(`containerPosition${id}`, {
266
+ getValue: (v) => v != null ? v : POSITION_OUT_OF_VIEW
267
+ });
268
+ return /* @__PURE__ */ React3__namespace.createElement(
269
+ reactNative.Animated.View,
270
+ {
271
+ ref: refView,
272
+ style: [
273
+ style,
274
+ horizontal ? { transform: [{ translateX: position$ }] } : { transform: [{ translateY: position$ }] }
275
+ ],
276
+ ...rest
277
+ }
278
+ );
279
+ });
280
+ var PositionViewSticky = typedMemo(function PositionViewSticky2({
281
+ id,
282
+ horizontal,
283
+ style,
284
+ refView,
285
+ animatedScrollY,
286
+ stickyOffset,
287
+ index,
288
+ ...rest
289
+ }) {
290
+ const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
291
+ const transform = React3__namespace.useMemo(() => {
292
+ if (animatedScrollY && stickyOffset) {
293
+ const stickyPosition = animatedScrollY.interpolate({
294
+ extrapolate: "clamp",
295
+ inputRange: [position, position + 5e3],
296
+ outputRange: [position, position + 5e3]
297
+ });
298
+ return horizontal ? [{ translateX: stickyPosition }] : [{ translateY: stickyPosition }];
299
+ }
300
+ }, [position, horizontal, animatedScrollY, stickyOffset]);
301
+ console.log("index", index, position, transform);
302
+ const viewStyle = React3__namespace.useMemo(() => [style, { zIndex: index + 1e3 }, { transform }], [style, transform]);
303
+ return /* @__PURE__ */ React3__namespace.createElement(reactNative.Animated.View, { ref: refView, style: viewStyle, ...rest });
304
+ });
305
+ var PositionView3 = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
306
+ function Separator({ ItemSeparatorComponent, itemKey, leadingItem }) {
307
+ const [lastItemKeys] = useArr$(["lastItemKeys"]);
308
+ const isALastItem = lastItemKeys.includes(itemKey);
309
+ return isALastItem ? null : /* @__PURE__ */ React3__namespace.createElement(ItemSeparatorComponent, { leadingItem });
310
+ }
200
311
  var symbolFirst = Symbol();
201
312
  function useInit(cb) {
202
313
  const refValue = React3.useRef(symbolFirst);
@@ -333,8 +444,6 @@ function useListScrollSize() {
333
444
  const [scrollSize] = useArr$(["scrollSize"]);
334
445
  return scrollSize;
335
446
  }
336
- var typedForwardRef = React3.forwardRef;
337
- var typedMemo = React3.memo;
338
447
 
339
448
  // src/components/Container.tsx
340
449
  var Container = typedMemo(function Container2({
@@ -346,14 +455,15 @@ var Container = typedMemo(function Container2({
346
455
  ItemSeparatorComponent
347
456
  }) {
348
457
  const ctx = useStateContext();
349
- const columnWrapperStyle = ctx.columnWrapperStyle;
350
- const [column = 0, data, itemKey, position = POSITION_OUT_OF_VIEW, numColumns, extraData] = useArr$([
458
+ const { columnWrapperStyle, animatedScrollY } = ctx;
459
+ const [column = 0, data, itemKey, numColumns, extraData, isSticky, stickyOffset] = useArr$([
351
460
  `containerColumn${id}`,
352
461
  `containerItemData${id}`,
353
462
  `containerItemKey${id}`,
354
- `containerPosition${id}`,
355
463
  "numColumns",
356
- "extraData"
464
+ "extraData",
465
+ `containerSticky${id}`,
466
+ `containerStickyOffset${id}`
357
467
  ]);
358
468
  const refLastSize = React3.useRef();
359
469
  const ref = React3.useRef(null);
@@ -361,36 +471,38 @@ var Container = typedMemo(function Container2({
361
471
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
362
472
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
363
473
  let didLayout = false;
364
- let paddingStyles;
365
- if (columnWrapperStyle) {
366
- const { columnGap, rowGap, gap } = columnWrapperStyle;
367
- if (horizontal) {
368
- paddingStyles = {
369
- paddingRight: columnGap || gap || void 0,
370
- paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
371
- };
372
- } else {
373
- paddingStyles = {
374
- paddingBottom: rowGap || gap || void 0,
375
- paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
376
- };
474
+ const style = React3.useMemo(() => {
475
+ let paddingStyles;
476
+ if (columnWrapperStyle) {
477
+ const { columnGap, rowGap, gap } = columnWrapperStyle;
478
+ if (horizontal) {
479
+ paddingStyles = {
480
+ paddingRight: columnGap || gap || void 0,
481
+ paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
482
+ };
483
+ } else {
484
+ paddingStyles = {
485
+ paddingBottom: rowGap || gap || void 0,
486
+ paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
487
+ };
488
+ }
377
489
  }
378
- }
379
- const style = horizontal ? {
380
- flexDirection: ItemSeparatorComponent ? "row" : void 0,
381
- height: otherAxisSize,
382
- left: position,
383
- position: "absolute",
384
- top: otherAxisPos,
385
- ...paddingStyles || {}
386
- } : {
387
- left: otherAxisPos,
388
- position: "absolute",
389
- right: numColumns > 1 ? null : 0,
390
- top: position,
391
- width: otherAxisSize,
392
- ...paddingStyles || {}
393
- };
490
+ return horizontal ? {
491
+ flexDirection: ItemSeparatorComponent ? "row" : void 0,
492
+ height: otherAxisSize,
493
+ left: 0,
494
+ position: "absolute",
495
+ top: otherAxisPos,
496
+ ...paddingStyles || {}
497
+ } : {
498
+ left: otherAxisPos,
499
+ position: "absolute",
500
+ right: numColumns > 1 ? null : 0,
501
+ top: 0,
502
+ width: otherAxisSize,
503
+ ...paddingStyles || {}
504
+ };
505
+ }, [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns]);
394
506
  const renderedItemInfo = React3.useMemo(
395
507
  () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
396
508
  [itemKey, data, extraData]
@@ -455,55 +567,30 @@ var Container = typedMemo(function Container2({
455
567
  }
456
568
  }, [itemKey]);
457
569
  }
458
- return /* @__PURE__ */ React3__namespace.createElement(LeanView, { key: recycleItems ? void 0 : itemKey, onLayout, ref, style }, /* @__PURE__ */ React3__namespace.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React3__namespace.createElement(
459
- Separator,
570
+ const PositionComponent = isSticky ? PositionViewSticky : PositionView3;
571
+ return /* @__PURE__ */ React3__namespace.createElement(
572
+ PositionComponent,
460
573
  {
461
- ItemSeparatorComponent,
462
- itemKey,
463
- leadingItem: renderedItemInfo.item
464
- }
465
- )));
466
- });
467
- var useAnimatedValue = (initialValue) => {
468
- return React3.useRef(new reactNative.Animated.Value(initialValue)).current;
469
- };
470
-
471
- // src/hooks/useValue$.ts
472
- function useValue$(key, params) {
473
- var _a;
474
- const { getValue, delay } = params || {};
475
- const ctx = useStateContext();
476
- const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
477
- React3.useMemo(() => {
478
- let newValue;
479
- let prevValue;
480
- let didQueueTask = false;
481
- listen$(ctx, key, (v) => {
482
- newValue = getValue ? getValue(v) : v;
483
- if (delay !== void 0) {
484
- const fn = () => {
485
- didQueueTask = false;
486
- if (newValue !== void 0) {
487
- animValue.setValue(newValue);
488
- }
489
- };
490
- const delayValue = typeof delay === "function" ? delay(newValue, prevValue) : delay;
491
- prevValue = newValue;
492
- if (!didQueueTask) {
493
- didQueueTask = true;
494
- if (delayValue === 0) {
495
- queueMicrotask(fn);
496
- } else {
497
- setTimeout(fn, delayValue);
498
- }
499
- }
500
- } else {
501
- animValue.setValue(newValue);
574
+ animatedScrollY: isSticky ? animatedScrollY : void 0,
575
+ horizontal,
576
+ id,
577
+ index,
578
+ key: recycleItems ? void 0 : itemKey,
579
+ onLayout,
580
+ refView: ref,
581
+ stickyOffset: isSticky ? stickyOffset : void 0,
582
+ style
583
+ },
584
+ /* @__PURE__ */ React3__namespace.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React3__namespace.createElement(
585
+ Separator,
586
+ {
587
+ ItemSeparatorComponent,
588
+ itemKey,
589
+ leadingItem: renderedItemInfo.item
502
590
  }
503
- });
504
- }, []);
505
- return animValue;
506
- }
591
+ ))
592
+ );
593
+ });
507
594
 
508
595
  // src/components/Containers.tsx
509
596
  var Containers = typedMemo(function Containers2({
@@ -663,6 +750,7 @@ var ListComponent = typedMemo(function ListComponent2({
663
750
  scrollAdjustHandler,
664
751
  onLayoutHeader,
665
752
  snapToIndices,
753
+ stickyIndices,
666
754
  ...rest
667
755
  }) {
668
756
  const ctx = useStateContext();
@@ -672,7 +760,7 @@ var ListComponent = typedMemo(function ListComponent2({
672
760
  const ScrollComponent = renderScrollComponent ? React3.useMemo(
673
761
  () => React3__namespace.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
674
762
  [renderScrollComponent]
675
- ) : reactNative.ScrollView;
763
+ ) : reactNative.Animated.ScrollView;
676
764
  React3__namespace.useEffect(() => {
677
765
  if (canRender) {
678
766
  setTimeout(() => {
@@ -725,9 +813,26 @@ var ListComponent = typedMemo(function ListComponent2({
725
813
  style: ListFooterComponentStyle
726
814
  },
727
815
  getComponent(ListFooterComponent)
728
- )
816
+ ),
817
+ __DEV__ && ENABLE_DEVMODE && /* @__PURE__ */ React3__namespace.createElement(DevNumbers, null)
729
818
  );
730
819
  });
820
+ var DevNumbers = __DEV__ && React3__namespace.memo(function DevNumbers2() {
821
+ return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3__namespace.createElement(
822
+ reactNative.View,
823
+ {
824
+ key: index,
825
+ style: {
826
+ height: 100,
827
+ pointerEvents: "none",
828
+ position: "absolute",
829
+ top: index * 100,
830
+ width: "100%"
831
+ }
832
+ },
833
+ /* @__PURE__ */ React3__namespace.createElement(reactNative.Text, { style: { color: "red" } }, index * 100)
834
+ ));
835
+ });
731
836
 
732
837
  // src/utils/getId.ts
733
838
  function getId(state, index) {
@@ -759,20 +864,36 @@ function calculateOffsetForIndex(ctx, state, index) {
759
864
  }
760
865
 
761
866
  // src/utils/getItemSize.ts
762
- function getItemSize(state, key, index, data, useAverageSize) {
867
+ function getItemSize(state, key, index, data, useAverageSize, defaultAverageSize) {
868
+ var _a, _b;
763
869
  const {
764
870
  sizesKnown,
765
871
  sizes,
766
872
  scrollingTo,
767
- props: { estimatedItemSize, getEstimatedItemSize }
873
+ averageSizes,
874
+ props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
768
875
  } = state;
769
876
  const sizeKnown = sizesKnown.get(key);
770
877
  if (sizeKnown !== void 0) {
771
878
  return sizeKnown;
772
879
  }
773
880
  let size;
774
- if (useAverageSize !== void 0 && sizeKnown === void 0 && !getEstimatedItemSize && !scrollingTo) {
775
- size = useAverageSize;
881
+ const itemType = getItemType ? (_a = getItemType(data, index)) != null ? _a : "" : "";
882
+ if (getFixedItemSize) {
883
+ size = getFixedItemSize(index, data, itemType);
884
+ if (size !== void 0) {
885
+ sizesKnown.set(key, size);
886
+ }
887
+ }
888
+ if (size === void 0 && useAverageSize && sizeKnown === void 0 && !scrollingTo) {
889
+ if (itemType === "") {
890
+ size = defaultAverageSize;
891
+ } else {
892
+ const averageSizeForType = (_b = averageSizes[itemType]) == null ? void 0 : _b.avg;
893
+ if (averageSizeForType !== void 0) {
894
+ size = roundSize(averageSizeForType);
895
+ }
896
+ }
776
897
  }
777
898
  if (size === void 0) {
778
899
  size = sizes.get(key);
@@ -781,7 +902,7 @@ function getItemSize(state, key, index, data, useAverageSize) {
781
902
  }
782
903
  }
783
904
  if (size === void 0) {
784
- size = getEstimatedItemSize ? getEstimatedItemSize(index, data) : estimatedItemSize;
905
+ size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
785
906
  }
786
907
  sizes.set(key, size);
787
908
  return size;
@@ -800,6 +921,37 @@ function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
800
921
  return offset;
801
922
  }
802
923
 
924
+ // src/core/finishScrollTo.ts
925
+ var finishScrollTo = (state) => {
926
+ if (state) {
927
+ state.scrollingTo = void 0;
928
+ state.scrollHistory.length = 0;
929
+ }
930
+ };
931
+
932
+ // src/core/scrollTo.ts
933
+ function scrollTo(state, params = {}) {
934
+ var _a;
935
+ const { animated } = params;
936
+ const {
937
+ refScroller,
938
+ props: { horizontal }
939
+ } = state;
940
+ const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
941
+ state.scrollHistory.length = 0;
942
+ state.scrollingTo = params;
943
+ state.scrollPending = offset;
944
+ (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
945
+ animated: !!animated,
946
+ x: horizontal ? offset : 0,
947
+ y: horizontal ? 0 : offset
948
+ });
949
+ if (!animated) {
950
+ state.scroll = offset;
951
+ setTimeout(() => finishScrollTo(state), 100);
952
+ }
953
+ }
954
+
803
955
  // src/utils/requestAdjust.ts
804
956
  function requestAdjust(ctx, state, positionDiff) {
805
957
  if (Math.abs(positionDiff) > 0.1) {
@@ -833,37 +985,63 @@ function requestAdjust(ctx, state, positionDiff) {
833
985
  }
834
986
 
835
987
  // src/core/prepareMVCP.ts
836
- function prepareMVCP(ctx, state) {
988
+ function prepareMVCP(ctx, state, dataChanged) {
837
989
  const {
990
+ idsInView,
838
991
  positions,
839
992
  scrollingTo,
840
993
  props: { maintainVisibleContentPosition }
841
994
  } = state;
842
995
  let prevPosition;
843
996
  let targetId;
844
- let targetIndex;
997
+ const idsInViewWithPositions = [];
845
998
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
846
999
  if (maintainVisibleContentPosition) {
847
1000
  const indexByKey = state.indexByKey;
848
1001
  if (scrollTarget !== void 0) {
849
1002
  targetId = getId(state, scrollTarget);
850
- targetIndex = scrollTarget;
851
- } else if (state.idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
852
- targetId = state.idsInView.find((id) => indexByKey.get(id) !== void 0);
853
- targetIndex = indexByKey.get(targetId);
1003
+ } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
1004
+ if (dataChanged) {
1005
+ for (let i = 0; i < idsInView.length; i++) {
1006
+ const id = idsInView[i];
1007
+ const index = indexByKey.get(id);
1008
+ if (index !== void 0) {
1009
+ idsInViewWithPositions.push({ id, position: positions.get(id) });
1010
+ }
1011
+ }
1012
+ } else {
1013
+ targetId = state.idsInView.find((id) => indexByKey.get(id) !== void 0);
1014
+ }
854
1015
  }
855
- if (targetId !== void 0 && targetIndex !== void 0) {
1016
+ if (targetId !== void 0) {
856
1017
  prevPosition = positions.get(targetId);
857
1018
  }
858
1019
  }
859
1020
  return () => {
1021
+ let positionDiff;
1022
+ if (targetId === void 0) {
1023
+ for (let i = 0; i < idsInViewWithPositions.length; i++) {
1024
+ const { id, position } = idsInViewWithPositions[i];
1025
+ const newPosition = positions.get(id);
1026
+ if (newPosition !== void 0) {
1027
+ positionDiff = newPosition - position;
1028
+ break;
1029
+ }
1030
+ }
1031
+ }
860
1032
  if (targetId !== void 0 && prevPosition !== void 0) {
861
1033
  const newPosition = positions.get(targetId);
862
1034
  if (newPosition !== void 0) {
863
- const positionDiff = newPosition - prevPosition;
864
- if (Math.abs(positionDiff) > 0.1) {
865
- requestAdjust(ctx, state, positionDiff);
866
- }
1035
+ positionDiff = newPosition - prevPosition;
1036
+ }
1037
+ }
1038
+ if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1039
+ if (reactNative.Platform.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff) {
1040
+ scrollTo(state, {
1041
+ offset: state.scroll + positionDiff
1042
+ });
1043
+ } else {
1044
+ requestAdjust(ctx, state, positionDiff);
867
1045
  }
868
1046
  }
869
1047
  };
@@ -1004,7 +1182,7 @@ function updateAllPositions(ctx, state, dataChanged) {
1004
1182
  firstFullyOnScreenIndex,
1005
1183
  idCache,
1006
1184
  sizesKnown,
1007
- props: { snapToIndices }
1185
+ props: { getEstimatedItemSize, snapToIndices }
1008
1186
  } = state;
1009
1187
  const data = state.props.data;
1010
1188
  const numColumns = peek$(ctx, "numColumns");
@@ -1013,7 +1191,9 @@ function updateAllPositions(ctx, state, dataChanged) {
1013
1191
  if (dataChanged) {
1014
1192
  indexByKey.clear();
1015
1193
  idCache.clear();
1194
+ positions.clear();
1016
1195
  }
1196
+ const useAverageSize = !getEstimatedItemSize;
1017
1197
  const itemType = "";
1018
1198
  let averageSize = (_a = averageSizes[itemType]) == null ? void 0 : _a.avg;
1019
1199
  if (averageSize !== void 0) {
@@ -1029,7 +1209,7 @@ function updateAllPositions(ctx, state, dataChanged) {
1029
1209
  let bailout = false;
1030
1210
  for (let i = firstFullyOnScreenIndex - 1; i >= 0; i--) {
1031
1211
  const id = (_b = idCache.get(i)) != null ? _b : getId(state, i);
1032
- const size = (_c = sizesKnown.get(id)) != null ? _c : getItemSize(state, id, i, data[i], averageSize);
1212
+ const size = (_c = sizesKnown.get(id)) != null ? _c : getItemSize(state, id, i, data[i], useAverageSize, averageSize);
1033
1213
  const itemColumn = columns.get(id);
1034
1214
  maxSizeInRow2 = Math.max(maxSizeInRow2, size);
1035
1215
  if (itemColumn === 1) {
@@ -1056,7 +1236,7 @@ function updateAllPositions(ctx, state, dataChanged) {
1056
1236
  const dataLength = data.length;
1057
1237
  for (let i = 0; i < dataLength; i++) {
1058
1238
  const id = (_d = idCache.get(i)) != null ? _d : getId(state, i);
1059
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(state, id, i, data[i], averageSize);
1239
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(state, id, i, data[i], useAverageSize, averageSize);
1060
1240
  if (__DEV__ && needsIndexByKey) {
1061
1241
  if (indexByKeyForChecking.has(id)) {
1062
1242
  console.error(
@@ -1295,35 +1475,84 @@ function checkAllSizesKnown(state) {
1295
1475
  }
1296
1476
 
1297
1477
  // src/utils/findAvailableContainers.ts
1298
- function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval) {
1478
+ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
1299
1479
  const numContainers = peek$(ctx, "numContainers");
1480
+ const { stickyIndicesSet } = state.props;
1300
1481
  const result = [];
1301
1482
  const availableContainers = [];
1302
- for (let u = 0; u < numContainers; u++) {
1303
- const key = peek$(ctx, `containerItemKey${u}`);
1304
- let isOk = key === void 0;
1305
- if (!isOk) {
1306
- const index = pendingRemoval.indexOf(u);
1307
- if (index !== -1) {
1308
- pendingRemoval.splice(index, 1);
1309
- isOk = true;
1483
+ const stickyItemIndices = (needNewContainers == null ? void 0 : needNewContainers.filter((index) => stickyIndicesSet.has(index))) || [];
1484
+ const nonStickyItemIndices = (needNewContainers == null ? void 0 : needNewContainers.filter((index) => !stickyIndicesSet.has(index))) || [];
1485
+ const canReuseContainer = (containerIndex, requiredType) => {
1486
+ if (!requiredType) return true;
1487
+ const existingType = state.containerItemTypes.get(containerIndex);
1488
+ if (!existingType) return true;
1489
+ return existingType === requiredType;
1490
+ };
1491
+ const neededTypes = requiredItemTypes ? [...requiredItemTypes] : [];
1492
+ let typeIndex = 0;
1493
+ for (let i = 0; i < stickyItemIndices.length; i++) {
1494
+ const requiredType = neededTypes[typeIndex];
1495
+ let foundContainer = false;
1496
+ for (const containerIndex of state.stickyContainerPool) {
1497
+ const key = peek$(ctx, `containerItemKey${containerIndex}`);
1498
+ const isPendingRemoval = pendingRemoval.includes(containerIndex);
1499
+ if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType)) {
1500
+ result.push(containerIndex);
1501
+ if (isPendingRemoval) {
1502
+ const index = pendingRemoval.indexOf(containerIndex);
1503
+ pendingRemoval.splice(index, 1);
1504
+ }
1505
+ foundContainer = true;
1506
+ if (requiredItemTypes) typeIndex++;
1507
+ break;
1310
1508
  }
1311
1509
  }
1312
- if (isOk) {
1313
- result.push(u);
1314
- if (result.length >= numNeeded) {
1315
- return result;
1510
+ if (!foundContainer) {
1511
+ const newContainerIndex = numContainers + result.filter((index) => index >= numContainers).length;
1512
+ result.push(newContainerIndex);
1513
+ state.stickyContainerPool.add(newContainerIndex);
1514
+ if (requiredItemTypes) typeIndex++;
1515
+ }
1516
+ }
1517
+ if (nonStickyItemIndices.length > 0) {
1518
+ for (let u = 0; u < numContainers; u++) {
1519
+ if (state.stickyContainerPool.has(u)) {
1520
+ continue;
1521
+ }
1522
+ const key = peek$(ctx, `containerItemKey${u}`);
1523
+ let isOk = key === void 0;
1524
+ if (!isOk) {
1525
+ const index = pendingRemoval.indexOf(u);
1526
+ if (index !== -1) {
1527
+ pendingRemoval.splice(index, 1);
1528
+ const requiredType = neededTypes[typeIndex];
1529
+ isOk = canReuseContainer(u, requiredType);
1530
+ }
1531
+ }
1532
+ if (isOk) {
1533
+ result.push(u);
1534
+ if (requiredItemTypes) {
1535
+ typeIndex++;
1536
+ }
1537
+ if (result.length >= numNeeded) {
1538
+ return result;
1539
+ }
1316
1540
  }
1317
1541
  }
1318
1542
  }
1319
1543
  for (let u = 0; u < numContainers; u++) {
1544
+ if (state.stickyContainerPool.has(u)) {
1545
+ continue;
1546
+ }
1320
1547
  const key = peek$(ctx, `containerItemKey${u}`);
1321
1548
  if (key === void 0) continue;
1322
1549
  const index = state.indexByKey.get(key);
1323
- if (index < startBuffered) {
1324
- availableContainers.push({ distance: startBuffered - index, index: u });
1325
- } else if (index > endBuffered) {
1326
- availableContainers.push({ distance: index - endBuffered, index: u });
1550
+ const isOutOfView = index < startBuffered || index > endBuffered;
1551
+ if (isOutOfView) {
1552
+ const distance = index < startBuffered ? startBuffered - index : index - endBuffered;
1553
+ if (!requiredItemTypes || typeIndex < neededTypes.length && canReuseContainer(u, neededTypes[typeIndex])) {
1554
+ availableContainers.push({ distance, index: u });
1555
+ }
1327
1556
  }
1328
1557
  }
1329
1558
  const remaining = numNeeded - result.length;
@@ -1335,6 +1564,9 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1335
1564
  }
1336
1565
  for (const container of availableContainers) {
1337
1566
  result.push(container.index);
1567
+ if (requiredItemTypes) {
1568
+ typeIndex++;
1569
+ }
1338
1570
  }
1339
1571
  }
1340
1572
  const stillNeeded = numNeeded - result.length;
@@ -1363,37 +1595,6 @@ function comparatorByDistance(a, b) {
1363
1595
  return b.distance - a.distance;
1364
1596
  }
1365
1597
 
1366
- // src/core/finishScrollTo.ts
1367
- var finishScrollTo = (state) => {
1368
- if (state) {
1369
- state.scrollingTo = void 0;
1370
- state.scrollHistory.length = 0;
1371
- }
1372
- };
1373
-
1374
- // src/core/scrollTo.ts
1375
- function scrollTo(state, params = {}) {
1376
- var _a;
1377
- const { animated } = params;
1378
- const {
1379
- refScroller,
1380
- props: { horizontal }
1381
- } = state;
1382
- const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
1383
- state.scrollHistory.length = 0;
1384
- state.scrollingTo = params;
1385
- state.scrollPending = offset;
1386
- (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
1387
- animated: !!animated,
1388
- x: horizontal ? offset : 0,
1389
- y: horizontal ? 0 : offset
1390
- });
1391
- if (!animated) {
1392
- state.scroll = offset;
1393
- setTimeout(() => finishScrollTo(state), 100);
1394
- }
1395
- }
1396
-
1397
1598
  // src/core/scrollToIndex.ts
1398
1599
  function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
1399
1600
  if (index >= state.props.data.length) {
@@ -1481,16 +1682,90 @@ function setDidLayout(ctx, state) {
1481
1682
  } = state;
1482
1683
  state.queuedInitialLayout = true;
1483
1684
  checkAtBottom(ctx, state);
1484
- if (!IsNewArchitecture && initialScroll) {
1485
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1486
- }
1487
- set$(ctx, "containersDidLayout", true);
1488
- if (onLoad) {
1489
- onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1685
+ const setIt = () => {
1686
+ set$(ctx, "containersDidLayout", true);
1687
+ if (onLoad) {
1688
+ onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1689
+ }
1690
+ };
1691
+ if (reactNative.Platform.OS === "android" || !IsNewArchitecture) {
1692
+ if (initialScroll) {
1693
+ queueMicrotask(() => {
1694
+ scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1695
+ requestAnimationFrame(() => {
1696
+ scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1697
+ setIt();
1698
+ });
1699
+ });
1700
+ } else {
1701
+ queueMicrotask(setIt);
1702
+ }
1703
+ } else {
1704
+ setIt();
1490
1705
  }
1491
1706
  }
1492
1707
 
1493
1708
  // src/core/calculateItemsInView.ts
1709
+ function findCurrentStickyIndex(stickyArray, scroll, state) {
1710
+ var _a;
1711
+ for (let i = stickyArray.length - 1; i >= 0; i--) {
1712
+ const stickyId = (_a = state.idCache.get(stickyArray[i])) != null ? _a : getId(state, stickyArray[i]);
1713
+ const stickyPos = stickyId ? state.positions.get(stickyId) : void 0;
1714
+ if (stickyPos !== void 0 && scroll >= stickyPos) {
1715
+ return i;
1716
+ }
1717
+ }
1718
+ return -1;
1719
+ }
1720
+ function getActiveStickyIndices(ctx, state, stickyIndices) {
1721
+ return new Set(
1722
+ Array.from(state.stickyContainerPool).map((i) => peek$(ctx, `containerItemKey${i}`)).map((key) => key ? state.indexByKey.get(key) : void 0).filter((idx) => idx !== void 0 && stickyIndices.has(idx))
1723
+ );
1724
+ }
1725
+ function handleStickyActivation(ctx, state, stickyIndices, stickyArray, scroll, needNewContainers, startBuffered, endBuffered) {
1726
+ var _a;
1727
+ const activeIndices = getActiveStickyIndices(ctx, state, stickyIndices);
1728
+ const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
1729
+ for (let offset = 0; offset <= 1; offset++) {
1730
+ const idx = currentStickyIdx - offset;
1731
+ if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
1732
+ const stickyIndex = stickyArray[idx];
1733
+ const stickyId = (_a = state.idCache.get(stickyIndex)) != null ? _a : getId(state, stickyIndex);
1734
+ if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered)) {
1735
+ needNewContainers.push(stickyIndex);
1736
+ }
1737
+ }
1738
+ }
1739
+ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, pendingRemoval) {
1740
+ var _a, _b, _c;
1741
+ const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
1742
+ for (const containerIndex of state.stickyContainerPool) {
1743
+ const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
1744
+ const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
1745
+ if (itemIndex === void 0) continue;
1746
+ const arrayIdx = stickyArray.indexOf(itemIndex);
1747
+ if (arrayIdx === -1) continue;
1748
+ const isRecentSticky = arrayIdx >= currentStickyIdx - 1 && arrayIdx <= currentStickyIdx + 1;
1749
+ if (isRecentSticky) continue;
1750
+ const nextIndex = stickyArray[arrayIdx + 1];
1751
+ let shouldRecycle = false;
1752
+ if (nextIndex) {
1753
+ const nextId = (_a = state.idCache.get(nextIndex)) != null ? _a : getId(state, nextIndex);
1754
+ const nextPos = nextId ? state.positions.get(nextId) : void 0;
1755
+ shouldRecycle = nextPos !== void 0 && scroll > nextPos + scrollBuffer * 2;
1756
+ } else {
1757
+ const currentId = (_b = state.idCache.get(itemIndex)) != null ? _b : getId(state, itemIndex);
1758
+ if (currentId) {
1759
+ const currentPos = state.positions.get(currentId);
1760
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(state, currentId, itemIndex, state.props.data[itemIndex]);
1761
+ shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
1762
+ }
1763
+ }
1764
+ if (shouldRecycle) {
1765
+ pendingRemoval.push(containerIndex);
1766
+ }
1767
+ }
1768
+ }
1494
1769
  function calculateItemsInView(ctx, state, params = {}) {
1495
1770
  reactNative.unstable_batchedUpdates(() => {
1496
1771
  var _a, _b, _c, _d, _e, _f, _g, _h;
@@ -1507,7 +1782,7 @@ function calculateItemsInView(ctx, state, params = {}) {
1507
1782
  enableScrollForNextCalculateItemsInView,
1508
1783
  minIndexSizeChanged
1509
1784
  } = state;
1510
- const data = state.props.data;
1785
+ const { data, stickyIndicesArr, stickyIndicesSet } = state.props;
1511
1786
  const prevNumContainers = peek$(ctx, "numContainers");
1512
1787
  if (!data || scrollLength === 0 || !prevNumContainers) {
1513
1788
  return;
@@ -1519,7 +1794,7 @@ function calculateItemsInView(ctx, state, params = {}) {
1519
1794
  const { dataChanged, doMVCP } = params;
1520
1795
  const speed = getScrollVelocity(state);
1521
1796
  if (doMVCP || dataChanged) {
1522
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state) : void 0;
1797
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
1523
1798
  updateAllPositions(ctx, state, dataChanged);
1524
1799
  checkMVCP == null ? void 0 : checkMVCP();
1525
1800
  }
@@ -1669,14 +1944,23 @@ function calculateItemsInView(ctx, state, params = {}) {
1669
1944
  needNewContainers.push(i);
1670
1945
  }
1671
1946
  }
1947
+ if (stickyIndicesArr.length > 0) {
1948
+ handleStickyActivation(ctx, state, stickyIndicesSet, stickyIndicesArr, scroll, needNewContainers, startBuffered, endBuffered);
1949
+ }
1672
1950
  if (needNewContainers.length > 0) {
1951
+ const requiredItemTypes = state.props.getItemType ? needNewContainers.map((i) => {
1952
+ const itemType = state.props.getItemType(data[i], i);
1953
+ return itemType ? String(itemType) : "";
1954
+ }) : void 0;
1673
1955
  const availableContainers = findAvailableContainers(
1674
1956
  ctx,
1675
1957
  state,
1676
1958
  needNewContainers.length,
1677
1959
  startBuffered,
1678
1960
  endBuffered,
1679
- pendingRemoval
1961
+ pendingRemoval,
1962
+ requiredItemTypes,
1963
+ needNewContainers
1680
1964
  );
1681
1965
  for (let idx = 0; idx < needNewContainers.length; idx++) {
1682
1966
  const i = needNewContainers[idx];
@@ -1688,7 +1972,18 @@ function calculateItemsInView(ctx, state, params = {}) {
1688
1972
  }
1689
1973
  set$(ctx, `containerItemKey${containerIndex}`, id);
1690
1974
  set$(ctx, `containerItemData${containerIndex}`, data[i]);
1975
+ if (requiredItemTypes) {
1976
+ state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
1977
+ }
1691
1978
  containerItemKeys.add(id);
1979
+ if (stickyIndicesSet.has(i)) {
1980
+ set$(ctx, `containerSticky${containerIndex}`, true);
1981
+ const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
1982
+ set$(ctx, `containerStickyOffset${containerIndex}`, new reactNative.Animated.Value(topPadding));
1983
+ state.stickyContainerPool.add(containerIndex);
1984
+ } else {
1985
+ state.stickyContainerPool.delete(containerIndex);
1986
+ }
1692
1987
  if (containerIndex >= numContainers2) {
1693
1988
  numContainers2 = containerIndex + 1;
1694
1989
  }
@@ -1701,12 +1996,21 @@ function calculateItemsInView(ctx, state, params = {}) {
1701
1996
  }
1702
1997
  }
1703
1998
  }
1999
+ if (stickyIndicesArr.length > 0) {
2000
+ handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, pendingRemoval);
2001
+ }
1704
2002
  for (let i = 0; i < numContainers; i++) {
1705
2003
  const itemKey = peek$(ctx, `containerItemKey${i}`);
1706
2004
  if (pendingRemoval.includes(i)) {
1707
2005
  if (itemKey) {
1708
2006
  containerItemKeys.delete(itemKey);
1709
2007
  }
2008
+ state.containerItemTypes.delete(i);
2009
+ if (state.stickyContainerPool.has(i)) {
2010
+ set$(ctx, `containerSticky${i}`, false);
2011
+ set$(ctx, `containerStickyOffset${i}`, void 0);
2012
+ state.stickyContainerPool.delete(i);
2013
+ }
1710
2014
  set$(ctx, `containerItemKey${i}`, void 0);
1711
2015
  set$(ctx, `containerItemData${i}`, void 0);
1712
2016
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
@@ -1757,10 +2061,14 @@ function calculateItemsInView(ctx, state, params = {}) {
1757
2061
 
1758
2062
  // src/core/doInitialAllocateContainers.ts
1759
2063
  function doInitialAllocateContainers(ctx, state) {
1760
- const { scrollLength } = state;
2064
+ var _a;
2065
+ const {
2066
+ scrollLength,
2067
+ props: { getItemType }
2068
+ } = state;
1761
2069
  const data = state.props.data;
1762
2070
  if (scrollLength > 0 && data.length > 0 && !peek$(ctx, "numContainers")) {
1763
- const averageItemSize = state.props.getEstimatedItemSize ? state.props.getEstimatedItemSize(0, data[0]) : state.props.estimatedItemSize;
2071
+ const averageItemSize = state.props.getEstimatedItemSize ? state.props.getEstimatedItemSize(0, data[0], getItemType ? (_a = getItemType(data[0], 0)) != null ? _a : "" : "") : state.props.estimatedItemSize;
1764
2072
  const Extra = 1.5;
1765
2073
  const numContainers = Math.ceil(
1766
2074
  (scrollLength + state.props.scrollBuffer * 2) / averageItemSize * state.props.numColumns * Extra
@@ -1797,16 +2105,18 @@ function doMaintainScrollAtEnd(ctx, state, animated) {
1797
2105
  }
1798
2106
  requestAnimationFrame(() => {
1799
2107
  var _a;
1800
- state.maintainingScrollAtEnd = true;
1801
- (_a = refScroller.current) == null ? void 0 : _a.scrollToEnd({
1802
- animated
1803
- });
1804
- setTimeout(
1805
- () => {
1806
- state.maintainingScrollAtEnd = false;
1807
- },
1808
- 0
1809
- );
2108
+ if (state == null ? void 0 : state.isAtEnd) {
2109
+ state.maintainingScrollAtEnd = true;
2110
+ (_a = refScroller.current) == null ? void 0 : _a.scrollToEnd({
2111
+ animated
2112
+ });
2113
+ setTimeout(
2114
+ () => {
2115
+ state.maintainingScrollAtEnd = false;
2116
+ },
2117
+ 0
2118
+ );
2119
+ }
1810
2120
  });
1811
2121
  return true;
1812
2122
  }
@@ -2026,7 +2336,22 @@ function updateItemSizes(ctx, state, itemUpdates) {
2026
2336
  }
2027
2337
  }
2028
2338
  function updateItemSize(ctx, state, itemKey, sizeObj) {
2029
- const { queuedItemSizeUpdates, queuedItemSizeUpdatesWaiting } = state;
2339
+ var _a;
2340
+ const {
2341
+ queuedItemSizeUpdates,
2342
+ queuedItemSizeUpdatesWaiting,
2343
+ sizesKnown,
2344
+ props: { getFixedItemSize, getItemType }
2345
+ } = state;
2346
+ if (getFixedItemSize) {
2347
+ const index = state.indexByKey.get(itemKey);
2348
+ const itemData = state.props.data[index];
2349
+ const type = getItemType ? (_a = getItemType(itemData, index)) != null ? _a : "" : "";
2350
+ const size = getFixedItemSize(index, itemData, type);
2351
+ if (size !== void 0 && size === sizesKnown.get(itemKey)) {
2352
+ return;
2353
+ }
2354
+ }
2030
2355
  const containersDidLayout = peek$(ctx, "containersDidLayout");
2031
2356
  if (!containersDidLayout || !queuedItemSizeUpdatesWaiting) {
2032
2357
  updateItemSizes(ctx, state, [{ itemKey, sizeObj }]);
@@ -2043,25 +2368,28 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2043
2368
  }
2044
2369
  }
2045
2370
  function updateOneItemSize(state, itemKey, sizeObj) {
2371
+ var _a;
2046
2372
  const {
2047
2373
  sizes,
2048
2374
  indexByKey,
2049
2375
  sizesKnown,
2050
2376
  averageSizes,
2051
- props: { data, horizontal }
2377
+ props: { data, horizontal, getEstimatedItemSize, getItemType }
2052
2378
  } = state;
2053
2379
  if (!data) return 0;
2054
2380
  const index = indexByKey.get(itemKey);
2055
2381
  const prevSize = getItemSize(state, itemKey, index, data);
2056
2382
  const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2057
2383
  sizesKnown.set(itemKey, size);
2058
- const itemType = "";
2059
- let averages = averageSizes[itemType];
2060
- if (!averages) {
2061
- averages = averageSizes[itemType] = { avg: 0, num: 0 };
2384
+ if (!getEstimatedItemSize) {
2385
+ const itemType = getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : "";
2386
+ let averages = averageSizes[itemType];
2387
+ if (!averages) {
2388
+ averages = averageSizes[itemType] = { avg: 0, num: 0 };
2389
+ }
2390
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2391
+ averages.num++;
2062
2392
  }
2063
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2064
- averages.num++;
2065
2393
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2066
2394
  sizes.set(itemKey, size);
2067
2395
  return size - prevSize;
@@ -2099,12 +2427,13 @@ function createColumnWrapperStyle(contentContainerStyle) {
2099
2427
  }
2100
2428
  }
2101
2429
  function getRenderedItem(ctx, state, key) {
2430
+ var _a;
2102
2431
  if (!state) {
2103
2432
  return null;
2104
2433
  }
2105
2434
  const {
2106
2435
  indexByKey,
2107
- props: { data, renderItem: renderItem2 }
2436
+ props: { data, getItemType, renderItem: renderItem2 }
2108
2437
  } = state;
2109
2438
  const index = indexByKey.get(key);
2110
2439
  if (index === void 0) {
@@ -2115,7 +2444,8 @@ function getRenderedItem(ctx, state, key) {
2115
2444
  const itemProps = {
2116
2445
  extraData: peek$(ctx, "extraData"),
2117
2446
  index,
2118
- item: data[index]
2447
+ item: data[index],
2448
+ type: getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : ""
2119
2449
  };
2120
2450
  renderedItem = React3__namespace.default.createElement(renderItem2, itemProps);
2121
2451
  }
@@ -2131,49 +2461,52 @@ var LegendList = typedForwardRef(function LegendList2(props, forwardedRef) {
2131
2461
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
2132
2462
  var _a;
2133
2463
  const {
2464
+ alignItemsAtEnd = false,
2465
+ columnWrapperStyle,
2466
+ contentContainerStyle: contentContainerStyleProp,
2134
2467
  data: dataProp = [],
2468
+ drawDistance = 250,
2469
+ estimatedItemSize: estimatedItemSizeProp,
2470
+ estimatedListSize,
2471
+ extraData,
2472
+ getEstimatedItemSize,
2473
+ getFixedItemSize,
2474
+ getItemType,
2475
+ horizontal,
2476
+ initialContainerPoolRatio = 2,
2135
2477
  initialScrollIndex: initialScrollIndexProp,
2136
2478
  initialScrollOffset,
2137
- horizontal,
2138
- drawDistance = 250,
2139
- recycleItems = false,
2140
- onEndReachedThreshold = 0.5,
2141
- onStartReachedThreshold = 0.5,
2479
+ keyExtractor: keyExtractorProp,
2480
+ ListEmptyComponent,
2481
+ ListHeaderComponent,
2142
2482
  maintainScrollAtEnd = false,
2143
2483
  maintainScrollAtEndThreshold = 0.1,
2144
- alignItemsAtEnd = false,
2145
2484
  maintainVisibleContentPosition = false,
2146
- onScroll: onScrollProp,
2147
- onMomentumScrollEnd,
2148
2485
  numColumns: numColumnsProp = 1,
2149
- columnWrapperStyle,
2150
- keyExtractor: keyExtractorProp,
2151
- renderItem: renderItem2,
2152
- estimatedListSize,
2153
- estimatedItemSize: estimatedItemSizeProp,
2154
- getEstimatedItemSize,
2155
- suggestEstimatedItemSize,
2156
- ListHeaderComponent,
2157
- ListEmptyComponent,
2486
+ onEndReached,
2487
+ onEndReachedThreshold = 0.5,
2158
2488
  onItemSizeChanged,
2159
- refScrollView,
2160
- waitForInitialLayout = true,
2161
- extraData,
2162
- contentContainerStyle: contentContainerStyleProp,
2163
- style: styleProp,
2164
2489
  onLayout: onLayoutProp,
2490
+ onLoad,
2491
+ onMomentumScrollEnd,
2165
2492
  onRefresh,
2166
- refreshing,
2493
+ onScroll: onScrollProp,
2494
+ onStartReached,
2495
+ onStartReachedThreshold = 0.5,
2496
+ onViewableItemsChanged,
2167
2497
  progressViewOffset,
2498
+ recycleItems = false,
2168
2499
  refreshControl,
2169
- initialContainerPoolRatio = 2,
2500
+ refreshing,
2501
+ refScrollView,
2502
+ renderItem: renderItem2,
2503
+ snapToIndices,
2504
+ stickyIndices,
2505
+ style: styleProp,
2506
+ suggestEstimatedItemSize,
2170
2507
  viewabilityConfig,
2171
2508
  viewabilityConfigCallbackPairs,
2172
- snapToIndices,
2173
- onViewableItemsChanged,
2174
- onStartReached,
2175
- onEndReached,
2176
- onLoad,
2509
+ waitForInitialLayout = true,
2177
2510
  ...rest
2178
2511
  } = props;
2179
2512
  const [renderNum, setRenderNum] = React3.useState(0);
@@ -2195,9 +2528,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2195
2528
  if (!refState.current) {
2196
2529
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { height: 0, width: 0 } : reactNative.Dimensions.get("window"))[horizontal ? "width" : "height"];
2197
2530
  refState.current = {
2531
+ activeStickyIndex: void 0,
2198
2532
  averageSizes: {},
2199
2533
  columns: /* @__PURE__ */ new Map(),
2200
2534
  containerItemKeys: /* @__PURE__ */ new Set(),
2535
+ containerItemTypes: /* @__PURE__ */ new Map(),
2201
2536
  enableScrollForNextCalculateItemsInView: true,
2202
2537
  endBuffered: -1,
2203
2538
  endNoBuffer: -1,
@@ -2236,6 +2571,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2236
2571
  startBuffered: -1,
2237
2572
  startNoBuffer: -1,
2238
2573
  startReachedBlockedByTimer: false,
2574
+ stickyContainerPool: /* @__PURE__ */ new Set(),
2575
+ stickyContainers: /* @__PURE__ */ new Map(),
2239
2576
  timeoutSizeMessage: 0,
2240
2577
  timeouts: /* @__PURE__ */ new Set(),
2241
2578
  totalSize: 0,
@@ -2252,6 +2589,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2252
2589
  data: dataProp,
2253
2590
  estimatedItemSize,
2254
2591
  getEstimatedItemSize,
2592
+ getFixedItemSize,
2593
+ getItemType,
2255
2594
  horizontal: !!horizontal,
2256
2595
  initialContainerPoolRatio,
2257
2596
  initialScroll,
@@ -2267,9 +2606,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2267
2606
  onScroll: onScrollProp,
2268
2607
  onStartReached,
2269
2608
  onStartReachedThreshold,
2609
+ recycleItems: !!recycleItems,
2270
2610
  renderItem: renderItem2,
2271
2611
  scrollBuffer,
2272
2612
  snapToIndices,
2613
+ stickyIndicesArr: stickyIndices != null ? stickyIndices : [],
2614
+ stickyIndicesSet: React3.useMemo(() => new Set(stickyIndices), [stickyIndices]),
2273
2615
  stylePaddingBottom: stylePaddingBottomState,
2274
2616
  stylePaddingTop: stylePaddingTopState,
2275
2617
  suggestEstimatedItemSize: !!suggestEstimatedItemSize
@@ -2507,6 +2849,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2507
2849
  }),
2508
2850
  []
2509
2851
  );
2852
+ const animatedScrollHandler = React3.useMemo(() => {
2853
+ if (stickyIndices == null ? void 0 : stickyIndices.length) {
2854
+ const { animatedScrollY } = ctx;
2855
+ return reactNative.Animated.event([{ nativeEvent: { contentOffset: { [horizontal ? "x" : "y"]: animatedScrollY } } }], {
2856
+ listener: fns.onScroll,
2857
+ useNativeDriver: true
2858
+ });
2859
+ }
2860
+ return fns.onScroll;
2861
+ }, [stickyIndices, horizontal, onScroll]);
2510
2862
  return /* @__PURE__ */ React3__namespace.createElement(React3__namespace.Fragment, null, /* @__PURE__ */ React3__namespace.createElement(
2511
2863
  ListComponent,
2512
2864
  {
@@ -2523,14 +2875,20 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2523
2875
  onLayout,
2524
2876
  onLayoutHeader,
2525
2877
  onMomentumScrollEnd: (event) => {
2526
- requestAnimationFrame(() => {
2527
- finishScrollTo(refState.current);
2528
- });
2878
+ if (IsNewArchitecture) {
2879
+ requestAnimationFrame(() => {
2880
+ finishScrollTo(refState.current);
2881
+ });
2882
+ } else {
2883
+ setTimeout(() => {
2884
+ finishScrollTo(refState.current);
2885
+ }, 1e3);
2886
+ }
2529
2887
  if (onMomentumScrollEnd) {
2530
2888
  onMomentumScrollEnd(event);
2531
2889
  }
2532
2890
  },
2533
- onScroll: fns.onScroll,
2891
+ onScroll: animatedScrollHandler,
2534
2892
  recycleItems,
2535
2893
  refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3__namespace.cloneElement(refreshControl, {
2536
2894
  progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
@@ -2546,6 +2904,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2546
2904
  scrollAdjustHandler: (_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler,
2547
2905
  scrollEventThrottle: reactNative.Platform.OS === "web" ? 16 : void 0,
2548
2906
  snapToIndices,
2907
+ stickyIndices,
2549
2908
  style,
2550
2909
  updateItemSize: fns.updateItemSize,
2551
2910
  waitForInitialLayout