@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.
@@ -253,12 +253,9 @@
253
253
  lastMeasuredIndex = result.newLastMeasuredIndex
254
254
  heightCache = result.updatedHeightCache
255
255
 
256
- // Update running totals for precise height calculation (only when significant changes)
257
- if (result.clearedDirtyItems.size > 10) {
258
- const heights = Object.values(heightCache)
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 processed in the viewport.
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
- }) => void, debounceTime: number, dirtyItems: Set<number>) => NodeJS.Timeout | null;
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
- // Initialize running totals for O(1) average calculation
174
- let totalValidHeight = 0;
175
- let validHeightCount = 0;
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, and height calculations. This information is essential for performance
45
- * monitoring, debugging scroll behavior, and optimizing virtual list configurations.
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, and height calculations. This information is essential for performance
44
- * monitoring, debugging scroll behavior, and optimizing virtual list configurations.
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",
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",