@legendapp/list 3.3.7 → 3.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.DS_Store +0 -0
- package/CHANGELOG.md +8 -0
- package/animated.d.ts +17 -1
- package/keyboard-legacy.d.ts +3 -1
- package/keyboard.d.ts +3 -1
- package/package.json +1 -1
- package/react-native.d.ts +17 -1
- package/react-native.js +72 -12
- package/react-native.mjs +72 -12
- package/react-native.web.d.ts +17 -1
- package/react-native.web.js +27 -5
- package/react-native.web.mjs +27 -5
- package/react.d.ts +17 -1
- package/react.js +27 -5
- package/react.mjs +27 -5
- package/reanimated.d.ts +17 -1
- package/reanimated.js +8 -4
- package/reanimated.mjs +8 -4
- package/section-list.d.ts +17 -1
package/.DS_Store
ADDED
|
Binary file
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## 3.3.9
|
|
2
|
+
|
|
3
|
+
- Fix: Rows after an item that changes size stay in the correct positions while scrolling
|
|
4
|
+
|
|
5
|
+
## 3.3.8
|
|
6
|
+
|
|
7
|
+
- Feat: Add `experimental_hideItemsUntilMeasured` to make items never display at provisional layouts and wait for correct sizing, at the cost of an extra render per recycled row. This fixes cases where slow item renders could display with gaps/overlaps when scrolling up quickly on slow phones.
|
|
8
|
+
|
|
1
9
|
## 3.3.7
|
|
2
10
|
|
|
3
11
|
- Fix: Recycled rows no longer briefly show content from the wrong item when data is prepended.
|
package/animated.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ interface MaintainVisibleContentPositionNormalized<ItemT = any> {
|
|
|
8
8
|
shouldRestorePosition?: (item: ItemT, index: number, data: readonly ItemT[]) => boolean;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
type ListenerType = "activeStickyIndex" | "alignItemsAtEndPadding" | "anchoredEndSpaceSize" | "containerLayoutEpoch" | "debugComputedScroll" | "debugRawScroll" | "extraData" | "footerSize" | "headerSize" | "lastItemKeys" | "lastPositionUpdate" | "maintainVisibleContentPosition" | "numColumns" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "scrollAdjust" | "scrollAdjustPending" | "scrollAdjustUserOffset" | "scrollSize" | "snapToOffsets" | "stylePaddingTop" | "totalSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | `containerColumn${number}` | `containerSpan${number}` | `containerItemData${number}` | `containerItemIndex${number}` | `containerItemKey${number}` | `containerPosition${number}` | `containerSticky${number}`;
|
|
11
|
+
type ListenerType = "activeStickyIndex" | "alignItemsAtEndPadding" | "anchoredEndSpaceSize" | "containerLayoutEpoch" | "debugComputedScroll" | "debugRawScroll" | "extraData" | "footerSize" | "headerSize" | "lastItemKeys" | "lastPositionUpdate" | "maintainVisibleContentPosition" | "numColumns" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "scrollAdjust" | "scrollAdjustPending" | "scrollAdjustUserOffset" | "scrollSize" | "snapToOffsets" | "stylePaddingTop" | "totalSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | `containerColumn${number}` | `containerSpan${number}` | `containerItemData${number}` | `containerItemIndex${number}` | `containerItemKey${number}` | `containerLayoutReady${number}` | `containerPosition${number}` | `containerSticky${number}`;
|
|
12
12
|
type LegendListListenerType = Extract<ListenerType, "activeStickyIndex" | "anchoredEndSpaceSize" | "footerSize" | "headerSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | "lastItemKeys" | "lastPositionUpdate" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "snapToOffsets" | "totalSize">;
|
|
13
13
|
type ListenerTypeValueMap = {
|
|
14
14
|
activeStickyIndex: number;
|
|
@@ -47,6 +47,8 @@ type ListenerTypeValueMap = {
|
|
|
47
47
|
adaptiveRender: "normal" | "light";
|
|
48
48
|
} & {
|
|
49
49
|
[K in ListenerType as K extends `containerItemKey${number}` ? K : never]: string;
|
|
50
|
+
} & {
|
|
51
|
+
[K in ListenerType as K extends `containerLayoutReady${number}` ? K : never]: boolean;
|
|
50
52
|
} & {
|
|
51
53
|
[K in ListenerType as K extends `containerItemData${number}` ? K : never]: any;
|
|
52
54
|
} & {
|
|
@@ -348,6 +350,20 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
|
|
|
348
350
|
* Configures the adaptive render signal. Items can use this to render a lighter version while scrolling quickly.
|
|
349
351
|
*/
|
|
350
352
|
experimental_adaptiveRender?: AdaptiveRenderConfig;
|
|
353
|
+
/**
|
|
354
|
+
* Keeps a newly recycled item laid out but invisible until its size has been measured, so it is never painted at
|
|
355
|
+
* the estimated position it was recycled to. Only applies on the new architecture.
|
|
356
|
+
*
|
|
357
|
+
* This trades a possible flash at the wrong position for an extra render and native commit per recycled row, so it
|
|
358
|
+
* is worth enabling only for lists with dynamically sized items whose estimates are visibly wrong. Items with a
|
|
359
|
+
* size from `getFixedItemSize`, or with an already measured size, are exact and render immediately either way.
|
|
360
|
+
*
|
|
361
|
+
* Sticky headers are intentionally excluded. They are painted from a scroll-driven interpolation rather than the
|
|
362
|
+
* committed position, so hiding them would blink a header out mid-scroll without preventing a flash.
|
|
363
|
+
*
|
|
364
|
+
* @default false
|
|
365
|
+
*/
|
|
366
|
+
experimental_hideItemsUntilMeasured?: boolean;
|
|
351
367
|
/**
|
|
352
368
|
* Function to call when the user pulls to refresh.
|
|
353
369
|
*/
|
package/keyboard-legacy.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ interface MaintainVisibleContentPositionNormalized<ItemT = any> {
|
|
|
9
9
|
shouldRestorePosition?: (item: ItemT, index: number, data: readonly ItemT[]) => boolean;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
type ListenerType = "activeStickyIndex" | "alignItemsAtEndPadding" | "anchoredEndSpaceSize" | "containerLayoutEpoch" | "debugComputedScroll" | "debugRawScroll" | "extraData" | "footerSize" | "headerSize" | "lastItemKeys" | "lastPositionUpdate" | "maintainVisibleContentPosition" | "numColumns" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "scrollAdjust" | "scrollAdjustPending" | "scrollAdjustUserOffset" | "scrollSize" | "snapToOffsets" | "stylePaddingTop" | "totalSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | `containerColumn${number}` | `containerSpan${number}` | `containerItemData${number}` | `containerItemIndex${number}` | `containerItemKey${number}` | `containerPosition${number}` | `containerSticky${number}`;
|
|
12
|
+
type ListenerType = "activeStickyIndex" | "alignItemsAtEndPadding" | "anchoredEndSpaceSize" | "containerLayoutEpoch" | "debugComputedScroll" | "debugRawScroll" | "extraData" | "footerSize" | "headerSize" | "lastItemKeys" | "lastPositionUpdate" | "maintainVisibleContentPosition" | "numColumns" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "scrollAdjust" | "scrollAdjustPending" | "scrollAdjustUserOffset" | "scrollSize" | "snapToOffsets" | "stylePaddingTop" | "totalSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | `containerColumn${number}` | `containerSpan${number}` | `containerItemData${number}` | `containerItemIndex${number}` | `containerItemKey${number}` | `containerLayoutReady${number}` | `containerPosition${number}` | `containerSticky${number}`;
|
|
13
13
|
type LegendListListenerType = Extract<ListenerType, "activeStickyIndex" | "anchoredEndSpaceSize" | "footerSize" | "headerSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | "lastItemKeys" | "lastPositionUpdate" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "snapToOffsets" | "totalSize">;
|
|
14
14
|
type ListenerTypeValueMap = {
|
|
15
15
|
activeStickyIndex: number;
|
|
@@ -48,6 +48,8 @@ type ListenerTypeValueMap = {
|
|
|
48
48
|
adaptiveRender: "normal" | "light";
|
|
49
49
|
} & {
|
|
50
50
|
[K in ListenerType as K extends `containerItemKey${number}` ? K : never]: string;
|
|
51
|
+
} & {
|
|
52
|
+
[K in ListenerType as K extends `containerLayoutReady${number}` ? K : never]: boolean;
|
|
51
53
|
} & {
|
|
52
54
|
[K in ListenerType as K extends `containerItemData${number}` ? K : never]: any;
|
|
53
55
|
} & {
|
package/keyboard.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ interface MaintainVisibleContentPositionNormalized<ItemT = any> {
|
|
|
10
10
|
shouldRestorePosition?: (item: ItemT, index: number, data: readonly ItemT[]) => boolean;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
type ListenerType = "activeStickyIndex" | "alignItemsAtEndPadding" | "anchoredEndSpaceSize" | "containerLayoutEpoch" | "debugComputedScroll" | "debugRawScroll" | "extraData" | "footerSize" | "headerSize" | "lastItemKeys" | "lastPositionUpdate" | "maintainVisibleContentPosition" | "numColumns" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "scrollAdjust" | "scrollAdjustPending" | "scrollAdjustUserOffset" | "scrollSize" | "snapToOffsets" | "stylePaddingTop" | "totalSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | `containerColumn${number}` | `containerSpan${number}` | `containerItemData${number}` | `containerItemIndex${number}` | `containerItemKey${number}` | `containerPosition${number}` | `containerSticky${number}`;
|
|
13
|
+
type ListenerType = "activeStickyIndex" | "alignItemsAtEndPadding" | "anchoredEndSpaceSize" | "containerLayoutEpoch" | "debugComputedScroll" | "debugRawScroll" | "extraData" | "footerSize" | "headerSize" | "lastItemKeys" | "lastPositionUpdate" | "maintainVisibleContentPosition" | "numColumns" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "scrollAdjust" | "scrollAdjustPending" | "scrollAdjustUserOffset" | "scrollSize" | "snapToOffsets" | "stylePaddingTop" | "totalSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | `containerColumn${number}` | `containerSpan${number}` | `containerItemData${number}` | `containerItemIndex${number}` | `containerItemKey${number}` | `containerLayoutReady${number}` | `containerPosition${number}` | `containerSticky${number}`;
|
|
14
14
|
type LegendListListenerType = Extract<ListenerType, "activeStickyIndex" | "anchoredEndSpaceSize" | "footerSize" | "headerSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | "lastItemKeys" | "lastPositionUpdate" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "snapToOffsets" | "totalSize">;
|
|
15
15
|
type ListenerTypeValueMap = {
|
|
16
16
|
activeStickyIndex: number;
|
|
@@ -49,6 +49,8 @@ type ListenerTypeValueMap = {
|
|
|
49
49
|
adaptiveRender: "normal" | "light";
|
|
50
50
|
} & {
|
|
51
51
|
[K in ListenerType as K extends `containerItemKey${number}` ? K : never]: string;
|
|
52
|
+
} & {
|
|
53
|
+
[K in ListenerType as K extends `containerLayoutReady${number}` ? K : never]: boolean;
|
|
52
54
|
} & {
|
|
53
55
|
[K in ListenerType as K extends `containerItemData${number}` ? K : never]: any;
|
|
54
56
|
} & {
|
package/package.json
CHANGED
package/react-native.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ interface MaintainVisibleContentPositionNormalized<ItemT = any> {
|
|
|
8
8
|
shouldRestorePosition?: (item: ItemT, index: number, data: readonly ItemT[]) => boolean;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
type ListenerType = "activeStickyIndex" | "alignItemsAtEndPadding" | "anchoredEndSpaceSize" | "containerLayoutEpoch" | "debugComputedScroll" | "debugRawScroll" | "extraData" | "footerSize" | "headerSize" | "lastItemKeys" | "lastPositionUpdate" | "maintainVisibleContentPosition" | "numColumns" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "scrollAdjust" | "scrollAdjustPending" | "scrollAdjustUserOffset" | "scrollSize" | "snapToOffsets" | "stylePaddingTop" | "totalSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | `containerColumn${number}` | `containerSpan${number}` | `containerItemData${number}` | `containerItemIndex${number}` | `containerItemKey${number}` | `containerPosition${number}` | `containerSticky${number}`;
|
|
11
|
+
type ListenerType = "activeStickyIndex" | "alignItemsAtEndPadding" | "anchoredEndSpaceSize" | "containerLayoutEpoch" | "debugComputedScroll" | "debugRawScroll" | "extraData" | "footerSize" | "headerSize" | "lastItemKeys" | "lastPositionUpdate" | "maintainVisibleContentPosition" | "numColumns" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "scrollAdjust" | "scrollAdjustPending" | "scrollAdjustUserOffset" | "scrollSize" | "snapToOffsets" | "stylePaddingTop" | "totalSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | `containerColumn${number}` | `containerSpan${number}` | `containerItemData${number}` | `containerItemIndex${number}` | `containerItemKey${number}` | `containerLayoutReady${number}` | `containerPosition${number}` | `containerSticky${number}`;
|
|
12
12
|
type LegendListListenerType = Extract<ListenerType, "activeStickyIndex" | "anchoredEndSpaceSize" | "footerSize" | "headerSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | "lastItemKeys" | "lastPositionUpdate" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "snapToOffsets" | "totalSize">;
|
|
13
13
|
type ListenerTypeValueMap = {
|
|
14
14
|
activeStickyIndex: number;
|
|
@@ -47,6 +47,8 @@ type ListenerTypeValueMap = {
|
|
|
47
47
|
adaptiveRender: "normal" | "light";
|
|
48
48
|
} & {
|
|
49
49
|
[K in ListenerType as K extends `containerItemKey${number}` ? K : never]: string;
|
|
50
|
+
} & {
|
|
51
|
+
[K in ListenerType as K extends `containerLayoutReady${number}` ? K : never]: boolean;
|
|
50
52
|
} & {
|
|
51
53
|
[K in ListenerType as K extends `containerItemData${number}` ? K : never]: any;
|
|
52
54
|
} & {
|
|
@@ -348,6 +350,20 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
|
|
|
348
350
|
* Configures the adaptive render signal. Items can use this to render a lighter version while scrolling quickly.
|
|
349
351
|
*/
|
|
350
352
|
experimental_adaptiveRender?: AdaptiveRenderConfig;
|
|
353
|
+
/**
|
|
354
|
+
* Keeps a newly recycled item laid out but invisible until its size has been measured, so it is never painted at
|
|
355
|
+
* the estimated position it was recycled to. Only applies on the new architecture.
|
|
356
|
+
*
|
|
357
|
+
* This trades a possible flash at the wrong position for an extra render and native commit per recycled row, so it
|
|
358
|
+
* is worth enabling only for lists with dynamically sized items whose estimates are visibly wrong. Items with a
|
|
359
|
+
* size from `getFixedItemSize`, or with an already measured size, are exact and render immediately either way.
|
|
360
|
+
*
|
|
361
|
+
* Sticky headers are intentionally excluded. They are painted from a scroll-driven interpolation rather than the
|
|
362
|
+
* committed position, so hiding them would blink a header out mid-scroll without preventing a flash.
|
|
363
|
+
*
|
|
364
|
+
* @default false
|
|
365
|
+
*/
|
|
366
|
+
experimental_hideItemsUntilMeasured?: boolean;
|
|
351
367
|
/**
|
|
352
368
|
* Function to call when the user pulls to refresh.
|
|
353
369
|
*/
|
package/react-native.js
CHANGED
|
@@ -4391,7 +4391,9 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4391
4391
|
const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
|
|
4392
4392
|
updateItemPositions(ctx, dataChanged, {
|
|
4393
4393
|
doMVCP,
|
|
4394
|
-
|
|
4394
|
+
// A changed size shifts every following position. The scrolling early-exit
|
|
4395
|
+
// would leave the untouched suffix in the old coordinate space.
|
|
4396
|
+
forceFullUpdate: !!forceFullItemPositions || minIndexSizeChanged !== void 0,
|
|
4395
4397
|
optimizeForVisibleWindow,
|
|
4396
4398
|
scrollBottomBuffered,
|
|
4397
4399
|
scrollVelocity: speed,
|
|
@@ -4596,15 +4598,19 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4596
4598
|
if (oldKey && oldKey !== id) {
|
|
4597
4599
|
containerItemKeys.delete(oldKey);
|
|
4598
4600
|
}
|
|
4601
|
+
state.containerItemMetadata.set(
|
|
4602
|
+
containerIndex,
|
|
4603
|
+
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4604
|
+
);
|
|
4599
4605
|
if (oldKey !== id) {
|
|
4600
4606
|
changedContainerIds != null ? changedContainerIds : changedContainerIds = /* @__PURE__ */ new Set();
|
|
4601
4607
|
changedContainerIds.add(containerIndex);
|
|
4602
4608
|
state.containerItemGenerations[containerIndex] = ((_p = state.containerItemGenerations[containerIndex]) != null ? _p : 0) + 1;
|
|
4609
|
+
if (state.props.hideItemsUntilMeasured) {
|
|
4610
|
+
const isLayoutReady = state.sizesKnown.has(id) || resolveContainerItemMetadata(state, containerIndex, i, data[i]).fixedItemSize !== void 0;
|
|
4611
|
+
set$(ctx, `containerLayoutReady${containerIndex}`, isLayoutReady);
|
|
4612
|
+
}
|
|
4603
4613
|
}
|
|
4604
|
-
state.containerItemMetadata.set(
|
|
4605
|
-
containerIndex,
|
|
4606
|
-
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4607
|
-
);
|
|
4608
4614
|
set$(ctx, `containerItemKey${containerIndex}`, id);
|
|
4609
4615
|
set$(ctx, `containerItemIndex${containerIndex}`, i);
|
|
4610
4616
|
set$(ctx, `containerItemData${containerIndex}`, data[i]);
|
|
@@ -5036,24 +5042,39 @@ function resolveSkippedAnchorReset(ctx, itemKey) {
|
|
|
5036
5042
|
state.userScrollAnchorReset = void 0;
|
|
5037
5043
|
}
|
|
5038
5044
|
}
|
|
5045
|
+
function revealMeasuredGeneration(ctx, containerId, itemKey, generation) {
|
|
5046
|
+
var _a3;
|
|
5047
|
+
if (!ctx.state.props.hideItemsUntilMeasured) {
|
|
5048
|
+
return;
|
|
5049
|
+
}
|
|
5050
|
+
const isCurrentGeneration = ((_a3 = ctx.state.containerItemGenerations[containerId]) != null ? _a3 : 0) === generation;
|
|
5051
|
+
const isCurrentAssignment = peek$(ctx, `containerItemKey${containerId}`) === itemKey;
|
|
5052
|
+
if (isCurrentGeneration && isCurrentAssignment) {
|
|
5053
|
+
set$(ctx, `containerLayoutReady${containerId}`, true);
|
|
5054
|
+
}
|
|
5055
|
+
}
|
|
5039
5056
|
function measureContainersInLayoutEffect(ctx, targetContainerIds = null) {
|
|
5040
|
-
var _a3, _b
|
|
5057
|
+
var _a3, _b;
|
|
5041
5058
|
const state = ctx.state;
|
|
5042
5059
|
const measurements = [];
|
|
5060
|
+
const measuredGenerations = state.props.hideItemsUntilMeasured ? [] : void 0;
|
|
5043
5061
|
let isCollectingSynchronousMeasurements = true;
|
|
5044
5062
|
const containerIds = targetContainerIds != null ? targetContainerIds : ctx.viewRefs.keys();
|
|
5045
5063
|
for (const containerId of containerIds) {
|
|
5046
|
-
const
|
|
5064
|
+
const view = (_a3 = ctx.viewRefs.get(containerId)) == null ? void 0 : _a3.current;
|
|
5047
5065
|
const itemKey = peek$(ctx, `containerItemKey${containerId}`);
|
|
5048
5066
|
if (itemKey !== void 0) {
|
|
5049
|
-
const generation = ((
|
|
5067
|
+
const generation = ((_b = state.containerItemGenerations[containerId]) != null ? _b : 0) + 1;
|
|
5050
5068
|
state.containerItemGenerations[containerId] = generation;
|
|
5051
5069
|
const fixedItemSize = resolveFixedItemSize(ctx, containerId, itemKey);
|
|
5052
5070
|
const canSkipMeasurement = !state.needsOtherAxisSize && fixedItemSize !== void 0 && state.sizesKnown.get(itemKey) === fixedItemSize + ctx.scrollAxisGap;
|
|
5053
5071
|
if (canSkipMeasurement) {
|
|
5054
5072
|
resolveSkippedAnchorReset(ctx, itemKey);
|
|
5055
|
-
|
|
5056
|
-
|
|
5073
|
+
if (measuredGenerations) {
|
|
5074
|
+
revealMeasuredGeneration(ctx, containerId, itemKey, generation);
|
|
5075
|
+
}
|
|
5076
|
+
} else if (view == null ? void 0 : view.measure) {
|
|
5077
|
+
view.measure((_x, _y, width, height) => {
|
|
5057
5078
|
var _a4;
|
|
5058
5079
|
const isCurrentGeneration = ((_a4 = ctx.state.containerItemGenerations[containerId]) != null ? _a4 : 0) === generation;
|
|
5059
5080
|
if (isCurrentGeneration) {
|
|
@@ -5064,17 +5085,28 @@ function measureContainersInLayoutEffect(ctx, targetContainerIds = null) {
|
|
|
5064
5085
|
};
|
|
5065
5086
|
if (isCollectingSynchronousMeasurements) {
|
|
5066
5087
|
measurements.push(measurement);
|
|
5088
|
+
measuredGenerations == null ? void 0 : measuredGenerations.push({ containerId, generation, itemKey });
|
|
5067
5089
|
} else {
|
|
5068
5090
|
updateItemSizes(ctx, measurement);
|
|
5091
|
+
if (measuredGenerations) {
|
|
5092
|
+
revealMeasuredGeneration(ctx, containerId, itemKey, generation);
|
|
5093
|
+
}
|
|
5069
5094
|
}
|
|
5070
5095
|
}
|
|
5071
5096
|
});
|
|
5097
|
+
} else if (measuredGenerations) {
|
|
5098
|
+
revealMeasuredGeneration(ctx, containerId, itemKey, generation);
|
|
5072
5099
|
}
|
|
5073
5100
|
}
|
|
5074
5101
|
}
|
|
5075
5102
|
isCollectingSynchronousMeasurements = false;
|
|
5076
5103
|
if (measurements.length > 0) {
|
|
5077
5104
|
updateItemSizesBatch(ctx, measurements);
|
|
5105
|
+
if (measuredGenerations) {
|
|
5106
|
+
for (const { containerId, generation, itemKey } of measuredGenerations) {
|
|
5107
|
+
revealMeasuredGeneration(ctx, containerId, itemKey, generation);
|
|
5108
|
+
}
|
|
5109
|
+
}
|
|
5078
5110
|
}
|
|
5079
5111
|
}
|
|
5080
5112
|
var typedForwardRef = React2__namespace.forwardRef;
|
|
@@ -5162,8 +5194,20 @@ var PositionViewState = typedMemo(function PositionViewState2({
|
|
|
5162
5194
|
refView,
|
|
5163
5195
|
...rest
|
|
5164
5196
|
}) {
|
|
5165
|
-
const [position = POSITION_OUT_OF_VIEW, _itemKey] = useArr$([
|
|
5166
|
-
|
|
5197
|
+
const [position = POSITION_OUT_OF_VIEW, _itemKey, layoutReady = true] = useArr$([
|
|
5198
|
+
`containerPosition${id}`,
|
|
5199
|
+
`containerItemKey${id}`,
|
|
5200
|
+
`containerLayoutReady${id}`
|
|
5201
|
+
]);
|
|
5202
|
+
return /* @__PURE__ */ React2__namespace.createElement(
|
|
5203
|
+
ReactNative.View,
|
|
5204
|
+
{
|
|
5205
|
+
ref: refView,
|
|
5206
|
+
style: [style, horizontal ? { left: position } : { top: position }, !layoutReady && { opacity: 0 }],
|
|
5207
|
+
...rest,
|
|
5208
|
+
pointerEvents: layoutReady ? void 0 : "none"
|
|
5209
|
+
}
|
|
5210
|
+
);
|
|
5167
5211
|
});
|
|
5168
5212
|
var PositionViewAnimated = typedMemo(function PositionViewAnimated2({
|
|
5169
5213
|
id,
|
|
@@ -6291,6 +6335,16 @@ function checkStructuralDataChange(state, dataProp, previousData) {
|
|
|
6291
6335
|
return false;
|
|
6292
6336
|
}
|
|
6293
6337
|
|
|
6338
|
+
// src/core/containerLayoutReady.ts
|
|
6339
|
+
var CONTAINER_LAYOUT_READY_PREFIX = "containerLayoutReady";
|
|
6340
|
+
function resetContainerLayoutReady(ctx) {
|
|
6341
|
+
for (const signalName of ctx.values.keys()) {
|
|
6342
|
+
if (signalName.startsWith(CONTAINER_LAYOUT_READY_PREFIX)) {
|
|
6343
|
+
set$(ctx, signalName, void 0);
|
|
6344
|
+
}
|
|
6345
|
+
}
|
|
6346
|
+
}
|
|
6347
|
+
|
|
6294
6348
|
// src/core/doInitialAllocateContainers.ts
|
|
6295
6349
|
function doInitialAllocateContainers(ctx) {
|
|
6296
6350
|
var _a3, _b;
|
|
@@ -7197,6 +7251,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7197
7251
|
initialScrollIndex: initialScrollIndexProp,
|
|
7198
7252
|
initialScrollOffset: initialScrollOffsetProp,
|
|
7199
7253
|
experimental_adaptiveRender,
|
|
7254
|
+
experimental_hideItemsUntilMeasured,
|
|
7200
7255
|
itemsAreEqual,
|
|
7201
7256
|
keyExtractor: keyExtractorProp,
|
|
7202
7257
|
ListEmptyComponent,
|
|
@@ -7417,6 +7472,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7417
7472
|
const state = refState.current;
|
|
7418
7473
|
const isFirstLocal = state.isFirst;
|
|
7419
7474
|
const previousAdaptiveRender = state.props.adaptiveRender;
|
|
7475
|
+
const previousHideItemsUntilMeasured = state.props.hideItemsUntilMeasured;
|
|
7420
7476
|
const previousNumColumnsProp = state.props.numColumns;
|
|
7421
7477
|
const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
|
|
7422
7478
|
ctx.scrollAxisGap = nextScrollAxisGap;
|
|
@@ -7462,6 +7518,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7462
7518
|
estimatedItemSize,
|
|
7463
7519
|
getFixedItemSize: useWrapIfItem(getFixedItemSize),
|
|
7464
7520
|
getItemType: useWrapIfItem(getItemType),
|
|
7521
|
+
hideItemsUntilMeasured: experimental_hideItemsUntilMeasured,
|
|
7465
7522
|
horizontal: !!horizontal,
|
|
7466
7523
|
itemsAreEqual,
|
|
7467
7524
|
keyExtractor: useWrapIfItem(keyExtractor),
|
|
@@ -7499,6 +7556,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7499
7556
|
if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
|
|
7500
7557
|
resetAdaptiveRender(ctx);
|
|
7501
7558
|
}
|
|
7559
|
+
if (!isFirstLocal && previousHideItemsUntilMeasured && !experimental_hideItemsUntilMeasured) {
|
|
7560
|
+
resetContainerLayoutReady(ctx);
|
|
7561
|
+
}
|
|
7502
7562
|
const memoizedLastItemKeys = React2.useMemo(() => {
|
|
7503
7563
|
if (!dataProp.length) return [];
|
|
7504
7564
|
return Array.from(
|
package/react-native.mjs
CHANGED
|
@@ -4370,7 +4370,9 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4370
4370
|
const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
|
|
4371
4371
|
updateItemPositions(ctx, dataChanged, {
|
|
4372
4372
|
doMVCP,
|
|
4373
|
-
|
|
4373
|
+
// A changed size shifts every following position. The scrolling early-exit
|
|
4374
|
+
// would leave the untouched suffix in the old coordinate space.
|
|
4375
|
+
forceFullUpdate: !!forceFullItemPositions || minIndexSizeChanged !== void 0,
|
|
4374
4376
|
optimizeForVisibleWindow,
|
|
4375
4377
|
scrollBottomBuffered,
|
|
4376
4378
|
scrollVelocity: speed,
|
|
@@ -4575,15 +4577,19 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4575
4577
|
if (oldKey && oldKey !== id) {
|
|
4576
4578
|
containerItemKeys.delete(oldKey);
|
|
4577
4579
|
}
|
|
4580
|
+
state.containerItemMetadata.set(
|
|
4581
|
+
containerIndex,
|
|
4582
|
+
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4583
|
+
);
|
|
4578
4584
|
if (oldKey !== id) {
|
|
4579
4585
|
changedContainerIds != null ? changedContainerIds : changedContainerIds = /* @__PURE__ */ new Set();
|
|
4580
4586
|
changedContainerIds.add(containerIndex);
|
|
4581
4587
|
state.containerItemGenerations[containerIndex] = ((_p = state.containerItemGenerations[containerIndex]) != null ? _p : 0) + 1;
|
|
4588
|
+
if (state.props.hideItemsUntilMeasured) {
|
|
4589
|
+
const isLayoutReady = state.sizesKnown.has(id) || resolveContainerItemMetadata(state, containerIndex, i, data[i]).fixedItemSize !== void 0;
|
|
4590
|
+
set$(ctx, `containerLayoutReady${containerIndex}`, isLayoutReady);
|
|
4591
|
+
}
|
|
4582
4592
|
}
|
|
4583
|
-
state.containerItemMetadata.set(
|
|
4584
|
-
containerIndex,
|
|
4585
|
-
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4586
|
-
);
|
|
4587
4593
|
set$(ctx, `containerItemKey${containerIndex}`, id);
|
|
4588
4594
|
set$(ctx, `containerItemIndex${containerIndex}`, i);
|
|
4589
4595
|
set$(ctx, `containerItemData${containerIndex}`, data[i]);
|
|
@@ -5015,24 +5021,39 @@ function resolveSkippedAnchorReset(ctx, itemKey) {
|
|
|
5015
5021
|
state.userScrollAnchorReset = void 0;
|
|
5016
5022
|
}
|
|
5017
5023
|
}
|
|
5024
|
+
function revealMeasuredGeneration(ctx, containerId, itemKey, generation) {
|
|
5025
|
+
var _a3;
|
|
5026
|
+
if (!ctx.state.props.hideItemsUntilMeasured) {
|
|
5027
|
+
return;
|
|
5028
|
+
}
|
|
5029
|
+
const isCurrentGeneration = ((_a3 = ctx.state.containerItemGenerations[containerId]) != null ? _a3 : 0) === generation;
|
|
5030
|
+
const isCurrentAssignment = peek$(ctx, `containerItemKey${containerId}`) === itemKey;
|
|
5031
|
+
if (isCurrentGeneration && isCurrentAssignment) {
|
|
5032
|
+
set$(ctx, `containerLayoutReady${containerId}`, true);
|
|
5033
|
+
}
|
|
5034
|
+
}
|
|
5018
5035
|
function measureContainersInLayoutEffect(ctx, targetContainerIds = null) {
|
|
5019
|
-
var _a3, _b
|
|
5036
|
+
var _a3, _b;
|
|
5020
5037
|
const state = ctx.state;
|
|
5021
5038
|
const measurements = [];
|
|
5039
|
+
const measuredGenerations = state.props.hideItemsUntilMeasured ? [] : void 0;
|
|
5022
5040
|
let isCollectingSynchronousMeasurements = true;
|
|
5023
5041
|
const containerIds = targetContainerIds != null ? targetContainerIds : ctx.viewRefs.keys();
|
|
5024
5042
|
for (const containerId of containerIds) {
|
|
5025
|
-
const
|
|
5043
|
+
const view = (_a3 = ctx.viewRefs.get(containerId)) == null ? void 0 : _a3.current;
|
|
5026
5044
|
const itemKey = peek$(ctx, `containerItemKey${containerId}`);
|
|
5027
5045
|
if (itemKey !== void 0) {
|
|
5028
|
-
const generation = ((
|
|
5046
|
+
const generation = ((_b = state.containerItemGenerations[containerId]) != null ? _b : 0) + 1;
|
|
5029
5047
|
state.containerItemGenerations[containerId] = generation;
|
|
5030
5048
|
const fixedItemSize = resolveFixedItemSize(ctx, containerId, itemKey);
|
|
5031
5049
|
const canSkipMeasurement = !state.needsOtherAxisSize && fixedItemSize !== void 0 && state.sizesKnown.get(itemKey) === fixedItemSize + ctx.scrollAxisGap;
|
|
5032
5050
|
if (canSkipMeasurement) {
|
|
5033
5051
|
resolveSkippedAnchorReset(ctx, itemKey);
|
|
5034
|
-
|
|
5035
|
-
|
|
5052
|
+
if (measuredGenerations) {
|
|
5053
|
+
revealMeasuredGeneration(ctx, containerId, itemKey, generation);
|
|
5054
|
+
}
|
|
5055
|
+
} else if (view == null ? void 0 : view.measure) {
|
|
5056
|
+
view.measure((_x, _y, width, height) => {
|
|
5036
5057
|
var _a4;
|
|
5037
5058
|
const isCurrentGeneration = ((_a4 = ctx.state.containerItemGenerations[containerId]) != null ? _a4 : 0) === generation;
|
|
5038
5059
|
if (isCurrentGeneration) {
|
|
@@ -5043,17 +5064,28 @@ function measureContainersInLayoutEffect(ctx, targetContainerIds = null) {
|
|
|
5043
5064
|
};
|
|
5044
5065
|
if (isCollectingSynchronousMeasurements) {
|
|
5045
5066
|
measurements.push(measurement);
|
|
5067
|
+
measuredGenerations == null ? void 0 : measuredGenerations.push({ containerId, generation, itemKey });
|
|
5046
5068
|
} else {
|
|
5047
5069
|
updateItemSizes(ctx, measurement);
|
|
5070
|
+
if (measuredGenerations) {
|
|
5071
|
+
revealMeasuredGeneration(ctx, containerId, itemKey, generation);
|
|
5072
|
+
}
|
|
5048
5073
|
}
|
|
5049
5074
|
}
|
|
5050
5075
|
});
|
|
5076
|
+
} else if (measuredGenerations) {
|
|
5077
|
+
revealMeasuredGeneration(ctx, containerId, itemKey, generation);
|
|
5051
5078
|
}
|
|
5052
5079
|
}
|
|
5053
5080
|
}
|
|
5054
5081
|
isCollectingSynchronousMeasurements = false;
|
|
5055
5082
|
if (measurements.length > 0) {
|
|
5056
5083
|
updateItemSizesBatch(ctx, measurements);
|
|
5084
|
+
if (measuredGenerations) {
|
|
5085
|
+
for (const { containerId, generation, itemKey } of measuredGenerations) {
|
|
5086
|
+
revealMeasuredGeneration(ctx, containerId, itemKey, generation);
|
|
5087
|
+
}
|
|
5088
|
+
}
|
|
5057
5089
|
}
|
|
5058
5090
|
}
|
|
5059
5091
|
var typedForwardRef = React2.forwardRef;
|
|
@@ -5141,8 +5173,20 @@ var PositionViewState = typedMemo(function PositionViewState2({
|
|
|
5141
5173
|
refView,
|
|
5142
5174
|
...rest
|
|
5143
5175
|
}) {
|
|
5144
|
-
const [position = POSITION_OUT_OF_VIEW, _itemKey] = useArr$([
|
|
5145
|
-
|
|
5176
|
+
const [position = POSITION_OUT_OF_VIEW, _itemKey, layoutReady = true] = useArr$([
|
|
5177
|
+
`containerPosition${id}`,
|
|
5178
|
+
`containerItemKey${id}`,
|
|
5179
|
+
`containerLayoutReady${id}`
|
|
5180
|
+
]);
|
|
5181
|
+
return /* @__PURE__ */ React2.createElement(
|
|
5182
|
+
View$1,
|
|
5183
|
+
{
|
|
5184
|
+
ref: refView,
|
|
5185
|
+
style: [style, horizontal ? { left: position } : { top: position }, !layoutReady && { opacity: 0 }],
|
|
5186
|
+
...rest,
|
|
5187
|
+
pointerEvents: layoutReady ? void 0 : "none"
|
|
5188
|
+
}
|
|
5189
|
+
);
|
|
5146
5190
|
});
|
|
5147
5191
|
var PositionViewAnimated = typedMemo(function PositionViewAnimated2({
|
|
5148
5192
|
id,
|
|
@@ -6270,6 +6314,16 @@ function checkStructuralDataChange(state, dataProp, previousData) {
|
|
|
6270
6314
|
return false;
|
|
6271
6315
|
}
|
|
6272
6316
|
|
|
6317
|
+
// src/core/containerLayoutReady.ts
|
|
6318
|
+
var CONTAINER_LAYOUT_READY_PREFIX = "containerLayoutReady";
|
|
6319
|
+
function resetContainerLayoutReady(ctx) {
|
|
6320
|
+
for (const signalName of ctx.values.keys()) {
|
|
6321
|
+
if (signalName.startsWith(CONTAINER_LAYOUT_READY_PREFIX)) {
|
|
6322
|
+
set$(ctx, signalName, void 0);
|
|
6323
|
+
}
|
|
6324
|
+
}
|
|
6325
|
+
}
|
|
6326
|
+
|
|
6273
6327
|
// src/core/doInitialAllocateContainers.ts
|
|
6274
6328
|
function doInitialAllocateContainers(ctx) {
|
|
6275
6329
|
var _a3, _b;
|
|
@@ -7176,6 +7230,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7176
7230
|
initialScrollIndex: initialScrollIndexProp,
|
|
7177
7231
|
initialScrollOffset: initialScrollOffsetProp,
|
|
7178
7232
|
experimental_adaptiveRender,
|
|
7233
|
+
experimental_hideItemsUntilMeasured,
|
|
7179
7234
|
itemsAreEqual,
|
|
7180
7235
|
keyExtractor: keyExtractorProp,
|
|
7181
7236
|
ListEmptyComponent,
|
|
@@ -7396,6 +7451,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7396
7451
|
const state = refState.current;
|
|
7397
7452
|
const isFirstLocal = state.isFirst;
|
|
7398
7453
|
const previousAdaptiveRender = state.props.adaptiveRender;
|
|
7454
|
+
const previousHideItemsUntilMeasured = state.props.hideItemsUntilMeasured;
|
|
7399
7455
|
const previousNumColumnsProp = state.props.numColumns;
|
|
7400
7456
|
const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
|
|
7401
7457
|
ctx.scrollAxisGap = nextScrollAxisGap;
|
|
@@ -7441,6 +7497,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7441
7497
|
estimatedItemSize,
|
|
7442
7498
|
getFixedItemSize: useWrapIfItem(getFixedItemSize),
|
|
7443
7499
|
getItemType: useWrapIfItem(getItemType),
|
|
7500
|
+
hideItemsUntilMeasured: experimental_hideItemsUntilMeasured,
|
|
7444
7501
|
horizontal: !!horizontal,
|
|
7445
7502
|
itemsAreEqual,
|
|
7446
7503
|
keyExtractor: useWrapIfItem(keyExtractor),
|
|
@@ -7478,6 +7535,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7478
7535
|
if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
|
|
7479
7536
|
resetAdaptiveRender(ctx);
|
|
7480
7537
|
}
|
|
7538
|
+
if (!isFirstLocal && previousHideItemsUntilMeasured && !experimental_hideItemsUntilMeasured) {
|
|
7539
|
+
resetContainerLayoutReady(ctx);
|
|
7540
|
+
}
|
|
7481
7541
|
const memoizedLastItemKeys = useMemo(() => {
|
|
7482
7542
|
if (!dataProp.length) return [];
|
|
7483
7543
|
return Array.from(
|
package/react-native.web.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ interface MaintainVisibleContentPositionNormalized<ItemT = any> {
|
|
|
31
31
|
shouldRestorePosition?: (item: ItemT, index: number, data: readonly ItemT[]) => boolean;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
type ListenerType = "activeStickyIndex" | "alignItemsAtEndPadding" | "anchoredEndSpaceSize" | "containerLayoutEpoch" | "debugComputedScroll" | "debugRawScroll" | "extraData" | "footerSize" | "headerSize" | "lastItemKeys" | "lastPositionUpdate" | "maintainVisibleContentPosition" | "numColumns" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "scrollAdjust" | "scrollAdjustPending" | "scrollAdjustUserOffset" | "scrollSize" | "snapToOffsets" | "stylePaddingTop" | "totalSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | `containerColumn${number}` | `containerSpan${number}` | `containerItemData${number}` | `containerItemIndex${number}` | `containerItemKey${number}` | `containerPosition${number}` | `containerSticky${number}`;
|
|
34
|
+
type ListenerType = "activeStickyIndex" | "alignItemsAtEndPadding" | "anchoredEndSpaceSize" | "containerLayoutEpoch" | "debugComputedScroll" | "debugRawScroll" | "extraData" | "footerSize" | "headerSize" | "lastItemKeys" | "lastPositionUpdate" | "maintainVisibleContentPosition" | "numColumns" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "scrollAdjust" | "scrollAdjustPending" | "scrollAdjustUserOffset" | "scrollSize" | "snapToOffsets" | "stylePaddingTop" | "totalSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | `containerColumn${number}` | `containerSpan${number}` | `containerItemData${number}` | `containerItemIndex${number}` | `containerItemKey${number}` | `containerLayoutReady${number}` | `containerPosition${number}` | `containerSticky${number}`;
|
|
35
35
|
type LegendListListenerType = Extract<ListenerType, "activeStickyIndex" | "anchoredEndSpaceSize" | "footerSize" | "headerSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | "lastItemKeys" | "lastPositionUpdate" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "snapToOffsets" | "totalSize">;
|
|
36
36
|
type ListenerTypeValueMap = {
|
|
37
37
|
activeStickyIndex: number;
|
|
@@ -70,6 +70,8 @@ type ListenerTypeValueMap = {
|
|
|
70
70
|
adaptiveRender: "normal" | "light";
|
|
71
71
|
} & {
|
|
72
72
|
[K in ListenerType as K extends `containerItemKey${number}` ? K : never]: string;
|
|
73
|
+
} & {
|
|
74
|
+
[K in ListenerType as K extends `containerLayoutReady${number}` ? K : never]: boolean;
|
|
73
75
|
} & {
|
|
74
76
|
[K in ListenerType as K extends `containerItemData${number}` ? K : never]: any;
|
|
75
77
|
} & {
|
|
@@ -371,6 +373,20 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
|
|
|
371
373
|
* Configures the adaptive render signal. Items can use this to render a lighter version while scrolling quickly.
|
|
372
374
|
*/
|
|
373
375
|
experimental_adaptiveRender?: AdaptiveRenderConfig;
|
|
376
|
+
/**
|
|
377
|
+
* Keeps a newly recycled item laid out but invisible until its size has been measured, so it is never painted at
|
|
378
|
+
* the estimated position it was recycled to. Only applies on the new architecture.
|
|
379
|
+
*
|
|
380
|
+
* This trades a possible flash at the wrong position for an extra render and native commit per recycled row, so it
|
|
381
|
+
* is worth enabling only for lists with dynamically sized items whose estimates are visibly wrong. Items with a
|
|
382
|
+
* size from `getFixedItemSize`, or with an already measured size, are exact and render immediately either way.
|
|
383
|
+
*
|
|
384
|
+
* Sticky headers are intentionally excluded. They are painted from a scroll-driven interpolation rather than the
|
|
385
|
+
* committed position, so hiding them would blink a header out mid-scroll without preventing a flash.
|
|
386
|
+
*
|
|
387
|
+
* @default false
|
|
388
|
+
*/
|
|
389
|
+
experimental_hideItemsUntilMeasured?: boolean;
|
|
374
390
|
/**
|
|
375
391
|
* Function to call when the user pulls to refresh.
|
|
376
392
|
*/
|
package/react-native.web.js
CHANGED
|
@@ -4420,7 +4420,9 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4420
4420
|
const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
|
|
4421
4421
|
updateItemPositions(ctx, dataChanged, {
|
|
4422
4422
|
doMVCP,
|
|
4423
|
-
|
|
4423
|
+
// A changed size shifts every following position. The scrolling early-exit
|
|
4424
|
+
// would leave the untouched suffix in the old coordinate space.
|
|
4425
|
+
forceFullUpdate: !!forceFullItemPositions || minIndexSizeChanged !== void 0,
|
|
4424
4426
|
optimizeForVisibleWindow,
|
|
4425
4427
|
scrollBottomBuffered,
|
|
4426
4428
|
scrollVelocity: speed,
|
|
@@ -4625,15 +4627,19 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4625
4627
|
if (oldKey && oldKey !== id) {
|
|
4626
4628
|
containerItemKeys.delete(oldKey);
|
|
4627
4629
|
}
|
|
4630
|
+
state.containerItemMetadata.set(
|
|
4631
|
+
containerIndex,
|
|
4632
|
+
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4633
|
+
);
|
|
4628
4634
|
if (oldKey !== id) {
|
|
4629
4635
|
changedContainerIds != null ? changedContainerIds : changedContainerIds = /* @__PURE__ */ new Set();
|
|
4630
4636
|
changedContainerIds.add(containerIndex);
|
|
4631
4637
|
state.containerItemGenerations[containerIndex] = ((_p = state.containerItemGenerations[containerIndex]) != null ? _p : 0) + 1;
|
|
4638
|
+
if (state.props.hideItemsUntilMeasured) {
|
|
4639
|
+
const isLayoutReady = state.sizesKnown.has(id) || resolveContainerItemMetadata(state, containerIndex, i, data[i]).fixedItemSize !== void 0;
|
|
4640
|
+
set$(ctx, `containerLayoutReady${containerIndex}`, isLayoutReady);
|
|
4641
|
+
}
|
|
4632
4642
|
}
|
|
4633
|
-
state.containerItemMetadata.set(
|
|
4634
|
-
containerIndex,
|
|
4635
|
-
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4636
|
-
);
|
|
4637
4643
|
set$(ctx, `containerItemKey${containerIndex}`, id);
|
|
4638
4644
|
set$(ctx, `containerItemIndex${containerIndex}`, i);
|
|
4639
4645
|
set$(ctx, `containerItemData${containerIndex}`, data[i]);
|
|
@@ -6950,6 +6956,16 @@ function checkStructuralDataChange(state, dataProp, previousData) {
|
|
|
6950
6956
|
return false;
|
|
6951
6957
|
}
|
|
6952
6958
|
|
|
6959
|
+
// src/core/containerLayoutReady.ts
|
|
6960
|
+
var CONTAINER_LAYOUT_READY_PREFIX = "containerLayoutReady";
|
|
6961
|
+
function resetContainerLayoutReady(ctx) {
|
|
6962
|
+
for (const signalName of ctx.values.keys()) {
|
|
6963
|
+
if (signalName.startsWith(CONTAINER_LAYOUT_READY_PREFIX)) {
|
|
6964
|
+
set$(ctx, signalName, void 0);
|
|
6965
|
+
}
|
|
6966
|
+
}
|
|
6967
|
+
}
|
|
6968
|
+
|
|
6953
6969
|
// src/core/doInitialAllocateContainers.ts
|
|
6954
6970
|
function doInitialAllocateContainers(ctx) {
|
|
6955
6971
|
var _a3, _b;
|
|
@@ -7840,6 +7856,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7840
7856
|
initialScrollIndex: initialScrollIndexProp,
|
|
7841
7857
|
initialScrollOffset: initialScrollOffsetProp,
|
|
7842
7858
|
experimental_adaptiveRender,
|
|
7859
|
+
experimental_hideItemsUntilMeasured,
|
|
7843
7860
|
itemsAreEqual,
|
|
7844
7861
|
keyExtractor: keyExtractorProp,
|
|
7845
7862
|
ListEmptyComponent,
|
|
@@ -8060,6 +8077,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8060
8077
|
const state = refState.current;
|
|
8061
8078
|
const isFirstLocal = state.isFirst;
|
|
8062
8079
|
const previousAdaptiveRender = state.props.adaptiveRender;
|
|
8080
|
+
const previousHideItemsUntilMeasured = state.props.hideItemsUntilMeasured;
|
|
8063
8081
|
const previousNumColumnsProp = state.props.numColumns;
|
|
8064
8082
|
const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
|
|
8065
8083
|
ctx.scrollAxisGap = nextScrollAxisGap;
|
|
@@ -8105,6 +8123,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8105
8123
|
estimatedItemSize,
|
|
8106
8124
|
getFixedItemSize: useWrapIfItem(getFixedItemSize),
|
|
8107
8125
|
getItemType: useWrapIfItem(getItemType),
|
|
8126
|
+
hideItemsUntilMeasured: experimental_hideItemsUntilMeasured,
|
|
8108
8127
|
horizontal: !!horizontal,
|
|
8109
8128
|
itemsAreEqual,
|
|
8110
8129
|
keyExtractor: useWrapIfItem(keyExtractor),
|
|
@@ -8142,6 +8161,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8142
8161
|
if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
|
|
8143
8162
|
resetAdaptiveRender(ctx);
|
|
8144
8163
|
}
|
|
8164
|
+
if (!isFirstLocal && previousHideItemsUntilMeasured && !experimental_hideItemsUntilMeasured) {
|
|
8165
|
+
resetContainerLayoutReady(ctx);
|
|
8166
|
+
}
|
|
8145
8167
|
const memoizedLastItemKeys = React3.useMemo(() => {
|
|
8146
8168
|
if (!dataProp.length) return [];
|
|
8147
8169
|
return Array.from(
|
package/react-native.web.mjs
CHANGED
|
@@ -4399,7 +4399,9 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4399
4399
|
const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
|
|
4400
4400
|
updateItemPositions(ctx, dataChanged, {
|
|
4401
4401
|
doMVCP,
|
|
4402
|
-
|
|
4402
|
+
// A changed size shifts every following position. The scrolling early-exit
|
|
4403
|
+
// would leave the untouched suffix in the old coordinate space.
|
|
4404
|
+
forceFullUpdate: !!forceFullItemPositions || minIndexSizeChanged !== void 0,
|
|
4403
4405
|
optimizeForVisibleWindow,
|
|
4404
4406
|
scrollBottomBuffered,
|
|
4405
4407
|
scrollVelocity: speed,
|
|
@@ -4604,15 +4606,19 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4604
4606
|
if (oldKey && oldKey !== id) {
|
|
4605
4607
|
containerItemKeys.delete(oldKey);
|
|
4606
4608
|
}
|
|
4609
|
+
state.containerItemMetadata.set(
|
|
4610
|
+
containerIndex,
|
|
4611
|
+
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4612
|
+
);
|
|
4607
4613
|
if (oldKey !== id) {
|
|
4608
4614
|
changedContainerIds != null ? changedContainerIds : changedContainerIds = /* @__PURE__ */ new Set();
|
|
4609
4615
|
changedContainerIds.add(containerIndex);
|
|
4610
4616
|
state.containerItemGenerations[containerIndex] = ((_p = state.containerItemGenerations[containerIndex]) != null ? _p : 0) + 1;
|
|
4617
|
+
if (state.props.hideItemsUntilMeasured) {
|
|
4618
|
+
const isLayoutReady = state.sizesKnown.has(id) || resolveContainerItemMetadata(state, containerIndex, i, data[i]).fixedItemSize !== void 0;
|
|
4619
|
+
set$(ctx, `containerLayoutReady${containerIndex}`, isLayoutReady);
|
|
4620
|
+
}
|
|
4611
4621
|
}
|
|
4612
|
-
state.containerItemMetadata.set(
|
|
4613
|
-
containerIndex,
|
|
4614
|
-
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4615
|
-
);
|
|
4616
4622
|
set$(ctx, `containerItemKey${containerIndex}`, id);
|
|
4617
4623
|
set$(ctx, `containerItemIndex${containerIndex}`, i);
|
|
4618
4624
|
set$(ctx, `containerItemData${containerIndex}`, data[i]);
|
|
@@ -6929,6 +6935,16 @@ function checkStructuralDataChange(state, dataProp, previousData) {
|
|
|
6929
6935
|
return false;
|
|
6930
6936
|
}
|
|
6931
6937
|
|
|
6938
|
+
// src/core/containerLayoutReady.ts
|
|
6939
|
+
var CONTAINER_LAYOUT_READY_PREFIX = "containerLayoutReady";
|
|
6940
|
+
function resetContainerLayoutReady(ctx) {
|
|
6941
|
+
for (const signalName of ctx.values.keys()) {
|
|
6942
|
+
if (signalName.startsWith(CONTAINER_LAYOUT_READY_PREFIX)) {
|
|
6943
|
+
set$(ctx, signalName, void 0);
|
|
6944
|
+
}
|
|
6945
|
+
}
|
|
6946
|
+
}
|
|
6947
|
+
|
|
6932
6948
|
// src/core/doInitialAllocateContainers.ts
|
|
6933
6949
|
function doInitialAllocateContainers(ctx) {
|
|
6934
6950
|
var _a3, _b;
|
|
@@ -7819,6 +7835,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7819
7835
|
initialScrollIndex: initialScrollIndexProp,
|
|
7820
7836
|
initialScrollOffset: initialScrollOffsetProp,
|
|
7821
7837
|
experimental_adaptiveRender,
|
|
7838
|
+
experimental_hideItemsUntilMeasured,
|
|
7822
7839
|
itemsAreEqual,
|
|
7823
7840
|
keyExtractor: keyExtractorProp,
|
|
7824
7841
|
ListEmptyComponent,
|
|
@@ -8039,6 +8056,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8039
8056
|
const state = refState.current;
|
|
8040
8057
|
const isFirstLocal = state.isFirst;
|
|
8041
8058
|
const previousAdaptiveRender = state.props.adaptiveRender;
|
|
8059
|
+
const previousHideItemsUntilMeasured = state.props.hideItemsUntilMeasured;
|
|
8042
8060
|
const previousNumColumnsProp = state.props.numColumns;
|
|
8043
8061
|
const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
|
|
8044
8062
|
ctx.scrollAxisGap = nextScrollAxisGap;
|
|
@@ -8084,6 +8102,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8084
8102
|
estimatedItemSize,
|
|
8085
8103
|
getFixedItemSize: useWrapIfItem(getFixedItemSize),
|
|
8086
8104
|
getItemType: useWrapIfItem(getItemType),
|
|
8105
|
+
hideItemsUntilMeasured: experimental_hideItemsUntilMeasured,
|
|
8087
8106
|
horizontal: !!horizontal,
|
|
8088
8107
|
itemsAreEqual,
|
|
8089
8108
|
keyExtractor: useWrapIfItem(keyExtractor),
|
|
@@ -8121,6 +8140,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8121
8140
|
if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
|
|
8122
8141
|
resetAdaptiveRender(ctx);
|
|
8123
8142
|
}
|
|
8143
|
+
if (!isFirstLocal && previousHideItemsUntilMeasured && !experimental_hideItemsUntilMeasured) {
|
|
8144
|
+
resetContainerLayoutReady(ctx);
|
|
8145
|
+
}
|
|
8124
8146
|
const memoizedLastItemKeys = useMemo(() => {
|
|
8125
8147
|
if (!dataProp.length) return [];
|
|
8126
8148
|
return Array.from(
|
package/react.d.ts
CHANGED
|
@@ -31,7 +31,7 @@ interface MaintainVisibleContentPositionNormalized<ItemT = any> {
|
|
|
31
31
|
shouldRestorePosition?: (item: ItemT, index: number, data: readonly ItemT[]) => boolean;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
type ListenerType = "activeStickyIndex" | "alignItemsAtEndPadding" | "anchoredEndSpaceSize" | "containerLayoutEpoch" | "debugComputedScroll" | "debugRawScroll" | "extraData" | "footerSize" | "headerSize" | "lastItemKeys" | "lastPositionUpdate" | "maintainVisibleContentPosition" | "numColumns" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "scrollAdjust" | "scrollAdjustPending" | "scrollAdjustUserOffset" | "scrollSize" | "snapToOffsets" | "stylePaddingTop" | "totalSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | `containerColumn${number}` | `containerSpan${number}` | `containerItemData${number}` | `containerItemIndex${number}` | `containerItemKey${number}` | `containerPosition${number}` | `containerSticky${number}`;
|
|
34
|
+
type ListenerType = "activeStickyIndex" | "alignItemsAtEndPadding" | "anchoredEndSpaceSize" | "containerLayoutEpoch" | "debugComputedScroll" | "debugRawScroll" | "extraData" | "footerSize" | "headerSize" | "lastItemKeys" | "lastPositionUpdate" | "maintainVisibleContentPosition" | "numColumns" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "scrollAdjust" | "scrollAdjustPending" | "scrollAdjustUserOffset" | "scrollSize" | "snapToOffsets" | "stylePaddingTop" | "totalSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | `containerColumn${number}` | `containerSpan${number}` | `containerItemData${number}` | `containerItemIndex${number}` | `containerItemKey${number}` | `containerLayoutReady${number}` | `containerPosition${number}` | `containerSticky${number}`;
|
|
35
35
|
type LegendListListenerType = Extract<ListenerType, "activeStickyIndex" | "anchoredEndSpaceSize" | "footerSize" | "headerSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | "lastItemKeys" | "lastPositionUpdate" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "snapToOffsets" | "totalSize">;
|
|
36
36
|
type ListenerTypeValueMap = {
|
|
37
37
|
activeStickyIndex: number;
|
|
@@ -70,6 +70,8 @@ type ListenerTypeValueMap = {
|
|
|
70
70
|
adaptiveRender: "normal" | "light";
|
|
71
71
|
} & {
|
|
72
72
|
[K in ListenerType as K extends `containerItemKey${number}` ? K : never]: string;
|
|
73
|
+
} & {
|
|
74
|
+
[K in ListenerType as K extends `containerLayoutReady${number}` ? K : never]: boolean;
|
|
73
75
|
} & {
|
|
74
76
|
[K in ListenerType as K extends `containerItemData${number}` ? K : never]: any;
|
|
75
77
|
} & {
|
|
@@ -371,6 +373,20 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
|
|
|
371
373
|
* Configures the adaptive render signal. Items can use this to render a lighter version while scrolling quickly.
|
|
372
374
|
*/
|
|
373
375
|
experimental_adaptiveRender?: AdaptiveRenderConfig;
|
|
376
|
+
/**
|
|
377
|
+
* Keeps a newly recycled item laid out but invisible until its size has been measured, so it is never painted at
|
|
378
|
+
* the estimated position it was recycled to. Only applies on the new architecture.
|
|
379
|
+
*
|
|
380
|
+
* This trades a possible flash at the wrong position for an extra render and native commit per recycled row, so it
|
|
381
|
+
* is worth enabling only for lists with dynamically sized items whose estimates are visibly wrong. Items with a
|
|
382
|
+
* size from `getFixedItemSize`, or with an already measured size, are exact and render immediately either way.
|
|
383
|
+
*
|
|
384
|
+
* Sticky headers are intentionally excluded. They are painted from a scroll-driven interpolation rather than the
|
|
385
|
+
* committed position, so hiding them would blink a header out mid-scroll without preventing a flash.
|
|
386
|
+
*
|
|
387
|
+
* @default false
|
|
388
|
+
*/
|
|
389
|
+
experimental_hideItemsUntilMeasured?: boolean;
|
|
374
390
|
/**
|
|
375
391
|
* Function to call when the user pulls to refresh.
|
|
376
392
|
*/
|
package/react.js
CHANGED
|
@@ -4420,7 +4420,9 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4420
4420
|
const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
|
|
4421
4421
|
updateItemPositions(ctx, dataChanged, {
|
|
4422
4422
|
doMVCP,
|
|
4423
|
-
|
|
4423
|
+
// A changed size shifts every following position. The scrolling early-exit
|
|
4424
|
+
// would leave the untouched suffix in the old coordinate space.
|
|
4425
|
+
forceFullUpdate: !!forceFullItemPositions || minIndexSizeChanged !== void 0,
|
|
4424
4426
|
optimizeForVisibleWindow,
|
|
4425
4427
|
scrollBottomBuffered,
|
|
4426
4428
|
scrollVelocity: speed,
|
|
@@ -4625,15 +4627,19 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4625
4627
|
if (oldKey && oldKey !== id) {
|
|
4626
4628
|
containerItemKeys.delete(oldKey);
|
|
4627
4629
|
}
|
|
4630
|
+
state.containerItemMetadata.set(
|
|
4631
|
+
containerIndex,
|
|
4632
|
+
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4633
|
+
);
|
|
4628
4634
|
if (oldKey !== id) {
|
|
4629
4635
|
changedContainerIds != null ? changedContainerIds : changedContainerIds = /* @__PURE__ */ new Set();
|
|
4630
4636
|
changedContainerIds.add(containerIndex);
|
|
4631
4637
|
state.containerItemGenerations[containerIndex] = ((_p = state.containerItemGenerations[containerIndex]) != null ? _p : 0) + 1;
|
|
4638
|
+
if (state.props.hideItemsUntilMeasured) {
|
|
4639
|
+
const isLayoutReady = state.sizesKnown.has(id) || resolveContainerItemMetadata(state, containerIndex, i, data[i]).fixedItemSize !== void 0;
|
|
4640
|
+
set$(ctx, `containerLayoutReady${containerIndex}`, isLayoutReady);
|
|
4641
|
+
}
|
|
4632
4642
|
}
|
|
4633
|
-
state.containerItemMetadata.set(
|
|
4634
|
-
containerIndex,
|
|
4635
|
-
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4636
|
-
);
|
|
4637
4643
|
set$(ctx, `containerItemKey${containerIndex}`, id);
|
|
4638
4644
|
set$(ctx, `containerItemIndex${containerIndex}`, i);
|
|
4639
4645
|
set$(ctx, `containerItemData${containerIndex}`, data[i]);
|
|
@@ -6950,6 +6956,16 @@ function checkStructuralDataChange(state, dataProp, previousData) {
|
|
|
6950
6956
|
return false;
|
|
6951
6957
|
}
|
|
6952
6958
|
|
|
6959
|
+
// src/core/containerLayoutReady.ts
|
|
6960
|
+
var CONTAINER_LAYOUT_READY_PREFIX = "containerLayoutReady";
|
|
6961
|
+
function resetContainerLayoutReady(ctx) {
|
|
6962
|
+
for (const signalName of ctx.values.keys()) {
|
|
6963
|
+
if (signalName.startsWith(CONTAINER_LAYOUT_READY_PREFIX)) {
|
|
6964
|
+
set$(ctx, signalName, void 0);
|
|
6965
|
+
}
|
|
6966
|
+
}
|
|
6967
|
+
}
|
|
6968
|
+
|
|
6953
6969
|
// src/core/doInitialAllocateContainers.ts
|
|
6954
6970
|
function doInitialAllocateContainers(ctx) {
|
|
6955
6971
|
var _a3, _b;
|
|
@@ -7840,6 +7856,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7840
7856
|
initialScrollIndex: initialScrollIndexProp,
|
|
7841
7857
|
initialScrollOffset: initialScrollOffsetProp,
|
|
7842
7858
|
experimental_adaptiveRender,
|
|
7859
|
+
experimental_hideItemsUntilMeasured,
|
|
7843
7860
|
itemsAreEqual,
|
|
7844
7861
|
keyExtractor: keyExtractorProp,
|
|
7845
7862
|
ListEmptyComponent,
|
|
@@ -8060,6 +8077,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8060
8077
|
const state = refState.current;
|
|
8061
8078
|
const isFirstLocal = state.isFirst;
|
|
8062
8079
|
const previousAdaptiveRender = state.props.adaptiveRender;
|
|
8080
|
+
const previousHideItemsUntilMeasured = state.props.hideItemsUntilMeasured;
|
|
8063
8081
|
const previousNumColumnsProp = state.props.numColumns;
|
|
8064
8082
|
const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
|
|
8065
8083
|
ctx.scrollAxisGap = nextScrollAxisGap;
|
|
@@ -8105,6 +8123,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8105
8123
|
estimatedItemSize,
|
|
8106
8124
|
getFixedItemSize: useWrapIfItem(getFixedItemSize),
|
|
8107
8125
|
getItemType: useWrapIfItem(getItemType),
|
|
8126
|
+
hideItemsUntilMeasured: experimental_hideItemsUntilMeasured,
|
|
8108
8127
|
horizontal: !!horizontal,
|
|
8109
8128
|
itemsAreEqual,
|
|
8110
8129
|
keyExtractor: useWrapIfItem(keyExtractor),
|
|
@@ -8142,6 +8161,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8142
8161
|
if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
|
|
8143
8162
|
resetAdaptiveRender(ctx);
|
|
8144
8163
|
}
|
|
8164
|
+
if (!isFirstLocal && previousHideItemsUntilMeasured && !experimental_hideItemsUntilMeasured) {
|
|
8165
|
+
resetContainerLayoutReady(ctx);
|
|
8166
|
+
}
|
|
8145
8167
|
const memoizedLastItemKeys = React3.useMemo(() => {
|
|
8146
8168
|
if (!dataProp.length) return [];
|
|
8147
8169
|
return Array.from(
|
package/react.mjs
CHANGED
|
@@ -4399,7 +4399,9 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4399
4399
|
const optimizeForVisibleWindow = !forceFullItemPositions && !dataChanged && numColumns > 1 && minIndexSizeChanged !== void 0;
|
|
4400
4400
|
updateItemPositions(ctx, dataChanged, {
|
|
4401
4401
|
doMVCP,
|
|
4402
|
-
|
|
4402
|
+
// A changed size shifts every following position. The scrolling early-exit
|
|
4403
|
+
// would leave the untouched suffix in the old coordinate space.
|
|
4404
|
+
forceFullUpdate: !!forceFullItemPositions || minIndexSizeChanged !== void 0,
|
|
4403
4405
|
optimizeForVisibleWindow,
|
|
4404
4406
|
scrollBottomBuffered,
|
|
4405
4407
|
scrollVelocity: speed,
|
|
@@ -4604,15 +4606,19 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4604
4606
|
if (oldKey && oldKey !== id) {
|
|
4605
4607
|
containerItemKeys.delete(oldKey);
|
|
4606
4608
|
}
|
|
4609
|
+
state.containerItemMetadata.set(
|
|
4610
|
+
containerIndex,
|
|
4611
|
+
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4612
|
+
);
|
|
4607
4613
|
if (oldKey !== id) {
|
|
4608
4614
|
changedContainerIds != null ? changedContainerIds : changedContainerIds = /* @__PURE__ */ new Set();
|
|
4609
4615
|
changedContainerIds.add(containerIndex);
|
|
4610
4616
|
state.containerItemGenerations[containerIndex] = ((_p = state.containerItemGenerations[containerIndex]) != null ? _p : 0) + 1;
|
|
4617
|
+
if (state.props.hideItemsUntilMeasured) {
|
|
4618
|
+
const isLayoutReady = state.sizesKnown.has(id) || resolveContainerItemMetadata(state, containerIndex, i, data[i]).fixedItemSize !== void 0;
|
|
4619
|
+
set$(ctx, `containerLayoutReady${containerIndex}`, isLayoutReady);
|
|
4620
|
+
}
|
|
4611
4621
|
}
|
|
4612
|
-
state.containerItemMetadata.set(
|
|
4613
|
-
containerIndex,
|
|
4614
|
-
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4615
|
-
);
|
|
4616
4622
|
set$(ctx, `containerItemKey${containerIndex}`, id);
|
|
4617
4623
|
set$(ctx, `containerItemIndex${containerIndex}`, i);
|
|
4618
4624
|
set$(ctx, `containerItemData${containerIndex}`, data[i]);
|
|
@@ -6929,6 +6935,16 @@ function checkStructuralDataChange(state, dataProp, previousData) {
|
|
|
6929
6935
|
return false;
|
|
6930
6936
|
}
|
|
6931
6937
|
|
|
6938
|
+
// src/core/containerLayoutReady.ts
|
|
6939
|
+
var CONTAINER_LAYOUT_READY_PREFIX = "containerLayoutReady";
|
|
6940
|
+
function resetContainerLayoutReady(ctx) {
|
|
6941
|
+
for (const signalName of ctx.values.keys()) {
|
|
6942
|
+
if (signalName.startsWith(CONTAINER_LAYOUT_READY_PREFIX)) {
|
|
6943
|
+
set$(ctx, signalName, void 0);
|
|
6944
|
+
}
|
|
6945
|
+
}
|
|
6946
|
+
}
|
|
6947
|
+
|
|
6932
6948
|
// src/core/doInitialAllocateContainers.ts
|
|
6933
6949
|
function doInitialAllocateContainers(ctx) {
|
|
6934
6950
|
var _a3, _b;
|
|
@@ -7819,6 +7835,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7819
7835
|
initialScrollIndex: initialScrollIndexProp,
|
|
7820
7836
|
initialScrollOffset: initialScrollOffsetProp,
|
|
7821
7837
|
experimental_adaptiveRender,
|
|
7838
|
+
experimental_hideItemsUntilMeasured,
|
|
7822
7839
|
itemsAreEqual,
|
|
7823
7840
|
keyExtractor: keyExtractorProp,
|
|
7824
7841
|
ListEmptyComponent,
|
|
@@ -8039,6 +8056,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8039
8056
|
const state = refState.current;
|
|
8040
8057
|
const isFirstLocal = state.isFirst;
|
|
8041
8058
|
const previousAdaptiveRender = state.props.adaptiveRender;
|
|
8059
|
+
const previousHideItemsUntilMeasured = state.props.hideItemsUntilMeasured;
|
|
8042
8060
|
const previousNumColumnsProp = state.props.numColumns;
|
|
8043
8061
|
const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
|
|
8044
8062
|
ctx.scrollAxisGap = nextScrollAxisGap;
|
|
@@ -8084,6 +8102,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8084
8102
|
estimatedItemSize,
|
|
8085
8103
|
getFixedItemSize: useWrapIfItem(getFixedItemSize),
|
|
8086
8104
|
getItemType: useWrapIfItem(getItemType),
|
|
8105
|
+
hideItemsUntilMeasured: experimental_hideItemsUntilMeasured,
|
|
8087
8106
|
horizontal: !!horizontal,
|
|
8088
8107
|
itemsAreEqual,
|
|
8089
8108
|
keyExtractor: useWrapIfItem(keyExtractor),
|
|
@@ -8121,6 +8140,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8121
8140
|
if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
|
|
8122
8141
|
resetAdaptiveRender(ctx);
|
|
8123
8142
|
}
|
|
8143
|
+
if (!isFirstLocal && previousHideItemsUntilMeasured && !experimental_hideItemsUntilMeasured) {
|
|
8144
|
+
resetContainerLayoutReady(ctx);
|
|
8145
|
+
}
|
|
8124
8146
|
const memoizedLastItemKeys = useMemo(() => {
|
|
8125
8147
|
if (!dataProp.length) return [];
|
|
8126
8148
|
return Array.from(
|
package/reanimated.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ interface MaintainVisibleContentPositionNormalized<ItemT = any> {
|
|
|
9
9
|
shouldRestorePosition?: (item: ItemT, index: number, data: readonly ItemT[]) => boolean;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
type ListenerType = "activeStickyIndex" | "alignItemsAtEndPadding" | "anchoredEndSpaceSize" | "containerLayoutEpoch" | "debugComputedScroll" | "debugRawScroll" | "extraData" | "footerSize" | "headerSize" | "lastItemKeys" | "lastPositionUpdate" | "maintainVisibleContentPosition" | "numColumns" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "scrollAdjust" | "scrollAdjustPending" | "scrollAdjustUserOffset" | "scrollSize" | "snapToOffsets" | "stylePaddingTop" | "totalSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | `containerColumn${number}` | `containerSpan${number}` | `containerItemData${number}` | `containerItemIndex${number}` | `containerItemKey${number}` | `containerPosition${number}` | `containerSticky${number}`;
|
|
12
|
+
type ListenerType = "activeStickyIndex" | "alignItemsAtEndPadding" | "anchoredEndSpaceSize" | "containerLayoutEpoch" | "debugComputedScroll" | "debugRawScroll" | "extraData" | "footerSize" | "headerSize" | "lastItemKeys" | "lastPositionUpdate" | "maintainVisibleContentPosition" | "numColumns" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "scrollAdjust" | "scrollAdjustPending" | "scrollAdjustUserOffset" | "scrollSize" | "snapToOffsets" | "stylePaddingTop" | "totalSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | `containerColumn${number}` | `containerSpan${number}` | `containerItemData${number}` | `containerItemIndex${number}` | `containerItemKey${number}` | `containerLayoutReady${number}` | `containerPosition${number}` | `containerSticky${number}`;
|
|
13
13
|
type LegendListListenerType = Extract<ListenerType, "activeStickyIndex" | "anchoredEndSpaceSize" | "footerSize" | "headerSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | "lastItemKeys" | "lastPositionUpdate" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "snapToOffsets" | "totalSize">;
|
|
14
14
|
type ListenerTypeValueMap = {
|
|
15
15
|
activeStickyIndex: number;
|
|
@@ -48,6 +48,8 @@ type ListenerTypeValueMap = {
|
|
|
48
48
|
adaptiveRender: "normal" | "light";
|
|
49
49
|
} & {
|
|
50
50
|
[K in ListenerType as K extends `containerItemKey${number}` ? K : never]: string;
|
|
51
|
+
} & {
|
|
52
|
+
[K in ListenerType as K extends `containerLayoutReady${number}` ? K : never]: boolean;
|
|
51
53
|
} & {
|
|
52
54
|
[K in ListenerType as K extends `containerItemData${number}` ? K : never]: any;
|
|
53
55
|
} & {
|
|
@@ -349,6 +351,20 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
|
|
|
349
351
|
* Configures the adaptive render signal. Items can use this to render a lighter version while scrolling quickly.
|
|
350
352
|
*/
|
|
351
353
|
experimental_adaptiveRender?: AdaptiveRenderConfig;
|
|
354
|
+
/**
|
|
355
|
+
* Keeps a newly recycled item laid out but invisible until its size has been measured, so it is never painted at
|
|
356
|
+
* the estimated position it was recycled to. Only applies on the new architecture.
|
|
357
|
+
*
|
|
358
|
+
* This trades a possible flash at the wrong position for an extra render and native commit per recycled row, so it
|
|
359
|
+
* is worth enabling only for lists with dynamically sized items whose estimates are visibly wrong. Items with a
|
|
360
|
+
* size from `getFixedItemSize`, or with an already measured size, are exact and render immediately either way.
|
|
361
|
+
*
|
|
362
|
+
* Sticky headers are intentionally excluded. They are painted from a scroll-driven interpolation rather than the
|
|
363
|
+
* committed position, so hiding them would blink a header out mid-scroll without preventing a flash.
|
|
364
|
+
*
|
|
365
|
+
* @default false
|
|
366
|
+
*/
|
|
367
|
+
experimental_hideItemsUntilMeasured?: boolean;
|
|
352
368
|
/**
|
|
353
369
|
* Function to call when the user pulls to refresh.
|
|
354
370
|
*/
|
package/reanimated.js
CHANGED
|
@@ -113,7 +113,10 @@ var ReanimatedPositionViewSticky = typedMemo(function ReanimatedPositionViewStic
|
|
|
113
113
|
var ReanimatedPositionView = typedMemo(function ReanimatedPositionViewComponent(props) {
|
|
114
114
|
const ctx = useStateContext();
|
|
115
115
|
const { id, horizontal, style, refView, children, recycleItems, layoutTransition, ...rest } = props;
|
|
116
|
-
const [positionValue = POSITION_OUT_OF_VIEW] = useArr$([
|
|
116
|
+
const [positionValue = POSITION_OUT_OF_VIEW, layoutReady = true] = useArr$([
|
|
117
|
+
`containerPosition${id}`,
|
|
118
|
+
`containerLayoutReady${id}`
|
|
119
|
+
]);
|
|
117
120
|
const prevItemKeyRef = React__namespace.useRef(void 0);
|
|
118
121
|
let shouldSkipTransitionForRecycleReuse = false;
|
|
119
122
|
if (recycleItems && layoutTransition) {
|
|
@@ -127,8 +130,8 @@ var ReanimatedPositionView = typedMemo(function ReanimatedPositionViewComponent(
|
|
|
127
130
|
prevItemKeyRef.current = void 0;
|
|
128
131
|
}
|
|
129
132
|
const viewStyle = React__namespace.useMemo(
|
|
130
|
-
() => [style, horizontal ? { left: positionValue } : { top: positionValue }],
|
|
131
|
-
[horizontal, positionValue, style]
|
|
133
|
+
() => [style, horizontal ? { left: positionValue } : { top: positionValue }, !layoutReady && { opacity: 0 }],
|
|
134
|
+
[horizontal, layoutReady, positionValue, style]
|
|
132
135
|
);
|
|
133
136
|
return /* @__PURE__ */ React__namespace.createElement(
|
|
134
137
|
Reanimated__default.default.View,
|
|
@@ -136,7 +139,8 @@ var ReanimatedPositionView = typedMemo(function ReanimatedPositionViewComponent(
|
|
|
136
139
|
layout: shouldSkipTransitionForRecycleReuse ? void 0 : layoutTransition,
|
|
137
140
|
ref: refView,
|
|
138
141
|
style: viewStyle,
|
|
139
|
-
...rest
|
|
142
|
+
...rest,
|
|
143
|
+
pointerEvents: layoutReady ? void 0 : "none"
|
|
140
144
|
},
|
|
141
145
|
children
|
|
142
146
|
);
|
package/reanimated.mjs
CHANGED
|
@@ -89,7 +89,10 @@ var ReanimatedPositionViewSticky = typedMemo(function ReanimatedPositionViewStic
|
|
|
89
89
|
var ReanimatedPositionView = typedMemo(function ReanimatedPositionViewComponent(props) {
|
|
90
90
|
const ctx = useStateContext();
|
|
91
91
|
const { id, horizontal, style, refView, children, recycleItems, layoutTransition, ...rest } = props;
|
|
92
|
-
const [positionValue = POSITION_OUT_OF_VIEW] = useArr$([
|
|
92
|
+
const [positionValue = POSITION_OUT_OF_VIEW, layoutReady = true] = useArr$([
|
|
93
|
+
`containerPosition${id}`,
|
|
94
|
+
`containerLayoutReady${id}`
|
|
95
|
+
]);
|
|
93
96
|
const prevItemKeyRef = React.useRef(void 0);
|
|
94
97
|
let shouldSkipTransitionForRecycleReuse = false;
|
|
95
98
|
if (recycleItems && layoutTransition) {
|
|
@@ -103,8 +106,8 @@ var ReanimatedPositionView = typedMemo(function ReanimatedPositionViewComponent(
|
|
|
103
106
|
prevItemKeyRef.current = void 0;
|
|
104
107
|
}
|
|
105
108
|
const viewStyle = React.useMemo(
|
|
106
|
-
() => [style, horizontal ? { left: positionValue } : { top: positionValue }],
|
|
107
|
-
[horizontal, positionValue, style]
|
|
109
|
+
() => [style, horizontal ? { left: positionValue } : { top: positionValue }, !layoutReady && { opacity: 0 }],
|
|
110
|
+
[horizontal, layoutReady, positionValue, style]
|
|
108
111
|
);
|
|
109
112
|
return /* @__PURE__ */ React.createElement(
|
|
110
113
|
Reanimated.View,
|
|
@@ -112,7 +115,8 @@ var ReanimatedPositionView = typedMemo(function ReanimatedPositionViewComponent(
|
|
|
112
115
|
layout: shouldSkipTransitionForRecycleReuse ? void 0 : layoutTransition,
|
|
113
116
|
ref: refView,
|
|
114
117
|
style: viewStyle,
|
|
115
|
-
...rest
|
|
118
|
+
...rest,
|
|
119
|
+
pointerEvents: layoutReady ? void 0 : "none"
|
|
116
120
|
},
|
|
117
121
|
children
|
|
118
122
|
);
|
package/section-list.d.ts
CHANGED
|
@@ -65,7 +65,7 @@ interface MaintainVisibleContentPositionNormalized<ItemT = any> {
|
|
|
65
65
|
shouldRestorePosition?: (item: ItemT, index: number, data: readonly ItemT[]) => boolean;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
type ListenerType = "activeStickyIndex" | "alignItemsAtEndPadding" | "anchoredEndSpaceSize" | "containerLayoutEpoch" | "debugComputedScroll" | "debugRawScroll" | "extraData" | "footerSize" | "headerSize" | "lastItemKeys" | "lastPositionUpdate" | "maintainVisibleContentPosition" | "numColumns" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "scrollAdjust" | "scrollAdjustPending" | "scrollAdjustUserOffset" | "scrollSize" | "snapToOffsets" | "stylePaddingTop" | "totalSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | `containerColumn${number}` | `containerSpan${number}` | `containerItemData${number}` | `containerItemIndex${number}` | `containerItemKey${number}` | `containerPosition${number}` | `containerSticky${number}`;
|
|
68
|
+
type ListenerType = "activeStickyIndex" | "alignItemsAtEndPadding" | "anchoredEndSpaceSize" | "containerLayoutEpoch" | "debugComputedScroll" | "debugRawScroll" | "extraData" | "footerSize" | "headerSize" | "lastItemKeys" | "lastPositionUpdate" | "maintainVisibleContentPosition" | "numColumns" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "scrollAdjust" | "scrollAdjustPending" | "scrollAdjustUserOffset" | "scrollSize" | "snapToOffsets" | "stylePaddingTop" | "totalSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | `containerColumn${number}` | `containerSpan${number}` | `containerItemData${number}` | `containerItemIndex${number}` | `containerItemKey${number}` | `containerLayoutReady${number}` | `containerPosition${number}` | `containerSticky${number}`;
|
|
69
69
|
type LegendListListenerType = Extract<ListenerType, "activeStickyIndex" | "anchoredEndSpaceSize" | "footerSize" | "headerSize" | "isAtEnd" | "isAtStart" | "isNearEnd" | "isNearStart" | "isWithinMaintainScrollAtEndThreshold" | "adaptiveRender" | "lastItemKeys" | "lastPositionUpdate" | "numContainers" | "numContainersPooled" | "otherAxisSize" | "readyToRender" | "snapToOffsets" | "totalSize">;
|
|
70
70
|
type ListenerTypeValueMap = {
|
|
71
71
|
activeStickyIndex: number;
|
|
@@ -104,6 +104,8 @@ type ListenerTypeValueMap = {
|
|
|
104
104
|
adaptiveRender: "normal" | "light";
|
|
105
105
|
} & {
|
|
106
106
|
[K in ListenerType as K extends `containerItemKey${number}` ? K : never]: string;
|
|
107
|
+
} & {
|
|
108
|
+
[K in ListenerType as K extends `containerLayoutReady${number}` ? K : never]: boolean;
|
|
107
109
|
} & {
|
|
108
110
|
[K in ListenerType as K extends `containerItemData${number}` ? K : never]: any;
|
|
109
111
|
} & {
|
|
@@ -405,6 +407,20 @@ interface LegendListSpecificProps<ItemT, TItemType extends string | undefined> {
|
|
|
405
407
|
* Configures the adaptive render signal. Items can use this to render a lighter version while scrolling quickly.
|
|
406
408
|
*/
|
|
407
409
|
experimental_adaptiveRender?: AdaptiveRenderConfig;
|
|
410
|
+
/**
|
|
411
|
+
* Keeps a newly recycled item laid out but invisible until its size has been measured, so it is never painted at
|
|
412
|
+
* the estimated position it was recycled to. Only applies on the new architecture.
|
|
413
|
+
*
|
|
414
|
+
* This trades a possible flash at the wrong position for an extra render and native commit per recycled row, so it
|
|
415
|
+
* is worth enabling only for lists with dynamically sized items whose estimates are visibly wrong. Items with a
|
|
416
|
+
* size from `getFixedItemSize`, or with an already measured size, are exact and render immediately either way.
|
|
417
|
+
*
|
|
418
|
+
* Sticky headers are intentionally excluded. They are painted from a scroll-driven interpolation rather than the
|
|
419
|
+
* committed position, so hiding them would blink a header out mid-scroll without preventing a flash.
|
|
420
|
+
*
|
|
421
|
+
* @default false
|
|
422
|
+
*/
|
|
423
|
+
experimental_hideItemsUntilMeasured?: boolean;
|
|
408
424
|
/**
|
|
409
425
|
* Function to call when the user pulls to refresh.
|
|
410
426
|
*/
|