@legendapp/list 0.5.4 → 0.5.6

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.
Files changed (5) hide show
  1. package/index.d.mts +14 -10
  2. package/index.d.ts +14 -10
  3. package/index.js +163 -35
  4. package/index.mjs +163 -35
  5. package/package.json +1 -1
package/index.d.mts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { ComponentProps, ReactNode, ForwardedRef, ReactElement } from 'react';
2
2
  import { ScrollView, StyleProp, ViewStyle, ScrollViewComponent, ScrollResponderMixin } from 'react-native';
3
3
 
4
- type LegendListProps<T> = Omit<ComponentProps<typeof ScrollView>, 'contentOffset' | 'contentInset' | 'maintainVisibleContentPosition'> & {
5
- data: ArrayLike<any> & T[];
4
+ type LegendListProps<ItemT> = Omit<ComponentProps<typeof ScrollView>, 'contentOffset' | 'contentInset' | 'maintainVisibleContentPosition' | 'stickyHeaderIndices'> & {
5
+ data: ArrayLike<any> & ItemT[];
6
6
  initialScrollOffset?: number;
7
7
  initialScrollIndex?: number;
8
8
  drawDistance?: number;
@@ -14,16 +14,17 @@ type LegendListProps<T> = Omit<ComponentProps<typeof ScrollView>, 'contentOffset
14
14
  maintainScrollAtEndThreshold?: number;
15
15
  alignItemsAtEnd?: boolean;
16
16
  maintainVisibleContentPosition?: boolean;
17
- estimatedItemSize: number;
18
- getEstimatedItemSize?: (index: number, item: T) => number;
19
- onEndReached?: ((info: {
20
- distanceFromEnd: number;
21
- }) => void) | null | undefined;
17
+ numColumns?: number;
18
+ estimatedItemSize?: number;
19
+ getEstimatedItemSize?: (index: number, item: ItemT) => number;
22
20
  onStartReached?: ((info: {
23
21
  distanceFromStart: number;
24
22
  }) => void) | null | undefined;
25
- keyExtractor?: (item: T, index: number) => string;
26
- renderItem?: (props: LegendListRenderItemProps<T>) => ReactNode;
23
+ onEndReached?: ((info: {
24
+ distanceFromEnd: number;
25
+ }) => void) | null | undefined;
26
+ keyExtractor?: (item: ItemT, index: number) => string;
27
+ renderItem?: (props: LegendListRenderItemProps<ItemT>) => ReactNode;
27
28
  ListHeaderComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
28
29
  ListHeaderComponentStyle?: StyleProp<ViewStyle> | undefined;
29
30
  ListFooterComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
@@ -37,7 +38,9 @@ type LegendListProps<T> = Omit<ComponentProps<typeof ScrollView>, 'contentOffset
37
38
  };
38
39
  interface InternalState {
39
40
  positions: Map<string, number>;
41
+ columns: Map<string, number>;
40
42
  sizes: Map<string, number>;
43
+ sizesLaidOut: Map<string, number> | undefined;
41
44
  pendingAdjust: number;
42
45
  animFrameLayout: any;
43
46
  animFrameTotalSize: number | null;
@@ -61,6 +64,7 @@ interface InternalState {
61
64
  scrollAdjustPending: number;
62
65
  totalSize: number;
63
66
  timeouts: Set<number>;
67
+ timeoutSizeMessage: any;
64
68
  nativeMarginTop: number;
65
69
  indexByKey: Map<string, number>;
66
70
  contentSize: {
@@ -87,7 +91,7 @@ interface LegendListRenderItemProps<ItemT> {
87
91
  useViewability: (configId: string, callback: ViewabilityCallback) => void;
88
92
  useViewabilityAmount: (callback: ViewabilityAmountCallback) => void;
89
93
  useRecyclingEffect: (effect: (info: LegendListRecyclingState<ItemT>) => void | (() => void)) => void;
90
- useRecyclingState: <T>(updateState: (info: LegendListRecyclingState<ItemT>) => T) => [T, React.Dispatch<T>];
94
+ useRecyclingState: <T>(updateState: ((info: LegendListRecyclingState<ItemT>) => T) | T) => [T, React.Dispatch<T>];
91
95
  }
92
96
  type LegendListRef = {
93
97
  /**
package/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { ComponentProps, ReactNode, ForwardedRef, ReactElement } from 'react';
2
2
  import { ScrollView, StyleProp, ViewStyle, ScrollViewComponent, ScrollResponderMixin } from 'react-native';
3
3
 
4
- type LegendListProps<T> = Omit<ComponentProps<typeof ScrollView>, 'contentOffset' | 'contentInset' | 'maintainVisibleContentPosition'> & {
5
- data: ArrayLike<any> & T[];
4
+ type LegendListProps<ItemT> = Omit<ComponentProps<typeof ScrollView>, 'contentOffset' | 'contentInset' | 'maintainVisibleContentPosition' | 'stickyHeaderIndices'> & {
5
+ data: ArrayLike<any> & ItemT[];
6
6
  initialScrollOffset?: number;
7
7
  initialScrollIndex?: number;
8
8
  drawDistance?: number;
@@ -14,16 +14,17 @@ type LegendListProps<T> = Omit<ComponentProps<typeof ScrollView>, 'contentOffset
14
14
  maintainScrollAtEndThreshold?: number;
15
15
  alignItemsAtEnd?: boolean;
16
16
  maintainVisibleContentPosition?: boolean;
17
- estimatedItemSize: number;
18
- getEstimatedItemSize?: (index: number, item: T) => number;
19
- onEndReached?: ((info: {
20
- distanceFromEnd: number;
21
- }) => void) | null | undefined;
17
+ numColumns?: number;
18
+ estimatedItemSize?: number;
19
+ getEstimatedItemSize?: (index: number, item: ItemT) => number;
22
20
  onStartReached?: ((info: {
23
21
  distanceFromStart: number;
24
22
  }) => void) | null | undefined;
25
- keyExtractor?: (item: T, index: number) => string;
26
- renderItem?: (props: LegendListRenderItemProps<T>) => ReactNode;
23
+ onEndReached?: ((info: {
24
+ distanceFromEnd: number;
25
+ }) => void) | null | undefined;
26
+ keyExtractor?: (item: ItemT, index: number) => string;
27
+ renderItem?: (props: LegendListRenderItemProps<ItemT>) => ReactNode;
27
28
  ListHeaderComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
28
29
  ListHeaderComponentStyle?: StyleProp<ViewStyle> | undefined;
29
30
  ListFooterComponent?: React.ComponentType<any> | React.ReactElement | null | undefined;
@@ -37,7 +38,9 @@ type LegendListProps<T> = Omit<ComponentProps<typeof ScrollView>, 'contentOffset
37
38
  };
38
39
  interface InternalState {
39
40
  positions: Map<string, number>;
41
+ columns: Map<string, number>;
40
42
  sizes: Map<string, number>;
43
+ sizesLaidOut: Map<string, number> | undefined;
41
44
  pendingAdjust: number;
42
45
  animFrameLayout: any;
43
46
  animFrameTotalSize: number | null;
@@ -61,6 +64,7 @@ interface InternalState {
61
64
  scrollAdjustPending: number;
62
65
  totalSize: number;
63
66
  timeouts: Set<number>;
67
+ timeoutSizeMessage: any;
64
68
  nativeMarginTop: number;
65
69
  indexByKey: Map<string, number>;
66
70
  contentSize: {
@@ -87,7 +91,7 @@ interface LegendListRenderItemProps<ItemT> {
87
91
  useViewability: (configId: string, callback: ViewabilityCallback) => void;
88
92
  useViewabilityAmount: (callback: ViewabilityAmountCallback) => void;
89
93
  useRecyclingEffect: (effect: (info: LegendListRecyclingState<ItemT>) => void | (() => void)) => void;
90
- useRecyclingState: <T>(updateState: (info: LegendListRecyclingState<ItemT>) => T) => [T, React.Dispatch<T>];
94
+ useRecyclingState: <T>(updateState: ((info: LegendListRecyclingState<ItemT>) => T) | T) => [T, React.Dispatch<T>];
91
95
  }
92
96
  type LegendListRef = {
93
97
  /**
package/index.js CHANGED
@@ -100,11 +100,11 @@ var LeanView = React7__namespace.forwardRef((props, ref) => {
100
100
  LeanView.displayName = "RCTView";
101
101
 
102
102
  // src/$View.tsx
103
- function $View({ $key, $key2, $style, ...rest }) {
103
+ function $View({ $key, $key2, $key3, $key4, $style, ...rest }) {
104
104
  use$($key);
105
- if ($key2) {
106
- use$($key2);
107
- }
105
+ $key2 && use$($key2);
106
+ $key3 && use$($key3);
107
+ $key4 && use$($key4);
108
108
  const style = $style();
109
109
  return /* @__PURE__ */ React7__namespace.createElement(LeanView, { style, ...rest });
110
110
  }
@@ -128,17 +128,23 @@ var Container = ({
128
128
  const ctx = useStateContext();
129
129
  const createStyle = () => {
130
130
  const position = peek$(ctx, `containerPosition${id}`);
131
+ const column = peek$(ctx, `containerColumn${id}`) || 0;
131
132
  const visible = peek$(ctx, `containerDidLayout${id}`);
133
+ const numColumns = peek$(ctx, "numColumns");
134
+ const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
135
+ const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
132
136
  return horizontal ? {
133
137
  flexDirection: "row",
134
138
  position: "absolute",
135
- top: visible ? 0 : -1e7,
136
- bottom: 0,
139
+ top: visible ? otherAxisPos : -1e7,
140
+ bottom: numColumns > 1 ? null : 0,
141
+ height: otherAxisSize,
137
142
  left: position
138
143
  } : {
139
144
  position: "absolute",
140
- left: visible ? 0 : -1e7,
141
- right: 0,
145
+ left: visible ? otherAxisPos : -1e7,
146
+ right: numColumns > 1 ? null : 0,
147
+ width: otherAxisSize,
142
148
  top: position
143
149
  };
144
150
  };
@@ -147,6 +153,8 @@ var Container = ({
147
153
  {
148
154
  $key: `containerPosition${id}`,
149
155
  $key2: `containerDidLayout${id}`,
156
+ $key3: `containerColumn${id}`,
157
+ $key4: "numColumns",
150
158
  $style: createStyle,
151
159
  onLayout: (event) => {
152
160
  const key = peek$(ctx, `containerItemKey${id}`);
@@ -466,6 +474,7 @@ function maybeUpdateViewabilityCallback(ctx, configId, viewToken) {
466
474
  var DEFAULT_DRAW_DISTANCE = 250;
467
475
  var INITIAL_SCROLL_ADJUST = 1e4;
468
476
  var POSITION_OUT_OF_VIEW = -1e7;
477
+ var DEFAULT_ITEM_SIZE = 100;
469
478
  var LegendList = React7.forwardRef(function LegendList2(props, forwardedRef) {
470
479
  return /* @__PURE__ */ React7__namespace.createElement(StateProvider, null, /* @__PURE__ */ React7__namespace.createElement(LegendListInner, { ...props, ref: forwardedRef }));
471
480
  });
@@ -486,6 +495,8 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
486
495
  alignItemsAtEnd = false,
487
496
  maintainVisibleContentPosition = false,
488
497
  onScroll: onScrollProp,
498
+ numColumns: numColumnsProp = 1,
499
+ style: styleProp,
489
500
  keyExtractor,
490
501
  renderItem,
491
502
  estimatedItemSize,
@@ -495,7 +506,7 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
495
506
  ListEmptyComponent,
496
507
  ...rest
497
508
  } = props;
498
- const { style, contentContainerStyle } = rest;
509
+ const { contentContainerStyle } = props;
499
510
  const ctx = useStateContext();
500
511
  const internalRef = React7.useRef(null);
501
512
  const refScroller = internalRef;
@@ -511,11 +522,12 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
511
522
  return `${ret}`;
512
523
  };
513
524
  const getItemSize = (key, index, data2) => {
525
+ var _a2;
514
526
  const sizeKnown = refState.current.sizes.get(key);
515
527
  if (sizeKnown !== void 0) {
516
528
  return sizeKnown;
517
529
  }
518
- const size = getEstimatedItemSize ? getEstimatedItemSize(index, data2) : estimatedItemSize;
530
+ const size = (_a2 = getEstimatedItemSize ? getEstimatedItemSize(index, data2) : estimatedItemSize) != null ? _a2 : DEFAULT_ITEM_SIZE;
519
531
  refState.current.sizes.set(key, size);
520
532
  return size;
521
533
  };
@@ -538,6 +550,7 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
538
550
  refState.current = {
539
551
  sizes: /* @__PURE__ */ new Map(),
540
552
  positions: /* @__PURE__ */ new Map(),
553
+ columns: /* @__PURE__ */ new Map(),
541
554
  pendingAdjust: 0,
542
555
  animFrameLayout: null,
543
556
  animFrameTotalSize: null,
@@ -566,7 +579,9 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
566
579
  indexByKey: /* @__PURE__ */ new Map(),
567
580
  scrollHistory: [],
568
581
  scrollVelocity: 0,
569
- contentSize: { width: 0, height: 0 }
582
+ contentSize: { width: 0, height: 0 },
583
+ sizesLaidOut: __DEV__ ? /* @__PURE__ */ new Map() : void 0,
584
+ timeoutSizeMessage: 0
570
585
  };
571
586
  refState.current.idsInFirstRender = new Set(data.map((_, i) => getId(i)));
572
587
  set$(ctx, "scrollAdjust", refState.current.scrollAdjustPending);
@@ -576,12 +591,12 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
576
591
  refState.current.scrollAdjustPending -= diff;
577
592
  }
578
593
  };
579
- const addTotalSize = React7.useCallback((key, add, set) => {
594
+ const addTotalSize = React7.useCallback((key, add) => {
580
595
  const state = refState.current;
581
596
  const index = key === null ? 0 : state.indexByKey.get(key);
582
597
  const isAbove = key !== null && index < (state.startNoBuffer || 0);
583
598
  const prev = state.totalSize;
584
- if (set) {
599
+ if (key === null) {
585
600
  state.totalSize = add;
586
601
  } else {
587
602
  state.totalSize += add;
@@ -597,7 +612,7 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
597
612
  if (isAbove) {
598
613
  adjustScroll(add);
599
614
  }
600
- if (!prev || set) {
615
+ if (!prev || key === null) {
601
616
  doAdd();
602
617
  } else if (!state.animFrameTotalSize) {
603
618
  state.animFrameTotalSize = requestAnimationFrame(doAdd);
@@ -606,7 +621,15 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
606
621
  const calculateItemsInView = React7.useCallback((speed = 0) => {
607
622
  var _a2, _b2, _c2;
608
623
  const state = refState.current;
609
- const { data: data2, scrollLength, scroll: scrollState, startBuffered: startBufferedState, positions } = state;
624
+ const {
625
+ data: data2,
626
+ scrollLength,
627
+ scroll: scrollState,
628
+ startBuffered: startBufferedState,
629
+ positions,
630
+ sizes,
631
+ columns
632
+ } = state;
610
633
  if (state.animFrameLayout) {
611
634
  cancelAnimationFrame(state.animFrameLayout);
612
635
  state.animFrameLayout = null;
@@ -621,6 +644,7 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
621
644
  0,
622
645
  scrollState - topPad - (USE_CONTENT_INSET ? scrollAdjustPending : 0) + scrollExtra
623
646
  );
647
+ const scrollBottom = scroll + scrollLength;
624
648
  let startNoBuffer = null;
625
649
  let startBuffered = null;
626
650
  let endNoBuffer = null;
@@ -641,13 +665,24 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
641
665
  }
642
666
  }
643
667
  }
668
+ const numColumns = peek$(ctx, "numColumns");
669
+ const loopStartMod = loopStart % numColumns;
670
+ if (loopStartMod > 0) {
671
+ loopStart -= loopStartMod;
672
+ }
644
673
  let top = loopStart > 0 ? positions.get(getId(loopStart)) : 0;
674
+ let column = 1;
675
+ let maxSizeInRow = 0;
645
676
  for (let i = loopStart; i < data2.length; i++) {
646
677
  const id = getId(i);
647
678
  const size = getItemSize(id, i, data2[i]);
679
+ maxSizeInRow = Math.max(maxSizeInRow, size);
648
680
  if (positions.get(id) !== top) {
649
681
  positions.set(id, top);
650
682
  }
683
+ if (columns.get(id) !== column) {
684
+ columns.set(id, column);
685
+ }
651
686
  if (startNoBuffer === null && top + size > scroll) {
652
687
  startNoBuffer = i;
653
688
  }
@@ -655,16 +690,21 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
655
690
  startBuffered = i;
656
691
  }
657
692
  if (startNoBuffer !== null) {
658
- if (top <= scroll + scrollLength) {
693
+ if (top <= scrollBottom) {
659
694
  endNoBuffer = i;
660
695
  }
661
- if (top <= scroll + scrollLength + scrollBuffer) {
696
+ if (top <= scrollBottom + scrollBuffer) {
662
697
  endBuffered = i;
663
698
  } else {
664
699
  break;
665
700
  }
666
701
  }
667
- top += size;
702
+ column++;
703
+ if (column > numColumns) {
704
+ top += maxSizeInRow;
705
+ column = 1;
706
+ maxSizeInRow = 0;
707
+ }
668
708
  }
669
709
  Object.assign(refState.current, {
670
710
  startBuffered,
@@ -712,6 +752,7 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
712
752
  numContainers++;
713
753
  set$(ctx, `containerItemKey${containerId}`, id);
714
754
  set$(ctx, `containerPosition${containerId}`, POSITION_OUT_OF_VIEW);
755
+ set$(ctx, `containerColumn${containerId}`, -1);
715
756
  if (__DEV__ && numContainers > peek$(ctx, "numContainersPooled")) {
716
757
  console.warn(
717
758
  "[legend-list] No container to recycle, consider increasing initialContainers or estimatedItemSize. numContainers:",
@@ -733,12 +774,24 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
733
774
  const item = data2[itemIndex];
734
775
  if (item) {
735
776
  const id = getId(itemIndex);
736
- if (!(itemKey !== id || itemIndex < startBuffered || itemIndex > endBuffered)) {
777
+ if (itemKey !== id || itemIndex < startBuffered || itemIndex > endBuffered) {
778
+ const prevPos = peek$(ctx, `containerPosition${i}`) - scrollAdjustPending;
779
+ const pos = positions.get(id) || 0;
780
+ const size = sizes.get(id) || 0;
781
+ if (pos + size >= scroll && pos <= scrollBottom || prevPos + size >= scroll && prevPos <= scrollBottom) {
782
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
783
+ }
784
+ } else {
737
785
  const pos = (positions.get(id) || 0) + scrollAdjustPending;
786
+ const column2 = columns.get(id) || 1;
738
787
  const prevPos = peek$(ctx, `containerPosition${i}`);
788
+ const prevColumn = peek$(ctx, `containerColumn${i}`);
739
789
  if (pos >= 0 && pos !== prevPos) {
740
790
  set$(ctx, `containerPosition${i}`, pos);
741
791
  }
792
+ if (column2 >= 0 && column2 !== prevColumn) {
793
+ set$(ctx, `containerColumn${i}`, column2);
794
+ }
742
795
  }
743
796
  }
744
797
  }
@@ -755,6 +808,18 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
755
808
  );
756
809
  }
757
810
  }, []);
811
+ const style = React7.useMemo(() => {
812
+ const extraStyle = {};
813
+ if (data.length > 0) {
814
+ const size = getItemSize(getId(0), 0, data[0]);
815
+ if (horizontal) {
816
+ extraStyle.minHeight = size;
817
+ } else {
818
+ extraStyle.minWidth = size;
819
+ }
820
+ }
821
+ return reactNative.StyleSheet.compose(styleProp, extraStyle);
822
+ }, []);
758
823
  const doUpdatePaddingTop = () => {
759
824
  if (alignItemsAtEnd) {
760
825
  const { scrollLength, totalSize } = refState.current;
@@ -819,20 +884,33 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
819
884
  }
820
885
  };
821
886
  const isFirst = !refState.current.renderItem;
822
- if (isFirst || data !== refState.current.data) {
887
+ if (isFirst || data !== refState.current.data || numColumnsProp !== peek$(ctx, "numColumns")) {
888
+ if (!keyExtractor && !isFirst && data !== refState.current.data) {
889
+ refState.current.sizes.clear();
890
+ refState.current.positions.clear();
891
+ }
823
892
  refState.current.data = data;
824
893
  let totalSize = 0;
825
894
  const indexByKey = /* @__PURE__ */ new Map();
895
+ let column = 1;
896
+ let maxSizeInRow = 0;
826
897
  for (let i = 0; i < data.length; i++) {
827
898
  const key = getId(i);
828
899
  indexByKey.set(key, i);
829
- totalSize += getItemSize(key, i, data[i]);
900
+ const size = getItemSize(key, i, data[i]);
901
+ maxSizeInRow = Math.max(maxSizeInRow, size);
830
902
  if (maintainVisibleContentPosition && i < refState.current.startNoBuffer && !refState.current.indexByKey.has(key)) {
831
- const size = getItemSize(key, i, data[i]);
832
- adjustScroll(size);
903
+ const size2 = getItemSize(key, i, data[i]);
904
+ adjustScroll(size2);
905
+ }
906
+ column++;
907
+ if (column > numColumnsProp) {
908
+ totalSize += maxSizeInRow;
909
+ column = 1;
910
+ maxSizeInRow = 0;
833
911
  }
834
912
  }
835
- addTotalSize(null, totalSize, true);
913
+ addTotalSize(null, totalSize);
836
914
  if (maintainVisibleContentPosition) {
837
915
  for (const [key, index] of refState.current.indexByKey) {
838
916
  if (index < refState.current.startNoBuffer && !indexByKey.has(key)) {
@@ -850,6 +928,11 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
850
928
  for (let i = 0; i < numContainers; i++) {
851
929
  set$(ctx, `containerItemKey${i}`, void 0);
852
930
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
931
+ set$(ctx, `containerColumn${i}`, -1);
932
+ }
933
+ if (!keyExtractor) {
934
+ refState.current.sizes.clear();
935
+ refState.current.positions;
853
936
  }
854
937
  calculateItemsInView();
855
938
  doMaintainScrollAtEnd(false);
@@ -859,6 +942,7 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
859
942
  }
860
943
  refState.current.renderItem = renderItem;
861
944
  set$(ctx, "lastItemKey", getId(data[data.length - 1]));
945
+ set$(ctx, "numColumns", numColumnsProp);
862
946
  set$(
863
947
  ctx,
864
948
  "stylePaddingTop",
@@ -934,17 +1018,17 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
934
1018
  listen$(ctx, signal, run);
935
1019
  }, []);
936
1020
  };
937
- const useRecyclingState = (updateState) => {
1021
+ const useRecyclingState = (valueOrFun) => {
938
1022
  const stateInfo = React7.useState(
939
- () => updateState({
1023
+ () => typeof valueOrFun === "function" ? valueOrFun({
940
1024
  index,
941
1025
  item: refState.current.data[index],
942
1026
  prevIndex: void 0,
943
1027
  prevItem: void 0
944
- })
1028
+ }) : valueOrFun
945
1029
  );
946
1030
  useRecyclingEffect((state2) => {
947
- const newState = updateState(state2);
1031
+ const newState = typeof valueOrFun === "function" ? valueOrFun(state2) : valueOrFun;
948
1032
  stateInfo[1](newState);
949
1033
  });
950
1034
  return stateInfo;
@@ -960,12 +1044,14 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
960
1044
  return renderedItem;
961
1045
  }, []);
962
1046
  useInit(() => {
1047
+ var _a2;
963
1048
  refState.current.viewabilityConfigCallbackPairs = setupViewability(props);
964
1049
  const scrollLength = refState.current.scrollLength;
965
- const averageItemSize = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, data[0]);
966
- const numContainers = initialNumContainers || Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize);
1050
+ const averageItemSize = (_a2 = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, data[0])) != null ? _a2 : DEFAULT_ITEM_SIZE;
1051
+ const numContainers = (initialNumContainers || Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize)) * numColumnsProp;
967
1052
  for (let i = 0; i < numContainers; i++) {
968
1053
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1054
+ set$(ctx, `containerColumn${i}`, -1);
969
1055
  }
970
1056
  set$(ctx, "numContainers", numContainers);
971
1057
  set$(ctx, "numContainersPooled", numContainers * 2);
@@ -977,15 +1063,56 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
977
1063
  if (!data2) {
978
1064
  return;
979
1065
  }
980
- const { sizes, indexByKey, idsInFirstRender } = refState.current;
1066
+ const state = refState.current;
1067
+ const { sizes, indexByKey, idsInFirstRender, columns, sizesLaidOut } = state;
981
1068
  const index = indexByKey.get(key);
982
1069
  const wasInFirstRender = idsInFirstRender.has(key);
983
1070
  const prevSize = sizes.get(key) || (wasInFirstRender ? getItemSize(key, index, data2[index]) : 0);
984
1071
  if (!prevSize || Math.abs(prevSize - size) > 0.5) {
985
- sizes.set(key, size);
986
- addTotalSize(key, size - prevSize);
1072
+ let diff;
1073
+ const numColumns = peek$(ctx, "numColumns");
1074
+ if (numColumns > 1) {
1075
+ const column = columns.get(key);
1076
+ const loopStart = index - (column - 1);
1077
+ let prevMaxSizeInRow = 0;
1078
+ for (let i = loopStart; i < loopStart + numColumns; i++) {
1079
+ const id = getId(i);
1080
+ const size2 = getItemSize(id, i, data2[i]);
1081
+ prevMaxSizeInRow = Math.max(prevMaxSizeInRow, size2);
1082
+ }
1083
+ sizes.set(key, size);
1084
+ let nextMaxSizeInRow = 0;
1085
+ for (let i = loopStart; i < loopStart + numColumns; i++) {
1086
+ const id = getId(i);
1087
+ const size2 = getItemSize(id, i, data2[i]);
1088
+ nextMaxSizeInRow = Math.max(nextMaxSizeInRow, size2);
1089
+ }
1090
+ diff = nextMaxSizeInRow - prevMaxSizeInRow;
1091
+ } else {
1092
+ sizes.set(key, size);
1093
+ diff = size - prevSize;
1094
+ }
1095
+ if (__DEV__ && !estimatedItemSize && !getEstimatedItemSize) {
1096
+ sizesLaidOut.set(key, size);
1097
+ if (state.timeoutSizeMessage) {
1098
+ clearTimeout(state.timeoutSizeMessage);
1099
+ }
1100
+ state.timeoutSizeMessage = setTimeout(() => {
1101
+ state.timeoutSizeMessage = void 0;
1102
+ let total = 0;
1103
+ let num = 0;
1104
+ for (const [key2, size2] of sizesLaidOut) {
1105
+ num++;
1106
+ total += size2;
1107
+ }
1108
+ const avg = Math.round(total / num);
1109
+ console.warn(
1110
+ `[legend-list] estimatedItemSize or getEstimatedItemSize are not defined. Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
1111
+ );
1112
+ }, 1e3);
1113
+ }
1114
+ addTotalSize(key, diff);
987
1115
  doMaintainScrollAtEnd(true);
988
- const state = refState.current;
989
1116
  const scrollVelocity = state.scrollVelocity;
990
1117
  if (!state.animFrameLayout && (Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1)) {
991
1118
  state.animFrameLayout = requestAnimationFrame(() => {
@@ -1103,7 +1230,8 @@ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forward
1103
1230
  recycleItems,
1104
1231
  alignItemsAtEnd,
1105
1232
  addTotalSize,
1106
- ListEmptyComponent: data.length === 0 ? ListEmptyComponent : void 0
1233
+ ListEmptyComponent: data.length === 0 ? ListEmptyComponent : void 0,
1234
+ style
1107
1235
  }
1108
1236
  );
1109
1237
  });
package/index.mjs CHANGED
@@ -79,11 +79,11 @@ var LeanView = React7.forwardRef((props, ref) => {
79
79
  LeanView.displayName = "RCTView";
80
80
 
81
81
  // src/$View.tsx
82
- function $View({ $key, $key2, $style, ...rest }) {
82
+ function $View({ $key, $key2, $key3, $key4, $style, ...rest }) {
83
83
  use$($key);
84
- if ($key2) {
85
- use$($key2);
86
- }
84
+ $key2 && use$($key2);
85
+ $key3 && use$($key3);
86
+ $key4 && use$($key4);
87
87
  const style = $style();
88
88
  return /* @__PURE__ */ React7.createElement(LeanView, { style, ...rest });
89
89
  }
@@ -107,17 +107,23 @@ var Container = ({
107
107
  const ctx = useStateContext();
108
108
  const createStyle = () => {
109
109
  const position = peek$(ctx, `containerPosition${id}`);
110
+ const column = peek$(ctx, `containerColumn${id}`) || 0;
110
111
  const visible = peek$(ctx, `containerDidLayout${id}`);
112
+ const numColumns = peek$(ctx, "numColumns");
113
+ const otherAxisPos = numColumns > 1 ? `${(column - 1) / numColumns * 100}%` : 0;
114
+ const otherAxisSize = numColumns > 1 ? `${1 / numColumns * 100}%` : void 0;
111
115
  return horizontal ? {
112
116
  flexDirection: "row",
113
117
  position: "absolute",
114
- top: visible ? 0 : -1e7,
115
- bottom: 0,
118
+ top: visible ? otherAxisPos : -1e7,
119
+ bottom: numColumns > 1 ? null : 0,
120
+ height: otherAxisSize,
116
121
  left: position
117
122
  } : {
118
123
  position: "absolute",
119
- left: visible ? 0 : -1e7,
120
- right: 0,
124
+ left: visible ? otherAxisPos : -1e7,
125
+ right: numColumns > 1 ? null : 0,
126
+ width: otherAxisSize,
121
127
  top: position
122
128
  };
123
129
  };
@@ -126,6 +132,8 @@ var Container = ({
126
132
  {
127
133
  $key: `containerPosition${id}`,
128
134
  $key2: `containerDidLayout${id}`,
135
+ $key3: `containerColumn${id}`,
136
+ $key4: "numColumns",
129
137
  $style: createStyle,
130
138
  onLayout: (event) => {
131
139
  const key = peek$(ctx, `containerItemKey${id}`);
@@ -445,6 +453,7 @@ function maybeUpdateViewabilityCallback(ctx, configId, viewToken) {
445
453
  var DEFAULT_DRAW_DISTANCE = 250;
446
454
  var INITIAL_SCROLL_ADJUST = 1e4;
447
455
  var POSITION_OUT_OF_VIEW = -1e7;
456
+ var DEFAULT_ITEM_SIZE = 100;
448
457
  var LegendList = forwardRef(function LegendList2(props, forwardedRef) {
449
458
  return /* @__PURE__ */ React7.createElement(StateProvider, null, /* @__PURE__ */ React7.createElement(LegendListInner, { ...props, ref: forwardedRef }));
450
459
  });
@@ -465,6 +474,8 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
465
474
  alignItemsAtEnd = false,
466
475
  maintainVisibleContentPosition = false,
467
476
  onScroll: onScrollProp,
477
+ numColumns: numColumnsProp = 1,
478
+ style: styleProp,
468
479
  keyExtractor,
469
480
  renderItem,
470
481
  estimatedItemSize,
@@ -474,7 +485,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
474
485
  ListEmptyComponent,
475
486
  ...rest
476
487
  } = props;
477
- const { style, contentContainerStyle } = rest;
488
+ const { contentContainerStyle } = props;
478
489
  const ctx = useStateContext();
479
490
  const internalRef = useRef(null);
480
491
  const refScroller = internalRef;
@@ -490,11 +501,12 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
490
501
  return `${ret}`;
491
502
  };
492
503
  const getItemSize = (key, index, data2) => {
504
+ var _a2;
493
505
  const sizeKnown = refState.current.sizes.get(key);
494
506
  if (sizeKnown !== void 0) {
495
507
  return sizeKnown;
496
508
  }
497
- const size = getEstimatedItemSize ? getEstimatedItemSize(index, data2) : estimatedItemSize;
509
+ const size = (_a2 = getEstimatedItemSize ? getEstimatedItemSize(index, data2) : estimatedItemSize) != null ? _a2 : DEFAULT_ITEM_SIZE;
498
510
  refState.current.sizes.set(key, size);
499
511
  return size;
500
512
  };
@@ -517,6 +529,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
517
529
  refState.current = {
518
530
  sizes: /* @__PURE__ */ new Map(),
519
531
  positions: /* @__PURE__ */ new Map(),
532
+ columns: /* @__PURE__ */ new Map(),
520
533
  pendingAdjust: 0,
521
534
  animFrameLayout: null,
522
535
  animFrameTotalSize: null,
@@ -545,7 +558,9 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
545
558
  indexByKey: /* @__PURE__ */ new Map(),
546
559
  scrollHistory: [],
547
560
  scrollVelocity: 0,
548
- contentSize: { width: 0, height: 0 }
561
+ contentSize: { width: 0, height: 0 },
562
+ sizesLaidOut: __DEV__ ? /* @__PURE__ */ new Map() : void 0,
563
+ timeoutSizeMessage: 0
549
564
  };
550
565
  refState.current.idsInFirstRender = new Set(data.map((_, i) => getId(i)));
551
566
  set$(ctx, "scrollAdjust", refState.current.scrollAdjustPending);
@@ -555,12 +570,12 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
555
570
  refState.current.scrollAdjustPending -= diff;
556
571
  }
557
572
  };
558
- const addTotalSize = useCallback((key, add, set) => {
573
+ const addTotalSize = useCallback((key, add) => {
559
574
  const state = refState.current;
560
575
  const index = key === null ? 0 : state.indexByKey.get(key);
561
576
  const isAbove = key !== null && index < (state.startNoBuffer || 0);
562
577
  const prev = state.totalSize;
563
- if (set) {
578
+ if (key === null) {
564
579
  state.totalSize = add;
565
580
  } else {
566
581
  state.totalSize += add;
@@ -576,7 +591,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
576
591
  if (isAbove) {
577
592
  adjustScroll(add);
578
593
  }
579
- if (!prev || set) {
594
+ if (!prev || key === null) {
580
595
  doAdd();
581
596
  } else if (!state.animFrameTotalSize) {
582
597
  state.animFrameTotalSize = requestAnimationFrame(doAdd);
@@ -585,7 +600,15 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
585
600
  const calculateItemsInView = useCallback((speed = 0) => {
586
601
  var _a2, _b2, _c2;
587
602
  const state = refState.current;
588
- const { data: data2, scrollLength, scroll: scrollState, startBuffered: startBufferedState, positions } = state;
603
+ const {
604
+ data: data2,
605
+ scrollLength,
606
+ scroll: scrollState,
607
+ startBuffered: startBufferedState,
608
+ positions,
609
+ sizes,
610
+ columns
611
+ } = state;
589
612
  if (state.animFrameLayout) {
590
613
  cancelAnimationFrame(state.animFrameLayout);
591
614
  state.animFrameLayout = null;
@@ -600,6 +623,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
600
623
  0,
601
624
  scrollState - topPad - (USE_CONTENT_INSET ? scrollAdjustPending : 0) + scrollExtra
602
625
  );
626
+ const scrollBottom = scroll + scrollLength;
603
627
  let startNoBuffer = null;
604
628
  let startBuffered = null;
605
629
  let endNoBuffer = null;
@@ -620,13 +644,24 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
620
644
  }
621
645
  }
622
646
  }
647
+ const numColumns = peek$(ctx, "numColumns");
648
+ const loopStartMod = loopStart % numColumns;
649
+ if (loopStartMod > 0) {
650
+ loopStart -= loopStartMod;
651
+ }
623
652
  let top = loopStart > 0 ? positions.get(getId(loopStart)) : 0;
653
+ let column = 1;
654
+ let maxSizeInRow = 0;
624
655
  for (let i = loopStart; i < data2.length; i++) {
625
656
  const id = getId(i);
626
657
  const size = getItemSize(id, i, data2[i]);
658
+ maxSizeInRow = Math.max(maxSizeInRow, size);
627
659
  if (positions.get(id) !== top) {
628
660
  positions.set(id, top);
629
661
  }
662
+ if (columns.get(id) !== column) {
663
+ columns.set(id, column);
664
+ }
630
665
  if (startNoBuffer === null && top + size > scroll) {
631
666
  startNoBuffer = i;
632
667
  }
@@ -634,16 +669,21 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
634
669
  startBuffered = i;
635
670
  }
636
671
  if (startNoBuffer !== null) {
637
- if (top <= scroll + scrollLength) {
672
+ if (top <= scrollBottom) {
638
673
  endNoBuffer = i;
639
674
  }
640
- if (top <= scroll + scrollLength + scrollBuffer) {
675
+ if (top <= scrollBottom + scrollBuffer) {
641
676
  endBuffered = i;
642
677
  } else {
643
678
  break;
644
679
  }
645
680
  }
646
- top += size;
681
+ column++;
682
+ if (column > numColumns) {
683
+ top += maxSizeInRow;
684
+ column = 1;
685
+ maxSizeInRow = 0;
686
+ }
647
687
  }
648
688
  Object.assign(refState.current, {
649
689
  startBuffered,
@@ -691,6 +731,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
691
731
  numContainers++;
692
732
  set$(ctx, `containerItemKey${containerId}`, id);
693
733
  set$(ctx, `containerPosition${containerId}`, POSITION_OUT_OF_VIEW);
734
+ set$(ctx, `containerColumn${containerId}`, -1);
694
735
  if (__DEV__ && numContainers > peek$(ctx, "numContainersPooled")) {
695
736
  console.warn(
696
737
  "[legend-list] No container to recycle, consider increasing initialContainers or estimatedItemSize. numContainers:",
@@ -712,12 +753,24 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
712
753
  const item = data2[itemIndex];
713
754
  if (item) {
714
755
  const id = getId(itemIndex);
715
- if (!(itemKey !== id || itemIndex < startBuffered || itemIndex > endBuffered)) {
756
+ if (itemKey !== id || itemIndex < startBuffered || itemIndex > endBuffered) {
757
+ const prevPos = peek$(ctx, `containerPosition${i}`) - scrollAdjustPending;
758
+ const pos = positions.get(id) || 0;
759
+ const size = sizes.get(id) || 0;
760
+ if (pos + size >= scroll && pos <= scrollBottom || prevPos + size >= scroll && prevPos <= scrollBottom) {
761
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
762
+ }
763
+ } else {
716
764
  const pos = (positions.get(id) || 0) + scrollAdjustPending;
765
+ const column2 = columns.get(id) || 1;
717
766
  const prevPos = peek$(ctx, `containerPosition${i}`);
767
+ const prevColumn = peek$(ctx, `containerColumn${i}`);
718
768
  if (pos >= 0 && pos !== prevPos) {
719
769
  set$(ctx, `containerPosition${i}`, pos);
720
770
  }
771
+ if (column2 >= 0 && column2 !== prevColumn) {
772
+ set$(ctx, `containerColumn${i}`, column2);
773
+ }
721
774
  }
722
775
  }
723
776
  }
@@ -734,6 +787,18 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
734
787
  );
735
788
  }
736
789
  }, []);
790
+ const style = useMemo(() => {
791
+ const extraStyle = {};
792
+ if (data.length > 0) {
793
+ const size = getItemSize(getId(0), 0, data[0]);
794
+ if (horizontal) {
795
+ extraStyle.minHeight = size;
796
+ } else {
797
+ extraStyle.minWidth = size;
798
+ }
799
+ }
800
+ return StyleSheet.compose(styleProp, extraStyle);
801
+ }, []);
737
802
  const doUpdatePaddingTop = () => {
738
803
  if (alignItemsAtEnd) {
739
804
  const { scrollLength, totalSize } = refState.current;
@@ -798,20 +863,33 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
798
863
  }
799
864
  };
800
865
  const isFirst = !refState.current.renderItem;
801
- if (isFirst || data !== refState.current.data) {
866
+ if (isFirst || data !== refState.current.data || numColumnsProp !== peek$(ctx, "numColumns")) {
867
+ if (!keyExtractor && !isFirst && data !== refState.current.data) {
868
+ refState.current.sizes.clear();
869
+ refState.current.positions.clear();
870
+ }
802
871
  refState.current.data = data;
803
872
  let totalSize = 0;
804
873
  const indexByKey = /* @__PURE__ */ new Map();
874
+ let column = 1;
875
+ let maxSizeInRow = 0;
805
876
  for (let i = 0; i < data.length; i++) {
806
877
  const key = getId(i);
807
878
  indexByKey.set(key, i);
808
- totalSize += getItemSize(key, i, data[i]);
879
+ const size = getItemSize(key, i, data[i]);
880
+ maxSizeInRow = Math.max(maxSizeInRow, size);
809
881
  if (maintainVisibleContentPosition && i < refState.current.startNoBuffer && !refState.current.indexByKey.has(key)) {
810
- const size = getItemSize(key, i, data[i]);
811
- adjustScroll(size);
882
+ const size2 = getItemSize(key, i, data[i]);
883
+ adjustScroll(size2);
884
+ }
885
+ column++;
886
+ if (column > numColumnsProp) {
887
+ totalSize += maxSizeInRow;
888
+ column = 1;
889
+ maxSizeInRow = 0;
812
890
  }
813
891
  }
814
- addTotalSize(null, totalSize, true);
892
+ addTotalSize(null, totalSize);
815
893
  if (maintainVisibleContentPosition) {
816
894
  for (const [key, index] of refState.current.indexByKey) {
817
895
  if (index < refState.current.startNoBuffer && !indexByKey.has(key)) {
@@ -829,6 +907,11 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
829
907
  for (let i = 0; i < numContainers; i++) {
830
908
  set$(ctx, `containerItemKey${i}`, void 0);
831
909
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
910
+ set$(ctx, `containerColumn${i}`, -1);
911
+ }
912
+ if (!keyExtractor) {
913
+ refState.current.sizes.clear();
914
+ refState.current.positions;
832
915
  }
833
916
  calculateItemsInView();
834
917
  doMaintainScrollAtEnd(false);
@@ -838,6 +921,7 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
838
921
  }
839
922
  refState.current.renderItem = renderItem;
840
923
  set$(ctx, "lastItemKey", getId(data[data.length - 1]));
924
+ set$(ctx, "numColumns", numColumnsProp);
841
925
  set$(
842
926
  ctx,
843
927
  "stylePaddingTop",
@@ -913,17 +997,17 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
913
997
  listen$(ctx, signal, run);
914
998
  }, []);
915
999
  };
916
- const useRecyclingState = (updateState) => {
1000
+ const useRecyclingState = (valueOrFun) => {
917
1001
  const stateInfo = useState(
918
- () => updateState({
1002
+ () => typeof valueOrFun === "function" ? valueOrFun({
919
1003
  index,
920
1004
  item: refState.current.data[index],
921
1005
  prevIndex: void 0,
922
1006
  prevItem: void 0
923
- })
1007
+ }) : valueOrFun
924
1008
  );
925
1009
  useRecyclingEffect((state2) => {
926
- const newState = updateState(state2);
1010
+ const newState = typeof valueOrFun === "function" ? valueOrFun(state2) : valueOrFun;
927
1011
  stateInfo[1](newState);
928
1012
  });
929
1013
  return stateInfo;
@@ -939,12 +1023,14 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
939
1023
  return renderedItem;
940
1024
  }, []);
941
1025
  useInit(() => {
1026
+ var _a2;
942
1027
  refState.current.viewabilityConfigCallbackPairs = setupViewability(props);
943
1028
  const scrollLength = refState.current.scrollLength;
944
- const averageItemSize = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, data[0]);
945
- const numContainers = initialNumContainers || Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize);
1029
+ const averageItemSize = (_a2 = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, data[0])) != null ? _a2 : DEFAULT_ITEM_SIZE;
1030
+ const numContainers = (initialNumContainers || Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize)) * numColumnsProp;
946
1031
  for (let i = 0; i < numContainers; i++) {
947
1032
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
1033
+ set$(ctx, `containerColumn${i}`, -1);
948
1034
  }
949
1035
  set$(ctx, "numContainers", numContainers);
950
1036
  set$(ctx, "numContainersPooled", numContainers * 2);
@@ -956,15 +1042,56 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
956
1042
  if (!data2) {
957
1043
  return;
958
1044
  }
959
- const { sizes, indexByKey, idsInFirstRender } = refState.current;
1045
+ const state = refState.current;
1046
+ const { sizes, indexByKey, idsInFirstRender, columns, sizesLaidOut } = state;
960
1047
  const index = indexByKey.get(key);
961
1048
  const wasInFirstRender = idsInFirstRender.has(key);
962
1049
  const prevSize = sizes.get(key) || (wasInFirstRender ? getItemSize(key, index, data2[index]) : 0);
963
1050
  if (!prevSize || Math.abs(prevSize - size) > 0.5) {
964
- sizes.set(key, size);
965
- addTotalSize(key, size - prevSize);
1051
+ let diff;
1052
+ const numColumns = peek$(ctx, "numColumns");
1053
+ if (numColumns > 1) {
1054
+ const column = columns.get(key);
1055
+ const loopStart = index - (column - 1);
1056
+ let prevMaxSizeInRow = 0;
1057
+ for (let i = loopStart; i < loopStart + numColumns; i++) {
1058
+ const id = getId(i);
1059
+ const size2 = getItemSize(id, i, data2[i]);
1060
+ prevMaxSizeInRow = Math.max(prevMaxSizeInRow, size2);
1061
+ }
1062
+ sizes.set(key, size);
1063
+ let nextMaxSizeInRow = 0;
1064
+ for (let i = loopStart; i < loopStart + numColumns; i++) {
1065
+ const id = getId(i);
1066
+ const size2 = getItemSize(id, i, data2[i]);
1067
+ nextMaxSizeInRow = Math.max(nextMaxSizeInRow, size2);
1068
+ }
1069
+ diff = nextMaxSizeInRow - prevMaxSizeInRow;
1070
+ } else {
1071
+ sizes.set(key, size);
1072
+ diff = size - prevSize;
1073
+ }
1074
+ if (__DEV__ && !estimatedItemSize && !getEstimatedItemSize) {
1075
+ sizesLaidOut.set(key, size);
1076
+ if (state.timeoutSizeMessage) {
1077
+ clearTimeout(state.timeoutSizeMessage);
1078
+ }
1079
+ state.timeoutSizeMessage = setTimeout(() => {
1080
+ state.timeoutSizeMessage = void 0;
1081
+ let total = 0;
1082
+ let num = 0;
1083
+ for (const [key2, size2] of sizesLaidOut) {
1084
+ num++;
1085
+ total += size2;
1086
+ }
1087
+ const avg = Math.round(total / num);
1088
+ console.warn(
1089
+ `[legend-list] estimatedItemSize or getEstimatedItemSize are not defined. Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
1090
+ );
1091
+ }, 1e3);
1092
+ }
1093
+ addTotalSize(key, diff);
966
1094
  doMaintainScrollAtEnd(true);
967
- const state = refState.current;
968
1095
  const scrollVelocity = state.scrollVelocity;
969
1096
  if (!state.animFrameLayout && (Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1)) {
970
1097
  state.animFrameLayout = requestAnimationFrame(() => {
@@ -1082,7 +1209,8 @@ var LegendListInner = forwardRef(function LegendListInner2(props, forwardedRef)
1082
1209
  recycleItems,
1083
1210
  alignItemsAtEnd,
1084
1211
  addTotalSize,
1085
- ListEmptyComponent: data.length === 0 ? ListEmptyComponent : void 0
1212
+ ListEmptyComponent: data.length === 0 ? ListEmptyComponent : void 0,
1213
+ style
1086
1214
  }
1087
1215
  );
1088
1216
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "0.5.4",
3
+ "version": "0.5.6",
4
4
  "description": "legend-list",
5
5
  "sideEffects": false,
6
6
  "private": false,