@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.
Files changed (26) hide show
  1. package/dist/SvelteVirtualList.svelte +262 -191
  2. package/dist/SvelteVirtualList.svelte.d.ts +5 -5
  3. package/dist/index.d.ts +3 -1
  4. package/dist/index.js +2 -0
  5. package/dist/{reactive-height-manager → reactive-list-manager}/INTEGRATION_EXAMPLE.md +10 -10
  6. package/dist/{reactive-height-manager → reactive-list-manager}/README.md +17 -17
  7. package/dist/reactive-list-manager/ReactiveListManager.svelte.d.ts +221 -0
  8. package/dist/reactive-list-manager/ReactiveListManager.svelte.js +635 -0
  9. package/dist/reactive-list-manager/RecomputeScheduler.d.ts +12 -0
  10. package/dist/reactive-list-manager/RecomputeScheduler.js +54 -0
  11. package/dist/reactive-list-manager/benchmark.d.ts +5 -0
  12. package/dist/{reactive-height-manager → reactive-list-manager}/benchmark.js +3 -3
  13. package/dist/{reactive-height-manager → reactive-list-manager}/index.d.ts +8 -12
  14. package/dist/{reactive-height-manager → reactive-list-manager}/index.js +10 -13
  15. package/dist/{reactive-height-manager → reactive-list-manager}/test/TestComponent.svelte +9 -9
  16. package/dist/{reactive-height-manager → reactive-list-manager}/test/TestComponent.svelte.d.ts +5 -5
  17. package/dist/{reactive-height-manager → reactive-list-manager}/types.d.ts +9 -3
  18. package/dist/utils/virtualList.d.ts +2 -2
  19. package/dist/utils/virtualList.js +44 -17
  20. package/package.json +134 -133
  21. package/dist/reactive-height-manager/ReactiveHeightManager.svelte.d.ts +0 -116
  22. package/dist/reactive-height-manager/ReactiveHeightManager.svelte.js +0 -200
  23. package/dist/reactive-height-manager/benchmark.d.ts +0 -5
  24. package/dist/utils/resizeObserver.d.ts +0 -89
  25. package/dist/utils/resizeObserver.js +0 -119
  26. /package/dist/{reactive-height-manager → reactive-list-manager}/types.js +0 -0
@@ -1,6 +1,6 @@
1
- import { createHeightManager } from './index.js';
2
- export function benchmarkHeightManager(itemCount, dirtyCount, iterations = 100) {
3
- const manager = createHeightManager(itemCount);
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 { ReactiveHeightManager } from './reactive-height-manager'
15
+ * import { ReactiveListManager } from './reactive-list-manager'
16
16
  *
17
- * const manager = new ReactiveHeightManager({
17
+ * const manager = new ReactiveListManager({
18
18
  * itemLength: 10000,
19
- * estimatedHeight: 40
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 { ReactiveHeightManager } from './ReactiveHeightManager.svelte.js';
37
- import { ReactiveHeightManager as ReactiveHeightManagerType } from './ReactiveHeightManager.svelte.js';
38
- export type { HeightChange, HeightManagerConfig, HeightManagerDebugInfo } from './types.js';
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 { benchmarkHeightManager } from './benchmark.js';
46
+ export { benchmarkListManager } from './benchmark.js';
@@ -12,11 +12,11 @@
12
12
  *
13
13
  * @example Basic Usage
14
14
  * ```typescript
15
- * import { ReactiveHeightManager } from './reactive-height-manager'
15
+ * import { ReactiveListManager } from './reactive-list-manager'
16
16
  *
17
- * const manager = new ReactiveHeightManager({
17
+ * const manager = new ReactiveListManager({
18
18
  * itemLength: 10000,
19
- * estimatedHeight: 40
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 { ReactiveHeightManager } from './ReactiveHeightManager.svelte.js';
38
- import { ReactiveHeightManager as ReactiveHeightManagerType } from './ReactiveHeightManager.svelte.js';
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
- * 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 });
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 { benchmarkHeightManager } from './benchmark.js';
52
+ export { benchmarkListManager } from './benchmark.js';
@@ -1,25 +1,25 @@
1
1
  <script lang="ts">
2
- import { untrack } from 'svelte'
3
- import { ReactiveHeightManager } from '../ReactiveHeightManager.svelte.js'
4
- import type { HeightChange, HeightManagerConfig } from '../types.js'
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: HeightManagerConfig
8
- onReactiveUpdate?: (data: {
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
- let { config, onReactiveUpdate }: Props = $props()
15
+ const { config, onReactiveUpdate }: Props = $props()
16
16
 
17
17
  // Create the manager
18
- const manager = new ReactiveHeightManager(config)
18
+ const manager = new ReactiveListManager(config)
19
19
 
20
20
  // Derived reactive values (clean, no side effects)
21
- let currentTotalHeight = $derived(manager.totalHeight)
22
- let currentMeasuredCount = $derived(manager.measuredCount)
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
@@ -1,8 +1,8 @@
1
- import { ReactiveHeightManager } from '../ReactiveHeightManager.svelte.js';
2
- import type { HeightChange, HeightManagerConfig } from '../types.js';
1
+ import { ReactiveListManager } from '../../index.js';
2
+ import type { HeightChange, ListManagerConfig } from '../types.js';
3
3
  interface Props {
4
- config: HeightManagerConfig;
5
- onReactiveUpdate?: (data: {
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: () => ReactiveHeightManager;
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 ReactiveHeightManager
15
+ * Configuration options for ReactiveListManager (formerly ReactiveListManager)
16
16
  */
17
- export interface HeightManagerConfig {
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 HeightManagerDebugInfo {
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
- // Add dynamic tolerance based on item height for browser rendering precision
64
- const tolerance = Math.max(itemHeight, 10); // At least one full item height or 10px minimum
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
- // When at the bottom, ensure we include all items up to the end
67
+ // Pack from the end using measured heights when available: walk backward until viewport filled
68
68
  const adjustedEnd = totalItems;
69
- const visibleItemCount = Math.ceil(viewportHeight / itemHeight) + bufferSize + 1;
70
- const adjustedStart = Math.max(0, adjustedEnd - visibleItemCount);
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: adjustedStart,
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, viewportHeight - actualTotalHeight);
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 = visibleRange.start + i;
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
- if (idx <= 0)
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 < idx; i++) {
349
- const height = heightCache[i] ?? calculatedItemHeight;
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(idx / blockSize);
355
- let offset = blockIdx > 0 ? blockSums[blockIdx - 1] : 0;
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 < idx; i++) {
358
- offset += heightCache[i] ?? calculatedItemHeight;
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
- "name": "@humanspeak/svelte-virtual-list",
3
- "version": "0.3.1-beta.1",
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
- "scripts": {
50
- "build": "vite build && npm run package",
51
- "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
52
- "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
53
- "dev": "vite dev",
54
- "format": "prettier --write .",
55
- "lint": "prettier --check . && eslint .",
56
- "lint:fix": "npm run format && eslint . --fix",
57
- "package": "svelte-kit sync && svelte-package && publint",
58
- "prepare": "husky",
59
- "prepublishOnly": "npm run package",
60
- "preview": "vite preview",
61
- "test": "vitest run --coverage --",
62
- "test:all": "npm run test && npm run test:e2e",
63
- "test:e2e": "playwright test --",
64
- "test:e2e:debug": "playwright test --debug --",
65
- "test:e2e:report": "playwright show-report",
66
- "test:e2e:ui": "playwright test --ui --",
67
- "test:only": "vitest run --",
68
- "test:watch": "vitest --"
69
- },
70
- "overrides": {
71
- "@sveltejs/kit": {
72
- "cookie": "^0.7.0"
73
- }
74
- },
75
- "dependencies": {
76
- "esm-env": "^1.2.2"
77
- },
78
- "devDependencies": {
79
- "@eslint/compat": "^1.3.1",
80
- "@eslint/js": "^9.32.0",
81
- "@faker-js/faker": "^9.9.0",
82
- "@playwright/test": "^1.54.2",
83
- "@sveltejs/adapter-auto": "^6.0.2",
84
- "@sveltejs/kit": "^2.27.3",
85
- "@sveltejs/package": "^2.4.1",
86
- "@sveltejs/vite-plugin-svelte": "^6.1.0",
87
- "@testing-library/jest-dom": "^6.6.4",
88
- "@testing-library/svelte": "^5.2.8",
89
- "@testing-library/user-event": "^14.6.1",
90
- "@types/node": "^24.2.0",
91
- "@typescript-eslint/eslint-plugin": "^8.39.0",
92
- "@typescript-eslint/parser": "^8.39.0",
93
- "@vitest/coverage-v8": "^3.2.4",
94
- "eslint": "^9.32.0",
95
- "eslint-config-prettier": "^10.1.8",
96
- "eslint-plugin-import": "^2.32.0",
97
- "eslint-plugin-svelte": "^3.11.0",
98
- "eslint-plugin-unused-imports": "^4.1.4",
99
- "globals": "^16.3.0",
100
- "husky": "^9.1.7",
101
- "jsdom": "^26.1.0",
102
- "prettier": "^3.6.2",
103
- "prettier-plugin-organize-imports": "^4.2.0",
104
- "prettier-plugin-sort-json": "^4.1.1",
105
- "prettier-plugin-svelte": "^3.4.0",
106
- "prettier-plugin-tailwindcss": "^0.6.14",
107
- "publint": "^0.3.12",
108
- "svelte": "^5.38.0",
109
- "svelte-check": "^4.3.1",
110
- "typescript": "^5.9.2",
111
- "typescript-eslint": "^8.39.0",
112
- "vite": "^7.1.1",
113
- "vitest": "^3.2.4"
114
- },
115
- "peerDependencies": {
116
- "svelte": "^5.0.0"
117
- },
118
- "volta": {
119
- "node": "22.18.0"
120
- },
121
- "publishConfig": {
122
- "access": "public"
123
- },
124
- "tags": [
125
- "svelte",
126
- "virtual-list",
127
- "virtual-scroll",
128
- "virtual-scroller",
129
- "infinite-scroll",
130
- "performance",
131
- "ui-component",
132
- "svelte5"
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
+ }