@legendapp/list 2.0.0 → 2.0.2

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,6 +345,11 @@ 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
+ };
348
353
  averageSizes: Record<string, {
349
354
  num: number;
350
355
  avg: number;
@@ -414,11 +419,11 @@ type ScrollState = {
414
419
  endBuffered: number;
415
420
  isAtEnd: boolean;
416
421
  isAtStart: boolean;
417
- positionAtIndex: (index: number) => number;
422
+ positionAtIndex: (index: number) => number | undefined;
418
423
  positions: Map<string, number>;
419
424
  scroll: number;
420
425
  scrollLength: number;
421
- sizeAtIndex: (index: number) => number;
426
+ sizeAtIndex: (index: number) => number | undefined;
422
427
  sizes: Map<string, number>;
423
428
  start: number;
424
429
  startBuffered: number;
package/index.d.ts CHANGED
@@ -345,6 +345,11 @@ 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
+ };
348
353
  averageSizes: Record<string, {
349
354
  num: number;
350
355
  avg: number;
@@ -414,11 +419,11 @@ type ScrollState = {
414
419
  endBuffered: number;
415
420
  isAtEnd: boolean;
416
421
  isAtStart: boolean;
417
- positionAtIndex: (index: number) => number;
422
+ positionAtIndex: (index: number) => number | undefined;
418
423
  positions: Map<string, number>;
419
424
  scroll: number;
420
425
  scrollLength: number;
421
- sizeAtIndex: (index: number) => number;
426
+ sizeAtIndex: (index: number) => number | undefined;
422
427
  sizes: Map<string, number>;
423
428
  start: number;
424
429
  startBuffered: number;
package/index.js CHANGED
@@ -897,23 +897,6 @@ 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
-
917
900
  // src/utils/getItemSize.ts
918
901
  function getItemSize(state, key, index, data, useAverageSize) {
919
902
  var _a, _b;
@@ -955,6 +938,280 @@ function getItemSize(state, key, index, data, useAverageSize) {
955
938
  return size;
956
939
  }
957
940
 
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
+
958
1215
  // src/core/calculateOffsetWithOffsetPosition.ts
959
1216
  function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
960
1217
  const { index, viewOffset, viewPosition } = params;
@@ -1048,7 +1305,6 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1048
1305
  function prepareMVCP(ctx, state, dataChanged) {
1049
1306
  const {
1050
1307
  idsInView,
1051
- positions,
1052
1308
  scrollingTo,
1053
1309
  props: { maintainVisibleContentPosition }
1054
1310
  } = state;
@@ -1066,7 +1322,10 @@ function prepareMVCP(ctx, state, dataChanged) {
1066
1322
  const id = idsInView[i];
1067
1323
  const index = indexByKey.get(id);
1068
1324
  if (index !== void 0) {
1069
- idsInViewWithPositions.push({ id, position: positions.get(id) });
1325
+ const position = getPositionById(ctx, state, id);
1326
+ if (position !== void 0) {
1327
+ idsInViewWithPositions.push({ id, position });
1328
+ }
1070
1329
  }
1071
1330
  }
1072
1331
  } else {
@@ -1074,7 +1333,10 @@ function prepareMVCP(ctx, state, dataChanged) {
1074
1333
  }
1075
1334
  }
1076
1335
  if (targetId !== void 0) {
1077
- prevPosition = positions.get(targetId);
1336
+ const pos = getPositionById(ctx, state, targetId);
1337
+ if (pos !== void 0) {
1338
+ prevPosition = pos;
1339
+ }
1078
1340
  }
1079
1341
  }
1080
1342
  return () => {
@@ -1082,7 +1344,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1082
1344
  if (dataChanged && targetId === void 0) {
1083
1345
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1084
1346
  const { id, position } = idsInViewWithPositions[i];
1085
- const newPosition = positions.get(id);
1347
+ const newPosition = getPositionById(ctx, state, id);
1086
1348
  if (newPosition !== void 0) {
1087
1349
  positionDiff = newPosition - position;
1088
1350
  break;
@@ -1090,7 +1352,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1090
1352
  }
1091
1353
  }
1092
1354
  if (targetId !== void 0 && prevPosition !== void 0) {
1093
- const newPosition = positions.get(targetId);
1355
+ const newPosition = getPositionById(ctx, state, targetId);
1094
1356
  if (newPosition !== void 0) {
1095
1357
  positionDiff = newPosition - prevPosition;
1096
1358
  }
@@ -1101,163 +1363,6 @@ function prepareMVCP(ctx, state, dataChanged) {
1101
1363
  };
1102
1364
  }
1103
1365
 
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
-
1261
1366
  // src/core/viewability.ts
1262
1367
  function ensureViewabilityState(ctx, configId) {
1263
1368
  let map = ctx.mapViewabilityConfigStates;
@@ -1838,7 +1943,7 @@ function calculateItemsInView(ctx, state, params = {}) {
1838
1943
  positions.clear();
1839
1944
  }
1840
1945
  const startIndex = dataChanged ? 0 : minIndexSizeChanged != null ? minIndexSizeChanged : 0;
1841
- updateAllPositions(ctx, state, dataChanged, startIndex);
1946
+ updateItemPositions(ctx, state, dataChanged, startIndex);
1842
1947
  if (minIndexSizeChanged !== void 0) {
1843
1948
  state.minIndexSizeChanged = void 0;
1844
1949
  }
@@ -1890,7 +1995,8 @@ function calculateItemsInView(ctx, state, params = {}) {
1890
1995
  let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
1891
1996
  for (let i = loopStart; i >= 0; i--) {
1892
1997
  const id = (_a = idCache.get(i)) != null ? _a : getId(state, i);
1893
- const top = positions.get(id);
1998
+ const top = getPositionById(ctx, state, id);
1999
+ if (top === void 0) break;
1894
2000
  const size = (_b = sizes.get(id)) != null ? _b : getItemSize(state, id, i, data[i]);
1895
2001
  const bottom = top + size;
1896
2002
  if (bottom > scroll - scrollBuffer) {
@@ -1919,7 +2025,7 @@ function calculateItemsInView(ctx, state, params = {}) {
1919
2025
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
1920
2026
  const id = (_c = idCache.get(i)) != null ? _c : getId(state, i);
1921
2027
  const size = (_d = sizes.get(id)) != null ? _d : getItemSize(state, id, i, data[i]);
1922
- const top = positions.get(id);
2028
+ const top = getPositionById(ctx, state, id);
1923
2029
  if (!foundEnd) {
1924
2030
  if (startNoBuffer === null && top + size > scroll) {
1925
2031
  startNoBuffer = i;
@@ -2070,7 +2176,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2070
2176
  const item = data[itemIndex];
2071
2177
  if (item !== void 0) {
2072
2178
  const id = (_h = idCache.get(itemIndex)) != null ? _h : getId(state, itemIndex);
2073
- const position = positions.get(id);
2179
+ const position = getPositionById(ctx, state, id);
2074
2180
  if (position === void 0) {
2075
2181
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2076
2182
  } else {
@@ -2286,8 +2392,6 @@ function updateScroll(ctx, state, newScroll) {
2286
2392
  if (state.scrollHistory.length > 5) {
2287
2393
  state.scrollHistory.shift();
2288
2394
  }
2289
- state.scrollPrev = state.scroll;
2290
- state.scrollPrevTime = state.scrollTime;
2291
2395
  state.scroll = newScroll;
2292
2396
  state.scrollTime = currentTime;
2293
2397
  if (Math.abs(state.scroll - state.scrollPrev) > 2) {
@@ -2295,6 +2399,8 @@ function updateScroll(ctx, state, newScroll) {
2295
2399
  checkAtBottom(ctx, state);
2296
2400
  checkAtTop(state);
2297
2401
  }
2402
+ state.scrollPrev = state.scroll;
2403
+ state.scrollPrevTime = state.scrollTime;
2298
2404
  }
2299
2405
 
2300
2406
  // src/core/ScrollAdjustHandler.ts
@@ -2683,6 +2789,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2683
2789
  loadStartTime: Date.now(),
2684
2790
  minIndexSizeChanged: 0,
2685
2791
  nativeMarginTop: 0,
2792
+ positionRange: { end: -1, start: -1, valid: false },
2686
2793
  positions: /* @__PURE__ */ new Map(),
2687
2794
  props: {},
2688
2795
  queuedCalculateItemsInView: 0,
@@ -2795,7 +2902,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2795
2902
  };
2796
2903
  if (isFirst) {
2797
2904
  initializeStateVars();
2798
- updateAllPositions(ctx, state);
2905
+ updateItemPositions(ctx, state);
2799
2906
  }
2800
2907
  const initialContentOffset = React3.useMemo(() => {
2801
2908
  if (initialScroll) {
@@ -2929,7 +3036,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2929
3036
  endBuffered: state2.endBuffered,
2930
3037
  isAtEnd: state2.isAtEnd,
2931
3038
  isAtStart: state2.isAtStart,
2932
- positionAtIndex: (index) => state2.positions.get(getId(state2, index)),
3039
+ positionAtIndex: (index) => getPositionByIndex(ctx, state2, index),
2933
3040
  positions: state2.positions,
2934
3041
  scroll: state2.scroll,
2935
3042
  scrollLength: state2.scrollLength,
package/index.mjs CHANGED
@@ -876,23 +876,6 @@ 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
-
896
879
  // src/utils/getItemSize.ts
897
880
  function getItemSize(state, key, index, data, useAverageSize) {
898
881
  var _a, _b;
@@ -934,6 +917,280 @@ function getItemSize(state, key, index, data, useAverageSize) {
934
917
  return size;
935
918
  }
936
919
 
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
+
937
1194
  // src/core/calculateOffsetWithOffsetPosition.ts
938
1195
  function calculateOffsetWithOffsetPosition(state, offsetParam, params) {
939
1196
  const { index, viewOffset, viewPosition } = params;
@@ -1027,7 +1284,6 @@ function requestAdjust(ctx, state, positionDiff, dataChanged) {
1027
1284
  function prepareMVCP(ctx, state, dataChanged) {
1028
1285
  const {
1029
1286
  idsInView,
1030
- positions,
1031
1287
  scrollingTo,
1032
1288
  props: { maintainVisibleContentPosition }
1033
1289
  } = state;
@@ -1045,7 +1301,10 @@ function prepareMVCP(ctx, state, dataChanged) {
1045
1301
  const id = idsInView[i];
1046
1302
  const index = indexByKey.get(id);
1047
1303
  if (index !== void 0) {
1048
- idsInViewWithPositions.push({ id, position: positions.get(id) });
1304
+ const position = getPositionById(ctx, state, id);
1305
+ if (position !== void 0) {
1306
+ idsInViewWithPositions.push({ id, position });
1307
+ }
1049
1308
  }
1050
1309
  }
1051
1310
  } else {
@@ -1053,7 +1312,10 @@ function prepareMVCP(ctx, state, dataChanged) {
1053
1312
  }
1054
1313
  }
1055
1314
  if (targetId !== void 0) {
1056
- prevPosition = positions.get(targetId);
1315
+ const pos = getPositionById(ctx, state, targetId);
1316
+ if (pos !== void 0) {
1317
+ prevPosition = pos;
1318
+ }
1057
1319
  }
1058
1320
  }
1059
1321
  return () => {
@@ -1061,7 +1323,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1061
1323
  if (dataChanged && targetId === void 0) {
1062
1324
  for (let i = 0; i < idsInViewWithPositions.length; i++) {
1063
1325
  const { id, position } = idsInViewWithPositions[i];
1064
- const newPosition = positions.get(id);
1326
+ const newPosition = getPositionById(ctx, state, id);
1065
1327
  if (newPosition !== void 0) {
1066
1328
  positionDiff = newPosition - position;
1067
1329
  break;
@@ -1069,7 +1331,7 @@ function prepareMVCP(ctx, state, dataChanged) {
1069
1331
  }
1070
1332
  }
1071
1333
  if (targetId !== void 0 && prevPosition !== void 0) {
1072
- const newPosition = positions.get(targetId);
1334
+ const newPosition = getPositionById(ctx, state, targetId);
1073
1335
  if (newPosition !== void 0) {
1074
1336
  positionDiff = newPosition - prevPosition;
1075
1337
  }
@@ -1080,163 +1342,6 @@ function prepareMVCP(ctx, state, dataChanged) {
1080
1342
  };
1081
1343
  }
1082
1344
 
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
-
1240
1345
  // src/core/viewability.ts
1241
1346
  function ensureViewabilityState(ctx, configId) {
1242
1347
  let map = ctx.mapViewabilityConfigStates;
@@ -1817,7 +1922,7 @@ function calculateItemsInView(ctx, state, params = {}) {
1817
1922
  positions.clear();
1818
1923
  }
1819
1924
  const startIndex = dataChanged ? 0 : minIndexSizeChanged != null ? minIndexSizeChanged : 0;
1820
- updateAllPositions(ctx, state, dataChanged, startIndex);
1925
+ updateItemPositions(ctx, state, dataChanged, startIndex);
1821
1926
  if (minIndexSizeChanged !== void 0) {
1822
1927
  state.minIndexSizeChanged = void 0;
1823
1928
  }
@@ -1869,7 +1974,8 @@ function calculateItemsInView(ctx, state, params = {}) {
1869
1974
  let loopStart = startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
1870
1975
  for (let i = loopStart; i >= 0; i--) {
1871
1976
  const id = (_a = idCache.get(i)) != null ? _a : getId(state, i);
1872
- const top = positions.get(id);
1977
+ const top = getPositionById(ctx, state, id);
1978
+ if (top === void 0) break;
1873
1979
  const size = (_b = sizes.get(id)) != null ? _b : getItemSize(state, id, i, data[i]);
1874
1980
  const bottom = top + size;
1875
1981
  if (bottom > scroll - scrollBuffer) {
@@ -1898,7 +2004,7 @@ function calculateItemsInView(ctx, state, params = {}) {
1898
2004
  for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
1899
2005
  const id = (_c = idCache.get(i)) != null ? _c : getId(state, i);
1900
2006
  const size = (_d = sizes.get(id)) != null ? _d : getItemSize(state, id, i, data[i]);
1901
- const top = positions.get(id);
2007
+ const top = getPositionById(ctx, state, id);
1902
2008
  if (!foundEnd) {
1903
2009
  if (startNoBuffer === null && top + size > scroll) {
1904
2010
  startNoBuffer = i;
@@ -2049,7 +2155,7 @@ function calculateItemsInView(ctx, state, params = {}) {
2049
2155
  const item = data[itemIndex];
2050
2156
  if (item !== void 0) {
2051
2157
  const id = (_h = idCache.get(itemIndex)) != null ? _h : getId(state, itemIndex);
2052
- const position = positions.get(id);
2158
+ const position = getPositionById(ctx, state, id);
2053
2159
  if (position === void 0) {
2054
2160
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
2055
2161
  } else {
@@ -2265,8 +2371,6 @@ function updateScroll(ctx, state, newScroll) {
2265
2371
  if (state.scrollHistory.length > 5) {
2266
2372
  state.scrollHistory.shift();
2267
2373
  }
2268
- state.scrollPrev = state.scroll;
2269
- state.scrollPrevTime = state.scrollTime;
2270
2374
  state.scroll = newScroll;
2271
2375
  state.scrollTime = currentTime;
2272
2376
  if (Math.abs(state.scroll - state.scrollPrev) > 2) {
@@ -2274,6 +2378,8 @@ function updateScroll(ctx, state, newScroll) {
2274
2378
  checkAtBottom(ctx, state);
2275
2379
  checkAtTop(state);
2276
2380
  }
2381
+ state.scrollPrev = state.scroll;
2382
+ state.scrollPrevTime = state.scrollTime;
2277
2383
  }
2278
2384
 
2279
2385
  // src/core/ScrollAdjustHandler.ts
@@ -2662,6 +2768,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2662
2768
  loadStartTime: Date.now(),
2663
2769
  minIndexSizeChanged: 0,
2664
2770
  nativeMarginTop: 0,
2771
+ positionRange: { end: -1, start: -1, valid: false },
2665
2772
  positions: /* @__PURE__ */ new Map(),
2666
2773
  props: {},
2667
2774
  queuedCalculateItemsInView: 0,
@@ -2774,7 +2881,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2774
2881
  };
2775
2882
  if (isFirst) {
2776
2883
  initializeStateVars();
2777
- updateAllPositions(ctx, state);
2884
+ updateItemPositions(ctx, state);
2778
2885
  }
2779
2886
  const initialContentOffset = useMemo(() => {
2780
2887
  if (initialScroll) {
@@ -2908,7 +3015,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
2908
3015
  endBuffered: state2.endBuffered,
2909
3016
  isAtEnd: state2.isAtEnd,
2910
3017
  isAtStart: state2.isAtStart,
2911
- positionAtIndex: (index) => state2.positions.get(getId(state2, index)),
3018
+ positionAtIndex: (index) => getPositionByIndex(ctx, state2, index),
2912
3019
  positions: state2.positions,
2913
3020
  scroll: state2.scroll,
2914
3021
  scrollLength: state2.scrollLength,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@legendapp/list",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
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,