Svelte
createPicker, use:attach, and use:portal.
The adapter is a subpath of the same package. Nothing extra to install.
<script>
import { createPicker } from 'loopem/svelte'
let { photos } = $props()
const picker = createPicker({
items: photos,
layout: 'arc',
radius: 900,
})
const { attach, portal, slots, selectedItem } = picker
</script>
<img src={$selectedItem?.full} alt="" />
<div class="picker" use:attach>
{#each $slots as slot (slot.key)}
<button class="thumb" use:portal={slot.element}>
<img src={photos[slot.index].thumb} alt="" />
</button>
{/each}
</div>use:attach on the container, use:portal={slot.element} on whatever should
live inside a slot.
What you get back
attach · portal · slots · activeIndex · activeItem · selectedIndex ·
selectedItem · scrollTo · next · previous · select · seek ·
update · play · pause
Everything reactive is a store, so read it with $. Svelte is the one adapter
with update(items), because its options are read once at creation.
Two-way binding
Svelte needs no extra option for this. initialIndex sets the start, and two
effects keep it in step:
<script>
let { selected, onSelect } = $props()
const picker = createPicker({
items: photos,
// svelte-ignore state_referenced_locally
initialIndex: selected,
})
const { selectedIndex } = picker
$effect(() => picker.select(selected))
$effect(() => onSelect($selectedIndex))
</script>That is safe here because Svelte’s stores settle synchronously, so neither
direction ever sees a stale index. React’s do not, which is why it needs an
onSelect option and this does not.
Working code: the Svelte gallery.