@legendapp/list 0.4.6 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. package/index.d.mts +24 -4
  2. package/index.d.ts +24 -4
  3. package/index.js +506 -367
  4. package/index.mjs +494 -355
  5. package/package.json +1 -1
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var React6 = require('react');
3
+ var React7 = require('react');
4
4
  var reactNative = require('react-native');
5
5
 
6
6
  function _interopNamespace(e) {
@@ -21,16 +21,13 @@ function _interopNamespace(e) {
21
21
  return Object.freeze(n);
22
22
  }
23
23
 
24
- var React6__namespace = /*#__PURE__*/_interopNamespace(React6);
24
+ var React7__namespace = /*#__PURE__*/_interopNamespace(React7);
25
25
 
26
26
  // src/LegendList.tsx
27
- var LeanView = React6__namespace.forwardRef((props, ref) => {
28
- return React6__namespace.createElement("RCTView", { ...props, ref });
29
- });
30
- LeanView.displayName = "RCTView";
31
- var ContextState = React6__namespace.createContext(null);
27
+ var USE_CONTENT_INSET = reactNative.Platform.OS === "ios";
28
+ var ContextState = React7__namespace.createContext(null);
32
29
  function StateProvider({ children }) {
33
- const [value] = React6__namespace.useState(() => ({
30
+ const [value] = React7__namespace.useState(() => ({
34
31
  hooks: /* @__PURE__ */ new Map(),
35
32
  listeners: /* @__PURE__ */ new Map(),
36
33
  values: /* @__PURE__ */ new Map(),
@@ -39,14 +36,14 @@ function StateProvider({ children }) {
39
36
  mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
40
37
  mapViewabilityAmountValues: /* @__PURE__ */ new Map()
41
38
  }));
42
- return /* @__PURE__ */ React6__namespace.createElement(ContextState.Provider, { value }, children);
39
+ return /* @__PURE__ */ React7__namespace.createElement(ContextState.Provider, { value }, children);
43
40
  }
44
41
  function useStateContext() {
45
- return React6__namespace.useContext(ContextState);
42
+ return React7__namespace.useContext(ContextState);
46
43
  }
47
44
  function use$(signalName) {
48
- const { hooks, values } = React6__namespace.useContext(ContextState);
49
- const [, forceUpdate] = React6__namespace.useReducer((x) => x + 1, 0);
45
+ const { hooks, values } = React7__namespace.useContext(ContextState);
46
+ const [, forceUpdate] = React7__namespace.useReducer((x) => x + 1, 0);
50
47
  hooks.set(signalName, forceUpdate);
51
48
  return values.get(signalName);
52
49
  }
@@ -79,27 +76,46 @@ function set$(ctx, signalName, value) {
79
76
  }
80
77
  }
81
78
 
79
+ // src/$ScrollView.tsx
80
+ var OFFSET_TEST = 0;
81
+ var $ScrollView = React7__namespace.forwardRef(function $ScrollView2(props, ref) {
82
+ const { style, horizontal, ...rest } = props;
83
+ const scrollAdjust = use$("scrollAdjust");
84
+ const adjustProps = {};
85
+ if (scrollAdjust !== 0) {
86
+ if (USE_CONTENT_INSET) {
87
+ adjustProps.contentInset = horizontal ? { left: -scrollAdjust } : { top: -scrollAdjust + OFFSET_TEST };
88
+ } else {
89
+ adjustProps.style = horizontal ? { marginLeft: -scrollAdjust } : { marginTop: -scrollAdjust };
90
+ if (style) {
91
+ adjustProps.style = reactNative.StyleSheet.compose(style, adjustProps.style);
92
+ }
93
+ }
94
+ }
95
+ return /* @__PURE__ */ React7__namespace.createElement(reactNative.ScrollView, { ...rest, style, horizontal, ...adjustProps, ref });
96
+ });
97
+ var LeanView = React7__namespace.forwardRef((props, ref) => {
98
+ return React7__namespace.createElement("RCTView", { ...props, ref });
99
+ });
100
+ LeanView.displayName = "RCTView";
101
+
82
102
  // src/$View.tsx
83
- function $View({ $key, $style, ...rest }) {
103
+ function $View({ $key, $key2, $style, ...rest }) {
84
104
  use$($key);
105
+ if ($key2) {
106
+ use$($key2);
107
+ }
85
108
  const style = $style();
86
- return /* @__PURE__ */ React6__namespace.createElement(LeanView, { style, ...rest });
109
+ return /* @__PURE__ */ React7__namespace.createElement(LeanView, { style, ...rest });
87
110
  }
88
- function InnerContainer({ id, getRenderedItem, recycleItems, ItemSeparatorComponent }) {
89
- const itemIndex = use$(`containerItemIndex${id}`);
90
- const numItems = ItemSeparatorComponent ? use$("numItems") : 0;
91
- if (itemIndex < 0) {
111
+ function InnerContainer({ containerId, getRenderedItem, recycleItems, ItemSeparatorComponent }) {
112
+ const lastItemKey = use$("lastItemKey");
113
+ const itemKey = use$(`containerItemKey${containerId}`);
114
+ if (itemKey === void 0) {
92
115
  return null;
93
116
  }
94
- return /* @__PURE__ */ React6__namespace.createElement(React6__namespace.Fragment, { key: recycleItems ? void 0 : itemIndex }, /* @__PURE__ */ React6__namespace.createElement(RenderedItem, { itemIndex, id, getRenderedItem }), ItemSeparatorComponent && itemIndex < numItems - 1 && ItemSeparatorComponent);
95
- }
96
- function RenderedItem({
97
- itemIndex,
98
- id,
99
- getRenderedItem
100
- }) {
101
- const renderedItem = getRenderedItem(itemIndex, id);
102
- return renderedItem;
117
+ const renderedItem = getRenderedItem(itemKey, containerId);
118
+ return /* @__PURE__ */ React7__namespace.default.createElement(React7__namespace.default.Fragment, { key: recycleItems ? void 0 : itemKey }, renderedItem, ItemSeparatorComponent && itemKey !== lastItemKey && ItemSeparatorComponent);
103
119
  }
104
120
  var Container = ({
105
121
  id,
@@ -112,38 +128,44 @@ var Container = ({
112
128
  const ctx = useStateContext();
113
129
  const createStyle = () => {
114
130
  const position = peek$(ctx, `containerPosition${id}`);
131
+ const visible = peek$(ctx, `containerDidLayout${id}`);
115
132
  return horizontal ? {
116
133
  flexDirection: "row",
117
134
  position: "absolute",
118
- top: 0,
135
+ top: visible ? 0 : -1e7,
119
136
  bottom: 0,
120
- left: position,
121
- opacity: position < 0 ? 0 : 1
137
+ left: position
122
138
  } : {
123
139
  position: "absolute",
124
- left: 0,
140
+ left: visible ? 0 : -1e7,
125
141
  right: 0,
126
- top: position,
127
- opacity: position < 0 ? 0 : 1
142
+ top: position
128
143
  };
129
144
  };
130
- return /* @__PURE__ */ React6__namespace.createElement(
145
+ return /* @__PURE__ */ React7__namespace.default.createElement(
131
146
  $View,
132
147
  {
133
148
  $key: `containerPosition${id}`,
149
+ $key2: `containerDidLayout${id}`,
134
150
  $style: createStyle,
135
151
  onLayout: (event) => {
136
- const index = peek$(ctx, `containerItemIndex${id}`);
137
- if (index >= 0) {
152
+ const key = peek$(ctx, `containerItemKey${id}`);
153
+ if (key !== void 0) {
138
154
  const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
139
- onLayout(index, size);
155
+ onLayout(key, size);
156
+ const measured = peek$(ctx, `containerDidLayout${id}`);
157
+ if (!measured) {
158
+ requestAnimationFrame(() => {
159
+ set$(ctx, `containerDidLayout${id}`, true);
160
+ });
161
+ }
140
162
  }
141
163
  }
142
164
  },
143
- /* @__PURE__ */ React6__namespace.createElement(
165
+ /* @__PURE__ */ React7__namespace.default.createElement(
144
166
  InnerContainer,
145
167
  {
146
- id,
168
+ containerId: id,
147
169
  getRenderedItem,
148
170
  recycleItems,
149
171
  ItemSeparatorComponent
@@ -153,7 +175,7 @@ var Container = ({
153
175
  };
154
176
 
155
177
  // src/Containers.tsx
156
- var Containers = React6__namespace.memo(function Containers2({
178
+ var Containers = React7__namespace.memo(function Containers2({
157
179
  horizontal,
158
180
  recycleItems,
159
181
  ItemSeparatorComponent,
@@ -161,11 +183,11 @@ var Containers = React6__namespace.memo(function Containers2({
161
183
  getRenderedItem
162
184
  }) {
163
185
  const ctx = useStateContext();
164
- const numContainers = use$("numContainers");
186
+ const numContainers = use$("numContainersPooled");
165
187
  const containers = [];
166
188
  for (let i = 0; i < numContainers; i++) {
167
189
  containers.push(
168
- /* @__PURE__ */ React6__namespace.createElement(
190
+ /* @__PURE__ */ React7__namespace.createElement(
169
191
  Container,
170
192
  {
171
193
  id: i,
@@ -179,14 +201,18 @@ var Containers = React6__namespace.memo(function Containers2({
179
201
  )
180
202
  );
181
203
  }
182
- return /* @__PURE__ */ React6__namespace.createElement(
204
+ return /* @__PURE__ */ React7__namespace.createElement(
183
205
  $View,
184
206
  {
185
207
  $key: "totalSize",
186
- $style: () => horizontal ? {
187
- width: peek$(ctx, "totalSize")
188
- } : {
189
- height: peek$(ctx, "totalSize")
208
+ $key2: "scrollAdjust",
209
+ $style: () => {
210
+ const size = peek$(ctx, "totalSize") + peek$(ctx, "scrollAdjust");
211
+ return horizontal ? {
212
+ width: size
213
+ } : {
214
+ height: size
215
+ };
190
216
  }
191
217
  },
192
218
  containers
@@ -195,15 +221,15 @@ var Containers = React6__namespace.memo(function Containers2({
195
221
 
196
222
  // src/ListComponent.tsx
197
223
  var getComponent = (Component) => {
198
- if (React6__namespace.isValidElement(Component)) {
224
+ if (React7__namespace.isValidElement(Component)) {
199
225
  return Component;
200
226
  }
201
227
  if (Component) {
202
- return /* @__PURE__ */ React6__namespace.createElement(Component, null);
228
+ return /* @__PURE__ */ React7__namespace.createElement(Component, null);
203
229
  }
204
230
  return null;
205
231
  };
206
- var ListComponent = React6__namespace.memo(function ListComponent2({
232
+ var ListComponent = React7__namespace.memo(function ListComponent2({
207
233
  style,
208
234
  contentContainerStyle,
209
235
  horizontal,
@@ -226,8 +252,8 @@ var ListComponent = React6__namespace.memo(function ListComponent2({
226
252
  ...rest
227
253
  }) {
228
254
  const ctx = useStateContext();
229
- return /* @__PURE__ */ React6__namespace.createElement(
230
- reactNative.ScrollView,
255
+ return /* @__PURE__ */ React7__namespace.createElement(
256
+ $ScrollView,
231
257
  {
232
258
  ...rest,
233
259
  style,
@@ -239,29 +265,35 @@ var ListComponent = React6__namespace.memo(function ListComponent2({
239
265
  ],
240
266
  onScroll: handleScroll,
241
267
  onLayout,
242
- scrollEventThrottle: 32,
243
268
  horizontal,
244
269
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
245
270
  ref: refScroller
246
271
  },
247
- alignItemsAtEnd && /* @__PURE__ */ React6__namespace.createElement($View, { $key: "paddingTop", $style: () => ({ height: peek$(ctx, "paddingTop") }) }),
248
- ListHeaderComponent && /* @__PURE__ */ React6__namespace.createElement(
249
- reactNative.View,
272
+ alignItemsAtEnd && /* @__PURE__ */ React7__namespace.createElement($View, { $key: "paddingTop", $style: () => ({ height: peek$(ctx, "paddingTop") }) }),
273
+ ListHeaderComponent && /* @__PURE__ */ React7__namespace.createElement(
274
+ $View,
250
275
  {
251
- style: ListHeaderComponentStyle,
276
+ $key: "scrollAdjust",
277
+ $style: () => reactNative.StyleSheet.compose(ListHeaderComponentStyle, { top: peek$(ctx, "scrollAdjust") }),
252
278
  onLayout: (event) => {
253
279
  const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
254
280
  const prevSize = peek$(ctx, "headerSize") || 0;
255
281
  if (size !== prevSize) {
256
282
  set$(ctx, "headerSize", size);
257
- addTotalSize(size - prevSize);
258
283
  }
259
284
  }
260
285
  },
261
286
  getComponent(ListHeaderComponent)
262
287
  ),
263
- ListEmptyComponent && /* @__PURE__ */ React6__namespace.createElement(reactNative.View, { style: ListEmptyComponentStyle }, getComponent(ListEmptyComponent)),
264
- /* @__PURE__ */ React6__namespace.createElement(
288
+ ListEmptyComponent && /* @__PURE__ */ React7__namespace.createElement(
289
+ $View,
290
+ {
291
+ $key: "scrollAdjust",
292
+ $style: () => reactNative.StyleSheet.compose(ListEmptyComponentStyle, { top: peek$(ctx, "scrollAdjust") })
293
+ },
294
+ getComponent(ListEmptyComponent)
295
+ ),
296
+ /* @__PURE__ */ React7__namespace.createElement(
265
297
  Containers,
266
298
  {
267
299
  horizontal,
@@ -271,12 +303,12 @@ var ListComponent = React6__namespace.memo(function ListComponent2({
271
303
  updateItemSize
272
304
  }
273
305
  ),
274
- ListFooterComponent && /* @__PURE__ */ React6__namespace.createElement(reactNative.View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
306
+ ListFooterComponent && /* @__PURE__ */ React7__namespace.createElement(reactNative.View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
275
307
  );
276
308
  });
277
309
  var symbolFirst = Symbol();
278
310
  function useInit(cb) {
279
- const refValue = React6.useRef(symbolFirst);
311
+ const refValue = React7.useRef(symbolFirst);
280
312
  if (refValue.current === symbolFirst) {
281
313
  refValue.current = cb();
282
314
  }
@@ -287,14 +319,17 @@ function useInit(cb) {
287
319
  var mapViewabilityConfigCallbackPairs = /* @__PURE__ */ new Map();
288
320
  function setupViewability(props) {
289
321
  let { viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged } = props;
290
- viewabilityConfigCallbackPairs = viewabilityConfigCallbackPairs || [
291
- {
292
- viewabilityConfig: viewabilityConfig || {
293
- viewAreaCoveragePercentThreshold: 0
294
- },
295
- onViewableItemsChanged
296
- }
297
- ];
322
+ if (viewabilityConfig || onViewableItemsChanged) {
323
+ viewabilityConfigCallbackPairs = [
324
+ ...viewabilityConfigCallbackPairs || [],
325
+ {
326
+ viewabilityConfig: viewabilityConfig || {
327
+ viewAreaCoveragePercentThreshold: 0
328
+ },
329
+ onViewableItemsChanged
330
+ }
331
+ ];
332
+ }
298
333
  if (viewabilityConfigCallbackPairs) {
299
334
  for (const pair of viewabilityConfigCallbackPairs) {
300
335
  mapViewabilityConfigCallbackPairs.set(pair.viewabilityConfig.id, {
@@ -390,7 +425,7 @@ function isViewable(state, ctx, viewabilityConfig, key, scrollSize, item, index)
390
425
  const percentOfScroller = size ? 100 * (sizeVisible / scrollSize) : 0;
391
426
  const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
392
427
  const isViewable2 = percent >= viewablePercentThreshold;
393
- const containerId = findContainerId(state, ctx, index);
428
+ const containerId = findContainerId(ctx, key);
394
429
  const value = {
395
430
  index,
396
431
  isViewable: isViewable2,
@@ -410,11 +445,11 @@ function isViewable(state, ctx, viewabilityConfig, key, scrollSize, item, index)
410
445
  }
411
446
  return isViewable2;
412
447
  }
413
- function findContainerId(state, ctx, index) {
448
+ function findContainerId(ctx, key) {
414
449
  const numContainers = peek$(ctx, "numContainers");
415
450
  for (let i = 0; i < numContainers; i++) {
416
- const itemIndex = peek$(ctx, `containerItemIndex${i}`);
417
- if (itemIndex === index) {
451
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
452
+ if (itemKey === key) {
418
453
  return i;
419
454
  }
420
455
  }
@@ -428,48 +463,44 @@ function maybeUpdateViewabilityCallback(ctx, configId, viewToken) {
428
463
  }
429
464
 
430
465
  // src/LegendList.tsx
431
- var DEFAULT_SCROLL_BUFFER = 0;
432
- var POSITION_OUT_OF_VIEW = -1e4;
433
- var LegendList = React6.forwardRef(function LegendList2(props, forwardedRef) {
434
- return /* @__PURE__ */ React6__namespace.createElement(StateProvider, null, /* @__PURE__ */ React6__namespace.createElement(LegendListInner, { ...props, ref: forwardedRef }));
466
+ var DEFAULT_DRAW_DISTANCE = 250;
467
+ var INITIAL_SCROLL_ADJUST = 1e4;
468
+ var POSITION_OUT_OF_VIEW = -1e7;
469
+ var LegendList = React7.forwardRef(function LegendList2(props, forwardedRef) {
470
+ return /* @__PURE__ */ React7__namespace.createElement(StateProvider, null, /* @__PURE__ */ React7__namespace.createElement(LegendListInner, { ...props, ref: forwardedRef }));
435
471
  });
436
- var LegendListInner = React6.forwardRef(function LegendListInner2(props, forwardedRef) {
437
- var _a, _b;
472
+ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forwardedRef) {
473
+ var _a, _b, _c, _d, _e;
438
474
  const {
439
475
  data,
440
476
  initialScrollIndex,
441
477
  initialScrollOffset,
442
478
  horizontal,
443
- style: styleProp,
444
- contentContainerStyle: contentContainerStyleProp,
445
479
  initialNumContainers,
446
480
  drawDistance = 250,
447
481
  recycleItems = false,
448
482
  onEndReachedThreshold = 0.5,
483
+ onStartReachedThreshold = 0.5,
449
484
  maintainScrollAtEnd = false,
450
485
  maintainScrollAtEndThreshold = 0.1,
451
486
  alignItemsAtEnd = false,
487
+ maintainVisibleContentPosition = false,
452
488
  onScroll: onScrollProp,
453
489
  keyExtractor,
454
490
  renderItem,
455
491
  estimatedItemSize,
456
492
  getEstimatedItemSize,
457
493
  onEndReached,
494
+ onStartReached,
458
495
  ListEmptyComponent,
459
496
  ...rest
460
497
  } = props;
498
+ const { style, contentContainerStyle } = rest;
461
499
  const ctx = useStateContext();
462
- const internalRef = React6.useRef(null);
500
+ const internalRef = React7.useRef(null);
463
501
  const refScroller = internalRef;
464
- const scrollBuffer = drawDistance != null ? drawDistance : DEFAULT_SCROLL_BUFFER;
465
- const styleFlattened = reactNative.StyleSheet.flatten(styleProp);
466
- const style = React6.useMemo(() => styleFlattened, [JSON.stringify(styleFlattened)]);
467
- const contentContainerStyleFlattened = reactNative.StyleSheet.flatten(contentContainerStyleProp);
468
- const contentContainerStyle = React6.useMemo(
469
- () => contentContainerStyleFlattened,
470
- [JSON.stringify(contentContainerStyleProp)]
471
- );
472
- const refState = React6.useRef();
502
+ const scrollBuffer = drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE;
503
+ const refState = React7.useRef();
473
504
  const getId = (index) => {
474
505
  var _a2;
475
506
  const data2 = (_a2 = refState.current) == null ? void 0 : _a2.data;
@@ -479,36 +510,41 @@ var LegendListInner = React6.forwardRef(function LegendListInner2(props, forward
479
510
  const ret = index < data2.length ? keyExtractor ? keyExtractor(data2[index], index) : index : null;
480
511
  return `${ret}`;
481
512
  };
482
- const getItemSize = (index, data2) => {
483
- return getEstimatedItemSize ? getEstimatedItemSize(index, data2) : estimatedItemSize;
513
+ const getItemSize = (key, index, data2) => {
514
+ const sizeKnown = refState.current.sizes.get(key);
515
+ if (sizeKnown !== void 0) {
516
+ return sizeKnown;
517
+ }
518
+ const size = getEstimatedItemSize ? getEstimatedItemSize(index, data2) : estimatedItemSize;
519
+ refState.current.sizes.set(key, size);
520
+ return size;
484
521
  };
485
522
  const calculateInitialOffset = (index = initialScrollIndex) => {
486
523
  if (index) {
524
+ let offset = 0;
487
525
  if (getEstimatedItemSize) {
488
- let offset = 0;
489
526
  for (let i = 0; i < index; i++) {
490
527
  offset += getEstimatedItemSize(i, data[i]);
491
528
  }
492
- return offset;
493
- }
494
- if (estimatedItemSize) {
495
- return index * estimatedItemSize;
529
+ } else if (estimatedItemSize) {
530
+ offset = index * estimatedItemSize;
496
531
  }
532
+ return offset + (maintainVisibleContentPosition ? INITIAL_SCROLL_ADJUST : 0);
497
533
  }
498
534
  return void 0;
499
535
  };
500
- const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : React6.useMemo(calculateInitialOffset, []);
536
+ const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : React7.useMemo(calculateInitialOffset, []);
501
537
  if (!refState.current) {
502
538
  refState.current = {
503
539
  sizes: /* @__PURE__ */ new Map(),
504
540
  positions: /* @__PURE__ */ new Map(),
505
541
  pendingAdjust: 0,
506
- animFrameScroll: null,
507
542
  animFrameLayout: null,
508
543
  animFrameTotalSize: null,
509
544
  isStartReached: false,
510
545
  isEndReached: false,
511
546
  isAtBottom: false,
547
+ isAtTop: false,
512
548
  data,
513
549
  idsInFirstRender: void 0,
514
550
  hasScrolled: false,
@@ -521,51 +557,324 @@ var LegendListInner = React6.forwardRef(function LegendListInner2(props, forward
521
557
  totalSize: 0,
522
558
  timeouts: /* @__PURE__ */ new Set(),
523
559
  viewabilityConfigCallbackPairs: void 0,
524
- renderItem: void 0
560
+ renderItem: void 0,
561
+ scrollAdjustPending: maintainVisibleContentPosition ? INITIAL_SCROLL_ADJUST : 0,
562
+ nativeMarginTop: 0,
563
+ scrollPrev: 0,
564
+ scrollPrevTime: 0,
565
+ scrollTime: 0,
566
+ indexByKey: /* @__PURE__ */ new Map(),
567
+ scrollHistory: [],
568
+ scrollVelocity: 0,
569
+ contentSize: { width: 0, height: 0 }
525
570
  };
526
571
  refState.current.idsInFirstRender = new Set(data.map((_, i) => getId(i)));
572
+ set$(ctx, "scrollAdjust", refState.current.scrollAdjustPending);
527
573
  }
528
- refState.current.data = data;
529
- refState.current.renderItem = renderItem;
530
- set$(ctx, "numItems", data.length);
531
- set$(ctx, "stylePaddingTop", (_b = (_a = styleFlattened == null ? void 0 : styleFlattened.paddingTop) != null ? _a : contentContainerStyleFlattened == null ? void 0 : contentContainerStyleFlattened.paddingTop) != null ? _b : 0);
532
- const addTotalSize = React6.useCallback((add) => {
533
- const prev = refState.current.totalSize;
534
- refState.current.totalSize += add;
535
- const totalSize = refState.current.totalSize;
574
+ const adjustScroll = (diff) => {
575
+ if (maintainVisibleContentPosition && refScroller.current) {
576
+ refState.current.scrollAdjustPending -= diff;
577
+ }
578
+ };
579
+ const addTotalSize = React7.useCallback((key, add, set) => {
580
+ const state = refState.current;
581
+ const index = key === null ? 0 : state.indexByKey.get(key);
582
+ const isAbove = index < (state.startNoBuffer || 0);
583
+ const prev = state.totalSize;
584
+ if (set) {
585
+ state.totalSize = add;
586
+ } else {
587
+ state.totalSize += add;
588
+ }
536
589
  const doAdd = () => {
537
- refState.current.animFrameTotalSize = null;
590
+ const totalSize = state.totalSize;
591
+ state.animFrameTotalSize = null;
538
592
  set$(ctx, "totalSize", totalSize);
539
- const screenLength = refState.current.scrollLength;
540
593
  if (alignItemsAtEnd) {
541
- const listPaddingTop = peek$(ctx, "stylePaddingTop");
542
- set$(ctx, "paddingTop", Math.max(0, screenLength - totalSize - listPaddingTop));
594
+ doUpdatePaddingTop();
543
595
  }
544
596
  };
545
- if (!prev) {
597
+ if (isAbove) {
598
+ adjustScroll(add);
599
+ }
600
+ if (!prev || set) {
546
601
  doAdd();
547
- } else if (!refState.current.animFrameTotalSize) {
548
- refState.current.animFrameTotalSize = requestAnimationFrame(doAdd);
602
+ } else if (!state.animFrameTotalSize) {
603
+ state.animFrameTotalSize = requestAnimationFrame(doAdd);
549
604
  }
550
605
  }, []);
551
- const getRenderedItem = React6.useCallback((index, containerId) => {
552
- var _a2, _b2, _c;
553
- const data2 = (_a2 = refState.current) == null ? void 0 : _a2.data;
606
+ const calculateItemsInView = React7.useCallback((speed = 0) => {
607
+ var _a2, _b2, _c2;
608
+ const state = refState.current;
609
+ const { data: data2, scrollLength, scroll: scrollState, startBuffered: startBufferedState, positions } = state;
610
+ if (state.animFrameLayout) {
611
+ cancelAnimationFrame(state.animFrameLayout);
612
+ state.animFrameLayout = null;
613
+ }
554
614
  if (!data2) {
615
+ return;
616
+ }
617
+ const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
618
+ const scrollAdjustPending = (_a2 = state.scrollAdjustPending) != null ? _a2 : 0;
619
+ const scrollExtra = Math.max(-16, Math.min(16, speed)) * 32;
620
+ const scroll = Math.max(
621
+ 0,
622
+ scrollState - topPad - (USE_CONTENT_INSET ? scrollAdjustPending : 0) + scrollExtra
623
+ );
624
+ let startNoBuffer = null;
625
+ let startBuffered = null;
626
+ let endNoBuffer = null;
627
+ let endBuffered = null;
628
+ let loopStart = startBufferedState || 0;
629
+ if (startBufferedState) {
630
+ for (let i = startBufferedState; i >= 0; i--) {
631
+ const id = getId(i);
632
+ const top2 = positions.get(id);
633
+ if (top2 !== void 0) {
634
+ const size = getItemSize(id, i, data2[i]);
635
+ const bottom = top2 + size;
636
+ if (bottom > scroll - scrollBuffer) {
637
+ loopStart = i;
638
+ } else {
639
+ break;
640
+ }
641
+ }
642
+ }
643
+ }
644
+ let top = loopStart > 0 ? positions.get(getId(loopStart)) : 0;
645
+ for (let i = loopStart; i < data2.length; i++) {
646
+ const id = getId(i);
647
+ const size = getItemSize(id, i, data2[i]);
648
+ if (positions.get(id) !== top) {
649
+ positions.set(id, top);
650
+ }
651
+ if (startNoBuffer === null && top + size > scroll) {
652
+ startNoBuffer = i;
653
+ }
654
+ if (startBuffered === null && top + size > scroll - scrollBuffer) {
655
+ startBuffered = i;
656
+ }
657
+ if (startNoBuffer !== null) {
658
+ if (top <= scroll + scrollLength) {
659
+ endNoBuffer = i;
660
+ }
661
+ if (top <= scroll + scrollLength + scrollBuffer) {
662
+ endBuffered = i;
663
+ } else {
664
+ break;
665
+ }
666
+ }
667
+ top += size;
668
+ }
669
+ Object.assign(refState.current, {
670
+ startBuffered,
671
+ startNoBuffer,
672
+ endBuffered,
673
+ endNoBuffer
674
+ });
675
+ if (startBuffered !== null && endBuffered !== null) {
676
+ const prevNumContainers = ctx.values.get("numContainers");
677
+ let numContainers = prevNumContainers;
678
+ for (let i = startBuffered; i <= endBuffered; i++) {
679
+ let isContained = false;
680
+ const id = getId(i);
681
+ for (let j = 0; j < numContainers; j++) {
682
+ const key = peek$(ctx, `containerItemKey${j}`);
683
+ if (key === id) {
684
+ isContained = true;
685
+ break;
686
+ }
687
+ }
688
+ if (!isContained) {
689
+ const top2 = (positions.get(id) || 0) + scrollAdjustPending;
690
+ let furthestIndex = -1;
691
+ let furthestDistance = 0;
692
+ for (let u = 0; u < numContainers; u++) {
693
+ const key = peek$(ctx, `containerItemKey${u}`);
694
+ if (key === void 0) {
695
+ furthestIndex = u;
696
+ break;
697
+ }
698
+ const index = (_b2 = refState.current) == null ? void 0 : _b2.indexByKey.get(key);
699
+ const pos = peek$(ctx, `containerPosition${u}`);
700
+ if (index < startBuffered || index > endBuffered) {
701
+ const distance = Math.abs(pos - top2);
702
+ if (index < 0 || distance > furthestDistance) {
703
+ furthestDistance = distance;
704
+ furthestIndex = u;
705
+ }
706
+ }
707
+ }
708
+ if (furthestIndex >= 0) {
709
+ set$(ctx, `containerItemKey${furthestIndex}`, id);
710
+ } else {
711
+ const containerId = numContainers;
712
+ numContainers++;
713
+ set$(ctx, `containerItemKey${containerId}`, id);
714
+ set$(ctx, `containerPosition${containerId}`, POSITION_OUT_OF_VIEW);
715
+ if (__DEV__ && numContainers > peek$(ctx, "numContainersPooled")) {
716
+ console.warn(
717
+ "[legend-list] No container to recycle, consider increasing initialContainers or estimatedItemSize. numContainers:",
718
+ numContainers
719
+ );
720
+ }
721
+ }
722
+ }
723
+ }
724
+ if (numContainers !== prevNumContainers) {
725
+ set$(ctx, "numContainers", numContainers);
726
+ if (numContainers > peek$(ctx, "numContainersPooled")) {
727
+ set$(ctx, "numContainersPooled", numContainers);
728
+ }
729
+ }
730
+ for (let i = 0; i < numContainers; i++) {
731
+ const itemKey = peek$(ctx, `containerItemKey${i}`);
732
+ const itemIndex = (_c2 = refState.current) == null ? void 0 : _c2.indexByKey.get(itemKey);
733
+ const item = data2[itemIndex];
734
+ if (item) {
735
+ const id = getId(itemIndex);
736
+ if (!(itemKey !== id || itemIndex < startBuffered || itemIndex > endBuffered)) {
737
+ const pos = (positions.get(id) || 0) + scrollAdjustPending;
738
+ const prevPos = peek$(ctx, `containerPosition${i}`);
739
+ if (pos >= 0 && pos !== prevPos) {
740
+ set$(ctx, `containerPosition${i}`, pos);
741
+ }
742
+ }
743
+ }
744
+ }
745
+ }
746
+ if (refState.current.viewabilityConfigCallbackPairs) {
747
+ updateViewableItems(
748
+ refState.current,
749
+ ctx,
750
+ refState.current.viewabilityConfigCallbackPairs,
751
+ getId,
752
+ scrollLength,
753
+ startNoBuffer,
754
+ endNoBuffer
755
+ );
756
+ }
757
+ }, []);
758
+ const doUpdatePaddingTop = () => {
759
+ if (alignItemsAtEnd) {
760
+ const { scrollLength, totalSize } = refState.current;
761
+ const listPaddingTop = peek$(ctx, "stylePaddingTop") || 0;
762
+ const paddingTop = Math.max(0, Math.floor(scrollLength - totalSize - listPaddingTop));
763
+ set$(ctx, "paddingTop", paddingTop);
764
+ }
765
+ };
766
+ const doMaintainScrollAtEnd = (animated) => {
767
+ var _a2;
768
+ if (((_a2 = refState.current) == null ? void 0 : _a2.isAtBottom) && maintainScrollAtEnd) {
769
+ refState.current.scroll = refState.current.totalSize - refState.current.scrollLength;
770
+ requestAnimationFrame(() => {
771
+ var _a3;
772
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
773
+ animated
774
+ });
775
+ });
776
+ }
777
+ };
778
+ const checkAtBottom = () => {
779
+ var _a2;
780
+ const { scrollLength, scroll, contentSize } = refState.current;
781
+ const distanceFromEnd = contentSize[horizontal ? "width" : "height"] - scroll - scrollLength;
782
+ if (refState.current) {
783
+ refState.current.isAtBottom = distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
784
+ }
785
+ if (onEndReached && !((_a2 = refState.current) == null ? void 0 : _a2.isEndReached)) {
786
+ if (distanceFromEnd < onEndReachedThreshold * scrollLength) {
787
+ if (refState.current) {
788
+ refState.current.isEndReached = true;
789
+ }
790
+ onEndReached({ distanceFromEnd });
791
+ }
792
+ }
793
+ };
794
+ const checkAtTop = () => {
795
+ var _a2;
796
+ const { scrollLength, scroll } = refState.current;
797
+ if (refState.current) {
798
+ refState.current.isAtTop = scroll === 0;
799
+ }
800
+ if (onStartReached && !((_a2 = refState.current) == null ? void 0 : _a2.isStartReached)) {
801
+ if (scroll < onStartReachedThreshold * scrollLength) {
802
+ if (refState.current) {
803
+ refState.current.isStartReached = true;
804
+ }
805
+ onStartReached({ distanceFromStart: scroll });
806
+ }
807
+ }
808
+ };
809
+ const isFirst = !refState.current.renderItem;
810
+ if (isFirst || data !== refState.current.data) {
811
+ refState.current.data = data;
812
+ let totalSize = 0;
813
+ const indexByKey = /* @__PURE__ */ new Map();
814
+ for (let i = 0; i < data.length; i++) {
815
+ const key = getId(i);
816
+ indexByKey.set(key, i);
817
+ totalSize += getItemSize(key, i, data[i]);
818
+ if (maintainVisibleContentPosition && i < refState.current.startNoBuffer && !refState.current.indexByKey.has(key)) {
819
+ const size = getItemSize(key, i, data[i]);
820
+ adjustScroll(size);
821
+ }
822
+ }
823
+ addTotalSize(null, totalSize, true);
824
+ if (maintainVisibleContentPosition) {
825
+ for (const [key, index] of refState.current.indexByKey) {
826
+ if (index < refState.current.startNoBuffer && !indexByKey.has(key)) {
827
+ const size = (_a = refState.current.sizes.get(key)) != null ? _a : 0;
828
+ if (size) {
829
+ adjustScroll(-size);
830
+ }
831
+ }
832
+ }
833
+ }
834
+ refState.current.indexByKey = indexByKey;
835
+ if (!isFirst) {
836
+ refState.current.isEndReached = false;
837
+ const numContainers = peek$(ctx, "numContainers");
838
+ for (let i = 0; i < numContainers; i++) {
839
+ set$(ctx, `containerItemKey${i}`, void 0);
840
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
841
+ }
842
+ calculateItemsInView();
843
+ doMaintainScrollAtEnd(false);
844
+ checkAtTop();
845
+ checkAtBottom();
846
+ }
847
+ }
848
+ refState.current.renderItem = renderItem;
849
+ set$(ctx, "lastItemKey", getId(data[data.length - 1]));
850
+ set$(
851
+ ctx,
852
+ "stylePaddingTop",
853
+ (_e = (_d = (_b = reactNative.StyleSheet.flatten(style)) == null ? void 0 : _b.paddingTop) != null ? _d : (_c = reactNative.StyleSheet.flatten(contentContainerStyle)) == null ? void 0 : _c.paddingTop) != null ? _e : 0
854
+ );
855
+ const getRenderedItem = React7.useCallback((key, containerId) => {
856
+ var _a2, _b2;
857
+ const state = refState.current;
858
+ if (!state) {
859
+ return null;
860
+ }
861
+ const { data: data2, indexByKey } = state;
862
+ const index = indexByKey.get(key);
863
+ if (index === void 0) {
555
864
  return null;
556
865
  }
557
866
  const useViewability = (configId, callback) => {
558
- const key = containerId + configId;
867
+ const key2 = containerId + configId;
559
868
  useInit(() => {
560
- const value = ctx.mapViewabilityValues.get(key);
869
+ const value = ctx.mapViewabilityValues.get(key2);
561
870
  if (value) {
562
871
  callback(value);
563
872
  }
564
873
  });
565
- ctx.mapViewabilityCallbacks.set(key, callback);
566
- React6.useEffect(
874
+ ctx.mapViewabilityCallbacks.set(key2, callback);
875
+ React7.useEffect(
567
876
  () => () => {
568
- ctx.mapViewabilityCallbacks.delete(key);
877
+ ctx.mapViewabilityCallbacks.delete(key2);
569
878
  },
570
879
  []
571
880
  );
@@ -578,7 +887,7 @@ var LegendListInner = React6.forwardRef(function LegendListInner2(props, forward
578
887
  }
579
888
  });
580
889
  ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
581
- React6.useEffect(
890
+ React7.useEffect(
582
891
  () => () => {
583
892
  ctx.mapViewabilityAmountCallbacks.delete(containerId);
584
893
  },
@@ -586,15 +895,16 @@ var LegendListInner = React6.forwardRef(function LegendListInner2(props, forward
586
895
  );
587
896
  };
588
897
  const useRecyclingEffect = (effect) => {
589
- React6.useEffect(() => {
590
- const state = refState.current;
898
+ React7.useEffect(() => {
899
+ const state2 = refState.current;
591
900
  let prevIndex = index;
592
- let prevItem = state.data[index];
593
- const signal = `containerItemIndex${containerId}`;
594
- listen$(ctx, signal, () => {
595
- const data3 = state.data;
901
+ let prevItem = state2.data[index];
902
+ const signal = `containerItemKey${containerId}`;
903
+ const run = () => {
904
+ const data3 = state2.data;
596
905
  if (data3) {
597
- const newIndex = peek$(ctx, signal);
906
+ const newKey = peek$(ctx, signal);
907
+ const newIndex = state2.indexByKey.get(newKey);
598
908
  const newItem = data3[newIndex];
599
909
  if (newItem) {
600
910
  effect({
@@ -607,11 +917,13 @@ var LegendListInner = React6.forwardRef(function LegendListInner2(props, forward
607
917
  prevIndex = newIndex;
608
918
  prevItem = newItem;
609
919
  }
610
- });
920
+ };
921
+ run();
922
+ listen$(ctx, signal, run);
611
923
  }, []);
612
924
  };
613
925
  const useRecyclingState = (updateState) => {
614
- const stateInfo = React6.useState(
926
+ const stateInfo = React7.useState(
615
927
  () => updateState({
616
928
  index,
617
929
  item: refState.current.data[index],
@@ -619,13 +931,13 @@ var LegendListInner = React6.forwardRef(function LegendListInner2(props, forward
619
931
  prevItem: void 0
620
932
  })
621
933
  );
622
- useRecyclingEffect((state) => {
623
- const newState = updateState(state);
934
+ useRecyclingEffect((state2) => {
935
+ const newState = updateState(state2);
624
936
  stateInfo[1](newState);
625
937
  });
626
938
  return stateInfo;
627
939
  };
628
- const renderedItem = (_c = (_b2 = refState.current).renderItem) == null ? void 0 : _c.call(_b2, {
940
+ const renderedItem = (_b2 = (_a2 = refState.current).renderItem) == null ? void 0 : _b2.call(_a2, {
629
941
  item: data2[index],
630
942
  index,
631
943
  useViewability,
@@ -635,250 +947,62 @@ var LegendListInner = React6.forwardRef(function LegendListInner2(props, forward
635
947
  });
636
948
  return renderedItem;
637
949
  }, []);
638
- const calculateItemsInView = React6.useCallback(() => {
639
- reactNative.unstable_batchedUpdates(() => {
640
- var _a2, _b2, _c;
641
- const {
642
- data: data2,
643
- scrollLength,
644
- scroll: scrollState,
645
- startBuffered: startBufferedState
646
- } = refState.current;
647
- if (!data2) {
648
- return;
649
- }
650
- const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
651
- const scroll = scrollState - topPad;
652
- const { sizes, positions } = refState.current;
653
- let startNoBuffer = null;
654
- let startBuffered = null;
655
- let endNoBuffer = null;
656
- let endBuffered = null;
657
- let loopStart = startBufferedState || 0;
658
- if (startBufferedState) {
659
- for (let i = startBufferedState; i >= 0; i--) {
660
- const id = getId(i);
661
- const top2 = positions.get(id);
662
- if (top2 !== void 0) {
663
- const size = (_a2 = sizes.get(id)) != null ? _a2 : getItemSize(i, data2[i]);
664
- const bottom = top2 + size;
665
- if (bottom > scroll - scrollBuffer) {
666
- loopStart = i;
667
- } else {
668
- break;
669
- }
670
- }
671
- }
672
- }
673
- let top = loopStart > 0 ? positions.get(getId(loopStart)) : 0;
674
- for (let i = loopStart; i < data2.length; i++) {
675
- const id = getId(i);
676
- const size = (_b2 = sizes.get(id)) != null ? _b2 : getItemSize(i, data2[i]);
677
- if (positions.get(id) !== top) {
678
- positions.set(id, top);
679
- }
680
- if (startNoBuffer === null && top + size > scroll) {
681
- startNoBuffer = i;
682
- }
683
- if (startBuffered === null && top + size > scroll - scrollBuffer) {
684
- startBuffered = i;
685
- }
686
- if (startNoBuffer !== null) {
687
- if (top <= scroll + scrollLength) {
688
- endNoBuffer = i;
689
- }
690
- if (top <= scroll + scrollLength + scrollBuffer) {
691
- endBuffered = i;
692
- } else {
693
- break;
694
- }
695
- }
696
- top += size;
697
- }
698
- Object.assign(refState.current, {
699
- startBuffered,
700
- startNoBuffer,
701
- endBuffered,
702
- endNoBuffer
703
- });
704
- if (startBuffered !== null && endBuffered !== null) {
705
- const prevNumContainers = ctx.values.get("numContainers");
706
- let numContainers = prevNumContainers;
707
- for (let i = startBuffered; i <= endBuffered; i++) {
708
- let isContained = false;
709
- const id = getId(i);
710
- for (let j = 0; j < numContainers; j++) {
711
- const index = peek$(ctx, `containerItemIndex${j}`);
712
- const key = peek$(ctx, `containerItemKey${j}`);
713
- if (index === i && key === id) {
714
- isContained = true;
715
- break;
716
- }
717
- }
718
- if (!isContained) {
719
- const top2 = positions.get(id) || 0;
720
- let furthestIndex = -1;
721
- let furthestDistance = 0;
722
- for (let u = 0; u < numContainers; u++) {
723
- const index = peek$(ctx, `containerItemIndex${u}`);
724
- if (index < 0) {
725
- furthestIndex = u;
726
- break;
727
- }
728
- const pos = peek$(ctx, `containerPosition${u}`);
729
- if (index < startBuffered || index > endBuffered) {
730
- const distance = Math.abs(pos - top2);
731
- if (index < 0 || distance > furthestDistance) {
732
- furthestDistance = distance;
733
- furthestIndex = u;
734
- }
735
- }
736
- }
737
- if (furthestIndex >= 0) {
738
- set$(ctx, `containerItemIndex${furthestIndex}`, i);
739
- set$(ctx, `containerItemKey${furthestIndex}`, id);
740
- } else {
741
- if (__DEV__) {
742
- console.warn(
743
- "[legend-list] No container to recycle, consider increasing initialContainers or estimatedItemSize",
744
- i
745
- );
746
- }
747
- const containerId = numContainers;
748
- numContainers++;
749
- set$(ctx, `containerItemIndex${containerId}`, i);
750
- set$(ctx, `containerItemKey${containerId}`, id);
751
- set$(ctx, `containerPosition${containerId}`, POSITION_OUT_OF_VIEW);
752
- }
753
- }
754
- }
755
- if (numContainers !== prevNumContainers) {
756
- set$(ctx, "numContainers", numContainers);
757
- }
758
- for (let i = 0; i < numContainers; i++) {
759
- const itemIndex = peek$(ctx, `containerItemIndex${i}`);
760
- const itemKey = peek$(ctx, `containerItemKey${i}`);
761
- const item = data2[itemIndex];
762
- if (item) {
763
- const id = getId(itemIndex);
764
- if (itemKey !== id || itemIndex < startBuffered || itemIndex > endBuffered) {
765
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
766
- } else {
767
- const pos = (_c = positions.get(id)) != null ? _c : -1;
768
- const prevPos = peek$(ctx, `containerPosition${i}`);
769
- if (pos >= 0 && pos !== prevPos) {
770
- set$(ctx, `containerPosition${i}`, pos);
771
- }
772
- }
773
- }
774
- }
775
- }
776
- if (refState.current.viewabilityConfigCallbackPairs) {
777
- updateViewableItems(
778
- refState.current,
779
- ctx,
780
- refState.current.viewabilityConfigCallbackPairs,
781
- getId,
782
- scrollLength,
783
- startNoBuffer,
784
- endNoBuffer
785
- );
786
- }
787
- });
788
- }, []);
789
950
  useInit(() => {
790
- var _a2;
791
951
  refState.current.viewabilityConfigCallbackPairs = setupViewability(props);
792
952
  const scrollLength = refState.current.scrollLength;
793
953
  const averageItemSize = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, data[0]);
794
- const numContainers = initialNumContainers || Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) + 4;
954
+ const numContainers = initialNumContainers || Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize);
795
955
  for (let i = 0; i < numContainers; i++) {
796
- set$(ctx, `containerItemIndex${i}`, -1);
797
956
  set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
798
957
  }
799
958
  set$(ctx, "numContainers", numContainers);
959
+ set$(ctx, "numContainersPooled", numContainers * 2);
800
960
  calculateItemsInView();
801
- const sizes = refState.current.sizes;
802
- let totalSize = 0;
803
- for (let i = 0; i < data.length; i++) {
804
- const id = getId(i);
805
- totalSize += (_a2 = sizes.get(id)) != null ? _a2 : getItemSize(i, data[i]);
806
- }
807
- addTotalSize(totalSize);
808
961
  });
809
- const checkAtBottom = () => {
962
+ const updateItemSize = React7.useCallback((key, size) => {
810
963
  var _a2;
811
- const { scrollLength, scroll } = refState.current;
812
- const totalSize = peek$(ctx, "totalSize");
813
- const distanceFromEnd = totalSize - scroll - scrollLength;
814
- if (refState.current) {
815
- refState.current.isAtBottom = distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
816
- }
817
- if (onEndReached && !((_a2 = refState.current) == null ? void 0 : _a2.isEndReached)) {
818
- if (distanceFromEnd < onEndReachedThreshold * scrollLength) {
819
- if (refState.current) {
820
- refState.current.isEndReached = true;
821
- }
822
- onEndReached({ distanceFromEnd });
823
- }
824
- }
825
- };
826
- React6.useEffect(() => {
827
- if (refState.current) {
828
- refState.current.isEndReached = false;
829
- }
830
- const numContainers = peek$(ctx, "numContainers");
831
- if (data.length < numContainers) {
832
- for (let i = 0; i < numContainers; i++) {
833
- const itemIndex = peek$(ctx, `containerItemIndex${i}`);
834
- if (itemIndex >= data.length) {
835
- set$(ctx, `containerItemIndex${i}`, -1);
836
- }
837
- }
838
- }
839
- calculateItemsInView();
840
- checkAtBottom();
841
- }, [data]);
842
- const updateItemSize = React6.useCallback((index, size) => {
843
- var _a2, _b2, _c;
844
964
  const data2 = (_a2 = refState.current) == null ? void 0 : _a2.data;
845
965
  if (!data2) {
846
966
  return;
847
967
  }
848
- const sizes = refState.current.sizes;
849
- const id = getId(index);
850
- const wasInFirstRender = (_b2 = refState.current) == null ? void 0 : _b2.idsInFirstRender.has(id);
851
- const prevSize = sizes.get(id) || (wasInFirstRender ? getItemSize(index, data2[index]) : 0);
968
+ const { sizes, indexByKey, idsInFirstRender } = refState.current;
969
+ const index = indexByKey.get(key);
970
+ const wasInFirstRender = idsInFirstRender.has(key);
971
+ const prevSize = sizes.get(key) || (wasInFirstRender ? getItemSize(key, index, data2[index]) : 0);
852
972
  if (!prevSize || Math.abs(prevSize - size) > 0.5) {
853
- sizes.set(id, size);
854
- addTotalSize(size - prevSize);
855
- if (((_c = refState.current) == null ? void 0 : _c.isAtBottom) && maintainScrollAtEnd) {
856
- requestAnimationFrame(() => {
857
- var _a3;
858
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
859
- animated: true
860
- });
861
- });
862
- }
973
+ sizes.set(key, size);
974
+ addTotalSize(key, size - prevSize);
975
+ doMaintainScrollAtEnd(true);
863
976
  const state = refState.current;
864
- if (!state.animFrameScroll && !state.animFrameLayout) {
977
+ const scrollVelocity = state.scrollVelocity;
978
+ if (!state.animFrameLayout && (Number.isNaN(scrollVelocity) || Math.abs(scrollVelocity) < 1)) {
865
979
  state.animFrameLayout = requestAnimationFrame(() => {
866
980
  state.animFrameLayout = null;
867
- calculateItemsInView();
981
+ calculateItemsInView(state.scrollVelocity);
868
982
  });
869
983
  }
870
984
  }
871
985
  }, []);
872
- const handleScrollDebounced = React6.useCallback(() => {
873
- calculateItemsInView();
986
+ const handleScrollDebounced = React7.useCallback((velocity) => {
987
+ var _a2, _b2;
988
+ const scrollAdjustPending = (_b2 = (_a2 = refState.current) == null ? void 0 : _a2.scrollAdjustPending) != null ? _b2 : 0;
989
+ set$(ctx, "scrollAdjust", scrollAdjustPending);
990
+ calculateItemsInView(velocity);
874
991
  checkAtBottom();
875
- if (refState.current) {
876
- refState.current.animFrameScroll = null;
877
- }
992
+ checkAtTop();
878
993
  }, []);
879
- const onLayout = React6.useCallback((event) => {
880
- const scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
994
+ const onLayout = React7.useCallback((event) => {
995
+ let scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
996
+ if (!USE_CONTENT_INSET) {
997
+ scrollLength += event.nativeEvent.layout[horizontal ? "x" : "y"];
998
+ }
881
999
  refState.current.scrollLength = scrollLength;
1000
+ if (refState.current.hasScrolled) {
1001
+ doMaintainScrollAtEnd(false);
1002
+ doUpdatePaddingTop();
1003
+ checkAtBottom();
1004
+ checkAtTop();
1005
+ }
882
1006
  if (__DEV__) {
883
1007
  const isWidthZero = event.nativeEvent.layout.width === 0;
884
1008
  const isHeightZero = event.nativeEvent.layout.height === 0;
@@ -889,25 +1013,42 @@ var LegendListInner = React6.forwardRef(function LegendListInner2(props, forward
889
1013
  }
890
1014
  }
891
1015
  }, []);
892
- const handleScroll = React6.useCallback(
1016
+ const handleScroll = React7.useCallback(
893
1017
  (event, fromSelf) => {
894
- var _a2, _b2, _c;
895
- if (((_b2 = (_a2 = event.nativeEvent) == null ? void 0 : _a2.contentSize) == null ? void 0 : _b2.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
1018
+ var _a2, _b2, _c2;
1019
+ if (((_b2 = (_a2 = event.nativeEvent) == null ? void 0 : _a2.contentSize) == null ? void 0 : _b2.height) === 0 && ((_c2 = event.nativeEvent.contentSize) == null ? void 0 : _c2.width) === 0) {
896
1020
  return;
897
1021
  }
898
- refState.current.hasScrolled = true;
1022
+ const state = refState.current;
1023
+ state.hasScrolled = true;
1024
+ state.contentSize = event.nativeEvent.contentSize;
1025
+ const currentTime = performance.now();
899
1026
  const newScroll = event.nativeEvent.contentOffset[horizontal ? "x" : "y"];
900
- refState.current.scroll = newScroll;
901
- if (refState.current && !refState.current.animFrameScroll) {
902
- refState.current.animFrameScroll = requestAnimationFrame(handleScrollDebounced);
1027
+ state.scrollHistory.push({ scroll: newScroll, time: currentTime });
1028
+ if (state.scrollHistory.length > 5) {
1029
+ state.scrollHistory.shift();
1030
+ }
1031
+ let velocity = 0;
1032
+ if (state.scrollHistory.length >= 2) {
1033
+ const newest = state.scrollHistory[state.scrollHistory.length - 1];
1034
+ const oldest = state.scrollHistory[0];
1035
+ const scrollDiff = newest.scroll - oldest.scroll;
1036
+ const timeDiff = newest.time - oldest.time;
1037
+ velocity = timeDiff > 0 ? scrollDiff / timeDiff : 0;
903
1038
  }
1039
+ state.scrollPrev = state.scroll;
1040
+ state.scrollPrevTime = state.scrollTime;
1041
+ state.scroll = newScroll;
1042
+ state.scrollTime = currentTime;
1043
+ state.scrollVelocity = velocity;
1044
+ handleScrollDebounced(velocity);
904
1045
  if (!fromSelf) {
905
1046
  onScrollProp == null ? void 0 : onScrollProp(event);
906
1047
  }
907
1048
  },
908
1049
  []
909
1050
  );
910
- React6.useImperativeHandle(
1051
+ React7.useImperativeHandle(
911
1052
  forwardedRef,
912
1053
  () => {
913
1054
  const scrollToIndex = ({ index, animated }) => {
@@ -936,12 +1077,10 @@ var LegendListInner = React6.forwardRef(function LegendListInner2(props, forward
936
1077
  },
937
1078
  []
938
1079
  );
939
- return /* @__PURE__ */ React6__namespace.createElement(
1080
+ return /* @__PURE__ */ React7__namespace.createElement(
940
1081
  ListComponent,
941
1082
  {
942
1083
  ...rest,
943
- contentContainerStyle,
944
- style: [style],
945
1084
  horizontal,
946
1085
  refScroller,
947
1086
  initialContentOffset,