diff --git a/src/implementations/twig/components/carousel/__snapshots__/carousel.test.js.snap b/src/implementations/twig/components/carousel/__snapshots__/carousel.test.js.snap index 9e730a2a55..b868542ab5 100644 --- a/src/implementations/twig/components/carousel/__snapshots__/carousel.test.js.snap +++ b/src/implementations/twig/components/carousel/__snapshots__/carousel.test.js.snap @@ -62,7 +62,7 @@ exports[`Carousel Default renders correctly 1`] = ` focusable="false" > @@ -448,7 +448,7 @@ exports[`Carousel Default renders correctly with extra attributes 1`] = ` focusable="false" > @@ -832,7 +832,7 @@ exports[`Carousel Default renders correctly with extra class names 1`] = ` focusable="false" > diff --git a/src/implementations/twig/components/carousel/carousel.html.twig b/src/implementations/twig/components/carousel/carousel.html.twig index 26984c623b..7fb5bf59f6 100644 --- a/src/implementations/twig/components/carousel/carousel.html.twig +++ b/src/implementations/twig/components/carousel/carousel.html.twig @@ -92,7 +92,7 @@ extra_classes: 'ecl-carousel__pause', icon: { path: _icon_path, - name: 'pause', + name: 'pause-outline', size: 'm', extra_classes: 'ecl-carousel__icon-default', }, diff --git a/src/implementations/twig/components/carousel/carousel.story.js b/src/implementations/twig/components/carousel/carousel.story.js index cfbf52c22f..78bca03f58 100644 --- a/src/implementations/twig/components/carousel/carousel.story.js +++ b/src/implementations/twig/components/carousel/carousel.story.js @@ -100,7 +100,7 @@ const renderStory = async (data, args) => { } if (args.grid_content) { story += - '

Content inside the grid

'; + '

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend auctor libero et scelerisque. Phasellus malesuada sem vel augue egestas facilisis. Curabitur velit nibh, scelerisque in massa vitae, consectetur tempor ligula. Nunc vehicula tellus vel nunc facilisis, ac condimentum nulla lacinia. Integer at vulputate sapien.

'; } return story; diff --git a/src/implementations/vanilla/components/carousel/carousel.js b/src/implementations/vanilla/components/carousel/carousel.js index 751bbe22fa..41f283e727 100644 --- a/src/implementations/vanilla/components/carousel/carousel.js +++ b/src/implementations/vanilla/components/carousel/carousel.js @@ -88,6 +88,7 @@ export class Carousel { this.cloneLastSLide = null; this.executionCount = 0; this.maxExecutions = 5; + this.slideWidth = 0; // Bind `this` for use in callbacks this.handleAutoPlay = this.handleAutoPlay.bind(this); @@ -115,7 +116,8 @@ export class Carousel { throw new TypeError('Called init but ECL is not present'); } ECL.components = ECL.components || new Map(); - + // Hide the carousel initially, we will show it in handleesize() + this.element.style.opacity = 0; this.btnPlay = queryOne(this.playSelector, this.element); this.btnPause = queryOne(this.pauseSelector, this.element); this.slidesContainer = queryOne(this.slidesClass, this.element); @@ -145,23 +147,27 @@ export class Carousel { const lastSlide = this.slides[this.slides.length - 1]; // Clone first and last slide - this.cloneFirstSLide = firstSlide.cloneNode(true); - this.cloneLastSLide = lastSlide.cloneNode(true); - this.slidesContainer.appendChild(this.cloneFirstSLide); - this.slidesContainer.insertBefore(this.cloneLastSLide, firstSlide); + this.cloneFirstSlide = firstSlide.cloneNode(true); + this.cloneLastSlide = lastSlide.cloneNode(true); + this.slidesContainer.appendChild(this.cloneFirstSlide); + this.slidesContainer.insertBefore(this.cloneLastSlide, firstSlide); + + // Initialize the js for the two cloned slides + const cloneFirstBanner = new ECL.Banner( + this.cloneFirstSlide.firstElementChild, + ); + const cloneLastBanner = new ECL.Banner( + this.cloneLastSlide.firstElementChild, + ); + + cloneFirstBanner.init(); + cloneLastBanner.init(); // Refresh the slides variable after adding new cloned slides this.slides = queryAll(this.slideClass, this.element); - // Initialize position of slides and size of the carousel - this.slides.forEach((slide) => { - slide.style.width = `${100 / this.slides.length}%`; - }); - this.handleResize(); - // Initialze pagination and navigation - this.checkIndex(); - + this.handleResize(); // Bind events if (this.navigationItems) { this.navigationItems.forEach((nav, index) => { @@ -268,6 +274,9 @@ export class Carousel { } const heightValues = this.slides.map((slide) => { const banner = queryOne('.ecl-banner', slide); + const bannerInstance = ECL.components.get(banner); + const ratio = bannerInstance.defaultRatio(); + bannerInstance.setHeight(ratio); const height = parseInt(banner.style.height, 10); if (banner.style.height === 'auto') { return 0; @@ -317,12 +326,28 @@ export class Carousel { this.slides.forEach((slide) => { const banner = queryOne('.ecl-banner', slide); let bannerImage = null; + let bannerVideo = null; + let bannerFooter = null; if (banner) { banner.style.height = ''; bannerImage = queryOne('img', banner); + bannerVideo = queryOne('video', banner); + bannerFooter = queryOne('.ecl-banner__credit', banner); + if (bannerImage) { bannerImage.style.aspectRatio = ''; } + if (bannerVideo) { + bannerVideo.style.aspectRatio = ''; + } + if (bannerFooter) { + setTimeout(() => { + banner.style.setProperty( + '--banner-footer-height', + `${bannerFooter.offsetHeight}px`, + ); + }, 100); + } } }); } @@ -399,7 +424,8 @@ export class Carousel { * @param {Boolean} transition */ moveSlides(transition) { - const newOffset = this.container.offsetWidth * this.index; + const newOffset = this.slideWidth * this.index; + this.slidesContainer.style.transitionDuration = transition ? '0.4s' : '0s'; if (this.direction === 'rtl') { this.slidesContainer.style.right = `-${newOffset}px`; @@ -410,8 +436,14 @@ export class Carousel { /** * Action to update slides index and position. + * @param {Event} e */ - checkIndex() { + checkIndex(e) { + if (e) { + if (e.propertyName !== 'left') { + return; + } + } // Update index if (this.index === 0) { this.index = this.total; @@ -520,7 +552,7 @@ export class Carousel { ); clearInterval(this.intervalId); clearTimeout(this.resizeTimer); - let containerWidth = 0; + // We set 250ms delay which is higher than the 200ms delay in the banner. this.resizeTimer = setTimeout(() => { if (vw >= 998) { @@ -528,19 +560,14 @@ export class Carousel { } else { this.resetBannerHeights(); } - }, 250); - if (vw >= 768) { - containerWidth = this.container.offsetWidth; - } else { - containerWidth = this.container.offsetWidth + 15; - } - - this.slidesContainer.style.width = `${ - containerWidth * this.slides.length - }px`; - - this.moveSlides(false); + this.slideWidth = this.slides[0].scrollWidth; + this.checkIndex(); + setTimeout(() => { + // Reveal the carousel + this.element.style.opacity = 1; + }, 250); + }, 250); // Add class to set a left margin to banner content and avoid arrow overlapping if (vw >= 1140 && vw <= 1260) { @@ -548,8 +575,7 @@ export class Carousel { } else { this.container.classList.remove('ecl-carousel-container--padded'); } - - // Desactivate autoPlay for mobile or activate autoPlay onLoad for desktop + // Deactivate autoPlay for mobile or activate autoPlay onLoad for desktop if ((vw <= 768 && this.autoPlay) || (vw > 768 && this.autoPlay === null)) { this.handleAutoPlay(); } diff --git a/src/implementations/vanilla/components/carousel/carousel.scss b/src/implementations/vanilla/components/carousel/carousel.scss index 08be7ae4e7..16b817282a 100644 --- a/src/implementations/vanilla/components/carousel/carousel.scss +++ b/src/implementations/vanilla/components/carousel/carousel.scss @@ -34,38 +34,30 @@ $carousel: null !default; } .ecl-carousel__container { + box-sizing: border-box; box-shadow: inset 0 -4px 12px -9px rgba(map.get($theme, 'color', 'black'), 0.6); order: 1; - width: calc(100% - var(--s-xl)); + width: 100%; } .ecl-carousel__slides { display: flex; + flex-direction: row; list-style: none; margin: 0; padding: 0; position: relative; - width: 100%; -} - -.ecl-carousel__slide { - position: relative; + scroll-snap-type: x mandatory; - &::before { - background: map.get($theme, 'color', 'white'); - content: ''; - display: block; - height: 100%; - left: calc(-1 * var(--s-2xs)); - position: absolute; - top: 0; - width: var(--s-2xs); + .ecl-carousel__slide { + flex: 0 0 auto; + scroll-snap-align: start; + width: 100%; } } .ecl-carousel__slide .ecl-banner__credit { - margin-inline-end: var(--s-2xs); width: auto; } @@ -83,6 +75,10 @@ $carousel: null !default; display: flex; justify-content: space-between; } + + .ecl-carousel__pause { + display: none; + } } .ecl-carousel__controls, @@ -115,12 +111,6 @@ $carousel: null !default; } } -.ecl-carousel-container--padded .ecl-banner { - .ecl-container { - margin-inline-start: 100px; - } -} - /* stylelint-disable-next-line order/order */ @include breakpoints.up('s') { .ecl-carousel__navigation { @@ -143,6 +133,11 @@ $carousel: null !default; /* stylelint-disable-next-line order/order */ @include breakpoints.up('l') { + .ecl-carousel__controls .ecl-container { + padding-inline-start: var(--s-2xl); + padding-inline-end: var(--s-2xl); + } + .ecl-carousel { .ecl-banner { height: initial; @@ -153,10 +148,6 @@ $carousel: null !default; } } - .ecl-carousel__container { - width: 100%; - } - .ecl-carousel__slide { position: relative; @@ -177,21 +168,6 @@ $carousel: null !default; /* stylelint-disable-next-line order/order */ @include breakpoints.up('xl') { - .ecl-container - .ecl-carousel:not(.ecl-carousel--full-width) - .ecl-banner - .ecl-container { - margin-inline-start: 120px; - } - - .ecl-container - .ecl-carousel:not(.ecl-carousel--full-width) - .ecl-banner - .ecl-banner__credit - .ecl-container { - margin-inline-start: 60px; - } - .ecl-carousel__prev { left: var(--s-m); } @@ -232,12 +208,3 @@ $carousel: null !default; margin-inline-start: -50vw; width: 100vw; } - -// stylelint-disable-next-line plugin/selector-bem-pattern, selector-max-compound-selectors -.ecl-container - .ecl-carousel--full-width - .ecl-banner:not(.ecl-banner--full-width) - .ecl-container { - padding-inline-start: var(--s-m); - padding-inline-end: var(--s-m); -} diff --git a/src/themes/ec/variables/_carousel.scss b/src/themes/ec/variables/_carousel.scss index 74158ac399..25b0272e94 100644 --- a/src/themes/ec/variables/_carousel.scss +++ b/src/themes/ec/variables/_carousel.scss @@ -3,9 +3,9 @@ $carousel: ( box-shadow: var(--sh-6), - separator: 1px solid var(--c-n), + separator: none, controls-background: map.get($color, 'white'), - controls-padding: var(--s-xs) 0, + controls-padding: var(--s-m) 0, navigation-background-active: var(--c-n), navigation-color-active: var(--c-d), navigation-border-active: var(--c-n),