@humanspeak/svelte-virtual-list 0.2.6 → 0.3.1-beta.0

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.
Files changed (32) hide show
  1. package/README.md +14 -2
  2. package/dist/SvelteVirtualList.svelte +619 -179
  3. package/dist/SvelteVirtualList.svelte.d.ts +156 -65
  4. package/dist/reactive-height-manager/INTEGRATION_EXAMPLE.md +136 -0
  5. package/dist/reactive-height-manager/README.md +324 -0
  6. package/dist/reactive-height-manager/ReactiveHeightManager.svelte.d.ts +116 -0
  7. package/dist/reactive-height-manager/ReactiveHeightManager.svelte.js +200 -0
  8. package/dist/reactive-height-manager/benchmark.d.ts +5 -0
  9. package/dist/reactive-height-manager/benchmark.js +25 -0
  10. package/dist/reactive-height-manager/index.d.ts +50 -0
  11. package/dist/reactive-height-manager/index.js +55 -0
  12. package/dist/reactive-height-manager/test/TestComponent.svelte +78 -0
  13. package/dist/reactive-height-manager/test/TestComponent.svelte.d.ts +23 -0
  14. package/dist/reactive-height-manager/types.d.ts +41 -0
  15. package/dist/reactive-height-manager/types.js +1 -0
  16. package/dist/types.d.ts +24 -5
  17. package/dist/utils/heightCalculation.d.ts +18 -8
  18. package/dist/utils/heightCalculation.js +18 -11
  19. package/dist/utils/heightChangeDetection.d.ts +12 -0
  20. package/dist/utils/heightChangeDetection.js +20 -0
  21. package/dist/utils/resizeObserver.d.ts +89 -0
  22. package/dist/utils/resizeObserver.js +119 -0
  23. package/dist/utils/scrollCalculation.d.ts +47 -0
  24. package/dist/utils/scrollCalculation.js +167 -0
  25. package/dist/utils/throttle.d.ts +95 -0
  26. package/dist/utils/throttle.js +155 -0
  27. package/dist/utils/types.d.ts +0 -6
  28. package/dist/utils/virtualList.d.ts +20 -23
  29. package/dist/utils/virtualList.js +153 -61
  30. package/dist/utils/virtualListDebug.d.ts +12 -7
  31. package/dist/utils/virtualListDebug.js +19 -9
  32. package/package.json +33 -31
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Reactive Height Manager
3
+ *
4
+ * A standalone, high-performance reactive height calculation system for virtualized lists.
5
+ *
6
+ * Features:
7
+ * - Incremental height processing (O(dirty items) instead of O(all items))
8
+ * - Reactive state management using Svelte 5 runes
9
+ * - Comprehensive performance testing
10
+ * - Framework-agnostic types and interfaces
11
+ * - Memory-efficient measurement tracking
12
+ *
13
+ * @example Basic Usage
14
+ * ```typescript
15
+ * import { ReactiveHeightManager } from './reactive-height-manager'
16
+ *
17
+ * const manager = new ReactiveHeightManager({
18
+ * itemLength: 10000,
19
+ * estimatedHeight: 40
20
+ * })
21
+ *
22
+ * // Process height changes incrementally
23
+ * manager.processDirtyHeights(heightChanges)
24
+ *
25
+ * // Get reactive total height
26
+ * const totalHeight = manager.getDerivedTotalHeight(calculatedItemHeight)
27
+ * ```
28
+ *
29
+ * @example Performance Monitoring
30
+ * ```typescript
31
+ * const debugInfo = manager.getDebugInfo()
32
+ * console.log(`Coverage: ${debugInfo.coveragePercent}%`)
33
+ * console.log(`Measured: ${debugInfo.measuredCount}/${debugInfo.itemLength}`)
34
+ * ```
35
+ */
36
+ export { ReactiveHeightManager } from './ReactiveHeightManager.svelte.js';
37
+ import { ReactiveHeightManager as ReactiveHeightManagerType } from './ReactiveHeightManager.svelte.js';
38
+ export type { HeightChange, HeightManagerConfig, HeightManagerDebugInfo } from './types.js';
39
+ export declare const VERSION = "1.0.0";
40
+ export declare const DEFAULT_ESTIMATED_HEIGHT = 40;
41
+ export declare const DEFAULT_MEASUREMENT_THRESHOLD = 10;
42
+ /**
43
+ * Factory function for creating ReactiveHeightManager instances
44
+ * with common configurations
45
+ */
46
+ export declare function createHeightManager(itemLength: number, itemHeight?: number): ReactiveHeightManagerType;
47
+ /**
48
+ * Performance benchmarking utility
49
+ */
50
+ export { benchmarkHeightManager } from './benchmark.js';
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Reactive Height Manager
3
+ *
4
+ * A standalone, high-performance reactive height calculation system for virtualized lists.
5
+ *
6
+ * Features:
7
+ * - Incremental height processing (O(dirty items) instead of O(all items))
8
+ * - Reactive state management using Svelte 5 runes
9
+ * - Comprehensive performance testing
10
+ * - Framework-agnostic types and interfaces
11
+ * - Memory-efficient measurement tracking
12
+ *
13
+ * @example Basic Usage
14
+ * ```typescript
15
+ * import { ReactiveHeightManager } from './reactive-height-manager'
16
+ *
17
+ * const manager = new ReactiveHeightManager({
18
+ * itemLength: 10000,
19
+ * estimatedHeight: 40
20
+ * })
21
+ *
22
+ * // Process height changes incrementally
23
+ * manager.processDirtyHeights(heightChanges)
24
+ *
25
+ * // Get reactive total height
26
+ * const totalHeight = manager.getDerivedTotalHeight(calculatedItemHeight)
27
+ * ```
28
+ *
29
+ * @example Performance Monitoring
30
+ * ```typescript
31
+ * const debugInfo = manager.getDebugInfo()
32
+ * console.log(`Coverage: ${debugInfo.coveragePercent}%`)
33
+ * console.log(`Measured: ${debugInfo.measuredCount}/${debugInfo.itemLength}`)
34
+ * ```
35
+ */
36
+ // Export the main class
37
+ export { ReactiveHeightManager } from './ReactiveHeightManager.svelte.js';
38
+ import { ReactiveHeightManager as ReactiveHeightManagerType } from './ReactiveHeightManager.svelte.js';
39
+ // Export version for potential npm package
40
+ export const VERSION = '1.0.0';
41
+ // Export utility constants
42
+ export const DEFAULT_ESTIMATED_HEIGHT = 40;
43
+ export const DEFAULT_MEASUREMENT_THRESHOLD = 10; // percentage
44
+ /**
45
+ * Factory function for creating ReactiveHeightManager instances
46
+ * with common configurations
47
+ */
48
+ export function createHeightManager(itemLength, itemHeight = DEFAULT_ESTIMATED_HEIGHT) {
49
+ return new ReactiveHeightManagerType({ itemLength, itemHeight });
50
+ }
51
+ /**
52
+ * Performance benchmarking utility
53
+ */
54
+ // Moved out to keep index clean; re-exported from benchmark.ts
55
+ export { benchmarkHeightManager } from './benchmark.js';
@@ -0,0 +1,78 @@
1
+ <script lang="ts">
2
+ import { untrack } from 'svelte'
3
+ import { ReactiveHeightManager } from '../ReactiveHeightManager.svelte.js'
4
+ import type { HeightChange, HeightManagerConfig } from '../types.js'
5
+
6
+ interface Props {
7
+ config: HeightManagerConfig
8
+ onReactiveUpdate?: (data: {
9
+ totalHeight: number
10
+ measuredCount: number
11
+ effectRuns: number
12
+ }) => void
13
+ }
14
+
15
+ let { config, onReactiveUpdate }: Props = $props()
16
+
17
+ // Create the manager
18
+ const manager = new ReactiveHeightManager(config)
19
+
20
+ // Derived reactive values (clean, no side effects)
21
+ let currentTotalHeight = $derived(manager.totalHeight)
22
+ let currentMeasuredCount = $derived(manager.measuredCount)
23
+
24
+ // Effect run counter (non-reactive - just for tracking)
25
+ let effectRunCount = 0
26
+
27
+ // Reactive counter for DOM display (separate from effect logic)
28
+ let displayEffectRuns = $state(0)
29
+
30
+ // Simple effect that just notifies - no state modification
31
+ $effect(() => {
32
+ // Read the current values (triggers when manager changes)
33
+ const totalHeight = manager.totalHeight
34
+ const measuredCount = manager.measuredCount
35
+
36
+ // Increment counters
37
+ effectRunCount++
38
+ displayEffectRuns = effectRunCount // Update reactive display
39
+
40
+ // Notify parent with fresh values each time
41
+ onReactiveUpdate?.({
42
+ totalHeight,
43
+ measuredCount,
44
+ effectRuns: effectRunCount
45
+ })
46
+ })
47
+
48
+ // Export methods for testing
49
+ export function processDirtyHeights(changes: HeightChange[]) {
50
+ manager.processDirtyHeights(changes)
51
+ }
52
+
53
+ export function updateItemLength(newLength: number) {
54
+ manager.updateItemLength(newLength)
55
+ }
56
+
57
+ export function setItemHeight(height: number) {
58
+ manager.itemHeight = height
59
+ }
60
+
61
+ export function getReactiveData() {
62
+ return {
63
+ totalHeight: currentTotalHeight,
64
+ measuredCount: currentMeasuredCount,
65
+ effectRuns: displayEffectRuns
66
+ }
67
+ }
68
+
69
+ export function getManager() {
70
+ return manager
71
+ }
72
+ </script>
73
+
74
+ <div data-testid="reactive-test-component">
75
+ <div data-testid="total-height">{currentTotalHeight}</div>
76
+ <div data-testid="measured-count">{currentMeasuredCount}</div>
77
+ <div data-testid="effect-runs">{displayEffectRuns}</div>
78
+ </div>
@@ -0,0 +1,23 @@
1
+ import { ReactiveHeightManager } from '../ReactiveHeightManager.svelte.js';
2
+ import type { HeightChange, HeightManagerConfig } from '../types.js';
3
+ interface Props {
4
+ config: HeightManagerConfig;
5
+ onReactiveUpdate?: (data: {
6
+ totalHeight: number;
7
+ measuredCount: number;
8
+ effectRuns: number;
9
+ }) => void;
10
+ }
11
+ declare const TestComponent: import("svelte").Component<Props, {
12
+ processDirtyHeights: (changes: HeightChange[]) => void;
13
+ updateItemLength: (newLength: number) => void;
14
+ setItemHeight: (height: number) => void;
15
+ getReactiveData: () => {
16
+ totalHeight: number;
17
+ measuredCount: number;
18
+ effectRuns: number;
19
+ };
20
+ getManager: () => ReactiveHeightManager;
21
+ }, "">;
22
+ type TestComponent = ReturnType<typeof TestComponent>;
23
+ export default TestComponent;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Represents a height change for a specific item
3
+ * This interface accepts any object with these minimum properties,
4
+ * allowing for additional fields that consumers may include
5
+ */
6
+ export interface HeightChange {
7
+ /** The index of the item that changed */
8
+ readonly index: number;
9
+ /** The previous height (undefined if first measurement) */
10
+ readonly oldHeight: number | undefined;
11
+ /** The new height measurement (undefined represents removal/unset) */
12
+ readonly newHeight: number | undefined;
13
+ }
14
+ /**
15
+ * Configuration options for ReactiveHeightManager
16
+ */
17
+ export interface HeightManagerConfig {
18
+ /** Total number of items in the list */
19
+ itemLength: number;
20
+ /** Height to use for unmeasured items */
21
+ itemHeight: number;
22
+ }
23
+ /**
24
+ * Debug information about the height manager state
25
+ */
26
+ export interface HeightManagerDebugInfo {
27
+ /** Total measured height of all measured items */
28
+ totalMeasuredHeight: number;
29
+ /** Number of items that have been measured */
30
+ measuredCount: number;
31
+ /** Total number of items in the list */
32
+ itemLength: number;
33
+ /** Percentage of items that have been measured */
34
+ coveragePercent: number;
35
+ /** Current height to use for unmeasured items */
36
+ itemHeight: number;
37
+ /** Calculated average height of measured items */
38
+ averageHeight: number;
39
+ /** Current total height (measured + estimated) */
40
+ totalHeight: number;
41
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/types.d.ts CHANGED
@@ -10,7 +10,7 @@ export type SvelteVirtualListMode = 'topToBottom' | 'bottomToTop';
10
10
  *
11
11
  * @typedef {Object} SvelteVirtualListProps
12
12
  */
13
- export type SvelteVirtualListProps = {
13
+ export type SvelteVirtualListProps<TItem = any> = {
14
14
  /**
15
15
  * Number of items to render outside the visible viewport for smooth scrolling.
16
16
  * @default 20
@@ -41,7 +41,7 @@ export type SvelteVirtualListProps = {
41
41
  /**
42
42
  * The complete array of items to be virtualized.
43
43
  */
44
- items: any[];
44
+ items: TItem[];
45
45
  /**
46
46
  * CSS class to apply to individual item containers.
47
47
  */
@@ -54,7 +54,7 @@ export type SvelteVirtualListProps = {
54
54
  /**
55
55
  * Svelte snippet function that defines how each item should be rendered. Receives the item and its index as arguments.
56
56
  */
57
- renderItem: Snippet<[item: any, index: number]>;
57
+ renderItem: Snippet<[item: TItem, index: number]>;
58
58
  /**
59
59
  * Base test ID for component elements to facilitate testing.
60
60
  */
@@ -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,8 +85,14 @@ 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
- export type SvelteVirtualListScrollAlign = 'auto' | 'top' | 'bottom';
92
+ /**
93
+ * Alignment options for programmatic scrolling.
94
+ */
95
+ export type SvelteVirtualListScrollAlign = 'auto' | 'top' | 'bottom' | 'nearest';
86
96
  /**
87
97
  * Options for scrolling to a specific index in the virtual list.
88
98
  */
@@ -100,3 +110,12 @@ export interface SvelteVirtualListScrollOptions {
100
110
  * Default options for scrolling.
101
111
  */
102
112
  export declare const DEFAULT_SCROLL_OPTIONS: Partial<SvelteVirtualListScrollOptions>;
113
+ export type SvelteVirtualListHeightCacheItem = {
114
+ currentHeight: number;
115
+ dirty: boolean;
116
+ };
117
+ export type SvelteVirtualListHeightCache = Record<number, SvelteVirtualListHeightCacheItem>;
118
+ export type SvelteVirtualListPreviousVisibleRange = {
119
+ start: number;
120
+ end: number;
121
+ };
@@ -1,24 +1,24 @@
1
- import type { HeightCache } from './types.js';
1
+ import type { SvelteVirtualListMode } from '../types.js';
2
2
  /**
3
3
  * Calculates and updates the average height of visible items with debouncing.
4
4
  *
5
5
  * This function optimizes performance by:
6
6
  * - Debouncing calculations to prevent excessive DOM reads (200ms default)
7
- * - Caching item heights to minimize recalculations
7
+ * - Caching item heights with dirty tracking to minimize recalculations
8
8
  * - Only updating when significant changes are detected (>1px difference)
9
9
  * - Early returns to prevent unnecessary processing
10
10
  *
11
11
  * Implementation details:
12
12
  * - Uses a debounce timeout to batch height calculations
13
13
  * - Tracks calculation state to prevent concurrent updates
14
- * - Caches heights in heightCache for reuse
14
+ * - Caches heights in heightCache with currentHeight and dirty flags for reuse
15
15
  * - Validates browser environment and calculation state
16
16
  * - Checks for meaningful height changes before updates
17
17
  *
18
18
  * State interactions:
19
19
  * - Updates calculatedItemHeight when significant changes occur
20
20
  * - Updates lastMeasuredIndex to track progress
21
- * - Modifies heightCache to store measured heights
21
+ * - Modifies heightCache to store measured heights with dirty tracking
22
22
  * - Uses isCalculatingHeight flag for concurrency control
23
23
  *
24
24
  * Guard clauses:
@@ -54,13 +54,14 @@ import type { HeightCache } from './types.js';
54
54
  * - Enhanced debounce timing precision
55
55
  * - Added proper cleanup for timeouts
56
56
  * - Documented all edge cases and failure modes
57
+ * - Updated to work with new HeightCache structure with dirty tracking
57
58
  *
58
59
  *
59
60
  * @param isCalculatingHeight - Flag to prevent concurrent calculations
60
61
  * @param heightUpdateTimeout - Reference to existing update timeout
61
62
  * @param visibleItemsGetter - Function to get current visible range
62
63
  * @param itemElements - Array of DOM elements to measure
63
- * @param heightCache - Cache of previously measured heights
64
+ * @param heightCache - Cache of previously measured heights with dirty tracking
64
65
  * @param lastMeasuredIndex - Index of last measured element
65
66
  * @param calculatedItemHeight - Current average height
66
67
  * @param onUpdate - Callback for height updates
@@ -70,8 +71,17 @@ import type { HeightCache } from './types.js';
70
71
  export declare const calculateAverageHeightDebounced: (isCalculatingHeight: boolean, heightUpdateTimeout: ReturnType<typeof setTimeout> | null, visibleItemsGetter: () => {
71
72
  start: number;
72
73
  end: number;
73
- }, itemElements: HTMLElement[], heightCache: HeightCache, lastMeasuredIndex: number, calculatedItemHeight: number, onUpdate: (result: {
74
+ }, itemElements: HTMLElement[], heightCache: Record<number, number>, lastMeasuredIndex: number, calculatedItemHeight: number, onUpdate: (result: {
74
75
  newHeight: number;
75
76
  newLastMeasuredIndex: number;
76
- updatedHeightCache: HeightCache;
77
- }) => void, debounceTime?: number) => NodeJS.Timeout | null;
77
+ updatedHeightCache: Record<number, number>;
78
+ clearedDirtyItems: Set<number>;
79
+ newTotalHeight: number;
80
+ newValidCount: number;
81
+ heightChanges: Array<{
82
+ index: number;
83
+ oldHeight: number;
84
+ newHeight: number;
85
+ delta: number;
86
+ }>;
87
+ }) => void, debounceTime: number, dirtyItems: Set<number>, currentTotalHeight?: number, currentValidCount?: number, mode?: SvelteVirtualListMode) => NodeJS.Timeout | null;
@@ -1,25 +1,25 @@
1
- import { BROWSER } from 'esm-env';
2
1
  import { calculateAverageHeight } from './virtualList.js';
2
+ import { BROWSER } from 'esm-env';
3
3
  /**
4
4
  * Calculates and updates the average height of visible items with debouncing.
5
5
  *
6
6
  * This function optimizes performance by:
7
7
  * - Debouncing calculations to prevent excessive DOM reads (200ms default)
8
- * - Caching item heights to minimize recalculations
8
+ * - Caching item heights with dirty tracking to minimize recalculations
9
9
  * - Only updating when significant changes are detected (>1px difference)
10
10
  * - Early returns to prevent unnecessary processing
11
11
  *
12
12
  * Implementation details:
13
13
  * - Uses a debounce timeout to batch height calculations
14
14
  * - Tracks calculation state to prevent concurrent updates
15
- * - Caches heights in heightCache for reuse
15
+ * - Caches heights in heightCache with currentHeight and dirty flags for reuse
16
16
  * - Validates browser environment and calculation state
17
17
  * - Checks for meaningful height changes before updates
18
18
  *
19
19
  * State interactions:
20
20
  * - Updates calculatedItemHeight when significant changes occur
21
21
  * - Updates lastMeasuredIndex to track progress
22
- * - Modifies heightCache to store measured heights
22
+ * - Modifies heightCache to store measured heights with dirty tracking
23
23
  * - Uses isCalculatingHeight flag for concurrency control
24
24
  *
25
25
  * Guard clauses:
@@ -55,13 +55,14 @@ import { calculateAverageHeight } from './virtualList.js';
55
55
  * - Enhanced debounce timing precision
56
56
  * - Added proper cleanup for timeouts
57
57
  * - Documented all edge cases and failure modes
58
+ * - Updated to work with new HeightCache structure with dirty tracking
58
59
  *
59
60
  *
60
61
  * @param isCalculatingHeight - Flag to prevent concurrent calculations
61
62
  * @param heightUpdateTimeout - Reference to existing update timeout
62
63
  * @param visibleItemsGetter - Function to get current visible range
63
64
  * @param itemElements - Array of DOM elements to measure
64
- * @param heightCache - Cache of previously measured heights
65
+ * @param heightCache - Cache of previously measured heights with dirty tracking
65
66
  * @param lastMeasuredIndex - Index of last measured element
66
67
  * @param calculatedItemHeight - Current average height
67
68
  * @param onUpdate - Callback for height updates
@@ -70,20 +71,26 @@ import { calculateAverageHeight } from './virtualList.js';
70
71
  */
71
72
  export const calculateAverageHeightDebounced = (isCalculatingHeight, heightUpdateTimeout, visibleItemsGetter, itemElements, heightCache, lastMeasuredIndex, calculatedItemHeight,
72
73
  /* trunk-ignore(eslint/no-unused-vars) */
73
- onUpdate, debounceTime = 200) => {
74
- if (!BROWSER || isCalculatingHeight || heightUpdateTimeout)
74
+ onUpdate, debounceTime, dirtyItems, currentTotalHeight = 0, currentValidCount = 0, mode = 'topToBottom') => {
75
+ if (!BROWSER || isCalculatingHeight)
75
76
  return null;
76
77
  const visibleRange = visibleItemsGetter();
77
78
  const currentIndex = visibleRange.start;
78
- if (currentIndex === lastMeasuredIndex)
79
+ if (currentIndex === lastMeasuredIndex && dirtyItems.size === 0)
79
80
  return null;
81
+ if (heightUpdateTimeout)
82
+ clearTimeout(heightUpdateTimeout);
80
83
  return setTimeout(() => {
81
- const { newHeight, newLastMeasuredIndex, updatedHeightCache } = calculateAverageHeight(itemElements, visibleRange, heightCache, calculatedItemHeight);
82
- if (Math.abs(newHeight - calculatedItemHeight) > 1) {
84
+ const { newHeight, newLastMeasuredIndex, updatedHeightCache, clearedDirtyItems, newTotalHeight, newValidCount, heightChanges } = calculateAverageHeight(itemElements, visibleRange, heightCache, calculatedItemHeight, dirtyItems, currentTotalHeight, currentValidCount, mode);
85
+ if (Math.abs(newHeight - calculatedItemHeight) > 1 || dirtyItems.size > 0) {
83
86
  onUpdate({
84
87
  newHeight,
85
88
  newLastMeasuredIndex,
86
- updatedHeightCache
89
+ updatedHeightCache,
90
+ clearedDirtyItems,
91
+ newTotalHeight,
92
+ newValidCount,
93
+ heightChanges
87
94
  });
88
95
  }
89
96
  }, debounceTime);
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Utility functions for detecting significant height changes in virtual list items
3
+ */
4
+ /**
5
+ * Checks if a height change is significant enough to warrant marking an item as dirty
6
+ * @param itemIndex - The index of the item
7
+ * @param newHeight - The new measured height
8
+ * @param heightCache - Existing height cache to compare against
9
+ * @param marginOfError - Height difference threshold (default: 1px)
10
+ * @returns true if the height change is significant
11
+ */
12
+ export declare const isSignificantHeightChange: (itemIndex: number, newHeight: number, heightCache: Record<number, number>, marginOfError?: number) => boolean;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Utility functions for detecting significant height changes in virtual list items
3
+ */
4
+ /**
5
+ * Checks if a height change is significant enough to warrant marking an item as dirty
6
+ * @param itemIndex - The index of the item
7
+ * @param newHeight - The new measured height
8
+ * @param heightCache - Existing height cache to compare against
9
+ * @param marginOfError - Height difference threshold (default: 1px)
10
+ * @returns true if the height change is significant
11
+ */
12
+ export const isSignificantHeightChange = (itemIndex, newHeight, heightCache, marginOfError = 1) => {
13
+ const previousHeight = heightCache[itemIndex];
14
+ if (previousHeight === undefined) {
15
+ // First time seeing this item, mark as significant
16
+ return true;
17
+ }
18
+ const heightDifference = Math.abs(newHeight - previousHeight);
19
+ return heightDifference > marginOfError;
20
+ };
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Configuration for item resize observation
3
+ */
4
+ export interface ItemResizeConfig {
5
+ /** Debug mode for logging resize events */
6
+ debug?: boolean;
7
+ /** Callback when items are marked as dirty */
8
+ onItemsDirty?: (dirtyIndices: Set<number>) => void;
9
+ }
10
+ /**
11
+ * Configuration for container resize observation
12
+ */
13
+ export interface ContainerResizeConfig {
14
+ /** Debug mode for logging resize events */
15
+ debug?: boolean;
16
+ /** Callback when container is resized */
17
+ onResize?: (entry: ResizeObserverEntry) => void;
18
+ }
19
+ /**
20
+ * Creates a ResizeObserver for monitoring container size changes.
21
+ *
22
+ * This function creates a ResizeObserver that watches for size changes in the
23
+ * virtual list container and triggers appropriate updates to height and scroll position.
24
+ *
25
+ * @param config - Configuration options
26
+ * @returns ResizeObserver instance
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * const containerResizeObserver = createContainerResizeObserver({
31
+ * debug: true,
32
+ * onResize: (entry) => {
33
+ * const newHeight = entry.contentRect.height
34
+ * updateHeightAndScroll(true)
35
+ * }
36
+ * })
37
+ *
38
+ * if (containerElement) {
39
+ * containerResizeObserver.observe(containerElement)
40
+ * }
41
+ * ```
42
+ */
43
+ export declare const createContainerResizeObserver: (config?: ContainerResizeConfig) => ResizeObserver;
44
+ /**
45
+ * Utility to safely observe elements with automatic cleanup.
46
+ *
47
+ * This function provides a safe way to observe elements with a ResizeObserver,
48
+ * handling cases where the observer might not be available or elements might be null.
49
+ *
50
+ * @param observer - ResizeObserver instance
51
+ * @param element - Element to observe
52
+ * @param debug - Whether to log debug information
53
+ * @returns Cleanup function to stop observing
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * const cleanup = safeObserve(resizeObserver, element, true)
58
+ *
59
+ * // Later, stop observing
60
+ * cleanup()
61
+ * ```
62
+ */
63
+ export declare const safeObserve: (observer: ResizeObserver | null, element: HTMLElement | null, debug?: boolean) => (() => void);
64
+ /**
65
+ * Manages multiple ResizeObserver instances with automatic cleanup.
66
+ *
67
+ * This class provides a convenient way to manage multiple ResizeObserver instances
68
+ * and ensures proper cleanup when the component is destroyed.
69
+ */
70
+ export declare class ResizeObserverManager {
71
+ private observers;
72
+ private cleanupFunctions;
73
+ /**
74
+ * Adds a ResizeObserver to the manager
75
+ */
76
+ addObserver(observer: ResizeObserver): void;
77
+ /**
78
+ * Adds a cleanup function to be called during cleanup
79
+ */
80
+ addCleanup(cleanup: () => void): void;
81
+ /**
82
+ * Observes an element with automatic cleanup tracking
83
+ */
84
+ observe(observer: ResizeObserver, element: HTMLElement, debug?: boolean): void;
85
+ /**
86
+ * Disconnects all observers and runs cleanup functions
87
+ */
88
+ cleanup(): void;
89
+ }