UNPKG

@ishitatsuyuki/oruga-next

Version:

UI components for Vue.js and CSS framework agnostic

548 lines (538 loc) 19.4 kB
'use strict'; var vue = require('vue'); var helpers = require('./helpers.js'); var config = require('./config.js'); var BaseComponentMixin = require('./BaseComponentMixin-a03c02e3.js'); var Icon = require('./Icon-172f9998.js'); var InjectedChildMixin = require('./InjectedChildMixin-5f524fc3.js'); /** * A Slideshow for cycling images in confined spaces * @displayName Carousel * @style _carousel.scss */ var script = vue.defineComponent({ name: 'OCarousel', components: { [Icon.script.name]: Icon.script }, configField: 'carousel', mixins: [InjectedChildMixin.ProviderParentMixin('carousel', InjectedChildMixin.Sorted), BaseComponentMixin.BaseComponentMixin], emits: ['update:modelValue', 'scroll', 'click'], props: { modelValue: { type: Number, default: 0 }, interval: { type: Number, default: () => { return helpers.getValueByPath(config.getOptions(), 'carousel.interval', 3500); } }, hasDrag: { type: Boolean, default: true }, autoplay: { type: Boolean, default: false }, pauseHover: { type: Boolean, default: false }, repeat: { type: Boolean, default: false }, indicator: { type: Boolean, default: true }, indicatorInside: { type: Boolean, default: false }, indicatorMode: { type: String, default: 'click' }, indicatorPosition: { type: String, default: 'bottom' }, indicatorStyle: { type: String, default: 'dots' }, overlay: Boolean, itemsToShow: { type: Number, default: 1 }, itemsToList: { type: Number, default: 1 }, asIndicator: Boolean, arrow: { type: Boolean, default: true }, arrowHover: { type: Boolean, default: true }, iconPack: String, iconSize: String, iconPrev: { type: String, default: () => { return helpers.getValueByPath(config.getOptions(), 'carousel.iconPrev', 'chevron-left'); } }, iconNext: { type: String, default: () => { return helpers.getValueByPath(config.getOptions(), 'carousel.iconNext', 'chevron-right'); } }, breakpoints: { type: Object, default: () => ({}) }, rootClass: [String, Function, Array], overlayClass: [String, Function, Array], sceneClass: [String, Function, Array], itemsClass: [String, Function, Array], itemsDraggingClass: [String, Function, Array], arrowIconClass: [String, Function, Array], arrowIconPrevClass: [String, Function, Array], arrowIconNextClass: [String, Function, Array], indicatorsClass: [String, Function, Array], indicatorsInsideClass: [String, Function, Array], indicatorsInsidePositionClass: [String, Function, Array], indicatorItemClass: [String, Function, Array], indicatorItemActiveClass: [String, Function, Array], indicatorItemStyleClass: [String, Function, Array] }, data() { return { activeIndex: this.modelValue, scrollIndex: this.modelValue, delta: 0, dragX: false, hold: 0, windowWidth: 0, touch: false, observer: null, refresh_: 0, itemsHovered: false, isPause: false, timer: null }; }, computed: { rootClasses() { return [ this.computedClass('rootClass', 'o-car'), { [this.computedClass('overlayClass', 'o-car__overlay')]: this.overlay } ]; }, sceneClasses() { return [ this.computedClass('sceneClass', 'o-car__scene') ]; }, itemsClasses() { return [ this.computedClass('itemsClass', 'o-car__items'), { [this.computedClass('itemsDraggingClass', 'o-car__items--dragging')]: this.dragging }, ]; }, arrowIconClasses() { return [ this.computedClass('arrowIconClass', 'o-car__arrow__icon'), ]; }, arrowIconPrevClasses() { return [ ...this.arrowIconClasses, this.computedClass('arrowIconPrevClass', 'o-car__arrow__icon-prev') ]; }, arrowIconNextClasses() { return [ ...this.arrowIconClasses, this.computedClass('arrowIconNextClass', 'o-car__arrow__icon-next') ]; }, indicatorsClasses() { return [ this.computedClass('indicatorsClass', 'o-car__indicators'), { [this.computedClass('indicatorsInsideClass', 'o-car__indicators--inside')]: this.indicatorInside }, { [this.computedClass('indicatorsInsidePositionClass', 'o-car__indicators--inside--', this.indicatorPosition)]: this.indicatorInside && this.indicatorPosition } ]; }, indicatorClasses() { return [ this.computedClass('indicatorClass', 'o-car__indicator') ]; }, dragging() { return this.dragX !== false; }, itemStyle() { return `width: ${this.itemWidth}px;`; }, translation() { return -helpers.bound(this.delta + (this.scrollIndex * this.itemWidth), 0, (this.childItems.length - this.settings.itemsToShow) * this.itemWidth); }, total() { return this.childItems.length - this.settings.itemsToShow; }, indicatorCount() { return Math.ceil(this.total / this.settings.itemsToList) + 1; }, indicatorIndex() { return Math.ceil(this.scrollIndex / this.settings.itemsToList); }, hasArrows() { return (this.settings.arrowHover && this.itemsHovered) || !this.settings.arrowHover; }, hasPrev() { return (this.settings.repeat || this.scrollIndex > 0) && this.hasArrows; }, hasNext() { return (this.settings.repeat || this.scrollIndex < this.total) && this.hasArrows; }, breakpointKeys() { const keys = Object.keys(this.breakpoints).map(Number); return keys.sort((a, b) => b - a); }, settings() { let breakpoint = this.breakpointKeys.filter((breakpoint) => { if (this.windowWidth >= breakpoint) { return true; } })[0]; if (breakpoint) { return { ...this.$props, ...this.breakpoints[breakpoint] }; } return this.$props; }, itemWidth() { if (this.windowWidth) { // Ensure component is mounted /* eslint-disable-next-line */ this.refresh_; // We force the computed property to refresh if this prop is changed const rect = this.$el.getBoundingClientRect(); return rect.width / this.settings.itemsToShow; } return 0; } }, watch: { /** * When v-model is changed set the new active item. */ modelValue(value) { if (value <= this.childItems.length - 1) { this.activeIndex = value; this.switchTo(value * this.settings.itemsToList, true); } }, /** * When autoplay is changed, start or pause timer accordingly */ autoplay(status) { if (status) { this.startTimer(); } else { this.pauseTimer(); } }, /** * Since the timer can get paused at the end, if repeat is changed we need to restart it */ repeat(status) { if (status) { this.startTimer(); } } }, methods: { indicatorItemClasses(index) { return [ this.computedClass('indicatorItemClass', 'o-car__indicator__item'), { [this.computedClass('indicatorItemActiveClass', 'o-car__indicator__item--active')]: this.indicatorIndex === index }, { [this.computedClass('indicatorItemStyleClass', 'o-car__indicator__item--', this.indicatorStyle)]: this.indicatorStyle }, ]; }, onMouseEnter() { this.itemsHovered = true; this.checkPause(); }, onMouseLeave() { this.itemsHovered = false; this.startTimer(); }, startTimer() { if (!this.autoplay || this.timer) return; this.isPause = false; this.timer = setInterval(() => { if (!this.repeat && this.activeIndex >= this.childItems.length - 1) { this.pauseTimer(); } else { this.next(); } }, this.interval); }, pauseTimer() { this.isPause = true; if (this.timer) { clearInterval(this.timer); this.timer = null; } }, restartTimer() { this.pauseTimer(); this.startTimer(); }, checkPause() { if (this.pauseHover && this.autoplay) { this.pauseTimer(); } }, modeChange(trigger, value) { if (this.indicatorMode === trigger) { return this.switchTo(value * this.settings.itemsToList); } }, resized() { this.windowWidth = window.innerWidth; }, switchTo(newIndex, onlyMove = this.asIndicator) { if (this.settings.repeat) { newIndex = helpers.mod(newIndex, this.total + 1); } newIndex = helpers.bound(newIndex, 0, this.total); this.scrollIndex = newIndex; this.$emit('scroll', this.indicatorIndex); if (!onlyMove) { this.activeIndex = Math.ceil(newIndex / this.settings.itemsToList); if (this.modelValue !== this.activeIndex) { this.$emit('update:modelValue', this.activeIndex); } } }, next() { this.switchTo(this.scrollIndex + this.settings.itemsToList); }, prev() { this.switchTo(this.scrollIndex - this.settings.itemsToList); }, // handle drag event dragStart(event) { if (this.dragging || !this.settings.hasDrag || (event.button !== 0 && event.type !== 'touchstart')) return; this.hold = Date.now(); this.touch = !!event.touches; this.dragX = this.touch ? event.touches[0].clientX : event.clientX; if (this.touch) { this.pauseTimer(); } window.addEventListener(this.touch ? 'touchmove' : 'mousemove', this.dragMove); window.addEventListener(this.touch ? 'touchend' : 'mouseup', this.dragEnd); }, dragMove(event) { if (!this.dragging) return; const dragEndX = event.touches ? (event.changedTouches[0] || event.touches[0]).clientX : event.clientX; this.delta = this.dragX - dragEndX; if (!event.touches) { event.preventDefault(); } }, dragEnd(event) { if (!this.dragging && !this.hold) return; if (this.hold) { const signCheck = helpers.sign(this.delta); const results = Math.round(Math.abs(this.delta / this.itemWidth) + 0.15); // Hack this.switchTo(this.scrollIndex + signCheck * results); } this.delta = 0; this.dragX = false; if (event && event.touches) { this.startTimer(); } window.removeEventListener(this.touch ? 'touchmove' : 'mousemove', this.dragMove); window.removeEventListener(this.touch ? 'touchend' : 'mouseup', this.dragEnd); }, refresh() { this.$nextTick(() => { this.refresh_++; }); } }, mounted() { if (typeof window !== 'undefined') { if (window.ResizeObserver) { this.observer = new window.ResizeObserver(this.refresh); this.observer.observe(this.$el); } window.addEventListener('resize', this.resized); document.addEventListener('animationend', this.refresh); document.addEventListener('transitionend', this.refresh); document.addEventListener('transitionstart', this.refresh); this.resized(); this.startTimer(); } if (this.$attrs.config) { throw new Error('The config prop was removed, you need to use v-bind instead'); } }, beforeUnmount() { if (typeof window !== 'undefined') { if (window.ResizeObserver) { this.observer.disconnect(); } window.removeEventListener('resize', this.resized); document.removeEventListener('animationend', this.refresh); document.removeEventListener('transitionend', this.refresh); document.removeEventListener('transitionstart', this.refresh); this.dragEnd(); this.pauseTimer(); } } }); function render(_ctx, _cache, $props, $setup, $data, $options) { const _component_o_icon = vue.resolveComponent("o-icon"); return vue.openBlock(), vue.createBlock("div", { class: _ctx.rootClasses, onMouseenter: _cache[3] || (_cache[3] = (...args) => _ctx.onMouseEnter(...args)), onMouseleave: _cache[4] || (_cache[4] = (...args) => _ctx.onMouseLeave(...args)) }, [vue.createVNode("div", { class: _ctx.sceneClasses }, [vue.createVNode("div", { onMousedown: _cache[1] || (_cache[1] = vue.withModifiers((...args) => _ctx.dragStart(...args), ["prevent"])), onTouchstart: _cache[2] || (_cache[2] = (...args) => _ctx.dragStart(...args)), class: _ctx.itemsClasses, style: 'transform:translateX(' + _ctx.translation + 'px)' }, [vue.renderSlot(_ctx.$slots, "default")], 38 /* CLASS, STYLE, HYDRATE_EVENTS */ ), vue.renderSlot(_ctx.$slots, "arrow", { hasPrev: _ctx.hasPrev, prev: _ctx.prev, hasNext: _ctx.hasNext, next: _ctx.next }, () => [_ctx.arrow ? (vue.openBlock(), vue.createBlock(vue.Fragment, { key: 0 }, [vue.withDirectives(vue.createVNode(_component_o_icon, { class: _ctx.arrowIconPrevClasses, onClick: _ctx.prev, pack: _ctx.iconPack, icon: _ctx.iconPrev, size: _ctx.iconSize, both: "" }, null, 8 /* PROPS */ , ["class", "onClick", "pack", "icon", "size"]), [[vue.vShow, _ctx.hasPrev]]), vue.withDirectives(vue.createVNode(_component_o_icon, { class: _ctx.arrowIconNextClasses, onClick: _ctx.next, pack: _ctx.iconPack, icon: _ctx.iconNext, size: _ctx.iconSize, both: "" }, null, 8 /* PROPS */ , ["class", "onClick", "pack", "icon", "size"]), [[vue.vShow, _ctx.hasNext]])], 64 /* STABLE_FRAGMENT */ )) : vue.createCommentVNode("v-if", true)])], 2 /* CLASS */ ), vue.renderSlot(_ctx.$slots, "indicators", { active: _ctx.activeIndex, switchTo: _ctx.switchTo, indicatorIndex: _ctx.indicatorIndex }, () => [_ctx.childItems.length ? (vue.openBlock(), vue.createBlock(vue.Fragment, { key: 0 }, [_ctx.indicator && !_ctx.asIndicator ? (vue.openBlock(), vue.createBlock("div", { key: 0, class: _ctx.indicatorsClasses }, [(vue.openBlock(true), vue.createBlock(vue.Fragment, null, vue.renderList(_ctx.indicatorCount, (_, index) => { return vue.openBlock(), vue.createBlock("a", { class: _ctx.indicatorClasses, onMouseover: $event => _ctx.modeChange('hover', index), onClick: $event => _ctx.modeChange('click', index), key: index }, [vue.renderSlot(_ctx.$slots, "indicator", { i: index }, () => [vue.createVNode("span", { class: _ctx.indicatorItemClasses(index) }, null, 2 /* CLASS */ )])], 42 /* CLASS, PROPS, HYDRATE_EVENTS */ , ["onMouseover", "onClick"]); }), 128 /* KEYED_FRAGMENT */ ))], 2 /* CLASS */ )) : vue.createCommentVNode("v-if", true)], 64 /* STABLE_FRAGMENT */ )) : vue.createCommentVNode("v-if", true)]), _ctx.overlay ? vue.renderSlot(_ctx.$slots, "overlay", { key: 0 }) : vue.createCommentVNode("v-if", true)], 34 /* CLASS, HYDRATE_EVENTS */ ); } script.render = render; script.__file = "src/components/carousel/Carousel.vue"; /** * @displayName Carousel Item */ var script$1 = vue.defineComponent({ name: 'OCarouselItem', configField: 'carousel', mixins: [InjectedChildMixin.InjectedChildMixin('carousel', InjectedChildMixin.Sorted$1), BaseComponentMixin.BaseComponentMixin], props: { itemClass: [String, Function, Array], itemActiveClass: [String, Function, Array] }, computed: { itemClasses() { return [ this.computedClass('itemClass', 'o-car__item'), { [this.computedClass('itemActiveClass', 'o-car__item--active')]: this.isActive } ]; }, itemStyle() { return `width: ${this.parent.itemWidth}px;`; }, isActive() { return this.parent.activeIndex === this.index; } }, methods: { onClick(event) { if (this.isActive) { this.parent.$emit('click', event); } if (this.parent.asIndicator) { this.parent.activeIndex = this.index; this.parent.$emit('update:modelValue', this.index); } } } }); function render$1(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createBlock("div", { class: _ctx.itemClasses, onClick: _cache[1] || (_cache[1] = (...args) => _ctx.onClick(...args)), style: _ctx.itemStyle }, [vue.renderSlot(_ctx.$slots, "default")], 6 /* CLASS, STYLE */ ); } script$1.render = render$1; script$1.__file = "src/components/carousel/CarouselItem.vue"; exports.script = script; exports.script$1 = script$1;