UNPKG

@coreui/vue

Version:

UI Components Library for Vue.js

242 lines (238 loc) 8.66 kB
'use strict'; var vue = require('vue'); var isRTL = require('../../utils/isRTL.js'); var isInViewport = require('../../utils/isInViewport.js'); var swipe = require('../../utils/swipe.js'); const CCarousel = vue.defineComponent({ name: 'CCarousel', props: { /** * Adding in the previous and next controls. */ controls: Boolean, /** * Add darker controls, indicators, and captions. */ dark: Boolean, /** * index of the active item. */ index: { type: Number, default: 0, }, /** * Adding indicators at the bottom of the carousel for each item. */ indicators: Boolean, /** * The amount of time to delay between automatically cycling an item. If false, carousel will not automatically cycle. */ interval: { type: [Boolean, Number], default: 5000, }, /** * If set to 'hover', pauses the cycling of the carousel on mouseenter and resumes the cycling of the carousel on mouseleave. If set to false, hovering over the carousel won't pause it. */ pause: { type: [Boolean, String], default: 'hover', validator: (value) => { return typeof value === 'boolean' || value === 'hover'; }, }, /** * Set type of the transition. * * @values 'crossfade', 'slide' */ transition: { type: String, default: 'slide', validator: (value) => { return ['crossfade', 'slide'].includes(value); }, }, /** * Set whether the carousel should support left/right swipe interactions on touchscreen devices. * * @since 5.10.0 */ touch: { type: Boolean, default: true, }, /** * Set whether the carousel should cycle continuously or have hard stops. */ wrap: { type: Boolean, default: true, }, }, emits: [ /** * Event called when the slide transition starts. * * @since 5.10.0 */ 'slide', /** * Event called when the slide transition ends. * * @since 5.10.0 */ 'slid', ], setup(props, { emit, slots }) { const carouselRef = vue.ref(); const active = vue.ref(props.index); const animating = vue.ref(false); const customInterval = vue.ref(props.interval); const direction = vue.ref('next'); const items = vue.ref([]); const timeout = vue.ref(); const visible = vue.ref(); let swipe$1; const setAnimating = (value) => { animating.value = value; }; const setCustomInterval = (value) => { customInterval.value = value; }; vue.provide('setAnimating', setAnimating); vue.provide('setCustomInterval', setCustomInterval); const pause = () => timeout.value && clearInterval(timeout.value); const cycle = () => { pause(); if (typeof props.interval === 'number') { timeout.value = setTimeout(() => nextItemWhenVisible(), typeof customInterval.value === 'number' ? customInterval.value : props.interval); } }; const handleControlClick = (_direction) => { if (animating.value) { return; } direction.value = _direction; if (_direction === 'next') { active.value = active.value === items.value.length - 1 ? 0 : active.value + 1; } else { active.value = active.value === 0 ? items.value.length - 1 : active.value - 1; } }; const nextItemWhenVisible = () => { // Don't call next when the page isn't visible // or the carousel or its parent isn't visible if (!document.hidden && carouselRef.value && isInViewport.default(carouselRef.value)) { handleControlClick('next'); } }; const handleIndicatorClick = (index) => { if (active.value === index) { return; } if (active.value < index) { direction.value = 'next'; active.value = index; return; } if (active.value > index) { direction.value = 'prev'; active.value = index; } }; const handleScroll = () => { visible.value = !document.hidden && carouselRef.value && isInViewport.default(carouselRef.value) ? true : false; }; vue.onBeforeMount(() => { if (slots.default) { const children = typeof slots.default()[0].type === 'symbol' ? slots.default()[0].children : slots.default(); if (children && Array.isArray(children)) { // @ts-expect-error TODO: fix types items.value = children.filter((child) => child.type.name === 'CCarouselItem'); } } }); vue.onMounted(() => { window.addEventListener('scroll', handleScroll); if (props.touch && carouselRef.value) { swipe$1 = new swipe.default(carouselRef.value, { onLeft: () => handleControlClick(isRTL.default(carouselRef.value) ? 'prev' : 'next'), onRight: () => handleControlClick(isRTL.default(carouselRef.value) ? 'next' : 'prev'), }); } }); vue.onBeforeUnmount(() => { window.removeEventListener('scroll', handleScroll); swipe$1?.dispose(); }); vue.watch(animating, () => { if (animating.value) { emit('slide', active.value, direction.value); return; } emit('slid', active.value, direction.value); if (props.wrap || active.value < items.value.length - 1) { cycle(); } }); vue.watch(visible, () => { if (visible.value) { cycle(); } }); return () => vue.h('div', { class: ['carousel slide', props.transition === 'crossfade' && 'carousel-fade'], ...(props.dark && { 'data-coreui-theme': 'dark' }), onmouseover: () => props.pause && pause(), onmouseleave: () => cycle(), ref: carouselRef, }, [ props.indicators && vue.h('div', { class: 'carousel-indicators', }, items.value.map((_, index) => { return vue.h('button', { type: 'button', id: index, 'data-coreui-target': '', ...(active.value === index && { class: 'active' }), onClick: () => handleIndicatorClick(index), }); })), vue.h('div', { class: 'carousel-inner' }, items.value.map((item, index) => { return vue.h(item, { active: active.value === index ? true : false, direction: direction.value, }); })), props.controls && [ vue.h('button', { type: 'button', class: 'carousel-control-prev', 'data-coreui-target': '', onClick: () => handleControlClick('prev'), }, [ vue.h('span', { class: 'carousel-control-prev-icon', ariaHidden: 'true' }), vue.h('span', { class: 'visually-hidden' }, 'Previous'), ]), vue.h('button', { type: 'button', class: 'carousel-control-next', 'data-coreui-target': '', onClick: () => handleControlClick('next'), }, [ vue.h('span', { class: 'carousel-control-next-icon', ariaHidden: 'true' }), vue.h('span', { class: 'visually-hidden' }, 'Next'), ]), ], ]); }, }); exports.CCarousel = CCarousel; //# sourceMappingURL=CCarousel.js.map