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 5 support #866

Open
2 tasks done
rayrw opened this issue Oct 28, 2024 · 1 comment
Open
2 tasks done

Svelte 5 support #866

rayrw opened this issue Oct 28, 2024 · 1 comment

Comments

@rayrw
Copy link

rayrw commented Oct 28, 2024

Describe the bug

It's working fine in Svelte 4. I'm currently trying out the library in Svelte 5 and found my use case doesn't work.
I got an empty table with the same code. I suspect it cannot keep track of the initial element binding of the scroll element, because it works if I manually make a mounted state and call $virtualizer._willUpdate().

Your minimal, reproducible example

https://www.sveltelab.dev/github.com/rayrw/svelte5-tanstack-virtual

Steps to reproduce

I've made a minimal reproduction repo.
Please note that we have to manually run npm i --force && npm run dev before #863 is merged.
With the hack from L19-L27, it seems to work. However, when I commented out it, I got an empty table.
I suspect it cannot keep track of the initial element binding of the scroll element?

Expected behavior

I hope we can get rid of the manual mounting/element binding check and call of $virtualizer._willUpdate().

How often does this bug happen?

None

Screenshots or Videos

No response

Platform

macOS, Arc browser Version 1.65.0 (54911)
Chromium Engine Version 130.0.6723.59

tanstack-virtual version

3.10.8

TypeScript version

No response

Additional context

No response

Terms & Code of Conduct

  • I agree to follow this project's Code of Conduct
  • I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.
@jithujoshyjy
Copy link

jithujoshyjy commented Nov 2, 2024

Here's how I made it work in svelte 5, mimicking the existing @tanstack/virtual-solid package:

import {
    Virtualizer,
    elementScroll,
    observeElementOffset,
    observeElementRect,
    observeWindowOffset,
    observeWindowRect,
    windowScroll,
    type PartialKeys,
    type VirtualizerOptions
} from "@tanstack/virtual-core"

export * from "@tanstack/virtual-core"

function createVirtualizerBase<
    TScrollElement extends Element | Window,
    TItemElement extends Element,
>(
    options: VirtualizerOptions<TScrollElement, TItemElement>,
): Virtualizer<TScrollElement, TItemElement> {

    const resolvedOptions = { ...options }
    const instance = new Virtualizer(resolvedOptions)

    let virtualItems = $state(instance.getVirtualItems())
    let totalSize = $state(instance.getTotalSize())

    const handler = {
        get(
            target: Virtualizer<TScrollElement, TItemElement>,
            prop: keyof Virtualizer<TScrollElement, TItemElement>
        ) {
            if (prop === "getVirtualItems")
                return () => virtualItems
            if (prop === "getTotalSize")
                return () => totalSize
            return Reflect.get(target, prop)
        }
    }

    const virtualizer = new Proxy(instance, handler)
    virtualizer.setOptions(resolvedOptions)

    $effect(() => {
        const cleanup = virtualizer._didMount()
        virtualizer._willUpdate()
        return cleanup
    })

    $effect(() => {
        virtualizer.setOptions({
            ...resolvedOptions,
            ...options,
            onChange: (instance, sync) => {
                instance._willUpdate()
                virtualItems = instance.getVirtualItems()
                totalSize = instance.getTotalSize()
                options.onChange?.(instance, sync)
            }
        })
        virtualizer.measure()
    })

    return virtualizer
}

export function createVirtualizer<
    TScrollElement extends Element,
    TItemElement extends Element,
>(
    options: PartialKeys<
        VirtualizerOptions<TScrollElement, TItemElement>,
        "observeElementRect" | "observeElementOffset" | "scrollToFn"
    >,
): Virtualizer<TScrollElement, TItemElement> {
    return createVirtualizerBase<TScrollElement, TItemElement>({
        observeElementRect: observeElementRect,
        observeElementOffset: observeElementOffset,
        scrollToFn: elementScroll,
        ...options
    });
}

export function createWindowVirtualizer<TItemElement extends Element>(
    options: PartialKeys<
        VirtualizerOptions<Window, TItemElement>,
        | "getScrollElement"
        | "observeElementRect"
        | "observeElementOffset"
        | "scrollToFn"
    >,
): Virtualizer<Window, TItemElement> {
    return createVirtualizerBase<Window, TItemElement>({
        getScrollElement: () => (typeof document !== "undefined" ? window : null),
        observeElementRect: observeWindowRect,
        observeElementOffset: observeWindowOffset,
        scrollToFn: windowScroll,
        initialOffset: () => (typeof document !== "undefined" ? window.scrollY : 0),
        ...options
    })
}

It's literally just a clone of the index.ts from @tanstack/virtual-solid using svelte runes.
Note: in svelte the file should be called index.svelte.ts for this to work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants