sigma-ui
Version:
CLI for SIGMA-UI components.
43 lines • 8.71 kB
JSON
{
"name": "carousel",
"dependencies": [
"embla-carousel-vue",
"@vueuse/core"
],
"registryDependencies": [],
"files": [
{
"name": "Carousel.vue",
"content": "<script setup lang=\"ts\">\nimport { useProvideCarousel } from './useCarousel';\nimport type { CarouselEmits, CarouselProps } from './interface';\n\nconst props = withDefaults(defineProps<CarouselProps>(), {\n orientation: 'horizontal',\n});\n\nconst emits = defineEmits<CarouselEmits>();\n\nconst carouselArgs = useProvideCarousel(props, emits);\n\ndefineExpose(carouselArgs);\n\nfunction onKeyDown(event: KeyboardEvent) {\n const prevKey = props.orientation === 'vertical' ? 'ArrowUp' : 'ArrowLeft';\n const nextKey = props.orientation === 'vertical' ? 'ArrowDown' : 'ArrowRight';\n\n if (event.key === prevKey) {\n event.preventDefault();\n carouselArgs.scrollPrev();\n\n return;\n }\n\n if (event.key === nextKey) {\n event.preventDefault();\n carouselArgs.scrollNext();\n }\n}\n</script>\n\n<template>\n <div\n class=\"sigma-ui-carousel\"\n :class=\"[$attrs.class]\"\n role=\"region\"\n aria-roledescription=\"carousel\"\n tabindex=\"0\"\n @keydown=\"onKeyDown\"\n >\n <slot v-bind=\"carouselArgs\" />\n </div>\n</template>\n\n<style>\n.sigma-ui-carousel {\n position: relative;\n}\n</style>\n"
},
{
"name": "CarouselContent.vue",
"content": "<script setup lang=\"ts\">\nimport { useCarousel } from './useCarousel';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\nconst { carouselRef, orientation } = useCarousel();\n</script>\n\n<template>\n <div\n ref=\"carouselRef\"\n class=\"sigma-ui-carousel-content\"\n >\n <div\n class=\"sigma-ui-carousel-content__wrapper\"\n :class=\"[\n orientation === 'horizontal' ? 'sigma-ui-carousel-content__wrapper--horizontal' : 'sigma-ui-carousel-content__wrapper--vertical',\n $attrs.class ?? '',\n ]\"\n v-bind=\"$attrs\"\n >\n <slot />\n </div>\n </div>\n</template>\n\n<style>\n.sigma-ui-carousel-content {\n overflow: hidden;\n}\n\n.sigma-ui-carousel-content__wrapper {\n display: flex;\n}\n\n.sigma-ui-carousel-content__wrapper--horizontal {\n margin-left: -1rem;\n}\n\n.sigma-ui-carousel-content__wrapper--vertical {\n flex-direction: column;\n margin-top: -1rem;\n}\n</style>\n"
},
{
"name": "CarouselItem.vue",
"content": "<script setup lang=\"ts\">\nimport { useCarousel } from './useCarousel';\n\nconst { orientation } = useCarousel();\n</script>\n\n<template>\n <div\n class=\"sigma-ui-carousel-item\"\n :class=\"[\n orientation === 'horizontal' ? 'sigma-ui-carousel-item--horizontal' : 'sigma-ui-carousel-item--vertical',\n $attrs.class ?? '',\n ]\"\n role=\"group\"\n aria-roledescription=\"slide\"\n >\n <slot />\n </div>\n</template>\n\n<style>\n.sigma-ui-carousel-item {\n min-width: 0;\n flex-basis: 100%;\n flex-shrink: 0;\n}\n\n.sigma-ui-carousel-item--horizontal {\n padding-left: 1rem;\n}\n\n.sigma-ui-carousel-item--vertical {\n padding-top: 1rem;\n}\n</style>\n"
},
{
"name": "CarouselNext.vue",
"content": "<script setup lang=\"ts\">\nimport { ArrowRightIcon } from 'lucide-vue-next';\nimport { useCarousel } from './useCarousel';\nimport { Button } from '@ui/registry/css/ui/button';\n\nconst { orientation, canScrollNext, scrollNext } = useCarousel();\n</script>\n\n<template>\n <Button\n :disabled=\"!canScrollNext\"\n class=\"sigma-ui-carousel-next\"\n :class=\"[\n orientation === 'horizontal' ? 'sigma-ui-carousel-next--horizontal' : 'sigma-ui-carousel-next--vertical',\n $attrs.class ?? '',\n ]\"\n variant=\"outline\"\n @click=\"scrollNext\"\n >\n <slot>\n <ArrowRightIcon class=\"sigma-ui-carousel-next__icon\" />\n <span class=\"sr-only\">Next Slide</span>\n </slot>\n </Button>\n</template>\n\n<style>\n.sigma-ui-carousel-next {\n position: absolute;\n width: 2rem;\n height: 2rem;\n padding: 0;\n border-radius: var(--radius);\n touch-action: manipulation;\n}\n\n.sigma-ui-carousel-next--horizontal {\n top: 50%;\n right: -3rem;\n transform: translateY(-50%);\n}\n\n.sigma-ui-carousel-next--vertical {\n bottom: -3rem;\n left: 50%;\n transform: translateX(-50%) rotate(90deg);\n}\n\n.sigma-ui-carousel-next__icon {\n width: 1rem;\n height: 1rem;\n}\n</style>\n"
},
{
"name": "CarouselPrevious.vue",
"content": "<script setup lang=\"ts\">\nimport { ArrowLeftIcon } from 'lucide-vue-next';\nimport { useCarousel } from './useCarousel';\nimport { Button } from '@ui/registry/css/ui/button';\n\nconst { orientation, canScrollPrev, scrollPrev } = useCarousel();\n</script>\n\n<template>\n <Button\n :disabled=\"!canScrollPrev\"\n class=\"sigma-ui-carousel-previous\"\n :class=\"[\n orientation === 'horizontal' ? 'sigma-ui-carousel-previous--horizontal' : 'sigma-ui-carousel-previous--vertical',\n $attrs.class ?? '',\n ]\"\n variant=\"outline\"\n @click=\"scrollPrev\"\n >\n <slot>\n <ArrowLeftIcon class=\"sigma-ui-carousel-previous__icon\" />\n <span class=\"sr-only\">Previous Slide</span>\n </slot>\n </Button>\n</template>\n\n<style>\n.sigma-ui-carousel-previous {\n position: absolute;\n width: 2rem;\n height: 2rem;\n padding: 0;\n border-radius: var(--radius);\n touch-action: manipulation;\n}\n\n.sigma-ui-carousel-previous--horizontal {\n top: 50%;\n left: -3rem;\n transform: translateY(-50%);\n}\n\n.sigma-ui-carousel-previous--vertical {\n top: -3rem;\n left: 50%;\n transform: translateX(-50%) rotate(90deg);\n}\n\n.sigma-ui-carousel-previous__icon {\n width: 1rem;\n height: 1rem;\n}\n</style>\n"
},
{
"name": "index.ts",
"content": "export { default as Carousel } from './Carousel.vue';\nexport { default as CarouselContent } from './CarouselContent.vue';\nexport { default as CarouselItem } from './CarouselItem.vue';\nexport { default as CarouselPrevious } from './CarouselPrevious.vue';\nexport { default as CarouselNext } from './CarouselNext.vue';\nexport { useCarousel } from './useCarousel';\n\nexport type {\n UnwrapRefCarouselApi as CarouselApi,\n} from './interface';\n"
},
{
"name": "interface.ts",
"content": "import type { UnwrapRef } from 'vue';\nimport type useEmblaCarousel from 'embla-carousel-vue';\nimport type {\n EmblaCarouselVueType,\n} from 'embla-carousel-vue';\n\ntype CarouselApi = EmblaCarouselVueType[1];\ntype UseCarouselParameters = Parameters<typeof useEmblaCarousel>;\ntype CarouselOptions = UseCarouselParameters[0];\ntype CarouselPlugin = UseCarouselParameters[1];\n\nexport type UnwrapRefCarouselApi = UnwrapRef<CarouselApi>;\n\nexport interface CarouselProps {\n opts?: CarouselOptions;\n plugins?: CarouselPlugin;\n orientation?: 'horizontal' | 'vertical';\n}\n\nexport interface CarouselEmits {\n (e: 'init-api', payload: UnwrapRefCarouselApi): void;\n}\n"
},
{
"name": "useCarousel.ts",
"content": "import { createInjectionState } from '@vueuse/core';\nimport emblaCarouselVue from 'embla-carousel-vue';\nimport { onMounted, ref } from 'vue';\nimport type { UnwrapRefCarouselApi as CarouselApi, CarouselEmits, CarouselProps } from './interface';\n\nconst [useProvideCarousel, useInjectCarousel] = createInjectionState(\n ({\n opts,\n orientation,\n plugins,\n }: CarouselProps, emits: CarouselEmits) => {\n const [emblaNode, emblaApi] = emblaCarouselVue({\n ...opts,\n axis: orientation === 'horizontal' ? 'x' : 'y',\n }, plugins);\n\n function scrollPrev() {\n emblaApi.value?.scrollPrev();\n }\n\n function scrollNext() {\n emblaApi.value?.scrollNext();\n }\n\n const canScrollNext = ref(false);\n const canScrollPrev = ref(false);\n\n function onSelect(api: CarouselApi) {\n canScrollNext.value = api?.canScrollNext() || false;\n canScrollPrev.value = api?.canScrollPrev() || false;\n }\n\n onMounted(() => {\n if (!emblaApi.value) {\n return;\n }\n\n emblaApi.value?.on('init', onSelect);\n emblaApi.value?.on('reInit', onSelect);\n emblaApi.value?.on('select', onSelect);\n\n emits('init-api', emblaApi.value);\n });\n\n return { carouselRef: emblaNode, carouselApi: emblaApi, canScrollPrev, canScrollNext, scrollPrev, scrollNext, orientation };\n },\n);\n\nfunction useCarousel() {\n const carouselState = useInjectCarousel();\n\n if (!carouselState) {\n throw new Error('useCarousel must be used within a <Carousel />');\n }\n\n return carouselState;\n}\n\nexport { useCarousel, useProvideCarousel };\n"
}
],
"type": "components:ui"
}