Skip to content

Commit

Permalink
feat(svelte-virtual): Svelte 4 Support & Svelte Examples (#624)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcusVirg authored Nov 15, 2023
1 parent e2e94d1 commit c383122
Show file tree
Hide file tree
Showing 87 changed files with 25,077 additions and 18,201 deletions.
2 changes: 1 addition & 1 deletion docs/adapters/svelte-virtual.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Svelte Virtual (Coming Soon)
title: Svelte Virtual
---

The `@tanstack/svelte-virtual` adapter is a wrapper around the core virtual logic.
Expand Down
10 changes: 9 additions & 1 deletion docs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,15 @@
},
{
"label": "Svelte Examples",
"children": [{ "to": "#", "label": "Coming Soon!" }]
"children": [
{ "to": "examples/svelte/fixed", "label": "Fixed" },
{ "to": "examples/svelte/variable", "label": "Variable" },
{ "to": "examples/svelte/dynamic", "label": "Dynamic" },
{ "to": "examples/svelte/sticky", "label": "Sticky" },
{ "to": "examples/svelte/infinite-scroll", "label": "Infinite Scroll" },
{ "to": "examples/svelte/smooth-scroll", "label": "Smooth Scroll" },
{ "to": "examples/svelte/table", "label": "Table" }
]
},
{
"label": "Vue Examples",
Expand Down
24 changes: 24 additions & 0 deletions examples/svelte/dynamic/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
6 changes: 6 additions & 0 deletions examples/svelte/dynamic/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Example

To run this example:

- `npm install` or `yarn`
- `npm run dev` or `yarn dev`
11 changes: 11 additions & 0 deletions examples/svelte/dynamic/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
25 changes: 25 additions & 0 deletions examples/svelte/dynamic/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "tanstack-svelte-virtual-example-dynamic",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.json"
},
"dependencies": {
"@faker-js/faker": "^7.6.0",
"@tanstack/svelte-virtual": "^3.0.0-beta.69"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^2.4.2",
"@tsconfig/svelte": "^5.0.0",
"svelte": "^4.0.5",
"svelte-check": "^3.4.6",
"tslib": "^2.6.0",
"typescript": "^5.0.2",
"vite": "^4.4.5"
}
}
44 changes: 44 additions & 0 deletions examples/svelte/dynamic/src/App.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<script lang="ts">
import RowVirtualizerDynamic from './RowVirtualizerDynamic.svelte'
import RowVirtualizerDynamicWindow from './RowVirtualizerDynamicWindow.svelte'
import ColumnVirtualizerDynamic from './ColumnVirtualizerDynamic.svelte'
import GridVirtualizerDynamic from './GridVirtualizerDynamic.svelte'
const pathname = window.location.pathname
</script>

<main>
<p>
These components are using <strong>dynamic</strong> sizes. This means that each
element's exact dimensions are unknown when rendered. An estimated dimension
is used to get an a initial measurement, then this measurement is readjusted
on the fly as each element is rendered.
</p>
<nav>
<ul>
<li>
<a href="/">List</a>
</li>
<li>
<a href="/window-list">List - window as scroller</a>
</li>
<li>
<a href="/columns">Column</a>
</li>
<li>
<a href="/grid">Grid</a>
</li>
</ul>
</nav>
{#if pathname === '/'}
<RowVirtualizerDynamic />
{:else if pathname === '/window-list'}
<RowVirtualizerDynamicWindow />
{:else if pathname === '/columns'}
<ColumnVirtualizerDynamic />
{:else if pathname === '/grid'}
<GridVirtualizerDynamic />
{:else}
<p>Not Found</p>
{/if}
</main>
56 changes: 56 additions & 0 deletions examples/svelte/dynamic/src/ColumnVirtualizerDynamic.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<script lang="ts">
import { faker } from '@faker-js/faker'
import { createVirtualizer } from '@tanstack/svelte-virtual'
let virtualListEl: HTMLDivElement
let virtualItemEls: HTMLDivElement[] = []
function randomNumber(min: number, max: number) {
return faker.datatype.number({ min, max })
}
const sentences = new Array(10000)
.fill(true)
.map(() => faker.lorem.sentence(randomNumber(20, 70)))
$: virtualizer = createVirtualizer<HTMLDivElement, HTMLDivElement>({
horizontal: true,
count: sentences.length,
getScrollElement: () => virtualListEl,
estimateSize: () => 45,
})
$: {
if (virtualItemEls.length)
virtualItemEls.forEach((el) => $virtualizer.measureElement(el))
}
</script>

<div class="list scroll-container" bind:this={virtualListEl}>
<div
style="position: relative; height: 100%; width: {$virtualizer.getTotalSize()}px;"
>
{#each $virtualizer.getVirtualItems() as col, idx (col.index)}
<div
bind:this={virtualItemEls[idx]}
data-index={col.index}
class:list-item-even={col.index % 2 === 0}
class:list-item-odd={col.index % 2 === 1}
style="position: absolute; top: 0; left: 0; height: 100%; transform: translateX({col.start}px);"
>
<div style="width: {sentences[col.index].length}px">
<div>Column {col.index}</div>
<div>{sentences[col.index]}</div>
</div>
</div>
{/each}
</div>
</div>

<style>
.scroll-container {
height: 400px;
width: 400px;
overflow: auto;
}
</style>
51 changes: 51 additions & 0 deletions examples/svelte/dynamic/src/GridVirtualizerDynamic.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<script lang="ts">
import { createVirtualizer } from '@tanstack/svelte-virtual'
let virtualListEl: HTMLDivElement
$: rowVirtualizer = createVirtualizer<HTMLDivElement, HTMLDivElement>({
count: 10000,
getScrollElement: () => virtualListEl,
estimateSize: () => 35,
overscan: 5,
})
$: columnVirtualizer = createVirtualizer<HTMLDivElement, HTMLDivElement>({
horizontal: true,
count: 10000,
getScrollElement: () => virtualListEl,
estimateSize: () => 100,
overscan: 5,
})
</script>

<div class="list scroll-container" bind:this={virtualListEl}>
<div
style="position: relative; height: {$rowVirtualizer.getTotalSize()}px; width: {$columnVirtualizer.getTotalSize()}px;"
>
{#each $rowVirtualizer.getVirtualItems() as row (row.index)}
{#each $columnVirtualizer.getVirtualItems() as col (col.index)}
<div
class={col.index % 2
? row.index % 2 === 0
? 'list-item-odd'
: 'list-item-even'
: row.index % 2
? 'list-item-odd'
: 'list-item-even'}
style="position: absolute; top: 0; left: 0; width: {col.size}px; height: {row.size}px; transform: translateX({col.start}px) translateY({row.start}px);"
>
Cell {row.index}, {col.index}
</div>
{/each}
{/each}
</div>
</div>

<style>
.scroll-container {
height: 500px;
width: 500px;
overflow: auto;
}
</style>
91 changes: 91 additions & 0 deletions examples/svelte/dynamic/src/RowVirtualizerDynamic.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<script lang="ts">
import { faker } from '@faker-js/faker'
import { createVirtualizer } from '@tanstack/svelte-virtual'
let virtualListEl: HTMLDivElement
let virtualItemEls: HTMLDivElement[] = []
function randomNumber(min: number, max: number) {
return faker.datatype.number({ min, max })
}
const sentences = new Array(10000)
.fill(true)
.map(() => faker.lorem.sentence(randomNumber(20, 70)))
const count = sentences.length
$: virtualizer = createVirtualizer<HTMLDivElement, HTMLDivElement>({
count,
getScrollElement: () => virtualListEl,
estimateSize: () => 45,
})
$: items = $virtualizer.getVirtualItems()
$: {
if (virtualItemEls.length)
virtualItemEls.forEach((el) => $virtualizer.measureElement(el))
}
</script>

<div>
<button
on:click={() => {
$virtualizer.scrollToIndex(0)
}}
>
scroll to the top
</button>
<span style="padding: 0 4px;" />
<button
on:click={() => {
$virtualizer.scrollToIndex(count / 2)
}}
>
scroll to the middle
</button>
<span style="padding: 0 4px;" />
<button
on:click={() => {
$virtualizer.scrollToIndex(count - 1)
}}
>
scroll to the end
</button>
<hr />
<div class="list scroll-container" bind:this={virtualListEl}>
<div
style="position: relative; height: {$virtualizer.getTotalSize()}px; width: 100%;"
>
<div
style="position: absolute; top: 0; left: 0; width: 100%; transform: translateY({items[0]
? items[0].start
: 0}px);"
>
{#each items as row, idx (row.index)}
<div
bind:this={virtualItemEls[idx]}
data-index={row.index}
class:list-item-even={row.index % 2 === 0}
class:list-item-odd={row.index % 2 === 1}
>
<div style="padding: 10px 0;">
<div>Row {row.index}</div>
<div>{sentences[row.index]}</div>
</div>
</div>
{/each}
</div>
</div>
</div>
</div>

<style>
.scroll-container {
height: 400px;
width: 400px;
overflow-y: auto;
contain: 'strict';
}
</style>
58 changes: 58 additions & 0 deletions examples/svelte/dynamic/src/RowVirtualizerDynamicWindow.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<script lang="ts">
import { faker } from '@faker-js/faker'
import { createWindowVirtualizer } from '@tanstack/svelte-virtual'
let virtualListEl: HTMLDivElement
let virtualItemEls: HTMLDivElement[] = []
function randomNumber(min: number, max: number) {
return faker.datatype.number({ min, max })
}
const sentences = new Array(10000)
.fill(true)
.map(() => faker.lorem.sentence(randomNumber(20, 70)))
const count = sentences.length
$: virtualizer = createWindowVirtualizer<HTMLDivElement>({
count,
scrollMargin: virtualListEl?.offsetTop ?? 0,
estimateSize: () => 45,
})
$: items = $virtualizer.getVirtualItems()
$: {
if (virtualItemEls.length)
virtualItemEls.forEach((el) => $virtualizer.measureElement(el))
}
</script>

<div>
<div class="list scroll-container" bind:this={virtualListEl}>
<div
style="position: relative; height: {$virtualizer.getTotalSize()}px; width: 100%;"
>
<div
style="position: absolute; top: 0; left: 0; width: 100%; transform: translateY({items[0]
? items[0].start - $virtualizer.options.scrollMargin
: 0}px);"
>
{#each items as row, idx (row.index)}
<div
bind:this={virtualItemEls[idx]}
data-index={row.index}
class:list-item-even={row.index % 2 === 0}
class:list-item-odd={row.index % 2 === 1}
>
<div style="padding: 10px 0;">
<div>Row {row.index}</div>
<div>{sentences[row.index]}</div>
</div>
</div>
{/each}
</div>
</div>
</div>
</div>
Loading

0 comments on commit c383122

Please sign in to comment.