mirror of
https://github.com/BradNut/AdelieStack
synced 2025-09-08 17:40:20 +00:00
99 lines
2.2 KiB
Svelte
99 lines
2.2 KiB
Svelte
|
|
<script lang="ts">
|
||
|
|
import { writable } from "svelte/store";
|
||
|
|
import { onDestroy } from "svelte";
|
||
|
|
import { type CarouselAPI, type CarouselProps, setEmblaContext } from "./context.js";
|
||
|
|
import { cn } from "$lib/utils/ui.js";
|
||
|
|
|
||
|
|
type $$Props = CarouselProps;
|
||
|
|
|
||
|
|
export let opts = {};
|
||
|
|
export let plugins: NonNullable<$$Props["plugins"]> = [];
|
||
|
|
export let api: $$Props["api"] = undefined;
|
||
|
|
export let orientation: NonNullable<$$Props["orientation"]> = "horizontal";
|
||
|
|
|
||
|
|
let className: $$Props["class"] = undefined;
|
||
|
|
export { className as class };
|
||
|
|
|
||
|
|
const apiStore = writable<CarouselAPI | undefined>(undefined);
|
||
|
|
const orientationStore = writable(orientation);
|
||
|
|
const canScrollPrev = writable(false);
|
||
|
|
const canScrollNext = writable(false);
|
||
|
|
const optionsStore = writable(opts);
|
||
|
|
const pluginStore = writable(plugins);
|
||
|
|
const scrollSnapsStore = writable<number[]>([]);
|
||
|
|
const selectedIndexStore = writable(0);
|
||
|
|
|
||
|
|
$: orientationStore.set(orientation);
|
||
|
|
$: pluginStore.set(plugins);
|
||
|
|
$: optionsStore.set(opts);
|
||
|
|
|
||
|
|
function scrollPrev() {
|
||
|
|
api?.scrollPrev();
|
||
|
|
}
|
||
|
|
function scrollNext() {
|
||
|
|
api?.scrollNext();
|
||
|
|
}
|
||
|
|
function scrollTo(index: number, jump?: boolean) {
|
||
|
|
api?.scrollTo(index, jump);
|
||
|
|
}
|
||
|
|
|
||
|
|
function onSelect(api: CarouselAPI) {
|
||
|
|
if (!api) return;
|
||
|
|
canScrollPrev.set(api.canScrollPrev());
|
||
|
|
canScrollNext.set(api.canScrollNext());
|
||
|
|
}
|
||
|
|
|
||
|
|
$: if (api) {
|
||
|
|
onSelect(api);
|
||
|
|
api.on("select", onSelect);
|
||
|
|
api.on("reInit", onSelect);
|
||
|
|
}
|
||
|
|
|
||
|
|
function handleKeyDown(e: KeyboardEvent) {
|
||
|
|
if (e.key === "ArrowLeft") {
|
||
|
|
e.preventDefault();
|
||
|
|
scrollPrev();
|
||
|
|
} else if (e.key === "ArrowRight") {
|
||
|
|
e.preventDefault();
|
||
|
|
scrollNext();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
setEmblaContext({
|
||
|
|
api: apiStore,
|
||
|
|
scrollPrev,
|
||
|
|
scrollNext,
|
||
|
|
orientation: orientationStore,
|
||
|
|
canScrollNext,
|
||
|
|
canScrollPrev,
|
||
|
|
handleKeyDown,
|
||
|
|
options: optionsStore,
|
||
|
|
plugins: pluginStore,
|
||
|
|
onInit,
|
||
|
|
scrollSnaps: scrollSnapsStore,
|
||
|
|
selectedIndex: selectedIndexStore,
|
||
|
|
scrollTo,
|
||
|
|
});
|
||
|
|
|
||
|
|
function onInit(event: CustomEvent<CarouselAPI>) {
|
||
|
|
api = event.detail;
|
||
|
|
apiStore.set(api);
|
||
|
|
scrollSnapsStore.set(api.scrollSnapList());
|
||
|
|
}
|
||
|
|
|
||
|
|
onDestroy(() => {
|
||
|
|
api?.off("select", onSelect);
|
||
|
|
});
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<div
|
||
|
|
class={cn("relative", className)}
|
||
|
|
on:mouseenter
|
||
|
|
on:mouseleave
|
||
|
|
role="region"
|
||
|
|
aria-roledescription="carousel"
|
||
|
|
{...$$restProps}
|
||
|
|
>
|
||
|
|
<slot />
|
||
|
|
</div>
|