@humanspeak/svelte-virtual-list 0.4.0 β 0.4.1
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/README.md +123 -148
- package/dist/SvelteVirtualList.svelte +30 -4
- package/dist/utils/virtualList.js +11 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -31,108 +31,20 @@ A high-performance virtual list component for Svelte 5 applications that efficie
|
|
|
31
31
|
- πΉοΈ Programmatic scrolling with `scroll`
|
|
32
32
|
- βΎοΈ Infinite scroll support with `onLoadMore`
|
|
33
33
|
|
|
34
|
-
##
|
|
34
|
+
## Requirements
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
### Usage Example
|
|
39
|
-
|
|
40
|
-
```svelte
|
|
41
|
-
<script lang="ts">
|
|
42
|
-
import SvelteVirtualList from '@humanspeak/svelte-virtual-list'
|
|
43
|
-
let listRef
|
|
44
|
-
const items = Array.from({ length: 10000 }, (_, i) => ({ id: i, text: `Item ${i}` }))
|
|
45
|
-
|
|
46
|
-
function goToItem5000() {
|
|
47
|
-
// Scroll to item 5000 with smooth scrolling and auto alignment
|
|
48
|
-
listRef.scroll({ index: 5000, smoothScroll: true, align: 'auto' })
|
|
49
|
-
}
|
|
50
|
-
</script>
|
|
51
|
-
|
|
52
|
-
<button on:click={goToItem5000}> Scroll to item 5000 </button>
|
|
53
|
-
<SvelteVirtualList {items} bind:this={listRef}>
|
|
54
|
-
{#snippet renderItem(item)}
|
|
55
|
-
<div>{item.text}</div>
|
|
56
|
-
{/snippet}
|
|
57
|
-
</SvelteVirtualList>
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### API
|
|
61
|
-
|
|
62
|
-
- `scroll(options: { index: number; smoothScroll?: boolean; shouldThrowOnBounds?: boolean; align?: 'auto' | 'top' | 'bottom' | 'nearest' })`
|
|
63
|
-
- `index`: The item index to scroll to (0-based)
|
|
64
|
-
- `smoothScroll`: If true, uses smooth scrolling (default: true)
|
|
65
|
-
- `shouldThrowOnBounds`: If true, throws if index is out of bounds (default: true)
|
|
66
|
-
- `align`: Where to align the item in the viewport:
|
|
67
|
-
- `'auto'` (default): Only scroll if not visible, align to top or bottom as appropriate
|
|
68
|
-
- `'top'`: Always align to the top
|
|
69
|
-
- `'bottom'`: Always align to the bottom
|
|
70
|
-
- `'nearest'`: Scroll as little as possible to bring the item into view (like native scrollIntoView({ block: 'nearest' }))
|
|
71
|
-
|
|
72
|
-
#### Usage Examples
|
|
73
|
-
|
|
74
|
-
```svelte
|
|
75
|
-
<button on:click={() => listRef.scroll({ index: 5000, align: 'nearest' })}>
|
|
76
|
-
Scroll to item 5000 (nearest)
|
|
77
|
-
</button>
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## Infinite Scroll
|
|
81
|
-
|
|
82
|
-
Load more data automatically as users scroll near the end of the list. Perfect for paginated APIs, infinite feeds, and chat applications.
|
|
83
|
-
|
|
84
|
-
```svelte
|
|
85
|
-
<script lang="ts">
|
|
86
|
-
import SvelteVirtualList from '@humanspeak/svelte-virtual-list'
|
|
87
|
-
|
|
88
|
-
let items = $state([...initialItems])
|
|
89
|
-
let hasMore = $state(true)
|
|
90
|
-
|
|
91
|
-
async function loadMore() {
|
|
92
|
-
const newItems = await fetchMoreItems()
|
|
93
|
-
items = [...items, ...newItems]
|
|
94
|
-
if (newItems.length === 0) {
|
|
95
|
-
hasMore = false
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
</script>
|
|
99
|
-
|
|
100
|
-
<SvelteVirtualList {items} onLoadMore={loadMore} loadMoreThreshold={20} {hasMore}>
|
|
101
|
-
{#snippet renderItem(item)}
|
|
102
|
-
<div>{item.text}</div>
|
|
103
|
-
{/snippet}
|
|
104
|
-
</SvelteVirtualList>
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### Infinite Scroll Props
|
|
108
|
-
|
|
109
|
-
| Prop | Type | Default | Description |
|
|
110
|
-
| ------------------- | ----------------------------- | ------- | ---------------------------------------------------- |
|
|
111
|
-
| `onLoadMore` | `() => void \| Promise<void>` | - | Callback when more data is needed (supports async) |
|
|
112
|
-
| `loadMoreThreshold` | `number` | `20` | Number of items from the end to trigger `onLoadMore` |
|
|
113
|
-
| `hasMore` | `boolean` | `true` | Set to `false` when all data has been loaded |
|
|
114
|
-
|
|
115
|
-
### Infinite Scroll Behavior
|
|
116
|
-
|
|
117
|
-
- Triggers when scrolling near the end of the list
|
|
118
|
-
- Automatically triggers on mount if initial items are below threshold
|
|
119
|
-
- Prevents concurrent `onLoadMore` calls while loading
|
|
120
|
-
- Works with both sync and async callbacks
|
|
121
|
-
- Supports both `topToBottom` and `bottomToTop` modes
|
|
122
|
-
|
|
123
|
-
### Integration Guides
|
|
124
|
-
|
|
125
|
-
- [Infinite Scroll with Convex](documentation/CONVEX_INFINITE_SCROLL.md) - Real-time data + pagination with Convex backend
|
|
36
|
+
- Svelte 5
|
|
37
|
+
- Node.js 18+
|
|
126
38
|
|
|
127
39
|
## Installation
|
|
128
40
|
|
|
129
41
|
```bash
|
|
130
|
-
# Using npm
|
|
131
|
-
npm install @humanspeak/svelte-virtual-list
|
|
132
|
-
|
|
133
42
|
# Using pnpm (recommended)
|
|
134
43
|
pnpm add @humanspeak/svelte-virtual-list
|
|
135
44
|
|
|
45
|
+
# Using npm
|
|
46
|
+
npm install @humanspeak/svelte-virtual-list
|
|
47
|
+
|
|
136
48
|
# Using yarn
|
|
137
49
|
yarn add @humanspeak/svelte-virtual-list
|
|
138
50
|
```
|
|
@@ -156,9 +68,27 @@ yarn add @humanspeak/svelte-virtual-list
|
|
|
156
68
|
</SvelteVirtualList>
|
|
157
69
|
```
|
|
158
70
|
|
|
159
|
-
##
|
|
71
|
+
## Props
|
|
160
72
|
|
|
161
|
-
|
|
73
|
+
| Prop | Type | Default | Description |
|
|
74
|
+
| ---------------------------- | -------------------------------- | --------------- | ----------------------------------------------------------------------------- |
|
|
75
|
+
| `items` | `T[]` | Required | Array of items to render |
|
|
76
|
+
| `defaultEstimatedItemHeight` | `number` | `40` | Initial height estimate used until items are measured |
|
|
77
|
+
| `mode` | `'topToBottom' \| 'bottomToTop'` | `'topToBottom'` | Scroll direction and anchoring behavior |
|
|
78
|
+
| `bufferSize` | `number` | `20` | Number of items rendered outside the viewport |
|
|
79
|
+
| `debug` | `boolean` | `false` | Enable debug logging and visualizations |
|
|
80
|
+
| `containerClass` | `string` | `''` | Class for outer container |
|
|
81
|
+
| `viewportClass` | `string` | `''` | Class for scrollable viewport |
|
|
82
|
+
| `contentClass` | `string` | `''` | Class for content wrapper |
|
|
83
|
+
| `itemsClass` | `string` | `''` | Class for items container |
|
|
84
|
+
| `testId` | `string` | `''` | Base test id used in internal test hooks (useful for E2E/tests and debugging) |
|
|
85
|
+
| `onLoadMore` | `() => void \| Promise<void>` | - | Callback when more data is needed for infinite scroll |
|
|
86
|
+
| `loadMoreThreshold` | `number` | `20` | Items from end to trigger `onLoadMore` |
|
|
87
|
+
| `hasMore` | `boolean` | `true` | Set to `false` when all data has been loaded |
|
|
88
|
+
|
|
89
|
+
## Bottom-to-Top Mode
|
|
90
|
+
|
|
91
|
+
Use `mode="bottomToTop"` for chat-like lists anchored to the bottom:
|
|
162
92
|
|
|
163
93
|
```svelte
|
|
164
94
|
<script lang="ts">
|
|
@@ -178,7 +108,7 @@ yarn add @humanspeak/svelte-virtual-list
|
|
|
178
108
|
</script>
|
|
179
109
|
|
|
180
110
|
<div style="height: 500px;">
|
|
181
|
-
<SvelteVirtualList items={messages} mode="bottomToTop"
|
|
111
|
+
<SvelteVirtualList items={messages} mode="bottomToTop">
|
|
182
112
|
{#snippet renderItem(message)}
|
|
183
113
|
<div class="message-container">
|
|
184
114
|
<p>{message.text}</p>
|
|
@@ -191,40 +121,100 @@ yarn add @humanspeak/svelte-virtual-list
|
|
|
191
121
|
</div>
|
|
192
122
|
```
|
|
193
123
|
|
|
194
|
-
|
|
124
|
+
## Programmatic Scrolling
|
|
195
125
|
|
|
196
|
-
|
|
126
|
+
Scroll to any item in the list using the `scroll` method. Useful for chat apps, jump-to-item navigation, and more.
|
|
197
127
|
|
|
198
128
|
```svelte
|
|
199
129
|
<script lang="ts">
|
|
200
130
|
import SvelteVirtualList from '@humanspeak/svelte-virtual-list'
|
|
201
131
|
let listRef
|
|
202
|
-
const
|
|
132
|
+
const items = Array.from({ length: 10000 }, (_, i) => ({ id: i, text: `Item ${i}` }))
|
|
133
|
+
|
|
134
|
+
function goToItem5000() {
|
|
135
|
+
listRef.scroll({ index: 5000, smoothScroll: true, align: 'auto' })
|
|
136
|
+
}
|
|
203
137
|
</script>
|
|
204
138
|
|
|
139
|
+
<button onclick={goToItem5000}> Scroll to item 5000 </button>
|
|
140
|
+
<SvelteVirtualList {items} bind:this={listRef}>
|
|
141
|
+
{#snippet renderItem(item)}
|
|
142
|
+
<div>{item.text}</div>
|
|
143
|
+
{/snippet}
|
|
144
|
+
</SvelteVirtualList>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### scroll() Options
|
|
148
|
+
|
|
149
|
+
| Option | Type | Default | Description |
|
|
150
|
+
| --------------------- | ------------------------------------------ | -------- | --------------------------------------- |
|
|
151
|
+
| `index` | `number` | Required | The item index to scroll to (0-based) |
|
|
152
|
+
| `smoothScroll` | `boolean` | `true` | Use smooth scrolling animation |
|
|
153
|
+
| `shouldThrowOnBounds` | `boolean` | `true` | Throw if index is out of bounds |
|
|
154
|
+
| `align` | `'auto' \| 'top' \| 'bottom' \| 'nearest'` | `'auto'` | Where to align the item in the viewport |
|
|
155
|
+
|
|
156
|
+
Alignment options:
|
|
157
|
+
|
|
158
|
+
- `'auto'` - Only scroll if not visible, align to nearest edge
|
|
159
|
+
- `'top'` - Always align to the top
|
|
160
|
+
- `'bottom'` - Always align to the bottom
|
|
161
|
+
- `'nearest'` - Scroll as little as possible to bring the item into view
|
|
162
|
+
|
|
163
|
+
Works with both `topToBottom` and `bottomToTop` modes:
|
|
164
|
+
|
|
165
|
+
```svelte
|
|
205
166
|
<SvelteVirtualList items={messages} mode="bottomToTop" bind:this={listRef} />
|
|
206
|
-
<button
|
|
167
|
+
<button onclick={() => listRef.scroll({ index: messages.length - 1, align: 'bottom' })}>
|
|
207
168
|
Jump to latest
|
|
208
169
|
</button>
|
|
209
170
|
```
|
|
210
171
|
|
|
211
|
-
##
|
|
172
|
+
## Infinite Scroll
|
|
212
173
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
174
|
+
Load more data automatically as users scroll near the end of the list. Perfect for paginated APIs, infinite feeds, and chat applications.
|
|
175
|
+
|
|
176
|
+
```svelte
|
|
177
|
+
<script lang="ts">
|
|
178
|
+
import SvelteVirtualList from '@humanspeak/svelte-virtual-list'
|
|
179
|
+
|
|
180
|
+
let items = $state([...initialItems])
|
|
181
|
+
let hasMore = $state(true)
|
|
182
|
+
|
|
183
|
+
async function loadMore() {
|
|
184
|
+
const newItems = await fetchMoreItems()
|
|
185
|
+
items = [...items, ...newItems]
|
|
186
|
+
if (newItems.length === 0) {
|
|
187
|
+
hasMore = false
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
</script>
|
|
191
|
+
|
|
192
|
+
<SvelteVirtualList {items} onLoadMore={loadMore} loadMoreThreshold={20} {hasMore}>
|
|
193
|
+
{#snippet renderItem(item)}
|
|
194
|
+
<div>{item.text}</div>
|
|
195
|
+
{/snippet}
|
|
196
|
+
</SvelteVirtualList>
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Infinite Scroll Behavior
|
|
200
|
+
|
|
201
|
+
- Triggers when scrolling near the end of the list
|
|
202
|
+
- Automatically triggers on mount if initial items are below threshold
|
|
203
|
+
- Prevents concurrent `onLoadMore` calls while loading
|
|
204
|
+
- Works with both sync and async callbacks
|
|
205
|
+
- Supports both `topToBottom` and `bottomToTop` modes
|
|
206
|
+
|
|
207
|
+
### Integration Guides
|
|
208
|
+
|
|
209
|
+
- [Infinite Scroll with Convex](documentation/CONVEX_INFINITE_SCROLL.md) - Real-time data + pagination with Convex backend
|
|
210
|
+
|
|
211
|
+
## Performance Considerations
|
|
212
|
+
|
|
213
|
+
- The `bufferSize` prop affects memory usage and scroll smoothness
|
|
214
|
+
- Items are measured and cached for optimal performance
|
|
215
|
+
- Dynamic height calculations happen automatically
|
|
216
|
+
- Resize observers handle container/content changes
|
|
217
|
+
- Virtual DOM updates are batched for efficiency
|
|
228
218
|
|
|
229
219
|
## Testing
|
|
230
220
|
|
|
@@ -254,33 +244,6 @@ npx playwright test tests/docs-visit.spec.ts --project=chromium
|
|
|
254
244
|
npx playwright test --debug
|
|
255
245
|
```
|
|
256
246
|
|
|
257
|
-
### Development Commands
|
|
258
|
-
|
|
259
|
-
```bash
|
|
260
|
-
# Start development server
|
|
261
|
-
pnpm dev
|
|
262
|
-
|
|
263
|
-
# Start both package and docs
|
|
264
|
-
pnpm run dev:all
|
|
265
|
-
|
|
266
|
-
# Check TypeScript/Svelte
|
|
267
|
-
pnpm run check
|
|
268
|
-
|
|
269
|
-
# Build package
|
|
270
|
-
pnpm run build
|
|
271
|
-
|
|
272
|
-
# Format and lint code
|
|
273
|
-
pnpm run lint:fix
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
## Performance Considerations
|
|
277
|
-
|
|
278
|
-
- The `bufferSize` prop affects memory usage and scroll smoothness
|
|
279
|
-
- Items are measured and cached for optimal performance
|
|
280
|
-
- Dynamic height calculations happen automatically
|
|
281
|
-
- Resize observers handle container/content changes
|
|
282
|
-
- Virtual DOM updates are batched for efficiency
|
|
283
|
-
|
|
284
247
|
## Project Structure
|
|
285
248
|
|
|
286
249
|
This is a **PNPM workspace** with two packages:
|
|
@@ -288,22 +251,34 @@ This is a **PNPM workspace** with two packages:
|
|
|
288
251
|
1. **`./`** - Main Svelte Virtual List component package
|
|
289
252
|
2. **`./docs`** - Documentation site with live demos and examples
|
|
290
253
|
|
|
291
|
-
### Development
|
|
254
|
+
### Development Commands
|
|
292
255
|
|
|
293
256
|
```bash
|
|
294
257
|
# Install dependencies for both packages
|
|
295
258
|
pnpm install
|
|
296
259
|
|
|
297
|
-
#
|
|
260
|
+
# Start development server
|
|
261
|
+
pnpm dev
|
|
262
|
+
|
|
263
|
+
# Start both package and docs
|
|
298
264
|
pnpm run dev:all
|
|
299
265
|
|
|
300
|
-
# Build
|
|
266
|
+
# Build package
|
|
301
267
|
pnpm run build
|
|
302
268
|
|
|
303
|
-
#
|
|
269
|
+
# Check TypeScript/Svelte
|
|
270
|
+
pnpm run check
|
|
271
|
+
|
|
272
|
+
# Format and lint code (uses Trunk)
|
|
273
|
+
trunk fmt
|
|
274
|
+
trunk check
|
|
275
|
+
|
|
276
|
+
# Run all tests
|
|
304
277
|
pnpm test:all
|
|
305
278
|
```
|
|
306
279
|
|
|
280
|
+
This project uses [Trunk](https://trunk.io) for formatting and linting. Trunk manages tool versions and runs checks automatically via pre-commit hooks.
|
|
281
|
+
|
|
307
282
|
## License
|
|
308
283
|
|
|
309
284
|
MIT Β© [Humanspeak, Inc.](LICENSE)
|
|
@@ -260,7 +260,7 @@
|
|
|
260
260
|
const blockSums = buildBlockSums(cache, est, items.length)
|
|
261
261
|
const offsetToIndex = getScrollOffsetForIndex(cache, est, anchorIndex, blockSums)
|
|
262
262
|
const currentTop = heightManager.viewport.scrollTop
|
|
263
|
-
let offsetWithin
|
|
263
|
+
let offsetWithin: number
|
|
264
264
|
if (mode === 'bottomToTop') {
|
|
265
265
|
// Convert distance-from-end to distance-from-start
|
|
266
266
|
const distanceFromStart = maxScrollTop - currentTop
|
|
@@ -598,6 +598,7 @@
|
|
|
598
598
|
// Keep height manager synchronized with items length
|
|
599
599
|
$effect(() => {
|
|
600
600
|
heightManager.updateItemLength(items.length)
|
|
601
|
+
stabilizedContentHeight = 0
|
|
601
602
|
})
|
|
602
603
|
|
|
603
604
|
// Infinite scroll: trigger onLoadMore when approaching end of list
|
|
@@ -1015,8 +1016,31 @@
|
|
|
1015
1016
|
* Computed content height for the virtual list.
|
|
1016
1017
|
* Uses the maximum of container height and total content height to ensure
|
|
1017
1018
|
* proper scrolling behavior.
|
|
1019
|
+
*
|
|
1020
|
+
* In bottomToTop mode during active scroll, contentHeight is "ratcheted" β
|
|
1021
|
+
* it can grow but never shrink. This prevents a feedback loop where
|
|
1022
|
+
* averageHeight oscillation causes scrollHeight to bounce, triggering
|
|
1023
|
+
* browser scrollTop adjustments that fire new scroll events.
|
|
1024
|
+
* When scrolling stops (isScrolling goes false), it snaps to the true value.
|
|
1018
1025
|
*/
|
|
1019
|
-
|
|
1026
|
+
let stabilizedContentHeight = 0
|
|
1027
|
+
|
|
1028
|
+
const contentHeight = $derived.by(() => {
|
|
1029
|
+
const raw = Math.max(height, totalHeight)
|
|
1030
|
+
|
|
1031
|
+
if (mode !== 'bottomToTop' || !isScrolling) {
|
|
1032
|
+
stabilizedContentHeight = raw
|
|
1033
|
+
return raw
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
// During active scroll in bottomToTop: only allow growth (ratchet)
|
|
1037
|
+
// Prevents shrink β scrollTop adjust β new scroll event feedback loop
|
|
1038
|
+
if (raw > stabilizedContentHeight) {
|
|
1039
|
+
stabilizedContentHeight = raw
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
return stabilizedContentHeight
|
|
1043
|
+
})
|
|
1020
1044
|
|
|
1021
1045
|
/**
|
|
1022
1046
|
* Computed transform Y value for positioning the visible items.
|
|
@@ -1029,7 +1053,9 @@
|
|
|
1029
1053
|
// Avoid synchronous DOM reads here; fall back once if height is 0
|
|
1030
1054
|
const effectiveHeight = viewportHeight === 0 ? 400 : viewportHeight
|
|
1031
1055
|
|
|
1032
|
-
// Use precise offset
|
|
1056
|
+
// Use precise offset using measured heights when available.
|
|
1057
|
+
// For bottomToTop, pass ratcheted contentHeight so the transform stays
|
|
1058
|
+
// stable while scrollHeight is stabilized (prevents visual shift).
|
|
1033
1059
|
return Math.round(
|
|
1034
1060
|
calculateTransformY(
|
|
1035
1061
|
mode,
|
|
@@ -1038,7 +1064,7 @@
|
|
|
1038
1064
|
visibleRange.start,
|
|
1039
1065
|
heightManager.averageHeight,
|
|
1040
1066
|
effectiveHeight,
|
|
1041
|
-
totalHeight,
|
|
1067
|
+
mode === 'bottomToTop' ? contentHeight : totalHeight,
|
|
1042
1068
|
heightManager.getHeightCache(),
|
|
1043
1069
|
measuredFallbackHeight
|
|
1044
1070
|
)
|
|
@@ -144,8 +144,17 @@ export const calculateTransformY = (mode, totalItems, visibleEnd, visibleStart,
|
|
|
144
144
|
if (mode === 'bottomToTop') {
|
|
145
145
|
// In bottomToTop mode, position items so they stack from bottom up
|
|
146
146
|
const actualTotalHeight = totalContentHeight ?? totalItems * itemHeight;
|
|
147
|
-
// Calculate transform to position visible items correctly
|
|
148
|
-
|
|
147
|
+
// Calculate transform to position visible items correctly.
|
|
148
|
+
// Use measured heights when available to avoid oscillation caused by
|
|
149
|
+
// averageHeight changes shifting (totalItems - visibleEnd) * avg.
|
|
150
|
+
let basicTransform;
|
|
151
|
+
if (heightCache) {
|
|
152
|
+
const offsetToVisibleEnd = getScrollOffsetForIndex(heightCache, itemHeight, visibleEnd);
|
|
153
|
+
basicTransform = actualTotalHeight - offsetToVisibleEnd;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
basicTransform = (totalItems - visibleEnd) * itemHeight;
|
|
157
|
+
}
|
|
149
158
|
// When content is smaller than viewport, push to bottom
|
|
150
159
|
const bottomOffset = Math.max(0, effectiveViewport - actualTotalHeight);
|
|
151
160
|
// Snap to integer pixels to avoid subpixel oscillation
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@humanspeak/svelte-virtual-list",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "A lightweight, high-performance virtual list component for Svelte 5 that renders large datasets with minimal memory usage. Features include dynamic height support, smooth scrolling, TypeScript support, and efficient DOM recycling. Ideal for infinite scrolling lists, data tables, chat interfaces, and any application requiring the rendering of thousands of items without compromising performance. Zero dependencies and fully customizable.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"svelte",
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"prettier-plugin-svelte": "^3.4.1",
|
|
92
92
|
"prettier-plugin-tailwindcss": "^0.7.2",
|
|
93
93
|
"publint": "^0.3.17",
|
|
94
|
-
"svelte": "^5.51.
|
|
94
|
+
"svelte": "^5.51.3",
|
|
95
95
|
"svelte-check": "^4.4.0",
|
|
96
96
|
"tailwindcss": "^4.1.18",
|
|
97
97
|
"tw-animate-css": "^1.4.0",
|