@legendapp/list 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +219 -106
- package/index.mjs +219 -106
- package/package.json +4 -1
package/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var React2 = require('react');
|
|
4
4
|
var reactNative = require('react-native');
|
|
5
|
+
var shim = require('use-sync-external-store/shim');
|
|
5
6
|
|
|
6
7
|
function _interopNamespace(e) {
|
|
7
8
|
if (e && e.__esModule) return e;
|
|
@@ -46,16 +47,43 @@ function StateProvider({ children }) {
|
|
|
46
47
|
function useStateContext() {
|
|
47
48
|
return React2__namespace.useContext(ContextState);
|
|
48
49
|
}
|
|
49
|
-
function
|
|
50
|
+
function createSelectorFunctionsArr(ctx, signalNames) {
|
|
51
|
+
let lastValues = [];
|
|
52
|
+
let lastSignalValues = [];
|
|
50
53
|
return {
|
|
51
|
-
subscribe: (cb) =>
|
|
52
|
-
|
|
54
|
+
subscribe: (cb) => {
|
|
55
|
+
const listeners = [];
|
|
56
|
+
for (const signalName of signalNames) {
|
|
57
|
+
listeners.push(listen$(ctx, signalName, cb));
|
|
58
|
+
}
|
|
59
|
+
return () => {
|
|
60
|
+
for (const listener of listeners) {
|
|
61
|
+
listener();
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
get: () => {
|
|
66
|
+
const currentValues = [];
|
|
67
|
+
let hasChanged = false;
|
|
68
|
+
for (let i = 0; i < signalNames.length; i++) {
|
|
69
|
+
const value = peek$(ctx, signalNames[i]);
|
|
70
|
+
currentValues.push(value);
|
|
71
|
+
if (value !== lastSignalValues[i]) {
|
|
72
|
+
hasChanged = true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
lastSignalValues = currentValues;
|
|
76
|
+
if (hasChanged) {
|
|
77
|
+
lastValues = currentValues;
|
|
78
|
+
}
|
|
79
|
+
return lastValues;
|
|
80
|
+
}
|
|
53
81
|
};
|
|
54
82
|
}
|
|
55
|
-
function
|
|
83
|
+
function useArr$(signalNames) {
|
|
56
84
|
const ctx = React2__namespace.useContext(ContextState);
|
|
57
|
-
const { subscribe, get } = React2__namespace.useMemo(() =>
|
|
58
|
-
const value =
|
|
85
|
+
const { subscribe, get } = React2__namespace.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
|
|
86
|
+
const value = shim.useSyncExternalStore(subscribe, get);
|
|
59
87
|
return value;
|
|
60
88
|
}
|
|
61
89
|
function listen$(ctx, signalName, cb) {
|
|
@@ -99,15 +127,25 @@ var DebugRow = ({ children }) => {
|
|
|
99
127
|
};
|
|
100
128
|
var DebugView = React2__namespace.memo(function DebugView2({ state }) {
|
|
101
129
|
const ctx = useStateContext();
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
130
|
+
const [
|
|
131
|
+
totalSize = 0,
|
|
132
|
+
totalSizeWithScrollAdjust = 0,
|
|
133
|
+
scrollAdjust = 0,
|
|
134
|
+
rawScroll = 0,
|
|
135
|
+
scroll = 0,
|
|
136
|
+
numContainers = 0,
|
|
137
|
+
numContainersPooled = 0
|
|
138
|
+
] = useArr$([
|
|
139
|
+
"totalSize",
|
|
140
|
+
"totalSizeWithScrollAdjust",
|
|
141
|
+
"scrollAdjust",
|
|
142
|
+
"debugRawScroll",
|
|
143
|
+
"debugComputedScroll",
|
|
144
|
+
"numContainers",
|
|
145
|
+
"numContainersPooled"
|
|
146
|
+
]);
|
|
107
147
|
const contentSize = getContentSize(ctx);
|
|
108
148
|
const [, forceUpdate] = React2.useReducer((x) => x + 1, 0);
|
|
109
|
-
use$("numContainers");
|
|
110
|
-
use$("numContainersPooled");
|
|
111
149
|
useInterval(() => {
|
|
112
150
|
forceUpdate();
|
|
113
151
|
}, 100);
|
|
@@ -162,6 +200,12 @@ function roundSize(size) {
|
|
|
162
200
|
function isNullOrUndefined(value) {
|
|
163
201
|
return value === null || value === void 0;
|
|
164
202
|
}
|
|
203
|
+
function comparatorByDistance(a, b) {
|
|
204
|
+
return b.distance - a.distance;
|
|
205
|
+
}
|
|
206
|
+
function comparatorDefault(a, b) {
|
|
207
|
+
return a - b;
|
|
208
|
+
}
|
|
165
209
|
var symbolFirst = Symbol();
|
|
166
210
|
function useInit(cb) {
|
|
167
211
|
const refValue = React2.useRef(symbolFirst);
|
|
@@ -285,14 +329,25 @@ var Container = ({
|
|
|
285
329
|
}) => {
|
|
286
330
|
const ctx = useStateContext();
|
|
287
331
|
const columnWrapperStyle = ctx.columnWrapperStyle;
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
332
|
+
const [
|
|
333
|
+
maintainVisibleContentPosition,
|
|
334
|
+
position = ANCHORED_POSITION_OUT_OF_VIEW,
|
|
335
|
+
column = 0,
|
|
336
|
+
numColumns,
|
|
337
|
+
lastItemKeys,
|
|
338
|
+
itemKey,
|
|
339
|
+
data,
|
|
340
|
+
extraData
|
|
341
|
+
] = useArr$([
|
|
342
|
+
"maintainVisibleContentPosition",
|
|
343
|
+
`containerPosition${id}`,
|
|
344
|
+
`containerColumn${id}`,
|
|
345
|
+
"numColumns",
|
|
346
|
+
"lastItemKeys",
|
|
347
|
+
`containerItemKey${id}`,
|
|
348
|
+
`containerItemData${id}`,
|
|
349
|
+
"extraData"
|
|
350
|
+
]);
|
|
296
351
|
const refLastSize = React2.useRef();
|
|
297
352
|
const ref = React2.useRef(null);
|
|
298
353
|
const [layoutRenderCount, forceLayoutRender] = React2.useState(0);
|
|
@@ -390,11 +445,11 @@ var Container = ({
|
|
|
390
445
|
const contentFragment = /* @__PURE__ */ React2__namespace.default.createElement(React2__namespace.default.Fragment, { key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React2__namespace.default.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && !lastItemKeys.includes(itemKey) && /* @__PURE__ */ React2__namespace.default.createElement(ItemSeparatorComponent, { leadingItem: renderedItemInfo.item })));
|
|
391
446
|
if (maintainVisibleContentPosition) {
|
|
392
447
|
const anchorStyle = position.type === "top" ? { position: "absolute", top: 0, left: 0, right: 0 } : { position: "absolute", bottom: 0, left: 0, right: 0 };
|
|
393
|
-
if (ENABLE_DEVMODE) {
|
|
448
|
+
if (__DEV__ && ENABLE_DEVMODE) {
|
|
394
449
|
anchorStyle.borderColor = position.type === "top" ? "red" : "blue";
|
|
395
450
|
anchorStyle.borderWidth = 1;
|
|
396
451
|
}
|
|
397
|
-
return /* @__PURE__ */ React2__namespace.default.createElement(LeanView, { style }, /* @__PURE__ */ React2__namespace.default.createElement(LeanView, { style: anchorStyle, onLayout, ref }, contentFragment, ENABLE_DEVMODE && /* @__PURE__ */ React2__namespace.default.createElement(reactNative.Text, { style: { position: "absolute", top: 0, left: 0, zIndex: 1e3 } }, position.top)));
|
|
452
|
+
return /* @__PURE__ */ React2__namespace.default.createElement(LeanView, { style }, /* @__PURE__ */ React2__namespace.default.createElement(LeanView, { style: anchorStyle, onLayout, ref }, contentFragment, __DEV__ && ENABLE_DEVMODE && /* @__PURE__ */ React2__namespace.default.createElement(reactNative.Text, { style: { position: "absolute", top: 0, left: 0, zIndex: 1e3 } }, position.top)));
|
|
398
453
|
}
|
|
399
454
|
return /* @__PURE__ */ React2__namespace.default.createElement(LeanView, { style, onLayout, ref }, contentFragment);
|
|
400
455
|
};
|
|
@@ -438,7 +493,7 @@ var Containers = typedMemo(function Containers2({
|
|
|
438
493
|
}) {
|
|
439
494
|
const ctx = useStateContext();
|
|
440
495
|
const columnWrapperStyle = ctx.columnWrapperStyle;
|
|
441
|
-
const numContainers =
|
|
496
|
+
const [numContainers] = useArr$(["numContainersPooled"]);
|
|
442
497
|
const animSize = useValue$(
|
|
443
498
|
"totalSizeWithScrollAdjust",
|
|
444
499
|
void 0,
|
|
@@ -1035,10 +1090,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1035
1090
|
isAtTop: false,
|
|
1036
1091
|
data: dataProp,
|
|
1037
1092
|
scrollLength: initialScrollLength,
|
|
1038
|
-
startBuffered:
|
|
1039
|
-
startNoBuffer:
|
|
1040
|
-
endBuffered:
|
|
1041
|
-
endNoBuffer:
|
|
1093
|
+
startBuffered: -1,
|
|
1094
|
+
startNoBuffer: -1,
|
|
1095
|
+
endBuffered: -1,
|
|
1096
|
+
endNoBuffer: -1,
|
|
1042
1097
|
scroll: initialContentOffset || 0,
|
|
1043
1098
|
totalSize: 0,
|
|
1044
1099
|
totalSizeBelowAnchor: 0,
|
|
@@ -1239,6 +1294,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1239
1294
|
const state = refState.current;
|
|
1240
1295
|
if (state.scrollingToOffset === void 0) {
|
|
1241
1296
|
state.disableScrollJumpsFrom = state.scroll - state.scrollAdjustHandler.getAppliedAdjust();
|
|
1297
|
+
state.scrollHistory.length = 0;
|
|
1242
1298
|
setTimeout(() => {
|
|
1243
1299
|
state.disableScrollJumpsFrom = void 0;
|
|
1244
1300
|
}, timeout);
|
|
@@ -1334,7 +1390,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1334
1390
|
}
|
|
1335
1391
|
return false;
|
|
1336
1392
|
}, []);
|
|
1337
|
-
const calculateItemsInView = React2.useCallback(() => {
|
|
1393
|
+
const calculateItemsInView = React2.useCallback((isReset) => {
|
|
1338
1394
|
var _a;
|
|
1339
1395
|
const state = refState.current;
|
|
1340
1396
|
const {
|
|
@@ -1353,14 +1409,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1353
1409
|
const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
|
|
1354
1410
|
const numColumns = peek$(ctx, "numColumns");
|
|
1355
1411
|
const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
|
|
1356
|
-
const scrollExtra = Math.max(-16, Math.min(16, speed)) * 16;
|
|
1357
1412
|
let scrollState = state.scroll;
|
|
1413
|
+
const scrollExtra = Math.max(-16, Math.min(16, speed)) * 24;
|
|
1358
1414
|
const useAverageSize = !state.disableScrollJumpsFrom && speed >= 0 && peek$(ctx, "containersDidLayout");
|
|
1359
1415
|
if (!state.queuedInitialLayout && initialScrollIndex) {
|
|
1360
1416
|
const updatedOffset = calculateOffsetForIndex(initialScrollIndex);
|
|
1361
1417
|
scrollState = updatedOffset;
|
|
1362
1418
|
}
|
|
1363
|
-
|
|
1419
|
+
const scrollAdjustPad = -previousScrollAdjust - topPad;
|
|
1420
|
+
let scroll = scrollState + scrollExtra + scrollAdjustPad;
|
|
1364
1421
|
if (scroll + scrollLength > totalSize) {
|
|
1365
1422
|
scroll = totalSize - scrollLength;
|
|
1366
1423
|
}
|
|
@@ -1370,13 +1427,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1370
1427
|
}
|
|
1371
1428
|
let scrollBufferTop = scrollBuffer;
|
|
1372
1429
|
let scrollBufferBottom = scrollBuffer;
|
|
1373
|
-
if (
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1430
|
+
if (Math.abs(speed) > 4) {
|
|
1431
|
+
if (speed > 0) {
|
|
1432
|
+
scrollBufferTop = scrollBuffer * 0.1;
|
|
1433
|
+
scrollBufferBottom = scrollBuffer * 1.9;
|
|
1434
|
+
} else {
|
|
1435
|
+
scrollBufferTop = scrollBuffer * 1.9;
|
|
1436
|
+
scrollBufferBottom = scrollBuffer * 0.1;
|
|
1437
|
+
}
|
|
1380
1438
|
}
|
|
1381
1439
|
if (state.scrollForNextCalculateItemsInView) {
|
|
1382
1440
|
const { top: top2, bottom } = state.scrollForNextCalculateItemsInView;
|
|
@@ -1436,6 +1494,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1436
1494
|
return topOffset;
|
|
1437
1495
|
};
|
|
1438
1496
|
let foundEnd = false;
|
|
1497
|
+
let nextTop;
|
|
1498
|
+
let nextBottom;
|
|
1439
1499
|
const prevNumContainers = ctx.values.get("numContainers");
|
|
1440
1500
|
let maxIndexRendered = 0;
|
|
1441
1501
|
for (let i = 0; i < prevNumContainers; i++) {
|
|
@@ -1465,6 +1525,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1465
1525
|
if (startBuffered === null && top + size > scroll - scrollBufferTop) {
|
|
1466
1526
|
startBuffered = i;
|
|
1467
1527
|
startBufferedId = id;
|
|
1528
|
+
nextTop = top;
|
|
1468
1529
|
}
|
|
1469
1530
|
if (startNoBuffer !== null) {
|
|
1470
1531
|
if (top <= scrollBottom) {
|
|
@@ -1472,6 +1533,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1472
1533
|
}
|
|
1473
1534
|
if (top <= scrollBottom + scrollBufferBottom) {
|
|
1474
1535
|
endBuffered = i;
|
|
1536
|
+
nextBottom = top + maxSizeInRow - scrollLength;
|
|
1475
1537
|
} else {
|
|
1476
1538
|
foundEnd = true;
|
|
1477
1539
|
}
|
|
@@ -1484,6 +1546,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1484
1546
|
maxSizeInRow = 0;
|
|
1485
1547
|
}
|
|
1486
1548
|
}
|
|
1549
|
+
const prevStartBuffered = state.startBuffered;
|
|
1550
|
+
const prevEndBuffered = state.endBuffered;
|
|
1487
1551
|
Object.assign(state, {
|
|
1488
1552
|
startBuffered,
|
|
1489
1553
|
startBufferedId,
|
|
@@ -1491,82 +1555,65 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1491
1555
|
endBuffered,
|
|
1492
1556
|
endNoBuffer
|
|
1493
1557
|
});
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
endBuffered !== null ? (positions.get(getId(endBuffered + 1)) || 0) - scrollLength - scrollBuffer : 0
|
|
1497
|
-
);
|
|
1498
|
-
if (state.enableScrollForNextCalculateItemsInView) {
|
|
1499
|
-
state.scrollForNextCalculateItemsInView = nextTop >= 0 && nextBottom >= 0 ? {
|
|
1558
|
+
if (state.enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0 && state.disableScrollJumpsFrom === void 0) {
|
|
1559
|
+
state.scrollForNextCalculateItemsInView = nextTop !== void 0 && nextBottom !== void 0 ? {
|
|
1500
1560
|
top: nextTop,
|
|
1501
1561
|
bottom: nextBottom
|
|
1502
1562
|
} : void 0;
|
|
1503
1563
|
}
|
|
1504
1564
|
if (startBuffered !== null && endBuffered !== null) {
|
|
1505
1565
|
let numContainers = prevNumContainers;
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
isContained = true;
|
|
1515
|
-
break;
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
if (!isContained) {
|
|
1519
|
-
const top2 = positions.get(id) || 0;
|
|
1520
|
-
let furthestIndex = -1;
|
|
1521
|
-
let furthestDistance = 0;
|
|
1522
|
-
for (let u = 0; u < numContainers; u++) {
|
|
1523
|
-
if (allocatedContainers.has(u)) {
|
|
1524
|
-
continue;
|
|
1566
|
+
const needNewContainers = [];
|
|
1567
|
+
if (isReset || startBuffered < prevStartBuffered || endBuffered > prevEndBuffered) {
|
|
1568
|
+
const isContained = (i) => {
|
|
1569
|
+
const id = getId(i);
|
|
1570
|
+
for (let j = 0; j < numContainers; j++) {
|
|
1571
|
+
const key = peek$(ctx, `containerItemKey${j}`);
|
|
1572
|
+
if (key === id) {
|
|
1573
|
+
return true;
|
|
1525
1574
|
}
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
const pos = peek$(ctx, `containerPosition${u}`).top;
|
|
1533
|
-
if (isNullOrUndefined(index2) || pos === POSITION_OUT_OF_VIEW) {
|
|
1534
|
-
furthestIndex = u;
|
|
1535
|
-
break;
|
|
1575
|
+
}
|
|
1576
|
+
};
|
|
1577
|
+
if (isReset) {
|
|
1578
|
+
for (let i = startBuffered; i <= endBuffered; i++) {
|
|
1579
|
+
if (!isContained(i)) {
|
|
1580
|
+
needNewContainers.push(i);
|
|
1536
1581
|
}
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
}
|
|
1582
|
+
}
|
|
1583
|
+
} else {
|
|
1584
|
+
for (let i = startBuffered; i < prevStartBuffered; i++) {
|
|
1585
|
+
if (!isContained(i)) {
|
|
1586
|
+
needNewContainers.push(i);
|
|
1543
1587
|
}
|
|
1544
1588
|
}
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
set$(ctx, `containerItemData${containerId}`, data[index]);
|
|
1549
|
-
allocatedContainers.add(containerId);
|
|
1550
|
-
if (furthestIndex === -1) {
|
|
1551
|
-
numContainers++;
|
|
1552
|
-
set$(ctx, `containerItemKey${containerId}`, id);
|
|
1553
|
-
const index2 = state.indexByKey.get(id);
|
|
1554
|
-
set$(ctx, `containerItemData${containerId}`, data[index2]);
|
|
1555
|
-
set$(ctx, `containerPosition${containerId}`, ANCHORED_POSITION_OUT_OF_VIEW);
|
|
1556
|
-
set$(ctx, `containerColumn${containerId}`, -1);
|
|
1557
|
-
if (__DEV__ && !didWarnMoreContainers && numContainers > peek$(ctx, "numContainersPooled")) {
|
|
1558
|
-
didWarnMoreContainers = true;
|
|
1559
|
-
console.warn(
|
|
1560
|
-
"[legend-list] No container to recycle, 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."
|
|
1561
|
-
);
|
|
1589
|
+
for (let i = Math.max(prevEndBuffered + 1, startBuffered); i <= endBuffered; i++) {
|
|
1590
|
+
if (!isContained(i)) {
|
|
1591
|
+
needNewContainers.push(i);
|
|
1562
1592
|
}
|
|
1563
1593
|
}
|
|
1564
1594
|
}
|
|
1565
1595
|
}
|
|
1566
|
-
if (
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1596
|
+
if (needNewContainers.length > 0) {
|
|
1597
|
+
const availableContainers = findAvailableContainers(
|
|
1598
|
+
needNewContainers.length,
|
|
1599
|
+
startBuffered,
|
|
1600
|
+
endBuffered
|
|
1601
|
+
);
|
|
1602
|
+
for (let idx = 0; idx < needNewContainers.length; idx++) {
|
|
1603
|
+
const i = needNewContainers[idx];
|
|
1604
|
+
const containerIndex = availableContainers[idx];
|
|
1605
|
+
const id = getId(i);
|
|
1606
|
+
set$(ctx, `containerItemKey${containerIndex}`, id);
|
|
1607
|
+
set$(ctx, `containerItemData${containerIndex}`, data[i]);
|
|
1608
|
+
if (containerIndex >= numContainers) {
|
|
1609
|
+
numContainers = containerIndex + 1;
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
if (numContainers !== prevNumContainers) {
|
|
1613
|
+
set$(ctx, "numContainers", numContainers);
|
|
1614
|
+
if (numContainers > peek$(ctx, "numContainersPooled")) {
|
|
1615
|
+
set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
|
|
1616
|
+
}
|
|
1570
1617
|
}
|
|
1571
1618
|
}
|
|
1572
1619
|
for (let i = 0; i < numContainers; i++) {
|
|
@@ -1596,7 +1643,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1596
1643
|
const prevPos = peek$(ctx, `containerPosition${i}`);
|
|
1597
1644
|
const prevColumn = peek$(ctx, `containerColumn${i}`);
|
|
1598
1645
|
const prevData = peek$(ctx, `containerItemData${i}`);
|
|
1599
|
-
if (pos.relativeCoordinate > POSITION_OUT_OF_VIEW && pos.top !== prevPos.top) {
|
|
1646
|
+
if (!prevPos || pos.relativeCoordinate > POSITION_OUT_OF_VIEW && pos.top !== prevPos.top) {
|
|
1600
1647
|
set$(ctx, `containerPosition${i}`, pos);
|
|
1601
1648
|
}
|
|
1602
1649
|
if (column2 >= 0 && column2 !== prevColumn) {
|
|
@@ -1791,7 +1838,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1791
1838
|
if (!keyExtractorProp) {
|
|
1792
1839
|
state.positions.clear();
|
|
1793
1840
|
}
|
|
1794
|
-
calculateItemsInView(
|
|
1841
|
+
calculateItemsInView(
|
|
1842
|
+
/*isReset*/
|
|
1843
|
+
true
|
|
1844
|
+
);
|
|
1795
1845
|
const didMaintainScrollAtEnd = doMaintainScrollAtEnd(false);
|
|
1796
1846
|
if (!didMaintainScrollAtEnd && dataProp.length > state.data.length) {
|
|
1797
1847
|
state.isEndReached = false;
|
|
@@ -1844,7 +1894,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1844
1894
|
(_b = state.belowAnchorElementPositions) == null ? void 0 : _b.clear();
|
|
1845
1895
|
scrollTo(0, false);
|
|
1846
1896
|
setTimeout(() => {
|
|
1847
|
-
calculateItemsInView(
|
|
1897
|
+
calculateItemsInView(
|
|
1898
|
+
/*reset*/
|
|
1899
|
+
true
|
|
1900
|
+
);
|
|
1848
1901
|
}, 0);
|
|
1849
1902
|
} else {
|
|
1850
1903
|
state.startBufferedId = void 0;
|
|
@@ -1859,7 +1912,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1859
1912
|
}
|
|
1860
1913
|
scrollTo(0, false);
|
|
1861
1914
|
setTimeout(() => {
|
|
1862
|
-
calculateItemsInView(
|
|
1915
|
+
calculateItemsInView(
|
|
1916
|
+
/*reset*/
|
|
1917
|
+
true
|
|
1918
|
+
);
|
|
1863
1919
|
}, 0);
|
|
1864
1920
|
}
|
|
1865
1921
|
}
|
|
@@ -1888,6 +1944,56 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1888
1944
|
});
|
|
1889
1945
|
addTotalSize(null, totalSize, totalSizeBelowIndex);
|
|
1890
1946
|
};
|
|
1947
|
+
const findAvailableContainers = (numNeeded, startBuffered, endBuffered) => {
|
|
1948
|
+
const state = refState.current;
|
|
1949
|
+
const numContainers = peek$(ctx, "numContainers");
|
|
1950
|
+
if (numNeeded === 0) return [];
|
|
1951
|
+
const result = [];
|
|
1952
|
+
const availableContainers = [];
|
|
1953
|
+
for (let u = 0; u < numContainers; u++) {
|
|
1954
|
+
const key = peek$(ctx, `containerItemKey${u}`);
|
|
1955
|
+
if (key === void 0) {
|
|
1956
|
+
result.push(u);
|
|
1957
|
+
if (result.length >= numNeeded) {
|
|
1958
|
+
return result;
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
for (let u = 0; u < numContainers; u++) {
|
|
1963
|
+
const key = peek$(ctx, `containerItemKey${u}`);
|
|
1964
|
+
if (key === void 0) continue;
|
|
1965
|
+
const index = state.indexByKey.get(key);
|
|
1966
|
+
if (index < startBuffered) {
|
|
1967
|
+
availableContainers.push({ index: u, distance: startBuffered - index });
|
|
1968
|
+
} else if (index > endBuffered) {
|
|
1969
|
+
availableContainers.push({ index: u, distance: index - endBuffered });
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
const remaining = numNeeded - result.length;
|
|
1973
|
+
if (remaining > 0) {
|
|
1974
|
+
if (availableContainers.length > 0) {
|
|
1975
|
+
if (availableContainers.length > remaining) {
|
|
1976
|
+
availableContainers.sort(comparatorByDistance);
|
|
1977
|
+
availableContainers.length = remaining;
|
|
1978
|
+
}
|
|
1979
|
+
for (const container of availableContainers) {
|
|
1980
|
+
result.push(container.index);
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
const stillNeeded = numNeeded - result.length;
|
|
1984
|
+
if (stillNeeded > 0) {
|
|
1985
|
+
for (let i = 0; i < stillNeeded; i++) {
|
|
1986
|
+
result.push(numContainers + i);
|
|
1987
|
+
}
|
|
1988
|
+
if (__DEV__ && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
|
|
1989
|
+
console.warn(
|
|
1990
|
+
"[legend-list] No container to recycle, 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."
|
|
1991
|
+
);
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
return result.sort(comparatorDefault);
|
|
1996
|
+
};
|
|
1891
1997
|
const isFirst = !refState.current.renderItem;
|
|
1892
1998
|
const memoizedLastItemKeys = React2.useMemo(() => {
|
|
1893
1999
|
if (!dataProp.length) return [];
|
|
@@ -1969,10 +2075,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1969
2075
|
set$(ctx, "numContainersPooled", numContainers * initialContainerPoolRatio);
|
|
1970
2076
|
if (initialScrollIndex) {
|
|
1971
2077
|
requestAnimationFrame(() => {
|
|
1972
|
-
calculateItemsInView(
|
|
2078
|
+
calculateItemsInView(
|
|
2079
|
+
/*isReset*/
|
|
2080
|
+
true
|
|
2081
|
+
);
|
|
1973
2082
|
});
|
|
1974
2083
|
} else {
|
|
1975
|
-
calculateItemsInView(
|
|
2084
|
+
calculateItemsInView(
|
|
2085
|
+
/*isReset*/
|
|
2086
|
+
true
|
|
2087
|
+
);
|
|
1976
2088
|
}
|
|
1977
2089
|
return true;
|
|
1978
2090
|
}
|
|
@@ -2008,6 +2120,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
2008
2120
|
}
|
|
2009
2121
|
const index = indexByKey.get(itemKey);
|
|
2010
2122
|
const numColumns = peek$(ctx, "numColumns");
|
|
2123
|
+
state.scrollForNextCalculateItemsInView = void 0;
|
|
2011
2124
|
state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, index) : index;
|
|
2012
2125
|
const prevSize = getItemSize(itemKey, index, data);
|
|
2013
2126
|
const prevSizeKnown = sizesKnown.get(itemKey);
|
package/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React2 from 'react';
|
|
2
|
-
import React2__default, { useReducer, useEffect, createContext, useMemo, useRef, useCallback, useImperativeHandle,
|
|
2
|
+
import React2__default, { useReducer, useEffect, createContext, useMemo, useRef, useCallback, useImperativeHandle, useContext, useState, forwardRef, memo, useLayoutEffect } from 'react';
|
|
3
3
|
import { View, Text, Platform, Animated, ScrollView, StyleSheet, Dimensions, RefreshControl } from 'react-native';
|
|
4
|
+
import { useSyncExternalStore } from 'use-sync-external-store/shim';
|
|
4
5
|
|
|
5
6
|
// src/LegendList.tsx
|
|
6
7
|
var ContextState = React2.createContext(null);
|
|
@@ -25,15 +26,42 @@ function StateProvider({ children }) {
|
|
|
25
26
|
function useStateContext() {
|
|
26
27
|
return React2.useContext(ContextState);
|
|
27
28
|
}
|
|
28
|
-
function
|
|
29
|
+
function createSelectorFunctionsArr(ctx, signalNames) {
|
|
30
|
+
let lastValues = [];
|
|
31
|
+
let lastSignalValues = [];
|
|
29
32
|
return {
|
|
30
|
-
subscribe: (cb) =>
|
|
31
|
-
|
|
33
|
+
subscribe: (cb) => {
|
|
34
|
+
const listeners = [];
|
|
35
|
+
for (const signalName of signalNames) {
|
|
36
|
+
listeners.push(listen$(ctx, signalName, cb));
|
|
37
|
+
}
|
|
38
|
+
return () => {
|
|
39
|
+
for (const listener of listeners) {
|
|
40
|
+
listener();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
get: () => {
|
|
45
|
+
const currentValues = [];
|
|
46
|
+
let hasChanged = false;
|
|
47
|
+
for (let i = 0; i < signalNames.length; i++) {
|
|
48
|
+
const value = peek$(ctx, signalNames[i]);
|
|
49
|
+
currentValues.push(value);
|
|
50
|
+
if (value !== lastSignalValues[i]) {
|
|
51
|
+
hasChanged = true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
lastSignalValues = currentValues;
|
|
55
|
+
if (hasChanged) {
|
|
56
|
+
lastValues = currentValues;
|
|
57
|
+
}
|
|
58
|
+
return lastValues;
|
|
59
|
+
}
|
|
32
60
|
};
|
|
33
61
|
}
|
|
34
|
-
function
|
|
62
|
+
function useArr$(signalNames) {
|
|
35
63
|
const ctx = React2.useContext(ContextState);
|
|
36
|
-
const { subscribe, get } = React2.useMemo(() =>
|
|
64
|
+
const { subscribe, get } = React2.useMemo(() => createSelectorFunctionsArr(ctx, signalNames), [ctx, signalNames]);
|
|
37
65
|
const value = useSyncExternalStore(subscribe, get);
|
|
38
66
|
return value;
|
|
39
67
|
}
|
|
@@ -78,15 +106,25 @@ var DebugRow = ({ children }) => {
|
|
|
78
106
|
};
|
|
79
107
|
var DebugView = React2.memo(function DebugView2({ state }) {
|
|
80
108
|
const ctx = useStateContext();
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
109
|
+
const [
|
|
110
|
+
totalSize = 0,
|
|
111
|
+
totalSizeWithScrollAdjust = 0,
|
|
112
|
+
scrollAdjust = 0,
|
|
113
|
+
rawScroll = 0,
|
|
114
|
+
scroll = 0,
|
|
115
|
+
numContainers = 0,
|
|
116
|
+
numContainersPooled = 0
|
|
117
|
+
] = useArr$([
|
|
118
|
+
"totalSize",
|
|
119
|
+
"totalSizeWithScrollAdjust",
|
|
120
|
+
"scrollAdjust",
|
|
121
|
+
"debugRawScroll",
|
|
122
|
+
"debugComputedScroll",
|
|
123
|
+
"numContainers",
|
|
124
|
+
"numContainersPooled"
|
|
125
|
+
]);
|
|
86
126
|
const contentSize = getContentSize(ctx);
|
|
87
127
|
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
|
88
|
-
use$("numContainers");
|
|
89
|
-
use$("numContainersPooled");
|
|
90
128
|
useInterval(() => {
|
|
91
129
|
forceUpdate();
|
|
92
130
|
}, 100);
|
|
@@ -141,6 +179,12 @@ function roundSize(size) {
|
|
|
141
179
|
function isNullOrUndefined(value) {
|
|
142
180
|
return value === null || value === void 0;
|
|
143
181
|
}
|
|
182
|
+
function comparatorByDistance(a, b) {
|
|
183
|
+
return b.distance - a.distance;
|
|
184
|
+
}
|
|
185
|
+
function comparatorDefault(a, b) {
|
|
186
|
+
return a - b;
|
|
187
|
+
}
|
|
144
188
|
var symbolFirst = Symbol();
|
|
145
189
|
function useInit(cb) {
|
|
146
190
|
const refValue = useRef(symbolFirst);
|
|
@@ -264,14 +308,25 @@ var Container = ({
|
|
|
264
308
|
}) => {
|
|
265
309
|
const ctx = useStateContext();
|
|
266
310
|
const columnWrapperStyle = ctx.columnWrapperStyle;
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
311
|
+
const [
|
|
312
|
+
maintainVisibleContentPosition,
|
|
313
|
+
position = ANCHORED_POSITION_OUT_OF_VIEW,
|
|
314
|
+
column = 0,
|
|
315
|
+
numColumns,
|
|
316
|
+
lastItemKeys,
|
|
317
|
+
itemKey,
|
|
318
|
+
data,
|
|
319
|
+
extraData
|
|
320
|
+
] = useArr$([
|
|
321
|
+
"maintainVisibleContentPosition",
|
|
322
|
+
`containerPosition${id}`,
|
|
323
|
+
`containerColumn${id}`,
|
|
324
|
+
"numColumns",
|
|
325
|
+
"lastItemKeys",
|
|
326
|
+
`containerItemKey${id}`,
|
|
327
|
+
`containerItemData${id}`,
|
|
328
|
+
"extraData"
|
|
329
|
+
]);
|
|
275
330
|
const refLastSize = useRef();
|
|
276
331
|
const ref = useRef(null);
|
|
277
332
|
const [layoutRenderCount, forceLayoutRender] = useState(0);
|
|
@@ -369,11 +424,11 @@ var Container = ({
|
|
|
369
424
|
const contentFragment = /* @__PURE__ */ React2__default.createElement(React2__default.Fragment, { key: recycleItems ? void 0 : itemKey }, /* @__PURE__ */ React2__default.createElement(ContextContainer.Provider, { value: contextValue }, renderedItem, renderedItemInfo && ItemSeparatorComponent && !lastItemKeys.includes(itemKey) && /* @__PURE__ */ React2__default.createElement(ItemSeparatorComponent, { leadingItem: renderedItemInfo.item })));
|
|
370
425
|
if (maintainVisibleContentPosition) {
|
|
371
426
|
const anchorStyle = position.type === "top" ? { position: "absolute", top: 0, left: 0, right: 0 } : { position: "absolute", bottom: 0, left: 0, right: 0 };
|
|
372
|
-
if (ENABLE_DEVMODE) {
|
|
427
|
+
if (__DEV__ && ENABLE_DEVMODE) {
|
|
373
428
|
anchorStyle.borderColor = position.type === "top" ? "red" : "blue";
|
|
374
429
|
anchorStyle.borderWidth = 1;
|
|
375
430
|
}
|
|
376
|
-
return /* @__PURE__ */ React2__default.createElement(LeanView, { style }, /* @__PURE__ */ React2__default.createElement(LeanView, { style: anchorStyle, onLayout, ref }, contentFragment, ENABLE_DEVMODE && /* @__PURE__ */ React2__default.createElement(Text, { style: { position: "absolute", top: 0, left: 0, zIndex: 1e3 } }, position.top)));
|
|
431
|
+
return /* @__PURE__ */ React2__default.createElement(LeanView, { style }, /* @__PURE__ */ React2__default.createElement(LeanView, { style: anchorStyle, onLayout, ref }, contentFragment, __DEV__ && ENABLE_DEVMODE && /* @__PURE__ */ React2__default.createElement(Text, { style: { position: "absolute", top: 0, left: 0, zIndex: 1e3 } }, position.top)));
|
|
377
432
|
}
|
|
378
433
|
return /* @__PURE__ */ React2__default.createElement(LeanView, { style, onLayout, ref }, contentFragment);
|
|
379
434
|
};
|
|
@@ -417,7 +472,7 @@ var Containers = typedMemo(function Containers2({
|
|
|
417
472
|
}) {
|
|
418
473
|
const ctx = useStateContext();
|
|
419
474
|
const columnWrapperStyle = ctx.columnWrapperStyle;
|
|
420
|
-
const numContainers =
|
|
475
|
+
const [numContainers] = useArr$(["numContainersPooled"]);
|
|
421
476
|
const animSize = useValue$(
|
|
422
477
|
"totalSizeWithScrollAdjust",
|
|
423
478
|
void 0,
|
|
@@ -1014,10 +1069,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1014
1069
|
isAtTop: false,
|
|
1015
1070
|
data: dataProp,
|
|
1016
1071
|
scrollLength: initialScrollLength,
|
|
1017
|
-
startBuffered:
|
|
1018
|
-
startNoBuffer:
|
|
1019
|
-
endBuffered:
|
|
1020
|
-
endNoBuffer:
|
|
1072
|
+
startBuffered: -1,
|
|
1073
|
+
startNoBuffer: -1,
|
|
1074
|
+
endBuffered: -1,
|
|
1075
|
+
endNoBuffer: -1,
|
|
1021
1076
|
scroll: initialContentOffset || 0,
|
|
1022
1077
|
totalSize: 0,
|
|
1023
1078
|
totalSizeBelowAnchor: 0,
|
|
@@ -1218,6 +1273,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1218
1273
|
const state = refState.current;
|
|
1219
1274
|
if (state.scrollingToOffset === void 0) {
|
|
1220
1275
|
state.disableScrollJumpsFrom = state.scroll - state.scrollAdjustHandler.getAppliedAdjust();
|
|
1276
|
+
state.scrollHistory.length = 0;
|
|
1221
1277
|
setTimeout(() => {
|
|
1222
1278
|
state.disableScrollJumpsFrom = void 0;
|
|
1223
1279
|
}, timeout);
|
|
@@ -1313,7 +1369,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1313
1369
|
}
|
|
1314
1370
|
return false;
|
|
1315
1371
|
}, []);
|
|
1316
|
-
const calculateItemsInView = useCallback(() => {
|
|
1372
|
+
const calculateItemsInView = useCallback((isReset) => {
|
|
1317
1373
|
var _a;
|
|
1318
1374
|
const state = refState.current;
|
|
1319
1375
|
const {
|
|
@@ -1332,14 +1388,15 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1332
1388
|
const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
|
|
1333
1389
|
const numColumns = peek$(ctx, "numColumns");
|
|
1334
1390
|
const previousScrollAdjust = scrollAdjustHandler.getAppliedAdjust();
|
|
1335
|
-
const scrollExtra = Math.max(-16, Math.min(16, speed)) * 16;
|
|
1336
1391
|
let scrollState = state.scroll;
|
|
1392
|
+
const scrollExtra = Math.max(-16, Math.min(16, speed)) * 24;
|
|
1337
1393
|
const useAverageSize = !state.disableScrollJumpsFrom && speed >= 0 && peek$(ctx, "containersDidLayout");
|
|
1338
1394
|
if (!state.queuedInitialLayout && initialScrollIndex) {
|
|
1339
1395
|
const updatedOffset = calculateOffsetForIndex(initialScrollIndex);
|
|
1340
1396
|
scrollState = updatedOffset;
|
|
1341
1397
|
}
|
|
1342
|
-
|
|
1398
|
+
const scrollAdjustPad = -previousScrollAdjust - topPad;
|
|
1399
|
+
let scroll = scrollState + scrollExtra + scrollAdjustPad;
|
|
1343
1400
|
if (scroll + scrollLength > totalSize) {
|
|
1344
1401
|
scroll = totalSize - scrollLength;
|
|
1345
1402
|
}
|
|
@@ -1349,13 +1406,14 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1349
1406
|
}
|
|
1350
1407
|
let scrollBufferTop = scrollBuffer;
|
|
1351
1408
|
let scrollBufferBottom = scrollBuffer;
|
|
1352
|
-
if (
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1409
|
+
if (Math.abs(speed) > 4) {
|
|
1410
|
+
if (speed > 0) {
|
|
1411
|
+
scrollBufferTop = scrollBuffer * 0.1;
|
|
1412
|
+
scrollBufferBottom = scrollBuffer * 1.9;
|
|
1413
|
+
} else {
|
|
1414
|
+
scrollBufferTop = scrollBuffer * 1.9;
|
|
1415
|
+
scrollBufferBottom = scrollBuffer * 0.1;
|
|
1416
|
+
}
|
|
1359
1417
|
}
|
|
1360
1418
|
if (state.scrollForNextCalculateItemsInView) {
|
|
1361
1419
|
const { top: top2, bottom } = state.scrollForNextCalculateItemsInView;
|
|
@@ -1415,6 +1473,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1415
1473
|
return topOffset;
|
|
1416
1474
|
};
|
|
1417
1475
|
let foundEnd = false;
|
|
1476
|
+
let nextTop;
|
|
1477
|
+
let nextBottom;
|
|
1418
1478
|
const prevNumContainers = ctx.values.get("numContainers");
|
|
1419
1479
|
let maxIndexRendered = 0;
|
|
1420
1480
|
for (let i = 0; i < prevNumContainers; i++) {
|
|
@@ -1444,6 +1504,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1444
1504
|
if (startBuffered === null && top + size > scroll - scrollBufferTop) {
|
|
1445
1505
|
startBuffered = i;
|
|
1446
1506
|
startBufferedId = id;
|
|
1507
|
+
nextTop = top;
|
|
1447
1508
|
}
|
|
1448
1509
|
if (startNoBuffer !== null) {
|
|
1449
1510
|
if (top <= scrollBottom) {
|
|
@@ -1451,6 +1512,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1451
1512
|
}
|
|
1452
1513
|
if (top <= scrollBottom + scrollBufferBottom) {
|
|
1453
1514
|
endBuffered = i;
|
|
1515
|
+
nextBottom = top + maxSizeInRow - scrollLength;
|
|
1454
1516
|
} else {
|
|
1455
1517
|
foundEnd = true;
|
|
1456
1518
|
}
|
|
@@ -1463,6 +1525,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1463
1525
|
maxSizeInRow = 0;
|
|
1464
1526
|
}
|
|
1465
1527
|
}
|
|
1528
|
+
const prevStartBuffered = state.startBuffered;
|
|
1529
|
+
const prevEndBuffered = state.endBuffered;
|
|
1466
1530
|
Object.assign(state, {
|
|
1467
1531
|
startBuffered,
|
|
1468
1532
|
startBufferedId,
|
|
@@ -1470,82 +1534,65 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1470
1534
|
endBuffered,
|
|
1471
1535
|
endNoBuffer
|
|
1472
1536
|
});
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
endBuffered !== null ? (positions.get(getId(endBuffered + 1)) || 0) - scrollLength - scrollBuffer : 0
|
|
1476
|
-
);
|
|
1477
|
-
if (state.enableScrollForNextCalculateItemsInView) {
|
|
1478
|
-
state.scrollForNextCalculateItemsInView = nextTop >= 0 && nextBottom >= 0 ? {
|
|
1537
|
+
if (state.enableScrollForNextCalculateItemsInView && nextTop !== void 0 && nextBottom !== void 0 && state.disableScrollJumpsFrom === void 0) {
|
|
1538
|
+
state.scrollForNextCalculateItemsInView = nextTop !== void 0 && nextBottom !== void 0 ? {
|
|
1479
1539
|
top: nextTop,
|
|
1480
1540
|
bottom: nextBottom
|
|
1481
1541
|
} : void 0;
|
|
1482
1542
|
}
|
|
1483
1543
|
if (startBuffered !== null && endBuffered !== null) {
|
|
1484
1544
|
let numContainers = prevNumContainers;
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
isContained = true;
|
|
1494
|
-
break;
|
|
1495
|
-
}
|
|
1496
|
-
}
|
|
1497
|
-
if (!isContained) {
|
|
1498
|
-
const top2 = positions.get(id) || 0;
|
|
1499
|
-
let furthestIndex = -1;
|
|
1500
|
-
let furthestDistance = 0;
|
|
1501
|
-
for (let u = 0; u < numContainers; u++) {
|
|
1502
|
-
if (allocatedContainers.has(u)) {
|
|
1503
|
-
continue;
|
|
1545
|
+
const needNewContainers = [];
|
|
1546
|
+
if (isReset || startBuffered < prevStartBuffered || endBuffered > prevEndBuffered) {
|
|
1547
|
+
const isContained = (i) => {
|
|
1548
|
+
const id = getId(i);
|
|
1549
|
+
for (let j = 0; j < numContainers; j++) {
|
|
1550
|
+
const key = peek$(ctx, `containerItemKey${j}`);
|
|
1551
|
+
if (key === id) {
|
|
1552
|
+
return true;
|
|
1504
1553
|
}
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
const pos = peek$(ctx, `containerPosition${u}`).top;
|
|
1512
|
-
if (isNullOrUndefined(index2) || pos === POSITION_OUT_OF_VIEW) {
|
|
1513
|
-
furthestIndex = u;
|
|
1514
|
-
break;
|
|
1554
|
+
}
|
|
1555
|
+
};
|
|
1556
|
+
if (isReset) {
|
|
1557
|
+
for (let i = startBuffered; i <= endBuffered; i++) {
|
|
1558
|
+
if (!isContained(i)) {
|
|
1559
|
+
needNewContainers.push(i);
|
|
1515
1560
|
}
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
}
|
|
1561
|
+
}
|
|
1562
|
+
} else {
|
|
1563
|
+
for (let i = startBuffered; i < prevStartBuffered; i++) {
|
|
1564
|
+
if (!isContained(i)) {
|
|
1565
|
+
needNewContainers.push(i);
|
|
1522
1566
|
}
|
|
1523
1567
|
}
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
set$(ctx, `containerItemData${containerId}`, data[index]);
|
|
1528
|
-
allocatedContainers.add(containerId);
|
|
1529
|
-
if (furthestIndex === -1) {
|
|
1530
|
-
numContainers++;
|
|
1531
|
-
set$(ctx, `containerItemKey${containerId}`, id);
|
|
1532
|
-
const index2 = state.indexByKey.get(id);
|
|
1533
|
-
set$(ctx, `containerItemData${containerId}`, data[index2]);
|
|
1534
|
-
set$(ctx, `containerPosition${containerId}`, ANCHORED_POSITION_OUT_OF_VIEW);
|
|
1535
|
-
set$(ctx, `containerColumn${containerId}`, -1);
|
|
1536
|
-
if (__DEV__ && !didWarnMoreContainers && numContainers > peek$(ctx, "numContainersPooled")) {
|
|
1537
|
-
didWarnMoreContainers = true;
|
|
1538
|
-
console.warn(
|
|
1539
|
-
"[legend-list] No container to recycle, 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."
|
|
1540
|
-
);
|
|
1568
|
+
for (let i = Math.max(prevEndBuffered + 1, startBuffered); i <= endBuffered; i++) {
|
|
1569
|
+
if (!isContained(i)) {
|
|
1570
|
+
needNewContainers.push(i);
|
|
1541
1571
|
}
|
|
1542
1572
|
}
|
|
1543
1573
|
}
|
|
1544
1574
|
}
|
|
1545
|
-
if (
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1575
|
+
if (needNewContainers.length > 0) {
|
|
1576
|
+
const availableContainers = findAvailableContainers(
|
|
1577
|
+
needNewContainers.length,
|
|
1578
|
+
startBuffered,
|
|
1579
|
+
endBuffered
|
|
1580
|
+
);
|
|
1581
|
+
for (let idx = 0; idx < needNewContainers.length; idx++) {
|
|
1582
|
+
const i = needNewContainers[idx];
|
|
1583
|
+
const containerIndex = availableContainers[idx];
|
|
1584
|
+
const id = getId(i);
|
|
1585
|
+
set$(ctx, `containerItemKey${containerIndex}`, id);
|
|
1586
|
+
set$(ctx, `containerItemData${containerIndex}`, data[i]);
|
|
1587
|
+
if (containerIndex >= numContainers) {
|
|
1588
|
+
numContainers = containerIndex + 1;
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
if (numContainers !== prevNumContainers) {
|
|
1592
|
+
set$(ctx, "numContainers", numContainers);
|
|
1593
|
+
if (numContainers > peek$(ctx, "numContainersPooled")) {
|
|
1594
|
+
set$(ctx, "numContainersPooled", Math.ceil(numContainers * 1.5));
|
|
1595
|
+
}
|
|
1549
1596
|
}
|
|
1550
1597
|
}
|
|
1551
1598
|
for (let i = 0; i < numContainers; i++) {
|
|
@@ -1575,7 +1622,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1575
1622
|
const prevPos = peek$(ctx, `containerPosition${i}`);
|
|
1576
1623
|
const prevColumn = peek$(ctx, `containerColumn${i}`);
|
|
1577
1624
|
const prevData = peek$(ctx, `containerItemData${i}`);
|
|
1578
|
-
if (pos.relativeCoordinate > POSITION_OUT_OF_VIEW && pos.top !== prevPos.top) {
|
|
1625
|
+
if (!prevPos || pos.relativeCoordinate > POSITION_OUT_OF_VIEW && pos.top !== prevPos.top) {
|
|
1579
1626
|
set$(ctx, `containerPosition${i}`, pos);
|
|
1580
1627
|
}
|
|
1581
1628
|
if (column2 >= 0 && column2 !== prevColumn) {
|
|
@@ -1770,7 +1817,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1770
1817
|
if (!keyExtractorProp) {
|
|
1771
1818
|
state.positions.clear();
|
|
1772
1819
|
}
|
|
1773
|
-
calculateItemsInView(
|
|
1820
|
+
calculateItemsInView(
|
|
1821
|
+
/*isReset*/
|
|
1822
|
+
true
|
|
1823
|
+
);
|
|
1774
1824
|
const didMaintainScrollAtEnd = doMaintainScrollAtEnd(false);
|
|
1775
1825
|
if (!didMaintainScrollAtEnd && dataProp.length > state.data.length) {
|
|
1776
1826
|
state.isEndReached = false;
|
|
@@ -1823,7 +1873,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1823
1873
|
(_b = state.belowAnchorElementPositions) == null ? void 0 : _b.clear();
|
|
1824
1874
|
scrollTo(0, false);
|
|
1825
1875
|
setTimeout(() => {
|
|
1826
|
-
calculateItemsInView(
|
|
1876
|
+
calculateItemsInView(
|
|
1877
|
+
/*reset*/
|
|
1878
|
+
true
|
|
1879
|
+
);
|
|
1827
1880
|
}, 0);
|
|
1828
1881
|
} else {
|
|
1829
1882
|
state.startBufferedId = void 0;
|
|
@@ -1838,7 +1891,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1838
1891
|
}
|
|
1839
1892
|
scrollTo(0, false);
|
|
1840
1893
|
setTimeout(() => {
|
|
1841
|
-
calculateItemsInView(
|
|
1894
|
+
calculateItemsInView(
|
|
1895
|
+
/*reset*/
|
|
1896
|
+
true
|
|
1897
|
+
);
|
|
1842
1898
|
}, 0);
|
|
1843
1899
|
}
|
|
1844
1900
|
}
|
|
@@ -1867,6 +1923,56 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1867
1923
|
});
|
|
1868
1924
|
addTotalSize(null, totalSize, totalSizeBelowIndex);
|
|
1869
1925
|
};
|
|
1926
|
+
const findAvailableContainers = (numNeeded, startBuffered, endBuffered) => {
|
|
1927
|
+
const state = refState.current;
|
|
1928
|
+
const numContainers = peek$(ctx, "numContainers");
|
|
1929
|
+
if (numNeeded === 0) return [];
|
|
1930
|
+
const result = [];
|
|
1931
|
+
const availableContainers = [];
|
|
1932
|
+
for (let u = 0; u < numContainers; u++) {
|
|
1933
|
+
const key = peek$(ctx, `containerItemKey${u}`);
|
|
1934
|
+
if (key === void 0) {
|
|
1935
|
+
result.push(u);
|
|
1936
|
+
if (result.length >= numNeeded) {
|
|
1937
|
+
return result;
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
for (let u = 0; u < numContainers; u++) {
|
|
1942
|
+
const key = peek$(ctx, `containerItemKey${u}`);
|
|
1943
|
+
if (key === void 0) continue;
|
|
1944
|
+
const index = state.indexByKey.get(key);
|
|
1945
|
+
if (index < startBuffered) {
|
|
1946
|
+
availableContainers.push({ index: u, distance: startBuffered - index });
|
|
1947
|
+
} else if (index > endBuffered) {
|
|
1948
|
+
availableContainers.push({ index: u, distance: index - endBuffered });
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
const remaining = numNeeded - result.length;
|
|
1952
|
+
if (remaining > 0) {
|
|
1953
|
+
if (availableContainers.length > 0) {
|
|
1954
|
+
if (availableContainers.length > remaining) {
|
|
1955
|
+
availableContainers.sort(comparatorByDistance);
|
|
1956
|
+
availableContainers.length = remaining;
|
|
1957
|
+
}
|
|
1958
|
+
for (const container of availableContainers) {
|
|
1959
|
+
result.push(container.index);
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
const stillNeeded = numNeeded - result.length;
|
|
1963
|
+
if (stillNeeded > 0) {
|
|
1964
|
+
for (let i = 0; i < stillNeeded; i++) {
|
|
1965
|
+
result.push(numContainers + i);
|
|
1966
|
+
}
|
|
1967
|
+
if (__DEV__ && numContainers + stillNeeded > peek$(ctx, "numContainersPooled")) {
|
|
1968
|
+
console.warn(
|
|
1969
|
+
"[legend-list] No container to recycle, 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."
|
|
1970
|
+
);
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
return result.sort(comparatorDefault);
|
|
1975
|
+
};
|
|
1870
1976
|
const isFirst = !refState.current.renderItem;
|
|
1871
1977
|
const memoizedLastItemKeys = useMemo(() => {
|
|
1872
1978
|
if (!dataProp.length) return [];
|
|
@@ -1948,10 +2054,16 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1948
2054
|
set$(ctx, "numContainersPooled", numContainers * initialContainerPoolRatio);
|
|
1949
2055
|
if (initialScrollIndex) {
|
|
1950
2056
|
requestAnimationFrame(() => {
|
|
1951
|
-
calculateItemsInView(
|
|
2057
|
+
calculateItemsInView(
|
|
2058
|
+
/*isReset*/
|
|
2059
|
+
true
|
|
2060
|
+
);
|
|
1952
2061
|
});
|
|
1953
2062
|
} else {
|
|
1954
|
-
calculateItemsInView(
|
|
2063
|
+
calculateItemsInView(
|
|
2064
|
+
/*isReset*/
|
|
2065
|
+
true
|
|
2066
|
+
);
|
|
1955
2067
|
}
|
|
1956
2068
|
return true;
|
|
1957
2069
|
}
|
|
@@ -1987,6 +2099,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
1987
2099
|
}
|
|
1988
2100
|
const index = indexByKey.get(itemKey);
|
|
1989
2101
|
const numColumns = peek$(ctx, "numColumns");
|
|
2102
|
+
state.scrollForNextCalculateItemsInView = void 0;
|
|
1990
2103
|
state.minIndexSizeChanged = state.minIndexSizeChanged !== void 0 ? Math.min(state.minIndexSizeChanged, index) : index;
|
|
1991
2104
|
const prevSize = getItemSize(itemKey, index, data);
|
|
1992
2105
|
const prevSizeKnown = sizesKnown.get(itemKey);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@legendapp/list",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "Legend List is a drop-in replacement for FlatList with much better performance and supporting dynamically sized items.",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"private": false,
|
|
@@ -28,5 +28,8 @@
|
|
|
28
28
|
"homepage": "https://github.com/LegendApp/legend-list#readme",
|
|
29
29
|
"publishConfig": {
|
|
30
30
|
"registry": "https://registry.npmjs.org/"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"use-sync-external-store": "^1.5.0"
|
|
31
34
|
}
|
|
32
35
|
}
|