UNPKG

ng-smooth-carousel

Version:

A smooth, customizable carousel component for Angular 14 applications

1 lines 59.4 kB
{"version":3,"file":"ng-smooth-carousel.mjs","sources":["../../../projects/ng-smooth-carousel/src/lib/carousel.component.ts","../../../projects/ng-smooth-carousel/src/lib/carousel.module.ts","../../../projects/ng-smooth-carousel/src/public-api.ts","../../../projects/ng-smooth-carousel/src/ng-smooth-carousel.ts"],"sourcesContent":["import {\n Component,\n Input,\n ContentChild,\n TemplateRef,\n ElementRef,\n AfterViewInit,\n OnDestroy,\n ViewChild,\n ChangeDetectorRef,\n OnInit,\n NgZone,\n OnChanges,\n SimpleChanges\n} from '@angular/core';\nimport { Subject, fromEvent } from 'rxjs';\nimport { takeUntil, debounceTime } from 'rxjs/operators';\nimport { CarouselConfig, ButtonStyle, ScrollSize } from './carousel-config.interface';\n\n/**\n * NgSmoothCarousel Component\n * \n * A carousel/slider component for Angular applications with smooth scrolling capabilities.\n * Supports both horizontal and vertical orientations, custom navigation styling,\n * and multiple configuration options.\n */\n@Component({\n selector: 'nsc',\n template: `\n <div [class.nsc--vertical]=\"isVertical\" [ngStyle]=\"containerStyles\" class=\"nsc\">\n <div\n #wrapper\n [style.--content-padding]=\"contentPadding\"\n class=\"nsc__wrapper\">\n <div\n #track\n [ngStyle]=\"trackStyles\"\n [class.nsc__track--vertical]=\"isVertical\"\n [style.--animation-duration]=\"animationDuration\"\n [style.--animation-timing]=\"animationTiming\"\n class=\"nsc__track\">\n <ng-container *ngIf=\"hasItems(); else emptyState\">\n <ng-container *ngFor=\"let item of filteredItems; let i = index\">\n <div class=\"nsc__item\" [ngStyle]=\"getItemStyle(i)\">\n <ng-container *ngIf=\"itemTemplate; else defaultTemplate\">\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { $implicit: item, index: i }\"></ng-container>\n </ng-container>\n <ng-template #defaultTemplate>\n <div class=\"nsc__item-default\">\n {{ item }}\n </div>\n </ng-template>\n </div>\n </ng-container>\n </ng-container>\n \n <ng-template #emptyState>\n <div class=\"nsc__empty-container\" [ngStyle]=\"getEmptyStateContainerStyle()\">\n <ng-container *ngIf=\"emptyStateTemplate; else defaultEmptyState\">\n <ng-container *ngTemplateOutlet=\"emptyStateTemplate; context: { $implicit: 'No items found' }\"></ng-container>\n </ng-container>\n <ng-template #defaultEmptyState>\n <div class=\"nsc__empty-state\">\n <div class=\"nsc__empty-icon\">📭</div>\n <div class=\"nsc__empty-text\">No items found</div>\n <!-- <button class=\"nsc__reset-button\" (click)=\"resetSearch()\">\n Show all items\n </button> -->\n </div>\n </ng-template>\n </div>\n </ng-template>\n </div>\n </div>\n\n <div *ngIf=\"showNavigation && hasItems()\" [ngClass]=\"getNavControlsClass()\" [ngStyle]=\"getNavControlsStyle()\">\n <!-- <div *ngIf=\"showSearch\" class=\"nsc__search\" style=\"position:absolute; bottom:16px; right:16px; pointer-events:auto;\">\n <button [ngStyle]=\"searchButtonStyles\" (click)=\"toggleSearchModal()\" class=\"nsc__nav-button nsc__nav-button--search\">\n <span class=\"nsc__nav-icon\" [ngStyle]=\"searchIconStyles\">{{ searchIcon }}</span>\n </button>\n <div *ngIf=\"isSearchModalOpen\" [class.nsc__dropdown--vertical]=\"isVertical\" (click)=\"$event.stopPropagation()\" class=\"nsc__dropdown\" >\n <input\n type=\"text\"\n [placeholder]=\"searchPlaceholder\"\n [(ngModel)]=\"searchQuery\"\n (keyup.enter)=\"applySearch()\"\n class=\"nsc__search-input\"\n #searchInput\n />\n </div>\n </div> -->\n \n <button \n [class.nsc__nav-button--disabled]=\"!showPrevButton\" \n [disabled]=\"!showPrevButton\" \n [ngStyle]=\"getPrevButtonFullStyles()\" \n (click)=\"previous()\" \n style=\"pointer-events:auto;\"\n class=\"nsc__nav-button\">\n <span class=\"nsc__nav-icon\" [ngStyle]=\"prevIconStyles\">{{ prevIcon }}</span>\n </button>\n \n <button\n [class.nsc__nav-button--disabled]=\"!showNextButton\"\n [disabled]=\"!showNextButton\"\n [ngStyle]=\"getNextButtonFullStyles()\"\n (click)=\"next()\"\n style=\"pointer-events:auto;\"\n class=\"nsc__nav-button\">\n <span class=\"nsc__nav-icon\" [ngStyle]=\"nextIconStyles\">{{ nextIcon }}</span>\n </button>\n </div>\n </div>\n `,\n styles: [\n `\n .nsc{position:relative;overflow:hidden;display:flex;flex-direction:column;border-radius:inherit}\n .nsc--vertical{flex-direction:column}\n .nsc__wrapper{flex:1;overflow:hidden;position:relative;padding:var(--content-padding,10px) 0;width:100%;border-radius:inherit}\n .nsc--vertical .nsc__wrapper{padding:0 var(--content-padding,10px)}\n .nsc__track{display:flex;flex-wrap:nowrap;transition:transform var(--animation-duration,.3s) var(--animation-timing,ease);width:fit-content;min-width:100%;border-radius:inherit}\n .nsc__track--vertical{flex-direction:column;width:100%;height:fit-content}\n .nsc__item{flex:0 0 auto;box-sizing:border-box;border-radius:inherit}\n .nsc--vertical .nsc__item{width:100%}\n .nsc__item-default{background:#fff;height:100%;display:flex;align-items:center;justify-content:center;border:1px solid #e0e0e0;border-radius:inherit;padding:20px}\n .nsc__empty-container{width:100%;box-sizing:border-box;border-radius:inherit}\n .nsc__empty-state{background:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:30px;text-align:center;color:#666;border-radius:inherit;min-height:200px}\n .nsc__nav-controls{position:absolute;display:flex;gap:24px;z-index:100;pointer-events:auto}\n .nsc__nav-button{background:#fff;border:1px solid #e0e0e0;width:32px;height:32px;padding:0;margin:0;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:101;position:relative}\n .nsc__nav-icon{display:flex;align-items:center;justify-content:center;width:100%;height:100%;font-size:16px;line-height:1}\n .nsc__nav-button:hover:not(.nsc__nav-button--disabled){opacity:0.9}\n .nsc__nav-button--disabled{opacity:.4;cursor:not-allowed;background-color:#f5f5f5;border-color:#ddd}\n .nsc__search{position:relative}\n .nsc__dropdown{position:absolute;background:#fff;border:1px solid #e0e0e0;border-radius:4px;box-shadow:0 2px 8px rgba(0,0,0,.1);z-index:1000;min-width:200px;top:100%;right:0;margin-top:8px}\n .nsc__dropdown--vertical{right:auto;left:100%;top:0;margin-top:0;margin-left:8px}\n .nsc__search-input{width:100%;padding:8px 12px;border:none;border-radius:4px;font-size:14px;outline:none}\n .nsc__empty-icon{font-size:32px;margin-bottom:12px}\n .nsc__empty-text{font-size:16px;margin-bottom:12px}\n .nsc__reset-button{background:none;border:none;padding:6px 12px;font-size:13px;color:#007bff;cursor:pointer;transition:opacity .2s ease}\n .nsc__reset-button:hover{opacity:.7}\n .nsc--vertical .nsc__nav-button .nsc__nav-icon{transform:rotate(90deg)}\n `,\n ],\n})\nexport class CarouselComponent implements OnInit, AfterViewInit, OnDestroy, OnChanges {\n @Input() items: any[] = [];\n @Input() config: CarouselConfig = {};\n\n @ContentChild('carouselItem') itemTemplate!: TemplateRef<any>;\n @ContentChild('emptyState') emptyStateTemplate!: TemplateRef<any>;\n @ViewChild('track') trackElement!: ElementRef<HTMLElement>;\n @ViewChild('wrapper') wrapperElement!: ElementRef<HTMLElement>;\n @ViewChild('searchInput') searchInput!: ElementRef<HTMLInputElement>;\n\n private currentTranslate = 0;\n private currentIndex = 0;\n private destroy$ = new Subject<void>();\n private autoplayInterval?: ReturnType<typeof setInterval>;\n private itemWidths: number[] = [];\n private itemHeights: number[] = [];\n private containerWidth: number = 0;\n private containerHeight: number = 0;\n private intersectionObserver: IntersectionObserver | null = null;\n private resizeObserver: ResizeObserver | null = null;\n private visibilityChangeTimeout: any = null;\n private initialized = false;\n\n private readonly scrollSizeMap = {\n 'xs': 50, 'sm': 100, 'md': 150, 'lg': 200, 'xl': 250,\n '2xl': 300, '3xl': 350, '4xl': 400, '5xl': 450, '6xl': 500,\n '7xl': 550, '8xl': 600, '9xl': 650, '10xl': 700, 'full': 1\n };\n\n showPrevButton = false;\n showNextButton = false;\n searchQuery = '';\n isSearchModalOpen = false;\n filteredItems: any[] = [];\n\n constructor(private readonly cdr: ChangeDetectorRef, private readonly ngZone: NgZone) {}\n\n /**\n * @description Initialize component on init\n */\n ngOnInit(): void {\n this.filteredItems = this.items || [];\n }\n\n /**\n * @description Handle changes to inputs\n */\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['items']) {\n this.filteredItems = this.items || [];\n \n if (this.initialized) {\n setTimeout(() => {\n this.updateContainerWidth();\n this.calculateItemWidths();\n this.checkOverflow();\n this.cdr.detectChanges();\n });\n }\n }\n }\n\n /**\n * @description Convert time string to milliseconds\n */\n private parseTimeToMs(time: string): number {\n if (time.endsWith('ms')) return parseInt(time.slice(0, -2), 10);\n if (time.endsWith('s')) return parseFloat(time.slice(0, -1)) * 1000;\n return parseInt(time, 10);\n }\n\n /**\n * @description Setup autoplay functionality if enabled\n */\n private setupAutoplay(): void {\n if (this.autoplayInterval) clearInterval(this.autoplayInterval);\n if (!this.config.autoplay) return;\n\n const delay = this.parseTimeToMs(this.config.autoplayDelay || '3000ms');\n this.autoplayInterval = setInterval(() => {\n const t = this.trackElement?.nativeElement;\n const w = this.wrapperElement?.nativeElement;\n \n if (!t || !w) return;\n \n const max = this.isVertical ? t.offsetHeight - w.offsetHeight : t.offsetWidth - w.offsetWidth;\n if (this.currentTranslate >= max) {\n if (this.config.loop) this.currentTranslate = 0;\n else {\n clearInterval(this.autoplayInterval);\n return;\n }\n } else this.next();\n \n this.cdr.detectChanges();\n }, delay);\n }\n\n /**\n * @description Initialize component after view is initialized\n */\n ngAfterViewInit(): void {\n this.initializeCarousel();\n this.setupResizeListener();\n this.setupIntersectionObserver();\n this.setupResizeObserver();\n this.setupAutoplay();\n \n setTimeout(() => {\n this.updateContainerWidth();\n this.calculateItemWidths();\n this.checkOverflow();\n this.initialized = true;\n });\n }\n\n /**\n * @description Clean up resources on component destruction\n */\n ngOnDestroy(): void {\n // Clear any interval timers\n if (this.autoplayInterval) {\n clearInterval(this.autoplayInterval);\n this.autoplayInterval = undefined;\n }\n\n // Disconnect observers\n if (this.intersectionObserver) {\n this.intersectionObserver.disconnect();\n this.intersectionObserver = null;\n }\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n // Clear any timeouts\n if (this.visibilityChangeTimeout) {\n clearTimeout(this.visibilityChangeTimeout);\n this.visibilityChangeTimeout = null;\n }\n\n // Complete all observables\n this.destroy$.next();\n this.destroy$.complete();\n \n // Clear arrays\n this.itemWidths = [];\n this.itemHeights = [];\n this.filteredItems = [];\n }\n\n /**\n * @description Whether carousel orientation is vertical\n */\n get isVertical(): boolean {\n return this.config.orientation === 'vertical';\n }\n\n /**\n * @description Get container styles based on configuration\n */\n get containerStyles(): Record<string, string> {\n return {\n width: this.config.containerWidth || '100%',\n height: this.config.containerHeight || 'auto',\n };\n }\n\n /**\n * @description Get track styles including transform property for translation\n */\n get trackStyles(): Record<string, string> {\n const base = {\n transform: this.isVertical\n ? `translateY(-${this.currentTranslate}px)`\n : `translateX(-${this.currentTranslate}px)`,\n };\n return this.isVertical ? { ...base, flexDirection: 'column' } : base;\n }\n\n /**\n * @description Initialize carousel state\n */\n private initializeCarousel(): void {\n if (!this.trackElement || !this.wrapperElement) return;\n this.currentTranslate = 0;\n this.checkOverflow();\n }\n\n private setupResizeListener(): void {\n fromEvent(window, 'resize')\n .pipe(debounceTime(200), takeUntil(this.destroy$))\n .subscribe(() => {\n this.updateContainerWidth();\n this.calculateItemWidths();\n this.checkOverflow();\n });\n }\n\n private setupIntersectionObserver(): void {\n // Create an IntersectionObserver to detect when the carousel becomes visible\n if ('IntersectionObserver' in window) {\n this.ngZone.runOutsideAngular(() => {\n this.intersectionObserver = new IntersectionObserver(entries => {\n const isVisible = entries[0]?.isIntersecting;\n \n if (isVisible && this.initialized) {\n // When component becomes visible, recalculate dimensions and update buttons\n this.ngZone.run(() => {\n // Use a small timeout to ensure the DOM has settled\n this.visibilityChangeTimeout = setTimeout(() => {\n this.updateContainerWidth();\n this.calculateItemWidths();\n this.checkOverflow();\n }, 50);\n });\n }\n }, { threshold: 0.1 });\n \n if (this.wrapperElement?.nativeElement) {\n this.intersectionObserver.observe(this.wrapperElement.nativeElement);\n }\n });\n }\n }\n\n private setupResizeObserver(): void {\n // Create a ResizeObserver to detect when the carousel's size changes\n if ('ResizeObserver' in window) {\n this.ngZone.runOutsideAngular(() => {\n this.resizeObserver = new ResizeObserver(entries => {\n if (this.initialized) {\n this.ngZone.run(() => {\n this.updateContainerWidth();\n this.calculateItemWidths();\n this.checkOverflow();\n });\n }\n });\n \n if (this.wrapperElement?.nativeElement) {\n this.resizeObserver.observe(this.wrapperElement.nativeElement);\n }\n });\n }\n }\n\n private updateContainerWidth(): void {\n if (!this.wrapperElement) return;\n this.containerWidth = this.wrapperElement.nativeElement.offsetWidth;\n this.containerHeight = this.wrapperElement.nativeElement.offsetHeight;\n }\n\n /**\n * @description Check if content overflows and update button visibility\n */\n private checkOverflow(): void {\n if (!this.showNavigation) {\n this.showPrevButton = this.showNextButton = false;\n return;\n }\n\n const t = this.trackElement?.nativeElement;\n const w = this.wrapperElement?.nativeElement;\n if (!t || !w) return;\n\n // Skip if element has zero dimensions (may be hidden)\n if (w.offsetWidth === 0 || w.offsetHeight === 0) return;\n\n if (this.config.enableOneItemScroll) {\n // In one-item mode, buttons depend on current index\n this.showPrevButton = this.currentIndex > 0;\n this.showNextButton = this.currentIndex < this.filteredItems.length - 1;\n } else if (this.isVertical) {\n // In vertical mode, check translation against content height\n this.showPrevButton = this.currentTranslate > 0;\n this.showNextButton = t.offsetHeight - this.currentTranslate > w.offsetHeight;\n } else {\n // In horizontal mode, check translation against content width\n this.showPrevButton = this.currentTranslate > 0;\n this.showNextButton = t.offsetWidth - this.currentTranslate > w.offsetWidth;\n }\n\n this.cdr.detectChanges();\n }\n\n private calculateItemWidths(): void {\n if (!this.trackElement || !this.wrapperElement) return;\n \n const w = this.wrapperElement.nativeElement;\n const items = Array.from(this.trackElement.nativeElement.children) as HTMLElement[];\n \n if (this.config.enableOneItemScroll) {\n if (this.isVertical) {\n const pHeight = w.offsetHeight;\n this.itemHeights = items.map(() => pHeight);\n \n this.itemWidths = items.map(item => {\n const style = window.getComputedStyle(item);\n const width = item.offsetWidth;\n const ml = parseInt(style.marginLeft || '0', 10);\n const mr = parseInt(style.marginRight || '0', 10);\n return width + ml + mr;\n });\n } else {\n const pWidth = w.offsetWidth;\n this.itemWidths = items.map(() => pWidth);\n \n this.itemHeights = items.map(item => {\n const style = window.getComputedStyle(item);\n const height = item.offsetHeight;\n const mt = parseInt(style.marginTop || '0', 10);\n const mb = parseInt(style.marginBottom || '0', 10);\n return height + mt + mb;\n });\n }\n return;\n }\n \n this.itemWidths = items.map(item => {\n const style = window.getComputedStyle(item);\n const width = item.offsetWidth;\n const ml = parseInt(style.marginLeft || '0', 10);\n const mr = parseInt(style.marginRight || '0', 10);\n return width + ml + mr;\n });\n \n this.itemHeights = items.map(item => {\n const style = window.getComputedStyle(item);\n const height = item.offsetHeight;\n const mt = parseInt(style.marginTop || '0', 10);\n const mb = parseInt(style.marginBottom || '0', 10);\n return height + mt + mb;\n });\n }\n\n /**\n * @description Calculate scroll amount based on configuration\n */\n private getScrollAmount(): number {\n // For one-item-scroll mode, return item dimension\n if (this.config.enableOneItemScroll) {\n if (this.isVertical && this.itemHeights.length > 0) {\n // Return height of current item or default to wrapper height\n return this.currentIndex < this.itemHeights.length \n ? this.itemHeights[this.currentIndex] \n : (this.itemHeights[0] || this.wrapperElement.nativeElement.offsetHeight);\n } else if (this.itemWidths.length > 0) {\n // Return width of current item or default to wrapper width\n return this.currentIndex < this.itemWidths.length \n ? this.itemWidths[this.currentIndex] \n : (this.itemWidths[0] || this.wrapperElement.nativeElement.offsetWidth);\n }\n }\n \n // Otherwise, use configured scroll size\n const size = this.config.scrollSize || 'sm';\n if (size === 'full') {\n // Full size returns container dimension\n return this.isVertical \n ? this.wrapperElement.nativeElement.offsetHeight \n : this.wrapperElement.nativeElement.offsetWidth;\n }\n \n // Return pixel value from map or default to small\n return this.scrollSizeMap[size as ScrollSize] || this.scrollSizeMap['sm'];\n }\n\n /**\n * @description Navigate to previous item\n */\n previous(): void {\n if (this.config.enableOneItemScroll) {\n if (this.currentIndex > 0) {\n this.currentIndex--;\n if (this.currentIndex === 0) {\n this.currentTranslate = 0;\n } else {\n const gap = this.config.itemGap ? parseInt(this.config.itemGap.replace('px', ''), 10) : 0;\n \n if (this.isVertical) {\n const ih = this.itemHeights[this.currentIndex] || this.wrapperElement.nativeElement.offsetHeight;\n this.currentTranslate = this.currentIndex * (ih + gap);\n } else {\n const iw = this.itemWidths[this.currentIndex] || this.wrapperElement.nativeElement.offsetWidth;\n this.currentTranslate = this.currentIndex * (iw + gap);\n }\n }\n }\n } else {\n const scrollAmount = this.getScrollAmount();\n this.currentTranslate = Math.max(0, this.currentTranslate - scrollAmount);\n }\n this.checkOverflow();\n }\n\n /**\n * @description Navigate to next item\n */\n next(): void {\n const t = this.trackElement.nativeElement;\n const w = this.wrapperElement.nativeElement;\n \n if (this.config.enableOneItemScroll) {\n if (this.currentIndex < this.filteredItems.length - 1) {\n const gap = this.config.itemGap ? parseInt(this.config.itemGap.replace('px', ''), 10) : 0;\n \n this.currentIndex++;\n \n if (this.isVertical) {\n const ih = this.itemHeights[this.currentIndex - 1] || w.offsetHeight;\n \n if (this.config.itemHeight === '100%') {\n this.currentTranslate = this.currentIndex * (ih + gap);\n } else {\n this.currentTranslate += ih + gap;\n }\n } else {\n const iw = this.itemWidths[this.currentIndex - 1] || w.offsetWidth;\n \n if (this.config.itemWidth === '100%') {\n this.currentTranslate = this.currentIndex * (iw + gap);\n } else {\n this.currentTranslate += iw + gap;\n }\n }\n }\n } else {\n const amt = this.getScrollAmount();\n const max = this.isVertical ? t.offsetHeight - w.offsetHeight : t.offsetWidth - w.offsetWidth;\n this.currentTranslate = Math.min(max, this.currentTranslate + amt);\n }\n this.checkOverflow();\n }\n\n /**\n * @description Get button shape styles based on configuration\n */\n private getButtonShapeStyles(): Record<string, string> {\n const shape = this.config.navigationStyle?.buttonShape;\n switch (shape) {\n case 'circle': return { borderRadius: '50%' };\n case 'rounded': return { borderRadius: '4px' };\n default: return { borderRadius: '0' };\n }\n }\n\n /**\n * @description Get styles for next button\n */\n get nextButtonStyles(): Record<string, any> {\n const bs = { ...(this.config.navigationStyle?.nextButton || {}) };\n const ss = this.getButtonShapeStyles();\n if (this.config.navigationStyle?.buttonShape && bs) delete bs['borderRadius'];\n return { ...ss, ...bs };\n }\n\n /**\n * @description Get styles for previous button\n */\n get prevButtonStyles(): Record<string, any> {\n const bs = { ...(this.config.navigationStyle?.prevButton || {}) };\n const ss = this.getButtonShapeStyles();\n if (this.config.navigationStyle?.buttonShape && bs) delete bs['borderRadius'];\n return { ...ss, ...bs };\n }\n\n /**\n * @description Get styles for search button\n * @deprecated COMING SOON - Search functionality will be available in future releases\n */\n // get searchButtonStyles(): Record<string, any> {\n // const bs = { ...(this.config.searchStyle?.button || {}) };\n // const ss = this.getButtonShapeStyles();\n // if (this.config.navigationStyle?.buttonShape && bs) delete bs['borderRadius'];\n // return { ...ss, ...bs };\n // }\n\n /**\n * @description Get individual item styling\n */\n getItemStyle(index: number): Record<string, string> {\n const s: Record<string, string> = {\n flexShrink: '0',\n flexGrow: '0',\n boxSizing: 'border-box',\n overflow: 'hidden',\n borderRadius: 'inherit'\n };\n\n // Handle width calculation\n if (this.config.itemWidth) {\n if (this.config.itemWidth === '100%' && this.config.enableOneItemScroll && this.containerWidth > 0) {\n // For full-width items, adjust based on orientation\n const widthAdjustment = this.isVertical ? 4 : 0;\n s['width'] = (this.containerWidth - widthAdjustment) + 'px';\n s['maxWidth'] = '100%';\n } else {\n s['width'] = this.config.itemWidth;\n }\n } else {\n s['width'] = '100%';\n }\n \n // Handle height calculation\n if (this.config.itemHeight) {\n if (this.config.itemHeight === '100%' && this.wrapperElement) {\n const containerHeight = this.wrapperElement.nativeElement.offsetHeight;\n if (containerHeight > 0) {\n // For full-height items, adjust based on orientation\n const heightAdjustment = this.isVertical ? 0 : 4;\n s['height'] = (containerHeight - heightAdjustment) + 'px';\n s['maxHeight'] = '100%';\n } else {\n s['height'] = this.config.itemHeight;\n }\n } else {\n s['height'] = this.config.itemHeight;\n }\n } else {\n s['height'] = 'auto';\n }\n\n // Add margin for gap between items (except first item)\n if (!this.config.itemGap) return s;\n\n const m = this.isVertical ? 'marginTop' : 'marginLeft';\n return { ...s, [m]: index === 0 ? '0' : this.config.itemGap };\n }\n\n /**\n * @description Content padding for the carousel\n */\n get contentPadding(): string { return this.config.contentPadding || '4px'; }\n \n /**\n * @description Animation duration for scrolling\n */\n get animationDuration(): string { return this.config.animationDuration || '300ms'; }\n \n /**\n * @description Animation timing function\n */\n get animationTiming(): string { return this.config.animationTiming || 'ease'; }\n \n /**\n * @description Whether search functionality is enabled\n * @deprecated COMING SOON - Search functionality will be available in future releases\n */\n // get showSearch(): boolean { return this.config.enableSearch ?? false; }\n \n /**\n * @description Placeholder text for search input\n * @deprecated COMING SOON - Search functionality will be available in future releases\n */\n // get searchPlaceholder(): string { return this.config.searchPlaceholder || 'Search...'; }\n \n /**\n * @description Title for search modal\n * @deprecated COMING SOON - Search functionality will be available in future releases\n */\n // get searchModalTitle(): string { return this.config.searchModalTitle || 'Filter Items'; }\n \n /**\n * @description Styles for search modal\n * @deprecated COMING SOON - Search functionality will be available in future releases\n */\n // get searchModalStyles(): Record<string, string> { return this.config.searchStyle?.modal || {}; }\n\n /**\n * @description Toggle search modal visibility\n * @deprecated COMING SOON - Search functionality will be available in future releases\n */\n // toggleSearchModal(): void {\n // this.isSearchModalOpen = !this.isSearchModalOpen;\n // if (this.isSearchModalOpen && this.searchInput) {\n // setTimeout(() => this.searchInput.nativeElement.focus());\n // }\n // }\n\n /**\n * @description Close search modal\n * @deprecated COMING SOON - Search functionality will be available in future releases\n */\n // closeSearchModal(): void {\n // this.isSearchModalOpen = false;\n // }\n\n /**\n * @description Apply search filter to items\n * @deprecated COMING SOON - Search functionality will be available in future releases\n */\n // applySearch(): void {\n // const q = this.searchQuery.trim().toLowerCase();\n // if (!q) {\n // this.filteredItems = this.items;\n // } else {\n // this.filteredItems = this.items.filter(item => {\n // if (typeof item === 'string') return item.toLowerCase().includes(q);\n // return Object.values(item).some(v => typeof v === 'string' && v.toLowerCase().includes(q));\n // });\n // }\n\n // this.currentTranslate = 0;\n // this.currentIndex = 0;\n // this.checkOverflow();\n // this.closeSearchModal();\n // }\n\n /**\n * @description Handle clicks outside search modal\n * @deprecated COMING SOON - Search functionality will be available in future releases\n */\n // @HostListener('document:click', ['$event'])\n // handleClickOutside(event: MouseEvent): void {\n // const sc = document.querySelector('.nsc__search');\n // if (this.isSearchModalOpen && sc && !sc.contains(event.target as Node)) {\n // this.closeSearchModal();\n // }\n // }\n\n /**\n * @description Reset search and show all items\n * @deprecated COMING SOON - Search functionality will be available in future releases\n */\n // resetSearch(): void {\n // this.searchQuery = '';\n // this.filteredItems = this.items;\n // this.currentTranslate = 0;\n // this.currentIndex = 0;\n // setTimeout(() => {\n // this.updateContainerWidth();\n // this.calculateItemWidths();\n // this.checkOverflow();\n // });\n // }\n\n /**\n * @description Get navigation icons based on configuration\n */\n private getNavigationIcons(): { prev: string; next: string; search?: string } {\n const defIcons = {\n horizontal: { prev: '❮', next: '❯' },\n vertical: { prev: '❮', next: '❯' },\n // search: '🔍'\n };\n\n const cfgIcons = this.config.navigationStyle?.icons || {};\n const vIcons = cfgIcons.vertical || {};\n\n // Get icons based on orientation\n return {\n prev: this.isVertical ? (vIcons.prev || defIcons.vertical.prev) : (cfgIcons.prev || defIcons.horizontal.prev),\n next: this.isVertical ? (vIcons.next || defIcons.vertical.next) : (cfgIcons.next || defIcons.horizontal.next),\n // search: cfgIcons.search || defIcons.search\n };\n }\n\n /**\n * @description Previous button icon\n */\n get prevIcon(): string { return this.getNavigationIcons().prev; }\n \n /**\n * @description Next button icon\n */\n get nextIcon(): string { return this.getNavigationIcons().next; }\n \n /**\n * @description Search button icon\n * @deprecated COMING SOON - Search functionality will be available in future releases\n */\n // get searchIcon(): string { return this.getNavigationIcons().search; }\n\n /**\n * @description Next button icon styles\n */\n get nextIconStyles(): Record<string, string> {\n return { color: (this.config.navigationStyle?.nextButton || {})['color'] || '#666' };\n }\n\n /**\n * @description Previous button icon styles\n */\n get prevIconStyles(): Record<string, string> {\n return { color: (this.config.navigationStyle?.prevButton || {})['color'] || '#666' };\n }\n\n /**\n * @description Search button icon styles\n * @deprecated COMING SOON - Search functionality will be available in future releases\n */\n // get searchIconStyles(): Record<string, string> {\n // return { color: (this.config.searchStyle?.button || {})['color'] || '#666' };\n // }\n\n /**\n * @description Whether navigation buttons should be shown\n */\n get showNavigation(): boolean {\n return this.config.showNavigation ?? true;\n }\n\n /**\n * @description Get styles for empty state container\n */\n getEmptyStateContainerStyle(): Record<string, string> {\n return {\n width: '100%',\n boxSizing: 'border-box',\n borderRadius: 'inherit'\n };\n }\n\n /**\n * @description Determines if carousel contains items\n */\n hasItems(): boolean {\n return this.filteredItems?.length > 0;\n }\n\n /**\n * @description Default CTA position (fixed to bottom-right)\n * @deprecated Will be removed in future versions\n */\n get ctaPosition(): string {\n return 'bottom-right';\n }\n\n /**\n * @description Get class for navigation controls container\n */\n getNavControlsClass(): string {\n return 'nsc__nav-controls';\n }\n \n /**\n * @description Get styles for navigation controls container\n */\n getNavControlsStyle(): Record<string, string> {\n return {\n position: 'absolute',\n top: '0',\n left: '0',\n width: '100%',\n height: '100%',\n pointerEvents: 'none',\n zIndex: '100'\n };\n }\n\n /**\n * @description Calculate position styles for navigation buttons\n */\n private getButtonPositionStyle(button: 'prev' | 'next'): Record<string, any> {\n const navConfig = this.config.navigationStyle;\n const buttonStyle: ButtonStyle = \n button === 'prev' \n ? navConfig?.prevButton || {} \n : navConfig?.nextButton || {};\n \n // Create a base style object with high z-index\n const style: Record<string, any> = {\n zIndex: buttonStyle['zIndex'] || '1000',\n position: 'absolute', // Always use absolute positioning\n pointerEvents: 'auto'\n };\n \n // Apply direct positioning if specified\n if (buttonStyle['top'] !== undefined) style['top'] = buttonStyle['top'];\n if (buttonStyle['bottom'] !== undefined) style['bottom'] = buttonStyle['bottom'];\n if (buttonStyle['left'] !== undefined) style['left'] = buttonStyle['left'];\n if (buttonStyle['right'] !== undefined) style['right'] = buttonStyle['right'];\n \n // Set transform if specified\n if (buttonStyle['transform'] !== undefined) {\n style['transform'] = buttonStyle['transform'];\n }\n \n // Apply default positioning if no position is provided\n if (buttonStyle['top'] === undefined && buttonStyle['bottom'] === undefined && \n buttonStyle['left'] === undefined && buttonStyle['right'] === undefined) {\n // Use default center positions\n style['top'] = '50%';\n style['transform'] = 'translateY(-50%)';\n \n if (button === 'prev') {\n style['left'] = '-10px';\n } else {\n style['right'] = '-10px';\n }\n }\n \n return style;\n }\n\n /**\n * @description Get full styles for previous button\n */\n getPrevButtonFullStyles(): Record<string, any> {\n const styles = { ...this.prevButtonStyles };\n \n // If the z-index is specified, ensure it's applied with higher priority\n if (styles['zIndex']) {\n styles['zIndex'] = (parseInt(styles['zIndex']) || 0).toString();\n }\n \n // Apply position styles if needed\n const positionStyles = this.getButtonPositionStyle('prev');\n return { ...positionStyles, ...styles };\n }\n\n /**\n * @description Get full styles for next button\n */\n getNextButtonFullStyles(): Record<string, any> {\n const styles = { ...this.nextButtonStyles };\n \n // If the z-index is specified, ensure it's applied with higher priority\n if (styles['zIndex']) {\n styles['zIndex'] = (parseInt(styles['zIndex']) || 0).toString();\n }\n \n // Apply position styles if needed\n const positionStyles = this.getButtonPositionStyle('next');\n return { ...positionStyles, ...styles };\n }\n}","import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { CarouselComponent } from './carousel.component';\n\n@NgModule({\n declarations: [CarouselComponent],\n imports: [CommonModule, FormsModule],\n exports: [CarouselComponent],\n})\nexport class NgSmoothCarouselModule {}\n","/*\n * Public API Surface of ng-smooth-carousel\n */\n\n// Component and Module exports\nexport * from './lib/carousel.component';\nexport * from './lib/carousel.module';\n\n// Interface exports\nexport * from './lib/carousel-config.interface';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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