@legendapp/list 3.0.0-beta.4 → 3.0.0-beta.41
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/.DS_Store +0 -0
- package/CHANGELOG.md +19 -0
- package/README.md +9 -2
- package/animated.d.ts +620 -5
- package/animated.js +2 -2
- package/animated.mjs +1 -1
- package/index.d.ts +1227 -11
- package/index.js +2594 -1023
- package/index.mjs +2593 -1024
- package/index.native.js +2347 -961
- package/index.native.mjs +2327 -943
- package/keyboard-test.d.ts +206 -0
- package/keyboard-test.js +34 -0
- package/keyboard-test.mjs +13 -0
- package/keyboard.d.ts +206 -8
- package/keyboard.js +340 -32
- package/keyboard.mjs +343 -34
- package/package.json +62 -1
- package/{types-JPHClxiw.d.mts → react-native.d.ts} +436 -158
- package/react-native.js +4942 -0
- package/react-native.mjs +4911 -0
- package/{types-JPHClxiw.d.ts → react-native.web.d.ts} +493 -158
- package/react-native.web.js +5357 -0
- package/react-native.web.mjs +5326 -0
- package/{types-YNdphn_A.d.mts → react.d.ts} +493 -158
- package/react.js +5357 -0
- package/react.mjs +5326 -0
- package/reanimated.d.ts +631 -7
- package/reanimated.js +156 -30
- package/reanimated.mjs +155 -29
- package/section-list.d.ts +620 -5
- package/section-list.js +38 -3679
- package/section-list.mjs +34 -3676
- package/animated.d.mts +0 -9
- package/index.d.mts +0 -23
- package/index.native.d.mts +0 -23
- package/index.native.d.ts +0 -23
- package/keyboard-controller.d.mts +0 -12
- package/keyboard-controller.d.ts +0 -12
- package/keyboard-controller.js +0 -69
- package/keyboard-controller.mjs +0 -48
- package/keyboard.d.mts +0 -13
- package/reanimated.d.mts +0 -18
- package/section-list.d.mts +0 -113
- package/section-list.native.d.mts +0 -113
- package/section-list.native.d.ts +0 -113
- package/section-list.native.js +0 -3700
- package/section-list.native.mjs +0 -3679
- package/types-YNdphn_A.d.ts +0 -670
package/react-native.js
ADDED
|
@@ -0,0 +1,4942 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React2 = require('react');
|
|
4
|
+
var ReactNative = require('react-native');
|
|
5
|
+
var shim = require('use-sync-external-store/shim');
|
|
6
|
+
|
|
7
|
+
function _interopNamespace(e) {
|
|
8
|
+
if (e && e.__esModule) return e;
|
|
9
|
+
var n = Object.create(null);
|
|
10
|
+
if (e) {
|
|
11
|
+
Object.keys(e).forEach(function (k) {
|
|
12
|
+
if (k !== 'default') {
|
|
13
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
14
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: function () { return e[k]; }
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
n.default = e;
|
|
22
|
+
return Object.freeze(n);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
|
|
26
|
+
var ReactNative__namespace = /*#__PURE__*/_interopNamespace(ReactNative);
|
|
27
|
+
|
|
28
|
+
// src/components/LegendList.tsx
|
|
29
|
+
ReactNative.Animated.View;
|
|
30
|
+
var View = ReactNative.View;
|
|
31
|
+
var Text = ReactNative.Text;
|
|
32
|
+
|
|
33
|
+
// src/state/getContentInsetEnd.ts
|
|
34
|
+
function getContentInsetEnd(state) {
|
|
35
|
+
var _a3;
|
|
36
|
+
const { props } = state;
|
|
37
|
+
const horizontal = props.horizontal;
|
|
38
|
+
const contentInset = props.contentInset;
|
|
39
|
+
const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
|
|
40
|
+
const overrideInset = (_a3 = state.contentInsetOverride) != null ? _a3 : void 0;
|
|
41
|
+
if (overrideInset) {
|
|
42
|
+
const mergedInset = { bottom: 0, right: 0, ...baseInset, ...overrideInset };
|
|
43
|
+
return (horizontal ? mergedInset.right : mergedInset.bottom) || 0;
|
|
44
|
+
}
|
|
45
|
+
if (baseInset) {
|
|
46
|
+
return (horizontal ? baseInset.right : baseInset.bottom) || 0;
|
|
47
|
+
}
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/state/getContentSize.ts
|
|
52
|
+
function getContentSize(ctx) {
|
|
53
|
+
var _a3;
|
|
54
|
+
const { values, state } = ctx;
|
|
55
|
+
const stylePaddingTop = values.get("stylePaddingTop") || 0;
|
|
56
|
+
const stylePaddingBottom = state.props.stylePaddingBottom || 0;
|
|
57
|
+
const headerSize = values.get("headerSize") || 0;
|
|
58
|
+
const footerSize = values.get("footerSize") || 0;
|
|
59
|
+
const contentInsetBottom = getContentInsetEnd(state);
|
|
60
|
+
const totalSize = (_a3 = state.pendingTotalSize) != null ? _a3 : values.get("totalSize");
|
|
61
|
+
return headerSize + footerSize + totalSize + stylePaddingTop + stylePaddingBottom + (contentInsetBottom || 0);
|
|
62
|
+
}
|
|
63
|
+
var createAnimatedValue = (value) => new ReactNative.Animated.Value(value);
|
|
64
|
+
|
|
65
|
+
// src/state/state.tsx
|
|
66
|
+
var ContextState = React2__namespace.createContext(null);
|
|
67
|
+
var contextNum = 0;
|
|
68
|
+
function StateProvider({ children }) {
|
|
69
|
+
const [value] = React2__namespace.useState(() => ({
|
|
70
|
+
animatedScrollY: createAnimatedValue(0),
|
|
71
|
+
columnWrapperStyle: void 0,
|
|
72
|
+
contextNum: contextNum++,
|
|
73
|
+
listeners: /* @__PURE__ */ new Map(),
|
|
74
|
+
mapViewabilityAmountCallbacks: /* @__PURE__ */ new Map(),
|
|
75
|
+
mapViewabilityAmountValues: /* @__PURE__ */ new Map(),
|
|
76
|
+
mapViewabilityCallbacks: /* @__PURE__ */ new Map(),
|
|
77
|
+
mapViewabilityConfigStates: /* @__PURE__ */ new Map(),
|
|
78
|
+
mapViewabilityValues: /* @__PURE__ */ new Map(),
|
|
79
|
+
positionListeners: /* @__PURE__ */ new Map(),
|
|
80
|
+
state: void 0,
|
|
81
|
+
values: /* @__PURE__ */ new Map([
|
|
82
|
+
["stylePaddingTop", 0],
|
|
83
|
+
["headerSize", 0],
|
|
84
|
+
["numContainers", 0],
|
|
85
|
+
["activeStickyIndex", -1],
|
|
86
|
+
["totalSize", 0],
|
|
87
|
+
["scrollAdjustPending", 0]
|
|
88
|
+
]),
|
|
89
|
+
viewRefs: /* @__PURE__ */ new Map()
|
|
90
|
+
}));
|
|
91
|
+
return /* @__PURE__ */ React2__namespace.createElement(ContextState.Provider, { value }, children);
|
|
92
|
+
}
|
|
93
|
+
function useStateContext() {
|
|
94
|
+
return React2__namespace.useContext(ContextState);
|
|
95
|
+
}
|
|
96
|
+
function createSelectorFunctionsArr(ctx, signalNames) {
|
|
97
|
+
let lastValues = [];
|
|
98
|
+
let lastSignalValues = [];
|
|
99
|
+
return {
|
|
100
|
+
get: () => {
|
|
101
|
+
const currentValues = [];
|
|
102
|
+
let hasChanged = false;
|
|
103
|
+
for (let i = 0; i < signalNames.length; i++) {
|
|
104
|
+
const value = peek$(ctx, signalNames[i]);
|
|
105
|
+
currentValues.push(value);
|
|
106
|
+
if (value !== lastSignalValues[i]) {
|
|
107
|
+
hasChanged = true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
lastSignalValues = currentValues;
|
|
111
|
+
if (hasChanged) {
|
|
112
|
+
lastValues = currentValues;
|
|
113
|
+
}
|
|
114
|
+
return lastValues;
|
|
115
|
+
},
|
|
116
|
+
subscribe: (cb) => {
|
|
117
|
+
const listeners = [];
|
|
118
|
+
for (const signalName of signalNames) {
|
|
119
|
+
listeners.push(listen$(ctx, signalName, cb));
|
|
120
|
+
}
|
|
121
|
+
return () => {
|
|
122
|
+
for (const listener of listeners) {
|
|
123
|
+
listener();
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function listen$(ctx, signalName, cb) {
|
|
130
|
+
const { listeners } = ctx;
|
|
131
|
+
let setListeners = listeners.get(signalName);
|
|
132
|
+
if (!setListeners) {
|
|
133
|
+
setListeners = /* @__PURE__ */ new Set();
|
|
134
|
+
listeners.set(signalName, setListeners);
|
|
135
|
+
}
|
|
136
|
+
setListeners.add(cb);
|
|
137
|
+
return () => setListeners.delete(cb);
|
|
138
|
+
}
|
|
139
|
+
function peek$(ctx, signalName) {
|
|
140
|
+
const { values } = ctx;
|
|
141
|
+
return values.get(signalName);
|
|
142
|
+
}
|
|
143
|
+
function set$(ctx, signalName, value) {
|
|
144
|
+
const { listeners, values } = ctx;
|
|
145
|
+
if (values.get(signalName) !== value) {
|
|
146
|
+
values.set(signalName, value);
|
|
147
|
+
const setListeners = listeners.get(signalName);
|
|
148
|
+
if (setListeners) {
|
|
149
|
+
for (const listener of setListeners) {
|
|
150
|
+
listener(value);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function listenPosition$(ctx, key, cb) {
|
|
156
|
+
const { positionListeners } = ctx;
|
|
157
|
+
let setListeners = positionListeners.get(key);
|
|
158
|
+
if (!setListeners) {
|
|
159
|
+
setListeners = /* @__PURE__ */ new Set();
|
|
160
|
+
positionListeners.set(key, setListeners);
|
|
161
|
+
}
|
|
162
|
+
setListeners.add(cb);
|
|
163
|
+
return () => setListeners.delete(cb);
|
|
164
|
+
}
|
|
165
|
+
function notifyPosition$(ctx, key, value) {
|
|
166
|
+
const { positionListeners } = ctx;
|
|
167
|
+
const setListeners = positionListeners.get(key);
|
|
168
|
+
if (setListeners) {
|
|
169
|
+
for (const listener of setListeners) {
|
|
170
|
+
listener(value);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function useArr$(signalNames) {
|
|
175
|
+
const ctx = React2__namespace.useContext(ContextState);
|
|
176
|
+
const { subscribe, get } = React2__namespace.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
|
|
177
|
+
const value = shim.useSyncExternalStore(subscribe, get);
|
|
178
|
+
return value;
|
|
179
|
+
}
|
|
180
|
+
function useSelector$(signalName, selector) {
|
|
181
|
+
const ctx = React2__namespace.useContext(ContextState);
|
|
182
|
+
const { subscribe, get } = React2__namespace.useMemo(() => createSelectorFunctionsArr(ctx, [signalName]), [ctx, signalName]);
|
|
183
|
+
const value = shim.useSyncExternalStore(subscribe, () => selector(get()[0]));
|
|
184
|
+
return value;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/components/DebugView.tsx
|
|
188
|
+
var DebugRow = ({ children }) => {
|
|
189
|
+
return /* @__PURE__ */ React2__namespace.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
|
|
190
|
+
};
|
|
191
|
+
React2__namespace.memo(function DebugView2({ state }) {
|
|
192
|
+
const ctx = useStateContext();
|
|
193
|
+
const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, _numContainers = 0, _numContainersPooled = 0] = useArr$([
|
|
194
|
+
"totalSize",
|
|
195
|
+
"scrollAdjust",
|
|
196
|
+
"debugRawScroll",
|
|
197
|
+
"debugComputedScroll",
|
|
198
|
+
"numContainers",
|
|
199
|
+
"numContainersPooled"
|
|
200
|
+
]);
|
|
201
|
+
const contentSize = getContentSize(ctx);
|
|
202
|
+
const [, forceUpdate] = React2.useReducer((x) => x + 1, 0);
|
|
203
|
+
useInterval(() => {
|
|
204
|
+
forceUpdate();
|
|
205
|
+
}, 100);
|
|
206
|
+
return /* @__PURE__ */ React2__namespace.createElement(
|
|
207
|
+
View,
|
|
208
|
+
{
|
|
209
|
+
pointerEvents: "none",
|
|
210
|
+
style: {
|
|
211
|
+
// height: 100,
|
|
212
|
+
backgroundColor: "#FFFFFFCC",
|
|
213
|
+
borderRadius: 4,
|
|
214
|
+
padding: 4,
|
|
215
|
+
paddingBottom: 4,
|
|
216
|
+
paddingLeft: 4,
|
|
217
|
+
position: "absolute",
|
|
218
|
+
right: 0,
|
|
219
|
+
top: 0
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
/* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(Text, null, "TotalSize:"), /* @__PURE__ */ React2__namespace.createElement(Text, null, totalSize.toFixed(2))),
|
|
223
|
+
/* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(Text, null, "ContentSize:"), /* @__PURE__ */ React2__namespace.createElement(Text, null, contentSize.toFixed(2))),
|
|
224
|
+
/* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(Text, null, "At end:"), /* @__PURE__ */ React2__namespace.createElement(Text, null, String(state.isAtEnd))),
|
|
225
|
+
/* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(Text, null, "ScrollAdjust:"), /* @__PURE__ */ React2__namespace.createElement(Text, null, scrollAdjust.toFixed(2))),
|
|
226
|
+
/* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(Text, null, "RawScroll: "), /* @__PURE__ */ React2__namespace.createElement(Text, null, rawScroll.toFixed(2))),
|
|
227
|
+
/* @__PURE__ */ React2__namespace.createElement(DebugRow, null, /* @__PURE__ */ React2__namespace.createElement(Text, null, "ComputedScroll: "), /* @__PURE__ */ React2__namespace.createElement(Text, null, scroll.toFixed(2)))
|
|
228
|
+
);
|
|
229
|
+
});
|
|
230
|
+
function useInterval(callback, delay) {
|
|
231
|
+
React2.useEffect(() => {
|
|
232
|
+
const interval = setInterval(callback, delay);
|
|
233
|
+
return () => clearInterval(interval);
|
|
234
|
+
}, [delay]);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// src/utils/devEnvironment.ts
|
|
238
|
+
var metroDev = typeof __DEV__ !== "undefined" ? __DEV__ : void 0;
|
|
239
|
+
var _a;
|
|
240
|
+
var envMode = typeof process !== "undefined" && typeof process.env === "object" && process.env ? (_a = process.env.NODE_ENV) != null ? _a : process.env.MODE : void 0;
|
|
241
|
+
var processDev = typeof envMode === "string" ? envMode.toLowerCase() !== "production" : void 0;
|
|
242
|
+
var _a2;
|
|
243
|
+
var IS_DEV = (_a2 = processDev != null ? processDev : metroDev) != null ? _a2 : false;
|
|
244
|
+
|
|
245
|
+
// src/constants.ts
|
|
246
|
+
var POSITION_OUT_OF_VIEW = -1e7;
|
|
247
|
+
var ENABLE_DEVMODE = IS_DEV && false;
|
|
248
|
+
var ENABLE_DEBUG_VIEW = IS_DEV && false;
|
|
249
|
+
|
|
250
|
+
// src/constants-platform.native.ts
|
|
251
|
+
var f = global.nativeFabricUIManager;
|
|
252
|
+
var IsNewArchitecture = f !== void 0 && f != null;
|
|
253
|
+
var useAnimatedValue = (initialValue) => {
|
|
254
|
+
const [animAnimatedValue] = React2.useState(() => new ReactNative.Animated.Value(initialValue));
|
|
255
|
+
return animAnimatedValue;
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// src/utils/helpers.ts
|
|
259
|
+
function isFunction(obj) {
|
|
260
|
+
return typeof obj === "function";
|
|
261
|
+
}
|
|
262
|
+
function isArray(obj) {
|
|
263
|
+
return Array.isArray(obj);
|
|
264
|
+
}
|
|
265
|
+
var warned = /* @__PURE__ */ new Set();
|
|
266
|
+
function warnDevOnce(id, text) {
|
|
267
|
+
if (IS_DEV && !warned.has(id)) {
|
|
268
|
+
warned.add(id);
|
|
269
|
+
console.warn(`[legend-list] ${text}`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function roundSize(size) {
|
|
273
|
+
return Math.floor(size * 8) / 8;
|
|
274
|
+
}
|
|
275
|
+
function isNullOrUndefined(value) {
|
|
276
|
+
return value === null || value === void 0;
|
|
277
|
+
}
|
|
278
|
+
function comparatorDefault(a, b) {
|
|
279
|
+
return a - b;
|
|
280
|
+
}
|
|
281
|
+
function getPadding(s, type) {
|
|
282
|
+
var _a3, _b, _c;
|
|
283
|
+
return (_c = (_b = (_a3 = s[`padding${type}`]) != null ? _a3 : s.paddingVertical) != null ? _b : s.padding) != null ? _c : 0;
|
|
284
|
+
}
|
|
285
|
+
function extractPadding(style, contentContainerStyle, type) {
|
|
286
|
+
return getPadding(style, type) + getPadding(contentContainerStyle, type);
|
|
287
|
+
}
|
|
288
|
+
function findContainerId(ctx, key) {
|
|
289
|
+
var _a3, _b;
|
|
290
|
+
const directMatch = (_b = (_a3 = ctx.state) == null ? void 0 : _a3.containerItemKeys) == null ? void 0 : _b.get(key);
|
|
291
|
+
if (directMatch !== void 0) {
|
|
292
|
+
return directMatch;
|
|
293
|
+
}
|
|
294
|
+
const numContainers = peek$(ctx, "numContainers");
|
|
295
|
+
for (let i = 0; i < numContainers; i++) {
|
|
296
|
+
const itemKey = peek$(ctx, `containerItemKey${i}`);
|
|
297
|
+
if (itemKey === key) {
|
|
298
|
+
return i;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return -1;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// src/hooks/useValue$.ts
|
|
305
|
+
function useValue$(key, params) {
|
|
306
|
+
const { getValue, delay } = params || {};
|
|
307
|
+
const ctx = useStateContext();
|
|
308
|
+
const getNewValue = () => {
|
|
309
|
+
var _a3;
|
|
310
|
+
return (_a3 = getValue ? getValue(peek$(ctx, key)) : peek$(ctx, key)) != null ? _a3 : 0;
|
|
311
|
+
};
|
|
312
|
+
const animValue = useAnimatedValue(getNewValue());
|
|
313
|
+
React2.useMemo(() => {
|
|
314
|
+
let prevValue;
|
|
315
|
+
let didQueueTask = false;
|
|
316
|
+
listen$(ctx, key, () => {
|
|
317
|
+
const newValue = getNewValue();
|
|
318
|
+
if (delay !== void 0) {
|
|
319
|
+
const fn = () => {
|
|
320
|
+
didQueueTask = false;
|
|
321
|
+
const latestValue = getNewValue();
|
|
322
|
+
if (latestValue !== void 0) {
|
|
323
|
+
animValue.setValue(latestValue);
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
const delayValue = isFunction(delay) ? delay(newValue, prevValue) : delay;
|
|
327
|
+
prevValue = newValue;
|
|
328
|
+
if (!didQueueTask) {
|
|
329
|
+
didQueueTask = true;
|
|
330
|
+
if (delayValue === void 0) {
|
|
331
|
+
fn();
|
|
332
|
+
} else if (delayValue === 0) {
|
|
333
|
+
queueMicrotask(fn);
|
|
334
|
+
} else {
|
|
335
|
+
setTimeout(fn, delayValue);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
} else {
|
|
339
|
+
animValue.setValue(newValue);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
}, []);
|
|
343
|
+
return animValue;
|
|
344
|
+
}
|
|
345
|
+
var typedMemo = React2__namespace.memo;
|
|
346
|
+
var getComponent = (Component) => {
|
|
347
|
+
if (React2__namespace.isValidElement(Component)) {
|
|
348
|
+
return Component;
|
|
349
|
+
}
|
|
350
|
+
if (Component) {
|
|
351
|
+
return /* @__PURE__ */ React2__namespace.createElement(Component, null);
|
|
352
|
+
}
|
|
353
|
+
return null;
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
// src/components/PositionView.native.tsx
|
|
357
|
+
var PositionViewState = typedMemo(function PositionViewState2({
|
|
358
|
+
id,
|
|
359
|
+
horizontal,
|
|
360
|
+
style,
|
|
361
|
+
refView,
|
|
362
|
+
...rest
|
|
363
|
+
}) {
|
|
364
|
+
const [position = POSITION_OUT_OF_VIEW] = useArr$([`containerPosition${id}`]);
|
|
365
|
+
return /* @__PURE__ */ React2__namespace.createElement(
|
|
366
|
+
ReactNative.View,
|
|
367
|
+
{
|
|
368
|
+
ref: refView,
|
|
369
|
+
style: [
|
|
370
|
+
style,
|
|
371
|
+
horizontal ? { transform: [{ translateX: position }] } : { transform: [{ translateY: position }] }
|
|
372
|
+
],
|
|
373
|
+
...rest
|
|
374
|
+
}
|
|
375
|
+
);
|
|
376
|
+
});
|
|
377
|
+
var PositionViewAnimated = typedMemo(function PositionViewAnimated2({
|
|
378
|
+
id,
|
|
379
|
+
horizontal,
|
|
380
|
+
style,
|
|
381
|
+
refView,
|
|
382
|
+
...rest
|
|
383
|
+
}) {
|
|
384
|
+
const position$ = useValue$(`containerPosition${id}`, {
|
|
385
|
+
getValue: (v) => v != null ? v : POSITION_OUT_OF_VIEW
|
|
386
|
+
});
|
|
387
|
+
let position;
|
|
388
|
+
if (ReactNative.Platform.OS === "ios" || ReactNative.Platform.OS === "android") {
|
|
389
|
+
position = horizontal ? { transform: [{ translateX: position$ }] } : { transform: [{ translateY: position$ }] };
|
|
390
|
+
} else {
|
|
391
|
+
position = horizontal ? { left: position$ } : { top: position$ };
|
|
392
|
+
}
|
|
393
|
+
return /* @__PURE__ */ React2__namespace.createElement(ReactNative.Animated.View, { ref: refView, style: [style, position], ...rest });
|
|
394
|
+
});
|
|
395
|
+
var PositionViewSticky = typedMemo(function PositionViewSticky2({
|
|
396
|
+
id,
|
|
397
|
+
horizontal,
|
|
398
|
+
style,
|
|
399
|
+
refView,
|
|
400
|
+
animatedScrollY,
|
|
401
|
+
index,
|
|
402
|
+
stickyHeaderConfig,
|
|
403
|
+
children,
|
|
404
|
+
...rest
|
|
405
|
+
}) {
|
|
406
|
+
const [position = POSITION_OUT_OF_VIEW, headerSize = 0, stylePaddingTop = 0] = useArr$([
|
|
407
|
+
`containerPosition${id}`,
|
|
408
|
+
"headerSize",
|
|
409
|
+
"stylePaddingTop"
|
|
410
|
+
]);
|
|
411
|
+
const transform = React2__namespace.useMemo(() => {
|
|
412
|
+
var _a3;
|
|
413
|
+
if (animatedScrollY) {
|
|
414
|
+
const stickyConfigOffset = (_a3 = stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset) != null ? _a3 : 0;
|
|
415
|
+
const stickyStart = position + headerSize + stylePaddingTop - stickyConfigOffset;
|
|
416
|
+
const stickyPosition = animatedScrollY.interpolate({
|
|
417
|
+
extrapolateLeft: "clamp",
|
|
418
|
+
extrapolateRight: "extend",
|
|
419
|
+
inputRange: [stickyStart, stickyStart + 5e3],
|
|
420
|
+
outputRange: [position, position + 5e3]
|
|
421
|
+
});
|
|
422
|
+
return horizontal ? [{ translateX: stickyPosition }] : [{ translateY: stickyPosition }];
|
|
423
|
+
}
|
|
424
|
+
}, [animatedScrollY, headerSize, horizontal, position, stylePaddingTop, stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.offset]);
|
|
425
|
+
const viewStyle = React2__namespace.useMemo(() => [style, { zIndex: index + 1e3 }, { transform }], [style, transform]);
|
|
426
|
+
const renderStickyHeaderBackdrop = React2__namespace.useMemo(() => {
|
|
427
|
+
if (!(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)) {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
return /* @__PURE__ */ React2__namespace.createElement(
|
|
431
|
+
ReactNative.View,
|
|
432
|
+
{
|
|
433
|
+
style: {
|
|
434
|
+
inset: 0,
|
|
435
|
+
pointerEvents: "none",
|
|
436
|
+
position: "absolute"
|
|
437
|
+
}
|
|
438
|
+
},
|
|
439
|
+
getComponent(stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent)
|
|
440
|
+
);
|
|
441
|
+
}, [stickyHeaderConfig == null ? void 0 : stickyHeaderConfig.backdropComponent]);
|
|
442
|
+
return /* @__PURE__ */ React2__namespace.createElement(ReactNative.Animated.View, { ref: refView, style: viewStyle, ...rest }, renderStickyHeaderBackdrop, children);
|
|
443
|
+
});
|
|
444
|
+
var PositionView = IsNewArchitecture ? PositionViewState : PositionViewAnimated;
|
|
445
|
+
function useInit(cb) {
|
|
446
|
+
React2.useState(() => cb());
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// src/state/ContextContainer.ts
|
|
450
|
+
var ContextContainer = React2.createContext(null);
|
|
451
|
+
function useContextContainer() {
|
|
452
|
+
return React2.useContext(ContextContainer);
|
|
453
|
+
}
|
|
454
|
+
function useViewability(callback, configId) {
|
|
455
|
+
const ctx = useStateContext();
|
|
456
|
+
const containerContext = useContextContainer();
|
|
457
|
+
useInit(() => {
|
|
458
|
+
if (!containerContext) {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
const { containerId } = containerContext;
|
|
462
|
+
const key = containerId + (configId != null ? configId : "");
|
|
463
|
+
const value = ctx.mapViewabilityValues.get(key);
|
|
464
|
+
if (value) {
|
|
465
|
+
callback(value);
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
React2.useEffect(() => {
|
|
469
|
+
if (!containerContext) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
const { containerId } = containerContext;
|
|
473
|
+
const key = containerId + (configId != null ? configId : "");
|
|
474
|
+
ctx.mapViewabilityCallbacks.set(key, callback);
|
|
475
|
+
return () => {
|
|
476
|
+
ctx.mapViewabilityCallbacks.delete(key);
|
|
477
|
+
};
|
|
478
|
+
}, [ctx, callback, configId, containerContext]);
|
|
479
|
+
}
|
|
480
|
+
function useViewabilityAmount(callback) {
|
|
481
|
+
const ctx = useStateContext();
|
|
482
|
+
const containerContext = useContextContainer();
|
|
483
|
+
useInit(() => {
|
|
484
|
+
if (!containerContext) {
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
const { containerId } = containerContext;
|
|
488
|
+
const value = ctx.mapViewabilityAmountValues.get(containerId);
|
|
489
|
+
if (value) {
|
|
490
|
+
callback(value);
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
React2.useEffect(() => {
|
|
494
|
+
if (!containerContext) {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
const { containerId } = containerContext;
|
|
498
|
+
ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
|
|
499
|
+
return () => {
|
|
500
|
+
ctx.mapViewabilityAmountCallbacks.delete(containerId);
|
|
501
|
+
};
|
|
502
|
+
}, [ctx, callback, containerContext]);
|
|
503
|
+
}
|
|
504
|
+
function useRecyclingEffect(effect) {
|
|
505
|
+
const containerContext = useContextContainer();
|
|
506
|
+
const prevValues = React2.useRef({
|
|
507
|
+
prevIndex: void 0,
|
|
508
|
+
prevItem: void 0
|
|
509
|
+
});
|
|
510
|
+
React2.useEffect(() => {
|
|
511
|
+
if (!containerContext) {
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
const { index, value } = containerContext;
|
|
515
|
+
let ret;
|
|
516
|
+
if (prevValues.current.prevIndex !== void 0 && prevValues.current.prevItem !== void 0) {
|
|
517
|
+
ret = effect({
|
|
518
|
+
index,
|
|
519
|
+
item: value,
|
|
520
|
+
prevIndex: prevValues.current.prevIndex,
|
|
521
|
+
prevItem: prevValues.current.prevItem
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
prevValues.current = {
|
|
525
|
+
prevIndex: index,
|
|
526
|
+
prevItem: value
|
|
527
|
+
};
|
|
528
|
+
return ret;
|
|
529
|
+
}, [effect, containerContext]);
|
|
530
|
+
}
|
|
531
|
+
function useRecyclingState(valueOrFun) {
|
|
532
|
+
var _a3, _b;
|
|
533
|
+
const containerContext = useContextContainer();
|
|
534
|
+
const computeValue = (ctx) => {
|
|
535
|
+
if (isFunction(valueOrFun)) {
|
|
536
|
+
const initializer = valueOrFun;
|
|
537
|
+
return ctx ? initializer({
|
|
538
|
+
index: ctx.index,
|
|
539
|
+
item: ctx.value,
|
|
540
|
+
prevIndex: void 0,
|
|
541
|
+
prevItem: void 0
|
|
542
|
+
}) : initializer();
|
|
543
|
+
}
|
|
544
|
+
return valueOrFun;
|
|
545
|
+
};
|
|
546
|
+
const [stateValue, setStateValue] = React2.useState(() => {
|
|
547
|
+
return computeValue(containerContext);
|
|
548
|
+
});
|
|
549
|
+
const prevItemKeyRef = React2.useRef((_a3 = containerContext == null ? void 0 : containerContext.itemKey) != null ? _a3 : null);
|
|
550
|
+
const currentItemKey = (_b = containerContext == null ? void 0 : containerContext.itemKey) != null ? _b : null;
|
|
551
|
+
if (currentItemKey !== null && prevItemKeyRef.current !== currentItemKey) {
|
|
552
|
+
prevItemKeyRef.current = currentItemKey;
|
|
553
|
+
setStateValue(computeValue(containerContext));
|
|
554
|
+
}
|
|
555
|
+
const triggerLayout = containerContext == null ? void 0 : containerContext.triggerLayout;
|
|
556
|
+
const setState = React2.useCallback(
|
|
557
|
+
(newState) => {
|
|
558
|
+
if (!triggerLayout) {
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
setStateValue((prevValue) => {
|
|
562
|
+
return isFunction(newState) ? newState(prevValue) : newState;
|
|
563
|
+
});
|
|
564
|
+
triggerLayout();
|
|
565
|
+
},
|
|
566
|
+
[triggerLayout]
|
|
567
|
+
);
|
|
568
|
+
return [stateValue, setState];
|
|
569
|
+
}
|
|
570
|
+
function useIsLastItem() {
|
|
571
|
+
const containerContext = useContextContainer();
|
|
572
|
+
const isLast = useSelector$("lastItemKeys", (lastItemKeys) => {
|
|
573
|
+
if (containerContext) {
|
|
574
|
+
const { itemKey } = containerContext;
|
|
575
|
+
if (!isNullOrUndefined(itemKey)) {
|
|
576
|
+
return (lastItemKeys == null ? void 0 : lastItemKeys.includes(itemKey)) || false;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return false;
|
|
580
|
+
});
|
|
581
|
+
return isLast;
|
|
582
|
+
}
|
|
583
|
+
function useListScrollSize() {
|
|
584
|
+
const [scrollSize] = useArr$(["scrollSize"]);
|
|
585
|
+
return scrollSize;
|
|
586
|
+
}
|
|
587
|
+
var noop = () => {
|
|
588
|
+
};
|
|
589
|
+
function useSyncLayout() {
|
|
590
|
+
const containerContext = useContextContainer();
|
|
591
|
+
if (IsNewArchitecture && containerContext) {
|
|
592
|
+
const { triggerLayout: syncLayout } = containerContext;
|
|
593
|
+
return syncLayout;
|
|
594
|
+
} else {
|
|
595
|
+
return noop;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// src/components/Separator.tsx
|
|
600
|
+
function Separator({ ItemSeparatorComponent, leadingItem }) {
|
|
601
|
+
const isLastItem = useIsLastItem();
|
|
602
|
+
return isLastItem ? null : /* @__PURE__ */ React2__namespace.createElement(ItemSeparatorComponent, { leadingItem });
|
|
603
|
+
}
|
|
604
|
+
function useOnLayoutSync({
|
|
605
|
+
ref,
|
|
606
|
+
onLayoutProp,
|
|
607
|
+
onLayoutChange
|
|
608
|
+
}, deps = []) {
|
|
609
|
+
const lastLayoutRef = React2.useRef(null);
|
|
610
|
+
const onLayout = React2.useCallback(
|
|
611
|
+
(event) => {
|
|
612
|
+
var _a3, _b;
|
|
613
|
+
const { layout } = event.nativeEvent;
|
|
614
|
+
if (layout.height !== ((_a3 = lastLayoutRef.current) == null ? void 0 : _a3.height) || layout.width !== ((_b = lastLayoutRef.current) == null ? void 0 : _b.width)) {
|
|
615
|
+
onLayoutChange(layout, false);
|
|
616
|
+
onLayoutProp == null ? void 0 : onLayoutProp(event);
|
|
617
|
+
lastLayoutRef.current = layout;
|
|
618
|
+
}
|
|
619
|
+
},
|
|
620
|
+
[onLayoutChange]
|
|
621
|
+
);
|
|
622
|
+
if (IsNewArchitecture) {
|
|
623
|
+
React2.useLayoutEffect(() => {
|
|
624
|
+
if (ref.current) {
|
|
625
|
+
ref.current.measure((x, y, width, height) => {
|
|
626
|
+
const layout = { height, width, x, y };
|
|
627
|
+
lastLayoutRef.current = layout;
|
|
628
|
+
onLayoutChange(layout, true);
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
}, deps);
|
|
632
|
+
}
|
|
633
|
+
return { onLayout };
|
|
634
|
+
}
|
|
635
|
+
var Platform2 = ReactNative.Platform;
|
|
636
|
+
var PlatformAdjustBreaksScroll = Platform2.OS === "android";
|
|
637
|
+
var typedForwardRef = React2__namespace.forwardRef;
|
|
638
|
+
var typedMemo2 = React2__namespace.memo;
|
|
639
|
+
|
|
640
|
+
// src/utils/isInMVCPActiveMode.native.ts
|
|
641
|
+
function isInMVCPActiveMode(state) {
|
|
642
|
+
return state.dataChangeNeedsScrollUpdate;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// src/components/Container.tsx
|
|
646
|
+
var Container = typedMemo2(function Container2({
|
|
647
|
+
id,
|
|
648
|
+
recycleItems,
|
|
649
|
+
horizontal,
|
|
650
|
+
getRenderedItem: getRenderedItem2,
|
|
651
|
+
updateItemSize: updateItemSize2,
|
|
652
|
+
ItemSeparatorComponent,
|
|
653
|
+
stickyHeaderConfig
|
|
654
|
+
}) {
|
|
655
|
+
const ctx = useStateContext();
|
|
656
|
+
const { columnWrapperStyle, animatedScrollY } = ctx;
|
|
657
|
+
const positionComponentInternal = ctx.state.props.positionComponentInternal;
|
|
658
|
+
const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
|
|
659
|
+
const [column = 0, span = 1, data, itemKey, numColumns = 1, extraData, isSticky] = useArr$([
|
|
660
|
+
`containerColumn${id}`,
|
|
661
|
+
`containerSpan${id}`,
|
|
662
|
+
`containerItemData${id}`,
|
|
663
|
+
`containerItemKey${id}`,
|
|
664
|
+
"numColumns",
|
|
665
|
+
"extraData",
|
|
666
|
+
`containerSticky${id}`
|
|
667
|
+
]);
|
|
668
|
+
const itemLayoutRef = React2.useRef({
|
|
669
|
+
didLayout: false,
|
|
670
|
+
horizontal,
|
|
671
|
+
itemKey,
|
|
672
|
+
pendingShrinkToken: 0,
|
|
673
|
+
updateItemSize: updateItemSize2
|
|
674
|
+
});
|
|
675
|
+
itemLayoutRef.current.horizontal = horizontal;
|
|
676
|
+
itemLayoutRef.current.itemKey = itemKey;
|
|
677
|
+
itemLayoutRef.current.updateItemSize = updateItemSize2;
|
|
678
|
+
const ref = React2.useRef(null);
|
|
679
|
+
const [layoutRenderCount, forceLayoutRender] = React2.useState(0);
|
|
680
|
+
const resolvedColumn = column > 0 ? column : 1;
|
|
681
|
+
const resolvedSpan = Math.min(Math.max(span || 1, 1), numColumns);
|
|
682
|
+
const otherAxisPos = numColumns > 1 ? `${(resolvedColumn - 1) / numColumns * 100}%` : 0;
|
|
683
|
+
const otherAxisSize = numColumns > 1 ? `${resolvedSpan / numColumns * 100}%` : void 0;
|
|
684
|
+
const style = React2.useMemo(() => {
|
|
685
|
+
let paddingStyles;
|
|
686
|
+
if (columnWrapperStyle) {
|
|
687
|
+
const { columnGap, rowGap, gap } = columnWrapperStyle;
|
|
688
|
+
if (horizontal) {
|
|
689
|
+
paddingStyles = {
|
|
690
|
+
paddingRight: columnGap || gap || void 0,
|
|
691
|
+
paddingVertical: numColumns > 1 ? (rowGap || gap || 0) / 2 : void 0
|
|
692
|
+
};
|
|
693
|
+
} else {
|
|
694
|
+
paddingStyles = {
|
|
695
|
+
paddingBottom: rowGap || gap || void 0,
|
|
696
|
+
paddingHorizontal: numColumns > 1 ? (columnGap || gap || 0) / 2 : void 0
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
return horizontal ? {
|
|
701
|
+
flexDirection: ItemSeparatorComponent ? "row" : void 0,
|
|
702
|
+
height: otherAxisSize,
|
|
703
|
+
left: 0,
|
|
704
|
+
position: "absolute",
|
|
705
|
+
top: otherAxisPos,
|
|
706
|
+
...paddingStyles || {}
|
|
707
|
+
} : {
|
|
708
|
+
left: otherAxisPos,
|
|
709
|
+
position: "absolute",
|
|
710
|
+
right: numColumns > 1 ? null : 0,
|
|
711
|
+
top: 0,
|
|
712
|
+
width: otherAxisSize,
|
|
713
|
+
...paddingStyles || {}
|
|
714
|
+
};
|
|
715
|
+
}, [horizontal, otherAxisPos, otherAxisSize, columnWrapperStyle, numColumns]);
|
|
716
|
+
const renderedItemInfo = React2.useMemo(
|
|
717
|
+
() => itemKey !== void 0 ? getRenderedItem2(itemKey) : null,
|
|
718
|
+
[itemKey, data, extraData]
|
|
719
|
+
);
|
|
720
|
+
const { index, renderedItem } = renderedItemInfo || {};
|
|
721
|
+
const contextValue = React2.useMemo(() => {
|
|
722
|
+
ctx.viewRefs.set(id, ref);
|
|
723
|
+
return {
|
|
724
|
+
containerId: id,
|
|
725
|
+
index,
|
|
726
|
+
itemKey,
|
|
727
|
+
triggerLayout: () => {
|
|
728
|
+
forceLayoutRender((v) => v + 1);
|
|
729
|
+
},
|
|
730
|
+
value: data
|
|
731
|
+
};
|
|
732
|
+
}, [id, itemKey, index, data]);
|
|
733
|
+
const onLayoutChange = React2.useCallback((rectangle) => {
|
|
734
|
+
var _a3, _b;
|
|
735
|
+
const {
|
|
736
|
+
horizontal: currentHorizontal,
|
|
737
|
+
itemKey: currentItemKey,
|
|
738
|
+
updateItemSize: updateItemSizeFn,
|
|
739
|
+
lastSize,
|
|
740
|
+
pendingShrinkToken
|
|
741
|
+
} = itemLayoutRef.current;
|
|
742
|
+
if (isNullOrUndefined(currentItemKey)) {
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
itemLayoutRef.current.didLayout = true;
|
|
746
|
+
let layout = rectangle;
|
|
747
|
+
const axis = currentHorizontal ? "width" : "height";
|
|
748
|
+
const size = roundSize(rectangle[axis]);
|
|
749
|
+
const prevSize = lastSize ? roundSize(lastSize[axis]) : void 0;
|
|
750
|
+
const doUpdate = () => {
|
|
751
|
+
itemLayoutRef.current.lastSize = layout;
|
|
752
|
+
updateItemSizeFn(currentItemKey, layout);
|
|
753
|
+
itemLayoutRef.current.didLayout = true;
|
|
754
|
+
};
|
|
755
|
+
const shouldDeferWebShrinkLayoutUpdate = Platform2.OS === "web" && !isInMVCPActiveMode(ctx.state) && prevSize !== void 0 && size + 1 < prevSize;
|
|
756
|
+
if (shouldDeferWebShrinkLayoutUpdate) {
|
|
757
|
+
const token = pendingShrinkToken + 1;
|
|
758
|
+
itemLayoutRef.current.pendingShrinkToken = token;
|
|
759
|
+
requestAnimationFrame(() => {
|
|
760
|
+
var _a4;
|
|
761
|
+
if (itemLayoutRef.current.pendingShrinkToken !== token) {
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
const element = ref.current;
|
|
765
|
+
const rect = (_a4 = element == null ? void 0 : element.getBoundingClientRect) == null ? void 0 : _a4.call(element);
|
|
766
|
+
if (rect) {
|
|
767
|
+
layout = { height: rect.height, width: rect.width };
|
|
768
|
+
}
|
|
769
|
+
doUpdate();
|
|
770
|
+
});
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
if (IsNewArchitecture || size > 0) {
|
|
774
|
+
doUpdate();
|
|
775
|
+
} else {
|
|
776
|
+
(_b = (_a3 = ref.current) == null ? void 0 : _a3.measure) == null ? void 0 : _b.call(_a3, (_x, _y, width, height) => {
|
|
777
|
+
layout = { height, width };
|
|
778
|
+
doUpdate();
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
}, []);
|
|
782
|
+
const { onLayout } = useOnLayoutSync(
|
|
783
|
+
{
|
|
784
|
+
onLayoutChange,
|
|
785
|
+
ref},
|
|
786
|
+
[itemKey, layoutRenderCount]
|
|
787
|
+
);
|
|
788
|
+
if (!IsNewArchitecture) {
|
|
789
|
+
React2.useEffect(() => {
|
|
790
|
+
if (!isNullOrUndefined(itemKey)) {
|
|
791
|
+
itemLayoutRef.current.didLayout = false;
|
|
792
|
+
const timeout = setTimeout(() => {
|
|
793
|
+
if (!itemLayoutRef.current.didLayout) {
|
|
794
|
+
const {
|
|
795
|
+
itemKey: currentItemKey,
|
|
796
|
+
lastSize,
|
|
797
|
+
updateItemSize: updateItemSizeFn
|
|
798
|
+
} = itemLayoutRef.current;
|
|
799
|
+
if (lastSize && !isNullOrUndefined(currentItemKey)) {
|
|
800
|
+
updateItemSizeFn(currentItemKey, lastSize);
|
|
801
|
+
itemLayoutRef.current.didLayout = true;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
}, 16);
|
|
805
|
+
return () => {
|
|
806
|
+
clearTimeout(timeout);
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
}, [itemKey]);
|
|
810
|
+
}
|
|
811
|
+
const PositionComponent = isSticky ? stickyPositionComponentInternal ? stickyPositionComponentInternal : PositionViewSticky : positionComponentInternal ? positionComponentInternal : PositionView;
|
|
812
|
+
return /* @__PURE__ */ React2__namespace.createElement(
|
|
813
|
+
PositionComponent,
|
|
814
|
+
{
|
|
815
|
+
animatedScrollY: isSticky ? animatedScrollY : void 0,
|
|
816
|
+
horizontal,
|
|
817
|
+
id,
|
|
818
|
+
index,
|
|
819
|
+
key: recycleItems ? void 0 : itemKey,
|
|
820
|
+
onLayout,
|
|
821
|
+
refView: ref,
|
|
822
|
+
stickyHeaderConfig,
|
|
823
|
+
style
|
|
824
|
+
},
|
|
825
|
+
/* @__PURE__ */ React2__namespace.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && /* @__PURE__ */ React2__namespace.createElement(Separator, { ItemSeparatorComponent, leadingItem: renderedItemInfo.item }))
|
|
826
|
+
);
|
|
827
|
+
});
|
|
828
|
+
|
|
829
|
+
// src/components/Containers.native.tsx
|
|
830
|
+
var Containers = typedMemo(function Containers2({
|
|
831
|
+
horizontal,
|
|
832
|
+
recycleItems,
|
|
833
|
+
ItemSeparatorComponent,
|
|
834
|
+
waitForInitialLayout,
|
|
835
|
+
stickyHeaderConfig,
|
|
836
|
+
updateItemSize: updateItemSize2,
|
|
837
|
+
getRenderedItem: getRenderedItem2
|
|
838
|
+
}) {
|
|
839
|
+
const ctx = useStateContext();
|
|
840
|
+
const columnWrapperStyle = ctx.columnWrapperStyle;
|
|
841
|
+
const [numContainers, numColumns] = useArr$(["numContainersPooled", "numColumns"]);
|
|
842
|
+
const animSize = useValue$("totalSize", {
|
|
843
|
+
// Use a microtask if increasing the size significantly, otherwise use a timeout
|
|
844
|
+
// If this is the initial scroll, we don't want to delay because we want to update the size immediately
|
|
845
|
+
delay: (value, prevValue) => {
|
|
846
|
+
var _a3;
|
|
847
|
+
return !((_a3 = ctx.state) == null ? void 0 : _a3.initialScroll) ? !prevValue || value - prevValue > 20 ? 0 : 200 : void 0;
|
|
848
|
+
}
|
|
849
|
+
});
|
|
850
|
+
const animOpacity = waitForInitialLayout ? useValue$("readyToRender", { getValue: (value) => value ? 1 : 0 }) : void 0;
|
|
851
|
+
const otherAxisSize = useValue$("otherAxisSize", { delay: 0 });
|
|
852
|
+
const containers = [];
|
|
853
|
+
for (let i = 0; i < numContainers; i++) {
|
|
854
|
+
containers.push(
|
|
855
|
+
/* @__PURE__ */ React2__namespace.createElement(
|
|
856
|
+
Container,
|
|
857
|
+
{
|
|
858
|
+
getRenderedItem: getRenderedItem2,
|
|
859
|
+
horizontal,
|
|
860
|
+
ItemSeparatorComponent,
|
|
861
|
+
id: i,
|
|
862
|
+
key: i,
|
|
863
|
+
recycleItems,
|
|
864
|
+
stickyHeaderConfig,
|
|
865
|
+
updateItemSize: updateItemSize2
|
|
866
|
+
}
|
|
867
|
+
)
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
const style = horizontal ? { minHeight: otherAxisSize, opacity: animOpacity, width: animSize } : { height: animSize, minWidth: otherAxisSize, opacity: animOpacity };
|
|
871
|
+
if (columnWrapperStyle) {
|
|
872
|
+
const { columnGap, rowGap, gap } = columnWrapperStyle;
|
|
873
|
+
const gapX = columnGap || gap || 0;
|
|
874
|
+
const gapY = rowGap || gap || 0;
|
|
875
|
+
if (horizontal) {
|
|
876
|
+
if (gapY && numColumns > 1) {
|
|
877
|
+
style.marginVertical = -gapY / 2;
|
|
878
|
+
}
|
|
879
|
+
if (gapX) {
|
|
880
|
+
style.marginRight = -gapX;
|
|
881
|
+
}
|
|
882
|
+
} else {
|
|
883
|
+
if (gapX && numColumns > 1) {
|
|
884
|
+
style.marginHorizontal = -gapX;
|
|
885
|
+
}
|
|
886
|
+
if (gapY) {
|
|
887
|
+
style.marginBottom = -gapY;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
return /* @__PURE__ */ React2__namespace.createElement(ReactNative.Animated.View, { style }, containers);
|
|
892
|
+
});
|
|
893
|
+
var ListComponentScrollView = ReactNative.Animated.ScrollView;
|
|
894
|
+
function ScrollAdjust() {
|
|
895
|
+
const bias = 1e7;
|
|
896
|
+
const [scrollAdjust, scrollAdjustUserOffset] = useArr$(["scrollAdjust", "scrollAdjustUserOffset"]);
|
|
897
|
+
const scrollOffset = (scrollAdjust || 0) + (scrollAdjustUserOffset || 0) + bias;
|
|
898
|
+
return /* @__PURE__ */ React2__namespace.createElement(
|
|
899
|
+
ReactNative.View,
|
|
900
|
+
{
|
|
901
|
+
style: {
|
|
902
|
+
height: 0,
|
|
903
|
+
left: 0,
|
|
904
|
+
position: "absolute",
|
|
905
|
+
top: scrollOffset,
|
|
906
|
+
width: 0
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
);
|
|
910
|
+
}
|
|
911
|
+
function SnapWrapper({ ScrollComponent, ...props }) {
|
|
912
|
+
const [snapToOffsets] = useArr$(["snapToOffsets"]);
|
|
913
|
+
return /* @__PURE__ */ React2__namespace.createElement(ScrollComponent, { ...props, snapToOffsets });
|
|
914
|
+
}
|
|
915
|
+
var LayoutView = ({ onLayoutChange, refView, ...rest }) => {
|
|
916
|
+
const ref = refView != null ? refView : React2.useRef(null);
|
|
917
|
+
const { onLayout } = useOnLayoutSync({ onLayoutChange, ref });
|
|
918
|
+
return /* @__PURE__ */ React2__namespace.createElement(ReactNative.View, { ...rest, onLayout, ref });
|
|
919
|
+
};
|
|
920
|
+
|
|
921
|
+
// src/components/ListComponent.tsx
|
|
922
|
+
var ListComponent = typedMemo2(function ListComponent2({
|
|
923
|
+
canRender,
|
|
924
|
+
style,
|
|
925
|
+
contentContainerStyle,
|
|
926
|
+
horizontal,
|
|
927
|
+
initialContentOffset,
|
|
928
|
+
recycleItems,
|
|
929
|
+
ItemSeparatorComponent,
|
|
930
|
+
alignItemsAtEnd: _alignItemsAtEnd,
|
|
931
|
+
waitForInitialLayout,
|
|
932
|
+
onScroll: onScroll2,
|
|
933
|
+
onLayout,
|
|
934
|
+
ListHeaderComponent,
|
|
935
|
+
ListHeaderComponentStyle,
|
|
936
|
+
ListFooterComponent,
|
|
937
|
+
ListFooterComponentStyle,
|
|
938
|
+
ListEmptyComponent,
|
|
939
|
+
getRenderedItem: getRenderedItem2,
|
|
940
|
+
updateItemSize: updateItemSize2,
|
|
941
|
+
refScrollView,
|
|
942
|
+
renderScrollComponent,
|
|
943
|
+
onLayoutFooter,
|
|
944
|
+
scrollAdjustHandler,
|
|
945
|
+
snapToIndices,
|
|
946
|
+
stickyHeaderConfig,
|
|
947
|
+
stickyHeaderIndices,
|
|
948
|
+
useWindowScroll = false,
|
|
949
|
+
...rest
|
|
950
|
+
}) {
|
|
951
|
+
const ctx = useStateContext();
|
|
952
|
+
const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
|
|
953
|
+
const ScrollComponent = renderScrollComponent ? React2.useMemo(
|
|
954
|
+
() => React2__namespace.forwardRef(
|
|
955
|
+
(props, ref) => renderScrollComponent({ ...props, ref })
|
|
956
|
+
),
|
|
957
|
+
[renderScrollComponent]
|
|
958
|
+
) : ListComponentScrollView;
|
|
959
|
+
const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
|
|
960
|
+
React2.useLayoutEffect(() => {
|
|
961
|
+
if (!ListHeaderComponent) {
|
|
962
|
+
set$(ctx, "headerSize", 0);
|
|
963
|
+
}
|
|
964
|
+
if (!ListFooterComponent) {
|
|
965
|
+
set$(ctx, "footerSize", 0);
|
|
966
|
+
}
|
|
967
|
+
}, [ListHeaderComponent, ListFooterComponent, ctx]);
|
|
968
|
+
const onLayoutHeader = React2.useCallback(
|
|
969
|
+
(rect) => {
|
|
970
|
+
const size = rect[horizontal ? "width" : "height"];
|
|
971
|
+
set$(ctx, "headerSize", size);
|
|
972
|
+
},
|
|
973
|
+
[ctx, horizontal]
|
|
974
|
+
);
|
|
975
|
+
const onLayoutFooterInternal = React2.useCallback(
|
|
976
|
+
(rect, fromLayoutEffect) => {
|
|
977
|
+
const size = rect[horizontal ? "width" : "height"];
|
|
978
|
+
set$(ctx, "footerSize", size);
|
|
979
|
+
onLayoutFooter == null ? void 0 : onLayoutFooter(rect, fromLayoutEffect);
|
|
980
|
+
},
|
|
981
|
+
[ctx, horizontal, onLayoutFooter]
|
|
982
|
+
);
|
|
983
|
+
return /* @__PURE__ */ React2__namespace.createElement(
|
|
984
|
+
SnapOrScroll,
|
|
985
|
+
{
|
|
986
|
+
...rest,
|
|
987
|
+
...ScrollComponent === ListComponentScrollView ? { useWindowScroll } : {},
|
|
988
|
+
contentContainerStyle: [
|
|
989
|
+
contentContainerStyle,
|
|
990
|
+
horizontal ? {
|
|
991
|
+
height: "100%"
|
|
992
|
+
} : {}
|
|
993
|
+
],
|
|
994
|
+
contentOffset: initialContentOffset ? horizontal ? { x: initialContentOffset, y: 0 } : { x: 0, y: initialContentOffset } : void 0,
|
|
995
|
+
horizontal,
|
|
996
|
+
maintainVisibleContentPosition: maintainVisibleContentPosition.size || maintainVisibleContentPosition.data ? { minIndexForVisible: 0 } : void 0,
|
|
997
|
+
onLayout,
|
|
998
|
+
onScroll: onScroll2,
|
|
999
|
+
ref: refScrollView,
|
|
1000
|
+
ScrollComponent: snapToIndices ? ScrollComponent : void 0,
|
|
1001
|
+
style
|
|
1002
|
+
},
|
|
1003
|
+
/* @__PURE__ */ React2__namespace.createElement(ScrollAdjust, null),
|
|
1004
|
+
ListHeaderComponent && /* @__PURE__ */ React2__namespace.createElement(LayoutView, { onLayoutChange: onLayoutHeader, style: ListHeaderComponentStyle }, getComponent(ListHeaderComponent)),
|
|
1005
|
+
ListEmptyComponent && getComponent(ListEmptyComponent),
|
|
1006
|
+
canRender && !ListEmptyComponent && /* @__PURE__ */ React2__namespace.createElement(
|
|
1007
|
+
Containers,
|
|
1008
|
+
{
|
|
1009
|
+
getRenderedItem: getRenderedItem2,
|
|
1010
|
+
horizontal,
|
|
1011
|
+
ItemSeparatorComponent,
|
|
1012
|
+
recycleItems,
|
|
1013
|
+
stickyHeaderConfig,
|
|
1014
|
+
updateItemSize: updateItemSize2,
|
|
1015
|
+
waitForInitialLayout
|
|
1016
|
+
}
|
|
1017
|
+
),
|
|
1018
|
+
ListFooterComponent && /* @__PURE__ */ React2__namespace.createElement(LayoutView, { onLayoutChange: onLayoutFooterInternal, style: ListFooterComponentStyle }, getComponent(ListFooterComponent)),
|
|
1019
|
+
IS_DEV && ENABLE_DEVMODE
|
|
1020
|
+
);
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
// src/core/calculateOffsetForIndex.ts
|
|
1024
|
+
function calculateOffsetForIndex(ctx, index) {
|
|
1025
|
+
const state = ctx.state;
|
|
1026
|
+
return index !== void 0 ? state.positions[index] || 0 : 0;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// src/core/getTopOffsetAdjustment.ts
|
|
1030
|
+
function getTopOffsetAdjustment(ctx) {
|
|
1031
|
+
return (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
// src/utils/getId.ts
|
|
1035
|
+
function getId(state, index) {
|
|
1036
|
+
const { data, keyExtractor } = state.props;
|
|
1037
|
+
if (!data) {
|
|
1038
|
+
return "";
|
|
1039
|
+
}
|
|
1040
|
+
const ret = index < data.length ? keyExtractor ? keyExtractor(data[index], index) : index : null;
|
|
1041
|
+
const id = ret;
|
|
1042
|
+
state.idCache[index] = id;
|
|
1043
|
+
return id;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
// src/core/addTotalSize.ts
|
|
1047
|
+
function addTotalSize(ctx, key, add) {
|
|
1048
|
+
const state = ctx.state;
|
|
1049
|
+
const prevTotalSize = state.totalSize;
|
|
1050
|
+
let totalSize = state.totalSize;
|
|
1051
|
+
if (key === null) {
|
|
1052
|
+
totalSize = add;
|
|
1053
|
+
if (state.timeoutSetPaddingTop) {
|
|
1054
|
+
clearTimeout(state.timeoutSetPaddingTop);
|
|
1055
|
+
state.timeoutSetPaddingTop = void 0;
|
|
1056
|
+
}
|
|
1057
|
+
} else {
|
|
1058
|
+
totalSize += add;
|
|
1059
|
+
}
|
|
1060
|
+
if (prevTotalSize !== totalSize) {
|
|
1061
|
+
if (!IsNewArchitecture && state.initialScroll && totalSize < prevTotalSize) {
|
|
1062
|
+
state.pendingTotalSize = totalSize;
|
|
1063
|
+
} else {
|
|
1064
|
+
state.pendingTotalSize = void 0;
|
|
1065
|
+
state.totalSize = totalSize;
|
|
1066
|
+
set$(ctx, "totalSize", totalSize);
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// src/core/setSize.ts
|
|
1072
|
+
function setSize(ctx, itemKey, size) {
|
|
1073
|
+
const state = ctx.state;
|
|
1074
|
+
const { sizes } = state;
|
|
1075
|
+
const previousSize = sizes.get(itemKey);
|
|
1076
|
+
const diff = previousSize !== void 0 ? size - previousSize : size;
|
|
1077
|
+
if (diff !== 0) {
|
|
1078
|
+
addTotalSize(ctx, itemKey, diff);
|
|
1079
|
+
}
|
|
1080
|
+
sizes.set(itemKey, size);
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// src/utils/getItemSize.ts
|
|
1084
|
+
function getItemSize(ctx, key, index, data, useAverageSize, preferCachedSize) {
|
|
1085
|
+
var _a3, _b;
|
|
1086
|
+
const state = ctx.state;
|
|
1087
|
+
const {
|
|
1088
|
+
sizesKnown,
|
|
1089
|
+
sizes,
|
|
1090
|
+
averageSizes,
|
|
1091
|
+
props: { estimatedItemSize, getEstimatedItemSize, getFixedItemSize, getItemType },
|
|
1092
|
+
scrollingTo
|
|
1093
|
+
} = state;
|
|
1094
|
+
const sizeKnown = sizesKnown.get(key);
|
|
1095
|
+
if (sizeKnown !== void 0) {
|
|
1096
|
+
return sizeKnown;
|
|
1097
|
+
}
|
|
1098
|
+
let size;
|
|
1099
|
+
if (preferCachedSize) {
|
|
1100
|
+
const cachedSize = sizes.get(key);
|
|
1101
|
+
if (cachedSize !== void 0) {
|
|
1102
|
+
return cachedSize;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
const itemType = getItemType ? (_a3 = getItemType(data, index)) != null ? _a3 : "" : "";
|
|
1106
|
+
if (getFixedItemSize) {
|
|
1107
|
+
size = getFixedItemSize(data, index, itemType);
|
|
1108
|
+
if (size !== void 0) {
|
|
1109
|
+
sizesKnown.set(key, size);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
if (size === void 0 && useAverageSize && sizeKnown === void 0 && !scrollingTo) {
|
|
1113
|
+
const averageSizeForType = (_b = averageSizes[itemType]) == null ? void 0 : _b.avg;
|
|
1114
|
+
if (averageSizeForType !== void 0) {
|
|
1115
|
+
size = roundSize(averageSizeForType);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
if (size === void 0) {
|
|
1119
|
+
size = sizes.get(key);
|
|
1120
|
+
if (size !== void 0) {
|
|
1121
|
+
return size;
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
if (size === void 0) {
|
|
1125
|
+
size = getEstimatedItemSize ? getEstimatedItemSize(data, index, itemType) : estimatedItemSize;
|
|
1126
|
+
}
|
|
1127
|
+
setSize(ctx, key, size);
|
|
1128
|
+
return size;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
// src/core/calculateOffsetWithOffsetPosition.ts
|
|
1132
|
+
function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
|
|
1133
|
+
var _a3;
|
|
1134
|
+
const state = ctx.state;
|
|
1135
|
+
const { index, viewOffset, viewPosition } = params;
|
|
1136
|
+
let offset = offsetParam;
|
|
1137
|
+
if (viewOffset) {
|
|
1138
|
+
offset -= viewOffset;
|
|
1139
|
+
}
|
|
1140
|
+
if (index !== void 0) {
|
|
1141
|
+
const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
|
|
1142
|
+
if (topOffsetAdjustment) {
|
|
1143
|
+
offset += topOffsetAdjustment;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
if (viewPosition !== void 0 && index !== void 0) {
|
|
1147
|
+
const dataLength = state.props.data.length;
|
|
1148
|
+
if (dataLength === 0) {
|
|
1149
|
+
return offset;
|
|
1150
|
+
}
|
|
1151
|
+
const isOutOfBounds = index < 0 || index >= dataLength;
|
|
1152
|
+
const fallbackEstimatedSize = (_a3 = state.props.estimatedItemSize) != null ? _a3 : 0;
|
|
1153
|
+
const itemSize = isOutOfBounds ? fallbackEstimatedSize : getItemSize(ctx, getId(state, index), index, state.props.data[index]);
|
|
1154
|
+
const trailingInset = getContentInsetEnd(state);
|
|
1155
|
+
offset -= viewPosition * (state.scrollLength - trailingInset - itemSize);
|
|
1156
|
+
if (!isOutOfBounds && index === state.props.data.length - 1) {
|
|
1157
|
+
const footerSize = peek$(ctx, "footerSize") || 0;
|
|
1158
|
+
offset += footerSize;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
return offset;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
// src/core/clampScrollOffset.ts
|
|
1165
|
+
function clampScrollOffset(ctx, offset, scrollTarget) {
|
|
1166
|
+
const state = ctx.state;
|
|
1167
|
+
const contentSize = getContentSize(ctx);
|
|
1168
|
+
let clampedOffset = offset;
|
|
1169
|
+
if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform2.OS !== "android" || state.lastLayout)) {
|
|
1170
|
+
const baseMaxOffset = Math.max(0, contentSize - state.scrollLength);
|
|
1171
|
+
const viewOffset = scrollTarget == null ? void 0 : scrollTarget.viewOffset;
|
|
1172
|
+
const extraEndOffset = typeof viewOffset === "number" && viewOffset < 0 ? -viewOffset : 0;
|
|
1173
|
+
const maxOffset = baseMaxOffset + extraEndOffset;
|
|
1174
|
+
clampedOffset = Math.min(offset, maxOffset);
|
|
1175
|
+
}
|
|
1176
|
+
clampedOffset = Math.max(0, clampedOffset);
|
|
1177
|
+
return clampedOffset;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
// src/utils/checkThreshold.ts
|
|
1181
|
+
var HYSTERESIS_MULTIPLIER = 1.3;
|
|
1182
|
+
var checkThreshold = (distance, atThreshold, threshold, wasReached, snapshot, context, onReached, setSnapshot, allowReentryOnChange) => {
|
|
1183
|
+
const absDistance = Math.abs(distance);
|
|
1184
|
+
const within = atThreshold || threshold > 0 && absDistance <= threshold;
|
|
1185
|
+
const updateSnapshot = () => {
|
|
1186
|
+
setSnapshot({
|
|
1187
|
+
atThreshold,
|
|
1188
|
+
contentSize: context.contentSize,
|
|
1189
|
+
dataLength: context.dataLength,
|
|
1190
|
+
scrollPosition: context.scrollPosition
|
|
1191
|
+
});
|
|
1192
|
+
};
|
|
1193
|
+
if (!wasReached) {
|
|
1194
|
+
if (!within) {
|
|
1195
|
+
return false;
|
|
1196
|
+
}
|
|
1197
|
+
onReached(distance);
|
|
1198
|
+
updateSnapshot();
|
|
1199
|
+
return true;
|
|
1200
|
+
}
|
|
1201
|
+
const reset = !atThreshold && threshold > 0 && absDistance >= threshold * HYSTERESIS_MULTIPLIER || !atThreshold && threshold <= 0 && absDistance > 0;
|
|
1202
|
+
if (reset) {
|
|
1203
|
+
setSnapshot(void 0);
|
|
1204
|
+
return false;
|
|
1205
|
+
}
|
|
1206
|
+
if (within) {
|
|
1207
|
+
const changed = !snapshot || snapshot.atThreshold !== atThreshold || snapshot.contentSize !== context.contentSize || snapshot.dataLength !== context.dataLength;
|
|
1208
|
+
if (changed) {
|
|
1209
|
+
if (allowReentryOnChange) {
|
|
1210
|
+
onReached(distance);
|
|
1211
|
+
}
|
|
1212
|
+
updateSnapshot();
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
return true;
|
|
1216
|
+
};
|
|
1217
|
+
|
|
1218
|
+
// src/utils/checkAtBottom.ts
|
|
1219
|
+
function checkAtBottom(ctx) {
|
|
1220
|
+
var _a3;
|
|
1221
|
+
const state = ctx.state;
|
|
1222
|
+
if (!state || state.initialScroll) {
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
const {
|
|
1226
|
+
queuedInitialLayout,
|
|
1227
|
+
scrollLength,
|
|
1228
|
+
scroll,
|
|
1229
|
+
maintainingScrollAtEnd,
|
|
1230
|
+
props: { maintainScrollAtEndThreshold, onEndReachedThreshold }
|
|
1231
|
+
} = state;
|
|
1232
|
+
if (state.initialScroll) {
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
const contentSize = getContentSize(ctx);
|
|
1236
|
+
if (contentSize > 0 && queuedInitialLayout && !maintainingScrollAtEnd) {
|
|
1237
|
+
const insetEnd = getContentInsetEnd(state);
|
|
1238
|
+
const distanceFromEnd = contentSize - scroll - scrollLength - insetEnd;
|
|
1239
|
+
const isContentLess = contentSize < scrollLength;
|
|
1240
|
+
state.isAtEnd = isContentLess || distanceFromEnd < scrollLength * maintainScrollAtEndThreshold;
|
|
1241
|
+
state.isEndReached = checkThreshold(
|
|
1242
|
+
distanceFromEnd,
|
|
1243
|
+
isContentLess,
|
|
1244
|
+
onEndReachedThreshold * scrollLength,
|
|
1245
|
+
state.isEndReached,
|
|
1246
|
+
state.endReachedSnapshot,
|
|
1247
|
+
{
|
|
1248
|
+
contentSize,
|
|
1249
|
+
dataLength: (_a3 = state.props.data) == null ? void 0 : _a3.length,
|
|
1250
|
+
scrollPosition: scroll
|
|
1251
|
+
},
|
|
1252
|
+
(distance) => {
|
|
1253
|
+
var _a4, _b;
|
|
1254
|
+
return (_b = (_a4 = state.props).onEndReached) == null ? void 0 : _b.call(_a4, { distanceFromEnd: distance });
|
|
1255
|
+
},
|
|
1256
|
+
(snapshot) => {
|
|
1257
|
+
state.endReachedSnapshot = snapshot;
|
|
1258
|
+
},
|
|
1259
|
+
true
|
|
1260
|
+
);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
// src/utils/checkAtTop.ts
|
|
1265
|
+
function checkAtTop(ctx) {
|
|
1266
|
+
const state = ctx == null ? void 0 : ctx.state;
|
|
1267
|
+
if (!state || state.initialScroll || state.scrollingTo) {
|
|
1268
|
+
return;
|
|
1269
|
+
}
|
|
1270
|
+
const {
|
|
1271
|
+
dataChangeEpoch,
|
|
1272
|
+
isStartReached,
|
|
1273
|
+
props: { data, onStartReachedThreshold },
|
|
1274
|
+
scroll,
|
|
1275
|
+
scrollLength,
|
|
1276
|
+
startReachedSnapshot,
|
|
1277
|
+
startReachedSnapshotDataChangeEpoch,
|
|
1278
|
+
totalSize
|
|
1279
|
+
} = state;
|
|
1280
|
+
const dataLength = data.length;
|
|
1281
|
+
const threshold = onStartReachedThreshold * scrollLength;
|
|
1282
|
+
const dataChanged = startReachedSnapshotDataChangeEpoch !== dataChangeEpoch;
|
|
1283
|
+
const withinThreshold = threshold > 0 && Math.abs(scroll) <= threshold;
|
|
1284
|
+
const allowReentryOnDataChange = !!isStartReached && withinThreshold && !!dataChanged && !isInMVCPActiveMode(state);
|
|
1285
|
+
if (isStartReached && threshold > 0 && scroll > threshold && startReachedSnapshot && (dataChanged || startReachedSnapshot.contentSize !== totalSize || startReachedSnapshot.dataLength !== dataLength)) {
|
|
1286
|
+
state.isStartReached = false;
|
|
1287
|
+
state.startReachedSnapshot = void 0;
|
|
1288
|
+
state.startReachedSnapshotDataChangeEpoch = void 0;
|
|
1289
|
+
}
|
|
1290
|
+
state.isAtStart = scroll <= 0;
|
|
1291
|
+
if (isStartReached && withinThreshold && dataChanged && !allowReentryOnDataChange) {
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
state.isStartReached = checkThreshold(
|
|
1295
|
+
scroll,
|
|
1296
|
+
false,
|
|
1297
|
+
threshold,
|
|
1298
|
+
state.isStartReached,
|
|
1299
|
+
allowReentryOnDataChange ? void 0 : startReachedSnapshot,
|
|
1300
|
+
{
|
|
1301
|
+
contentSize: totalSize,
|
|
1302
|
+
dataLength,
|
|
1303
|
+
scrollPosition: scroll
|
|
1304
|
+
},
|
|
1305
|
+
(distance) => {
|
|
1306
|
+
var _a3, _b;
|
|
1307
|
+
return (_b = (_a3 = state.props).onStartReached) == null ? void 0 : _b.call(_a3, { distanceFromStart: distance });
|
|
1308
|
+
},
|
|
1309
|
+
(snapshot) => {
|
|
1310
|
+
state.startReachedSnapshot = snapshot;
|
|
1311
|
+
state.startReachedSnapshotDataChangeEpoch = snapshot ? dataChangeEpoch : void 0;
|
|
1312
|
+
},
|
|
1313
|
+
allowReentryOnDataChange
|
|
1314
|
+
);
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
// src/utils/checkThresholds.ts
|
|
1318
|
+
function checkThresholds(ctx) {
|
|
1319
|
+
checkAtBottom(ctx);
|
|
1320
|
+
checkAtTop(ctx);
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
// src/utils/setInitialRenderState.ts
|
|
1324
|
+
function setInitialRenderState(ctx, {
|
|
1325
|
+
didLayout,
|
|
1326
|
+
didInitialScroll
|
|
1327
|
+
}) {
|
|
1328
|
+
const { state } = ctx;
|
|
1329
|
+
const {
|
|
1330
|
+
loadStartTime,
|
|
1331
|
+
props: { onLoad }
|
|
1332
|
+
} = state;
|
|
1333
|
+
if (didLayout) {
|
|
1334
|
+
state.didContainersLayout = true;
|
|
1335
|
+
}
|
|
1336
|
+
if (didInitialScroll) {
|
|
1337
|
+
state.didFinishInitialScroll = true;
|
|
1338
|
+
}
|
|
1339
|
+
const isReadyToRender = Boolean(state.didContainersLayout && state.didFinishInitialScroll);
|
|
1340
|
+
if (isReadyToRender && !peek$(ctx, "readyToRender")) {
|
|
1341
|
+
set$(ctx, "readyToRender", true);
|
|
1342
|
+
if (onLoad) {
|
|
1343
|
+
onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
// src/core/finishScrollTo.ts
|
|
1349
|
+
function finishScrollTo(ctx) {
|
|
1350
|
+
var _a3, _b;
|
|
1351
|
+
const state = ctx.state;
|
|
1352
|
+
if (state == null ? void 0 : state.scrollingTo) {
|
|
1353
|
+
const resolvePendingScroll = state.pendingScrollResolve;
|
|
1354
|
+
state.pendingScrollResolve = void 0;
|
|
1355
|
+
const scrollingTo = state.scrollingTo;
|
|
1356
|
+
state.scrollHistory.length = 0;
|
|
1357
|
+
state.initialScroll = void 0;
|
|
1358
|
+
state.initialScrollUsesOffset = false;
|
|
1359
|
+
state.initialAnchor = void 0;
|
|
1360
|
+
state.initialNativeScrollWatchdog = void 0;
|
|
1361
|
+
state.scrollingTo = void 0;
|
|
1362
|
+
if (state.pendingTotalSize !== void 0) {
|
|
1363
|
+
addTotalSize(ctx, null, state.pendingTotalSize);
|
|
1364
|
+
}
|
|
1365
|
+
if ((_a3 = state.props) == null ? void 0 : _a3.data) {
|
|
1366
|
+
(_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
|
|
1367
|
+
}
|
|
1368
|
+
if (PlatformAdjustBreaksScroll) {
|
|
1369
|
+
state.scrollAdjustHandler.commitPendingAdjust(scrollingTo);
|
|
1370
|
+
}
|
|
1371
|
+
setInitialRenderState(ctx, { didInitialScroll: true });
|
|
1372
|
+
checkThresholds(ctx);
|
|
1373
|
+
resolvePendingScroll == null ? void 0 : resolvePendingScroll();
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
// src/core/checkFinishedScroll.ts
|
|
1378
|
+
var INITIAL_SCROLL_MIN_TARGET_OFFSET = 1;
|
|
1379
|
+
var INITIAL_SCROLL_MAX_FALLBACK_CHECKS = 20;
|
|
1380
|
+
var INITIAL_SCROLL_ZERO_TARGET_EPSILON = 1;
|
|
1381
|
+
function checkFinishedScroll(ctx) {
|
|
1382
|
+
ctx.state.animFrameCheckFinishedScroll = requestAnimationFrame(() => checkFinishedScrollFrame(ctx));
|
|
1383
|
+
}
|
|
1384
|
+
function checkFinishedScrollFrame(ctx) {
|
|
1385
|
+
var _a3;
|
|
1386
|
+
const scrollingTo = ctx.state.scrollingTo;
|
|
1387
|
+
if (scrollingTo) {
|
|
1388
|
+
const { state } = ctx;
|
|
1389
|
+
state.animFrameCheckFinishedScroll = void 0;
|
|
1390
|
+
const scroll = state.scrollPending;
|
|
1391
|
+
const adjust = state.scrollAdjustHandler.getAdjust();
|
|
1392
|
+
const clampedTargetOffset = (_a3 = scrollingTo.targetOffset) != null ? _a3 : clampScrollOffset(ctx, scrollingTo.offset - (scrollingTo.viewOffset || 0), scrollingTo);
|
|
1393
|
+
const maxOffset = clampScrollOffset(ctx, scroll, scrollingTo);
|
|
1394
|
+
const diff1 = Math.abs(scroll - clampedTargetOffset);
|
|
1395
|
+
const diff2 = Math.abs(diff1 - adjust);
|
|
1396
|
+
const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
|
|
1397
|
+
const isAtTarget = diff1 < 1 || !scrollingTo.animated && diff2 < 1;
|
|
1398
|
+
if (isNotOverscrolled && isAtTarget) {
|
|
1399
|
+
finishScrollTo(ctx);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
function checkFinishedScrollFallback(ctx) {
|
|
1404
|
+
const state = ctx.state;
|
|
1405
|
+
const scrollingTo = state.scrollingTo;
|
|
1406
|
+
const shouldFinishInitialZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
|
|
1407
|
+
const slowTimeout = (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll) && !shouldFinishInitialZeroTarget || !state.didContainersLayout;
|
|
1408
|
+
state.timeoutCheckFinishedScrollFallback = setTimeout(
|
|
1409
|
+
() => {
|
|
1410
|
+
let numChecks = 0;
|
|
1411
|
+
const checkHasScrolled = () => {
|
|
1412
|
+
var _a3, _b;
|
|
1413
|
+
state.timeoutCheckFinishedScrollFallback = void 0;
|
|
1414
|
+
const isStillScrollingTo = state.scrollingTo;
|
|
1415
|
+
if (isStillScrollingTo) {
|
|
1416
|
+
numChecks++;
|
|
1417
|
+
const isNativeInitialPending = isNativeInitialNonZeroTarget(state) && !state.hasScrolled;
|
|
1418
|
+
const maxChecks = isNativeInitialPending ? INITIAL_SCROLL_MAX_FALLBACK_CHECKS : 5;
|
|
1419
|
+
const shouldFinishZeroTarget = shouldFinishInitialZeroTargetScroll(ctx);
|
|
1420
|
+
if (shouldFinishZeroTarget || state.hasScrolled || numChecks > maxChecks) {
|
|
1421
|
+
finishScrollTo(ctx);
|
|
1422
|
+
} else if (isNativeInitialPending && numChecks <= maxChecks) {
|
|
1423
|
+
const targetOffset = (_b = (_a3 = state.initialNativeScrollWatchdog) == null ? void 0 : _a3.targetOffset) != null ? _b : state.scrollPending;
|
|
1424
|
+
const scroller = state.refScroller.current;
|
|
1425
|
+
if (scroller) {
|
|
1426
|
+
scroller.scrollTo({
|
|
1427
|
+
animated: false,
|
|
1428
|
+
x: state.props.horizontal ? targetOffset : 0,
|
|
1429
|
+
y: state.props.horizontal ? 0 : targetOffset
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
|
|
1433
|
+
} else {
|
|
1434
|
+
state.timeoutCheckFinishedScrollFallback = setTimeout(checkHasScrolled, 100);
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
};
|
|
1438
|
+
checkHasScrolled();
|
|
1439
|
+
},
|
|
1440
|
+
slowTimeout ? 500 : 100
|
|
1441
|
+
);
|
|
1442
|
+
}
|
|
1443
|
+
function isNativeInitialNonZeroTarget(state) {
|
|
1444
|
+
return !state.didFinishInitialScroll && !!state.initialNativeScrollWatchdog && state.initialNativeScrollWatchdog.targetOffset > INITIAL_SCROLL_MIN_TARGET_OFFSET;
|
|
1445
|
+
}
|
|
1446
|
+
function shouldFinishInitialZeroTargetScroll(ctx) {
|
|
1447
|
+
var _a3;
|
|
1448
|
+
const { state } = ctx;
|
|
1449
|
+
return !!((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) && state.props.data.length > 0 && getContentSize(ctx) <= state.scrollLength && state.scrollPending <= INITIAL_SCROLL_ZERO_TARGET_EPSILON;
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
// src/core/doScrollTo.native.ts
|
|
1453
|
+
function doScrollTo(ctx, params) {
|
|
1454
|
+
const state = ctx.state;
|
|
1455
|
+
const { animated, horizontal, offset } = params;
|
|
1456
|
+
const isAnimated = !!animated;
|
|
1457
|
+
const { refScroller } = state;
|
|
1458
|
+
const scroller = refScroller.current;
|
|
1459
|
+
if (!scroller) {
|
|
1460
|
+
return;
|
|
1461
|
+
}
|
|
1462
|
+
scroller.scrollTo({
|
|
1463
|
+
animated: isAnimated,
|
|
1464
|
+
x: horizontal ? offset : 0,
|
|
1465
|
+
y: horizontal ? 0 : offset
|
|
1466
|
+
});
|
|
1467
|
+
if (!isAnimated) {
|
|
1468
|
+
state.scroll = offset;
|
|
1469
|
+
checkFinishedScrollFallback(ctx);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
// src/core/scrollTo.ts
|
|
1474
|
+
var WATCHDOG_OFFSET_EPSILON = 1;
|
|
1475
|
+
function scrollTo(ctx, params) {
|
|
1476
|
+
var _a3, _b;
|
|
1477
|
+
const state = ctx.state;
|
|
1478
|
+
const { noScrollingTo, forceScroll, ...scrollTarget } = params;
|
|
1479
|
+
const { animated, isInitialScroll, offset: scrollTargetOffset, precomputedWithViewOffset } = scrollTarget;
|
|
1480
|
+
const {
|
|
1481
|
+
props: { horizontal }
|
|
1482
|
+
} = state;
|
|
1483
|
+
if (state.animFrameCheckFinishedScroll) {
|
|
1484
|
+
cancelAnimationFrame(ctx.state.animFrameCheckFinishedScroll);
|
|
1485
|
+
}
|
|
1486
|
+
if (state.timeoutCheckFinishedScrollFallback) {
|
|
1487
|
+
clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
|
|
1488
|
+
}
|
|
1489
|
+
let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
|
|
1490
|
+
offset = clampScrollOffset(ctx, offset, scrollTarget);
|
|
1491
|
+
state.scrollHistory.length = 0;
|
|
1492
|
+
if (!noScrollingTo) {
|
|
1493
|
+
state.scrollingTo = {
|
|
1494
|
+
...scrollTarget,
|
|
1495
|
+
targetOffset: offset
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
state.scrollPending = offset;
|
|
1499
|
+
const shouldWatchInitialNativeScroll = !state.didFinishInitialScroll && (isInitialScroll || !!state.initialNativeScrollWatchdog) && offset > WATCHDOG_OFFSET_EPSILON;
|
|
1500
|
+
const shouldClearInitialNativeScrollWatchdog = !state.didFinishInitialScroll && !!state.initialNativeScrollWatchdog && offset <= WATCHDOG_OFFSET_EPSILON;
|
|
1501
|
+
if (shouldWatchInitialNativeScroll) {
|
|
1502
|
+
state.hasScrolled = false;
|
|
1503
|
+
state.initialNativeScrollWatchdog = {
|
|
1504
|
+
startScroll: (_b = (_a3 = state.initialNativeScrollWatchdog) == null ? void 0 : _a3.startScroll) != null ? _b : state.scroll,
|
|
1505
|
+
targetOffset: offset
|
|
1506
|
+
};
|
|
1507
|
+
} else if (shouldClearInitialNativeScrollWatchdog) {
|
|
1508
|
+
state.initialNativeScrollWatchdog = void 0;
|
|
1509
|
+
}
|
|
1510
|
+
if (forceScroll || !isInitialScroll || Platform2.OS === "android") {
|
|
1511
|
+
doScrollTo(ctx, { animated, horizontal, offset });
|
|
1512
|
+
} else {
|
|
1513
|
+
state.scroll = offset;
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
// src/core/doMaintainScrollAtEnd.ts
|
|
1518
|
+
function doMaintainScrollAtEnd(ctx) {
|
|
1519
|
+
const state = ctx.state;
|
|
1520
|
+
const {
|
|
1521
|
+
didContainersLayout,
|
|
1522
|
+
isAtEnd,
|
|
1523
|
+
pendingNativeMVCPAdjust,
|
|
1524
|
+
refScroller,
|
|
1525
|
+
props: { maintainScrollAtEnd }
|
|
1526
|
+
} = state;
|
|
1527
|
+
const shouldMaintainScrollAtEnd = !!(isAtEnd && maintainScrollAtEnd && didContainersLayout);
|
|
1528
|
+
if (pendingNativeMVCPAdjust) {
|
|
1529
|
+
state.pendingMaintainScrollAtEnd = shouldMaintainScrollAtEnd;
|
|
1530
|
+
return false;
|
|
1531
|
+
}
|
|
1532
|
+
state.pendingMaintainScrollAtEnd = false;
|
|
1533
|
+
if (shouldMaintainScrollAtEnd) {
|
|
1534
|
+
const contentSize = getContentSize(ctx);
|
|
1535
|
+
if (contentSize < state.scrollLength) {
|
|
1536
|
+
state.scroll = 0;
|
|
1537
|
+
}
|
|
1538
|
+
requestAnimationFrame(() => {
|
|
1539
|
+
var _a3;
|
|
1540
|
+
if (state.isAtEnd) {
|
|
1541
|
+
state.maintainingScrollAtEnd = true;
|
|
1542
|
+
(_a3 = refScroller.current) == null ? void 0 : _a3.scrollToEnd({
|
|
1543
|
+
animated: maintainScrollAtEnd.animated
|
|
1544
|
+
});
|
|
1545
|
+
setTimeout(
|
|
1546
|
+
() => {
|
|
1547
|
+
state.maintainingScrollAtEnd = false;
|
|
1548
|
+
},
|
|
1549
|
+
maintainScrollAtEnd.animated ? 500 : 0
|
|
1550
|
+
);
|
|
1551
|
+
}
|
|
1552
|
+
});
|
|
1553
|
+
return true;
|
|
1554
|
+
}
|
|
1555
|
+
return false;
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
// src/core/mvcp.ts
|
|
1559
|
+
var MVCP_POSITION_EPSILON = 0.1;
|
|
1560
|
+
var MVCP_ANCHOR_LOCK_TTL_MS = 300;
|
|
1561
|
+
var MVCP_ANCHOR_LOCK_QUIET_PASSES_TO_RELEASE = 2;
|
|
1562
|
+
var NATIVE_END_CLAMP_EPSILON = 1;
|
|
1563
|
+
function resolveAnchorLock(state, enableMVCPAnchorLock, mvcpData, now) {
|
|
1564
|
+
if (!enableMVCPAnchorLock) {
|
|
1565
|
+
state.mvcpAnchorLock = void 0;
|
|
1566
|
+
return void 0;
|
|
1567
|
+
}
|
|
1568
|
+
const lock = state.mvcpAnchorLock;
|
|
1569
|
+
if (!lock) {
|
|
1570
|
+
return void 0;
|
|
1571
|
+
}
|
|
1572
|
+
const isExpired = now > lock.expiresAt;
|
|
1573
|
+
const isMissing = state.indexByKey.get(lock.id) === void 0;
|
|
1574
|
+
if (isExpired || isMissing || !mvcpData) {
|
|
1575
|
+
state.mvcpAnchorLock = void 0;
|
|
1576
|
+
return void 0;
|
|
1577
|
+
}
|
|
1578
|
+
return lock;
|
|
1579
|
+
}
|
|
1580
|
+
function updateAnchorLock(state, params) {
|
|
1581
|
+
if (Platform2.OS === "web") {
|
|
1582
|
+
const { anchorId, anchorPosition, dataChanged, now, positionDiff } = params;
|
|
1583
|
+
const enableMVCPAnchorLock = !!dataChanged || !!state.mvcpAnchorLock;
|
|
1584
|
+
const mvcpData = state.props.maintainVisibleContentPosition.data;
|
|
1585
|
+
if (!enableMVCPAnchorLock || !mvcpData || state.scrollingTo || !anchorId || anchorPosition === void 0) {
|
|
1586
|
+
return;
|
|
1587
|
+
}
|
|
1588
|
+
const existingLock = state.mvcpAnchorLock;
|
|
1589
|
+
const quietPasses = !dataChanged && Math.abs(positionDiff) <= MVCP_POSITION_EPSILON && (existingLock == null ? void 0 : existingLock.id) === anchorId ? existingLock.quietPasses + 1 : 0;
|
|
1590
|
+
if (!dataChanged && quietPasses >= MVCP_ANCHOR_LOCK_QUIET_PASSES_TO_RELEASE) {
|
|
1591
|
+
state.mvcpAnchorLock = void 0;
|
|
1592
|
+
return;
|
|
1593
|
+
}
|
|
1594
|
+
state.mvcpAnchorLock = {
|
|
1595
|
+
expiresAt: now + MVCP_ANCHOR_LOCK_TTL_MS,
|
|
1596
|
+
id: anchorId,
|
|
1597
|
+
position: anchorPosition,
|
|
1598
|
+
quietPasses
|
|
1599
|
+
};
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
function shouldQueueNativeMVCPAdjust(dataChanged, state, positionDiff, prevTotalSize, prevScroll, scrollTarget) {
|
|
1603
|
+
if (!dataChanged || Platform2.OS === "web" || !state.props.maintainVisibleContentPosition.data || scrollTarget !== void 0 || positionDiff >= -MVCP_POSITION_EPSILON) {
|
|
1604
|
+
return false;
|
|
1605
|
+
}
|
|
1606
|
+
const distanceFromEnd = prevTotalSize - prevScroll - state.scrollLength;
|
|
1607
|
+
return distanceFromEnd < Math.abs(positionDiff) - MVCP_POSITION_EPSILON;
|
|
1608
|
+
}
|
|
1609
|
+
function getPredictedNativeClamp(state, unresolvedAmount, totalSize) {
|
|
1610
|
+
if (Math.abs(unresolvedAmount) <= MVCP_POSITION_EPSILON) {
|
|
1611
|
+
return 0;
|
|
1612
|
+
}
|
|
1613
|
+
const maxScroll = Math.max(0, totalSize - state.scrollLength);
|
|
1614
|
+
const clampDelta = maxScroll - state.scroll;
|
|
1615
|
+
if (unresolvedAmount < 0) {
|
|
1616
|
+
return Math.max(unresolvedAmount, Math.min(0, clampDelta));
|
|
1617
|
+
}
|
|
1618
|
+
if (unresolvedAmount > 0) {
|
|
1619
|
+
return Math.min(unresolvedAmount, Math.max(0, clampDelta));
|
|
1620
|
+
}
|
|
1621
|
+
return 0;
|
|
1622
|
+
}
|
|
1623
|
+
function maybeApplyPredictedNativeMVCPAdjust(ctx) {
|
|
1624
|
+
const state = ctx.state;
|
|
1625
|
+
const pending = state.pendingNativeMVCPAdjust;
|
|
1626
|
+
if (!pending || Math.abs(pending.manualApplied) > MVCP_POSITION_EPSILON) {
|
|
1627
|
+
return;
|
|
1628
|
+
}
|
|
1629
|
+
const totalSize = getContentSize(ctx);
|
|
1630
|
+
const predictedNativeClamp = getPredictedNativeClamp(state, pending.amount, totalSize);
|
|
1631
|
+
if (Math.abs(predictedNativeClamp) <= MVCP_POSITION_EPSILON) {
|
|
1632
|
+
return;
|
|
1633
|
+
}
|
|
1634
|
+
const manualDesired = pending.amount - predictedNativeClamp;
|
|
1635
|
+
if (Math.abs(manualDesired) <= MVCP_POSITION_EPSILON) {
|
|
1636
|
+
return;
|
|
1637
|
+
}
|
|
1638
|
+
pending.manualApplied = manualDesired;
|
|
1639
|
+
requestAdjust(ctx, manualDesired, true);
|
|
1640
|
+
}
|
|
1641
|
+
function resolvePendingNativeMVCPAdjust(ctx, newScroll) {
|
|
1642
|
+
const state = ctx.state;
|
|
1643
|
+
const pending = state.pendingNativeMVCPAdjust;
|
|
1644
|
+
if (!pending) {
|
|
1645
|
+
return false;
|
|
1646
|
+
}
|
|
1647
|
+
const remainingAfterManual = pending.amount - pending.manualApplied;
|
|
1648
|
+
const nativeDelta = newScroll - (pending.startScroll + pending.manualApplied);
|
|
1649
|
+
const isWrongDirection = remainingAfterManual < 0 && nativeDelta > MVCP_POSITION_EPSILON || remainingAfterManual > 0 && nativeDelta < -MVCP_POSITION_EPSILON;
|
|
1650
|
+
if (Math.abs(remainingAfterManual) <= MVCP_POSITION_EPSILON) {
|
|
1651
|
+
state.pendingNativeMVCPAdjust = void 0;
|
|
1652
|
+
return true;
|
|
1653
|
+
}
|
|
1654
|
+
if (isWrongDirection) {
|
|
1655
|
+
state.pendingNativeMVCPAdjust = void 0;
|
|
1656
|
+
return false;
|
|
1657
|
+
}
|
|
1658
|
+
const expectedNativeClampScroll = Math.max(0, getContentSize(ctx) - state.scrollLength);
|
|
1659
|
+
const distanceToClamp = Math.abs(newScroll - expectedNativeClampScroll);
|
|
1660
|
+
const didApproachClamp = distanceToClamp < pending.closestDistanceToClamp - MVCP_POSITION_EPSILON;
|
|
1661
|
+
const didMoveAwayAfterApproach = pending.hasApproachedClamp && distanceToClamp > pending.closestDistanceToClamp + MVCP_POSITION_EPSILON;
|
|
1662
|
+
if (didApproachClamp) {
|
|
1663
|
+
pending.closestDistanceToClamp = distanceToClamp;
|
|
1664
|
+
pending.hasApproachedClamp = true;
|
|
1665
|
+
} else if (didMoveAwayAfterApproach) {
|
|
1666
|
+
state.pendingNativeMVCPAdjust = void 0;
|
|
1667
|
+
return false;
|
|
1668
|
+
}
|
|
1669
|
+
const isAtExpectedNativeClamp = distanceToClamp <= NATIVE_END_CLAMP_EPSILON;
|
|
1670
|
+
if (!isAtExpectedNativeClamp) {
|
|
1671
|
+
return false;
|
|
1672
|
+
}
|
|
1673
|
+
state.pendingNativeMVCPAdjust = void 0;
|
|
1674
|
+
const remaining = remainingAfterManual - nativeDelta;
|
|
1675
|
+
if (Math.abs(remaining) > MVCP_POSITION_EPSILON) {
|
|
1676
|
+
requestAdjust(ctx, remaining, true);
|
|
1677
|
+
}
|
|
1678
|
+
return true;
|
|
1679
|
+
}
|
|
1680
|
+
function prepareMVCP(ctx, dataChanged) {
|
|
1681
|
+
const state = ctx.state;
|
|
1682
|
+
const { idsInView, positions, props } = state;
|
|
1683
|
+
const {
|
|
1684
|
+
maintainVisibleContentPosition: { data: mvcpData, size: mvcpScroll, shouldRestorePosition }
|
|
1685
|
+
} = props;
|
|
1686
|
+
const isWeb = Platform2.OS === "web";
|
|
1687
|
+
const now = Date.now();
|
|
1688
|
+
const enableMVCPAnchorLock = isWeb && (!!dataChanged || !!state.mvcpAnchorLock);
|
|
1689
|
+
const scrollingTo = state.scrollingTo;
|
|
1690
|
+
const anchorLock = isWeb ? resolveAnchorLock(state, enableMVCPAnchorLock, mvcpData, now) : void 0;
|
|
1691
|
+
let prevPosition;
|
|
1692
|
+
let targetId;
|
|
1693
|
+
const idsInViewWithPositions = [];
|
|
1694
|
+
const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
|
|
1695
|
+
const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
|
|
1696
|
+
const isEndAnchoredScrollTarget = scrollTarget !== void 0 && state.props.data.length > 0 && scrollTarget >= state.props.data.length - 1 && (scrollingToViewPosition != null ? scrollingToViewPosition : 0) > 0;
|
|
1697
|
+
const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
|
|
1698
|
+
const indexByKey = state.indexByKey;
|
|
1699
|
+
const prevScroll = state.scroll;
|
|
1700
|
+
const prevTotalSize = getContentSize(ctx);
|
|
1701
|
+
if (shouldMVCP) {
|
|
1702
|
+
if (!isWeb && state.pendingNativeMVCPAdjust && scrollTarget === void 0) {
|
|
1703
|
+
maybeApplyPredictedNativeMVCPAdjust(ctx);
|
|
1704
|
+
return void 0;
|
|
1705
|
+
}
|
|
1706
|
+
if (anchorLock && scrollTarget === void 0) {
|
|
1707
|
+
targetId = anchorLock.id;
|
|
1708
|
+
prevPosition = anchorLock.position;
|
|
1709
|
+
} else if (scrollTarget !== void 0) {
|
|
1710
|
+
if (!IsNewArchitecture && (scrollingTo == null ? void 0 : scrollingTo.isInitialScroll)) {
|
|
1711
|
+
return void 0;
|
|
1712
|
+
}
|
|
1713
|
+
targetId = getId(state, scrollTarget);
|
|
1714
|
+
} else if (idsInView.length > 0 && state.didContainersLayout && !dataChanged) {
|
|
1715
|
+
targetId = idsInView.find((id) => indexByKey.get(id) !== void 0);
|
|
1716
|
+
}
|
|
1717
|
+
if (dataChanged && idsInView.length > 0 && state.didContainersLayout) {
|
|
1718
|
+
for (let i = 0; i < idsInView.length; i++) {
|
|
1719
|
+
const id = idsInView[i];
|
|
1720
|
+
const index = indexByKey.get(id);
|
|
1721
|
+
if (index !== void 0) {
|
|
1722
|
+
const position = positions[index];
|
|
1723
|
+
if (position !== void 0) {
|
|
1724
|
+
idsInViewWithPositions.push({ id, position });
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
if (targetId !== void 0 && prevPosition === void 0) {
|
|
1730
|
+
const targetIndex = indexByKey.get(targetId);
|
|
1731
|
+
if (targetIndex !== void 0) {
|
|
1732
|
+
prevPosition = positions[targetIndex];
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
return () => {
|
|
1736
|
+
let positionDiff = 0;
|
|
1737
|
+
let anchorIdForLock = anchorLock == null ? void 0 : anchorLock.id;
|
|
1738
|
+
let anchorPositionForLock;
|
|
1739
|
+
let skipTargetAnchor = false;
|
|
1740
|
+
const data = state.props.data;
|
|
1741
|
+
const shouldValidateLockedAnchor = isWeb && dataChanged && mvcpData && scrollTarget === void 0 && targetId !== void 0 && (anchorLock == null ? void 0 : anchorLock.id) === targetId && shouldRestorePosition !== void 0;
|
|
1742
|
+
if (shouldValidateLockedAnchor && targetId !== void 0) {
|
|
1743
|
+
const index = indexByKey.get(targetId);
|
|
1744
|
+
if (index !== void 0) {
|
|
1745
|
+
const item = data[index];
|
|
1746
|
+
skipTargetAnchor = item === void 0 || !shouldRestorePosition(item, index, data);
|
|
1747
|
+
if (skipTargetAnchor && (anchorLock == null ? void 0 : anchorLock.id) === targetId) {
|
|
1748
|
+
state.mvcpAnchorLock = void 0;
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
const shouldUseFallbackVisibleAnchor = dataChanged && mvcpData && scrollTarget === void 0 && (() => {
|
|
1753
|
+
if (targetId === void 0 || skipTargetAnchor) {
|
|
1754
|
+
return true;
|
|
1755
|
+
}
|
|
1756
|
+
const targetIndex = indexByKey.get(targetId);
|
|
1757
|
+
return targetIndex === void 0 || positions[targetIndex] === void 0;
|
|
1758
|
+
})();
|
|
1759
|
+
if (shouldUseFallbackVisibleAnchor) {
|
|
1760
|
+
for (let i = 0; i < idsInViewWithPositions.length; i++) {
|
|
1761
|
+
const { id, position } = idsInViewWithPositions[i];
|
|
1762
|
+
const index = indexByKey.get(id);
|
|
1763
|
+
if (index !== void 0 && shouldRestorePosition) {
|
|
1764
|
+
const item = data[index];
|
|
1765
|
+
if (item === void 0 || !shouldRestorePosition(item, index, data)) {
|
|
1766
|
+
continue;
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
const newPosition = index !== void 0 ? positions[index] : void 0;
|
|
1770
|
+
if (newPosition !== void 0) {
|
|
1771
|
+
positionDiff = newPosition - position;
|
|
1772
|
+
anchorIdForLock = id;
|
|
1773
|
+
anchorPositionForLock = newPosition;
|
|
1774
|
+
break;
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
if (!skipTargetAnchor && targetId !== void 0 && prevPosition !== void 0) {
|
|
1779
|
+
const targetIndex = indexByKey.get(targetId);
|
|
1780
|
+
const newPosition = targetIndex !== void 0 ? positions[targetIndex] : void 0;
|
|
1781
|
+
if (newPosition !== void 0) {
|
|
1782
|
+
const totalSize = getContentSize(ctx);
|
|
1783
|
+
let diff = newPosition - prevPosition;
|
|
1784
|
+
if (diff !== 0 && isEndAnchoredScrollTarget && state.scroll + state.scrollLength > totalSize) {
|
|
1785
|
+
if (diff > 0) {
|
|
1786
|
+
diff = Math.max(0, totalSize - state.scroll - state.scrollLength);
|
|
1787
|
+
} else {
|
|
1788
|
+
diff = 0;
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
positionDiff = diff;
|
|
1792
|
+
anchorIdForLock = targetId;
|
|
1793
|
+
anchorPositionForLock = newPosition;
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
if (scrollingToViewPosition && scrollingToViewPosition > 0) {
|
|
1797
|
+
const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
|
|
1798
|
+
const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
|
|
1799
|
+
if (newSize !== void 0 && prevSize !== void 0 && newSize !== prevSize) {
|
|
1800
|
+
const diff = newSize - prevSize;
|
|
1801
|
+
if (diff !== 0) {
|
|
1802
|
+
positionDiff += diff * scrollingToViewPosition;
|
|
1803
|
+
scrollingTo.itemSize = newSize;
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
updateAnchorLock(state, {
|
|
1808
|
+
anchorId: anchorIdForLock,
|
|
1809
|
+
anchorPosition: anchorPositionForLock,
|
|
1810
|
+
dataChanged,
|
|
1811
|
+
now,
|
|
1812
|
+
positionDiff
|
|
1813
|
+
});
|
|
1814
|
+
if (shouldQueueNativeMVCPAdjust(dataChanged, state, positionDiff, prevTotalSize, prevScroll, scrollTarget)) {
|
|
1815
|
+
state.pendingNativeMVCPAdjust = {
|
|
1816
|
+
amount: positionDiff,
|
|
1817
|
+
closestDistanceToClamp: Math.abs(
|
|
1818
|
+
prevScroll - Math.max(0, getContentSize(ctx) - state.scrollLength)
|
|
1819
|
+
),
|
|
1820
|
+
hasApproachedClamp: false,
|
|
1821
|
+
manualApplied: 0,
|
|
1822
|
+
startScroll: prevScroll
|
|
1823
|
+
};
|
|
1824
|
+
maybeApplyPredictedNativeMVCPAdjust(ctx);
|
|
1825
|
+
return;
|
|
1826
|
+
}
|
|
1827
|
+
if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
|
|
1828
|
+
requestAdjust(ctx, positionDiff, dataChanged && mvcpData);
|
|
1829
|
+
}
|
|
1830
|
+
};
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
// src/platform/flushSync.native.ts
|
|
1835
|
+
var flushSync = (fn) => {
|
|
1836
|
+
fn();
|
|
1837
|
+
};
|
|
1838
|
+
|
|
1839
|
+
// src/core/updateScroll.ts
|
|
1840
|
+
function updateScroll(ctx, newScroll, forceUpdate) {
|
|
1841
|
+
var _a3;
|
|
1842
|
+
const state = ctx.state;
|
|
1843
|
+
const { ignoreScrollFromMVCP, lastScrollAdjustForHistory, scrollAdjustHandler, scrollHistory, scrollingTo } = state;
|
|
1844
|
+
const prevScroll = state.scroll;
|
|
1845
|
+
state.hasScrolled = true;
|
|
1846
|
+
state.lastBatchingAction = Date.now();
|
|
1847
|
+
const currentTime = Date.now();
|
|
1848
|
+
const adjust = scrollAdjustHandler.getAdjust();
|
|
1849
|
+
const adjustChanged = lastScrollAdjustForHistory !== void 0 && Math.abs(adjust - lastScrollAdjustForHistory) > 0.1;
|
|
1850
|
+
if (adjustChanged) {
|
|
1851
|
+
scrollHistory.length = 0;
|
|
1852
|
+
}
|
|
1853
|
+
state.lastScrollAdjustForHistory = adjust;
|
|
1854
|
+
if (scrollingTo === void 0 && !(scrollHistory.length === 0 && newScroll === state.scroll)) {
|
|
1855
|
+
if (!adjustChanged) {
|
|
1856
|
+
scrollHistory.push({ scroll: newScroll, time: currentTime });
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
if (scrollHistory.length > 5) {
|
|
1860
|
+
scrollHistory.shift();
|
|
1861
|
+
}
|
|
1862
|
+
if (ignoreScrollFromMVCP && !scrollingTo) {
|
|
1863
|
+
const { lt, gt } = ignoreScrollFromMVCP;
|
|
1864
|
+
if (lt && newScroll < lt || gt && newScroll > gt) {
|
|
1865
|
+
state.ignoreScrollFromMVCPIgnored = true;
|
|
1866
|
+
return;
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
state.scrollPrev = prevScroll;
|
|
1870
|
+
state.scrollPrevTime = state.scrollTime;
|
|
1871
|
+
state.scroll = newScroll;
|
|
1872
|
+
state.scrollTime = currentTime;
|
|
1873
|
+
const scrollDelta = Math.abs(newScroll - prevScroll);
|
|
1874
|
+
const didResolvePendingNativeMVCPAdjust = resolvePendingNativeMVCPAdjust(ctx, newScroll);
|
|
1875
|
+
const scrollLength = state.scrollLength;
|
|
1876
|
+
const lastCalculated = state.scrollLastCalculate;
|
|
1877
|
+
const useAggressiveItemRecalculation = isInMVCPActiveMode(state);
|
|
1878
|
+
const shouldUpdate = useAggressiveItemRecalculation || didResolvePendingNativeMVCPAdjust || forceUpdate || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
|
|
1879
|
+
if (shouldUpdate) {
|
|
1880
|
+
state.scrollLastCalculate = state.scroll;
|
|
1881
|
+
state.ignoreScrollFromMVCPIgnored = false;
|
|
1882
|
+
state.lastScrollDelta = scrollDelta;
|
|
1883
|
+
const runCalculateItems = () => {
|
|
1884
|
+
var _a4;
|
|
1885
|
+
(_a4 = state.triggerCalculateItemsInView) == null ? void 0 : _a4.call(state, { doMVCP: scrollingTo !== void 0 });
|
|
1886
|
+
checkThresholds(ctx);
|
|
1887
|
+
};
|
|
1888
|
+
if (Platform2.OS === "web" && scrollLength > 0 && scrollingTo === void 0 && scrollDelta > scrollLength) {
|
|
1889
|
+
flushSync(runCalculateItems);
|
|
1890
|
+
} else {
|
|
1891
|
+
runCalculateItems();
|
|
1892
|
+
}
|
|
1893
|
+
const shouldMaintainScrollAtEndAfterPendingSettle = !!state.pendingMaintainScrollAtEnd || !!((_a3 = state.props.maintainScrollAtEnd) == null ? void 0 : _a3.onDataChange);
|
|
1894
|
+
if (didResolvePendingNativeMVCPAdjust && shouldMaintainScrollAtEndAfterPendingSettle) {
|
|
1895
|
+
state.pendingMaintainScrollAtEnd = false;
|
|
1896
|
+
doMaintainScrollAtEnd(ctx);
|
|
1897
|
+
}
|
|
1898
|
+
state.dataChangeNeedsScrollUpdate = false;
|
|
1899
|
+
state.lastScrollDelta = 0;
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
// src/utils/requestAdjust.ts
|
|
1904
|
+
function requestAdjust(ctx, positionDiff, dataChanged) {
|
|
1905
|
+
const state = ctx.state;
|
|
1906
|
+
if (Math.abs(positionDiff) > 0.1) {
|
|
1907
|
+
const needsScrollWorkaround = Platform2.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff;
|
|
1908
|
+
const doit = () => {
|
|
1909
|
+
if (needsScrollWorkaround) {
|
|
1910
|
+
scrollTo(ctx, {
|
|
1911
|
+
noScrollingTo: true,
|
|
1912
|
+
offset: state.scroll
|
|
1913
|
+
});
|
|
1914
|
+
} else {
|
|
1915
|
+
state.scrollAdjustHandler.requestAdjust(positionDiff);
|
|
1916
|
+
if (state.adjustingFromInitialMount) {
|
|
1917
|
+
state.adjustingFromInitialMount--;
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
};
|
|
1921
|
+
state.scroll += positionDiff;
|
|
1922
|
+
state.scrollForNextCalculateItemsInView = void 0;
|
|
1923
|
+
const readyToRender = peek$(ctx, "readyToRender");
|
|
1924
|
+
if (readyToRender) {
|
|
1925
|
+
doit();
|
|
1926
|
+
if (Platform2.OS !== "web") {
|
|
1927
|
+
const threshold = state.scroll - positionDiff / 2;
|
|
1928
|
+
if (!state.ignoreScrollFromMVCP) {
|
|
1929
|
+
state.ignoreScrollFromMVCP = {};
|
|
1930
|
+
}
|
|
1931
|
+
if (positionDiff > 0) {
|
|
1932
|
+
state.ignoreScrollFromMVCP.lt = threshold;
|
|
1933
|
+
} else {
|
|
1934
|
+
state.ignoreScrollFromMVCP.gt = threshold;
|
|
1935
|
+
}
|
|
1936
|
+
if (state.ignoreScrollFromMVCPTimeout) {
|
|
1937
|
+
clearTimeout(state.ignoreScrollFromMVCPTimeout);
|
|
1938
|
+
}
|
|
1939
|
+
const delay = needsScrollWorkaround ? 250 : 100;
|
|
1940
|
+
state.ignoreScrollFromMVCPTimeout = setTimeout(() => {
|
|
1941
|
+
state.ignoreScrollFromMVCP = void 0;
|
|
1942
|
+
const shouldForceUpdate = state.ignoreScrollFromMVCPIgnored && state.scrollProcessingEnabled !== false;
|
|
1943
|
+
if (shouldForceUpdate) {
|
|
1944
|
+
state.ignoreScrollFromMVCPIgnored = false;
|
|
1945
|
+
state.scrollPending = state.scroll;
|
|
1946
|
+
updateScroll(ctx, state.scroll, true);
|
|
1947
|
+
}
|
|
1948
|
+
}, delay);
|
|
1949
|
+
}
|
|
1950
|
+
} else {
|
|
1951
|
+
state.adjustingFromInitialMount = (state.adjustingFromInitialMount || 0) + 1;
|
|
1952
|
+
requestAnimationFrame(doit);
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
// src/core/ensureInitialAnchor.ts
|
|
1958
|
+
var INITIAL_ANCHOR_TOLERANCE = 0.5;
|
|
1959
|
+
var INITIAL_ANCHOR_MAX_ATTEMPTS = 4;
|
|
1960
|
+
var INITIAL_ANCHOR_SETTLED_TICKS = 2;
|
|
1961
|
+
function ensureInitialAnchor(ctx) {
|
|
1962
|
+
var _a3, _b, _c, _d, _e, _f;
|
|
1963
|
+
const state = ctx.state;
|
|
1964
|
+
const { initialAnchor, didContainersLayout, scroll, scrollLength } = state;
|
|
1965
|
+
const anchor = initialAnchor;
|
|
1966
|
+
if (state.initialScroll || ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll)) {
|
|
1967
|
+
return;
|
|
1968
|
+
}
|
|
1969
|
+
const item = state.props.data[anchor.index];
|
|
1970
|
+
if (!didContainersLayout) {
|
|
1971
|
+
return;
|
|
1972
|
+
}
|
|
1973
|
+
const id = getId(state, anchor.index);
|
|
1974
|
+
if (state.positions[anchor.index] === void 0) {
|
|
1975
|
+
return;
|
|
1976
|
+
}
|
|
1977
|
+
const size = getItemSize(ctx, id, anchor.index, item, true, true);
|
|
1978
|
+
if (size === void 0) {
|
|
1979
|
+
return;
|
|
1980
|
+
}
|
|
1981
|
+
const availableSpace = Math.max(0, scrollLength - size);
|
|
1982
|
+
const topOffsetAdjustment = getTopOffsetAdjustment(ctx);
|
|
1983
|
+
const desiredOffset = calculateOffsetForIndex(ctx, anchor.index) + topOffsetAdjustment - ((_b = anchor.viewOffset) != null ? _b : 0) - ((_c = anchor.viewPosition) != null ? _c : 0) * availableSpace;
|
|
1984
|
+
const clampedDesiredOffset = clampScrollOffset(ctx, desiredOffset, anchor);
|
|
1985
|
+
const delta = clampedDesiredOffset - scroll;
|
|
1986
|
+
if (Math.abs(delta) <= INITIAL_ANCHOR_TOLERANCE) {
|
|
1987
|
+
const settledTicks = ((_d = anchor.settledTicks) != null ? _d : 0) + 1;
|
|
1988
|
+
if (settledTicks >= INITIAL_ANCHOR_SETTLED_TICKS) {
|
|
1989
|
+
state.initialAnchor = void 0;
|
|
1990
|
+
} else {
|
|
1991
|
+
anchor.settledTicks = settledTicks;
|
|
1992
|
+
}
|
|
1993
|
+
return;
|
|
1994
|
+
}
|
|
1995
|
+
if (((_e = anchor.attempts) != null ? _e : 0) >= INITIAL_ANCHOR_MAX_ATTEMPTS) {
|
|
1996
|
+
state.initialAnchor = void 0;
|
|
1997
|
+
return;
|
|
1998
|
+
}
|
|
1999
|
+
const lastDelta = anchor.lastDelta;
|
|
2000
|
+
if (lastDelta !== void 0 && Math.abs(delta) >= Math.abs(lastDelta)) {
|
|
2001
|
+
state.initialAnchor = void 0;
|
|
2002
|
+
return;
|
|
2003
|
+
}
|
|
2004
|
+
Object.assign(anchor, {
|
|
2005
|
+
attempts: ((_f = anchor.attempts) != null ? _f : 0) + 1,
|
|
2006
|
+
lastDelta: delta,
|
|
2007
|
+
settledTicks: 0
|
|
2008
|
+
});
|
|
2009
|
+
requestAdjust(ctx, delta);
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
// src/core/prepareColumnStartState.ts
|
|
2013
|
+
function prepareColumnStartState(ctx, startIndex, useAverageSize) {
|
|
2014
|
+
var _a3;
|
|
2015
|
+
const state = ctx.state;
|
|
2016
|
+
const numColumns = peek$(ctx, "numColumns");
|
|
2017
|
+
let rowStartIndex = startIndex;
|
|
2018
|
+
const columnAtStart = state.columns[startIndex];
|
|
2019
|
+
if (columnAtStart !== 1) {
|
|
2020
|
+
rowStartIndex = findRowStartIndex(state, numColumns, startIndex);
|
|
2021
|
+
}
|
|
2022
|
+
let currentRowTop = 0;
|
|
2023
|
+
const column = state.columns[rowStartIndex];
|
|
2024
|
+
if (rowStartIndex > 0) {
|
|
2025
|
+
const prevIndex = rowStartIndex - 1;
|
|
2026
|
+
const prevPosition = (_a3 = state.positions[prevIndex]) != null ? _a3 : 0;
|
|
2027
|
+
const prevRowStart = findRowStartIndex(state, numColumns, prevIndex);
|
|
2028
|
+
const prevRowHeight = calculateRowMaxSize(ctx, prevRowStart, prevIndex, useAverageSize);
|
|
2029
|
+
currentRowTop = prevPosition + prevRowHeight;
|
|
2030
|
+
}
|
|
2031
|
+
return {
|
|
2032
|
+
column,
|
|
2033
|
+
currentRowTop,
|
|
2034
|
+
startIndex: rowStartIndex
|
|
2035
|
+
};
|
|
2036
|
+
}
|
|
2037
|
+
function findRowStartIndex(state, numColumns, index) {
|
|
2038
|
+
if (numColumns <= 1) {
|
|
2039
|
+
return Math.max(0, index);
|
|
2040
|
+
}
|
|
2041
|
+
let rowStart = Math.max(0, index);
|
|
2042
|
+
while (rowStart > 0) {
|
|
2043
|
+
const columnForIndex = state.columns[rowStart];
|
|
2044
|
+
if (columnForIndex === 1) {
|
|
2045
|
+
break;
|
|
2046
|
+
}
|
|
2047
|
+
rowStart--;
|
|
2048
|
+
}
|
|
2049
|
+
return rowStart;
|
|
2050
|
+
}
|
|
2051
|
+
function calculateRowMaxSize(ctx, startIndex, endIndex, useAverageSize) {
|
|
2052
|
+
const state = ctx.state;
|
|
2053
|
+
if (endIndex < startIndex) {
|
|
2054
|
+
return 0;
|
|
2055
|
+
}
|
|
2056
|
+
const { data } = state.props;
|
|
2057
|
+
if (!data) {
|
|
2058
|
+
return 0;
|
|
2059
|
+
}
|
|
2060
|
+
let maxSize = 0;
|
|
2061
|
+
for (let i = startIndex; i <= endIndex; i++) {
|
|
2062
|
+
if (i < 0 || i >= data.length) {
|
|
2063
|
+
continue;
|
|
2064
|
+
}
|
|
2065
|
+
const id = state.idCache[i];
|
|
2066
|
+
const size = getItemSize(ctx, id, i, data[i], useAverageSize);
|
|
2067
|
+
if (size > maxSize) {
|
|
2068
|
+
maxSize = size;
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
return maxSize;
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
// src/core/updateTotalSize.ts
|
|
2075
|
+
function updateTotalSize(ctx) {
|
|
2076
|
+
var _a3, _b;
|
|
2077
|
+
const state = ctx.state;
|
|
2078
|
+
const {
|
|
2079
|
+
positions,
|
|
2080
|
+
props: { data }
|
|
2081
|
+
} = state;
|
|
2082
|
+
const numColumns = (_a3 = peek$(ctx, "numColumns")) != null ? _a3 : 1;
|
|
2083
|
+
if (data.length === 0) {
|
|
2084
|
+
addTotalSize(ctx, null, 0);
|
|
2085
|
+
} else {
|
|
2086
|
+
const lastIndex = data.length - 1;
|
|
2087
|
+
const lastId = getId(state, lastIndex);
|
|
2088
|
+
const lastPosition = positions[lastIndex];
|
|
2089
|
+
if (lastId !== void 0 && lastPosition !== void 0) {
|
|
2090
|
+
if (numColumns > 1) {
|
|
2091
|
+
let rowStart = lastIndex;
|
|
2092
|
+
while (rowStart > 0) {
|
|
2093
|
+
const column = state.columns[rowStart];
|
|
2094
|
+
if (column === 1 || column === void 0) {
|
|
2095
|
+
break;
|
|
2096
|
+
}
|
|
2097
|
+
rowStart -= 1;
|
|
2098
|
+
}
|
|
2099
|
+
let maxSize = 0;
|
|
2100
|
+
for (let i = rowStart; i <= lastIndex; i++) {
|
|
2101
|
+
const rowId = (_b = state.idCache[i]) != null ? _b : getId(state, i);
|
|
2102
|
+
const size = getItemSize(ctx, rowId, i, data[i]);
|
|
2103
|
+
if (size > maxSize) {
|
|
2104
|
+
maxSize = size;
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
addTotalSize(ctx, null, lastPosition + maxSize);
|
|
2108
|
+
} else {
|
|
2109
|
+
const lastSize = getItemSize(ctx, lastId, lastIndex, data[lastIndex]);
|
|
2110
|
+
if (lastSize !== void 0) {
|
|
2111
|
+
const totalSize = lastPosition + lastSize;
|
|
2112
|
+
addTotalSize(ctx, null, totalSize);
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
// src/utils/getScrollVelocity.ts
|
|
2120
|
+
var getScrollVelocity = (state) => {
|
|
2121
|
+
const { scrollHistory } = state;
|
|
2122
|
+
const newestIndex = scrollHistory.length - 1;
|
|
2123
|
+
if (newestIndex < 1) {
|
|
2124
|
+
return 0;
|
|
2125
|
+
}
|
|
2126
|
+
const newest = scrollHistory[newestIndex];
|
|
2127
|
+
const now = Date.now();
|
|
2128
|
+
let direction = 0;
|
|
2129
|
+
for (let i = newestIndex; i > 0; i--) {
|
|
2130
|
+
const delta = scrollHistory[i].scroll - scrollHistory[i - 1].scroll;
|
|
2131
|
+
if (delta !== 0) {
|
|
2132
|
+
direction = Math.sign(delta);
|
|
2133
|
+
break;
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
if (direction === 0) {
|
|
2137
|
+
return 0;
|
|
2138
|
+
}
|
|
2139
|
+
let oldest = newest;
|
|
2140
|
+
for (let i = newestIndex - 1; i >= 0; i--) {
|
|
2141
|
+
const current = scrollHistory[i];
|
|
2142
|
+
const next = scrollHistory[i + 1];
|
|
2143
|
+
const delta = next.scroll - current.scroll;
|
|
2144
|
+
const deltaSign = Math.sign(delta);
|
|
2145
|
+
if (deltaSign !== 0 && deltaSign !== direction) {
|
|
2146
|
+
break;
|
|
2147
|
+
}
|
|
2148
|
+
if (now - current.time > 1e3) {
|
|
2149
|
+
break;
|
|
2150
|
+
}
|
|
2151
|
+
oldest = current;
|
|
2152
|
+
}
|
|
2153
|
+
const scrollDiff = newest.scroll - oldest.scroll;
|
|
2154
|
+
const timeDiff = newest.time - oldest.time;
|
|
2155
|
+
return timeDiff > 0 ? scrollDiff / timeDiff : 0;
|
|
2156
|
+
};
|
|
2157
|
+
|
|
2158
|
+
// src/utils/updateSnapToOffsets.ts
|
|
2159
|
+
function updateSnapToOffsets(ctx) {
|
|
2160
|
+
const state = ctx.state;
|
|
2161
|
+
const {
|
|
2162
|
+
props: { snapToIndices }
|
|
2163
|
+
} = state;
|
|
2164
|
+
const snapToOffsets = Array(snapToIndices.length);
|
|
2165
|
+
for (let i = 0; i < snapToIndices.length; i++) {
|
|
2166
|
+
const idx = snapToIndices[i];
|
|
2167
|
+
getId(state, idx);
|
|
2168
|
+
snapToOffsets[i] = state.positions[idx];
|
|
2169
|
+
}
|
|
2170
|
+
set$(ctx, "snapToOffsets", snapToOffsets);
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
// src/core/updateItemPositions.ts
|
|
2174
|
+
function updateItemPositions(ctx, dataChanged, { startIndex, scrollBottomBuffered, forceFullUpdate = false, doMVCP } = {
|
|
2175
|
+
doMVCP: false,
|
|
2176
|
+
forceFullUpdate: false,
|
|
2177
|
+
scrollBottomBuffered: -1,
|
|
2178
|
+
startIndex: 0
|
|
2179
|
+
}) {
|
|
2180
|
+
var _a3, _b, _c, _d, _e;
|
|
2181
|
+
const state = ctx.state;
|
|
2182
|
+
const hasPositionListeners = ctx.positionListeners.size > 0;
|
|
2183
|
+
const {
|
|
2184
|
+
columns,
|
|
2185
|
+
columnSpans,
|
|
2186
|
+
indexByKey,
|
|
2187
|
+
positions,
|
|
2188
|
+
idCache,
|
|
2189
|
+
sizesKnown,
|
|
2190
|
+
props: { data, getEstimatedItemSize, overrideItemLayout, snapToIndices },
|
|
2191
|
+
scrollingTo
|
|
2192
|
+
} = state;
|
|
2193
|
+
const dataLength = data.length;
|
|
2194
|
+
const numColumns = (_a3 = peek$(ctx, "numColumns")) != null ? _a3 : 1;
|
|
2195
|
+
const hasColumns = numColumns > 1;
|
|
2196
|
+
const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
|
|
2197
|
+
const extraData = peek$(ctx, "extraData");
|
|
2198
|
+
const layoutConfig = overrideItemLayout ? { span: 1 } : void 0;
|
|
2199
|
+
const lastScrollDelta = state.lastScrollDelta;
|
|
2200
|
+
const velocity = getScrollVelocity(state);
|
|
2201
|
+
const shouldOptimize = !forceFullUpdate && !dataChanged && (Math.abs(velocity) > 0 || Platform2.OS === "web" && state.scrollLength > 0 && lastScrollDelta > state.scrollLength);
|
|
2202
|
+
const maxVisibleArea = scrollBottomBuffered + 1e3;
|
|
2203
|
+
const useAverageSize = !getEstimatedItemSize;
|
|
2204
|
+
const preferCachedSize = !doMVCP || dataChanged || state.scrollAdjustHandler.getAdjust() !== 0 || ((_b = peek$(ctx, "scrollAdjustPending")) != null ? _b : 0) !== 0;
|
|
2205
|
+
let currentRowTop = 0;
|
|
2206
|
+
let column = 1;
|
|
2207
|
+
let maxSizeInRow = 0;
|
|
2208
|
+
if (dataChanged) {
|
|
2209
|
+
columnSpans.length = 0;
|
|
2210
|
+
}
|
|
2211
|
+
if (!hasColumns) {
|
|
2212
|
+
if (columns.length) {
|
|
2213
|
+
columns.length = 0;
|
|
2214
|
+
}
|
|
2215
|
+
if (columnSpans.length) {
|
|
2216
|
+
columnSpans.length = 0;
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
if (startIndex > 0) {
|
|
2220
|
+
if (hasColumns) {
|
|
2221
|
+
const { startIndex: processedStartIndex, currentRowTop: initialRowTop } = prepareColumnStartState(
|
|
2222
|
+
ctx,
|
|
2223
|
+
startIndex,
|
|
2224
|
+
useAverageSize
|
|
2225
|
+
);
|
|
2226
|
+
startIndex = processedStartIndex;
|
|
2227
|
+
currentRowTop = initialRowTop;
|
|
2228
|
+
} else if (startIndex < dataLength) {
|
|
2229
|
+
const prevIndex = startIndex - 1;
|
|
2230
|
+
const prevId = getId(state, prevIndex);
|
|
2231
|
+
const prevPosition = (_c = positions[prevIndex]) != null ? _c : 0;
|
|
2232
|
+
const prevSize = (_d = sizesKnown.get(prevId)) != null ? _d : getItemSize(ctx, prevId, prevIndex, data[prevIndex], useAverageSize, preferCachedSize);
|
|
2233
|
+
currentRowTop = prevPosition + prevSize;
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
const needsIndexByKey = dataChanged || indexByKey.size === 0;
|
|
2237
|
+
const canOverrideSpan = hasColumns && !!overrideItemLayout && !!layoutConfig;
|
|
2238
|
+
let didBreakEarly = false;
|
|
2239
|
+
let breakAt;
|
|
2240
|
+
for (let i = startIndex; i < dataLength; i++) {
|
|
2241
|
+
if (shouldOptimize && breakAt !== void 0 && i > breakAt) {
|
|
2242
|
+
didBreakEarly = true;
|
|
2243
|
+
break;
|
|
2244
|
+
}
|
|
2245
|
+
if (shouldOptimize && breakAt === void 0 && !scrollingTo && !dataChanged && currentRowTop > maxVisibleArea) {
|
|
2246
|
+
const itemsPerRow = hasColumns ? numColumns : 1;
|
|
2247
|
+
breakAt = i + itemsPerRow + 10;
|
|
2248
|
+
}
|
|
2249
|
+
const id = (_e = idCache[i]) != null ? _e : getId(state, i);
|
|
2250
|
+
let span = 1;
|
|
2251
|
+
if (canOverrideSpan) {
|
|
2252
|
+
layoutConfig.span = 1;
|
|
2253
|
+
overrideItemLayout(layoutConfig, data[i], i, numColumns, extraData);
|
|
2254
|
+
const requestedSpan = layoutConfig.span;
|
|
2255
|
+
if (requestedSpan !== void 0 && Number.isFinite(requestedSpan)) {
|
|
2256
|
+
span = Math.max(1, Math.min(numColumns, Math.round(requestedSpan)));
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
if (hasColumns && column + span - 1 > numColumns) {
|
|
2260
|
+
currentRowTop += maxSizeInRow;
|
|
2261
|
+
column = 1;
|
|
2262
|
+
maxSizeInRow = 0;
|
|
2263
|
+
}
|
|
2264
|
+
const knownSize = sizesKnown.get(id);
|
|
2265
|
+
const size = knownSize !== void 0 ? knownSize : getItemSize(ctx, id, i, data[i], useAverageSize, preferCachedSize);
|
|
2266
|
+
if (IS_DEV && needsIndexByKey) {
|
|
2267
|
+
if (indexByKeyForChecking.has(id)) {
|
|
2268
|
+
console.error(
|
|
2269
|
+
`[legend-list] Error: Detected overlapping key (${id}) which causes missing items and gaps and other terrrible things. Check that keyExtractor returns unique values.`
|
|
2270
|
+
);
|
|
2271
|
+
}
|
|
2272
|
+
indexByKeyForChecking.set(id, i);
|
|
2273
|
+
}
|
|
2274
|
+
if (currentRowTop !== positions[i]) {
|
|
2275
|
+
positions[i] = currentRowTop;
|
|
2276
|
+
if (hasPositionListeners) {
|
|
2277
|
+
notifyPosition$(ctx, id, currentRowTop);
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
if (needsIndexByKey) {
|
|
2281
|
+
indexByKey.set(id, i);
|
|
2282
|
+
}
|
|
2283
|
+
if (!hasColumns) {
|
|
2284
|
+
currentRowTop += size;
|
|
2285
|
+
} else {
|
|
2286
|
+
columns[i] = column;
|
|
2287
|
+
columnSpans[i] = span;
|
|
2288
|
+
if (size > maxSizeInRow) {
|
|
2289
|
+
maxSizeInRow = size;
|
|
2290
|
+
}
|
|
2291
|
+
column += span;
|
|
2292
|
+
if (column > numColumns) {
|
|
2293
|
+
currentRowTop += maxSizeInRow;
|
|
2294
|
+
column = 1;
|
|
2295
|
+
maxSizeInRow = 0;
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
if (!didBreakEarly) {
|
|
2300
|
+
updateTotalSize(ctx);
|
|
2301
|
+
}
|
|
2302
|
+
if (snapToIndices) {
|
|
2303
|
+
updateSnapToOffsets(ctx);
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
// src/core/viewability.ts
|
|
2308
|
+
function ensureViewabilityState(ctx, configId) {
|
|
2309
|
+
let map = ctx.mapViewabilityConfigStates;
|
|
2310
|
+
if (!map) {
|
|
2311
|
+
map = /* @__PURE__ */ new Map();
|
|
2312
|
+
ctx.mapViewabilityConfigStates = map;
|
|
2313
|
+
}
|
|
2314
|
+
let state = map.get(configId);
|
|
2315
|
+
if (!state) {
|
|
2316
|
+
state = { end: -1, previousEnd: -1, previousStart: -1, start: -1, viewableItems: [] };
|
|
2317
|
+
map.set(configId, state);
|
|
2318
|
+
}
|
|
2319
|
+
return state;
|
|
2320
|
+
}
|
|
2321
|
+
function setupViewability(props) {
|
|
2322
|
+
let { viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged } = props;
|
|
2323
|
+
if (viewabilityConfig || onViewableItemsChanged) {
|
|
2324
|
+
viewabilityConfigCallbackPairs = [
|
|
2325
|
+
...viewabilityConfigCallbackPairs || [],
|
|
2326
|
+
{
|
|
2327
|
+
onViewableItemsChanged,
|
|
2328
|
+
viewabilityConfig: viewabilityConfig || {
|
|
2329
|
+
viewAreaCoveragePercentThreshold: 0
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
];
|
|
2333
|
+
}
|
|
2334
|
+
return viewabilityConfigCallbackPairs;
|
|
2335
|
+
}
|
|
2336
|
+
function updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollSize, start, end) {
|
|
2337
|
+
const {
|
|
2338
|
+
timeouts,
|
|
2339
|
+
props: { data }
|
|
2340
|
+
} = state;
|
|
2341
|
+
for (const viewabilityConfigCallbackPair of viewabilityConfigCallbackPairs) {
|
|
2342
|
+
const viewabilityState = ensureViewabilityState(ctx, viewabilityConfigCallbackPair.viewabilityConfig.id);
|
|
2343
|
+
viewabilityState.start = start;
|
|
2344
|
+
viewabilityState.end = end;
|
|
2345
|
+
if (viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime) {
|
|
2346
|
+
const timer = setTimeout(() => {
|
|
2347
|
+
timeouts.delete(timer);
|
|
2348
|
+
updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
|
|
2349
|
+
}, viewabilityConfigCallbackPair.viewabilityConfig.minimumViewTime);
|
|
2350
|
+
timeouts.add(timer);
|
|
2351
|
+
} else {
|
|
2352
|
+
updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize);
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
function updateViewableItemsWithConfig(data, viewabilityConfigCallbackPair, state, ctx, scrollSize) {
|
|
2357
|
+
const { viewabilityConfig, onViewableItemsChanged } = viewabilityConfigCallbackPair;
|
|
2358
|
+
const configId = viewabilityConfig.id;
|
|
2359
|
+
const viewabilityState = ensureViewabilityState(ctx, configId);
|
|
2360
|
+
const { viewableItems: previousViewableItems, start, end } = viewabilityState;
|
|
2361
|
+
const viewabilityTokens = /* @__PURE__ */ new Map();
|
|
2362
|
+
for (const [containerId, value] of ctx.mapViewabilityAmountValues) {
|
|
2363
|
+
viewabilityTokens.set(
|
|
2364
|
+
containerId,
|
|
2365
|
+
computeViewability(
|
|
2366
|
+
state,
|
|
2367
|
+
ctx,
|
|
2368
|
+
viewabilityConfig,
|
|
2369
|
+
containerId,
|
|
2370
|
+
value.key,
|
|
2371
|
+
scrollSize,
|
|
2372
|
+
value.item,
|
|
2373
|
+
value.index
|
|
2374
|
+
)
|
|
2375
|
+
);
|
|
2376
|
+
}
|
|
2377
|
+
const changed = [];
|
|
2378
|
+
if (previousViewableItems) {
|
|
2379
|
+
for (const viewToken of previousViewableItems) {
|
|
2380
|
+
const containerId = findContainerId(ctx, viewToken.key);
|
|
2381
|
+
if (!checkIsViewable(
|
|
2382
|
+
state,
|
|
2383
|
+
ctx,
|
|
2384
|
+
viewabilityConfig,
|
|
2385
|
+
containerId,
|
|
2386
|
+
viewToken.key,
|
|
2387
|
+
scrollSize,
|
|
2388
|
+
viewToken.item,
|
|
2389
|
+
viewToken.index
|
|
2390
|
+
)) {
|
|
2391
|
+
viewToken.isViewable = false;
|
|
2392
|
+
changed.push(viewToken);
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
const viewableItems = [];
|
|
2397
|
+
for (let i = start; i <= end; i++) {
|
|
2398
|
+
const item = data[i];
|
|
2399
|
+
if (item) {
|
|
2400
|
+
const key = getId(state, i);
|
|
2401
|
+
const containerId = findContainerId(ctx, key);
|
|
2402
|
+
if (checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, i)) {
|
|
2403
|
+
const viewToken = {
|
|
2404
|
+
containerId,
|
|
2405
|
+
index: i,
|
|
2406
|
+
isViewable: true,
|
|
2407
|
+
item,
|
|
2408
|
+
key
|
|
2409
|
+
};
|
|
2410
|
+
viewableItems.push(viewToken);
|
|
2411
|
+
if (!(previousViewableItems == null ? void 0 : previousViewableItems.find((v) => v.key === viewToken.key))) {
|
|
2412
|
+
changed.push(viewToken);
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
}
|
|
2417
|
+
Object.assign(viewabilityState, {
|
|
2418
|
+
previousEnd: end,
|
|
2419
|
+
previousStart: start,
|
|
2420
|
+
viewableItems
|
|
2421
|
+
});
|
|
2422
|
+
if (changed.length > 0) {
|
|
2423
|
+
viewabilityState.viewableItems = viewableItems;
|
|
2424
|
+
for (let i = 0; i < changed.length; i++) {
|
|
2425
|
+
const change = changed[i];
|
|
2426
|
+
maybeUpdateViewabilityCallback(ctx, configId, change.containerId, change);
|
|
2427
|
+
}
|
|
2428
|
+
if (onViewableItemsChanged) {
|
|
2429
|
+
onViewableItemsChanged({ changed, viewableItems });
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
for (const [containerId, value] of ctx.mapViewabilityAmountValues) {
|
|
2433
|
+
if (value.sizeVisible < 0) {
|
|
2434
|
+
ctx.mapViewabilityAmountValues.delete(containerId);
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
function shallowEqual(prev, next) {
|
|
2439
|
+
if (!prev) return false;
|
|
2440
|
+
const keys = Object.keys(next);
|
|
2441
|
+
for (let i = 0; i < keys.length; i++) {
|
|
2442
|
+
const k = keys[i];
|
|
2443
|
+
if (prev[k] !== next[k]) return false;
|
|
2444
|
+
}
|
|
2445
|
+
return true;
|
|
2446
|
+
}
|
|
2447
|
+
function computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
|
|
2448
|
+
const { sizes, scroll: scrollState } = state;
|
|
2449
|
+
const topPad = (peek$(ctx, "stylePaddingTop") || 0) + (peek$(ctx, "headerSize") || 0);
|
|
2450
|
+
const { itemVisiblePercentThreshold, viewAreaCoveragePercentThreshold } = viewabilityConfig;
|
|
2451
|
+
const viewAreaMode = viewAreaCoveragePercentThreshold != null;
|
|
2452
|
+
const viewablePercentThreshold = viewAreaMode ? viewAreaCoveragePercentThreshold : itemVisiblePercentThreshold;
|
|
2453
|
+
const scroll = scrollState - topPad;
|
|
2454
|
+
const position = state.positions[index];
|
|
2455
|
+
const size = sizes.get(key) || 0;
|
|
2456
|
+
if (position === void 0) {
|
|
2457
|
+
const value2 = {
|
|
2458
|
+
containerId,
|
|
2459
|
+
index,
|
|
2460
|
+
isViewable: false,
|
|
2461
|
+
item,
|
|
2462
|
+
key,
|
|
2463
|
+
percentOfScroller: 0,
|
|
2464
|
+
percentVisible: 0,
|
|
2465
|
+
scrollSize,
|
|
2466
|
+
size,
|
|
2467
|
+
sizeVisible: -1
|
|
2468
|
+
};
|
|
2469
|
+
const prev2 = ctx.mapViewabilityAmountValues.get(containerId);
|
|
2470
|
+
if (!shallowEqual(prev2, value2)) {
|
|
2471
|
+
ctx.mapViewabilityAmountValues.set(containerId, value2);
|
|
2472
|
+
const cb = ctx.mapViewabilityAmountCallbacks.get(containerId);
|
|
2473
|
+
if (cb) {
|
|
2474
|
+
cb(value2);
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
return value2;
|
|
2478
|
+
}
|
|
2479
|
+
const top = position - scroll;
|
|
2480
|
+
const bottom = top + size;
|
|
2481
|
+
const isEntirelyVisible = top >= 0 && bottom <= scrollSize && bottom > top;
|
|
2482
|
+
const sizeVisible = isEntirelyVisible ? size : Math.min(bottom, scrollSize) - Math.max(top, 0);
|
|
2483
|
+
const percentVisible = size ? isEntirelyVisible ? 100 : 100 * (sizeVisible / size) : 0;
|
|
2484
|
+
const percentOfScroller = size ? 100 * (sizeVisible / scrollSize) : 0;
|
|
2485
|
+
const percent = isEntirelyVisible ? 100 : viewAreaMode ? percentOfScroller : percentVisible;
|
|
2486
|
+
const isViewable = percent >= viewablePercentThreshold;
|
|
2487
|
+
const value = {
|
|
2488
|
+
containerId,
|
|
2489
|
+
index,
|
|
2490
|
+
isViewable,
|
|
2491
|
+
item,
|
|
2492
|
+
key,
|
|
2493
|
+
percentOfScroller,
|
|
2494
|
+
percentVisible,
|
|
2495
|
+
scrollSize,
|
|
2496
|
+
size,
|
|
2497
|
+
sizeVisible
|
|
2498
|
+
};
|
|
2499
|
+
const prev = ctx.mapViewabilityAmountValues.get(containerId);
|
|
2500
|
+
if (!shallowEqual(prev, value)) {
|
|
2501
|
+
ctx.mapViewabilityAmountValues.set(containerId, value);
|
|
2502
|
+
const cb = ctx.mapViewabilityAmountCallbacks.get(containerId);
|
|
2503
|
+
if (cb) {
|
|
2504
|
+
cb(value);
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
return value;
|
|
2508
|
+
}
|
|
2509
|
+
function checkIsViewable(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index) {
|
|
2510
|
+
let value = ctx.mapViewabilityAmountValues.get(containerId);
|
|
2511
|
+
if (!value || value.key !== key) {
|
|
2512
|
+
value = computeViewability(state, ctx, viewabilityConfig, containerId, key, scrollSize, item, index);
|
|
2513
|
+
}
|
|
2514
|
+
return value.isViewable;
|
|
2515
|
+
}
|
|
2516
|
+
function maybeUpdateViewabilityCallback(ctx, configId, containerId, viewToken) {
|
|
2517
|
+
const key = containerId + configId;
|
|
2518
|
+
ctx.mapViewabilityValues.set(key, viewToken);
|
|
2519
|
+
const cb = ctx.mapViewabilityCallbacks.get(key);
|
|
2520
|
+
cb == null ? void 0 : cb(viewToken);
|
|
2521
|
+
}
|
|
2522
|
+
var unstableBatchedUpdates = ReactNative__namespace.unstable_batchedUpdates;
|
|
2523
|
+
var batchedUpdates = typeof unstableBatchedUpdates === "function" ? unstableBatchedUpdates : (fn) => fn();
|
|
2524
|
+
|
|
2525
|
+
// src/utils/checkAllSizesKnown.ts
|
|
2526
|
+
function isNullOrUndefined2(value) {
|
|
2527
|
+
return value === null || value === void 0;
|
|
2528
|
+
}
|
|
2529
|
+
function checkAllSizesKnown(state) {
|
|
2530
|
+
const { startBuffered, endBuffered, sizesKnown } = state;
|
|
2531
|
+
if (!isNullOrUndefined2(endBuffered) && !isNullOrUndefined2(startBuffered) && startBuffered >= 0 && endBuffered >= 0) {
|
|
2532
|
+
let areAllKnown = true;
|
|
2533
|
+
for (let i = startBuffered; areAllKnown && i <= endBuffered; i++) {
|
|
2534
|
+
const key = getId(state, i);
|
|
2535
|
+
areAllKnown && (areAllKnown = sizesKnown.has(key));
|
|
2536
|
+
}
|
|
2537
|
+
return areAllKnown;
|
|
2538
|
+
}
|
|
2539
|
+
return false;
|
|
2540
|
+
}
|
|
2541
|
+
|
|
2542
|
+
// src/utils/findAvailableContainers.ts
|
|
2543
|
+
function findAvailableContainers(ctx, numNeeded, startBuffered, endBuffered, pendingRemoval, requiredItemTypes, needNewContainers) {
|
|
2544
|
+
const numContainers = peek$(ctx, "numContainers");
|
|
2545
|
+
const state = ctx.state;
|
|
2546
|
+
const { stickyContainerPool, containerItemTypes } = state;
|
|
2547
|
+
const result = [];
|
|
2548
|
+
const availableContainers = [];
|
|
2549
|
+
const pendingRemovalSet = new Set(pendingRemoval);
|
|
2550
|
+
let pendingRemovalChanged = false;
|
|
2551
|
+
const stickyIndicesSet = state.props.stickyIndicesSet;
|
|
2552
|
+
const stickyItemIndices = (needNewContainers == null ? void 0 : needNewContainers.filter((index) => stickyIndicesSet.has(index))) || [];
|
|
2553
|
+
const canReuseContainer = (containerIndex, requiredType) => {
|
|
2554
|
+
if (!requiredType) return true;
|
|
2555
|
+
const existingType = containerItemTypes.get(containerIndex);
|
|
2556
|
+
if (!existingType) return true;
|
|
2557
|
+
return existingType === requiredType;
|
|
2558
|
+
};
|
|
2559
|
+
const neededTypes = requiredItemTypes ? [...requiredItemTypes] : [];
|
|
2560
|
+
let typeIndex = 0;
|
|
2561
|
+
for (let i = 0; i < stickyItemIndices.length; i++) {
|
|
2562
|
+
const requiredType = neededTypes[typeIndex];
|
|
2563
|
+
let foundContainer = false;
|
|
2564
|
+
for (const containerIndex of stickyContainerPool) {
|
|
2565
|
+
const key = peek$(ctx, `containerItemKey${containerIndex}`);
|
|
2566
|
+
const isPendingRemoval = pendingRemovalSet.has(containerIndex);
|
|
2567
|
+
if ((key === void 0 || isPendingRemoval) && canReuseContainer(containerIndex, requiredType) && !result.includes(containerIndex)) {
|
|
2568
|
+
result.push(containerIndex);
|
|
2569
|
+
if (isPendingRemoval && pendingRemovalSet.delete(containerIndex)) {
|
|
2570
|
+
pendingRemovalChanged = true;
|
|
2571
|
+
}
|
|
2572
|
+
foundContainer = true;
|
|
2573
|
+
if (requiredItemTypes) typeIndex++;
|
|
2574
|
+
break;
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
if (!foundContainer) {
|
|
2578
|
+
const newContainerIndex = numContainers + result.filter((index) => index >= numContainers).length;
|
|
2579
|
+
result.push(newContainerIndex);
|
|
2580
|
+
stickyContainerPool.add(newContainerIndex);
|
|
2581
|
+
if (requiredItemTypes) typeIndex++;
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
for (let u = 0; u < numContainers && result.length < numNeeded; u++) {
|
|
2585
|
+
if (stickyContainerPool.has(u)) {
|
|
2586
|
+
continue;
|
|
2587
|
+
}
|
|
2588
|
+
const key = peek$(ctx, `containerItemKey${u}`);
|
|
2589
|
+
const requiredType = neededTypes[typeIndex];
|
|
2590
|
+
const isPending = key !== void 0 && pendingRemovalSet.has(u);
|
|
2591
|
+
const canUse = key === void 0 || isPending && canReuseContainer(u, requiredType);
|
|
2592
|
+
if (canUse) {
|
|
2593
|
+
if (isPending) {
|
|
2594
|
+
pendingRemovalSet.delete(u);
|
|
2595
|
+
pendingRemovalChanged = true;
|
|
2596
|
+
}
|
|
2597
|
+
result.push(u);
|
|
2598
|
+
if (requiredItemTypes) {
|
|
2599
|
+
typeIndex++;
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
for (let u = 0; u < numContainers && result.length < numNeeded; u++) {
|
|
2604
|
+
if (stickyContainerPool.has(u)) {
|
|
2605
|
+
continue;
|
|
2606
|
+
}
|
|
2607
|
+
const key = peek$(ctx, `containerItemKey${u}`);
|
|
2608
|
+
if (key === void 0) continue;
|
|
2609
|
+
const index = state.indexByKey.get(key);
|
|
2610
|
+
const isOutOfView = index < startBuffered || index > endBuffered;
|
|
2611
|
+
if (isOutOfView) {
|
|
2612
|
+
const distance = index < startBuffered ? startBuffered - index : index - endBuffered;
|
|
2613
|
+
if (!requiredItemTypes || typeIndex < neededTypes.length && canReuseContainer(u, neededTypes[typeIndex])) {
|
|
2614
|
+
availableContainers.push({ distance, index: u });
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
const remaining = numNeeded - result.length;
|
|
2619
|
+
if (remaining > 0) {
|
|
2620
|
+
if (availableContainers.length > 0) {
|
|
2621
|
+
if (availableContainers.length > remaining) {
|
|
2622
|
+
availableContainers.sort(comparatorByDistance);
|
|
2623
|
+
availableContainers.length = remaining;
|
|
2624
|
+
}
|
|
2625
|
+
for (const container of availableContainers) {
|
|
2626
|
+
result.push(container.index);
|
|
2627
|
+
if (requiredItemTypes) {
|
|
2628
|
+
typeIndex++;
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
}
|
|
2632
|
+
const stillNeeded = numNeeded - result.length;
|
|
2633
|
+
if (stillNeeded > 0) {
|
|
2634
|
+
for (let i = 0; i < stillNeeded; i++) {
|
|
2635
|
+
result.push(numContainers + i);
|
|
2636
|
+
}
|
|
2637
|
+
if (IS_DEV && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
|
|
2638
|
+
console.warn(
|
|
2639
|
+
"[legend-list] No unused container available, so creating one on demand. This can be a minor performance issue and is likely caused by the estimatedItemSize being too large. Consider decreasing estimatedItemSize or increasing initialContainerPoolRatio.",
|
|
2640
|
+
{
|
|
2641
|
+
debugInfo: {
|
|
2642
|
+
numContainers,
|
|
2643
|
+
numContainersPooled: peek$(ctx, "numContainersPooled"),
|
|
2644
|
+
numNeeded,
|
|
2645
|
+
stillNeeded
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
);
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2652
|
+
if (pendingRemovalChanged) {
|
|
2653
|
+
pendingRemoval.length = 0;
|
|
2654
|
+
for (const value of pendingRemovalSet) {
|
|
2655
|
+
pendingRemoval.push(value);
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
2658
|
+
return result.sort(comparatorDefault);
|
|
2659
|
+
}
|
|
2660
|
+
function comparatorByDistance(a, b) {
|
|
2661
|
+
return b.distance - a.distance;
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2664
|
+
// src/core/scrollToIndex.ts
|
|
2665
|
+
function scrollToIndex(ctx, {
|
|
2666
|
+
index,
|
|
2667
|
+
viewOffset = 0,
|
|
2668
|
+
animated = true,
|
|
2669
|
+
forceScroll,
|
|
2670
|
+
isInitialScroll,
|
|
2671
|
+
viewPosition
|
|
2672
|
+
}) {
|
|
2673
|
+
const state = ctx.state;
|
|
2674
|
+
const { data } = state.props;
|
|
2675
|
+
if (index >= data.length) {
|
|
2676
|
+
index = data.length - 1;
|
|
2677
|
+
} else if (index < 0) {
|
|
2678
|
+
index = 0;
|
|
2679
|
+
}
|
|
2680
|
+
const firstIndexOffset = calculateOffsetForIndex(ctx, index);
|
|
2681
|
+
const isLast = index === data.length - 1;
|
|
2682
|
+
if (isLast && viewPosition === void 0) {
|
|
2683
|
+
viewPosition = 1;
|
|
2684
|
+
}
|
|
2685
|
+
state.scrollForNextCalculateItemsInView = void 0;
|
|
2686
|
+
const targetId = getId(state, index);
|
|
2687
|
+
const itemSize = getItemSize(ctx, targetId, index, state.props.data[index]);
|
|
2688
|
+
scrollTo(ctx, {
|
|
2689
|
+
animated,
|
|
2690
|
+
forceScroll,
|
|
2691
|
+
index,
|
|
2692
|
+
isInitialScroll,
|
|
2693
|
+
itemSize,
|
|
2694
|
+
offset: firstIndexOffset,
|
|
2695
|
+
viewOffset,
|
|
2696
|
+
viewPosition: viewPosition != null ? viewPosition : 0
|
|
2697
|
+
});
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
// src/utils/performInitialScroll.ts
|
|
2701
|
+
function performInitialScroll(ctx, params) {
|
|
2702
|
+
var _a3;
|
|
2703
|
+
const { forceScroll, initialScrollUsesOffset, resolvedOffset, target } = params;
|
|
2704
|
+
if (initialScrollUsesOffset || resolvedOffset !== void 0) {
|
|
2705
|
+
scrollTo(ctx, {
|
|
2706
|
+
animated: false,
|
|
2707
|
+
forceScroll,
|
|
2708
|
+
index: initialScrollUsesOffset ? void 0 : target.index,
|
|
2709
|
+
isInitialScroll: true,
|
|
2710
|
+
offset: (_a3 = resolvedOffset != null ? resolvedOffset : target.contentOffset) != null ? _a3 : 0,
|
|
2711
|
+
precomputedWithViewOffset: resolvedOffset !== void 0
|
|
2712
|
+
});
|
|
2713
|
+
return;
|
|
2714
|
+
}
|
|
2715
|
+
if (target.index === void 0) {
|
|
2716
|
+
return;
|
|
2717
|
+
}
|
|
2718
|
+
scrollToIndex(ctx, {
|
|
2719
|
+
...target,
|
|
2720
|
+
animated: false,
|
|
2721
|
+
forceScroll,
|
|
2722
|
+
isInitialScroll: true
|
|
2723
|
+
});
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2726
|
+
// src/utils/setDidLayout.ts
|
|
2727
|
+
function setDidLayout(ctx) {
|
|
2728
|
+
const state = ctx.state;
|
|
2729
|
+
const { initialScroll } = state;
|
|
2730
|
+
state.queuedInitialLayout = true;
|
|
2731
|
+
checkAtBottom(ctx);
|
|
2732
|
+
if (initialScroll) {
|
|
2733
|
+
const runScroll = () => {
|
|
2734
|
+
var _a3, _b;
|
|
2735
|
+
const target = state.initialScroll;
|
|
2736
|
+
if (!target) {
|
|
2737
|
+
return;
|
|
2738
|
+
}
|
|
2739
|
+
const activeInitialTargetOffset = ((_a3 = state.scrollingTo) == null ? void 0 : _a3.isInitialScroll) ? (_b = state.scrollingTo.targetOffset) != null ? _b : state.scrollingTo.offset : void 0;
|
|
2740
|
+
const desiredInitialTargetOffset = state.initialScrollUsesOffset ? target.contentOffset : activeInitialTargetOffset;
|
|
2741
|
+
const isAlreadyAtDesiredInitialTarget = desiredInitialTargetOffset !== void 0 && Math.abs(state.scroll - desiredInitialTargetOffset) <= 1 && Math.abs(state.scrollPending - desiredInitialTargetOffset) <= 1;
|
|
2742
|
+
if (!isAlreadyAtDesiredInitialTarget) {
|
|
2743
|
+
performInitialScroll(ctx, {
|
|
2744
|
+
forceScroll: true,
|
|
2745
|
+
initialScrollUsesOffset: state.initialScrollUsesOffset,
|
|
2746
|
+
// Offset-based initial scrolls do not need item lookup, so they can run even before data exists.
|
|
2747
|
+
// Re-run on the next frame to pick up measured viewport size without waiting for index resolution.
|
|
2748
|
+
target
|
|
2749
|
+
});
|
|
2750
|
+
}
|
|
2751
|
+
};
|
|
2752
|
+
runScroll();
|
|
2753
|
+
requestAnimationFrame(runScroll);
|
|
2754
|
+
}
|
|
2755
|
+
setInitialRenderState(ctx, { didLayout: true });
|
|
2756
|
+
}
|
|
2757
|
+
|
|
2758
|
+
// src/core/calculateItemsInView.ts
|
|
2759
|
+
function findCurrentStickyIndex(stickyArray, scroll, state) {
|
|
2760
|
+
const positions = state.positions;
|
|
2761
|
+
for (let i = stickyArray.length - 1; i >= 0; i--) {
|
|
2762
|
+
const stickyIndex = stickyArray[i];
|
|
2763
|
+
const stickyPos = positions[stickyIndex];
|
|
2764
|
+
if (stickyPos !== void 0 && scroll >= stickyPos) {
|
|
2765
|
+
return i;
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
return -1;
|
|
2769
|
+
}
|
|
2770
|
+
function getActiveStickyIndices(ctx, stickyHeaderIndices) {
|
|
2771
|
+
const state = ctx.state;
|
|
2772
|
+
return new Set(
|
|
2773
|
+
Array.from(state.stickyContainerPool).map((i) => peek$(ctx, `containerItemKey${i}`)).map((key) => key ? state.indexByKey.get(key) : void 0).filter((idx) => idx !== void 0 && stickyHeaderIndices.has(idx))
|
|
2774
|
+
);
|
|
2775
|
+
}
|
|
2776
|
+
function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentStickyIdx, needNewContainers, needNewContainersSet, startBuffered, endBuffered) {
|
|
2777
|
+
var _a3;
|
|
2778
|
+
const state = ctx.state;
|
|
2779
|
+
const activeIndices = getActiveStickyIndices(ctx, stickyHeaderIndices);
|
|
2780
|
+
set$(ctx, "activeStickyIndex", currentStickyIdx >= 0 ? stickyArray[currentStickyIdx] : -1);
|
|
2781
|
+
for (let offset = 0; offset <= 1; offset++) {
|
|
2782
|
+
const idx = currentStickyIdx - offset;
|
|
2783
|
+
if (idx < 0 || activeIndices.has(stickyArray[idx])) continue;
|
|
2784
|
+
const stickyIndex = stickyArray[idx];
|
|
2785
|
+
const stickyId = (_a3 = state.idCache[stickyIndex]) != null ? _a3 : getId(state, stickyIndex);
|
|
2786
|
+
if (stickyId && !state.containerItemKeys.has(stickyId) && (stickyIndex < startBuffered || stickyIndex > endBuffered) && !needNewContainersSet.has(stickyIndex)) {
|
|
2787
|
+
needNewContainersSet.add(stickyIndex);
|
|
2788
|
+
needNewContainers.push(stickyIndex);
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentStickyIdx, pendingRemoval, alwaysRenderIndicesSet) {
|
|
2793
|
+
var _a3, _b;
|
|
2794
|
+
const state = ctx.state;
|
|
2795
|
+
for (const containerIndex of state.stickyContainerPool) {
|
|
2796
|
+
const itemKey = peek$(ctx, `containerItemKey${containerIndex}`);
|
|
2797
|
+
const itemIndex = itemKey ? state.indexByKey.get(itemKey) : void 0;
|
|
2798
|
+
if (itemIndex === void 0) continue;
|
|
2799
|
+
if (alwaysRenderIndicesSet.has(itemIndex)) continue;
|
|
2800
|
+
const arrayIdx = stickyArray.indexOf(itemIndex);
|
|
2801
|
+
if (arrayIdx === -1) {
|
|
2802
|
+
state.stickyContainerPool.delete(containerIndex);
|
|
2803
|
+
set$(ctx, `containerSticky${containerIndex}`, false);
|
|
2804
|
+
continue;
|
|
2805
|
+
}
|
|
2806
|
+
const isRecentSticky = arrayIdx >= currentStickyIdx - 1 && arrayIdx <= currentStickyIdx + 1;
|
|
2807
|
+
if (isRecentSticky) continue;
|
|
2808
|
+
const nextIndex = stickyArray[arrayIdx + 1];
|
|
2809
|
+
let shouldRecycle = false;
|
|
2810
|
+
if (nextIndex) {
|
|
2811
|
+
const nextPos = state.positions[nextIndex];
|
|
2812
|
+
shouldRecycle = nextPos !== void 0 && scroll > nextPos + drawDistance * 2;
|
|
2813
|
+
} else {
|
|
2814
|
+
const currentId = (_a3 = state.idCache[itemIndex]) != null ? _a3 : getId(state, itemIndex);
|
|
2815
|
+
if (currentId) {
|
|
2816
|
+
const currentPos = state.positions[itemIndex];
|
|
2817
|
+
const currentSize = (_b = state.sizes.get(currentId)) != null ? _b : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
|
|
2818
|
+
shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + drawDistance * 3;
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
if (shouldRecycle) {
|
|
2822
|
+
pendingRemoval.push(containerIndex);
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
function calculateItemsInView(ctx, params = {}) {
|
|
2827
|
+
const state = ctx.state;
|
|
2828
|
+
batchedUpdates(() => {
|
|
2829
|
+
var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
2830
|
+
const {
|
|
2831
|
+
columns,
|
|
2832
|
+
columnSpans,
|
|
2833
|
+
containerItemKeys,
|
|
2834
|
+
enableScrollForNextCalculateItemsInView,
|
|
2835
|
+
idCache,
|
|
2836
|
+
indexByKey,
|
|
2837
|
+
initialScroll,
|
|
2838
|
+
minIndexSizeChanged,
|
|
2839
|
+
positions,
|
|
2840
|
+
props: {
|
|
2841
|
+
alwaysRenderIndicesArr,
|
|
2842
|
+
alwaysRenderIndicesSet,
|
|
2843
|
+
drawDistance,
|
|
2844
|
+
getItemType,
|
|
2845
|
+
itemsAreEqual,
|
|
2846
|
+
keyExtractor,
|
|
2847
|
+
onStickyHeaderChange
|
|
2848
|
+
},
|
|
2849
|
+
scrollForNextCalculateItemsInView,
|
|
2850
|
+
scrollLength,
|
|
2851
|
+
sizes,
|
|
2852
|
+
startBufferedId: startBufferedIdOrig,
|
|
2853
|
+
viewabilityConfigCallbackPairs
|
|
2854
|
+
} = state;
|
|
2855
|
+
const { data } = state.props;
|
|
2856
|
+
const stickyIndicesArr = state.props.stickyIndicesArr || [];
|
|
2857
|
+
const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
|
|
2858
|
+
const alwaysRenderArr = alwaysRenderIndicesArr || [];
|
|
2859
|
+
const alwaysRenderSet = alwaysRenderIndicesSet || /* @__PURE__ */ new Set();
|
|
2860
|
+
const { dataChanged, doMVCP, forceFullItemPositions } = params;
|
|
2861
|
+
const prevNumContainers = peek$(ctx, "numContainers");
|
|
2862
|
+
if (!data || scrollLength === 0 || !prevNumContainers) {
|
|
2863
|
+
if (!IsNewArchitecture && state.initialAnchor) {
|
|
2864
|
+
ensureInitialAnchor(ctx);
|
|
2865
|
+
}
|
|
2866
|
+
return;
|
|
2867
|
+
}
|
|
2868
|
+
let totalSize = getContentSize(ctx);
|
|
2869
|
+
const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
|
|
2870
|
+
const numColumns = peek$(ctx, "numColumns");
|
|
2871
|
+
const speed = getScrollVelocity(state);
|
|
2872
|
+
const scrollExtra = 0;
|
|
2873
|
+
const { queuedInitialLayout } = state;
|
|
2874
|
+
let { scroll: scrollState } = state;
|
|
2875
|
+
if (!queuedInitialLayout && initialScroll) {
|
|
2876
|
+
const updatedOffset = state.initialScrollUsesOffset ? (_a3 = initialScroll.contentOffset) != null ? _a3 : 0 : calculateOffsetWithOffsetPosition(
|
|
2877
|
+
ctx,
|
|
2878
|
+
calculateOffsetForIndex(ctx, initialScroll.index),
|
|
2879
|
+
initialScroll
|
|
2880
|
+
);
|
|
2881
|
+
scrollState = updatedOffset;
|
|
2882
|
+
}
|
|
2883
|
+
const scrollAdjustPending = (_b = peek$(ctx, "scrollAdjustPending")) != null ? _b : 0;
|
|
2884
|
+
const scrollAdjustPad = scrollAdjustPending - topPad;
|
|
2885
|
+
let scroll = Math.round(scrollState + scrollExtra + scrollAdjustPad);
|
|
2886
|
+
if (scroll + scrollLength > totalSize) {
|
|
2887
|
+
scroll = Math.max(0, totalSize - scrollLength);
|
|
2888
|
+
}
|
|
2889
|
+
const previousStickyIndex = peek$(ctx, "activeStickyIndex");
|
|
2890
|
+
const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
|
|
2891
|
+
const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
|
|
2892
|
+
if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
|
|
2893
|
+
set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
|
|
2894
|
+
}
|
|
2895
|
+
let scrollBufferTop = drawDistance;
|
|
2896
|
+
let scrollBufferBottom = drawDistance;
|
|
2897
|
+
if (speed > 0 || speed === 0 && scroll < Math.max(50, drawDistance)) {
|
|
2898
|
+
scrollBufferTop = drawDistance * 0.5;
|
|
2899
|
+
scrollBufferBottom = drawDistance * 1.5;
|
|
2900
|
+
} else {
|
|
2901
|
+
scrollBufferTop = drawDistance * 1.5;
|
|
2902
|
+
scrollBufferBottom = drawDistance * 0.5;
|
|
2903
|
+
}
|
|
2904
|
+
const scrollTopBuffered = scroll - scrollBufferTop;
|
|
2905
|
+
const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
|
|
2906
|
+
const scrollBottomBuffered = scrollBottom + scrollBufferBottom;
|
|
2907
|
+
if (!dataChanged && !forceFullItemPositions && scrollForNextCalculateItemsInView) {
|
|
2908
|
+
const { top, bottom } = scrollForNextCalculateItemsInView;
|
|
2909
|
+
if (top === null && bottom === null) {
|
|
2910
|
+
state.scrollForNextCalculateItemsInView = void 0;
|
|
2911
|
+
} else if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
|
|
2912
|
+
if (!IsNewArchitecture && state.initialAnchor) {
|
|
2913
|
+
ensureInitialAnchor(ctx);
|
|
2914
|
+
}
|
|
2915
|
+
if (Platform2.OS !== "web" || !isInMVCPActiveMode(state)) {
|
|
2916
|
+
return;
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
|
|
2921
|
+
if (dataChanged) {
|
|
2922
|
+
indexByKey.clear();
|
|
2923
|
+
idCache.length = 0;
|
|
2924
|
+
positions.length = 0;
|
|
2925
|
+
columns.length = 0;
|
|
2926
|
+
columnSpans.length = 0;
|
|
2927
|
+
}
|
|
2928
|
+
const startIndex = forceFullItemPositions || dataChanged ? 0 : (_c = minIndexSizeChanged != null ? minIndexSizeChanged : state.startBuffered) != null ? _c : 0;
|
|
2929
|
+
updateItemPositions(ctx, dataChanged, {
|
|
2930
|
+
doMVCP,
|
|
2931
|
+
forceFullUpdate: !!forceFullItemPositions,
|
|
2932
|
+
scrollBottomBuffered,
|
|
2933
|
+
startIndex
|
|
2934
|
+
});
|
|
2935
|
+
totalSize = getContentSize(ctx);
|
|
2936
|
+
if (minIndexSizeChanged !== void 0) {
|
|
2937
|
+
state.minIndexSizeChanged = void 0;
|
|
2938
|
+
}
|
|
2939
|
+
checkMVCP == null ? void 0 : checkMVCP();
|
|
2940
|
+
let startNoBuffer = null;
|
|
2941
|
+
let startBuffered = null;
|
|
2942
|
+
let startBufferedId = null;
|
|
2943
|
+
let endNoBuffer = null;
|
|
2944
|
+
let endBuffered = null;
|
|
2945
|
+
let loopStart = !dataChanged && startBufferedIdOrig ? indexByKey.get(startBufferedIdOrig) || 0 : 0;
|
|
2946
|
+
for (let i = loopStart; i >= 0; i--) {
|
|
2947
|
+
const id = (_d = idCache[i]) != null ? _d : getId(state, i);
|
|
2948
|
+
const top = positions[i];
|
|
2949
|
+
const size = (_e = sizes.get(id)) != null ? _e : getItemSize(ctx, id, i, data[i]);
|
|
2950
|
+
const bottom = top + size;
|
|
2951
|
+
if (bottom > scroll - scrollBufferTop) {
|
|
2952
|
+
loopStart = i;
|
|
2953
|
+
} else {
|
|
2954
|
+
break;
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
if (numColumns > 1) {
|
|
2958
|
+
while (loopStart > 0) {
|
|
2959
|
+
const loopColumn = columns[loopStart];
|
|
2960
|
+
if (loopColumn === 1 || loopColumn === void 0) {
|
|
2961
|
+
break;
|
|
2962
|
+
}
|
|
2963
|
+
loopStart -= 1;
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
let foundEnd = false;
|
|
2967
|
+
let nextTop;
|
|
2968
|
+
let nextBottom;
|
|
2969
|
+
let maxIndexRendered = 0;
|
|
2970
|
+
for (let i = 0; i < prevNumContainers; i++) {
|
|
2971
|
+
const key = peek$(ctx, `containerItemKey${i}`);
|
|
2972
|
+
if (key !== void 0) {
|
|
2973
|
+
const index = indexByKey.get(key);
|
|
2974
|
+
maxIndexRendered = Math.max(maxIndexRendered, index);
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2977
|
+
let firstFullyOnScreenIndex;
|
|
2978
|
+
const dataLength = data.length;
|
|
2979
|
+
for (let i = Math.max(0, loopStart); i < dataLength && (!foundEnd || i <= maxIndexRendered); i++) {
|
|
2980
|
+
const id = (_f = idCache[i]) != null ? _f : getId(state, i);
|
|
2981
|
+
const size = (_g = sizes.get(id)) != null ? _g : getItemSize(ctx, id, i, data[i]);
|
|
2982
|
+
const top = positions[i];
|
|
2983
|
+
if (!foundEnd) {
|
|
2984
|
+
if (startNoBuffer === null && top + size > scroll) {
|
|
2985
|
+
startNoBuffer = i;
|
|
2986
|
+
}
|
|
2987
|
+
if (firstFullyOnScreenIndex === void 0 && top >= scroll - 10 && top <= scrollBottom) {
|
|
2988
|
+
firstFullyOnScreenIndex = i;
|
|
2989
|
+
}
|
|
2990
|
+
if (startBuffered === null && top + size > scrollTopBuffered) {
|
|
2991
|
+
startBuffered = i;
|
|
2992
|
+
startBufferedId = id;
|
|
2993
|
+
if (scrollTopBuffered < 0) {
|
|
2994
|
+
nextTop = null;
|
|
2995
|
+
} else {
|
|
2996
|
+
nextTop = top;
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2999
|
+
if (startNoBuffer !== null) {
|
|
3000
|
+
if (top <= scrollBottom) {
|
|
3001
|
+
endNoBuffer = i;
|
|
3002
|
+
}
|
|
3003
|
+
if (top <= scrollBottomBuffered) {
|
|
3004
|
+
endBuffered = i;
|
|
3005
|
+
if (scrollBottomBuffered > totalSize) {
|
|
3006
|
+
nextBottom = null;
|
|
3007
|
+
} else {
|
|
3008
|
+
nextBottom = top + size;
|
|
3009
|
+
}
|
|
3010
|
+
} else {
|
|
3011
|
+
foundEnd = true;
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
const idsInView = [];
|
|
3017
|
+
const firstVisibleAnchorIndex = firstFullyOnScreenIndex != null ? firstFullyOnScreenIndex : startNoBuffer;
|
|
3018
|
+
if (firstVisibleAnchorIndex !== null && firstVisibleAnchorIndex !== void 0 && endNoBuffer !== null) {
|
|
3019
|
+
for (let i = firstVisibleAnchorIndex; i <= endNoBuffer; i++) {
|
|
3020
|
+
const id = (_h = idCache[i]) != null ? _h : getId(state, i);
|
|
3021
|
+
idsInView.push(id);
|
|
3022
|
+
}
|
|
3023
|
+
}
|
|
3024
|
+
Object.assign(state, {
|
|
3025
|
+
endBuffered,
|
|
3026
|
+
endNoBuffer,
|
|
3027
|
+
firstFullyOnScreenIndex,
|
|
3028
|
+
idsInView,
|
|
3029
|
+
startBuffered,
|
|
3030
|
+
startBufferedId,
|
|
3031
|
+
startNoBuffer
|
|
3032
|
+
});
|
|
3033
|
+
if (enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0) {
|
|
3034
|
+
state.scrollForNextCalculateItemsInView = isNullOrUndefined(nextTop) && isNullOrUndefined(nextBottom) ? void 0 : {
|
|
3035
|
+
bottom: nextBottom,
|
|
3036
|
+
top: nextTop
|
|
3037
|
+
};
|
|
3038
|
+
}
|
|
3039
|
+
let numContainers = prevNumContainers;
|
|
3040
|
+
const pendingRemoval = [];
|
|
3041
|
+
if (dataChanged) {
|
|
3042
|
+
for (let i = 0; i < numContainers; i++) {
|
|
3043
|
+
const itemKey = peek$(ctx, `containerItemKey${i}`);
|
|
3044
|
+
if (!keyExtractor || itemKey && indexByKey.get(itemKey) === void 0) {
|
|
3045
|
+
pendingRemoval.push(i);
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
if (startBuffered !== null && endBuffered !== null) {
|
|
3050
|
+
const needNewContainers = [];
|
|
3051
|
+
const needNewContainersSet = /* @__PURE__ */ new Set();
|
|
3052
|
+
for (let i = startBuffered; i <= endBuffered; i++) {
|
|
3053
|
+
const id = (_i = idCache[i]) != null ? _i : getId(state, i);
|
|
3054
|
+
if (!containerItemKeys.has(id)) {
|
|
3055
|
+
needNewContainersSet.add(i);
|
|
3056
|
+
needNewContainers.push(i);
|
|
3057
|
+
}
|
|
3058
|
+
}
|
|
3059
|
+
if (alwaysRenderArr.length > 0) {
|
|
3060
|
+
for (const index of alwaysRenderArr) {
|
|
3061
|
+
if (index < 0 || index >= dataLength) continue;
|
|
3062
|
+
const id = (_j = idCache[index]) != null ? _j : getId(state, index);
|
|
3063
|
+
if (id && !containerItemKeys.has(id) && !needNewContainersSet.has(index)) {
|
|
3064
|
+
needNewContainersSet.add(index);
|
|
3065
|
+
needNewContainers.push(index);
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
}
|
|
3069
|
+
if (stickyIndicesArr.length > 0) {
|
|
3070
|
+
handleStickyActivation(
|
|
3071
|
+
ctx,
|
|
3072
|
+
stickyIndicesSet,
|
|
3073
|
+
stickyIndicesArr,
|
|
3074
|
+
currentStickyIdx,
|
|
3075
|
+
needNewContainers,
|
|
3076
|
+
needNewContainersSet,
|
|
3077
|
+
startBuffered,
|
|
3078
|
+
endBuffered
|
|
3079
|
+
);
|
|
3080
|
+
} else if (previousStickyIndex !== -1) {
|
|
3081
|
+
set$(ctx, "activeStickyIndex", -1);
|
|
3082
|
+
}
|
|
3083
|
+
if (needNewContainers.length > 0) {
|
|
3084
|
+
const requiredItemTypes = getItemType ? needNewContainers.map((i) => {
|
|
3085
|
+
const itemType = getItemType(data[i], i);
|
|
3086
|
+
return itemType !== void 0 ? String(itemType) : "";
|
|
3087
|
+
}) : void 0;
|
|
3088
|
+
const availableContainers = findAvailableContainers(
|
|
3089
|
+
ctx,
|
|
3090
|
+
needNewContainers.length,
|
|
3091
|
+
startBuffered,
|
|
3092
|
+
endBuffered,
|
|
3093
|
+
pendingRemoval,
|
|
3094
|
+
requiredItemTypes,
|
|
3095
|
+
needNewContainers
|
|
3096
|
+
);
|
|
3097
|
+
for (let idx = 0; idx < needNewContainers.length; idx++) {
|
|
3098
|
+
const i = needNewContainers[idx];
|
|
3099
|
+
const containerIndex = availableContainers[idx];
|
|
3100
|
+
const id = (_k = idCache[i]) != null ? _k : getId(state, i);
|
|
3101
|
+
const oldKey = peek$(ctx, `containerItemKey${containerIndex}`);
|
|
3102
|
+
if (oldKey && oldKey !== id) {
|
|
3103
|
+
containerItemKeys.delete(oldKey);
|
|
3104
|
+
}
|
|
3105
|
+
set$(ctx, `containerItemKey${containerIndex}`, id);
|
|
3106
|
+
set$(ctx, `containerItemData${containerIndex}`, data[i]);
|
|
3107
|
+
if (requiredItemTypes) {
|
|
3108
|
+
state.containerItemTypes.set(containerIndex, requiredItemTypes[idx]);
|
|
3109
|
+
}
|
|
3110
|
+
containerItemKeys.set(id, containerIndex);
|
|
3111
|
+
const containerSticky = `containerSticky${containerIndex}`;
|
|
3112
|
+
const isSticky = stickyIndicesSet.has(i);
|
|
3113
|
+
const isAlwaysRender = alwaysRenderSet.has(i);
|
|
3114
|
+
if (isSticky) {
|
|
3115
|
+
set$(ctx, containerSticky, true);
|
|
3116
|
+
state.stickyContainerPool.add(containerIndex);
|
|
3117
|
+
} else {
|
|
3118
|
+
if (peek$(ctx, containerSticky)) {
|
|
3119
|
+
set$(ctx, containerSticky, false);
|
|
3120
|
+
}
|
|
3121
|
+
if (isAlwaysRender) {
|
|
3122
|
+
state.stickyContainerPool.add(containerIndex);
|
|
3123
|
+
} else if (state.stickyContainerPool.has(containerIndex)) {
|
|
3124
|
+
state.stickyContainerPool.delete(containerIndex);
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
3127
|
+
if (containerIndex >= numContainers) {
|
|
3128
|
+
numContainers = containerIndex + 1;
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
3131
|
+
if (numContainers !== prevNumContainers) {
|
|
3132
|
+
set$(ctx, "numContainers", numContainers);
|
|
3133
|
+
if (numContainers > peek$(ctx, "numContainersPooled")) {
|
|
3134
|
+
set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
if (alwaysRenderArr.length > 0) {
|
|
3139
|
+
for (const index of alwaysRenderArr) {
|
|
3140
|
+
if (index < 0 || index >= dataLength) continue;
|
|
3141
|
+
const id = (_l = idCache[index]) != null ? _l : getId(state, index);
|
|
3142
|
+
const containerIndex = containerItemKeys.get(id);
|
|
3143
|
+
if (containerIndex !== void 0) {
|
|
3144
|
+
state.stickyContainerPool.add(containerIndex);
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
if (state.stickyContainerPool.size > 0) {
|
|
3150
|
+
handleStickyRecycling(
|
|
3151
|
+
ctx,
|
|
3152
|
+
stickyIndicesArr,
|
|
3153
|
+
scroll,
|
|
3154
|
+
drawDistance,
|
|
3155
|
+
currentStickyIdx,
|
|
3156
|
+
pendingRemoval,
|
|
3157
|
+
alwaysRenderSet
|
|
3158
|
+
);
|
|
3159
|
+
}
|
|
3160
|
+
let didChangePositions = false;
|
|
3161
|
+
for (let i = 0; i < numContainers; i++) {
|
|
3162
|
+
const itemKey = peek$(ctx, `containerItemKey${i}`);
|
|
3163
|
+
if (pendingRemoval.includes(i)) {
|
|
3164
|
+
if (itemKey !== void 0) {
|
|
3165
|
+
containerItemKeys.delete(itemKey);
|
|
3166
|
+
}
|
|
3167
|
+
state.containerItemTypes.delete(i);
|
|
3168
|
+
if (state.stickyContainerPool.has(i)) {
|
|
3169
|
+
set$(ctx, `containerSticky${i}`, false);
|
|
3170
|
+
state.stickyContainerPool.delete(i);
|
|
3171
|
+
}
|
|
3172
|
+
set$(ctx, `containerItemKey${i}`, void 0);
|
|
3173
|
+
set$(ctx, `containerItemData${i}`, void 0);
|
|
3174
|
+
set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
|
|
3175
|
+
set$(ctx, `containerColumn${i}`, -1);
|
|
3176
|
+
set$(ctx, `containerSpan${i}`, 1);
|
|
3177
|
+
} else {
|
|
3178
|
+
const itemIndex = indexByKey.get(itemKey);
|
|
3179
|
+
const item = data[itemIndex];
|
|
3180
|
+
if (item !== void 0) {
|
|
3181
|
+
const positionValue = positions[itemIndex];
|
|
3182
|
+
if (positionValue === void 0) {
|
|
3183
|
+
set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
|
|
3184
|
+
} else {
|
|
3185
|
+
const position = (positionValue || 0) - scrollAdjustPending;
|
|
3186
|
+
const column = columns[itemIndex] || 1;
|
|
3187
|
+
const span = columnSpans[itemIndex] || 1;
|
|
3188
|
+
const prevPos = peek$(ctx, `containerPosition${i}`);
|
|
3189
|
+
const prevColumn = peek$(ctx, `containerColumn${i}`);
|
|
3190
|
+
const prevSpan = peek$(ctx, `containerSpan${i}`);
|
|
3191
|
+
const prevData = peek$(ctx, `containerItemData${i}`);
|
|
3192
|
+
if (position > POSITION_OUT_OF_VIEW && position !== prevPos) {
|
|
3193
|
+
set$(ctx, `containerPosition${i}`, position);
|
|
3194
|
+
didChangePositions = true;
|
|
3195
|
+
}
|
|
3196
|
+
if (column >= 0 && column !== prevColumn) {
|
|
3197
|
+
set$(ctx, `containerColumn${i}`, column);
|
|
3198
|
+
}
|
|
3199
|
+
if (span !== prevSpan) {
|
|
3200
|
+
set$(ctx, `containerSpan${i}`, span);
|
|
3201
|
+
}
|
|
3202
|
+
if (prevData !== item && (itemsAreEqual ? !itemsAreEqual(prevData, item, itemIndex, data) : true)) {
|
|
3203
|
+
set$(ctx, `containerItemData${i}`, item);
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
}
|
|
3209
|
+
if (Platform2.OS === "web" && didChangePositions) {
|
|
3210
|
+
set$(ctx, "lastPositionUpdate", Date.now());
|
|
3211
|
+
}
|
|
3212
|
+
if (!queuedInitialLayout && endBuffered !== null) {
|
|
3213
|
+
if (checkAllSizesKnown(state)) {
|
|
3214
|
+
setDidLayout(ctx);
|
|
3215
|
+
}
|
|
3216
|
+
}
|
|
3217
|
+
if (viewabilityConfigCallbackPairs) {
|
|
3218
|
+
updateViewableItems(state, ctx, viewabilityConfigCallbackPairs, scrollLength, startNoBuffer, endNoBuffer);
|
|
3219
|
+
}
|
|
3220
|
+
if (onStickyHeaderChange && stickyIndicesArr.length > 0 && nextActiveStickyIndex !== void 0 && nextActiveStickyIndex !== previousStickyIndex) {
|
|
3221
|
+
const item = data[nextActiveStickyIndex];
|
|
3222
|
+
if (item !== void 0) {
|
|
3223
|
+
onStickyHeaderChange({ index: nextActiveStickyIndex, item });
|
|
3224
|
+
}
|
|
3225
|
+
}
|
|
3226
|
+
});
|
|
3227
|
+
if (!IsNewArchitecture && state.initialAnchor) {
|
|
3228
|
+
ensureInitialAnchor(ctx);
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
|
|
3232
|
+
// src/core/checkActualChange.ts
|
|
3233
|
+
function checkActualChange(state, dataProp, previousData) {
|
|
3234
|
+
if (!previousData || !dataProp || dataProp.length !== previousData.length) {
|
|
3235
|
+
return true;
|
|
3236
|
+
}
|
|
3237
|
+
const {
|
|
3238
|
+
idCache,
|
|
3239
|
+
props: { keyExtractor }
|
|
3240
|
+
} = state;
|
|
3241
|
+
for (let i = 0; i < dataProp.length; i++) {
|
|
3242
|
+
if (dataProp[i] !== previousData[i]) {
|
|
3243
|
+
return true;
|
|
3244
|
+
}
|
|
3245
|
+
if (keyExtractor ? idCache[i] !== keyExtractor(previousData[i], i) : dataProp[i] !== previousData[i]) {
|
|
3246
|
+
return true;
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3249
|
+
return false;
|
|
3250
|
+
}
|
|
3251
|
+
|
|
3252
|
+
// src/utils/updateAveragesOnDataChange.ts
|
|
3253
|
+
function updateAveragesOnDataChange(state, oldData, newData) {
|
|
3254
|
+
var _a3;
|
|
3255
|
+
const {
|
|
3256
|
+
averageSizes,
|
|
3257
|
+
sizesKnown,
|
|
3258
|
+
indexByKey,
|
|
3259
|
+
props: { itemsAreEqual, getItemType, keyExtractor }
|
|
3260
|
+
} = state;
|
|
3261
|
+
if (!itemsAreEqual || !oldData.length || !newData.length) {
|
|
3262
|
+
for (const key in averageSizes) {
|
|
3263
|
+
delete averageSizes[key];
|
|
3264
|
+
}
|
|
3265
|
+
return;
|
|
3266
|
+
}
|
|
3267
|
+
const itemTypesToPreserve = {};
|
|
3268
|
+
const newDataLength = newData.length;
|
|
3269
|
+
const oldDataLength = oldData.length;
|
|
3270
|
+
for (let newIndex = 0; newIndex < newDataLength; newIndex++) {
|
|
3271
|
+
const newItem = newData[newIndex];
|
|
3272
|
+
const id = keyExtractor ? keyExtractor(newItem, newIndex) : String(newIndex);
|
|
3273
|
+
const oldIndex = indexByKey.get(id);
|
|
3274
|
+
if (oldIndex !== void 0 && oldIndex < oldDataLength) {
|
|
3275
|
+
const knownSize = sizesKnown.get(id);
|
|
3276
|
+
if (knownSize === void 0) continue;
|
|
3277
|
+
const oldItem = oldData[oldIndex];
|
|
3278
|
+
const areEqual = itemsAreEqual(oldItem, newItem, newIndex, newData);
|
|
3279
|
+
if (areEqual) {
|
|
3280
|
+
const itemType = getItemType ? (_a3 = getItemType(newItem, newIndex)) != null ? _a3 : "" : "";
|
|
3281
|
+
let typeData = itemTypesToPreserve[itemType];
|
|
3282
|
+
if (!typeData) {
|
|
3283
|
+
typeData = itemTypesToPreserve[itemType] = { count: 0, totalSize: 0 };
|
|
3284
|
+
}
|
|
3285
|
+
typeData.totalSize += knownSize;
|
|
3286
|
+
typeData.count++;
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
}
|
|
3290
|
+
for (const key in averageSizes) {
|
|
3291
|
+
delete averageSizes[key];
|
|
3292
|
+
}
|
|
3293
|
+
for (const itemType in itemTypesToPreserve) {
|
|
3294
|
+
const { totalSize, count } = itemTypesToPreserve[itemType];
|
|
3295
|
+
if (count > 0) {
|
|
3296
|
+
averageSizes[itemType] = {
|
|
3297
|
+
avg: totalSize / count,
|
|
3298
|
+
num: count
|
|
3299
|
+
};
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
3303
|
+
|
|
3304
|
+
// src/core/checkResetContainers.ts
|
|
3305
|
+
function checkResetContainers(ctx, dataProp) {
|
|
3306
|
+
const state = ctx.state;
|
|
3307
|
+
const { previousData } = state;
|
|
3308
|
+
if (previousData) {
|
|
3309
|
+
updateAveragesOnDataChange(state, previousData, dataProp);
|
|
3310
|
+
}
|
|
3311
|
+
const { maintainScrollAtEnd } = state.props;
|
|
3312
|
+
calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
|
|
3313
|
+
const shouldMaintainScrollAtEnd = maintainScrollAtEnd == null ? void 0 : maintainScrollAtEnd.onDataChange;
|
|
3314
|
+
const didMaintainScrollAtEnd = shouldMaintainScrollAtEnd && doMaintainScrollAtEnd(ctx);
|
|
3315
|
+
if (!didMaintainScrollAtEnd && previousData && dataProp.length > previousData.length) {
|
|
3316
|
+
state.isEndReached = false;
|
|
3317
|
+
}
|
|
3318
|
+
if (!didMaintainScrollAtEnd) {
|
|
3319
|
+
checkThresholds(ctx);
|
|
3320
|
+
}
|
|
3321
|
+
delete state.previousData;
|
|
3322
|
+
}
|
|
3323
|
+
|
|
3324
|
+
// src/core/doInitialAllocateContainers.ts
|
|
3325
|
+
function doInitialAllocateContainers(ctx) {
|
|
3326
|
+
var _a3, _b, _c;
|
|
3327
|
+
const state = ctx.state;
|
|
3328
|
+
const {
|
|
3329
|
+
scrollLength,
|
|
3330
|
+
props: {
|
|
3331
|
+
data,
|
|
3332
|
+
drawDistance,
|
|
3333
|
+
getEstimatedItemSize,
|
|
3334
|
+
getFixedItemSize,
|
|
3335
|
+
getItemType,
|
|
3336
|
+
numColumns,
|
|
3337
|
+
estimatedItemSize
|
|
3338
|
+
}
|
|
3339
|
+
} = state;
|
|
3340
|
+
const hasContainers = peek$(ctx, "numContainers");
|
|
3341
|
+
if (scrollLength > 0 && data.length > 0 && !hasContainers) {
|
|
3342
|
+
let averageItemSize;
|
|
3343
|
+
if (getFixedItemSize || getEstimatedItemSize) {
|
|
3344
|
+
let totalSize = 0;
|
|
3345
|
+
const num = Math.min(20, data.length);
|
|
3346
|
+
for (let i = 0; i < num; i++) {
|
|
3347
|
+
const item = data[i];
|
|
3348
|
+
if (item !== void 0) {
|
|
3349
|
+
const itemType = (_a3 = getItemType == null ? void 0 : getItemType(item, i)) != null ? _a3 : "";
|
|
3350
|
+
totalSize += (_c = (_b = getFixedItemSize == null ? void 0 : getFixedItemSize(item, i, itemType)) != null ? _b : getEstimatedItemSize == null ? void 0 : getEstimatedItemSize(item, i, itemType)) != null ? _c : estimatedItemSize;
|
|
3351
|
+
}
|
|
3352
|
+
}
|
|
3353
|
+
averageItemSize = totalSize / num;
|
|
3354
|
+
} else {
|
|
3355
|
+
averageItemSize = estimatedItemSize;
|
|
3356
|
+
}
|
|
3357
|
+
const numContainers = Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns);
|
|
3358
|
+
for (let i = 0; i < numContainers; i++) {
|
|
3359
|
+
set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
|
|
3360
|
+
set$(ctx, `containerColumn${i}`, -1);
|
|
3361
|
+
set$(ctx, `containerSpan${i}`, 1);
|
|
3362
|
+
}
|
|
3363
|
+
set$(ctx, "numContainers", numContainers);
|
|
3364
|
+
set$(ctx, "numContainersPooled", numContainers * state.props.initialContainerPoolRatio);
|
|
3365
|
+
if (!IsNewArchitecture || state.lastLayout) {
|
|
3366
|
+
if (state.initialScroll) {
|
|
3367
|
+
requestAnimationFrame(() => {
|
|
3368
|
+
calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
|
|
3369
|
+
});
|
|
3370
|
+
} else {
|
|
3371
|
+
calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
|
|
3372
|
+
}
|
|
3373
|
+
}
|
|
3374
|
+
return true;
|
|
3375
|
+
}
|
|
3376
|
+
}
|
|
3377
|
+
function getWindowSize() {
|
|
3378
|
+
const screenSize = ReactNative.Dimensions.get("window");
|
|
3379
|
+
return {
|
|
3380
|
+
height: screenSize.height,
|
|
3381
|
+
width: screenSize.width
|
|
3382
|
+
};
|
|
3383
|
+
}
|
|
3384
|
+
|
|
3385
|
+
// src/core/handleLayout.ts
|
|
3386
|
+
function handleLayout(ctx, layoutParam, setCanRender) {
|
|
3387
|
+
const state = ctx.state;
|
|
3388
|
+
const { maintainScrollAtEnd, useWindowScroll } = state.props;
|
|
3389
|
+
const scrollAxis = state.props.horizontal ? "width" : "height";
|
|
3390
|
+
const otherAxis = state.props.horizontal ? "height" : "width";
|
|
3391
|
+
let layout = layoutParam;
|
|
3392
|
+
if (useWindowScroll) {
|
|
3393
|
+
const windowScrollAxisLength = getWindowSize()[scrollAxis];
|
|
3394
|
+
layout = windowScrollAxisLength > 0 ? { ...layoutParam, [scrollAxis]: windowScrollAxisLength } : layoutParam;
|
|
3395
|
+
}
|
|
3396
|
+
const measuredLength = layout[scrollAxis];
|
|
3397
|
+
const previousLength = state.scrollLength;
|
|
3398
|
+
const scrollLength = measuredLength > 0 ? measuredLength : previousLength;
|
|
3399
|
+
const otherAxisSize = layout[otherAxis];
|
|
3400
|
+
const needsCalculate = !state.lastLayout || scrollLength > state.scrollLength || state.lastLayout.x !== layout.x || state.lastLayout.y !== layout.y;
|
|
3401
|
+
state.lastLayout = layout;
|
|
3402
|
+
const prevOtherAxisSize = state.otherAxisSize;
|
|
3403
|
+
const didChange = scrollLength !== state.scrollLength || otherAxisSize !== prevOtherAxisSize;
|
|
3404
|
+
if (didChange) {
|
|
3405
|
+
state.scrollLength = scrollLength;
|
|
3406
|
+
state.otherAxisSize = otherAxisSize;
|
|
3407
|
+
state.lastBatchingAction = Date.now();
|
|
3408
|
+
state.scrollForNextCalculateItemsInView = void 0;
|
|
3409
|
+
if (scrollLength > 0) {
|
|
3410
|
+
doInitialAllocateContainers(ctx);
|
|
3411
|
+
}
|
|
3412
|
+
if (needsCalculate) {
|
|
3413
|
+
calculateItemsInView(ctx, { doMVCP: true });
|
|
3414
|
+
}
|
|
3415
|
+
if (didChange || otherAxisSize !== prevOtherAxisSize) {
|
|
3416
|
+
set$(ctx, "scrollSize", { height: layout.height, width: layout.width });
|
|
3417
|
+
}
|
|
3418
|
+
if (maintainScrollAtEnd == null ? void 0 : maintainScrollAtEnd.onLayout) {
|
|
3419
|
+
doMaintainScrollAtEnd(ctx);
|
|
3420
|
+
}
|
|
3421
|
+
checkThresholds(ctx);
|
|
3422
|
+
if (state) {
|
|
3423
|
+
state.needsOtherAxisSize = otherAxisSize - (state.props.stylePaddingTop || 0) < 10;
|
|
3424
|
+
}
|
|
3425
|
+
if (IS_DEV && measuredLength === 0) {
|
|
3426
|
+
warnDevOnce(
|
|
3427
|
+
"height0",
|
|
3428
|
+
`List ${state.props.horizontal ? "width" : "height"} is 0. You may need to set a style or \`flex: \` for the list, because children are absolutely positioned.`
|
|
3429
|
+
);
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
setCanRender(true);
|
|
3433
|
+
}
|
|
3434
|
+
|
|
3435
|
+
// src/core/onScroll.ts
|
|
3436
|
+
var INITIAL_SCROLL_PROGRESS_EPSILON = 1;
|
|
3437
|
+
function didObserveInitialScrollProgress(newScroll, watchdog) {
|
|
3438
|
+
const previousDistance = Math.abs(watchdog.startScroll - watchdog.targetOffset);
|
|
3439
|
+
const nextDistance = Math.abs(newScroll - watchdog.targetOffset);
|
|
3440
|
+
return nextDistance <= INITIAL_SCROLL_PROGRESS_EPSILON || nextDistance + INITIAL_SCROLL_PROGRESS_EPSILON < previousDistance;
|
|
3441
|
+
}
|
|
3442
|
+
function onScroll(ctx, event) {
|
|
3443
|
+
var _a3, _b, _c, _d;
|
|
3444
|
+
const state = ctx.state;
|
|
3445
|
+
const {
|
|
3446
|
+
scrollProcessingEnabled,
|
|
3447
|
+
props: { onScroll: onScrollProp }
|
|
3448
|
+
} = state;
|
|
3449
|
+
if (scrollProcessingEnabled === false) {
|
|
3450
|
+
return;
|
|
3451
|
+
}
|
|
3452
|
+
if (((_b = (_a3 = event.nativeEvent) == null ? void 0 : _a3.contentSize) == null ? void 0 : _b.height) === 0 && ((_c = event.nativeEvent.contentSize) == null ? void 0 : _c.width) === 0) {
|
|
3453
|
+
return;
|
|
3454
|
+
}
|
|
3455
|
+
let insetChanged = false;
|
|
3456
|
+
if ((_d = event.nativeEvent) == null ? void 0 : _d.contentInset) {
|
|
3457
|
+
const { contentInset } = event.nativeEvent;
|
|
3458
|
+
const prevInset = state.nativeContentInset;
|
|
3459
|
+
if (!prevInset || prevInset.top !== contentInset.top || prevInset.bottom !== contentInset.bottom || prevInset.left !== contentInset.left || prevInset.right !== contentInset.right) {
|
|
3460
|
+
state.nativeContentInset = contentInset;
|
|
3461
|
+
insetChanged = true;
|
|
3462
|
+
}
|
|
3463
|
+
}
|
|
3464
|
+
let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
|
|
3465
|
+
if (state.scrollingTo && state.scrollingTo.offset >= newScroll) {
|
|
3466
|
+
const maxOffset = clampScrollOffset(ctx, newScroll, state.scrollingTo);
|
|
3467
|
+
if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
|
|
3468
|
+
newScroll = maxOffset;
|
|
3469
|
+
scrollTo(ctx, {
|
|
3470
|
+
forceScroll: true,
|
|
3471
|
+
isInitialScroll: true,
|
|
3472
|
+
noScrollingTo: true,
|
|
3473
|
+
offset: newScroll
|
|
3474
|
+
});
|
|
3475
|
+
return;
|
|
3476
|
+
}
|
|
3477
|
+
}
|
|
3478
|
+
state.scrollPending = newScroll;
|
|
3479
|
+
const initialNativeScrollWatchdog = state.initialNativeScrollWatchdog;
|
|
3480
|
+
const didInitialScrollProgress = !!initialNativeScrollWatchdog && didObserveInitialScrollProgress(newScroll, initialNativeScrollWatchdog);
|
|
3481
|
+
if (didInitialScrollProgress) {
|
|
3482
|
+
state.initialNativeScrollWatchdog = void 0;
|
|
3483
|
+
}
|
|
3484
|
+
updateScroll(ctx, newScroll, insetChanged);
|
|
3485
|
+
if (initialNativeScrollWatchdog && !didInitialScrollProgress) {
|
|
3486
|
+
state.hasScrolled = false;
|
|
3487
|
+
state.initialNativeScrollWatchdog = initialNativeScrollWatchdog;
|
|
3488
|
+
}
|
|
3489
|
+
if (state.scrollingTo) {
|
|
3490
|
+
checkFinishedScroll(ctx);
|
|
3491
|
+
}
|
|
3492
|
+
onScrollProp == null ? void 0 : onScrollProp(event);
|
|
3493
|
+
}
|
|
3494
|
+
|
|
3495
|
+
// src/core/ScrollAdjustHandler.ts
|
|
3496
|
+
var ScrollAdjustHandler = class {
|
|
3497
|
+
constructor(ctx) {
|
|
3498
|
+
this.appliedAdjust = 0;
|
|
3499
|
+
this.pendingAdjust = 0;
|
|
3500
|
+
this.ctx = ctx;
|
|
3501
|
+
}
|
|
3502
|
+
requestAdjust(add) {
|
|
3503
|
+
const scrollingTo = this.ctx.state.scrollingTo;
|
|
3504
|
+
if (PlatformAdjustBreaksScroll && (scrollingTo == null ? void 0 : scrollingTo.animated) && !scrollingTo.isInitialScroll) {
|
|
3505
|
+
this.pendingAdjust += add;
|
|
3506
|
+
set$(this.ctx, "scrollAdjustPending", this.pendingAdjust);
|
|
3507
|
+
} else {
|
|
3508
|
+
this.appliedAdjust += add;
|
|
3509
|
+
set$(this.ctx, "scrollAdjust", this.appliedAdjust);
|
|
3510
|
+
}
|
|
3511
|
+
if (this.ctx.state.scrollingTo) {
|
|
3512
|
+
checkFinishedScroll(this.ctx);
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
getAdjust() {
|
|
3516
|
+
return this.appliedAdjust;
|
|
3517
|
+
}
|
|
3518
|
+
commitPendingAdjust(scrollTarget) {
|
|
3519
|
+
if (PlatformAdjustBreaksScroll) {
|
|
3520
|
+
const state = this.ctx.state;
|
|
3521
|
+
const pending = this.pendingAdjust;
|
|
3522
|
+
this.pendingAdjust = 0;
|
|
3523
|
+
if (pending !== 0) {
|
|
3524
|
+
let targetScroll;
|
|
3525
|
+
if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
|
|
3526
|
+
const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
|
|
3527
|
+
targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
|
|
3528
|
+
targetScroll = clampScrollOffset(this.ctx, targetScroll, scrollTarget);
|
|
3529
|
+
} else {
|
|
3530
|
+
targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
|
|
3531
|
+
}
|
|
3532
|
+
const adjustment = targetScroll - state.scroll;
|
|
3533
|
+
if (Math.abs(adjustment) > 0.1 || Math.abs(pending) > 0.1) {
|
|
3534
|
+
this.appliedAdjust += adjustment;
|
|
3535
|
+
state.scroll = targetScroll;
|
|
3536
|
+
state.scrollForNextCalculateItemsInView = void 0;
|
|
3537
|
+
set$(this.ctx, "scrollAdjust", this.appliedAdjust);
|
|
3538
|
+
}
|
|
3539
|
+
set$(this.ctx, "scrollAdjustPending", 0);
|
|
3540
|
+
calculateItemsInView(this.ctx);
|
|
3541
|
+
}
|
|
3542
|
+
}
|
|
3543
|
+
}
|
|
3544
|
+
};
|
|
3545
|
+
|
|
3546
|
+
// src/core/updateItemSize.ts
|
|
3547
|
+
function runOrScheduleMVCPRecalculate(ctx) {
|
|
3548
|
+
const state = ctx.state;
|
|
3549
|
+
if (Platform2.OS === "web") {
|
|
3550
|
+
if (!state.mvcpAnchorLock) {
|
|
3551
|
+
if (state.queuedMVCPRecalculate !== void 0) {
|
|
3552
|
+
cancelAnimationFrame(state.queuedMVCPRecalculate);
|
|
3553
|
+
state.queuedMVCPRecalculate = void 0;
|
|
3554
|
+
}
|
|
3555
|
+
calculateItemsInView(ctx, { doMVCP: true });
|
|
3556
|
+
return;
|
|
3557
|
+
}
|
|
3558
|
+
if (state.queuedMVCPRecalculate !== void 0) {
|
|
3559
|
+
return;
|
|
3560
|
+
}
|
|
3561
|
+
state.queuedMVCPRecalculate = requestAnimationFrame(() => {
|
|
3562
|
+
state.queuedMVCPRecalculate = void 0;
|
|
3563
|
+
calculateItemsInView(ctx, { doMVCP: true });
|
|
3564
|
+
});
|
|
3565
|
+
} else {
|
|
3566
|
+
calculateItemsInView(ctx, { doMVCP: true });
|
|
3567
|
+
}
|
|
3568
|
+
}
|
|
3569
|
+
function updateItemSize(ctx, itemKey, sizeObj) {
|
|
3570
|
+
var _a3;
|
|
3571
|
+
const state = ctx.state;
|
|
3572
|
+
const {
|
|
3573
|
+
didContainersLayout,
|
|
3574
|
+
sizesKnown,
|
|
3575
|
+
props: {
|
|
3576
|
+
getFixedItemSize,
|
|
3577
|
+
getItemType,
|
|
3578
|
+
horizontal,
|
|
3579
|
+
suggestEstimatedItemSize,
|
|
3580
|
+
onItemSizeChanged,
|
|
3581
|
+
data,
|
|
3582
|
+
maintainScrollAtEnd
|
|
3583
|
+
}
|
|
3584
|
+
} = state;
|
|
3585
|
+
if (!data) return;
|
|
3586
|
+
const index = state.indexByKey.get(itemKey);
|
|
3587
|
+
if (getFixedItemSize) {
|
|
3588
|
+
if (index === void 0) {
|
|
3589
|
+
return;
|
|
3590
|
+
}
|
|
3591
|
+
const itemData = state.props.data[index];
|
|
3592
|
+
if (itemData === void 0) {
|
|
3593
|
+
return;
|
|
3594
|
+
}
|
|
3595
|
+
const type = getItemType ? (_a3 = getItemType(itemData, index)) != null ? _a3 : "" : "";
|
|
3596
|
+
const size2 = getFixedItemSize(itemData, index, type);
|
|
3597
|
+
if (size2 !== void 0 && size2 === sizesKnown.get(itemKey)) {
|
|
3598
|
+
return;
|
|
3599
|
+
}
|
|
3600
|
+
}
|
|
3601
|
+
let needsRecalculate = !didContainersLayout;
|
|
3602
|
+
let shouldMaintainScrollAtEnd = false;
|
|
3603
|
+
let minIndexSizeChanged;
|
|
3604
|
+
let maxOtherAxisSize = peek$(ctx, "otherAxisSize") || 0;
|
|
3605
|
+
const prevSizeKnown = state.sizesKnown.get(itemKey);
|
|
3606
|
+
const diff = updateOneItemSize(ctx, itemKey, sizeObj);
|
|
3607
|
+
const size = roundSize(horizontal ? sizeObj.width : sizeObj.height);
|
|
3608
|
+
if (diff !== 0) {
|
|
3609
|
+
minIndexSizeChanged = minIndexSizeChanged !== void 0 ? Math.min(minIndexSizeChanged, index) : index;
|
|
3610
|
+
const { startBuffered, endBuffered } = state;
|
|
3611
|
+
needsRecalculate || (needsRecalculate = index >= startBuffered && index <= endBuffered);
|
|
3612
|
+
if (!needsRecalculate && state.containerItemKeys.has(itemKey)) {
|
|
3613
|
+
needsRecalculate = true;
|
|
3614
|
+
}
|
|
3615
|
+
if (state.needsOtherAxisSize) {
|
|
3616
|
+
const otherAxisSize = horizontal ? sizeObj.height : sizeObj.width;
|
|
3617
|
+
maxOtherAxisSize = Math.max(maxOtherAxisSize, otherAxisSize);
|
|
3618
|
+
}
|
|
3619
|
+
if (prevSizeKnown !== void 0 && Math.abs(prevSizeKnown - size) > 5) {
|
|
3620
|
+
shouldMaintainScrollAtEnd = true;
|
|
3621
|
+
}
|
|
3622
|
+
onItemSizeChanged == null ? void 0 : onItemSizeChanged({
|
|
3623
|
+
index,
|
|
3624
|
+
itemData: state.props.data[index],
|
|
3625
|
+
itemKey,
|
|
3626
|
+
previous: size - diff,
|
|
3627
|
+
size
|
|
3628
|
+
});
|
|
3629
|
+
}
|
|
3630
|
+
if (minIndexSizeChanged !== void 0) {
|
|
3631
|
+
state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, minIndexSizeChanged) : minIndexSizeChanged;
|
|
3632
|
+
}
|
|
3633
|
+
if (IS_DEV && suggestEstimatedItemSize && minIndexSizeChanged !== void 0) {
|
|
3634
|
+
if (state.timeoutSizeMessage) clearTimeout(state.timeoutSizeMessage);
|
|
3635
|
+
state.timeoutSizeMessage = setTimeout(() => {
|
|
3636
|
+
var _a4;
|
|
3637
|
+
state.timeoutSizeMessage = void 0;
|
|
3638
|
+
const num = state.sizesKnown.size;
|
|
3639
|
+
const avg = (_a4 = state.averageSizes[""]) == null ? void 0 : _a4.avg;
|
|
3640
|
+
console.warn(
|
|
3641
|
+
`[legend-list] Based on the ${num} items rendered so far, the optimal estimated size is ${avg}.`
|
|
3642
|
+
);
|
|
3643
|
+
}, 1e3);
|
|
3644
|
+
}
|
|
3645
|
+
const cur = peek$(ctx, "otherAxisSize");
|
|
3646
|
+
if (!cur || maxOtherAxisSize > cur) {
|
|
3647
|
+
set$(ctx, "otherAxisSize", maxOtherAxisSize);
|
|
3648
|
+
}
|
|
3649
|
+
if (didContainersLayout || checkAllSizesKnown(state)) {
|
|
3650
|
+
if (needsRecalculate) {
|
|
3651
|
+
state.scrollForNextCalculateItemsInView = void 0;
|
|
3652
|
+
runOrScheduleMVCPRecalculate(ctx);
|
|
3653
|
+
}
|
|
3654
|
+
if (shouldMaintainScrollAtEnd) {
|
|
3655
|
+
if (maintainScrollAtEnd == null ? void 0 : maintainScrollAtEnd.onItemLayout) {
|
|
3656
|
+
doMaintainScrollAtEnd(ctx);
|
|
3657
|
+
}
|
|
3658
|
+
}
|
|
3659
|
+
}
|
|
3660
|
+
}
|
|
3661
|
+
function updateOneItemSize(ctx, itemKey, sizeObj) {
|
|
3662
|
+
var _a3;
|
|
3663
|
+
const state = ctx.state;
|
|
3664
|
+
const {
|
|
3665
|
+
indexByKey,
|
|
3666
|
+
sizesKnown,
|
|
3667
|
+
averageSizes,
|
|
3668
|
+
props: { data, horizontal, getEstimatedItemSize, getItemType, getFixedItemSize }
|
|
3669
|
+
} = state;
|
|
3670
|
+
if (!data) return 0;
|
|
3671
|
+
const index = indexByKey.get(itemKey);
|
|
3672
|
+
const prevSize = getItemSize(ctx, itemKey, index, data[index]);
|
|
3673
|
+
const rawSize = horizontal ? sizeObj.width : sizeObj.height;
|
|
3674
|
+
const size = Platform2.OS === "web" ? Math.round(rawSize) : roundSize(rawSize);
|
|
3675
|
+
const prevSizeKnown = sizesKnown.get(itemKey);
|
|
3676
|
+
sizesKnown.set(itemKey, size);
|
|
3677
|
+
if (!getEstimatedItemSize && !getFixedItemSize && size > 0) {
|
|
3678
|
+
const itemType = getItemType ? (_a3 = getItemType(data[index], index)) != null ? _a3 : "" : "";
|
|
3679
|
+
let averages = averageSizes[itemType];
|
|
3680
|
+
if (!averages) {
|
|
3681
|
+
averages = averageSizes[itemType] = { avg: 0, num: 0 };
|
|
3682
|
+
}
|
|
3683
|
+
if (averages.num === 0) {
|
|
3684
|
+
averages.avg = size;
|
|
3685
|
+
averages.num++;
|
|
3686
|
+
} else if (prevSizeKnown !== void 0 && prevSizeKnown > 0) {
|
|
3687
|
+
averages.avg += (size - prevSizeKnown) / averages.num;
|
|
3688
|
+
} else {
|
|
3689
|
+
averages.avg = (averages.avg * averages.num + size) / (averages.num + 1);
|
|
3690
|
+
averages.num++;
|
|
3691
|
+
}
|
|
3692
|
+
}
|
|
3693
|
+
if (!prevSize || Math.abs(prevSize - size) > 0.1) {
|
|
3694
|
+
setSize(ctx, itemKey, size);
|
|
3695
|
+
return size - prevSize;
|
|
3696
|
+
}
|
|
3697
|
+
return 0;
|
|
3698
|
+
}
|
|
3699
|
+
function useWrapIfItem(fn) {
|
|
3700
|
+
return React2.useMemo(
|
|
3701
|
+
() => fn ? (arg1, arg2, arg3) => arg1 !== void 0 && arg2 !== void 0 ? fn(arg1, arg2, arg3) : void 0 : void 0,
|
|
3702
|
+
[fn]
|
|
3703
|
+
);
|
|
3704
|
+
}
|
|
3705
|
+
var useCombinedRef = (...refs) => {
|
|
3706
|
+
const callback = React2.useCallback((element) => {
|
|
3707
|
+
for (const ref of refs) {
|
|
3708
|
+
if (!ref) {
|
|
3709
|
+
continue;
|
|
3710
|
+
}
|
|
3711
|
+
if (isFunction(ref)) {
|
|
3712
|
+
ref(element);
|
|
3713
|
+
} else {
|
|
3714
|
+
ref.current = element;
|
|
3715
|
+
}
|
|
3716
|
+
}
|
|
3717
|
+
}, refs);
|
|
3718
|
+
return callback;
|
|
3719
|
+
};
|
|
3720
|
+
var StyleSheet = ReactNative.StyleSheet;
|
|
3721
|
+
function useStickyScrollHandler(stickyHeaderIndices, horizontal, ctx, onScroll2) {
|
|
3722
|
+
const shouldUseRnAnimatedEngine = !ctx.state.props.stickyPositionComponentInternal;
|
|
3723
|
+
return React2.useMemo(() => {
|
|
3724
|
+
if ((stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.length) && shouldUseRnAnimatedEngine) {
|
|
3725
|
+
const { animatedScrollY } = ctx;
|
|
3726
|
+
return ReactNative.Animated.event(
|
|
3727
|
+
[
|
|
3728
|
+
{
|
|
3729
|
+
nativeEvent: {
|
|
3730
|
+
contentOffset: { [horizontal ? "x" : "y"]: animatedScrollY }
|
|
3731
|
+
}
|
|
3732
|
+
}
|
|
3733
|
+
],
|
|
3734
|
+
{
|
|
3735
|
+
listener: onScroll2,
|
|
3736
|
+
useNativeDriver: true
|
|
3737
|
+
}
|
|
3738
|
+
);
|
|
3739
|
+
}
|
|
3740
|
+
return onScroll2;
|
|
3741
|
+
}, [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(","), horizontal, shouldUseRnAnimatedEngine]);
|
|
3742
|
+
}
|
|
3743
|
+
|
|
3744
|
+
// src/utils/createColumnWrapperStyle.ts
|
|
3745
|
+
function createColumnWrapperStyle(contentContainerStyle) {
|
|
3746
|
+
const { gap, columnGap, rowGap } = contentContainerStyle;
|
|
3747
|
+
if (gap || columnGap || rowGap) {
|
|
3748
|
+
contentContainerStyle.gap = void 0;
|
|
3749
|
+
contentContainerStyle.columnGap = void 0;
|
|
3750
|
+
contentContainerStyle.rowGap = void 0;
|
|
3751
|
+
return {
|
|
3752
|
+
columnGap,
|
|
3753
|
+
gap,
|
|
3754
|
+
rowGap
|
|
3755
|
+
};
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
|
|
3759
|
+
// src/utils/hasActiveMVCPAnchorLock.ts
|
|
3760
|
+
function hasActiveMVCPAnchorLock(state) {
|
|
3761
|
+
const lock = state.mvcpAnchorLock;
|
|
3762
|
+
if (!lock) {
|
|
3763
|
+
return false;
|
|
3764
|
+
}
|
|
3765
|
+
if (Date.now() > lock.expiresAt) {
|
|
3766
|
+
state.mvcpAnchorLock = void 0;
|
|
3767
|
+
return false;
|
|
3768
|
+
}
|
|
3769
|
+
return true;
|
|
3770
|
+
}
|
|
3771
|
+
|
|
3772
|
+
// src/utils/createImperativeHandle.ts
|
|
3773
|
+
function createImperativeHandle(ctx) {
|
|
3774
|
+
const state = ctx.state;
|
|
3775
|
+
const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
|
|
3776
|
+
const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
|
|
3777
|
+
let imperativeScrollToken = 0;
|
|
3778
|
+
const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.queuedMVCPRecalculate !== void 0 || state.ignoreScrollFromMVCP !== void 0 || hasActiveMVCPAnchorLock(state);
|
|
3779
|
+
const runWhenSettled = (token, run) => {
|
|
3780
|
+
const startedAt = Date.now();
|
|
3781
|
+
let stableFrames = 0;
|
|
3782
|
+
const check = () => {
|
|
3783
|
+
if (token !== imperativeScrollToken) {
|
|
3784
|
+
return;
|
|
3785
|
+
}
|
|
3786
|
+
if (isSettlingAfterDataChange()) {
|
|
3787
|
+
stableFrames = 0;
|
|
3788
|
+
} else {
|
|
3789
|
+
stableFrames += 1;
|
|
3790
|
+
}
|
|
3791
|
+
const timedOut = Date.now() - startedAt >= IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS;
|
|
3792
|
+
if (stableFrames >= IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES || timedOut) {
|
|
3793
|
+
run();
|
|
3794
|
+
return;
|
|
3795
|
+
}
|
|
3796
|
+
requestAnimationFrame(check);
|
|
3797
|
+
};
|
|
3798
|
+
requestAnimationFrame(check);
|
|
3799
|
+
};
|
|
3800
|
+
const runScrollWithPromise = (run) => new Promise((resolve) => {
|
|
3801
|
+
var _a3;
|
|
3802
|
+
const token = ++imperativeScrollToken;
|
|
3803
|
+
(_a3 = state.pendingScrollResolve) == null ? void 0 : _a3.call(state);
|
|
3804
|
+
state.pendingScrollResolve = resolve;
|
|
3805
|
+
const runNow = () => {
|
|
3806
|
+
if (token !== imperativeScrollToken) {
|
|
3807
|
+
return;
|
|
3808
|
+
}
|
|
3809
|
+
const didStartScroll = run();
|
|
3810
|
+
if (!didStartScroll || !state.scrollingTo) {
|
|
3811
|
+
if (state.pendingScrollResolve === resolve) {
|
|
3812
|
+
state.pendingScrollResolve = void 0;
|
|
3813
|
+
}
|
|
3814
|
+
resolve();
|
|
3815
|
+
}
|
|
3816
|
+
};
|
|
3817
|
+
if (isSettlingAfterDataChange()) {
|
|
3818
|
+
runWhenSettled(token, runNow);
|
|
3819
|
+
return;
|
|
3820
|
+
}
|
|
3821
|
+
runNow();
|
|
3822
|
+
});
|
|
3823
|
+
const scrollIndexIntoView = (options) => {
|
|
3824
|
+
if (state) {
|
|
3825
|
+
const { index, ...rest } = options;
|
|
3826
|
+
const { startNoBuffer, endNoBuffer } = state;
|
|
3827
|
+
if (index < startNoBuffer || index > endNoBuffer) {
|
|
3828
|
+
const viewPosition = index < startNoBuffer ? 0 : 1;
|
|
3829
|
+
scrollToIndex(ctx, {
|
|
3830
|
+
...rest,
|
|
3831
|
+
index,
|
|
3832
|
+
viewPosition
|
|
3833
|
+
});
|
|
3834
|
+
return true;
|
|
3835
|
+
}
|
|
3836
|
+
}
|
|
3837
|
+
return false;
|
|
3838
|
+
};
|
|
3839
|
+
const refScroller = state.refScroller;
|
|
3840
|
+
const clearCaches = (options) => {
|
|
3841
|
+
var _a3, _b;
|
|
3842
|
+
const mode = (_a3 = options == null ? void 0 : options.mode) != null ? _a3 : "sizes";
|
|
3843
|
+
state.sizes.clear();
|
|
3844
|
+
state.sizesKnown.clear();
|
|
3845
|
+
for (const key in state.averageSizes) {
|
|
3846
|
+
delete state.averageSizes[key];
|
|
3847
|
+
}
|
|
3848
|
+
state.minIndexSizeChanged = 0;
|
|
3849
|
+
state.scrollForNextCalculateItemsInView = void 0;
|
|
3850
|
+
state.pendingTotalSize = void 0;
|
|
3851
|
+
state.totalSize = 0;
|
|
3852
|
+
set$(ctx, "totalSize", 0);
|
|
3853
|
+
if (mode === "full") {
|
|
3854
|
+
state.indexByKey.clear();
|
|
3855
|
+
state.idCache.length = 0;
|
|
3856
|
+
state.positions.length = 0;
|
|
3857
|
+
state.columns.length = 0;
|
|
3858
|
+
state.columnSpans.length = 0;
|
|
3859
|
+
}
|
|
3860
|
+
(_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
|
|
3861
|
+
};
|
|
3862
|
+
return {
|
|
3863
|
+
clearCaches,
|
|
3864
|
+
flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
|
|
3865
|
+
getNativeScrollRef: () => refScroller.current,
|
|
3866
|
+
getScrollableNode: () => refScroller.current.getScrollableNode(),
|
|
3867
|
+
getScrollResponder: () => refScroller.current.getScrollResponder(),
|
|
3868
|
+
getState: () => ({
|
|
3869
|
+
activeStickyIndex: peek$(ctx, "activeStickyIndex"),
|
|
3870
|
+
contentLength: getContentSize(ctx),
|
|
3871
|
+
data: state.props.data,
|
|
3872
|
+
elementAtIndex: (index) => {
|
|
3873
|
+
var _a3;
|
|
3874
|
+
return (_a3 = ctx.viewRefs.get(findContainerId(ctx, getId(state, index)))) == null ? void 0 : _a3.current;
|
|
3875
|
+
},
|
|
3876
|
+
end: state.endNoBuffer,
|
|
3877
|
+
endBuffered: state.endBuffered,
|
|
3878
|
+
isAtEnd: state.isAtEnd,
|
|
3879
|
+
isAtStart: state.isAtStart,
|
|
3880
|
+
isEndReached: state.isEndReached,
|
|
3881
|
+
isStartReached: state.isStartReached,
|
|
3882
|
+
listen: (signalName, cb) => listen$(ctx, signalName, cb),
|
|
3883
|
+
listenToPosition: (key, cb) => listenPosition$(ctx, key, cb),
|
|
3884
|
+
positionAtIndex: (index) => state.positions[index],
|
|
3885
|
+
positionByKey: (key) => {
|
|
3886
|
+
const index = state.indexByKey.get(key);
|
|
3887
|
+
return index === void 0 ? void 0 : state.positions[index];
|
|
3888
|
+
},
|
|
3889
|
+
scroll: state.scroll,
|
|
3890
|
+
scrollLength: state.scrollLength,
|
|
3891
|
+
scrollVelocity: getScrollVelocity(state),
|
|
3892
|
+
sizeAtIndex: (index) => state.sizesKnown.get(getId(state, index)),
|
|
3893
|
+
sizes: state.sizesKnown,
|
|
3894
|
+
start: state.startNoBuffer,
|
|
3895
|
+
startBuffered: state.startBuffered
|
|
3896
|
+
}),
|
|
3897
|
+
reportContentInset: (inset) => {
|
|
3898
|
+
state.contentInsetOverride = inset != null ? inset : void 0;
|
|
3899
|
+
updateScroll(ctx, state.scroll, true);
|
|
3900
|
+
},
|
|
3901
|
+
scrollIndexIntoView: (options) => runScrollWithPromise(() => scrollIndexIntoView(options)),
|
|
3902
|
+
scrollItemIntoView: ({ item, ...props }) => runScrollWithPromise(() => {
|
|
3903
|
+
const data = state.props.data;
|
|
3904
|
+
const index = data.indexOf(item);
|
|
3905
|
+
if (index !== -1) {
|
|
3906
|
+
scrollIndexIntoView({ index, ...props });
|
|
3907
|
+
return true;
|
|
3908
|
+
}
|
|
3909
|
+
return false;
|
|
3910
|
+
}),
|
|
3911
|
+
scrollToEnd: (options) => runScrollWithPromise(() => {
|
|
3912
|
+
const data = state.props.data;
|
|
3913
|
+
const stylePaddingBottom = state.props.stylePaddingBottom;
|
|
3914
|
+
const index = data.length - 1;
|
|
3915
|
+
if (index !== -1) {
|
|
3916
|
+
const paddingBottom = stylePaddingBottom || 0;
|
|
3917
|
+
const footerSize = peek$(ctx, "footerSize") || 0;
|
|
3918
|
+
scrollToIndex(ctx, {
|
|
3919
|
+
...options,
|
|
3920
|
+
index,
|
|
3921
|
+
viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
|
|
3922
|
+
viewPosition: 1
|
|
3923
|
+
});
|
|
3924
|
+
return true;
|
|
3925
|
+
}
|
|
3926
|
+
return false;
|
|
3927
|
+
}),
|
|
3928
|
+
scrollToIndex: (params) => runScrollWithPromise(() => {
|
|
3929
|
+
scrollToIndex(ctx, params);
|
|
3930
|
+
return true;
|
|
3931
|
+
}),
|
|
3932
|
+
scrollToItem: ({ item, ...props }) => runScrollWithPromise(() => {
|
|
3933
|
+
const data = state.props.data;
|
|
3934
|
+
const index = data.indexOf(item);
|
|
3935
|
+
if (index !== -1) {
|
|
3936
|
+
scrollToIndex(ctx, { index, ...props });
|
|
3937
|
+
return true;
|
|
3938
|
+
}
|
|
3939
|
+
return false;
|
|
3940
|
+
}),
|
|
3941
|
+
scrollToOffset: (params) => runScrollWithPromise(() => {
|
|
3942
|
+
scrollTo(ctx, params);
|
|
3943
|
+
return true;
|
|
3944
|
+
}),
|
|
3945
|
+
setScrollProcessingEnabled: (enabled) => {
|
|
3946
|
+
state.scrollProcessingEnabled = enabled;
|
|
3947
|
+
},
|
|
3948
|
+
setVisibleContentAnchorOffset: (value) => {
|
|
3949
|
+
const val = isFunction(value) ? value(peek$(ctx, "scrollAdjustUserOffset") || 0) : value;
|
|
3950
|
+
set$(ctx, "scrollAdjustUserOffset", val);
|
|
3951
|
+
}
|
|
3952
|
+
};
|
|
3953
|
+
}
|
|
3954
|
+
|
|
3955
|
+
// src/utils/getAlwaysRenderIndices.ts
|
|
3956
|
+
var sortAsc = (a, b) => a - b;
|
|
3957
|
+
var toCount = (value) => typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0;
|
|
3958
|
+
var addIndex = (result, dataLength, index) => {
|
|
3959
|
+
if (index >= 0 && index < dataLength) {
|
|
3960
|
+
result.add(index);
|
|
3961
|
+
}
|
|
3962
|
+
};
|
|
3963
|
+
function getAlwaysRenderIndices(config, data, keyExtractor) {
|
|
3964
|
+
var _a3, _b;
|
|
3965
|
+
if (!config || data.length === 0) {
|
|
3966
|
+
return [];
|
|
3967
|
+
}
|
|
3968
|
+
const result = /* @__PURE__ */ new Set();
|
|
3969
|
+
const dataLength = data.length;
|
|
3970
|
+
const topCount = toCount(config.top);
|
|
3971
|
+
if (topCount > 0) {
|
|
3972
|
+
for (let i = 0; i < Math.min(topCount, dataLength); i++) {
|
|
3973
|
+
addIndex(result, dataLength, i);
|
|
3974
|
+
}
|
|
3975
|
+
}
|
|
3976
|
+
const bottomCount = toCount(config.bottom);
|
|
3977
|
+
if (bottomCount > 0) {
|
|
3978
|
+
for (let i = Math.max(0, dataLength - bottomCount); i < dataLength; i++) {
|
|
3979
|
+
addIndex(result, dataLength, i);
|
|
3980
|
+
}
|
|
3981
|
+
}
|
|
3982
|
+
if ((_a3 = config.indices) == null ? void 0 : _a3.length) {
|
|
3983
|
+
for (const index of config.indices) {
|
|
3984
|
+
if (!Number.isFinite(index)) continue;
|
|
3985
|
+
addIndex(result, dataLength, Math.floor(index));
|
|
3986
|
+
}
|
|
3987
|
+
}
|
|
3988
|
+
if ((_b = config.keys) == null ? void 0 : _b.length) {
|
|
3989
|
+
const keys = new Set(config.keys);
|
|
3990
|
+
for (let i = 0; i < dataLength && keys.size > 0; i++) {
|
|
3991
|
+
const key = keyExtractor(data[i], i);
|
|
3992
|
+
if (keys.has(key)) {
|
|
3993
|
+
addIndex(result, dataLength, i);
|
|
3994
|
+
keys.delete(key);
|
|
3995
|
+
}
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3998
|
+
const indices = Array.from(result);
|
|
3999
|
+
indices.sort(sortAsc);
|
|
4000
|
+
return indices;
|
|
4001
|
+
}
|
|
4002
|
+
function getRenderedItem(ctx, key) {
|
|
4003
|
+
var _a3;
|
|
4004
|
+
const state = ctx.state;
|
|
4005
|
+
if (!state) {
|
|
4006
|
+
return null;
|
|
4007
|
+
}
|
|
4008
|
+
const {
|
|
4009
|
+
indexByKey,
|
|
4010
|
+
props: { data, getItemType, renderItem }
|
|
4011
|
+
} = state;
|
|
4012
|
+
const index = indexByKey.get(key);
|
|
4013
|
+
if (index === void 0) {
|
|
4014
|
+
return null;
|
|
4015
|
+
}
|
|
4016
|
+
let renderedItem = null;
|
|
4017
|
+
const extraData = peek$(ctx, "extraData");
|
|
4018
|
+
const item = data[index];
|
|
4019
|
+
if (renderItem && !isNullOrUndefined(item)) {
|
|
4020
|
+
const itemProps = {
|
|
4021
|
+
data,
|
|
4022
|
+
extraData,
|
|
4023
|
+
index,
|
|
4024
|
+
item,
|
|
4025
|
+
type: getItemType ? (_a3 = getItemType(item, index)) != null ? _a3 : "" : ""
|
|
4026
|
+
};
|
|
4027
|
+
renderedItem = isFunction(renderItem) ? renderItem(itemProps) : React2__namespace.default.createElement(renderItem, itemProps);
|
|
4028
|
+
}
|
|
4029
|
+
return { index, item: data[index], renderedItem };
|
|
4030
|
+
}
|
|
4031
|
+
|
|
4032
|
+
// src/utils/normalizeMaintainScrollAtEnd.ts
|
|
4033
|
+
function normalizeMaintainScrollAtEndOn(on, hasExplicitOn) {
|
|
4034
|
+
var _a3, _b, _c;
|
|
4035
|
+
return {
|
|
4036
|
+
animated: false,
|
|
4037
|
+
onDataChange: hasExplicitOn ? (_a3 = on == null ? void 0 : on.dataChange) != null ? _a3 : false : true,
|
|
4038
|
+
onItemLayout: hasExplicitOn ? (_b = on == null ? void 0 : on.itemLayout) != null ? _b : false : true,
|
|
4039
|
+
onLayout: hasExplicitOn ? (_c = on == null ? void 0 : on.layout) != null ? _c : false : true
|
|
4040
|
+
};
|
|
4041
|
+
}
|
|
4042
|
+
function normalizeMaintainScrollAtEnd(value) {
|
|
4043
|
+
var _a3;
|
|
4044
|
+
if (!value) {
|
|
4045
|
+
return void 0;
|
|
4046
|
+
}
|
|
4047
|
+
if (value === true) {
|
|
4048
|
+
return {
|
|
4049
|
+
...normalizeMaintainScrollAtEndOn(void 0, false),
|
|
4050
|
+
animated: false
|
|
4051
|
+
};
|
|
4052
|
+
}
|
|
4053
|
+
const normalizedTriggers = normalizeMaintainScrollAtEndOn(value.on, "on" in value);
|
|
4054
|
+
return {
|
|
4055
|
+
...normalizedTriggers,
|
|
4056
|
+
animated: (_a3 = value.animated) != null ? _a3 : false
|
|
4057
|
+
};
|
|
4058
|
+
}
|
|
4059
|
+
|
|
4060
|
+
// src/utils/normalizeMaintainVisibleContentPosition.ts
|
|
4061
|
+
function normalizeMaintainVisibleContentPosition(value) {
|
|
4062
|
+
var _a3, _b;
|
|
4063
|
+
if (value === true) {
|
|
4064
|
+
return { data: true, size: true };
|
|
4065
|
+
}
|
|
4066
|
+
if (value && typeof value === "object") {
|
|
4067
|
+
return {
|
|
4068
|
+
data: (_a3 = value.data) != null ? _a3 : false,
|
|
4069
|
+
shouldRestorePosition: value.shouldRestorePosition,
|
|
4070
|
+
size: (_b = value.size) != null ? _b : true
|
|
4071
|
+
};
|
|
4072
|
+
}
|
|
4073
|
+
if (value === false) {
|
|
4074
|
+
return { data: false, size: false };
|
|
4075
|
+
}
|
|
4076
|
+
return { data: false, size: true };
|
|
4077
|
+
}
|
|
4078
|
+
|
|
4079
|
+
// src/utils/setPaddingTop.ts
|
|
4080
|
+
function setPaddingTop(ctx, { stylePaddingTop }) {
|
|
4081
|
+
const state = ctx.state;
|
|
4082
|
+
if (stylePaddingTop !== void 0) {
|
|
4083
|
+
const prevStylePaddingTop = peek$(ctx, "stylePaddingTop") || 0;
|
|
4084
|
+
if (stylePaddingTop < prevStylePaddingTop) {
|
|
4085
|
+
let prevTotalSize = peek$(ctx, "totalSize") || 0;
|
|
4086
|
+
set$(ctx, "totalSize", prevTotalSize + prevStylePaddingTop);
|
|
4087
|
+
state.timeoutSetPaddingTop = setTimeout(() => {
|
|
4088
|
+
prevTotalSize = peek$(ctx, "totalSize") || 0;
|
|
4089
|
+
set$(ctx, "totalSize", prevTotalSize - prevStylePaddingTop);
|
|
4090
|
+
}, 16);
|
|
4091
|
+
}
|
|
4092
|
+
set$(ctx, "stylePaddingTop", stylePaddingTop);
|
|
4093
|
+
}
|
|
4094
|
+
}
|
|
4095
|
+
function useThrottleDebounce(mode) {
|
|
4096
|
+
const timeoutRef = React2.useRef(null);
|
|
4097
|
+
const lastCallTimeRef = React2.useRef(0);
|
|
4098
|
+
const lastArgsRef = React2.useRef(null);
|
|
4099
|
+
const clearTimeoutRef = () => {
|
|
4100
|
+
if (timeoutRef.current) {
|
|
4101
|
+
clearTimeout(timeoutRef.current);
|
|
4102
|
+
timeoutRef.current = null;
|
|
4103
|
+
}
|
|
4104
|
+
};
|
|
4105
|
+
const execute = React2.useCallback(
|
|
4106
|
+
(callback, delay, ...args) => {
|
|
4107
|
+
{
|
|
4108
|
+
const now = Date.now();
|
|
4109
|
+
lastArgsRef.current = args;
|
|
4110
|
+
if (now - lastCallTimeRef.current >= delay) {
|
|
4111
|
+
lastCallTimeRef.current = now;
|
|
4112
|
+
callback(...args);
|
|
4113
|
+
clearTimeoutRef();
|
|
4114
|
+
} else {
|
|
4115
|
+
clearTimeoutRef();
|
|
4116
|
+
timeoutRef.current = setTimeout(
|
|
4117
|
+
() => {
|
|
4118
|
+
if (lastArgsRef.current) {
|
|
4119
|
+
lastCallTimeRef.current = Date.now();
|
|
4120
|
+
callback(...lastArgsRef.current);
|
|
4121
|
+
timeoutRef.current = null;
|
|
4122
|
+
lastArgsRef.current = null;
|
|
4123
|
+
}
|
|
4124
|
+
},
|
|
4125
|
+
delay - (now - lastCallTimeRef.current)
|
|
4126
|
+
);
|
|
4127
|
+
}
|
|
4128
|
+
}
|
|
4129
|
+
},
|
|
4130
|
+
[mode]
|
|
4131
|
+
);
|
|
4132
|
+
return execute;
|
|
4133
|
+
}
|
|
4134
|
+
|
|
4135
|
+
// src/utils/throttledOnScroll.ts
|
|
4136
|
+
function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
|
|
4137
|
+
const throttle = useThrottleDebounce("throttle");
|
|
4138
|
+
return (event) => throttle(originalHandler, scrollEventThrottle, { nativeEvent: event.nativeEvent });
|
|
4139
|
+
}
|
|
4140
|
+
|
|
4141
|
+
// src/components/LegendList.tsx
|
|
4142
|
+
var LegendList = typedMemo2(
|
|
4143
|
+
// biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
|
|
4144
|
+
typedForwardRef(function LegendList2(props, forwardedRef) {
|
|
4145
|
+
const { children, data: dataProp, renderItem: renderItemProp, ...restProps } = props;
|
|
4146
|
+
const isChildrenMode = children !== void 0 && dataProp === void 0;
|
|
4147
|
+
const processedProps = isChildrenMode ? {
|
|
4148
|
+
...restProps,
|
|
4149
|
+
childrenMode: true,
|
|
4150
|
+
data: (isArray(children) ? children : React2__namespace.Children.toArray(children)).flat(1),
|
|
4151
|
+
renderItem: ({ item }) => item
|
|
4152
|
+
} : {
|
|
4153
|
+
...restProps,
|
|
4154
|
+
data: dataProp || [],
|
|
4155
|
+
renderItem: renderItemProp
|
|
4156
|
+
};
|
|
4157
|
+
return /* @__PURE__ */ React2__namespace.createElement(StateProvider, null, /* @__PURE__ */ React2__namespace.createElement(LegendListInner, { ...processedProps, ref: forwardedRef }));
|
|
4158
|
+
})
|
|
4159
|
+
);
|
|
4160
|
+
var LegendListInner = typedForwardRef(function LegendListInner2(props, forwardedRef) {
|
|
4161
|
+
var _a3, _b, _c, _d, _e, _f, _g, _h;
|
|
4162
|
+
const {
|
|
4163
|
+
alignItemsAtEnd = false,
|
|
4164
|
+
alwaysRender,
|
|
4165
|
+
columnWrapperStyle,
|
|
4166
|
+
contentContainerStyle: contentContainerStyleProp,
|
|
4167
|
+
contentInset,
|
|
4168
|
+
data: dataProp = [],
|
|
4169
|
+
dataVersion,
|
|
4170
|
+
drawDistance = 250,
|
|
4171
|
+
estimatedItemSize = 100,
|
|
4172
|
+
estimatedListSize,
|
|
4173
|
+
extraData,
|
|
4174
|
+
getEstimatedItemSize,
|
|
4175
|
+
getFixedItemSize,
|
|
4176
|
+
getItemType,
|
|
4177
|
+
horizontal,
|
|
4178
|
+
initialContainerPoolRatio = 2,
|
|
4179
|
+
initialScrollAtEnd = false,
|
|
4180
|
+
initialScrollIndex: initialScrollIndexProp,
|
|
4181
|
+
initialScrollOffset: initialScrollOffsetProp,
|
|
4182
|
+
itemsAreEqual,
|
|
4183
|
+
keyExtractor: keyExtractorProp,
|
|
4184
|
+
ListEmptyComponent,
|
|
4185
|
+
ListHeaderComponent,
|
|
4186
|
+
maintainScrollAtEnd = false,
|
|
4187
|
+
maintainScrollAtEndThreshold = 0.1,
|
|
4188
|
+
maintainVisibleContentPosition: maintainVisibleContentPositionProp,
|
|
4189
|
+
numColumns: numColumnsProp = 1,
|
|
4190
|
+
overrideItemLayout,
|
|
4191
|
+
onEndReached,
|
|
4192
|
+
onEndReachedThreshold = 0.5,
|
|
4193
|
+
onItemSizeChanged,
|
|
4194
|
+
onMetricsChange,
|
|
4195
|
+
onLayout: onLayoutProp,
|
|
4196
|
+
onLoad,
|
|
4197
|
+
onMomentumScrollEnd,
|
|
4198
|
+
onRefresh,
|
|
4199
|
+
onScroll: onScrollProp,
|
|
4200
|
+
onStartReached,
|
|
4201
|
+
onStartReachedThreshold = 0.5,
|
|
4202
|
+
onStickyHeaderChange,
|
|
4203
|
+
onViewableItemsChanged,
|
|
4204
|
+
progressViewOffset,
|
|
4205
|
+
recycleItems = false,
|
|
4206
|
+
refreshControl,
|
|
4207
|
+
refreshing,
|
|
4208
|
+
refScrollView,
|
|
4209
|
+
renderScrollComponent,
|
|
4210
|
+
renderItem,
|
|
4211
|
+
scrollEventThrottle,
|
|
4212
|
+
snapToIndices,
|
|
4213
|
+
stickyHeaderIndices: stickyHeaderIndicesProp,
|
|
4214
|
+
stickyIndices: stickyIndicesDeprecated,
|
|
4215
|
+
// TODOV3: Remove from v3 release
|
|
4216
|
+
style: styleProp,
|
|
4217
|
+
suggestEstimatedItemSize,
|
|
4218
|
+
useWindowScroll = false,
|
|
4219
|
+
viewabilityConfig,
|
|
4220
|
+
viewabilityConfigCallbackPairs,
|
|
4221
|
+
waitForInitialLayout = true,
|
|
4222
|
+
...rest
|
|
4223
|
+
} = props;
|
|
4224
|
+
const animatedPropsInternal = props.animatedPropsInternal;
|
|
4225
|
+
const positionComponentInternal = props.positionComponentInternal;
|
|
4226
|
+
const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
|
|
4227
|
+
const {
|
|
4228
|
+
childrenMode,
|
|
4229
|
+
positionComponentInternal: _positionComponentInternal,
|
|
4230
|
+
stickyPositionComponentInternal: _stickyPositionComponentInternal,
|
|
4231
|
+
...restProps
|
|
4232
|
+
} = rest;
|
|
4233
|
+
const contentContainerStyleBase = StyleSheet.flatten(contentContainerStyleProp);
|
|
4234
|
+
const shouldFlexGrow = alignItemsAtEnd && (horizontal ? (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minWidth) == null : (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minHeight) == null);
|
|
4235
|
+
const contentContainerStyle = {
|
|
4236
|
+
...contentContainerStyleBase,
|
|
4237
|
+
...alignItemsAtEnd ? {
|
|
4238
|
+
display: "flex",
|
|
4239
|
+
flexDirection: horizontal ? "row" : "column",
|
|
4240
|
+
...shouldFlexGrow ? { flexGrow: 1 } : {},
|
|
4241
|
+
justifyContent: "flex-end"
|
|
4242
|
+
} : {}
|
|
4243
|
+
};
|
|
4244
|
+
const style = { ...StyleSheet.flatten(styleProp) };
|
|
4245
|
+
const stylePaddingTopState = extractPadding(style, contentContainerStyle, "Top");
|
|
4246
|
+
const stylePaddingBottomState = extractPadding(style, contentContainerStyle, "Bottom");
|
|
4247
|
+
const maintainScrollAtEndConfig = normalizeMaintainScrollAtEnd(maintainScrollAtEnd);
|
|
4248
|
+
const maintainVisibleContentPositionConfig = normalizeMaintainVisibleContentPosition(
|
|
4249
|
+
maintainVisibleContentPositionProp
|
|
4250
|
+
);
|
|
4251
|
+
const hasInitialScrollIndex = initialScrollIndexProp !== void 0 && initialScrollIndexProp !== null;
|
|
4252
|
+
const hasInitialScrollOffset = initialScrollOffsetProp !== void 0 && initialScrollOffsetProp !== null;
|
|
4253
|
+
const initialScrollUsesOffsetOnly = !initialScrollAtEnd && !hasInitialScrollIndex && hasInitialScrollOffset;
|
|
4254
|
+
const initialScrollProp = initialScrollAtEnd ? { index: Math.max(0, dataProp.length - 1), viewOffset: -stylePaddingBottomState, viewPosition: 1 } : hasInitialScrollIndex ? typeof initialScrollIndexProp === "object" ? {
|
|
4255
|
+
index: (_a3 = initialScrollIndexProp.index) != null ? _a3 : 0,
|
|
4256
|
+
viewOffset: (_b = initialScrollIndexProp.viewOffset) != null ? _b : initialScrollIndexProp.viewPosition === 1 ? -stylePaddingBottomState : 0,
|
|
4257
|
+
viewPosition: (_c = initialScrollIndexProp.viewPosition) != null ? _c : 0
|
|
4258
|
+
} : {
|
|
4259
|
+
index: initialScrollIndexProp != null ? initialScrollIndexProp : 0,
|
|
4260
|
+
viewOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : 0
|
|
4261
|
+
} : initialScrollUsesOffsetOnly ? {
|
|
4262
|
+
contentOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : 0,
|
|
4263
|
+
index: 0,
|
|
4264
|
+
viewOffset: 0
|
|
4265
|
+
} : void 0;
|
|
4266
|
+
const [canRender, setCanRender] = React2__namespace.useState(!IsNewArchitecture);
|
|
4267
|
+
const ctx = useStateContext();
|
|
4268
|
+
ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
|
|
4269
|
+
const refScroller = React2.useRef(null);
|
|
4270
|
+
const combinedRef = useCombinedRef(refScroller, refScrollView);
|
|
4271
|
+
const keyExtractor = keyExtractorProp != null ? keyExtractorProp : ((_item, index) => index.toString());
|
|
4272
|
+
const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
|
|
4273
|
+
const alwaysRenderIndices = React2.useMemo(() => {
|
|
4274
|
+
const indices = getAlwaysRenderIndices(alwaysRender, dataProp, keyExtractor);
|
|
4275
|
+
return { arr: indices, set: new Set(indices) };
|
|
4276
|
+
}, [
|
|
4277
|
+
alwaysRender == null ? void 0 : alwaysRender.top,
|
|
4278
|
+
alwaysRender == null ? void 0 : alwaysRender.bottom,
|
|
4279
|
+
(_d = alwaysRender == null ? void 0 : alwaysRender.indices) == null ? void 0 : _d.join(","),
|
|
4280
|
+
(_e = alwaysRender == null ? void 0 : alwaysRender.keys) == null ? void 0 : _e.join(","),
|
|
4281
|
+
dataProp,
|
|
4282
|
+
dataVersion,
|
|
4283
|
+
keyExtractor
|
|
4284
|
+
]);
|
|
4285
|
+
if (IS_DEV && stickyIndicesDeprecated && !stickyHeaderIndicesProp) {
|
|
4286
|
+
warnDevOnce(
|
|
4287
|
+
"stickyIndices",
|
|
4288
|
+
"stickyIndices has been renamed to stickyHeaderIndices. Please update your props to use stickyHeaderIndices."
|
|
4289
|
+
);
|
|
4290
|
+
}
|
|
4291
|
+
if (IS_DEV && useWindowScroll && renderScrollComponent) {
|
|
4292
|
+
warnDevOnce(
|
|
4293
|
+
"useWindowScrollRenderScrollComponent",
|
|
4294
|
+
"useWindowScroll is not supported when renderScrollComponent is provided."
|
|
4295
|
+
);
|
|
4296
|
+
}
|
|
4297
|
+
const useWindowScrollResolved = Platform2.OS === "web" && !!useWindowScroll && !renderScrollComponent;
|
|
4298
|
+
const refState = React2.useRef(void 0);
|
|
4299
|
+
const hasOverrideItemLayout = !!overrideItemLayout;
|
|
4300
|
+
const prevHasOverrideItemLayout = React2.useRef(hasOverrideItemLayout);
|
|
4301
|
+
if (!refState.current) {
|
|
4302
|
+
if (!ctx.state) {
|
|
4303
|
+
const initialScrollLength = (estimatedListSize != null ? estimatedListSize : IsNewArchitecture ? { height: 0, width: 0 } : getWindowSize())[horizontal ? "width" : "height"];
|
|
4304
|
+
ctx.state = {
|
|
4305
|
+
activeStickyIndex: -1,
|
|
4306
|
+
averageSizes: {},
|
|
4307
|
+
columnSpans: [],
|
|
4308
|
+
columns: [],
|
|
4309
|
+
containerItemKeys: /* @__PURE__ */ new Map(),
|
|
4310
|
+
containerItemTypes: /* @__PURE__ */ new Map(),
|
|
4311
|
+
contentInsetOverride: void 0,
|
|
4312
|
+
dataChangeEpoch: 0,
|
|
4313
|
+
dataChangeNeedsScrollUpdate: false,
|
|
4314
|
+
didColumnsChange: false,
|
|
4315
|
+
didDataChange: false,
|
|
4316
|
+
enableScrollForNextCalculateItemsInView: true,
|
|
4317
|
+
endBuffered: -1,
|
|
4318
|
+
endNoBuffer: -1,
|
|
4319
|
+
endReachedSnapshot: void 0,
|
|
4320
|
+
firstFullyOnScreenIndex: -1,
|
|
4321
|
+
idCache: [],
|
|
4322
|
+
idsInView: [],
|
|
4323
|
+
indexByKey: /* @__PURE__ */ new Map(),
|
|
4324
|
+
initialAnchor: !initialScrollUsesOffsetOnly && (initialScrollProp == null ? void 0 : initialScrollProp.index) !== void 0 && (initialScrollProp == null ? void 0 : initialScrollProp.viewPosition) !== void 0 ? {
|
|
4325
|
+
attempts: 0,
|
|
4326
|
+
index: initialScrollProp.index,
|
|
4327
|
+
settledTicks: 0,
|
|
4328
|
+
viewOffset: (_f = initialScrollProp.viewOffset) != null ? _f : 0,
|
|
4329
|
+
viewPosition: initialScrollProp.viewPosition
|
|
4330
|
+
} : void 0,
|
|
4331
|
+
initialNativeScrollWatchdog: void 0,
|
|
4332
|
+
initialScroll: initialScrollProp,
|
|
4333
|
+
initialScrollLastDidFinish: false,
|
|
4334
|
+
initialScrollLastTarget: initialScrollProp,
|
|
4335
|
+
initialScrollLastTargetUsesOffset: initialScrollUsesOffsetOnly,
|
|
4336
|
+
initialScrollPreviousDataLength: dataProp.length,
|
|
4337
|
+
initialScrollRetryLastLength: void 0,
|
|
4338
|
+
initialScrollRetryWindowUntil: 0,
|
|
4339
|
+
initialScrollUsesOffset: initialScrollUsesOffsetOnly,
|
|
4340
|
+
isAtEnd: false,
|
|
4341
|
+
isAtStart: false,
|
|
4342
|
+
isEndReached: null,
|
|
4343
|
+
isFirst: true,
|
|
4344
|
+
isStartReached: null,
|
|
4345
|
+
lastBatchingAction: Date.now(),
|
|
4346
|
+
lastLayout: void 0,
|
|
4347
|
+
lastScrollDelta: 0,
|
|
4348
|
+
loadStartTime: Date.now(),
|
|
4349
|
+
minIndexSizeChanged: 0,
|
|
4350
|
+
nativeContentInset: void 0,
|
|
4351
|
+
nativeMarginTop: 0,
|
|
4352
|
+
pendingNativeMVCPAdjust: void 0,
|
|
4353
|
+
positions: [],
|
|
4354
|
+
props: {},
|
|
4355
|
+
queuedCalculateItemsInView: 0,
|
|
4356
|
+
refScroller: { current: null },
|
|
4357
|
+
scroll: 0,
|
|
4358
|
+
scrollAdjustHandler: new ScrollAdjustHandler(ctx),
|
|
4359
|
+
scrollForNextCalculateItemsInView: void 0,
|
|
4360
|
+
scrollHistory: [],
|
|
4361
|
+
scrollLength: initialScrollLength,
|
|
4362
|
+
scrollPending: 0,
|
|
4363
|
+
scrollPrev: 0,
|
|
4364
|
+
scrollPrevTime: 0,
|
|
4365
|
+
scrollProcessingEnabled: true,
|
|
4366
|
+
scrollTime: 0,
|
|
4367
|
+
sizes: /* @__PURE__ */ new Map(),
|
|
4368
|
+
sizesKnown: /* @__PURE__ */ new Map(),
|
|
4369
|
+
startBuffered: -1,
|
|
4370
|
+
startNoBuffer: -1,
|
|
4371
|
+
startReachedSnapshot: void 0,
|
|
4372
|
+
startReachedSnapshotDataChangeEpoch: void 0,
|
|
4373
|
+
stickyContainerPool: /* @__PURE__ */ new Set(),
|
|
4374
|
+
stickyContainers: /* @__PURE__ */ new Map(),
|
|
4375
|
+
timeoutSizeMessage: 0,
|
|
4376
|
+
timeouts: /* @__PURE__ */ new Set(),
|
|
4377
|
+
totalSize: 0,
|
|
4378
|
+
viewabilityConfigCallbackPairs: void 0
|
|
4379
|
+
};
|
|
4380
|
+
const internalState = ctx.state;
|
|
4381
|
+
internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
|
|
4382
|
+
set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPositionConfig);
|
|
4383
|
+
set$(ctx, "extraData", extraData);
|
|
4384
|
+
}
|
|
4385
|
+
refState.current = ctx.state;
|
|
4386
|
+
}
|
|
4387
|
+
const state = refState.current;
|
|
4388
|
+
const isFirstLocal = state.isFirst;
|
|
4389
|
+
state.didColumnsChange = numColumnsProp !== state.props.numColumns;
|
|
4390
|
+
const didDataReferenceChangeLocal = state.props.data !== dataProp;
|
|
4391
|
+
const didDataVersionChangeLocal = state.props.dataVersion !== dataVersion;
|
|
4392
|
+
const didDataChangeLocal = didDataVersionChangeLocal || didDataReferenceChangeLocal && checkActualChange(state, dataProp, state.props.data);
|
|
4393
|
+
if (didDataChangeLocal) {
|
|
4394
|
+
state.dataChangeEpoch += 1;
|
|
4395
|
+
state.dataChangeNeedsScrollUpdate = true;
|
|
4396
|
+
state.didDataChange = true;
|
|
4397
|
+
state.previousData = state.props.data;
|
|
4398
|
+
}
|
|
4399
|
+
const throttleScrollFn = scrollEventThrottle && onScrollProp ? useThrottledOnScroll(onScrollProp, scrollEventThrottle) : onScrollProp;
|
|
4400
|
+
state.props = {
|
|
4401
|
+
alignItemsAtEnd,
|
|
4402
|
+
alwaysRender,
|
|
4403
|
+
alwaysRenderIndicesArr: alwaysRenderIndices.arr,
|
|
4404
|
+
alwaysRenderIndicesSet: alwaysRenderIndices.set,
|
|
4405
|
+
animatedProps: animatedPropsInternal,
|
|
4406
|
+
contentInset,
|
|
4407
|
+
data: dataProp,
|
|
4408
|
+
dataVersion,
|
|
4409
|
+
drawDistance,
|
|
4410
|
+
estimatedItemSize,
|
|
4411
|
+
getEstimatedItemSize: useWrapIfItem(getEstimatedItemSize),
|
|
4412
|
+
getFixedItemSize: useWrapIfItem(getFixedItemSize),
|
|
4413
|
+
getItemType: useWrapIfItem(getItemType),
|
|
4414
|
+
horizontal: !!horizontal,
|
|
4415
|
+
initialContainerPoolRatio,
|
|
4416
|
+
itemsAreEqual,
|
|
4417
|
+
keyExtractor: useWrapIfItem(keyExtractor),
|
|
4418
|
+
maintainScrollAtEnd: maintainScrollAtEndConfig,
|
|
4419
|
+
maintainScrollAtEndThreshold,
|
|
4420
|
+
maintainVisibleContentPosition: maintainVisibleContentPositionConfig,
|
|
4421
|
+
numColumns: numColumnsProp,
|
|
4422
|
+
onEndReached,
|
|
4423
|
+
onEndReachedThreshold,
|
|
4424
|
+
onItemSizeChanged,
|
|
4425
|
+
onLoad,
|
|
4426
|
+
onScroll: throttleScrollFn,
|
|
4427
|
+
onStartReached,
|
|
4428
|
+
onStartReachedThreshold,
|
|
4429
|
+
onStickyHeaderChange,
|
|
4430
|
+
overrideItemLayout,
|
|
4431
|
+
positionComponentInternal,
|
|
4432
|
+
recycleItems: !!recycleItems,
|
|
4433
|
+
renderItem,
|
|
4434
|
+
snapToIndices,
|
|
4435
|
+
stickyIndicesArr: stickyHeaderIndices != null ? stickyHeaderIndices : [],
|
|
4436
|
+
stickyIndicesSet: React2.useMemo(() => new Set(stickyHeaderIndices != null ? stickyHeaderIndices : []), [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(",")]),
|
|
4437
|
+
stickyPositionComponentInternal,
|
|
4438
|
+
stylePaddingBottom: stylePaddingBottomState,
|
|
4439
|
+
stylePaddingTop: stylePaddingTopState,
|
|
4440
|
+
suggestEstimatedItemSize: !!suggestEstimatedItemSize,
|
|
4441
|
+
useWindowScroll: useWindowScrollResolved
|
|
4442
|
+
};
|
|
4443
|
+
state.refScroller = refScroller;
|
|
4444
|
+
const memoizedLastItemKeys = React2.useMemo(() => {
|
|
4445
|
+
if (!dataProp.length) return [];
|
|
4446
|
+
return Array.from(
|
|
4447
|
+
{ length: Math.min(numColumnsProp, dataProp.length) },
|
|
4448
|
+
(_, i) => getId(state, dataProp.length - 1 - i)
|
|
4449
|
+
);
|
|
4450
|
+
}, [dataProp, dataVersion, numColumnsProp]);
|
|
4451
|
+
const initializeStateVars = (shouldAdjustPadding) => {
|
|
4452
|
+
set$(ctx, "lastItemKeys", memoizedLastItemKeys);
|
|
4453
|
+
set$(ctx, "numColumns", numColumnsProp);
|
|
4454
|
+
const prevPaddingTop = peek$(ctx, "stylePaddingTop");
|
|
4455
|
+
setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
|
|
4456
|
+
refState.current.props.stylePaddingBottom = stylePaddingBottomState;
|
|
4457
|
+
let paddingDiff = stylePaddingTopState - prevPaddingTop;
|
|
4458
|
+
if (shouldAdjustPadding && maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform2.OS === "ios") {
|
|
4459
|
+
if (state.scroll < 0) {
|
|
4460
|
+
paddingDiff += state.scroll;
|
|
4461
|
+
}
|
|
4462
|
+
requestAdjust(ctx, paddingDiff);
|
|
4463
|
+
}
|
|
4464
|
+
};
|
|
4465
|
+
if (isFirstLocal) {
|
|
4466
|
+
initializeStateVars(false);
|
|
4467
|
+
updateItemPositions(
|
|
4468
|
+
ctx,
|
|
4469
|
+
/*dataChanged*/
|
|
4470
|
+
true
|
|
4471
|
+
);
|
|
4472
|
+
}
|
|
4473
|
+
const resolveInitialScrollOffset = React2.useCallback((initialScroll) => {
|
|
4474
|
+
var _a4;
|
|
4475
|
+
if (state.initialScrollUsesOffset) {
|
|
4476
|
+
return clampScrollOffset(ctx, (_a4 = initialScroll.contentOffset) != null ? _a4 : 0);
|
|
4477
|
+
}
|
|
4478
|
+
const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
|
|
4479
|
+
const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
|
|
4480
|
+
return clampScrollOffset(ctx, resolvedOffset, initialScroll);
|
|
4481
|
+
}, []);
|
|
4482
|
+
const finishInitialScrollWithoutScroll = React2.useCallback(() => {
|
|
4483
|
+
refState.current.initialAnchor = void 0;
|
|
4484
|
+
refState.current.initialScroll = void 0;
|
|
4485
|
+
state.initialAnchor = void 0;
|
|
4486
|
+
state.initialScroll = void 0;
|
|
4487
|
+
state.initialScrollUsesOffset = false;
|
|
4488
|
+
state.initialScrollLastTarget = void 0;
|
|
4489
|
+
state.initialScrollLastTargetUsesOffset = false;
|
|
4490
|
+
setInitialRenderState(ctx, { didInitialScroll: true });
|
|
4491
|
+
}, []);
|
|
4492
|
+
const setActiveInitialScrollTarget = React2.useCallback(
|
|
4493
|
+
(target, options) => {
|
|
4494
|
+
var _a4;
|
|
4495
|
+
const usesOffset = !!(options == null ? void 0 : options.usesOffset);
|
|
4496
|
+
state.initialScrollUsesOffset = usesOffset;
|
|
4497
|
+
state.initialScrollLastTarget = target;
|
|
4498
|
+
state.initialScrollLastTargetUsesOffset = usesOffset;
|
|
4499
|
+
refState.current.initialScroll = target;
|
|
4500
|
+
state.initialScroll = target;
|
|
4501
|
+
if ((options == null ? void 0 : options.resetDidFinish) && state.didFinishInitialScroll) {
|
|
4502
|
+
state.didFinishInitialScroll = false;
|
|
4503
|
+
}
|
|
4504
|
+
if (!(options == null ? void 0 : options.syncAnchor)) {
|
|
4505
|
+
return;
|
|
4506
|
+
}
|
|
4507
|
+
if (!IsNewArchitecture && !usesOffset && target.index !== void 0 && target.viewPosition !== void 0) {
|
|
4508
|
+
state.initialAnchor = {
|
|
4509
|
+
attempts: 0,
|
|
4510
|
+
index: target.index,
|
|
4511
|
+
settledTicks: 0,
|
|
4512
|
+
viewOffset: (_a4 = target.viewOffset) != null ? _a4 : 0,
|
|
4513
|
+
viewPosition: target.viewPosition
|
|
4514
|
+
};
|
|
4515
|
+
}
|
|
4516
|
+
},
|
|
4517
|
+
[]
|
|
4518
|
+
);
|
|
4519
|
+
const shouldFinishInitialScrollAtOrigin = React2.useCallback(
|
|
4520
|
+
(initialScroll, offset) => {
|
|
4521
|
+
var _a4, _b2, _c2;
|
|
4522
|
+
if (offset !== 0 || initialScrollAtEnd) {
|
|
4523
|
+
return false;
|
|
4524
|
+
}
|
|
4525
|
+
if (state.initialScrollUsesOffset) {
|
|
4526
|
+
return Math.abs((_a4 = initialScroll.contentOffset) != null ? _a4 : 0) <= 1;
|
|
4527
|
+
}
|
|
4528
|
+
return initialScroll.index === 0 && ((_b2 = initialScroll.viewPosition) != null ? _b2 : 0) === 0 && Math.abs((_c2 = initialScroll.viewOffset) != null ? _c2 : 0) <= 1;
|
|
4529
|
+
},
|
|
4530
|
+
[initialScrollAtEnd]
|
|
4531
|
+
);
|
|
4532
|
+
const shouldFinishEmptyInitialScrollAtEnd = React2.useCallback(
|
|
4533
|
+
(initialScroll, offset) => {
|
|
4534
|
+
return dataProp.length === 0 && initialScrollAtEnd && offset === 0 && initialScroll.viewPosition === 1;
|
|
4535
|
+
},
|
|
4536
|
+
[dataProp.length, initialScrollAtEnd]
|
|
4537
|
+
);
|
|
4538
|
+
const shouldRearmFinishedEmptyInitialScrollAtEnd = React2.useCallback(
|
|
4539
|
+
(initialScroll) => {
|
|
4540
|
+
var _a4;
|
|
4541
|
+
return !!(state.didFinishInitialScroll && dataProp.length > 0 && initialScroll && !state.initialScrollUsesOffset && initialScroll.index === 0 && initialScroll.viewPosition === 1 && ((_a4 = initialScroll.contentOffset) != null ? _a4 : 0) === 0);
|
|
4542
|
+
},
|
|
4543
|
+
[dataProp.length]
|
|
4544
|
+
);
|
|
4545
|
+
const initialContentOffset = React2.useMemo(() => {
|
|
4546
|
+
var _a4;
|
|
4547
|
+
let value;
|
|
4548
|
+
const { initialScroll, initialAnchor } = refState.current;
|
|
4549
|
+
if (initialScroll) {
|
|
4550
|
+
if (!state.initialScrollUsesOffset && !IsNewArchitecture && initialScroll.index !== void 0 && (!initialAnchor || (initialAnchor == null ? void 0 : initialAnchor.index) !== initialScroll.index)) {
|
|
4551
|
+
refState.current.initialAnchor = {
|
|
4552
|
+
attempts: 0,
|
|
4553
|
+
index: initialScroll.index,
|
|
4554
|
+
settledTicks: 0,
|
|
4555
|
+
viewOffset: (_a4 = initialScroll.viewOffset) != null ? _a4 : 0,
|
|
4556
|
+
viewPosition: initialScroll.viewPosition
|
|
4557
|
+
};
|
|
4558
|
+
}
|
|
4559
|
+
if (initialScroll.contentOffset !== void 0) {
|
|
4560
|
+
value = initialScroll.contentOffset;
|
|
4561
|
+
} else {
|
|
4562
|
+
const clampedOffset = resolveInitialScrollOffset(initialScroll);
|
|
4563
|
+
const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
|
|
4564
|
+
setActiveInitialScrollTarget(updatedInitialScroll, {
|
|
4565
|
+
usesOffset: state.initialScrollUsesOffset
|
|
4566
|
+
});
|
|
4567
|
+
value = clampedOffset;
|
|
4568
|
+
}
|
|
4569
|
+
} else {
|
|
4570
|
+
refState.current.initialAnchor = void 0;
|
|
4571
|
+
value = 0;
|
|
4572
|
+
}
|
|
4573
|
+
const hasPendingDataDependentInitialScroll = !!initialScroll && dataProp.length === 0 && !shouldFinishInitialScrollAtOrigin(initialScroll, value) && !shouldFinishEmptyInitialScrollAtEnd(initialScroll, value);
|
|
4574
|
+
if (!value && !hasPendingDataDependentInitialScroll) {
|
|
4575
|
+
if (initialScroll && shouldFinishInitialScrollAtOrigin(initialScroll, value)) {
|
|
4576
|
+
finishInitialScrollWithoutScroll();
|
|
4577
|
+
} else {
|
|
4578
|
+
setInitialRenderState(ctx, { didInitialScroll: true });
|
|
4579
|
+
}
|
|
4580
|
+
}
|
|
4581
|
+
return value;
|
|
4582
|
+
}, []);
|
|
4583
|
+
if (isFirstLocal || didDataChangeLocal || numColumnsProp !== peek$(ctx, "numColumns")) {
|
|
4584
|
+
refState.current.lastBatchingAction = Date.now();
|
|
4585
|
+
if (!keyExtractorProp && !isFirstLocal && didDataChangeLocal) {
|
|
4586
|
+
IS_DEV && !childrenMode && warnDevOnce(
|
|
4587
|
+
"keyExtractor",
|
|
4588
|
+
"Changing data without a keyExtractor can cause slow performance and resetting scroll. If your list data can change you should use a keyExtractor with a unique id for best performance and behavior."
|
|
4589
|
+
);
|
|
4590
|
+
refState.current.sizes.clear();
|
|
4591
|
+
refState.current.positions.length = 0;
|
|
4592
|
+
refState.current.totalSize = 0;
|
|
4593
|
+
set$(ctx, "totalSize", 0);
|
|
4594
|
+
}
|
|
4595
|
+
}
|
|
4596
|
+
const doInitialScroll = React2.useCallback((options) => {
|
|
4597
|
+
var _a4, _b2;
|
|
4598
|
+
const allowPostFinishRetry = !!(options == null ? void 0 : options.allowPostFinishRetry);
|
|
4599
|
+
const { didFinishInitialScroll, queuedInitialLayout, scrollingTo } = state;
|
|
4600
|
+
const initialScroll = (_a4 = state.initialScroll) != null ? _a4 : allowPostFinishRetry ? state.initialScrollLastTarget : void 0;
|
|
4601
|
+
const isInitialScrollInProgress = !!(scrollingTo == null ? void 0 : scrollingTo.isInitialScroll);
|
|
4602
|
+
const needsContainerLayoutForInitialScroll = !state.initialScrollUsesOffset;
|
|
4603
|
+
const shouldWaitForInitialLayout = waitForInitialLayout && needsContainerLayoutForInitialScroll && !queuedInitialLayout && !allowPostFinishRetry && !isInitialScrollInProgress;
|
|
4604
|
+
if (!initialScroll || shouldWaitForInitialLayout || didFinishInitialScroll && !allowPostFinishRetry || scrollingTo && !isInitialScrollInProgress) {
|
|
4605
|
+
return;
|
|
4606
|
+
}
|
|
4607
|
+
if (allowPostFinishRetry && state.initialScrollLastTargetUsesOffset) {
|
|
4608
|
+
return;
|
|
4609
|
+
}
|
|
4610
|
+
const didMoveAwayFromInitialTarget = allowPostFinishRetry && initialScroll.contentOffset !== void 0 && Math.abs(state.scroll - initialScroll.contentOffset) > 1;
|
|
4611
|
+
if (didMoveAwayFromInitialTarget) {
|
|
4612
|
+
state.initialScrollRetryWindowUntil = 0;
|
|
4613
|
+
return;
|
|
4614
|
+
}
|
|
4615
|
+
const offset = resolveInitialScrollOffset(initialScroll);
|
|
4616
|
+
const activeInitialTargetOffset = isInitialScrollInProgress ? (_b2 = scrollingTo.targetOffset) != null ? _b2 : scrollingTo.offset : void 0;
|
|
4617
|
+
const didOffsetChange = initialScroll.contentOffset === void 0 || Math.abs(initialScroll.contentOffset - offset) > 1;
|
|
4618
|
+
const didActiveInitialTargetChange = activeInitialTargetOffset !== void 0 && Math.abs(activeInitialTargetOffset - offset) > 1;
|
|
4619
|
+
if (!didOffsetChange && (allowPostFinishRetry || isInitialScrollInProgress && !didActiveInitialTargetChange)) {
|
|
4620
|
+
return;
|
|
4621
|
+
}
|
|
4622
|
+
if (didOffsetChange) {
|
|
4623
|
+
const updatedInitialScroll = { ...initialScroll, contentOffset: offset };
|
|
4624
|
+
if (!state.initialScrollUsesOffset) {
|
|
4625
|
+
state.initialScrollLastTarget = updatedInitialScroll;
|
|
4626
|
+
state.initialScrollLastTargetUsesOffset = false;
|
|
4627
|
+
if (state.initialScroll) {
|
|
4628
|
+
refState.current.initialScroll = updatedInitialScroll;
|
|
4629
|
+
state.initialScroll = updatedInitialScroll;
|
|
4630
|
+
}
|
|
4631
|
+
}
|
|
4632
|
+
}
|
|
4633
|
+
const hasMeasuredScrollLayout = !!state.lastLayout && state.scrollLength > 0;
|
|
4634
|
+
const shouldForceNativeInitialScroll = state.initialScrollUsesOffset && hasMeasuredScrollLayout || allowPostFinishRetry || !!queuedInitialLayout || isInitialScrollInProgress && didOffsetChange;
|
|
4635
|
+
performInitialScroll(ctx, {
|
|
4636
|
+
forceScroll: shouldForceNativeInitialScroll,
|
|
4637
|
+
initialScrollUsesOffset: state.initialScrollUsesOffset,
|
|
4638
|
+
resolvedOffset: offset,
|
|
4639
|
+
target: initialScroll
|
|
4640
|
+
});
|
|
4641
|
+
}, []);
|
|
4642
|
+
React2.useLayoutEffect(() => {
|
|
4643
|
+
var _a4;
|
|
4644
|
+
const previousDataLength = state.initialScrollPreviousDataLength;
|
|
4645
|
+
state.initialScrollPreviousDataLength = dataProp.length;
|
|
4646
|
+
if (previousDataLength !== 0 || dataProp.length === 0 || !state.initialScroll || !state.queuedInitialLayout) {
|
|
4647
|
+
return;
|
|
4648
|
+
}
|
|
4649
|
+
if (initialScrollAtEnd) {
|
|
4650
|
+
const lastIndex = Math.max(0, dataProp.length - 1);
|
|
4651
|
+
const initialScroll = state.initialScroll;
|
|
4652
|
+
const shouldRearm = shouldRearmFinishedEmptyInitialScrollAtEnd(initialScroll);
|
|
4653
|
+
if (state.didFinishInitialScroll && !shouldRearm) {
|
|
4654
|
+
return;
|
|
4655
|
+
}
|
|
4656
|
+
if (initialScroll && !state.initialScrollUsesOffset && initialScroll.index === lastIndex && initialScroll.viewPosition === 1 && !shouldRearm) {
|
|
4657
|
+
return;
|
|
4658
|
+
}
|
|
4659
|
+
const updatedInitialScroll = {
|
|
4660
|
+
contentOffset: void 0,
|
|
4661
|
+
index: lastIndex,
|
|
4662
|
+
viewOffset: (_a4 = initialScroll == null ? void 0 : initialScroll.viewOffset) != null ? _a4 : -stylePaddingBottomState,
|
|
4663
|
+
viewPosition: 1
|
|
4664
|
+
};
|
|
4665
|
+
setActiveInitialScrollTarget(updatedInitialScroll, {
|
|
4666
|
+
resetDidFinish: shouldRearm,
|
|
4667
|
+
syncAnchor: true
|
|
4668
|
+
});
|
|
4669
|
+
doInitialScroll();
|
|
4670
|
+
return;
|
|
4671
|
+
}
|
|
4672
|
+
if (state.didFinishInitialScroll) {
|
|
4673
|
+
return;
|
|
4674
|
+
}
|
|
4675
|
+
doInitialScroll();
|
|
4676
|
+
}, [
|
|
4677
|
+
dataProp.length,
|
|
4678
|
+
doInitialScroll,
|
|
4679
|
+
initialScrollAtEnd,
|
|
4680
|
+
shouldRearmFinishedEmptyInitialScrollAtEnd,
|
|
4681
|
+
stylePaddingBottomState
|
|
4682
|
+
]);
|
|
4683
|
+
React2.useLayoutEffect(() => {
|
|
4684
|
+
var _a4;
|
|
4685
|
+
if (!initialScrollAtEnd) {
|
|
4686
|
+
return;
|
|
4687
|
+
}
|
|
4688
|
+
const lastIndex = Math.max(0, dataProp.length - 1);
|
|
4689
|
+
const initialScroll = state.initialScroll;
|
|
4690
|
+
const shouldRearm = shouldRearmFinishedEmptyInitialScrollAtEnd(initialScroll);
|
|
4691
|
+
if (state.didFinishInitialScroll && !shouldRearm) {
|
|
4692
|
+
return;
|
|
4693
|
+
}
|
|
4694
|
+
if (shouldRearm) {
|
|
4695
|
+
state.didFinishInitialScroll = false;
|
|
4696
|
+
}
|
|
4697
|
+
if (initialScroll && !state.initialScrollUsesOffset && initialScroll.index === lastIndex && initialScroll.viewPosition === 1 && !shouldRearm) {
|
|
4698
|
+
return;
|
|
4699
|
+
}
|
|
4700
|
+
const updatedInitialScroll = {
|
|
4701
|
+
contentOffset: void 0,
|
|
4702
|
+
index: lastIndex,
|
|
4703
|
+
viewOffset: (_a4 = initialScroll == null ? void 0 : initialScroll.viewOffset) != null ? _a4 : -stylePaddingBottomState,
|
|
4704
|
+
viewPosition: 1
|
|
4705
|
+
};
|
|
4706
|
+
setActiveInitialScrollTarget(updatedInitialScroll, {
|
|
4707
|
+
resetDidFinish: shouldRearm,
|
|
4708
|
+
syncAnchor: true
|
|
4709
|
+
});
|
|
4710
|
+
doInitialScroll();
|
|
4711
|
+
}, [
|
|
4712
|
+
dataProp.length,
|
|
4713
|
+
doInitialScroll,
|
|
4714
|
+
initialScrollAtEnd,
|
|
4715
|
+
shouldRearmFinishedEmptyInitialScrollAtEnd,
|
|
4716
|
+
stylePaddingBottomState
|
|
4717
|
+
]);
|
|
4718
|
+
const onLayoutFooter = React2.useCallback(
|
|
4719
|
+
(layout) => {
|
|
4720
|
+
var _a4;
|
|
4721
|
+
if (!initialScrollAtEnd) {
|
|
4722
|
+
return;
|
|
4723
|
+
}
|
|
4724
|
+
const { initialScroll } = state;
|
|
4725
|
+
if (!initialScroll) {
|
|
4726
|
+
return;
|
|
4727
|
+
}
|
|
4728
|
+
const lastIndex = Math.max(0, dataProp.length - 1);
|
|
4729
|
+
if (initialScroll.index !== lastIndex || initialScroll.viewPosition !== 1) {
|
|
4730
|
+
return;
|
|
4731
|
+
}
|
|
4732
|
+
const footerSize = layout[horizontal ? "width" : "height"];
|
|
4733
|
+
const viewOffset = -stylePaddingBottomState - footerSize;
|
|
4734
|
+
if (initialScroll.viewOffset !== viewOffset) {
|
|
4735
|
+
const previousTargetOffset = (_a4 = initialScroll.contentOffset) != null ? _a4 : resolveInitialScrollOffset(initialScroll);
|
|
4736
|
+
const didMoveAwayFromFinishedInitialTarget = state.didFinishInitialScroll && Math.abs(state.scroll - previousTargetOffset) > 1;
|
|
4737
|
+
if (didMoveAwayFromFinishedInitialTarget) {
|
|
4738
|
+
return;
|
|
4739
|
+
}
|
|
4740
|
+
const updatedInitialScroll = { ...initialScroll, viewOffset };
|
|
4741
|
+
setActiveInitialScrollTarget(updatedInitialScroll, {
|
|
4742
|
+
resetDidFinish: true
|
|
4743
|
+
});
|
|
4744
|
+
doInitialScroll();
|
|
4745
|
+
}
|
|
4746
|
+
},
|
|
4747
|
+
[
|
|
4748
|
+
dataProp.length,
|
|
4749
|
+
doInitialScroll,
|
|
4750
|
+
horizontal,
|
|
4751
|
+
initialScrollAtEnd,
|
|
4752
|
+
resolveInitialScrollOffset,
|
|
4753
|
+
stylePaddingBottomState
|
|
4754
|
+
]
|
|
4755
|
+
);
|
|
4756
|
+
const onLayoutChange = React2.useCallback((layout) => {
|
|
4757
|
+
var _a4;
|
|
4758
|
+
handleLayout(ctx, layout, setCanRender);
|
|
4759
|
+
const SCROLL_LENGTH_RETRY_WINDOW_MS = 600;
|
|
4760
|
+
const now = Date.now();
|
|
4761
|
+
const didFinishInitialScroll = !!state.didFinishInitialScroll;
|
|
4762
|
+
if (didFinishInitialScroll && !state.initialScrollLastDidFinish) {
|
|
4763
|
+
state.initialScrollRetryWindowUntil = now + SCROLL_LENGTH_RETRY_WINDOW_MS;
|
|
4764
|
+
}
|
|
4765
|
+
state.initialScrollLastDidFinish = didFinishInitialScroll;
|
|
4766
|
+
const previousScrollLength = state.initialScrollRetryLastLength;
|
|
4767
|
+
const currentScrollLength = state.scrollLength;
|
|
4768
|
+
const didScrollLengthChange = previousScrollLength === void 0 || Math.abs(currentScrollLength - previousScrollLength) > 1;
|
|
4769
|
+
if (didScrollLengthChange) {
|
|
4770
|
+
state.initialScrollRetryLastLength = currentScrollLength;
|
|
4771
|
+
}
|
|
4772
|
+
if (didFinishInitialScroll && didScrollLengthChange && now <= state.initialScrollRetryWindowUntil && !state.initialScrollLastTargetUsesOffset && ((_a4 = state.initialScrollLastTarget) == null ? void 0 : _a4.index) !== void 0) {
|
|
4773
|
+
doInitialScroll({ allowPostFinishRetry: true });
|
|
4774
|
+
return;
|
|
4775
|
+
}
|
|
4776
|
+
doInitialScroll();
|
|
4777
|
+
}, []);
|
|
4778
|
+
const { onLayout } = useOnLayoutSync({
|
|
4779
|
+
onLayoutChange,
|
|
4780
|
+
onLayoutProp,
|
|
4781
|
+
ref: refScroller
|
|
4782
|
+
// the type of ScrollView doesn't include measure?
|
|
4783
|
+
});
|
|
4784
|
+
React2.useLayoutEffect(() => {
|
|
4785
|
+
if (snapToIndices) {
|
|
4786
|
+
updateSnapToOffsets(ctx);
|
|
4787
|
+
}
|
|
4788
|
+
}, [snapToIndices]);
|
|
4789
|
+
React2.useLayoutEffect(() => {
|
|
4790
|
+
const {
|
|
4791
|
+
didColumnsChange,
|
|
4792
|
+
didDataChange,
|
|
4793
|
+
isFirst,
|
|
4794
|
+
props: { data }
|
|
4795
|
+
} = state;
|
|
4796
|
+
const didAllocateContainers = data.length > 0 && doInitialAllocateContainers(ctx);
|
|
4797
|
+
if (!didAllocateContainers && !isFirst && (didDataChange || didColumnsChange)) {
|
|
4798
|
+
checkResetContainers(ctx, data);
|
|
4799
|
+
}
|
|
4800
|
+
state.didColumnsChange = false;
|
|
4801
|
+
state.didDataChange = false;
|
|
4802
|
+
state.isFirst = false;
|
|
4803
|
+
}, [dataProp, dataVersion, numColumnsProp]);
|
|
4804
|
+
React2.useLayoutEffect(() => {
|
|
4805
|
+
var _a4;
|
|
4806
|
+
set$(ctx, "extraData", extraData);
|
|
4807
|
+
const didToggleOverride = prevHasOverrideItemLayout.current !== hasOverrideItemLayout;
|
|
4808
|
+
prevHasOverrideItemLayout.current = hasOverrideItemLayout;
|
|
4809
|
+
if ((hasOverrideItemLayout || didToggleOverride) && numColumnsProp > 1) {
|
|
4810
|
+
(_a4 = state.triggerCalculateItemsInView) == null ? void 0 : _a4.call(state, { forceFullItemPositions: true });
|
|
4811
|
+
}
|
|
4812
|
+
}, [extraData, hasOverrideItemLayout, numColumnsProp]);
|
|
4813
|
+
React2.useLayoutEffect(
|
|
4814
|
+
() => initializeStateVars(true),
|
|
4815
|
+
[dataVersion, memoizedLastItemKeys.join(","), numColumnsProp, stylePaddingBottomState, stylePaddingTopState]
|
|
4816
|
+
);
|
|
4817
|
+
React2.useEffect(() => {
|
|
4818
|
+
if (!onMetricsChange) {
|
|
4819
|
+
return;
|
|
4820
|
+
}
|
|
4821
|
+
let lastMetrics;
|
|
4822
|
+
const emitMetrics = () => {
|
|
4823
|
+
const metrics = {
|
|
4824
|
+
footerSize: peek$(ctx, "footerSize") || 0,
|
|
4825
|
+
headerSize: peek$(ctx, "headerSize") || 0
|
|
4826
|
+
};
|
|
4827
|
+
if (!lastMetrics || metrics.headerSize !== lastMetrics.headerSize || metrics.footerSize !== lastMetrics.footerSize) {
|
|
4828
|
+
lastMetrics = metrics;
|
|
4829
|
+
onMetricsChange(metrics);
|
|
4830
|
+
}
|
|
4831
|
+
};
|
|
4832
|
+
emitMetrics();
|
|
4833
|
+
const unsubscribe = [listen$(ctx, "headerSize", emitMetrics), listen$(ctx, "footerSize", emitMetrics)];
|
|
4834
|
+
return () => {
|
|
4835
|
+
for (const unsub of unsubscribe) {
|
|
4836
|
+
unsub();
|
|
4837
|
+
}
|
|
4838
|
+
};
|
|
4839
|
+
}, [ctx, onMetricsChange]);
|
|
4840
|
+
React2.useEffect(() => {
|
|
4841
|
+
const viewability = setupViewability({
|
|
4842
|
+
onViewableItemsChanged,
|
|
4843
|
+
viewabilityConfig,
|
|
4844
|
+
viewabilityConfigCallbackPairs
|
|
4845
|
+
});
|
|
4846
|
+
state.viewabilityConfigCallbackPairs = viewability;
|
|
4847
|
+
state.enableScrollForNextCalculateItemsInView = !viewability;
|
|
4848
|
+
}, [viewabilityConfig, viewabilityConfigCallbackPairs, onViewableItemsChanged]);
|
|
4849
|
+
if (!IsNewArchitecture) {
|
|
4850
|
+
useInit(() => {
|
|
4851
|
+
doInitialAllocateContainers(ctx);
|
|
4852
|
+
});
|
|
4853
|
+
}
|
|
4854
|
+
React2.useImperativeHandle(forwardedRef, () => createImperativeHandle(ctx), []);
|
|
4855
|
+
if (Platform2.OS === "web") {
|
|
4856
|
+
React2.useEffect(doInitialScroll, []);
|
|
4857
|
+
}
|
|
4858
|
+
const fns = React2.useMemo(
|
|
4859
|
+
() => ({
|
|
4860
|
+
getRenderedItem: (key) => getRenderedItem(ctx, key),
|
|
4861
|
+
onMomentumScrollEnd: (event) => {
|
|
4862
|
+
checkFinishedScrollFallback(ctx);
|
|
4863
|
+
if (onMomentumScrollEnd) {
|
|
4864
|
+
onMomentumScrollEnd(event);
|
|
4865
|
+
}
|
|
4866
|
+
},
|
|
4867
|
+
onScroll: (event) => onScroll(ctx, event),
|
|
4868
|
+
updateItemSize: (itemKey, sizeObj) => updateItemSize(ctx, itemKey, sizeObj)
|
|
4869
|
+
}),
|
|
4870
|
+
[]
|
|
4871
|
+
);
|
|
4872
|
+
const onScrollHandler = useStickyScrollHandler(stickyHeaderIndices, horizontal, ctx, fns.onScroll);
|
|
4873
|
+
const refreshControlElement = refreshControl;
|
|
4874
|
+
return /* @__PURE__ */ React2__namespace.createElement(React2__namespace.Fragment, null, /* @__PURE__ */ React2__namespace.createElement(
|
|
4875
|
+
ListComponent,
|
|
4876
|
+
{
|
|
4877
|
+
...restProps,
|
|
4878
|
+
alignItemsAtEnd,
|
|
4879
|
+
canRender,
|
|
4880
|
+
contentContainerStyle,
|
|
4881
|
+
contentInset,
|
|
4882
|
+
getRenderedItem: fns.getRenderedItem,
|
|
4883
|
+
horizontal,
|
|
4884
|
+
initialContentOffset,
|
|
4885
|
+
ListEmptyComponent: dataProp.length === 0 ? ListEmptyComponent : void 0,
|
|
4886
|
+
ListHeaderComponent,
|
|
4887
|
+
onLayout,
|
|
4888
|
+
onLayoutFooter,
|
|
4889
|
+
onMomentumScrollEnd: fns.onMomentumScrollEnd,
|
|
4890
|
+
onScroll: onScrollHandler,
|
|
4891
|
+
recycleItems,
|
|
4892
|
+
refreshControl: refreshControlElement ? stylePaddingTopState > 0 ? React2__namespace.cloneElement(refreshControlElement, {
|
|
4893
|
+
progressViewOffset: ((_g = refreshControlElement.props.progressViewOffset) != null ? _g : 0) + stylePaddingTopState
|
|
4894
|
+
}) : refreshControlElement : onRefresh && /* @__PURE__ */ React2__namespace.createElement(
|
|
4895
|
+
ReactNative.RefreshControl,
|
|
4896
|
+
{
|
|
4897
|
+
onRefresh,
|
|
4898
|
+
progressViewOffset: (progressViewOffset || 0) + stylePaddingTopState,
|
|
4899
|
+
refreshing: !!refreshing
|
|
4900
|
+
}
|
|
4901
|
+
),
|
|
4902
|
+
refScrollView: combinedRef,
|
|
4903
|
+
renderScrollComponent,
|
|
4904
|
+
scrollAdjustHandler: (_h = refState.current) == null ? void 0 : _h.scrollAdjustHandler,
|
|
4905
|
+
scrollEventThrottle: 0,
|
|
4906
|
+
snapToIndices,
|
|
4907
|
+
stickyHeaderIndices,
|
|
4908
|
+
style,
|
|
4909
|
+
updateItemSize: fns.updateItemSize,
|
|
4910
|
+
useWindowScroll: useWindowScrollResolved,
|
|
4911
|
+
waitForInitialLayout
|
|
4912
|
+
}
|
|
4913
|
+
), IS_DEV && ENABLE_DEBUG_VIEW);
|
|
4914
|
+
});
|
|
4915
|
+
|
|
4916
|
+
// src/entrypoints/shared.ts
|
|
4917
|
+
var LegendListRuntime = LegendList;
|
|
4918
|
+
var internal = {
|
|
4919
|
+
getComponent,
|
|
4920
|
+
IsNewArchitecture,
|
|
4921
|
+
POSITION_OUT_OF_VIEW,
|
|
4922
|
+
peek$,
|
|
4923
|
+
useArr$,
|
|
4924
|
+
useCombinedRef,
|
|
4925
|
+
useStateContext
|
|
4926
|
+
};
|
|
4927
|
+
|
|
4928
|
+
// src/react-native.ts
|
|
4929
|
+
var LegendList3 = LegendListRuntime;
|
|
4930
|
+
var internal2 = internal;
|
|
4931
|
+
|
|
4932
|
+
exports.LegendList = LegendList3;
|
|
4933
|
+
exports.internal = internal2;
|
|
4934
|
+
exports.typedForwardRef = typedForwardRef;
|
|
4935
|
+
exports.typedMemo = typedMemo2;
|
|
4936
|
+
exports.useIsLastItem = useIsLastItem;
|
|
4937
|
+
exports.useListScrollSize = useListScrollSize;
|
|
4938
|
+
exports.useRecyclingEffect = useRecyclingEffect;
|
|
4939
|
+
exports.useRecyclingState = useRecyclingState;
|
|
4940
|
+
exports.useSyncLayout = useSyncLayout;
|
|
4941
|
+
exports.useViewability = useViewability;
|
|
4942
|
+
exports.useViewabilityAmount = useViewabilityAmount;
|