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