Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Svelte 4 Support & Svelte Examples #624

Merged
merged 4 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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