You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

108 lines
2.8 KiB

import {
CUSTOM_ELEMENTS_SCHEMA,
ChangeDetectionStrategy,
Component,
contentChildren,
ElementRef,
HostBinding,
Inject,
Input,
Optional,
ViewChild
} from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { ANIMATION_MODULE_TYPE } from '@angular/platform-browser/animations';
import { IonIcon } from '@ionic/angular/standalone';
import { addIcons } from 'ionicons';
import { chevronBackOutline, chevronForwardOutline } from 'ionicons/icons';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [IonIcon, MatButtonModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
selector: 'gf-carousel',
styleUrls: ['./carousel.component.scss'],
templateUrl: './carousel.component.html'
})
export class GfCarouselComponent {
@HostBinding('class.animations-disabled')
public readonly animationsDisabled: boolean;
@Input('aria-label') public ariaLabel: string | undefined;
@ViewChild('list') public list!: ElementRef<HTMLElement>;
public items = contentChildren('carouselItem', { read: ElementRef });
public showPrevArrow = false;
public showNextArrow = true;
private index = 0;
private position = 0;
public constructor(
@Optional() @Inject(ANIMATION_MODULE_TYPE) animationsModule?: string
) {
this.animationsDisabled = animationsModule === 'NoopAnimations';
addIcons({ chevronBackOutline, chevronForwardOutline });
}
public next() {
for (let i = this.index; i < this.items().length; i++) {
if (this.isOutOfView(i)) {
this.index = i;
this.scrollToActiveItem();
break;
}
}
}
public previous() {
for (let i = this.index; i > -1; i--) {
if (this.isOutOfView(i)) {
this.index = i;
this.scrollToActiveItem();
break;
}
}
}
private isOutOfView(index: number, side?: 'start' | 'end') {
const { offsetWidth, offsetLeft } = this.items()[index].nativeElement;
if ((!side || side === 'start') && offsetLeft - this.position < 0) {
return true;
}
return (
(!side || side === 'end') &&
offsetWidth + offsetLeft - this.position >
this.list.nativeElement.clientWidth
);
}
private scrollToActiveItem() {
if (!this.isOutOfView(this.index)) {
return;
}
let targetItemIndex = this.index;
if (this.index > 0 && !this.isOutOfView(this.index - 1)) {
targetItemIndex =
this.items().findIndex((_, i) => !this.isOutOfView(i)) + 1;
}
this.position = this.items()[targetItemIndex].nativeElement.offsetLeft;
this.list.nativeElement.style.transform = `translateX(-${this.position}px)`;
this.showPrevArrow = this.index > 0;
this.showNextArrow = false;
for (let i = this.items().length - 1; i > -1; i--) {
if (this.isOutOfView(i, 'end')) {
this.showNextArrow = true;
break;
}
}
}
}