@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,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export function
|
|
3
|
-
const manager =
|
|
1
|
+
import { createListManager } from './index.js';
|
|
2
|
+
export function benchmarkListManager(itemCount, dirtyCount, iterations = 100) {
|
|
3
|
+
const manager = createListManager(itemCount);
|
|
4
4
|
const times = [];
|
|
5
5
|
for (let i = 0; i < iterations; i++) {
|
|
6
6
|
const dirtyResults = Array.from({ length: dirtyCount }, (_, idx) => ({
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
*
|
|
13
13
|
* @example Basic Usage
|
|
14
14
|
* ```typescript
|
|
15
|
-
* import {
|
|
15
|
+
* import { ReactiveListManager } from './reactive-list-manager'
|
|
16
16
|
*
|
|
17
|
-
* const manager = new
|
|
17
|
+
* const manager = new ReactiveListManager({
|
|
18
18
|
* itemLength: 10000,
|
|
19
|
-
*
|
|
19
|
+
* itemHeight: 40
|
|
20
20
|
* })
|
|
21
21
|
*
|
|
22
22
|
* // Process height changes incrementally
|
|
@@ -33,18 +33,14 @@
|
|
|
33
33
|
* console.log(`Measured: ${debugInfo.measuredCount}/${debugInfo.itemLength}`)
|
|
34
34
|
* ```
|
|
35
35
|
*/
|
|
36
|
-
export {
|
|
37
|
-
import {
|
|
38
|
-
export type { HeightChange,
|
|
36
|
+
export { ReactiveListManager } from './ReactiveListManager.svelte.js';
|
|
37
|
+
import { ReactiveListManager as ReactiveListManagerType } from './ReactiveListManager.svelte.js';
|
|
38
|
+
export type { HeightChange, ListManagerConfig, ListManagerDebugInfo } from './types.js';
|
|
39
39
|
export declare const VERSION = "1.0.0";
|
|
40
40
|
export declare const DEFAULT_ESTIMATED_HEIGHT = 40;
|
|
41
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;
|
|
42
|
+
export declare function createListManager(itemLength: number, itemHeight?: number): ReactiveListManagerType;
|
|
47
43
|
/**
|
|
48
44
|
* Performance benchmarking utility
|
|
49
45
|
*/
|
|
50
|
-
export {
|
|
46
|
+
export { benchmarkListManager } from './benchmark.js';
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
*
|
|
13
13
|
* @example Basic Usage
|
|
14
14
|
* ```typescript
|
|
15
|
-
* import {
|
|
15
|
+
* import { ReactiveListManager } from './reactive-list-manager'
|
|
16
16
|
*
|
|
17
|
-
* const manager = new
|
|
17
|
+
* const manager = new ReactiveListManager({
|
|
18
18
|
* itemLength: 10000,
|
|
19
|
-
*
|
|
19
|
+
* itemHeight: 40
|
|
20
20
|
* })
|
|
21
21
|
*
|
|
22
22
|
* // Process height changes incrementally
|
|
@@ -33,23 +33,20 @@
|
|
|
33
33
|
* console.log(`Measured: ${debugInfo.measuredCount}/${debugInfo.itemLength}`)
|
|
34
34
|
* ```
|
|
35
35
|
*/
|
|
36
|
-
// Export the main class
|
|
37
|
-
export {
|
|
38
|
-
import {
|
|
36
|
+
// Export the main class under the new name; keep legacy name as alias
|
|
37
|
+
export { ReactiveListManager } from './ReactiveListManager.svelte.js';
|
|
38
|
+
import { ReactiveListManager as ReactiveListManagerType } from './ReactiveListManager.svelte.js';
|
|
39
39
|
// Export version for potential npm package
|
|
40
40
|
export const VERSION = '1.0.0';
|
|
41
41
|
// Export utility constants
|
|
42
42
|
export const DEFAULT_ESTIMATED_HEIGHT = 40;
|
|
43
43
|
export const DEFAULT_MEASUREMENT_THRESHOLD = 10; // percentage
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
*/
|
|
48
|
-
export function createHeightManager(itemLength, itemHeight = DEFAULT_ESTIMATED_HEIGHT) {
|
|
49
|
-
return new ReactiveHeightManagerType({ itemLength, itemHeight });
|
|
44
|
+
// New factory alias with the renamed type
|
|
45
|
+
export function createListManager(itemLength, itemHeight = DEFAULT_ESTIMATED_HEIGHT) {
|
|
46
|
+
return new ReactiveListManagerType({ itemLength, itemHeight });
|
|
50
47
|
}
|
|
51
48
|
/**
|
|
52
49
|
* Performance benchmarking utility
|
|
53
50
|
*/
|
|
54
51
|
// Moved out to keep index clean; re-exported from benchmark.ts
|
|
55
|
-
export {
|
|
52
|
+
export { benchmarkListManager } from './benchmark.js';
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import type { HeightChange,
|
|
2
|
+
// untrack not used in this test component
|
|
3
|
+
import { ReactiveListManager } from '../../index.js'
|
|
4
|
+
import type { HeightChange, ListManagerConfig } from '../types.js'
|
|
5
5
|
|
|
6
6
|
interface Props {
|
|
7
|
-
config:
|
|
8
|
-
onReactiveUpdate?: (
|
|
7
|
+
config: ListManagerConfig
|
|
8
|
+
onReactiveUpdate?: (_data: {
|
|
9
9
|
totalHeight: number
|
|
10
10
|
measuredCount: number
|
|
11
11
|
effectRuns: number
|
|
12
12
|
}) => void
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
const { config, onReactiveUpdate }: Props = $props()
|
|
16
16
|
|
|
17
17
|
// Create the manager
|
|
18
|
-
const manager = new
|
|
18
|
+
const manager = new ReactiveListManager(config)
|
|
19
19
|
|
|
20
20
|
// Derived reactive values (clean, no side effects)
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
const currentTotalHeight = $derived(manager.totalHeight)
|
|
22
|
+
const currentMeasuredCount = $derived(manager.measuredCount)
|
|
23
23
|
|
|
24
24
|
// Effect run counter (non-reactive - just for tracking)
|
|
25
25
|
let effectRunCount = 0
|
package/dist/{reactive-height-manager → reactive-list-manager}/test/TestComponent.svelte.d.ts
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { HeightChange,
|
|
1
|
+
import { ReactiveListManager } from '../../index.js';
|
|
2
|
+
import type { HeightChange, ListManagerConfig } from '../types.js';
|
|
3
3
|
interface Props {
|
|
4
|
-
config:
|
|
5
|
-
onReactiveUpdate?: (
|
|
4
|
+
config: ListManagerConfig;
|
|
5
|
+
onReactiveUpdate?: (_data: {
|
|
6
6
|
totalHeight: number;
|
|
7
7
|
measuredCount: number;
|
|
8
8
|
effectRuns: number;
|
|
@@ -17,7 +17,7 @@ declare const TestComponent: import("svelte").Component<Props, {
|
|
|
17
17
|
measuredCount: number;
|
|
18
18
|
effectRuns: number;
|
|
19
19
|
};
|
|
20
|
-
getManager: () =>
|
|
20
|
+
getManager: () => ReactiveListManager;
|
|
21
21
|
}, "">;
|
|
22
22
|
type TestComponent = ReturnType<typeof TestComponent>;
|
|
23
23
|
export default TestComponent;
|
|
@@ -12,18 +12,20 @@ export interface HeightChange {
|
|
|
12
12
|
readonly newHeight: number | undefined;
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
|
-
* Configuration options for
|
|
15
|
+
* Configuration options for ReactiveListManager (formerly ReactiveListManager)
|
|
16
16
|
*/
|
|
17
|
-
export interface
|
|
17
|
+
export interface ListManagerConfig {
|
|
18
18
|
/** Total number of items in the list */
|
|
19
19
|
itemLength: number;
|
|
20
20
|
/** Height to use for unmeasured items */
|
|
21
21
|
itemHeight: number;
|
|
22
|
+
/** Whether to enable internal debug logging */
|
|
23
|
+
internalDebug?: boolean;
|
|
22
24
|
}
|
|
23
25
|
/**
|
|
24
26
|
* Debug information about the height manager state
|
|
25
27
|
*/
|
|
26
|
-
export interface
|
|
28
|
+
export interface ListManagerDebugInfo {
|
|
27
29
|
/** Total measured height of all measured items */
|
|
28
30
|
totalMeasuredHeight: number;
|
|
29
31
|
/** Number of items that have been measured */
|
|
@@ -38,4 +40,8 @@ export interface HeightManagerDebugInfo {
|
|
|
38
40
|
averageHeight: number;
|
|
39
41
|
/** Current total height (measured + estimated) */
|
|
40
42
|
totalHeight: number;
|
|
43
|
+
/** Whether CSS grid detected on items wrapper */
|
|
44
|
+
gridDetected: boolean;
|
|
45
|
+
/** Number of columns when grid detected */
|
|
46
|
+
gridColumns: number;
|
|
41
47
|
}
|
|
@@ -28,7 +28,7 @@ export declare const calculateScrollPosition: (totalItems: number, itemHeight: n
|
|
|
28
28
|
* @param {SvelteVirtualListMode} mode - Scroll direction mode
|
|
29
29
|
* @returns {SvelteVirtualListPreviousVisibleRange} Range of indices to render
|
|
30
30
|
*/
|
|
31
|
-
export declare const calculateVisibleRange: (scrollTop: number, viewportHeight: number, itemHeight: number, totalItems: number, bufferSize: number, mode: SvelteVirtualListMode, atBottom: boolean, wasAtBottomBeforeHeightChange: boolean, lastVisibleRange: SvelteVirtualListPreviousVisibleRange | null, totalContentHeight?: number) => SvelteVirtualListPreviousVisibleRange;
|
|
31
|
+
export declare const calculateVisibleRange: (scrollTop: number, viewportHeight: number, itemHeight: number, totalItems: number, bufferSize: number, mode: SvelteVirtualListMode, atBottom: boolean, wasAtBottomBeforeHeightChange: boolean, lastVisibleRange: SvelteVirtualListPreviousVisibleRange | null, totalContentHeight?: number, heightCache?: Record<number, number>) => SvelteVirtualListPreviousVisibleRange;
|
|
32
32
|
/**
|
|
33
33
|
* Calculates the CSS transform value for positioning the virtual list items.
|
|
34
34
|
*
|
|
@@ -44,7 +44,7 @@ export declare const calculateVisibleRange: (scrollTop: number, viewportHeight:
|
|
|
44
44
|
* @param {number} viewportHeight - Height of the viewport in pixels
|
|
45
45
|
* @returns {number} The calculated transform Y value in pixels
|
|
46
46
|
*/
|
|
47
|
-
export declare const calculateTransformY: (mode: SvelteVirtualListMode, totalItems: number, visibleEnd: number, visibleStart: number, itemHeight: number, viewportHeight: number, totalContentHeight?: number) => number;
|
|
47
|
+
export declare const calculateTransformY: (mode: SvelteVirtualListMode, totalItems: number, visibleEnd: number, visibleStart: number, itemHeight: number, viewportHeight: number, totalContentHeight?: number, heightCache?: Record<number, number>, measuredFallbackHeight?: number) => number;
|
|
48
48
|
/**
|
|
49
49
|
* Updates the virtual list's height and scroll position when necessary.
|
|
50
50
|
*
|
|
@@ -31,7 +31,7 @@ export const calculateScrollPosition = (totalItems, itemHeight, containerHeight)
|
|
|
31
31
|
* @param {SvelteVirtualListMode} mode - Scroll direction mode
|
|
32
32
|
* @returns {SvelteVirtualListPreviousVisibleRange} Range of indices to render
|
|
33
33
|
*/
|
|
34
|
-
export const calculateVisibleRange = (scrollTop, viewportHeight, itemHeight, totalItems, bufferSize, mode, atBottom, wasAtBottomBeforeHeightChange, lastVisibleRange, totalContentHeight) => {
|
|
34
|
+
export const calculateVisibleRange = (scrollTop, viewportHeight, itemHeight, totalItems, bufferSize, mode, atBottom, wasAtBottomBeforeHeightChange, lastVisibleRange, totalContentHeight, heightCache) => {
|
|
35
35
|
if (mode === 'bottomToTop') {
|
|
36
36
|
const visibleCount = Math.ceil(viewportHeight / itemHeight) + 1;
|
|
37
37
|
// In bottomToTop mode, scrollTop represents distance from the total content end
|
|
@@ -60,16 +60,25 @@ export const calculateVisibleRange = (scrollTop, viewportHeight, itemHeight, tot
|
|
|
60
60
|
// Safeguard for topToBottom: ensure last item is fully visible when at max scroll
|
|
61
61
|
const totalHeight = totalContentHeight ?? totalItems * itemHeight;
|
|
62
62
|
const maxScrollTop = Math.max(0, totalHeight - viewportHeight);
|
|
63
|
-
//
|
|
64
|
-
const tolerance = Math.max(
|
|
63
|
+
// Use strict tolerance to avoid premature bottom anchoring that leaves a visible gap
|
|
64
|
+
const tolerance = Math.max(1, Math.floor(itemHeight * 0.25)); // pixels, adaptive for wrong initial sizes
|
|
65
65
|
const isAtBottom = Math.abs(scrollTop - maxScrollTop) <= tolerance;
|
|
66
66
|
if (isAtBottom) {
|
|
67
|
-
//
|
|
67
|
+
// Pack from the end using measured heights when available: walk backward until viewport filled
|
|
68
68
|
const adjustedEnd = totalItems;
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
let startCore = adjustedEnd;
|
|
70
|
+
let acc = 0;
|
|
71
|
+
const getH = (i) => {
|
|
72
|
+
const v = heightCache ? heightCache[i] : undefined;
|
|
73
|
+
return Number.isFinite(v) && v > 0 ? v : itemHeight;
|
|
74
|
+
};
|
|
75
|
+
while (startCore > 0 && acc < viewportHeight) {
|
|
76
|
+
const h = getH(startCore - 1);
|
|
77
|
+
acc += h;
|
|
78
|
+
startCore -= 1;
|
|
79
|
+
}
|
|
71
80
|
return {
|
|
72
|
-
start:
|
|
81
|
+
start: Math.max(0, startCore - bufferSize),
|
|
73
82
|
end: adjustedEnd
|
|
74
83
|
};
|
|
75
84
|
}
|
|
@@ -97,17 +106,23 @@ export const calculateVisibleRange = (scrollTop, viewportHeight, itemHeight, tot
|
|
|
97
106
|
* @param {number} viewportHeight - Height of the viewport in pixels
|
|
98
107
|
* @returns {number} The calculated transform Y value in pixels
|
|
99
108
|
*/
|
|
100
|
-
export const calculateTransformY = (mode, totalItems, visibleEnd, visibleStart, itemHeight, viewportHeight, totalContentHeight) => {
|
|
109
|
+
export const calculateTransformY = (mode, totalItems, visibleEnd, visibleStart, itemHeight, viewportHeight, totalContentHeight, heightCache, measuredFallbackHeight) => {
|
|
110
|
+
const effectiveViewport = viewportHeight || measuredFallbackHeight || 0;
|
|
101
111
|
if (mode === 'bottomToTop') {
|
|
102
112
|
// In bottomToTop mode, position items so they stack from bottom up
|
|
103
113
|
const actualTotalHeight = totalContentHeight ?? totalItems * itemHeight;
|
|
104
114
|
// Calculate transform to position visible items correctly
|
|
105
115
|
const basicTransform = (totalItems - visibleEnd) * itemHeight;
|
|
106
116
|
// When content is smaller than viewport, push to bottom
|
|
107
|
-
const bottomOffset = Math.max(0,
|
|
117
|
+
const bottomOffset = Math.max(0, effectiveViewport - actualTotalHeight);
|
|
108
118
|
return basicTransform + bottomOffset;
|
|
109
119
|
}
|
|
110
120
|
else {
|
|
121
|
+
// For topToBottom, prefer precise offset using measured heights when available
|
|
122
|
+
if (heightCache) {
|
|
123
|
+
const offset = getScrollOffsetForIndex(heightCache, itemHeight, visibleStart);
|
|
124
|
+
return Math.max(0, Math.round(offset));
|
|
125
|
+
}
|
|
111
126
|
return visibleStart * itemHeight;
|
|
112
127
|
}
|
|
113
128
|
};
|
|
@@ -247,7 +262,9 @@ export const calculateAverageHeight = (itemElements, visibleRange, heightCache,
|
|
|
247
262
|
else {
|
|
248
263
|
// Original behavior: process all visible items
|
|
249
264
|
validElements.forEach((el, i) => {
|
|
250
|
-
const itemIndex =
|
|
265
|
+
const itemIndex = mode === 'bottomToTop'
|
|
266
|
+
? Math.max(0, (visibleRange.end ?? visibleRange.start + validElements.length) - 1 - i)
|
|
267
|
+
: visibleRange.start + i;
|
|
251
268
|
if (!newHeightCache[itemIndex]) {
|
|
252
269
|
try {
|
|
253
270
|
const height = el.getBoundingClientRect().height;
|
|
@@ -340,22 +357,32 @@ onComplete) => {
|
|
|
340
357
|
* const offset = getScrollOffsetForIndex(heightCache, calculatedItemHeight, 12345, blockSums);
|
|
341
358
|
*/
|
|
342
359
|
export const getScrollOffsetForIndex = (heightCache, calculatedItemHeight, idx, blockSums, blockSize = 1000) => {
|
|
343
|
-
|
|
360
|
+
// normalize and clamp index
|
|
361
|
+
const safeIdx = Math.max(0, Math.floor(idx));
|
|
362
|
+
if (safeIdx <= 0)
|
|
344
363
|
return 0;
|
|
345
364
|
if (!blockSums) {
|
|
346
365
|
// Fallback: O(n) for a single query
|
|
347
366
|
let offset = 0;
|
|
348
|
-
for (let i = 0; i <
|
|
349
|
-
const
|
|
367
|
+
for (let i = 0; i < safeIdx; i++) {
|
|
368
|
+
const raw = heightCache[i];
|
|
369
|
+
const height = Number.isFinite(raw) && raw > 0 ? raw : calculatedItemHeight;
|
|
350
370
|
offset += height;
|
|
351
371
|
}
|
|
352
372
|
return offset;
|
|
353
373
|
}
|
|
354
|
-
const blockIdx = Math.floor(
|
|
355
|
-
let
|
|
374
|
+
const blockIdx = Math.floor(safeIdx / blockSize);
|
|
375
|
+
let offsetBase = 0;
|
|
376
|
+
if (blockIdx > 0) {
|
|
377
|
+
const base = blockSums[blockIdx - 1];
|
|
378
|
+
offsetBase = Number.isFinite(base) ? base : 0;
|
|
379
|
+
}
|
|
380
|
+
let offset = offsetBase;
|
|
356
381
|
const start = blockIdx * blockSize;
|
|
357
|
-
for (let i = start; i <
|
|
358
|
-
|
|
382
|
+
for (let i = start; i < safeIdx; i++) {
|
|
383
|
+
const raw = heightCache[i];
|
|
384
|
+
const height = Number.isFinite(raw) && raw > 0 ? raw : calculatedItemHeight;
|
|
385
|
+
offset += height;
|
|
359
386
|
}
|
|
360
387
|
return offset;
|
|
361
388
|
};
|
package/package.json
CHANGED
|
@@ -1,134 +1,135 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
"
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
"
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
"
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
"
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
"
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
"
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
2
|
+
"name": "@humanspeak/svelte-virtual-list",
|
|
3
|
+
"version": "0.3.2",
|
|
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
|
+
"keywords": [
|
|
6
|
+
"svelte",
|
|
7
|
+
"virtual-list",
|
|
8
|
+
"virtual-scroll",
|
|
9
|
+
"infinite-scroll",
|
|
10
|
+
"performance",
|
|
11
|
+
"ui-component",
|
|
12
|
+
"svelte5",
|
|
13
|
+
"dom-recycling",
|
|
14
|
+
"large-lists",
|
|
15
|
+
"scroll-optimization"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://virtuallist.svelte.page",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/humanspeak/svelte-virtual-list/issues"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/humanspeak/svelte-virtual-list.git"
|
|
24
|
+
},
|
|
25
|
+
"funding": {
|
|
26
|
+
"type": "github",
|
|
27
|
+
"url": "https://github.com/sponsors/humanspeak"
|
|
28
|
+
},
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"author": "Humanspeak, Inc.",
|
|
31
|
+
"sideEffects": [
|
|
32
|
+
"**/*.css"
|
|
33
|
+
],
|
|
34
|
+
"type": "module",
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"svelte": "./dist/index.js"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"svelte": "./dist/index.js",
|
|
42
|
+
"types": "./dist/index.d.ts",
|
|
43
|
+
"files": [
|
|
44
|
+
"dist",
|
|
45
|
+
"!dist/**/*.test.*",
|
|
46
|
+
"!dist/**/*.spec.*",
|
|
47
|
+
"!dist/test/**/*"
|
|
48
|
+
],
|
|
49
|
+
"overrides": {
|
|
50
|
+
"@sveltejs/kit": {
|
|
51
|
+
"cookie": "^0.7.0"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"esm-env": "^1.2.2"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@eslint/compat": "^1.3.2",
|
|
59
|
+
"@eslint/js": "^9.34.0",
|
|
60
|
+
"@faker-js/faker": "^10.0.0",
|
|
61
|
+
"@playwright/test": "^1.55.0",
|
|
62
|
+
"@sveltejs/adapter-auto": "^6.1.0",
|
|
63
|
+
"@sveltejs/kit": "^2.37.0",
|
|
64
|
+
"@sveltejs/package": "^2.5.0",
|
|
65
|
+
"@sveltejs/vite-plugin-svelte": "^6.1.3",
|
|
66
|
+
"@tailwindcss/vite": "^4.1.12",
|
|
67
|
+
"@testing-library/jest-dom": "^6.8.0",
|
|
68
|
+
"@testing-library/svelte": "^5.2.8",
|
|
69
|
+
"@testing-library/user-event": "^14.6.1",
|
|
70
|
+
"@types/node": "^24.3.0",
|
|
71
|
+
"@typescript-eslint/eslint-plugin": "^8.41.0",
|
|
72
|
+
"@typescript-eslint/parser": "^8.41.0",
|
|
73
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
74
|
+
"eslint": "^9.34.0",
|
|
75
|
+
"eslint-config-prettier": "^10.1.8",
|
|
76
|
+
"eslint-plugin-import": "^2.32.0",
|
|
77
|
+
"eslint-plugin-svelte": "^3.11.0",
|
|
78
|
+
"eslint-plugin-unused-imports": "^4.2.0",
|
|
79
|
+
"globals": "^16.3.0",
|
|
80
|
+
"husky": "^9.1.7",
|
|
81
|
+
"jsdom": "^26.1.0",
|
|
82
|
+
"prettier": "^3.6.2",
|
|
83
|
+
"prettier-plugin-organize-imports": "^4.2.0",
|
|
84
|
+
"prettier-plugin-sort-json": "^4.1.1",
|
|
85
|
+
"prettier-plugin-svelte": "^3.4.0",
|
|
86
|
+
"prettier-plugin-tailwindcss": "^0.6.14",
|
|
87
|
+
"publint": "^0.3.12",
|
|
88
|
+
"svelte": "^5.38.6",
|
|
89
|
+
"svelte-check": "^4.3.1",
|
|
90
|
+
"tailwindcss": "^4.1.12",
|
|
91
|
+
"tw-animate-css": "^1.3.7",
|
|
92
|
+
"typescript": "^5.9.2",
|
|
93
|
+
"typescript-eslint": "^8.41.0",
|
|
94
|
+
"vite": "^7.1.3",
|
|
95
|
+
"vitest": "^3.2.4"
|
|
96
|
+
},
|
|
97
|
+
"peerDependencies": {
|
|
98
|
+
"svelte": "^5.0.0"
|
|
99
|
+
},
|
|
100
|
+
"volta": {
|
|
101
|
+
"node": "22.18.0"
|
|
102
|
+
},
|
|
103
|
+
"publishConfig": {
|
|
104
|
+
"access": "public"
|
|
105
|
+
},
|
|
106
|
+
"tags": [
|
|
107
|
+
"svelte",
|
|
108
|
+
"virtual-list",
|
|
109
|
+
"virtual-scroll",
|
|
110
|
+
"virtual-scroller",
|
|
111
|
+
"infinite-scroll",
|
|
112
|
+
"performance",
|
|
113
|
+
"ui-component",
|
|
114
|
+
"svelte5"
|
|
115
|
+
],
|
|
116
|
+
"scripts": {
|
|
117
|
+
"build": "vite build && pnpm run package",
|
|
118
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
119
|
+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
120
|
+
"dev": "vite dev",
|
|
121
|
+
"format": "prettier --write .",
|
|
122
|
+
"lint": "prettier --check . && eslint .",
|
|
123
|
+
"lint:fix": "pnpm run format && eslint . --fix",
|
|
124
|
+
"package": "svelte-kit sync && svelte-package && publint",
|
|
125
|
+
"preview": "vite preview",
|
|
126
|
+
"test": "vitest run --coverage --",
|
|
127
|
+
"test:all": "pnpm run test && pnpm run test:e2e",
|
|
128
|
+
"test:e2e": "playwright test",
|
|
129
|
+
"test:e2e:debug": "playwright test --debug",
|
|
130
|
+
"test:e2e:report": "playwright show-report",
|
|
131
|
+
"test:e2e:ui": "playwright test --ui",
|
|
132
|
+
"test:only": "vitest run --",
|
|
133
|
+
"test:watch": "vitest --"
|
|
134
|
+
}
|
|
135
|
+
}
|