UNPKG

@tanstack/svelte-table

Version:

Headless UI for building powerful tables & datagrids for Svelte.

95 lines (94 loc) 3.48 kB
import { untrack } from 'svelte'; import { batch, createAtom } from '@tanstack/svelte-store'; const optionsStoreDebugName = 'table/optionsStore'; function observerToCallback(observerOrNext) { return typeof observerOrNext === 'function' ? observerOrNext : (value) => observerOrNext.next?.(value); } function subscribeToRune(getValue, observerOrNext) { const callback = observerToCallback(observerOrNext); const unsubscribe = $effect.root(() => { $effect(() => { const value = getValue(); untrack(() => callback(value)); }); }); return { unsubscribe }; } function createRuneWritableAtom(initialValue) { let value = $state(initialValue); return { set: (updater) => { value = typeof updater === 'function' ? updater(value) : updater; }, get: () => value, subscribe: ((observerOrNext) => { return subscribeToRune(() => value, observerOrNext); }), }; } /** * Creates the table-core reactivity bindings used by the Svelte adapter. * * Table state atoms are backed by TanStack Store atoms. The options store stays * framework-native because row-model APIs read `table.options` directly during * render. Readonly table atoms bridge Store dependency tracking into * `$derived.by`, so their `.get()` methods participate in Svelte dependency * tracking when called in templates, `$derived`, or `$effect`. */ export function svelteReactivity() { return { createOptionsStore: true, wrapExternalAtoms: false, addSubscription: () => { throw new Error('Feature not supported in current reactivity implementation'); }, unmount: () => { throw new Error('Feature not supported in current reactivity implementation'); }, schedule: (fn) => queueMicrotask(() => fn()), createReadonlyAtom: (fn, _options) => { const storeAtom = createAtom(() => fn(), { compare: _options?.compare, }); let version = $state(0); $effect(() => { const subscription = storeAtom.subscribe(() => { version += 1; }); return () => subscription.unsubscribe(); }); const value = $derived.by(() => { version; return storeAtom.get(); }); return { get: () => { // Both reads are load-bearing: the Store read preserves dependency // tracking between table atoms, while touching `value` registers the // current Svelte reactive scope with the rune-backed bridge. const currentValue = storeAtom.get(); value; return currentValue; }, subscribe: ((observerOrNext) => { return subscribeToRune(() => value, observerOrNext); }), }; }, createWritableAtom: (initialValue, _options) => { if (_options?.debugName === optionsStoreDebugName) { return createRuneWritableAtom(initialValue); } return createAtom(initialValue, { compare: _options?.compare, }); }, untrack: untrack, batch, }; }