feat(carousel): adjust item width calculation for better distribution and responsiveness

This commit is contained in:
2026-07-23 13:37:10 -03:00
parent 862751fec8
commit 37bbd65cfe
5 changed files with 27 additions and 26 deletions

View File

@@ -59,18 +59,11 @@ export class CarouselComponent<T> implements AfterViewInit {
protected readonly canScrollPrevious = signal(false);
protected readonly canScrollNext = signal(false);
protected readonly hasOverflow = signal(false);
protected readonly viewportWidth = signal<number | null>(null);
protected readonly itemWidth = signal<number | null>(null);
protected readonly itemsPerPage = signal(Number.MAX_SAFE_INTEGER);
protected readonly currentPage = signal(0);
protected readonly transitionDirection = signal<-1 | 0 | 1>(0);
protected readonly hasMultipleItems = computed(() => this.items().length > 1);
protected readonly frameWidth = computed(() => {
const viewportWidth = this.viewportWidth();
return viewportWidth === null
? null
: viewportWidth + (this.hasMultipleItems() ? CarouselComponent.CONTROL_SLOT_WIDTH * 2 : 0);
});
protected readonly resolvedGap = computed(() => Math.max(this.gap(), 0));
protected readonly pageCount = computed(() =>
Math.max(1, Math.ceil(this.items().length / this.itemsPerPage())),
@@ -234,15 +227,18 @@ export class CarouselComponent<T> implements AfterViewInit {
);
if (!firstItem || availableViewportWidth <= 0) {
this.viewportWidth.set(null);
this.itemWidth.set(null);
this.refreshNavigation();
return;
}
const itemWidth = firstItem.getBoundingClientRect().width;
const assignedWidth = firstItem.style.width;
firstItem.style.width = '';
const naturalItemWidth = firstItem.getBoundingClientRect().width;
firstItem.style.width = assignedWidth;
if (itemWidth <= 0) {
this.viewportWidth.set(null);
if (naturalItemWidth <= 0) {
this.itemWidth.set(null);
this.refreshNavigation();
return;
}
@@ -250,10 +246,11 @@ export class CarouselComponent<T> implements AfterViewInit {
const gap = this.resolvedGap();
const fittingItems = Math.max(
1,
Math.floor((availableViewportWidth + gap) / (itemWidth + gap)),
Math.floor((availableViewportWidth + gap) / (naturalItemWidth + gap)),
);
const visibleItems = Math.min(fittingItems, this.items().length);
const fittedWidth = visibleItems * itemWidth + Math.max(visibleItems - 1, 0) * gap;
const distributedItemWidth =
(availableViewportWidth - Math.max(visibleItems - 1, 0) * gap) / visibleItems;
if (this.itemsPerPage() !== fittingItems) {
this.itemsPerPage.set(fittingItems);
@@ -261,7 +258,7 @@ export class CarouselComponent<T> implements AfterViewInit {
this.transitionDirection.set(0);
}
this.viewportWidth.set(Math.min(Math.ceil(fittedWidth), availableViewportWidth));
this.itemWidth.set(distributedItemWidth);
if (this.circular()) {
const hasOverflow = this.items().length > fittingItems;
this.hasOverflow.set(hasOverflow);