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