feat(carousel): enhance carousel layout and control positioning for improved responsiveness

This commit is contained in:
2026-07-23 12:29:08 -03:00
parent ca1cacc9ea
commit 4f444fd757
4 changed files with 52 additions and 14 deletions

View File

@@ -39,6 +39,8 @@ interface CarouselPage<T> {
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CarouselComponent<T> implements AfterViewInit {
private static readonly CONTROL_SLOT_WIDTH = 48;
private readonly destroyRef = inject(DestroyRef);
private readonly platformId = inject(PLATFORM_ID);
private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);
@@ -62,6 +64,13 @@ export class CarouselComponent<T> implements AfterViewInit {
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())),
@@ -219,8 +228,12 @@ export class CarouselComponent<T> implements AfterViewInit {
const viewport = this.viewport().nativeElement;
const firstItem = viewport.querySelector<HTMLElement>('.carousel__item');
const availableWidth = this.host.nativeElement.clientWidth;
const availableViewportWidth = Math.max(
availableWidth - (this.hasMultipleItems() ? CarouselComponent.CONTROL_SLOT_WIDTH * 2 : 0),
0,
);
if (!firstItem || availableWidth <= 0) {
if (!firstItem || availableViewportWidth <= 0) {
this.viewportWidth.set(null);
this.refreshNavigation();
return;
@@ -235,7 +248,10 @@ export class CarouselComponent<T> implements AfterViewInit {
}
const gap = this.resolvedGap();
const fittingItems = Math.max(1, Math.floor((availableWidth + gap) / (itemWidth + gap)));
const fittingItems = Math.max(
1,
Math.floor((availableViewportWidth + gap) / (itemWidth + gap)),
);
const visibleItems = Math.min(fittingItems, this.items().length);
const fittedWidth = visibleItems * itemWidth + Math.max(visibleItems - 1, 0) * gap;
@@ -245,7 +261,7 @@ export class CarouselComponent<T> implements AfterViewInit {
this.transitionDirection.set(0);
}
this.viewportWidth.set(Math.min(Math.ceil(fittedWidth), availableWidth));
this.viewportWidth.set(Math.min(Math.ceil(fittedWidth), availableViewportWidth));
if (this.circular()) {
const hasOverflow = this.items().length > fittingItems;
this.hasOverflow.set(hasOverflow);