@humanspeak/svelte-virtual-list 0.3.1-beta.1 → 0.3.2
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 +262 -191
- package/dist/SvelteVirtualList.svelte.d.ts +5 -5
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/{reactive-height-manager → reactive-list-manager}/INTEGRATION_EXAMPLE.md +10 -10
- package/dist/{reactive-height-manager → reactive-list-manager}/README.md +17 -17
- package/dist/reactive-list-manager/ReactiveListManager.svelte.d.ts +221 -0
- package/dist/reactive-list-manager/ReactiveListManager.svelte.js +635 -0
- package/dist/reactive-list-manager/RecomputeScheduler.d.ts +12 -0
- package/dist/reactive-list-manager/RecomputeScheduler.js +54 -0
- package/dist/reactive-list-manager/benchmark.d.ts +5 -0
- package/dist/{reactive-height-manager → reactive-list-manager}/benchmark.js +3 -3
- package/dist/{reactive-height-manager → reactive-list-manager}/index.d.ts +8 -12
- package/dist/{reactive-height-manager → reactive-list-manager}/index.js +10 -13
- package/dist/{reactive-height-manager → reactive-list-manager}/test/TestComponent.svelte +9 -9
- package/dist/{reactive-height-manager → reactive-list-manager}/test/TestComponent.svelte.d.ts +5 -5
- package/dist/{reactive-height-manager → reactive-list-manager}/types.d.ts +9 -3
- package/dist/utils/virtualList.d.ts +2 -2
- package/dist/utils/virtualList.js +44 -17
- package/package.json +134 -133
- package/dist/reactive-height-manager/ReactiveHeightManager.svelte.d.ts +0 -116
- package/dist/reactive-height-manager/ReactiveHeightManager.svelte.js +0 -200
- package/dist/reactive-height-manager/benchmark.d.ts +0 -5
- package/dist/utils/resizeObserver.d.ts +0 -89
- package/dist/utils/resizeObserver.js +0 -119
- /package/dist/{reactive-height-manager → reactive-list-manager}/types.js +0 -0
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import type { HeightChange, HeightManagerConfig, HeightManagerDebugInfo } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* ReactiveHeightManager - A standalone reactive height calculation system
|
|
4
|
-
*
|
|
5
|
-
* Efficiently manages height calculations for virtualized lists by:
|
|
6
|
-
* - Tracking measured vs unmeasured items incrementally
|
|
7
|
-
* - Processing only dirty/changed items (O(dirty) instead of O(all))
|
|
8
|
-
* - Providing reactive state updates using Svelte 5 runes
|
|
9
|
-
* - Maintaining accurate total height calculations
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```typescript
|
|
13
|
-
* const manager = new ReactiveHeightManager({ itemLength: 10000, estimatedHeight: 40 })
|
|
14
|
-
*
|
|
15
|
-
* // Process height changes incrementally
|
|
16
|
-
* manager.processDirtyHeights(dirtyResults)
|
|
17
|
-
*
|
|
18
|
-
* // Update calculated item height
|
|
19
|
-
* manager.calculatedItemHeight = 42
|
|
20
|
-
*
|
|
21
|
-
* // Get reactive total height (automatically updates)
|
|
22
|
-
* const totalHeight = manager.totalHeight
|
|
23
|
-
* ```
|
|
24
|
-
*/
|
|
25
|
-
export declare class ReactiveHeightManager {
|
|
26
|
-
private _totalMeasuredHeight;
|
|
27
|
-
private _measuredCount;
|
|
28
|
-
private _itemLength;
|
|
29
|
-
private _itemHeight;
|
|
30
|
-
private _averageHeight;
|
|
31
|
-
private _totalHeight;
|
|
32
|
-
private _measuredFlags;
|
|
33
|
-
private recomputeDerivedHeights;
|
|
34
|
-
/**
|
|
35
|
-
* Get total measured height of all measured items
|
|
36
|
-
*/
|
|
37
|
-
get totalMeasuredHeight(): number;
|
|
38
|
-
/**
|
|
39
|
-
* Get count of items that have been measured
|
|
40
|
-
*/
|
|
41
|
-
get measuredCount(): number;
|
|
42
|
-
/**
|
|
43
|
-
* Get total number of items in the list
|
|
44
|
-
*/
|
|
45
|
-
get itemLength(): number;
|
|
46
|
-
/**
|
|
47
|
-
* Get/Set the height to use for unmeasured items (reactive)
|
|
48
|
-
*/
|
|
49
|
-
get itemHeight(): number;
|
|
50
|
-
set itemHeight(value: number);
|
|
51
|
-
/**
|
|
52
|
-
* Get the calculated average height of measured items
|
|
53
|
-
* Falls back to itemHeight if no items have been measured yet
|
|
54
|
-
*/
|
|
55
|
-
get averageHeight(): number;
|
|
56
|
-
/**
|
|
57
|
-
* Get the reactive total height of all items (measured + estimated)
|
|
58
|
-
* This automatically updates when any dependencies change
|
|
59
|
-
*/
|
|
60
|
-
get totalHeight(): number;
|
|
61
|
-
/**
|
|
62
|
-
* Create a new ReactiveHeightManager instance
|
|
63
|
-
*
|
|
64
|
-
* @param config - Configuration object containing itemLength and itemHeight
|
|
65
|
-
*/
|
|
66
|
-
constructor(config: HeightManagerConfig);
|
|
67
|
-
/**
|
|
68
|
-
* Process height changes incrementally - O(dirty items) instead of O(all items)
|
|
69
|
-
*
|
|
70
|
-
* This is the core optimization: instead of recalculating totals for all items,
|
|
71
|
-
* we only process the items that have changed, maintaining running totals.
|
|
72
|
-
*
|
|
73
|
-
* Accepts any object that has index, oldHeight, and newHeight properties,
|
|
74
|
-
* allowing consumers to pass objects with additional fields.
|
|
75
|
-
*
|
|
76
|
-
* @param dirtyResults - Array of height changes to process
|
|
77
|
-
*/
|
|
78
|
-
processDirtyHeights(dirtyResults: HeightChange[]): void;
|
|
79
|
-
/**
|
|
80
|
-
* Update when items array length changes
|
|
81
|
-
*
|
|
82
|
-
* @param newLength - New total number of items
|
|
83
|
-
*/
|
|
84
|
-
updateItemLength(newLength: number): void;
|
|
85
|
-
/**
|
|
86
|
-
* Update estimated height for unmeasured items
|
|
87
|
-
*
|
|
88
|
-
* @param newEstimatedHeight - New estimated height
|
|
89
|
-
*/
|
|
90
|
-
updateEstimatedHeight(newEstimatedHeight: number): void;
|
|
91
|
-
/**
|
|
92
|
-
* Reset all state to initial values
|
|
93
|
-
*
|
|
94
|
-
* Useful for testing or when completely reinitializing the list
|
|
95
|
-
*/
|
|
96
|
-
reset(): void;
|
|
97
|
-
/**
|
|
98
|
-
* Get comprehensive debug information
|
|
99
|
-
*
|
|
100
|
-
* @returns Debug information object
|
|
101
|
-
*/
|
|
102
|
-
getDebugInfo(): HeightManagerDebugInfo;
|
|
103
|
-
/**
|
|
104
|
-
* Get the percentage of items that have been measured
|
|
105
|
-
*
|
|
106
|
-
* @returns Percentage (0-100) of measured items
|
|
107
|
-
*/
|
|
108
|
-
getMeasurementCoverage(): number;
|
|
109
|
-
/**
|
|
110
|
-
* Check if the manager has sufficient measurement data
|
|
111
|
-
*
|
|
112
|
-
* @param threshold - Minimum percentage of items that should be measured (default: 10)
|
|
113
|
-
* @returns true if coverage meets threshold
|
|
114
|
-
*/
|
|
115
|
-
hasSufficientMeasurements(threshold?: number): boolean;
|
|
116
|
-
}
|
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ReactiveHeightManager - A standalone reactive height calculation system
|
|
3
|
-
*
|
|
4
|
-
* Efficiently manages height calculations for virtualized lists by:
|
|
5
|
-
* - Tracking measured vs unmeasured items incrementally
|
|
6
|
-
* - Processing only dirty/changed items (O(dirty) instead of O(all))
|
|
7
|
-
* - Providing reactive state updates using Svelte 5 runes
|
|
8
|
-
* - Maintaining accurate total height calculations
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```typescript
|
|
12
|
-
* const manager = new ReactiveHeightManager({ itemLength: 10000, estimatedHeight: 40 })
|
|
13
|
-
*
|
|
14
|
-
* // Process height changes incrementally
|
|
15
|
-
* manager.processDirtyHeights(dirtyResults)
|
|
16
|
-
*
|
|
17
|
-
* // Update calculated item height
|
|
18
|
-
* manager.calculatedItemHeight = 42
|
|
19
|
-
*
|
|
20
|
-
* // Get reactive total height (automatically updates)
|
|
21
|
-
* const totalHeight = manager.totalHeight
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
export class ReactiveHeightManager {
|
|
25
|
-
// Reactive state using Svelte 5 runes
|
|
26
|
-
_totalMeasuredHeight = $state(0);
|
|
27
|
-
_measuredCount = $state(0);
|
|
28
|
-
_itemLength = $state(0);
|
|
29
|
-
_itemHeight = $state(40);
|
|
30
|
-
_averageHeight = $state(40);
|
|
31
|
-
_totalHeight = $state(0);
|
|
32
|
-
_measuredFlags = null;
|
|
33
|
-
recomputeDerivedHeights() {
|
|
34
|
-
const average = this._measuredCount > 0
|
|
35
|
-
? this._totalMeasuredHeight / this._measuredCount
|
|
36
|
-
: this._itemHeight;
|
|
37
|
-
this._averageHeight = average;
|
|
38
|
-
const unmeasuredCount = this._itemLength - this._measuredCount;
|
|
39
|
-
this._totalHeight = this._totalMeasuredHeight + unmeasuredCount * average;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Get total measured height of all measured items
|
|
43
|
-
*/
|
|
44
|
-
get totalMeasuredHeight() {
|
|
45
|
-
return this._totalMeasuredHeight;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Get count of items that have been measured
|
|
49
|
-
*/
|
|
50
|
-
get measuredCount() {
|
|
51
|
-
return this._measuredCount;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Get total number of items in the list
|
|
55
|
-
*/
|
|
56
|
-
get itemLength() {
|
|
57
|
-
return this._itemLength;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Get/Set the height to use for unmeasured items (reactive)
|
|
61
|
-
*/
|
|
62
|
-
get itemHeight() {
|
|
63
|
-
return this._itemHeight;
|
|
64
|
-
}
|
|
65
|
-
set itemHeight(value) {
|
|
66
|
-
this._itemHeight = value;
|
|
67
|
-
this.recomputeDerivedHeights();
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Get the calculated average height of measured items
|
|
71
|
-
* Falls back to itemHeight if no items have been measured yet
|
|
72
|
-
*/
|
|
73
|
-
get averageHeight() {
|
|
74
|
-
return this._averageHeight;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Get the reactive total height of all items (measured + estimated)
|
|
78
|
-
* This automatically updates when any dependencies change
|
|
79
|
-
*/
|
|
80
|
-
get totalHeight() {
|
|
81
|
-
return this._totalHeight;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Create a new ReactiveHeightManager instance
|
|
85
|
-
*
|
|
86
|
-
* @param config - Configuration object containing itemLength and itemHeight
|
|
87
|
-
*/
|
|
88
|
-
constructor(config) {
|
|
89
|
-
this._itemLength = config.itemLength;
|
|
90
|
-
this._itemHeight = config.itemHeight;
|
|
91
|
-
this._measuredFlags = new Uint8Array(Math.max(0, this._itemLength));
|
|
92
|
-
this.recomputeDerivedHeights();
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Process height changes incrementally - O(dirty items) instead of O(all items)
|
|
96
|
-
*
|
|
97
|
-
* This is the core optimization: instead of recalculating totals for all items,
|
|
98
|
-
* we only process the items that have changed, maintaining running totals.
|
|
99
|
-
*
|
|
100
|
-
* Accepts any object that has index, oldHeight, and newHeight properties,
|
|
101
|
-
* allowing consumers to pass objects with additional fields.
|
|
102
|
-
*
|
|
103
|
-
* @param dirtyResults - Array of height changes to process
|
|
104
|
-
*/
|
|
105
|
-
processDirtyHeights(dirtyResults) {
|
|
106
|
-
if (dirtyResults.length === 0)
|
|
107
|
-
return;
|
|
108
|
-
// Batch calculate changes to trigger reactivity only once
|
|
109
|
-
let heightDelta = 0;
|
|
110
|
-
let countDelta = 0;
|
|
111
|
-
for (const change of dirtyResults) {
|
|
112
|
-
const { index, oldHeight, newHeight } = change;
|
|
113
|
-
// Remove old contribution if it existed
|
|
114
|
-
if (oldHeight !== undefined) {
|
|
115
|
-
heightDelta -= oldHeight;
|
|
116
|
-
countDelta -= 1;
|
|
117
|
-
}
|
|
118
|
-
// Add new contribution
|
|
119
|
-
if (newHeight !== undefined) {
|
|
120
|
-
heightDelta += newHeight;
|
|
121
|
-
countDelta += 1;
|
|
122
|
-
}
|
|
123
|
-
// Track measured flag (best-effort; full coalescing handled separately)
|
|
124
|
-
if (this._measuredFlags && index >= 0 && index < this._measuredFlags.length) {
|
|
125
|
-
this._measuredFlags[index] = 1;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
if (heightDelta === 0 && countDelta === 0)
|
|
129
|
-
return;
|
|
130
|
-
// Apply all changes at once - triggers reactivity only once
|
|
131
|
-
this._totalMeasuredHeight += heightDelta;
|
|
132
|
-
this._measuredCount += countDelta;
|
|
133
|
-
this.recomputeDerivedHeights();
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Update when items array length changes
|
|
137
|
-
*
|
|
138
|
-
* @param newLength - New total number of items
|
|
139
|
-
*/
|
|
140
|
-
updateItemLength(newLength) {
|
|
141
|
-
this._itemLength = newLength;
|
|
142
|
-
this._measuredFlags = new Uint8Array(Math.max(0, newLength));
|
|
143
|
-
this.recomputeDerivedHeights();
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Update estimated height for unmeasured items
|
|
147
|
-
*
|
|
148
|
-
* @param newEstimatedHeight - New estimated height
|
|
149
|
-
*/
|
|
150
|
-
updateEstimatedHeight(newEstimatedHeight) {
|
|
151
|
-
// Keep a single source of truth for the estimated height
|
|
152
|
-
this._itemHeight = newEstimatedHeight;
|
|
153
|
-
this.recomputeDerivedHeights();
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Reset all state to initial values
|
|
157
|
-
*
|
|
158
|
-
* Useful for testing or when completely reinitializing the list
|
|
159
|
-
*/
|
|
160
|
-
reset() {
|
|
161
|
-
this._totalMeasuredHeight = 0;
|
|
162
|
-
this._measuredCount = 0;
|
|
163
|
-
this._measuredFlags = this._itemLength > 0 ? new Uint8Array(this._itemLength) : null;
|
|
164
|
-
// Note: Don't reset _itemLength, _itemHeight as they represent configuration, not measured state
|
|
165
|
-
this.recomputeDerivedHeights();
|
|
166
|
-
}
|
|
167
|
-
/**
|
|
168
|
-
* Get comprehensive debug information
|
|
169
|
-
*
|
|
170
|
-
* @returns Debug information object
|
|
171
|
-
*/
|
|
172
|
-
getDebugInfo() {
|
|
173
|
-
return {
|
|
174
|
-
totalMeasuredHeight: this._totalMeasuredHeight,
|
|
175
|
-
measuredCount: this._measuredCount,
|
|
176
|
-
itemLength: this._itemLength,
|
|
177
|
-
coveragePercent: this._itemLength > 0 ? (this._measuredCount / this._itemLength) * 100 : 0,
|
|
178
|
-
itemHeight: this._itemHeight,
|
|
179
|
-
averageHeight: this.averageHeight,
|
|
180
|
-
totalHeight: this.totalHeight
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Get the percentage of items that have been measured
|
|
185
|
-
*
|
|
186
|
-
* @returns Percentage (0-100) of measured items
|
|
187
|
-
*/
|
|
188
|
-
getMeasurementCoverage() {
|
|
189
|
-
return this.getDebugInfo().coveragePercent;
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Check if the manager has sufficient measurement data
|
|
193
|
-
*
|
|
194
|
-
* @param threshold - Minimum percentage of items that should be measured (default: 10)
|
|
195
|
-
* @returns true if coverage meets threshold
|
|
196
|
-
*/
|
|
197
|
-
hasSufficientMeasurements(threshold = 10) {
|
|
198
|
-
return this.getMeasurementCoverage() >= threshold;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Creates a ResizeObserver for monitoring container size changes.
|
|
3
|
-
*
|
|
4
|
-
* This function creates a ResizeObserver that watches for size changes in the
|
|
5
|
-
* virtual list container and triggers appropriate updates to height and scroll position.
|
|
6
|
-
*
|
|
7
|
-
* @param config - Configuration options
|
|
8
|
-
* @returns ResizeObserver instance
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```typescript
|
|
12
|
-
* const containerResizeObserver = createContainerResizeObserver({
|
|
13
|
-
* debug: true,
|
|
14
|
-
* onResize: (entry) => {
|
|
15
|
-
* const newHeight = entry.contentRect.height
|
|
16
|
-
* updateHeightAndScroll(true)
|
|
17
|
-
* }
|
|
18
|
-
* })
|
|
19
|
-
*
|
|
20
|
-
* if (containerElement) {
|
|
21
|
-
* containerResizeObserver.observe(containerElement)
|
|
22
|
-
* }
|
|
23
|
-
* ```
|
|
24
|
-
*/
|
|
25
|
-
export const createContainerResizeObserver = (config = {}) => {
|
|
26
|
-
const { debug = false, onResize } = config;
|
|
27
|
-
return new ResizeObserver((entries) => {
|
|
28
|
-
for (const entry of entries) {
|
|
29
|
-
if (debug) {
|
|
30
|
-
console.log('Container resized:', entry.contentRect);
|
|
31
|
-
}
|
|
32
|
-
onResize?.(entry);
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
};
|
|
36
|
-
/**
|
|
37
|
-
* Utility to safely observe elements with automatic cleanup.
|
|
38
|
-
*
|
|
39
|
-
* This function provides a safe way to observe elements with a ResizeObserver,
|
|
40
|
-
* handling cases where the observer might not be available or elements might be null.
|
|
41
|
-
*
|
|
42
|
-
* @param observer - ResizeObserver instance
|
|
43
|
-
* @param element - Element to observe
|
|
44
|
-
* @param debug - Whether to log debug information
|
|
45
|
-
* @returns Cleanup function to stop observing
|
|
46
|
-
*
|
|
47
|
-
* @example
|
|
48
|
-
* ```typescript
|
|
49
|
-
* const cleanup = safeObserve(resizeObserver, element, true)
|
|
50
|
-
*
|
|
51
|
-
* // Later, stop observing
|
|
52
|
-
* cleanup()
|
|
53
|
-
* ```
|
|
54
|
-
*/
|
|
55
|
-
export const safeObserve = (observer, element, debug = false) => {
|
|
56
|
-
if (observer && element) {
|
|
57
|
-
observer.observe(element);
|
|
58
|
-
if (debug) {
|
|
59
|
-
console.log('Started observing element:', element);
|
|
60
|
-
}
|
|
61
|
-
return () => {
|
|
62
|
-
if (observer && element) {
|
|
63
|
-
observer.unobserve(element);
|
|
64
|
-
if (debug) {
|
|
65
|
-
console.log('Stopped observing element:', element);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
if (debug && !observer) {
|
|
71
|
-
console.log('ResizeObserver not available for element:', element);
|
|
72
|
-
}
|
|
73
|
-
return () => { }; // No-op cleanup function
|
|
74
|
-
};
|
|
75
|
-
/**
|
|
76
|
-
* Manages multiple ResizeObserver instances with automatic cleanup.
|
|
77
|
-
*
|
|
78
|
-
* This class provides a convenient way to manage multiple ResizeObserver instances
|
|
79
|
-
* and ensures proper cleanup when the component is destroyed.
|
|
80
|
-
*/
|
|
81
|
-
export class ResizeObserverManager {
|
|
82
|
-
observers = [];
|
|
83
|
-
cleanupFunctions = [];
|
|
84
|
-
/**
|
|
85
|
-
* Adds a ResizeObserver to the manager
|
|
86
|
-
*/
|
|
87
|
-
addObserver(observer) {
|
|
88
|
-
this.observers.push(observer);
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Adds a cleanup function to be called during cleanup
|
|
92
|
-
*/
|
|
93
|
-
addCleanup(cleanup) {
|
|
94
|
-
this.cleanupFunctions.push(cleanup);
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Observes an element with automatic cleanup tracking
|
|
98
|
-
*/
|
|
99
|
-
observe(observer, element, debug = false) {
|
|
100
|
-
const cleanup = safeObserve(observer, element, debug);
|
|
101
|
-
this.addCleanup(cleanup);
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Disconnects all observers and runs cleanup functions
|
|
105
|
-
*/
|
|
106
|
-
cleanup() {
|
|
107
|
-
// Disconnect all observers
|
|
108
|
-
for (const observer of this.observers) {
|
|
109
|
-
observer.disconnect();
|
|
110
|
-
}
|
|
111
|
-
// Run all cleanup functions
|
|
112
|
-
for (const cleanup of this.cleanupFunctions) {
|
|
113
|
-
cleanup();
|
|
114
|
-
}
|
|
115
|
-
// Clear arrays
|
|
116
|
-
this.observers.length = 0;
|
|
117
|
-
this.cleanupFunctions.length = 0;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
File without changes
|