@legendapp/list 3.0.0-beta.54 → 3.0.0-beta.55

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.native.mjs CHANGED
@@ -1,13 +1,118 @@
1
1
  import * as React2 from 'react';
2
2
  import React2__default, { useReducer, useEffect, createContext, useRef, useState, useMemo, useCallback, useLayoutEffect, useImperativeHandle, useContext } from 'react';
3
3
  import * as ReactNative from 'react-native';
4
- import { Animated, View as View$1, Text as Text$1, Platform as Platform$1, StyleSheet as StyleSheet$1, RefreshControl, Dimensions } from 'react-native';
4
+ import { Animated, Platform as Platform$1, View as View$1, Text as Text$1, StyleSheet as StyleSheet$1, RefreshControl, Dimensions, I18nManager } from 'react-native';
5
5
  import { useSyncExternalStore } from 'use-sync-external-store/shim';
6
6
 
7
7
  // src/components/LegendList.tsx
8
8
  Animated.View;
9
9
  var View = View$1;
10
10
  var Text = Text$1;
11
+ var Platform = Platform$1;
12
+ var PlatformAdjustBreaksScroll = Platform.OS === "android";
13
+
14
+ // src/utils/rtl.ts
15
+ function clampHorizontalOffset(offset, maxOffset) {
16
+ if (maxOffset === void 0) {
17
+ return offset;
18
+ }
19
+ return Math.max(0, Math.min(maxOffset, offset));
20
+ }
21
+ function getHorizontalMaxOffset(state, contentWidth) {
22
+ if (contentWidth === void 0 || !Number.isFinite(contentWidth) || !Number.isFinite(state.scrollLength) || contentWidth <= state.scrollLength) {
23
+ return contentWidth !== void 0 && Number.isFinite(contentWidth) && Number.isFinite(state.scrollLength) ? 0 : void 0;
24
+ }
25
+ return Math.max(0, contentWidth - state.scrollLength);
26
+ }
27
+ function getDefaultHorizontalRTLScrollType() {
28
+ return Platform.OS === "web" ? "normal" : "inverted";
29
+ }
30
+ function getNativeHorizontalRTLScrollType(state) {
31
+ var _a3;
32
+ return (_a3 = state == null ? void 0 : state.horizontalRTLScrollType) != null ? _a3 : getDefaultHorizontalRTLScrollType();
33
+ }
34
+ function isRTLProps(props) {
35
+ var _a3;
36
+ return (_a3 = props == null ? void 0 : props.rtl) != null ? _a3 : !!I18nManager.isRTL;
37
+ }
38
+ function isHorizontalRTL(state) {
39
+ return isHorizontalRTLProps(state == null ? void 0 : state.props);
40
+ }
41
+ function isHorizontalRTLProps(props) {
42
+ return !!(props == null ? void 0 : props.horizontal) && isRTLProps(props);
43
+ }
44
+ function getLogicalHorizontalMaxOffset(state, contentWidth) {
45
+ var _a3;
46
+ return (_a3 = getHorizontalMaxOffset(state, contentWidth)) != null ? _a3 : 0;
47
+ }
48
+ function getHorizontalInsetEnd(state, inset) {
49
+ if (!inset) {
50
+ return 0;
51
+ }
52
+ return (isHorizontalRTL(state) ? inset.left : inset.right) || 0;
53
+ }
54
+ function toPhysicalHorizontalItemPosition(state, logicalPosition, itemSize, listSize) {
55
+ if (!isHorizontalRTL(state) || listSize === void 0 || !Number.isFinite(listSize)) {
56
+ return logicalPosition;
57
+ }
58
+ return Math.max(0, listSize - logicalPosition - itemSize);
59
+ }
60
+ function toNativeHorizontalOffset(state, logicalOffset, contentWidth) {
61
+ if (!state || !isHorizontalRTL(state)) {
62
+ return logicalOffset;
63
+ }
64
+ const maxOffset = getHorizontalMaxOffset(state, contentWidth);
65
+ const clampedLogicalOffset = clampHorizontalOffset(logicalOffset, maxOffset);
66
+ const mode = getNativeHorizontalRTLScrollType(state);
67
+ if (mode === "negative") {
68
+ return clampedLogicalOffset === 0 ? 0 : -clampedLogicalOffset;
69
+ }
70
+ if (mode === "inverted") {
71
+ if (maxOffset === void 0) {
72
+ return clampedLogicalOffset;
73
+ }
74
+ return clampHorizontalOffset(maxOffset - clampedLogicalOffset, maxOffset);
75
+ }
76
+ return clampedLogicalOffset;
77
+ }
78
+ function toLogicalHorizontalOffset(state, rawOffset, contentWidth) {
79
+ if (!isHorizontalRTL(state)) {
80
+ state.horizontalRTLScrollType = void 0;
81
+ return rawOffset;
82
+ }
83
+ const maxOffset = getHorizontalMaxOffset(state, contentWidth);
84
+ if (rawOffset < 0) {
85
+ state.horizontalRTLScrollType = "negative";
86
+ return clampHorizontalOffset(-rawOffset, maxOffset);
87
+ }
88
+ if (maxOffset === void 0) {
89
+ return rawOffset;
90
+ }
91
+ const normalOffset = rawOffset;
92
+ const invertedOffset = maxOffset - rawOffset;
93
+ if (!Number.isFinite(invertedOffset)) {
94
+ state.horizontalRTLScrollType = "normal";
95
+ return normalOffset;
96
+ }
97
+ const previousMode = state.horizontalRTLScrollType;
98
+ if (previousMode === "inverted") {
99
+ return clampHorizontalOffset(invertedOffset, maxOffset);
100
+ }
101
+ if (previousMode === "normal") {
102
+ return clampHorizontalOffset(normalOffset, maxOffset);
103
+ }
104
+ if (!state.hasScrolled) {
105
+ const defaultMode = getDefaultHorizontalRTLScrollType();
106
+ state.horizontalRTLScrollType = defaultMode;
107
+ return clampHorizontalOffset(defaultMode === "inverted" ? invertedOffset : normalOffset, maxOffset);
108
+ }
109
+ const referenceScroll = state.scroll;
110
+ const distanceNormal = Math.abs(normalOffset - referenceScroll);
111
+ const distanceInverted = Math.abs(invertedOffset - referenceScroll);
112
+ const useInverted = distanceInverted + 0.5 < distanceNormal;
113
+ state.horizontalRTLScrollType = useInverted ? "inverted" : "normal";
114
+ return clampHorizontalOffset(useInverted ? invertedOffset : normalOffset, maxOffset);
115
+ }
11
116
  var createAnimatedValue = (value) => new Animated.Value(value);
12
117
 
13
118
  // src/state/state.tsx
@@ -149,7 +254,7 @@ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
149
254
  const horizontal = props.horizontal;
150
255
  const contentInset = props.contentInset;
151
256
  const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
152
- const baseEndInset = (horizontal ? baseInset == null ? void 0 : baseInset.right : baseInset == null ? void 0 : baseInset.bottom) || 0;
257
+ const baseEndInset = (horizontal ? getHorizontalInsetEnd(state, baseInset) : baseInset == null ? void 0 : baseInset.bottom) || 0;
153
258
  const contentInsetEndAdjustment = getContentInsetEndAdjustmentEnd(
154
259
  contentInsetEndAdjustmentOverride != null ? contentInsetEndAdjustmentOverride : props.contentInsetEndAdjustment
155
260
  );
@@ -158,9 +263,9 @@ function getContentInsetEnd(ctx, contentInsetEndAdjustmentOverride) {
158
263
  const overrideInset = (_b = state.contentInsetOverride) != null ? _b : void 0;
159
264
  const adjustedBaseEndInset = baseEndInset + contentInsetEndAdjustment;
160
265
  if (overrideInset) {
161
- const mergedInset = { bottom: 0, right: 0, ...baseInset, ...overrideInset };
266
+ const mergedInset = { bottom: 0, left: 0, right: 0, ...baseInset, ...overrideInset };
162
267
  return Math.max(
163
- ((horizontal ? mergedInset.right : mergedInset.bottom) || 0) + contentInsetEndAdjustment,
268
+ ((horizontal ? getHorizontalInsetEnd(state, mergedInset) : mergedInset.bottom) || 0) + contentInsetEndAdjustment,
164
269
  anchoredEndInset
165
270
  );
166
271
  }
@@ -440,7 +545,8 @@ function comparatorDefault(a, b) {
440
545
  }
441
546
  function getPadding(s, type) {
442
547
  var _a3, _b, _c;
443
- return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : s.paddingVertical) != null ? _b : s.padding) != null ? _c : 0;
548
+ const axisPadding = type === "Left" || type === "Right" ? s.paddingHorizontal : s.paddingVertical;
549
+ return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : axisPadding) != null ? _b : s.padding) != null ? _c : 0;
444
550
  }
445
551
  function extractPadding(style, contentContainerStyle, type) {
446
552
  return getPadding(style, type) + getPadding(contentContainerStyle, type);
@@ -647,8 +753,6 @@ function useOnLayoutSync({
647
753
  }
648
754
  return { onLayout };
649
755
  }
650
- var Platform = Platform$1;
651
- var PlatformAdjustBreaksScroll = Platform.OS === "android";
652
756
 
653
757
  // src/utils/isInMVCPActiveMode.native.ts
654
758
  function isInMVCPActiveMode(state) {
@@ -660,6 +764,7 @@ function getContainerPositionStyle({
660
764
  columnWrapperStyle,
661
765
  horizontal,
662
766
  hasItemSeparator,
767
+ isHorizontalRTLList,
663
768
  numColumns,
664
769
  otherAxisPos,
665
770
  otherAxisSize
@@ -683,6 +788,7 @@ function getContainerPositionStyle({
683
788
  }
684
789
  return horizontal ? {
685
790
  boxSizing: paddingStyles ? "border-box" : void 0,
791
+ direction: isHorizontalRTLList && Platform.OS === "web" ? "ltr" : void 0,
686
792
  flexDirection: hasItemSeparator ? "row" : void 0,
687
793
  height: otherAxisSize,
688
794
  left: 0,
@@ -711,6 +817,7 @@ var Container = typedMemo(function Container2({
711
817
  }) {
712
818
  const ctx = useStateContext();
713
819
  const { columnWrapperStyle, animatedScrollY } = ctx;
820
+ const isHorizontalRTLList = isHorizontalRTL(ctx.state);
714
821
  const positionComponentInternal = ctx.state.props.positionComponentInternal;
715
822
  const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
716
823
  const [column = 0, span = 1, data, numColumns = 1, extraData, isSticky] = useArr$([
@@ -742,11 +849,20 @@ var Container = typedMemo(function Container2({
742
849
  columnWrapperStyle,
743
850
  hasItemSeparator: !!ItemSeparatorComponent,
744
851
  horizontal,
852
+ isHorizontalRTLList,
745
853
  numColumns,
746
854
  otherAxisPos,
747
855
  otherAxisSize
748
856
  }),
749
- [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns, ItemSeparatorComponent]
857
+ [
858
+ horizontal,
859
+ isHorizontalRTLList,
860
+ otherAxisPos,
861
+ otherAxisSize,
862
+ columnWrapperStyle,
863
+ numColumns,
864
+ ItemSeparatorComponent
865
+ ]
750
866
  );
751
867
  const renderedItemInfo = useMemo(
752
868
  () => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
@@ -899,9 +1015,13 @@ var ContainersLayer = typedMemo(function ContainersLayer2({ children, horizontal
899
1015
  const ctx = useStateContext();
900
1016
  const columnWrapperStyle = ctx.columnWrapperStyle;
901
1017
  const animSize = useValue$("totalSize");
902
- const otherAxisSize = useValue$("otherAxisSize");
903
- const [readyToRender, numColumns] = useArr$(["readyToRender", "numColumns"]);
904
- const style = horizontal ? { minHeight: otherAxisSize, opacity: readyToRender ? 1 : 0, width: animSize } : { height: animSize, minWidth: otherAxisSize, opacity: readyToRender ? 1 : 0 };
1018
+ const [readyToRender, numColumns, otherAxisSize = 0] = useArr$(["readyToRender", "numColumns", "otherAxisSize"]);
1019
+ const style = horizontal ? {
1020
+ height: otherAxisSize || "100%",
1021
+ minHeight: otherAxisSize,
1022
+ opacity: readyToRender ? 1 : 0,
1023
+ width: animSize
1024
+ } : { height: animSize, minWidth: otherAxisSize, opacity: readyToRender ? 1 : 0 };
905
1025
  if (columnWrapperStyle) {
906
1026
  const { columnGap, rowGap, gap } = columnWrapperStyle;
907
1027
  const gapX = columnGap || gap || 0;
@@ -954,6 +1074,18 @@ var Containers = typedMemo(function Containers2({
954
1074
  return /* @__PURE__ */ React2.createElement(ContainersLayer, { horizontal }, containers);
955
1075
  });
956
1076
  var ListComponentScrollView = Animated.ScrollView;
1077
+
1078
+ // src/components/listComponentStyles.ts
1079
+ function getAutoOtherAxisStyle({
1080
+ horizontal,
1081
+ needsOtherAxisSize,
1082
+ otherAxisSize
1083
+ }) {
1084
+ if (!needsOtherAxisSize || !otherAxisSize || otherAxisSize <= 0) {
1085
+ return void 0;
1086
+ }
1087
+ return horizontal ? { height: otherAxisSize } : { width: otherAxisSize };
1088
+ }
957
1089
  function ScrollAdjust() {
958
1090
  var _a3;
959
1091
  const ctx = useStateContext();
@@ -974,10 +1106,10 @@ function ScrollAdjust() {
974
1106
  }
975
1107
  );
976
1108
  }
977
- function SnapWrapper({ ScrollComponent, ...props }) {
1109
+ var SnapWrapper = React2.forwardRef(function SnapWrapperInner({ ScrollComponent, ...props }, ref) {
978
1110
  const [snapToOffsets] = useArr$(["snapToOffsets"]);
979
- return /* @__PURE__ */ React2.createElement(ScrollComponent, { ...props, snapToOffsets });
980
- }
1111
+ return /* @__PURE__ */ React2.createElement(ScrollComponent, { ...props, ref, snapToOffsets });
1112
+ });
981
1113
  function WebAnchoredEndSpace({ horizontal }) {
982
1114
  const ctx = useStateContext();
983
1115
  const [anchoredEndSpaceSize] = useArr$(["anchoredEndSpaceSize"]);
@@ -1026,6 +1158,12 @@ var ListComponent = typedMemo(function ListComponent2({
1026
1158
  }) {
1027
1159
  const ctx = useStateContext();
1028
1160
  const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
1161
+ const [otherAxisSize = 0] = useArr$(["otherAxisSize"]);
1162
+ const autoOtherAxisStyle = getAutoOtherAxisStyle({
1163
+ horizontal,
1164
+ needsOtherAxisSize: ctx.state.needsOtherAxisSize,
1165
+ otherAxisSize
1166
+ });
1029
1167
  const ScrollComponent = useMemo(() => {
1030
1168
  if (!renderScrollComponent) {
1031
1169
  return ListComponentScrollView;
@@ -1064,10 +1202,10 @@ var ListComponent = typedMemo(function ListComponent2({
1064
1202
  ...rest,
1065
1203
  ...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
1066
1204
  contentContainerStyle: [
1067
- contentContainerStyle,
1068
1205
  horizontal ? {
1069
1206
  height: "100%"
1070
- } : {}
1207
+ } : {},
1208
+ contentContainerStyle
1071
1209
  ],
1072
1210
  contentOffset: initialContentOffset !== void 0 ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
1073
1211
  horizontal,
@@ -1076,7 +1214,7 @@ var ListComponent = typedMemo(function ListComponent2({
1076
1214
  onScroll: onScroll2,
1077
1215
  ref: refScrollView,
1078
1216
  ScrollComponent: snapToIndices ? ScrollComponent : void 0,
1079
- style
1217
+ style: autoOtherAxisStyle ? [autoOtherAxisStyle, style] : style
1080
1218
  },
1081
1219
  /* @__PURE__ */ React2.createElement(ScrollAdjust, null),
1082
1220
  ListHeaderComponent && /* @__PURE__ */ React2.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
@@ -1936,10 +2074,13 @@ function doScrollTo(ctx, params) {
1936
2074
  if (!scroller) {
1937
2075
  return;
1938
2076
  }
2077
+ const isHorizontal = !!horizontal;
2078
+ const contentSize = isHorizontal ? getContentSize(ctx) : void 0;
2079
+ const nativeOffset = toNativeHorizontalOffset(state, offset, contentSize);
1939
2080
  scroller.scrollTo({
1940
2081
  animated: isAnimated,
1941
- x: horizontal ? offset : 0,
1942
- y: horizontal ? 0 : offset
2082
+ x: isHorizontal ? nativeOffset : 0,
2083
+ y: isHorizontal ? 0 : offset
1943
2084
  });
1944
2085
  if (isInitialScroll) {
1945
2086
  initialScrollCompletion.markInitialScrollNativeDispatch(state);
@@ -2839,7 +2980,14 @@ function handleInitialScrollLayoutReady(ctx) {
2839
2980
  }
2840
2981
  function initializeInitialScrollOnMount(ctx, options) {
2841
2982
  var _a3, _b;
2842
- const { dataLength, hasFooterComponent, initialContentOffset, initialScrollAtEnd, useBootstrapInitialScroll } = options;
2983
+ const {
2984
+ alwaysDispatchInitialScroll,
2985
+ dataLength,
2986
+ hasFooterComponent,
2987
+ initialContentOffset,
2988
+ initialScrollAtEnd,
2989
+ useBootstrapInitialScroll
2990
+ } = options;
2843
2991
  const state = ctx.state;
2844
2992
  const initialScroll = state.initialScroll;
2845
2993
  const resolvedInitialContentOffset = initialContentOffset != null ? initialContentOffset : 0;
@@ -2859,7 +3007,7 @@ function initializeInitialScrollOnMount(ctx, options) {
2859
3007
  return;
2860
3008
  }
2861
3009
  const hasPendingDataDependentInitialScroll = !!initialScroll && dataLength === 0 && !(resolvedInitialContentOffset === 0 && !initialScrollAtEnd);
2862
- if (!resolvedInitialContentOffset && !hasPendingDataDependentInitialScroll) {
3010
+ if (!alwaysDispatchInitialScroll && !resolvedInitialContentOffset && !hasPendingDataDependentInitialScroll) {
2863
3011
  if (initialScroll && !initialScrollAtEnd) {
2864
3012
  finishInitialScroll(ctx, {
2865
3013
  resolvedOffset: resolvedInitialContentOffset
@@ -3190,9 +3338,18 @@ function prepareMVCP(ctx, dataChanged) {
3190
3338
  }
3191
3339
  }
3192
3340
 
3341
+ // src/core/resetLayoutCachesForDataChange.ts
3342
+ function resetLayoutCachesForDataChange(state) {
3343
+ state.indexByKey.clear();
3344
+ state.idCache.length = 0;
3345
+ state.positions.length = 0;
3346
+ state.columns.length = 0;
3347
+ state.columnSpans.length = 0;
3348
+ }
3349
+
3193
3350
  // src/core/syncMountedContainer.ts
3194
3351
  function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3195
- var _a3, _b, _c, _d, _e, _f, _g, _h;
3352
+ var _a3, _b, _c, _d, _e, _f, _g, _h, _i;
3196
3353
  const state = ctx.state;
3197
3354
  const {
3198
3355
  columns,
@@ -3204,7 +3361,8 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3204
3361
  if (item === void 0) {
3205
3362
  return { didChangePosition: false, didRefreshData: false };
3206
3363
  }
3207
- const updateLayout = (_a3 = options == null ? void 0 : options.updateLayout) != null ? _a3 : true;
3364
+ const itemKey = (_a3 = state.idCache[itemIndex]) != null ? _a3 : getId(state, itemIndex);
3365
+ const updateLayout = (_b = options == null ? void 0 : options.updateLayout) != null ? _b : true;
3208
3366
  let didChangePosition = false;
3209
3367
  let didRefreshData = false;
3210
3368
  if (updateLayout) {
@@ -3213,7 +3371,9 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3213
3371
  set$(ctx, `containerPosition${containerIndex}`, POSITION_OUT_OF_VIEW);
3214
3372
  return { didChangePosition: false, didRefreshData: false };
3215
3373
  }
3216
- const position = (positionValue || 0) - ((_b = options == null ? void 0 : options.scrollAdjustPending) != null ? _b : 0);
3374
+ const logicalPosition = (positionValue || 0) - ((_c = options == null ? void 0 : options.scrollAdjustPending) != null ? _c : 0);
3375
+ const itemSize = (_d = state.sizes.get(itemKey)) != null ? _d : getItemSize(ctx, itemKey, itemIndex, item);
3376
+ const position = toPhysicalHorizontalItemPosition(state, logicalPosition, itemSize, peek$(ctx, "totalSize"));
3217
3377
  const column = columns[itemIndex] || 1;
3218
3378
  const span = columnSpans[itemIndex] || 1;
3219
3379
  const prevPos = peek$(ctx, `containerPosition${containerIndex}`);
@@ -3232,15 +3392,15 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3232
3392
  }
3233
3393
  const prevData = peek$(ctx, `containerItemData${containerIndex}`);
3234
3394
  if (prevData !== item) {
3235
- const pendingDataComparison = ((_c = state.pendingDataComparison) == null ? void 0 : _c.previousData) === state.previousData && ((_d = state.pendingDataComparison) == null ? void 0 : _d.nextData) === data ? state.pendingDataComparison : void 0;
3236
- const cachedComparison = (_e = pendingDataComparison == null ? void 0 : pendingDataComparison.byIndex[itemIndex]) != null ? _e : 0;
3395
+ const pendingDataComparison = ((_e = state.pendingDataComparison) == null ? void 0 : _e.previousData) === state.previousData && ((_f = state.pendingDataComparison) == null ? void 0 : _f.nextData) === data ? state.pendingDataComparison : void 0;
3396
+ const cachedComparison = (_g = pendingDataComparison == null ? void 0 : pendingDataComparison.byIndex[itemIndex]) != null ? _g : 0;
3237
3397
  if (cachedComparison === 2) {
3238
3398
  set$(ctx, `containerItemData${containerIndex}`, item);
3239
3399
  didRefreshData = true;
3240
3400
  } else if (cachedComparison !== 1) {
3241
- const itemKey = (_g = (_f = peek$(ctx, `containerItemKey${containerIndex}`)) != null ? _f : state.idCache[itemIndex]) != null ? _g : getId(state, itemIndex);
3401
+ const nextItemKey = (_h = peek$(ctx, `containerItemKey${containerIndex}`)) != null ? _h : itemKey;
3242
3402
  const prevKey = keyExtractor == null ? void 0 : keyExtractor(prevData, itemIndex);
3243
- if (prevData === void 0 || !keyExtractor || prevKey !== itemKey) {
3403
+ if (prevData === void 0 || !keyExtractor || prevKey !== nextItemKey) {
3244
3404
  set$(ctx, `containerItemData${containerIndex}`, item);
3245
3405
  didRefreshData = true;
3246
3406
  } else if (!itemsAreEqual) {
@@ -3257,7 +3417,7 @@ function syncMountedContainer(ctx, containerIndex, itemIndex, options) {
3257
3417
  };
3258
3418
  }
3259
3419
  }
3260
- if ((_h = state.pendingDataComparison) == null ? void 0 : _h.byIndex) {
3420
+ if ((_i = state.pendingDataComparison) == null ? void 0 : _i.byIndex) {
3261
3421
  state.pendingDataComparison.byIndex[itemIndex] = isEqual ? 1 : 2;
3262
3422
  }
3263
3423
  if (!isEqual) {
@@ -3422,11 +3582,13 @@ function updateSnapToOffsets(ctx) {
3422
3582
  const {
3423
3583
  props: { snapToIndices }
3424
3584
  } = state;
3585
+ const contentSize = state.props.horizontal ? getContentSize(ctx) : void 0;
3425
3586
  const snapToOffsets = Array(snapToIndices.length);
3426
3587
  for (let i = 0; i < snapToIndices.length; i++) {
3427
3588
  const idx = snapToIndices[i];
3428
3589
  getId(state, idx);
3429
- snapToOffsets[i] = state.positions[idx];
3590
+ const logicalOffset = state.positions[idx];
3591
+ snapToOffsets[i] = toNativeHorizontalOffset(state, logicalOffset, contentSize);
3430
3592
  }
3431
3593
  set$(ctx, "snapToOffsets", snapToOffsets);
3432
3594
  }
@@ -4035,7 +4197,6 @@ function calculateItemsInView(ctx, params = {}) {
4035
4197
  var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
4036
4198
  const {
4037
4199
  columns,
4038
- columnSpans,
4039
4200
  containerItemKeys,
4040
4201
  enableScrollForNextCalculateItemsInView,
4041
4202
  idCache,
@@ -4085,8 +4246,10 @@ function calculateItemsInView(ctx, params = {}) {
4085
4246
  let scrollTopBuffered = 0;
4086
4247
  let scrollBottom = 0;
4087
4248
  let scrollBottomBuffered = 0;
4249
+ let nativeScrollState = scrollState;
4088
4250
  const updateScroll2 = (nextScrollState) => {
4089
4251
  var _a4;
4252
+ nativeScrollState = nextScrollState;
4090
4253
  scrollAdjustPending = (_a4 = peek$(ctx, "scrollAdjustPending")) != null ? _a4 : 0;
4091
4254
  scrollAdjustPad = scrollAdjustPending - topPad;
4092
4255
  scroll = Math.round(nextScrollState + scrollExtra + scrollAdjustPad);
@@ -4098,9 +4261,17 @@ function calculateItemsInView(ctx, params = {}) {
4098
4261
  const previousStickyIndex = peek$(ctx, "activeStickyIndex");
4099
4262
  const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
4100
4263
  const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
4264
+ const stickyIndexDidChange = previousStickyIndex !== nextActiveStickyIndex;
4101
4265
  if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
4102
4266
  set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
4103
4267
  }
4268
+ const shouldNotifyStickyHeaderChange = !!onStickyHeaderChange && stickyIndicesArr.length > 0 && stickyIndexDidChange;
4269
+ const finishCalculateItemsInView = shouldNotifyStickyHeaderChange ? () => {
4270
+ const item = data[nextActiveStickyIndex];
4271
+ if (item !== void 0) {
4272
+ onStickyHeaderChange == null ? void 0 : onStickyHeaderChange({ index: nextActiveStickyIndex, item });
4273
+ }
4274
+ } : void 0;
4104
4275
  let scrollBufferTop = drawDistance;
4105
4276
  let scrollBufferBottom = drawDistance;
4106
4277
  if (speed > 0 || speed === 0 && scroll < Math.max(50, drawDistance)) {
@@ -4111,8 +4282,10 @@ function calculateItemsInView(ctx, params = {}) {
4111
4282
  scrollBufferBottom = drawDistance * 0.5;
4112
4283
  }
4113
4284
  const updateScrollRange = () => {
4114
- scrollTopBuffered = scroll - scrollBufferTop;
4115
- scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
4285
+ const scrollStart = Math.max(0, scroll);
4286
+ const overscrollBeforeContent = Math.max(0, -nativeScrollState);
4287
+ scrollTopBuffered = scrollStart - scrollBufferTop;
4288
+ scrollBottom = Math.max(scrollStart, scroll + scrollLength + overscrollBeforeContent);
4116
4289
  scrollBottomBuffered = scrollBottom + scrollBufferBottom;
4117
4290
  };
4118
4291
  updateScrollRange();
@@ -4122,17 +4295,14 @@ function calculateItemsInView(ctx, params = {}) {
4122
4295
  state.scrollForNextCalculateItemsInView = void 0;
4123
4296
  } else if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
4124
4297
  if (Platform.OS !== "web" || !isInMVCPActiveMode(state)) {
4298
+ finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
4125
4299
  return;
4126
4300
  }
4127
4301
  }
4128
4302
  }
4129
4303
  const checkMVCP = doMVCP && !suppressInitialScrollSideEffects ? prepareMVCP(ctx, dataChanged) : void 0;
4130
4304
  if (dataChanged) {
4131
- indexByKey.clear();
4132
- idCache.length = 0;
4133
- positions.length = 0;
4134
- columns.length = 0;
4135
- columnSpans.length = 0;
4305
+ resetLayoutCachesForDataChange(state);
4136
4306
  }
4137
4307
  const startIndex = forceFullItemPositions || dataChanged ? 0 : (_c = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _c : 0;
4138
4308
  const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
@@ -4446,12 +4616,7 @@ function calculateItemsInView(ctx, params = {}) {
4446
4616
  );
4447
4617
  }
4448
4618
  }
4449
- if (onStickyHeaderChange && stickyIndicesArr.length > 0 && nextActiveStickyIndex !== void 0 && nextActiveStickyIndex !== previousStickyIndex) {
4450
- const item = data[nextActiveStickyIndex];
4451
- if (item !== void 0) {
4452
- onStickyHeaderChange({ index: nextActiveStickyIndex, item });
4453
- }
4454
- }
4619
+ finishCalculateItemsInView == null ? void 0 : finishCalculateItemsInView();
4455
4620
  });
4456
4621
  }
4457
4622
 
@@ -4479,11 +4644,22 @@ function doMaintainScrollAtEnd(ctx) {
4479
4644
  if (!state.maintainingScrollAtEnd) {
4480
4645
  state.maintainingScrollAtEnd = true;
4481
4646
  requestAnimationFrame(() => {
4482
- var _a3;
4483
4647
  if (peek$(ctx, "isWithinMaintainScrollAtEndThreshold")) {
4484
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
4485
- animated: maintainScrollAtEnd.animated
4486
- });
4648
+ const scroller = refScroller.current;
4649
+ if (state.props.horizontal && isHorizontalRTL(state)) {
4650
+ const currentContentSize = getContentSize(ctx);
4651
+ const logicalEndOffset = getLogicalHorizontalMaxOffset(state, currentContentSize);
4652
+ const nativeOffset = toNativeHorizontalOffset(state, logicalEndOffset, currentContentSize);
4653
+ scroller == null ? void 0 : scroller.scrollTo({
4654
+ animated: maintainScrollAtEnd.animated,
4655
+ x: nativeOffset,
4656
+ y: 0
4657
+ });
4658
+ } else {
4659
+ scroller == null ? void 0 : scroller.scrollToEnd({
4660
+ animated: maintainScrollAtEnd.animated
4661
+ });
4662
+ }
4487
4663
  setTimeout(
4488
4664
  () => {
4489
4665
  state.maintainingScrollAtEnd = false;
@@ -4679,7 +4855,8 @@ function handleLayout(ctx, layoutParam, setCanRender) {
4679
4855
  }
4680
4856
  checkThresholds(ctx);
4681
4857
  if (state) {
4682
- state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
4858
+ const crossAxisPadding = state.props.horizontal ? (state.props.stylePaddingTop || 0) + (state.props.stylePaddingBottom || 0) : (state.props.stylePaddingLeft || 0) + (state.props.stylePaddingRight || 0);
4859
+ state.needsOtherAxisSize = otherAxisSize - crossAxisPadding < 10;
4683
4860
  }
4684
4861
  if (IS_DEV && measuredLength === 0) {
4685
4862
  warnDevOnce(
@@ -4798,7 +4975,7 @@ function cloneScrollEvent(event) {
4798
4975
  };
4799
4976
  }
4800
4977
  function onScroll(ctx, event) {
4801
- var _a3, _b, _c, _d;
4978
+ var _a3, _b, _c, _d, _e;
4802
4979
  const state = ctx.state;
4803
4980
  const { scrollProcessingEnabled } = state;
4804
4981
  if (scrollProcessingEnabled === false) {
@@ -4817,6 +4994,9 @@ function onScroll(ctx, event) {
4817
4994
  }
4818
4995
  }
4819
4996
  let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
4997
+ if (state.props.horizontal) {
4998
+ newScroll = toLogicalHorizontalOffset(state, newScroll, (_e = event.nativeEvent.contentSize) == null ? void 0 : _e.width);
4999
+ }
4820
5000
  if (state.scrollingTo && state.scrollingTo.offset >= newScroll) {
4821
5001
  const maxOffset = clampScrollOffset(ctx, newScroll, state.scrollingTo);
4822
5002
  if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
@@ -4990,6 +5170,16 @@ function runOrScheduleMVCPRecalculate(ctx) {
4990
5170
  calculateItemsInView(ctx, { doMVCP: true });
4991
5171
  }
4992
5172
  }
5173
+ function updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal) {
5174
+ const state = ctx.state;
5175
+ if (state.needsOtherAxisSize) {
5176
+ const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
5177
+ const currentOtherAxisSize = peek$(ctx, "otherAxisSize");
5178
+ if (!currentOtherAxisSize || otherAxisSize > currentOtherAxisSize) {
5179
+ set$(ctx, "otherAxisSize", otherAxisSize);
5180
+ }
5181
+ }
5182
+ }
4993
5183
  function updateItemSize(ctx, itemKey, sizeObj) {
4994
5184
  var _a3;
4995
5185
  const state = ctx.state;
@@ -5013,13 +5203,13 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5013
5203
  const type = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
5014
5204
  const size2 = getFixedItemSize(itemData, index, type);
5015
5205
  if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
5206
+ updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
5016
5207
  return;
5017
5208
  }
5018
5209
  }
5019
5210
  let needsRecalculate = !didContainersLayout;
5020
5211
  let shouldMaintainScrollAtEnd = false;
5021
5212
  let minIndexSizeChanged;
5022
- let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
5023
5213
  const prevSizeKnown = state.sizesKnown.get(itemKey);
5024
5214
  const diff = updateOneItemSize(ctx, itemKey, sizeObj);
5025
5215
  const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
@@ -5030,10 +5220,6 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5030
5220
  if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
5031
5221
  needsRecalculate = true;
5032
5222
  }
5033
- if (state.needsOtherAxisSize) {
5034
- const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
5035
- maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
5036
- }
5037
5223
  if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
5038
5224
  shouldMaintainScrollAtEnd = true;
5039
5225
  }
@@ -5049,10 +5235,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
5049
5235
  if (minIndexSizeChanged !== void 0) {
5050
5236
  state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
5051
5237
  }
5052
- const cur = peek$(ctx, "otherAxisSize");
5053
- if (!cur || maxOtherAxisSize > cur) {
5054
- set$(ctx, "otherAxisSize", maxOtherAxisSize);
5055
- }
5238
+ updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal);
5056
5239
  if (didContainersLayout || checkAllSizesKnown(state, getMountedBufferedIndices(state))) {
5057
5240
  if (needsRecalculate) {
5058
5241
  state.scrollForNextCalculateItemsInView = void 0;
@@ -5640,7 +5823,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5640
5823
  getFixedItemSize,
5641
5824
  getItemType,
5642
5825
  horizontal,
5826
+ rtl,
5643
5827
  initialContainerPoolRatio = 3,
5828
+ estimatedHeaderSize,
5644
5829
  initialScrollAtEnd = false,
5645
5830
  initialScrollIndex: initialScrollIndexProp,
5646
5831
  initialScrollOffset: initialScrollOffsetProp,
@@ -5708,13 +5893,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5708
5893
  const style = { ...StyleSheet.flatten(styleProp) };
5709
5894
  const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
5710
5895
  const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
5896
+ const stylePaddingLeftState = extractPadding(style, contentContainerStyle, "Left");
5897
+ const stylePaddingRightState = extractPadding(style, contentContainerStyle, "Right");
5711
5898
  const maintainScrollAtEndConfig = normalizeMaintainScrollAtEnd(maintainScrollAtEnd);
5712
5899
  const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
5713
5900
  maintainVisibleContentPositionProp
5714
5901
  );
5715
5902
  const hasInitialScrollIndex = initialScrollIndexProp !== void 0 && initialScrollIndexProp !== null;
5716
5903
  const hasInitialScrollOffset = initialScrollOffsetProp !== void 0 && initialScrollOffsetProp !== null;
5717
- const initialScrollUsesOffsetOnly = !initialScrollAtEnd && !hasInitialScrollIndex && hasInitialScrollOffset;
5904
+ const shouldInitializeHorizontalRTL = !initialScrollAtEnd && !hasInitialScrollIndex && !hasInitialScrollOffset && isHorizontalRTLProps({ horizontal, rtl });
5905
+ const initialScrollUsesOffsetOnly = !initialScrollAtEnd && !hasInitialScrollIndex && (hasInitialScrollOffset || shouldInitializeHorizontalRTL);
5718
5906
  const usesBootstrapInitialScroll = initialScrollAtEnd || hasInitialScrollIndex;
5719
5907
  const initialScrollProp = initialScrollAtEnd ? {
5720
5908
  index: Math.max(0, dataProp.length - 1),
@@ -5830,6 +6018,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5830
6018
  internalState.reprocessCurrentScroll = () => updateScroll(ctx, internalState.scroll, true);
5831
6019
  set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPositionConfig);
5832
6020
  set$(ctx, "extraData", extraData);
6021
+ if (estimatedHeaderSize !== void 0) {
6022
+ set$(ctx, "headerSize", estimatedHeaderSize);
6023
+ }
5833
6024
  }
5834
6025
  refState.current = ctx.state;
5835
6026
  }
@@ -5889,11 +6080,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5889
6080
  positionComponentInternal,
5890
6081
  recycleItems: !!recycleItems,
5891
6082
  renderItem,
6083
+ rtl,
5892
6084
  snapToIndices,
5893
6085
  stickyIndicesArr: stickyHeaderIndices != null ? stickyHeaderIndices : [],
5894
6086
  stickyIndicesSet: useMemo(() => new Set(stickyHeaderIndices != null ? stickyHeaderIndices : []), [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(",")]),
5895
6087
  stickyPositionComponentInternal,
5896
6088
  stylePaddingBottom: stylePaddingBottomState,
6089
+ stylePaddingLeft: stylePaddingLeftState,
6090
+ stylePaddingRight: stylePaddingRightState,
5897
6091
  stylePaddingTop: stylePaddingTopState,
5898
6092
  useWindowScroll: useWindowScrollResolved
5899
6093
  };
@@ -5921,6 +6115,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5921
6115
  };
5922
6116
  if (isFirstLocal) {
5923
6117
  initializeStateVars(false);
6118
+ resetLayoutCachesForDataChange(state);
5924
6119
  updateItemPositions(
5925
6120
  ctx,
5926
6121
  /*dataChanged*/
@@ -5938,6 +6133,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
5938
6133
  }, [usesBootstrapInitialScroll]);
5939
6134
  useLayoutEffect(() => {
5940
6135
  initializeInitialScrollOnMount(ctx, {
6136
+ alwaysDispatchInitialScroll: shouldInitializeHorizontalRTL,
5941
6137
  dataLength: dataProp.length,
5942
6138
  hasFooterComponent: !!ListFooterComponent,
5943
6139
  initialContentOffset,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "3.0.0-beta.54",
3
+ "version": "3.0.0-beta.55",
4
4
  "description": "Legend List is a drop-in replacement for FlatList with much better performance and supporting dynamically sized items.",
5
5
  "sideEffects": false,
6
6
  "private": false,