UNPKG

quasar

Version:

Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time

283 lines (237 loc) 8.2 kB
import { h, computed, watch, onMounted, onBeforeUnmount, getCurrentInstance } from 'vue' import QBtn from '../btn/QBtn.js' import useDark, { useDarkProps } from '../../composables/private/use-dark.js' import usePanel, { usePanelProps, usePanelEmits } from '../../composables/private/use-panel.js' import useFullscreen, { useFullscreenProps, useFullscreenEmits } from '../../composables/private/use-fullscreen.js' import { createComponent } from '../../utils/private/create.js' import { isNumber } from '../../utils/is.js' import { hMergeSlot, hDir } from '../../utils/private/render.js' const navigationPositionOptions = [ 'top', 'right', 'bottom', 'left' ] const controlTypeOptions = [ 'regular', 'flat', 'outline', 'push', 'unelevated' ] export default createComponent({ name: 'QCarousel', props: { ...useDarkProps, ...usePanelProps, ...useFullscreenProps, transitionPrev: { // usePanelParentProps override type: String, default: 'fade' }, transitionNext: { // usePanelParentProps override type: String, default: 'fade' }, height: String, padding: Boolean, controlColor: String, controlTextColor: String, controlType: { type: String, validator: v => controlTypeOptions.includes(v), default: 'flat' }, autoplay: [ Number, Boolean ], arrows: Boolean, prevIcon: String, nextIcon: String, navigation: Boolean, navigationPosition: { type: String, validator: v => navigationPositionOptions.includes(v) }, navigationIcon: String, navigationActiveIcon: String, thumbnails: Boolean }, emits: [ ...useFullscreenEmits, ...usePanelEmits ], setup (props, { slots }) { const { proxy: { $q } } = getCurrentInstance() const isDark = useDark(props, $q) let timer = null, panelsLen const { updatePanelsList, getPanelContent, panelDirectives, goToPanel, previousPanel, nextPanel, getEnabledPanels, panelIndex } = usePanel() const { inFullscreen } = useFullscreen() const style = computed(() => ( inFullscreen.value !== true && props.height !== void 0 ? { height: props.height } : {} )) const direction = computed(() => (props.vertical === true ? 'vertical' : 'horizontal')) const classes = computed(() => `q-carousel q-panel-parent q-carousel--with${ props.padding === true ? '' : 'out' }-padding` + (inFullscreen.value === true ? ' fullscreen' : '') + (isDark.value === true ? ' q-carousel--dark q-dark' : '') + (props.arrows === true ? ` q-carousel--arrows-${ direction.value }` : '') + (props.navigation === true ? ` q-carousel--navigation-${ navigationPosition.value }` : '') ) const arrowIcons = computed(() => { const ico = [ props.prevIcon || $q.iconSet.carousel[ props.vertical === true ? 'up' : 'left' ], props.nextIcon || $q.iconSet.carousel[ props.vertical === true ? 'down' : 'right' ] ] return props.vertical === false && $q.lang.rtl === true ? ico.reverse() : ico }) const navIcon = computed(() => props.navigationIcon || $q.iconSet.carousel.navigationIcon) const navActiveIcon = computed(() => props.navigationActiveIcon || navIcon.value) const navigationPosition = computed(() => props.navigationPosition || (props.vertical === true ? 'right' : 'bottom') ) const controlProps = computed(() => ({ color: props.controlColor, textColor: props.controlTextColor, round: true, [ props.controlType ]: true, dense: true })) watch(() => props.modelValue, () => { if (props.autoplay) { startTimer() } }) watch(() => props.autoplay, val => { if (val) { startTimer() } else if (timer !== null) { clearTimeout(timer) timer = null } }) function startTimer () { const duration = isNumber(props.autoplay) === true ? Math.abs(props.autoplay) : 5000 timer !== null && clearTimeout(timer) timer = setTimeout(() => { timer = null if (duration >= 0) { nextPanel() } else { previousPanel() } }, duration) } onMounted(() => { props.autoplay && startTimer() }) onBeforeUnmount(() => { timer !== null && clearTimeout(timer) }) function getNavigationContainer (type, mapping) { return h('div', { class: 'q-carousel__control q-carousel__navigation no-wrap absolute flex' + ` q-carousel__navigation--${ type } q-carousel__navigation--${ navigationPosition.value }` + (props.controlColor !== void 0 ? ` text-${ props.controlColor }` : '') }, [ h('div', { class: 'q-carousel__navigation-inner flex flex-center no-wrap' }, getEnabledPanels().map(mapping)) ]) } function getContent () { const node = [] if (props.navigation === true) { const fn = slots[ 'navigation-icon' ] !== void 0 ? slots[ 'navigation-icon' ] : opts => h(QBtn, { key: 'nav' + opts.name, class: `q-carousel__navigation-icon q-carousel__navigation-icon--${ opts.active === true ? '' : 'in' }active`, ...opts.btnProps, onClick: opts.onClick }) const maxIndex = panelsLen - 1 node.push( getNavigationContainer('buttons', (panel, index) => { const name = panel.props.name const active = panelIndex.value === index return fn({ index, maxIndex, name, active, btnProps: { icon: active === true ? navActiveIcon.value : navIcon.value, size: 'sm', ...controlProps.value }, onClick: () => { goToPanel(name) } }) }) ) } else if (props.thumbnails === true) { const color = props.controlColor !== void 0 ? ` text-${ props.controlColor }` : '' node.push(getNavigationContainer('thumbnails', panel => { const slide = panel.props return h('img', { key: 'tmb#' + slide.name, class: `q-carousel__thumbnail q-carousel__thumbnail--${ slide.name === props.modelValue ? '' : 'in' }active` + color, src: slide.imgSrc || slide[ 'img-src' ], onClick: () => { goToPanel(slide.name) } }) })) } if (props.arrows === true && panelIndex.value >= 0) { if (props.infinite === true || panelIndex.value > 0) { node.push( h('div', { key: 'prev', class: `q-carousel__control q-carousel__arrow q-carousel__prev-arrow q-carousel__prev-arrow--${ direction.value } absolute flex flex-center` }, [ h(QBtn, { icon: arrowIcons.value[ 0 ], ...controlProps.value, onClick: previousPanel }) ]) ) } if (props.infinite === true || panelIndex.value < panelsLen - 1) { node.push( h('div', { key: 'next', class: 'q-carousel__control q-carousel__arrow q-carousel__next-arrow' + ` q-carousel__next-arrow--${ direction.value } absolute flex flex-center` }, [ h(QBtn, { icon: arrowIcons.value[ 1 ], ...controlProps.value, onClick: nextPanel }) ]) ) } } return hMergeSlot(slots.control, node) } return () => { panelsLen = updatePanelsList(slots) return h('div', { class: classes.value, style: style.value }, [ hDir( 'div', { class: 'q-carousel__slides-container' }, getPanelContent(), 'sl-cont', props.swipeable, () => panelDirectives.value ) ].concat(getContent())) } } })