primeng
Version:
PrimeNG is a premium UI library for Angular featuring a rich set of 90+ components, a theme designer, various theme alternatives such as Material, Bootstrap, Tailwind, premium templates and professional support. In addition, it integrates with PrimeBlock,
1 lines • 125 kB
Source Map (JSON)
{"version":3,"file":"primeng-galleria.mjs","sources":["../../src/galleria/galleria-token.ts","../../src/galleria/galleria-item-slot.ts","../../src/galleria/style/galleriastyle.ts","../../src/galleria/galleria-item.ts","../../src/galleria/galleria-thumbnails.ts","../../src/galleria/galleria-content.ts","../../src/galleria/galleria.ts","../../src/galleria/primeng-galleria.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\n\nexport const GALLERIA_INSTANCE = new InjectionToken<any>('GALLERIA_INSTANCE');\n","import { NgTemplateOutlet } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';\nimport { BaseComponent } from 'primeng/basecomponent';\nimport type { GalleriaPassThrough } from 'primeng/types/galleria';\nimport type { Galleria } from './galleria';\nimport { GALLERIA_INSTANCE } from './galleria-token';\n\n@Component({\n selector: 'div[pGalleriaItemSlot]',\n standalone: true,\n imports: [NgTemplateOutlet],\n template: `\n @if (shouldRender()) {\n <ng-container [ngTemplateOutlet]=\"contentTemplate()\" [ngTemplateOutletContext]=\"context()\"></ng-container>\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class GalleriaItemSlot extends BaseComponent<GalleriaPassThrough> {\n hostName: string = 'Galleria';\n\n index = input<number>();\n\n item = input<any>();\n\n type = input<string>();\n\n galleria = inject<Galleria>(GALLERIA_INSTANCE);\n\n $pcGalleria: Galleria | undefined = inject(GALLERIA_INSTANCE, { optional: true, skipSelf: true }) ?? undefined;\n\n contentTemplate = computed(() => {\n const type = this.type();\n switch (type) {\n case 'item':\n return this.galleria.itemTemplate();\n case 'caption':\n return this.galleria.captionTemplate();\n case 'thumbnail':\n return this.galleria.thumbnailTemplate();\n case 'indicator':\n return this.galleria.indicatorTemplate();\n case 'footer':\n return this.galleria.footerTemplate();\n case 'header':\n return this.galleria.headerTemplate();\n default:\n return this.galleria.itemTemplate();\n }\n });\n\n context = computed(() => {\n const type = this.type();\n if (type === 'indicator') {\n return { $implicit: this.index() };\n }\n return { $implicit: this.item() };\n });\n\n shouldRender() {\n return !!this.contentTemplate();\n }\n}\n","import { Injectable } from '@angular/core';\nimport { style } from '@primeuix/styles/galleria';\nimport { BaseStyle } from 'primeng/base';\n\nconst classes = {\n mask: 'p-galleria-mask p-overlay-mask',\n root: ({ instance }) => {\n const thumbnailsPosClass = instance.galleria.showThumbnails() && instance.getPositionClass('p-galleria-thumbnails', instance.galleria.thumbnailsPosition());\n const indicatorPosClass = instance.galleria.showIndicators() && instance.getPositionClass('p-galleria-indicators', instance.galleria.indicatorsPosition());\n\n return [\n 'p-galleria p-component',\n {\n 'p-galleria-fullscreen': instance.galleria.fullScreen(),\n 'p-galleria-inset-indicators': instance.galleria.showIndicatorsOnItem(),\n 'p-galleria-hover-navigators': instance.galleria.showItemNavigatorsOnHover() && !instance.galleria.fullScreen()\n },\n thumbnailsPosClass,\n indicatorPosClass\n ];\n },\n closeButton: 'p-galleria-close-button',\n closeIcon: 'p-galleria-close-icon',\n header: 'p-galleria-header',\n content: 'p-galleria-content',\n footer: 'p-galleria-footer',\n itemsContainer: 'p-galleria-items-container',\n items: 'p-galleria-items',\n prevButton: ({ instance }) => [\n 'p-galleria-prev-button p-galleria-nav-button',\n {\n 'p-disabled': instance.isNavBackwardDisabled()\n }\n ],\n prevIcon: 'p-galleria-prev-icon',\n item: 'p-galleria-item',\n nextButton: ({ instance }) => [\n 'p-galleria-next-button p-galleria-nav-button',\n {\n 'p-disabled': instance.isNavForwardDisabled()\n }\n ],\n nextIcon: 'p-galleria-next-icon',\n caption: 'p-galleria-caption',\n indicatorList: 'p-galleria-indicator-list',\n indicator: ({ instance, index }) => [\n 'p-galleria-indicator',\n {\n 'p-galleria-indicator-active': instance.isIndicatorItemActive(index)\n }\n ],\n indicatorButton: 'p-galleria-indicator-button',\n thumbnails: 'p-galleria-thumbnails',\n thumbnailContent: 'p-galleria-thumbnails-content',\n thumbnailPrevButton: ({ instance }) => [\n 'p-galleria-thumbnail-prev-button p-galleria-thumbnail-nav-button',\n {\n 'p-disabled': instance.isNavBackwardDisabled()\n }\n ],\n thumbnailPrevIcon: 'p-galleria-thumbnail-prev-icon',\n thumbnailsViewport: 'p-galleria-thumbnails-viewport',\n thumbnailItems: 'p-galleria-thumbnail-items',\n thumbnailItem: ({ instance, index, activeIndex }) => [\n 'p-galleria-thumbnail-item',\n {\n 'p-galleria-thumbnail-item-current': activeIndex === index,\n 'p-galleria-thumbnail-item-active': instance.isItemActive(index),\n 'p-galleria-thumbnail-item-start': instance.firstItemAciveIndex() === index,\n 'p-galleria-thumbnail-item-end': instance.lastItemActiveIndex() === index\n }\n ],\n thumbnail: 'p-galleria-thumbnail',\n thumbnailNextButton: ({ instance }) => [\n 'p-galleria-thumbnail-next-button p-galleria-thumbnail-nav-button',\n {\n 'p-disabled': instance.isNavForwardDisabled()\n }\n ],\n thumbnailNextIcon: 'p-galleria-thumbnail-next-icon'\n};\n\n@Injectable()\nexport class GalleriaStyle extends BaseStyle {\n name = 'galleria';\n\n style = style;\n\n classes = classes;\n}\n\n/**\n *\n * Galleria is an advanced content gallery component.\n *\n * [Live Demo](https://www.primeng.org/galleria/)\n *\n * @module galleriastyle\n *\n */\nexport enum GalleriaClasses {\n /**\n * Class name of the mask element\n */\n mask = 'p-galleria-mask',\n /**\n * Class name of the root element\n */\n root = 'p-galleria',\n /**\n * Class name of the close button element\n */\n closeButton = 'p-galleria-close-button',\n /**\n * Class name of the close icon element\n */\n closeIcon = 'p-galleria-close-icon',\n /**\n * Class name of the header element\n */\n header = 'p-galleria-header',\n /**\n * Class name of the content element\n */\n content = 'p-galleria-content',\n /**\n * Class name of the footer element\n */\n footer = 'p-galleria-footer',\n /**\n * Class name of the items container element\n */\n itemsContainer = 'p-galleria-items-container',\n /**\n * Class name of the items element\n */\n items = 'p-galleria-items',\n /**\n * Class name of the previous item button element\n */\n prevButton = 'p-galleria-prev-button',\n /**\n * Class name of the previous item icon element\n */\n prevIcon = 'p-galleria-prev-icon',\n /**\n * Class name of the item element\n */\n item = 'p-galleria-item',\n /**\n * Class name of the next item button element\n */\n nextButton = 'p-galleria-next-button',\n /**\n * Class name of the next item icon element\n */\n nextIcon = 'p-galleria-next-icon',\n /**\n * Class name of the caption element\n */\n caption = 'p-galleria-caption',\n /**\n * Class name of the indicator list element\n */\n indicatorList = 'p-galleria-indicator-list',\n /**\n * Class name of the indicator element\n */\n indicator = 'p-galleria-indicator',\n /**\n * Class name of the indicator button element\n */\n indicatorButton = 'p-galleria-indicator-button',\n /**\n * Class name of the thumbnails element\n */\n thumbnails = 'p-galleria-thumbnails',\n /**\n * Class name of the thumbnail content element\n */\n thumbnailContent = 'p-galleria-thumbnails-content',\n /**\n * Class name of the previous thumbnail button element\n */\n previousThumbnailButton = 'p-galleria-thumbnail-prev-button',\n /**\n * Class name of the previous thumbnail icon element\n */\n previousThumbnailIcon = 'p-galleria-thumbnail-prev-icon',\n /**\n * Class name of the thumbnails viewport element\n */\n thumbnailsViewport = 'p-galleria-thumbnails-viewport',\n /**\n * Class name of the thumbnail items element\n */\n thumbnailItems = 'p-galleria-thumbnail-items',\n /**\n * Class name of the thumbnail item element\n */\n thumbnailItem = 'p-galleria-thumbnail-item',\n /**\n * Class name of the thumbnail element\n */\n thumbnail = 'p-galleria-thumbnail',\n /**\n * Class name of the next thumbnail button element\n */\n nextThumbnailButton = 'p-galleria-thumbnail-next-button',\n /**\n * Class name of the next thumbnail icon element\n */\n nextThumbnailIcon = 'p-galleria-thumbnail-next-icon'\n}\n\nexport interface GalleriaStyle extends BaseStyle {}\n","import { NgTemplateOutlet } from '@angular/common';\nimport { booleanAttribute, ChangeDetectionStrategy, Component, computed, effect, inject, input, linkedSignal, output } from '@angular/core';\nimport { BaseComponent } from 'primeng/basecomponent';\nimport { Bind, BindModule } from 'primeng/bind';\nimport { ChevronLeft as ChevronLeftIcon } from '@primeicons/angular/chevron-left';\nimport { ChevronRight as ChevronRightIcon } from '@primeicons/angular/chevron-right';\nimport type { GalleriaPassThrough } from 'primeng/types/galleria';\nimport type { Galleria } from './galleria';\nimport { GalleriaItemSlot } from './galleria-item-slot';\nimport { GALLERIA_INSTANCE } from './galleria-token';\nimport { GalleriaStyle } from './style/galleriastyle';\n\n@Component({\n selector: 'div[pGalleriaItem]',\n standalone: true,\n imports: [NgTemplateOutlet, BindModule, ChevronLeftIcon, ChevronRightIcon, GalleriaItemSlot],\n template: `\n <div [pBind]=\"ptm('items')\" [class]=\"cx('items')\">\n @if (showItemNavigators()) {\n <button type=\"button\" role=\"navigation\" [pBind]=\"ptm('prevButton')\" [class]=\"cx('prevButton')\" (click)=\"navBackward($event)\" (focus)=\"onButtonFocus('left')\" (blur)=\"onButtonBlur('left')\" data-pc-group-section=\"itemnavigator\">\n @if (!galleria.itemPreviousIconTemplate()) {\n <svg data-p-icon=\"chevron-left\" [pBind]=\"ptm('prevIcon')\" [class]=\"cx('prevIcon')\" />\n }\n <ng-template [ngTemplateOutlet]=\"galleria.itemPreviousIconTemplate()\"></ng-template>\n </button>\n }\n <div\n pGalleriaItemSlot\n [pBind]=\"ptm('item')\"\n [unstyled]=\"unstyled()\"\n [class]=\"cx('item')\"\n [item]=\"activeItem()\"\n [id]=\"activeItemId()\"\n role=\"group\"\n [attr.aria-label]=\"ariaSlideNumber(_activeIndex() + 1)\"\n [attr.aria-roledescription]=\"ariaSlideLabel()\"\n ></div>\n @if (showItemNavigators()) {\n <button type=\"button\" [pBind]=\"ptm('nextButton')\" [class]=\"cx('nextButton')\" (click)=\"navForward($event)\" role=\"navigation\" (focus)=\"onButtonFocus('right')\" (blur)=\"onButtonBlur('right')\" data-pc-group-section=\"itemnavigator\">\n @if (!galleria.itemNextIconTemplate()) {\n <svg data-p-icon=\"chevron-right\" [pBind]=\"ptm('nextIcon')\" [class]=\"cx('nextIcon')\" />\n }\n <ng-template [ngTemplateOutlet]=\"galleria.itemNextIconTemplate()\"></ng-template>\n </button>\n }\n @if (galleria.captionTemplate()) {\n <div pGalleriaItemSlot [pBind]=\"ptm('caption')\" [unstyled]=\"unstyled()\" [class]=\"cx('caption')\" type=\"caption\" [item]=\"activeItem()\"></div>\n }\n </div>\n @if (showIndicators()) {\n <ul [pBind]=\"ptm('indicatorList')\" [class]=\"cx('indicatorList')\">\n @for (item of value(); track $index) {\n <li\n [pBind]=\"getIndicatorPTOptions($index)\"\n tabindex=\"0\"\n (click)=\"onIndicatorClick($index)\"\n (mouseenter)=\"onIndicatorMouseEnter($index)\"\n (keydown)=\"onIndicatorKeyDown($event, $index)\"\n [class]=\"cx('indicator', { index: $index })\"\n [attr.aria-label]=\"ariaPageLabel($index + 1)\"\n [attr.aria-selected]=\"_activeIndex() === $index\"\n [attr.aria-controls]=\"id() + '_item_' + $index\"\n [pBind]=\"ptm('indicator', getIndicatorPTOptions($index))\"\n [attr.data-p-active]=\"isIndicatorItemActive($index)\"\n >\n @if (!galleria.indicatorTemplate()) {\n <button type=\"button\" tabIndex=\"-1\" [pBind]=\"ptm('indicatorButton', getIndicatorPTOptions($index))\" [class]=\"cx('indicatorButton')\"></button>\n } @else {\n <div pGalleriaItemSlot type=\"indicator\" [index]=\"$index\" [pBind]=\"ptm('item')\" [unstyled]=\"unstyled()\"></div>\n }\n </li>\n }\n </ul>\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [GalleriaStyle],\n hostDirectives: [Bind]\n})\nexport class GalleriaItem extends BaseComponent<GalleriaPassThrough> {\n hostName: string = 'Galleria';\n\n galleria = inject<Galleria>(GALLERIA_INSTANCE);\n\n bindDirectiveInstance = inject(Bind, { self: true });\n\n onAfterViewChecked() {\n this.bindDirectiveInstance.setAttrs(this.ptm('itemsContainer'));\n }\n\n id = input<string>();\n\n circular = input(false, { transform: booleanAttribute });\n\n value = input<any[]>();\n\n showItemNavigators = input(false, { transform: booleanAttribute });\n\n showIndicators = input(true, { transform: booleanAttribute });\n\n slideShowActive = input(true, { transform: booleanAttribute });\n\n changeItemOnIndicatorHover = input(true, { transform: booleanAttribute });\n\n autoPlay = input(false, { transform: booleanAttribute });\n\n startSlideShow = output<void>();\n\n stopSlideShow = output<void>();\n\n onActiveIndexChange = output<number>();\n\n _componentStyle = inject(GalleriaStyle);\n\n _activeIndex = linkedSignal(() => this.activeIndexInput());\n\n activeItem = computed(() => {\n const val = this.value();\n return val && val[this._activeIndex()];\n });\n\n activeItemId = computed(() => this.id() + '_item_' + this._activeIndex());\n\n leftButtonFocused = false;\n\n rightButtonFocused = false;\n\n private get aria() {\n return this.galleria.config.translation.aria;\n }\n\n constructor() {\n super();\n\n // Handle autoPlay changes\n effect(() => {\n const auto = this.autoPlay();\n if (auto) {\n this.startSlideShow.emit();\n }\n });\n }\n\n activeIndexInput = input<number>(0, { alias: 'activeIndex' });\n\n getIndicatorPTOptions(index: number) {\n return this.ptm('indicator', {\n context: {\n highlighted: this._activeIndex() === index\n }\n });\n }\n\n next() {\n const val = this.value();\n const currentIndex = this._activeIndex();\n let nextItemIndex = currentIndex + 1;\n let activeIndex = this.circular() && val!.length - 1 === currentIndex ? 0 : nextItemIndex;\n this.onActiveIndexChange.emit(activeIndex);\n }\n\n prev() {\n const val = this.value();\n const currentIndex = this._activeIndex();\n let prevItemIndex = currentIndex !== 0 ? currentIndex - 1 : 0;\n let activeIndex = this.circular() && currentIndex === 0 ? val!.length - 1 : prevItemIndex;\n this.onActiveIndexChange.emit(activeIndex);\n }\n\n onButtonFocus(pos: 'left' | 'right') {\n if (pos === 'left') {\n this.leftButtonFocused = true;\n } else this.rightButtonFocused = true;\n }\n\n onButtonBlur(pos: 'left' | 'right') {\n if (pos === 'left') {\n this.leftButtonFocused = false;\n } else this.rightButtonFocused = false;\n }\n\n stopTheSlideShow() {\n if (this.slideShowActive()) {\n this.stopSlideShow.emit();\n }\n }\n\n navForward(e: MouseEvent) {\n this.stopTheSlideShow();\n this.next();\n\n if (e && e.cancelable) {\n e.stopPropagation();\n e.preventDefault();\n }\n }\n\n navBackward(e: MouseEvent) {\n this.stopTheSlideShow();\n this.prev();\n\n if (e && e.cancelable) {\n e.stopPropagation();\n e.preventDefault();\n }\n }\n\n onIndicatorClick(index: number) {\n this.stopTheSlideShow();\n this.onActiveIndexChange.emit(index);\n }\n\n onIndicatorMouseEnter(index: number) {\n if (this.changeItemOnIndicatorHover()) {\n this.stopTheSlideShow();\n this.onActiveIndexChange.emit(index);\n }\n }\n\n onIndicatorKeyDown(event: KeyboardEvent, index: number) {\n switch (event.code) {\n case 'Enter':\n case 'Space':\n this.stopTheSlideShow();\n this.onActiveIndexChange.emit(index);\n event.preventDefault();\n break;\n\n case 'ArrowDown':\n case 'ArrowUp':\n event.preventDefault();\n break;\n\n default:\n break;\n }\n }\n\n isNavForwardDisabled() {\n const val = this.value();\n return !this.circular() && this._activeIndex() === val!.length - 1;\n }\n\n isNavBackwardDisabled() {\n return !this.circular() && this._activeIndex() === 0;\n }\n\n isIndicatorItemActive(index: number) {\n return this._activeIndex() === index;\n }\n\n ariaSlideLabel() {\n return this.aria?.slide;\n }\n\n ariaSlideNumber(value: any) {\n return this.aria?.slideNumber?.replace(/{slideNumber}/g, value);\n }\n\n ariaPageLabel(value: any) {\n return this.aria?.pageLabel?.replace(/{page}/g, value);\n }\n}\n","import { isPlatformBrowser, NgTemplateOutlet } from '@angular/common';\nimport { booleanAttribute, ChangeDetectionStrategy, Component, computed, ElementRef, inject, input, linkedSignal, output, viewChild } from '@angular/core';\nimport { addClass, find, findSingle, focus, getAttribute, removeClass, setAttribute } from '@primeuix/utils';\nimport { BaseComponent } from 'primeng/basecomponent';\nimport { Bind, BindModule } from 'primeng/bind';\nimport { ChevronDown as ChevronDownIcon } from '@primeicons/angular/chevron-down';\nimport { ChevronLeft as ChevronLeftIcon } from '@primeicons/angular/chevron-left';\nimport { ChevronRight as ChevronRightIcon } from '@primeicons/angular/chevron-right';\nimport { ChevronUp as ChevronUpIcon } from '@primeicons/angular/chevron-up';\nimport { Ripple } from 'primeng/ripple';\nimport { VoidListener } from 'primeng/ts-helpers';\nimport type { GalleriaPassThrough, GalleriaResponsiveOptions } from 'primeng/types/galleria';\nimport type { Galleria } from './galleria';\nimport { GalleriaItemSlot } from './galleria-item-slot';\nimport { GALLERIA_INSTANCE } from './galleria-token';\nimport { GalleriaStyle } from './style/galleriastyle';\n\n@Component({\n selector: 'div[pGalleriaThumbnails]',\n standalone: true,\n imports: [NgTemplateOutlet, BindModule, Ripple, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ChevronDownIcon, GalleriaItemSlot],\n template: `\n <div [pBind]=\"ptm('thumbnailContent')\" [class]=\"cx('thumbnailContent')\">\n @if (showThumbnailNavigators()) {\n <button type=\"button\" [pBind]=\"ptm('thumbnailPrevButton')\" [class]=\"cx('thumbnailPrevButton')\" (click)=\"navBackward($event)\" pRipple [attr.aria-label]=\"ariaPrevButtonLabel()\" data-pc-group-section=\"thumbnailnavigator\">\n @if (!galleria.previousThumbnailIconTemplate()) {\n @if (!isVertical()) {\n <svg data-p-icon=\"chevron-left\" [pBind]=\"ptm('thumbnailPrevIcon')\" [class]=\"cx('thumbnailPrevIcon')\" />\n } @else {\n <svg data-p-icon=\"chevron-up\" [pBind]=\"ptm('thumbnailPrevIcon')\" [class]=\"cx('thumbnailPrevIcon')\" />\n }\n }\n <ng-template [ngTemplateOutlet]=\"galleria.previousThumbnailIconTemplate()\"></ng-template>\n </button>\n }\n <div [pBind]=\"ptm('thumbnailsViewport')\" [class]=\"cx('thumbnailsViewport')\" [style.height]=\"viewportHeight()\">\n <div #itemsContainer [pBind]=\"ptm('thumbnailItems')\" [class]=\"cx('thumbnailItems')\" (transitionend)=\"onTransitionEnd()\" (touchstart)=\"onTouchStart($event)\" (touchmove)=\"onTouchMove($event)\" role=\"tablist\">\n @for (item of value(); track $index) {\n <div\n [pBind]=\"ptm('thumbnailItem')\"\n [class]=\"cx('thumbnailItem', { index: $index, activeIndex: _activeIndex() })\"\n [attr.aria-selected]=\"isActiveItem($index)\"\n [attr.aria-controls]=\"getAriaControls($index)\"\n (keydown)=\"onThumbnailKeydown($event, $index)\"\n [attr.data-p-active]=\"isActiveItem($index)\"\n >\n <div\n [pBind]=\"ptm('thumbnail')\"\n [class]=\"cx('thumbnail')\"\n [attr.tabindex]=\"getItemTabIndex($index)\"\n [attr.aria-current]=\"getAriaCurrent($index)\"\n [attr.aria-label]=\"ariaPageLabel($index + 1)\"\n (click)=\"onItemClick($index)\"\n (touchend)=\"onItemClick($index)\"\n (keydown.enter)=\"onItemClick($index)\"\n >\n <div pGalleriaItemSlot type=\"thumbnail\" [pBind]=\"ptm('thumbnailItem')\" [item]=\"item\" [unstyled]=\"unstyled()\"></div>\n </div>\n </div>\n }\n </div>\n </div>\n @if (showThumbnailNavigators()) {\n <button type=\"button\" [pBind]=\"ptm('thumbnailNextButton')\" [class]=\"cx('thumbnailNextButton')\" (click)=\"navForward($event)\" pRipple [attr.aria-label]=\"ariaNextButtonLabel()\" data-pc-group-section=\"thumbnailnavigator\">\n @if (!galleria.nextThumbnailIconTemplate()) {\n @if (!isVertical()) {\n <svg data-p-icon=\"chevron-right\" [pBind]=\"ptm('thumbnailNextIcon')\" [class]=\"cx('thumbnailNextIcon')\" />\n } @else {\n <svg data-p-icon=\"chevron-down\" [pBind]=\"ptm('thumbnailNextIcon')\" [class]=\"cx('thumbnailNextIcon')\" />\n }\n }\n <ng-template [ngTemplateOutlet]=\"galleria.nextThumbnailIconTemplate()\"></ng-template>\n </button>\n }\n </div>\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [GalleriaStyle],\n host: {\n '[class]': 'cx(\"thumbnails\")'\n },\n hostDirectives: [Bind]\n})\nexport class GalleriaThumbnails extends BaseComponent<GalleriaPassThrough> {\n hostName: string = 'Galleria';\n\n galleria = inject<Galleria>(GALLERIA_INSTANCE);\n\n bindDirectiveInstance = inject(Bind, { self: true });\n\n onAfterViewChecked() {\n this.bindDirectiveInstance.setAttrs(this.ptm('thumbnails'));\n }\n\n containerId = input<string>();\n\n value = input<any[]>();\n\n isVertical = input(false, { transform: booleanAttribute });\n\n slideShowActive = input(false, { transform: booleanAttribute });\n\n circular = input(false, { transform: booleanAttribute });\n\n responsiveOptions = input<GalleriaResponsiveOptions[]>();\n\n contentHeight = input('300px');\n\n showThumbnailNavigators = input(true, { transform: booleanAttribute });\n\n numVisibleInput = input<number>(0, { alias: 'numVisible' });\n\n activeIndexInput = input<number>(0, { alias: 'activeIndex' });\n\n onActiveIndexChange = output<number>();\n\n stopSlideShow = output<void>();\n\n itemsContainer = viewChild<ElementRef>('itemsContainer');\n\n index: number | undefined;\n\n startPos: { x: number; y: number } | null = null;\n\n thumbnailsStyle: HTMLStyleElement | null = null;\n\n sortedResponsiveOptions: GalleriaResponsiveOptions[] | null = null;\n\n totalShiftedItems: number = 0;\n\n page: number = 0;\n\n documentResizeListener: VoidListener;\n\n _numVisible = linkedSignal(() => this.numVisibleInput());\n\n _oldNumVisible = 0;\n\n d_numVisible = linkedSignal<number, number>({\n source: () => this.numVisibleInput(),\n computation: (source, previous) => {\n if (previous) {\n this._oldNumVisible = previous.value;\n }\n return source;\n }\n });\n\n _oldactiveIndex = 0;\n\n _activeIndex = linkedSignal<number, number>({\n source: () => this.activeIndexInput(),\n computation: (source, previous) => {\n if (previous) {\n this._oldactiveIndex = previous.value;\n }\n return source;\n }\n });\n\n _componentStyle = inject(GalleriaStyle);\n\n viewportHeight = computed(() => (this.isVertical() ? this.contentHeight() : ''));\n\n private get aria() {\n return this.galleria.config.translation.aria;\n }\n\n isActiveItem(index: number) {\n return this._activeIndex() === index;\n }\n\n getItemTabIndex(index: number) {\n return this.isActiveItem(index) ? 0 : -1;\n }\n\n getAriaCurrent(index: number) {\n return this.isActiveItem(index) ? 'page' : undefined;\n }\n\n getAriaControls(index: number) {\n return this.containerId() + '_item_' + index;\n }\n\n onInit() {\n if (isPlatformBrowser(this.platformId)) {\n this.createStyle();\n\n if (this.responsiveOptions()) {\n this.bindDocumentListeners();\n }\n }\n }\n\n onAfterContentChecked() {\n let totalShiftedItems = this.totalShiftedItems;\n const d_numVisible = this.d_numVisible();\n const activeIndex = this._activeIndex();\n const itemsContainer = this.itemsContainer();\n const val = this.value();\n\n if ((this._oldNumVisible !== d_numVisible || this._oldactiveIndex !== activeIndex) && itemsContainer) {\n if (activeIndex <= this.getMedianItemIndex()) {\n totalShiftedItems = 0;\n } else if (val!.length - d_numVisible + this.getMedianItemIndex() < activeIndex) {\n totalShiftedItems = d_numVisible - val!.length;\n } else if (val!.length - d_numVisible < activeIndex && d_numVisible % 2 === 0) {\n totalShiftedItems = activeIndex * -1 + this.getMedianItemIndex() + 1;\n } else {\n totalShiftedItems = activeIndex * -1 + this.getMedianItemIndex();\n }\n\n if (totalShiftedItems !== this.totalShiftedItems) {\n this.totalShiftedItems = totalShiftedItems;\n }\n\n if (itemsContainer && itemsContainer.nativeElement) {\n itemsContainer.nativeElement.style.transform = this.isVertical() ? `translate3d(0, ${totalShiftedItems * (100 / d_numVisible)}%, 0)` : `translate3d(${totalShiftedItems * (100 / d_numVisible)}%, 0, 0)`;\n }\n\n if (this._oldactiveIndex !== activeIndex) {\n this.document.body.setAttribute('data-p-items-hidden', 'false');\n !this.$unstyled() && removeClass(itemsContainer.nativeElement, 'p-items-hidden');\n itemsContainer.nativeElement.style.transition = 'transform 500ms ease 0s';\n }\n\n this._oldactiveIndex = activeIndex;\n this._oldNumVisible = d_numVisible;\n }\n }\n\n onAfterViewInit() {\n if (isPlatformBrowser(this.platformId)) {\n this.calculatePosition();\n }\n }\n\n createStyle() {\n if (!this.thumbnailsStyle) {\n this.thumbnailsStyle = this.document.createElement('style');\n setAttribute(this.thumbnailsStyle, 'nonce', this.galleria.config?.csp()?.nonce);\n this.document.body.appendChild(this.thumbnailsStyle);\n }\n\n const d_numVisible = this.d_numVisible();\n let innerHTML = `\n #${this.containerId()} .p-galleria-thumbnail-item {\n flex: 1 0 ${100 / d_numVisible}%\n }\n `;\n\n const responsiveOptions = this.responsiveOptions();\n if (responsiveOptions && !this.$unstyled()) {\n this.sortedResponsiveOptions = [...responsiveOptions];\n this.sortedResponsiveOptions.sort((data1, data2) => {\n const value1 = data1.breakpoint;\n const value2 = data2.breakpoint;\n let result: number;\n\n if (value1 == null && value2 != null) result = -1;\n else if (value1 != null && value2 == null) result = 1;\n else if (value1 == null && value2 == null) result = 0;\n else if (typeof value1 === 'string' && typeof value2 === 'string') result = value1.localeCompare(value2, undefined, { numeric: true });\n else result = value1 < value2 ? -1 : value1 > value2 ? 1 : 0;\n\n return -1 * result;\n });\n\n for (let i = 0; i < this.sortedResponsiveOptions.length; i++) {\n let res = this.sortedResponsiveOptions[i];\n\n innerHTML += `\n @media screen and (max-width: ${res.breakpoint}) {\n #${this.containerId()} .p-galleria-thumbnail-item {\n flex: 1 0 ${100 / res.numVisible}%\n }\n }\n `;\n }\n }\n\n this.thumbnailsStyle.innerHTML = innerHTML;\n setAttribute(this.thumbnailsStyle, 'nonce', this.galleria.config?.csp()?.nonce);\n }\n\n calculatePosition() {\n if (isPlatformBrowser(this.platformId)) {\n const itemsContainer = this.itemsContainer();\n if (itemsContainer && this.sortedResponsiveOptions) {\n let windowWidth = window.innerWidth;\n let matchedResponsiveData = {\n numVisible: this._numVisible()\n };\n\n for (let i = 0; i < this.sortedResponsiveOptions.length; i++) {\n let res = this.sortedResponsiveOptions[i];\n\n if (parseInt(res.breakpoint, 10) >= windowWidth) {\n matchedResponsiveData = res;\n }\n }\n\n if (this.d_numVisible() !== matchedResponsiveData.numVisible) {\n this.d_numVisible.set(matchedResponsiveData.numVisible);\n }\n }\n }\n }\n\n getTabIndex(index: number) {\n return this.isItemActive(index) ? 0 : null;\n }\n\n navForward(e: TouchEvent | MouseEvent) {\n this.stopTheSlideShow();\n\n const activeIndex = this._activeIndex();\n const val = this.value();\n let nextItemIndex = activeIndex + 1;\n if (nextItemIndex + this.totalShiftedItems > this.getMedianItemIndex() && (-1 * this.totalShiftedItems < this.getTotalPageNumber() - 1 || this.circular())) {\n this.step(-1);\n }\n\n let newActiveIndex = this.circular() && val!.length - 1 === activeIndex ? 0 : nextItemIndex;\n this.onActiveIndexChange.emit(newActiveIndex);\n\n if (e.cancelable) {\n e.preventDefault();\n }\n }\n\n navBackward(e: TouchEvent | MouseEvent) {\n this.stopTheSlideShow();\n\n const activeIndex = this._activeIndex();\n const val = this.value();\n let prevItemIndex = activeIndex !== 0 ? activeIndex - 1 : 0;\n let diff = prevItemIndex + this.totalShiftedItems;\n if (this.d_numVisible() - diff - 1 > this.getMedianItemIndex() && (-1 * this.totalShiftedItems !== 0 || this.circular())) {\n this.step(1);\n }\n\n let newActiveIndex = this.circular() && activeIndex === 0 ? val!.length - 1 : prevItemIndex;\n this.onActiveIndexChange.emit(newActiveIndex);\n\n if (e.cancelable) {\n e.preventDefault();\n }\n }\n\n onItemClick(index: number) {\n this.stopTheSlideShow();\n\n const activeIndex = this._activeIndex();\n let selectedItemIndex = index;\n if (selectedItemIndex !== activeIndex) {\n const diff = selectedItemIndex + this.totalShiftedItems;\n let dir = 0;\n if (selectedItemIndex < activeIndex) {\n dir = this.d_numVisible() - diff - 1 - this.getMedianItemIndex();\n if (dir > 0 && -1 * this.totalShiftedItems !== 0) {\n this.step(dir);\n }\n } else {\n dir = this.getMedianItemIndex() - diff;\n if (dir < 0 && -1 * this.totalShiftedItems < this.getTotalPageNumber() - 1) {\n this.step(dir);\n }\n }\n\n this._activeIndex.set(selectedItemIndex);\n this.onActiveIndexChange.emit(selectedItemIndex);\n }\n }\n\n onThumbnailKeydown(event: KeyboardEvent, index: number) {\n if (event.code === 'Enter' || event.code === 'Space') {\n this.onItemClick(index);\n event.preventDefault();\n }\n\n switch (event.code) {\n case 'ArrowRight':\n this.onRightKey();\n break;\n\n case 'ArrowLeft':\n this.onLeftKey();\n break;\n\n case 'Home':\n this.onHomeKey();\n event.preventDefault();\n break;\n\n case 'End':\n this.onEndKey();\n event.preventDefault();\n break;\n\n case 'ArrowUp':\n case 'ArrowDown':\n event.preventDefault();\n break;\n\n case 'Tab':\n this.onTabKey();\n break;\n\n default:\n break;\n }\n }\n\n onRightKey() {\n const itemsContainer = this.itemsContainer();\n const indicators = find(itemsContainer?.nativeElement, '[data-pc-section=\"thumbnailitem\"]');\n const activeIndex = this.findFocusedIndicatorIndex();\n\n this.changedFocusedIndicator(activeIndex, activeIndex + 1 === indicators.length ? indicators.length - 1 : activeIndex + 1);\n }\n\n onLeftKey() {\n const activeIndex = this.findFocusedIndicatorIndex();\n\n this.changedFocusedIndicator(activeIndex, activeIndex - 1 <= 0 ? 0 : activeIndex - 1);\n }\n\n onHomeKey() {\n const activeIndex = this.findFocusedIndicatorIndex();\n\n this.changedFocusedIndicator(activeIndex, 0);\n }\n\n onEndKey() {\n const itemsContainer = this.itemsContainer();\n const indicators = find(itemsContainer?.nativeElement, '[data-pc-section=\"thumbnailitem\"]');\n const activeIndex = this.findFocusedIndicatorIndex();\n\n this.changedFocusedIndicator(activeIndex, indicators.length - 1);\n }\n\n onTabKey() {\n const itemsContainer = this.itemsContainer();\n const indicators = <any>[...find(itemsContainer?.nativeElement, '[data-pc-section=\"thumbnailitem\"]')];\n const highlightedIndex = indicators.findIndex((ind: any) => getAttribute(ind, 'data-p-active') === true);\n\n const activeIndicator = <any>findSingle(itemsContainer?.nativeElement, '[tabindex=\"0\"]');\n\n const activeIndex = indicators.findIndex((ind: any) => ind === activeIndicator?.parentElement);\n\n indicators[activeIndex].children[0].tabIndex = '-1';\n indicators[highlightedIndex].children[0].tabIndex = '0';\n }\n\n findFocusedIndicatorIndex() {\n const itemsContainer = this.itemsContainer();\n const indicators = [...find(itemsContainer?.nativeElement, '[data-pc-section=\"thumbnailitem\"]')];\n const activeIndicator = findSingle(itemsContainer?.nativeElement, '[data-pc-section=\"thumbnailitem\"] > [tabindex=\"0\"]');\n\n return indicators.findIndex((ind) => ind === activeIndicator?.parentElement);\n }\n\n changedFocusedIndicator(prevInd: number, nextInd: number) {\n const itemsContainer = this.itemsContainer();\n const indicators = <any>find(itemsContainer?.nativeElement, '[data-pc-section=\"thumbnailitem\"]');\n\n indicators[prevInd].children[0].tabIndex = '-1';\n indicators[nextInd].children[0].tabIndex = '0';\n indicators[nextInd].children[0].focus();\n }\n\n step(dir: number) {\n const d_numVisible = this.d_numVisible();\n const val = this.value();\n const activeIndex = this._activeIndex();\n let totalShiftedItems = this.totalShiftedItems + dir;\n\n if (dir < 0 && -1 * totalShiftedItems + d_numVisible > val!.length - 1) {\n totalShiftedItems = d_numVisible - val!.length;\n } else if (dir > 0 && totalShiftedItems > 0) {\n totalShiftedItems = 0;\n }\n\n if (this.circular()) {\n if (dir < 0 && val!.length - 1 === activeIndex) {\n totalShiftedItems = 0;\n } else if (dir > 0 && activeIndex === 0) {\n totalShiftedItems = d_numVisible - val!.length;\n }\n }\n\n const itemsContainer = this.itemsContainer();\n if (itemsContainer) {\n this.document.body.setAttribute('data-p-items-hidden', 'false');\n !this.$unstyled() && removeClass(itemsContainer.nativeElement, 'p-items-hidden');\n itemsContainer.nativeElement.style.transform = this.isVertical() ? `translate3d(0, ${totalShiftedItems * (100 / d_numVisible)}%, 0)` : `translate3d(${totalShiftedItems * (100 / d_numVisible)}%, 0, 0)`;\n itemsContainer.nativeElement.style.transition = 'transform 500ms ease 0s';\n }\n\n this.totalShiftedItems = totalShiftedItems;\n }\n\n stopTheSlideShow() {\n if (this.slideShowActive()) {\n this.stopSlideShow.emit();\n }\n }\n\n changePageOnTouch(e: TouchEvent, diff: number) {\n if (diff < 0) {\n // left\n this.navForward(e);\n } else {\n // right\n this.navBackward(e);\n }\n }\n\n getTotalPageNumber() {\n const val = this.value();\n const d_numVisible = this.d_numVisible();\n return val!.length > d_numVisible ? val!.length - d_numVisible + 1 : 0;\n }\n\n getMedianItemIndex() {\n const d_numVisible = this.d_numVisible();\n let index = Math.floor(d_numVisible / 2);\n\n return d_numVisible % 2 ? index : index - 1;\n }\n\n onTransitionEnd() {\n const itemsContainer = this.itemsContainer();\n if (itemsContainer && itemsContainer.nativeElement) {\n this.document.body.setAttribute('data-p-items-hidden', 'true');\n !this.$unstyled() && addClass(itemsContainer.nativeElement, 'p-items-hidden');\n itemsContainer.nativeElement.style.transition = '';\n }\n }\n\n onTouchEnd(e: TouchEvent) {\n let touchobj = e.changedTouches[0];\n\n if (this.isVertical()) {\n this.changePageOnTouch(e, touchobj.pageY - (<{ x: number; y: number }>this.startPos).y);\n } else {\n this.changePageOnTouch(e, touchobj.pageX - (<{ x: number; y: number }>this.startPos).x);\n }\n }\n\n onTouchMove(e: TouchEvent) {\n if (e.cancelable) {\n e.preventDefault();\n }\n }\n\n onTouchStart(e: TouchEvent) {\n let touchobj = e.changedTouches[0];\n\n this.startPos = {\n x: touchobj.pageX,\n y: touchobj.pageY\n };\n }\n\n isNavBackwardDisabled() {\n const val = this.value();\n const d_numVisible = this.d_numVisible();\n return (!this.circular() && this._activeIndex() === 0) || val!.length <= d_numVisible;\n }\n\n isNavForwardDisabled() {\n const val = this.value();\n const d_numVisible = this.d_numVisible();\n return (!this.circular() && this._activeIndex() === val!.length - 1) || val!.length <= d_numVisible;\n }\n\n firstItemAciveIndex() {\n return this.totalShiftedItems * -1;\n }\n\n lastItemActiveIndex() {\n return this.firstItemAciveIndex() + this.d_numVisible() - 1;\n }\n\n isItemActive(index: number) {\n return this.firstItemAciveIndex() <= index && this.lastItemActiveIndex() >= index;\n }\n\n bindDocumentListeners() {\n if (isPlatformBrowser(this.platformId)) {\n const window = this.document.defaultView || 'window';\n this.documentResizeListener = this.renderer.listen(window, 'resize', () => {\n this.calculatePosition();\n });\n }\n }\n\n unbindDocumentListeners() {\n if (this.documentResizeListener) {\n this.documentResizeListener();\n this.documentResizeListener = null;\n }\n }\n\n onDestroy() {\n if (this.responsiveOptions()) {\n this.unbindDocumentListeners();\n }\n\n if (this.thumbnailsStyle) {\n this.thumbnailsStyle.parentNode?.removeChild(this.thumbnailsStyle);\n }\n }\n\n ariaPrevButtonLabel() {\n return this.aria?.prevPageLabel;\n }\n\n ariaNextButtonLabel() {\n return this.aria?.nextPageLabel;\n }\n\n ariaPageLabel(value: any) {\n return this.aria?.pageLabel?.replace(/{page}/g, value);\n }\n}\n","import { isPlatformBrowser, NgTemplateOutlet } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, computed, ElementRef, HostListener, inject, input, linkedSignal, model, numberAttribute, output, viewChild } from '@angular/core';\nimport { uuid } from '@primeuix/utils';\nimport { BaseComponent } from 'primeng/basecomponent';\nimport { Bind, BindModule } from 'primeng/bind';\nimport { Times as TimesIcon } from '@primeicons/angular/times';\nimport type { GalleriaPassThrough } from 'primeng/types/galleria';\nimport type { Galleria } from './galleria';\nimport { GalleriaItem } from './galleria-item';\nimport { GalleriaItemSlot } from './galleria-item-slot';\nimport { GALLERIA_INSTANCE } from './galleria-token';\nimport { GalleriaThumbnails } from './galleria-thumbnails';\nimport { GalleriaStyle } from './style/galleriastyle';\n\n@Component({\n selector: 'div[pGalleriaContent]',\n standalone: true,\n imports: [NgTemplateOutlet, BindModule, TimesIcon, GalleriaItemSlot, GalleriaItem, GalleriaThumbnails],\n template: `\n @if (hasValue()) {\n @if (galleria.fullScreen()) {\n <button type=\"button\" [pBind]=\"getPTOptions('closeButton')\" [class]=\"cx('closeButton')\" (click)=\"maskHide.emit(true)\" [attr.aria-label]=\"closeAriaLabel()\">\n @if (!galleria.closeIconTemplate()) {\n <svg data-p-icon=\"times\" [pBind]=\"getPTOptions('closeIcon')\" [class]=\"cx('closeIcon')\" />\n }\n <ng-template [ngTemplateOutlet]=\"galleria.closeIconTemplate()\"></ng-template>\n </button>\n }\n @if (shouldRenderHeader()) {\n <div pGalleriaItemSlot [unstyled]=\"unstyled()\" type=\"header\" [pBind]=\"getPTOptions('header')\" [class]=\"cx('header')\"></div>\n }\n <div [pBind]=\"getPTOptions('content')\" [class]=\"cx('content')\" [attr.aria-live]=\"contentAriaLive()\">\n <div\n pGalleriaItem\n [id]=\"id()\"\n [value]=\"value()\"\n [activeIndex]=\"_activeIndex()\"\n [circular]=\"galleria.circular()\"\n (onActiveIndexChange)=\"onActiveIndexChange($event)\"\n [showIndicators]=\"galleria.showIndicators()\"\n [changeItemOnIndicatorHover]=\"galleria.changeItemOnIndicatorHover()\"\n [showItemNavigators]=\"galleria.showItemNavigators()\"\n [autoPlay]=\"galleria.autoPlay()\"\n [slideShowActive]=\"slideShowActive\"\n (startSlideShow)=\"startSlideShow()\"\n (stopSlideShow)=\"stopSlideShow()\"\n [pt]=\"pt()\"\n [unstyled]=\"unstyled()\"\n [class]=\"cx('itemsContainer')\"\n ></div>\n\n @if (galleria.showThumbnails()) {\n <div\n pGalleriaThumbnails\n [containerId]=\"id()\"\n [value]=\"value()\"\n (onActiveIndexChange)=\"onActiveIndexChange($event)\"\n [activeIndex]=\"_activeIndex()\"\n [numVisible]=\"numVisible()\"\n [responsiveOptions]=\"galleria.responsiveOptions()\"\n [circular]=\"galleria.circular()\"\n [isVertical]=\"isVertical()\"\n [contentHeight]=\"galleria.verticalThumbnailViewPortHeight()\"\n [showThumbnailNavigators]=\"galleria.showThumbnailNavigators()\"\n [slideShowActive]=\"slideShowActive\"\n (stopSlideShow)=\"stopSlideShow()\"\n [pt]=\"pt()\"\n [unstyled]=\"unstyled()\"\n ></div>\n }\n </div>\n @if (shouldRenderFooter()) {\n <div pGalleriaItemSlot [pBind]=\"getPTOptions('footer')\" [class]=\"cx('footer')\" type=\"footer\" [unstyled]=\"unstyled()\"></div>\n }\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [GalleriaStyle],\n host: {\n '[attr.id]': 'id()',\n '[attr.role]': '\"region\"',\n '[style]': 'hostStyle()',\n '[class]': \"cx('root')\"\n },\n hostDirectives: [Bind]\n})\nexport class GalleriaContent extends BaseComponent<GalleriaPassThrough> {\n hostName: string = 'Galleria';\n\n galleria = inject<Galleria>(GALLERIA_INSTANCE);\n\n bindDirectiveInstance = inject(Bind, { self: true });\n\n onAfterViewChecked() {\n this.bindDirectiveInstance.setAttrs(this.getPTOptions('root'));\n }\n\n value = input<any[]>([]);\n\n numVisible = input<number>();\n\n fullScreen = model(false);\n\n activeIndexInput = input<number>(0, { alias: 'activeIndex' });\n\n maskHide = output<boolean>();\n\n activeItemChange = output<number>();\n\n closeButton = viewChild<ElementRef>('closeButton');\n\n _componentStyle = inject(GalleriaStyle);\n\n $pcGalleria: Galleria | undefined = inject(GALLERIA_INSTANCE, { optional: true, skipSelf: true }) ?? undefined;\n\n private _generatedId = uuid('pn_id_');\n\n id = computed(() => this.galleria.id() || this._generatedId);\n\n _activeIndex = linkedSignal(() => this.activeIndexInput());\n\n slideShowActive = true;\n\n interval: any;\n\n hostStyle = computed(() => (!this.galleria.fullScreen() ? this.galleria.containerStyle() : {}));\n\n contentAriaLive = computed(() => (this.galleria.autoPlay() ? 'polite' : 'off'));\n\n isVertical = computed(() => this.galleria.thumbnailsPosition() === 'left' || this.galleria.thumbnailsPosition() === 'right');\n\n hasValue = computed(() => {\n const val = this.value();\n return val && val.length > 0;\n });\n\n // For custom fullscreen\n @HostListener('document:fullscreenchange')\n handleFullscreenChange() {\n if (document?.fullscreenElement === this.el.nativeElement?.children[0]) {\n this.fullScreen.set(true);\n } else {\n this.fullScreen.set(false);\n }\n }\n\n shouldRenderHeader() {\n return !!this.galleria.headerTemplate();\n }\n\n shouldRenderFooter() {\n return !!this.galleria.footerTemplate();\n