@legendapp/list 0.2.2 → 0.3.0

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.js CHANGED
@@ -1,9 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  var React2 = require('react');
4
- var state = require('@legendapp/state');
5
- var enableReactNativeComponents = require('@legendapp/state/config/enableReactNativeComponents');
6
- var react = require('@legendapp/state/react');
7
4
  var reactNative = require('react-native');
8
5
 
9
6
  function _interopNamespace(e) {
@@ -27,405 +24,537 @@ function _interopNamespace(e) {
27
24
  var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
28
25
 
29
26
  // src/LegendList.tsx
30
- enableReactNativeComponents.enableReactNativeComponents();
27
+ var LeanView = React2__namespace.forwardRef((props, ref) => {
28
+ return React2__namespace.createElement("RCTView", { ...props, ref });
29
+ });
30
+ LeanView.displayName = "RCTView";
31
+ var ContextListener = React2__namespace.createContext(null);
32
+ function StateProvider({ children }) {
33
+ const [value] = React2__namespace.useState(() => ({
34
+ listeners: /* @__PURE__ */ new Map(),
35
+ values: /* @__PURE__ */ new Map()
36
+ }));
37
+ return /* @__PURE__ */ React2__namespace.createElement(ContextListener.Provider, { value }, children);
38
+ }
39
+ function useStateContext() {
40
+ return React2__namespace.useContext(ContextListener);
41
+ }
42
+ function use$(signalName) {
43
+ const { listeners, values } = React2__namespace.useContext(ContextListener);
44
+ const [_, setState] = React2__namespace.useState(0);
45
+ React2__namespace.useMemo(() => {
46
+ const render = () => setState((prev) => prev > 1e4 ? 0 : prev + 1);
47
+ listeners.set(signalName, render);
48
+ }, []);
49
+ return values.get(signalName);
50
+ }
51
+ function peek$(signalName, ctx) {
52
+ const { values } = ctx || React2__namespace.useContext(ContextListener);
53
+ return values.get(signalName);
54
+ }
55
+ function set$(signalName, ctx, value) {
56
+ var _a;
57
+ const { listeners, values } = ctx || React2__namespace.useContext(ContextListener);
58
+ if (values.get(signalName) !== value) {
59
+ values.set(signalName, value);
60
+ (_a = listeners.get(signalName)) == null ? void 0 : _a();
61
+ }
62
+ }
63
+
64
+ // src/$View.tsx
65
+ function $View({ $key, $style, ...rest }) {
66
+ use$($key);
67
+ const style = $style();
68
+ return /* @__PURE__ */ React2__namespace.createElement(LeanView, { style, ...rest });
69
+ }
31
70
  var Container = ({
32
- $container,
71
+ id,
33
72
  recycleItems,
34
- listProps,
73
+ horizontal,
35
74
  getRenderedItem,
36
75
  onLayout,
37
76
  ItemSeparatorComponent
38
77
  }) => {
39
- const { horizontal } = listProps;
40
- const { id } = $container.peek();
41
- const itemIndex = react.use$($container.itemIndex);
42
- const key = recycleItems ? void 0 : itemIndex;
43
- const createStyle = () => horizontal ? {
44
- flexDirection: "row",
45
- position: "absolute",
46
- top: 0,
47
- bottom: 0,
48
- left: $container.position.get(),
49
- opacity: $container.position.get() < 0 ? 0 : 1
50
- } : {
51
- position: "absolute",
52
- left: 0,
53
- right: 0,
54
- top: $container.position.get(),
55
- opacity: $container.position.get() < 0 ? 0 : 1
78
+ const ctx = useStateContext();
79
+ const numItems = ItemSeparatorComponent ? use$("numItems") : 0;
80
+ const itemIndex = use$(`containerIndex${id}`);
81
+ if (itemIndex < 0) {
82
+ return null;
83
+ }
84
+ const createStyle = () => {
85
+ const position = peek$(`containerPosition${id}`, ctx);
86
+ return horizontal ? {
87
+ flexDirection: "row",
88
+ position: "absolute",
89
+ top: 0,
90
+ bottom: 0,
91
+ left: position,
92
+ opacity: position < 0 ? 0 : 1
93
+ } : {
94
+ position: "absolute",
95
+ left: 0,
96
+ right: 0,
97
+ top: position,
98
+ opacity: position < 0 ? 0 : 1
99
+ };
56
100
  };
57
- return itemIndex < 0 ? null : /* @__PURE__ */ React2__namespace.createElement(
58
- react.Reactive.View,
101
+ const renderedItem = getRenderedItem(itemIndex);
102
+ return /* @__PURE__ */ React2__namespace.createElement(
103
+ $View,
59
104
  {
60
- key: id,
105
+ $key: `containerPosition${id}`,
61
106
  $style: createStyle,
62
107
  onLayout: (event) => {
63
- const index = $container.itemIndex.peek();
108
+ const index = peek$(`containerIndex${id}`, ctx);
64
109
  const length = Math.round(event.nativeEvent.layout[horizontal ? "width" : "height"]);
65
110
  onLayout(index, length);
66
111
  }
67
112
  },
68
- /* @__PURE__ */ React2__namespace.createElement(reactNative.View, { key }, getRenderedItem(itemIndex)),
69
- ItemSeparatorComponent && itemIndex !== listProps.data.length - 1 && /* @__PURE__ */ React2__namespace.createElement(react.Reactive.View, null, ItemSeparatorComponent)
113
+ recycleItems ? renderedItem : /* @__PURE__ */ React2__namespace.createElement(React2__namespace.Fragment, { key: itemIndex }, renderedItem),
114
+ ItemSeparatorComponent && itemIndex < numItems - 1 && ItemSeparatorComponent
70
115
  );
71
116
  };
72
117
 
118
+ // src/Containers.tsx
119
+ var Containers = React2__namespace.memo(function Containers2({
120
+ horizontal,
121
+ recycleItems,
122
+ ItemSeparatorComponent,
123
+ updateItemLength,
124
+ getRenderedItem
125
+ }) {
126
+ const ctx = useStateContext();
127
+ const numContainers = use$("numContainers");
128
+ const containers = [];
129
+ for (let i = 0; i < numContainers; i++) {
130
+ containers.push(
131
+ /* @__PURE__ */ React2__namespace.createElement(
132
+ Container,
133
+ {
134
+ id: i,
135
+ key: i,
136
+ recycleItems,
137
+ horizontal,
138
+ getRenderedItem,
139
+ onLayout: updateItemLength,
140
+ ItemSeparatorComponent
141
+ }
142
+ )
143
+ );
144
+ }
145
+ return /* @__PURE__ */ React2__namespace.createElement(
146
+ $View,
147
+ {
148
+ $key: "totalLength",
149
+ $style: () => horizontal ? {
150
+ width: peek$("totalLength", ctx)
151
+ } : {
152
+ height: peek$("totalLength", ctx)
153
+ }
154
+ },
155
+ containers
156
+ );
157
+ });
158
+
159
+ // src/ListComponent.tsx
160
+ var getComponent = (Component) => {
161
+ if (React2__namespace.isValidElement(Component)) {
162
+ return Component;
163
+ }
164
+ if (Component) {
165
+ return /* @__PURE__ */ React2__namespace.createElement(Component, null);
166
+ }
167
+ return null;
168
+ };
169
+ var ListComponent = React2__namespace.memo(function ListComponent2({
170
+ style,
171
+ contentContainerStyle,
172
+ horizontal,
173
+ initialContentOffset,
174
+ recycleItems,
175
+ ItemSeparatorComponent,
176
+ alignItemsAtEnd,
177
+ handleScroll,
178
+ onLayout,
179
+ ListHeaderComponent,
180
+ ListHeaderComponentStyle,
181
+ ListFooterComponent,
182
+ ListFooterComponentStyle,
183
+ getRenderedItem,
184
+ updateItemLength,
185
+ refScroller,
186
+ ...rest
187
+ }) {
188
+ const ctx = useStateContext();
189
+ return /* @__PURE__ */ React2__namespace.createElement(
190
+ reactNative.ScrollView,
191
+ {
192
+ style,
193
+ contentContainerStyle: [
194
+ contentContainerStyle,
195
+ horizontal ? {
196
+ height: "100%"
197
+ } : {}
198
+ ],
199
+ onScroll: handleScroll,
200
+ onLayout,
201
+ scrollEventThrottle: 32,
202
+ horizontal,
203
+ contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
204
+ ...rest,
205
+ ref: refScroller
206
+ },
207
+ alignItemsAtEnd && /* @__PURE__ */ React2__namespace.createElement($View, { $key: "paddingTop", $style: () => ({ height: peek$("paddingTop", ctx) }) }),
208
+ ListHeaderComponent && /* @__PURE__ */ React2__namespace.createElement(reactNative.View, { style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
209
+ /* @__PURE__ */ React2__namespace.createElement(
210
+ Containers,
211
+ {
212
+ horizontal,
213
+ recycleItems,
214
+ getRenderedItem,
215
+ ItemSeparatorComponent: ItemSeparatorComponent && getComponent(ItemSeparatorComponent),
216
+ updateItemLength
217
+ }
218
+ ),
219
+ ListFooterComponent && /* @__PURE__ */ React2__namespace.createElement(reactNative.View, { style: ListFooterComponentStyle }, getComponent(ListFooterComponent))
220
+ );
221
+ });
222
+
73
223
  // src/LegendList.tsx
74
- enableReactNativeComponents.enableReactNativeComponents();
75
224
  var DEFAULT_SCROLL_BUFFER = 0;
76
225
  var POSITION_OUT_OF_VIEW = -1e4;
77
226
  var LegendList = React2.forwardRef(function LegendList2(props, forwardedRef) {
78
- const {
79
- data,
80
- initialScrollIndex,
81
- initialScrollOffset,
82
- horizontal,
83
- style,
84
- contentContainerStyle,
85
- initialContainers,
86
- drawDistance,
87
- recycleItems = true,
88
- onEndReachedThreshold,
89
- maintainScrollAtEnd = false,
90
- maintainScrollAtEndThreshold = 0.1,
91
- alignItemsAtEnd = false,
92
- keyExtractor,
93
- renderItem,
94
- estimatedItemLength,
95
- onEndReached,
96
- onViewableRangeChanged,
97
- ListHeaderComponent,
98
- ListHeaderComponentStyle,
99
- ListFooterComponent,
100
- ListFooterComponentStyle,
101
- ItemSeparatorComponent,
102
- ...rest
103
- } = props;
104
- const internalRef = React2.useRef(null);
105
- const refScroller = forwardedRef || internalRef;
106
- const containers$ = react.useObservable(() => []);
107
- const paddingTop$ = react.useObservable(0);
108
- const visibleRange$ = react.useObservable(() => ({
109
- start: 0,
110
- end: 0,
111
- totalLength: 0,
112
- scroll: 0,
113
- topPad: 0
114
- }));
115
- const scrollBuffer = drawDistance != null ? drawDistance : DEFAULT_SCROLL_BUFFER;
116
- const refPositions = React2.useRef();
117
- const getId = (index) => {
118
- var _a;
119
- const data2 = (_a = refPositions.current) == null ? void 0 : _a.data;
120
- if (!data2) {
121
- return "";
122
- }
123
- const ret = index < data2.length ? keyExtractor ? keyExtractor(data2[index], index) : index : null;
124
- return ret + "";
125
- };
126
- if (!refPositions.current) {
127
- refPositions.current = {
128
- lengths: /* @__PURE__ */ new Map(),
129
- positions: /* @__PURE__ */ new Map(),
130
- pendingAdjust: 0,
131
- animFrame: null,
132
- isStartReached: false,
133
- isEndReached: false,
134
- isAtBottom: false,
227
+ return /* @__PURE__ */ React2__namespace.createElement(StateProvider, null, /* @__PURE__ */ React2__namespace.createElement(LegendListInner, { ...props, ref: forwardedRef }));
228
+ });
229
+ var LegendListInner = React2.forwardRef(
230
+ function LegendListInner2(props, forwardedRef) {
231
+ const {
135
232
  data,
136
- idsInFirstRender: void 0,
137
- hasScrolled: false,
138
- scrollLength: reactNative.Dimensions.get("window")[horizontal ? "width" : "height"]
139
- };
140
- refPositions.current.idsInFirstRender = new Set(data.map((_, i) => getId(i)));
141
- }
142
- refPositions.current.data = data;
143
- const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : initialScrollIndex ? initialScrollIndex * estimatedItemLength(initialScrollIndex) : void 0;
144
- const setTotalLength = (length) => {
145
- visibleRange$.totalLength.set(length);
146
- const screenLength = refPositions.current.scrollLength;
147
- if (alignItemsAtEnd) {
148
- const listPaddingTop = ((style == null ? void 0 : style.paddingTop) || 0) + ((contentContainerStyle == null ? void 0 : contentContainerStyle.paddingTop) || 0);
149
- paddingTop$.set(Math.max(0, screenLength - length - listPaddingTop));
150
- }
151
- };
152
- const allocateContainers = React2.useCallback(() => {
153
- const scrollLength = refPositions.current.scrollLength;
154
- const numContainers = initialContainers || Math.ceil((scrollLength + scrollBuffer * 2) / estimatedItemLength(0)) + 4;
155
- const containers2 = [];
156
- for (let i = 0; i < numContainers; i++) {
157
- containers2.push({
158
- id: i,
159
- itemIndex: -1,
160
- position: POSITION_OUT_OF_VIEW
161
- });
162
- }
163
- containers$.set(containers2);
164
- }, []);
165
- const getRenderedItem = React2.useCallback(
166
- (index) => {
233
+ initialScrollIndex,
234
+ initialScrollOffset,
235
+ horizontal,
236
+ style: styleProp,
237
+ contentContainerStyle: contentContainerStyleProp,
238
+ initialContainers,
239
+ drawDistance,
240
+ recycleItems = true,
241
+ onEndReachedThreshold = 0.5,
242
+ maintainScrollAtEnd = false,
243
+ maintainScrollAtEndThreshold = 0.1,
244
+ alignItemsAtEnd = false,
245
+ keyExtractor,
246
+ renderItem,
247
+ estimatedItemLength,
248
+ onEndReached,
249
+ onViewableRangeChanged,
250
+ ...rest
251
+ } = props;
252
+ const ctx = useStateContext();
253
+ const internalRef = React2.useRef(null);
254
+ const refScroller = forwardedRef || internalRef;
255
+ const scrollBuffer = drawDistance != null ? drawDistance : DEFAULT_SCROLL_BUFFER;
256
+ const styleFlattened = reactNative.StyleSheet.flatten(styleProp);
257
+ const style = React2.useMemo(() => styleFlattened, [JSON.stringify(styleProp)]);
258
+ const contentContainerStyleFlattened = reactNative.StyleSheet.flatten(contentContainerStyleProp);
259
+ const contentContainerStyle = React2.useMemo(
260
+ () => contentContainerStyleFlattened,
261
+ [JSON.stringify(contentContainerStyleProp)]
262
+ );
263
+ const refState = React2.useRef();
264
+ const getId = (index) => {
167
265
  var _a;
168
- const data2 = (_a = refPositions.current) == null ? void 0 : _a.data;
266
+ const data2 = (_a = refState.current) == null ? void 0 : _a.data;
169
267
  if (!data2) {
170
- return null;
268
+ return "";
171
269
  }
172
- const renderedItem = renderItem == null ? void 0 : renderItem({
173
- item: data2[index],
174
- index
175
- });
176
- return renderedItem;
177
- },
178
- [renderItem]
179
- );
180
- const calculateItemsInView = React2.useCallback(() => {
181
- var _a, _b;
182
- const { data: data2, scrollLength } = refPositions.current;
183
- if (!data2) {
184
- return;
270
+ const ret = index < data2.length ? keyExtractor ? keyExtractor(data2[index], index) : index : null;
271
+ return ret + "";
272
+ };
273
+ if (!refState.current) {
274
+ refState.current = {
275
+ lengths: /* @__PURE__ */ new Map(),
276
+ positions: /* @__PURE__ */ new Map(),
277
+ pendingAdjust: 0,
278
+ animFrame: null,
279
+ isStartReached: false,
280
+ isEndReached: false,
281
+ isAtBottom: false,
282
+ data,
283
+ idsInFirstRender: void 0,
284
+ hasScrolled: false,
285
+ scrollLength: reactNative.Dimensions.get("window")[horizontal ? "width" : "height"],
286
+ startBuffered: 0,
287
+ startNoBuffer: 0,
288
+ endBuffered: 0,
289
+ endNoBuffer: 0,
290
+ scroll: 0,
291
+ topPad: 0
292
+ };
293
+ refState.current.idsInFirstRender = new Set(data.map((_, i) => getId(i)));
185
294
  }
186
- const scroll = visibleRange$.scroll.peek() - visibleRange$.topPad.peek();
187
- const containers2 = containers$.peek();
188
- const { lengths, positions } = refPositions.current;
189
- let top = 0;
190
- let startNoBuffer = null;
191
- let startBuffered = null;
192
- let endNoBuffer = null;
193
- let endBuffered = null;
194
- const prevRange = onViewableRangeChanged ? { ...visibleRange$.peek() } : void 0;
195
- for (let i = 0; i < data2.length; i++) {
196
- const id = getId(i);
197
- const length = (_a = lengths.get(id)) != null ? _a : estimatedItemLength(i);
198
- if (positions.get(id) !== top) {
199
- positions.set(id, top);
295
+ refState.current.data = data;
296
+ set$(`numItems`, ctx, data.length);
297
+ const initialContentOffset = initialScrollOffset != null ? initialScrollOffset : initialScrollIndex ? initialScrollIndex * estimatedItemLength(initialScrollIndex) : void 0;
298
+ const setTotalLength = (length) => {
299
+ set$(`totalLength`, ctx, length);
300
+ const screenLength = refState.current.scrollLength;
301
+ if (alignItemsAtEnd) {
302
+ const listPaddingTop = ((style == null ? void 0 : style.paddingTop) || 0) + ((contentContainerStyle == null ? void 0 : contentContainerStyle.paddingTop) || 0);
303
+ set$(`paddingTop`, ctx, Math.max(0, screenLength - length - listPaddingTop));
200
304
  }
201
- if (startNoBuffer === null && top + length > scroll) {
202
- startNoBuffer = i;
305
+ };
306
+ const allocateContainers = React2.useCallback(() => {
307
+ const scrollLength = refState.current.scrollLength;
308
+ const numContainers = initialContainers || Math.ceil((scrollLength + scrollBuffer * 2) / estimatedItemLength(0)) + 4;
309
+ for (let i = 0; i < numContainers; i++) {
310
+ set$(`containerIndex${i}`, ctx, -1);
311
+ set$(`containerPosition${i}`, ctx, POSITION_OUT_OF_VIEW);
203
312
  }
204
- if (startBuffered === null && top + length > scroll - scrollBuffer) {
205
- startBuffered = i;
313
+ set$(`numContainers`, ctx, numContainers);
314
+ }, []);
315
+ const getRenderedItem = React2.useCallback(
316
+ (index) => {
317
+ var _a;
318
+ const data2 = (_a = refState.current) == null ? void 0 : _a.data;
319
+ if (!data2) {
320
+ return null;
321
+ }
322
+ const renderedItem = renderItem == null ? void 0 : renderItem({
323
+ item: data2[index],
324
+ index
325
+ });
326
+ return renderedItem;
327
+ },
328
+ [renderItem]
329
+ );
330
+ const calculateItemsInView = React2.useCallback(() => {
331
+ var _a, _b;
332
+ const {
333
+ data: data2,
334
+ scrollLength,
335
+ scroll: scrollState,
336
+ topPad,
337
+ startNoBuffer: startNoBufferState,
338
+ startBuffered: startBufferedState,
339
+ endNoBuffer: endNoBufferState,
340
+ endBuffered: endBufferedState
341
+ } = refState.current;
342
+ if (!data2) {
343
+ return;
206
344
  }
207
- if (startNoBuffer !== null) {
208
- if (top <= scroll + scrollLength) {
209
- endNoBuffer = i;
345
+ const scroll = scrollState - topPad;
346
+ const { lengths, positions } = refState.current;
347
+ let top = 0;
348
+ let startNoBuffer = null;
349
+ let startBuffered = null;
350
+ let endNoBuffer = null;
351
+ let endBuffered = null;
352
+ for (let i = 0; i < data2.length; i++) {
353
+ const id = getId(i);
354
+ const length = (_a = lengths.get(id)) != null ? _a : estimatedItemLength(i);
355
+ if (positions.get(id) !== top) {
356
+ positions.set(id, top);
210
357
  }
211
- if (top <= scroll + scrollLength + scrollBuffer) {
212
- endBuffered = i;
213
- } else {
214
- break;
358
+ if (startNoBuffer === null && top + length > scroll) {
359
+ startNoBuffer = i;
215
360
  }
216
- }
217
- top += length;
218
- }
219
- visibleRange$.assign({
220
- startBuffered,
221
- startNoBuffer,
222
- endBuffered,
223
- endNoBuffer
224
- });
225
- state.beginBatch();
226
- if (startBuffered !== null && endBuffered !== null) {
227
- for (let i = startBuffered; i <= endBuffered; i++) {
228
- let isContained = false;
229
- for (let j = 0; j < containers2.length; j++) {
230
- const container = containers2[j];
231
- if (container.itemIndex === i) {
232
- isContained = true;
361
+ if (startBuffered === null && top + length > scroll - scrollBuffer) {
362
+ startBuffered = i;
363
+ }
364
+ if (startNoBuffer !== null) {
365
+ if (top <= scroll + scrollLength) {
366
+ endNoBuffer = i;
367
+ }
368
+ if (top <= scroll + scrollLength + scrollBuffer) {
369
+ endBuffered = i;
370
+ } else {
233
371
  break;
234
372
  }
235
373
  }
236
- if (!isContained) {
237
- let didRecycle = false;
238
- for (let u = 0; u < containers2.length; u++) {
239
- const container = containers2[u];
240
- if (container.itemIndex < startBuffered || container.itemIndex > endBuffered) {
241
- containers$[u].itemIndex.set(i);
242
- didRecycle = true;
374
+ top += length;
375
+ }
376
+ Object.assign(refState.current, {
377
+ startBuffered,
378
+ startNoBuffer,
379
+ endBuffered,
380
+ endNoBuffer
381
+ });
382
+ if (startBuffered !== null && endBuffered !== null) {
383
+ const prevNumContainers = ctx.values.get("numContainers");
384
+ let numContainers = prevNumContainers;
385
+ for (let i = startBuffered; i <= endBuffered; i++) {
386
+ let isContained = false;
387
+ for (let j = 0; j < numContainers; j++) {
388
+ const index = peek$(`containerIndex${j}`, ctx);
389
+ if (index === i) {
390
+ isContained = true;
243
391
  break;
244
392
  }
245
393
  }
246
- if (!didRecycle) {
247
- if (__DEV__) {
248
- console.warn(
249
- "[legend-list] No container to recycle, consider increasing initialContainers or estimatedItemLength",
250
- i
251
- );
394
+ if (!isContained) {
395
+ let didRecycle = false;
396
+ for (let u = 0; u < numContainers; u++) {
397
+ const index = peek$(`containerIndex${u}`, ctx);
398
+ if (index < startBuffered || index > endBuffered) {
399
+ set$(`containerIndex${u}`, ctx, i);
400
+ didRecycle = true;
401
+ break;
402
+ }
403
+ }
404
+ if (!didRecycle) {
405
+ if (__DEV__) {
406
+ console.warn(
407
+ "[legend-list] No container to recycle, consider increasing initialContainers or estimatedItemLength",
408
+ i
409
+ );
410
+ }
411
+ const id = numContainers;
412
+ numContainers++;
413
+ set$(`containerIndex${id}`, ctx, i);
414
+ set$(`containerPosition${id}`, ctx, POSITION_OUT_OF_VIEW);
415
+ }
416
+ }
417
+ }
418
+ if (numContainers !== prevNumContainers) {
419
+ set$(`numContainers`, ctx, numContainers);
420
+ }
421
+ for (let i = 0; i < numContainers; i++) {
422
+ const itemIndex = peek$(`containerIndex${i}`, ctx);
423
+ const item = data2[itemIndex];
424
+ if (item) {
425
+ const id = getId(itemIndex);
426
+ if (itemIndex < startBuffered || itemIndex > endBuffered) {
427
+ set$(`containerPosition${i}`, ctx, POSITION_OUT_OF_VIEW);
428
+ } else {
429
+ const pos = (_b = positions.get(id)) != null ? _b : -1;
430
+ const prevPos = peek$(`containerPosition${i}`, ctx);
431
+ if (pos >= 0 && pos !== prevPos) {
432
+ set$(`containerPosition${i}`, ctx, pos);
433
+ }
252
434
  }
253
- containers$.push({
254
- id: containers$.peek().length,
255
- itemIndex: i,
256
- position: POSITION_OUT_OF_VIEW
435
+ }
436
+ }
437
+ if (onViewableRangeChanged) {
438
+ if (startNoBuffer !== startNoBufferState || startBuffered !== startBufferedState || endNoBuffer !== endNoBufferState || endBuffered !== endBufferedState) {
439
+ onViewableRangeChanged({
440
+ start: startNoBuffer,
441
+ startBuffered,
442
+ end: endNoBuffer,
443
+ endBuffered,
444
+ items: data2.slice(startNoBuffer, endNoBuffer + 1)
257
445
  });
258
446
  }
259
447
  }
260
448
  }
261
- for (let i = 0; i < containers2.length; i++) {
262
- const container = containers2[i];
263
- const item = data2[container.itemIndex];
264
- if (item) {
265
- const id = getId(container.itemIndex);
266
- if (container.itemIndex < startBuffered || container.itemIndex > endBuffered) {
267
- containers$[i].position.set(POSITION_OUT_OF_VIEW);
268
- } else {
269
- const pos = (_b = positions.get(id)) != null ? _b : -1;
270
- if (pos >= 0 && pos !== containers$[i].position.peek()) {
271
- containers$[i].position.set(pos);
272
- }
449
+ }, [data]);
450
+ React2.useMemo(() => {
451
+ var _a, _b;
452
+ allocateContainers();
453
+ calculateItemsInView();
454
+ const lengths = (_a = refState.current) == null ? void 0 : _a.lengths;
455
+ let totalLength = 0;
456
+ for (let i = 0; i < data.length; i++) {
457
+ const id = getId(i);
458
+ totalLength += (_b = lengths.get(id)) != null ? _b : estimatedItemLength(i);
459
+ }
460
+ setTotalLength(totalLength);
461
+ }, []);
462
+ const checkAtBottom = () => {
463
+ var _a;
464
+ const { scrollLength, scroll } = refState.current;
465
+ const totalLength = peek$("totalLength", ctx);
466
+ const distanceFromEnd = totalLength - scroll - scrollLength;
467
+ if (refState.current) {
468
+ refState.current.isAtBottom = distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
469
+ }
470
+ if (onEndReached && !((_a = refState.current) == null ? void 0 : _a.isEndReached)) {
471
+ if (distanceFromEnd < onEndReachedThreshold * scrollLength) {
472
+ if (refState.current) {
473
+ refState.current.isEndReached = true;
273
474
  }
475
+ onEndReached({ distanceFromEnd });
274
476
  }
275
477
  }
276
- if (onViewableRangeChanged) {
277
- if (startNoBuffer !== (prevRange == null ? void 0 : prevRange.startNoBuffer) || startBuffered !== (prevRange == null ? void 0 : prevRange.startBuffered) || endNoBuffer !== (prevRange == null ? void 0 : prevRange.endNoBuffer) || endBuffered !== (prevRange == null ? void 0 : prevRange.endBuffered)) {
278
- onViewableRangeChanged({
279
- start: startNoBuffer,
280
- startBuffered,
281
- end: endNoBuffer,
282
- endBuffered,
283
- items: data2.slice(startNoBuffer, endNoBuffer + 1)
478
+ };
479
+ React2.useMemo(() => {
480
+ if (refState.current) {
481
+ refState.current.isEndReached = false;
482
+ }
483
+ calculateItemsInView();
484
+ checkAtBottom();
485
+ }, [data]);
486
+ const updateItemLength = React2.useCallback((index, length) => {
487
+ var _a, _b, _c, _d, _e;
488
+ const data2 = (_a = refState.current) == null ? void 0 : _a.data;
489
+ if (!data2) {
490
+ return;
491
+ }
492
+ const lengths = (_b = refState.current) == null ? void 0 : _b.lengths;
493
+ const id = getId(index);
494
+ const wasInFirstRender = (_c = refState.current) == null ? void 0 : _c.idsInFirstRender.has(id);
495
+ const prevLength = lengths.get(id) || (wasInFirstRender ? estimatedItemLength(index) : 0);
496
+ if (!prevLength || prevLength !== length) {
497
+ lengths.set(id, length);
498
+ const totalLength = peek$("totalLength", ctx);
499
+ setTotalLength(totalLength + (length - prevLength));
500
+ if (((_d = refState.current) == null ? void 0 : _d.isAtBottom) && maintainScrollAtEnd) {
501
+ requestAnimationFrame(() => {
502
+ var _a2;
503
+ (_a2 = refScroller.current) == null ? void 0 : _a2.scrollToEnd({
504
+ animated: true
505
+ });
284
506
  });
285
507
  }
286
- }
287
- }
288
- state.endBatch();
289
- }, [data]);
290
- React2.useMemo(() => {
291
- var _a, _b;
292
- allocateContainers();
293
- calculateItemsInView();
294
- const lengths = (_a = refPositions.current) == null ? void 0 : _a.lengths;
295
- let totalLength = 0;
296
- for (let i = 0; i < data.length; i++) {
297
- const id = getId(i);
298
- totalLength += (_b = lengths.get(id)) != null ? _b : estimatedItemLength(i);
299
- }
300
- setTotalLength(totalLength);
301
- }, []);
302
- const checkAtBottom = () => {
303
- var _a;
304
- const scrollLength = refPositions.current.scrollLength;
305
- const newScroll = visibleRange$.scroll.peek();
306
- const distanceFromEnd = visibleRange$.totalLength.peek() - newScroll - scrollLength;
307
- if (refPositions.current) {
308
- refPositions.current.isAtBottom = distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
309
- }
310
- if (onEndReached && !((_a = refPositions.current) == null ? void 0 : _a.isEndReached)) {
311
- if (distanceFromEnd < (onEndReachedThreshold || 0.5) * scrollLength) {
312
- if (refPositions.current) {
313
- refPositions.current.isEndReached = true;
508
+ if (!((_e = refState.current) == null ? void 0 : _e.animFrame)) {
509
+ calculateItemsInView();
314
510
  }
315
- onEndReached({ distanceFromEnd });
316
511
  }
317
- }
318
- };
319
- React2.useMemo(() => {
320
- var _a;
321
- if (refPositions.current) {
322
- if (!((_a = refPositions.current) == null ? void 0 : _a.isAtBottom)) {
323
- refPositions.current.isEndReached = false;
512
+ }, []);
513
+ const handleScrollDebounced = React2.useCallback(() => {
514
+ calculateItemsInView();
515
+ checkAtBottom();
516
+ if (refState.current) {
517
+ refState.current.animFrame = null;
324
518
  }
325
- }
326
- calculateItemsInView();
327
- checkAtBottom();
328
- }, [data]);
329
- const containers = react.use$(containers$, { shallow: true });
330
- const updateItemLength = React2.useCallback((index, length) => {
331
- var _a, _b, _c, _d, _e;
332
- const data2 = (_a = refPositions.current) == null ? void 0 : _a.data;
333
- if (!data2) {
334
- return;
335
- }
336
- const lengths = (_b = refPositions.current) == null ? void 0 : _b.lengths;
337
- const id = getId(index);
338
- const wasInFirstRender = (_c = refPositions.current) == null ? void 0 : _c.idsInFirstRender.has(id);
339
- const prevLength = lengths.get(id) || (wasInFirstRender ? estimatedItemLength(index) : 0);
340
- if (!prevLength || prevLength !== length) {
341
- state.beginBatch();
342
- lengths.set(id, length);
343
- setTotalLength(visibleRange$.totalLength.peek() + (length - prevLength));
344
- if (((_d = refPositions.current) == null ? void 0 : _d.isAtBottom) && maintainScrollAtEnd) {
345
- requestAnimationFrame(() => {
346
- var _a2;
347
- (_a2 = refScroller.current) == null ? void 0 : _a2.scrollToEnd({
348
- animated: true
349
- });
350
- });
519
+ }, []);
520
+ const onLayout = React2.useCallback((event) => {
521
+ const scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
522
+ refState.current.scrollLength = scrollLength;
523
+ }, []);
524
+ const handleScroll = React2.useCallback((event) => {
525
+ refState.current.hasScrolled = true;
526
+ const newScroll = event.nativeEvent.contentOffset[horizontal ? "x" : "y"];
527
+ refState.current.scroll = newScroll;
528
+ if (refState.current && !refState.current.animFrame) {
529
+ refState.current.animFrame = requestAnimationFrame(handleScrollDebounced);
351
530
  }
352
- if (!((_e = refPositions.current) == null ? void 0 : _e.animFrame)) {
531
+ }, []);
532
+ React2.useEffect(() => {
533
+ if (initialContentOffset) {
534
+ handleScroll({
535
+ nativeEvent: { contentOffset: { y: initialContentOffset } }
536
+ });
353
537
  calculateItemsInView();
354
538
  }
355
- state.endBatch();
356
- }
357
- }, []);
358
- const handleScrollDebounced = React2.useCallback(() => {
359
- calculateItemsInView();
360
- checkAtBottom();
361
- if (refPositions.current) {
362
- refPositions.current.animFrame = null;
363
- }
364
- }, []);
365
- const onLayout = (event) => {
366
- const scrollLength = event.nativeEvent.layout[horizontal ? "width" : "height"];
367
- refPositions.current.scrollLength = scrollLength;
368
- };
369
- const handleScroll = React2.useCallback((event) => {
370
- refPositions.current.hasScrolled = true;
371
- const newScroll = event.nativeEvent.contentOffset[horizontal ? "x" : "y"];
372
- visibleRange$.scroll.set(newScroll);
373
- if (refPositions.current && !refPositions.current.animFrame) {
374
- refPositions.current.animFrame = requestAnimationFrame(handleScrollDebounced);
375
- }
376
- }, []);
377
- React2.useEffect(() => {
378
- if (initialContentOffset) {
379
- handleScroll({
380
- nativeEvent: { contentOffset: { y: initialContentOffset } }
381
- });
382
- calculateItemsInView();
383
- }
384
- }, []);
385
- return /* @__PURE__ */ React2__namespace.createElement(
386
- react.Reactive.ScrollView,
387
- {
388
- style,
389
- contentContainerStyle: [
390
- contentContainerStyle,
391
- horizontal ? {
392
- height: "100%"
393
- } : {}
394
- ],
395
- onScroll: handleScroll,
396
- onLayout,
397
- scrollEventThrottle: 32,
398
- horizontal,
399
- contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
400
- ...rest,
401
- ref: refScroller
402
- },
403
- alignItemsAtEnd && /* @__PURE__ */ React2__namespace.createElement(react.Reactive.View, { $style: () => ({ height: paddingTop$.get() }) }),
404
- ListHeaderComponent && /* @__PURE__ */ React2__namespace.createElement(react.Reactive.View, { $style: ListHeaderComponentStyle }, ListHeaderComponent),
405
- /* @__PURE__ */ React2__namespace.createElement(
406
- react.Reactive.View,
539
+ }, []);
540
+ return /* @__PURE__ */ React2__namespace.createElement(
541
+ ListComponent,
407
542
  {
408
- $style: () => horizontal ? {
409
- width: visibleRange$.totalLength.get()
410
- } : {
411
- height: visibleRange$.totalLength.get()
412
- }
413
- },
414
- containers.map((container, i) => /* @__PURE__ */ React2__namespace.createElement(
415
- Container,
416
- {
417
- key: container.id,
418
- recycleItems,
419
- $container: containers$[i],
420
- listProps: props,
421
- getRenderedItem,
422
- onLayout: updateItemLength,
423
- ItemSeparatorComponent
424
- }
425
- ))
426
- ),
427
- ListFooterComponent && /* @__PURE__ */ React2__namespace.createElement(react.Reactive.View, { $style: ListFooterComponentStyle }, ListFooterComponent)
428
- );
429
- });
543
+ ...rest,
544
+ contentContainerStyle,
545
+ style,
546
+ horizontal,
547
+ refScroller,
548
+ initialContentOffset,
549
+ getRenderedItem,
550
+ updateItemLength,
551
+ handleScroll,
552
+ onLayout,
553
+ recycleItems,
554
+ alignItemsAtEnd
555
+ }
556
+ );
557
+ }
558
+ );
430
559
 
431
560
  exports.LegendList = LegendList;