@legendapp/list 0.3.5 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. package/index.d.mts +104 -3
  2. package/index.d.ts +104 -3
  3. package/index.js +518 -381
  4. package/index.mjs +517 -380
  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,27 +21,27 @@ 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 });
27
+ var LeanView = React7__namespace.forwardRef((props, ref) => {
28
+ return React7__namespace.createElement("RCTView", { ...props, ref });
29
29
  });
30
30
  LeanView.displayName = "RCTView";
31
- var ContextListener = React6__namespace.createContext(null);
31
+ var ContextState = React7__namespace.createContext(null);
32
32
  function StateProvider({ children }) {
33
- const [value] = React6__namespace.useState(() => ({
33
+ const [value] = React7__namespace.useState(() => ({
34
34
  listeners: /* @__PURE__ */ new Map(),
35
35
  values: /* @__PURE__ */ new Map()
36
36
  }));
37
- return /* @__PURE__ */ React6__namespace.createElement(ContextListener.Provider, { value }, children);
37
+ return /* @__PURE__ */ React7__namespace.createElement(ContextState.Provider, { value }, children);
38
38
  }
39
39
  function useStateContext() {
40
- return React6__namespace.useContext(ContextListener);
40
+ return React7__namespace.useContext(ContextState);
41
41
  }
42
42
  function use$(signalName) {
43
- const { listeners, values } = React6__namespace.useContext(ContextListener);
44
- const [, forceUpdate] = React6__namespace.useReducer((x) => x + 1, 0);
43
+ const { listeners, values } = React7__namespace.useContext(ContextState);
44
+ const [, forceUpdate] = React7__namespace.useReducer((x) => x + 1, 0);
45
45
  listeners.set(signalName, forceUpdate);
46
46
  return values.get(signalName);
47
47
  }
@@ -62,7 +62,7 @@ function set$(ctx, signalName, value) {
62
62
  function $View({ $key, $style, ...rest }) {
63
63
  use$($key);
64
64
  const style = $style();
65
- return /* @__PURE__ */ React6__namespace.createElement(LeanView, { style, ...rest });
65
+ return /* @__PURE__ */ React7__namespace.createElement(LeanView, { style, ...rest });
66
66
  }
67
67
  function InnerContainer({ id, getRenderedItem, recycleItems, ItemSeparatorComponent }) {
68
68
  const itemIndex = use$(`containerIndex${id}`);
@@ -71,7 +71,7 @@ function InnerContainer({ id, getRenderedItem, recycleItems, ItemSeparatorCompon
71
71
  return null;
72
72
  }
73
73
  const renderedItem = getRenderedItem(itemIndex);
74
- return /* @__PURE__ */ React6__namespace.createElement(React6__namespace.Fragment, { key: recycleItems ? void 0 : itemIndex }, renderedItem, ItemSeparatorComponent && itemIndex < numItems - 1 && ItemSeparatorComponent);
74
+ return /* @__PURE__ */ React7__namespace.createElement(React7__namespace.Fragment, { key: recycleItems ? void 0 : itemIndex }, renderedItem, ItemSeparatorComponent && itemIndex < numItems - 1 && ItemSeparatorComponent);
75
75
  }
76
76
  var Container = ({
77
77
  id,
@@ -99,7 +99,7 @@ var Container = ({
99
99
  opacity: position < 0 ? 0 : 1
100
100
  };
101
101
  };
102
- return /* @__PURE__ */ React6__namespace.createElement(
102
+ return /* @__PURE__ */ React7__namespace.createElement(
103
103
  $View,
104
104
  {
105
105
  $key: `containerPosition${id}`,
@@ -107,12 +107,12 @@ var Container = ({
107
107
  onLayout: (event) => {
108
108
  const index = peek$(ctx, `containerIndex${id}`);
109
109
  if (index >= 0) {
110
- const length = event.nativeEvent.layout[horizontal ? "width" : "height"];
111
- onLayout(index, length);
110
+ const size = event.nativeEvent.layout[horizontal ? "width" : "height"];
111
+ onLayout(index, size);
112
112
  }
113
113
  }
114
114
  },
115
- /* @__PURE__ */ React6__namespace.createElement(
115
+ /* @__PURE__ */ React7__namespace.createElement(
116
116
  InnerContainer,
117
117
  {
118
118
  id,
@@ -125,7 +125,7 @@ var Container = ({
125
125
  };
126
126
 
127
127
  // src/Containers.tsx
128
- var Containers = React6__namespace.memo(function Containers2({
128
+ var Containers = React7__namespace.memo(function Containers2({
129
129
  horizontal,
130
130
  recycleItems,
131
131
  ItemSeparatorComponent,
@@ -137,7 +137,7 @@ var Containers = React6__namespace.memo(function Containers2({
137
137
  const containers = [];
138
138
  for (let i = 0; i < numContainers; i++) {
139
139
  containers.push(
140
- /* @__PURE__ */ React6__namespace.createElement(
140
+ /* @__PURE__ */ React7__namespace.createElement(
141
141
  Container,
142
142
  {
143
143
  id: i,
@@ -151,14 +151,14 @@ var Containers = React6__namespace.memo(function Containers2({
151
151
  )
152
152
  );
153
153
  }
154
- return /* @__PURE__ */ React6__namespace.createElement(
154
+ return /* @__PURE__ */ React7__namespace.createElement(
155
155
  $View,
156
156
  {
157
- $key: "totalLength",
157
+ $key: "totalSize",
158
158
  $style: () => horizontal ? {
159
- width: peek$(ctx, "totalLength")
159
+ width: peek$(ctx, "totalSize")
160
160
  } : {
161
- height: peek$(ctx, "totalLength")
161
+ height: peek$(ctx, "totalSize")
162
162
  }
163
163
  },
164
164
  containers
@@ -167,15 +167,15 @@ var Containers = React6__namespace.memo(function Containers2({
167
167
 
168
168
  // src/ListComponent.tsx
169
169
  var getComponent = (Component) => {
170
- if (React6__namespace.isValidElement(Component)) {
170
+ if (React7__namespace.isValidElement(Component)) {
171
171
  return Component;
172
172
  }
173
173
  if (Component) {
174
- return /* @__PURE__ */ React6__namespace.createElement(Component, null);
174
+ return /* @__PURE__ */ React7__namespace.createElement(Component, null);
175
175
  }
176
176
  return null;
177
177
  };
178
- var ListComponent = React6__namespace.memo(function ListComponent2({
178
+ var ListComponent = React7__namespace.memo(function ListComponent2({
179
179
  style,
180
180
  contentContainerStyle,
181
181
  horizontal,
@@ -195,7 +195,7 @@ var ListComponent = React6__namespace.memo(function ListComponent2({
195
195
  ...rest
196
196
  }) {
197
197
  const ctx = useStateContext();
198
- return /* @__PURE__ */ React6__namespace.createElement(
198
+ return /* @__PURE__ */ React7__namespace.createElement(
199
199
  reactNative.ScrollView,
200
200
  {
201
201
  ...rest,
@@ -213,9 +213,9 @@ var ListComponent = React6__namespace.memo(function ListComponent2({
213
213
  contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
214
214
  ref: refScroller
215
215
  },
216
- alignItemsAtEnd && /* @__PURE__ */ React6__namespace.createElement($View, { $key: "paddingTop", $style: () => ({ height: peek$(ctx, "paddingTop") }) }),
217
- ListHeaderComponent && /* @__PURE__ */ React6__namespace.createElement(reactNative.View, { style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
218
- /* @__PURE__ */ React6__namespace.createElement(
216
+ alignItemsAtEnd && /* @__PURE__ */ React7__namespace.createElement($View, { $key: "paddingTop", $style: () => ({ height: peek$(ctx, "paddingTop") }) }),
217
+ ListHeaderComponent && /* @__PURE__ */ React7__namespace.createElement(reactNative.View, { style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
218
+ /* @__PURE__ */ React7__namespace.createElement(
219
219
  Containers,
220
220
  {
221
221
  horizontal,
@@ -225,402 +225,539 @@ var ListComponent = React6__namespace.memo(function ListComponent2({
225
225
  updateItemSize
226
226
  }
227
227
  ),
228
- ListFooterComponent && /* @__PURE__ */ React6__namespace.createElement(reactNative.View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
228
+ ListFooterComponent && /* @__PURE__ */ React7__namespace.createElement(reactNative.View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
229
229
  );
230
230
  });
231
231
 
232
+ // src/viewability.ts
233
+ var mapViewabilityConfigCallbackPairs = /* @__PURE__ */ new WeakMap();
234
+ function setupViewability(props) {
235
+ let { viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged } = props;
236
+ viewabilityConfigCallbackPairs = viewabilityConfigCallbackPairs || onViewableItemsChanged && [
237
+ { viewabilityConfig: viewabilityConfig || { viewAreaCoveragePercentThreshold: 0 }, onViewableItemsChanged }
238
+ ];
239
+ if (viewabilityConfigCallbackPairs) {
240
+ for (const pair of viewabilityConfigCallbackPairs) {
241
+ mapViewabilityConfigCallbackPairs.set(pair, {
242
+ viewableItems: [],
243
+ start: -1,
244
+ end: -1,
245
+ previousStart: -1,
246
+ previousEnd: -1
247
+ });
248
+ }
249
+ }
250
+ return viewabilityConfigCallbackPairs;
251
+ }
252
+ function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, getId, scrollSize, start, end) {
253
+ for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
254
+ const viewabilityState = mapViewabilityConfigCallbackPairs.get(viewabilityConfigCallbackPair);
255
+ viewabilityState.start = start;
256
+ viewabilityState.end = end;
257
+ if (viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime) {
258
+ const timer = setTimeout(() => {
259
+ state.timeouts.delete(timer);
260
+ updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize);
261
+ }, viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime);
262
+ state.timeouts.add(timer);
263
+ } else {
264
+ updateViewableItemsWithConfig(state.data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize);
265
+ }
266
+ }
267
+ }
268
+ function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, getId, state, ctx, scrollSize) {
269
+ var _a;
270
+ const viewabilityState = mapViewabilityConfigCallbackPairs.get(viewabilityConfigCallbackPair);
271
+ const { viewableItems: previousViewableItems, start, previousStart, end, previousEnd } = viewabilityState;
272
+ const changed = [];
273
+ if (previousViewableItems) {
274
+ for (const viewToken of previousViewableItems) {
275
+ if (viewToken.index < start || viewToken.index > end) {
276
+ viewToken.isViewable = false;
277
+ changed.push(viewToken);
278
+ }
279
+ }
280
+ }
281
+ const viewableItems = [];
282
+ for (let i = start; i <= end; i++) {
283
+ const item = data[i];
284
+ if (item) {
285
+ const key = getId(i);
286
+ if (isViewable(state, ctx, viewabilityConfigCallbackPair.viewabilityConfig, key, scrollSize)) {
287
+ const viewToken = {
288
+ item,
289
+ key,
290
+ index: i,
291
+ isViewable: true
292
+ };
293
+ viewableItems.push(viewToken);
294
+ if (!(previousViewableItems == null ? void 0 : previousViewableItems.find((v) => v.key === viewToken.key))) {
295
+ changed.push(viewToken);
296
+ }
297
+ }
298
+ }
299
+ }
300
+ Object.assign(viewabilityState, { viewableItems, previousStart: start, previousEnd: end });
301
+ if (changed.length > 0) {
302
+ (_a = viewabilityConfigCallbackPair.onViewableItemsChanged) == null ? void 0 : _a.call(viewabilityConfigCallbackPair, { viewableItems, changed });
303
+ }
304
+ }
305
+ function isViewable(state, ctx, viewabilityConfig, key, scrollSize) {
306
+ const { sizes, positions, scroll } = state;
307
+ const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
308
+ const { itemVisiblePercentThreshold, viewAreaCoveragePercentThreshold } = viewabilityConfig;
309
+ const viewAreaMode = viewAreaCoveragePercentThreshold != null;
310
+ const viewablePercentThreshold = viewAreaMode ? viewAreaCoveragePercentThreshold : itemVisiblePercentThreshold;
311
+ const top = positions.get(key) - scroll + topPad;
312
+ const size = sizes.get(key) || 0;
313
+ const bottom = top + size;
314
+ const isEntirelyVisible = top >= 0 && bottom <= scrollSize && bottom > top;
315
+ if (isEntirelyVisible) {
316
+ return true;
317
+ }
318
+ const visibleHeight = Math.min(bottom, scrollSize) - Math.max(top, 0);
319
+ const percent = 100 * (visibleHeight / (viewAreaMode ? scrollSize : size));
320
+ return percent >= viewablePercentThreshold;
321
+ }
322
+
232
323
  // src/LegendList.tsx
233
324
  var DEFAULT_SCROLL_BUFFER = 0;
234
325
  var POSITION_OUT_OF_VIEW = -1e4;
235
- var LegendList = React6.forwardRef(function LegendList2(props, forwardedRef) {
236
- return /* @__PURE__ */ React6__namespace.createElement(StateProvider, null, /* @__PURE__ */ React6__namespace.createElement(LegendListInner, { ...props, ref: forwardedRef }));
326
+ var LegendList = React7.forwardRef(function LegendList2(props, forwardedRef) {
327
+ return /* @__PURE__ */ React.createElement(StateProvider, null, /* @__PURE__ */ React.createElement(LegendListInner, { ...props, ref: forwardedRef }));
237
328
  });
238
- var LegendListInner = React6.forwardRef(
239
- function LegendListInner2(props, forwardedRef) {
240
- var _a, _b;
241
- const {
329
+ var LegendListInner = React7.forwardRef(function LegendListInner2(props, forwardedRef) {
330
+ var _a, _b;
331
+ const {
332
+ data,
333
+ initialScrollIndex,
334
+ initialScrollOffset,
335
+ horizontal,
336
+ style: styleProp,
337
+ contentContainerStyle: contentContainerStyleProp,
338
+ initialNumContainers,
339
+ drawDistance,
340
+ recycleItems = true,
341
+ onEndReachedThreshold = 0.5,
342
+ maintainScrollAtEnd = false,
343
+ maintainScrollAtEndThreshold = 0.1,
344
+ alignItemsAtEnd = false,
345
+ onScroll: onScrollProp,
346
+ keyExtractor,
347
+ renderItem,
348
+ estimatedItemSize,
349
+ getEstimatedItemSize,
350
+ onEndReached,
351
+ onViewableRangeChanged,
352
+ ...rest
353
+ } = props;
354
+ const ctx = useStateContext();
355
+ const internalRef = React7.useRef(null);
356
+ const refScroller = internalRef;
357
+ const scrollBuffer = drawDistance != null ? drawDistance : DEFAULT_SCROLL_BUFFER;
358
+ const styleFlattened = reactNative.StyleSheet.flatten(styleProp);
359
+ const style = React7.useMemo(() => styleFlattened, [JSON.stringify(styleFlattened)]);
360
+ const contentContainerStyleFlattened = reactNative.StyleSheet.flatten(contentContainerStyleProp);
361
+ const contentContainerStyle = React7.useMemo(
362
+ () => contentContainerStyleFlattened,
363
+ [JSON.stringify(contentContainerStyleProp)]
364
+ );
365
+ const refState = React7.useRef();
366
+ const getId = (index) => {
367
+ var _a2;
368
+ const data2 = (_a2 = refState.current) == null ? void 0 : _a2.data;
369
+ if (!data2) {
370
+ return "";
371
+ }
372
+ const ret = index < data2.length ? keyExtractor ? keyExtractor(data2[index], index) : index : null;
373
+ return `${ret}`;
374
+ };
375
+ const getItemSize = (index, data2) => {
376
+ return getEstimatedItemSize ? getEstimatedItemSize(index, data2) : estimatedItemSize;
377
+ };
378
+ const calculateInitialOffset = (index = initialScrollIndex) => {
379
+ if (index) {
380
+ if (getEstimatedItemSize) {
381
+ let offset = 0;
382
+ for (let i = 0; i < index; i++) {
383
+ offset += getEstimatedItemSize(i, data[i]);
384
+ }
385
+ return offset;
386
+ }
387
+ if (estimatedItemSize) {
388
+ return index * estimatedItemSize;
389
+ }
390
+ }
391
+ return void 0;
392
+ };
393
+ const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : React7.useMemo(calculateInitialOffset, []);
394
+ if (!refState.current) {
395
+ refState.current = {
396
+ sizes: /* @__PURE__ */ new Map(),
397
+ positions: /* @__PURE__ */ new Map(),
398
+ pendingAdjust: 0,
399
+ animFrameScroll: null,
400
+ animFrameLayout: null,
401
+ animFrameTotalSize: null,
402
+ isStartReached: false,
403
+ isEndReached: false,
404
+ isAtBottom: false,
242
405
  data,
243
- initialScrollIndex,
244
- initialScrollOffset,
245
- horizontal,
246
- style: styleProp,
247
- contentContainerStyle: contentContainerStyleProp,
248
- initialNumContainers,
249
- drawDistance,
250
- recycleItems = true,
251
- onEndReachedThreshold = 0.5,
252
- maintainScrollAtEnd = false,
253
- maintainScrollAtEndThreshold = 0.1,
254
- alignItemsAtEnd = false,
255
- onScroll: onScrollProp,
256
- keyExtractor,
257
- renderItem,
258
- estimatedItemSize,
259
- getEstimatedItemSize,
260
- onEndReached,
261
- onViewableRangeChanged,
262
- ...rest
263
- } = props;
264
- const ctx = useStateContext();
265
- const internalRef = React6.useRef(null);
266
- const refScroller = forwardedRef || internalRef;
267
- const scrollBuffer = drawDistance != null ? drawDistance : DEFAULT_SCROLL_BUFFER;
268
- const styleFlattened = reactNative.StyleSheet.flatten(styleProp);
269
- const style = React6.useMemo(() => styleFlattened, [JSON.stringify(styleProp)]);
270
- const contentContainerStyleFlattened = reactNative.StyleSheet.flatten(contentContainerStyleProp);
271
- const contentContainerStyle = React6.useMemo(
272
- () => contentContainerStyleFlattened,
273
- [JSON.stringify(contentContainerStyleProp)]
274
- );
275
- const refState = React6.useRef();
276
- const getId = (index) => {
406
+ idsInFirstRender: void 0,
407
+ hasScrolled: false,
408
+ scrollLength: reactNative.Dimensions.get("window")[horizontal ? "width" : "height"],
409
+ startBuffered: 0,
410
+ startNoBuffer: 0,
411
+ endBuffered: 0,
412
+ endNoBuffer: 0,
413
+ scroll: initialContentOffset || 0,
414
+ totalSize: 0,
415
+ timeouts: /* @__PURE__ */ new Set(),
416
+ viewabilityConfigCallbackPairs: void 0
417
+ };
418
+ refState.current.idsInFirstRender = new Set(data.map((_, i) => getId(i)));
419
+ }
420
+ refState.current.data = data;
421
+ set$(ctx, "numItems", data.length);
422
+ set$(ctx, "stylePaddingTop", (_b = (_a = styleFlattened == null ? void 0 : styleFlattened.paddingTop) != null ? _a : contentContainerStyleFlattened == null ? void 0 : contentContainerStyleFlattened.paddingTop) != null ? _b : 0);
423
+ const addTotalSize = (add) => {
424
+ const prev = refState.current.totalSize;
425
+ refState.current.totalSize += add;
426
+ const totalSize = refState.current.totalSize;
427
+ const doAdd = () => {
428
+ refState.current.animFrameTotalSize = null;
429
+ set$(ctx, "totalSize", totalSize);
430
+ const screenLength = refState.current.scrollLength;
431
+ if (alignItemsAtEnd) {
432
+ const listPaddingTop = peek$(ctx, "stylePaddingTop");
433
+ set$(ctx, "paddingTop", Math.max(0, screenLength - totalSize - listPaddingTop));
434
+ }
435
+ };
436
+ if (!prev) {
437
+ doAdd();
438
+ } else if (!refState.current.animFrameTotalSize) {
439
+ refState.current.animFrameTotalSize = requestAnimationFrame(doAdd);
440
+ }
441
+ };
442
+ const getRenderedItem = React7.useCallback(
443
+ (index) => {
277
444
  var _a2;
278
445
  const data2 = (_a2 = refState.current) == null ? void 0 : _a2.data;
279
446
  if (!data2) {
280
- return "";
447
+ return null;
281
448
  }
282
- const ret = index < data2.length ? keyExtractor ? keyExtractor(data2[index], index) : index : null;
283
- return ret + "";
284
- };
285
- const getItemLength = (index, data2) => {
286
- return getEstimatedItemSize ? getEstimatedItemSize(index, data2) : estimatedItemSize;
287
- };
288
- const calculateInitialOffset = () => {
289
- if (initialScrollIndex) {
290
- if (getEstimatedItemSize) {
291
- let offset = 0;
292
- for (let i = 0; i < initialScrollIndex; i++) {
293
- offset += getEstimatedItemSize(i, data[i]);
294
- }
295
- return offset;
296
- } else if (estimatedItemSize) {
297
- return initialScrollIndex * estimatedItemSize;
298
- }
449
+ const renderedItem = renderItem == null ? void 0 : renderItem({
450
+ item: data2[index],
451
+ index
452
+ });
453
+ return renderedItem;
454
+ },
455
+ [renderItem]
456
+ );
457
+ const calculateItemsInView = React7.useCallback(() => {
458
+ reactNative.unstable_batchedUpdates(() => {
459
+ var _a2, _b2, _c;
460
+ const {
461
+ data: data2,
462
+ scrollLength,
463
+ scroll: scrollState,
464
+ startNoBuffer: startNoBufferState,
465
+ startBuffered: startBufferedState,
466
+ endNoBuffer: endNoBufferState,
467
+ endBuffered: endBufferedState
468
+ } = refState.current;
469
+ if (!data2) {
470
+ return;
299
471
  }
300
- return void 0;
301
- };
302
- const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : React6.useMemo(calculateInitialOffset, [initialScrollIndex, estimatedItemSize]);
303
- if (!refState.current) {
304
- refState.current = {
305
- lengths: /* @__PURE__ */ new Map(),
306
- positions: /* @__PURE__ */ new Map(),
307
- pendingAdjust: 0,
308
- animFrameScroll: null,
309
- animFrameLayout: null,
310
- animFrameTotalSize: null,
311
- isStartReached: false,
312
- isEndReached: false,
313
- isAtBottom: false,
314
- data,
315
- idsInFirstRender: void 0,
316
- hasScrolled: false,
317
- scrollLength: reactNative.Dimensions.get("window")[horizontal ? "width" : "height"],
318
- startBuffered: 0,
319
- startNoBuffer: 0,
320
- endBuffered: 0,
321
- endNoBuffer: 0,
322
- scroll: initialContentOffset || 0,
323
- totalSize: 0
324
- };
325
- refState.current.idsInFirstRender = new Set(data.map((_, i) => getId(i)));
326
- }
327
- refState.current.data = data;
328
- set$(ctx, `numItems`, data.length);
329
- set$(ctx, `stylePaddingTop`, (_b = (_a = styleFlattened == null ? void 0 : styleFlattened.paddingTop) != null ? _a : contentContainerStyleFlattened == null ? void 0 : contentContainerStyleFlattened.paddingTop) != null ? _b : 0);
330
- const addTotalSize = (add) => {
331
- const prev = refState.current.totalSize;
332
- const length = refState.current.totalSize += add;
333
- const doAdd = () => {
334
- refState.current.animFrameTotalSize = null;
335
- set$(ctx, `totalLength`, length);
336
- const screenLength = refState.current.scrollLength;
337
- if (alignItemsAtEnd) {
338
- const listPaddingTop = peek$(ctx, `stylePaddingTop`);
339
- set$(ctx, `paddingTop`, Math.max(0, screenLength - length - listPaddingTop));
472
+ const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
473
+ const scroll = scrollState - topPad;
474
+ const { sizes, positions } = refState.current;
475
+ let startNoBuffer = null;
476
+ let startBuffered = null;
477
+ let endNoBuffer = null;
478
+ let endBuffered = null;
479
+ let loopStart = startBufferedState || 0;
480
+ if (startBufferedState) {
481
+ for (let i = startBufferedState; i >= 0; i--) {
482
+ const id = getId(i);
483
+ const top2 = positions.get(id);
484
+ if (top2 !== void 0) {
485
+ const size = (_a2 = sizes.get(id)) != null ? _a2 : getItemSize(i, data2[i]);
486
+ const bottom = top2 + size;
487
+ if (bottom > scroll - scrollBuffer) {
488
+ loopStart = i;
489
+ } else {
490
+ break;
491
+ }
492
+ }
340
493
  }
341
- };
342
- if (!prev) {
343
- doAdd();
344
- } else if (!refState.current.animFrameTotalSize) {
345
- refState.current.animFrameTotalSize = requestAnimationFrame(doAdd);
346
494
  }
347
- };
348
- const allocateContainers = React6.useCallback(() => {
349
- const scrollLength = refState.current.scrollLength;
350
- const averageItemSize = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, data[0]);
351
- const numContainers = initialNumContainers || Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) + 4;
352
- for (let i = 0; i < numContainers; i++) {
353
- set$(ctx, `containerIndex${i}`, -1);
354
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
355
- }
356
- set$(ctx, `numContainers`, numContainers);
357
- }, []);
358
- const getRenderedItem = React6.useCallback(
359
- (index) => {
360
- var _a2;
361
- const data2 = (_a2 = refState.current) == null ? void 0 : _a2.data;
362
- if (!data2) {
363
- return null;
495
+ let top = loopStart > 0 ? positions.get(getId(loopStart)) : 0;
496
+ for (let i = loopStart; i < data2.length; i++) {
497
+ const id = getId(i);
498
+ const size = (_b2 = sizes.get(id)) != null ? _b2 : getItemSize(i, data2[i]);
499
+ if (positions.get(id) !== top) {
500
+ positions.set(id, top);
364
501
  }
365
- const renderedItem = renderItem == null ? void 0 : renderItem({
366
- item: data2[index],
367
- index
368
- });
369
- return renderedItem;
370
- },
371
- [renderItem]
372
- );
373
- const calculateItemsInView = React6.useCallback(() => {
374
- reactNative.unstable_batchedUpdates(() => {
375
- var _a2, _b2, _c;
376
- const {
377
- data: data2,
378
- scrollLength,
379
- scroll: scrollState,
380
- startNoBuffer: startNoBufferState,
381
- startBuffered: startBufferedState,
382
- endNoBuffer: endNoBufferState,
383
- endBuffered: endBufferedState
384
- } = refState.current;
385
- if (!data2) {
386
- return;
502
+ if (startNoBuffer === null && top + size > scroll) {
503
+ startNoBuffer = i;
387
504
  }
388
- const topPad = (peek$(ctx, `stylePaddingTop`) || 0) + (peek$(ctx, `headerSize`) || 0);
389
- const scroll = scrollState - topPad;
390
- const { lengths, positions } = refState.current;
391
- let startNoBuffer = null;
392
- let startBuffered = null;
393
- let endNoBuffer = null;
394
- let endBuffered = null;
395
- let loopStart = startBufferedState || 0;
396
- if (startBufferedState) {
397
- for (let i = startBufferedState; i >= 0; i--) {
398
- const id = getId(i);
399
- const top2 = positions.get(id);
400
- if (top2 !== void 0) {
401
- const length = (_a2 = lengths.get(id)) != null ? _a2 : getItemLength(i, data2[i]);
402
- const bottom = top2 + length;
403
- if (bottom > scroll - scrollBuffer) {
404
- loopStart = i;
405
- } else {
406
- break;
407
- }
408
- }
409
- }
505
+ if (startBuffered === null && top + size > scroll - scrollBuffer) {
506
+ startBuffered = i;
410
507
  }
411
- let top = loopStart > 0 ? positions.get(getId(loopStart)) : 0;
412
- for (let i = loopStart; i < data2.length; i++) {
413
- const id = getId(i);
414
- const length = (_b2 = lengths.get(id)) != null ? _b2 : getItemLength(i, data2[i]);
415
- if (positions.get(id) !== top) {
416
- positions.set(id, top);
417
- }
418
- if (startNoBuffer === null && top + length > scroll) {
419
- startNoBuffer = i;
508
+ if (startNoBuffer !== null) {
509
+ if (top <= scroll + scrollLength) {
510
+ endNoBuffer = i;
420
511
  }
421
- if (startBuffered === null && top + length > scroll - scrollBuffer) {
422
- startBuffered = i;
512
+ if (top <= scroll + scrollLength + scrollBuffer) {
513
+ endBuffered = i;
514
+ } else {
515
+ break;
423
516
  }
424
- if (startNoBuffer !== null) {
425
- if (top <= scroll + scrollLength) {
426
- endNoBuffer = i;
427
- }
428
- if (top <= scroll + scrollLength + scrollBuffer) {
429
- endBuffered = i;
430
- } else {
517
+ }
518
+ top += size;
519
+ }
520
+ Object.assign(refState.current, {
521
+ startBuffered,
522
+ startNoBuffer,
523
+ endBuffered,
524
+ endNoBuffer
525
+ });
526
+ if (startBuffered !== null && endBuffered !== null) {
527
+ const prevNumContainers = ctx.values.get("numContainers");
528
+ let numContainers = prevNumContainers;
529
+ for (let i = startBuffered; i <= endBuffered; i++) {
530
+ let isContained = false;
531
+ for (let j = 0; j < numContainers; j++) {
532
+ const index = peek$(ctx, `containerIndex${j}`);
533
+ if (index === i) {
534
+ isContained = true;
431
535
  break;
432
536
  }
433
537
  }
434
- top += length;
435
- }
436
- Object.assign(refState.current, {
437
- startBuffered,
438
- startNoBuffer,
439
- endBuffered,
440
- endNoBuffer
441
- });
442
- if (startBuffered !== null && endBuffered !== null) {
443
- const prevNumContainers = ctx.values.get("numContainers");
444
- let numContainers = prevNumContainers;
445
- for (let i = startBuffered; i <= endBuffered; i++) {
446
- let isContained = false;
447
- for (let j = 0; j < numContainers; j++) {
448
- const index = peek$(ctx, `containerIndex${j}`);
449
- if (index === i) {
450
- isContained = true;
538
+ if (!isContained) {
539
+ const id = getId(i);
540
+ const top2 = positions.get(id) || 0;
541
+ let furthestIndex = -1;
542
+ let furthestDistance = 0;
543
+ for (let u = 0; u < numContainers; u++) {
544
+ const index = peek$(ctx, `containerIndex${u}`);
545
+ if (index < 0) {
546
+ furthestIndex = u;
451
547
  break;
452
548
  }
453
- }
454
- if (!isContained) {
455
- let didRecycle = false;
456
- for (let u = 0; u < numContainers; u++) {
457
- const index = peek$(ctx, `containerIndex${u}`);
458
- if (index < startBuffered || index > endBuffered) {
459
- set$(ctx, `containerIndex${u}`, i);
460
- didRecycle = true;
461
- break;
549
+ const pos = peek$(ctx, `containerPosition${u}`);
550
+ if (index < startBuffered || index > endBuffered) {
551
+ const distance = Math.abs(pos - top2);
552
+ if (index < 0 || distance > furthestDistance) {
553
+ furthestDistance = distance;
554
+ furthestIndex = u;
462
555
  }
463
556
  }
464
- if (!didRecycle) {
465
- if (__DEV__) {
466
- console.warn(
467
- "[legend-list] No container to recycle, consider increasing initialContainers or estimatedItemSize",
468
- i
469
- );
470
- }
471
- const id = numContainers;
472
- numContainers++;
473
- set$(ctx, `containerIndex${id}`, i);
474
- set$(ctx, `containerPosition${id}`, POSITION_OUT_OF_VIEW);
557
+ }
558
+ if (furthestIndex >= 0) {
559
+ set$(ctx, `containerIndex${furthestIndex}`, i);
560
+ } else {
561
+ if (__DEV__) {
562
+ console.warn(
563
+ "[legend-list] No container to recycle, consider increasing initialContainers or estimatedItemSize",
564
+ i
565
+ );
475
566
  }
567
+ const containerId = numContainers;
568
+ numContainers++;
569
+ set$(ctx, `containerIndex${containerId}`, i);
570
+ set$(ctx, `containerPosition${containerId}`, POSITION_OUT_OF_VIEW);
476
571
  }
477
572
  }
478
- if (numContainers !== prevNumContainers) {
479
- set$(ctx, `numContainers`, numContainers);
480
- }
481
- for (let i = 0; i < numContainers; i++) {
482
- const itemIndex = peek$(ctx, `containerIndex${i}`);
483
- const item = data2[itemIndex];
484
- if (item) {
485
- const id = getId(itemIndex);
486
- if (itemIndex < startBuffered || itemIndex > endBuffered) {
487
- set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
488
- } else {
489
- const pos = (_c = positions.get(id)) != null ? _c : -1;
490
- const prevPos = peek$(ctx, `containerPosition${i}`);
491
- if (pos >= 0 && pos !== prevPos) {
492
- set$(ctx, `containerPosition${i}`, pos);
493
- }
573
+ }
574
+ if (numContainers !== prevNumContainers) {
575
+ set$(ctx, "numContainers", numContainers);
576
+ }
577
+ for (let i = 0; i < numContainers; i++) {
578
+ const itemIndex = peek$(ctx, `containerIndex${i}`);
579
+ const item = data2[itemIndex];
580
+ if (item) {
581
+ const id = getId(itemIndex);
582
+ if (itemIndex < startBuffered || itemIndex > endBuffered) {
583
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
584
+ } else {
585
+ const pos = (_c = positions.get(id)) != null ? _c : -1;
586
+ const prevPos = peek$(ctx, `containerPosition${i}`);
587
+ if (pos >= 0 && pos !== prevPos) {
588
+ set$(ctx, `containerPosition${i}`, pos);
494
589
  }
495
590
  }
496
591
  }
497
- if (onViewableRangeChanged) {
498
- if (startNoBuffer !== startNoBufferState || startBuffered !== startBufferedState || endNoBuffer !== endNoBufferState || endBuffered !== endBufferedState) {
499
- onViewableRangeChanged({
500
- start: startNoBuffer,
501
- startBuffered,
502
- end: endNoBuffer,
503
- endBuffered,
504
- items: data2.slice(startNoBuffer, endNoBuffer + 1)
505
- });
506
- }
592
+ }
593
+ if (onViewableRangeChanged) {
594
+ if (startNoBuffer !== startNoBufferState || startBuffered !== startBufferedState || endNoBuffer !== endNoBufferState || endBuffered !== endBufferedState) {
595
+ onViewableRangeChanged({
596
+ start: startNoBuffer,
597
+ startBuffered,
598
+ end: endNoBuffer,
599
+ endBuffered,
600
+ items: data2.slice(startNoBuffer, endNoBuffer + 1)
601
+ });
507
602
  }
508
603
  }
509
- });
510
- }, [data]);
511
- React6.useMemo(() => {
512
- var _a2, _b2;
513
- allocateContainers();
514
- calculateItemsInView();
515
- const lengths = (_a2 = refState.current) == null ? void 0 : _a2.lengths;
516
- let totalLength = 0;
517
- for (let i = 0; i < data.length; i++) {
518
- const id = getId(i);
519
- totalLength += (_b2 = lengths.get(id)) != null ? _b2 : getItemLength(i, data[i]);
520
- }
521
- addTotalSize(totalLength);
522
- }, []);
523
- const checkAtBottom = () => {
524
- var _a2;
525
- const { scrollLength, scroll } = refState.current;
526
- const totalLength = peek$(ctx, "totalLength");
527
- const distanceFromEnd = totalLength - scroll - scrollLength;
528
- if (refState.current) {
529
- refState.current.isAtBottom = distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
604
+ updateViewableItems(
605
+ refState.current,
606
+ ctx,
607
+ refState.current.viewabilityConfigCallbackPairs,
608
+ getId,
609
+ scrollLength,
610
+ startNoBuffer,
611
+ endNoBuffer
612
+ );
530
613
  }
531
- if (onEndReached && !((_a2 = refState.current) == null ? void 0 : _a2.isEndReached)) {
532
- if (distanceFromEnd < onEndReachedThreshold * scrollLength) {
533
- if (refState.current) {
534
- refState.current.isEndReached = true;
535
- }
536
- onEndReached({ distanceFromEnd });
614
+ });
615
+ }, [data]);
616
+ React7.useMemo(() => {
617
+ var _a2, _b2;
618
+ refState.current.viewabilityConfigCallbackPairs = setupViewability(props);
619
+ const scrollLength = refState.current.scrollLength;
620
+ const averageItemSize = estimatedItemSize != null ? estimatedItemSize : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(0, data[0]);
621
+ const numContainers = initialNumContainers || Math.ceil((scrollLength + scrollBuffer * 2) / averageItemSize) + 4;
622
+ for (let i = 0; i < numContainers; i++) {
623
+ set$(ctx, `containerIndex${i}`, -1);
624
+ set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
625
+ }
626
+ set$(ctx, "numContainers", numContainers);
627
+ calculateItemsInView();
628
+ const sizes = (_a2 = refState.current) == null ? void 0 : _a2.sizes;
629
+ let totalSize = 0;
630
+ for (let i = 0; i < data.length; i++) {
631
+ const id = getId(i);
632
+ totalSize += (_b2 = sizes.get(id)) != null ? _b2 : getItemSize(i, data[i]);
633
+ }
634
+ addTotalSize(totalSize);
635
+ }, []);
636
+ const checkAtBottom = () => {
637
+ var _a2;
638
+ const { scrollLength, scroll } = refState.current;
639
+ const totalSize = peek$(ctx, "totalSize");
640
+ const distanceFromEnd = totalSize - scroll - scrollLength;
641
+ if (refState.current) {
642
+ refState.current.isAtBottom = distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
643
+ }
644
+ if (onEndReached && !((_a2 = refState.current) == null ? void 0 : _a2.isEndReached)) {
645
+ if (distanceFromEnd < onEndReachedThreshold * scrollLength) {
646
+ if (refState.current) {
647
+ refState.current.isEndReached = true;
537
648
  }
649
+ onEndReached({ distanceFromEnd });
538
650
  }
539
- };
540
- React6.useMemo(() => {
541
- if (refState.current) {
542
- refState.current.isEndReached = false;
651
+ }
652
+ };
653
+ React7.useEffect(() => {
654
+ if (refState.current) {
655
+ refState.current.isEndReached = false;
656
+ }
657
+ calculateItemsInView();
658
+ checkAtBottom();
659
+ }, [data]);
660
+ const updateItemSize = React7.useCallback((index, size) => {
661
+ var _a2, _b2, _c, _d;
662
+ const data2 = (_a2 = refState.current) == null ? void 0 : _a2.data;
663
+ if (!data2) {
664
+ return;
665
+ }
666
+ const sizes = (_b2 = refState.current) == null ? void 0 : _b2.sizes;
667
+ const id = getId(index);
668
+ const wasInFirstRender = (_c = refState.current) == null ? void 0 : _c.idsInFirstRender.has(id);
669
+ const prevSize = sizes.get(id) || (wasInFirstRender ? getItemSize(index, data2[index]) : 0);
670
+ if (!prevSize || Math.abs(prevSize - size) > 0.5) {
671
+ sizes.set(id, size);
672
+ addTotalSize(size - prevSize);
673
+ if (((_d = refState.current) == null ? void 0 : _d.isAtBottom) && maintainScrollAtEnd) {
674
+ requestAnimationFrame(() => {
675
+ var _a3;
676
+ (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
677
+ animated: true
678
+ });
679
+ });
543
680
  }
544
- calculateItemsInView();
545
- checkAtBottom();
546
- }, [data]);
547
- const updateItemSize = React6.useCallback((index, length) => {
548
- var _a2, _b2, _c, _d;
549
- const data2 = (_a2 = refState.current) == null ? void 0 : _a2.data;
550
- if (!data2) {
681
+ const state = refState.current;
682
+ if (!state.animFrameScroll && !state.animFrameLayout) {
683
+ state.animFrameLayout = requestAnimationFrame(() => {
684
+ state.animFrameLayout = null;
685
+ calculateItemsInView();
686
+ });
687
+ }
688
+ }
689
+ }, []);
690
+ const handleScrollDebounced = React7.useCallback(() => {
691
+ calculateItemsInView();
692
+ checkAtBottom();
693
+ if (refState.current) {
694
+ refState.current.animFrameScroll = null;
695
+ }
696
+ }, []);
697
+ const onLayout = React7.useCallback((event) => {
698
+ const scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
699
+ refState.current.scrollLength = scrollLength;
700
+ }, []);
701
+ const handleScroll = React7.useCallback(
702
+ (event, fromSelf) => {
703
+ var _a2, _b2, _c;
704
+ 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) {
551
705
  return;
552
706
  }
553
- const lengths = (_b2 = refState.current) == null ? void 0 : _b2.lengths;
554
- const id = getId(index);
555
- const wasInFirstRender = (_c = refState.current) == null ? void 0 : _c.idsInFirstRender.has(id);
556
- const prevLength = lengths.get(id) || (wasInFirstRender ? getItemLength(index, data2[index]) : 0);
557
- if (!prevLength || Math.abs(prevLength - length) > 0.5) {
558
- lengths.set(id, length);
559
- addTotalSize(length - prevLength);
560
- if (((_d = refState.current) == null ? void 0 : _d.isAtBottom) && maintainScrollAtEnd) {
561
- requestAnimationFrame(() => {
562
- var _a3;
563
- (_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
564
- animated: true
565
- });
566
- });
567
- }
568
- const state = refState.current;
569
- if (!state.animFrameScroll && !state.animFrameLayout) {
570
- state.animFrameLayout = requestAnimationFrame(() => {
571
- state.animFrameLayout = null;
572
- calculateItemsInView();
573
- });
574
- }
707
+ refState.current.hasScrolled = true;
708
+ const newScroll = event.nativeEvent.contentOffset[horizontal ? "x" : "y"];
709
+ refState.current.scroll = newScroll;
710
+ if (refState.current && !refState.current.animFrameScroll) {
711
+ refState.current.animFrameScroll = requestAnimationFrame(handleScrollDebounced);
575
712
  }
576
- }, []);
577
- const handleScrollDebounced = React6.useCallback(() => {
578
- calculateItemsInView();
579
- checkAtBottom();
580
- if (refState.current) {
581
- refState.current.animFrameScroll = null;
713
+ if (!fromSelf) {
714
+ onScrollProp == null ? void 0 : onScrollProp(event);
582
715
  }
583
- }, []);
584
- const onLayout = React6.useCallback((event) => {
585
- const scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
586
- refState.current.scrollLength = scrollLength;
587
- }, []);
588
- const handleScroll = React6.useCallback(
589
- (event, fromSelf) => {
590
- var _a2, _b2, _c;
591
- 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) {
592
- return;
593
- }
594
- refState.current.hasScrolled = true;
595
- const newScroll = event.nativeEvent.contentOffset[horizontal ? "x" : "y"];
596
- refState.current.scroll = newScroll;
597
- if (refState.current && !refState.current.animFrameScroll) {
598
- refState.current.animFrameScroll = requestAnimationFrame(handleScrollDebounced);
599
- }
600
- if (!fromSelf) {
601
- onScrollProp == null ? void 0 : onScrollProp(event);
716
+ },
717
+ []
718
+ );
719
+ React7.useImperativeHandle(forwardedRef, () => {
720
+ const scrollToIndex = ({ index, animated }) => {
721
+ const offsetObj = calculateInitialOffset(index);
722
+ const offset = horizontal ? { x: offsetObj, y: 0 } : { x: 0, y: offsetObj };
723
+ refScroller.current.scrollTo({ ...offset, animated });
724
+ };
725
+ return {
726
+ getNativeScrollRef: () => refScroller.current,
727
+ getScrollableNode: refScroller.current.getScrollableNode,
728
+ getScrollResponder: refScroller.current.getScrollResponder,
729
+ flashScrollIndicators: refScroller.current.flashScrollIndicators,
730
+ scrollToIndex,
731
+ scrollToOffset: ({ offset, animated }) => {
732
+ const offsetObj = horizontal ? { x: offset, y: 0 } : { x: 0, y: offset };
733
+ refScroller.current.scrollTo({ ...offsetObj, animated });
734
+ },
735
+ scrollToItem: ({ item, animated }) => {
736
+ const index = data.indexOf(item);
737
+ if (index !== -1) {
738
+ scrollToIndex({ index, animated });
602
739
  }
603
740
  },
604
- []
605
- );
606
- return /* @__PURE__ */ React6__namespace.createElement(
607
- ListComponent,
608
- {
609
- ...rest,
610
- contentContainerStyle,
611
- style,
612
- horizontal,
613
- refScroller,
614
- initialContentOffset,
615
- getRenderedItem,
616
- updateItemSize,
617
- handleScroll,
618
- onLayout,
619
- recycleItems,
620
- alignItemsAtEnd
621
- }
622
- );
623
- }
624
- );
741
+ scrollToEnd: refScroller.current.scrollToEnd
742
+ };
743
+ }, []);
744
+ return /* @__PURE__ */ React.createElement(
745
+ ListComponent,
746
+ {
747
+ ...rest,
748
+ contentContainerStyle,
749
+ style,
750
+ horizontal,
751
+ refScroller,
752
+ initialContentOffset,
753
+ getRenderedItem,
754
+ updateItemSize,
755
+ handleScroll,
756
+ onLayout,
757
+ recycleItems,
758
+ alignItemsAtEnd
759
+ }
760
+ );
761
+ });
625
762
 
626
763
  exports.LegendList = LegendList;