@blossom-carousel/svelte
Version:
A native-scroll-first carousel component for Svelte.
55 lines (54 loc) • 1.94 kB
JavaScript
import { writable } from "svelte/store";
import { getMarkerTargets, observeNavigationState, registerCommands, } from "./vendor/navigation/index.js";
import { getSlideCount } from "./slideRegistry.js";
const INITIAL = {
activeIndex: -1,
count: 0,
canPrev: false,
canNext: false,
};
function seededState(forId) {
if (!forId)
return { ...INITIAL };
// Server: BlossomCarousel already rendered (document order) and registered
// its slide count from a server-side snippet render (see ssrSlideCount.ts).
if (typeof document === "undefined") {
return { ...INITIAL, count: getSlideCount(forId) };
}
// Client: hydrating server-rendered HTML (or mounting later) — read the
// live DOM directly, since the registry above only exists on the server.
const scroller = document.getElementById(forId);
return {
...INITIAL,
count: scroller ? getMarkerTargets(scroller).length : 0,
};
}
export function createNavigationStore(forId) {
const store = writable(seededState(forId));
let cleanup;
return {
subscribe: store.subscribe,
connect(id) {
cleanup?.();
cleanup = undefined;
store.set(seededState(id));
// Defense in depth: `connect` is only ever invoked from a client-only
// `$effect`, but guard directly against SSR too, since it's cheap.
if (!id || typeof document === "undefined")
return;
const scroller = document.getElementById(id);
if (!scroller)
return;
const unregister = registerCommands(scroller);
const unobserve = observeNavigationState(scroller, store.set);
cleanup = () => {
unregister();
unobserve();
};
},
disconnect() {
cleanup?.();
cleanup = undefined;
},
};
}