@legendapp/list 3.3.7 → 3.3.8
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 +4 -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 +69 -11
- package/react-native.mjs +69 -11
- package/react-native.web.d.ts +17 -1
- package/react-native.web.js +24 -4
- package/react-native.web.mjs +24 -4
- package/react.d.ts +17 -1
- package/react.js +24 -4
- package/react.mjs +24 -4
- package/reanimated.d.ts +17 -1
- package/reanimated.js +8 -4
- package/reanimated.mjs +8 -4
- package/section-list.d.ts +17 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
## 3.3.8
|
|
2
|
+
|
|
3
|
+
- 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.
|
|
4
|
+
|
|
1
5
|
## 3.3.7
|
|
2
6
|
|
|
3
7
|
- 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
|
@@ -4596,15 +4596,19 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4596
4596
|
if (oldKey && oldKey !== id) {
|
|
4597
4597
|
containerItemKeys.delete(oldKey);
|
|
4598
4598
|
}
|
|
4599
|
+
state.containerItemMetadata.set(
|
|
4600
|
+
containerIndex,
|
|
4601
|
+
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4602
|
+
);
|
|
4599
4603
|
if (oldKey !== id) {
|
|
4600
4604
|
changedContainerIds != null ? changedContainerIds : changedContainerIds = /* @__PURE__ */ new Set();
|
|
4601
4605
|
changedContainerIds.add(containerIndex);
|
|
4602
4606
|
state.containerItemGenerations[containerIndex] = ((_p = state.containerItemGenerations[containerIndex]) != null ? _p : 0) + 1;
|
|
4607
|
+
if (state.props.hideItemsUntilMeasured) {
|
|
4608
|
+
const isLayoutReady = state.sizesKnown.has(id) || resolveContainerItemMetadata(state, containerIndex, i, data[i]).fixedItemSize !== void 0;
|
|
4609
|
+
set$(ctx, `containerLayoutReady${containerIndex}`, isLayoutReady);
|
|
4610
|
+
}
|
|
4603
4611
|
}
|
|
4604
|
-
state.containerItemMetadata.set(
|
|
4605
|
-
containerIndex,
|
|
4606
|
-
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4607
|
-
);
|
|
4608
4612
|
set$(ctx, `containerItemKey${containerIndex}`, id);
|
|
4609
4613
|
set$(ctx, `containerItemIndex${containerIndex}`, i);
|
|
4610
4614
|
set$(ctx, `containerItemData${containerIndex}`, data[i]);
|
|
@@ -5036,24 +5040,39 @@ function resolveSkippedAnchorReset(ctx, itemKey) {
|
|
|
5036
5040
|
state.userScrollAnchorReset = void 0;
|
|
5037
5041
|
}
|
|
5038
5042
|
}
|
|
5043
|
+
function revealMeasuredGeneration(ctx, containerId, itemKey, generation) {
|
|
5044
|
+
var _a3;
|
|
5045
|
+
if (!ctx.state.props.hideItemsUntilMeasured) {
|
|
5046
|
+
return;
|
|
5047
|
+
}
|
|
5048
|
+
const isCurrentGeneration = ((_a3 = ctx.state.containerItemGenerations[containerId]) != null ? _a3 : 0) === generation;
|
|
5049
|
+
const isCurrentAssignment = peek$(ctx, `containerItemKey${containerId}`) === itemKey;
|
|
5050
|
+
if (isCurrentGeneration && isCurrentAssignment) {
|
|
5051
|
+
set$(ctx, `containerLayoutReady${containerId}`, true);
|
|
5052
|
+
}
|
|
5053
|
+
}
|
|
5039
5054
|
function measureContainersInLayoutEffect(ctx, targetContainerIds = null) {
|
|
5040
|
-
var _a3, _b
|
|
5055
|
+
var _a3, _b;
|
|
5041
5056
|
const state = ctx.state;
|
|
5042
5057
|
const measurements = [];
|
|
5058
|
+
const measuredGenerations = state.props.hideItemsUntilMeasured ? [] : void 0;
|
|
5043
5059
|
let isCollectingSynchronousMeasurements = true;
|
|
5044
5060
|
const containerIds = targetContainerIds != null ? targetContainerIds : ctx.viewRefs.keys();
|
|
5045
5061
|
for (const containerId of containerIds) {
|
|
5046
|
-
const
|
|
5062
|
+
const view = (_a3 = ctx.viewRefs.get(containerId)) == null ? void 0 : _a3.current;
|
|
5047
5063
|
const itemKey = peek$(ctx, `containerItemKey${containerId}`);
|
|
5048
5064
|
if (itemKey !== void 0) {
|
|
5049
|
-
const generation = ((
|
|
5065
|
+
const generation = ((_b = state.containerItemGenerations[containerId]) != null ? _b : 0) + 1;
|
|
5050
5066
|
state.containerItemGenerations[containerId] = generation;
|
|
5051
5067
|
const fixedItemSize = resolveFixedItemSize(ctx, containerId, itemKey);
|
|
5052
5068
|
const canSkipMeasurement = !state.needsOtherAxisSize && fixedItemSize !== void 0 && state.sizesKnown.get(itemKey) === fixedItemSize + ctx.scrollAxisGap;
|
|
5053
5069
|
if (canSkipMeasurement) {
|
|
5054
5070
|
resolveSkippedAnchorReset(ctx, itemKey);
|
|
5055
|
-
|
|
5056
|
-
|
|
5071
|
+
if (measuredGenerations) {
|
|
5072
|
+
revealMeasuredGeneration(ctx, containerId, itemKey, generation);
|
|
5073
|
+
}
|
|
5074
|
+
} else if (view == null ? void 0 : view.measure) {
|
|
5075
|
+
view.measure((_x, _y, width, height) => {
|
|
5057
5076
|
var _a4;
|
|
5058
5077
|
const isCurrentGeneration = ((_a4 = ctx.state.containerItemGenerations[containerId]) != null ? _a4 : 0) === generation;
|
|
5059
5078
|
if (isCurrentGeneration) {
|
|
@@ -5064,17 +5083,28 @@ function measureContainersInLayoutEffect(ctx, targetContainerIds = null) {
|
|
|
5064
5083
|
};
|
|
5065
5084
|
if (isCollectingSynchronousMeasurements) {
|
|
5066
5085
|
measurements.push(measurement);
|
|
5086
|
+
measuredGenerations == null ? void 0 : measuredGenerations.push({ containerId, generation, itemKey });
|
|
5067
5087
|
} else {
|
|
5068
5088
|
updateItemSizes(ctx, measurement);
|
|
5089
|
+
if (measuredGenerations) {
|
|
5090
|
+
revealMeasuredGeneration(ctx, containerId, itemKey, generation);
|
|
5091
|
+
}
|
|
5069
5092
|
}
|
|
5070
5093
|
}
|
|
5071
5094
|
});
|
|
5095
|
+
} else if (measuredGenerations) {
|
|
5096
|
+
revealMeasuredGeneration(ctx, containerId, itemKey, generation);
|
|
5072
5097
|
}
|
|
5073
5098
|
}
|
|
5074
5099
|
}
|
|
5075
5100
|
isCollectingSynchronousMeasurements = false;
|
|
5076
5101
|
if (measurements.length > 0) {
|
|
5077
5102
|
updateItemSizesBatch(ctx, measurements);
|
|
5103
|
+
if (measuredGenerations) {
|
|
5104
|
+
for (const { containerId, generation, itemKey } of measuredGenerations) {
|
|
5105
|
+
revealMeasuredGeneration(ctx, containerId, itemKey, generation);
|
|
5106
|
+
}
|
|
5107
|
+
}
|
|
5078
5108
|
}
|
|
5079
5109
|
}
|
|
5080
5110
|
var typedForwardRef = React2__namespace.forwardRef;
|
|
@@ -5162,8 +5192,20 @@ var PositionViewState = typedMemo(function PositionViewState2({
|
|
|
5162
5192
|
refView,
|
|
5163
5193
|
...rest
|
|
5164
5194
|
}) {
|
|
5165
|
-
const [position = POSITION_OUT_OF_VIEW, _itemKey] = useArr$([
|
|
5166
|
-
|
|
5195
|
+
const [position = POSITION_OUT_OF_VIEW, _itemKey, layoutReady = true] = useArr$([
|
|
5196
|
+
`containerPosition${id}`,
|
|
5197
|
+
`containerItemKey${id}`,
|
|
5198
|
+
`containerLayoutReady${id}`
|
|
5199
|
+
]);
|
|
5200
|
+
return /* @__PURE__ */ React2__namespace.createElement(
|
|
5201
|
+
ReactNative.View,
|
|
5202
|
+
{
|
|
5203
|
+
ref: refView,
|
|
5204
|
+
style: [style, horizontal ? { left: position } : { top: position }, !layoutReady && { opacity: 0 }],
|
|
5205
|
+
...rest,
|
|
5206
|
+
pointerEvents: layoutReady ? void 0 : "none"
|
|
5207
|
+
}
|
|
5208
|
+
);
|
|
5167
5209
|
});
|
|
5168
5210
|
var PositionViewAnimated = typedMemo(function PositionViewAnimated2({
|
|
5169
5211
|
id,
|
|
@@ -6291,6 +6333,16 @@ function checkStructuralDataChange(state, dataProp, previousData) {
|
|
|
6291
6333
|
return false;
|
|
6292
6334
|
}
|
|
6293
6335
|
|
|
6336
|
+
// src/core/containerLayoutReady.ts
|
|
6337
|
+
var CONTAINER_LAYOUT_READY_PREFIX = "containerLayoutReady";
|
|
6338
|
+
function resetContainerLayoutReady(ctx) {
|
|
6339
|
+
for (const signalName of ctx.values.keys()) {
|
|
6340
|
+
if (signalName.startsWith(CONTAINER_LAYOUT_READY_PREFIX)) {
|
|
6341
|
+
set$(ctx, signalName, void 0);
|
|
6342
|
+
}
|
|
6343
|
+
}
|
|
6344
|
+
}
|
|
6345
|
+
|
|
6294
6346
|
// src/core/doInitialAllocateContainers.ts
|
|
6295
6347
|
function doInitialAllocateContainers(ctx) {
|
|
6296
6348
|
var _a3, _b;
|
|
@@ -7197,6 +7249,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7197
7249
|
initialScrollIndex: initialScrollIndexProp,
|
|
7198
7250
|
initialScrollOffset: initialScrollOffsetProp,
|
|
7199
7251
|
experimental_adaptiveRender,
|
|
7252
|
+
experimental_hideItemsUntilMeasured,
|
|
7200
7253
|
itemsAreEqual,
|
|
7201
7254
|
keyExtractor: keyExtractorProp,
|
|
7202
7255
|
ListEmptyComponent,
|
|
@@ -7417,6 +7470,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7417
7470
|
const state = refState.current;
|
|
7418
7471
|
const isFirstLocal = state.isFirst;
|
|
7419
7472
|
const previousAdaptiveRender = state.props.adaptiveRender;
|
|
7473
|
+
const previousHideItemsUntilMeasured = state.props.hideItemsUntilMeasured;
|
|
7420
7474
|
const previousNumColumnsProp = state.props.numColumns;
|
|
7421
7475
|
const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
|
|
7422
7476
|
ctx.scrollAxisGap = nextScrollAxisGap;
|
|
@@ -7462,6 +7516,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7462
7516
|
estimatedItemSize,
|
|
7463
7517
|
getFixedItemSize: useWrapIfItem(getFixedItemSize),
|
|
7464
7518
|
getItemType: useWrapIfItem(getItemType),
|
|
7519
|
+
hideItemsUntilMeasured: experimental_hideItemsUntilMeasured,
|
|
7465
7520
|
horizontal: !!horizontal,
|
|
7466
7521
|
itemsAreEqual,
|
|
7467
7522
|
keyExtractor: useWrapIfItem(keyExtractor),
|
|
@@ -7499,6 +7554,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7499
7554
|
if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
|
|
7500
7555
|
resetAdaptiveRender(ctx);
|
|
7501
7556
|
}
|
|
7557
|
+
if (!isFirstLocal && previousHideItemsUntilMeasured && !experimental_hideItemsUntilMeasured) {
|
|
7558
|
+
resetContainerLayoutReady(ctx);
|
|
7559
|
+
}
|
|
7502
7560
|
const memoizedLastItemKeys = React2.useMemo(() => {
|
|
7503
7561
|
if (!dataProp.length) return [];
|
|
7504
7562
|
return Array.from(
|
package/react-native.mjs
CHANGED
|
@@ -4575,15 +4575,19 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4575
4575
|
if (oldKey && oldKey !== id) {
|
|
4576
4576
|
containerItemKeys.delete(oldKey);
|
|
4577
4577
|
}
|
|
4578
|
+
state.containerItemMetadata.set(
|
|
4579
|
+
containerIndex,
|
|
4580
|
+
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4581
|
+
);
|
|
4578
4582
|
if (oldKey !== id) {
|
|
4579
4583
|
changedContainerIds != null ? changedContainerIds : changedContainerIds = /* @__PURE__ */ new Set();
|
|
4580
4584
|
changedContainerIds.add(containerIndex);
|
|
4581
4585
|
state.containerItemGenerations[containerIndex] = ((_p = state.containerItemGenerations[containerIndex]) != null ? _p : 0) + 1;
|
|
4586
|
+
if (state.props.hideItemsUntilMeasured) {
|
|
4587
|
+
const isLayoutReady = state.sizesKnown.has(id) || resolveContainerItemMetadata(state, containerIndex, i, data[i]).fixedItemSize !== void 0;
|
|
4588
|
+
set$(ctx, `containerLayoutReady${containerIndex}`, isLayoutReady);
|
|
4589
|
+
}
|
|
4582
4590
|
}
|
|
4583
|
-
state.containerItemMetadata.set(
|
|
4584
|
-
containerIndex,
|
|
4585
|
-
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4586
|
-
);
|
|
4587
4591
|
set$(ctx, `containerItemKey${containerIndex}`, id);
|
|
4588
4592
|
set$(ctx, `containerItemIndex${containerIndex}`, i);
|
|
4589
4593
|
set$(ctx, `containerItemData${containerIndex}`, data[i]);
|
|
@@ -5015,24 +5019,39 @@ function resolveSkippedAnchorReset(ctx, itemKey) {
|
|
|
5015
5019
|
state.userScrollAnchorReset = void 0;
|
|
5016
5020
|
}
|
|
5017
5021
|
}
|
|
5022
|
+
function revealMeasuredGeneration(ctx, containerId, itemKey, generation) {
|
|
5023
|
+
var _a3;
|
|
5024
|
+
if (!ctx.state.props.hideItemsUntilMeasured) {
|
|
5025
|
+
return;
|
|
5026
|
+
}
|
|
5027
|
+
const isCurrentGeneration = ((_a3 = ctx.state.containerItemGenerations[containerId]) != null ? _a3 : 0) === generation;
|
|
5028
|
+
const isCurrentAssignment = peek$(ctx, `containerItemKey${containerId}`) === itemKey;
|
|
5029
|
+
if (isCurrentGeneration && isCurrentAssignment) {
|
|
5030
|
+
set$(ctx, `containerLayoutReady${containerId}`, true);
|
|
5031
|
+
}
|
|
5032
|
+
}
|
|
5018
5033
|
function measureContainersInLayoutEffect(ctx, targetContainerIds = null) {
|
|
5019
|
-
var _a3, _b
|
|
5034
|
+
var _a3, _b;
|
|
5020
5035
|
const state = ctx.state;
|
|
5021
5036
|
const measurements = [];
|
|
5037
|
+
const measuredGenerations = state.props.hideItemsUntilMeasured ? [] : void 0;
|
|
5022
5038
|
let isCollectingSynchronousMeasurements = true;
|
|
5023
5039
|
const containerIds = targetContainerIds != null ? targetContainerIds : ctx.viewRefs.keys();
|
|
5024
5040
|
for (const containerId of containerIds) {
|
|
5025
|
-
const
|
|
5041
|
+
const view = (_a3 = ctx.viewRefs.get(containerId)) == null ? void 0 : _a3.current;
|
|
5026
5042
|
const itemKey = peek$(ctx, `containerItemKey${containerId}`);
|
|
5027
5043
|
if (itemKey !== void 0) {
|
|
5028
|
-
const generation = ((
|
|
5044
|
+
const generation = ((_b = state.containerItemGenerations[containerId]) != null ? _b : 0) + 1;
|
|
5029
5045
|
state.containerItemGenerations[containerId] = generation;
|
|
5030
5046
|
const fixedItemSize = resolveFixedItemSize(ctx, containerId, itemKey);
|
|
5031
5047
|
const canSkipMeasurement = !state.needsOtherAxisSize && fixedItemSize !== void 0 && state.sizesKnown.get(itemKey) === fixedItemSize + ctx.scrollAxisGap;
|
|
5032
5048
|
if (canSkipMeasurement) {
|
|
5033
5049
|
resolveSkippedAnchorReset(ctx, itemKey);
|
|
5034
|
-
|
|
5035
|
-
|
|
5050
|
+
if (measuredGenerations) {
|
|
5051
|
+
revealMeasuredGeneration(ctx, containerId, itemKey, generation);
|
|
5052
|
+
}
|
|
5053
|
+
} else if (view == null ? void 0 : view.measure) {
|
|
5054
|
+
view.measure((_x, _y, width, height) => {
|
|
5036
5055
|
var _a4;
|
|
5037
5056
|
const isCurrentGeneration = ((_a4 = ctx.state.containerItemGenerations[containerId]) != null ? _a4 : 0) === generation;
|
|
5038
5057
|
if (isCurrentGeneration) {
|
|
@@ -5043,17 +5062,28 @@ function measureContainersInLayoutEffect(ctx, targetContainerIds = null) {
|
|
|
5043
5062
|
};
|
|
5044
5063
|
if (isCollectingSynchronousMeasurements) {
|
|
5045
5064
|
measurements.push(measurement);
|
|
5065
|
+
measuredGenerations == null ? void 0 : measuredGenerations.push({ containerId, generation, itemKey });
|
|
5046
5066
|
} else {
|
|
5047
5067
|
updateItemSizes(ctx, measurement);
|
|
5068
|
+
if (measuredGenerations) {
|
|
5069
|
+
revealMeasuredGeneration(ctx, containerId, itemKey, generation);
|
|
5070
|
+
}
|
|
5048
5071
|
}
|
|
5049
5072
|
}
|
|
5050
5073
|
});
|
|
5074
|
+
} else if (measuredGenerations) {
|
|
5075
|
+
revealMeasuredGeneration(ctx, containerId, itemKey, generation);
|
|
5051
5076
|
}
|
|
5052
5077
|
}
|
|
5053
5078
|
}
|
|
5054
5079
|
isCollectingSynchronousMeasurements = false;
|
|
5055
5080
|
if (measurements.length > 0) {
|
|
5056
5081
|
updateItemSizesBatch(ctx, measurements);
|
|
5082
|
+
if (measuredGenerations) {
|
|
5083
|
+
for (const { containerId, generation, itemKey } of measuredGenerations) {
|
|
5084
|
+
revealMeasuredGeneration(ctx, containerId, itemKey, generation);
|
|
5085
|
+
}
|
|
5086
|
+
}
|
|
5057
5087
|
}
|
|
5058
5088
|
}
|
|
5059
5089
|
var typedForwardRef = React2.forwardRef;
|
|
@@ -5141,8 +5171,20 @@ var PositionViewState = typedMemo(function PositionViewState2({
|
|
|
5141
5171
|
refView,
|
|
5142
5172
|
...rest
|
|
5143
5173
|
}) {
|
|
5144
|
-
const [position = POSITION_OUT_OF_VIEW, _itemKey] = useArr$([
|
|
5145
|
-
|
|
5174
|
+
const [position = POSITION_OUT_OF_VIEW, _itemKey, layoutReady = true] = useArr$([
|
|
5175
|
+
`containerPosition${id}`,
|
|
5176
|
+
`containerItemKey${id}`,
|
|
5177
|
+
`containerLayoutReady${id}`
|
|
5178
|
+
]);
|
|
5179
|
+
return /* @__PURE__ */ React2.createElement(
|
|
5180
|
+
View$1,
|
|
5181
|
+
{
|
|
5182
|
+
ref: refView,
|
|
5183
|
+
style: [style, horizontal ? { left: position } : { top: position }, !layoutReady && { opacity: 0 }],
|
|
5184
|
+
...rest,
|
|
5185
|
+
pointerEvents: layoutReady ? void 0 : "none"
|
|
5186
|
+
}
|
|
5187
|
+
);
|
|
5146
5188
|
});
|
|
5147
5189
|
var PositionViewAnimated = typedMemo(function PositionViewAnimated2({
|
|
5148
5190
|
id,
|
|
@@ -6270,6 +6312,16 @@ function checkStructuralDataChange(state, dataProp, previousData) {
|
|
|
6270
6312
|
return false;
|
|
6271
6313
|
}
|
|
6272
6314
|
|
|
6315
|
+
// src/core/containerLayoutReady.ts
|
|
6316
|
+
var CONTAINER_LAYOUT_READY_PREFIX = "containerLayoutReady";
|
|
6317
|
+
function resetContainerLayoutReady(ctx) {
|
|
6318
|
+
for (const signalName of ctx.values.keys()) {
|
|
6319
|
+
if (signalName.startsWith(CONTAINER_LAYOUT_READY_PREFIX)) {
|
|
6320
|
+
set$(ctx, signalName, void 0);
|
|
6321
|
+
}
|
|
6322
|
+
}
|
|
6323
|
+
}
|
|
6324
|
+
|
|
6273
6325
|
// src/core/doInitialAllocateContainers.ts
|
|
6274
6326
|
function doInitialAllocateContainers(ctx) {
|
|
6275
6327
|
var _a3, _b;
|
|
@@ -7176,6 +7228,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7176
7228
|
initialScrollIndex: initialScrollIndexProp,
|
|
7177
7229
|
initialScrollOffset: initialScrollOffsetProp,
|
|
7178
7230
|
experimental_adaptiveRender,
|
|
7231
|
+
experimental_hideItemsUntilMeasured,
|
|
7179
7232
|
itemsAreEqual,
|
|
7180
7233
|
keyExtractor: keyExtractorProp,
|
|
7181
7234
|
ListEmptyComponent,
|
|
@@ -7396,6 +7449,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7396
7449
|
const state = refState.current;
|
|
7397
7450
|
const isFirstLocal = state.isFirst;
|
|
7398
7451
|
const previousAdaptiveRender = state.props.adaptiveRender;
|
|
7452
|
+
const previousHideItemsUntilMeasured = state.props.hideItemsUntilMeasured;
|
|
7399
7453
|
const previousNumColumnsProp = state.props.numColumns;
|
|
7400
7454
|
const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
|
|
7401
7455
|
ctx.scrollAxisGap = nextScrollAxisGap;
|
|
@@ -7441,6 +7495,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7441
7495
|
estimatedItemSize,
|
|
7442
7496
|
getFixedItemSize: useWrapIfItem(getFixedItemSize),
|
|
7443
7497
|
getItemType: useWrapIfItem(getItemType),
|
|
7498
|
+
hideItemsUntilMeasured: experimental_hideItemsUntilMeasured,
|
|
7444
7499
|
horizontal: !!horizontal,
|
|
7445
7500
|
itemsAreEqual,
|
|
7446
7501
|
keyExtractor: useWrapIfItem(keyExtractor),
|
|
@@ -7478,6 +7533,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7478
7533
|
if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
|
|
7479
7534
|
resetAdaptiveRender(ctx);
|
|
7480
7535
|
}
|
|
7536
|
+
if (!isFirstLocal && previousHideItemsUntilMeasured && !experimental_hideItemsUntilMeasured) {
|
|
7537
|
+
resetContainerLayoutReady(ctx);
|
|
7538
|
+
}
|
|
7481
7539
|
const memoizedLastItemKeys = useMemo(() => {
|
|
7482
7540
|
if (!dataProp.length) return [];
|
|
7483
7541
|
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
|
@@ -4625,15 +4625,19 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4625
4625
|
if (oldKey && oldKey !== id) {
|
|
4626
4626
|
containerItemKeys.delete(oldKey);
|
|
4627
4627
|
}
|
|
4628
|
+
state.containerItemMetadata.set(
|
|
4629
|
+
containerIndex,
|
|
4630
|
+
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4631
|
+
);
|
|
4628
4632
|
if (oldKey !== id) {
|
|
4629
4633
|
changedContainerIds != null ? changedContainerIds : changedContainerIds = /* @__PURE__ */ new Set();
|
|
4630
4634
|
changedContainerIds.add(containerIndex);
|
|
4631
4635
|
state.containerItemGenerations[containerIndex] = ((_p = state.containerItemGenerations[containerIndex]) != null ? _p : 0) + 1;
|
|
4636
|
+
if (state.props.hideItemsUntilMeasured) {
|
|
4637
|
+
const isLayoutReady = state.sizesKnown.has(id) || resolveContainerItemMetadata(state, containerIndex, i, data[i]).fixedItemSize !== void 0;
|
|
4638
|
+
set$(ctx, `containerLayoutReady${containerIndex}`, isLayoutReady);
|
|
4639
|
+
}
|
|
4632
4640
|
}
|
|
4633
|
-
state.containerItemMetadata.set(
|
|
4634
|
-
containerIndex,
|
|
4635
|
-
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4636
|
-
);
|
|
4637
4641
|
set$(ctx, `containerItemKey${containerIndex}`, id);
|
|
4638
4642
|
set$(ctx, `containerItemIndex${containerIndex}`, i);
|
|
4639
4643
|
set$(ctx, `containerItemData${containerIndex}`, data[i]);
|
|
@@ -6950,6 +6954,16 @@ function checkStructuralDataChange(state, dataProp, previousData) {
|
|
|
6950
6954
|
return false;
|
|
6951
6955
|
}
|
|
6952
6956
|
|
|
6957
|
+
// src/core/containerLayoutReady.ts
|
|
6958
|
+
var CONTAINER_LAYOUT_READY_PREFIX = "containerLayoutReady";
|
|
6959
|
+
function resetContainerLayoutReady(ctx) {
|
|
6960
|
+
for (const signalName of ctx.values.keys()) {
|
|
6961
|
+
if (signalName.startsWith(CONTAINER_LAYOUT_READY_PREFIX)) {
|
|
6962
|
+
set$(ctx, signalName, void 0);
|
|
6963
|
+
}
|
|
6964
|
+
}
|
|
6965
|
+
}
|
|
6966
|
+
|
|
6953
6967
|
// src/core/doInitialAllocateContainers.ts
|
|
6954
6968
|
function doInitialAllocateContainers(ctx) {
|
|
6955
6969
|
var _a3, _b;
|
|
@@ -7840,6 +7854,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7840
7854
|
initialScrollIndex: initialScrollIndexProp,
|
|
7841
7855
|
initialScrollOffset: initialScrollOffsetProp,
|
|
7842
7856
|
experimental_adaptiveRender,
|
|
7857
|
+
experimental_hideItemsUntilMeasured,
|
|
7843
7858
|
itemsAreEqual,
|
|
7844
7859
|
keyExtractor: keyExtractorProp,
|
|
7845
7860
|
ListEmptyComponent,
|
|
@@ -8060,6 +8075,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8060
8075
|
const state = refState.current;
|
|
8061
8076
|
const isFirstLocal = state.isFirst;
|
|
8062
8077
|
const previousAdaptiveRender = state.props.adaptiveRender;
|
|
8078
|
+
const previousHideItemsUntilMeasured = state.props.hideItemsUntilMeasured;
|
|
8063
8079
|
const previousNumColumnsProp = state.props.numColumns;
|
|
8064
8080
|
const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
|
|
8065
8081
|
ctx.scrollAxisGap = nextScrollAxisGap;
|
|
@@ -8105,6 +8121,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8105
8121
|
estimatedItemSize,
|
|
8106
8122
|
getFixedItemSize: useWrapIfItem(getFixedItemSize),
|
|
8107
8123
|
getItemType: useWrapIfItem(getItemType),
|
|
8124
|
+
hideItemsUntilMeasured: experimental_hideItemsUntilMeasured,
|
|
8108
8125
|
horizontal: !!horizontal,
|
|
8109
8126
|
itemsAreEqual,
|
|
8110
8127
|
keyExtractor: useWrapIfItem(keyExtractor),
|
|
@@ -8142,6 +8159,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8142
8159
|
if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
|
|
8143
8160
|
resetAdaptiveRender(ctx);
|
|
8144
8161
|
}
|
|
8162
|
+
if (!isFirstLocal && previousHideItemsUntilMeasured && !experimental_hideItemsUntilMeasured) {
|
|
8163
|
+
resetContainerLayoutReady(ctx);
|
|
8164
|
+
}
|
|
8145
8165
|
const memoizedLastItemKeys = React3.useMemo(() => {
|
|
8146
8166
|
if (!dataProp.length) return [];
|
|
8147
8167
|
return Array.from(
|
package/react-native.web.mjs
CHANGED
|
@@ -4604,15 +4604,19 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4604
4604
|
if (oldKey && oldKey !== id) {
|
|
4605
4605
|
containerItemKeys.delete(oldKey);
|
|
4606
4606
|
}
|
|
4607
|
+
state.containerItemMetadata.set(
|
|
4608
|
+
containerIndex,
|
|
4609
|
+
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4610
|
+
);
|
|
4607
4611
|
if (oldKey !== id) {
|
|
4608
4612
|
changedContainerIds != null ? changedContainerIds : changedContainerIds = /* @__PURE__ */ new Set();
|
|
4609
4613
|
changedContainerIds.add(containerIndex);
|
|
4610
4614
|
state.containerItemGenerations[containerIndex] = ((_p = state.containerItemGenerations[containerIndex]) != null ? _p : 0) + 1;
|
|
4615
|
+
if (state.props.hideItemsUntilMeasured) {
|
|
4616
|
+
const isLayoutReady = state.sizesKnown.has(id) || resolveContainerItemMetadata(state, containerIndex, i, data[i]).fixedItemSize !== void 0;
|
|
4617
|
+
set$(ctx, `containerLayoutReady${containerIndex}`, isLayoutReady);
|
|
4618
|
+
}
|
|
4611
4619
|
}
|
|
4612
|
-
state.containerItemMetadata.set(
|
|
4613
|
-
containerIndex,
|
|
4614
|
-
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4615
|
-
);
|
|
4616
4620
|
set$(ctx, `containerItemKey${containerIndex}`, id);
|
|
4617
4621
|
set$(ctx, `containerItemIndex${containerIndex}`, i);
|
|
4618
4622
|
set$(ctx, `containerItemData${containerIndex}`, data[i]);
|
|
@@ -6929,6 +6933,16 @@ function checkStructuralDataChange(state, dataProp, previousData) {
|
|
|
6929
6933
|
return false;
|
|
6930
6934
|
}
|
|
6931
6935
|
|
|
6936
|
+
// src/core/containerLayoutReady.ts
|
|
6937
|
+
var CONTAINER_LAYOUT_READY_PREFIX = "containerLayoutReady";
|
|
6938
|
+
function resetContainerLayoutReady(ctx) {
|
|
6939
|
+
for (const signalName of ctx.values.keys()) {
|
|
6940
|
+
if (signalName.startsWith(CONTAINER_LAYOUT_READY_PREFIX)) {
|
|
6941
|
+
set$(ctx, signalName, void 0);
|
|
6942
|
+
}
|
|
6943
|
+
}
|
|
6944
|
+
}
|
|
6945
|
+
|
|
6932
6946
|
// src/core/doInitialAllocateContainers.ts
|
|
6933
6947
|
function doInitialAllocateContainers(ctx) {
|
|
6934
6948
|
var _a3, _b;
|
|
@@ -7819,6 +7833,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7819
7833
|
initialScrollIndex: initialScrollIndexProp,
|
|
7820
7834
|
initialScrollOffset: initialScrollOffsetProp,
|
|
7821
7835
|
experimental_adaptiveRender,
|
|
7836
|
+
experimental_hideItemsUntilMeasured,
|
|
7822
7837
|
itemsAreEqual,
|
|
7823
7838
|
keyExtractor: keyExtractorProp,
|
|
7824
7839
|
ListEmptyComponent,
|
|
@@ -8039,6 +8054,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8039
8054
|
const state = refState.current;
|
|
8040
8055
|
const isFirstLocal = state.isFirst;
|
|
8041
8056
|
const previousAdaptiveRender = state.props.adaptiveRender;
|
|
8057
|
+
const previousHideItemsUntilMeasured = state.props.hideItemsUntilMeasured;
|
|
8042
8058
|
const previousNumColumnsProp = state.props.numColumns;
|
|
8043
8059
|
const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
|
|
8044
8060
|
ctx.scrollAxisGap = nextScrollAxisGap;
|
|
@@ -8084,6 +8100,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8084
8100
|
estimatedItemSize,
|
|
8085
8101
|
getFixedItemSize: useWrapIfItem(getFixedItemSize),
|
|
8086
8102
|
getItemType: useWrapIfItem(getItemType),
|
|
8103
|
+
hideItemsUntilMeasured: experimental_hideItemsUntilMeasured,
|
|
8087
8104
|
horizontal: !!horizontal,
|
|
8088
8105
|
itemsAreEqual,
|
|
8089
8106
|
keyExtractor: useWrapIfItem(keyExtractor),
|
|
@@ -8121,6 +8138,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8121
8138
|
if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
|
|
8122
8139
|
resetAdaptiveRender(ctx);
|
|
8123
8140
|
}
|
|
8141
|
+
if (!isFirstLocal && previousHideItemsUntilMeasured && !experimental_hideItemsUntilMeasured) {
|
|
8142
|
+
resetContainerLayoutReady(ctx);
|
|
8143
|
+
}
|
|
8124
8144
|
const memoizedLastItemKeys = useMemo(() => {
|
|
8125
8145
|
if (!dataProp.length) return [];
|
|
8126
8146
|
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
|
@@ -4625,15 +4625,19 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4625
4625
|
if (oldKey && oldKey !== id) {
|
|
4626
4626
|
containerItemKeys.delete(oldKey);
|
|
4627
4627
|
}
|
|
4628
|
+
state.containerItemMetadata.set(
|
|
4629
|
+
containerIndex,
|
|
4630
|
+
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4631
|
+
);
|
|
4628
4632
|
if (oldKey !== id) {
|
|
4629
4633
|
changedContainerIds != null ? changedContainerIds : changedContainerIds = /* @__PURE__ */ new Set();
|
|
4630
4634
|
changedContainerIds.add(containerIndex);
|
|
4631
4635
|
state.containerItemGenerations[containerIndex] = ((_p = state.containerItemGenerations[containerIndex]) != null ? _p : 0) + 1;
|
|
4636
|
+
if (state.props.hideItemsUntilMeasured) {
|
|
4637
|
+
const isLayoutReady = state.sizesKnown.has(id) || resolveContainerItemMetadata(state, containerIndex, i, data[i]).fixedItemSize !== void 0;
|
|
4638
|
+
set$(ctx, `containerLayoutReady${containerIndex}`, isLayoutReady);
|
|
4639
|
+
}
|
|
4632
4640
|
}
|
|
4633
|
-
state.containerItemMetadata.set(
|
|
4634
|
-
containerIndex,
|
|
4635
|
-
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4636
|
-
);
|
|
4637
4641
|
set$(ctx, `containerItemKey${containerIndex}`, id);
|
|
4638
4642
|
set$(ctx, `containerItemIndex${containerIndex}`, i);
|
|
4639
4643
|
set$(ctx, `containerItemData${containerIndex}`, data[i]);
|
|
@@ -6950,6 +6954,16 @@ function checkStructuralDataChange(state, dataProp, previousData) {
|
|
|
6950
6954
|
return false;
|
|
6951
6955
|
}
|
|
6952
6956
|
|
|
6957
|
+
// src/core/containerLayoutReady.ts
|
|
6958
|
+
var CONTAINER_LAYOUT_READY_PREFIX = "containerLayoutReady";
|
|
6959
|
+
function resetContainerLayoutReady(ctx) {
|
|
6960
|
+
for (const signalName of ctx.values.keys()) {
|
|
6961
|
+
if (signalName.startsWith(CONTAINER_LAYOUT_READY_PREFIX)) {
|
|
6962
|
+
set$(ctx, signalName, void 0);
|
|
6963
|
+
}
|
|
6964
|
+
}
|
|
6965
|
+
}
|
|
6966
|
+
|
|
6953
6967
|
// src/core/doInitialAllocateContainers.ts
|
|
6954
6968
|
function doInitialAllocateContainers(ctx) {
|
|
6955
6969
|
var _a3, _b;
|
|
@@ -7840,6 +7854,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7840
7854
|
initialScrollIndex: initialScrollIndexProp,
|
|
7841
7855
|
initialScrollOffset: initialScrollOffsetProp,
|
|
7842
7856
|
experimental_adaptiveRender,
|
|
7857
|
+
experimental_hideItemsUntilMeasured,
|
|
7843
7858
|
itemsAreEqual,
|
|
7844
7859
|
keyExtractor: keyExtractorProp,
|
|
7845
7860
|
ListEmptyComponent,
|
|
@@ -8060,6 +8075,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8060
8075
|
const state = refState.current;
|
|
8061
8076
|
const isFirstLocal = state.isFirst;
|
|
8062
8077
|
const previousAdaptiveRender = state.props.adaptiveRender;
|
|
8078
|
+
const previousHideItemsUntilMeasured = state.props.hideItemsUntilMeasured;
|
|
8063
8079
|
const previousNumColumnsProp = state.props.numColumns;
|
|
8064
8080
|
const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
|
|
8065
8081
|
ctx.scrollAxisGap = nextScrollAxisGap;
|
|
@@ -8105,6 +8121,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8105
8121
|
estimatedItemSize,
|
|
8106
8122
|
getFixedItemSize: useWrapIfItem(getFixedItemSize),
|
|
8107
8123
|
getItemType: useWrapIfItem(getItemType),
|
|
8124
|
+
hideItemsUntilMeasured: experimental_hideItemsUntilMeasured,
|
|
8108
8125
|
horizontal: !!horizontal,
|
|
8109
8126
|
itemsAreEqual,
|
|
8110
8127
|
keyExtractor: useWrapIfItem(keyExtractor),
|
|
@@ -8142,6 +8159,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8142
8159
|
if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
|
|
8143
8160
|
resetAdaptiveRender(ctx);
|
|
8144
8161
|
}
|
|
8162
|
+
if (!isFirstLocal && previousHideItemsUntilMeasured && !experimental_hideItemsUntilMeasured) {
|
|
8163
|
+
resetContainerLayoutReady(ctx);
|
|
8164
|
+
}
|
|
8145
8165
|
const memoizedLastItemKeys = React3.useMemo(() => {
|
|
8146
8166
|
if (!dataProp.length) return [];
|
|
8147
8167
|
return Array.from(
|
package/react.mjs
CHANGED
|
@@ -4604,15 +4604,19 @@ function calculateItemsInView(ctx, params = {}) {
|
|
|
4604
4604
|
if (oldKey && oldKey !== id) {
|
|
4605
4605
|
containerItemKeys.delete(oldKey);
|
|
4606
4606
|
}
|
|
4607
|
+
state.containerItemMetadata.set(
|
|
4608
|
+
containerIndex,
|
|
4609
|
+
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4610
|
+
);
|
|
4607
4611
|
if (oldKey !== id) {
|
|
4608
4612
|
changedContainerIds != null ? changedContainerIds : changedContainerIds = /* @__PURE__ */ new Set();
|
|
4609
4613
|
changedContainerIds.add(containerIndex);
|
|
4610
4614
|
state.containerItemGenerations[containerIndex] = ((_p = state.containerItemGenerations[containerIndex]) != null ? _p : 0) + 1;
|
|
4615
|
+
if (state.props.hideItemsUntilMeasured) {
|
|
4616
|
+
const isLayoutReady = state.sizesKnown.has(id) || resolveContainerItemMetadata(state, containerIndex, i, data[i]).fixedItemSize !== void 0;
|
|
4617
|
+
set$(ctx, `containerLayoutReady${containerIndex}`, isLayoutReady);
|
|
4618
|
+
}
|
|
4611
4619
|
}
|
|
4612
|
-
state.containerItemMetadata.set(
|
|
4613
|
-
containerIndex,
|
|
4614
|
-
createContainerItemMetadata(state, i, data[i], allocation.itemType)
|
|
4615
|
-
);
|
|
4616
4620
|
set$(ctx, `containerItemKey${containerIndex}`, id);
|
|
4617
4621
|
set$(ctx, `containerItemIndex${containerIndex}`, i);
|
|
4618
4622
|
set$(ctx, `containerItemData${containerIndex}`, data[i]);
|
|
@@ -6929,6 +6933,16 @@ function checkStructuralDataChange(state, dataProp, previousData) {
|
|
|
6929
6933
|
return false;
|
|
6930
6934
|
}
|
|
6931
6935
|
|
|
6936
|
+
// src/core/containerLayoutReady.ts
|
|
6937
|
+
var CONTAINER_LAYOUT_READY_PREFIX = "containerLayoutReady";
|
|
6938
|
+
function resetContainerLayoutReady(ctx) {
|
|
6939
|
+
for (const signalName of ctx.values.keys()) {
|
|
6940
|
+
if (signalName.startsWith(CONTAINER_LAYOUT_READY_PREFIX)) {
|
|
6941
|
+
set$(ctx, signalName, void 0);
|
|
6942
|
+
}
|
|
6943
|
+
}
|
|
6944
|
+
}
|
|
6945
|
+
|
|
6932
6946
|
// src/core/doInitialAllocateContainers.ts
|
|
6933
6947
|
function doInitialAllocateContainers(ctx) {
|
|
6934
6948
|
var _a3, _b;
|
|
@@ -7819,6 +7833,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
7819
7833
|
initialScrollIndex: initialScrollIndexProp,
|
|
7820
7834
|
initialScrollOffset: initialScrollOffsetProp,
|
|
7821
7835
|
experimental_adaptiveRender,
|
|
7836
|
+
experimental_hideItemsUntilMeasured,
|
|
7822
7837
|
itemsAreEqual,
|
|
7823
7838
|
keyExtractor: keyExtractorProp,
|
|
7824
7839
|
ListEmptyComponent,
|
|
@@ -8039,6 +8054,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8039
8054
|
const state = refState.current;
|
|
8040
8055
|
const isFirstLocal = state.isFirst;
|
|
8041
8056
|
const previousAdaptiveRender = state.props.adaptiveRender;
|
|
8057
|
+
const previousHideItemsUntilMeasured = state.props.hideItemsUntilMeasured;
|
|
8042
8058
|
const previousNumColumnsProp = state.props.numColumns;
|
|
8043
8059
|
const didScrollAxisGapChange = !isFirstLocal && ctx.scrollAxisGap !== nextScrollAxisGap;
|
|
8044
8060
|
ctx.scrollAxisGap = nextScrollAxisGap;
|
|
@@ -8084,6 +8100,7 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8084
8100
|
estimatedItemSize,
|
|
8085
8101
|
getFixedItemSize: useWrapIfItem(getFixedItemSize),
|
|
8086
8102
|
getItemType: useWrapIfItem(getItemType),
|
|
8103
|
+
hideItemsUntilMeasured: experimental_hideItemsUntilMeasured,
|
|
8087
8104
|
horizontal: !!horizontal,
|
|
8088
8105
|
itemsAreEqual,
|
|
8089
8106
|
keyExtractor: useWrapIfItem(keyExtractor),
|
|
@@ -8121,6 +8138,9 @@ var LegendListInner = typedForwardRef(function LegendListInner2(props, forwarded
|
|
|
8121
8138
|
if (!isFirstLocal && previousAdaptiveRender && !experimental_adaptiveRender) {
|
|
8122
8139
|
resetAdaptiveRender(ctx);
|
|
8123
8140
|
}
|
|
8141
|
+
if (!isFirstLocal && previousHideItemsUntilMeasured && !experimental_hideItemsUntilMeasured) {
|
|
8142
|
+
resetContainerLayoutReady(ctx);
|
|
8143
|
+
}
|
|
8124
8144
|
const memoizedLastItemKeys = useMemo(() => {
|
|
8125
8145
|
if (!dataProp.length) return [];
|
|
8126
8146
|
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
|
*/
|