@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.mjs CHANGED
@@ -1,12 +1,13 @@
1
1
  import * as React3 from 'react';
2
- import React3__default, { useReducer, useEffect, createContext, useRef, useState, useMemo, useLayoutEffect, useCallback, useImperativeHandle, useContext, forwardRef, memo } from 'react';
3
- import { View, Text, Platform, Animated, ScrollView, StyleSheet, Dimensions, RefreshControl, unstable_batchedUpdates } from 'react-native';
2
+ import React3__default, { useReducer, useEffect, createContext, useRef, useState, useMemo, useLayoutEffect, useCallback, useImperativeHandle, forwardRef, memo, useContext } from 'react';
3
+ import { View, Text, Platform, Animated, StyleSheet, Dimensions, RefreshControl, unstable_batchedUpdates } from 'react-native';
4
4
  import { useSyncExternalStore } from 'use-sync-external-store/shim';
5
5
 
6
6
  // src/components/LazyLegendList.tsx
7
7
  var ContextState = React3.createContext(null);
8
8
  function StateProvider({ children }) {
9
9
  const [value] = React3.useState(() => ({
10
+ animatedScrollY: new Animated.Value(0),
10
11
  columnWrapperStyle: void 0,
11
12
  listeners: /* @__PURE__ */ new Map(),
12
13
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
@@ -164,18 +165,128 @@ var LeanViewComponent = React3.forwardRef((props, ref) => {
164
165
  LeanViewComponent.displayName = "RCTView";
165
166
  var LeanView = Platform.OS === "android" || Platform.OS === "ios" ? LeanViewComponent : View;
166
167
 
167
- // src/components/Separator.tsx
168
- function Separator({ ItemSeparatorComponent, itemKey, leadingItem }) {
169
- const [lastItemKeys] = useArr$(["lastItemKeys"]);
170
- const isALastItem = lastItemKeys.includes(itemKey);
171
- return isALastItem ? null : /* @__PURE__ */ React.createElement(ItemSeparatorComponent, { leadingItem });
172
- }
173
-
174
168
  // src/constants.ts
175
169
  var POSITION_OUT_OF_VIEW = -1e7;
176
170
  var ENABLE_DEVMODE = __DEV__ && false;
177
171
  var ENABLE_DEBUG_VIEW = __DEV__ && false;
178
172
  var IsNewArchitecture = global.nativeFabricUIManager != null;
173
+ var useAnimatedValue = (initialValue) => {
174
+ return useRef(new Animated.Value(initialValue)).current;
175
+ };
176
+
177
+ // src/hooks/useValue$.ts
178
+ function useValue$(key, params) {
179
+ var _a;
180
+ const { getValue, delay } = params || {};
181
+ const ctx = useStateContext();
182
+ const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
183
+ useMemo(() => {
184
+ let newValue;
185
+ let prevValue;
186
+ let didQueueTask = false;
187
+ listen$(ctx, key, (v) => {
188
+ newValue = getValue ? getValue(v) : v;
189
+ if (delay !== void 0) {
190
+ const fn = () => {
191
+ didQueueTask = false;
192
+ if (newValue !== void 0) {
193
+ animValue.setValue(newValue);
194
+ }
195
+ };
196
+ const delayValue = typeof delay === "function" ? delay(newValue, prevValue) : delay;
197
+ prevValue = newValue;
198
+ if (!didQueueTask) {
199
+ didQueueTask = true;
200
+ if (delayValue === 0) {
201
+ queueMicrotask(fn);
202
+ } else {
203
+ setTimeout(fn, delayValue);
204
+ }
205
+ }
206
+ } else {
207
+ animValue.setValue(newValue);
208
+ }
209
+ });
210
+ }, []);
211
+ return animValue;
212
+ }
213
+ var typedForwardRef = forwardRef;
214
+ var typedMemo = memo;
215
+
216
+ // src/components/PositionView.tsx
217
+ var PositionViewState = typedMemo(function PositionView({
218
+ id,
219
+ horizontal,
220
+ style,
221
+ refView,
222
+ ...rest
223
+ }) {
224
+ const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
225
+ return /* @__PURE__ */ React3.createElement(
226
+ LeanView,
227
+ {
228
+ ref: refView,
229
+ style: [
230
+ style,
231
+ horizontal ? { transform: [{ translateX: position }] } : { transform: [{ translateY: position }] }
232
+ ],
233
+ ...rest
234
+ }
235
+ );
236
+ });
237
+ var PositionViewAnimated = typedMemo(function PositionView2({
238
+ id,
239
+ horizontal,
240
+ style,
241
+ refView,
242
+ ...rest
243
+ }) {
244
+ const position$ = useValue$(`containerPosition${id}`, {
245
+ getValue: (v) => v != null ? v : POSITION_OUT_OF_VIEW
246
+ });
247
+ return /* @__PURE__ */ React3.createElement(
248
+ Animated.View,
249
+ {
250
+ ref: refView,
251
+ style: [
252
+ style,
253
+ horizontal ? { transform: [{ translateX: position$ }] } : { transform: [{ translateY: position$ }] }
254
+ ],
255
+ ...rest
256
+ }
257
+ );
258
+ });
259
+ var PositionViewSticky = typedMemo(function PositionViewSticky2({
260
+ id,
261
+ horizontal,
262
+ style,
263
+ refView,
264
+ animatedScrollY,
265
+ stickyOffset,
266
+ index,
267
+ ...rest
268
+ }) {
269
+ const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
270
+ const transform = React3.useMemo(() => {
271
+ if (animatedScrollY && stickyOffset) {
272
+ const stickyPosition = animatedScrollY.interpolate({
273
+ extrapolate: "clamp",
274
+ inputRange: [position, position + 5e3],
275
+ outputRange: [position, position + 5e3]
276
+ });
277
+ return horizontal ? [{ translateX: stickyPosition }] : [{ translateY: stickyPosition }];
278
+ }
279
+ }, [position, horizontal, animatedScrollY, stickyOffset]);
280
+ console.log("index", index, position, transform);
281
+ const viewStyle = React3.useMemo(() => [style, { zIndex: index + 1e3 }, { transform }], [style, transform]);
282
+ return /* @__PURE__ */ React3.createElement(Animated.View, { ref: refView, style: viewStyle, ...rest });
283
+ });
284
+ var PositionView3 = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
285
+ function Separator({ ItemSeparatorComponent, itemKey, leadingItem }) {
286
+ const [lastItemKeys] = useArr$(["lastItemKeys"]);
287
+ const isALastItem = lastItemKeys.includes(itemKey);
288
+ return isALastItem ? null : /* @__PURE__ */ React3.createElement(ItemSeparatorComponent, { leadingItem });
289
+ }
179
290
  var symbolFirst = Symbol();
180
291
  function useInit(cb) {
181
292
  const refValue = useRef(symbolFirst);
@@ -312,8 +423,6 @@ function useListScrollSize() {
312
423
  const [scrollSize] = useArr$(["scrollSize"]);
313
424
  return scrollSize;
314
425
  }
315
- var typedForwardRef = forwardRef;
316
- var typedMemo = memo;
317
426
 
318
427
  // src/components/Container.tsx
319
428
  var Container = typedMemo(function Container2({
@@ -325,14 +434,15 @@ var Container = typedMemo(function Container2({
325
434
  ItemSeparatorComponent
326
435
  }) {
327
436
  const ctx = useStateContext();
328
- const columnWrapperStyle = ctx.columnWrapperStyle;
329
- const [column = 0, data, itemKey, position = POSITION_OUT_OF_VIEW, numColumns, extraData] = useArr$([
437
+ const { columnWrapperStyle, animatedScrollY } = ctx;
438
+ const [column = 0, data, itemKey, numColumns, extraData, isSticky, stickyOffset] = useArr$([
330
439
  `containerColumn${id}`,
331
440
  `containerItemData${id}`,
332
441
  `containerItemKey${id}`,
333
- `containerPosition${id}`,
334
442
  "numColumns",
335
- "extraData"
443
+ "extraData",
444
+ `containerSticky${id}`,
445
+ `containerStickyOffset${id}`
336
446
  ]);
337
447
  const refLastSize = useRef();
338
448
  const ref = useRef(null);
@@ -340,36 +450,38 @@ var Container = typedMemo(function Container2({
340
450
  const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
341
451
  const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
342
452
  let didLayout = false;
343
- let paddingStyles;
344
- if (columnWrapperStyle) {
345
- const { columnGap, rowGap, gap } = columnWrapperStyle;
346
- if (horizontal) {
347
- paddingStyles = {
348
- paddingRight: columnGap || gap || void 0,
349
- paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
350
- };
351
- } else {
352
- paddingStyles = {
353
- paddingBottom: rowGap || gap || void 0,
354
- paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
355
- };
453
+ const style = useMemo(() => {
454
+ let paddingStyles;
455
+ if (columnWrapperStyle) {
456
+ const { columnGap, rowGap, gap } = columnWrapperStyle;
457
+ if (horizontal) {
458
+ paddingStyles = {
459
+ paddingRight: columnGap || gap || void 0,
460
+ paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
461
+ };
462
+ } else {
463
+ paddingStyles = {
464
+ paddingBottom: rowGap || gap || void 0,
465
+ paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
466
+ };
467
+ }
356
468
  }
357
- }
358
- const style = horizontal ? {
359
- flexDirection: ItemSeparatorComponent ? "row" : void 0,
360
- height: otherAxisSize,
361
- left: position,
362
- position: "absolute",
363
- top: otherAxisPos,
364
- ...paddingStyles || {}
365
- } : {
366
- left: otherAxisPos,
367
- position: "absolute",
368
- right: numColumns > 1 ? null : 0,
369
- top: position,
370
- width: otherAxisSize,
371
- ...paddingStyles || {}
372
- };
469
+ return horizontal ? {
470
+ flexDirection: ItemSeparatorComponent ? "row" : void 0,
471
+ height: otherAxisSize,
472
+ left: 0,
473
+ position: "absolute",
474
+ top: otherAxisPos,
475
+ ...paddingStyles || {}
476
+ } : {
477
+ left: otherAxisPos,
478
+ position: "absolute",
479
+ right: numColumns > 1 ? null : 0,
480
+ top: 0,
481
+ width: otherAxisSize,
482
+ ...paddingStyles || {}
483
+ };
484
+ }, [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns]);
373
485
  const renderedItemInfo = useMemo(
374
486
  () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
375
487
  [itemKey, data, extraData]
@@ -434,55 +546,30 @@ var Container = typedMemo(function Container2({
434
546
  }
435
547
  }, [itemKey]);
436
548
  }
437
- return /* @__PURE__ */ React3.createElement(LeanView, { key: recycleItems ? void 0 : itemKey, onLayout, ref, style }, /* @__PURE__ */ React3.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React3.createElement(
438
- Separator,
549
+ const PositionComponent = isSticky ? PositionViewSticky : PositionView3;
550
+ return /* @__PURE__ */ React3.createElement(
551
+ PositionComponent,
439
552
  {
440
- ItemSeparatorComponent,
441
- itemKey,
442
- leadingItem: renderedItemInfo.item
443
- }
444
- )));
445
- });
446
- var useAnimatedValue = (initialValue) => {
447
- return useRef(new Animated.Value(initialValue)).current;
448
- };
449
-
450
- // src/hooks/useValue$.ts
451
- function useValue$(key, params) {
452
- var _a;
453
- const { getValue, delay } = params || {};
454
- const ctx = useStateContext();
455
- const animValue = useAnimatedValue((_a = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a : 0);
456
- useMemo(() => {
457
- let newValue;
458
- let prevValue;
459
- let didQueueTask = false;
460
- listen$(ctx, key, (v) => {
461
- newValue = getValue ? getValue(v) : v;
462
- if (delay !== void 0) {
463
- const fn = () => {
464
- didQueueTask = false;
465
- if (newValue !== void 0) {
466
- animValue.setValue(newValue);
467
- }
468
- };
469
- const delayValue = typeof delay === "function" ? delay(newValue, prevValue) : delay;
470
- prevValue = newValue;
471
- if (!didQueueTask) {
472
- didQueueTask = true;
473
- if (delayValue === 0) {
474
- queueMicrotask(fn);
475
- } else {
476
- setTimeout(fn, delayValue);
477
- }
478
- }
479
- } else {
480
- animValue.setValue(newValue);
553
+ animatedScrollY: isSticky ? animatedScrollY : void 0,
554
+ horizontal,
555
+ id,
556
+ index,
557
+ key: recycleItems ? void 0 : itemKey,
558
+ onLayout,
559
+ refView: ref,
560
+ stickyOffset: isSticky ? stickyOffset : void 0,
561
+ style
562
+ },
563
+ /* @__PURE__ */ React3.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React3.createElement(
564
+ Separator,
565
+ {
566
+ ItemSeparatorComponent,
567
+ itemKey,
568
+ leadingItem: renderedItemInfo.item
481
569
  }
482
- });
483
- }, []);
484
- return animValue;
485
- }
570
+ ))
571
+ );
572
+ });
486
573
 
487
574
  // src/components/Containers.tsx
488
575
  var Containers = typedMemo(function Containers2({
@@ -642,6 +729,7 @@ var ListComponent = typedMemo(function ListComponent2({
642
729
  scrollAdjustHandler,
643
730
  onLayoutHeader,
644
731
  snapToIndices,
732
+ stickyIndices,
645
733
  ...rest
646
734
  }) {
647
735
  const ctx = useStateContext();
@@ -651,7 +739,7 @@ var ListComponent = typedMemo(function ListComponent2({
651
739
  const ScrollComponent = renderScrollComponent ? useMemo(
652
740
  () => React3.forwardRef((props, ref) => renderScrollComponent({ ...props, ref })),
653
741
  [renderScrollComponent]
654
- ) : ScrollView;
742
+ ) : Animated.ScrollView;
655
743
  React3.useEffect(() => {
656
744
  if (canRender) {
657
745
  setTimeout(() => {
@@ -704,9 +792,26 @@ var ListComponent = typedMemo(function ListComponent2({
704
792
  style: ListFooterComponentStyle
705
793
  },
706
794
  getComponent(ListFooterComponent)
707
- )
795
+ ),
796
+ __DEV__ && ENABLE_DEVMODE && /* @__PURE__ */ React3.createElement(DevNumbers, null)
708
797
  );
709
798
  });
799
+ var DevNumbers = __DEV__ && React3.memo(function DevNumbers2() {
800
+ return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3.createElement(
801
+ View,
802
+ {
803
+ key: index,
804
+ style: {
805
+ height: 100,
806
+ pointerEvents: "none",
807
+ position: "absolute",
808
+ top: index * 100,
809
+ width: "100%"
810
+ }
811
+ },
812
+ /* @__PURE__ */ React3.createElement(Text, { style: { color: "red" } }, index * 100)
813
+ ));
814
+ });
710
815
 
711
816
  // src/utils/getId.ts
712
817
  function getId(state, index) {
@@ -738,20 +843,36 @@ function calculateOffsetForIndex(ctx, state, index) {
738
843
  }
739
844
 
740
845
  // src/utils/getItemSize.ts
741
- function getItemSize(state, key, index, data, useAverageSize) {
846
+ function getItemSize(state, key, index, data, useAverageSize, defaultAverageSize) {
847
+ var _a, _b;
742
848
  const {
743
849
  sizesKnown,
744
850
  sizes,
745
851
  scrollingTo,
746
- props: { estimatedItemSize, getEstimatedItemSize }
852
+ averageSizes,
853
+ props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType }
747
854
  } = state;
748
855
  const sizeKnown = sizesKnown.get(key);
749
856
  if (sizeKnown !== void 0) {
750
857
  return sizeKnown;
751
858
  }
752
859
  let size;
753
- if (useAverageSize !== void 0 && sizeKnown === void 0 && !getEstimatedItemSize && !scrollingTo) {
754
- size = useAverageSize;
860
+ const itemType = getItemType ? (_a = getItemType(data, index)) != null ? _a : "" : "";
861
+ if (getFixedItemSize) {
862
+ size = getFixedItemSize(index, data, itemType);
863
+ if (size !== void 0) {
864
+ sizesKnown.set(key, size);
865
+ }
866
+ }
867
+ if (size === void 0 && useAverageSize && sizeKnown === void 0 && !scrollingTo) {
868
+ if (itemType === "") {
869
+ size = defaultAverageSize;
870
+ } else {
871
+ const averageSizeForType = (_b = averageSizes[itemType]) == null ? void 0 : _b.avg;
872
+ if (averageSizeForType !== void 0) {
873
+ size = roundSize(averageSizeForType);
874
+ }
875
+ }
755
876
  }
756
877
  if (size === void 0) {
757
878
  size = sizes.get(key);
@@ -760,7 +881,7 @@ function getItemSize(state, key, index, data, useAverageSize) {
760
881
  }
761
882
  }
762
883
  if (size === void 0) {
763
- size = getEstimatedItemSize ? getEstimatedItemSize(index, data) : estimatedItemSize;
884
+ size = getEstimatedItemSize ? getEstimatedItemSize(index, data, itemType) : estimatedItemSize;
764
885
  }
765
886
  sizes.set(key, size);
766
887
  return size;
@@ -779,6 +900,37 @@ function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
779
900
  return offset;
780
901
  }
781
902
 
903
+ // src/core/finishScrollTo.ts
904
+ var finishScrollTo = (state) => {
905
+ if (state) {
906
+ state.scrollingTo = void 0;
907
+ state.scrollHistory.length = 0;
908
+ }
909
+ };
910
+
911
+ // src/core/scrollTo.ts
912
+ function scrollTo(state, params = {}) {
913
+ var _a;
914
+ const { animated } = params;
915
+ const {
916
+ refScroller,
917
+ props: { horizontal }
918
+ } = state;
919
+ const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
920
+ state.scrollHistory.length = 0;
921
+ state.scrollingTo = params;
922
+ state.scrollPending = offset;
923
+ (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
924
+ animated: !!animated,
925
+ x: horizontal ? offset : 0,
926
+ y: horizontal ? 0 : offset
927
+ });
928
+ if (!animated) {
929
+ state.scroll = offset;
930
+ setTimeout(() => finishScrollTo(state), 100);
931
+ }
932
+ }
933
+
782
934
  // src/utils/requestAdjust.ts
783
935
  function requestAdjust(ctx, state, positionDiff) {
784
936
  if (Math.abs(positionDiff) > 0.1) {
@@ -812,37 +964,63 @@ function requestAdjust(ctx, state, positionDiff) {
812
964
  }
813
965
 
814
966
  // src/core/prepareMVCP.ts
815
- function prepareMVCP(ctx, state) {
967
+ function prepareMVCP(ctx, state, dataChanged) {
816
968
  const {
969
+ idsInView,
817
970
  positions,
818
971
  scrollingTo,
819
972
  props: { maintainVisibleContentPosition }
820
973
  } = state;
821
974
  let prevPosition;
822
975
  let targetId;
823
- let targetIndex;
976
+ const idsInViewWithPositions = [];
824
977
  const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
825
978
  if (maintainVisibleContentPosition) {
826
979
  const indexByKey = state.indexByKey;
827
980
  if (scrollTarget !== void 0) {
828
981
  targetId = getId(state, scrollTarget);
829
- targetIndex = scrollTarget;
830
- } else if (state.idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
831
- targetId = state.idsInView.find((id) => indexByKey.get(id) !== void 0);
832
- targetIndex = indexByKey.get(targetId);
982
+ } else if (idsInView.length > 0 && peek$(ctx, "containersDidLayout")) {
983
+ if (dataChanged) {
984
+ for (let i = 0; i < idsInView.length; i++) {
985
+ const id = idsInView[i];
986
+ const index = indexByKey.get(id);
987
+ if (index !== void 0) {
988
+ idsInViewWithPositions.push({ id, position: positions.get(id) });
989
+ }
990
+ }
991
+ } else {
992
+ targetId = state.idsInView.find((id) => indexByKey.get(id) !== void 0);
993
+ }
833
994
  }
834
- if (targetId !== void 0 && targetIndex !== void 0) {
995
+ if (targetId !== void 0) {
835
996
  prevPosition = positions.get(targetId);
836
997
  }
837
998
  }
838
999
  return () => {
1000
+ let positionDiff;
1001
+ if (targetId === void 0) {
1002
+ for (let i = 0; i < idsInViewWithPositions.length; i++) {
1003
+ const { id, position } = idsInViewWithPositions[i];
1004
+ const newPosition = positions.get(id);
1005
+ if (newPosition !== void 0) {
1006
+ positionDiff = newPosition - position;
1007
+ break;
1008
+ }
1009
+ }
1010
+ }
839
1011
  if (targetId !== void 0 && prevPosition !== void 0) {
840
1012
  const newPosition = positions.get(targetId);
841
1013
  if (newPosition !== void 0) {
842
- const positionDiff = newPosition - prevPosition;
843
- if (Math.abs(positionDiff) > 0.1) {
844
- requestAdjust(ctx, state, positionDiff);
845
- }
1014
+ positionDiff = newPosition - prevPosition;
1015
+ }
1016
+ }
1017
+ if (positionDiff !== void 0 && Math.abs(positionDiff) > 0.1) {
1018
+ if (Platform.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff) {
1019
+ scrollTo(state, {
1020
+ offset: state.scroll + positionDiff
1021
+ });
1022
+ } else {
1023
+ requestAdjust(ctx, state, positionDiff);
846
1024
  }
847
1025
  }
848
1026
  };
@@ -983,7 +1161,7 @@ function updateAllPositions(ctx, state, dataChanged) {
983
1161
  firstFullyOnScreenIndex,
984
1162
  idCache,
985
1163
  sizesKnown,
986
- props: { snapToIndices }
1164
+ props: { getEstimatedItemSize, snapToIndices }
987
1165
  } = state;
988
1166
  const data = state.props.data;
989
1167
  const numColumns = peek$(ctx, "numColumns");
@@ -992,7 +1170,9 @@ function updateAllPositions(ctx, state, dataChanged) {
992
1170
  if (dataChanged) {
993
1171
  indexByKey.clear();
994
1172
  idCache.clear();
1173
+ positions.clear();
995
1174
  }
1175
+ const useAverageSize = !getEstimatedItemSize;
996
1176
  const itemType = "";
997
1177
  let averageSize = (_a = averageSizes[itemType]) == null ? void 0 : _a.avg;
998
1178
  if (averageSize !== void 0) {
@@ -1008,7 +1188,7 @@ function updateAllPositions(ctx, state, dataChanged) {
1008
1188
  let bailout = false;
1009
1189
  for (let i = firstFullyOnScreenIndex - 1; i >= 0; i--) {
1010
1190
  const id = (_b = idCache.get(i)) != null ? _b : getId(state, i);
1011
- const size = (_c = sizesKnown.get(id)) != null ? _c : getItemSize(state, id, i, data[i], averageSize);
1191
+ const size = (_c = sizesKnown.get(id)) != null ? _c : getItemSize(state, id, i, data[i], useAverageSize, averageSize);
1012
1192
  const itemColumn = columns.get(id);
1013
1193
  maxSizeInRow2 = Math.max(maxSizeInRow2, size);
1014
1194
  if (itemColumn === 1) {
@@ -1035,7 +1215,7 @@ function updateAllPositions(ctx, state, dataChanged) {
1035
1215
  const dataLength = data.length;
1036
1216
  for (let i = 0; i < dataLength; i++) {
1037
1217
  const id = (_d = idCache.get(i)) != null ? _d : getId(state, i);
1038
- const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(state, id, i, data[i], averageSize);
1218
+ const size = (_e = sizesKnown.get(id)) != null ? _e : getItemSize(state, id, i, data[i], useAverageSize, averageSize);
1039
1219
  if (__DEV__ && needsIndexByKey) {
1040
1220
  if (indexByKeyForChecking.has(id)) {
1041
1221
  console.error(
@@ -1274,35 +1454,84 @@ function checkAllSizesKnown(state) {
1274
1454
  }
1275
1455
 
1276
1456
  // src/utils/findAvailableContainers.ts
1277
- function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval) {
1457
+ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
1278
1458
  const numContainers = peek$(ctx, "numContainers");
1459
+ const { stickyIndicesSet } = state.props;
1279
1460
  const result = [];
1280
1461
  const availableContainers = [];
1281
- for (let u = 0; u < numContainers; u++) {
1282
- const key = peek$(ctx, `containerItemKey${u}`);
1283
- let isOk = key === void 0;
1284
- if (!isOk) {
1285
- const index = pendingRemoval.indexOf(u);
1286
- if (index !== -1) {
1287
- pendingRemoval.splice(index, 1);
1288
- isOk = true;
1462
+ const stickyItemIndices = (needNewContainers == null ? void 0 : needNewContainers.filter((index) => stickyIndicesSet.has(index))) || [];
1463
+ const nonStickyItemIndices = (needNewContainers == null ? void 0 : needNewContainers.filter((index) => !stickyIndicesSet.has(index))) || [];
1464
+ const canReuseContainer = (containerIndex, requiredType) => {
1465
+ if (!requiredType) return true;
1466
+ const existingType = state.containerItemTypes.get(containerIndex);
1467
+ if (!existingType) return true;
1468
+ return existingType === requiredType;
1469
+ };
1470
+ const neededTypes = requiredItemTypes ? [...requiredItemTypes] : [];
1471
+ let typeIndex = 0;
1472
+ for (let i = 0; i < stickyItemIndices.length; i++) {
1473
+ const requiredType = neededTypes[typeIndex];
1474
+ let foundContainer = false;
1475
+ for (const containerIndex of state.stickyContainerPool) {
1476
+ const key = peek$(ctx, `containerItemKey${containerIndex}`);
1477
+ const isPendingRemoval = pendingRemoval.includes(containerIndex);
1478
+ if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType)) {
1479
+ result.push(containerIndex);
1480
+ if (isPendingRemoval) {
1481
+ const index = pendingRemoval.indexOf(containerIndex);
1482
+ pendingRemoval.splice(index, 1);
1483
+ }
1484
+ foundContainer = true;
1485
+ if (requiredItemTypes) typeIndex++;
1486
+ break;
1289
1487
  }
1290
1488
  }
1291
- if (isOk) {
1292
- result.push(u);
1293
- if (result.length >= numNeeded) {
1294
- return result;
1489
+ if (!foundContainer) {
1490
+ const newContainerIndex = numContainers + result.filter((index) => index >= numContainers).length;
1491
+ result.push(newContainerIndex);
1492
+ state.stickyContainerPool.add(newContainerIndex);
1493
+ if (requiredItemTypes) typeIndex++;
1494
+ }
1495
+ }
1496
+ if (nonStickyItemIndices.length > 0) {
1497
+ for (let u = 0; u < numContainers; u++) {
1498
+ if (state.stickyContainerPool.has(u)) {
1499
+ continue;
1500
+ }
1501
+ const key = peek$(ctx, `containerItemKey${u}`);
1502
+ let isOk = key === void 0;
1503
+ if (!isOk) {
1504
+ const index = pendingRemoval.indexOf(u);
1505
+ if (index !== -1) {
1506
+ pendingRemoval.splice(index, 1);
1507
+ const requiredType = neededTypes[typeIndex];
1508
+ isOk = canReuseContainer(u, requiredType);
1509
+ }
1510
+ }
1511
+ if (isOk) {
1512
+ result.push(u);
1513
+ if (requiredItemTypes) {
1514
+ typeIndex++;
1515
+ }
1516
+ if (result.length >= numNeeded) {
1517
+ return result;
1518
+ }
1295
1519
  }
1296
1520
  }
1297
1521
  }
1298
1522
  for (let u = 0; u < numContainers; u++) {
1523
+ if (state.stickyContainerPool.has(u)) {
1524
+ continue;
1525
+ }
1299
1526
  const key = peek$(ctx, `containerItemKey${u}`);
1300
1527
  if (key === void 0) continue;
1301
1528
  const index = state.indexByKey.get(key);
1302
- if (index < startBuffered) {
1303
- availableContainers.push({ distance: startBuffered - index, index: u });
1304
- } else if (index > endBuffered) {
1305
- availableContainers.push({ distance: index - endBuffered, index: u });
1529
+ const isOutOfView = index < startBuffered || index > endBuffered;
1530
+ if (isOutOfView) {
1531
+ const distance = index < startBuffered ? startBuffered - index : index - endBuffered;
1532
+ if (!requiredItemTypes || typeIndex < neededTypes.length && canReuseContainer(u, neededTypes[typeIndex])) {
1533
+ availableContainers.push({ distance, index: u });
1534
+ }
1306
1535
  }
1307
1536
  }
1308
1537
  const remaining = numNeeded - result.length;
@@ -1314,6 +1543,9 @@ function findAvailableContainers(ctx, state, numNeeded, startBuffered, endBuffer
1314
1543
  }
1315
1544
  for (const container of availableContainers) {
1316
1545
  result.push(container.index);
1546
+ if (requiredItemTypes) {
1547
+ typeIndex++;
1548
+ }
1317
1549
  }
1318
1550
  }
1319
1551
  const stillNeeded = numNeeded - result.length;
@@ -1342,37 +1574,6 @@ function comparatorByDistance(a, b) {
1342
1574
  return b.distance - a.distance;
1343
1575
  }
1344
1576
 
1345
- // src/core/finishScrollTo.ts
1346
- var finishScrollTo = (state) => {
1347
- if (state) {
1348
- state.scrollingTo = void 0;
1349
- state.scrollHistory.length = 0;
1350
- }
1351
- };
1352
-
1353
- // src/core/scrollTo.ts
1354
- function scrollTo(state, params = {}) {
1355
- var _a;
1356
- const { animated } = params;
1357
- const {
1358
- refScroller,
1359
- props: { horizontal }
1360
- } = state;
1361
- const offset = calculateOffsetWithOffsetPosition(state, params.offset, params);
1362
- state.scrollHistory.length = 0;
1363
- state.scrollingTo = params;
1364
- state.scrollPending = offset;
1365
- (_a = refScroller.current) == null ? void 0 : _a.scrollTo({
1366
- animated: !!animated,
1367
- x: horizontal ? offset : 0,
1368
- y: horizontal ? 0 : offset
1369
- });
1370
- if (!animated) {
1371
- state.scroll = offset;
1372
- setTimeout(() => finishScrollTo(state), 100);
1373
- }
1374
- }
1375
-
1376
1577
  // src/core/scrollToIndex.ts
1377
1578
  function scrollToIndex(ctx, state, { index, viewOffset = 0, animated = true, viewPosition }) {
1378
1579
  if (index >= state.props.data.length) {
@@ -1460,16 +1661,90 @@ function setDidLayout(ctx, state) {
1460
1661
  } = state;
1461
1662
  state.queuedInitialLayout = true;
1462
1663
  checkAtBottom(ctx, state);
1463
- if (!IsNewArchitecture && initialScroll) {
1464
- scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1465
- }
1466
- set$(ctx, "containersDidLayout", true);
1467
- if (onLoad) {
1468
- onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1664
+ const setIt = () => {
1665
+ set$(ctx, "containersDidLayout", true);
1666
+ if (onLoad) {
1667
+ onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
1668
+ }
1669
+ };
1670
+ if (Platform.OS === "android" || !IsNewArchitecture) {
1671
+ if (initialScroll) {
1672
+ queueMicrotask(() => {
1673
+ scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1674
+ requestAnimationFrame(() => {
1675
+ scrollToIndex(ctx, state, { ...initialScroll, animated: false });
1676
+ setIt();
1677
+ });
1678
+ });
1679
+ } else {
1680
+ queueMicrotask(setIt);
1681
+ }
1682
+ } else {
1683
+ setIt();
1469
1684
  }
1470
1685
  }
1471
1686
 
1472
1687
  // src/core/calculateItemsInView.ts
1688
+ function findCurrentStickyIndex(stickyArray, scroll, state) {
1689
+ var _a;
1690
+ for (let i = stickyArray.length - 1; i >= 0; i--) {
1691
+ const stickyId = (_a = state.idCache.get(stickyArray[i])) != null ? _a : getId(state, stickyArray[i]);
1692
+ const stickyPos = stickyId ? state.positions.get(stickyId) : void 0;
1693
+ if (stickyPos !== void 0 && scroll >= stickyPos) {
1694
+ return i;
1695
+ }
1696
+ }
1697
+ return -1;
1698
+ }
1699
+ function getActiveStickyIndices(ctx, state, stickyIndices) {
1700
+ return new Set(
1701
+ 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))
1702
+ );
1703
+ }
1704
+ function handleStickyActivation(ctx, state, stickyIndices, stickyArray, scroll, needNewContainers, startBuffered, endBuffered) {
1705
+ var _a;
1706
+ const activeIndices = getActiveStickyIndices(ctx, state, stickyIndices);
1707
+ const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
1708
+ for (let offset = 0; offset <= 1; offset++) {
1709
+ const idx = currentStickyIdx - offset;
1710
+ if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
1711
+ const stickyIndex = stickyArray[idx];
1712
+ const stickyId = (_a = state.idCache.get(stickyIndex)) != null ? _a : getId(state, stickyIndex);
1713
+ if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered)) {
1714
+ needNewContainers.push(stickyIndex);
1715
+ }
1716
+ }
1717
+ }
1718
+ function handleStickyRecycling(ctx, state, stickyArray, scroll, scrollBuffer, pendingRemoval) {
1719
+ var _a, _b, _c;
1720
+ const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
1721
+ for (const containerIndex of state.stickyContainerPool) {
1722
+ const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
1723
+ const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
1724
+ if (itemIndex === void 0) continue;
1725
+ const arrayIdx = stickyArray.indexOf(itemIndex);
1726
+ if (arrayIdx === -1) continue;
1727
+ const isRecentSticky = arrayIdx >= currentStickyIdx - 1 && arrayIdx <= currentStickyIdx + 1;
1728
+ if (isRecentSticky) continue;
1729
+ const nextIndex = stickyArray[arrayIdx + 1];
1730
+ let shouldRecycle = false;
1731
+ if (nextIndex) {
1732
+ const nextId = (_a = state.idCache.get(nextIndex)) != null ? _a : getId(state, nextIndex);
1733
+ const nextPos = nextId ? state.positions.get(nextId) : void 0;
1734
+ shouldRecycle = nextPos !== void 0 && scroll > nextPos + scrollBuffer * 2;
1735
+ } else {
1736
+ const currentId = (_b = state.idCache.get(itemIndex)) != null ? _b : getId(state, itemIndex);
1737
+ if (currentId) {
1738
+ const currentPos = state.positions.get(currentId);
1739
+ const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(state, currentId, itemIndex, state.props.data[itemIndex]);
1740
+ shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + scrollBuffer * 3;
1741
+ }
1742
+ }
1743
+ if (shouldRecycle) {
1744
+ pendingRemoval.push(containerIndex);
1745
+ }
1746
+ }
1747
+ }
1473
1748
  function calculateItemsInView(ctx, state, params = {}) {
1474
1749
  unstable_batchedUpdates(() => {
1475
1750
  var _a, _b, _c, _d, _e, _f, _g, _h;
@@ -1486,7 +1761,7 @@ function calculateItemsInView(ctx, state, params = {}) {
1486
1761
  enableScrollForNextCalculateItemsInView,
1487
1762
  minIndexSizeChanged
1488
1763
  } = state;
1489
- const data = state.props.data;
1764
+ const { data, stickyIndicesArr, stickyIndicesSet } = state.props;
1490
1765
  const prevNumContainers = peek$(ctx, "numContainers");
1491
1766
  if (!data || scrollLength === 0 || !prevNumContainers) {
1492
1767
  return;
@@ -1498,7 +1773,7 @@ function calculateItemsInView(ctx, state, params = {}) {
1498
1773
  const { dataChanged, doMVCP } = params;
1499
1774
  const speed = getScrollVelocity(state);
1500
1775
  if (doMVCP || dataChanged) {
1501
- const checkMVCP = doMVCP ? prepareMVCP(ctx, state) : void 0;
1776
+ const checkMVCP = doMVCP ? prepareMVCP(ctx, state, dataChanged) : void 0;
1502
1777
  updateAllPositions(ctx, state, dataChanged);
1503
1778
  checkMVCP == null ? void 0 : checkMVCP();
1504
1779
  }
@@ -1648,14 +1923,23 @@ function calculateItemsInView(ctx, state, params = {}) {
1648
1923
  needNewContainers.push(i);
1649
1924
  }
1650
1925
  }
1926
+ if (stickyIndicesArr.length > 0) {
1927
+ handleStickyActivation(ctx, state, stickyIndicesSet, stickyIndicesArr, scroll, needNewContainers, startBuffered, endBuffered);
1928
+ }
1651
1929
  if (needNewContainers.length > 0) {
1930
+ const requiredItemTypes = state.props.getItemType ? needNewContainers.map((i) => {
1931
+ const itemType = state.props.getItemType(data[i], i);
1932
+ return itemType ? String(itemType) : "";
1933
+ }) : void 0;
1652
1934
  const availableContainers = findAvailableContainers(
1653
1935
  ctx,
1654
1936
  state,
1655
1937
  needNewContainers.length,
1656
1938
  startBuffered,
1657
1939
  endBuffered,
1658
- pendingRemoval
1940
+ pendingRemoval,
1941
+ requiredItemTypes,
1942
+ needNewContainers
1659
1943
  );
1660
1944
  for (let idx = 0; idx < needNewContainers.length; idx++) {
1661
1945
  const i = needNewContainers[idx];
@@ -1667,7 +1951,18 @@ function calculateItemsInView(ctx, state, params = {}) {
1667
1951
  }
1668
1952
  set$(ctx, `containerItemKey${containerIndex}`, id);
1669
1953
  set$(ctx, `containerItemData${containerIndex}`, data[i]);
1954
+ if (requiredItemTypes) {
1955
+ state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
1956
+ }
1670
1957
  containerItemKeys.add(id);
1958
+ if (stickyIndicesSet.has(i)) {
1959
+ set$(ctx, `containerSticky${containerIndex}`, true);
1960
+ const topPadding = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
1961
+ set$(ctx, `containerStickyOffset${containerIndex}`, new Animated.Value(topPadding));
1962
+ state.stickyContainerPool.add(containerIndex);
1963
+ } else {
1964
+ state.stickyContainerPool.delete(containerIndex);
1965
+ }
1671
1966
  if (containerIndex >= numContainers2) {
1672
1967
  numContainers2 = containerIndex + 1;
1673
1968
  }
@@ -1680,12 +1975,21 @@ function calculateItemsInView(ctx, state, params = {}) {
1680
1975
  }
1681
1976
  }
1682
1977
  }
1978
+ if (stickyIndicesArr.length > 0) {
1979
+ handleStickyRecycling(ctx, state, stickyIndicesArr, scroll, scrollBuffer, pendingRemoval);
1980
+ }
1683
1981
  for (let i = 0; i < numContainers; i++) {
1684
1982
  const itemKey = peek$(ctx, `containerItemKey${i}`);
1685
1983
  if (pendingRemoval.includes(i)) {
1686
1984
  if (itemKey) {
1687
1985
  containerItemKeys.delete(itemKey);
1688
1986
  }
1987
+ state.containerItemTypes.delete(i);
1988
+ if (state.stickyContainerPool.has(i)) {
1989
+ set$(ctx, `containerSticky${i}`, false);
1990
+ set$(ctx, `containerStickyOffset${i}`, void 0);
1991
+ state.stickyContainerPool.delete(i);
1992
+ }
1689
1993
  set$(ctx, `containerItemKey${i}`, void 0);
1690
1994
  set$(ctx, `containerItemData${i}`, void 0);
1691
1995
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
@@ -1736,10 +2040,14 @@ function calculateItemsInView(ctx, state, params = {}) {
1736
2040
 
1737
2041
  // src/core/doInitialAllocateContainers.ts
1738
2042
  function doInitialAllocateContainers(ctx, state) {
1739
- const { scrollLength } = state;
2043
+ var _a;
2044
+ const {
2045
+ scrollLength,
2046
+ props: { getItemType }
2047
+ } = state;
1740
2048
  const data = state.props.data;
1741
2049
  if (scrollLength > 0 && data.length > 0 && !peek$(ctx, "numContainers")) {
1742
- const averageItemSize = state.props.getEstimatedItemSize ? state.props.getEstimatedItemSize(0, data[0]) : state.props.estimatedItemSize;
2050
+ const averageItemSize = state.props.getEstimatedItemSize ? state.props.getEstimatedItemSize(0, data[0], getItemType ? (_a = getItemType(data[0], 0)) != null ? _a : "" : "") : state.props.estimatedItemSize;
1743
2051
  const Extra = 1.5;
1744
2052
  const numContainers = Math.ceil(
1745
2053
  (scrollLength + state.props.scrollBuffer * 2) / averageItemSize * state.props.numColumns * Extra
@@ -1776,16 +2084,18 @@ function doMaintainScrollAtEnd(ctx, state, animated) {
1776
2084
  }
1777
2085
  requestAnimationFrame(() => {
1778
2086
  var _a;
1779
- state.maintainingScrollAtEnd = true;
1780
- (_a = refScroller.current) == null ? void 0 : _a.scrollToEnd({
1781
- animated
1782
- });
1783
- setTimeout(
1784
- () => {
1785
- state.maintainingScrollAtEnd = false;
1786
- },
1787
- 0
1788
- );
2087
+ if (state == null ? void 0 : state.isAtEnd) {
2088
+ state.maintainingScrollAtEnd = true;
2089
+ (_a = refScroller.current) == null ? void 0 : _a.scrollToEnd({
2090
+ animated
2091
+ });
2092
+ setTimeout(
2093
+ () => {
2094
+ state.maintainingScrollAtEnd = false;
2095
+ },
2096
+ 0
2097
+ );
2098
+ }
1789
2099
  });
1790
2100
  return true;
1791
2101
  }
@@ -2005,7 +2315,22 @@ function updateItemSizes(ctx, state, itemUpdates) {
2005
2315
  }
2006
2316
  }
2007
2317
  function updateItemSize(ctx, state, itemKey, sizeObj) {
2008
- const { queuedItemSizeUpdates, queuedItemSizeUpdatesWaiting } = state;
2318
+ var _a;
2319
+ const {
2320
+ queuedItemSizeUpdates,
2321
+ queuedItemSizeUpdatesWaiting,
2322
+ sizesKnown,
2323
+ props: { getFixedItemSize, getItemType }
2324
+ } = state;
2325
+ if (getFixedItemSize) {
2326
+ const index = state.indexByKey.get(itemKey);
2327
+ const itemData = state.props.data[index];
2328
+ const type = getItemType ? (_a = getItemType(itemData, index)) != null ? _a : "" : "";
2329
+ const size = getFixedItemSize(index, itemData, type);
2330
+ if (size !== void 0 && size === sizesKnown.get(itemKey)) {
2331
+ return;
2332
+ }
2333
+ }
2009
2334
  const containersDidLayout = peek$(ctx, "containersDidLayout");
2010
2335
  if (!containersDidLayout || !queuedItemSizeUpdatesWaiting) {
2011
2336
  updateItemSizes(ctx, state, [{ itemKey, sizeObj }]);
@@ -2022,25 +2347,28 @@ function updateItemSize(ctx, state, itemKey, sizeObj) {
2022
2347
  }
2023
2348
  }
2024
2349
  function updateOneItemSize(state, itemKey, sizeObj) {
2350
+ var _a;
2025
2351
  const {
2026
2352
  sizes,
2027
2353
  indexByKey,
2028
2354
  sizesKnown,
2029
2355
  averageSizes,
2030
- props: { data, horizontal }
2356
+ props: { data, horizontal, getEstimatedItemSize, getItemType }
2031
2357
  } = state;
2032
2358
  if (!data) return 0;
2033
2359
  const index = indexByKey.get(itemKey);
2034
2360
  const prevSize = getItemSize(state, itemKey, index, data);
2035
2361
  const size = Math.floor((horizontal ? sizeObj.width : sizeObj.height) * 8) / 8;
2036
2362
  sizesKnown.set(itemKey, size);
2037
- const itemType = "";
2038
- let averages = averageSizes[itemType];
2039
- if (!averages) {
2040
- averages = averageSizes[itemType] = { avg: 0, num: 0 };
2363
+ if (!getEstimatedItemSize) {
2364
+ const itemType = getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : "";
2365
+ let averages = averageSizes[itemType];
2366
+ if (!averages) {
2367
+ averages = averageSizes[itemType] = { avg: 0, num: 0 };
2368
+ }
2369
+ averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2370
+ averages.num++;
2041
2371
  }
2042
- averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
2043
- averages.num++;
2044
2372
  if (!prevSize || Math.abs(prevSize - size) > 0.1) {
2045
2373
  sizes.set(itemKey, size);
2046
2374
  return size - prevSize;
@@ -2078,12 +2406,13 @@ function createColumnWrapperStyle(contentContainerStyle) {
2078
2406
  }
2079
2407
  }
2080
2408
  function getRenderedItem(ctx, state, key) {
2409
+ var _a;
2081
2410
  if (!state) {
2082
2411
  return null;
2083
2412
  }
2084
2413
  const {
2085
2414
  indexByKey,
2086
- props: { data, renderItem: renderItem2 }
2415
+ props: { data, getItemType, renderItem: renderItem2 }
2087
2416
  } = state;
2088
2417
  const index = indexByKey.get(key);
2089
2418
  if (index === void 0) {
@@ -2094,7 +2423,8 @@ function getRenderedItem(ctx, state, key) {
2094
2423
  const itemProps = {
2095
2424
  extraData: peek$(ctx, "extraData"),
2096
2425
  index,
2097
- item: data[index]
2426
+ item: data[index],
2427
+ type: getItemType ? (_a = getItemType(data[index], index)) != null ? _a : "" : ""
2098
2428
  };
2099
2429
  renderedItem = React3__default.createElement(renderItem2, itemProps);
2100
2430
  }
@@ -2110,49 +2440,52 @@ var LegendList = typedForwardRef(function LegendList2(props, forwardedRef) {
2110
2440
  var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
2111
2441
  var _a;
2112
2442
  const {
2443
+ alignItemsAtEnd = false,
2444
+ columnWrapperStyle,
2445
+ contentContainerStyle: contentContainerStyleProp,
2113
2446
  data: dataProp = [],
2447
+ drawDistance = 250,
2448
+ estimatedItemSize: estimatedItemSizeProp,
2449
+ estimatedListSize,
2450
+ extraData,
2451
+ getEstimatedItemSize,
2452
+ getFixedItemSize,
2453
+ getItemType,
2454
+ horizontal,
2455
+ initialContainerPoolRatio = 2,
2114
2456
  initialScrollIndex: initialScrollIndexProp,
2115
2457
  initialScrollOffset,
2116
- horizontal,
2117
- drawDistance = 250,
2118
- recycleItems = false,
2119
- onEndReachedThreshold = 0.5,
2120
- onStartReachedThreshold = 0.5,
2458
+ keyExtractor: keyExtractorProp,
2459
+ ListEmptyComponent,
2460
+ ListHeaderComponent,
2121
2461
  maintainScrollAtEnd = false,
2122
2462
  maintainScrollAtEndThreshold = 0.1,
2123
- alignItemsAtEnd = false,
2124
2463
  maintainVisibleContentPosition = false,
2125
- onScroll: onScrollProp,
2126
- onMomentumScrollEnd,
2127
2464
  numColumns: numColumnsProp = 1,
2128
- columnWrapperStyle,
2129
- keyExtractor: keyExtractorProp,
2130
- renderItem: renderItem2,
2131
- estimatedListSize,
2132
- estimatedItemSize: estimatedItemSizeProp,
2133
- getEstimatedItemSize,
2134
- suggestEstimatedItemSize,
2135
- ListHeaderComponent,
2136
- ListEmptyComponent,
2465
+ onEndReached,
2466
+ onEndReachedThreshold = 0.5,
2137
2467
  onItemSizeChanged,
2138
- refScrollView,
2139
- waitForInitialLayout = true,
2140
- extraData,
2141
- contentContainerStyle: contentContainerStyleProp,
2142
- style: styleProp,
2143
2468
  onLayout: onLayoutProp,
2469
+ onLoad,
2470
+ onMomentumScrollEnd,
2144
2471
  onRefresh,
2145
- refreshing,
2472
+ onScroll: onScrollProp,
2473
+ onStartReached,
2474
+ onStartReachedThreshold = 0.5,
2475
+ onViewableItemsChanged,
2146
2476
  progressViewOffset,
2477
+ recycleItems = false,
2147
2478
  refreshControl,
2148
- initialContainerPoolRatio = 2,
2479
+ refreshing,
2480
+ refScrollView,
2481
+ renderItem: renderItem2,
2482
+ snapToIndices,
2483
+ stickyIndices,
2484
+ style: styleProp,
2485
+ suggestEstimatedItemSize,
2149
2486
  viewabilityConfig,
2150
2487
  viewabilityConfigCallbackPairs,
2151
- snapToIndices,
2152
- onViewableItemsChanged,
2153
- onStartReached,
2154
- onEndReached,
2155
- onLoad,
2488
+ waitForInitialLayout = true,
2156
2489
  ...rest
2157
2490
  } = props;
2158
2491
  const [renderNum, setRenderNum] = useState(0);
@@ -2174,9 +2507,11 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2174
2507
  if (!refState.current) {
2175
2508
  const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { height: 0, width: 0 } : Dimensions.get("window"))[horizontal ? "width" : "height"];
2176
2509
  refState.current = {
2510
+ activeStickyIndex: void 0,
2177
2511
  averageSizes: {},
2178
2512
  columns: /* @__PURE__ */ new Map(),
2179
2513
  containerItemKeys: /* @__PURE__ */ new Set(),
2514
+ containerItemTypes: /* @__PURE__ */ new Map(),
2180
2515
  enableScrollForNextCalculateItemsInView: true,
2181
2516
  endBuffered: -1,
2182
2517
  endNoBuffer: -1,
@@ -2215,6 +2550,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2215
2550
  startBuffered: -1,
2216
2551
  startNoBuffer: -1,
2217
2552
  startReachedBlockedByTimer: false,
2553
+ stickyContainerPool: /* @__PURE__ */ new Set(),
2554
+ stickyContainers: /* @__PURE__ */ new Map(),
2218
2555
  timeoutSizeMessage: 0,
2219
2556
  timeouts: /* @__PURE__ */ new Set(),
2220
2557
  totalSize: 0,
@@ -2231,6 +2568,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2231
2568
  data: dataProp,
2232
2569
  estimatedItemSize,
2233
2570
  getEstimatedItemSize,
2571
+ getFixedItemSize,
2572
+ getItemType,
2234
2573
  horizontal: !!horizontal,
2235
2574
  initialContainerPoolRatio,
2236
2575
  initialScroll,
@@ -2246,9 +2585,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2246
2585
  onScroll: onScrollProp,
2247
2586
  onStartReached,
2248
2587
  onStartReachedThreshold,
2588
+ recycleItems: !!recycleItems,
2249
2589
  renderItem: renderItem2,
2250
2590
  scrollBuffer,
2251
2591
  snapToIndices,
2592
+ stickyIndicesArr: stickyIndices != null ? stickyIndices : [],
2593
+ stickyIndicesSet: useMemo(() => new Set(stickyIndices), [stickyIndices]),
2252
2594
  stylePaddingBottom: stylePaddingBottomState,
2253
2595
  stylePaddingTop: stylePaddingTopState,
2254
2596
  suggestEstimatedItemSize: !!suggestEstimatedItemSize
@@ -2486,6 +2828,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2486
2828
  }),
2487
2829
  []
2488
2830
  );
2831
+ const animatedScrollHandler = useMemo(() => {
2832
+ if (stickyIndices == null ? void 0 : stickyIndices.length) {
2833
+ const { animatedScrollY } = ctx;
2834
+ return Animated.event([{ nativeEvent: { contentOffset: { [horizontal ? "x" : "y"]: animatedScrollY } } }], {
2835
+ listener: fns.onScroll,
2836
+ useNativeDriver: true
2837
+ });
2838
+ }
2839
+ return fns.onScroll;
2840
+ }, [stickyIndices, horizontal, onScroll]);
2489
2841
  return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(
2490
2842
  ListComponent,
2491
2843
  {
@@ -2502,14 +2854,20 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2502
2854
  onLayout,
2503
2855
  onLayoutHeader,
2504
2856
  onMomentumScrollEnd: (event) => {
2505
- requestAnimationFrame(() => {
2506
- finishScrollTo(refState.current);
2507
- });
2857
+ if (IsNewArchitecture) {
2858
+ requestAnimationFrame(() => {
2859
+ finishScrollTo(refState.current);
2860
+ });
2861
+ } else {
2862
+ setTimeout(() => {
2863
+ finishScrollTo(refState.current);
2864
+ }, 1e3);
2865
+ }
2508
2866
  if (onMomentumScrollEnd) {
2509
2867
  onMomentumScrollEnd(event);
2510
2868
  }
2511
2869
  },
2512
- onScroll: fns.onScroll,
2870
+ onScroll: animatedScrollHandler,
2513
2871
  recycleItems,
2514
2872
  refreshControl: refreshControl ? stylePaddingTopState > 0 ? React3.cloneElement(refreshControl, {
2515
2873
  progressViewOffset: (refreshControl.props.progressViewOffset || 0) + stylePaddingTopState
@@ -2525,6 +2883,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2525
2883
  scrollAdjustHandler: (_a = refState.current) == null ? void 0 : _a.scrollAdjustHandler,
2526
2884
  scrollEventThrottle: Platform.OS === "web" ? 16 : void 0,
2527
2885
  snapToIndices,
2886
+ stickyIndices,
2528
2887
  style,
2529
2888
  updateItemSize: fns.updateItemSize,
2530
2889
  waitForInitialLayout