Carousel experimental
Ark UI Carousel 기반 wrapper입니다. Root, Control, ItemGroup, Item, PrevTrigger, NextTrigger, IndicatorGroup, Indicator, ProgressText anatomy를 제공합니다.
Preview
1 / 3 재생
<script lang="ts">
import * as Carousel from '@odbd/svelte/carousel'
const slides = [
{
title: '토큰 계약',
body: 'semantic token으로 색상과 간격을 공유해요.',
tone: 'muted',
},
{
title: 'Ark UI primitive',
body: '드래그, 키보드 이동, pagination 상태를 Ark가 관리해요.',
tone: 'surface',
},
{
title: '동일한 anatomy',
body: 'React와 Svelte wrapper가 같은 class contract를 제공해요.',
tone: 'accent',
},
]
// 모션 축소 환경에서는 자동 재생을 시작하지 않는다 (정지 버튼과 별개의 기본값)
const reduceMotion =
typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches
const translations = {
nextTrigger: '다음 슬라이드',
prevTrigger: '이전 슬라이드',
indicator: (index: number) => `${index + 1}번 슬라이드로 이동`,
item: (index: number, count: number) => `${count}개 중 ${index + 1}번 슬라이드`,
autoplayStart: '자동 재생 시작',
autoplayStop: '자동 재생 정지',
progressText: ({ page, totalPages }: { page: number; totalPages: number }) =>
`${page} / ${totalPages}`,
}
</script>
<Carousel.Root
class="carousel-demo"
slideCount={slides.length}
defaultPage={0}
slidesPerPage={1}
spacing="0.75rem"
autoplay={reduceMotion ? false : { delay: 4000 }}
{translations}
allowMouseDrag
loop
>
<Carousel.ItemGroup>
{#each slides as slide, index}
<Carousel.Item {index}>
<section class="carousel-demo-slide" data-tone={slide.tone}>
<strong>{slide.title}</strong>
<span>{slide.body}</span>
</section>
</Carousel.Item>
{/each}
</Carousel.ItemGroup>
<Carousel.Control>
<Carousel.PrevTrigger>‹</Carousel.PrevTrigger>
<Carousel.IndicatorGroup>
{#each slides as _, index}
<Carousel.Indicator {index} />
{/each}
</Carousel.IndicatorGroup>
<div class="carousel-demo__playback">
<Carousel.AutoplayTrigger />
<Carousel.ProgressText />
<Carousel.AutoplayIndicator>
재생
{#snippet fallback()}
정지
{/snippet}
</Carousel.AutoplayIndicator>
</div>
<Carousel.NextTrigger>›</Carousel.NextTrigger>
</Carousel.Control>
</Carousel.Root>
<style>
:global(.carousel-demo.odbd-carousel) {
max-width: 30rem;
}
.carousel-demo__playback {
display: inline-flex;
flex: 0 0 auto;
align-items: center;
gap: var(--odbd-space-2);
color: var(--odbd-color-muted-foreground);
font-size: var(--odbd-font-size-sm);
font-weight: 600;
}
.carousel-demo-slide {
display: flex;
min-height: 12rem;
flex-direction: column;
justify-content: flex-end;
gap: var(--odbd-space-2);
padding: var(--odbd-space-5);
border: 1px solid var(--odbd-color-border);
border-radius: var(--odbd-radius-lg);
background: var(--odbd-color-muted);
}
.carousel-demo-slide[data-tone='surface'] {
background: var(--odbd-color-surface-raised, var(--odbd-color-surface));
}
.carousel-demo-slide[data-tone='accent'] {
color: var(--odbd-color-accent-foreground);
background: var(--odbd-color-accent);
border-color: var(--odbd-color-accent);
}
.carousel-demo-slide strong {
font-size: var(--odbd-font-size-lg);
line-height: var(--odbd-line-height);
}
.carousel-demo-slide span {
max-width: 22rem;
color: inherit;
font-size: var(--odbd-font-size-md);
line-height: var(--odbd-line-height);
}
</style>
Import
Svelte와 React가 같은 anatomy 계약을 공유합니다. 선택한 프레임워크는 모든 페이지에서 유지됩니다. 패키지 설치는 Getting Started를 참고하세요.
import * as Carousel from '@odbd/svelte/carousel' import { Carousel } from '@odbd/react/carousel'