chat-layout 1.2.0-7 → 1.2.0-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/README.md +1 -1
- package/example/chat.ts +1 -1
- package/index.d.mts +14 -25
- package/index.mjs +690 -716
- package/index.mjs.map +1 -1
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -2041,6 +2041,154 @@ function createRichSourceItems(spans, defaultFont) {
|
|
|
2041
2041
|
}));
|
|
2042
2042
|
}
|
|
2043
2043
|
//#endregion
|
|
2044
|
+
//#region src/text/justify.ts
|
|
2045
|
+
let _justifySupported;
|
|
2046
|
+
function isJustifySupported(ctx) {
|
|
2047
|
+
if (_justifySupported !== void 0) return _justifySupported;
|
|
2048
|
+
_justifySupported = typeof ctx.wordSpacing === "string" && typeof ctx.letterSpacing === "string";
|
|
2049
|
+
return _justifySupported;
|
|
2050
|
+
}
|
|
2051
|
+
function resolveJustifyMode(justify) {
|
|
2052
|
+
if (justify === true) return "inter-word";
|
|
2053
|
+
if (justify === "inter-word" || justify === "inter-character") return justify;
|
|
2054
|
+
return null;
|
|
2055
|
+
}
|
|
2056
|
+
const HYBRID_WORD_SHARE_CANDIDATES = [
|
|
2057
|
+
.15,
|
|
2058
|
+
.2,
|
|
2059
|
+
.25,
|
|
2060
|
+
.3,
|
|
2061
|
+
.35,
|
|
2062
|
+
.4,
|
|
2063
|
+
.45,
|
|
2064
|
+
.5,
|
|
2065
|
+
.55,
|
|
2066
|
+
.6,
|
|
2067
|
+
.65,
|
|
2068
|
+
.7,
|
|
2069
|
+
.75,
|
|
2070
|
+
.8,
|
|
2071
|
+
.85,
|
|
2072
|
+
1,
|
|
2073
|
+
0
|
|
2074
|
+
];
|
|
2075
|
+
const PUNCTUATION_OR_SYMBOL_PATTERN = /^[\p{P}\p{S}]$/u;
|
|
2076
|
+
const JUSTIFY_SCORE_EPSILON = 1e-9;
|
|
2077
|
+
function analyzeLineForJustify(prepared, line) {
|
|
2078
|
+
let wordGapCount = 0;
|
|
2079
|
+
let wordCount = 0;
|
|
2080
|
+
let renderAtomCount = 0;
|
|
2081
|
+
let spaceCount = 0;
|
|
2082
|
+
let nonSpaceCount = 0;
|
|
2083
|
+
let cjkCount = 0;
|
|
2084
|
+
let latinLikeCount = 0;
|
|
2085
|
+
let punctuationCount = 0;
|
|
2086
|
+
let nonSpaceWidth = 0;
|
|
2087
|
+
let insideWord = false;
|
|
2088
|
+
forEachAtomInRange(prepared, line.start, line.end, (atom) => {
|
|
2089
|
+
if (atom.kind === "space" && !atom.preservesLineEnd && atom.atomicGroupId == null) wordGapCount++;
|
|
2090
|
+
renderAtomCount++;
|
|
2091
|
+
if (atom.kind === "space") {
|
|
2092
|
+
spaceCount++;
|
|
2093
|
+
insideWord = false;
|
|
2094
|
+
return;
|
|
2095
|
+
}
|
|
2096
|
+
nonSpaceCount++;
|
|
2097
|
+
nonSpaceWidth += atom.width + atom.extraWidthAfter;
|
|
2098
|
+
if (!insideWord) {
|
|
2099
|
+
wordCount++;
|
|
2100
|
+
insideWord = true;
|
|
2101
|
+
}
|
|
2102
|
+
if (isCJK(atom.text)) {
|
|
2103
|
+
cjkCount++;
|
|
2104
|
+
return;
|
|
2105
|
+
}
|
|
2106
|
+
if (PUNCTUATION_OR_SYMBOL_PATTERN.test(atom.text)) {
|
|
2107
|
+
punctuationCount++;
|
|
2108
|
+
return;
|
|
2109
|
+
}
|
|
2110
|
+
latinLikeCount++;
|
|
2111
|
+
});
|
|
2112
|
+
return {
|
|
2113
|
+
wordGapCount,
|
|
2114
|
+
wordCount,
|
|
2115
|
+
renderAtomCount,
|
|
2116
|
+
letterGapCount: Math.max(renderAtomCount - 1, 0),
|
|
2117
|
+
spaceCount,
|
|
2118
|
+
nonSpaceCount,
|
|
2119
|
+
cjkCount,
|
|
2120
|
+
latinLikeCount,
|
|
2121
|
+
punctuationCount,
|
|
2122
|
+
lineWidth: line.width,
|
|
2123
|
+
nonSpaceWidth
|
|
2124
|
+
};
|
|
2125
|
+
}
|
|
2126
|
+
function getAverageWordWidth(info) {
|
|
2127
|
+
return info.wordCount > 0 ? info.nonSpaceWidth / info.wordCount : info.lineWidth;
|
|
2128
|
+
}
|
|
2129
|
+
function getAverageCharWidth(info) {
|
|
2130
|
+
return info.renderAtomCount > 0 ? info.lineWidth / info.renderAtomCount : info.lineWidth;
|
|
2131
|
+
}
|
|
2132
|
+
function resolvePerGapSpacing(totalSpace, gapCount) {
|
|
2133
|
+
if (totalSpace === 0) return 0;
|
|
2134
|
+
if (gapCount <= 0) return null;
|
|
2135
|
+
return totalSpace / gapCount;
|
|
2136
|
+
}
|
|
2137
|
+
function exceedsThreshold(perGap, averageWidth, threshold) {
|
|
2138
|
+
if (!Number.isFinite(threshold)) return false;
|
|
2139
|
+
return perGap > threshold * averageWidth;
|
|
2140
|
+
}
|
|
2141
|
+
function createJustifySpacing(wordSpacingPx, letterSpacingPx) {
|
|
2142
|
+
return {
|
|
2143
|
+
wordSpacing: `${wordSpacingPx}px`,
|
|
2144
|
+
letterSpacing: `${letterSpacingPx}px`,
|
|
2145
|
+
wordSpacingPx,
|
|
2146
|
+
letterSpacingPx
|
|
2147
|
+
};
|
|
2148
|
+
}
|
|
2149
|
+
function computeJustifySpacing(lineWidth, maxWidth, info, mode, threshold = Number.POSITIVE_INFINITY) {
|
|
2150
|
+
const extraSpace = maxWidth - lineWidth;
|
|
2151
|
+
if (extraSpace <= 0 || mode == null) return null;
|
|
2152
|
+
if (mode === "inter-word" && info.wordGapCount > 0) {
|
|
2153
|
+
const perGap = extraSpace / info.wordGapCount;
|
|
2154
|
+
if (exceedsThreshold(perGap, Math.max(getAverageWordWidth(info), Number.EPSILON), threshold)) return null;
|
|
2155
|
+
return createJustifySpacing(perGap, 0);
|
|
2156
|
+
}
|
|
2157
|
+
if (mode !== "inter-character" || info.renderAtomCount === 0) return null;
|
|
2158
|
+
const avgCharWidth = Math.max(getAverageCharWidth(info), Number.EPSILON);
|
|
2159
|
+
if (info.wordGapCount === 0) {
|
|
2160
|
+
const perGap = resolvePerGapSpacing(extraSpace, info.letterGapCount);
|
|
2161
|
+
if (perGap == null) return null;
|
|
2162
|
+
if (exceedsThreshold(perGap, avgCharWidth, threshold)) return null;
|
|
2163
|
+
return createJustifySpacing(0, perGap);
|
|
2164
|
+
}
|
|
2165
|
+
const avgWordWidth = Math.max(getAverageWordWidth(info), Number.EPSILON);
|
|
2166
|
+
const nonSpaceCount = Math.max(info.nonSpaceCount, 1);
|
|
2167
|
+
const cjkRatio = info.cjkCount / nonSpaceCount;
|
|
2168
|
+
const latinLikeRatio = info.latinLikeCount / nonSpaceCount;
|
|
2169
|
+
const punctuationRatio = info.punctuationCount / nonSpaceCount;
|
|
2170
|
+
const wordPenalty = 1 + cjkRatio;
|
|
2171
|
+
const letterPenalty = 1 + latinLikeRatio + .5 * punctuationRatio;
|
|
2172
|
+
let bestCandidate = null;
|
|
2173
|
+
for (const wordShare of HYBRID_WORD_SHARE_CANDIDATES) {
|
|
2174
|
+
const wordExtraSpace = extraSpace * wordShare;
|
|
2175
|
+
const letterExtraSpace = extraSpace - wordExtraSpace;
|
|
2176
|
+
const wordSpacingPx = resolvePerGapSpacing(wordExtraSpace, info.wordGapCount);
|
|
2177
|
+
const letterSpacingPx = resolvePerGapSpacing(letterExtraSpace, info.letterGapCount);
|
|
2178
|
+
if (wordSpacingPx == null || letterSpacingPx == null) continue;
|
|
2179
|
+
if (exceedsThreshold(wordSpacingPx, avgWordWidth, threshold) || exceedsThreshold(letterSpacingPx, avgCharWidth, threshold)) continue;
|
|
2180
|
+
const wordRatio = wordSpacingPx / avgWordWidth;
|
|
2181
|
+
const letterRatio = letterSpacingPx / avgCharWidth;
|
|
2182
|
+
const score = wordPenalty * wordRatio ** 2 + letterPenalty * letterRatio ** 2;
|
|
2183
|
+
if (bestCandidate == null || score < bestCandidate.score - JUSTIFY_SCORE_EPSILON || Math.abs(score - bestCandidate.score) <= JUSTIFY_SCORE_EPSILON && wordShare > bestCandidate.wordShare) bestCandidate = {
|
|
2184
|
+
spacing: createJustifySpacing(wordSpacingPx, letterSpacingPx),
|
|
2185
|
+
score,
|
|
2186
|
+
wordShare
|
|
2187
|
+
};
|
|
2188
|
+
}
|
|
2189
|
+
return bestCandidate?.spacing ?? null;
|
|
2190
|
+
}
|
|
2191
|
+
//#endregion
|
|
2044
2192
|
//#region src/text/plain-core.ts
|
|
2045
2193
|
function readPreparedText(text, font, whiteSpace, wordBreak) {
|
|
2046
2194
|
return readPreparedInlineLayout(getPlainPreparedKey(text, font, whiteSpace, wordBreak), createPlainSourceItems(text, font), whiteSpace, wordBreak);
|
|
@@ -2759,174 +2907,26 @@ function layoutRichTextWithOverflow(ctx, spans, maxWidth, defaultFont, defaultCo
|
|
|
2759
2907
|
};
|
|
2760
2908
|
}
|
|
2761
2909
|
//#endregion
|
|
2762
|
-
//#region src/text
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
if (
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
if (justify === "inter-word" || justify === "inter-character") return justify;
|
|
2772
|
-
return null;
|
|
2773
|
-
}
|
|
2774
|
-
const HYBRID_WORD_SHARE_CANDIDATES = [
|
|
2775
|
-
.15,
|
|
2776
|
-
.2,
|
|
2777
|
-
.25,
|
|
2778
|
-
.3,
|
|
2779
|
-
.35,
|
|
2780
|
-
.4,
|
|
2781
|
-
.45,
|
|
2782
|
-
.5,
|
|
2783
|
-
.55,
|
|
2784
|
-
.6,
|
|
2785
|
-
.65,
|
|
2786
|
-
.7,
|
|
2787
|
-
.75,
|
|
2788
|
-
.8,
|
|
2789
|
-
.85,
|
|
2790
|
-
1,
|
|
2791
|
-
0
|
|
2792
|
-
];
|
|
2793
|
-
const PUNCTUATION_OR_SYMBOL_PATTERN = /^[\p{P}\p{S}]$/u;
|
|
2794
|
-
const JUSTIFY_SCORE_EPSILON = 1e-9;
|
|
2795
|
-
function analyzeLineForJustify(prepared, line) {
|
|
2796
|
-
let wordGapCount = 0;
|
|
2797
|
-
let wordCount = 0;
|
|
2798
|
-
let renderAtomCount = 0;
|
|
2799
|
-
let spaceCount = 0;
|
|
2800
|
-
let nonSpaceCount = 0;
|
|
2801
|
-
let cjkCount = 0;
|
|
2802
|
-
let latinLikeCount = 0;
|
|
2803
|
-
let punctuationCount = 0;
|
|
2804
|
-
let nonSpaceWidth = 0;
|
|
2805
|
-
let insideWord = false;
|
|
2806
|
-
forEachAtomInRange(prepared, line.start, line.end, (atom) => {
|
|
2807
|
-
if (atom.kind === "space" && !atom.preservesLineEnd && atom.atomicGroupId == null) wordGapCount++;
|
|
2808
|
-
renderAtomCount++;
|
|
2809
|
-
if (atom.kind === "space") {
|
|
2810
|
-
spaceCount++;
|
|
2811
|
-
insideWord = false;
|
|
2812
|
-
return;
|
|
2813
|
-
}
|
|
2814
|
-
nonSpaceCount++;
|
|
2815
|
-
nonSpaceWidth += atom.width + atom.extraWidthAfter;
|
|
2816
|
-
if (!insideWord) {
|
|
2817
|
-
wordCount++;
|
|
2818
|
-
insideWord = true;
|
|
2819
|
-
}
|
|
2820
|
-
if (isCJK(atom.text)) {
|
|
2821
|
-
cjkCount++;
|
|
2822
|
-
return;
|
|
2823
|
-
}
|
|
2824
|
-
if (PUNCTUATION_OR_SYMBOL_PATTERN.test(atom.text)) {
|
|
2825
|
-
punctuationCount++;
|
|
2826
|
-
return;
|
|
2827
|
-
}
|
|
2828
|
-
latinLikeCount++;
|
|
2829
|
-
});
|
|
2830
|
-
return {
|
|
2831
|
-
wordGapCount,
|
|
2832
|
-
wordCount,
|
|
2833
|
-
renderAtomCount,
|
|
2834
|
-
letterGapCount: Math.max(renderAtomCount - 1, 0),
|
|
2835
|
-
spaceCount,
|
|
2836
|
-
nonSpaceCount,
|
|
2837
|
-
cjkCount,
|
|
2838
|
-
latinLikeCount,
|
|
2839
|
-
punctuationCount,
|
|
2840
|
-
lineWidth: line.width,
|
|
2841
|
-
nonSpaceWidth
|
|
2842
|
-
};
|
|
2843
|
-
}
|
|
2844
|
-
function getAverageWordWidth(info) {
|
|
2845
|
-
return info.wordCount > 0 ? info.nonSpaceWidth / info.wordCount : info.lineWidth;
|
|
2910
|
+
//#region src/nodes/text.ts
|
|
2911
|
+
function resolvePhysicalTextAlign(options) {
|
|
2912
|
+
if (options.physicalAlign != null) return options.physicalAlign;
|
|
2913
|
+
if (options.align != null) switch (options.align) {
|
|
2914
|
+
case "start": return "left";
|
|
2915
|
+
case "center": return "center";
|
|
2916
|
+
case "end": return "right";
|
|
2917
|
+
}
|
|
2918
|
+
return "left";
|
|
2846
2919
|
}
|
|
2847
|
-
function
|
|
2848
|
-
|
|
2920
|
+
function normalizeTextMaxWidth(maxWidth) {
|
|
2921
|
+
if (maxWidth == null) return;
|
|
2922
|
+
return Math.max(0, maxWidth);
|
|
2849
2923
|
}
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
if (!Number.isFinite(threshold)) return false;
|
|
2857
|
-
return perGap > threshold * averageWidth;
|
|
2858
|
-
}
|
|
2859
|
-
function createJustifySpacing(wordSpacingPx, letterSpacingPx) {
|
|
2860
|
-
return {
|
|
2861
|
-
wordSpacing: `${wordSpacingPx}px`,
|
|
2862
|
-
letterSpacing: `${letterSpacingPx}px`,
|
|
2863
|
-
wordSpacingPx,
|
|
2864
|
-
letterSpacingPx
|
|
2865
|
-
};
|
|
2866
|
-
}
|
|
2867
|
-
function computeJustifySpacing(lineWidth, maxWidth, info, mode, threshold = Number.POSITIVE_INFINITY) {
|
|
2868
|
-
const extraSpace = maxWidth - lineWidth;
|
|
2869
|
-
if (extraSpace <= 0 || mode == null) return null;
|
|
2870
|
-
if (mode === "inter-word" && info.wordGapCount > 0) {
|
|
2871
|
-
const perGap = extraSpace / info.wordGapCount;
|
|
2872
|
-
if (exceedsThreshold(perGap, Math.max(getAverageWordWidth(info), Number.EPSILON), threshold)) return null;
|
|
2873
|
-
return createJustifySpacing(perGap, 0);
|
|
2874
|
-
}
|
|
2875
|
-
if (mode !== "inter-character" || info.renderAtomCount === 0) return null;
|
|
2876
|
-
const avgCharWidth = Math.max(getAverageCharWidth(info), Number.EPSILON);
|
|
2877
|
-
if (info.wordGapCount === 0) {
|
|
2878
|
-
const perGap = resolvePerGapSpacing(extraSpace, info.letterGapCount);
|
|
2879
|
-
if (perGap == null) return null;
|
|
2880
|
-
if (exceedsThreshold(perGap, avgCharWidth, threshold)) return null;
|
|
2881
|
-
return createJustifySpacing(0, perGap);
|
|
2882
|
-
}
|
|
2883
|
-
const avgWordWidth = Math.max(getAverageWordWidth(info), Number.EPSILON);
|
|
2884
|
-
const nonSpaceCount = Math.max(info.nonSpaceCount, 1);
|
|
2885
|
-
const cjkRatio = info.cjkCount / nonSpaceCount;
|
|
2886
|
-
const latinLikeRatio = info.latinLikeCount / nonSpaceCount;
|
|
2887
|
-
const punctuationRatio = info.punctuationCount / nonSpaceCount;
|
|
2888
|
-
const wordPenalty = 1 + cjkRatio;
|
|
2889
|
-
const letterPenalty = 1 + latinLikeRatio + .5 * punctuationRatio;
|
|
2890
|
-
let bestCandidate = null;
|
|
2891
|
-
for (const wordShare of HYBRID_WORD_SHARE_CANDIDATES) {
|
|
2892
|
-
const wordExtraSpace = extraSpace * wordShare;
|
|
2893
|
-
const letterExtraSpace = extraSpace - wordExtraSpace;
|
|
2894
|
-
const wordSpacingPx = resolvePerGapSpacing(wordExtraSpace, info.wordGapCount);
|
|
2895
|
-
const letterSpacingPx = resolvePerGapSpacing(letterExtraSpace, info.letterGapCount);
|
|
2896
|
-
if (wordSpacingPx == null || letterSpacingPx == null) continue;
|
|
2897
|
-
if (exceedsThreshold(wordSpacingPx, avgWordWidth, threshold) || exceedsThreshold(letterSpacingPx, avgCharWidth, threshold)) continue;
|
|
2898
|
-
const wordRatio = wordSpacingPx / avgWordWidth;
|
|
2899
|
-
const letterRatio = letterSpacingPx / avgCharWidth;
|
|
2900
|
-
const score = wordPenalty * wordRatio ** 2 + letterPenalty * letterRatio ** 2;
|
|
2901
|
-
if (bestCandidate == null || score < bestCandidate.score - JUSTIFY_SCORE_EPSILON || Math.abs(score - bestCandidate.score) <= JUSTIFY_SCORE_EPSILON && wordShare > bestCandidate.wordShare) bestCandidate = {
|
|
2902
|
-
spacing: createJustifySpacing(wordSpacingPx, letterSpacingPx),
|
|
2903
|
-
score,
|
|
2904
|
-
wordShare
|
|
2905
|
-
};
|
|
2906
|
-
}
|
|
2907
|
-
return bestCandidate?.spacing ?? null;
|
|
2908
|
-
}
|
|
2909
|
-
//#endregion
|
|
2910
|
-
//#region src/nodes/text.ts
|
|
2911
|
-
function resolvePhysicalTextAlign(options) {
|
|
2912
|
-
if (options.physicalAlign != null) return options.physicalAlign;
|
|
2913
|
-
if (options.align != null) switch (options.align) {
|
|
2914
|
-
case "start": return "left";
|
|
2915
|
-
case "center": return "center";
|
|
2916
|
-
case "end": return "right";
|
|
2917
|
-
}
|
|
2918
|
-
return "left";
|
|
2919
|
-
}
|
|
2920
|
-
function normalizeTextMaxWidth(maxWidth) {
|
|
2921
|
-
if (maxWidth == null) return;
|
|
2922
|
-
return Math.max(0, maxWidth);
|
|
2923
|
-
}
|
|
2924
|
-
const DEFAULT_TEXT_SPACING = {
|
|
2925
|
-
wordSpacing: "0px",
|
|
2926
|
-
letterSpacing: "0px"
|
|
2927
|
-
};
|
|
2928
|
-
function supportsTextSpacing(g) {
|
|
2929
|
-
return typeof g.wordSpacing === "string" && typeof g.letterSpacing === "string";
|
|
2924
|
+
const DEFAULT_TEXT_SPACING = {
|
|
2925
|
+
wordSpacing: "0px",
|
|
2926
|
+
letterSpacing: "0px"
|
|
2927
|
+
};
|
|
2928
|
+
function supportsTextSpacing(g) {
|
|
2929
|
+
return typeof g.wordSpacing === "string" && typeof g.letterSpacing === "string";
|
|
2930
2930
|
}
|
|
2931
2931
|
function withTextSpacing(g, spacing, cb) {
|
|
2932
2932
|
if (!supportsTextSpacing(g)) return cb();
|
|
@@ -3598,6 +3598,7 @@ const listStateListenerRegistry = typeof FinalizationRegistry === "function" ? n
|
|
|
3598
3598
|
}) : null;
|
|
3599
3599
|
const listScrollMutations = /* @__PURE__ */ new WeakMap();
|
|
3600
3600
|
const WRITE_LIST_SCROLL_STATE = Symbol("writeListScrollState");
|
|
3601
|
+
const FINALIZE_LIST_DELETE = Symbol("finalizeListDelete");
|
|
3601
3602
|
function normalizePosition(value) {
|
|
3602
3603
|
return typeof value === "number" && Number.isFinite(value) ? Math.trunc(value) : void 0;
|
|
3603
3604
|
}
|
|
@@ -3630,6 +3631,9 @@ function readListScrollMutation(list) {
|
|
|
3630
3631
|
function writeInternalListScrollState(list, state) {
|
|
3631
3632
|
list[WRITE_LIST_SCROLL_STATE](state, "internal");
|
|
3632
3633
|
}
|
|
3634
|
+
function finalizeInternalListDelete(list, item) {
|
|
3635
|
+
list[FINALIZE_LIST_DELETE](item);
|
|
3636
|
+
}
|
|
3633
3637
|
function deleteListStateListener(list, token) {
|
|
3634
3638
|
const listeners = listStateListeners.get(list);
|
|
3635
3639
|
if (listeners == null) return;
|
|
@@ -3706,16 +3710,10 @@ var ListState = class {
|
|
|
3706
3710
|
get offset() {
|
|
3707
3711
|
return this.#offset;
|
|
3708
3712
|
}
|
|
3709
|
-
set offset(value) {
|
|
3710
|
-
this.#writeScrollState({ offset: normalizeOffset$1(value) }, "external");
|
|
3711
|
-
}
|
|
3712
3713
|
/** Anchor item index, or `undefined` to use the renderer default. */
|
|
3713
3714
|
get position() {
|
|
3714
3715
|
return this.#position;
|
|
3715
3716
|
}
|
|
3716
|
-
set position(value) {
|
|
3717
|
-
this.#writeScrollState({ position: normalizePosition(value) }, "external");
|
|
3718
|
-
}
|
|
3719
3717
|
/** Items currently managed by the renderer. */
|
|
3720
3718
|
get items() {
|
|
3721
3719
|
return this.#items;
|
|
@@ -3798,7 +3796,7 @@ var ListState = class {
|
|
|
3798
3796
|
const normalizedAnimation = normalizeDeleteAnimation(animation);
|
|
3799
3797
|
if (!((normalizedAnimation?.duration ?? 0) > 0)) {
|
|
3800
3798
|
this.#pendingDeletes.add(item);
|
|
3801
|
-
this
|
|
3799
|
+
this[FINALIZE_LIST_DELETE](item);
|
|
3802
3800
|
return;
|
|
3803
3801
|
}
|
|
3804
3802
|
this.#pendingDeletes.add(item);
|
|
@@ -3811,7 +3809,7 @@ var ListState = class {
|
|
|
3811
3809
|
/**
|
|
3812
3810
|
* Finalizes a pending delete by removing the item from the list.
|
|
3813
3811
|
*/
|
|
3814
|
-
|
|
3812
|
+
[FINALIZE_LIST_DELETE](item) {
|
|
3815
3813
|
if (!this.#pendingDeletes.has(item)) return;
|
|
3816
3814
|
const index = this.#items.indexOf(item);
|
|
3817
3815
|
this.#pendingDeletes.delete(item);
|
|
@@ -3831,15 +3829,6 @@ var ListState = class {
|
|
|
3831
3829
|
});
|
|
3832
3830
|
}
|
|
3833
3831
|
/**
|
|
3834
|
-
* Sets the current anchor item and pixel offset.
|
|
3835
|
-
*/
|
|
3836
|
-
setAnchor(position, offset = 0) {
|
|
3837
|
-
this.#writeScrollState({
|
|
3838
|
-
position: normalizePosition(position),
|
|
3839
|
-
offset: normalizeOffset$1(offset)
|
|
3840
|
-
}, "external");
|
|
3841
|
-
}
|
|
3842
|
-
/**
|
|
3843
3832
|
* Replaces all items and clears scroll state.
|
|
3844
3833
|
*/
|
|
3845
3834
|
reset(items = []) {
|
|
@@ -3853,13 +3842,6 @@ var ListState = class {
|
|
|
3853
3842
|
}, "internal");
|
|
3854
3843
|
emitListStateChange(this, { type: "reset" });
|
|
3855
3844
|
}
|
|
3856
|
-
/** Clears the current scroll anchor while keeping the items. */
|
|
3857
|
-
resetScroll() {
|
|
3858
|
-
this.#writeScrollState({
|
|
3859
|
-
position: void 0,
|
|
3860
|
-
offset: 0
|
|
3861
|
-
}, "external");
|
|
3862
|
-
}
|
|
3863
3845
|
/** Applies a relative pixel scroll delta. */
|
|
3864
3846
|
applyScroll(delta) {
|
|
3865
3847
|
this.#writeScrollState({ offset: this.#offset + delta }, "external");
|
|
@@ -3948,7 +3930,22 @@ function memoRenderItemBy(keyOf, renderItem, options = {}) {
|
|
|
3948
3930
|
});
|
|
3949
3931
|
}
|
|
3950
3932
|
//#endregion
|
|
3951
|
-
//#region src/renderer/virtualized/
|
|
3933
|
+
//#region src/renderer/virtualized/frame-session.ts
|
|
3934
|
+
function prepareFrameSession(params) {
|
|
3935
|
+
let solution = params.resolveVisibleWindow(params.now);
|
|
3936
|
+
params.captureVisibleItemSnapshot(solution);
|
|
3937
|
+
const requestSettleRedraw = params.pruneTransitionAnimations(solution.window, params.now);
|
|
3938
|
+
if (requestSettleRedraw) {
|
|
3939
|
+
solution = params.resolveVisibleWindow(params.now);
|
|
3940
|
+
params.captureVisibleItemSnapshot(solution);
|
|
3941
|
+
}
|
|
3942
|
+
return {
|
|
3943
|
+
solution,
|
|
3944
|
+
requestSettleRedraw
|
|
3945
|
+
};
|
|
3946
|
+
}
|
|
3947
|
+
//#endregion
|
|
3948
|
+
//#region src/renderer/virtualized/virtualized-animation.ts
|
|
3952
3949
|
const CONTROLLED_STATE_OFFSET_EPSILON = 1e-9;
|
|
3953
3950
|
function clamp$1(value, min, max) {
|
|
3954
3951
|
return Math.min(Math.max(value, min), max);
|
|
@@ -4039,21 +4036,6 @@ function getNow() {
|
|
|
4039
4036
|
return globalThis.performance?.now() ?? Date.now();
|
|
4040
4037
|
}
|
|
4041
4038
|
//#endregion
|
|
4042
|
-
//#region src/renderer/virtualized/frame-session.ts
|
|
4043
|
-
function prepareFrameSession(params) {
|
|
4044
|
-
let solution = params.resolveVisibleWindow(params.now);
|
|
4045
|
-
params.captureVisibleItemSnapshot(solution);
|
|
4046
|
-
const requestSettleRedraw = params.pruneTransitionAnimations(solution.window, params.now);
|
|
4047
|
-
if (requestSettleRedraw) {
|
|
4048
|
-
solution = params.resolveVisibleWindow(params.now);
|
|
4049
|
-
params.captureVisibleItemSnapshot(solution);
|
|
4050
|
-
}
|
|
4051
|
-
return {
|
|
4052
|
-
solution,
|
|
4053
|
-
requestSettleRedraw
|
|
4054
|
-
};
|
|
4055
|
-
}
|
|
4056
|
-
//#endregion
|
|
4057
4039
|
//#region src/renderer/virtualized/jump-controller.ts
|
|
4058
4040
|
var JumpController = class JumpController {
|
|
4059
4041
|
static TRANSITION_SETTLE_SNAP_DURATION = 120;
|
|
@@ -4369,87 +4351,395 @@ var JumpController = class JumpController {
|
|
|
4369
4351
|
}
|
|
4370
4352
|
};
|
|
4371
4353
|
//#endregion
|
|
4372
|
-
//#region src/renderer/virtualized/
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
maxVisibleIndex = Math.max(maxVisibleIndex, idx);
|
|
4438
|
-
nextVisibleItems.add(item);
|
|
4439
|
-
if (y < nextTopBoundaryY) {
|
|
4440
|
-
nextTopBoundaryY = y;
|
|
4441
|
-
nextTopBoundaryItem = item;
|
|
4442
|
-
}
|
|
4443
|
-
if (y + height > nextBottomBoundaryY) {
|
|
4444
|
-
nextBottomBoundaryY = y + height;
|
|
4445
|
-
nextBottomBoundaryItem = item;
|
|
4446
|
-
}
|
|
4447
|
-
}
|
|
4354
|
+
//#region src/renderer/virtualized/solver.ts
|
|
4355
|
+
function clamp(value, min, max) {
|
|
4356
|
+
return Math.min(Math.max(value, min), max);
|
|
4357
|
+
}
|
|
4358
|
+
function normalizeOffset(offset) {
|
|
4359
|
+
return Number.isFinite(offset) ? offset : 0;
|
|
4360
|
+
}
|
|
4361
|
+
function normalizeListPadding(padding) {
|
|
4362
|
+
return {
|
|
4363
|
+
top: typeof padding?.top === "number" && Number.isFinite(padding.top) ? Math.max(0, padding.top) : 0,
|
|
4364
|
+
bottom: typeof padding?.bottom === "number" && Number.isFinite(padding.bottom) ? Math.max(0, padding.bottom) : 0
|
|
4365
|
+
};
|
|
4366
|
+
}
|
|
4367
|
+
function resolveListViewport(outerHeight, padding) {
|
|
4368
|
+
const height = typeof outerHeight === "number" && Number.isFinite(outerHeight) ? Math.max(0, outerHeight) : 0;
|
|
4369
|
+
const resolvedPadding = normalizeListPadding(padding);
|
|
4370
|
+
const contentTop = resolvedPadding.top;
|
|
4371
|
+
const contentBottom = Math.max(contentTop, height - resolvedPadding.bottom);
|
|
4372
|
+
return {
|
|
4373
|
+
outerHeight: height,
|
|
4374
|
+
contentTop,
|
|
4375
|
+
contentBottom,
|
|
4376
|
+
contentHeight: contentBottom - contentTop,
|
|
4377
|
+
outerContentTop: -contentTop,
|
|
4378
|
+
outerContentBottom: height - contentTop
|
|
4379
|
+
};
|
|
4380
|
+
}
|
|
4381
|
+
function resolveListLayoutOptions(options = {}) {
|
|
4382
|
+
return {
|
|
4383
|
+
anchorMode: options.anchorMode ?? "top",
|
|
4384
|
+
underflowAlign: options.underflowAlign ?? "top",
|
|
4385
|
+
padding: normalizeListPadding(options.padding)
|
|
4386
|
+
};
|
|
4387
|
+
}
|
|
4388
|
+
function normalizeVisibleState(itemCount, state, layout) {
|
|
4389
|
+
if (itemCount <= 0) return {
|
|
4390
|
+
position: 0,
|
|
4391
|
+
offset: 0
|
|
4392
|
+
};
|
|
4393
|
+
const position = state.position;
|
|
4394
|
+
const fallbackPosition = layout.anchorMode === "top" ? 0 : itemCount - 1;
|
|
4395
|
+
if (typeof position !== "number" || !Number.isFinite(position)) return {
|
|
4396
|
+
position: fallbackPosition,
|
|
4397
|
+
offset: normalizeOffset(state.offset)
|
|
4398
|
+
};
|
|
4399
|
+
return {
|
|
4400
|
+
position: clamp(Math.trunc(position), 0, itemCount - 1),
|
|
4401
|
+
offset: normalizeOffset(state.offset)
|
|
4402
|
+
};
|
|
4403
|
+
}
|
|
4404
|
+
function resolveVisibleWindow(items, state, viewportHeight, resolveItem, layout) {
|
|
4405
|
+
const viewport = typeof viewportHeight === "number" ? resolveListViewport(viewportHeight, layout.padding) : viewportHeight;
|
|
4406
|
+
const contentHeight = viewport.contentHeight;
|
|
4407
|
+
const normalizedState = normalizeVisibleState(items.length, state, layout);
|
|
4408
|
+
const resolutionPath = /* @__PURE__ */ new Set();
|
|
4409
|
+
const readResolvedItem = (item, idx) => {
|
|
4410
|
+
resolutionPath.add(idx);
|
|
4411
|
+
return resolveItem(item, idx);
|
|
4412
|
+
};
|
|
4413
|
+
if (items.length === 0) return {
|
|
4414
|
+
normalizedState,
|
|
4415
|
+
resolutionPath: [],
|
|
4416
|
+
window: {
|
|
4417
|
+
drawList: [],
|
|
4418
|
+
shift: 0
|
|
4448
4419
|
}
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4420
|
+
};
|
|
4421
|
+
if (layout.anchorMode === "top") {
|
|
4422
|
+
let { position, offset } = normalizedState;
|
|
4423
|
+
let drawLength = 0;
|
|
4424
|
+
if (offset > 0) if (position === 0) offset = 0;
|
|
4425
|
+
else {
|
|
4426
|
+
for (let i = position - 1; i >= 0; i -= 1) {
|
|
4427
|
+
const { height } = readResolvedItem(items[i], i);
|
|
4428
|
+
position = i;
|
|
4429
|
+
offset -= height;
|
|
4430
|
+
if (offset <= 0) break;
|
|
4431
|
+
}
|
|
4432
|
+
if (position === 0 && offset > 0) offset = 0;
|
|
4433
|
+
}
|
|
4434
|
+
let y = offset;
|
|
4435
|
+
const drawList = [];
|
|
4436
|
+
for (let i = position; i < items.length; i += 1) {
|
|
4437
|
+
const { value, height } = readResolvedItem(items[i], i);
|
|
4438
|
+
if (y + height > 0) {
|
|
4439
|
+
drawList.push({
|
|
4440
|
+
index: i,
|
|
4441
|
+
value,
|
|
4442
|
+
offset: y,
|
|
4443
|
+
height
|
|
4444
|
+
});
|
|
4445
|
+
drawLength += height;
|
|
4446
|
+
} else {
|
|
4447
|
+
offset += height;
|
|
4448
|
+
position = i + 1;
|
|
4449
|
+
}
|
|
4450
|
+
y += height;
|
|
4451
|
+
if (y >= contentHeight) break;
|
|
4452
|
+
}
|
|
4453
|
+
let shift = 0;
|
|
4454
|
+
if (y < contentHeight) {
|
|
4455
|
+
if (drawList.length > 0 && drawList.at(-1)?.index === items.length - 1 && !(drawList.at(-1)?.height > Number.EPSILON)) return finalizeVisibleWindowResult(items.length, viewport, layout, {
|
|
4456
|
+
position,
|
|
4457
|
+
offset
|
|
4458
|
+
}, Array.from(resolutionPath), extendVisibleWindowToOuterBounds(items, {
|
|
4459
|
+
drawList,
|
|
4460
|
+
shift
|
|
4461
|
+
}, viewport, readResolvedItem));
|
|
4462
|
+
if (position === 0 && drawLength < contentHeight) {
|
|
4463
|
+
shift = -offset;
|
|
4464
|
+
offset = 0;
|
|
4465
|
+
} else {
|
|
4466
|
+
shift = contentHeight - y;
|
|
4467
|
+
y = offset += shift;
|
|
4468
|
+
let lastIdx = -1;
|
|
4469
|
+
for (let i = position - 1; i >= 0; i -= 1) {
|
|
4470
|
+
const { value, height } = readResolvedItem(items[i], i);
|
|
4471
|
+
drawLength += height;
|
|
4472
|
+
y -= height;
|
|
4473
|
+
drawList.push({
|
|
4474
|
+
index: i,
|
|
4475
|
+
value,
|
|
4476
|
+
offset: y - shift,
|
|
4477
|
+
height
|
|
4478
|
+
});
|
|
4479
|
+
lastIdx = i;
|
|
4480
|
+
if (y < 0) break;
|
|
4481
|
+
}
|
|
4482
|
+
if (lastIdx === 0 && drawLength < contentHeight) {
|
|
4483
|
+
shift = drawList.at(-1)?.offset == null ? 0 : -drawList.at(-1).offset;
|
|
4484
|
+
position = 0;
|
|
4485
|
+
offset = 0;
|
|
4486
|
+
}
|
|
4487
|
+
}
|
|
4488
|
+
}
|
|
4489
|
+
return finalizeVisibleWindowResult(items.length, viewport, layout, {
|
|
4490
|
+
position,
|
|
4491
|
+
offset
|
|
4492
|
+
}, Array.from(resolutionPath), extendVisibleWindowToOuterBounds(items, {
|
|
4493
|
+
drawList,
|
|
4494
|
+
shift
|
|
4495
|
+
}, viewport, readResolvedItem));
|
|
4496
|
+
}
|
|
4497
|
+
let { position, offset } = normalizedState;
|
|
4498
|
+
let drawLength = 0;
|
|
4499
|
+
if (offset < 0) if (position === items.length - 1) offset = 0;
|
|
4500
|
+
else for (let i = position + 1; i < items.length; i += 1) {
|
|
4501
|
+
const { height } = readResolvedItem(items[i], i);
|
|
4502
|
+
position = i;
|
|
4503
|
+
offset += height;
|
|
4504
|
+
if (offset > 0) break;
|
|
4505
|
+
}
|
|
4506
|
+
let y = contentHeight + offset;
|
|
4507
|
+
const drawList = [];
|
|
4508
|
+
for (let i = position; i >= 0; i -= 1) {
|
|
4509
|
+
const { value, height } = readResolvedItem(items[i], i);
|
|
4510
|
+
y -= height;
|
|
4511
|
+
if (y <= contentHeight) {
|
|
4512
|
+
drawList.push({
|
|
4513
|
+
index: i,
|
|
4514
|
+
value,
|
|
4515
|
+
offset: y,
|
|
4516
|
+
height
|
|
4517
|
+
});
|
|
4518
|
+
drawLength += height;
|
|
4519
|
+
} else {
|
|
4520
|
+
offset -= height;
|
|
4521
|
+
position = i - 1;
|
|
4522
|
+
}
|
|
4523
|
+
if (y < 0) break;
|
|
4524
|
+
}
|
|
4525
|
+
let shift = 0;
|
|
4526
|
+
if (y > 0) {
|
|
4527
|
+
shift = -y;
|
|
4528
|
+
if (drawLength < contentHeight) {
|
|
4529
|
+
y = drawLength;
|
|
4530
|
+
for (let i = position + 1; i < items.length; i += 1) {
|
|
4531
|
+
const { value, height } = readResolvedItem(items[i], i);
|
|
4532
|
+
drawList.push({
|
|
4533
|
+
index: i,
|
|
4534
|
+
value,
|
|
4535
|
+
offset: y - shift,
|
|
4536
|
+
height
|
|
4537
|
+
});
|
|
4538
|
+
y = drawLength += height;
|
|
4539
|
+
if (height > Number.EPSILON) position = i;
|
|
4540
|
+
if (y >= contentHeight) break;
|
|
4541
|
+
}
|
|
4542
|
+
offset = drawLength < contentHeight ? 0 : drawLength - contentHeight;
|
|
4543
|
+
} else offset = drawLength - contentHeight;
|
|
4544
|
+
}
|
|
4545
|
+
return finalizeVisibleWindowResult(items.length, viewport, layout, {
|
|
4546
|
+
position,
|
|
4547
|
+
offset
|
|
4548
|
+
}, Array.from(resolutionPath), extendVisibleWindowToOuterBounds(items, {
|
|
4549
|
+
drawList,
|
|
4550
|
+
shift
|
|
4551
|
+
}, viewport, readResolvedItem));
|
|
4552
|
+
}
|
|
4553
|
+
function finalizeVisibleWindowResult(itemCount, viewport, layout, normalizedState, resolutionPath, window) {
|
|
4554
|
+
const viewportHeight = viewport.contentHeight;
|
|
4555
|
+
if (window.drawList.length !== itemCount || itemCount <= 0) return {
|
|
4556
|
+
normalizedState,
|
|
4557
|
+
resolutionPath,
|
|
4558
|
+
window
|
|
4559
|
+
};
|
|
4560
|
+
let minIndex = Number.POSITIVE_INFINITY;
|
|
4561
|
+
let maxIndex = Number.NEGATIVE_INFINITY;
|
|
4562
|
+
let minOffset = Number.POSITIVE_INFINITY;
|
|
4563
|
+
let maxBottom = Number.NEGATIVE_INFINITY;
|
|
4564
|
+
let hasDeferredSlots = false;
|
|
4565
|
+
for (const entry of window.drawList) {
|
|
4566
|
+
if (!(entry.height > Number.EPSILON)) hasDeferredSlots = true;
|
|
4567
|
+
else {
|
|
4568
|
+
minOffset = Math.min(minOffset, entry.offset);
|
|
4569
|
+
maxBottom = Math.max(maxBottom, entry.offset + entry.height);
|
|
4570
|
+
}
|
|
4571
|
+
minIndex = Math.min(minIndex, entry.index);
|
|
4572
|
+
maxIndex = Math.max(maxIndex, entry.index);
|
|
4573
|
+
}
|
|
4574
|
+
if (!Number.isFinite(minOffset) || !Number.isFinite(maxBottom)) return {
|
|
4575
|
+
normalizedState,
|
|
4576
|
+
resolutionPath,
|
|
4577
|
+
window
|
|
4578
|
+
};
|
|
4579
|
+
const contentHeight = maxBottom - minOffset;
|
|
4580
|
+
if (minIndex !== 0 || maxIndex !== itemCount - 1 || !(contentHeight < viewportHeight - Number.EPSILON)) return {
|
|
4581
|
+
normalizedState,
|
|
4582
|
+
resolutionPath,
|
|
4583
|
+
window
|
|
4584
|
+
};
|
|
4585
|
+
const desiredTop = layout.underflowAlign === "bottom" ? viewportHeight - contentHeight : 0;
|
|
4586
|
+
return {
|
|
4587
|
+
normalizedState: hasDeferredSlots ? normalizedState : layout.anchorMode === "top" ? {
|
|
4588
|
+
position: 0,
|
|
4589
|
+
offset: 0
|
|
4590
|
+
} : {
|
|
4591
|
+
position: itemCount - 1,
|
|
4592
|
+
offset: 0
|
|
4593
|
+
},
|
|
4594
|
+
resolutionPath,
|
|
4595
|
+
window: {
|
|
4596
|
+
drawList: window.drawList,
|
|
4597
|
+
shift: desiredTop - minOffset
|
|
4598
|
+
}
|
|
4599
|
+
};
|
|
4600
|
+
}
|
|
4601
|
+
function extendVisibleWindowToOuterBounds(items, window, viewport, resolveItem) {
|
|
4602
|
+
if (window.drawList.length === 0 || items.length === 0) return window;
|
|
4603
|
+
const drawList = [...window.drawList];
|
|
4604
|
+
const existingIndices = new Set(drawList.map((entry) => entry.index));
|
|
4605
|
+
let topEntry = drawList[0];
|
|
4606
|
+
let bottomEntry = drawList[0];
|
|
4607
|
+
for (const entry of drawList) {
|
|
4608
|
+
if (entry.offset < topEntry.offset) topEntry = entry;
|
|
4609
|
+
if (entry.offset + entry.height > bottomEntry.offset + bottomEntry.height) bottomEntry = entry;
|
|
4610
|
+
}
|
|
4611
|
+
let topIdx = topEntry.index;
|
|
4612
|
+
let topY = topEntry.offset + window.shift;
|
|
4613
|
+
while (topIdx > 0) {
|
|
4614
|
+
const prevIdx = topIdx - 1;
|
|
4615
|
+
if (existingIndices.has(prevIdx)) {
|
|
4616
|
+
const existing = drawList.find((entry) => entry.index === prevIdx);
|
|
4617
|
+
topIdx = prevIdx;
|
|
4618
|
+
if (existing != null) topY = existing.offset + window.shift;
|
|
4619
|
+
continue;
|
|
4620
|
+
}
|
|
4621
|
+
const { value, height } = resolveItem(items[prevIdx], prevIdx);
|
|
4622
|
+
const prevY = topY - height;
|
|
4623
|
+
if (prevY + height <= viewport.outerContentTop) break;
|
|
4624
|
+
drawList.push({
|
|
4625
|
+
index: prevIdx,
|
|
4626
|
+
value,
|
|
4627
|
+
offset: prevY - window.shift,
|
|
4628
|
+
height
|
|
4629
|
+
});
|
|
4630
|
+
existingIndices.add(prevIdx);
|
|
4631
|
+
topIdx = prevIdx;
|
|
4632
|
+
topY = prevY;
|
|
4633
|
+
}
|
|
4634
|
+
let bottomIdx = bottomEntry.index;
|
|
4635
|
+
let bottomY = bottomEntry.offset + window.shift + bottomEntry.height;
|
|
4636
|
+
while (bottomIdx < items.length - 1) {
|
|
4637
|
+
const nextIdx = bottomIdx + 1;
|
|
4638
|
+
if (existingIndices.has(nextIdx)) {
|
|
4639
|
+
const existing = drawList.find((entry) => entry.index === nextIdx);
|
|
4640
|
+
bottomIdx = nextIdx;
|
|
4641
|
+
if (existing != null) bottomY = Math.max(bottomY, existing.offset + window.shift + existing.height);
|
|
4642
|
+
continue;
|
|
4643
|
+
}
|
|
4644
|
+
const { value, height } = resolveItem(items[nextIdx], nextIdx);
|
|
4645
|
+
if (bottomY >= viewport.outerContentBottom) break;
|
|
4646
|
+
drawList.push({
|
|
4647
|
+
index: nextIdx,
|
|
4648
|
+
value,
|
|
4649
|
+
offset: bottomY - window.shift,
|
|
4650
|
+
height
|
|
4651
|
+
});
|
|
4652
|
+
existingIndices.add(nextIdx);
|
|
4653
|
+
bottomIdx = nextIdx;
|
|
4654
|
+
bottomY += height;
|
|
4655
|
+
}
|
|
4656
|
+
return {
|
|
4657
|
+
drawList,
|
|
4658
|
+
shift: window.shift
|
|
4659
|
+
};
|
|
4660
|
+
}
|
|
4661
|
+
//#endregion
|
|
4662
|
+
//#region src/renderer/virtualized/transition-snapshot.ts
|
|
4663
|
+
var VisibilitySnapshot = class {
|
|
4664
|
+
#drawnItems = /* @__PURE__ */ new Set();
|
|
4665
|
+
#visibleItems = /* @__PURE__ */ new Set();
|
|
4666
|
+
#previousVisibleItems = /* @__PURE__ */ new Set();
|
|
4667
|
+
#hasSnapshot = false;
|
|
4668
|
+
#snapshotState;
|
|
4669
|
+
#previousSnapshotState;
|
|
4670
|
+
#emptyState;
|
|
4671
|
+
#coversShortList = false;
|
|
4672
|
+
#atStartBoundary = false;
|
|
4673
|
+
#atEndBoundary = false;
|
|
4674
|
+
#minDrawnIndex = Number.POSITIVE_INFINITY;
|
|
4675
|
+
#maxDrawnIndex = Number.NEGATIVE_INFINITY;
|
|
4676
|
+
#topBoundaryItem;
|
|
4677
|
+
#bottomBoundaryItem;
|
|
4678
|
+
get coversShortList() {
|
|
4679
|
+
return this.#hasSnapshot && this.#snapshotState != null && this.#coversShortList;
|
|
4680
|
+
}
|
|
4681
|
+
get hasSnapshot() {
|
|
4682
|
+
return this.#hasSnapshot;
|
|
4683
|
+
}
|
|
4684
|
+
get previousState() {
|
|
4685
|
+
return this.#previousSnapshotState;
|
|
4686
|
+
}
|
|
4687
|
+
readDrawnIndexRange() {
|
|
4688
|
+
if (!Number.isFinite(this.#minDrawnIndex) || !Number.isFinite(this.#maxDrawnIndex)) return;
|
|
4689
|
+
return {
|
|
4690
|
+
minIndex: this.#minDrawnIndex,
|
|
4691
|
+
maxIndex: this.#maxDrawnIndex
|
|
4692
|
+
};
|
|
4693
|
+
}
|
|
4694
|
+
readBoundaryItem(boundary) {
|
|
4695
|
+
return boundary === "top" ? this.#topBoundaryItem : this.#bottomBoundaryItem;
|
|
4696
|
+
}
|
|
4697
|
+
capture(window, _resolutionPath, items, viewport, snapshotState, readVisibleRange, readOuterVisibleRange) {
|
|
4698
|
+
this.#previousVisibleItems = this.#visibleItems;
|
|
4699
|
+
this.#previousSnapshotState = this.#snapshotState;
|
|
4700
|
+
const nextDrawnItems = /* @__PURE__ */ new Set();
|
|
4701
|
+
const nextVisibleItems = /* @__PURE__ */ new Set();
|
|
4702
|
+
let minVisibleIndex = Number.POSITIVE_INFINITY;
|
|
4703
|
+
let maxVisibleIndex = Number.NEGATIVE_INFINITY;
|
|
4704
|
+
let topMostY = Number.POSITIVE_INFINITY;
|
|
4705
|
+
let bottomMostY = Number.NEGATIVE_INFINITY;
|
|
4706
|
+
let nextMinDrawnIndex = Number.POSITIVE_INFINITY;
|
|
4707
|
+
let nextMaxDrawnIndex = Number.NEGATIVE_INFINITY;
|
|
4708
|
+
let nextTopBoundaryItem;
|
|
4709
|
+
let nextBottomBoundaryItem;
|
|
4710
|
+
let nextTopBoundaryY = Number.POSITIVE_INFINITY;
|
|
4711
|
+
let nextBottomBoundaryY = Number.NEGATIVE_INFINITY;
|
|
4712
|
+
const effectiveShift = window.shift;
|
|
4713
|
+
const contentOriginY = viewport.contentTop;
|
|
4714
|
+
for (const { index, offset, height } of window.drawList) {
|
|
4715
|
+
const y = offset + effectiveShift + contentOriginY;
|
|
4716
|
+
topMostY = Math.min(topMostY, y);
|
|
4717
|
+
bottomMostY = Math.max(bottomMostY, y + height);
|
|
4718
|
+
const item = items[index];
|
|
4719
|
+
if (item != null && readOuterVisibleRange(y, height) != null) {
|
|
4720
|
+
nextDrawnItems.add(item);
|
|
4721
|
+
nextMinDrawnIndex = Math.min(nextMinDrawnIndex, index);
|
|
4722
|
+
nextMaxDrawnIndex = Math.max(nextMaxDrawnIndex, index);
|
|
4723
|
+
}
|
|
4724
|
+
if (item == null) continue;
|
|
4725
|
+
if (readVisibleRange(y, height) != null) {
|
|
4726
|
+
minVisibleIndex = Math.min(minVisibleIndex, index);
|
|
4727
|
+
maxVisibleIndex = Math.max(maxVisibleIndex, index);
|
|
4728
|
+
nextVisibleItems.add(item);
|
|
4729
|
+
if (y < nextTopBoundaryY) {
|
|
4730
|
+
nextTopBoundaryY = y;
|
|
4731
|
+
nextTopBoundaryItem = item;
|
|
4732
|
+
}
|
|
4733
|
+
if (y + height > nextBottomBoundaryY) {
|
|
4734
|
+
nextBottomBoundaryY = y + height;
|
|
4735
|
+
nextBottomBoundaryItem = item;
|
|
4736
|
+
}
|
|
4737
|
+
}
|
|
4738
|
+
}
|
|
4739
|
+
this.#drawnItems = nextDrawnItems;
|
|
4740
|
+
this.#visibleItems = nextVisibleItems;
|
|
4741
|
+
this.#hasSnapshot = true;
|
|
4742
|
+
this.#snapshotState = snapshotState;
|
|
4453
4743
|
this.#minDrawnIndex = nextMinDrawnIndex;
|
|
4454
4744
|
this.#maxDrawnIndex = nextMaxDrawnIndex;
|
|
4455
4745
|
this.#topBoundaryItem = nextTopBoundaryItem;
|
|
@@ -4588,7 +4878,7 @@ function findVisibleEntry(index, resolveVisibleWindow, readVisibleRange) {
|
|
|
4588
4878
|
if (index < 0) return;
|
|
4589
4879
|
const solution = resolveVisibleWindow();
|
|
4590
4880
|
for (const entry of solution.window.drawList) {
|
|
4591
|
-
if (entry.
|
|
4881
|
+
if (entry.index !== index) continue;
|
|
4592
4882
|
if (readVisibleRange(entry.offset + solution.window.shift, entry.height) != null) return entry;
|
|
4593
4883
|
}
|
|
4594
4884
|
}
|
|
@@ -4606,7 +4896,7 @@ function hasVisibleBoundaryInsertItems(direction, count, ctx) {
|
|
|
4606
4896
|
const end = direction === "push" ? ctx.items.length : Math.min(count, ctx.items.length);
|
|
4607
4897
|
if (start < 0 || end <= start) return false;
|
|
4608
4898
|
const solution = ctx.resolveVisibleWindow();
|
|
4609
|
-
return solution.window.drawList.some((entry) => entry.
|
|
4899
|
+
return solution.window.drawList.some((entry) => entry.index >= start && entry.index < end && ctx.readOuterVisibleRange(entry.offset + solution.window.shift, entry.height) != null);
|
|
4610
4900
|
}
|
|
4611
4901
|
function sampleScalarAnimation(animation, now) {
|
|
4612
4902
|
return interpolate(animation.from, animation.to, animation.startTime, animation.duration, now);
|
|
@@ -4851,432 +5141,124 @@ function handleTransitionStateChange(store, snapshot, change, ctx, lifecycle) {
|
|
|
4851
5141
|
const boundaryItem = snapshot.readBoundaryItem(boundary);
|
|
4852
5142
|
if (boundaryItem != null) lifecycle.snapItemToViewportBoundary(boundaryItem, boundary);
|
|
4853
5143
|
}
|
|
4854
|
-
return;
|
|
4855
|
-
}
|
|
4856
|
-
case "reset":
|
|
4857
|
-
case "set":
|
|
4858
|
-
store.reset();
|
|
4859
|
-
snapshot.reset();
|
|
4860
|
-
return;
|
|
4861
|
-
}
|
|
4862
|
-
}
|
|
4863
|
-
//#endregion
|
|
4864
|
-
//#region src/renderer/virtualized/base-transition.ts
|
|
4865
|
-
function remapAnchorAfterDeletes(anchor, deletedIndices) {
|
|
4866
|
-
if (!Number.isFinite(anchor) || deletedIndices.length === 0) return anchor;
|
|
4867
|
-
const sortedIndices = [...deletedIndices].filter((index) => Number.isFinite(index) && index >= 0).sort((a, b) => a - b);
|
|
4868
|
-
let removedBeforeAnchor = 0;
|
|
4869
|
-
for (const index of sortedIndices) {
|
|
4870
|
-
if (anchor > index + 1) {
|
|
4871
|
-
removedBeforeAnchor += 1;
|
|
4872
|
-
continue;
|
|
4873
|
-
}
|
|
4874
|
-
if (anchor >= index) return index - removedBeforeAnchor;
|
|
4875
|
-
}
|
|
4876
|
-
return anchor - removedBeforeAnchor;
|
|
4877
|
-
}
|
|
4878
|
-
var TransitionController = class {
|
|
4879
|
-
#store = new TransitionStore();
|
|
4880
|
-
#snapshot = new VisibilitySnapshot();
|
|
4881
|
-
captureVisibilitySnapshot(window, resolutionPath, items, viewport, snapshotState, readVisibleRange, readOuterVisibleRange) {
|
|
4882
|
-
this.#snapshot.capture(window, resolutionPath, items, viewport, snapshotState, readVisibleRange, readOuterVisibleRange);
|
|
4883
|
-
}
|
|
4884
|
-
pruneInvisible(ctx, lifecycle) {
|
|
4885
|
-
return this.pruneInvisibleAt(getNow(), ctx, lifecycle);
|
|
4886
|
-
}
|
|
4887
|
-
prepare(now, lifecycle) {
|
|
4888
|
-
this.settle(now, lifecycle);
|
|
4889
|
-
return this.#store.prepare(now);
|
|
4890
|
-
}
|
|
4891
|
-
canAutoFollowBoundaryInsert(direction, count, position, offset) {
|
|
4892
|
-
return this.#snapshot.matchesFollowBoundaryInsertState(direction, count, position, offset);
|
|
4893
|
-
}
|
|
4894
|
-
getItemHeight(item, now, adapter) {
|
|
4895
|
-
return getTransitionedItemHeight(item, now, this.#store, adapter);
|
|
4896
|
-
}
|
|
4897
|
-
resolveItem(item, now, adapter, lifecycle) {
|
|
4898
|
-
return resolveTransitionedItem(item, now, this.#store, adapter, lifecycle);
|
|
4899
|
-
}
|
|
4900
|
-
handleListStateChange(change, ctx, lifecycle) {
|
|
4901
|
-
const now = getNow();
|
|
4902
|
-
this.settle(now, lifecycle);
|
|
4903
|
-
handleTransitionStateChange(this.#store, this.#snapshot, change, ctx, lifecycle);
|
|
4904
|
-
}
|
|
4905
|
-
settle(now, lifecycle) {
|
|
4906
|
-
return this.#settleTransitions(this.#store.findCompleted(now), now, lifecycle);
|
|
4907
|
-
}
|
|
4908
|
-
pruneInvisibleAt(now, ctx, lifecycle) {
|
|
4909
|
-
const removals = this.#store.findInvisible(this.#snapshot);
|
|
4910
|
-
return this.#settleTransitions(removals, now, lifecycle, this.#resolveNaturalBoundarySnap(removals, now, ctx, lifecycle));
|
|
4911
|
-
}
|
|
4912
|
-
reset() {
|
|
4913
|
-
this.#store.reset();
|
|
4914
|
-
this.#snapshot.reset();
|
|
4915
|
-
}
|
|
4916
|
-
#settleTransitions(removals, now, lifecycle, boundarySnap) {
|
|
4917
|
-
if (removals.length === 0) return false;
|
|
4918
|
-
const anchor = lifecycle.captureVisualAnchor(now);
|
|
4919
|
-
const beforeState = lifecycle.readScrollState();
|
|
4920
|
-
const completedDeleteIndices = [];
|
|
4921
|
-
for (const { item, transition } of removals) {
|
|
4922
|
-
if (transition.kind === "delete") {
|
|
4923
|
-
const index = lifecycle.readItemIndex(item);
|
|
4924
|
-
if (index >= 0) completedDeleteIndices.push(index);
|
|
4925
|
-
}
|
|
4926
|
-
this.#store.delete(item);
|
|
4927
|
-
if (transition.kind === "delete") lifecycle.onDeleteComplete(item);
|
|
4928
|
-
}
|
|
4929
|
-
if (anchor != null && Number.isFinite(anchor)) lifecycle.restoreVisualAnchor(remapAnchorAfterDeletes(anchor, completedDeleteIndices));
|
|
4930
|
-
if (boundarySnap != null) lifecycle.snapItemToViewportBoundary(boundarySnap.item, boundarySnap.boundary);
|
|
4931
|
-
const afterState = lifecycle.readScrollState();
|
|
4932
|
-
if (!sameState(beforeState, afterState.position, afterState.offset)) lifecycle.onTransitionSettleScrollAdjusted();
|
|
4933
|
-
return true;
|
|
4934
|
-
}
|
|
4935
|
-
#resolveNaturalBoundarySnap(removals, now, ctx, lifecycle) {
|
|
4936
|
-
const previousState = this.#snapshot.previousState;
|
|
4937
|
-
const drawnRange = this.#snapshot.readDrawnIndexRange();
|
|
4938
|
-
if (previousState == null || drawnRange == null) return;
|
|
4939
|
-
const naturalIndices = [];
|
|
4940
|
-
for (const { item, transition } of removals) {
|
|
4941
|
-
if (transition.kind !== "update" && transition.kind !== "delete") continue;
|
|
4942
|
-
const index = lifecycle.readItemIndex(item);
|
|
4943
|
-
if (index < 0 || !this.#snapshot.wasVisible(item)) return;
|
|
4944
|
-
if (this.#isTransitionVisibleInState(index, previousState, now, ctx)) return;
|
|
4945
|
-
naturalIndices.push(index);
|
|
4946
|
-
}
|
|
4947
|
-
if (naturalIndices.length === 0) return;
|
|
4948
|
-
if (naturalIndices.every((index) => index < drawnRange.minIndex)) {
|
|
4949
|
-
const item = this.#snapshot.readBoundaryItem("top");
|
|
4950
|
-
return item == null ? void 0 : {
|
|
4951
|
-
item,
|
|
4952
|
-
boundary: "top"
|
|
4953
|
-
};
|
|
4954
|
-
}
|
|
4955
|
-
if (naturalIndices.every((index) => index > drawnRange.maxIndex)) {
|
|
4956
|
-
const item = this.#snapshot.readBoundaryItem("bottom");
|
|
4957
|
-
return item == null ? void 0 : {
|
|
4958
|
-
item,
|
|
4959
|
-
boundary: "bottom"
|
|
4960
|
-
};
|
|
4961
|
-
}
|
|
4962
|
-
}
|
|
4963
|
-
#isTransitionVisibleInState(index, state, now, ctx) {
|
|
4964
|
-
const solution = ctx.resolveVisibleWindowForState(state, now);
|
|
4965
|
-
for (const entry of solution.window.drawList) {
|
|
4966
|
-
if (entry.idx !== index) continue;
|
|
4967
|
-
return ctx.readOuterVisibleRange(entry.offset + solution.window.shift, entry.height) != null;
|
|
4968
|
-
}
|
|
4969
|
-
return false;
|
|
4970
|
-
}
|
|
4971
|
-
};
|
|
4972
|
-
//#endregion
|
|
4973
|
-
//#region src/renderer/virtualized/solver.ts
|
|
4974
|
-
function clamp(value, min, max) {
|
|
4975
|
-
return Math.min(Math.max(value, min), max);
|
|
4976
|
-
}
|
|
4977
|
-
function normalizeOffset(offset) {
|
|
4978
|
-
return Number.isFinite(offset) ? offset : 0;
|
|
4979
|
-
}
|
|
4980
|
-
function normalizeListPadding(padding) {
|
|
4981
|
-
return {
|
|
4982
|
-
top: typeof padding?.top === "number" && Number.isFinite(padding.top) ? Math.max(0, padding.top) : 0,
|
|
4983
|
-
bottom: typeof padding?.bottom === "number" && Number.isFinite(padding.bottom) ? Math.max(0, padding.bottom) : 0
|
|
4984
|
-
};
|
|
4985
|
-
}
|
|
4986
|
-
function resolveListViewport(outerHeight, padding) {
|
|
4987
|
-
const height = typeof outerHeight === "number" && Number.isFinite(outerHeight) ? Math.max(0, outerHeight) : 0;
|
|
4988
|
-
const resolvedPadding = normalizeListPadding(padding);
|
|
4989
|
-
const contentTop = resolvedPadding.top;
|
|
4990
|
-
const contentBottom = Math.max(contentTop, height - resolvedPadding.bottom);
|
|
4991
|
-
return {
|
|
4992
|
-
outerHeight: height,
|
|
4993
|
-
contentTop,
|
|
4994
|
-
contentBottom,
|
|
4995
|
-
contentHeight: contentBottom - contentTop,
|
|
4996
|
-
outerContentTop: -contentTop,
|
|
4997
|
-
outerContentBottom: height - contentTop
|
|
4998
|
-
};
|
|
4999
|
-
}
|
|
5000
|
-
function resolveListLayoutOptions(options = {}) {
|
|
5001
|
-
return {
|
|
5002
|
-
anchorMode: options.anchorMode ?? "top",
|
|
5003
|
-
underflowAlign: options.underflowAlign ?? "top",
|
|
5004
|
-
padding: normalizeListPadding(options.padding)
|
|
5005
|
-
};
|
|
5006
|
-
}
|
|
5007
|
-
function normalizeVisibleState(itemCount, state, layout) {
|
|
5008
|
-
if (itemCount <= 0) return {
|
|
5009
|
-
position: 0,
|
|
5010
|
-
offset: 0
|
|
5011
|
-
};
|
|
5012
|
-
const position = state.position;
|
|
5013
|
-
const fallbackPosition = layout.anchorMode === "top" ? 0 : itemCount - 1;
|
|
5014
|
-
if (typeof position !== "number" || !Number.isFinite(position)) return {
|
|
5015
|
-
position: fallbackPosition,
|
|
5016
|
-
offset: normalizeOffset(state.offset)
|
|
5017
|
-
};
|
|
5018
|
-
return {
|
|
5019
|
-
position: clamp(Math.trunc(position), 0, itemCount - 1),
|
|
5020
|
-
offset: normalizeOffset(state.offset)
|
|
5021
|
-
};
|
|
5022
|
-
}
|
|
5023
|
-
function resolveVisibleWindow(items, state, viewportHeight, resolveItem, layout) {
|
|
5024
|
-
const viewport = typeof viewportHeight === "number" ? resolveListViewport(viewportHeight, layout.padding) : viewportHeight;
|
|
5025
|
-
const contentHeight = viewport.contentHeight;
|
|
5026
|
-
const normalizedState = normalizeVisibleState(items.length, state, layout);
|
|
5027
|
-
const resolutionPath = /* @__PURE__ */ new Set();
|
|
5028
|
-
const readResolvedItem = (item, idx) => {
|
|
5029
|
-
resolutionPath.add(idx);
|
|
5030
|
-
return resolveItem(item, idx);
|
|
5031
|
-
};
|
|
5032
|
-
if (items.length === 0) return {
|
|
5033
|
-
normalizedState,
|
|
5034
|
-
resolutionPath: [],
|
|
5035
|
-
window: {
|
|
5036
|
-
drawList: [],
|
|
5037
|
-
shift: 0
|
|
5038
|
-
}
|
|
5039
|
-
};
|
|
5040
|
-
if (layout.anchorMode === "top") {
|
|
5041
|
-
let { position, offset } = normalizedState;
|
|
5042
|
-
let drawLength = 0;
|
|
5043
|
-
if (offset > 0) if (position === 0) offset = 0;
|
|
5044
|
-
else {
|
|
5045
|
-
for (let i = position - 1; i >= 0; i -= 1) {
|
|
5046
|
-
const { height } = readResolvedItem(items[i], i);
|
|
5047
|
-
position = i;
|
|
5048
|
-
offset -= height;
|
|
5049
|
-
if (offset <= 0) break;
|
|
5050
|
-
}
|
|
5051
|
-
if (position === 0 && offset > 0) offset = 0;
|
|
5052
|
-
}
|
|
5053
|
-
let y = offset;
|
|
5054
|
-
const drawList = [];
|
|
5055
|
-
for (let i = position; i < items.length; i += 1) {
|
|
5056
|
-
const { value, height } = readResolvedItem(items[i], i);
|
|
5057
|
-
if (y + height > 0) {
|
|
5058
|
-
drawList.push({
|
|
5059
|
-
idx: i,
|
|
5060
|
-
value,
|
|
5061
|
-
offset: y,
|
|
5062
|
-
height
|
|
5063
|
-
});
|
|
5064
|
-
drawLength += height;
|
|
5065
|
-
} else {
|
|
5066
|
-
offset += height;
|
|
5067
|
-
position = i + 1;
|
|
5068
|
-
}
|
|
5069
|
-
y += height;
|
|
5070
|
-
if (y >= contentHeight) break;
|
|
5071
|
-
}
|
|
5072
|
-
let shift = 0;
|
|
5073
|
-
if (y < contentHeight) {
|
|
5074
|
-
if (drawList.length > 0 && drawList.at(-1)?.idx === items.length - 1 && !(drawList.at(-1)?.height > Number.EPSILON)) return finalizeVisibleWindowResult(items.length, viewport, layout, {
|
|
5075
|
-
position,
|
|
5076
|
-
offset
|
|
5077
|
-
}, Array.from(resolutionPath), extendVisibleWindowToOuterBounds(items, {
|
|
5078
|
-
drawList,
|
|
5079
|
-
shift
|
|
5080
|
-
}, viewport, readResolvedItem));
|
|
5081
|
-
if (position === 0 && drawLength < contentHeight) {
|
|
5082
|
-
shift = -offset;
|
|
5083
|
-
offset = 0;
|
|
5084
|
-
} else {
|
|
5085
|
-
shift = contentHeight - y;
|
|
5086
|
-
y = offset += shift;
|
|
5087
|
-
let lastIdx = -1;
|
|
5088
|
-
for (let i = position - 1; i >= 0; i -= 1) {
|
|
5089
|
-
const { value, height } = readResolvedItem(items[i], i);
|
|
5090
|
-
drawLength += height;
|
|
5091
|
-
y -= height;
|
|
5092
|
-
drawList.push({
|
|
5093
|
-
idx: i,
|
|
5094
|
-
value,
|
|
5095
|
-
offset: y - shift,
|
|
5096
|
-
height
|
|
5097
|
-
});
|
|
5098
|
-
lastIdx = i;
|
|
5099
|
-
if (y < 0) break;
|
|
5100
|
-
}
|
|
5101
|
-
if (lastIdx === 0 && drawLength < contentHeight) {
|
|
5102
|
-
shift = drawList.at(-1)?.offset == null ? 0 : -drawList.at(-1).offset;
|
|
5103
|
-
position = 0;
|
|
5104
|
-
offset = 0;
|
|
5105
|
-
}
|
|
5106
|
-
}
|
|
5144
|
+
return;
|
|
5107
5145
|
}
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
shift
|
|
5114
|
-
}, viewport, readResolvedItem));
|
|
5115
|
-
}
|
|
5116
|
-
let { position, offset } = normalizedState;
|
|
5117
|
-
let drawLength = 0;
|
|
5118
|
-
if (offset < 0) if (position === items.length - 1) offset = 0;
|
|
5119
|
-
else for (let i = position + 1; i < items.length; i += 1) {
|
|
5120
|
-
const { height } = readResolvedItem(items[i], i);
|
|
5121
|
-
position = i;
|
|
5122
|
-
offset += height;
|
|
5123
|
-
if (offset > 0) break;
|
|
5146
|
+
case "reset":
|
|
5147
|
+
case "set":
|
|
5148
|
+
store.reset();
|
|
5149
|
+
snapshot.reset();
|
|
5150
|
+
return;
|
|
5124
5151
|
}
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
});
|
|
5137
|
-
drawLength += height;
|
|
5138
|
-
} else {
|
|
5139
|
-
offset -= height;
|
|
5140
|
-
position = i - 1;
|
|
5152
|
+
}
|
|
5153
|
+
//#endregion
|
|
5154
|
+
//#region src/renderer/virtualized/transition-controller.ts
|
|
5155
|
+
function remapAnchorAfterDeletes(anchor, deletedIndices) {
|
|
5156
|
+
if (!Number.isFinite(anchor) || deletedIndices.length === 0) return anchor;
|
|
5157
|
+
const sortedIndices = [...deletedIndices].filter((index) => Number.isFinite(index) && index >= 0).sort((a, b) => a - b);
|
|
5158
|
+
let removedBeforeAnchor = 0;
|
|
5159
|
+
for (const index of sortedIndices) {
|
|
5160
|
+
if (anchor > index + 1) {
|
|
5161
|
+
removedBeforeAnchor += 1;
|
|
5162
|
+
continue;
|
|
5141
5163
|
}
|
|
5142
|
-
if (
|
|
5143
|
-
}
|
|
5144
|
-
let shift = 0;
|
|
5145
|
-
if (y > 0) {
|
|
5146
|
-
shift = -y;
|
|
5147
|
-
if (drawLength < contentHeight) {
|
|
5148
|
-
y = drawLength;
|
|
5149
|
-
for (let i = position + 1; i < items.length; i += 1) {
|
|
5150
|
-
const { value, height } = readResolvedItem(items[i], i);
|
|
5151
|
-
drawList.push({
|
|
5152
|
-
idx: i,
|
|
5153
|
-
value,
|
|
5154
|
-
offset: y - shift,
|
|
5155
|
-
height
|
|
5156
|
-
});
|
|
5157
|
-
y = drawLength += height;
|
|
5158
|
-
if (height > Number.EPSILON) position = i;
|
|
5159
|
-
if (y >= contentHeight) break;
|
|
5160
|
-
}
|
|
5161
|
-
offset = drawLength < contentHeight ? 0 : drawLength - contentHeight;
|
|
5162
|
-
} else offset = drawLength - contentHeight;
|
|
5164
|
+
if (anchor >= index) return index - removedBeforeAnchor;
|
|
5163
5165
|
}
|
|
5164
|
-
return
|
|
5165
|
-
position,
|
|
5166
|
-
offset
|
|
5167
|
-
}, Array.from(resolutionPath), extendVisibleWindowToOuterBounds(items, {
|
|
5168
|
-
drawList,
|
|
5169
|
-
shift
|
|
5170
|
-
}, viewport, readResolvedItem));
|
|
5166
|
+
return anchor - removedBeforeAnchor;
|
|
5171
5167
|
}
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
resolutionPath,
|
|
5177
|
-
window
|
|
5178
|
-
};
|
|
5179
|
-
let minIndex = Number.POSITIVE_INFINITY;
|
|
5180
|
-
let maxIndex = Number.NEGATIVE_INFINITY;
|
|
5181
|
-
let minOffset = Number.POSITIVE_INFINITY;
|
|
5182
|
-
let maxBottom = Number.NEGATIVE_INFINITY;
|
|
5183
|
-
let hasDeferredSlots = false;
|
|
5184
|
-
for (const entry of window.drawList) {
|
|
5185
|
-
if (!(entry.height > Number.EPSILON)) hasDeferredSlots = true;
|
|
5186
|
-
else {
|
|
5187
|
-
minOffset = Math.min(minOffset, entry.offset);
|
|
5188
|
-
maxBottom = Math.max(maxBottom, entry.offset + entry.height);
|
|
5189
|
-
}
|
|
5190
|
-
minIndex = Math.min(minIndex, entry.idx);
|
|
5191
|
-
maxIndex = Math.max(maxIndex, entry.idx);
|
|
5168
|
+
var TransitionController = class {
|
|
5169
|
+
#store = new TransitionStore();
|
|
5170
|
+
#snapshot = new VisibilitySnapshot();
|
|
5171
|
+
captureVisibilitySnapshot(window, resolutionPath, items, viewport, snapshotState, readVisibleRange, readOuterVisibleRange) {
|
|
5172
|
+
this.#snapshot.capture(window, resolutionPath, items, viewport, snapshotState, readVisibleRange, readOuterVisibleRange);
|
|
5192
5173
|
}
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5174
|
+
pruneInvisible(ctx, lifecycle) {
|
|
5175
|
+
return this.pruneInvisibleAt(getNow(), ctx, lifecycle);
|
|
5176
|
+
}
|
|
5177
|
+
prepare(now, lifecycle) {
|
|
5178
|
+
this.settle(now, lifecycle);
|
|
5179
|
+
return this.#store.prepare(now);
|
|
5180
|
+
}
|
|
5181
|
+
canAutoFollowBoundaryInsert(direction, count, position, offset) {
|
|
5182
|
+
return this.#snapshot.matchesFollowBoundaryInsertState(direction, count, position, offset);
|
|
5183
|
+
}
|
|
5184
|
+
getItemHeight(item, now, adapter) {
|
|
5185
|
+
return getTransitionedItemHeight(item, now, this.#store, adapter);
|
|
5186
|
+
}
|
|
5187
|
+
resolveItem(item, now, adapter, lifecycle) {
|
|
5188
|
+
return resolveTransitionedItem(item, now, this.#store, adapter, lifecycle);
|
|
5189
|
+
}
|
|
5190
|
+
handleListStateChange(change, ctx, lifecycle) {
|
|
5191
|
+
const now = getNow();
|
|
5192
|
+
this.settle(now, lifecycle);
|
|
5193
|
+
handleTransitionStateChange(this.#store, this.#snapshot, change, ctx, lifecycle);
|
|
5194
|
+
}
|
|
5195
|
+
settle(now, lifecycle) {
|
|
5196
|
+
return this.#settleTransitions(this.#store.findCompleted(now), now, lifecycle);
|
|
5197
|
+
}
|
|
5198
|
+
pruneInvisibleAt(now, ctx, lifecycle) {
|
|
5199
|
+
const removals = this.#store.findInvisible(this.#snapshot);
|
|
5200
|
+
return this.#settleTransitions(removals, now, lifecycle, this.#resolveNaturalBoundarySnap(removals, now, ctx, lifecycle));
|
|
5201
|
+
}
|
|
5202
|
+
reset() {
|
|
5203
|
+
this.#store.reset();
|
|
5204
|
+
this.#snapshot.reset();
|
|
5205
|
+
}
|
|
5206
|
+
#settleTransitions(removals, now, lifecycle, boundarySnap) {
|
|
5207
|
+
if (removals.length === 0) return false;
|
|
5208
|
+
const anchor = lifecycle.captureVisualAnchor(now);
|
|
5209
|
+
const beforeState = lifecycle.readScrollState();
|
|
5210
|
+
const completedDeleteIndices = [];
|
|
5211
|
+
for (const { item, transition } of removals) {
|
|
5212
|
+
if (transition.kind === "delete") {
|
|
5213
|
+
const index = lifecycle.readItemIndex(item);
|
|
5214
|
+
if (index >= 0) completedDeleteIndices.push(index);
|
|
5215
|
+
}
|
|
5216
|
+
this.#store.delete(item);
|
|
5217
|
+
if (transition.kind === "delete") lifecycle.onDeleteComplete(item);
|
|
5217
5218
|
}
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
const existingIndices = new Set(drawList.map((entry) => entry.idx));
|
|
5224
|
-
let topEntry = drawList[0];
|
|
5225
|
-
let bottomEntry = drawList[0];
|
|
5226
|
-
for (const entry of drawList) {
|
|
5227
|
-
if (entry.offset < topEntry.offset) topEntry = entry;
|
|
5228
|
-
if (entry.offset + entry.height > bottomEntry.offset + bottomEntry.height) bottomEntry = entry;
|
|
5219
|
+
if (anchor != null && Number.isFinite(anchor)) lifecycle.restoreVisualAnchor(remapAnchorAfterDeletes(anchor, completedDeleteIndices));
|
|
5220
|
+
if (boundarySnap != null) lifecycle.snapItemToViewportBoundary(boundarySnap.item, boundarySnap.boundary);
|
|
5221
|
+
const afterState = lifecycle.readScrollState();
|
|
5222
|
+
if (!sameState(beforeState, afterState.position, afterState.offset)) lifecycle.onTransitionSettleScrollAdjusted();
|
|
5223
|
+
return true;
|
|
5229
5224
|
}
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5225
|
+
#resolveNaturalBoundarySnap(removals, now, ctx, lifecycle) {
|
|
5226
|
+
const previousState = this.#snapshot.previousState;
|
|
5227
|
+
const drawnRange = this.#snapshot.readDrawnIndexRange();
|
|
5228
|
+
if (previousState == null || drawnRange == null) return;
|
|
5229
|
+
const naturalIndices = [];
|
|
5230
|
+
for (const { item, transition } of removals) {
|
|
5231
|
+
if (transition.kind !== "update" && transition.kind !== "delete") continue;
|
|
5232
|
+
const index = lifecycle.readItemIndex(item);
|
|
5233
|
+
if (index < 0 || !this.#snapshot.wasVisible(item)) return;
|
|
5234
|
+
if (this.#isTransitionVisibleInState(index, previousState, now, ctx)) return;
|
|
5235
|
+
naturalIndices.push(index);
|
|
5236
|
+
}
|
|
5237
|
+
if (naturalIndices.length === 0) return;
|
|
5238
|
+
if (naturalIndices.every((index) => index < drawnRange.minIndex)) {
|
|
5239
|
+
const item = this.#snapshot.readBoundaryItem("top");
|
|
5240
|
+
return item == null ? void 0 : {
|
|
5241
|
+
item,
|
|
5242
|
+
boundary: "top"
|
|
5243
|
+
};
|
|
5244
|
+
}
|
|
5245
|
+
if (naturalIndices.every((index) => index > drawnRange.maxIndex)) {
|
|
5246
|
+
const item = this.#snapshot.readBoundaryItem("bottom");
|
|
5247
|
+
return item == null ? void 0 : {
|
|
5248
|
+
item,
|
|
5249
|
+
boundary: "bottom"
|
|
5250
|
+
};
|
|
5239
5251
|
}
|
|
5240
|
-
const { value, height } = resolveItem(items[prevIdx], prevIdx);
|
|
5241
|
-
const prevY = topY - height;
|
|
5242
|
-
if (prevY + height <= viewport.outerContentTop) break;
|
|
5243
|
-
drawList.push({
|
|
5244
|
-
idx: prevIdx,
|
|
5245
|
-
value,
|
|
5246
|
-
offset: prevY - window.shift,
|
|
5247
|
-
height
|
|
5248
|
-
});
|
|
5249
|
-
existingIndices.add(prevIdx);
|
|
5250
|
-
topIdx = prevIdx;
|
|
5251
|
-
topY = prevY;
|
|
5252
5252
|
}
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
const existing = drawList.find((entry) => entry.idx === nextIdx);
|
|
5259
|
-
bottomIdx = nextIdx;
|
|
5260
|
-
if (existing != null) bottomY = Math.max(bottomY, existing.offset + window.shift + existing.height);
|
|
5261
|
-
continue;
|
|
5253
|
+
#isTransitionVisibleInState(index, state, now, ctx) {
|
|
5254
|
+
const solution = ctx.resolveVisibleWindowForState(state, now);
|
|
5255
|
+
for (const entry of solution.window.drawList) {
|
|
5256
|
+
if (entry.index !== index) continue;
|
|
5257
|
+
return ctx.readOuterVisibleRange(entry.offset + solution.window.shift, entry.height) != null;
|
|
5262
5258
|
}
|
|
5263
|
-
|
|
5264
|
-
if (bottomY >= viewport.outerContentBottom) break;
|
|
5265
|
-
drawList.push({
|
|
5266
|
-
idx: nextIdx,
|
|
5267
|
-
value,
|
|
5268
|
-
offset: bottomY - window.shift,
|
|
5269
|
-
height
|
|
5270
|
-
});
|
|
5271
|
-
existingIndices.add(nextIdx);
|
|
5272
|
-
bottomIdx = nextIdx;
|
|
5273
|
-
bottomY += height;
|
|
5259
|
+
return false;
|
|
5274
5260
|
}
|
|
5275
|
-
|
|
5276
|
-
drawList,
|
|
5277
|
-
shift: window.shift
|
|
5278
|
-
};
|
|
5279
|
-
}
|
|
5261
|
+
};
|
|
5280
5262
|
//#endregion
|
|
5281
5263
|
//#region src/renderer/virtualized/base.ts
|
|
5282
5264
|
/**
|
|
@@ -5313,18 +5295,10 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
5313
5295
|
get position() {
|
|
5314
5296
|
return this.options.list.position;
|
|
5315
5297
|
}
|
|
5316
|
-
/** Updates the current anchor item index. */
|
|
5317
|
-
set position(value) {
|
|
5318
|
-
this.options.list.position = value;
|
|
5319
|
-
}
|
|
5320
5298
|
/** Pixel offset from the anchored item edge. */
|
|
5321
5299
|
get offset() {
|
|
5322
5300
|
return this.options.list.offset;
|
|
5323
5301
|
}
|
|
5324
|
-
/** Updates the pixel offset from the anchored item edge. */
|
|
5325
|
-
set offset(value) {
|
|
5326
|
-
this.options.list.offset = value;
|
|
5327
|
-
}
|
|
5328
5302
|
/** Items currently available to the renderer. */
|
|
5329
5303
|
get items() {
|
|
5330
5304
|
return this.options.list.items;
|
|
@@ -5424,9 +5398,9 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
5424
5398
|
_renderDrawList(list, shift, feedback) {
|
|
5425
5399
|
let result = false;
|
|
5426
5400
|
const viewport = this._getViewportMetrics();
|
|
5427
|
-
for (const {
|
|
5401
|
+
for (const { index, value: item, offset, height } of list) {
|
|
5428
5402
|
const y = offset + shift + viewport.contentTop;
|
|
5429
|
-
if (feedback != null) this._accumulateRenderFeedback(feedback,
|
|
5403
|
+
if (feedback != null) this._accumulateRenderFeedback(feedback, index, y, height);
|
|
5430
5404
|
if (y + height < 0 || y > viewport.outerHeight) continue;
|
|
5431
5405
|
if (item.draw(y)) result = true;
|
|
5432
5406
|
}
|
|
@@ -5446,9 +5420,9 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
5446
5420
|
let topMostY = Number.POSITIVE_INFINITY;
|
|
5447
5421
|
let bottomMostY = Number.NEGATIVE_INFINITY;
|
|
5448
5422
|
const viewport = this._getViewportMetrics();
|
|
5449
|
-
for (const {
|
|
5450
|
-
minIndex = Math.min(minIndex,
|
|
5451
|
-
maxIndex = Math.max(maxIndex,
|
|
5423
|
+
for (const { index, offset, height } of window.drawList) {
|
|
5424
|
+
minIndex = Math.min(minIndex, index);
|
|
5425
|
+
maxIndex = Math.max(maxIndex, index);
|
|
5452
5426
|
const y = offset + window.shift + viewport.contentTop;
|
|
5453
5427
|
topMostY = Math.min(topMostY, y);
|
|
5454
5428
|
bottomMostY = Math.max(bottomMostY, y + height);
|
|
@@ -5539,7 +5513,7 @@ var VirtualizedRenderer = class VirtualizedRenderer extends BaseRenderer {
|
|
|
5539
5513
|
return resolveListViewport(this.graphics.canvas.clientHeight, this._getLayoutOptions().padding);
|
|
5540
5514
|
}
|
|
5541
5515
|
#handleDeleteComplete(item) {
|
|
5542
|
-
this.options.list
|
|
5516
|
+
finalizeInternalListDelete(this.options.list, item);
|
|
5543
5517
|
}
|
|
5544
5518
|
#getTransitionLifecycleAdapter() {
|
|
5545
5519
|
return {
|