UNPKG

@ussebastian/kitdigital

Version:

Kit Digital de la Universidad San Sebastián

271 lines (222 loc) 9.68 kB
import EmblaCarousel from 'embla-carousel/embla-carousel.esm'; import Autoplay from 'embla-carousel-autoplay/embla-carousel-autoplay.esm'; import { wrap } from './utils/InitUtils'; export default class ComponentCarousel { constructor(el) { this.rootNode = el; // data attributes const getAttr = (attribute) => this.rootNode.getAttribute(attribute); const hasAttr = (attribute) => this.rootNode.hasAttribute(attribute); this.carouselClass = getAttr('data-uss-carousel'); this.rootNode.classList.add(this.carouselClass); this.carouselType = this.carouselClass.split('-').pop(); this.visibleItems = null; if (this.carouselType === 'cards') { this.visibleItems = getAttr('data-uss-visible-items') || 1; } this.align = this.carouselType === 'cards' ? 'start' : 'center'; this.carouselItemsClass = getAttr('data-uss-items-class'); this.autoplayDelay = getAttr('data-uss-autoplay'); this.title = getAttr('data-uss-title'); this.hideControlls = hasAttr('data-uss-hide-controls'); this.EmblaOptions = { loop: hasAttr('data-uss-loop'), draggable: hasAttr('data-uss-draggable'), speed: getAttr('data-uss-speed') || 10, startIndex: getAttr('data-uss-startIndex') || 0, align: this.align, }; this.emblaInstance = null; this.prevButtonNode = null; this.nextButtonNode = null; this.pageButtonContainer = null; this.pageButtonsArray = null; this.mobileBreakpoint = 990; this.counterNode = null; this.carouselItems = !this.carouselItemsClass ? this.rootNode.querySelectorAll(':scope > *') : this.rootNode.querySelectorAll(`.${this.carouselItemsClass}`); this.totalItems = this.carouselItems.length; this.disableNextButtonAtIndex = this.totalItems - 1; this.carouselViewport = null; } setupPageButtons = (embla) => { this.pageButtonsArray.forEach((dotNode, i) => { dotNode.addEventListener('click', () => embla.scrollTo(i), false); }); }; generatePageButtons = (embla) => { const template = `<button class="uss-carousel-${this.carouselType}__page-single-button" type="button"> </button>`; this.pageButtonContainer.innerHTML = embla.scrollSnapList().reduce((acc) => acc + template, ''); const pageButtonsArray = Array.prototype.slice.call(this.pageButtonContainer.children); for (let i = 0; i < pageButtonsArray.length; i += 1) { const index = i + 1; const indexFormatted = index.toString().padStart(2, '0'); pageButtonsArray[i].innerHTML = indexFormatted; } return pageButtonsArray; }; selectPage = (embla) => () => { const previous = embla.previousScrollSnap(); const selected = embla.selectedScrollSnap(); this.pageButtonsArray[previous].classList.remove( `uss-carousel-${this.carouselType}__page-single-button--selected`, ); this.pageButtonsArray[selected].classList.add( `uss-carousel-${this.carouselType}__page-single-button--selected`, ); }; makeControls() { const controlContainer = document.createElement('div'); controlContainer.classList.add(`uss-carousel-${this.carouselType}__control-container`); if (this.title) { const title = document.createElement('h2'); title.classList.add(`uss-carousel-${this.carouselType}__title`); title.innerHTML = this.title; if (this.carouselType === 'cards') { this.rootNode.prepend(title); } else { controlContainer.appendChild(title); } } const control = document.createElement('div'); control.classList.add(`uss-carousel-${this.carouselType}__control`); let pageButtonContainer = null; pageButtonContainer = document.createElement('div'); pageButtonContainer.classList.add(`uss-carousel-${this.carouselType}__page-buttons`); this.pageButtonContainer = pageButtonContainer; // make a div with the current and total items like so: 01/10 const counter = document.createElement('div'); counter.classList.add(`uss-carousel-${this.carouselType}__counter`); // add number of items to the counter counter.innerHTML = `01/${this.totalItems.toString().padStart(2, '0')}`; const pageTotals = document.createElement('div'); pageTotals.classList.add(`uss-carousel-${this.carouselType}__page-totals`); const controlButtonsContainer = document.createElement('div'); controlButtonsContainer.classList.add( `uss-carousel-${this.carouselType}__control-buttons-container`, ); const prevButton = document.createElement('button'); prevButton.classList.add('uss-btn', 'uss-btn--slide', 'uss-btn--slide-prev'); prevButton.setAttribute('data-uss-carousel-button', 'prev'); this.prevButtonNode = prevButton; const prevButtonIcon = document.createElement('i'); prevButtonIcon.classList.add('uss-icon', 'ri-arrow-left-s-line'); const nextButton = document.createElement('button'); nextButton.classList.add('uss-btn', 'uss-btn--slide', 'uss-btn--slide-next'); nextButton.setAttribute('data-uss-carousel-button', 'next'); this.nextButtonNode = nextButton; const nextButtonIcon = document.createElement('i'); nextButtonIcon.classList.add('uss-icon', 'ri-arrow-right-s-line'); // append this prevButton.appendChild(prevButtonIcon); nextButton.appendChild(nextButtonIcon); controlButtonsContainer.appendChild(prevButton); controlButtonsContainer.appendChild(nextButton); control.appendChild(pageButtonContainer); pageButtonContainer.before(counter); this.counterNode = counter; control.appendChild(controlButtonsContainer); controlContainer.appendChild(control); if (this.carouselType === 'cards') { controlContainer.appendChild(control); controlContainer.appendChild(counter); } return controlContainer; } handleButtonsDisableState() { const width = document.body.clientWidth; const selected = this.emblaInstance.selectedScrollSnap(); if (width < this.mobileBreakpoint) { if (selected === 0) { this.prevButtonNode.setAttribute('disabled', true); this.nextButtonNode.removeAttribute('disabled'); } else if (selected >= this.totalItems - 1) { this.nextButtonNode.setAttribute('disabled', true); this.prevButtonNode.removeAttribute('disabled'); } else { this.prevButtonNode.removeAttribute('disabled'); this.nextButtonNode.removeAttribute('disabled'); } } else if (selected >= this.disableNextButtonAtIndex) { this.nextButtonNode.setAttribute('disabled', true); this.prevButtonNode.removeAttribute('disabled', false); } else { this.nextButtonNode.removeAttribute('disabled', false); this.prevButtonNode.removeAttribute('disabled', false); if (selected === 0) this.prevButtonNode.setAttribute('disabled', true); } } handleCounter() { const selected = this.emblaInstance.selectedScrollSnap(); const selectedFormatted = (selected + 1).toString().padStart(2, '0'); this.counterNode.innerHTML = `${selectedFormatted}/${this.totalItems .toString() .padStart(2, '0')}`; } init() { if (this.carouselType === 'cards' && this.visibleItems) { this.carouselItems.forEach((_, i) => { this.carouselItems[i].classList.add(`uss-carousel-cards__md-col-${this.visibleItems}`); }); this.disableNextButtonAtIndex = this.carouselItems.length - this.visibleItems; } let container = document.createElement('div'); container.classList.add(`uss-carousel-${this.carouselType}__container`); const carouselItemsContainer = wrap(this.carouselItems, container); this.rootNode.appendChild(carouselItemsContainer); container = this.rootNode.querySelector(`.uss-carousel-${this.carouselType}__container`); const viewport = document.createElement('div'); viewport.classList.add(`uss-carousel-${this.carouselType}__viewport`); this.carouselViewport = wrap([container], viewport); this.rootNode.appendChild(this.carouselViewport); if (!this.hideControlls) { const carouselConstrols = this.makeControls(); if (this.carouselType === 'cards') { this.rootNode.appendChild(carouselConstrols); } else { this.rootNode.appendChild(carouselConstrols); } } let autoplay = null; if (this.autoplayDelay) { autoplay = Autoplay({ delay: this.autoplayDelay }, this.rootNode); } const embla = EmblaCarousel( this.carouselViewport, this.EmblaOptions, autoplay ? [autoplay] : null, ); this.emblaInstance = embla; if (!this.hideControlls && this.carouselType !== 'cards') { // for hero and single-content this.pageButtonsArray = this.generatePageButtons(embla); const setSelectedPage = this.selectPage(embla); this.setupPageButtons(embla); embla.on('init', setSelectedPage); embla.on('select', setSelectedPage); if (!this.EmblaOptions.loop) { embla.on('init', () => { this.handleButtonsDisableState(); }); embla.on('select', () => { this.handleButtonsDisableState(); }); } } else if (!this.hideControlls) { // for cards embla.on('init', () => { this.handleButtonsDisableState(); }); embla.on('select', () => { this.handleCounter(); this.handleButtonsDisableState(); }); } if (!this.hideControlls) { this.prevButtonNode.addEventListener('click', embla.scrollPrev, false); this.nextButtonNode.addEventListener('click', embla.scrollNext, false); } } }