@legendapp/list 2.0.2 → 2.0.4

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.d.mts CHANGED
@@ -345,11 +345,6 @@ interface InternalState {
345
345
  animated?: boolean;
346
346
  } | undefined;
347
347
  needsOtherAxisSize?: boolean;
348
- positionRange: {
349
- start: number;
350
- end: number;
351
- valid: boolean;
352
- };
353
348
  averageSizes: Record<string, {
354
349
  num: number;
355
350
  avg: number;
@@ -413,17 +408,18 @@ interface LegendListRenderItemProps<ItemT, TItemType extends string | number | u
413
408
  extraData: any;
414
409
  }
415
410
  type ScrollState = {
411
+ activeStickyIndex: number | undefined;
416
412
  contentLength: number;
417
413
  data: readonly any[];
418
414
  end: number;
419
415
  endBuffered: number;
420
416
  isAtEnd: boolean;
421
417
  isAtStart: boolean;
422
- positionAtIndex: (index: number) => number | undefined;
418
+ positionAtIndex: (index: number) => number;
423
419
  positions: Map<string, number>;
424
420
  scroll: number;
425
421
  scrollLength: number;
426
- sizeAtIndex: (index: number) => number | undefined;
422
+ sizeAtIndex: (index: number) => number;
427
423
  sizes: Map<string, number>;
428
424
  start: number;
429
425
  startBuffered: number;
package/index.d.ts CHANGED
@@ -345,11 +345,6 @@ interface InternalState {
345
345
  animated?: boolean;
346
346
  } | undefined;
347
347
  needsOtherAxisSize?: boolean;
348
- positionRange: {
349
- start: number;
350
- end: number;
351
- valid: boolean;
352
- };
353
348
  averageSizes: Record<string, {
354
349
  num: number;
355
350
  avg: number;
@@ -413,17 +408,18 @@ interface LegendListRenderItemProps<ItemT, TItemType extends string | number | u
413
408
  extraData: any;
414
409
  }
415
410
  type ScrollState = {
411
+ activeStickyIndex: number | undefined;
416
412
  contentLength: number;
417
413
  data: readonly any[];
418
414
  end: number;
419
415
  endBuffered: number;
420
416
  isAtEnd: boolean;
421
417
  isAtStart: boolean;
422
- positionAtIndex: (index: number) => number | undefined;
418
+ positionAtIndex: (index: number) => number;
423
419
  positions: Map<string, number>;
424
420
  scroll: number;
425
421
  scrollLength: number;
426
- sizeAtIndex: (index: number) => number | undefined;
422
+ sizeAtIndex: (index: number) => number;
427
423
  sizes: Map<string, number>;
428
424
  start: number;
429
425
  startBuffered: number;
package/index.js CHANGED
@@ -897,6 +897,23 @@ function getId(state, index) {
897
897
  return id;
898
898
  }
899
899
 
900
+ // src/core/calculateOffsetForIndex.ts
901
+ function calculateOffsetForIndex(ctx, state, index) {
902
+ let position = 0;
903
+ if (index !== void 0) {
904
+ position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
905
+ const paddingTop = peek$(ctx, "stylePaddingTop");
906
+ if (paddingTop) {
907
+ position += paddingTop;
908
+ }
909
+ const headerSize = peek$(ctx, "headerSize");
910
+ if (headerSize) {
911
+ position += headerSize;
912
+ }
913
+ }
914
+ return position;
915
+ }
916
+
900
917
  // src/utils/getItemSize.ts
901
918
  function getItemSize(state, key, index, data, useAverageSize) {
902
919
  var _a, _b;
@@ -938,280 +955,6 @@ function getItemSize(state, key, index, data, useAverageSize) {
938
955
  return size;
939
956
  }
940
957
 
941
- // src/utils/setPaddingTop.ts
942
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
943
- if (stylePaddingTop !== void 0) {
944
- const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
945
- if (stylePaddingTop < prevStylePaddingTop) {
946
- let prevTotalSize = peek$(ctx, "totalSize") || 0;
947
- set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
948
- state.timeoutSetPaddingTop = setTimeout(() => {
949
- prevTotalSize = peek$(ctx, "totalSize") || 0;
950
- set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
951
- }, 16);
952
- }
953
- set$(ctx, "stylePaddingTop", stylePaddingTop);
954
- }
955
- if (alignItemsPaddingTop !== void 0) {
956
- set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
957
- }
958
- }
959
-
960
- // src/utils/updateAlignItemsPaddingTop.ts
961
- function updateAlignItemsPaddingTop(ctx, state) {
962
- const {
963
- scrollLength,
964
- props: { alignItemsAtEnd, data }
965
- } = state;
966
- if (alignItemsAtEnd) {
967
- let alignItemsPaddingTop = 0;
968
- if ((data == null ? void 0 : data.length) > 0) {
969
- const contentSize = getContentSize(ctx);
970
- alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
971
- }
972
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
973
- }
974
- }
975
-
976
- // src/core/updateTotalSize.ts
977
- function updateTotalSize(ctx, state) {
978
- const {
979
- props: { data }
980
- } = state;
981
- if (data.length === 0) {
982
- addTotalSize(ctx, state, null, 0);
983
- } else {
984
- const lastIndex = data.length - 1;
985
- const lastId = getId(state, lastIndex);
986
- if (lastId !== void 0) {
987
- const lastPosition = getPositionByIndex(ctx, state, lastIndex);
988
- if (lastPosition !== void 0) {
989
- const lastSize = getItemSize(state, lastId, data.length - 1, data[data.length - 1]);
990
- if (lastSize !== void 0) {
991
- const totalSize = lastPosition + lastSize;
992
- addTotalSize(ctx, state, null, totalSize);
993
- }
994
- }
995
- }
996
- }
997
- }
998
- function addTotalSize(ctx, state, key, add) {
999
- const { alignItemsAtEnd } = state.props;
1000
- {
1001
- state.totalSize = add;
1002
- if (state.timeoutSetPaddingTop) {
1003
- clearTimeout(state.timeoutSetPaddingTop);
1004
- state.timeoutSetPaddingTop = void 0;
1005
- }
1006
- }
1007
- set$(ctx, "totalSize", state.totalSize);
1008
- if (alignItemsAtEnd) {
1009
- updateAlignItemsPaddingTop(ctx, state);
1010
- }
1011
- }
1012
-
1013
- // src/utils/updateSnapToOffsets.ts
1014
- function updateSnapToOffsets(ctx, state) {
1015
- const {
1016
- props: { snapToIndices }
1017
- } = state;
1018
- const snapToOffsets = Array(snapToIndices.length);
1019
- for (let i = 0; i < snapToIndices.length; i++) {
1020
- const idx = snapToIndices[i];
1021
- snapToOffsets[i] = getPositionByIndex(ctx, state, idx) || 0;
1022
- }
1023
- set$(ctx, "snapToOffsets", snapToOffsets);
1024
- }
1025
-
1026
- // src/core/updateItemPositions.ts
1027
- function getRequiredRange(_ctx, state) {
1028
- var _a;
1029
- const bufferSize = 10;
1030
- const dataLength = state.props.data.length;
1031
- let minIndex = 0;
1032
- let maxIndex = dataLength - 1;
1033
- if (dataLength < 500) {
1034
- return { end: maxIndex, start: 0 };
1035
- }
1036
- const hasVisibleRange = state.startBuffered >= 0 && state.endBuffered >= 0;
1037
- if (hasVisibleRange) {
1038
- minIndex = state.startBuffered;
1039
- maxIndex = state.endBuffered;
1040
- }
1041
- if (((_a = state.scrollingTo) == null ? void 0 : _a.index) !== void 0) {
1042
- if (hasVisibleRange) {
1043
- minIndex = Math.min(minIndex, state.scrollingTo.index);
1044
- maxIndex = Math.max(maxIndex, state.scrollingTo.index);
1045
- } else {
1046
- minIndex = state.scrollingTo.index;
1047
- maxIndex = state.scrollingTo.index;
1048
- }
1049
- }
1050
- minIndex = Math.max(0, minIndex - bufferSize);
1051
- maxIndex = Math.min(dataLength - 1, maxIndex + bufferSize);
1052
- return { end: maxIndex, start: minIndex };
1053
- }
1054
- function ensurePositionCalculated(ctx, state, index) {
1055
- if (!state.positionRange) {
1056
- state.positionRange = { end: -1, start: 0, valid: false };
1057
- }
1058
- if (state.positionRange.valid && index >= state.positionRange.start && index <= state.positionRange.end) {
1059
- return;
1060
- }
1061
- const newStart = state.positionRange.valid ? Math.min(state.positionRange.start, index) : 0;
1062
- const newEnd = Math.min(
1063
- state.props.data.length - 1,
1064
- Math.max(state.positionRange.valid ? state.positionRange.end : 0, index + 50)
1065
- );
1066
- updateItemPositions(ctx, state, false, newStart, newEnd);
1067
- }
1068
- function updateItemPositions(ctx, state, dataChanged, startIndex = 0, endIndex) {
1069
- var _a, _b, _c, _d, _e, _f, _g, _h;
1070
- const {
1071
- columns,
1072
- indexByKey,
1073
- positions,
1074
- idCache,
1075
- sizesKnown,
1076
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
1077
- } = state;
1078
- const data = state.props.data;
1079
- const numColumns = peek$(ctx, "numColumns");
1080
- const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
1081
- const useAverageSize = enableAverages && !getEstimatedItemSize;
1082
- let currentRowTop = 0;
1083
- let column = 1;
1084
- let maxSizeInRow = 0;
1085
- const hasColumns = numColumns > 1;
1086
- const dataLength = data.length;
1087
- const requiredRange = getRequiredRange(ctx, state);
1088
- const shouldOptimize = dataLength >= 500;
1089
- const optimizedEndIndex = shouldOptimize ? Math.min(dataLength - 1, requiredRange.end) : dataLength - 1;
1090
- const actualEndIndex = endIndex !== void 0 ? Math.min(endIndex, dataLength - 1) : optimizedEndIndex;
1091
- let adjustedStartIndex = startIndex;
1092
- let adjustedEndIndex = actualEndIndex;
1093
- if (((_a = state.positionRange) == null ? void 0 : _a.valid) && !dataChanged && shouldOptimize) {
1094
- const existingStart = state.positionRange.start;
1095
- const existingEnd = state.positionRange.end;
1096
- const requiredStart = requiredRange.start;
1097
- const requiredEnd = requiredRange.end;
1098
- if (requiredStart <= existingEnd + 1 && requiredEnd >= existingStart - 1) {
1099
- adjustedStartIndex = Math.min(startIndex, Math.min(existingStart, requiredStart));
1100
- adjustedEndIndex = Math.max(actualEndIndex, Math.max(existingEnd, requiredEnd));
1101
- } else if (requiredStart > existingEnd + 1) {
1102
- adjustedStartIndex = Math.min(startIndex, existingEnd + 1);
1103
- adjustedEndIndex = Math.max(actualEndIndex, requiredEnd);
1104
- } else if (requiredEnd < existingStart - 1) {
1105
- adjustedStartIndex = Math.min(startIndex, requiredStart);
1106
- adjustedEndIndex = Math.max(actualEndIndex, existingStart - 1);
1107
- }
1108
- }
1109
- if (adjustedStartIndex > 0) {
1110
- const prevIndex = adjustedStartIndex - 1;
1111
- const prevId = (_b = idCache.get(prevIndex)) != null ? _b : getId(state, prevIndex);
1112
- const prevPosition = (_c = positions.get(prevId)) != null ? _c : 0;
1113
- if (hasColumns) {
1114
- const prevColumn = (_d = columns.get(prevId)) != null ? _d : 1;
1115
- currentRowTop = prevPosition;
1116
- column = prevColumn % numColumns + 1;
1117
- } else {
1118
- const prevSize = (_e = sizesKnown.get(prevId)) != null ? _e : getItemSize(state, prevId, prevIndex, data[prevIndex], useAverageSize);
1119
- currentRowTop = prevPosition + prevSize;
1120
- }
1121
- }
1122
- const needsIndexByKey = dataChanged || indexByKey.size === 0;
1123
- let actualEndReached = adjustedStartIndex;
1124
- for (let i = adjustedStartIndex; i < dataLength; i++) {
1125
- const id = (_f = idCache.get(i)) != null ? _f : getId(state, i);
1126
- const size = (_g = sizesKnown.get(id)) != null ? _g : getItemSize(state, id, i, data[i], useAverageSize);
1127
- if (__DEV__ && needsIndexByKey) {
1128
- if (indexByKeyForChecking.has(id)) {
1129
- console.error(
1130
- `[legend-list] Error: Detected overlapping key (${id}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
1131
- );
1132
- }
1133
- indexByKeyForChecking.set(id, i);
1134
- }
1135
- positions.set(id, currentRowTop);
1136
- if (needsIndexByKey) {
1137
- indexByKey.set(id, i);
1138
- }
1139
- columns.set(id, column);
1140
- if (hasColumns) {
1141
- if (size > maxSizeInRow) {
1142
- maxSizeInRow = size;
1143
- }
1144
- column++;
1145
- if (column > numColumns) {
1146
- currentRowTop += maxSizeInRow;
1147
- column = 1;
1148
- maxSizeInRow = 0;
1149
- }
1150
- } else {
1151
- currentRowTop += size;
1152
- }
1153
- actualEndReached = i;
1154
- if (shouldOptimize && i >= adjustedEndIndex && (!((_h = state.scrollingTo) == null ? void 0 : _h.index) || i >= state.scrollingTo.index)) {
1155
- break;
1156
- }
1157
- }
1158
- if (!state.positionRange) {
1159
- state.positionRange = { end: -1, start: 0, valid: false };
1160
- }
1161
- if (dataChanged) {
1162
- state.positionRange = {
1163
- end: actualEndReached,
1164
- start: adjustedStartIndex,
1165
- valid: true
1166
- };
1167
- } else {
1168
- state.positionRange = {
1169
- end: Math.max(state.positionRange.valid ? state.positionRange.end : actualEndReached, actualEndReached),
1170
- start: Math.min(
1171
- state.positionRange.valid ? state.positionRange.start : adjustedStartIndex,
1172
- adjustedStartIndex
1173
- ),
1174
- valid: true
1175
- };
1176
- }
1177
- updateTotalSize(ctx, state);
1178
- if (snapToIndices) {
1179
- updateSnapToOffsets(ctx, state);
1180
- }
1181
- }
1182
-
1183
- // src/utils/getPosition.ts
1184
- function getPositionByIndex(ctx, state, index) {
1185
- ensurePositionCalculated(ctx, state, index);
1186
- const id = getId(state, index);
1187
- return id ? state.positions.get(id) : void 0;
1188
- }
1189
- function getPositionById(ctx, state, id) {
1190
- const index = state.indexByKey.get(id);
1191
- if (index === void 0) {
1192
- return state.positions.get(id);
1193
- }
1194
- ensurePositionCalculated(ctx, state, index);
1195
- return state.positions.get(id);
1196
- }
1197
-
1198
- // src/core/calculateOffsetForIndex.ts
1199
- function calculateOffsetForIndex(ctx, state, index) {
1200
- let position = 0;
1201
- if (index !== void 0) {
1202
- position = getPositionByIndex(ctx, state, index) || 0;
1203
- const paddingTop = peek$(ctx, "stylePaddingTop");
1204
- if (paddingTop) {
1205
- position += paddingTop;
1206
- }
1207
- const headerSize = peek$(ctx, "headerSize");
1208
- if (headerSize) {
1209
- position += headerSize;
1210
- }
1211
- }
1212
- return position;
1213
- }
1214
-
1215
958
  // src/core/calculateOffsetWithOffsetPosition.ts
1216
959
  function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
1217
960
  const { index, viewOffset, viewPosition } = params;
@@ -1305,6 +1048,7 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1305
1048
  function prepareMVCP(ctx, state, dataChanged) {
1306
1049
  const {
1307
1050
  idsInView,
1051
+ positions,
1308
1052
  scrollingTo,
1309
1053
  props: { maintainVisibleContentPosition }
1310
1054
  } = state;
@@ -1322,10 +1066,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1322
1066
  const id = idsInView[i];
1323
1067
  const index = indexByKey.get(id);
1324
1068
  if (index !== void 0) {
1325
- const position = getPositionById(ctx, state, id);
1326
- if (position !== void 0) {
1327
- idsInViewWithPositions.push({ id, position });
1328
- }
1069
+ idsInViewWithPositions.push({ id, position: positions.get(id) });
1329
1070
  }
1330
1071
  }
1331
1072
  } else {
@@ -1333,10 +1074,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1333
1074
  }
1334
1075
  }
1335
1076
  if (targetId !== void 0) {
1336
- const pos = getPositionById(ctx, state, targetId);
1337
- if (pos !== void 0) {
1338
- prevPosition = pos;
1339
- }
1077
+ prevPosition = positions.get(targetId);
1340
1078
  }
1341
1079
  }
1342
1080
  return () => {
@@ -1344,7 +1082,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1344
1082
  if (dataChanged && targetId === void 0) {
1345
1083
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1346
1084
  const { id, position } = idsInViewWithPositions[i];
1347
- const newPosition = getPositionById(ctx, state, id);
1085
+ const newPosition = positions.get(id);
1348
1086
  if (newPosition !== void 0) {
1349
1087
  positionDiff = newPosition - position;
1350
1088
  break;
@@ -1352,7 +1090,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1352
1090
  }
1353
1091
  }
1354
1092
  if (targetId !== void 0 && prevPosition !== void 0) {
1355
- const newPosition = getPositionById(ctx, state, targetId);
1093
+ const newPosition = positions.get(targetId);
1356
1094
  if (newPosition !== void 0) {
1357
1095
  positionDiff = newPosition - prevPosition;
1358
1096
  }
@@ -1363,6 +1101,163 @@ function prepareMVCP(ctx, state, dataChanged) {
1363
1101
  };
1364
1102
  }
1365
1103
 
1104
+ // src/utils/setPaddingTop.ts
1105
+ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1106
+ if (stylePaddingTop !== void 0) {
1107
+ const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1108
+ if (stylePaddingTop < prevStylePaddingTop) {
1109
+ let prevTotalSize = peek$(ctx, "totalSize") || 0;
1110
+ set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1111
+ state.timeoutSetPaddingTop = setTimeout(() => {
1112
+ prevTotalSize = peek$(ctx, "totalSize") || 0;
1113
+ set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
1114
+ }, 16);
1115
+ }
1116
+ set$(ctx, "stylePaddingTop", stylePaddingTop);
1117
+ }
1118
+ if (alignItemsPaddingTop !== void 0) {
1119
+ set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1120
+ }
1121
+ }
1122
+
1123
+ // src/utils/updateAlignItemsPaddingTop.ts
1124
+ function updateAlignItemsPaddingTop(ctx, state) {
1125
+ const {
1126
+ scrollLength,
1127
+ props: { alignItemsAtEnd, data }
1128
+ } = state;
1129
+ if (alignItemsAtEnd) {
1130
+ let alignItemsPaddingTop = 0;
1131
+ if ((data == null ? void 0 : data.length) > 0) {
1132
+ const contentSize = getContentSize(ctx);
1133
+ alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1134
+ }
1135
+ setPaddingTop(ctx, state, { alignItemsPaddingTop });
1136
+ }
1137
+ }
1138
+
1139
+ // src/core/updateTotalSize.ts
1140
+ function updateTotalSize(ctx, state) {
1141
+ const {
1142
+ positions,
1143
+ props: { data }
1144
+ } = state;
1145
+ if (data.length === 0) {
1146
+ addTotalSize(ctx, state, null, 0);
1147
+ } else {
1148
+ const lastId = getId(state, data.length - 1);
1149
+ if (lastId !== void 0) {
1150
+ const lastPosition = positions.get(lastId);
1151
+ if (lastPosition !== void 0) {
1152
+ const lastSize = getItemSize(state, lastId, data.length - 1, data[data.length - 1]);
1153
+ if (lastSize !== void 0) {
1154
+ const totalSize = lastPosition + lastSize;
1155
+ addTotalSize(ctx, state, null, totalSize);
1156
+ }
1157
+ }
1158
+ }
1159
+ }
1160
+ }
1161
+ function addTotalSize(ctx, state, key, add) {
1162
+ const { alignItemsAtEnd } = state.props;
1163
+ {
1164
+ state.totalSize = add;
1165
+ if (state.timeoutSetPaddingTop) {
1166
+ clearTimeout(state.timeoutSetPaddingTop);
1167
+ state.timeoutSetPaddingTop = void 0;
1168
+ }
1169
+ }
1170
+ set$(ctx, "totalSize", state.totalSize);
1171
+ if (alignItemsAtEnd) {
1172
+ updateAlignItemsPaddingTop(ctx, state);
1173
+ }
1174
+ }
1175
+
1176
+ // src/utils/updateSnapToOffsets.ts
1177
+ function updateSnapToOffsets(ctx, state) {
1178
+ const {
1179
+ positions,
1180
+ props: { snapToIndices }
1181
+ } = state;
1182
+ const snapToOffsets = Array(snapToIndices.length);
1183
+ for (let i = 0; i < snapToIndices.length; i++) {
1184
+ const idx = snapToIndices[i];
1185
+ const key = getId(state, idx);
1186
+ snapToOffsets[i] = positions.get(key);
1187
+ }
1188
+ set$(ctx, "snapToOffsets", snapToOffsets);
1189
+ }
1190
+
1191
+ // src/core/updateAllPositions.ts
1192
+ function updateAllPositions(ctx, state, dataChanged, startIndex = 0) {
1193
+ var _a, _b, _c, _d, _e, _f;
1194
+ const {
1195
+ columns,
1196
+ indexByKey,
1197
+ positions,
1198
+ idCache,
1199
+ sizesKnown,
1200
+ props: { getEstimatedItemSize, snapToIndices, enableAverages }
1201
+ } = state;
1202
+ const data = state.props.data;
1203
+ const numColumns = peek$(ctx, "numColumns");
1204
+ const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
1205
+ const useAverageSize = enableAverages && !getEstimatedItemSize;
1206
+ let currentRowTop = 0;
1207
+ let column = 1;
1208
+ let maxSizeInRow = 0;
1209
+ const hasColumns = numColumns > 1;
1210
+ if (startIndex > 0) {
1211
+ const prevIndex = startIndex - 1;
1212
+ const prevId = (_a = idCache.get(prevIndex)) != null ? _a : getId(state, prevIndex);
1213
+ const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1214
+ if (hasColumns) {
1215
+ const prevColumn = (_c = columns.get(prevId)) != null ? _c : 1;
1216
+ currentRowTop = prevPosition;
1217
+ column = prevColumn % numColumns + 1;
1218
+ } else {
1219
+ const prevSize = (_d = sizesKnown.get(prevId)) != null ? _d : getItemSize(state, prevId, prevIndex, data[prevIndex], useAverageSize);
1220
+ currentRowTop = prevPosition + prevSize;
1221
+ }
1222
+ }
1223
+ const needsIndexByKey = dataChanged || indexByKey.size === 0;
1224
+ const dataLength = data.length;
1225
+ for (let i = startIndex; i < dataLength; i++) {
1226
+ const id = (_e = idCache.get(i)) != null ? _e : getId(state, i);
1227
+ const size = (_f = sizesKnown.get(id)) != null ? _f : getItemSize(state, id, i, data[i], useAverageSize);
1228
+ if (__DEV__ && needsIndexByKey) {
1229
+ if (indexByKeyForChecking.has(id)) {
1230
+ console.error(
1231
+ `[legend-list] Error: Detected overlapping key (${id}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
1232
+ );
1233
+ }
1234
+ indexByKeyForChecking.set(id, i);
1235
+ }
1236
+ positions.set(id, currentRowTop);
1237
+ if (needsIndexByKey) {
1238
+ indexByKey.set(id, i);
1239
+ }
1240
+ columns.set(id, column);
1241
+ if (hasColumns) {
1242
+ if (size > maxSizeInRow) {
1243
+ maxSizeInRow = size;
1244
+ }
1245
+ column++;
1246
+ if (column > numColumns) {
1247
+ currentRowTop += maxSizeInRow;
1248
+ column = 1;
1249
+ maxSizeInRow = 0;
1250
+ }
1251
+ } else {
1252
+ currentRowTop += size;
1253
+ }
1254
+ }
1255
+ updateTotalSize(ctx, state);
1256
+ if (snapToIndices) {
1257
+ updateSnapToOffsets(ctx, state);
1258
+ }
1259
+ }
1260
+
1366
1261
  // src/core/viewability.ts
1367
1262
  function ensureViewabilityState(ctx, configId) {
1368
1263
  let map = ctx.mapViewabilityConfigStates;
@@ -1864,6 +1759,7 @@ function handleStickyActivation(ctx, state, stickyIndices, stickyArray, scroll,
1864
1759
  var _a;
1865
1760
  const activeIndices = getActiveStickyIndices(ctx, state, stickyIndices);
1866
1761
  const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
1762
+ state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
1867
1763
  for (let offset = 0; offset <= 1; offset++) {
1868
1764
  const idx = currentStickyIdx - offset;
1869
1765
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
@@ -1943,7 +1839,7 @@ function calculateItemsInView(ctx, state, params = {}) {
1943
1839
  positions.clear();
1944
1840
  }
1945
1841
  const startIndex = dataChanged ? 0 : minIndexSizeChanged != null ? minIndexSizeChanged : 0;
1946
- updateItemPositions(ctx, state, dataChanged, startIndex);
1842
+ updateAllPositions(ctx, state, dataChanged, startIndex);
1947
1843
  if (minIndexSizeChanged !== void 0) {
1948
1844
  state.minIndexSizeChanged = void 0;
1949
1845
  }
@@ -1995,8 +1891,7 @@ function calculateItemsInView(ctx, state, params = {}) {
1995
1891
  let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
1996
1892
  for (let i = loopStart; i >= 0; i--) {
1997
1893
  const id = (_a = idCache.get(i)) != null ? _a : getId(state, i);
1998
- const top = getPositionById(ctx, state, id);
1999
- if (top === void 0) break;
1894
+ const top = positions.get(id);
2000
1895
  const size = (_b = sizes.get(id)) != null ? _b : getItemSize(state, id, i, data[i]);
2001
1896
  const bottom = top + size;
2002
1897
  if (bottom > scroll - scrollBuffer) {
@@ -2025,7 +1920,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2025
1920
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2026
1921
  const id = (_c = idCache.get(i)) != null ? _c : getId(state, i);
2027
1922
  const size = (_d = sizes.get(id)) != null ? _d : getItemSize(state, id, i, data[i]);
2028
- const top = getPositionById(ctx, state, id);
1923
+ const top = positions.get(id);
2029
1924
  if (!foundEnd) {
2030
1925
  if (startNoBuffer === null && top + size > scroll) {
2031
1926
  startNoBuffer = i;
@@ -2101,6 +1996,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2101
1996
  startBuffered,
2102
1997
  endBuffered
2103
1998
  );
1999
+ } else {
2000
+ state.activeStickyIndex = void 0;
2104
2001
  }
2105
2002
  if (needNewContainers.length > 0) {
2106
2003
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
@@ -2176,7 +2073,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2176
2073
  const item = data[itemIndex];
2177
2074
  if (item !== void 0) {
2178
2075
  const id = (_h = idCache.get(itemIndex)) != null ? _h : getId(state, itemIndex);
2179
- const position = getPositionById(ctx, state, id);
2076
+ const position = positions.get(id);
2180
2077
  if (position === void 0) {
2181
2078
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2182
2079
  } else {
@@ -2392,6 +2289,8 @@ function updateScroll(ctx, state, newScroll) {
2392
2289
  if (state.scrollHistory.length > 5) {
2393
2290
  state.scrollHistory.shift();
2394
2291
  }
2292
+ state.scrollPrev = state.scroll;
2293
+ state.scrollPrevTime = state.scrollTime;
2395
2294
  state.scroll = newScroll;
2396
2295
  state.scrollTime = currentTime;
2397
2296
  if (Math.abs(state.scroll - state.scrollPrev) > 2) {
@@ -2399,8 +2298,6 @@ function updateScroll(ctx, state, newScroll) {
2399
2298
  checkAtBottom(ctx, state);
2400
2299
  checkAtTop(state);
2401
2300
  }
2402
- state.scrollPrev = state.scroll;
2403
- state.scrollPrevTime = state.scrollTime;
2404
2301
  }
2405
2302
 
2406
2303
  // src/core/ScrollAdjustHandler.ts
@@ -2789,7 +2686,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2789
2686
  loadStartTime: Date.now(),
2790
2687
  minIndexSizeChanged: 0,
2791
2688
  nativeMarginTop: 0,
2792
- positionRange: { end: -1, start: -1, valid: false },
2793
2689
  positions: /* @__PURE__ */ new Map(),
2794
2690
  props: {},
2795
2691
  queuedCalculateItemsInView: 0,
@@ -2902,7 +2798,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2902
2798
  };
2903
2799
  if (isFirst) {
2904
2800
  initializeStateVars();
2905
- updateItemPositions(ctx, state);
2801
+ updateAllPositions(ctx, state);
2906
2802
  }
2907
2803
  const initialContentOffset = React3.useMemo(() => {
2908
2804
  if (initialScroll) {
@@ -2963,9 +2859,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2963
2859
  set$(ctx, "extraData", extraData);
2964
2860
  }, [extraData]);
2965
2861
  React3.useLayoutEffect(() => {
2862
+ var _a2;
2966
2863
  if (IsNewArchitecture) {
2967
2864
  let measured;
2968
- refScroller.current.measure((x, y, width, height) => {
2865
+ (_a2 = refScroller.current) == null ? void 0 : _a2.measure((x, y, width, height) => {
2969
2866
  measured = { height, width, x, y };
2970
2867
  });
2971
2868
  if (measured) {
@@ -3030,13 +2927,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3030
2927
  getState: () => {
3031
2928
  const state2 = refState.current;
3032
2929
  return state2 ? {
2930
+ activeStickyIndex: state2.activeStickyIndex,
3033
2931
  contentLength: state2.totalSize,
3034
2932
  data: state2.props.data,
3035
2933
  end: state2.endNoBuffer,
3036
2934
  endBuffered: state2.endBuffered,
3037
2935
  isAtEnd: state2.isAtEnd,
3038
2936
  isAtStart: state2.isAtStart,
3039
- positionAtIndex: (index) => getPositionByIndex(ctx, state2, index),
2937
+ positionAtIndex: (index) => state2.positions.get(getId(state2, index)),
3040
2938
  positions: state2.positions,
3041
2939
  scroll: state2.scroll,
3042
2940
  scrollLength: state2.scrollLength,
package/index.mjs CHANGED
@@ -876,6 +876,23 @@ function getId(state, index) {
876
876
  return id;
877
877
  }
878
878
 
879
+ // src/core/calculateOffsetForIndex.ts
880
+ function calculateOffsetForIndex(ctx, state, index) {
881
+ let position = 0;
882
+ if (index !== void 0) {
883
+ position = (state == null ? void 0 : state.positions.get(getId(state, index))) || 0;
884
+ const paddingTop = peek$(ctx, "stylePaddingTop");
885
+ if (paddingTop) {
886
+ position += paddingTop;
887
+ }
888
+ const headerSize = peek$(ctx, "headerSize");
889
+ if (headerSize) {
890
+ position += headerSize;
891
+ }
892
+ }
893
+ return position;
894
+ }
895
+
879
896
  // src/utils/getItemSize.ts
880
897
  function getItemSize(state, key, index, data, useAverageSize) {
881
898
  var _a, _b;
@@ -917,280 +934,6 @@ function getItemSize(state, key, index, data, useAverageSize) {
917
934
  return size;
918
935
  }
919
936
 
920
- // src/utils/setPaddingTop.ts
921
- function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
922
- if (stylePaddingTop !== void 0) {
923
- const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
924
- if (stylePaddingTop < prevStylePaddingTop) {
925
- let prevTotalSize = peek$(ctx, "totalSize") || 0;
926
- set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
927
- state.timeoutSetPaddingTop = setTimeout(() => {
928
- prevTotalSize = peek$(ctx, "totalSize") || 0;
929
- set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
930
- }, 16);
931
- }
932
- set$(ctx, "stylePaddingTop", stylePaddingTop);
933
- }
934
- if (alignItemsPaddingTop !== void 0) {
935
- set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
936
- }
937
- }
938
-
939
- // src/utils/updateAlignItemsPaddingTop.ts
940
- function updateAlignItemsPaddingTop(ctx, state) {
941
- const {
942
- scrollLength,
943
- props: { alignItemsAtEnd, data }
944
- } = state;
945
- if (alignItemsAtEnd) {
946
- let alignItemsPaddingTop = 0;
947
- if ((data == null ? void 0 : data.length) > 0) {
948
- const contentSize = getContentSize(ctx);
949
- alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
950
- }
951
- setPaddingTop(ctx, state, { alignItemsPaddingTop });
952
- }
953
- }
954
-
955
- // src/core/updateTotalSize.ts
956
- function updateTotalSize(ctx, state) {
957
- const {
958
- props: { data }
959
- } = state;
960
- if (data.length === 0) {
961
- addTotalSize(ctx, state, null, 0);
962
- } else {
963
- const lastIndex = data.length - 1;
964
- const lastId = getId(state, lastIndex);
965
- if (lastId !== void 0) {
966
- const lastPosition = getPositionByIndex(ctx, state, lastIndex);
967
- if (lastPosition !== void 0) {
968
- const lastSize = getItemSize(state, lastId, data.length - 1, data[data.length - 1]);
969
- if (lastSize !== void 0) {
970
- const totalSize = lastPosition + lastSize;
971
- addTotalSize(ctx, state, null, totalSize);
972
- }
973
- }
974
- }
975
- }
976
- }
977
- function addTotalSize(ctx, state, key, add) {
978
- const { alignItemsAtEnd } = state.props;
979
- {
980
- state.totalSize = add;
981
- if (state.timeoutSetPaddingTop) {
982
- clearTimeout(state.timeoutSetPaddingTop);
983
- state.timeoutSetPaddingTop = void 0;
984
- }
985
- }
986
- set$(ctx, "totalSize", state.totalSize);
987
- if (alignItemsAtEnd) {
988
- updateAlignItemsPaddingTop(ctx, state);
989
- }
990
- }
991
-
992
- // src/utils/updateSnapToOffsets.ts
993
- function updateSnapToOffsets(ctx, state) {
994
- const {
995
- props: { snapToIndices }
996
- } = state;
997
- const snapToOffsets = Array(snapToIndices.length);
998
- for (let i = 0; i < snapToIndices.length; i++) {
999
- const idx = snapToIndices[i];
1000
- snapToOffsets[i] = getPositionByIndex(ctx, state, idx) || 0;
1001
- }
1002
- set$(ctx, "snapToOffsets", snapToOffsets);
1003
- }
1004
-
1005
- // src/core/updateItemPositions.ts
1006
- function getRequiredRange(_ctx, state) {
1007
- var _a;
1008
- const bufferSize = 10;
1009
- const dataLength = state.props.data.length;
1010
- let minIndex = 0;
1011
- let maxIndex = dataLength - 1;
1012
- if (dataLength < 500) {
1013
- return { end: maxIndex, start: 0 };
1014
- }
1015
- const hasVisibleRange = state.startBuffered >= 0 && state.endBuffered >= 0;
1016
- if (hasVisibleRange) {
1017
- minIndex = state.startBuffered;
1018
- maxIndex = state.endBuffered;
1019
- }
1020
- if (((_a = state.scrollingTo) == null ? void 0 : _a.index) !== void 0) {
1021
- if (hasVisibleRange) {
1022
- minIndex = Math.min(minIndex, state.scrollingTo.index);
1023
- maxIndex = Math.max(maxIndex, state.scrollingTo.index);
1024
- } else {
1025
- minIndex = state.scrollingTo.index;
1026
- maxIndex = state.scrollingTo.index;
1027
- }
1028
- }
1029
- minIndex = Math.max(0, minIndex - bufferSize);
1030
- maxIndex = Math.min(dataLength - 1, maxIndex + bufferSize);
1031
- return { end: maxIndex, start: minIndex };
1032
- }
1033
- function ensurePositionCalculated(ctx, state, index) {
1034
- if (!state.positionRange) {
1035
- state.positionRange = { end: -1, start: 0, valid: false };
1036
- }
1037
- if (state.positionRange.valid && index >= state.positionRange.start && index <= state.positionRange.end) {
1038
- return;
1039
- }
1040
- const newStart = state.positionRange.valid ? Math.min(state.positionRange.start, index) : 0;
1041
- const newEnd = Math.min(
1042
- state.props.data.length - 1,
1043
- Math.max(state.positionRange.valid ? state.positionRange.end : 0, index + 50)
1044
- );
1045
- updateItemPositions(ctx, state, false, newStart, newEnd);
1046
- }
1047
- function updateItemPositions(ctx, state, dataChanged, startIndex = 0, endIndex) {
1048
- var _a, _b, _c, _d, _e, _f, _g, _h;
1049
- const {
1050
- columns,
1051
- indexByKey,
1052
- positions,
1053
- idCache,
1054
- sizesKnown,
1055
- props: { getEstimatedItemSize, snapToIndices, enableAverages }
1056
- } = state;
1057
- const data = state.props.data;
1058
- const numColumns = peek$(ctx, "numColumns");
1059
- const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
1060
- const useAverageSize = enableAverages && !getEstimatedItemSize;
1061
- let currentRowTop = 0;
1062
- let column = 1;
1063
- let maxSizeInRow = 0;
1064
- const hasColumns = numColumns > 1;
1065
- const dataLength = data.length;
1066
- const requiredRange = getRequiredRange(ctx, state);
1067
- const shouldOptimize = dataLength >= 500;
1068
- const optimizedEndIndex = shouldOptimize ? Math.min(dataLength - 1, requiredRange.end) : dataLength - 1;
1069
- const actualEndIndex = endIndex !== void 0 ? Math.min(endIndex, dataLength - 1) : optimizedEndIndex;
1070
- let adjustedStartIndex = startIndex;
1071
- let adjustedEndIndex = actualEndIndex;
1072
- if (((_a = state.positionRange) == null ? void 0 : _a.valid) && !dataChanged && shouldOptimize) {
1073
- const existingStart = state.positionRange.start;
1074
- const existingEnd = state.positionRange.end;
1075
- const requiredStart = requiredRange.start;
1076
- const requiredEnd = requiredRange.end;
1077
- if (requiredStart <= existingEnd + 1 && requiredEnd >= existingStart - 1) {
1078
- adjustedStartIndex = Math.min(startIndex, Math.min(existingStart, requiredStart));
1079
- adjustedEndIndex = Math.max(actualEndIndex, Math.max(existingEnd, requiredEnd));
1080
- } else if (requiredStart > existingEnd + 1) {
1081
- adjustedStartIndex = Math.min(startIndex, existingEnd + 1);
1082
- adjustedEndIndex = Math.max(actualEndIndex, requiredEnd);
1083
- } else if (requiredEnd < existingStart - 1) {
1084
- adjustedStartIndex = Math.min(startIndex, requiredStart);
1085
- adjustedEndIndex = Math.max(actualEndIndex, existingStart - 1);
1086
- }
1087
- }
1088
- if (adjustedStartIndex > 0) {
1089
- const prevIndex = adjustedStartIndex - 1;
1090
- const prevId = (_b = idCache.get(prevIndex)) != null ? _b : getId(state, prevIndex);
1091
- const prevPosition = (_c = positions.get(prevId)) != null ? _c : 0;
1092
- if (hasColumns) {
1093
- const prevColumn = (_d = columns.get(prevId)) != null ? _d : 1;
1094
- currentRowTop = prevPosition;
1095
- column = prevColumn % numColumns + 1;
1096
- } else {
1097
- const prevSize = (_e = sizesKnown.get(prevId)) != null ? _e : getItemSize(state, prevId, prevIndex, data[prevIndex], useAverageSize);
1098
- currentRowTop = prevPosition + prevSize;
1099
- }
1100
- }
1101
- const needsIndexByKey = dataChanged || indexByKey.size === 0;
1102
- let actualEndReached = adjustedStartIndex;
1103
- for (let i = adjustedStartIndex; i < dataLength; i++) {
1104
- const id = (_f = idCache.get(i)) != null ? _f : getId(state, i);
1105
- const size = (_g = sizesKnown.get(id)) != null ? _g : getItemSize(state, id, i, data[i], useAverageSize);
1106
- if (__DEV__ && needsIndexByKey) {
1107
- if (indexByKeyForChecking.has(id)) {
1108
- console.error(
1109
- `[legend-list] Error: Detected overlapping key (${id}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
1110
- );
1111
- }
1112
- indexByKeyForChecking.set(id, i);
1113
- }
1114
- positions.set(id, currentRowTop);
1115
- if (needsIndexByKey) {
1116
- indexByKey.set(id, i);
1117
- }
1118
- columns.set(id, column);
1119
- if (hasColumns) {
1120
- if (size > maxSizeInRow) {
1121
- maxSizeInRow = size;
1122
- }
1123
- column++;
1124
- if (column > numColumns) {
1125
- currentRowTop += maxSizeInRow;
1126
- column = 1;
1127
- maxSizeInRow = 0;
1128
- }
1129
- } else {
1130
- currentRowTop += size;
1131
- }
1132
- actualEndReached = i;
1133
- if (shouldOptimize && i >= adjustedEndIndex && (!((_h = state.scrollingTo) == null ? void 0 : _h.index) || i >= state.scrollingTo.index)) {
1134
- break;
1135
- }
1136
- }
1137
- if (!state.positionRange) {
1138
- state.positionRange = { end: -1, start: 0, valid: false };
1139
- }
1140
- if (dataChanged) {
1141
- state.positionRange = {
1142
- end: actualEndReached,
1143
- start: adjustedStartIndex,
1144
- valid: true
1145
- };
1146
- } else {
1147
- state.positionRange = {
1148
- end: Math.max(state.positionRange.valid ? state.positionRange.end : actualEndReached, actualEndReached),
1149
- start: Math.min(
1150
- state.positionRange.valid ? state.positionRange.start : adjustedStartIndex,
1151
- adjustedStartIndex
1152
- ),
1153
- valid: true
1154
- };
1155
- }
1156
- updateTotalSize(ctx, state);
1157
- if (snapToIndices) {
1158
- updateSnapToOffsets(ctx, state);
1159
- }
1160
- }
1161
-
1162
- // src/utils/getPosition.ts
1163
- function getPositionByIndex(ctx, state, index) {
1164
- ensurePositionCalculated(ctx, state, index);
1165
- const id = getId(state, index);
1166
- return id ? state.positions.get(id) : void 0;
1167
- }
1168
- function getPositionById(ctx, state, id) {
1169
- const index = state.indexByKey.get(id);
1170
- if (index === void 0) {
1171
- return state.positions.get(id);
1172
- }
1173
- ensurePositionCalculated(ctx, state, index);
1174
- return state.positions.get(id);
1175
- }
1176
-
1177
- // src/core/calculateOffsetForIndex.ts
1178
- function calculateOffsetForIndex(ctx, state, index) {
1179
- let position = 0;
1180
- if (index !== void 0) {
1181
- position = getPositionByIndex(ctx, state, index) || 0;
1182
- const paddingTop = peek$(ctx, "stylePaddingTop");
1183
- if (paddingTop) {
1184
- position += paddingTop;
1185
- }
1186
- const headerSize = peek$(ctx, "headerSize");
1187
- if (headerSize) {
1188
- position += headerSize;
1189
- }
1190
- }
1191
- return position;
1192
- }
1193
-
1194
937
  // src/core/calculateOffsetWithOffsetPosition.ts
1195
938
  function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
1196
939
  const { index, viewOffset, viewPosition } = params;
@@ -1284,6 +1027,7 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1284
1027
  function prepareMVCP(ctx, state, dataChanged) {
1285
1028
  const {
1286
1029
  idsInView,
1030
+ positions,
1287
1031
  scrollingTo,
1288
1032
  props: { maintainVisibleContentPosition }
1289
1033
  } = state;
@@ -1301,10 +1045,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1301
1045
  const id = idsInView[i];
1302
1046
  const index = indexByKey.get(id);
1303
1047
  if (index !== void 0) {
1304
- const position = getPositionById(ctx, state, id);
1305
- if (position !== void 0) {
1306
- idsInViewWithPositions.push({ id, position });
1307
- }
1048
+ idsInViewWithPositions.push({ id, position: positions.get(id) });
1308
1049
  }
1309
1050
  }
1310
1051
  } else {
@@ -1312,10 +1053,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1312
1053
  }
1313
1054
  }
1314
1055
  if (targetId !== void 0) {
1315
- const pos = getPositionById(ctx, state, targetId);
1316
- if (pos !== void 0) {
1317
- prevPosition = pos;
1318
- }
1056
+ prevPosition = positions.get(targetId);
1319
1057
  }
1320
1058
  }
1321
1059
  return () => {
@@ -1323,7 +1061,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1323
1061
  if (dataChanged && targetId === void 0) {
1324
1062
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1325
1063
  const { id, position } = idsInViewWithPositions[i];
1326
- const newPosition = getPositionById(ctx, state, id);
1064
+ const newPosition = positions.get(id);
1327
1065
  if (newPosition !== void 0) {
1328
1066
  positionDiff = newPosition - position;
1329
1067
  break;
@@ -1331,7 +1069,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1331
1069
  }
1332
1070
  }
1333
1071
  if (targetId !== void 0 && prevPosition !== void 0) {
1334
- const newPosition = getPositionById(ctx, state, targetId);
1072
+ const newPosition = positions.get(targetId);
1335
1073
  if (newPosition !== void 0) {
1336
1074
  positionDiff = newPosition - prevPosition;
1337
1075
  }
@@ -1342,6 +1080,163 @@ function prepareMVCP(ctx, state, dataChanged) {
1342
1080
  };
1343
1081
  }
1344
1082
 
1083
+ // src/utils/setPaddingTop.ts
1084
+ function setPaddingTop(ctx, state, { stylePaddingTop, alignItemsPaddingTop }) {
1085
+ if (stylePaddingTop !== void 0) {
1086
+ const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
1087
+ if (stylePaddingTop < prevStylePaddingTop) {
1088
+ let prevTotalSize = peek$(ctx, "totalSize") || 0;
1089
+ set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
1090
+ state.timeoutSetPaddingTop = setTimeout(() => {
1091
+ prevTotalSize = peek$(ctx, "totalSize") || 0;
1092
+ set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
1093
+ }, 16);
1094
+ }
1095
+ set$(ctx, "stylePaddingTop", stylePaddingTop);
1096
+ }
1097
+ if (alignItemsPaddingTop !== void 0) {
1098
+ set$(ctx, "alignItemsPaddingTop", alignItemsPaddingTop);
1099
+ }
1100
+ }
1101
+
1102
+ // src/utils/updateAlignItemsPaddingTop.ts
1103
+ function updateAlignItemsPaddingTop(ctx, state) {
1104
+ const {
1105
+ scrollLength,
1106
+ props: { alignItemsAtEnd, data }
1107
+ } = state;
1108
+ if (alignItemsAtEnd) {
1109
+ let alignItemsPaddingTop = 0;
1110
+ if ((data == null ? void 0 : data.length) > 0) {
1111
+ const contentSize = getContentSize(ctx);
1112
+ alignItemsPaddingTop = Math.max(0, Math.floor(scrollLength - contentSize));
1113
+ }
1114
+ setPaddingTop(ctx, state, { alignItemsPaddingTop });
1115
+ }
1116
+ }
1117
+
1118
+ // src/core/updateTotalSize.ts
1119
+ function updateTotalSize(ctx, state) {
1120
+ const {
1121
+ positions,
1122
+ props: { data }
1123
+ } = state;
1124
+ if (data.length === 0) {
1125
+ addTotalSize(ctx, state, null, 0);
1126
+ } else {
1127
+ const lastId = getId(state, data.length - 1);
1128
+ if (lastId !== void 0) {
1129
+ const lastPosition = positions.get(lastId);
1130
+ if (lastPosition !== void 0) {
1131
+ const lastSize = getItemSize(state, lastId, data.length - 1, data[data.length - 1]);
1132
+ if (lastSize !== void 0) {
1133
+ const totalSize = lastPosition + lastSize;
1134
+ addTotalSize(ctx, state, null, totalSize);
1135
+ }
1136
+ }
1137
+ }
1138
+ }
1139
+ }
1140
+ function addTotalSize(ctx, state, key, add) {
1141
+ const { alignItemsAtEnd } = state.props;
1142
+ {
1143
+ state.totalSize = add;
1144
+ if (state.timeoutSetPaddingTop) {
1145
+ clearTimeout(state.timeoutSetPaddingTop);
1146
+ state.timeoutSetPaddingTop = void 0;
1147
+ }
1148
+ }
1149
+ set$(ctx, "totalSize", state.totalSize);
1150
+ if (alignItemsAtEnd) {
1151
+ updateAlignItemsPaddingTop(ctx, state);
1152
+ }
1153
+ }
1154
+
1155
+ // src/utils/updateSnapToOffsets.ts
1156
+ function updateSnapToOffsets(ctx, state) {
1157
+ const {
1158
+ positions,
1159
+ props: { snapToIndices }
1160
+ } = state;
1161
+ const snapToOffsets = Array(snapToIndices.length);
1162
+ for (let i = 0; i < snapToIndices.length; i++) {
1163
+ const idx = snapToIndices[i];
1164
+ const key = getId(state, idx);
1165
+ snapToOffsets[i] = positions.get(key);
1166
+ }
1167
+ set$(ctx, "snapToOffsets", snapToOffsets);
1168
+ }
1169
+
1170
+ // src/core/updateAllPositions.ts
1171
+ function updateAllPositions(ctx, state, dataChanged, startIndex = 0) {
1172
+ var _a, _b, _c, _d, _e, _f;
1173
+ const {
1174
+ columns,
1175
+ indexByKey,
1176
+ positions,
1177
+ idCache,
1178
+ sizesKnown,
1179
+ props: { getEstimatedItemSize, snapToIndices, enableAverages }
1180
+ } = state;
1181
+ const data = state.props.data;
1182
+ const numColumns = peek$(ctx, "numColumns");
1183
+ const indexByKeyForChecking = __DEV__ ? /* @__PURE__ */ new Map() : void 0;
1184
+ const useAverageSize = enableAverages && !getEstimatedItemSize;
1185
+ let currentRowTop = 0;
1186
+ let column = 1;
1187
+ let maxSizeInRow = 0;
1188
+ const hasColumns = numColumns > 1;
1189
+ if (startIndex > 0) {
1190
+ const prevIndex = startIndex - 1;
1191
+ const prevId = (_a = idCache.get(prevIndex)) != null ? _a : getId(state, prevIndex);
1192
+ const prevPosition = (_b = positions.get(prevId)) != null ? _b : 0;
1193
+ if (hasColumns) {
1194
+ const prevColumn = (_c = columns.get(prevId)) != null ? _c : 1;
1195
+ currentRowTop = prevPosition;
1196
+ column = prevColumn % numColumns + 1;
1197
+ } else {
1198
+ const prevSize = (_d = sizesKnown.get(prevId)) != null ? _d : getItemSize(state, prevId, prevIndex, data[prevIndex], useAverageSize);
1199
+ currentRowTop = prevPosition + prevSize;
1200
+ }
1201
+ }
1202
+ const needsIndexByKey = dataChanged || indexByKey.size === 0;
1203
+ const dataLength = data.length;
1204
+ for (let i = startIndex; i < dataLength; i++) {
1205
+ const id = (_e = idCache.get(i)) != null ? _e : getId(state, i);
1206
+ const size = (_f = sizesKnown.get(id)) != null ? _f : getItemSize(state, id, i, data[i], useAverageSize);
1207
+ if (__DEV__ && needsIndexByKey) {
1208
+ if (indexByKeyForChecking.has(id)) {
1209
+ console.error(
1210
+ `[legend-list] Error: Detected overlapping key (${id}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
1211
+ );
1212
+ }
1213
+ indexByKeyForChecking.set(id, i);
1214
+ }
1215
+ positions.set(id, currentRowTop);
1216
+ if (needsIndexByKey) {
1217
+ indexByKey.set(id, i);
1218
+ }
1219
+ columns.set(id, column);
1220
+ if (hasColumns) {
1221
+ if (size > maxSizeInRow) {
1222
+ maxSizeInRow = size;
1223
+ }
1224
+ column++;
1225
+ if (column > numColumns) {
1226
+ currentRowTop += maxSizeInRow;
1227
+ column = 1;
1228
+ maxSizeInRow = 0;
1229
+ }
1230
+ } else {
1231
+ currentRowTop += size;
1232
+ }
1233
+ }
1234
+ updateTotalSize(ctx, state);
1235
+ if (snapToIndices) {
1236
+ updateSnapToOffsets(ctx, state);
1237
+ }
1238
+ }
1239
+
1345
1240
  // src/core/viewability.ts
1346
1241
  function ensureViewabilityState(ctx, configId) {
1347
1242
  let map = ctx.mapViewabilityConfigStates;
@@ -1843,6 +1738,7 @@ function handleStickyActivation(ctx, state, stickyIndices, stickyArray, scroll,
1843
1738
  var _a;
1844
1739
  const activeIndices = getActiveStickyIndices(ctx, state, stickyIndices);
1845
1740
  const currentStickyIdx = findCurrentStickyIndex(stickyArray, scroll, state);
1741
+ state.activeStickyIndex = currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : void 0;
1846
1742
  for (let offset = 0; offset <= 1; offset++) {
1847
1743
  const idx = currentStickyIdx - offset;
1848
1744
  if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
@@ -1922,7 +1818,7 @@ function calculateItemsInView(ctx, state, params = {}) {
1922
1818
  positions.clear();
1923
1819
  }
1924
1820
  const startIndex = dataChanged ? 0 : minIndexSizeChanged != null ? minIndexSizeChanged : 0;
1925
- updateItemPositions(ctx, state, dataChanged, startIndex);
1821
+ updateAllPositions(ctx, state, dataChanged, startIndex);
1926
1822
  if (minIndexSizeChanged !== void 0) {
1927
1823
  state.minIndexSizeChanged = void 0;
1928
1824
  }
@@ -1974,8 +1870,7 @@ function calculateItemsInView(ctx, state, params = {}) {
1974
1870
  let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
1975
1871
  for (let i = loopStart; i >= 0; i--) {
1976
1872
  const id = (_a = idCache.get(i)) != null ? _a : getId(state, i);
1977
- const top = getPositionById(ctx, state, id);
1978
- if (top === void 0) break;
1873
+ const top = positions.get(id);
1979
1874
  const size = (_b = sizes.get(id)) != null ? _b : getItemSize(state, id, i, data[i]);
1980
1875
  const bottom = top + size;
1981
1876
  if (bottom > scroll - scrollBuffer) {
@@ -2004,7 +1899,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2004
1899
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
2005
1900
  const id = (_c = idCache.get(i)) != null ? _c : getId(state, i);
2006
1901
  const size = (_d = sizes.get(id)) != null ? _d : getItemSize(state, id, i, data[i]);
2007
- const top = getPositionById(ctx, state, id);
1902
+ const top = positions.get(id);
2008
1903
  if (!foundEnd) {
2009
1904
  if (startNoBuffer === null && top + size > scroll) {
2010
1905
  startNoBuffer = i;
@@ -2080,6 +1975,8 @@ function calculateItemsInView(ctx, state, params = {}) {
2080
1975
  startBuffered,
2081
1976
  endBuffered
2082
1977
  );
1978
+ } else {
1979
+ state.activeStickyIndex = void 0;
2083
1980
  }
2084
1981
  if (needNewContainers.length > 0) {
2085
1982
  const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
@@ -2155,7 +2052,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2155
2052
  const item = data[itemIndex];
2156
2053
  if (item !== void 0) {
2157
2054
  const id = (_h = idCache.get(itemIndex)) != null ? _h : getId(state, itemIndex);
2158
- const position = getPositionById(ctx, state, id);
2055
+ const position = positions.get(id);
2159
2056
  if (position === void 0) {
2160
2057
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2161
2058
  } else {
@@ -2371,6 +2268,8 @@ function updateScroll(ctx, state, newScroll) {
2371
2268
  if (state.scrollHistory.length > 5) {
2372
2269
  state.scrollHistory.shift();
2373
2270
  }
2271
+ state.scrollPrev = state.scroll;
2272
+ state.scrollPrevTime = state.scrollTime;
2374
2273
  state.scroll = newScroll;
2375
2274
  state.scrollTime = currentTime;
2376
2275
  if (Math.abs(state.scroll - state.scrollPrev) > 2) {
@@ -2378,8 +2277,6 @@ function updateScroll(ctx, state, newScroll) {
2378
2277
  checkAtBottom(ctx, state);
2379
2278
  checkAtTop(state);
2380
2279
  }
2381
- state.scrollPrev = state.scroll;
2382
- state.scrollPrevTime = state.scrollTime;
2383
2280
  }
2384
2281
 
2385
2282
  // src/core/ScrollAdjustHandler.ts
@@ -2768,7 +2665,6 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2768
2665
  loadStartTime: Date.now(),
2769
2666
  minIndexSizeChanged: 0,
2770
2667
  nativeMarginTop: 0,
2771
- positionRange: { end: -1, start: -1, valid: false },
2772
2668
  positions: /* @__PURE__ */ new Map(),
2773
2669
  props: {},
2774
2670
  queuedCalculateItemsInView: 0,
@@ -2881,7 +2777,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2881
2777
  };
2882
2778
  if (isFirst) {
2883
2779
  initializeStateVars();
2884
- updateItemPositions(ctx, state);
2780
+ updateAllPositions(ctx, state);
2885
2781
  }
2886
2782
  const initialContentOffset = useMemo(() => {
2887
2783
  if (initialScroll) {
@@ -2942,9 +2838,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2942
2838
  set$(ctx, "extraData", extraData);
2943
2839
  }, [extraData]);
2944
2840
  useLayoutEffect(() => {
2841
+ var _a2;
2945
2842
  if (IsNewArchitecture) {
2946
2843
  let measured;
2947
- refScroller.current.measure((x, y, width, height) => {
2844
+ (_a2 = refScroller.current) == null ? void 0 : _a2.measure((x, y, width, height) => {
2948
2845
  measured = { height, width, x, y };
2949
2846
  });
2950
2847
  if (measured) {
@@ -3009,13 +2906,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
3009
2906
  getState: () => {
3010
2907
  const state2 = refState.current;
3011
2908
  return state2 ? {
2909
+ activeStickyIndex: state2.activeStickyIndex,
3012
2910
  contentLength: state2.totalSize,
3013
2911
  data: state2.props.data,
3014
2912
  end: state2.endNoBuffer,
3015
2913
  endBuffered: state2.endBuffered,
3016
2914
  isAtEnd: state2.isAtEnd,
3017
2915
  isAtStart: state2.isAtStart,
3018
- positionAtIndex: (index) => getPositionByIndex(ctx, state2, index),
2916
+ positionAtIndex: (index) => state2.positions.get(getId(state2, index)),
3019
2917
  positions: state2.positions,
3020
2918
  scroll: state2.scroll,
3021
2919
  scrollLength: state2.scrollLength,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
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,