feat(carousel): add circular scrolling support and improve button disable logic
This commit is contained in:
@@ -39,15 +39,23 @@ export class CarouselComponent<T> implements AfterViewInit {
|
||||
readonly trackBy = input<CarouselTrackBy<T>>((index) => index);
|
||||
readonly scrollStep = input<number | null>(null);
|
||||
readonly gap = input(0);
|
||||
readonly circular = input(false);
|
||||
readonly ariaLabel = input('Carrusel');
|
||||
readonly previousLabel = input('Mostrar elementos anteriores');
|
||||
readonly nextLabel = input('Mostrar elementos siguientes');
|
||||
|
||||
protected readonly canScrollPrevious = signal(false);
|
||||
protected readonly canScrollNext = signal(false);
|
||||
protected readonly hasOverflow = signal(false);
|
||||
protected readonly viewportWidth = signal<number | null>(null);
|
||||
protected readonly hasMultipleItems = computed(() => this.items().length > 1);
|
||||
protected readonly resolvedGap = computed(() => Math.max(this.gap(), 0));
|
||||
protected readonly isPreviousDisabled = computed(
|
||||
() => !this.hasOverflow() || (!this.circular() && !this.canScrollPrevious()),
|
||||
);
|
||||
protected readonly isNextDisabled = computed(
|
||||
() => !this.hasOverflow() || (!this.circular() && !this.canScrollNext()),
|
||||
);
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
if (!isPlatformBrowser(this.platformId)) {
|
||||
@@ -74,10 +82,20 @@ export class CarouselComponent<T> implements AfterViewInit {
|
||||
}
|
||||
|
||||
previous(): void {
|
||||
if (this.circular() && this.hasOverflow() && !this.canScrollPrevious()) {
|
||||
this.scrollToEdge('end');
|
||||
return;
|
||||
}
|
||||
|
||||
this.scroll(-1);
|
||||
}
|
||||
|
||||
next(): void {
|
||||
if (this.circular() && this.hasOverflow() && !this.canScrollNext()) {
|
||||
this.scrollToEdge('start');
|
||||
return;
|
||||
}
|
||||
|
||||
this.scroll(1);
|
||||
}
|
||||
|
||||
@@ -126,10 +144,20 @@ export class CarouselComponent<T> implements AfterViewInit {
|
||||
const maxScrollLeft = Math.max(viewport.scrollWidth - viewport.clientWidth, 0);
|
||||
const tolerance = 1;
|
||||
|
||||
this.hasOverflow.set(maxScrollLeft > tolerance);
|
||||
this.canScrollPrevious.set(viewport.scrollLeft > tolerance);
|
||||
this.canScrollNext.set(viewport.scrollLeft < maxScrollLeft - tolerance);
|
||||
}
|
||||
|
||||
private scrollToEdge(edge: 'start' | 'end'): void {
|
||||
const viewport = this.viewport().nativeElement;
|
||||
|
||||
viewport.scrollTo({
|
||||
left: edge === 'start' ? 0 : viewport.scrollWidth - viewport.clientWidth,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
}
|
||||
|
||||
private refreshLayout(): void {
|
||||
const viewport = this.viewport().nativeElement;
|
||||
const firstItem = viewport.firstElementChild as HTMLElement | null;
|
||||
|
||||
Reference in New Issue
Block a user