fix(carousel): update page navigation logic

pull/1605/head
alenaksu 2023-10-17 01:14:27 +02:00
rodzic c1c4fa6a74
commit 25cf89e161
2 zmienionych plików z 34 dodań i 13 usunięć

Wyświetl plik

@ -140,19 +140,19 @@ export default class SlCarousel extends ShoelaceElement {
}
private getPageCount() {
return Math.ceil(this.getSlides().length / this.slidesPerPage);
return Math.ceil((this.getSlides().length - this.slidesPerPage) / this.slidesPerMove) + 1;
}
private getCurrentPage() {
return Math.floor(this.activeSlide / this.slidesPerPage);
return Math.floor(this.activeSlide / this.slidesPerMove);
}
private canScrollNext(): boolean {
return this.loop || this.activeSlide + this.slidesPerPage <= this.getSlides().length - 1;
return this.loop || this.getCurrentPage() < this.getPageCount() - 1;
}
private canScrollPrev(): boolean {
return this.loop || this.activeSlide > 0;
return this.loop || this.getCurrentPage() > 0;
}
/** @internal Gets all carousel items. */
@ -215,13 +215,11 @@ export default class SlCarousel extends ShoelaceElement {
// Scrolls to the original slide without animating, so the user won't notice that the position has changed
this.goToSlide(clonePosition, 'auto');
return;
}
// Activate the first intersecting slide
if (firstIntersecting) {
this.activeSlide = slides.indexOf(firstIntersecting.target as SlCarouselItem);
} else if (firstIntersecting) {
// Update the current index based on the first visible slide
const slideIndex = slides.indexOf(firstIntersecting.target as SlCarouselItem);
// Set the index to the first "snappable" slide
this.activeSlide = Math.ceil(slideIndex / this.slidesPerMove) * this.slidesPerMove;
}
}
@ -240,7 +238,8 @@ export default class SlCarousel extends ShoelaceElement {
if (needsInitialization) {
this.initializeSlides();
}
this.requestUpdate();
this.goToSlide(this.activeSlide);
};
@watch('loop', { waitUntilFirstUpdate: true })
@ -377,7 +376,7 @@ export default class SlCarousel extends ShoelaceElement {
const slides = this.getSlides();
const slidesWithClones = this.getSlides({ excludeClones: false });
// No need to to anything in case there are no items in the carousel
// No need to do anything in case there are no items in the carousel
if (!slides.length) {
return;
}

Wyświetl plik

@ -1,6 +1,8 @@
import '../../../dist/shoelace.js';
import { clickOnElement } from '../../internal/test.js';
import { expect, fixture, html, oneEvent } from '@open-wc/testing';
import { map } from 'lit/directives/map.js';
import { range } from 'lit/directives/range.js';
import sinon from 'sinon';
import type SlCarousel from './carousel.js';
@ -223,6 +225,26 @@ describe('<sl-carousel>', () => {
// Assert
expect(el.scrollContainer.style.getPropertyValue('--slides-per-page').trim()).to.be.equal('2');
});
[
[7, 2, 1, 6],
[7, 2, 2, 4],
[5, 3, 2, 2],
[5, 3, 3, 2]
].forEach(([slides, slidesPerPage, slidesPerMove, expected]) => {
it(`should display the correct ${expected} pages for ${slides} slides grouped by ${slidesPerPage} and scrolling by ${slidesPerMove}`, async () => {
// Arrange
const el = await fixture<SlCarousel>(html`
<sl-carousel pagination navigation slides-per-page="${slidesPerPage}" slides-per-move="${slidesPerMove}">
${map(range(slides), i => html`<sl-carousel-item>${i}</sl-carousel-item>`)}
</sl-carousel>
`);
// Assert
const paginationItems = el.shadowRoot!.querySelectorAll('.carousel__pagination-item');
expect(paginationItems.length).to.equal(expected);
});
});
});
describe('when `slides-per-move` attribute is provided', () => {