UNPKG

primeng

Version:

PrimeNG is an open source UI library for Angular featuring a rich set of 80+ components, a theme designer, various theme alternatives such as Material, Bootstrap, Tailwind, premium templates and professional support. In addition, it integrates with PrimeB

1,157 lines (1,139 loc) 55.2 kB
import * as i1 from '@angular/common'; import { isPlatformBrowser, CommonModule } from '@angular/common'; import * as i0 from '@angular/core'; import { Injectable, EventEmitter, inject, numberAttribute, booleanAttribute, ContentChildren, ContentChild, ViewChild, Output, Input, ViewEncapsulation, ChangeDetectionStrategy, Component, NgModule } from '@angular/core'; import { uuid, setAttribute, find, getAttribute, findSingle } from '@primeuix/utils'; import { SharedModule, Header, Footer, PrimeTemplate } from 'primeng/api'; import { BaseComponent } from 'primeng/basecomponent'; import * as i2 from 'primeng/button'; import { ButtonModule } from 'primeng/button'; import { ChevronRightIcon, ChevronLeftIcon, ChevronDownIcon, ChevronUpIcon } from 'primeng/icons'; import { BaseStyle } from 'primeng/base'; const theme = ({ dt }) => ` .p-carousel { display: flex; flex-direction: column; } .p-carousel-content-container { display: flex; flex-direction: column; overflow: auto; } .p-carousel-content { display: flex; flex-direction: row; gap: ${dt('carousel.content.gap')}; } .p-carousel-content:dir(rtl) { flex-direction: row-reverse; } .p-carousel-viewport { overflow: hidden; width: 100%; } .p-carousel-item-list { display: flex; flex-direction: row; } .p-carousel-item-list:dir(rtl) { flex-direction: row-reverse; } .p-carousel-prev-button, .p-carousel-next-button { align-self: center; flex-shrink: 0; } .p-carousel-indicator-list { display: flex; flex-direction: row; justify-content: center; flex-wrap: wrap; padding: ${dt('carousel.indicator.list.padding')}; gap: ${dt('carousel.indicator.list.gap')}; margin: 0; list-style: none; } .p-carousel-indicator-button { display: flex; align-items: center; justify-content: center; background: ${dt('carousel.indicator.background')}; width: ${dt('carousel.indicator.width')}; height: ${dt('carousel.indicator.height')}; border: 0 none; transition: background ${dt('carousel.transition.duration')}, color ${dt('carousel.transition.duration')}, outline-color ${dt('carousel.transition.duration')}, box-shadow ${dt('carousel.transition.duration')}; outline-color: transparent; border-radius: ${dt('carousel.indicator.border.radius')}; padding: 0; margin: 0; user-select: none; cursor: pointer; } .p-carousel-indicator-button:focus-visible { box-shadow: ${dt('carousel.indicator.focus.ring.shadow')}; outline: ${dt('carousel.indicator.focus.ring.width')} ${dt('carousel.indicator.focus.ring.style')} ${dt('carousel.indicator.focus.ring.color')}; outline-offset: ${dt('carousel.indicator.focus.ring.offset')}; } .p-carousel-indicator-button:hover { background: ${dt('carousel.indicator.hover.background')}; } .p-carousel-indicator-active .p-carousel-indicator-button { background: ${dt('carousel.indicator.active.background')}; } .p-carousel-vertical .p-carousel-content { flex-direction: column; } .p-carousel-vertical .p-carousel-item-list { flex-direction: column; height: 100%; } .p-items-hidden .p-carousel-item { visibility: hidden; } .p-items-hidden .p-carousel-item.p-carousel-item-active { visibility: visible; } `; const classes = { root: ({ instance }) => [ 'p-carousel p-component', { 'p-carousel-vertical': instance.isVertical(), 'p-carousel-horizontal': !instance.isVertical() } ], header: 'p-carousel-header', contentContainer: 'p-carousel-content-container', content: 'p-carousel-content', pcPrevButton: ({ instance }) => [ 'p-carousel-prev-button', { 'p-disabled': instance.backwardIsDisabled } ], viewport: 'p-carousel-viewport', itemList: 'p-carousel-item-list', itemClone: ({ index, value, totalShiftedItems, d_numVisible }) => [ 'p-carousel-item p-carousel-item-clone', { 'p-carousel-item-active': totalShiftedItems * -1 === value.length + d_numVisible, 'p-carousel-item-start': index === 0, 'p-carousel-item-end': value.slice(-1 * d_numVisible).length - 1 === index } ], item: ({ instance, index }) => [ 'p-carousel-item', { 'p-carousel-item-active': instance.firstIndex() <= index && instance.lastIndex() >= index, 'p-carousel-item-start': instance.firstIndex() === index, 'p-carousel-item-end': instance.lastIndex() === index } ], pcNextButton: ({ instance }) => [ 'p-carousel-next-button', { 'p-disabled': instance.forwardIsDisabled } ], indicatorList: 'p-carousel-indicator-list', indicator: ({ instance, index }) => [ 'p-carousel-indicator', { 'p-carousel-indicator-active': instance.d_page === index } ], indicatorButton: 'p-carousel-indicator-button', footer: 'p-carousel-footer' }; class CarouselStyle extends BaseStyle { name = 'carousel'; theme = theme; classes = classes; static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: CarouselStyle, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: CarouselStyle }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: CarouselStyle, decorators: [{ type: Injectable }] }); /** * * Carousel is a content slider featuring various customization options. * * [Live Demo](https://www.primeng.org/carousel/) * * @module carouselstyle * */ var CarouselClasses; (function (CarouselClasses) { /** * Class name of the root element */ CarouselClasses["root"] = "p-carousel"; /** * Class name of the header element */ CarouselClasses["header"] = "p-carousel-header"; /** * Class name of the content container element */ CarouselClasses["contentContainer"] = "p-carousel-content-container"; /** * Class name of the content element */ CarouselClasses["content"] = "p-carousel-content"; /** * Class name of the previous button element */ CarouselClasses["pcPrevButton"] = "p-carousel-prev-button"; /** * Class name of the viewport element */ CarouselClasses["viewport"] = "p-carousel-viewport"; /** * Class name of the item list element */ CarouselClasses["itemList"] = "p-carousel-item-list"; /** * Class name of the item clone element */ CarouselClasses["itemClone"] = "p-carousel-item-clone"; /** * Class name of the item element */ CarouselClasses["item"] = "p-carousel-item"; /** * Class name of the next button element */ CarouselClasses["pcNextButton"] = "p-carousel-next-button"; /** * Class name of the indicator list element */ CarouselClasses["indicatorList"] = "p-carousel-indicator-list"; /** * Class name of the indicator element */ CarouselClasses["indicator"] = "p-carousel-indicator"; /** * Class name of the indicator button element */ CarouselClasses["indicatorButton"] = "p-carousel-indicator-button"; /** * Class name of the footer element */ CarouselClasses["footer"] = "p-carousel-footer"; })(CarouselClasses || (CarouselClasses = {})); /** * Carousel is a content slider featuring various customization options. * @group Components */ class Carousel extends BaseComponent { el; zone; /** * Index of the first item. * @defaultValue 0 * @group Props */ get page() { return this._page; } set page(val) { if (this.isCreated && val !== this._page) { if (this.autoplayInterval) { this.stopAutoplay(); } if (val > this._page && val <= this.totalDots() - 1) { this.step(-1, val); } else if (val < this._page) { this.step(1, val); } } this._page = val; } /** * Number of items per page. * @defaultValue 1 * @group Props */ get numVisible() { return this._numVisible; } set numVisible(val) { this._numVisible = val; } /** * Number of items to scroll. * @defaultValue 1 * @group Props */ get numScroll() { return this._numVisible; } set numScroll(val) { this._numScroll = val; } /** * An array of options for responsive design. * @see {CarouselResponsiveOptions} * @group Props */ responsiveOptions; /** * Specifies the layout of the component. * @group Props */ orientation = 'horizontal'; /** * Height of the viewport in vertical layout. * @group Props */ verticalViewPortHeight = '300px'; /** * Style class of main content. * @group Props */ contentClass = ''; /** * Style class of the indicator items. * @group Props */ indicatorsContentClass = ''; /** * Inline style of the indicator items. * @group Props */ indicatorsContentStyle; /** * Style class of the indicators. * @group Props */ indicatorStyleClass = ''; /** * Style of the indicators. * @group Props */ indicatorStyle; /** * An array of objects to display. * @defaultValue null * @group Props */ get value() { return this._value; } set value(val) { this._value = val; } /** * Defines if scrolling would be infinite. * @group Props */ circular = false; /** * Whether to display indicator container. * @group Props */ showIndicators = true; /** * Whether to display navigation buttons in container. * @group Props */ showNavigators = true; /** * Time in milliseconds to scroll items automatically. * @group Props */ autoplayInterval = 0; /** * Inline style of the component. * @group Props */ style; /** * Style class of the viewport container. * @group Props */ styleClass; /** * Used to pass all properties of the ButtonProps to the Button component. * @group Props */ prevButtonProps = { severity: 'secondary', text: true, rounded: true }; /** * Used to pass all properties of the ButtonProps to the Button component. * @group Props */ nextButtonProps = { severity: 'secondary', text: true, rounded: true }; /** * Callback to invoke after scroll. * @param {CarouselPageEvent} event - Custom page event. * @group Emits */ onPage = new EventEmitter(); itemsContainer; indicatorContent; headerFacet; footerFacet; _numVisible = 1; _numScroll = 1; _oldNumScroll = 0; prevState = { numScroll: 0, numVisible: 0, value: [] }; defaultNumScroll = 1; defaultNumVisible = 1; _page = 0; _value; carouselStyle; id; totalShiftedItems; isRemainingItemsAdded = false; animationTimeout; translateTimeout; remainingItems = 0; _items; startPos; documentResizeListener; clonedItemsForStarting; clonedItemsForFinishing; allowAutoplay; interval; isCreated; swipeThreshold = 20; /** * Template for carousel items. * @group Templates */ itemTemplate; /** * Template for the carousel header. * @group Templates */ headerTemplate; /** * Template for the carousel footer. * @group Templates */ footerTemplate; /** * Template for the previous button icon. * @group Templates */ previousIconTemplate; /** * Template for the next button icon. * @group Templates */ nextIconTemplate; _itemTemplate; _headerTemplate; _footerTemplate; _previousIconTemplate; _nextIconTemplate; window; _componentStyle = inject(CarouselStyle); constructor(el, zone) { super(); this.el = el; this.zone = zone; this.totalShiftedItems = this.page * this.numScroll * -1; this.window = this.document.defaultView; } ngOnChanges(simpleChange) { if (isPlatformBrowser(this.platformId)) { if (simpleChange.value) { if (this.circular && this._value) { this.setCloneItems(); } } if (this.isCreated) { if (simpleChange.numVisible) { if (this.responsiveOptions) { this.defaultNumVisible = this.numVisible; } if (this.isCircular()) { this.setCloneItems(); } this.createStyle(); this.calculatePosition(); } if (simpleChange.numScroll) { if (this.responsiveOptions) { this.defaultNumScroll = this.numScroll; } } } } this.cd.markForCheck(); } templates; ngAfterContentInit() { this.id = uuid('pn_id_'); if (isPlatformBrowser(this.platformId)) { this.allowAutoplay = !!this.autoplayInterval; if (this.circular) { this.setCloneItems(); } if (this.responsiveOptions) { this.defaultNumScroll = this._numScroll; this.defaultNumVisible = this._numVisible; } this.createStyle(); this.calculatePosition(); if (this.responsiveOptions) { this.bindDocumentListeners(); } } this.templates?.forEach((item) => { switch (item.getType()) { case 'item': this._itemTemplate = item.template; break; case 'header': this._headerTemplate = item.template; break; case 'footer': this._footerTemplate = item.template; break; case 'previousicon': this._previousIconTemplate = item.template; break; case 'nexticon': this._nextIconTemplate = item.template; break; default: this._itemTemplate = item.template; break; } }); this.cd.detectChanges(); } ngAfterContentChecked() { if (isPlatformBrowser(this.platformId)) { const isCircular = this.isCircular(); let totalShiftedItems = this.totalShiftedItems; if (this.value && this.itemsContainer && (this.prevState.numScroll !== this._numScroll || this.prevState.numVisible !== this._numVisible || this.prevState.value.length !== this.value.length)) { if (this.autoplayInterval) { this.stopAutoplay(false); } this.remainingItems = (this.value.length - this._numVisible) % this._numScroll; let page = this._page; if (this.totalDots() !== 0 && page >= this.totalDots()) { page = this.totalDots() - 1; this._page = page; this.onPage.emit({ page: this.page }); } totalShiftedItems = page * this._numScroll * -1; if (isCircular) { totalShiftedItems -= this._numVisible; } if (page === this.totalDots() - 1 && this.remainingItems > 0) { totalShiftedItems += -1 * this.remainingItems + this._numScroll; this.isRemainingItemsAdded = true; } else { this.isRemainingItemsAdded = false; } if (totalShiftedItems !== this.totalShiftedItems) { this.totalShiftedItems = totalShiftedItems; } this._oldNumScroll = this._numScroll; this.prevState.numScroll = this._numScroll; this.prevState.numVisible = this._numVisible; this.prevState.value = [...this._value]; if (this.totalDots() > 0 && this.itemsContainer.nativeElement) { this.itemsContainer.nativeElement.style.transform = this.isVertical() ? `translate3d(0, ${totalShiftedItems * (100 / this._numVisible)}%, 0)` : `translate3d(${totalShiftedItems * (100 / this._numVisible)}%, 0, 0)`; } this.isCreated = true; if (this.autoplayInterval && this.isAutoplay()) { this.startAutoplay(); } } if (isCircular) { if (this.page === 0) { totalShiftedItems = -1 * this._numVisible; } else if (totalShiftedItems === 0) { totalShiftedItems = -1 * this.value.length; if (this.remainingItems > 0) { this.isRemainingItemsAdded = true; } } if (totalShiftedItems !== this.totalShiftedItems) { this.totalShiftedItems = totalShiftedItems; } } } } createStyle() { if (!this.carouselStyle) { this.carouselStyle = this.renderer.createElement('style'); this.carouselStyle.type = 'text/css'; setAttribute(this.carouselStyle, 'nonce', this.config?.csp()?.nonce); this.renderer.appendChild(this.document.head, this.carouselStyle); } let innerHTML = ` #${this.id} .p-carousel-item { flex: 1 0 ${100 / this.numVisible}% } `; if (this.responsiveOptions) { this.responsiveOptions.sort((data1, data2) => { const value1 = data1.breakpoint; const value2 = data2.breakpoint; let result = null; if (value1 == null && value2 != null) result = -1; else if (value1 != null && value2 == null) result = 1; else if (value1 == null && value2 == null) result = 0; else if (typeof value1 === 'string' && typeof value2 === 'string') result = value1.localeCompare(value2, undefined, { numeric: true }); else result = value1 < value2 ? -1 : value1 > value2 ? 1 : 0; return -1 * result; }); for (let i = 0; i < this.responsiveOptions.length; i++) { let res = this.responsiveOptions[i]; innerHTML += ` @media screen and (max-width: ${res.breakpoint}) { #${this.id} .p-carousel-item { flex: 1 0 ${100 / res.numVisible}% } } `; } } this.carouselStyle.innerHTML = innerHTML; } calculatePosition() { if (this.responsiveOptions) { let matchedResponsiveData = { numVisible: this.defaultNumVisible, numScroll: this.defaultNumScroll }; if (typeof window !== 'undefined') { let windowWidth = window.innerWidth; for (let i = 0; i < this.responsiveOptions.length; i++) { let res = this.responsiveOptions[i]; if (parseInt(res.breakpoint, 10) >= windowWidth) { matchedResponsiveData = res; } } } if (this._numScroll !== matchedResponsiveData.numScroll) { let page = this._page; page = Math.floor((page * this._numScroll) / matchedResponsiveData.numScroll); let totalShiftedItems = matchedResponsiveData.numScroll * this.page * -1; if (this.isCircular()) { totalShiftedItems -= matchedResponsiveData.numVisible; } this.totalShiftedItems = totalShiftedItems; this._numScroll = matchedResponsiveData.numScroll; this._page = page; this.onPage.emit({ page: this.page }); } if (this._numVisible !== matchedResponsiveData.numVisible) { this._numVisible = matchedResponsiveData.numVisible; this.setCloneItems(); } this.cd.markForCheck(); } } setCloneItems() { this.clonedItemsForStarting = []; this.clonedItemsForFinishing = []; if (this.isCircular()) { this.clonedItemsForStarting.push(...this.value.slice(-1 * this._numVisible)); this.clonedItemsForFinishing.push(...this.value.slice(0, this._numVisible)); } } firstIndex() { return this.isCircular() ? -1 * (this.totalShiftedItems + this.numVisible) : this.totalShiftedItems * -1; } lastIndex() { return this.firstIndex() + this.numVisible - 1; } totalDots() { return this.value?.length ? Math.ceil((this.value.length - this._numVisible) / this._numScroll) + 1 : 0; } totalDotsArray() { const totalDots = this.totalDots(); return totalDots <= 0 ? [] : Array(totalDots).fill(0); } isVertical() { return this.orientation === 'vertical'; } isCircular() { return this.circular && this.value && this.value.length >= this.numVisible; } isAutoplay() { return this.autoplayInterval && this.allowAutoplay; } isForwardNavDisabled() { return this.isEmpty() || (this._page >= this.totalDots() - 1 && !this.isCircular()); } isBackwardNavDisabled() { return this.isEmpty() || (this._page <= 0 && !this.isCircular()); } isEmpty() { return !this.value || this.value.length === 0; } navForward(e, index) { if (this.isCircular() || this._page < this.totalDots() - 1) { this.step(-1, index); } if (this.autoplayInterval) { this.stopAutoplay(); } if (e && e.cancelable) { e.preventDefault(); } } navBackward(e, index) { if (this.isCircular() || this._page !== 0) { this.step(1, index); } if (this.autoplayInterval) { this.stopAutoplay(); } if (e && e.cancelable) { e.preventDefault(); } } onDotClick(e, index) { let page = this._page; if (this.autoplayInterval) { this.stopAutoplay(); } if (index > page) { this.navForward(e, index); } else if (index < page) { this.navBackward(e, index); } } onIndicatorKeydown(event) { switch (event.code) { case 'ArrowRight': this.onRightKey(); break; case 'ArrowLeft': this.onLeftKey(); break; } } onRightKey() { const indicators = [...find(this.indicatorContent.nativeElement, '[data-pc-section="indicator"]')]; const activeIndex = this.findFocusedIndicatorIndex(); this.changedFocusedIndicator(activeIndex, activeIndex + 1 === indicators.length ? indicators.length - 1 : activeIndex + 1); } onLeftKey() { const activeIndex = this.findFocusedIndicatorIndex(); this.changedFocusedIndicator(activeIndex, activeIndex - 1 <= 0 ? 0 : activeIndex - 1); } onHomeKey() { const activeIndex = this.findFocusedIndicatorIndex(); this.changedFocusedIndicator(activeIndex, 0); } onEndKey() { const indicators = [...find(this.indicatorContent.nativeElement, '[data-pc-section="indicator"]r')]; const activeIndex = this.findFocusedIndicatorIndex(); this.changedFocusedIndicator(activeIndex, indicators.length - 1); } onTabKey() { const indicators = [...find(this.indicatorContent.nativeElement, '[data-pc-section="indicator"]')]; const highlightedIndex = indicators.findIndex((ind) => getAttribute(ind, 'data-p-highlight') === true); const activeIndicator = findSingle(this.indicatorContent.nativeElement, '[data-pc-section="indicator"] > button[tabindex="0"]'); const activeIndex = indicators.findIndex((ind) => ind === activeIndicator.parentElement); indicators[activeIndex].children[0].tabIndex = '-1'; indicators[highlightedIndex].children[0].tabIndex = '0'; } findFocusedIndicatorIndex() { const indicators = [...find(this.indicatorContent.nativeElement, '[data-pc-section="indicator"]')]; const activeIndicator = findSingle(this.indicatorContent.nativeElement, '[data-pc-section="indicator"] > button[tabindex="0"]'); return indicators.findIndex((ind) => ind === activeIndicator.parentElement); } changedFocusedIndicator(prevInd, nextInd) { const indicators = [...find(this.indicatorContent.nativeElement, '[data-pc-section="indicator"]')]; indicators[prevInd].children[0].tabIndex = '-1'; indicators[nextInd].children[0].tabIndex = '0'; indicators[nextInd].children[0].focus(); } step(dir, page) { let totalShiftedItems = this.totalShiftedItems; const isCircular = this.isCircular(); if (page != null) { totalShiftedItems = this._numScroll * page * -1; if (isCircular) { totalShiftedItems -= this._numVisible; } this.isRemainingItemsAdded = false; } else { totalShiftedItems += this._numScroll * dir; if (this.isRemainingItemsAdded) { totalShiftedItems += this.remainingItems - this._numScroll * dir; this.isRemainingItemsAdded = false; } let originalShiftedItems = isCircular ? totalShiftedItems + this._numVisible : totalShiftedItems; page = Math.abs(Math.floor(originalShiftedItems / this._numScroll)); } if (isCircular && this.page === this.totalDots() - 1 && dir === -1) { totalShiftedItems = -1 * (this.value.length + this._numVisible); page = 0; } else if (isCircular && this.page === 0 && dir === 1) { totalShiftedItems = 0; page = this.totalDots() - 1; } else if (page === this.totalDots() - 1 && this.remainingItems > 0) { totalShiftedItems += this.remainingItems * -1 - this._numScroll * dir; this.isRemainingItemsAdded = true; } if (this.itemsContainer) { this.itemsContainer.nativeElement.style.transform = this.isVertical() ? `translate3d(0, ${totalShiftedItems * (100 / this._numVisible)}%, 0)` : `translate3d(${totalShiftedItems * (100 / this._numVisible)}%, 0, 0)`; this.itemsContainer.nativeElement.style.transition = 'transform 500ms ease 0s'; } this.totalShiftedItems = totalShiftedItems; this._page = page; this.onPage.emit({ page: this.page }); this.cd.markForCheck(); } startAutoplay() { this.interval = setInterval(() => { if (this.totalDots() > 0) { if (this.page === this.totalDots() - 1) { this.step(-1, 0); } else { this.step(-1, this.page + 1); } } }, this.autoplayInterval); this.allowAutoplay = true; this.cd.markForCheck(); } stopAutoplay(changeAllow = true) { if (this.interval) { clearInterval(this.interval); this.interval = undefined; if (changeAllow) { this.allowAutoplay = false; } } this.cd.markForCheck(); } isPlaying() { return !!this.interval; } onTransitionEnd() { if (this.itemsContainer) { this.itemsContainer.nativeElement.style.transition = ''; if ((this.page === 0 || this.page === this.totalDots() - 1) && this.isCircular()) { this.itemsContainer.nativeElement.style.transform = this.isVertical() ? `translate3d(0, ${this.totalShiftedItems * (100 / this._numVisible)}%, 0)` : `translate3d(${this.totalShiftedItems * (100 / this._numVisible)}%, 0, 0)`; } } } onTouchStart(e) { let touchobj = e.changedTouches[0]; this.startPos = { x: touchobj.pageX, y: touchobj.pageY }; } onTouchMove(e) { if (e.cancelable) { e.preventDefault(); } } onTouchEnd(e) { let touchobj = e.changedTouches[0]; if (this.isVertical()) { this.changePageOnTouch(e, touchobj.pageY - this.startPos.y); } else { this.changePageOnTouch(e, touchobj.pageX - this.startPos.x); } } changePageOnTouch(e, diff) { if (Math.abs(diff) > this.swipeThreshold) { if (diff < 0) { this.navForward(e); } else { this.navBackward(e); } } } ariaPrevButtonLabel() { return this.config.translation.aria ? this.config.translation.aria.prevPageLabel : undefined; } ariaSlideLabel() { return this.config.translation.aria ? this.config.translation.aria.slide : undefined; } ariaNextButtonLabel() { return this.config.translation.aria ? this.config.translation.aria.nextPageLabel : undefined; } ariaSlideNumber(value) { return this.config.translation.aria ? this.config.translation.aria.slideNumber.replace(/{slideNumber}/g, value) : undefined; } ariaPageLabel(value) { return this.config.translation.aria ? this.config.translation.aria.pageLabel.replace(/{page}/g, value) : undefined; } bindDocumentListeners() { if (isPlatformBrowser(this.platformId)) { if (!this.documentResizeListener) { this.documentResizeListener = this.renderer.listen(this.window, 'resize', (event) => { this.calculatePosition(); }); } } } unbindDocumentListeners() { if (isPlatformBrowser(this.platformId)) { if (this.documentResizeListener) { this.documentResizeListener(); this.documentResizeListener = null; } } } ngOnDestroy() { if (this.responsiveOptions) { this.unbindDocumentListeners(); } if (this.autoplayInterval) { this.stopAutoplay(); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: Carousel, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "19.2.5", type: Carousel, isStandalone: true, selector: "p-carousel", inputs: { page: "page", numVisible: "numVisible", numScroll: "numScroll", responsiveOptions: "responsiveOptions", orientation: "orientation", verticalViewPortHeight: "verticalViewPortHeight", contentClass: "contentClass", indicatorsContentClass: "indicatorsContentClass", indicatorsContentStyle: "indicatorsContentStyle", indicatorStyleClass: "indicatorStyleClass", indicatorStyle: "indicatorStyle", value: "value", circular: ["circular", "circular", booleanAttribute], showIndicators: ["showIndicators", "showIndicators", booleanAttribute], showNavigators: ["showNavigators", "showNavigators", booleanAttribute], autoplayInterval: ["autoplayInterval", "autoplayInterval", numberAttribute], style: "style", styleClass: "styleClass", prevButtonProps: "prevButtonProps", nextButtonProps: "nextButtonProps" }, outputs: { onPage: "onPage" }, providers: [CarouselStyle], queries: [{ propertyName: "headerFacet", first: true, predicate: Header, descendants: true }, { propertyName: "footerFacet", first: true, predicate: Footer, descendants: true }, { propertyName: "itemTemplate", first: true, predicate: ["item"] }, { propertyName: "headerTemplate", first: true, predicate: ["header"] }, { propertyName: "footerTemplate", first: true, predicate: ["footer"] }, { propertyName: "previousIconTemplate", first: true, predicate: ["previousicon"] }, { propertyName: "nextIconTemplate", first: true, predicate: ["nexticon"] }, { propertyName: "templates", predicate: PrimeTemplate }], viewQueries: [{ propertyName: "itemsContainer", first: true, predicate: ["itemsContainer"], descendants: true }, { propertyName: "indicatorContent", first: true, predicate: ["indicatorContent"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: ` <div [attr.id]="id" [ngClass]="{ 'p-carousel p-component': true, 'p-carousel-vertical': isVertical(), 'p-carousel-horizontal': !isVertical() }" [ngStyle]="style" [class]="styleClass" role="region"> <div class="p-carousel-header" *ngIf="headerFacet || headerTemplate"> <ng-content select="p-header"></ng-content> <ng-container *ngTemplateOutlet="headerTemplate"></ng-container> </div> <div [class]="contentClass" [ngClass]="'p-carousel-content-container'"> <div class="p-carousel-content" [attr.aria-live]="allowAutoplay ? 'polite' : 'off'"> <p-button *ngIf="showNavigators" [ngClass]="{ 'p-carousel-prev-button': true, 'p-disabled': isBackwardNavDisabled() }" [disabled]="isBackwardNavDisabled()" [attr.aria-label]="ariaPrevButtonLabel()" (click)="navBackward($event)" [text]="true" [buttonProps]="prevButtonProps" > <ng-template #icon> <ng-container *ngIf="!previousIconTemplate && !_previousIconTemplate && !prevButtonProps?.icon"> <ChevronLeftIcon *ngIf="!isVertical()" [styleClass]="'carousel-prev-icon'" /> <ChevronUpIcon *ngIf="isVertical()" [styleClass]="'carousel-prev-icon'" /> </ng-container> <span *ngIf="(previousIconTemplate || _previousIconTemplate) && !prevButtonProps?.icon" class="p-carousel-prev-icon"> <ng-template *ngTemplateOutlet="previousIconTemplate || _previousIconTemplate"></ng-template> </span> </ng-template> </p-button> <div class="p-carousel-viewport" [ngStyle]="{ height: isVertical() ? verticalViewPortHeight : 'auto' }" (touchend)="onTouchEnd($event)" (touchstart)="onTouchStart($event)" (touchmove)="onTouchMove($event)"> <div #itemsContainer class="p-carousel-item-list" (transitionend)="onTransitionEnd()"> <div *ngFor="let item of clonedItemsForStarting; let index = index" [ngClass]="{ 'p-carousel-item p-carousel-item-clone': true, 'p-carousel-item-active': totalShiftedItems * -1 === value.length, 'p-carousel-item-start': 0 === index, 'p-carousel-item-end': clonedItemsForStarting.length - 1 === index }" [attr.aria-hidden]="!(totalShiftedItems * -1 === value.length)" [attr.aria-label]="ariaSlideNumber(index)" [attr.aria-roledescription]="ariaSlideLabel()" > <ng-container *ngTemplateOutlet="itemTemplate || _itemTemplate; context: { $implicit: item }"></ng-container> </div> <div *ngFor="let item of value; let index = index" [ngClass]="{ 'p-carousel-item': true, 'p-carousel-item-active': firstIndex() <= index && lastIndex() >= index, 'p-carousel-item-start': firstIndex() === index, 'p-carousel-item-end': lastIndex() === index }" [attr.aria-hidden]="!(firstIndex() <= index && lastIndex() >= index)" [attr.aria-label]="ariaSlideNumber(index)" [attr.aria-roledescription]="ariaSlideLabel()" > <ng-container *ngTemplateOutlet="itemTemplate || _itemTemplate; context: { $implicit: item }"></ng-container> </div> <div *ngFor="let item of clonedItemsForFinishing; let index = index" [ngClass]="{ 'p-carousel-item p-carousel-item-clone': true, 'p-carousel-item-active': totalShiftedItems * -1 === numVisible, 'p-carousel-item-start': 0 === index, 'p-carousel-item-end': clonedItemsForFinishing.length - 1 === index }" > <ng-container *ngTemplateOutlet="itemTemplate || _itemTemplate; context: { $implicit: item }"></ng-container> </div> </div> </div> <p-button type="button" *ngIf="showNavigators" [ngClass]="{ 'p-carousel-next-button': true, 'p-disabled': isForwardNavDisabled() }" [disabled]="isForwardNavDisabled()" (click)="navForward($event)" [attr.aria-label]="ariaNextButtonLabel()" [buttonProps]="nextButtonProps" [text]="true" > <ng-template #icon> <ng-container *ngIf="!nextIconTemplate && !_nextIconTemplate && !nextButtonProps?.icon"> <ChevronRightIcon *ngIf="!isVertical()" [styleClass]="'carousel-next-icon'" /> <ChevronDownIcon *ngIf="isVertical()" [styleClass]="'carousel-next-icon'" /> </ng-container> <span *ngIf="nextIconTemplate || (_nextIconTemplate && !nextButtonProps?.icon)" class="next"> <ng-template *ngTemplateOutlet="nextIconTemplate || _nextIconTemplate"></ng-template> </span> </ng-template> </p-button> </div> <ul #indicatorContent [ngClass]="'p-carousel-indicator-list'" [class]="indicatorsContentClass" [ngStyle]="indicatorsContentStyle" *ngIf="showIndicators" (keydown)="onIndicatorKeydown($event)"> <li *ngFor="let totalDot of totalDotsArray(); let i = index" [ngClass]="{ 'p-carousel-indicator': true, 'p-carousel-indicator-active': _page === i }" [attr.data-pc-section]="'indicator'"> <button type="button" [ngClass]="'p-carousel-indicator-button'" (click)="onDotClick($event, i)" [class]="indicatorStyleClass" [ngStyle]="indicatorStyle" [attr.aria-label]="ariaPageLabel(i + 1)" [attr.aria-current]="_page === i ? 'page' : undefined" [tabindex]="_page === i ? 0 : -1" ></button> </li> </ul> </div> <div class="p-carousel-footer" *ngIf="footerFacet || footerTemplate || _footerTemplate"> <ng-content select="p-footer"></ng-content> <ng-container *ngTemplateOutlet="footerTemplate || _footerTemplate"></ng-container> </div> </div> `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: ChevronRightIcon, selector: "ChevronRightIcon" }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i2.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: ChevronLeftIcon, selector: "ChevronLeftIcon" }, { kind: "component", type: ChevronDownIcon, selector: "ChevronDownIcon" }, { kind: "component", type: ChevronUpIcon, selector: "ChevronUpIcon" }, { kind: "ngmodule", type: SharedModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: Carousel, decorators: [{ type: Component, args: [{ selector: 'p-carousel', standalone: true, imports: [CommonModule, ChevronRightIcon, ButtonModule, ChevronLeftIcon, ChevronDownIcon, ChevronUpIcon, SharedModule], template: ` <div [attr.id]="id" [ngClass]="{ 'p-carousel p-component': true, 'p-carousel-vertical': isVertical(), 'p-carousel-horizontal': !isVertical() }" [ngStyle]="style" [class]="styleClass" role="region"> <div class="p-carousel-header" *ngIf="headerFacet || headerTemplate"> <ng-content select="p-header"></ng-content> <ng-container *ngTemplateOutlet="headerTemplate"></ng-container> </div> <div [class]="contentClass" [ngClass]="'p-carousel-content-container'"> <div class="p-carousel-content" [attr.aria-live]="allowAutoplay ? 'polite' : 'off'"> <p-button *ngIf="showNavigators" [ngClass]="{ 'p-carousel-prev-button': true, 'p-disabled': isBackwardNavDisabled() }" [disabled]="isBackwardNavDisabled()" [attr.aria-label]="ariaPrevButtonLabel()" (click)="navBackward($event)" [text]="true" [buttonProps]="prevButtonProps" > <ng-template #icon> <ng-container *ngIf="!previousIconTemplate && !_previousIconTemplate && !prevButtonProps?.icon"> <ChevronLeftIcon *ngIf="!isVertical()" [styleClass]="'carousel-prev-icon'" /> <ChevronUpIcon *ngIf="isVertical()" [styleClass]="'carousel-prev-icon'" /> </ng-container> <span *ngIf="(previousIconTemplate || _previousIconTemplate) && !prevButtonProps?.icon" class="p-carousel-prev-icon"> <ng-template *ngTemplateOutlet="previousIconTemplate || _previousIconTemplate"></ng-template> </span> </ng-template> </p-button> <div class="p-carousel-viewport" [ngStyle]="{ height: isVertical() ? verticalViewPortHeight : 'auto' }" (touchend)="onTouchEnd($event)" (touchstart)="onTouchStart($event)" (touchmove)="onTouchMove($event)"> <div #itemsContainer class="p-carousel-item-list" (transitionend)="onTransitionEnd()"> <div *ngFor="let item of clonedItemsForStarting; let index = index" [ngClass]="{ 'p-carousel-item p-carousel-item-clone': true, 'p-carousel-item-active': totalShiftedItems * -1 === value.length, 'p-carousel-item-start': 0 === index, 'p-carousel-item-end': clonedItemsForStarting.length - 1 === index }" [attr.aria-hidden]="!(totalShiftedItems * -1 === value.length)" [attr.aria-label]="ariaSlideNumber(index)" [attr.aria-roledescription]="ariaSlideLabel()" > <ng-container *ngTemplateOutlet="itemTemplate || _itemTemplate; context: { $implicit: item }"></ng-container> </div> <div *ngFor="let item of value; let index = index" [ngClass]="{ 'p-carousel-item': true, 'p-carousel-item-active': firstIndex() <= index && lastIndex() >= index, 'p-carousel-item-start': firstIndex() === index, 'p-carousel-item-end': lastIndex() === index }" [attr.aria-hidden]="!(firstIndex() <= index && lastIndex() >= index)" [attr.aria-label]="ariaSlideNumber(index)" [attr.aria-roledescription]="ariaSlideLabel()" > <ng-container *ngTemplateOutlet="itemTemplate || _itemTemplate; context: { $implicit: item }"></ng-container> </div> <div *ngFor="let item of clonedItemsForFinishing; let index = index" [ngClass]="{ 'p-carousel-item p-carousel-item-clone': true, 'p-carousel-item-active': totalShiftedItems * -1 === numVisible, 'p-carousel-item-start': 0 === index, 'p-carousel-item-end': clonedItemsForFinishing.length - 1 === index }" > <ng-container *ngTemplateOutlet="itemTemplate || _itemTemplate; context: { $implicit: item }"></ng-container> </div> </div> </div> <p-button type="button" *ngIf="showNavigators" [ngClass]="{ 'p-carousel-next-button': true, 'p-disabled': isForwardNavDisabled() }" [disabled]="isForwardNavDisabled()" (click)="navForward($event)" [attr.aria-label]="ariaNextButtonLabel()" [buttonProps]="nextButtonProps" [text]="true" > <ng-template #icon> <ng-container *ngIf="!nextIconTemplate && !_nextIconTemplate && !nextButtonProps?.icon"> <ChevronRightIcon *ngIf="!isVertical()" [styleClass]="'carousel-next-icon'" /> <ChevronDownIcon *ngIf="isVertical()" [styleClass]="'carousel-next-icon'" /> </ng-container> <span *ngIf="nextIconTemplate || (_nextIconTemplate && !nextButtonProps?.icon)" class="next"> <ng-template *ngTemplateOutlet="nextIconTemplate || _nextIconTemplate"></ng-template> </span> </ng-template> </p-button> </div> <ul #indicatorContent [ngClass]="'p-carousel-indicator-list'" [class]="indicatorsContentClass" [ngStyle]="indicatorsContentStyle" *ngIf="showIndicators" (keydown)="o