@legendapp/list 3.0.0-beta.31 → 3.0.0-beta.33
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/README.md +7 -1
- package/animated.d.ts +600 -6
- package/animated.js +2 -2
- package/animated.mjs +1 -1
- package/index.d.ts +462 -109
- package/index.js +290 -147
- package/index.mjs +290 -147
- package/index.native.js +245 -122
- package/index.native.mjs +246 -123
- package/keyboard-controller.d.ts +611 -6
- package/keyboard-controller.js +2 -2
- package/keyboard-controller.mjs +1 -1
- package/keyboard.d.ts +204 -8
- package/keyboard.js +66 -52
- package/keyboard.mjs +69 -54
- package/{index.d.mts → list-react-native.d.ts} +103 -33
- package/list-react-native.js +4234 -0
- package/list-react-native.mjs +4204 -0
- package/{index.native.d.mts → list-react.d.ts} +363 -41
- package/list-react.js +4426 -0
- package/list-react.mjs +4396 -0
- package/package.json +52 -1
- package/reanimated.d.ts +595 -7
- package/reanimated.js +156 -11
- package/reanimated.mjs +153 -8
- package/section-list.d.ts +610 -14
- package/section-list.js +6 -6
- package/section-list.mjs +1 -1
- package/animated.d.mts +0 -9
- package/animated.native.d.mts +0 -9
- package/animated.native.d.ts +0 -9
- package/animated.native.js +0 -9
- package/animated.native.mjs +0 -7
- package/index.native.d.ts +0 -810
- package/keyboard-controller.d.mts +0 -12
- package/keyboard-controller.native.d.mts +0 -12
- package/keyboard-controller.native.d.ts +0 -12
- package/keyboard-controller.native.js +0 -69
- package/keyboard-controller.native.mjs +0 -48
- package/keyboard.d.mts +0 -13
- package/keyboard.native.d.mts +0 -13
- package/keyboard.native.d.ts +0 -13
- package/keyboard.native.js +0 -399
- package/keyboard.native.mjs +0 -377
- package/reanimated.d.mts +0 -18
- package/reanimated.native.d.mts +0 -18
- package/reanimated.native.d.ts +0 -18
- package/reanimated.native.js +0 -89
- package/reanimated.native.mjs +0 -65
- package/section-list.d.mts +0 -112
- package/section-list.native.d.mts +0 -112
- package/section-list.native.d.ts +0 -112
- package/section-list.native.js +0 -293
- package/section-list.native.mjs +0 -271
package/index.js
CHANGED
|
@@ -42,7 +42,7 @@ function getContentInsetEnd(state) {
|
|
|
42
42
|
const baseInset = contentInset != null ? contentInset : state.nativeContentInset;
|
|
43
43
|
const overrideInset = (_a3 = state.contentInsetOverride) != null ? _a3 : void 0;
|
|
44
44
|
if (overrideInset) {
|
|
45
|
-
const mergedInset = { bottom: 0,
|
|
45
|
+
const mergedInset = { bottom: 0, right: 0, ...baseInset, ...overrideInset };
|
|
46
46
|
return (horizontal ? mergedInset.right : mergedInset.bottom) || 0;
|
|
47
47
|
}
|
|
48
48
|
if (baseInset) {
|
|
@@ -193,7 +193,7 @@ function useSelector$(signalName, selector) {
|
|
|
193
193
|
var DebugRow = ({ children }) => {
|
|
194
194
|
return /* @__PURE__ */ React3__namespace.createElement(View, { style: { alignItems: "center", flexDirection: "row", justifyContent: "space-between" } }, children);
|
|
195
195
|
};
|
|
196
|
-
|
|
196
|
+
React3__namespace.memo(function DebugView2({ state }) {
|
|
197
197
|
const ctx = useStateContext();
|
|
198
198
|
const [totalSize = 0, scrollAdjust = 0, rawScroll = 0, scroll = 0, _numContainers = 0, _numContainersPooled = 0] = useArr$([
|
|
199
199
|
"totalSize",
|
|
@@ -245,7 +245,7 @@ var _a;
|
|
|
245
245
|
var envMode = typeof process !== "undefined" && typeof process.env === "object" && process.env ? (_a = process.env.NODE_ENV) != null ? _a : process.env.MODE : void 0;
|
|
246
246
|
var processDev = typeof envMode === "string" ? envMode.toLowerCase() !== "production" : void 0;
|
|
247
247
|
var _a2;
|
|
248
|
-
var IS_DEV = (_a2 =
|
|
248
|
+
var IS_DEV = (_a2 = processDev != null ? processDev : metroDev) != null ? _a2 : false;
|
|
249
249
|
|
|
250
250
|
// src/constants.ts
|
|
251
251
|
var POSITION_OUT_OF_VIEW = -1e7;
|
|
@@ -328,7 +328,10 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
|
|
|
328
328
|
children,
|
|
329
329
|
...rest
|
|
330
330
|
}) {
|
|
331
|
-
const [position = POSITION_OUT_OF_VIEW, activeStickyIndex] = useArr$([
|
|
331
|
+
const [position = POSITION_OUT_OF_VIEW, activeStickyIndex] = useArr$([
|
|
332
|
+
`containerPosition${id}`,
|
|
333
|
+
"activeStickyIndex"
|
|
334
|
+
]);
|
|
332
335
|
const base = {
|
|
333
336
|
contain: "paint layout style"
|
|
334
337
|
};
|
|
@@ -358,9 +361,6 @@ var PositionViewSticky = typedMemo(function PositionViewSticky2({
|
|
|
358
361
|
return /* @__PURE__ */ React3__namespace.createElement("div", { ref: refView, style: viewStyle, ...rest }, children);
|
|
359
362
|
});
|
|
360
363
|
var PositionView = PositionViewState;
|
|
361
|
-
|
|
362
|
-
// src/constants-platform.ts
|
|
363
|
-
var IsNewArchitecture = true;
|
|
364
364
|
function useInit(cb) {
|
|
365
365
|
React3.useState(() => cb());
|
|
366
366
|
}
|
|
@@ -571,7 +571,8 @@ function createResizeObserver(element, callback) {
|
|
|
571
571
|
function useOnLayoutSync({
|
|
572
572
|
ref,
|
|
573
573
|
onLayoutProp,
|
|
574
|
-
onLayoutChange
|
|
574
|
+
onLayoutChange,
|
|
575
|
+
webLayoutResync
|
|
575
576
|
}, deps) {
|
|
576
577
|
React3.useLayoutEffect(() => {
|
|
577
578
|
var _a3, _b;
|
|
@@ -595,7 +596,9 @@ function useOnLayoutSync({
|
|
|
595
596
|
var _a4;
|
|
596
597
|
const target = entry.target instanceof HTMLElement ? entry.target : void 0;
|
|
597
598
|
const rectObserved = (_a4 = entry.contentRect) != null ? _a4 : target == null ? void 0 : target.getBoundingClientRect();
|
|
598
|
-
|
|
599
|
+
const didSizeChange = rectObserved.width !== prevRect.width || rectObserved.height !== prevRect.height;
|
|
600
|
+
const shouldResyncLayout = !!(webLayoutResync == null ? void 0 : webLayoutResync());
|
|
601
|
+
if (didSizeChange || shouldResyncLayout) {
|
|
599
602
|
prevRect = rectObserved;
|
|
600
603
|
emit(toLayout(rectObserved), false);
|
|
601
604
|
}
|
|
@@ -621,6 +624,15 @@ var Platform = {
|
|
|
621
624
|
OS: "web"
|
|
622
625
|
};
|
|
623
626
|
|
|
627
|
+
// src/utils/isInMVCPActiveMode.ts
|
|
628
|
+
function isInMVCPActiveMode(state) {
|
|
629
|
+
const lock = state.mvcpAnchorLock;
|
|
630
|
+
if (lock && Date.now() > lock.expiresAt) {
|
|
631
|
+
state.mvcpAnchorLock = void 0;
|
|
632
|
+
}
|
|
633
|
+
return state.dataChangeNeedsScrollUpdate || !!state.mvcpAnchorLock;
|
|
634
|
+
}
|
|
635
|
+
|
|
624
636
|
// src/components/Container.tsx
|
|
625
637
|
var Container = typedMemo(function Container2({
|
|
626
638
|
id,
|
|
@@ -633,6 +645,7 @@ var Container = typedMemo(function Container2({
|
|
|
633
645
|
}) {
|
|
634
646
|
const ctx = useStateContext();
|
|
635
647
|
const { columnWrapperStyle, animatedScrollY } = ctx;
|
|
648
|
+
const stickyPositionComponentInternal = ctx.state.props.stickyPositionComponentInternal;
|
|
636
649
|
const [column = 0, span = 1, data, itemKey, numColumns = 1, extraData, isSticky] = useArr$([
|
|
637
650
|
`containerColumn${id}`,
|
|
638
651
|
`containerSpan${id}`,
|
|
@@ -728,7 +741,8 @@ var Container = typedMemo(function Container2({
|
|
|
728
741
|
updateItemSizeFn(currentItemKey, layout);
|
|
729
742
|
itemLayoutRef.current.didLayout = true;
|
|
730
743
|
};
|
|
731
|
-
|
|
744
|
+
const shouldDeferWebShrinkLayoutUpdate = !isInMVCPActiveMode(ctx.state) && prevSize !== void 0 && size + 1 < prevSize;
|
|
745
|
+
if (shouldDeferWebShrinkLayoutUpdate) {
|
|
732
746
|
const token = pendingShrinkToken + 1;
|
|
733
747
|
itemLayoutRef.current.pendingShrinkToken = token;
|
|
734
748
|
requestAnimationFrame(() => {
|
|
@@ -752,11 +766,12 @@ var Container = typedMemo(function Container2({
|
|
|
752
766
|
const { onLayout } = useOnLayoutSync(
|
|
753
767
|
{
|
|
754
768
|
onLayoutChange,
|
|
755
|
-
ref
|
|
769
|
+
ref,
|
|
770
|
+
webLayoutResync: () => isInMVCPActiveMode(ctx.state)
|
|
756
771
|
},
|
|
757
772
|
[itemKey, layoutRenderCount]
|
|
758
773
|
);
|
|
759
|
-
const PositionComponent = isSticky ? PositionViewSticky : PositionView;
|
|
774
|
+
const PositionComponent = isSticky ? stickyPositionComponentInternal ? stickyPositionComponentInternal : PositionViewSticky : PositionView;
|
|
760
775
|
return /* @__PURE__ */ React3__namespace.createElement(
|
|
761
776
|
PositionComponent,
|
|
762
777
|
{
|
|
@@ -944,25 +959,6 @@ var Containers = typedMemo(function Containers2({
|
|
|
944
959
|
}
|
|
945
960
|
return /* @__PURE__ */ React3__namespace.createElement(ContainersInner, { horizontal, numColumns, waitForInitialLayout }, containers);
|
|
946
961
|
});
|
|
947
|
-
function DevNumbers() {
|
|
948
|
-
return IS_DEV && // biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
|
|
949
|
-
React3__namespace.memo(function DevNumbers2() {
|
|
950
|
-
return Array.from({ length: 100 }).map((_, index) => /* @__PURE__ */ React3__namespace.createElement(
|
|
951
|
-
"div",
|
|
952
|
-
{
|
|
953
|
-
key: index,
|
|
954
|
-
style: {
|
|
955
|
-
height: 100,
|
|
956
|
-
pointerEvents: "none",
|
|
957
|
-
position: "absolute",
|
|
958
|
-
top: index * 100,
|
|
959
|
-
width: "100%"
|
|
960
|
-
}
|
|
961
|
-
},
|
|
962
|
-
/* @__PURE__ */ React3__namespace.createElement("div", { style: { color: "red" } }, index * 100)
|
|
963
|
-
));
|
|
964
|
-
});
|
|
965
|
-
}
|
|
966
962
|
|
|
967
963
|
// src/platform/StyleSheet.tsx
|
|
968
964
|
function flattenStyles(styles) {
|
|
@@ -1137,6 +1133,7 @@ function useValueListener$(key, callback) {
|
|
|
1137
1133
|
function ScrollAdjust() {
|
|
1138
1134
|
const ctx = useStateContext();
|
|
1139
1135
|
const lastScrollOffsetRef = React3__namespace.useRef(0);
|
|
1136
|
+
const resetPaddingRafRef = React3__namespace.useRef(void 0);
|
|
1140
1137
|
const callback = React3__namespace.useCallback(() => {
|
|
1141
1138
|
var _a3;
|
|
1142
1139
|
const scrollAdjust = peek$(ctx, "scrollAdjust");
|
|
@@ -1151,13 +1148,17 @@ function ScrollAdjust() {
|
|
|
1151
1148
|
const nextScroll = prevScroll + scrollDelta;
|
|
1152
1149
|
const totalSize = el.scrollHeight;
|
|
1153
1150
|
if (scrollDelta > 0 && !ctx.state.adjustingFromInitialMount && totalSize < nextScroll + el.clientHeight) {
|
|
1151
|
+
const paddingBottom = ctx.state.props.stylePaddingBottom || 0;
|
|
1154
1152
|
const child = el.firstElementChild;
|
|
1155
1153
|
const pad = (nextScroll + el.clientHeight - totalSize) * 2;
|
|
1156
1154
|
child.style.paddingBottom = `${pad}px`;
|
|
1157
1155
|
void el.offsetHeight;
|
|
1158
1156
|
scrollView.scrollBy(0, scrollDelta);
|
|
1159
|
-
|
|
1160
|
-
|
|
1157
|
+
if (resetPaddingRafRef.current !== void 0) {
|
|
1158
|
+
cancelAnimationFrame(resetPaddingRafRef.current);
|
|
1159
|
+
}
|
|
1160
|
+
resetPaddingRafRef.current = requestAnimationFrame(() => {
|
|
1161
|
+
resetPaddingRafRef.current = void 0;
|
|
1161
1162
|
child.style.paddingBottom = paddingBottom ? `${paddingBottom}px` : "0";
|
|
1162
1163
|
});
|
|
1163
1164
|
} else {
|
|
@@ -1222,7 +1223,9 @@ var ListComponent = typedMemo(function ListComponent2({
|
|
|
1222
1223
|
const ctx = useStateContext();
|
|
1223
1224
|
const maintainVisibleContentPosition = ctx.state.props.maintainVisibleContentPosition;
|
|
1224
1225
|
const ScrollComponent = renderScrollComponent ? React3.useMemo(
|
|
1225
|
-
() => React3__namespace.forwardRef(
|
|
1226
|
+
() => React3__namespace.forwardRef(
|
|
1227
|
+
(props, ref) => renderScrollComponent({ ...props, ref })
|
|
1228
|
+
),
|
|
1226
1229
|
[renderScrollComponent]
|
|
1227
1230
|
) : ListComponentScrollView;
|
|
1228
1231
|
const SnapOrScroll = snapToIndices ? SnapWrapper : ScrollComponent;
|
|
@@ -1279,7 +1282,7 @@ var ListComponent = typedMemo(function ListComponent2({
|
|
|
1279
1282
|
},
|
|
1280
1283
|
getComponent(ListFooterComponent)
|
|
1281
1284
|
),
|
|
1282
|
-
IS_DEV && ENABLE_DEVMODE
|
|
1285
|
+
IS_DEV && ENABLE_DEVMODE
|
|
1283
1286
|
);
|
|
1284
1287
|
});
|
|
1285
1288
|
|
|
@@ -1413,12 +1416,15 @@ function calculateOffsetWithOffsetPosition(ctx, offsetParam, params) {
|
|
|
1413
1416
|
}
|
|
1414
1417
|
|
|
1415
1418
|
// src/core/clampScrollOffset.ts
|
|
1416
|
-
function clampScrollOffset(ctx, offset) {
|
|
1419
|
+
function clampScrollOffset(ctx, offset, scrollTarget) {
|
|
1417
1420
|
const state = ctx.state;
|
|
1418
1421
|
const contentSize = getContentSize(ctx);
|
|
1419
1422
|
let clampedOffset = offset;
|
|
1420
1423
|
if (Number.isFinite(contentSize) && Number.isFinite(state.scrollLength) && (Platform.OS !== "android")) {
|
|
1421
|
-
const
|
|
1424
|
+
const baseMaxOffset = Math.max(0, contentSize - state.scrollLength);
|
|
1425
|
+
const viewOffset = scrollTarget == null ? void 0 : scrollTarget.viewOffset;
|
|
1426
|
+
const extraEndOffset = typeof viewOffset === "number" && viewOffset < 0 ? -viewOffset : 0;
|
|
1427
|
+
const maxOffset = baseMaxOffset + extraEndOffset;
|
|
1422
1428
|
clampedOffset = Math.min(offset, maxOffset);
|
|
1423
1429
|
}
|
|
1424
1430
|
clampedOffset = Math.max(0, clampedOffset);
|
|
@@ -1513,7 +1519,7 @@ function checkAtBottom(ctx) {
|
|
|
1513
1519
|
function checkAtTop(ctx) {
|
|
1514
1520
|
var _a3;
|
|
1515
1521
|
const state = ctx == null ? void 0 : ctx.state;
|
|
1516
|
-
if (!state || state.initialScroll) {
|
|
1522
|
+
if (!state || state.initialScroll || state.scrollingTo) {
|
|
1517
1523
|
return;
|
|
1518
1524
|
}
|
|
1519
1525
|
const {
|
|
@@ -1557,14 +1563,22 @@ function setInitialRenderState(ctx, {
|
|
|
1557
1563
|
didInitialScroll
|
|
1558
1564
|
}) {
|
|
1559
1565
|
const { state } = ctx;
|
|
1566
|
+
const {
|
|
1567
|
+
loadStartTime,
|
|
1568
|
+
props: { onLoad }
|
|
1569
|
+
} = state;
|
|
1560
1570
|
if (didLayout) {
|
|
1561
1571
|
state.didContainersLayout = true;
|
|
1562
1572
|
}
|
|
1563
1573
|
if (didInitialScroll) {
|
|
1564
1574
|
state.didFinishInitialScroll = true;
|
|
1565
1575
|
}
|
|
1566
|
-
|
|
1576
|
+
const isReadyToRender = Boolean(state.didContainersLayout && state.didFinishInitialScroll);
|
|
1577
|
+
if (isReadyToRender && !peek$(ctx, "readyToRender")) {
|
|
1567
1578
|
set$(ctx, "readyToRender", true);
|
|
1579
|
+
if (onLoad) {
|
|
1580
|
+
onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
|
|
1581
|
+
}
|
|
1568
1582
|
}
|
|
1569
1583
|
}
|
|
1570
1584
|
|
|
@@ -1596,6 +1610,7 @@ function finishScrollTo(ctx) {
|
|
|
1596
1610
|
var SCROLL_END_IDLE_MS = 80;
|
|
1597
1611
|
var SCROLL_END_MAX_MS = 1500;
|
|
1598
1612
|
var SMOOTH_SCROLL_DURATION_MS = 320;
|
|
1613
|
+
var SCROLL_END_TARGET_EPSILON = 1;
|
|
1599
1614
|
function doScrollTo(ctx, params) {
|
|
1600
1615
|
const state = ctx.state;
|
|
1601
1616
|
const { animated, horizontal, offset } = params;
|
|
@@ -1606,7 +1621,10 @@ function doScrollTo(ctx, params) {
|
|
|
1606
1621
|
const top = horizontal ? 0 : offset;
|
|
1607
1622
|
node.scrollTo({ behavior: animated ? "smooth" : "auto", left, top });
|
|
1608
1623
|
if (animated) {
|
|
1609
|
-
listenForScrollEnd(ctx, node
|
|
1624
|
+
listenForScrollEnd(ctx, node, {
|
|
1625
|
+
horizontal: !!horizontal,
|
|
1626
|
+
targetOffset: offset
|
|
1627
|
+
});
|
|
1610
1628
|
} else {
|
|
1611
1629
|
state.scroll = offset;
|
|
1612
1630
|
setTimeout(() => {
|
|
@@ -1615,31 +1633,17 @@ function doScrollTo(ctx, params) {
|
|
|
1615
1633
|
}
|
|
1616
1634
|
}
|
|
1617
1635
|
}
|
|
1618
|
-
function listenForScrollEnd(ctx, node) {
|
|
1636
|
+
function listenForScrollEnd(ctx, node, params) {
|
|
1637
|
+
const { horizontal, targetOffset } = params;
|
|
1619
1638
|
const supportsScrollEnd = "onscrollend" in node;
|
|
1620
1639
|
let idleTimeout;
|
|
1621
1640
|
let maxTimeout;
|
|
1622
1641
|
let settled = false;
|
|
1623
1642
|
const targetToken = ctx.state.scrollingTo;
|
|
1624
|
-
const finish = () => {
|
|
1625
|
-
if (settled) return;
|
|
1626
|
-
settled = true;
|
|
1627
|
-
cleanup();
|
|
1628
|
-
if (targetToken === ctx.state.scrollingTo) {
|
|
1629
|
-
finishScrollTo(ctx);
|
|
1630
|
-
}
|
|
1631
|
-
};
|
|
1632
|
-
const onScroll2 = () => {
|
|
1633
|
-
if (idleTimeout) {
|
|
1634
|
-
clearTimeout(idleTimeout);
|
|
1635
|
-
}
|
|
1636
|
-
idleTimeout = setTimeout(finish, SCROLL_END_IDLE_MS);
|
|
1637
|
-
};
|
|
1638
1643
|
const cleanup = () => {
|
|
1644
|
+
node.removeEventListener("scroll", onScroll2);
|
|
1639
1645
|
if (supportsScrollEnd) {
|
|
1640
|
-
node.removeEventListener("scrollend",
|
|
1641
|
-
} else {
|
|
1642
|
-
node.removeEventListener("scroll", onScroll2);
|
|
1646
|
+
node.removeEventListener("scrollend", onScrollEnd);
|
|
1643
1647
|
}
|
|
1644
1648
|
if (idleTimeout) {
|
|
1645
1649
|
clearTimeout(idleTimeout);
|
|
@@ -1648,14 +1652,37 @@ function listenForScrollEnd(ctx, node) {
|
|
|
1648
1652
|
clearTimeout(maxTimeout);
|
|
1649
1653
|
}
|
|
1650
1654
|
};
|
|
1655
|
+
const finish = (reason) => {
|
|
1656
|
+
if (settled) return;
|
|
1657
|
+
if (targetToken !== ctx.state.scrollingTo) {
|
|
1658
|
+
settled = true;
|
|
1659
|
+
cleanup();
|
|
1660
|
+
return;
|
|
1661
|
+
}
|
|
1662
|
+
const currentOffset = horizontal ? node.scrollLeft : node.scrollTop;
|
|
1663
|
+
const isNearTarget = Math.abs(currentOffset - targetOffset) <= SCROLL_END_TARGET_EPSILON;
|
|
1664
|
+
if (reason === "scrollend" && !isNearTarget) {
|
|
1665
|
+
return;
|
|
1666
|
+
}
|
|
1667
|
+
settled = true;
|
|
1668
|
+
cleanup();
|
|
1669
|
+
finishScrollTo(ctx);
|
|
1670
|
+
};
|
|
1671
|
+
const onScroll2 = () => {
|
|
1672
|
+
if (idleTimeout) {
|
|
1673
|
+
clearTimeout(idleTimeout);
|
|
1674
|
+
}
|
|
1675
|
+
idleTimeout = setTimeout(() => finish("idle"), SCROLL_END_IDLE_MS);
|
|
1676
|
+
};
|
|
1677
|
+
const onScrollEnd = () => finish("scrollend");
|
|
1678
|
+
node.addEventListener("scroll", onScroll2);
|
|
1651
1679
|
if (supportsScrollEnd) {
|
|
1652
|
-
node.addEventListener("scrollend",
|
|
1680
|
+
node.addEventListener("scrollend", onScrollEnd);
|
|
1681
|
+
maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
|
|
1653
1682
|
} else {
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
maxTimeout = setTimeout(finish, SCROLL_END_MAX_MS);
|
|
1683
|
+
idleTimeout = setTimeout(() => finish("idle"), SMOOTH_SCROLL_DURATION_MS);
|
|
1684
|
+
maxTimeout = setTimeout(() => finish("max"), SCROLL_END_MAX_MS);
|
|
1657
1685
|
}
|
|
1658
|
-
return cleanup;
|
|
1659
1686
|
}
|
|
1660
1687
|
|
|
1661
1688
|
// src/core/scrollTo.ts
|
|
@@ -1673,14 +1700,14 @@ function scrollTo(ctx, params) {
|
|
|
1673
1700
|
clearTimeout(ctx.state.timeoutCheckFinishedScrollFallback);
|
|
1674
1701
|
}
|
|
1675
1702
|
let offset = precomputedWithViewOffset ? scrollTargetOffset : calculateOffsetWithOffsetPosition(ctx, scrollTargetOffset, scrollTarget);
|
|
1676
|
-
offset = clampScrollOffset(ctx, offset);
|
|
1703
|
+
offset = clampScrollOffset(ctx, offset, scrollTarget);
|
|
1677
1704
|
state.scrollHistory.length = 0;
|
|
1678
1705
|
if (!noScrollingTo) {
|
|
1679
1706
|
state.scrollingTo = scrollTarget;
|
|
1680
1707
|
}
|
|
1681
1708
|
state.scrollPending = offset;
|
|
1682
1709
|
if (forceScroll || !isInitialScroll || Platform.OS === "android") {
|
|
1683
|
-
doScrollTo(ctx, { animated, horizontal,
|
|
1710
|
+
doScrollTo(ctx, { animated, horizontal, offset });
|
|
1684
1711
|
} else {
|
|
1685
1712
|
state.scroll = offset;
|
|
1686
1713
|
}
|
|
@@ -1723,7 +1750,8 @@ function updateScroll(ctx, newScroll, forceUpdate) {
|
|
|
1723
1750
|
const scrollDelta = Math.abs(newScroll - prevScroll);
|
|
1724
1751
|
const scrollLength = state.scrollLength;
|
|
1725
1752
|
const lastCalculated = state.scrollLastCalculate;
|
|
1726
|
-
const
|
|
1753
|
+
const useAggressiveItemRecalculation = isInMVCPActiveMode(state);
|
|
1754
|
+
const shouldUpdate = useAggressiveItemRecalculation || forceUpdate || lastCalculated === void 0 || Math.abs(state.scroll - lastCalculated) > 2;
|
|
1727
1755
|
if (shouldUpdate) {
|
|
1728
1756
|
state.scrollLastCalculate = state.scroll;
|
|
1729
1757
|
state.ignoreScrollFromMVCPIgnored = false;
|
|
@@ -1768,43 +1796,106 @@ function requestAdjust(ctx, positionDiff, dataChanged) {
|
|
|
1768
1796
|
}
|
|
1769
1797
|
|
|
1770
1798
|
// src/core/mvcp.ts
|
|
1799
|
+
var MVCP_POSITION_EPSILON = 0.1;
|
|
1800
|
+
var MVCP_ANCHOR_LOCK_TTL_MS = 300;
|
|
1801
|
+
var MVCP_ANCHOR_LOCK_QUIET_PASSES_TO_RELEASE = 2;
|
|
1802
|
+
function resolveAnchorLock(state, enableMVCPAnchorLock, mvcpData, now) {
|
|
1803
|
+
if (!enableMVCPAnchorLock) {
|
|
1804
|
+
state.mvcpAnchorLock = void 0;
|
|
1805
|
+
return void 0;
|
|
1806
|
+
}
|
|
1807
|
+
const lock = state.mvcpAnchorLock;
|
|
1808
|
+
if (!lock) {
|
|
1809
|
+
return void 0;
|
|
1810
|
+
}
|
|
1811
|
+
const isExpired = now > lock.expiresAt;
|
|
1812
|
+
const isMissing = state.indexByKey.get(lock.id) === void 0;
|
|
1813
|
+
if (isExpired || isMissing || !mvcpData) {
|
|
1814
|
+
state.mvcpAnchorLock = void 0;
|
|
1815
|
+
return void 0;
|
|
1816
|
+
}
|
|
1817
|
+
return lock;
|
|
1818
|
+
}
|
|
1819
|
+
function updateAnchorLock(state, params) {
|
|
1820
|
+
{
|
|
1821
|
+
const { anchorId, anchorPosition, dataChanged, now, positionDiff } = params;
|
|
1822
|
+
const enableMVCPAnchorLock = !!dataChanged || !!state.mvcpAnchorLock;
|
|
1823
|
+
const mvcpData = state.props.maintainVisibleContentPosition.data;
|
|
1824
|
+
if (!enableMVCPAnchorLock || !mvcpData || state.scrollingTo || !anchorId || anchorPosition === void 0) {
|
|
1825
|
+
return;
|
|
1826
|
+
}
|
|
1827
|
+
const existingLock = state.mvcpAnchorLock;
|
|
1828
|
+
const quietPasses = !dataChanged && Math.abs(positionDiff) <= MVCP_POSITION_EPSILON && (existingLock == null ? void 0 : existingLock.id) === anchorId ? existingLock.quietPasses + 1 : 0;
|
|
1829
|
+
if (!dataChanged && quietPasses >= MVCP_ANCHOR_LOCK_QUIET_PASSES_TO_RELEASE) {
|
|
1830
|
+
state.mvcpAnchorLock = void 0;
|
|
1831
|
+
return;
|
|
1832
|
+
}
|
|
1833
|
+
state.mvcpAnchorLock = {
|
|
1834
|
+
expiresAt: now + MVCP_ANCHOR_LOCK_TTL_MS,
|
|
1835
|
+
id: anchorId,
|
|
1836
|
+
position: anchorPosition,
|
|
1837
|
+
quietPasses
|
|
1838
|
+
};
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1771
1841
|
function prepareMVCP(ctx, dataChanged) {
|
|
1772
1842
|
const state = ctx.state;
|
|
1773
1843
|
const { idsInView, positions, props } = state;
|
|
1774
1844
|
const {
|
|
1775
1845
|
maintainVisibleContentPosition: { data: mvcpData, size: mvcpScroll, shouldRestorePosition }
|
|
1776
1846
|
} = props;
|
|
1847
|
+
const now = Date.now();
|
|
1848
|
+
const enableMVCPAnchorLock = (!!dataChanged || !!state.mvcpAnchorLock);
|
|
1777
1849
|
const scrollingTo = state.scrollingTo;
|
|
1850
|
+
const anchorLock = resolveAnchorLock(state, enableMVCPAnchorLock, mvcpData, now) ;
|
|
1778
1851
|
let prevPosition;
|
|
1779
1852
|
let targetId;
|
|
1780
1853
|
const idsInViewWithPositions = [];
|
|
1781
1854
|
const scrollTarget = scrollingTo == null ? void 0 : scrollingTo.index;
|
|
1782
1855
|
const scrollingToViewPosition = scrollingTo == null ? void 0 : scrollingTo.viewPosition;
|
|
1856
|
+
const isEndAnchoredScrollTarget = scrollTarget !== void 0 && state.props.data.length > 0 && scrollTarget >= state.props.data.length - 1 && (scrollingToViewPosition != null ? scrollingToViewPosition : 0) > 0;
|
|
1783
1857
|
const shouldMVCP = dataChanged ? mvcpData : mvcpScroll;
|
|
1784
1858
|
const indexByKey = state.indexByKey;
|
|
1785
1859
|
if (shouldMVCP) {
|
|
1786
|
-
if (scrollTarget
|
|
1860
|
+
if (anchorLock && scrollTarget === void 0) {
|
|
1861
|
+
targetId = anchorLock.id;
|
|
1862
|
+
prevPosition = anchorLock.position;
|
|
1863
|
+
} else if (scrollTarget !== void 0) {
|
|
1787
1864
|
targetId = getId(state, scrollTarget);
|
|
1788
|
-
} else if (idsInView.length > 0 && state.didContainersLayout) {
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1865
|
+
} else if (idsInView.length > 0 && state.didContainersLayout && !dataChanged) {
|
|
1866
|
+
targetId = idsInView.find((id) => indexByKey.get(id) !== void 0);
|
|
1867
|
+
}
|
|
1868
|
+
if (dataChanged && idsInView.length > 0 && state.didContainersLayout) {
|
|
1869
|
+
for (let i = 0; i < idsInView.length; i++) {
|
|
1870
|
+
const id = idsInView[i];
|
|
1871
|
+
const index = indexByKey.get(id);
|
|
1872
|
+
if (index !== void 0) {
|
|
1873
|
+
idsInViewWithPositions.push({ id, position: positions.get(id) });
|
|
1796
1874
|
}
|
|
1797
|
-
} else {
|
|
1798
|
-
targetId = idsInView.find((id) => indexByKey.get(id) !== void 0);
|
|
1799
1875
|
}
|
|
1800
1876
|
}
|
|
1801
|
-
if (targetId !== void 0) {
|
|
1877
|
+
if (targetId !== void 0 && prevPosition === void 0) {
|
|
1802
1878
|
prevPosition = positions.get(targetId);
|
|
1803
1879
|
}
|
|
1804
1880
|
return () => {
|
|
1805
1881
|
let positionDiff = 0;
|
|
1806
|
-
|
|
1807
|
-
|
|
1882
|
+
let anchorIdForLock = anchorLock == null ? void 0 : anchorLock.id;
|
|
1883
|
+
let anchorPositionForLock;
|
|
1884
|
+
let skipTargetAnchor = false;
|
|
1885
|
+
const data = state.props.data;
|
|
1886
|
+
const shouldValidateLockedAnchor = dataChanged && mvcpData && scrollTarget === void 0 && targetId !== void 0 && (anchorLock == null ? void 0 : anchorLock.id) === targetId && shouldRestorePosition !== void 0;
|
|
1887
|
+
if (shouldValidateLockedAnchor && targetId !== void 0) {
|
|
1888
|
+
const index = indexByKey.get(targetId);
|
|
1889
|
+
if (index !== void 0) {
|
|
1890
|
+
const item = data[index];
|
|
1891
|
+
skipTargetAnchor = item === void 0 || !shouldRestorePosition(item, index, data);
|
|
1892
|
+
if (skipTargetAnchor && (anchorLock == null ? void 0 : anchorLock.id) === targetId) {
|
|
1893
|
+
state.mvcpAnchorLock = void 0;
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
const shouldUseFallbackVisibleAnchor = dataChanged && mvcpData && scrollTarget === void 0 && (targetId === void 0 || positions.get(targetId) === void 0 || skipTargetAnchor);
|
|
1898
|
+
if (shouldUseFallbackVisibleAnchor) {
|
|
1808
1899
|
for (let i = 0; i < idsInViewWithPositions.length; i++) {
|
|
1809
1900
|
const { id, position } = idsInViewWithPositions[i];
|
|
1810
1901
|
const index = indexByKey.get(id);
|
|
@@ -1817,16 +1908,18 @@ function prepareMVCP(ctx, dataChanged) {
|
|
|
1817
1908
|
const newPosition = positions.get(id);
|
|
1818
1909
|
if (newPosition !== void 0) {
|
|
1819
1910
|
positionDiff = newPosition - position;
|
|
1911
|
+
anchorIdForLock = id;
|
|
1912
|
+
anchorPositionForLock = newPosition;
|
|
1820
1913
|
break;
|
|
1821
1914
|
}
|
|
1822
1915
|
}
|
|
1823
1916
|
}
|
|
1824
|
-
if (targetId !== void 0 && prevPosition !== void 0) {
|
|
1917
|
+
if (!skipTargetAnchor && targetId !== void 0 && prevPosition !== void 0) {
|
|
1825
1918
|
const newPosition = positions.get(targetId);
|
|
1826
1919
|
if (newPosition !== void 0) {
|
|
1827
1920
|
const totalSize = getContentSize(ctx);
|
|
1828
1921
|
let diff = newPosition - prevPosition;
|
|
1829
|
-
if (diff !== 0 && state.scroll + state.scrollLength > totalSize) {
|
|
1922
|
+
if (diff !== 0 && isEndAnchoredScrollTarget && state.scroll + state.scrollLength > totalSize) {
|
|
1830
1923
|
if (diff > 0) {
|
|
1831
1924
|
diff = Math.max(0, totalSize - state.scroll - state.scrollLength);
|
|
1832
1925
|
} else {
|
|
@@ -1834,20 +1927,29 @@ function prepareMVCP(ctx, dataChanged) {
|
|
|
1834
1927
|
}
|
|
1835
1928
|
}
|
|
1836
1929
|
positionDiff = diff;
|
|
1930
|
+
anchorIdForLock = targetId;
|
|
1931
|
+
anchorPositionForLock = newPosition;
|
|
1837
1932
|
}
|
|
1838
1933
|
}
|
|
1839
1934
|
if (scrollingToViewPosition && scrollingToViewPosition > 0) {
|
|
1840
1935
|
const newSize = getItemSize(ctx, targetId, scrollTarget, state.props.data[scrollTarget]);
|
|
1841
1936
|
const prevSize = scrollingTo == null ? void 0 : scrollingTo.itemSize;
|
|
1842
|
-
if (newSize !== void 0 && prevSize !== void 0 && newSize !==
|
|
1937
|
+
if (newSize !== void 0 && prevSize !== void 0 && newSize !== prevSize) {
|
|
1843
1938
|
const diff = newSize - prevSize;
|
|
1844
1939
|
if (diff !== 0) {
|
|
1845
|
-
positionDiff +=
|
|
1940
|
+
positionDiff += diff * scrollingToViewPosition;
|
|
1846
1941
|
scrollingTo.itemSize = newSize;
|
|
1847
1942
|
}
|
|
1848
1943
|
}
|
|
1849
1944
|
}
|
|
1850
|
-
|
|
1945
|
+
updateAnchorLock(state, {
|
|
1946
|
+
anchorId: anchorIdForLock,
|
|
1947
|
+
anchorPosition: anchorPositionForLock,
|
|
1948
|
+
dataChanged,
|
|
1949
|
+
now,
|
|
1950
|
+
positionDiff
|
|
1951
|
+
});
|
|
1952
|
+
if (Math.abs(positionDiff) > MVCP_POSITION_EPSILON) {
|
|
1851
1953
|
requestAdjust(ctx, positionDiff);
|
|
1852
1954
|
}
|
|
1853
1955
|
};
|
|
@@ -2502,26 +2604,16 @@ function scrollToIndex(ctx, { index, viewOffset = 0, animated = true, viewPositi
|
|
|
2502
2604
|
// src/utils/setDidLayout.ts
|
|
2503
2605
|
function setDidLayout(ctx) {
|
|
2504
2606
|
const state = ctx.state;
|
|
2505
|
-
const {
|
|
2506
|
-
loadStartTime,
|
|
2507
|
-
initialScroll,
|
|
2508
|
-
props: { onLoad }
|
|
2509
|
-
} = state;
|
|
2607
|
+
const { initialScroll } = state;
|
|
2510
2608
|
state.queuedInitialLayout = true;
|
|
2511
2609
|
checkAtBottom(ctx);
|
|
2512
|
-
const setIt = () => {
|
|
2513
|
-
setInitialRenderState(ctx, { didLayout: true });
|
|
2514
|
-
if (onLoad) {
|
|
2515
|
-
onLoad({ elapsedTimeInMs: Date.now() - loadStartTime });
|
|
2516
|
-
}
|
|
2517
|
-
};
|
|
2518
2610
|
if ((initialScroll == null ? void 0 : initialScroll.index) !== void 0) {
|
|
2519
2611
|
const target = initialScroll;
|
|
2520
2612
|
const runScroll = () => scrollToIndex(ctx, { ...target, animated: false });
|
|
2521
2613
|
runScroll();
|
|
2522
2614
|
requestAnimationFrame(runScroll);
|
|
2523
2615
|
}
|
|
2524
|
-
|
|
2616
|
+
setInitialRenderState(ctx, { didLayout: true });
|
|
2525
2617
|
}
|
|
2526
2618
|
|
|
2527
2619
|
// src/core/calculateItemsInView.ts
|
|
@@ -2561,7 +2653,7 @@ function handleStickyActivation(ctx, stickyHeaderIndices, stickyArray, currentSt
|
|
|
2561
2653
|
}
|
|
2562
2654
|
}
|
|
2563
2655
|
}
|
|
2564
|
-
function handleStickyRecycling(ctx, stickyArray, scroll,
|
|
2656
|
+
function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentStickyIdx, pendingRemoval, alwaysRenderIndicesSet) {
|
|
2565
2657
|
var _a3, _b, _c;
|
|
2566
2658
|
const state = ctx.state;
|
|
2567
2659
|
for (const containerIndex of state.stickyContainerPool) {
|
|
@@ -2582,13 +2674,13 @@ function handleStickyRecycling(ctx, stickyArray, scroll, scrollBuffer, currentSt
|
|
|
2582
2674
|
if (nextIndex) {
|
|
2583
2675
|
const nextId = (_a3 = state.idCache[nextIndex]) != null ? _a3 : getId(state, nextIndex);
|
|
2584
2676
|
const nextPos = nextId ? state.positions.get(nextId) : void 0;
|
|
2585
|
-
shouldRecycle = nextPos !== void 0 && scroll > nextPos +
|
|
2677
|
+
shouldRecycle = nextPos !== void 0 && scroll > nextPos + drawDistance * 2;
|
|
2586
2678
|
} else {
|
|
2587
2679
|
const currentId = (_b = state.idCache[itemIndex]) != null ? _b : getId(state, itemIndex);
|
|
2588
2680
|
if (currentId) {
|
|
2589
2681
|
const currentPos = state.positions.get(currentId);
|
|
2590
2682
|
const currentSize = (_c = state.sizes.get(currentId)) != null ? _c : getItemSize(ctx, currentId, itemIndex, state.props.data[itemIndex]);
|
|
2591
|
-
shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize +
|
|
2683
|
+
shouldRecycle = currentPos !== void 0 && scroll > currentPos + currentSize + drawDistance * 3;
|
|
2592
2684
|
}
|
|
2593
2685
|
}
|
|
2594
2686
|
if (shouldRecycle) {
|
|
@@ -2613,11 +2705,11 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
2613
2705
|
props: {
|
|
2614
2706
|
alwaysRenderIndicesArr,
|
|
2615
2707
|
alwaysRenderIndicesSet,
|
|
2708
|
+
drawDistance,
|
|
2616
2709
|
getItemType,
|
|
2617
2710
|
itemsAreEqual,
|
|
2618
2711
|
keyExtractor,
|
|
2619
|
-
onStickyHeaderChange
|
|
2620
|
-
scrollBuffer
|
|
2712
|
+
onStickyHeaderChange
|
|
2621
2713
|
},
|
|
2622
2714
|
scrollForNextCalculateItemsInView,
|
|
2623
2715
|
scrollLength,
|
|
@@ -2630,6 +2722,7 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
2630
2722
|
const stickyIndicesSet = state.props.stickyIndicesSet || /* @__PURE__ */ new Set();
|
|
2631
2723
|
const alwaysRenderArr = alwaysRenderIndicesArr || [];
|
|
2632
2724
|
const alwaysRenderSet = alwaysRenderIndicesSet || /* @__PURE__ */ new Set();
|
|
2725
|
+
const { dataChanged, doMVCP, forceFullItemPositions } = params;
|
|
2633
2726
|
const prevNumContainers = peek$(ctx, "numContainers");
|
|
2634
2727
|
if (!data || scrollLength === 0 || !prevNumContainers) {
|
|
2635
2728
|
return;
|
|
@@ -2637,7 +2730,6 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
2637
2730
|
const totalSize = getContentSize(ctx);
|
|
2638
2731
|
const topPad = peek$(ctx, "stylePaddingTop") + peek$(ctx, "headerSize");
|
|
2639
2732
|
const numColumns = peek$(ctx, "numColumns");
|
|
2640
|
-
const { dataChanged, doMVCP, forceFullItemPositions } = params;
|
|
2641
2733
|
const speed = getScrollVelocity(state);
|
|
2642
2734
|
const scrollExtra = 0;
|
|
2643
2735
|
const { queuedInitialLayout } = state;
|
|
@@ -2656,24 +2748,20 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
2656
2748
|
if (scroll + scrollLength > totalSize) {
|
|
2657
2749
|
scroll = Math.max(0, totalSize - scrollLength);
|
|
2658
2750
|
}
|
|
2659
|
-
if (ENABLE_DEBUG_VIEW) {
|
|
2660
|
-
set$(ctx, "debugRawScroll", scrollState);
|
|
2661
|
-
set$(ctx, "debugComputedScroll", scroll);
|
|
2662
|
-
}
|
|
2663
2751
|
const previousStickyIndex = peek$(ctx, "activeStickyIndex");
|
|
2664
2752
|
const currentStickyIdx = stickyIndicesArr.length > 0 ? findCurrentStickyIndex(stickyIndicesArr, scroll, state) : -1;
|
|
2665
2753
|
const nextActiveStickyIndex = currentStickyIdx >= 0 ? stickyIndicesArr[currentStickyIdx] : -1;
|
|
2666
2754
|
if (currentStickyIdx >= 0 || previousStickyIndex >= 0) {
|
|
2667
2755
|
set$(ctx, "activeStickyIndex", nextActiveStickyIndex);
|
|
2668
2756
|
}
|
|
2669
|
-
let scrollBufferTop =
|
|
2670
|
-
let scrollBufferBottom =
|
|
2671
|
-
if (speed > 0 || speed === 0 && scroll < Math.max(50,
|
|
2672
|
-
scrollBufferTop =
|
|
2673
|
-
scrollBufferBottom =
|
|
2757
|
+
let scrollBufferTop = drawDistance;
|
|
2758
|
+
let scrollBufferBottom = drawDistance;
|
|
2759
|
+
if (speed > 0 || speed === 0 && scroll < Math.max(50, drawDistance)) {
|
|
2760
|
+
scrollBufferTop = drawDistance * 0.5;
|
|
2761
|
+
scrollBufferBottom = drawDistance * 1.5;
|
|
2674
2762
|
} else {
|
|
2675
|
-
scrollBufferTop =
|
|
2676
|
-
scrollBufferBottom =
|
|
2763
|
+
scrollBufferTop = drawDistance * 1.5;
|
|
2764
|
+
scrollBufferBottom = drawDistance * 0.5;
|
|
2677
2765
|
}
|
|
2678
2766
|
const scrollTopBuffered = scroll - scrollBufferTop;
|
|
2679
2767
|
const scrollBottom = scroll + scrollLength + (scroll < 0 ? -scroll : 0);
|
|
@@ -2683,7 +2771,9 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
2683
2771
|
if (top === null && bottom === null) {
|
|
2684
2772
|
state.scrollForNextCalculateItemsInView = void 0;
|
|
2685
2773
|
} else if ((top === null || scrollTopBuffered > top) && (bottom === null || scrollBottomBuffered < bottom)) {
|
|
2686
|
-
|
|
2774
|
+
if (!isInMVCPActiveMode(state)) {
|
|
2775
|
+
return;
|
|
2776
|
+
}
|
|
2687
2777
|
}
|
|
2688
2778
|
}
|
|
2689
2779
|
const checkMVCP = doMVCP ? prepareMVCP(ctx, dataChanged) : void 0;
|
|
@@ -2915,7 +3005,7 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
2915
3005
|
ctx,
|
|
2916
3006
|
stickyIndicesArr,
|
|
2917
3007
|
scroll,
|
|
2918
|
-
|
|
3008
|
+
drawDistance,
|
|
2919
3009
|
currentStickyIdx,
|
|
2920
3010
|
pendingRemoval,
|
|
2921
3011
|
alwaysRenderSet
|
|
@@ -3022,12 +3112,17 @@ function checkFinishedScrollFrame(ctx) {
|
|
|
3022
3112
|
state.animFrameCheckFinishedScroll = void 0;
|
|
3023
3113
|
const scroll = state.scrollPending;
|
|
3024
3114
|
const adjust = state.scrollAdjustHandler.getAdjust();
|
|
3025
|
-
const clampedTargetOffset = clampScrollOffset(
|
|
3026
|
-
|
|
3115
|
+
const clampedTargetOffset = clampScrollOffset(
|
|
3116
|
+
ctx,
|
|
3117
|
+
scrollingTo.offset - (scrollingTo.viewOffset || 0),
|
|
3118
|
+
scrollingTo
|
|
3119
|
+
);
|
|
3120
|
+
const maxOffset = clampScrollOffset(ctx, scroll, scrollingTo);
|
|
3027
3121
|
const diff1 = Math.abs(scroll - clampedTargetOffset);
|
|
3028
3122
|
const diff2 = Math.abs(diff1 - adjust);
|
|
3029
3123
|
const isNotOverscrolled = Math.abs(scroll - maxOffset) < 1;
|
|
3030
|
-
|
|
3124
|
+
const isAtTarget = diff1 < 1 || !scrollingTo.animated && diff2 < 1;
|
|
3125
|
+
if (isNotOverscrolled && isAtTarget) {
|
|
3031
3126
|
finishScrollTo(ctx);
|
|
3032
3127
|
}
|
|
3033
3128
|
}
|
|
@@ -3171,10 +3266,10 @@ function doInitialAllocateContainers(ctx) {
|
|
|
3171
3266
|
scrollLength,
|
|
3172
3267
|
props: {
|
|
3173
3268
|
data,
|
|
3269
|
+
drawDistance,
|
|
3174
3270
|
getEstimatedItemSize,
|
|
3175
3271
|
getFixedItemSize,
|
|
3176
3272
|
getItemType,
|
|
3177
|
-
scrollBuffer,
|
|
3178
3273
|
numColumns,
|
|
3179
3274
|
estimatedItemSize
|
|
3180
3275
|
}
|
|
@@ -3196,7 +3291,7 @@ function doInitialAllocateContainers(ctx) {
|
|
|
3196
3291
|
} else {
|
|
3197
3292
|
averageItemSize = estimatedItemSize;
|
|
3198
3293
|
}
|
|
3199
|
-
const numContainers = Math.ceil((scrollLength +
|
|
3294
|
+
const numContainers = Math.ceil((scrollLength + drawDistance * 2) / averageItemSize * numColumns);
|
|
3200
3295
|
for (let i = 0; i < numContainers; i++) {
|
|
3201
3296
|
set$(ctx, `containerPosition${i}`, POSITION_OUT_OF_VIEW);
|
|
3202
3297
|
set$(ctx, `containerColumn${i}`, -1);
|
|
@@ -3284,8 +3379,8 @@ function onScroll(ctx, event) {
|
|
|
3284
3379
|
}
|
|
3285
3380
|
}
|
|
3286
3381
|
let newScroll = event.nativeEvent.contentOffset[state.props.horizontal ? "x" : "y"];
|
|
3287
|
-
if (state.scrollingTo) {
|
|
3288
|
-
const maxOffset = clampScrollOffset(ctx, newScroll);
|
|
3382
|
+
if (state.scrollingTo && state.scrollingTo.offset >= newScroll) {
|
|
3383
|
+
const maxOffset = clampScrollOffset(ctx, newScroll, state.scrollingTo);
|
|
3289
3384
|
if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
|
|
3290
3385
|
newScroll = maxOffset;
|
|
3291
3386
|
scrollTo(ctx, {
|
|
@@ -3338,7 +3433,7 @@ var ScrollAdjustHandler = class {
|
|
|
3338
3433
|
if ((scrollTarget == null ? void 0 : scrollTarget.index) !== void 0) {
|
|
3339
3434
|
const currentOffset = calculateOffsetForIndex(this.ctx, scrollTarget.index);
|
|
3340
3435
|
targetScroll = calculateOffsetWithOffsetPosition(this.ctx, currentOffset, scrollTarget);
|
|
3341
|
-
targetScroll = clampScrollOffset(this.ctx, targetScroll);
|
|
3436
|
+
targetScroll = clampScrollOffset(this.ctx, targetScroll, scrollTarget);
|
|
3342
3437
|
} else {
|
|
3343
3438
|
targetScroll = clampScrollOffset(this.ctx, state.scroll + pending);
|
|
3344
3439
|
}
|
|
@@ -3357,6 +3452,26 @@ var ScrollAdjustHandler = class {
|
|
|
3357
3452
|
};
|
|
3358
3453
|
|
|
3359
3454
|
// src/core/updateItemSize.ts
|
|
3455
|
+
function runOrScheduleMVCPRecalculate(ctx) {
|
|
3456
|
+
const state = ctx.state;
|
|
3457
|
+
{
|
|
3458
|
+
if (!state.mvcpAnchorLock) {
|
|
3459
|
+
if (state.queuedMVCPRecalculate !== void 0) {
|
|
3460
|
+
cancelAnimationFrame(state.queuedMVCPRecalculate);
|
|
3461
|
+
state.queuedMVCPRecalculate = void 0;
|
|
3462
|
+
}
|
|
3463
|
+
calculateItemsInView(ctx, { doMVCP: true });
|
|
3464
|
+
return;
|
|
3465
|
+
}
|
|
3466
|
+
if (state.queuedMVCPRecalculate !== void 0) {
|
|
3467
|
+
return;
|
|
3468
|
+
}
|
|
3469
|
+
state.queuedMVCPRecalculate = requestAnimationFrame(() => {
|
|
3470
|
+
state.queuedMVCPRecalculate = void 0;
|
|
3471
|
+
calculateItemsInView(ctx, { doMVCP: true });
|
|
3472
|
+
});
|
|
3473
|
+
}
|
|
3474
|
+
}
|
|
3360
3475
|
function updateItemSize(ctx, itemKey, sizeObj) {
|
|
3361
3476
|
var _a3;
|
|
3362
3477
|
const state = ctx.state;
|
|
@@ -3440,7 +3555,7 @@ function updateItemSize(ctx, itemKey, sizeObj) {
|
|
|
3440
3555
|
if (didContainersLayout || checkAllSizesKnown(state)) {
|
|
3441
3556
|
if (needsRecalculate) {
|
|
3442
3557
|
state.scrollForNextCalculateItemsInView = void 0;
|
|
3443
|
-
|
|
3558
|
+
runOrScheduleMVCPRecalculate(ctx);
|
|
3444
3559
|
}
|
|
3445
3560
|
if (shouldMaintainScrollAtEnd) {
|
|
3446
3561
|
if (maintainScrollAtEnd === true || maintainScrollAtEnd.onItemLayout) {
|
|
@@ -3552,7 +3667,30 @@ function createImperativeHandle(ctx) {
|
|
|
3552
3667
|
}
|
|
3553
3668
|
};
|
|
3554
3669
|
const refScroller = state.refScroller;
|
|
3670
|
+
const clearCaches = (options) => {
|
|
3671
|
+
var _a3, _b;
|
|
3672
|
+
const mode = (_a3 = options == null ? void 0 : options.mode) != null ? _a3 : "sizes";
|
|
3673
|
+
state.sizes.clear();
|
|
3674
|
+
state.sizesKnown.clear();
|
|
3675
|
+
for (const key in state.averageSizes) {
|
|
3676
|
+
delete state.averageSizes[key];
|
|
3677
|
+
}
|
|
3678
|
+
state.minIndexSizeChanged = 0;
|
|
3679
|
+
state.scrollForNextCalculateItemsInView = void 0;
|
|
3680
|
+
state.pendingTotalSize = void 0;
|
|
3681
|
+
state.totalSize = 0;
|
|
3682
|
+
set$(ctx, "totalSize", 0);
|
|
3683
|
+
if (mode === "full") {
|
|
3684
|
+
state.indexByKey.clear();
|
|
3685
|
+
state.idCache.length = 0;
|
|
3686
|
+
state.positions.clear();
|
|
3687
|
+
state.columns.clear();
|
|
3688
|
+
state.columnSpans.clear();
|
|
3689
|
+
}
|
|
3690
|
+
(_b = state.triggerCalculateItemsInView) == null ? void 0 : _b.call(state, { forceFullItemPositions: true });
|
|
3691
|
+
};
|
|
3555
3692
|
return {
|
|
3693
|
+
clearCaches,
|
|
3556
3694
|
flashScrollIndicators: () => refScroller.current.flashScrollIndicators(),
|
|
3557
3695
|
getNativeScrollRef: () => refScroller.current,
|
|
3558
3696
|
getScrollableNode: () => refScroller.current.getScrollableNode(),
|
|
@@ -3713,8 +3851,8 @@ function normalizeMaintainVisibleContentPosition(value) {
|
|
|
3713
3851
|
if (value && typeof value === "object") {
|
|
3714
3852
|
return {
|
|
3715
3853
|
data: (_a3 = value.data) != null ? _a3 : false,
|
|
3716
|
-
|
|
3717
|
-
|
|
3854
|
+
shouldRestorePosition: value.shouldRestorePosition,
|
|
3855
|
+
size: (_b = value.size) != null ? _b : true
|
|
3718
3856
|
};
|
|
3719
3857
|
}
|
|
3720
3858
|
if (value === false) {
|
|
@@ -3786,8 +3924,6 @@ function useThrottledOnScroll(originalHandler, scrollEventThrottle) {
|
|
|
3786
3924
|
}
|
|
3787
3925
|
|
|
3788
3926
|
// src/components/LegendList.tsx
|
|
3789
|
-
var DEFAULT_DRAW_DISTANCE = 250;
|
|
3790
|
-
var DEFAULT_ITEM_SIZE = 100;
|
|
3791
3927
|
var LegendList = typedMemo(
|
|
3792
3928
|
// biome-ignore lint/nursery/noShadow: const function name shadowing is intentional
|
|
3793
3929
|
typedForwardRef(function LegendList2(props, forwardedRef) {
|
|
@@ -3817,7 +3953,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
3817
3953
|
data: dataProp = [],
|
|
3818
3954
|
dataVersion,
|
|
3819
3955
|
drawDistance = 250,
|
|
3820
|
-
estimatedItemSize
|
|
3956
|
+
estimatedItemSize = 100,
|
|
3821
3957
|
estimatedListSize,
|
|
3822
3958
|
extraData,
|
|
3823
3959
|
getEstimatedItemSize,
|
|
@@ -3869,7 +4005,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
3869
4005
|
...rest
|
|
3870
4006
|
} = props;
|
|
3871
4007
|
const animatedPropsInternal = props.animatedPropsInternal;
|
|
3872
|
-
const
|
|
4008
|
+
const stickyPositionComponentInternal = props.stickyPositionComponentInternal;
|
|
4009
|
+
const {
|
|
4010
|
+
childrenMode,
|
|
4011
|
+
stickyPositionComponentInternal: _stickyPositionComponentInternal,
|
|
4012
|
+
...restProps
|
|
4013
|
+
} = rest;
|
|
3873
4014
|
const contentContainerStyleBase = StyleSheet.flatten(contentContainerStyleProp);
|
|
3874
4015
|
const shouldFlexGrow = alignItemsAtEnd && (horizontal ? (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minWidth) == null : (contentContainerStyleBase == null ? void 0 : contentContainerStyleBase.minHeight) == null);
|
|
3875
4016
|
const contentContainerStyle = {
|
|
@@ -3896,14 +4037,12 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
3896
4037
|
index: initialScrollIndexProp || 0,
|
|
3897
4038
|
viewOffset: initialScrollOffsetProp || 0
|
|
3898
4039
|
} : void 0;
|
|
3899
|
-
const [canRender, setCanRender] = React3__namespace.useState(
|
|
4040
|
+
const [canRender, setCanRender] = React3__namespace.useState(false);
|
|
3900
4041
|
const ctx = useStateContext();
|
|
3901
4042
|
ctx.columnWrapperStyle = columnWrapperStyle || (contentContainerStyle ? createColumnWrapperStyle(contentContainerStyle) : void 0);
|
|
3902
4043
|
const refScroller = React3.useRef(null);
|
|
3903
4044
|
const combinedRef = useCombinedRef(refScroller, refScrollView);
|
|
3904
|
-
const
|
|
3905
|
-
const scrollBuffer = (drawDistance != null ? drawDistance : DEFAULT_DRAW_DISTANCE) || 1;
|
|
3906
|
-
const keyExtractor = keyExtractorProp != null ? keyExtractorProp : (_item, index) => index.toString();
|
|
4045
|
+
const keyExtractor = keyExtractorProp != null ? keyExtractorProp : ((_item, index) => index.toString());
|
|
3907
4046
|
const stickyHeaderIndices = stickyHeaderIndicesProp != null ? stickyHeaderIndicesProp : stickyIndicesDeprecated;
|
|
3908
4047
|
const alwaysRenderIndices = React3.useMemo(() => {
|
|
3909
4048
|
const indices = getAlwaysRenderIndices(alwaysRender, dataProp, keyExtractor);
|
|
@@ -3932,8 +4071,8 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
3932
4071
|
ctx.state = {
|
|
3933
4072
|
activeStickyIndex: -1,
|
|
3934
4073
|
averageSizes: {},
|
|
3935
|
-
columns: /* @__PURE__ */ new Map(),
|
|
3936
4074
|
columnSpans: /* @__PURE__ */ new Map(),
|
|
4075
|
+
columns: /* @__PURE__ */ new Map(),
|
|
3937
4076
|
containerItemKeys: /* @__PURE__ */ new Map(),
|
|
3938
4077
|
containerItemTypes: /* @__PURE__ */ new Map(),
|
|
3939
4078
|
contentInsetOverride: void 0,
|
|
@@ -4020,6 +4159,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
4020
4159
|
contentInset,
|
|
4021
4160
|
data: dataProp,
|
|
4022
4161
|
dataVersion,
|
|
4162
|
+
drawDistance,
|
|
4023
4163
|
estimatedItemSize,
|
|
4024
4164
|
getEstimatedItemSize: useWrapIfItem(getEstimatedItemSize),
|
|
4025
4165
|
getFixedItemSize: useWrapIfItem(getFixedItemSize),
|
|
@@ -4043,10 +4183,10 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
4043
4183
|
overrideItemLayout,
|
|
4044
4184
|
recycleItems: !!recycleItems,
|
|
4045
4185
|
renderItem,
|
|
4046
|
-
scrollBuffer,
|
|
4047
4186
|
snapToIndices,
|
|
4048
4187
|
stickyIndicesArr: stickyHeaderIndices != null ? stickyHeaderIndices : [],
|
|
4049
4188
|
stickyIndicesSet: React3.useMemo(() => new Set(stickyHeaderIndices != null ? stickyHeaderIndices : []), [stickyHeaderIndices == null ? void 0 : stickyHeaderIndices.join(",")]),
|
|
4189
|
+
stickyPositionComponentInternal,
|
|
4050
4190
|
stylePaddingBottom: stylePaddingBottomState,
|
|
4051
4191
|
stylePaddingTop: stylePaddingTopState,
|
|
4052
4192
|
suggestEstimatedItemSize: !!suggestEstimatedItemSize
|
|
@@ -4066,12 +4206,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
4066
4206
|
setPaddingTop(ctx, { stylePaddingTop: stylePaddingTopState });
|
|
4067
4207
|
refState.current.props.stylePaddingBottom = stylePaddingBottomState;
|
|
4068
4208
|
let paddingDiff = stylePaddingTopState - prevPaddingTop;
|
|
4069
|
-
if (shouldAdjustPadding && maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios")
|
|
4070
|
-
if (state.scroll < 0) {
|
|
4071
|
-
paddingDiff += state.scroll;
|
|
4072
|
-
}
|
|
4073
|
-
requestAdjust(ctx, paddingDiff);
|
|
4074
|
-
}
|
|
4209
|
+
if (shouldAdjustPadding && maintainVisibleContentPositionConfig.size && paddingDiff && prevPaddingTop !== void 0 && Platform.OS === "ios") ;
|
|
4075
4210
|
};
|
|
4076
4211
|
if (isFirstLocal) {
|
|
4077
4212
|
initializeStateVars(false);
|
|
@@ -4090,7 +4225,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
4090
4225
|
} else {
|
|
4091
4226
|
const baseOffset = initialScroll.index !== void 0 ? calculateOffsetForIndex(ctx, initialScroll.index) : 0;
|
|
4092
4227
|
const resolvedOffset = calculateOffsetWithOffsetPosition(ctx, baseOffset, initialScroll);
|
|
4093
|
-
const clampedOffset = clampScrollOffset(ctx, resolvedOffset);
|
|
4228
|
+
const clampedOffset = clampScrollOffset(ctx, resolvedOffset, initialScroll);
|
|
4094
4229
|
const updatedInitialScroll = { ...initialScroll, contentOffset: clampedOffset };
|
|
4095
4230
|
refState.current.initialScroll = updatedInitialScroll;
|
|
4096
4231
|
state.initialScroll = updatedInitialScroll;
|
|
@@ -4239,7 +4374,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
4239
4374
|
return /* @__PURE__ */ React3__namespace.createElement(React3__namespace.Fragment, null, /* @__PURE__ */ React3__namespace.createElement(
|
|
4240
4375
|
ListComponent,
|
|
4241
4376
|
{
|
|
4242
|
-
...
|
|
4377
|
+
...restProps,
|
|
4243
4378
|
alignItemsAtEnd,
|
|
4244
4379
|
canRender,
|
|
4245
4380
|
contentContainerStyle,
|
|
@@ -4273,10 +4408,18 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
4273
4408
|
updateItemSize: fns.updateItemSize,
|
|
4274
4409
|
waitForInitialLayout
|
|
4275
4410
|
}
|
|
4276
|
-
), IS_DEV && ENABLE_DEBUG_VIEW
|
|
4411
|
+
), IS_DEV && ENABLE_DEBUG_VIEW);
|
|
4277
4412
|
});
|
|
4278
4413
|
|
|
4279
|
-
|
|
4414
|
+
// src/index.ts
|
|
4415
|
+
var LegendList3 = LegendList;
|
|
4416
|
+
if (IS_DEV) {
|
|
4417
|
+
console.warn(
|
|
4418
|
+
"[legend-list] Legend List 3.0 deprecates the root import (@legendapp/list) because it now supports both react and react-native. The root import is fully functional, but please switch to platform-specific imports for strict platform types:\n - React Native: @legendapp/list/react-native\n - React: @legendapp/list/react\nSee README for details."
|
|
4419
|
+
);
|
|
4420
|
+
}
|
|
4421
|
+
|
|
4422
|
+
exports.LegendList = LegendList3;
|
|
4280
4423
|
exports.typedForwardRef = typedForwardRef;
|
|
4281
4424
|
exports.typedMemo = typedMemo;
|
|
4282
4425
|
exports.useIsLastItem = useIsLastItem;
|