UNPKG

@salla.sa/twilight-components

Version:
1,266 lines 76.9 kB
/*! * Crafted with ❤ by Salla */ import { h, Host } from "@stencil/core"; // Import from bundle.mjs to avoid bundling issue since module resolution is set to `node` import Swiper from "swiper/swiper-bundle.mjs"; import ArrowRightIcon from "../../assets/svg/keyboard_arrow_right.svg"; import ArrowLeftIcon from "../../assets/svg/keyboard_arrow_left.svg"; /** * @slot items - Slider items. * @slot thumbs - Thumbs slider items. */ export class SallaSlider { constructor() { /** * Show/hide slider block title */ this.blockTitle = ''; /** * Enable call a specific slide by index from thumbnails or color option in `salla-slider-options` component, works only if `data-img-id` and `data-slid-index` attributes are set on each slide */ this.listenToThumbnailsOption = false; /** * Show/hide slider block sub title */ this.blockSubtitle = ''; /** * Show/hide display all button beside arrows */ this.displayAllUrl = ''; /** * Show/hide display all button beside arrows */ this.arrowsCentered = false; /** * Vertical or Horizontal thumbs slider */ this.verticalThumbs = false; /** * Disable thumbs slider and show it as a grid */ this.gridThumbs = false; /** * Vertical or Horizontal main slider */ this.vertical = false; /** * Auto Height slider */ this.autoHeight = false; /** * Show/hide arrows */ this.showControls = true; /** * Show/hide arrows */ this.controlsOuter = false; /** * Show/hide thumbs slider arrows */ this.showThumbsControls = true; /** * When enabled and there is exactly one slide in the `items` slot, * render without initializing Swiper (single slide mode). */ this.staticWhenSingle = false; /** * Enable autoplay - working with `type="carousel" only` */ this.autoPlay = false; /** * slidesPerView */ this.slidesPerView = "auto"; /** * Enable pagination */ this.pagination = false; /** * Enable center mode - working with `type="carousel" only` */ this.centered = false; /** * Run slider in loop, Don't use it for slides with custom components inside it, because it may cause re-render issue */ this.loop = false; /** * Set the type of the slider * Default: '' */ this.type = ''; // States this.currentIndex = undefined; this.isEnd = false; this.isBeginning = true; /** Use matchMedia instead of window.innerWidth to avoid forced reflow (Lighthouse recommended) */ this.isDesktopViewport = typeof window !== 'undefined' ? window.matchMedia('(min-width: 768px)').matches : true; this._rafId = null; this.viewportMediaQuery = null; this.hasThumbSlot = false; this.pre_defined_config = { carousel: { speed: 300, slidesPerView: 'auto', spaceBetween: 0, }, fullwidth: { speed: 750, parallax: true, }, fullscreen: { speed: 1000, parallax: true, direction: "vertical", followFinger: false, touchReleaseOnEdges: true, // v9+: lazy is native (use loading="lazy" on images + .swiper-lazy-preloader) mousewheel: {} }, testimonials: { draggable: true, slidesPerView: 1, breakpoints: { 1024: { slidesPerView: 2 } } }, blog: { parallax: true, speed: 800, loop: true, slidesPerView: 1, centeredSlides: true, spaceBetween: 30, breakpoints: { 320: { spaceBetween: 10 }, 768: { spaceBetween: 15 }, 980: { spaceBetween: 30 }, } }, thumbs: { slidesPerView: 1, spaceBetween: 30 } }; this.onViewportChange = (e) => { this.isDesktopViewport = e.matches; }; this.direction = this.direction || document.documentElement.dir; } // Methods /** * Returns the Swiper instance to allow direct manipulation * @returns The Swiper slider instance */ async sliderInstance() { return this.slider; } /** * Run transition to the slide with index number equal to 'index' parameter for the duration equal to 'speed' parameter. * * @param {number} index - Index number of slide. * @param {number} speed - Transition duration (in ms). * @param {boolean} runCallbacks - Set it to false (by default it is true) and transition will not produce transition events. * **/ async slideTo(index, speed, runCallbacks) { if (!this.slider) return; return this.slider.slideTo(index, speed, runCallbacks); } /** * Run transition to the next slide. * * @param {number} speed - Transition duration (in ms). * @param {boolean} runCallbacks - Set it to false (by default it is true) and transition will not produce transition events. * **/ async slideNext(speed, runCallbacks) { this.slider?.slideNext(speed, runCallbacks); } /** * Run transition to the previous slide. * * @param {number} speed - Transition duration (in ms). * @param {boolean} runCallbacks - Set it to false (by default it is true) and transition will not produce transition events. * **/ async slidePrev(speed, runCallbacks) { this.slider?.slidePrev(speed, runCallbacks); } /** * Does the same as .slideTo but for the case when used with enabled loop. So this method will slide to slides with realIndex matching to passed index * * @param {number} speed - Transition duration (in ms). * @param {boolean} runCallbacks - Set it to false (by default it is true) and transition will not produce transition events. * **/ async slideToLoop(index, speed, runCallbacks) { this.slider?.slideToLoop(index, speed, runCallbacks); } /** * Does the same as .slideNext but for the case when used with enabled loop. So this method will slide to next slide with realIndex matching to next index * * @param {number} speed - Transition duration (in ms). * @param {boolean} runCallbacks - Set it to false (by default it is true) and transition will not produce transition events. * **/ async slideNextLoop(speed, runCallbacks) { this.slider?.slideNextLoop(speed, runCallbacks); } /** * Does the same as .slidePrev but for the case when used with enabled loop. So this method will slide to previous slide with realIndex matching to previous index * * @param {number} speed - Transition duration (in ms). * @param {boolean} runCallbacks - Set it to false (by default it is true) and transition will not produce transition events. * **/ async slidePrevLoop(speed, runCallbacks) { this.slider?.slidePrevLoop(speed, runCallbacks); } /** * Reset slider position to currently active slide for the duration equal to 'speed' parameter. * * @param {number} speed - Transition duration (in ms). * @param {boolean} runCallbacks - Set it to false (by default it is true) and transition will not produce transition events. * **/ async slideReset(speed, runCallbacks) { this.slider?.slideReset(speed, runCallbacks); } /** * Reset slider position to closest slide/snap point for the duration equal to 'speed' parameter. * @param {number} speed - Transition duration (in ms). * @param {boolean} runCallbacks - Set it to false (by default it is true) and transition will not produce transition events. * **/ async slideToClosest(speed, runCallbacks) { this.slider?.slideToClosest(speed, runCallbacks); } /** * You should call it after you add/remove slides manually, or after you hide/show it, or do any custom DOM modifications with Swiper This method also includes subcall of the following methods which you can use separately: * **/ async update() { this.slider?.update(); } /** * Force slider to update its height (when autoHeight enabled) for the duration equal to 'speed' parameter * @param {number} speed - Transition duration (in ms). * **/ async updateAutoHeight(speed) { this.slider?.updateAutoHeight(speed); } /** * recalculate number of slides and their offsets. Useful after you add/remove slides with JavaScript * **/ async updateSlides() { this.slider?.updateSlides(); } /** * recalculate slider progress * **/ async updateProgress() { this.slider?.updateProgress(); } /** * update active/prev/next classes on slides and bullets * **/ async updateSlidesClasses() { this.slider?.updateSlidesClasses(); } /** * Get slider slides * **/ async getSlides() { return this.slider?.slides; } /** * Get slider slides * **/ async updateSize() { return await this.slider?.updateSize(); } /** * Get thumbs slider update * **/ async sliderInit() { return await this.slider?.init(); } /** * Get thumbs slider slides * **/ async thumbsSliderInstance() { return await this.thumbsSlider; } /** * Get thumbs slider update * **/ async thumbsSliderInit() { return await this.thumbsSlider.init(); } /** * Get thumbs slider update * **/ async thumbsSliderUpdate() { return await this.thumbsSlider.update(); } /** * Get thumbs slider updateSlides * **/ async thumbsSliderUpdateSlides() { return await this.thumbsSlider.updateSlides(); } /** * Get thumbs slider updateSize * **/ async getThumbsUpdateSize() { return await this.thumbsSlider?.updateSize(); } /** * Does the same as .slideTo but for the case when used with enabled loop. So this method will slide to slides with realIndex matching to passed index * * @param {number} speed - Transition duration (in ms). * @param {boolean} runCallbacks - Set it to false (by default it is true) and transition will not produce transition events. * **/ async thumbsSlideTo(index, speed, runCallbacks) { return this.thumbsSlider?.slideTo(index, speed, runCallbacks); } /** * Get thumbs slider slides * **/ async getThumbsSlides() { return await this.thumbsSlider?.slides; } isStaticWhenSingle() { return this.staticWhenSingle && this.host.querySelector('[slot="items"]')?.children?.length === 1; } async componentWillLoad() { if (this.isStaticWhenSingle()) { this.host.classList.add('s-slider-single-mode'); return; } salla.lang.onLoaded(() => { this.displayAllTitle = salla.lang.get('blocks.home.display_all'); }); this.hasThumbSlot = !!this.host.querySelector('[slot="thumbs"]'); if (this.listenToThumbnailsOption) { salla.event.on('product-options::change', data => { const isSupportedOptionType = ['thumbnail', 'color'].includes(data?.option?.type); const optionImageId = data?.detail?.option_value; if (!isSupportedOptionType || !optionImageId) { return; } const slideIndex = this.sliderWrapper ?.querySelector(`[data-img-id="${optionImageId}"]`) ?.getAttribute('data-slid-index'); if (slideIndex) { this.slideTo(parseInt(slideIndex), 300, false); } }); } } getSwiperConfig() { let autoplay = this.autoPlay; if (autoplay && typeof autoplay !== 'object') { autoplay = { delay: 10000 }; } let pre_defined_config = { loop: this.loop, autoplay, centeredSlides: this.centered, slidesPerView: this.slidesPerView, autoHeight: this.autoHeight, // v9+: native lazy (loading="lazy" on images); no lazy module on: { // todo:: find better way for this workaround to show lazyLoad for duplicated slides, because it clones the slide after it's already rendered, // then it re appended it as is,in this case the image is loaded but class not added. afterInit: (slider) => { this.afterInit.emit(slider); document.lazyLoadInstance?.update(); this.loop && slider.slides.map(slide => { if (!slide.classList.contains('swiper-slide-duplicate')) { return; } slide.querySelectorAll('img.lazy:not(.loaded)').forEach(img => img.classList.add('loaded')); }); }, }, pagination: this.pagination ? { el: this.host.id ? `#${this.host.id} .swiper-pagination` : '', clickable: true, } : false, navigation: this.showControls ? { nextEl: this.host.id ? `#${this.host.id} .s-slider-next` : '', prevEl: this.host.id ? `#${this.host.id} .s-slider-prev` : '' } : false, breakpoints: { 768: { direction: this.vertical ? "vertical" : "horizontal", }, }, }; let pre_defined_thumbs_config = { freeMode: false, watchSlidesProgress: true, slidesPerView: 4, spaceBetween: 10, watchOverflow: true, breakpoints: { 768: { direction: this.verticalThumbs ? "vertical" : "horizontal", spaceBetween: 16, }, }, navigation: this.showThumbsControls ? { nextEl: this.host.id ? `#${this.host.id} .s-slider-thumbs-next` : '', prevEl: this.host.id ? `#${this.host.id} .s-slider-thumbs-prev` : '' } : false, }; this.pre_defined_config.fullscreen.mousewheel = { releaseOnEdges: this.host.querySelectorAll('.swiper-slide').length > 1 ? false : true }, pre_defined_config = { ...pre_defined_config, ...(this.pre_defined_config[this.type] || {}) }; if (this.type == 'thumbs' && this.thumbsSliderWrapper) { for (const slide of Array.from(this.thumbsSliderWrapper.children)) { if (slide.nodeType === Node.ELEMENT_NODE) slide.classList.add('swiper-slide'); } if (this.hasThumbSlot && this.thumbsConfig) { try { pre_defined_thumbs_config = { ...pre_defined_thumbs_config, ...(typeof this.thumbsConfig === 'string' ? JSON.parse(this.thumbsConfig) : this.thumbsConfig) }; } catch (error) { salla.logger.warn('Failed to parse thumbs slider config:', error); } } if (!this.thumbsSliderContainer) { return pre_defined_config; } this.thumbsSlider = new Swiper(this.thumbsSliderContainer, pre_defined_thumbs_config); // @ts-ignore pre_defined_config.thumbs = { swiper: this.thumbsSlider, }; } pre_defined_config = { ...pre_defined_config, }; if (this.sliderConfig) { try { pre_defined_config = { ...pre_defined_config, ...(typeof this.sliderConfig === 'string' ? JSON.parse(this.sliderConfig) : this.sliderConfig) }; } catch (error) { salla.logger.warn('Failed to parse slider config:', error); } } return pre_defined_config; } getThumbsDirection() { const { verticalThumbs, isDesktopViewport, direction } = this; if (verticalThumbs && !isDesktopViewport && direction === 'rtl') { return 'rtl'; } if (verticalThumbs && isDesktopViewport && direction === 'rtl') { return 'ltr'; } return direction; } initSlider() { for (const slide of Array.from(this.sliderWrapper?.children || [])) { if (slide.nodeType === Node.ELEMENT_NODE) slide.classList.add('swiper-slide'); } if (!this.sliderContainer) { salla.logger.warn('Slider container not found'); return; } this.slider = new Swiper(this.sliderContainer, this.getSwiperConfig()); // Backward compatibility: lazy load data-background as background-image (removed in Swiper v9+) this.loadLazyBackgrounds(); this.slider.on('slideChange', () => this.loadLazyBackgrounds()); // Add swiper-lazy-loaded to lazy images when visible this.observeLazyImages(); // Expose slider events this.slider.on('slideChange', (slider) => { //todo:: it doesn't change when loop is active, always will be false this.isBeginning = slider.isBeginning; this.isEnd = slider.isEnd; this.slideChange.emit(slider); }); this.slider.on('reachBeginning', (slider) => this.reachBeginning.emit(slider)); this.slider.on('reachEnd', (slider) => this.reachEnd.emit(slider)); this.slider.on('slideChangeTransitionEnd', (slider) => { if (this.type == "fullscreen") { const activeIndex = slider.activeIndex; slider.params.mousewheel.releaseOnEdges = activeIndex === 0 || (activeIndex === slider.slides.length - 1); } this.slideChangeTransitionEnd.emit(slider); }); this.slider.on('slideChangeTransitionStart', (slider) => this.slideChangeTransitionStart.emit(slider)); this.slider.on('slideNextTransitionEnd', (slider) => this.slideNextTransitionEnd.emit(slider)); this.slider.on('slideNextTransitionStart', (slider) => this.slideNextTransitionStart.emit(slider)); this.slider.on('slidePrevTransitionEnd', (slider) => this.slidePrevTransitionEnd.emit(slider)); this.slider.on('slidePrevTransitionStart', (slider) => this.slidePrevTransitionStart.emit(slider)); this.slider.on('sliderMove', (slider) => this.sliderMove.emit(slider)); this.slider.on('touchEnd', (slider) => this.touchSliderEnd.emit(slider)); this.slider.on('touchMove', (slider) => this.touchSliderMove.emit(slider)); this.slider.on('touchStart', (slider) => this.touchSliderStart.emit(slider)); this.slider.on('transitionEnd', (slider) => this.sliderTransitionEnd.emit(slider)); this.slider.on('transitionStart', (slider) => this.sliderTransitionStart.emit(slider)); } render() { if (this.isStaticWhenSingle()) { return; } let classes = this.type ? this.type + '-slider ' : ''; classes += this.controlsOuter ? ' s-slider-controls-outer ' : ''; classes += this.blockTitle == '' ? ' s-slider-has-notitle s-slider-v-centered ' : ''; classes += this.verticalThumbs ? ' s-slider-vertical ' : ' s-slider-horizontal '; classes += this.arrowsCentered ? ' s-slider-v-centered ' : ''; classes += this.gridThumbs ? ' s-slider-with-grid-thumbs ' : ''; return (h(Host, { class: 's-slider-wrapper ' + classes }, this.blockTitle || this.showControls ? h("div", { class: "s-slider-block__title" }, this.blockTitle ? h("div", { class: "s-slider-block__title-right" }, h("h2", null, this.blockTitle), this.blockSubtitle ? h("p", { innerHTML: this.blockSubtitle }) : '') : '', h("div", { class: "s-slider-block__title-left" }, this.displayAllUrl ? h("a", { href: this.displayAllUrl, class: "s-slider-block__display-all" }, this.displayAllTitle) : '', this.showControls ? h("div", { class: "s-slider-block__title-nav", dir: "rtl" }, h("button", { "aria-label": "Previous Slide", class: "s-slider-prev s-slider-nav-arrow" }, h("span", { class: "s-slider-button-icon", innerHTML: this.direction == 'rtl' ? ArrowRightIcon : ArrowLeftIcon })), h("button", { "aria-label": "Next Slide", class: "s-slider-next s-slider-nav-arrow" }, h("span", { class: "s-slider-button-icon", innerHTML: this.direction == 'rtl' ? ArrowLeftIcon : ArrowRightIcon }))) : '')) : '', h("div", { class: "swiper s-slider-container", ref: el => this.sliderContainer = el, dir: this.vertical ? "ltr" : this.direction }, h("slot", null), h("div", { class: "swiper-wrapper s-slider-swiper-wrapper", ref: el => this.sliderWrapper = el }, h("slot", { name: 'items' })), this.pagination ? h("div", { class: "swiper-pagination" }) : ''), this.type == 'thumbs' && this.hasThumbSlot ? h("div", { class: "s-slider-thumbs" }, h("div", { class: "swiper s-slider-thumbs-container", dir: this.getThumbsDirection(), ref: el => this.thumbsSliderContainer = el }, h("div", { class: { "s-slider-swiper-wrapper swiper-wrapper": true, "s-slider-grid-thumbs": this.gridThumbs }, ref: el => this.thumbsSliderWrapper = el }, h("slot", { name: "thumbs" })), this.showThumbsControls ? h("div", { class: "s-slider-thumbs-nav", dir: "rtl" }, h("button", { "aria-label": "Previous Slide", class: "s-slider-thumbs-prev s-slider-nav-arrow" }, h("span", { class: "s-slider-button-icon", innerHTML: this.direction == 'rtl' ? ArrowRightIcon : ArrowLeftIcon })), h("button", { "aria-label": "Next Slide", class: "s-slider-thumbs-next s-slider-nav-arrow" }, h("span", { class: "s-slider-button-icon", innerHTML: this.direction == 'rtl' ? ArrowLeftIcon : ArrowRightIcon }))) : null)) : null)); } /** Observe all .swiper-lazy images and add swiper-lazy-loaded when they enter viewport. */ observeLazyImages() { const lazyEls = this.sliderContainer?.querySelectorAll('.swiper-lazy:not(.swiper-lazy-loaded)'); if (!lazyEls?.length) return; if (!this.lazyImageObserver) { this.lazyImageObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (!entry.isIntersecting) return; entry.target.classList.add('swiper-lazy-loaded'); observer.unobserve(entry.target); }); }, { rootMargin: '50px' }); } lazyEls.forEach(el => this.lazyImageObserver.observe(el)); } /** Lazy load data-background for active slide and adjacent slides (backward compat for Swiper v9+). */ loadLazyBackgrounds() { if (!this.slider?.slides) return; const active = this.slider.activeIndex; const toLoad = [active - 1, active, active + 1]; toLoad.forEach(i => { const slide = this.slider.slides[i]; if (!slide) return; slide.querySelectorAll('[data-background]').forEach((el) => { this.loadBackgroundIfVisible(el); }); }); } /** Load background only when element is in viewport. */ loadBackgroundIfVisible(el) { if (el.classList.contains('swiper-lazy-loaded')) return; if (!this.lazyObserver) { this.lazyObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (!entry.isIntersecting) return; const target = entry.target; const bg = target.getAttribute('data-background'); if (bg) { target.style.backgroundImage = `url('${bg}')`; target.classList.add('swiper-lazy-loaded'); target.removeAttribute('data-background'); } observer.unobserve(target); }); }, { rootMargin: '50px' }); } this.lazyObserver.observe(el); } componentDidLoad() { if (this.isStaticWhenSingle()) { return; } // 1. Batch Reads (Get all elements first without modifying DOM) const tasks = []; const prepareFlatten = (container, slotSelector) => { const slotEl = container?.querySelector(slotSelector); if (!slotEl) return; const elements = Array.from(slotEl.children).filter((node) => node.nodeType === Node.ELEMENT_NODE); if (elements.length) { // Queue the Write operation tasks.push(() => slotEl.replaceWith(...elements)); } }; prepareFlatten(this.sliderWrapper, 'div[slot="items"]'); if (this.type == 'thumbs' && this.hasThumbSlot) { prepareFlatten(this.thumbsSliderWrapper, 'div[slot="thumbs"]'); } // 2. Batch Writes (Execute all DOM modifications together) tasks.forEach(task => task()); // 3. Init Swiper inside rAF this._rafId = requestAnimationFrame(() => this.initSlider()); this.viewportMediaQuery = window.matchMedia('(min-width: 768px)'); this.viewportMediaQuery.addEventListener('change', this.onViewportChange); } disconnectedCallback() { if (this.isStaticWhenSingle()) { return; } if (this._rafId) cancelAnimationFrame(this._rafId); this.viewportMediaQuery?.removeEventListener('change', this.onViewportChange); this.lazyObserver?.disconnect(); this.lazyImageObserver?.disconnect(); } static get is() { return "salla-slider"; } static get originalStyleUrls() { return { "$": ["salla-slider.scss"] }; } static get styleUrls() { return { "$": ["salla-slider.css"] }; } static get properties() { return { "blockTitle": { "type": "string", "attribute": "block-title", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Show/hide slider block title" }, "getter": false, "setter": false, "reflect": true, "defaultValue": "''" }, "listenToThumbnailsOption": { "type": "boolean", "attribute": "listen-to-thumbnails-option", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Enable call a specific slide by index from thumbnails or color option in `salla-slider-options` component, works only if `data-img-id` and `data-slid-index` attributes are set on each slide" }, "getter": false, "setter": false, "reflect": true, "defaultValue": "false" }, "blockSubtitle": { "type": "string", "attribute": "block-subtitle", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Show/hide slider block sub title" }, "getter": false, "setter": false, "reflect": true, "defaultValue": "''" }, "displayAllUrl": { "type": "string", "attribute": "display-all-url", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Show/hide display all button beside arrows" }, "getter": false, "setter": false, "reflect": true, "defaultValue": "''" }, "arrowsCentered": { "type": "boolean", "attribute": "arrows-centered", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Show/hide display all button beside arrows" }, "getter": false, "setter": false, "reflect": true, "defaultValue": "false" }, "verticalThumbs": { "type": "boolean", "attribute": "vertical-thumbs", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Vertical or Horizontal thumbs slider" }, "getter": false, "setter": false, "reflect": true, "defaultValue": "false" }, "gridThumbs": { "type": "boolean", "attribute": "grid-thumbs", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Disable thumbs slider and show it as a grid" }, "getter": false, "setter": false, "reflect": true, "defaultValue": "false" }, "vertical": { "type": "boolean", "attribute": "vertical", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Vertical or Horizontal main slider" }, "getter": false, "setter": false, "reflect": true, "defaultValue": "false" }, "autoHeight": { "type": "boolean", "attribute": "auto-height", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Auto Height slider" }, "getter": false, "setter": false, "reflect": true, "defaultValue": "false" }, "showControls": { "type": "boolean", "attribute": "show-controls", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Show/hide arrows" }, "getter": false, "setter": false, "reflect": true, "defaultValue": "true" }, "controlsOuter": { "type": "boolean", "attribute": "controls-outer", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Show/hide arrows" }, "getter": false, "setter": false, "reflect": true, "defaultValue": "false" }, "showThumbsControls": { "type": "boolean", "attribute": "show-thumbs-controls", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Show/hide thumbs slider arrows" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "true" }, "staticWhenSingle": { "type": "boolean", "attribute": "static-when-single", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "When enabled and there is exactly one slide in the `items` slot,\nrender without initializing Swiper (single slide mode)." }, "getter": false, "setter": false, "reflect": true, "defaultValue": "false" }, "autoPlay": { "type": "boolean", "attribute": "auto-play", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Enable autoplay - working with `type=\"carousel\" only`" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "false" }, "slidesPerView": { "type": "string", "attribute": "slides-per-view", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "slidesPerView" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "\"auto\"" }, "pagination": { "type": "boolean", "attribute": "pagination", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Enable pagination" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "false" }, "centered": { "type": "boolean", "attribute": "centered", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Enable center mode - working with `type=\"carousel\" only`" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "false" }, "loop": { "type": "boolean", "attribute": "loop", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Run slider in loop, Don't use it for slides with custom components inside it, because it may cause re-render issue" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "false" }, "direction": { "type": "string", "attribute": "direction", "mutable": true, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Slider direction. Default: document.documentElement.dir" }, "getter": false, "setter": false, "reflect": true }, "type": { "type": "string", "attribute": "type", "mutable": false, "complexType": { "original": "'carousel' | 'fullscreen' | 'thumbs' | 'default' | 'hero' | 'testimonials' | 'blog' | 'fullwidth' | ''", "resolved": "\"\" | \"blog\" | \"carousel\" | \"default\" | \"fullscreen\" | \"fullwidth\" | \"hero\" | \"testimonials\" | \"thumbs\"", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Set the type of the slider\nDefault: ''" }, "getter": false, "setter": false, "reflect": false, "defaultValue": "''" }, "sliderConfig": { "type": "any", "attribute": "slider-config", "mutable": false, "complexType": { "original": "any", "resolved": "any", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "example", "text": "let slider = document.querySelector('salla-slider');\n slider.sliderConfig = {\n slidesPerView: 1,\n spaceBetween : 30,\n lazy: true,\n}" }], "text": "Slider Configs refer to https://swiperjs.com/swiper-api#parameters and pass the entire config object" }, "getter": false, "setter": false, "reflect": true }, "thumbsConfig": { "type": "any", "attribute": "thumbs-config", "mutable": false, "complexType": { "original": "any", "resolved": "any", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "example", "text": "let slider = document.querySelector('salla-slider');\n slider.thumbsConfig = {\n slidesPerView: 1,\n spaceBetween : 30,\n lazy: true,\n}" }], "text": "Thumbs Slider Configs refer to https://swiperjs.com/swiper-api#parameters and pass the entire config object" }, "getter": false, "setter": false, "reflect": true } }; } static get states() { return { "currentIndex": {}, "isEnd": {}, "isBeginning": {}, "displayAllTitle": {}, "isDesktopViewport": {} }; } static get events() { return [{ "method": "afterInit", "name": "afterInit", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Event will fired right after initialization." }, "complexType": { "original": "any", "resolved": "any", "references": {} } }, { "method": "slideChange", "name": "slideChange", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Event will be fired when currently active slide is changed" }, "complexType": { "original": "any", "resolved": "any", "references": {} } }, { "method": "reachBeginning", "name": "reachBeginning", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Event will be fired when Swiper reach its beginning (initial position)" }, "complexType": { "original": "any", "resolved": "any", "references": {} } }, { "method": "reachEnd", "name": "reachEnd", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Event will be fired when Swiper reach last slide" }, "complexType": { "original": "any", "resolved": "any", "references": {} } }, { "method": "slideChangeTransitionEnd", "name": "slideChangeTransitionEnd", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Event will be fired after animation to other slide (next or previous)." }, "complexType": { "original": "any", "resolved": "any", "references": {} } }, { "method": "slideChangeTransitionStart", "name": "slideChangeTransitionStart", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Event will be fired in the beginning of animation to other slide (next or previous)." }, "complexType": { "original": "any", "resolved": "any", "references": {} } }, { "method": "slideNextTransitionEnd", "name": "slideNextTransitionEnd", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Same as \"slideChangeTransitionEnd\" but for \"forward\" direction only" }, "complexType": { "original": "any", "resolved": "any", "references": {} } }, { "method": "slideNextTransitionStart", "name": "slideNextTransitionStart", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Same as \"slideChangeTransitionStart\" but for \"forward\" direction only" }, "complexType": { "original": "any", "resolved": "any", "references": {} } }, { "method": "slidePrevTransitionEnd", "name": "slidePrevTransitionEnd", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Same as \"slideChangeTransitionEnd\" but for \"backward\" direction only" }, "complexType": { "original": "any", "resolved": "any", "references": {} } }, { "method": "slidePrevTransitionStart", "name": "slidePrevTransitionStart", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Same as \"slideChangeTransitionStart\" but for \"backward\" direction only" }, "complexType": { "original": "any", "resolved": "any", "references": {} } }, { "method": "sliderMove", "name": "sliderMove", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Event will be fired when user touch and move finger over Swiper and move it.\nReceives touchmove event as an arguments." }, "complexType": { "original": "any", "resolved": "any", "references": {} } }, { "method": "touchSliderEnd", "name": "touchSliderEnd", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Event will be fired when user release Swiper. Receives touchen