diff --git a/packages/module/playground/components/ui/carousel/Carousel.vue b/packages/module/playground/components/ui/carousel/Carousel.vue new file mode 100644 index 00000000..c88d61ad --- /dev/null +++ b/packages/module/playground/components/ui/carousel/Carousel.vue @@ -0,0 +1,45 @@ + + + diff --git a/packages/module/playground/components/ui/carousel/CarouselContent.vue b/packages/module/playground/components/ui/carousel/CarouselContent.vue new file mode 100644 index 00000000..f432d015 --- /dev/null +++ b/packages/module/playground/components/ui/carousel/CarouselContent.vue @@ -0,0 +1,29 @@ + + + diff --git a/packages/module/playground/components/ui/carousel/CarouselItem.vue b/packages/module/playground/components/ui/carousel/CarouselItem.vue new file mode 100644 index 00000000..53ea50da --- /dev/null +++ b/packages/module/playground/components/ui/carousel/CarouselItem.vue @@ -0,0 +1,23 @@ + + + diff --git a/packages/module/playground/components/ui/carousel/CarouselNext.vue b/packages/module/playground/components/ui/carousel/CarouselNext.vue new file mode 100644 index 00000000..ca65f8d1 --- /dev/null +++ b/packages/module/playground/components/ui/carousel/CarouselNext.vue @@ -0,0 +1,30 @@ + + + diff --git a/packages/module/playground/components/ui/carousel/CarouselPrevious.vue b/packages/module/playground/components/ui/carousel/CarouselPrevious.vue new file mode 100644 index 00000000..331522b7 --- /dev/null +++ b/packages/module/playground/components/ui/carousel/CarouselPrevious.vue @@ -0,0 +1,30 @@ + + + diff --git a/packages/module/playground/components/ui/carousel/index.ts b/packages/module/playground/components/ui/carousel/index.ts new file mode 100644 index 00000000..addfe036 --- /dev/null +++ b/packages/module/playground/components/ui/carousel/index.ts @@ -0,0 +1,10 @@ +export { default as Carousel } from './Carousel.vue' +export { default as CarouselContent } from './CarouselContent.vue' +export { default as CarouselItem } from './CarouselItem.vue' +export { default as CarouselPrevious } from './CarouselPrevious.vue' +export { default as CarouselNext } from './CarouselNext.vue' +export { useCarousel } from './useCarousel' + +export type { + EmblaCarouselType as CarouselApi, +} from 'embla-carousel' diff --git a/packages/module/playground/components/ui/carousel/interface.ts b/packages/module/playground/components/ui/carousel/interface.ts new file mode 100644 index 00000000..99c4f1a8 --- /dev/null +++ b/packages/module/playground/components/ui/carousel/interface.ts @@ -0,0 +1,20 @@ +import type { + EmblaCarouselType as CarouselApi, + EmblaOptionsType as CarouselOptions, + EmblaPluginType as CarouselPlugin, +} from 'embla-carousel' +import type { HTMLAttributes, Ref } from 'vue' + +export interface CarouselProps { + opts?: CarouselOptions | Ref + plugins?: CarouselPlugin[] | Ref + orientation?: 'horizontal' | 'vertical' +} + +export interface CarouselEmits { + (e: 'init-api', payload: CarouselApi): void +} + +export interface WithClassAsProps { + class?: HTMLAttributes['class'] +} diff --git a/packages/module/playground/components/ui/carousel/useCarousel.ts b/packages/module/playground/components/ui/carousel/useCarousel.ts new file mode 100644 index 00000000..85a97ebc --- /dev/null +++ b/packages/module/playground/components/ui/carousel/useCarousel.ts @@ -0,0 +1,57 @@ +import { createInjectionState } from '@vueuse/core' +import emblaCarouselVue from 'embla-carousel-vue' +import { onMounted, ref } from 'vue' +import type { + EmblaCarouselType as CarouselApi, +} from 'embla-carousel' +import type { CarouselEmits, CarouselProps } from './interface' + +const [useProvideCarousel, useInjectCarousel] = createInjectionState( + ({ + opts, orientation, plugins, + }: CarouselProps, emits: CarouselEmits) => { + const [emblaNode, emblaApi] = emblaCarouselVue({ + ...opts, + axis: orientation === 'horizontal' ? 'x' : 'y', + }, plugins) + + function scrollPrev() { + emblaApi.value?.scrollPrev() + } + function scrollNext() { + emblaApi.value?.scrollNext() + } + + const canScrollNext = ref(true) + const canScrollPrev = ref(true) + + function onSelect(api: CarouselApi) { + canScrollNext.value = api.canScrollNext() + canScrollPrev.value = api.canScrollPrev() + } + + onMounted(() => { + if (!emblaApi.value) + return + + emblaApi.value?.on('init', onSelect) + emblaApi.value?.on('reInit', onSelect) + emblaApi.value?.on('select', onSelect) + + emits('init-api', emblaApi.value) + }) + + return { carouselRef: emblaNode, carouselApi: emblaApi, canScrollPrev, canScrollNext, scrollPrev, scrollNext, orientation } + }, +) + +function useCarousel() { + const carouselState = useInjectCarousel() + + if (!carouselState) + throw new Error('useCarousel must be used within a ') + + return carouselState +} + +export { useCarousel, useProvideCarousel } diff --git a/packages/module/playground/package.json b/packages/module/playground/package.json index 4e770f3d..9ed5f882 100644 --- a/packages/module/playground/package.json +++ b/packages/module/playground/package.json @@ -11,6 +11,8 @@ "@nuxtjs/tailwindcss": "^6.10.1", "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", + "embla-carousel": "8.0.0-rc19", + "embla-carousel-vue": "8.0.0-rc19", "lucide-vue-next": "^0.276.0", "radix-vue": "^1.3.0", "tailwind-merge": "^2.0.0",