@legendapp/list 3.3.5 → 3.3.6
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/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/react-native.js +259 -147
- package/react-native.mjs +259 -147
- package/react-native.web.js +240 -129
- package/react-native.web.mjs +240 -129
- package/react.js +240 -129
- package/react.mjs +240 -129
- package/.DS_Store +0 -0
package/react-native.mjs
CHANGED
|
@@ -47,10 +47,6 @@ function getStylePaddingEnd(props) {
|
|
|
47
47
|
}
|
|
48
48
|
return (isHorizontalRTLProps(props) ? props.stylePaddingLeft : props.stylePaddingRight) || 0;
|
|
49
49
|
}
|
|
50
|
-
function getLogicalHorizontalMaxOffset(state, contentWidth) {
|
|
51
|
-
var _a3;
|
|
52
|
-
return (_a3 = getHorizontalMaxOffset(state, contentWidth)) != null ? _a3 : 0;
|
|
53
|
-
}
|
|
54
50
|
function getHorizontalInsetEnd(state, inset) {
|
|
55
51
|
if (!inset) {
|
|
56
52
|
return 0;
|
|
@@ -712,6 +708,12 @@ function checkAtBottom(ctx, allowedEdge, allowGateCreatedInCurrentCheck) {
|
|
|
712
708
|
} = state;
|
|
713
709
|
const contentSize = getContentSize(ctx);
|
|
714
710
|
resetSharedEdgeGateIfOutsideHysteresis(ctx);
|
|
711
|
+
if (state.props.data.length === 0 && scrollLength > 0 && contentSize <= scrollLength) {
|
|
712
|
+
set$(ctx, "isAtEnd", true);
|
|
713
|
+
set$(ctx, "isNearEnd", true);
|
|
714
|
+
set$(ctx, "isWithinMaintainScrollAtEndThreshold", true);
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
715
717
|
if (contentSize > 0 && queuedInitialLayout) {
|
|
716
718
|
const insetEnd = getContentInsetEnd(ctx);
|
|
717
719
|
const distanceFromEnd = contentSize - scroll - scrollLength - insetEnd;
|
|
@@ -721,7 +723,7 @@ function checkAtBottom(ctx, allowedEdge, allowGateCreatedInCurrentCheck) {
|
|
|
721
723
|
set$(
|
|
722
724
|
ctx,
|
|
723
725
|
"isWithinMaintainScrollAtEndThreshold",
|
|
724
|
-
isContentLess || distanceFromEnd <= maintainScrollAtEndThreshold * scrollLength
|
|
726
|
+
isContentLess || distanceFromEnd <= maintainScrollAtEndThreshold * scrollLength || state.pendingMaintainScrollAtEnd || maintainingScrollAtEnd === "animated" || maintainingScrollAtEnd === "instant"
|
|
725
727
|
);
|
|
726
728
|
const shouldSkipThresholdChecks = hasActiveInitialScroll(state) || maintainingScrollAtEnd;
|
|
727
729
|
if (!shouldSkipThresholdChecks) {
|
|
@@ -1072,10 +1074,22 @@ function getAlignItemsAtEndPadding(ctx) {
|
|
|
1072
1074
|
return shouldPad ? Math.max(0, state.scrollLength - getRawContentLength(ctx) - getContentInsetEnd(ctx)) : 0;
|
|
1073
1075
|
}
|
|
1074
1076
|
function updateContentMetricsState(ctx) {
|
|
1077
|
+
var _a3;
|
|
1078
|
+
const { state } = ctx;
|
|
1075
1079
|
const previousPadding = peek$(ctx, "alignItemsAtEndPadding") || 0;
|
|
1076
1080
|
const nextPadding = getAlignItemsAtEndPadding(ctx);
|
|
1077
1081
|
if (previousPadding !== nextPadding) {
|
|
1078
|
-
|
|
1082
|
+
const isAnimatedMaintainActive = state.maintainingScrollAtEnd === "pending-animated" || state.maintainingScrollAtEnd === "animated";
|
|
1083
|
+
const isMaintainExpected = state.didContainersLayout && ((_a3 = state.props.maintainScrollAtEnd) == null ? void 0 : _a3.animated) && (isAnimatedMaintainActive || previousPadding > nextPadding && peek$(ctx, "isWithinMaintainScrollAtEndThreshold"));
|
|
1084
|
+
if (isMaintainExpected && !isAnimatedMaintainActive && !state.pendingMaintainScrollAtEnd) {
|
|
1085
|
+
state.scheduledWork.microtask(() => {
|
|
1086
|
+
if (!state.maintainingScrollAtEnd && !state.pendingMaintainScrollAtEnd) {
|
|
1087
|
+
set$(ctx, "alignItemsAtEndPadding", getAlignItemsAtEndPadding(ctx));
|
|
1088
|
+
}
|
|
1089
|
+
}, "alignItemsAtEndPaddingFallback");
|
|
1090
|
+
} else if (!isMaintainExpected) {
|
|
1091
|
+
set$(ctx, "alignItemsAtEndPadding", nextPadding);
|
|
1092
|
+
}
|
|
1079
1093
|
}
|
|
1080
1094
|
}
|
|
1081
1095
|
|
|
@@ -1528,81 +1542,55 @@ function doScrollTo(ctx, params) {
|
|
|
1528
1542
|
}
|
|
1529
1543
|
}
|
|
1530
1544
|
|
|
1531
|
-
// src/core/
|
|
1532
|
-
function
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
if (!state.maintainingScrollAtEnd) {
|
|
1553
|
-
const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
|
|
1554
|
-
const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
|
|
1555
|
-
const scrollAtRequest = state.scroll;
|
|
1556
|
-
state.maintainingScrollAtEnd = pendingState;
|
|
1557
|
-
requestAnimationFrame(() => {
|
|
1558
|
-
const isStillWithinThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
|
|
1559
|
-
const didScrollSinceRequest = state.scroll !== scrollAtRequest;
|
|
1560
|
-
if (isStillWithinThreshold || !didScrollSinceRequest) {
|
|
1561
|
-
state.maintainingScrollAtEnd = activeState;
|
|
1562
|
-
const scroller = refScroller.current;
|
|
1563
|
-
if (state.props.horizontal && isHorizontalRTL(state)) {
|
|
1564
|
-
const currentContentSize = getContentSize(ctx);
|
|
1565
|
-
const logicalEndOffset = getLogicalHorizontalMaxOffset(state, currentContentSize);
|
|
1566
|
-
const nativeOffset = toNativeHorizontalOffset(state, logicalEndOffset, currentContentSize);
|
|
1567
|
-
scroller == null ? void 0 : scroller.scrollTo({
|
|
1568
|
-
animated: maintainScrollAtEnd.animated,
|
|
1569
|
-
x: nativeOffset,
|
|
1570
|
-
y: 0
|
|
1571
|
-
});
|
|
1572
|
-
} else {
|
|
1573
|
-
scroller == null ? void 0 : scroller.scrollToEnd({
|
|
1574
|
-
animated: maintainScrollAtEnd.animated
|
|
1575
|
-
});
|
|
1576
|
-
}
|
|
1577
|
-
setTimeout(
|
|
1578
|
-
() => {
|
|
1579
|
-
if (state.maintainingScrollAtEnd === activeState) {
|
|
1580
|
-
state.maintainingScrollAtEnd = void 0;
|
|
1581
|
-
if (state.pendingMaintainScrollAtEnd) {
|
|
1582
|
-
doMaintainScrollAtEnd(ctx);
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1585
|
-
},
|
|
1586
|
-
maintainScrollAtEnd.animated ? 500 : 0
|
|
1587
|
-
);
|
|
1588
|
-
} else if (state.maintainingScrollAtEnd === pendingState) {
|
|
1589
|
-
state.maintainingScrollAtEnd = void 0;
|
|
1590
|
-
state.pendingMaintainScrollAtEnd = false;
|
|
1545
|
+
// src/core/scrollRequestTracker.ts
|
|
1546
|
+
function getScrollRequestTracker(ctx) {
|
|
1547
|
+
if (!ctx.scrollRequestTracker) {
|
|
1548
|
+
let currentToken = 0;
|
|
1549
|
+
const start = (resolve) => {
|
|
1550
|
+
const state = ctx.state;
|
|
1551
|
+
state.scheduledWork.cancel("imperativeScrollReady");
|
|
1552
|
+
const token = ++currentToken;
|
|
1553
|
+
settlePendingImperativeScroll(state);
|
|
1554
|
+
state.pendingScrollResolve = resolve;
|
|
1555
|
+
return token;
|
|
1556
|
+
};
|
|
1557
|
+
const runNow = (token, resolve, run) => {
|
|
1558
|
+
const state = ctx.state;
|
|
1559
|
+
if (token !== currentToken) {
|
|
1560
|
+
return;
|
|
1561
|
+
}
|
|
1562
|
+
const didStartScroll = run();
|
|
1563
|
+
if (!didStartScroll || !state.scrollingTo) {
|
|
1564
|
+
if (state.pendingScrollResolve === resolve) {
|
|
1565
|
+
state.pendingScrollResolve = void 0;
|
|
1591
1566
|
}
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1567
|
+
resolve();
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1570
|
+
ctx.scrollRequestTracker = {
|
|
1571
|
+
isCurrent: (token) => token === currentToken,
|
|
1572
|
+
runNow,
|
|
1573
|
+
runNowIfIdle: (run) => {
|
|
1574
|
+
const state = ctx.state;
|
|
1575
|
+
if (state.pendingScrollResolve || state.scrollingTo) {
|
|
1576
|
+
return Promise.resolve();
|
|
1577
|
+
}
|
|
1578
|
+
return new Promise((resolve) => {
|
|
1579
|
+
const token = start(resolve);
|
|
1580
|
+
runNow(token, resolve, run);
|
|
1581
|
+
});
|
|
1582
|
+
},
|
|
1583
|
+
start
|
|
1584
|
+
};
|
|
1597
1585
|
}
|
|
1598
|
-
|
|
1599
|
-
return false;
|
|
1586
|
+
return ctx.scrollRequestTracker;
|
|
1600
1587
|
}
|
|
1601
1588
|
|
|
1602
1589
|
// src/utils/requestAdjust.ts
|
|
1603
|
-
function requestAdjust(ctx, positionDiff,
|
|
1590
|
+
function requestAdjust(ctx, positionDiff, source) {
|
|
1604
1591
|
const state = ctx.state;
|
|
1605
1592
|
if (Math.abs(positionDiff) > 0.1) {
|
|
1593
|
+
const dataChanged = source === "data";
|
|
1606
1594
|
const needsScrollWorkaround = Platform.OS === "android" && !IsNewArchitecture && dataChanged && state.scroll <= positionDiff;
|
|
1607
1595
|
const doit = () => {
|
|
1608
1596
|
if (needsScrollWorkaround) {
|
|
@@ -1619,7 +1607,7 @@ function requestAdjust(ctx, positionDiff, dataChanged) {
|
|
|
1619
1607
|
const readyToRender = peek$(ctx, "readyToRender");
|
|
1620
1608
|
if (readyToRender) {
|
|
1621
1609
|
doit();
|
|
1622
|
-
if (Platform.OS !== "web") {
|
|
1610
|
+
if (Platform.OS !== "web" && source !== "item-size") {
|
|
1623
1611
|
const threshold = state.scroll - positionDiff / 2;
|
|
1624
1612
|
if (!state.ignoreScrollFromMVCP) {
|
|
1625
1613
|
state.ignoreScrollFromMVCP = {};
|
|
@@ -1652,6 +1640,87 @@ function requestAdjust(ctx, positionDiff, dataChanged) {
|
|
|
1652
1640
|
}
|
|
1653
1641
|
}
|
|
1654
1642
|
|
|
1643
|
+
// src/core/doMaintainScrollAtEnd.ts
|
|
1644
|
+
function finishMaintainScrollAtEnd(ctx) {
|
|
1645
|
+
var _a3;
|
|
1646
|
+
const { state } = ctx;
|
|
1647
|
+
const currentPadding = peek$(ctx, "alignItemsAtEndPadding") || 0;
|
|
1648
|
+
const nextPadding = getAlignItemsAtEndPadding(ctx);
|
|
1649
|
+
state.maintainingScrollAtEnd = void 0;
|
|
1650
|
+
state.pendingMaintainScrollAtEnd = false;
|
|
1651
|
+
if (currentPadding !== nextPadding) {
|
|
1652
|
+
set$(ctx, "alignItemsAtEndPadding", nextPadding);
|
|
1653
|
+
state.scrollForNextCalculateItemsInView = void 0;
|
|
1654
|
+
(_a3 = state.triggerCalculateItemsInView) == null ? void 0 : _a3.call(state, { forceFullItemPositions: true });
|
|
1655
|
+
const nextScroll = clampScrollOffset(ctx, state.scroll + nextPadding - currentPadding);
|
|
1656
|
+
requestAdjust(ctx, nextScroll - state.scroll);
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
function doMaintainScrollAtEnd(ctx) {
|
|
1660
|
+
const state = ctx.state;
|
|
1661
|
+
const {
|
|
1662
|
+
didContainersLayout,
|
|
1663
|
+
didFinishInitialScroll,
|
|
1664
|
+
pendingNativeMVCPAdjust,
|
|
1665
|
+
props: { maintainScrollAtEnd }
|
|
1666
|
+
} = state;
|
|
1667
|
+
const isWithinMaintainScrollAtEndThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
|
|
1668
|
+
const isReplayingPendingMaintain = !!state.pendingMaintainScrollAtEnd;
|
|
1669
|
+
const shouldMaintainScrollAtEnd = !!((isWithinMaintainScrollAtEndThreshold || isReplayingPendingMaintain) && maintainScrollAtEnd && didFinishInitialScroll);
|
|
1670
|
+
if (shouldMaintainScrollAtEnd && !didContainersLayout) {
|
|
1671
|
+
state.pendingMaintainScrollAtEnd = true;
|
|
1672
|
+
return false;
|
|
1673
|
+
}
|
|
1674
|
+
if (pendingNativeMVCPAdjust) {
|
|
1675
|
+
state.pendingMaintainScrollAtEnd = shouldMaintainScrollAtEnd;
|
|
1676
|
+
return false;
|
|
1677
|
+
}
|
|
1678
|
+
if (shouldMaintainScrollAtEnd && didContainersLayout) {
|
|
1679
|
+
state.pendingMaintainScrollAtEnd = false;
|
|
1680
|
+
const contentSize = getContentSize(ctx);
|
|
1681
|
+
if (contentSize < state.scrollLength) {
|
|
1682
|
+
state.scroll = 0;
|
|
1683
|
+
}
|
|
1684
|
+
if (!state.maintainingScrollAtEnd) {
|
|
1685
|
+
const pendingState = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
|
|
1686
|
+
const activeState = maintainScrollAtEnd.animated ? "animated" : "instant";
|
|
1687
|
+
const scrollAtRequest = state.scroll;
|
|
1688
|
+
state.maintainingScrollAtEnd = pendingState;
|
|
1689
|
+
requestAnimationFrame(() => {
|
|
1690
|
+
if (state.maintainingScrollAtEnd !== pendingState) {
|
|
1691
|
+
return;
|
|
1692
|
+
}
|
|
1693
|
+
const isStillWithinThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
|
|
1694
|
+
const didScrollSinceRequest = state.scroll !== scrollAtRequest;
|
|
1695
|
+
if (isReplayingPendingMaintain || isStillWithinThreshold || !didScrollSinceRequest) {
|
|
1696
|
+
state.maintainingScrollAtEnd = activeState;
|
|
1697
|
+
const scrollPromise = getScrollRequestTracker(ctx).runNowIfIdle(
|
|
1698
|
+
() => ctx.scrollToEnd({ animated: maintainScrollAtEnd.animated })
|
|
1699
|
+
);
|
|
1700
|
+
void scrollPromise.then(() => {
|
|
1701
|
+
if (state.maintainingScrollAtEnd !== activeState) {
|
|
1702
|
+
return;
|
|
1703
|
+
}
|
|
1704
|
+
if (state.pendingMaintainScrollAtEnd) {
|
|
1705
|
+
state.maintainingScrollAtEnd = void 0;
|
|
1706
|
+
doMaintainScrollAtEnd(ctx);
|
|
1707
|
+
} else {
|
|
1708
|
+
finishMaintainScrollAtEnd(ctx);
|
|
1709
|
+
}
|
|
1710
|
+
});
|
|
1711
|
+
} else if (state.maintainingScrollAtEnd === pendingState) {
|
|
1712
|
+
finishMaintainScrollAtEnd(ctx);
|
|
1713
|
+
}
|
|
1714
|
+
});
|
|
1715
|
+
} else {
|
|
1716
|
+
state.pendingMaintainScrollAtEnd = true;
|
|
1717
|
+
}
|
|
1718
|
+
return true;
|
|
1719
|
+
}
|
|
1720
|
+
finishMaintainScrollAtEnd(ctx);
|
|
1721
|
+
return false;
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1655
1724
|
// src/core/mvcp.ts
|
|
1656
1725
|
var MVCP_POSITION_EPSILON = 0.1;
|
|
1657
1726
|
var MVCP_ANCHOR_LOCK_TTL_MS = 300;
|
|
@@ -1725,7 +1794,7 @@ function settlePendingNativeMVCPAdjust(ctx, remainingAfterManual, nativeDelta) {
|
|
|
1725
1794
|
state.pendingNativeMVCPAdjust = void 0;
|
|
1726
1795
|
const remaining = remainingAfterManual - nativeDelta;
|
|
1727
1796
|
if (Math.abs(remaining) > MVCP_POSITION_EPSILON) {
|
|
1728
|
-
requestAdjust(ctx, remaining,
|
|
1797
|
+
requestAdjust(ctx, remaining, "data");
|
|
1729
1798
|
}
|
|
1730
1799
|
}
|
|
1731
1800
|
function maybeApplyPredictedNativeMVCPAdjust(ctx) {
|
|
@@ -1744,7 +1813,7 @@ function maybeApplyPredictedNativeMVCPAdjust(ctx) {
|
|
|
1744
1813
|
return;
|
|
1745
1814
|
}
|
|
1746
1815
|
pending.manualApplied = manualDesired;
|
|
1747
|
-
requestAdjust(ctx, manualDesired,
|
|
1816
|
+
requestAdjust(ctx, manualDesired, "data");
|
|
1748
1817
|
pending.furthestProgressTowardAmount = 0;
|
|
1749
1818
|
}
|
|
1750
1819
|
function resolvePendingNativeMVCPAdjust(ctx, newScroll) {
|
|
@@ -1790,7 +1859,7 @@ function resolvePendingNativeMVCPAdjust(ctx, newScroll) {
|
|
|
1790
1859
|
}
|
|
1791
1860
|
return false;
|
|
1792
1861
|
}
|
|
1793
|
-
function prepareMVCP(ctx, dataChanged) {
|
|
1862
|
+
function prepareMVCP(ctx, dataChanged, adjustmentSource) {
|
|
1794
1863
|
const state = ctx.state;
|
|
1795
1864
|
const { idsInView, positions, props } = state;
|
|
1796
1865
|
const {
|
|
@@ -1944,7 +2013,7 @@ function prepareMVCP(ctx, dataChanged) {
|
|
|
1944
2013
|
if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
|
|
1945
2014
|
const shouldSkipAdjustForMaintainedEnd = (state.maintainingScrollAtEnd === "pending-animated" || state.maintainingScrollAtEnd === "animated") && peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
|
|
1946
2015
|
if (!shouldSkipAdjustForMaintainedEnd) {
|
|
1947
|
-
requestAdjust(ctx, positionDiff, dataChanged && mvcpData);
|
|
2016
|
+
requestAdjust(ctx, positionDiff, dataChanged && mvcpData ? "data" : adjustmentSource);
|
|
1948
2017
|
}
|
|
1949
2018
|
}
|
|
1950
2019
|
};
|
|
@@ -2042,6 +2111,10 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
|
|
|
2042
2111
|
state.scrollTime = currentTime;
|
|
2043
2112
|
const scrollDelta = Math.abs(newScroll - prevScroll);
|
|
2044
2113
|
const isUserScrollEvent = !!(options == null ? void 0 : options.fromNativeScrollEvent) && scrollDelta > 0.1 && !adjustChanged && scrollingTo === void 0 && !state.pendingNativeMVCPAdjust;
|
|
2114
|
+
const didCancelMaintainScrollAtEnd = isUserScrollEvent && newScroll < prevScroll && !!(state.maintainingScrollAtEnd || state.pendingMaintainScrollAtEnd);
|
|
2115
|
+
if (didCancelMaintainScrollAtEnd) {
|
|
2116
|
+
finishMaintainScrollAtEnd(ctx);
|
|
2117
|
+
}
|
|
2045
2118
|
const allowedEdge = isUserScrollEvent ? beginReachedEdgeUserScroll(ctx, newScroll - prevScroll) : void 0;
|
|
2046
2119
|
const didResolvePendingNativeMVCPAdjust = resolvePendingNativeMVCPAdjust(ctx, newScroll);
|
|
2047
2120
|
const scrollLength = state.scrollLength;
|
|
@@ -2050,7 +2123,7 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
|
|
|
2050
2123
|
updateAdaptiveRender(ctx, scrollVelocity, { forceLight: isLargeUserScrollJump });
|
|
2051
2124
|
const lastCalculated = state.scrollLastCalculate;
|
|
2052
2125
|
const useAggressiveItemRecalculation = isInMVCPActiveMode(state);
|
|
2053
|
-
const shouldUpdate = useAggressiveItemRecalculation || didResolvePendingNativeMVCPAdjust || allowedEdge !== void 0 || forceUpdate || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
|
|
2126
|
+
const shouldUpdate = useAggressiveItemRecalculation || didResolvePendingNativeMVCPAdjust || didCancelMaintainScrollAtEnd || allowedEdge !== void 0 || forceUpdate || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
|
|
2054
2127
|
if (shouldUpdate) {
|
|
2055
2128
|
state.scrollLastCalculate = state.scroll;
|
|
2056
2129
|
state.ignoreScrollFromMVCPIgnored = false;
|
|
@@ -2879,7 +2952,7 @@ function handleBootstrapInitialScrollFooterLayout(ctx, options) {
|
|
|
2879
2952
|
}
|
|
2880
2953
|
}
|
|
2881
2954
|
function handleBootstrapInitialScrollLayoutChange(ctx) {
|
|
2882
|
-
var _a3, _b
|
|
2955
|
+
var _a3, _b;
|
|
2883
2956
|
const state = ctx.state;
|
|
2884
2957
|
const initialScroll = state.initialScroll;
|
|
2885
2958
|
const bootstrapInitialScroll = getBootstrapInitialScrollSession(state);
|
|
@@ -2893,19 +2966,15 @@ function handleBootstrapInitialScrollLayoutChange(ctx) {
|
|
|
2893
2966
|
if (state.didFinishInitialScroll) {
|
|
2894
2967
|
schedulePreservedEndAnchorCorrection(ctx);
|
|
2895
2968
|
} else if (scrollingTo) {
|
|
2896
|
-
const existingWatchdog = initialScrollWatchdog.get(state);
|
|
2897
|
-
scrollingTo.offset = resolvedOffset;
|
|
2898
|
-
scrollingTo.targetOffset = resolvedOffset;
|
|
2899
2969
|
state.initialScroll = {
|
|
2900
2970
|
...initialScroll,
|
|
2901
2971
|
contentOffset: resolvedOffset
|
|
2902
2972
|
};
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2973
|
+
dispatchInitialScroll(ctx, {
|
|
2974
|
+
forceScroll: true,
|
|
2975
|
+
resolvedOffset,
|
|
2976
|
+
target: state.initialScroll
|
|
2907
2977
|
});
|
|
2908
|
-
requestAdjust(ctx, offsetDiff);
|
|
2909
2978
|
}
|
|
2910
2979
|
}
|
|
2911
2980
|
} else {
|
|
@@ -3947,6 +4016,9 @@ function setDidLayout(ctx) {
|
|
|
3947
4016
|
state.queuedInitialLayout = true;
|
|
3948
4017
|
checkAtBottom(ctx);
|
|
3949
4018
|
setInitialRenderState(ctx, { didLayout: true });
|
|
4019
|
+
if (state.pendingMaintainScrollAtEnd) {
|
|
4020
|
+
doMaintainScrollAtEnd(ctx);
|
|
4021
|
+
}
|
|
3950
4022
|
}
|
|
3951
4023
|
|
|
3952
4024
|
// src/core/calculateItemsInView.ts
|
|
@@ -4183,7 +4255,7 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4183
4255
|
const stickyHeaderIndicesArr = state.props.stickyHeaderIndicesArr || [];
|
|
4184
4256
|
const stickyHeaderIndicesSet = state.props.stickyHeaderIndicesSet || /* @__PURE__ */ new Set();
|
|
4185
4257
|
const drawDistance = getEffectiveDrawDistance(ctx, params.drawDistanceMode);
|
|
4186
|
-
const { dataChanged, doMVCP, forceFullItemPositions } = params;
|
|
4258
|
+
const { dataChanged, doMVCP, forceFullItemPositions, mvcpAdjustmentSource } = params;
|
|
4187
4259
|
const bootstrapInitialScrollState = ((_a3 = state.initialScrollSession) == null ? void 0 : _a3.kind) === "bootstrap" ? state.initialScrollSession.bootstrap : void 0;
|
|
4188
4260
|
const suppressInitialScrollSideEffects = !!bootstrapInitialScrollState;
|
|
4189
4261
|
const prevNumContainers = peek$(ctx, "numContainers");
|
|
@@ -4284,7 +4356,7 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4284
4356
|
}
|
|
4285
4357
|
}
|
|
4286
4358
|
}
|
|
4287
|
-
const checkMVCP = doMVCP && !suppressInitialScrollSideEffects ? prepareMVCP(ctx, dataChanged) : void 0;
|
|
4359
|
+
const checkMVCP = doMVCP && !suppressInitialScrollSideEffects ? prepareMVCP(ctx, dataChanged, mvcpAdjustmentSource) : void 0;
|
|
4288
4360
|
if (dataChanged) {
|
|
4289
4361
|
resetLayoutCachesForDataChange(state);
|
|
4290
4362
|
}
|
|
@@ -4698,12 +4770,15 @@ function runOrScheduleMVCPRecalculate(ctx) {
|
|
|
4698
4770
|
} else if (Platform.OS === "web") {
|
|
4699
4771
|
if (!state.mvcpAnchorLock) {
|
|
4700
4772
|
state.scheduledWork.cancel("mvcpRecalculate");
|
|
4701
|
-
calculateItemsInView(ctx, { doMVCP: true });
|
|
4773
|
+
calculateItemsInView(ctx, { doMVCP: true, mvcpAdjustmentSource: "item-size" });
|
|
4702
4774
|
} else if (!state.scheduledWork.has("mvcpRecalculate")) {
|
|
4703
|
-
state.scheduledWork.frame(
|
|
4775
|
+
state.scheduledWork.frame(
|
|
4776
|
+
() => calculateItemsInView(ctx, { doMVCP: true, mvcpAdjustmentSource: "item-size" }),
|
|
4777
|
+
"mvcpRecalculate"
|
|
4778
|
+
);
|
|
4704
4779
|
}
|
|
4705
4780
|
} else {
|
|
4706
|
-
calculateItemsInView(ctx, { doMVCP: true });
|
|
4781
|
+
calculateItemsInView(ctx, { doMVCP: true, mvcpAdjustmentSource: "item-size" });
|
|
4707
4782
|
}
|
|
4708
4783
|
}
|
|
4709
4784
|
function updateOtherAxisSizeIfNeeded(ctx, sizeObj, horizontal) {
|
|
@@ -5192,6 +5267,30 @@ function useContainerItemSignals(containerContext) {
|
|
|
5192
5267
|
itemKey
|
|
5193
5268
|
};
|
|
5194
5269
|
}
|
|
5270
|
+
function scheduleViewabilityConfigWarning(ctx, hookName, configId) {
|
|
5271
|
+
let cancelled = false;
|
|
5272
|
+
Promise.resolve().then(() => {
|
|
5273
|
+
var _a3;
|
|
5274
|
+
const viewabilityConfigCallbackPairs = (_a3 = ctx.state) == null ? void 0 : _a3.viewabilityConfigCallbackPairs;
|
|
5275
|
+
if (!cancelled && ctx.state) {
|
|
5276
|
+
if (!(viewabilityConfigCallbackPairs == null ? void 0 : viewabilityConfigCallbackPairs.length)) {
|
|
5277
|
+
warnDevOnce(
|
|
5278
|
+
`${hookName}-missing-viewability-config`,
|
|
5279
|
+
`${hookName} requires viewability to be configured on the owning LegendList. Add viewabilityConfig with a visibility threshold.`
|
|
5280
|
+
);
|
|
5281
|
+
} else if (hookName === "useViewability" && !viewabilityConfigCallbackPairs.some((pair) => pair.viewabilityConfig.id === (configId != null ? configId : ""))) {
|
|
5282
|
+
const configDescription = configId ? ` for configId "${configId}"` : "";
|
|
5283
|
+
warnDevOnce(
|
|
5284
|
+
`${hookName}-missing-viewability-config-${configId != null ? configId : "default"}`,
|
|
5285
|
+
`${hookName}${configDescription} requires a matching viewabilityConfig.id on the owning LegendList. Add an id to viewabilityConfig and pass the same id to useViewability.`
|
|
5286
|
+
);
|
|
5287
|
+
}
|
|
5288
|
+
}
|
|
5289
|
+
});
|
|
5290
|
+
return () => {
|
|
5291
|
+
cancelled = true;
|
|
5292
|
+
};
|
|
5293
|
+
}
|
|
5195
5294
|
function useAdaptiveRender() {
|
|
5196
5295
|
const [mode] = useArr$(["adaptiveRender"]);
|
|
5197
5296
|
return mode;
|
|
@@ -5231,7 +5330,9 @@ function useViewability(callback, configId) {
|
|
|
5231
5330
|
const { containerId } = containerContext;
|
|
5232
5331
|
const key = containerId + (configId != null ? configId : "");
|
|
5233
5332
|
ctx.mapViewabilityCallbacks.set(key, callback);
|
|
5333
|
+
const cancelConfigWarning = IS_DEV ? scheduleViewabilityConfigWarning(ctx, "useViewability", configId) : void 0;
|
|
5234
5334
|
return () => {
|
|
5335
|
+
cancelConfigWarning == null ? void 0 : cancelConfigWarning();
|
|
5235
5336
|
ctx.mapViewabilityCallbacks.delete(key);
|
|
5236
5337
|
};
|
|
5237
5338
|
}, [ctx, callback, configId, containerContext]);
|
|
@@ -5255,7 +5356,9 @@ function useViewabilityAmount(callback) {
|
|
|
5255
5356
|
}
|
|
5256
5357
|
const { containerId } = containerContext;
|
|
5257
5358
|
ctx.mapViewabilityAmountCallbacks.set(containerId, callback);
|
|
5359
|
+
const cancelConfigWarning = IS_DEV ? scheduleViewabilityConfigWarning(ctx, "useViewabilityAmount") : void 0;
|
|
5258
5360
|
return () => {
|
|
5361
|
+
cancelConfigWarning == null ? void 0 : cancelConfigWarning();
|
|
5259
5362
|
ctx.mapViewabilityAmountCallbacks.delete(containerId);
|
|
5260
5363
|
};
|
|
5261
5364
|
}, [ctx, callback, containerContext]);
|
|
@@ -6362,11 +6465,29 @@ var ScheduledWork = class {
|
|
|
6362
6465
|
constructor() {
|
|
6363
6466
|
this.work = /* @__PURE__ */ new Map();
|
|
6364
6467
|
}
|
|
6468
|
+
microtask(callback, key) {
|
|
6469
|
+
const pendingWork = this.work.get(key);
|
|
6470
|
+
if (pendingWork == null ? void 0 : pendingWork.callback) {
|
|
6471
|
+
pendingWork.callback = callback;
|
|
6472
|
+
} else {
|
|
6473
|
+
this.cancel(key);
|
|
6474
|
+
const work = { callback, cancel: () => {
|
|
6475
|
+
} };
|
|
6476
|
+
this.work.set(key, work);
|
|
6477
|
+
queueMicrotask(() => {
|
|
6478
|
+
var _a3;
|
|
6479
|
+
if (this.work.get(key) === work) {
|
|
6480
|
+
this.work.delete(key);
|
|
6481
|
+
(_a3 = work.callback) == null ? void 0 : _a3.call(work);
|
|
6482
|
+
}
|
|
6483
|
+
});
|
|
6484
|
+
}
|
|
6485
|
+
}
|
|
6365
6486
|
timeout(callback, delay, key) {
|
|
6366
6487
|
if (key) {
|
|
6367
6488
|
this.cancel(key);
|
|
6368
6489
|
}
|
|
6369
|
-
const work =
|
|
6490
|
+
const work = { cancel: () => clearTimeout(handle) };
|
|
6370
6491
|
const handle = setTimeout(() => {
|
|
6371
6492
|
const workKey = key != null ? key : handle;
|
|
6372
6493
|
if (this.work.get(workKey) === work) {
|
|
@@ -6374,14 +6495,13 @@ var ScheduledWork = class {
|
|
|
6374
6495
|
callback();
|
|
6375
6496
|
}
|
|
6376
6497
|
}, delay);
|
|
6377
|
-
work[0] = handle;
|
|
6378
6498
|
this.work.set(key != null ? key : handle, work);
|
|
6379
6499
|
}
|
|
6380
6500
|
frame(callback, key) {
|
|
6381
6501
|
this.cancel(key);
|
|
6382
|
-
const work =
|
|
6502
|
+
const work = { cancel: () => cancelAnimationFrame(handle) };
|
|
6383
6503
|
this.work.set(key, work);
|
|
6384
|
-
|
|
6504
|
+
const handle = requestAnimationFrame(() => {
|
|
6385
6505
|
if (this.work.get(key) === work) {
|
|
6386
6506
|
this.work.delete(key);
|
|
6387
6507
|
callback();
|
|
@@ -6390,22 +6510,21 @@ var ScheduledWork = class {
|
|
|
6390
6510
|
}
|
|
6391
6511
|
register(key, cancel) {
|
|
6392
6512
|
this.cancel(key);
|
|
6393
|
-
this.work.set(key,
|
|
6513
|
+
this.work.set(key, { cancel });
|
|
6394
6514
|
}
|
|
6395
6515
|
cancel(key) {
|
|
6396
6516
|
const work = this.work.get(key);
|
|
6397
6517
|
if (work) {
|
|
6398
6518
|
this.work.delete(key);
|
|
6399
|
-
|
|
6400
|
-
cancel(handle);
|
|
6519
|
+
work.cancel();
|
|
6401
6520
|
}
|
|
6402
6521
|
}
|
|
6403
6522
|
has(key) {
|
|
6404
6523
|
return this.work.has(key);
|
|
6405
6524
|
}
|
|
6406
6525
|
dispose() {
|
|
6407
|
-
for (const
|
|
6408
|
-
cancel(
|
|
6526
|
+
for (const work of this.work.values()) {
|
|
6527
|
+
work.cancel();
|
|
6409
6528
|
}
|
|
6410
6529
|
this.work.clear();
|
|
6411
6530
|
}
|
|
@@ -6462,6 +6581,25 @@ var ScrollAdjustHandler = class {
|
|
|
6462
6581
|
}
|
|
6463
6582
|
};
|
|
6464
6583
|
|
|
6584
|
+
// src/core/scrollToEnd.ts
|
|
6585
|
+
function scrollToEnd(ctx, options) {
|
|
6586
|
+
const state = ctx.state;
|
|
6587
|
+
const data = state.props.data;
|
|
6588
|
+
const index = data.length - 1;
|
|
6589
|
+
if (index === -1) {
|
|
6590
|
+
return false;
|
|
6591
|
+
}
|
|
6592
|
+
const paddingBottom = state.props.stylePaddingBottom || 0;
|
|
6593
|
+
const footerSize = peek$(ctx, "footerSize") || 0;
|
|
6594
|
+
scrollToIndex(ctx, {
|
|
6595
|
+
...options,
|
|
6596
|
+
index,
|
|
6597
|
+
viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
|
|
6598
|
+
viewPosition: 1
|
|
6599
|
+
});
|
|
6600
|
+
return true;
|
|
6601
|
+
}
|
|
6602
|
+
|
|
6465
6603
|
// src/core/updateContentInsetEndAdjustment.ts
|
|
6466
6604
|
function updateContentInsetEndAdjustment(ctx, previousContentInsetEndAdjustment) {
|
|
6467
6605
|
const state = ctx.state;
|
|
@@ -6536,25 +6674,6 @@ function createColumnWrapperStyle(contentContainerStyle) {
|
|
|
6536
6674
|
}
|
|
6537
6675
|
}
|
|
6538
6676
|
|
|
6539
|
-
// src/core/scrollToEnd.ts
|
|
6540
|
-
function scrollToEnd(ctx, options) {
|
|
6541
|
-
const state = ctx.state;
|
|
6542
|
-
const data = state.props.data;
|
|
6543
|
-
const index = data.length - 1;
|
|
6544
|
-
if (index === -1) {
|
|
6545
|
-
return false;
|
|
6546
|
-
}
|
|
6547
|
-
const paddingBottom = state.props.stylePaddingBottom || 0;
|
|
6548
|
-
const footerSize = peek$(ctx, "footerSize") || 0;
|
|
6549
|
-
scrollToIndex(ctx, {
|
|
6550
|
-
...options,
|
|
6551
|
-
index,
|
|
6552
|
-
viewOffset: -paddingBottom - footerSize + ((options == null ? void 0 : options.viewOffset) || 0),
|
|
6553
|
-
viewPosition: 1
|
|
6554
|
-
});
|
|
6555
|
-
return true;
|
|
6556
|
-
}
|
|
6557
|
-
|
|
6558
6677
|
// src/utils/createImperativeHandle.ts
|
|
6559
6678
|
var DEFAULT_AVERAGE_ITEM_SIZE_TYPE = "default";
|
|
6560
6679
|
function getAverageItemSizes(state) {
|
|
@@ -6581,9 +6700,9 @@ function triggerMountedContainerLayouts(ctx) {
|
|
|
6581
6700
|
}
|
|
6582
6701
|
function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
|
|
6583
6702
|
const state = ctx.state;
|
|
6703
|
+
const scrollRequestTracker = getScrollRequestTracker(ctx);
|
|
6584
6704
|
const IMPERATIVE_SCROLL_SETTLE_MAX_WAIT_MS = 800;
|
|
6585
6705
|
const IMPERATIVE_SCROLL_SETTLE_STABLE_FRAMES = 2;
|
|
6586
|
-
let imperativeScrollToken = 0;
|
|
6587
6706
|
const isSettlingAfterDataChange = () => !!state.didDataChange || !!state.didColumnsChange || state.scheduledWork.has("mvcpRecalculate") || state.ignoreScrollFromMVCP !== void 0;
|
|
6588
6707
|
const isScrollToIndexReady = (targetIndex, allowEmpty = false) => {
|
|
6589
6708
|
var _a3;
|
|
@@ -6605,7 +6724,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
|
|
|
6605
6724
|
const startedAt = Date.now();
|
|
6606
6725
|
let stableFrames = 0;
|
|
6607
6726
|
const check = () => {
|
|
6608
|
-
if (token
|
|
6727
|
+
if (!scrollRequestTracker.isCurrent(token)) {
|
|
6609
6728
|
return;
|
|
6610
6729
|
}
|
|
6611
6730
|
if (isSettlingAfterDataChange() || !isReady()) {
|
|
@@ -6623,33 +6742,15 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
|
|
|
6623
6742
|
state.scheduledWork.frame(check, "imperativeScrollReady");
|
|
6624
6743
|
};
|
|
6625
6744
|
const runScrollRequest = (token, resolve, run, isReady = () => true) => {
|
|
6626
|
-
const runNow = () =>
|
|
6627
|
-
if (token !== imperativeScrollToken) {
|
|
6628
|
-
return;
|
|
6629
|
-
}
|
|
6630
|
-
const didStartScroll = run();
|
|
6631
|
-
if (!didStartScroll || !state.scrollingTo) {
|
|
6632
|
-
if (state.pendingScrollResolve === resolve) {
|
|
6633
|
-
state.pendingScrollResolve = void 0;
|
|
6634
|
-
}
|
|
6635
|
-
resolve();
|
|
6636
|
-
}
|
|
6637
|
-
};
|
|
6745
|
+
const runNow = () => scrollRequestTracker.runNow(token, resolve, run);
|
|
6638
6746
|
if (isSettlingAfterDataChange() || !isReady()) {
|
|
6639
6747
|
runWhenReady(token, runNow, isReady);
|
|
6640
6748
|
} else {
|
|
6641
6749
|
runNow();
|
|
6642
6750
|
}
|
|
6643
6751
|
};
|
|
6644
|
-
const startImperativeScroll = (resolve) => {
|
|
6645
|
-
state.scheduledWork.cancel("imperativeScrollReady");
|
|
6646
|
-
const token = ++imperativeScrollToken;
|
|
6647
|
-
settlePendingImperativeScroll(state);
|
|
6648
|
-
state.pendingScrollResolve = resolve;
|
|
6649
|
-
return token;
|
|
6650
|
-
};
|
|
6651
6752
|
const runScrollWithPromise = (run, isReady = () => true) => new Promise((resolve) => {
|
|
6652
|
-
const token =
|
|
6753
|
+
const token = scrollRequestTracker.start(resolve);
|
|
6653
6754
|
supersedeInitialScroll(ctx);
|
|
6654
6755
|
runScrollRequest(token, resolve, run, isReady);
|
|
6655
6756
|
});
|
|
@@ -6657,7 +6758,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
|
|
|
6657
6758
|
const pendingScroll = state.pendingScrollToEnd;
|
|
6658
6759
|
if (pendingScroll) {
|
|
6659
6760
|
state.pendingScrollToEnd = void 0;
|
|
6660
|
-
if (pendingScroll.token
|
|
6761
|
+
if (scrollRequestTracker.isCurrent(pendingScroll.token)) {
|
|
6661
6762
|
runScrollRequest(
|
|
6662
6763
|
pendingScroll.token,
|
|
6663
6764
|
pendingScroll.resolve,
|
|
@@ -6771,7 +6872,7 @@ function createImperativeHandle(ctx, scheduleImperativeScrollCommit) {
|
|
|
6771
6872
|
}),
|
|
6772
6873
|
scrollToEnd: (options) => new Promise((resolve) => {
|
|
6773
6874
|
var _a3;
|
|
6774
|
-
const token =
|
|
6875
|
+
const token = scrollRequestTracker.start(resolve);
|
|
6775
6876
|
state.pendingScrollToEnd = {
|
|
6776
6877
|
options,
|
|
6777
6878
|
resolve,
|
|
@@ -7151,6 +7252,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7151
7252
|
const shouldInitializeHorizontalRTL = !initialScrollAtEnd && !hasInitialScrollIndex && !hasInitialScrollOffset && isHorizontalRTLProps({ horizontal, rtl });
|
|
7152
7253
|
const initialScrollUsesOffsetOnly = !initialScrollAtEnd && !hasInitialScrollIndex && (hasInitialScrollOffset || shouldInitializeHorizontalRTL);
|
|
7153
7254
|
const usesBootstrapInitialScroll = initialScrollAtEnd || hasInitialScrollIndex;
|
|
7255
|
+
const shouldBottomAlignNumericInitialScrollIndex = typeof initialScrollIndexProp === "number" && !hasInitialScrollOffset && dataProp.length > 1 && initialScrollIndexProp >= dataProp.length - 1;
|
|
7154
7256
|
const initialScrollProp = initialScrollAtEnd ? {
|
|
7155
7257
|
index: Math.max(0, dataProp.length - 1),
|
|
7156
7258
|
preserveForBottomPadding: true,
|
|
@@ -7163,7 +7265,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7163
7265
|
viewPosition: (_d = initialScrollIndexProp.viewPosition) != null ? _d : 0
|
|
7164
7266
|
} : {
|
|
7165
7267
|
index: initialScrollIndexProp != null ? initialScrollIndexProp : 0,
|
|
7166
|
-
|
|
7268
|
+
preserveForBottomPadding: shouldBottomAlignNumericInitialScrollIndex ? true : void 0,
|
|
7269
|
+
viewOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : shouldBottomAlignNumericInitialScrollIndex ? -stylePaddingEndState : 0,
|
|
7270
|
+
viewPosition: shouldBottomAlignNumericInitialScrollIndex ? 1 : void 0
|
|
7167
7271
|
} : initialScrollUsesOffsetOnly ? {
|
|
7168
7272
|
contentOffset: initialScrollOffsetProp != null ? initialScrollOffsetProp : 0,
|
|
7169
7273
|
index: 0,
|
|
@@ -7269,6 +7373,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7269
7373
|
viewabilityConfigCallbackPairs: void 0
|
|
7270
7374
|
};
|
|
7271
7375
|
const internalState = ctx.state;
|
|
7376
|
+
ctx.scrollToEnd = (options) => scrollToEnd(ctx, options);
|
|
7272
7377
|
internalState.triggerCalculateItemsInView = (params) => calculateItemsInView(ctx, params);
|
|
7273
7378
|
internalState.reprocessCurrentScroll = () => updateScroll(ctx, internalState.scroll, true);
|
|
7274
7379
|
set$(ctx, "maintainVisibleContentPosition", maintainVisibleContentPositionConfig);
|
|
@@ -7630,6 +7735,13 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7630
7735
|
onScroll: (event) => onScroll(ctx, event),
|
|
7631
7736
|
onScrollBeginDrag: (event) => {
|
|
7632
7737
|
var _a4, _b2;
|
|
7738
|
+
const maintainingScrollAtEnd = state.maintainingScrollAtEnd;
|
|
7739
|
+
if (maintainingScrollAtEnd === "animated" || maintainingScrollAtEnd === "instant") {
|
|
7740
|
+
cancelImperativeScroll(state);
|
|
7741
|
+
}
|
|
7742
|
+
if (maintainingScrollAtEnd) {
|
|
7743
|
+
finishMaintainScrollAtEnd(ctx);
|
|
7744
|
+
}
|
|
7633
7745
|
prepareReachedEdgeForNextUserScroll(ctx);
|
|
7634
7746
|
(_b2 = (_a4 = state.props).onScrollBeginDrag) == null ? void 0 : _b2.call(_a4, event);
|
|
7635
7747
|
},
|