@ipi-soft/ng-components
Version:
Custom Angular Components
1 lines • 13 kB
Source Map (JSON)
{"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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"}