@humanspeak/svelte-virtual-list 0.2.6-beta.3 → 0.2.6-beta.5
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/dist/SvelteVirtualList.svelte +9 -8
- package/dist/types.d.ts +8 -1
- package/dist/utils/heightCalculation.d.ts +3 -1
- package/dist/utils/heightCalculation.js +5 -3
- package/dist/utils/virtualList.d.ts +3 -1
- package/dist/utils/virtualList.js +10 -13
- package/dist/utils/virtualListDebug.d.ts +9 -4
- package/dist/utils/virtualListDebug.js +16 -5
- package/package.json +1 -1
|
@@ -253,12 +253,9 @@
|
|
|
253
253
|
lastMeasuredIndex = result.newLastMeasuredIndex
|
|
254
254
|
heightCache = result.updatedHeightCache
|
|
255
255
|
|
|
256
|
-
// Update running totals
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
totalMeasuredHeight = heights.reduce((sum, h) => sum + h, 0)
|
|
260
|
-
measuredCount = heights.length
|
|
261
|
-
}
|
|
256
|
+
// Update running totals efficiently (O(1) instead of O(n)!)
|
|
257
|
+
totalMeasuredHeight = result.newTotalHeight
|
|
258
|
+
measuredCount = result.newValidCount
|
|
262
259
|
|
|
263
260
|
// Clear processed dirty items
|
|
264
261
|
result.clearedDirtyItems.forEach((index) => {
|
|
@@ -273,7 +270,9 @@
|
|
|
273
270
|
}
|
|
274
271
|
},
|
|
275
272
|
100, // debounceTime
|
|
276
|
-
dirtyItems // Pass dirty items for processing
|
|
273
|
+
dirtyItems, // Pass dirty items for processing
|
|
274
|
+
totalMeasuredHeight, // Current running total height
|
|
275
|
+
measuredCount // Current running total count
|
|
277
276
|
)
|
|
278
277
|
}
|
|
279
278
|
|
|
@@ -836,7 +835,9 @@
|
|
|
836
835
|
visibleItems(),
|
|
837
836
|
items.length,
|
|
838
837
|
Object.keys(heightCache).length,
|
|
839
|
-
calculatedItemHeight
|
|
838
|
+
calculatedItemHeight,
|
|
839
|
+
scrollTop,
|
|
840
|
+
height || 0
|
|
840
841
|
)}
|
|
841
842
|
{debugFunction
|
|
842
843
|
? debugFunction(debugInfo)
|
package/dist/types.d.ts
CHANGED
|
@@ -72,7 +72,11 @@ export type SvelteVirtualListProps = {
|
|
|
72
72
|
* @property {number} startIndex - Index of the first rendered item in the viewport.
|
|
73
73
|
* @property {number} totalItems - Total number of items in the list.
|
|
74
74
|
* @property {number} visibleItemsCount - Number of items currently visible in the viewport.
|
|
75
|
-
* @property {number} processedItems - Number of items
|
|
75
|
+
* @property {number} processedItems - Number of items with measured heights in cache.
|
|
76
|
+
* @property {number} averageItemHeight - Current calculated average height per item.
|
|
77
|
+
* @property {boolean} atTop - Whether the list is scrolled to the top position.
|
|
78
|
+
* @property {boolean} atBottom - Whether the list is scrolled to the bottom position.
|
|
79
|
+
* @property {number} totalHeight - Total calculated height of all items in the list.
|
|
76
80
|
*/
|
|
77
81
|
export type SvelteVirtualListDebugInfo = {
|
|
78
82
|
endIndex: number;
|
|
@@ -81,6 +85,9 @@ export type SvelteVirtualListDebugInfo = {
|
|
|
81
85
|
visibleItemsCount: number;
|
|
82
86
|
processedItems: number;
|
|
83
87
|
averageItemHeight: number;
|
|
88
|
+
atTop: boolean;
|
|
89
|
+
atBottom: boolean;
|
|
90
|
+
totalHeight: number;
|
|
84
91
|
};
|
|
85
92
|
/**
|
|
86
93
|
* Alignment options for programmatic scrolling.
|
|
@@ -75,4 +75,6 @@ export declare const calculateAverageHeightDebounced: (isCalculatingHeight: bool
|
|
|
75
75
|
newLastMeasuredIndex: number;
|
|
76
76
|
updatedHeightCache: Record<number, number>;
|
|
77
77
|
clearedDirtyItems: Set<number>;
|
|
78
|
-
|
|
78
|
+
newTotalHeight: number;
|
|
79
|
+
newValidCount: number;
|
|
80
|
+
}) => void, debounceTime: number, dirtyItems: Set<number>, currentTotalHeight?: number, currentValidCount?: number) => NodeJS.Timeout | null;
|
|
@@ -71,7 +71,7 @@ import { BROWSER } from 'esm-env';
|
|
|
71
71
|
*/
|
|
72
72
|
export const calculateAverageHeightDebounced = (isCalculatingHeight, heightUpdateTimeout, visibleItemsGetter, itemElements, heightCache, lastMeasuredIndex, calculatedItemHeight,
|
|
73
73
|
/* trunk-ignore(eslint/no-unused-vars) */
|
|
74
|
-
onUpdate, debounceTime, dirtyItems) => {
|
|
74
|
+
onUpdate, debounceTime, dirtyItems, currentTotalHeight = 0, currentValidCount = 0) => {
|
|
75
75
|
if (!BROWSER || isCalculatingHeight)
|
|
76
76
|
return null;
|
|
77
77
|
const visibleRange = visibleItemsGetter();
|
|
@@ -81,13 +81,15 @@ onUpdate, debounceTime, dirtyItems) => {
|
|
|
81
81
|
if (heightUpdateTimeout)
|
|
82
82
|
clearTimeout(heightUpdateTimeout);
|
|
83
83
|
return setTimeout(() => {
|
|
84
|
-
const { newHeight, newLastMeasuredIndex, updatedHeightCache, clearedDirtyItems } = calculateAverageHeight(itemElements, visibleRange, heightCache, calculatedItemHeight, dirtyItems);
|
|
84
|
+
const { newHeight, newLastMeasuredIndex, updatedHeightCache, clearedDirtyItems, newTotalHeight, newValidCount } = calculateAverageHeight(itemElements, visibleRange, heightCache, calculatedItemHeight, dirtyItems, currentTotalHeight, currentValidCount);
|
|
85
85
|
if (Math.abs(newHeight - calculatedItemHeight) > 1 || dirtyItems.size > 0) {
|
|
86
86
|
onUpdate({
|
|
87
87
|
newHeight,
|
|
88
88
|
newLastMeasuredIndex,
|
|
89
89
|
updatedHeightCache,
|
|
90
|
-
clearedDirtyItems
|
|
90
|
+
clearedDirtyItems,
|
|
91
|
+
newTotalHeight,
|
|
92
|
+
newValidCount
|
|
91
93
|
});
|
|
92
94
|
}
|
|
93
95
|
}, debounceTime);
|
|
@@ -86,11 +86,13 @@ export declare const updateHeightAndScroll: (state: VirtualListState, setters: V
|
|
|
86
86
|
*/
|
|
87
87
|
export declare const calculateAverageHeight: (itemElements: HTMLElement[], visibleRange: {
|
|
88
88
|
start: number;
|
|
89
|
-
}, heightCache: Record<number, number>, currentItemHeight: number, dirtyItems: Set<number
|
|
89
|
+
}, heightCache: Record<number, number>, currentItemHeight: number, dirtyItems: Set<number>, currentTotalHeight?: number, currentValidCount?: number) => {
|
|
90
90
|
newHeight: number;
|
|
91
91
|
newLastMeasuredIndex: number;
|
|
92
92
|
updatedHeightCache: Record<number, number>;
|
|
93
93
|
clearedDirtyItems: Set<number>;
|
|
94
|
+
newTotalHeight: number;
|
|
95
|
+
newValidCount: number;
|
|
94
96
|
};
|
|
95
97
|
/**
|
|
96
98
|
* Processes large arrays in chunks to prevent UI blocking.
|
|
@@ -158,28 +158,23 @@ export const updateHeightAndScroll = (state, setters, immediate = false) => {
|
|
|
158
158
|
* 40
|
|
159
159
|
* )
|
|
160
160
|
*/
|
|
161
|
-
export const calculateAverageHeight = (itemElements, visibleRange, heightCache, currentItemHeight, dirtyItems) => {
|
|
161
|
+
export const calculateAverageHeight = (itemElements, visibleRange, heightCache, currentItemHeight, dirtyItems, currentTotalHeight = 0, currentValidCount = 0) => {
|
|
162
162
|
const validElements = itemElements.filter((el) => el);
|
|
163
163
|
if (validElements.length === 0) {
|
|
164
164
|
return {
|
|
165
165
|
newHeight: currentItemHeight,
|
|
166
166
|
newLastMeasuredIndex: visibleRange.start,
|
|
167
167
|
updatedHeightCache: heightCache,
|
|
168
|
-
clearedDirtyItems: new Set()
|
|
168
|
+
clearedDirtyItems: new Set(),
|
|
169
|
+
newTotalHeight: currentTotalHeight,
|
|
170
|
+
newValidCount: currentValidCount
|
|
169
171
|
};
|
|
170
172
|
}
|
|
171
173
|
const newHeightCache = { ...heightCache };
|
|
172
174
|
const clearedDirtyItems = new Set();
|
|
173
|
-
//
|
|
174
|
-
let totalValidHeight =
|
|
175
|
-
let validHeightCount =
|
|
176
|
-
// Calculate initial totals from existing cache
|
|
177
|
-
for (const height of Object.values(heightCache)) {
|
|
178
|
-
if (Number.isFinite(height) && height > 0) {
|
|
179
|
-
totalValidHeight += height;
|
|
180
|
-
validHeightCount++;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
175
|
+
// Start with current running totals (O(1) instead of O(n))
|
|
176
|
+
let totalValidHeight = currentTotalHeight;
|
|
177
|
+
let validHeightCount = currentValidCount;
|
|
183
178
|
// Process only dirty items if they exist, otherwise process all visible items
|
|
184
179
|
if (dirtyItems.size > 0) {
|
|
185
180
|
// Process only dirty items
|
|
@@ -240,7 +235,9 @@ export const calculateAverageHeight = (itemElements, visibleRange, heightCache,
|
|
|
240
235
|
newHeight: validHeightCount > 0 ? totalValidHeight / validHeightCount : currentItemHeight,
|
|
241
236
|
newLastMeasuredIndex: visibleRange.start,
|
|
242
237
|
updatedHeightCache: newHeightCache,
|
|
243
|
-
clearedDirtyItems
|
|
238
|
+
clearedDirtyItems,
|
|
239
|
+
newTotalHeight: totalValidHeight,
|
|
240
|
+
newValidCount: validHeightCount
|
|
244
241
|
};
|
|
245
242
|
};
|
|
246
243
|
/**
|
|
@@ -41,8 +41,9 @@ export declare function shouldShowDebugInfo(prevRange: {
|
|
|
41
41
|
* This utility function generates a structured debug object that captures the complete
|
|
42
42
|
* state of a virtual list at any given moment. It includes critical metrics such as
|
|
43
43
|
* visible item count, viewport boundaries, total items, processed items with measured
|
|
44
|
-
* heights,
|
|
45
|
-
* monitoring, debugging scroll behavior,
|
|
44
|
+
* heights, height calculations, scroll position, and total content dimensions.
|
|
45
|
+
* This information is essential for performance monitoring, debugging scroll behavior,
|
|
46
|
+
* and optimizing virtual list configurations.
|
|
46
47
|
*
|
|
47
48
|
* Performance considerations:
|
|
48
49
|
* - All calculations are O(1)
|
|
@@ -53,6 +54,8 @@ export declare function shouldShowDebugInfo(prevRange: {
|
|
|
53
54
|
* @param totalItems - Total number of items in the virtual list
|
|
54
55
|
* @param processedItems - Number of items with measured heights (heightCache.length)
|
|
55
56
|
* @param averageItemHeight - Current calculated average height per item in pixels
|
|
57
|
+
* @param scrollTop - Current scroll position in pixels
|
|
58
|
+
* @param viewportHeight - Height of the viewport in pixels
|
|
56
59
|
* @returns {SvelteVirtualListDebugInfo} A structured debug information object
|
|
57
60
|
*
|
|
58
61
|
* @example
|
|
@@ -60,7 +63,9 @@ export declare function shouldShowDebugInfo(prevRange: {
|
|
|
60
63
|
* { start: 0, end: 10 },
|
|
61
64
|
* 1000,
|
|
62
65
|
* 50,
|
|
63
|
-
* 45
|
|
66
|
+
* 45,
|
|
67
|
+
* 200,
|
|
68
|
+
* 400
|
|
64
69
|
* );
|
|
65
70
|
* console.log('Virtual List State:', debugInfo);
|
|
66
71
|
*
|
|
@@ -69,4 +74,4 @@ export declare function shouldShowDebugInfo(prevRange: {
|
|
|
69
74
|
export declare function createDebugInfo(visibleRange: {
|
|
70
75
|
start: number;
|
|
71
76
|
end: number;
|
|
72
|
-
}, totalItems: number, processedItems: number, averageItemHeight: number): SvelteVirtualListDebugInfo;
|
|
77
|
+
}, totalItems: number, processedItems: number, averageItemHeight: number, scrollTop: number, viewportHeight: number): SvelteVirtualListDebugInfo;
|
|
@@ -40,8 +40,9 @@ export function shouldShowDebugInfo(prevRange, currentRange, prevHeight, current
|
|
|
40
40
|
* This utility function generates a structured debug object that captures the complete
|
|
41
41
|
* state of a virtual list at any given moment. It includes critical metrics such as
|
|
42
42
|
* visible item count, viewport boundaries, total items, processed items with measured
|
|
43
|
-
* heights,
|
|
44
|
-
* monitoring, debugging scroll behavior,
|
|
43
|
+
* heights, height calculations, scroll position, and total content dimensions.
|
|
44
|
+
* This information is essential for performance monitoring, debugging scroll behavior,
|
|
45
|
+
* and optimizing virtual list configurations.
|
|
45
46
|
*
|
|
46
47
|
* Performance considerations:
|
|
47
48
|
* - All calculations are O(1)
|
|
@@ -52,6 +53,8 @@ export function shouldShowDebugInfo(prevRange, currentRange, prevHeight, current
|
|
|
52
53
|
* @param totalItems - Total number of items in the virtual list
|
|
53
54
|
* @param processedItems - Number of items with measured heights (heightCache.length)
|
|
54
55
|
* @param averageItemHeight - Current calculated average height per item in pixels
|
|
56
|
+
* @param scrollTop - Current scroll position in pixels
|
|
57
|
+
* @param viewportHeight - Height of the viewport in pixels
|
|
55
58
|
* @returns {SvelteVirtualListDebugInfo} A structured debug information object
|
|
56
59
|
*
|
|
57
60
|
* @example
|
|
@@ -59,19 +62,27 @@ export function shouldShowDebugInfo(prevRange, currentRange, prevHeight, current
|
|
|
59
62
|
* { start: 0, end: 10 },
|
|
60
63
|
* 1000,
|
|
61
64
|
* 50,
|
|
62
|
-
* 45
|
|
65
|
+
* 45,
|
|
66
|
+
* 200,
|
|
67
|
+
* 400
|
|
63
68
|
* );
|
|
64
69
|
* console.log('Virtual List State:', debugInfo);
|
|
65
70
|
*
|
|
66
71
|
* @throws {Error} Will throw if end index is less than start index in visibleRange
|
|
67
72
|
*/
|
|
68
|
-
export function createDebugInfo(visibleRange, totalItems, processedItems, averageItemHeight) {
|
|
73
|
+
export function createDebugInfo(visibleRange, totalItems, processedItems, averageItemHeight, scrollTop, viewportHeight) {
|
|
74
|
+
const totalHeight = totalItems * averageItemHeight;
|
|
75
|
+
const atTop = scrollTop <= 1; // Small tolerance for floating point precision
|
|
76
|
+
const atBottom = scrollTop >= totalHeight - viewportHeight - 1; // Small tolerance
|
|
69
77
|
return {
|
|
70
78
|
visibleItemsCount: visibleRange.end - visibleRange.start,
|
|
71
79
|
startIndex: visibleRange.start,
|
|
72
80
|
endIndex: visibleRange.end,
|
|
73
81
|
totalItems,
|
|
74
82
|
processedItems, // Number of items with measured heights in heightCache
|
|
75
|
-
averageItemHeight
|
|
83
|
+
averageItemHeight,
|
|
84
|
+
atTop,
|
|
85
|
+
atBottom,
|
|
86
|
+
totalHeight
|
|
76
87
|
};
|
|
77
88
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@humanspeak/svelte-virtual-list",
|
|
3
|
-
"version": "0.2.6-beta.
|
|
3
|
+
"version": "0.2.6-beta.5",
|
|
4
4
|
"description": "A lightweight, high-performance virtual list component for Svelte 5 that renders large datasets with minimal memory usage. Features include dynamic height support, smooth scrolling, TypeScript support, and efficient DOM recycling. Ideal for infinite scrolling lists, data tables, chat interfaces, and any application requiring the rendering of thousands of items without compromising performance. Zero dependencies and fully customizable.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"svelte",
|