{"version":3,"file":"ipi-soft-ng-components-carousel.mjs","sources":["../../../../projects/ipi-soft/ng-components/carousel/src/carousel.component.ts","../../../../projects/ipi-soft/ng-components/carousel/src/carousel.component.html","../../../../projects/ipi-soft/ng-components/carousel/ipi-soft-ng-components-carousel.ts"],"sourcesContent":["import { Component, ViewChild, ElementRef, HostListener, inject, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\nimport { Subject, Subscription, throttleTime } from 'rxjs';\n\n@Component({\n  selector: 'ipi-carousel',\n  templateUrl: './carousel.component.html',\n  styleUrls: ['./carousel.component.css'],\n})\n\nexport class IpiCarouselComponent {\n\n  constructor() { }\n\n  @ViewChild('carousel') carousel!: ElementRef<HTMLDivElement>;\n\n  @ViewChild('prevButton') prevButton!: ElementRef;\n  @ViewChild('nextButton') nextButton!: ElementRef;\n\n  public scrollProgress = 0;\n  public scrollAnimationDuration = 500; // ms\n  \n  public scrollSubject = new Subject<'prev' | 'next'>();\n\n  private currentCenteredElemIndex = 0; \n\n  private isProgrammaticScroll = false;\n  private scrollSubscription!: Subscription;\n\n  private platformId = inject(PLATFORM_ID);\n\n  public ngAfterViewInit(): void {\n    this.applyScrollSnapAlign();\n\n    if (isPlatformBrowser(this.platformId)) {\n      this.adjustCarouselSpacing();\n    }\n\n    this.scrollSubject.pipe(throttleTime(this.scrollAnimationDuration)).subscribe((direction: 'prev' | 'next') => {\n      this.scroll(direction);\n    });\n\n    this.updateCurrentCenterdElemIndex(this.carousel.nativeElement);\n  }\n\n  public ngOnDestroy(): void {\n    if (this.scrollSubscription) {\n      this.scrollSubscription.unsubscribe();\n    }\n  }\n\n  public scroll(direction: 'prev' | 'next'): void {\n    const carouselEl = this.carousel.nativeElement;\n    const children = Array.from(carouselEl.children) as HTMLElement[];\n  \n    if (direction === 'next') {\n      this.currentCenteredElemIndex = Math.min(this.currentCenteredElemIndex + 1, children.length - 1);\n\n    } else {\n      this.currentCenteredElemIndex = Math.max(this.currentCenteredElemIndex - 1, 0);\n    }\n  \n    const targetElement = children[this.currentCenteredElemIndex];\n  \n    this.isProgrammaticScroll = true; \n  \n    if (!targetElement) {\n      return;\n    }\n    \n    switch (this.currentCenteredElemIndex) {\n      case 0:\n        carouselEl.scrollTo({ left: 0, behavior: 'smooth' });\n    \n        break;\n      case children.length - 1:\n        const scrollEnd = carouselEl.scrollWidth - carouselEl.clientWidth;\n\n        carouselEl.scrollTo({ left: scrollEnd, behavior: 'smooth' });\n\n        break;\n      default:\n        targetElement.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' });\n    }  \n\n    setTimeout(() => {\n      this.isProgrammaticScroll = false;\n    }, this.scrollAnimationDuration);\n  }\n\n  @HostListener('window:resize')\n  public onResize(): void {\n    const carouselEl = this.carousel.nativeElement;\n\n    const carouselCenter = carouselEl.offsetWidth / 2;\n    const scrollLeft = carouselEl.scrollLeft;\n\n    const children = Array.from(carouselEl.children) as HTMLElement[];\n\n    const currentlyCenteredElement = children.find(child => {\n      const childLeft = child.offsetLeft - scrollLeft;\n      const childCenter = childLeft + child.offsetWidth / 2;\n      return Math.abs(childCenter - carouselCenter) < child.offsetWidth / 2;\n    });\n\n    if (currentlyCenteredElement) {\n      const targetLeft = currentlyCenteredElement.offsetLeft;\n      const targetCenter = targetLeft + currentlyCenteredElement.offsetWidth / 2;\n      const newScrollPosition = targetCenter - carouselCenter;\n\n      carouselEl.scrollTo({ left: newScrollPosition, behavior: 'smooth' });\n    }\n  }\n\n  public onNavigationKeydown(event: KeyboardEvent, direction: 'prev' | 'next'): void {\n    if (event.code === 'Space' || event.code === 'Enter') {\n      this.scroll(direction);\n\n      return;\n    }\n\n    if (event.code === 'ArrowLeft' || event.code === 'ArrowRight') {\n      if (this.nextButton.nativeElement === document.activeElement) {\n        this.prevButton.nativeElement.focus();\n      } else {\n        this.nextButton.nativeElement.focus();\n      }\n    }\n  }\n\n  public onScroll(event: Event): void {\n    const container = event.target as HTMLElement;\n  \n    this.updateProgressBar(container);\n  \n    if (this.isProgrammaticScroll) {\n      return;\n    }\n\n    this.updateCurrentCenterdElemIndex(container);\n  }\n\n  private updateProgressBar(container: HTMLElement) {\n    const scrollLeft = container.scrollLeft;\n    const scrollWidth = container.scrollWidth - container.clientWidth;\n\n    this.scrollProgress = ((scrollLeft / scrollWidth) * 100) - (104 / container.clientWidth);\n  }\n\n  private updateCurrentCenterdElemIndex(container: HTMLElement): void {\n    const carouselEl = this.carousel.nativeElement;\n    const carouselWidth = carouselEl.offsetWidth;\n    const carouselCenter = container.scrollLeft + carouselWidth / 2;\n\n    const children = Array.from(carouselEl.children) as HTMLElement[];\n  \n    let closestIndex = 0;\n    let minDistance = Infinity;\n  \n    for (let i = 0; i < children.length; i++) {\n      const childCenter = children[i].offsetLeft + children[i].offsetWidth / 2;\n      const distance = Math.abs(carouselCenter - childCenter);\n\n      if (distance < minDistance) {\n        minDistance = distance;\n        closestIndex = i;\n      }\n    }\n\n    this.currentCenteredElemIndex = closestIndex;\n  }\n\n  private applyScrollSnapAlign(): void {\n    const children = this.carousel.nativeElement.children;\n\n    for (let i = 0; i < children.length; i++) {\n      (children[i] as HTMLElement).style.scrollSnapAlign = 'center';\n    }\n  }\n\n  private adjustCarouselSpacing(): void {\n    const carouselEl = this.carousel.nativeElement;\n  \n    const carouselRect = carouselEl.getBoundingClientRect();\n    const rightCalculatedValue = window.innerWidth - carouselRect.right;\n  \n    const leftCalculatedValue = carouselRect.left;\n\n    carouselEl.style.marginRight = `-${rightCalculatedValue}px`;\n    carouselEl.style.paddingRight = `${rightCalculatedValue}px`;\n\n    carouselEl.style.marginLeft = `-${leftCalculatedValue}px`;\n    carouselEl.style.paddingLeft = `${leftCalculatedValue}px`;\n  }\n\n}\n","<div class=\"carousel-container\">\n    <div #carousel class=\"carousel\" (scroll)=\"onScroll($event)\">\n            <ng-content></ng-content>\n    </div>\n</div>\n\n<div class=\"carousel-navigation\">\n    <div class=\"navigation-buttons-wrapper\">\n        <div \n            #prevButton\n            tabindex=\"0\"\n            class=\"chevron-wrapper\"\n            aria-label=\"Scroll to previous item\"\n            (click)=\"scrollSubject.next('prev')\"\n            (keydown)=\"onNavigationKeydown($event, 'prev')\">\n                <div class=\"chevron prev\"></div>\n        </div>\n\n        <div\n            #nextButton\n            tabindex=\"0\"\n            class=\"chevron-wrapper\"\n            aria-label=\"Scroll to next item\"\n            (click)=\"scrollSubject.next('next')\"\n            (keydown)=\"onNavigationKeydown($event, 'next')\">\n                <div class=\"chevron next\"></div>\n        </div>\n    </div>\n\n    <div #progressBarContainer class=\"scroll-bar-container\">\n        <div class=\"scroll-indicator\" [style.width.%]=\"scrollProgress\"></div>\n    </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}