Skip to content

Commit

Permalink
fix: 🤔 sd-carousel - numbered variant - show total clicks (#1247)
Browse files Browse the repository at this point in the history
  • Loading branch information
Vahid1919 authored Aug 15, 2024
1 parent 5bb4cea commit 7f22b7f
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default {
type: 'slot',
name: 'default',
value: `
<sd-carousel-item><div class="slot slot--border slot--text h-16">Default slot 1</div></sd-carousel-item>
<sd-carousel-item><div class="slot slot--border slot--text h-16">Default slot 2</div></sd-carousel-item>
<sd-carousel-item><div class="slot slot--border slot--text h-16">Default slot 3</div></sd-carousel-item>
Expand Down Expand Up @@ -154,7 +155,6 @@ export const SlidesPerMove = {
y: { type: 'attribute', name: 'slides-per-move', values: [2] }
},
constants: [
{ type: 'attribute', name: 'loop', value: 'true' },
{ type: 'attribute', name: 'slides-per-page', value: 2 },
{
type: 'slot',
Expand Down
87 changes: 86 additions & 1 deletion packages/components/src/components/carousel/carousel.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { aTimeout, expect, fixture, html, oneEvent } from '@open-wc/testing';
import { clickOnElement } from '../../internal/test.js';
import SdCarousel from './carousel';
import sinon from 'sinon';
import type SdCarousel from './carousel';

describe('<sd-carousel>', () => {
it('should render a carousel with default configuration', async () => {
Expand Down Expand Up @@ -576,4 +576,89 @@ describe('<sd-carousel>', () => {
});
});
});

describe('getPageCount', () => {
it('should return the correct page count when totalSlides is divisible by slidesPerPage', () => {
// Arrange
const totalSlides = 10;
const slidesPerPage = 2;
const slidesPerMove = 1;

// Act
const pageCount = SdCarousel.getPageCount(totalSlides, slidesPerPage, slidesPerMove);

// Assert
expect(pageCount).to.equal(9);
});

it('should return the correct page count when totalSlides is not divisible by slidesPerPage', () => {
// Arrange
const totalSlides = 11;
const slidesPerPage = 3;
const slidesPerMove = 2;

// Act
const pageCount = SdCarousel.getPageCount(totalSlides, slidesPerPage, slidesPerMove);

// Assert
expect(pageCount).to.equal(5);
});

it('should return 1 when totalSlides is less than or equal to slidesPerPage', () => {
// Arrange
const totalSlides = 3;
const slidesPerPage = 5;
const slidesPerMove = 1;

// Act
const pageCount = SdCarousel.getPageCount(totalSlides, slidesPerPage, slidesPerMove);

// Assert
expect(pageCount).to.equal(1);
});
});

describe('getCurrentPage', () => {
it('should return the correct current page when the active slide is the first slide', () => {
// Arrange
const totalSlides = 5;
const activeSlide = 0;
const slidesPerPage = 2;
const slidesPerMove = 1;

// Act
const currentPage = SdCarousel.getCurrentPage(totalSlides, activeSlide, slidesPerPage, slidesPerMove);

// Assert
expect(currentPage).to.equal(1);
});

it('should return the correct current page when the active slide is in the middle of the carousel', () => {
// Arrange
const totalSlides = 5;
const activeSlide = 2;
const slidesPerPage = 2;
const slidesPerMove = 1;

// Act
const currentPage = SdCarousel.getCurrentPage(totalSlides, activeSlide, slidesPerPage, slidesPerMove);

// Assert
expect(currentPage).to.equal(3);
});

it('should return the correct current page when the active slide is the last slide', () => {
// Arrange
const totalSlides = 5;
const activeSlide = 4;
const slidesPerPage = 2;
const slidesPerMove = 1;

// Act
const currentPage = SdCarousel.getCurrentPage(totalSlides, activeSlide, slidesPerPage, slidesPerMove);

// Assert
expect(currentPage).to.equal(5);
});
});
});
88 changes: 74 additions & 14 deletions packages/components/src/components/carousel/carousel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ export default class SdCarousel extends SolidElement {
*/
@state() activeSlide = 0;

/**
* The current page of the carousel
* @internal
*/
@state() currentPage = 1;

/**
* Boolean keeping track of the autoplay pause/play button
* @internal
Expand Down Expand Up @@ -141,12 +147,24 @@ export default class SdCarousel extends SolidElement {
this.mutationObserver.observe(this, { childList: true, subtree: false });
}

private getPageCount() {
return Math.ceil(this.getSlides().length / this.slidesPerPage);
static getPageCount(totalSlides: number, slidesPerPage: number, slidesPerMove: number) {
return Math.ceil((totalSlides - slidesPerPage) / slidesPerMove) + 1 > 0
? Math.ceil((totalSlides - slidesPerPage) / slidesPerMove) + 1
: // Returns 1 if the total number of slides is less than the number of slides per page
1;
}

private getCurrentPage() {
return Math.ceil(this.activeSlide / this.slidesPerPage);
static getCurrentPage(
totalSlides: number,
activeSlide: number,
slidesPerPage: number,
slidesPerMove: number
): number {
return (
Math.ceil((totalSlides - slidesPerPage) / slidesPerMove) -
Math.ceil((totalSlides - slidesPerPage - activeSlide) / slidesPerMove) +
1
);
}

private getSlides({ excludeClones = true }: { excludeClones?: boolean } = {}) {
Expand Down Expand Up @@ -289,6 +307,13 @@ export default class SdCarousel extends SolidElement {

@watch('activeSlide')
handelSlideChange() {
this.currentPage = SdCarousel.getCurrentPage(
this.getSlides().length,
this.activeSlide,
this.slidesPerPage,
this.slidesPerMove
);

const slides = this.getSlides();
slides.forEach((slide, i) => {
slide.classList.toggle('--is-active', i === this.activeSlide);
Expand All @@ -303,6 +328,10 @@ export default class SdCarousel extends SolidElement {
}
});
}

if (this.currentPage > SdCarousel.getPageCount(this.getSlides().length, this.slidesPerPage, this.slidesPerMove)) {
this.nextTillFirst();
}
}

@watch('slidesPerMove')
Expand All @@ -318,6 +347,8 @@ export default class SdCarousel extends SolidElement {
slide.style.setProperty('scroll-snap-align', 'none');
}
});

// this.handleScrollEnd();
}

@watch('autoplay')
Expand All @@ -342,7 +373,11 @@ export default class SdCarousel extends SolidElement {
canSnap = Math.abs(previousIndex - this.slidesPerMove) % this.slidesPerMove === 0;
}

this.goToSlide(previousIndex, behavior);
if (this.currentPage - 1 === 0 && this.loop) {
this.goToSlide(this.activeSlide - this.slidesPerPage, behavior);
} else {
this.goToSlide(previousIndex, behavior);
}
}

/**
Expand All @@ -351,7 +386,27 @@ export default class SdCarousel extends SolidElement {
* @param behavior - The behavior used for scrolling.
*/
next(behavior: ScrollBehavior = 'smooth') {
this.goToSlide(this.activeSlide + this.slidesPerMove, behavior);
if (
this.currentPage + 1 > SdCarousel.getPageCount(this.getSlides().length, this.slidesPerPage, this.slidesPerMove) &&
this.loop
) {
this.nextTillFirst(behavior);
} else {
this.goToSlide(this.activeSlide + this.slidesPerMove, behavior);
}
}

nextTillFirst(behavior: ScrollBehavior = 'smooth') {
while (this.activeSlide !== 0) {
this.goToSlide(this.activeSlide + 1, behavior);
}

this.currentPage = SdCarousel.getCurrentPage(
this.getSlides().length,
this.activeSlide,
this.slidesPerPage,
this.slidesPerMove
);
}

/**
Expand All @@ -374,10 +429,11 @@ export default class SdCarousel extends SolidElement {

// Get the index of the next slide. For looping carousel it adds `slidesPerPage`
// to normalize the starting index in order to ignore the first nth clones.
const nextSlideIndex = clamp(index + (loop ? slidesPerPage : 0), 0, slidesWithClones.length - 1);
const nextSlideIndex = clamp(index + (loop ? slidesPerPage : 0), 0, slidesWithClones.length + 1);
const nextSlide = slidesWithClones[nextSlideIndex];

const scrollContainerRect = scrollContainer.getBoundingClientRect();

const nextSlideRect = nextSlide.getBoundingClientRect();

scrollContainer.scrollTo({
Expand All @@ -389,10 +445,15 @@ export default class SdCarousel extends SolidElement {

render() {
const { scrollController, slidesPerPage } = this;
const pagesCount = this.getPageCount();
const currentPage = this.getCurrentPage();
const prevEnabled = this.loop || currentPage > 0;
const nextEnabled = this.loop || currentPage < pagesCount - 1;
const pagesCount = SdCarousel.getPageCount(this.getSlides().length, this.slidesPerPage, this.slidesPerMove);
const currentPage = SdCarousel.getCurrentPage(
this.getSlides().length,
this.activeSlide,
this.slidesPerPage,
this.slidesPerMove
);
const prevEnabled = this.loop || currentPage > 1;
const nextEnabled = this.loop || currentPage < pagesCount;
const isLtr = this.localize.dir() === 'ltr';

return html`
Expand Down Expand Up @@ -451,7 +512,7 @@ export default class SdCarousel extends SolidElement {
aria-controls="scroll-container"
>
${map(range(pagesCount), index => {
const isActive = index === currentPage;
const isActive = index + 1 === currentPage;
return html`
<button
part="pagination-item ${isActive ? 'pagination-item--active' : ''}"
Expand Down Expand Up @@ -489,7 +550,7 @@ export default class SdCarousel extends SolidElement {
<span
part="pagination-item"
class=${cx('w-5 text-center border-b-2 border-accent', this.inverted ? 'text-white' : 'text-black')}
>${currentPage + 1}</span
>${currentPage}</span
>
<span
part="pagination-divider"
Expand Down Expand Up @@ -517,7 +578,6 @@ export default class SdCarousel extends SolidElement {
aria-disabled="${nextEnabled ? 'false' : 'true'}"
@click=${nextEnabled
? () => {
console.log('click-next');
this.next();
}
: null}
Expand Down

0 comments on commit 7f22b7f

Please sign in to comment.