@legendapp/list 3.4.0 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +33 -0
- package/package.json +1 -1
- package/react-native.js +102 -51
- package/react-native.mjs +102 -51
- package/react-native.web.d.ts +12 -2
- package/react-native.web.js +277 -178
- package/react-native.web.mjs +277 -178
- package/react.d.ts +12 -2
- package/react.js +277 -178
- package/react.mjs +277 -178
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## 3.5.0
|
|
2
|
+
|
|
3
|
+
- Feat: Add `scrollElement` so web lists can share an ancestor element's scrollbar
|
|
4
|
+
- Fix: Stopping scrolling keeps rows prepared in the last scroll direction instead of shifting the render buffer backward.
|
|
5
|
+
- Perf: Single-column lists do less layout work during initial rendering and scrolling when item sizes and data are unchanged.
|
|
6
|
+
|
|
1
7
|
## 3.4.0
|
|
2
8
|
|
|
3
9
|
- Feat: Add `onReady`, called after each initial placement and scroll cycle completes, including cycles restarted by a `dataKey` change.
|
package/README.md
CHANGED
|
@@ -112,6 +112,39 @@ export default LegendListExample
|
|
|
112
112
|
|
|
113
113
|
---
|
|
114
114
|
|
|
115
|
+
### Sharing a scrollbar on the web
|
|
116
|
+
|
|
117
|
+
React DOM lists can use an ancestor element's scrollbar with `scrollElement`:
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
import { LegendList } from "@legendapp/list/react";
|
|
121
|
+
import { useState } from "react";
|
|
122
|
+
|
|
123
|
+
function History({ swaps, renderSwap }) {
|
|
124
|
+
const [scrollElement, setScrollElement] = useState<HTMLDivElement | null>(null);
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<div ref={setScrollElement} style={{ height: 600, overflow: "auto" }}>
|
|
128
|
+
<ProfileHeader />
|
|
129
|
+
<LegendList
|
|
130
|
+
data={swaps}
|
|
131
|
+
renderItem={renderSwap}
|
|
132
|
+
keyExtractor={(swap) => swap.id}
|
|
133
|
+
scrollElement={scrollElement}
|
|
134
|
+
/>
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Use a state-backed callback ref so the list receives the element after mounting and whenever it changes. `null` waits for an external element; `undefined` keeps the default list-owned scrollbar. The element must be an ancestor of the list. Keep the list's own height unconstrained so its content contributes to the parent's scroll range.
|
|
141
|
+
|
|
142
|
+
Multiple lists can share the same element, including lists in separate columns. Each uses the owner's viewport on the scroll axis and its own width/height on the cross axis. Content above the list is accounted for automatically, including preceding content that resizes. `scrollToIndex`, `scrollToOffset`, and `scrollToEnd` remain list-relative and move the shared owner.
|
|
143
|
+
|
|
144
|
+
`maintainVisibleContentPosition` anchors changes to the list's own rows; it does not freeze the layout of surrounding content. An offscreen list does not pull the owner back into view to apply a measurement correction.
|
|
145
|
+
|
|
146
|
+
`useWindowScroll` continues to use the browser window. Both modes share the same web implementation; `scrollElement` takes precedence when provided. As with window scrolling, external mode does not configure the owner's scrollbar styling or CSS snapping. It is not supported with `renderScrollComponent`.
|
|
147
|
+
|
|
115
148
|
## How to Build
|
|
116
149
|
|
|
117
150
|
1. `bun i`
|
package/package.json
CHANGED
package/react-native.js
CHANGED
|
@@ -935,8 +935,14 @@ function scheduleFullDrawDistancePrewarm(ctx) {
|
|
|
935
935
|
return;
|
|
936
936
|
}
|
|
937
937
|
state.scheduledWork.frame(() => {
|
|
938
|
-
var _a3;
|
|
939
|
-
|
|
938
|
+
var _a3, _b, _c;
|
|
939
|
+
if (state.props.hasExternalScroll && !hasActiveInitialScroll(state) && !state.scrollingTo && !state.pendingNativeMVCPAdjust) {
|
|
940
|
+
const offset = (_b = (_a3 = state.refScroller.current) == null ? void 0 : _a3.getRawScrollOffset) == null ? void 0 : _b.call(_a3);
|
|
941
|
+
if (offset !== void 0) {
|
|
942
|
+
state.scroll = state.scrollPending = state.props.horizontal ? toLogicalHorizontalOffset(state, offset, state.totalSize) : offset;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
(_c = state.triggerCalculateItemsInView) == null ? void 0 : _c.call(state);
|
|
940
946
|
}, "fullDrawDistancePrewarm");
|
|
941
947
|
}
|
|
942
948
|
|
|
@@ -949,6 +955,9 @@ function resetInitialRenderState(ctx, {
|
|
|
949
955
|
if (resetLayout) {
|
|
950
956
|
state.didContainersLayout = false;
|
|
951
957
|
state.queuedInitialLayout = false;
|
|
958
|
+
state.scrollBufferDirection = void 0;
|
|
959
|
+
state.scrollHistory.length = 0;
|
|
960
|
+
state.scheduledWork.cancel("renderRangeProjection");
|
|
952
961
|
state.edgeReachedGate = void 0;
|
|
953
962
|
state.isStartReached = null;
|
|
954
963
|
state.isEndReached = null;
|
|
@@ -1177,6 +1186,7 @@ function setSize(ctx, itemKey, size, notifyTotalSize = true) {
|
|
|
1177
1186
|
const previousSize = sizes.get(itemKey);
|
|
1178
1187
|
const diff = previousSize !== void 0 ? size - previousSize : size;
|
|
1179
1188
|
if (diff !== 0) {
|
|
1189
|
+
state.positionsAreCurrent = false;
|
|
1180
1190
|
addTotalSize(ctx, itemKey, diff, notifyTotalSize);
|
|
1181
1191
|
}
|
|
1182
1192
|
sizes.set(itemKey, size);
|
|
@@ -1237,6 +1247,7 @@ function getKnownOrFixedSize(ctx, key, index, data, resolved) {
|
|
|
1237
1247
|
const fixedSize = (resolved == null ? void 0 : resolved.didResolveFixedItemSize) ? resolved.fixedItemSize : getFixedItemSize(data, index, itemType);
|
|
1238
1248
|
if (fixedSize !== void 0) {
|
|
1239
1249
|
size = fixedSize + ctx.scrollAxisGap;
|
|
1250
|
+
state.positionsAreCurrent = false;
|
|
1240
1251
|
state.sizesKnown.set(key, size);
|
|
1241
1252
|
}
|
|
1242
1253
|
}
|
|
@@ -1850,6 +1861,9 @@ function updateScroll(ctx, newScroll, forceUpdate, options) {
|
|
|
1850
1861
|
state.scrollTime = currentTime;
|
|
1851
1862
|
const scrollDelta = Math.abs(newScroll - prevScroll);
|
|
1852
1863
|
const isUserScrollEvent = !!(options == null ? void 0 : options.fromNativeScrollEvent) && scrollDelta > 0.1 && !adjustChanged && scrollingTo === void 0 && !state.pendingNativeMVCPAdjust;
|
|
1864
|
+
if (isUserScrollEvent) {
|
|
1865
|
+
state.scrollBufferDirection = newScroll > prevScroll ? 1 : -1;
|
|
1866
|
+
}
|
|
1853
1867
|
const didCancelMaintainScrollAtEnd = Platform.OS === "web" && isUserScrollEvent && newScroll < prevScroll && !!(state.maintainingScrollAtEnd || state.pendingMaintainScrollAtEnd);
|
|
1854
1868
|
if (didCancelMaintainScrollAtEnd) {
|
|
1855
1869
|
finishMaintainScrollAtEnd(ctx);
|
|
@@ -1929,10 +1943,10 @@ function finishMaintainScrollAtEnd(ctx) {
|
|
|
1929
1943
|
}
|
|
1930
1944
|
}
|
|
1931
1945
|
function doMaintainScrollAtEnd(ctx, options) {
|
|
1932
|
-
var _a3, _b, _c, _d, _e, _f;
|
|
1946
|
+
var _a3, _b, _c, _d, _e, _f, _g, _h;
|
|
1933
1947
|
const state = ctx.state;
|
|
1934
1948
|
let didMaintain = false;
|
|
1935
|
-
if (state.isDragging) {
|
|
1949
|
+
if (state.isDragging || ((_b = (_a3 = state.refScroller.current) == null ? void 0 : _a3.isScrollInRange) == null ? void 0 : _b.call(_a3)) === false) {
|
|
1936
1950
|
finishMaintainScrollAtEnd(ctx);
|
|
1937
1951
|
} else {
|
|
1938
1952
|
const {
|
|
@@ -1944,11 +1958,11 @@ function doMaintainScrollAtEnd(ctx, options) {
|
|
|
1944
1958
|
const immediate = (options == null ? void 0 : options.immediate) && Platform.OS === "web" && !(maintainScrollAtEnd == null ? void 0 : maintainScrollAtEnd.animated);
|
|
1945
1959
|
const isWithinMaintainScrollAtEndThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
|
|
1946
1960
|
const isReplayingPendingMaintain = !!state.pendingMaintainScrollAtEnd;
|
|
1947
|
-
const shouldMaintainScrollAtEnd = !!(!((
|
|
1961
|
+
const shouldMaintainScrollAtEnd = !!(!((_c = ctx.scrollRequestTracker) == null ? void 0 : _c.isWaitingToRun()) && (!state.scrollingTo || state.scrollingTo.isScrollToEnd) && (isWithinMaintainScrollAtEndThreshold || isReplayingPendingMaintain || ((_d = state.scrollingTo) == null ? void 0 : _d.isScrollToEnd)) && maintainScrollAtEnd && didFinishInitialScroll);
|
|
1948
1962
|
if (shouldMaintainScrollAtEnd && !state.scrollingTo) {
|
|
1949
1963
|
const scroller = state.refScroller.current;
|
|
1950
|
-
const nativeMax = (
|
|
1951
|
-
const observed = (
|
|
1964
|
+
const nativeMax = (_e = scroller == null ? void 0 : scroller.getMaxScrollOffset) == null ? void 0 : _e.call(scroller);
|
|
1965
|
+
const observed = (_f = scroller == null ? void 0 : scroller.getCurrentScrollOffset) == null ? void 0 : _f.call(scroller);
|
|
1952
1966
|
if (nativeMax !== void 0 && observed !== void 0 && nativeMax < state.scroll - 1 && Math.abs(observed - nativeMax) <= 1) {
|
|
1953
1967
|
state.pendingMaintainScrollAtEnd = true;
|
|
1954
1968
|
state.scrollPending = observed;
|
|
@@ -1960,13 +1974,13 @@ function doMaintainScrollAtEnd(ctx, options) {
|
|
|
1960
1974
|
} else if (pendingNativeMVCPAdjust) {
|
|
1961
1975
|
state.pendingMaintainScrollAtEnd = shouldMaintainScrollAtEnd;
|
|
1962
1976
|
} else if (shouldMaintainScrollAtEnd && (state.scrollingTo || state.pendingScrollResolve)) {
|
|
1963
|
-
if (immediate && ((
|
|
1977
|
+
if (immediate && ((_g = state.scrollingTo) == null ? void 0 : _g.isScrollToEnd) && !state.scrollingTo.animated) {
|
|
1964
1978
|
state.pendingMaintainScrollAtEnd = false;
|
|
1965
1979
|
ctx.scrollToEnd({ animated: false });
|
|
1966
1980
|
didMaintain = true;
|
|
1967
1981
|
} else {
|
|
1968
1982
|
state.pendingMaintainScrollAtEnd = true;
|
|
1969
|
-
(
|
|
1983
|
+
(_h = state.maintainingScrollAtEnd) != null ? _h : state.maintainingScrollAtEnd = maintainScrollAtEnd.animated ? "pending-animated" : "pending-instant";
|
|
1970
1984
|
}
|
|
1971
1985
|
} else if (shouldMaintainScrollAtEnd && didContainersLayout) {
|
|
1972
1986
|
state.pendingMaintainScrollAtEnd = false;
|
|
@@ -1980,8 +1994,9 @@ function doMaintainScrollAtEnd(ctx, options) {
|
|
|
1980
1994
|
const scrollAtRequest = state.scroll;
|
|
1981
1995
|
state.maintainingScrollAtEnd = pendingState;
|
|
1982
1996
|
const run = () => {
|
|
1997
|
+
var _a4, _b2;
|
|
1983
1998
|
if (state.maintainingScrollAtEnd === pendingState) {
|
|
1984
|
-
if (state.isDragging) {
|
|
1999
|
+
if (state.isDragging || ((_b2 = (_a4 = state.refScroller.current) == null ? void 0 : _a4.isScrollInRange) == null ? void 0 : _b2.call(_a4)) === false) {
|
|
1985
2000
|
finishMaintainScrollAtEnd(ctx);
|
|
1986
2001
|
} else {
|
|
1987
2002
|
const isStillWithinThreshold = peek$(ctx, "isWithinMaintainScrollAtEndThreshold");
|
|
@@ -3319,6 +3334,7 @@ function handleInitialScrollDataChange(ctx, options) {
|
|
|
3319
3334
|
|
|
3320
3335
|
// src/core/resetLayoutCachesForDataChange.ts
|
|
3321
3336
|
function resetLayoutCachesForDataChange(state) {
|
|
3337
|
+
state.positionsAreCurrent = false;
|
|
3322
3338
|
state.indexByKey.clear();
|
|
3323
3339
|
state.idCache.length = 0;
|
|
3324
3340
|
state.positions.length = 0;
|
|
@@ -3599,7 +3615,7 @@ function updateItemPositions(ctx, dataChanged, {
|
|
|
3599
3615
|
scrollBottomBuffered: -1,
|
|
3600
3616
|
startIndex: 0
|
|
3601
3617
|
}) {
|
|
3602
|
-
var _a3, _b, _c, _d, _e;
|
|
3618
|
+
var _a3, _b, _c, _d, _e, _f;
|
|
3603
3619
|
const state = ctx.state;
|
|
3604
3620
|
const hasPositionListeners = ctx.positionListeners.size > 0;
|
|
3605
3621
|
const {
|
|
@@ -3615,6 +3631,11 @@ function updateItemPositions(ctx, dataChanged, {
|
|
|
3615
3631
|
const dataLength = data.length;
|
|
3616
3632
|
const numColumns = (_a3 = peek$(ctx, "numColumns")) != null ? _a3 : 1;
|
|
3617
3633
|
const hasColumns = numColumns > 1;
|
|
3634
|
+
const canReuseEstimates = !doMVCP || !state.didContainersLayout && Object.keys(state.averageSizes).length === 0;
|
|
3635
|
+
if (state.positionsAreCurrent && !dataChanged && !forceFullUpdate && state.positionRecalculationStartIndex === void 0 && !scrollingTo && !hasColumns && !snapToIndices && positions.length === dataLength && canReuseEstimates) {
|
|
3636
|
+
return;
|
|
3637
|
+
}
|
|
3638
|
+
state.positionsAreCurrent = false;
|
|
3618
3639
|
const indexByKeyForChecking = IS_DEV ? /* @__PURE__ */ new Map() : void 0;
|
|
3619
3640
|
const extraData = peek$(ctx, "extraData");
|
|
3620
3641
|
const layoutConfig = overrideItemLayout ? { span: 1 } : void 0;
|
|
@@ -3729,6 +3750,10 @@ function updateItemPositions(ctx, dataChanged, {
|
|
|
3729
3750
|
}
|
|
3730
3751
|
if (!didBreakEarly) {
|
|
3731
3752
|
updateTotalSize(ctx);
|
|
3753
|
+
state.positionsAreCurrent = !hasColumns;
|
|
3754
|
+
if (startIndex <= ((_f = state.positionRecalculationStartIndex) != null ? _f : -1)) {
|
|
3755
|
+
state.positionRecalculationStartIndex = void 0;
|
|
3756
|
+
}
|
|
3732
3757
|
}
|
|
3733
3758
|
if (snapToIndices) {
|
|
3734
3759
|
updateSnapToOffsets(ctx);
|
|
@@ -4291,7 +4316,7 @@ function handleStickyRecycling(ctx, stickyArray, scroll, drawDistance, currentSt
|
|
|
4291
4316
|
}
|
|
4292
4317
|
function trackVisibleRange(range, i, top, size, scroll, scrollBottom) {
|
|
4293
4318
|
let didPassVisibleEnd = false;
|
|
4294
|
-
if (range.startNoBuffer === null && top + size > scroll) {
|
|
4319
|
+
if (range.startNoBuffer === null && top + size > scroll && top <= scrollBottom) {
|
|
4295
4320
|
range.startNoBuffer = i;
|
|
4296
4321
|
}
|
|
4297
4322
|
if (range.firstFullyOnScreenIndex === void 0 && top >= scroll - 10 && top <= scrollBottom) {
|
|
@@ -4357,7 +4382,7 @@ function findFirstVisibleIndexInCachedRange(ctx, scroll) {
|
|
|
4357
4382
|
return null;
|
|
4358
4383
|
}
|
|
4359
4384
|
function updateViewabilityForCachedRange(ctx, viewabilityConfigCallbackPairs, scrollLength, scroll, scrollBottom) {
|
|
4360
|
-
var _a3, _b;
|
|
4385
|
+
var _a3, _b, _c, _d;
|
|
4361
4386
|
const state = ctx.state;
|
|
4362
4387
|
const {
|
|
4363
4388
|
endBuffered,
|
|
@@ -4391,14 +4416,14 @@ function updateViewabilityForCachedRange(ctx, viewabilityConfigCallbackPairs, sc
|
|
|
4391
4416
|
startNoBuffer: visibleRange.startNoBuffer
|
|
4392
4417
|
});
|
|
4393
4418
|
maybeEmitFirstVisibleItemChanged(state, visibleRange.startNoBuffer);
|
|
4394
|
-
if (visibleRange.startNoBuffer !== null && visibleRange.endNoBuffer !== null) {
|
|
4419
|
+
if (state.props.hasExternalScroll || visibleRange.startNoBuffer !== null && visibleRange.endNoBuffer !== null) {
|
|
4395
4420
|
updateViewableItems(
|
|
4396
4421
|
state,
|
|
4397
4422
|
ctx,
|
|
4398
4423
|
viewabilityConfigCallbackPairs,
|
|
4399
4424
|
scrollLength,
|
|
4400
|
-
visibleRange.startNoBuffer,
|
|
4401
|
-
visibleRange.endNoBuffer,
|
|
4425
|
+
(_c = visibleRange.startNoBuffer) != null ? _c : 0,
|
|
4426
|
+
(_d = visibleRange.endNoBuffer) != null ? _d : -1,
|
|
4402
4427
|
startBuffered,
|
|
4403
4428
|
endBuffered
|
|
4404
4429
|
);
|
|
@@ -4407,7 +4432,7 @@ function updateViewabilityForCachedRange(ctx, viewabilityConfigCallbackPairs, sc
|
|
|
4407
4432
|
function calculateItemsInView(ctx, params = {}) {
|
|
4408
4433
|
const state = ctx.state;
|
|
4409
4434
|
batchedUpdates(() => {
|
|
4410
|
-
var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u;
|
|
4435
|
+
var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
|
|
4411
4436
|
const {
|
|
4412
4437
|
columns,
|
|
4413
4438
|
containerItemKeys,
|
|
@@ -4459,7 +4484,7 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4459
4484
|
scrollAdjustPending = (_a4 = peek$(ctx, "scrollAdjustPending")) != null ? _a4 : 0;
|
|
4460
4485
|
scrollAdjustPad = scrollAdjustPending - topPad;
|
|
4461
4486
|
scroll = Math.round(nextScrollState + scrollExtra + scrollAdjustPad);
|
|
4462
|
-
if (scroll + scrollLength > totalSize) {
|
|
4487
|
+
if (!state.props.hasExternalScroll && scroll + scrollLength > totalSize) {
|
|
4463
4488
|
scroll = Math.max(0, totalSize - scrollLength);
|
|
4464
4489
|
}
|
|
4465
4490
|
};
|
|
@@ -4486,7 +4511,11 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4486
4511
|
let stickyState = dataChanged ? void 0 : resolveStickyState();
|
|
4487
4512
|
let scrollBufferTop = drawDistance;
|
|
4488
4513
|
let scrollBufferBottom = drawDistance;
|
|
4489
|
-
if (speed
|
|
4514
|
+
if (speed !== 0) {
|
|
4515
|
+
state.scrollBufferDirection = speed > 0 ? 1 : -1;
|
|
4516
|
+
}
|
|
4517
|
+
const bufferForward = state.scrollBufferDirection === 1 || state.scrollBufferDirection === void 0 && scroll < Math.max(50, drawDistance);
|
|
4518
|
+
if (bufferForward) {
|
|
4490
4519
|
scrollBufferTop = drawDistance * 0.5;
|
|
4491
4520
|
scrollBufferBottom = drawDistance * 1.5;
|
|
4492
4521
|
} else {
|
|
@@ -4496,8 +4525,8 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4496
4525
|
const shouldProjectRenderRange = !dataChanged && !forceFullItemPositions && !suppressInitialScrollSideEffects && !hasActiveInitialScroll(state) && !state.scrollingTo && !state.pendingNativeMVCPAdjust && !!peek$(ctx, "readyToRender");
|
|
4497
4526
|
const projectedBufferAdjustment = shouldProjectRenderRange ? getProjectedBufferAdjustment(speed, Math.min(scrollBufferTop, scrollBufferBottom)) : 0;
|
|
4498
4527
|
const updateScrollRange = () => {
|
|
4499
|
-
const scrollStart = Math.max(0, scroll);
|
|
4500
|
-
const overscrollBeforeContent = Math.max(0, -nativeScrollState);
|
|
4528
|
+
const scrollStart = state.props.hasExternalScroll ? scroll : Math.max(0, scroll);
|
|
4529
|
+
const overscrollBeforeContent = state.props.hasExternalScroll ? 0 : Math.max(0, -nativeScrollState);
|
|
4501
4530
|
scrollBottom = Math.max(scrollStart, scroll + scrollLength + overscrollBeforeContent);
|
|
4502
4531
|
scrollTopBuffered = scrollStart - scrollBufferTop + projectedBufferAdjustment;
|
|
4503
4532
|
scrollBottomBuffered = scrollBottom + scrollBufferBottom + projectedBufferAdjustment;
|
|
@@ -4626,7 +4655,7 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4626
4655
|
nextTop = top;
|
|
4627
4656
|
}
|
|
4628
4657
|
}
|
|
4629
|
-
if (
|
|
4658
|
+
if (startBuffered !== null) {
|
|
4630
4659
|
if (top <= scrollBottomBuffered) {
|
|
4631
4660
|
endBuffered = i;
|
|
4632
4661
|
if (scrollBottomBuffered > totalSize) {
|
|
@@ -4637,6 +4666,8 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4637
4666
|
} else {
|
|
4638
4667
|
foundEnd = true;
|
|
4639
4668
|
}
|
|
4669
|
+
} else if (top > scrollBottomBuffered) {
|
|
4670
|
+
foundEnd = true;
|
|
4640
4671
|
}
|
|
4641
4672
|
}
|
|
4642
4673
|
}
|
|
@@ -4654,6 +4685,12 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4654
4685
|
bottom: nextBottom,
|
|
4655
4686
|
top: nextTop
|
|
4656
4687
|
};
|
|
4688
|
+
} else if (enableScrollForNextCalculateItemsInView && state.props.hasExternalScroll) {
|
|
4689
|
+
if (scrollBottomBuffered < 0) {
|
|
4690
|
+
state.scrollForNextCalculateItemsInView = { bottom: 0, top: null };
|
|
4691
|
+
} else if (scrollTopBuffered > totalSize) {
|
|
4692
|
+
state.scrollForNextCalculateItemsInView = { bottom: null, top: totalSize };
|
|
4693
|
+
}
|
|
4657
4694
|
}
|
|
4658
4695
|
let numContainers = prevNumContainers;
|
|
4659
4696
|
const pendingRemoval = [];
|
|
@@ -4677,7 +4714,9 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4677
4714
|
}
|
|
4678
4715
|
const hasScrollTargetPinnedRange = scrollTargetPinnedStart <= scrollTargetPinnedEnd;
|
|
4679
4716
|
const isPinnedRenderIndex = (index) => alwaysRenderIndicesSet.has(index) || hasScrollTargetPinnedRange && index >= scrollTargetPinnedStart && index <= scrollTargetPinnedEnd;
|
|
4680
|
-
if (startBuffered !== null && endBuffered !== null) {
|
|
4717
|
+
if (startBuffered !== null && endBuffered !== null || alwaysRenderIndicesArr.length || hasScrollTargetPinnedRange) {
|
|
4718
|
+
const allocationStart = startBuffered != null ? startBuffered : 0;
|
|
4719
|
+
const allocationEnd = endBuffered != null ? endBuffered : -1;
|
|
4681
4720
|
const needNewContainers = [];
|
|
4682
4721
|
const needNewContainersSet = /* @__PURE__ */ new Set();
|
|
4683
4722
|
const addPinnedIndex = (index) => {
|
|
@@ -4693,7 +4732,7 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4693
4732
|
}
|
|
4694
4733
|
}
|
|
4695
4734
|
};
|
|
4696
|
-
for (let i =
|
|
4735
|
+
for (let i = allocationStart; i <= allocationEnd; i++) {
|
|
4697
4736
|
const id = (_m = idCache[i]) != null ? _m : getId(state, i);
|
|
4698
4737
|
if (!containerItemKeys.has(id)) {
|
|
4699
4738
|
needNewContainersSet.add(i);
|
|
@@ -4715,8 +4754,8 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4715
4754
|
(_n = stickyState == null ? void 0 : stickyState.currentStickyIdx) != null ? _n : -1,
|
|
4716
4755
|
needNewContainers,
|
|
4717
4756
|
needNewContainersSet,
|
|
4718
|
-
|
|
4719
|
-
|
|
4757
|
+
allocationStart,
|
|
4758
|
+
allocationEnd
|
|
4720
4759
|
);
|
|
4721
4760
|
} else if (previousStickyIndex !== -1) {
|
|
4722
4761
|
set$(ctx, "activeStickyIndex", -1);
|
|
@@ -4725,8 +4764,8 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4725
4764
|
const availableContainerAllocations = findAvailableContainers(
|
|
4726
4765
|
ctx,
|
|
4727
4766
|
needNewContainers,
|
|
4728
|
-
|
|
4729
|
-
|
|
4767
|
+
allocationStart,
|
|
4768
|
+
allocationEnd,
|
|
4730
4769
|
pendingRemoval,
|
|
4731
4770
|
protectedContainerKeys,
|
|
4732
4771
|
// Initial end alignment has no scroll velocity yet. Keep its
|
|
@@ -4853,19 +4892,19 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4853
4892
|
handleInitialScrollLayoutReady(ctx);
|
|
4854
4893
|
}
|
|
4855
4894
|
}
|
|
4856
|
-
if (viewabilityConfigCallbackPairs && visibleRange.startNoBuffer !== null && visibleRange.endNoBuffer !== null) {
|
|
4895
|
+
if (viewabilityConfigCallbackPairs && (state.props.hasExternalScroll || visibleRange.startNoBuffer !== null && visibleRange.endNoBuffer !== null)) {
|
|
4857
4896
|
updateViewableItems(
|
|
4858
4897
|
ctx.state,
|
|
4859
4898
|
ctx,
|
|
4860
4899
|
viewabilityConfigCallbackPairs,
|
|
4861
4900
|
scrollLength,
|
|
4862
|
-
visibleRange.startNoBuffer,
|
|
4863
|
-
visibleRange.endNoBuffer,
|
|
4864
|
-
startBuffered != null ? startBuffered : visibleRange.startNoBuffer,
|
|
4865
|
-
endBuffered != null ? endBuffered : visibleRange.endNoBuffer
|
|
4901
|
+
(_u = visibleRange.startNoBuffer) != null ? _u : 0,
|
|
4902
|
+
(_v = visibleRange.endNoBuffer) != null ? _v : -1,
|
|
4903
|
+
(_w = startBuffered != null ? startBuffered : visibleRange.startNoBuffer) != null ? _w : 0,
|
|
4904
|
+
(_x = endBuffered != null ? endBuffered : visibleRange.endNoBuffer) != null ? _x : -1
|
|
4866
4905
|
);
|
|
4867
4906
|
}
|
|
4868
|
-
(
|
|
4907
|
+
(_y = stickyState == null ? void 0 : stickyState.finishCalculateItemsInView) == null ? void 0 : _y.call(stickyState);
|
|
4869
4908
|
});
|
|
4870
4909
|
}
|
|
4871
4910
|
|
|
@@ -5160,6 +5199,7 @@ function updateOneItemSize(ctx, itemKey, sizeObj, resolvedMeasurementItem, notif
|
|
|
5160
5199
|
return 0;
|
|
5161
5200
|
}
|
|
5162
5201
|
const size = Platform.OS === "web" ? Math.round(rawSize) : roundSize(rawSize);
|
|
5202
|
+
if (prevSizeKnown !== size) state.positionsAreCurrent = false;
|
|
5163
5203
|
sizesKnown.set(itemKey, size);
|
|
5164
5204
|
if (fixedItemSize === void 0 && size > 0) {
|
|
5165
5205
|
itemType != null ? itemType : itemType = getItemType ? (_b = getItemType(itemData, index)) != null ? _b : "" : "";
|
|
@@ -6260,6 +6300,7 @@ var ListComponent = typedMemo(function ListComponent2({
|
|
|
6260
6300
|
stickyHeaderConfig,
|
|
6261
6301
|
stickyHeaderIndices,
|
|
6262
6302
|
useWindowScroll = false,
|
|
6303
|
+
scrollElement,
|
|
6263
6304
|
...rest
|
|
6264
6305
|
}) {
|
|
6265
6306
|
const ctx = useStateContext();
|
|
@@ -6325,7 +6366,7 @@ var ListComponent = typedMemo(function ListComponent2({
|
|
|
6325
6366
|
SnapOrScroll,
|
|
6326
6367
|
{
|
|
6327
6368
|
...rest,
|
|
6328
|
-
...Platform.OS === "web" ? ScrollComponent === ListComponentScrollView ? { onInternalScrollEnd, useWindowScroll } : {} : { onScrollBeginDrag: onInternalScrollBeginDrag, onScrollEndDrag: onInternalScrollEndDrag },
|
|
6369
|
+
...Platform.OS === "web" ? ScrollComponent === ListComponentScrollView ? { onInternalScrollEnd, scrollElement, useWindowScroll } : {} : { onScrollBeginDrag: onInternalScrollBeginDrag, onScrollEndDrag: onInternalScrollEndDrag },
|
|
6329
6370
|
contentContainerStyle: [
|
|
6330
6371
|
horizontal ? { height: "100%" } : {},
|
|
6331
6372
|
contentContainerStyle,
|
|
@@ -6365,7 +6406,15 @@ var WEB_UNBOUNDED_HEIGHT_CONTAINER_RATIO = 0.9;
|
|
|
6365
6406
|
var WEB_UNBOUNDED_HEIGHT_VIEWPORT_RATIO = 0.9;
|
|
6366
6407
|
function useDevChecksImpl(props) {
|
|
6367
6408
|
const ctx = useStateContext();
|
|
6368
|
-
const {
|
|
6409
|
+
const {
|
|
6410
|
+
anchoredEndSpace,
|
|
6411
|
+
childrenMode,
|
|
6412
|
+
keyExtractor,
|
|
6413
|
+
numColumns,
|
|
6414
|
+
renderScrollComponent,
|
|
6415
|
+
scrollElement,
|
|
6416
|
+
useWindowScroll
|
|
6417
|
+
} = props;
|
|
6369
6418
|
const hasAnchoredEndSpace = !!anchoredEndSpace;
|
|
6370
6419
|
React2.useEffect(() => {
|
|
6371
6420
|
if (hasAnchoredEndSpace && (numColumns != null ? numColumns : 1) > 1) {
|
|
@@ -6376,13 +6425,13 @@ function useDevChecksImpl(props) {
|
|
|
6376
6425
|
}
|
|
6377
6426
|
}, [hasAnchoredEndSpace, numColumns]);
|
|
6378
6427
|
React2.useEffect(() => {
|
|
6379
|
-
if (useWindowScroll && renderScrollComponent) {
|
|
6428
|
+
if ((useWindowScroll || scrollElement !== void 0) && renderScrollComponent) {
|
|
6380
6429
|
warnDevOnce(
|
|
6381
6430
|
"useWindowScrollRenderScrollComponent",
|
|
6382
|
-
"useWindowScroll
|
|
6431
|
+
"useWindowScroll and scrollElement are not supported when renderScrollComponent is provided."
|
|
6383
6432
|
);
|
|
6384
6433
|
}
|
|
6385
|
-
}, [renderScrollComponent, useWindowScroll]);
|
|
6434
|
+
}, [renderScrollComponent, scrollElement, useWindowScroll]);
|
|
6386
6435
|
React2.useEffect(() => {
|
|
6387
6436
|
if (!keyExtractor && !ctx.state.isFirst && ctx.state.didDataChange && !childrenMode) {
|
|
6388
6437
|
warnDevOnce(
|
|
@@ -6394,8 +6443,8 @@ function useDevChecksImpl(props) {
|
|
|
6394
6443
|
React2.useEffect(() => {
|
|
6395
6444
|
const state = ctx.state;
|
|
6396
6445
|
const dataLength = state.props.data.length;
|
|
6397
|
-
const
|
|
6398
|
-
if (Platform.OS !== "web" ||
|
|
6446
|
+
const usesExternalScroll = state.props.hasExternalScroll;
|
|
6447
|
+
if (Platform.OS !== "web" || usesExternalScroll || dataLength < WEB_UNBOUNDED_HEIGHT_MIN_DATA_LENGTH) {
|
|
6399
6448
|
return;
|
|
6400
6449
|
}
|
|
6401
6450
|
const warnIfUnboundedOuterSize = () => {
|
|
@@ -6559,7 +6608,8 @@ function doInitialAllocateContainers(ctx) {
|
|
|
6559
6608
|
calculateItemsInView(ctx, { dataChanged: true, doMVCP: true });
|
|
6560
6609
|
});
|
|
6561
6610
|
} else {
|
|
6562
|
-
|
|
6611
|
+
const reuseInitialPositions = !state.didLoad && state.positionsAreCurrent && !state.didDataChange && !state.didColumnsChange;
|
|
6612
|
+
calculateItemsInView(ctx, { dataChanged: !reuseInitialPositions, doMVCP: true });
|
|
6563
6613
|
}
|
|
6564
6614
|
}
|
|
6565
6615
|
return true;
|
|
@@ -6598,10 +6648,8 @@ function handleLayout(ctx, layoutParam, setCanRender) {
|
|
|
6598
6648
|
updateContentMetricsState(ctx);
|
|
6599
6649
|
state.lastBatchingAction = Date.now();
|
|
6600
6650
|
state.scrollForNextCalculateItemsInView = void 0;
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
}
|
|
6604
|
-
if (needsCalculate) {
|
|
6651
|
+
const didAllocate = scrollLength > 0 && doInitialAllocateContainers(ctx);
|
|
6652
|
+
if (needsCalculate && (!didAllocate || state.initialScroll)) {
|
|
6605
6653
|
calculateItemsInView(ctx, { doMVCP: true });
|
|
6606
6654
|
}
|
|
6607
6655
|
if (didChange || otherAxisSize !== prevOtherAxisSize) {
|
|
@@ -6683,7 +6731,7 @@ function onScroll(ctx, event) {
|
|
|
6683
6731
|
}
|
|
6684
6732
|
state.lastNativeScroll = newScroll;
|
|
6685
6733
|
state.lastNativeScrollTime = Date.now();
|
|
6686
|
-
if (state.scrollingTo && state.scrollingTo.offset >= newScroll) {
|
|
6734
|
+
if (!state.props.hasExternalScroll && state.scrollingTo && state.scrollingTo.offset >= newScroll) {
|
|
6687
6735
|
const maxOffset = clampScrollOffset(ctx, newScroll, state.scrollingTo);
|
|
6688
6736
|
if (newScroll !== maxOffset && Math.abs(newScroll - maxOffset) > 1) {
|
|
6689
6737
|
newScroll = maxOffset;
|
|
@@ -7466,6 +7514,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7466
7514
|
stickyHeaderIndices: stickyHeaderIndicesProp,
|
|
7467
7515
|
style: styleProp,
|
|
7468
7516
|
useWindowScroll = false,
|
|
7517
|
+
scrollElement,
|
|
7469
7518
|
viewabilityConfig,
|
|
7470
7519
|
viewabilityConfigCallbackPairs,
|
|
7471
7520
|
...rest
|
|
@@ -7560,7 +7609,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7560
7609
|
dataVersion,
|
|
7561
7610
|
keyExtractor
|
|
7562
7611
|
]);
|
|
7563
|
-
const
|
|
7612
|
+
const scrollElementResolved = Platform.OS === "web" && !renderScrollComponent ? scrollElement : void 0;
|
|
7613
|
+
const useWindowScrollResolved = Platform.OS === "web" && !!useWindowScroll && scrollElementResolved === void 0 && !renderScrollComponent;
|
|
7614
|
+
const hasExternalScroll = useWindowScrollResolved || scrollElementResolved !== void 0;
|
|
7564
7615
|
const refState = React2.useRef(void 0);
|
|
7565
7616
|
const hasOverrideItemLayout = !!overrideItemLayout;
|
|
7566
7617
|
const prevHasOverrideItemLayout = React2.useRef(hasOverrideItemLayout);
|
|
@@ -7698,6 +7749,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7698
7749
|
estimatedItemSize,
|
|
7699
7750
|
getFixedItemSize: useWrapIfItem(getFixedItemSize),
|
|
7700
7751
|
getItemType: useWrapIfItem(getItemType),
|
|
7752
|
+
hasExternalScroll,
|
|
7701
7753
|
hideItemsUntilMeasured: experimental_hideItemsUntilMeasured,
|
|
7702
7754
|
horizontal: !!horizontal,
|
|
7703
7755
|
itemsAreEqual,
|
|
@@ -7894,9 +7946,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7894
7946
|
const { onLayout } = useOnLayoutSync({
|
|
7895
7947
|
onLayoutChange,
|
|
7896
7948
|
onLayoutProp,
|
|
7897
|
-
ref: refScroller
|
|
7898
|
-
// the type of ScrollView doesn't include measure?
|
|
7899
|
-
});
|
|
7949
|
+
ref: refScroller});
|
|
7900
7950
|
React2.useLayoutEffect(() => {
|
|
7901
7951
|
if (snapToIndices) {
|
|
7902
7952
|
updateSnapToOffsets(ctx);
|
|
@@ -8064,6 +8114,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8064
8114
|
refScrollView: combinedRef,
|
|
8065
8115
|
renderScrollComponent,
|
|
8066
8116
|
scrollAdjustHandler: (_s = refState.current) == null ? void 0 : _s.scrollAdjustHandler,
|
|
8117
|
+
scrollElement: scrollElementResolved,
|
|
8067
8118
|
scrollEventThrottle: 0,
|
|
8068
8119
|
snapToIndices,
|
|
8069
8120
|
stickyHeaderIndices,
|