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

916 lines (910 loc) 84.5 kB
export * from 'primeng/types/panelmenu'; import { trigger, state, transition, style as style$2, animate } from '@angular/animations'; import * as i2 from '@angular/common'; import { CommonModule } from '@angular/common'; import * as i0 from '@angular/core'; import { Injectable, InjectionToken, EventEmitter, inject, ElementRef, forwardRef, booleanAttribute, numberAttribute, Output, Input, ViewEncapsulation, Component, signal, computed, ViewChild, ChangeDetectionStrategy, ContentChildren, ContentChild, NgModule } from '@angular/core'; import * as i3 from '@angular/router'; import { RouterModule } from '@angular/router'; import { resolve, isNotEmpty, findLast, findSingle, isPrintableCharacter, isEmpty, uuid, equals, focus, getAttribute } from '@primeuix/utils'; import { SharedModule, PrimeTemplate } from 'primeng/api'; import { BaseComponent, PARENT_INSTANCE } from 'primeng/basecomponent'; import * as i1 from 'primeng/bind'; import { Bind, BindModule } from 'primeng/bind'; import { ChevronDownIcon, ChevronRightIcon } from 'primeng/icons'; import * as i4 from 'primeng/tooltip'; import { TooltipModule } from 'primeng/tooltip'; import { style as style$1 } from '@primeuix/styles/panelmenu'; import { BaseStyle } from 'primeng/base'; const style = /*css*/ ` ${style$1} /*For PrimeNG*/ .p-panelmenu-item:not(.ng-animating) { overflow: hidden; } .p-panelmenu-panel { overflow: hidden; } .p-panelmenu-root-list, .p-panelmenu-submenu, .p-panelmenu-item-link { outline: 0 none; } `; const classes = { root: () => ['p-panelmenu p-component'], panel: 'p-panelmenu-panel', header: ({ instance, item }) => [ 'p-panelmenu-header', { 'p-panelmenu-header-active': instance.isItemActive(item) && !!item.items, 'p-disabled': instance.isItemDisabled(item) } ], headerContent: 'p-panelmenu-header-content', headerLink: 'p-panelmenu-header-link', headerIcon: 'p-panelmenu-header-icon', headerLabel: 'p-panelmenu-header-label', contentContainer: ({ instance, processedItem }) => ['p-panelmenu-content-container', { 'p-panelmenu-expanded': instance.isItemActive(processedItem) }], content: 'p-panelmenu-content', rootList: 'p-panelmenu-root-list', item: ({ instance, processedItem }) => [ 'p-panelmenu-item', { 'p-focus': instance.isItemFocused(processedItem) && !instance.isItemDisabled(processedItem), 'p-disabled': instance.isItemDisabled(processedItem) } ], itemContent: 'p-panelmenu-item-content', itemLink: 'p-panelmenu-item-link', itemIcon: 'p-panelmenu-item-icon', itemLabel: 'p-panelmenu-item-label', submenuIcon: 'p-panelmenu-submenu-icon', submenu: 'p-panelmenu-submenu', separator: 'p-menuitem-separator', badge: 'p-menuitem-badge' }; class PanelMenuStyle extends BaseStyle { name = 'panelmenu'; style = style; classes = classes; static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PanelMenuStyle, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PanelMenuStyle }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PanelMenuStyle, decorators: [{ type: Injectable }] }); /** * * PanelMenu is a hybrid of Accordion and Tree components. * * [Live Demo](https://www.primeng.org/panelmenu/) * * @module panelmenustyle * */ var PanelMenuClasses; (function (PanelMenuClasses) { /** * Class name of the root element */ PanelMenuClasses["root"] = "p-panelmenu"; /** * Class name of the panel element */ PanelMenuClasses["panel"] = "p-panelmenu-panel"; /** * Class name of the header element */ PanelMenuClasses["header"] = "p-panelmenu-header"; /** * Class name of the header content element */ PanelMenuClasses["headerContent"] = "p-panelmenu-header-content"; /** * Class name of the header link element */ PanelMenuClasses["headerLink"] = "p-panelmenu-header-link"; /** * Class name of the header icon element */ PanelMenuClasses["headerIcon"] = "p-panelmenu-header-icon"; /** * Class name of the header label element */ PanelMenuClasses["headerLabel"] = "p-panelmenu-header-label"; /** * Class name of the content container element */ PanelMenuClasses["contentContainer"] = "p-panelmenu-content-container"; /** * Class name of the content element */ PanelMenuClasses["content"] = "p-panelmenu-content"; /** * Class name of the root list element */ PanelMenuClasses["rootList"] = "p-panelmenu-root-list"; /** * Class name of the item element */ PanelMenuClasses["item"] = "p-panelmenu-item"; /** * Class name of the item content element */ PanelMenuClasses["itemContent"] = "p-panelmenu-item-content"; /** * Class name of the item link element */ PanelMenuClasses["itemLink"] = "p-panelmenu-item-link"; /** * Class name of the item icon element */ PanelMenuClasses["itemIcon"] = "p-panelmenu-item-icon"; /** * Class name of the item label element */ PanelMenuClasses["itemLabel"] = "p-panelmenu-item-label"; /** * Class name of the submenu icon element */ PanelMenuClasses["submenuIcon"] = "p-panelmenu-submenu-icon"; /** * Class name of the submenu element */ PanelMenuClasses["submenu"] = "p-panelmenu-submenu"; PanelMenuClasses["separator"] = "p-menuitem-separator"; })(PanelMenuClasses || (PanelMenuClasses = {})); const PANELMENU_INSTANCE = new InjectionToken('PANELMENU_INSTANCE'); const PANELMENUSUB_INSTANCE = new InjectionToken('PANELMENUSUB_INSTANCE'); class PanelMenuSub extends BaseComponent { panelId; focusedItemId; items; itemTemplate; level = 0; activeItemPath; root; tabindex; transitionOptions; parentExpanded; itemToggle = new EventEmitter(); menuFocus = new EventEmitter(); menuBlur = new EventEmitter(); menuKeyDown = new EventEmitter(); listViewChild = inject(ElementRef); panelMenu = inject(forwardRef(() => PanelMenu)); _componentStyle = inject(PanelMenuStyle); bindDirectiveInstance = inject(Bind, { self: true }); $pcPanelMenu = inject(PANELMENU_INSTANCE, { optional: true, skipSelf: true }) ?? undefined; onAfterViewChecked() { this.bindDirectiveInstance.setAttrs(this.ptm(this.root ? 'rootList' : 'submenu')); } getPTOptions(processedItem, index, key) { return this.ptm(key, { context: { item: processedItem.item, index, active: this.isItemActive(processedItem), focused: this.isItemFocused(processedItem), disabled: this.isItemDisabled(processedItem) } }); } getItemId(processedItem) { return processedItem.item?.id ?? `${this.panelId}_${processedItem.key}`; } getItemKey(processedItem) { return this.getItemId(processedItem); } getItemClass(processedItem) { return { 'p-panelmenu-item': true, 'p-disabled': this.isItemDisabled(processedItem), 'p-focus': this.isItemFocused(processedItem) }; } getItemProp(processedItem, name, params) { return processedItem && processedItem.item ? resolve(processedItem.item[name], params) : undefined; } getItemLabel(processedItem) { return this.getItemProp(processedItem, 'label'); } isItemExpanded(processedItem) { return processedItem.expanded; } isItemActive(processedItem) { return this.isItemExpanded(processedItem) || this.activeItemPath.some((path) => path && path.key === processedItem.key); } isItemVisible(processedItem) { return this.getItemProp(processedItem, 'visible') !== false; } isItemDisabled(processedItem) { return this.getItemProp(processedItem, 'disabled'); } isItemFocused(processedItem) { return this.focusedItemId === this.getItemId(processedItem); } isItemGroup(processedItem) { return isNotEmpty(processedItem.items); } getAnimation(processedItem) { return this.isItemActive(processedItem) ? { value: 'visible', params: { transitionParams: this.transitionOptions, height: '*' } } : { value: 'hidden', params: { transitionParams: this.transitionOptions, height: '0' } }; } getAriaSetSize() { return this.items.filter((processedItem) => this.isItemVisible(processedItem) && !this.getItemProp(processedItem, 'separator')).length; } getAriaPosInset(index) { return index - this.items.slice(0, index).filter((processedItem) => this.isItemVisible(processedItem) && this.getItemProp(processedItem, 'separator')).length + 1; } onItemClick(event, processedItem) { if (!this.isItemDisabled(processedItem)) { this.getItemProp(processedItem, 'command', { originalEvent: event, item: processedItem.item }); this.itemToggle.emit({ processedItem, expanded: !this.isItemActive(processedItem) }); } } onItemToggle(event) { this.itemToggle.emit(event); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PanelMenuSub, deps: null, target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "20.3.4", type: PanelMenuSub, isStandalone: true, selector: "ul[pPanelMenuSub]", inputs: { panelId: "panelId", focusedItemId: "focusedItemId", items: "items", itemTemplate: "itemTemplate", level: ["level", "level", numberAttribute], activeItemPath: "activeItemPath", root: ["root", "root", booleanAttribute], tabindex: ["tabindex", "tabindex", numberAttribute], transitionOptions: "transitionOptions", parentExpanded: ["parentExpanded", "parentExpanded", booleanAttribute] }, outputs: { itemToggle: "itemToggle", menuFocus: "menuFocus", menuBlur: "menuBlur", menuKeyDown: "menuKeyDown" }, host: { attributes: { "role": "tree" }, listeners: { "focusin": "menuFocus.emit($event)", "focusout": "menuBlur.emit($event)", "keydown": "menuKeyDown.emit($event)" }, properties: { "class": "root ? cn(cx(\"rootList\"), cx(\"submenu\")) : cx(\"submenu\")", "tabindex": "-1", "attr.aria-activedescendant": "focusedItemId", "attr.aria-hidden": "!parentExpanded" } }, providers: [PanelMenuStyle, { provide: PANELMENUSUB_INSTANCE, useExisting: PanelMenuSub }, { provide: PARENT_INSTANCE, useExisting: PanelMenuSub }], usesInheritance: true, hostDirectives: [{ directive: i1.Bind }], ngImport: i0, template: ` <ng-template ngFor let-processedItem let-index="index" [ngForOf]="items"> <li *ngIf="processedItem.separator" [class]="cn(cx('separator'), getItemProp(processedItem, 'styleClass'))" role="separator" [pBind]="ptm('separator')"></li> <li *ngIf="!processedItem.separator && isItemVisible(processedItem)" role="treeitem" [attr.id]="getItemId(processedItem)" [attr.aria-label]="getItemProp(processedItem, 'label')" [attr.aria-expanded]="isItemGroup(processedItem) ? isItemActive(processedItem) : undefined" [attr.aria-level]="level + 1" [attr.aria-setsize]="getAriaSetSize()" [attr.aria-posinset]="getAriaPosInset(index)" [class]="cn(cx('item', { processedItem }), getItemProp(processedItem, 'styleClass'))" [ngStyle]="getItemProp(processedItem, 'style')" [pTooltip]="getItemProp(processedItem, 'tooltip')" [pBind]="getPTOptions(processedItem, index, 'item')" [attr.data-p-disabled]="isItemDisabled(processedItem)" [tooltipOptions]="getItemProp(processedItem, 'tooltipOptions')" > <div [class]="cx('itemContent')" [pBind]="getPTOptions(processedItem, index, 'itemContent')" (click)="onItemClick($event, processedItem)"> <ng-container *ngIf="!itemTemplate"> <a *ngIf="!getItemProp(processedItem, 'routerLink')" [attr.href]="getItemProp(processedItem, 'url')" [class]="cx('itemLink')" [target]="getItemProp(processedItem, 'target')" [attr.tabindex]="!!parentExpanded ? '0' : '-1'" [pBind]="getPTOptions(processedItem, index, 'itemLink')" > <ng-container *ngIf="isItemGroup(processedItem)"> <ng-container *ngIf="!panelMenu.submenuIconTemplate && !panelMenu._submenuIconTemplate"> <svg data-p-icon="chevron-down" [class]="cn(cx('submenuIcon'), getItemProp(processedItem, 'icon'))" *ngIf="isItemActive(processedItem)" [ngStyle]="getItemProp(processedItem, 'iconStyle')" [pBind]="getPTOptions(processedItem, index, 'submenuIcon')" /> <svg data-p-icon="chevron-right" [class]="cn(cx('submenuIcon'), getItemProp(processedItem, 'icon'))" *ngIf="!isItemActive(processedItem)" [ngStyle]="getItemProp(processedItem, 'iconStyle')" [pBind]="getPTOptions(processedItem, index, 'submenuIcon')" /> </ng-container> <ng-template *ngTemplateOutlet="panelMenu.submenuIconTemplate || panelMenu._submenuIconTemplate"></ng-template> </ng-container> <span [class]="cn(cx('itemIcon'), getItemProp(processedItem, 'icon'))" *ngIf="processedItem.icon" [ngStyle]="getItemProp(processedItem, 'iconStyle')" [pBind]="getPTOptions(processedItem, index, 'itemIcon')"></span> <span [class]="cx('itemLabel')" *ngIf="processedItem.item?.escape !== false; else htmlLabel" [pBind]="getPTOptions(processedItem, index, 'itemLabel')">{{ getItemProp(processedItem, 'label') }}</span> <ng-template #htmlLabel><span [class]="cx('itemLabel')" [innerHTML]="getItemProp(processedItem, 'label')" [pBind]="getPTOptions(processedItem, index, 'itemLabel')"></span></ng-template> </a> <a *ngIf="getItemProp(processedItem, 'routerLink')" [routerLink]="getItemProp(processedItem, 'routerLink')" [queryParams]="getItemProp(processedItem, 'queryParams')" [routerLinkActive]="'p-panelmenu-item-link-active'" [routerLinkActiveOptions]="getItemProp(processedItem, 'routerLinkActiveOptions') || { exact: false }" [class]="cx('itemLink')" [target]="getItemProp(processedItem, 'target')" [attr.title]="getItemProp(processedItem, 'title')" [fragment]="getItemProp(processedItem, 'fragment')" [queryParamsHandling]="getItemProp(processedItem, 'queryParamsHandling')" [preserveFragment]="getItemProp(processedItem, 'preserveFragment')" [skipLocationChange]="getItemProp(processedItem, 'skipLocationChange')" [replaceUrl]="getItemProp(processedItem, 'replaceUrl')" [state]="getItemProp(processedItem, 'state')" [attr.tabindex]="!!parentExpanded ? '0' : '-1'" [pBind]="getPTOptions(processedItem, index, 'itemLink')" > <ng-container *ngIf="isItemGroup(processedItem)"> <ng-container *ngIf="!panelMenu.submenuIconTemplate && !panelMenu._submenuIconTemplate"> <svg data-p-icon="chevron-down" *ngIf="isItemActive(processedItem)" [class]="cn(cx('submenuIcon'), getItemProp(processedItem, 'icon'))" [ngStyle]="getItemProp(processedItem, 'iconStyle')" [pBind]="getPTOptions(processedItem, index, 'submenuIcon')" /> <svg data-p-icon="chevron-right" *ngIf="!isItemActive(processedItem)" [class]="cn(cx('submenuIcon'), getItemProp(processedItem, 'icon'))" [ngStyle]="getItemProp(processedItem, 'iconStyle')" [pBind]="getPTOptions(processedItem, index, 'submenuIcon')" /> </ng-container> <ng-template *ngTemplateOutlet="panelMenu.submenuIconTemplate && panelMenu._submenuIconTemplate"></ng-template> </ng-container> <span [class]="cn(cx('itemIcon'), getItemProp(processedItem, 'icon'))" *ngIf="processedItem.icon" [ngStyle]="getItemProp(processedItem, 'iconStyle')" [pBind]="getPTOptions(processedItem, index, 'itemIcon')"></span> <span *ngIf="getItemProp(processedItem, 'label')" [class]="cx('itemLabel')" [innerHTML]="getItemProp(processedItem, 'label')" [pBind]="getPTOptions(processedItem, index, 'itemLabel')"></span> <span [class]="cn(cx('badge'), getItemProp(processedItem, 'badgeStyleClass'))" *ngIf="processedItem.badge">{{ processedItem.badge }}</span> </a> </ng-container> <ng-container *ngIf="itemTemplate"> <ng-template *ngTemplateOutlet="itemTemplate; context: { $implicit: processedItem.item }"></ng-template> </ng-container> </div> <div [@submenu]="getAnimation(processedItem)"> <ul pPanelMenuSub *ngIf="isItemVisible(processedItem) && isItemGroup(processedItem) && isItemExpanded(processedItem)" [id]="getItemId(processedItem) + '_list'" [panelId]="panelId" [items]="processedItem?.items" [itemTemplate]="itemTemplate" [transitionOptions]="transitionOptions" [focusedItemId]="focusedItemId" [activeItemPath]="activeItemPath" [level]="level + 1" [pt]="pt()" [parentExpanded]="!!parentExpanded && isItemExpanded(processedItem)" (itemToggle)="onItemToggle($event)" ></ul> </div> </li> </ng-template> `, isInline: true, dependencies: [{ kind: "component", type: PanelMenuSub, selector: "ul[pPanelMenuSub]", inputs: ["panelId", "focusedItemId", "items", "itemTemplate", "level", "activeItemPath", "root", "tabindex", "transitionOptions", "parentExpanded"], outputs: ["itemToggle", "menuFocus", "menuBlur", "menuKeyDown"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i3.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i3.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i4.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "directive", type: i1.Bind, selector: "[pBind]", inputs: ["pBind"] }, { kind: "component", type: ChevronDownIcon, selector: "[data-p-icon=\"chevron-down\"]" }, { kind: "component", type: ChevronRightIcon, selector: "[data-p-icon=\"chevron-right\"]" }, { kind: "ngmodule", type: SharedModule }, { kind: "ngmodule", type: BindModule }], animations: [ trigger('submenu', [ state('hidden', style$2({ height: '0' })), state('visible', style$2({ height: '*' })), transition('visible <=> hidden', [animate('{{transitionParams}}')]), transition('void => *', animate(0)) ]) ], encapsulation: i0.ViewEncapsulation.None }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PanelMenuSub, decorators: [{ type: Component, args: [{ selector: 'ul[pPanelMenuSub]', imports: [CommonModule, RouterModule, TooltipModule, ChevronDownIcon, ChevronRightIcon, SharedModule, BindModule], standalone: true, template: ` <ng-template ngFor let-processedItem let-index="index" [ngForOf]="items"> <li *ngIf="processedItem.separator" [class]="cn(cx('separator'), getItemProp(processedItem, 'styleClass'))" role="separator" [pBind]="ptm('separator')"></li> <li *ngIf="!processedItem.separator && isItemVisible(processedItem)" role="treeitem" [attr.id]="getItemId(processedItem)" [attr.aria-label]="getItemProp(processedItem, 'label')" [attr.aria-expanded]="isItemGroup(processedItem) ? isItemActive(processedItem) : undefined" [attr.aria-level]="level + 1" [attr.aria-setsize]="getAriaSetSize()" [attr.aria-posinset]="getAriaPosInset(index)" [class]="cn(cx('item', { processedItem }), getItemProp(processedItem, 'styleClass'))" [ngStyle]="getItemProp(processedItem, 'style')" [pTooltip]="getItemProp(processedItem, 'tooltip')" [pBind]="getPTOptions(processedItem, index, 'item')" [attr.data-p-disabled]="isItemDisabled(processedItem)" [tooltipOptions]="getItemProp(processedItem, 'tooltipOptions')" > <div [class]="cx('itemContent')" [pBind]="getPTOptions(processedItem, index, 'itemContent')" (click)="onItemClick($event, processedItem)"> <ng-container *ngIf="!itemTemplate"> <a *ngIf="!getItemProp(processedItem, 'routerLink')" [attr.href]="getItemProp(processedItem, 'url')" [class]="cx('itemLink')" [target]="getItemProp(processedItem, 'target')" [attr.tabindex]="!!parentExpanded ? '0' : '-1'" [pBind]="getPTOptions(processedItem, index, 'itemLink')" > <ng-container *ngIf="isItemGroup(processedItem)"> <ng-container *ngIf="!panelMenu.submenuIconTemplate && !panelMenu._submenuIconTemplate"> <svg data-p-icon="chevron-down" [class]="cn(cx('submenuIcon'), getItemProp(processedItem, 'icon'))" *ngIf="isItemActive(processedItem)" [ngStyle]="getItemProp(processedItem, 'iconStyle')" [pBind]="getPTOptions(processedItem, index, 'submenuIcon')" /> <svg data-p-icon="chevron-right" [class]="cn(cx('submenuIcon'), getItemProp(processedItem, 'icon'))" *ngIf="!isItemActive(processedItem)" [ngStyle]="getItemProp(processedItem, 'iconStyle')" [pBind]="getPTOptions(processedItem, index, 'submenuIcon')" /> </ng-container> <ng-template *ngTemplateOutlet="panelMenu.submenuIconTemplate || panelMenu._submenuIconTemplate"></ng-template> </ng-container> <span [class]="cn(cx('itemIcon'), getItemProp(processedItem, 'icon'))" *ngIf="processedItem.icon" [ngStyle]="getItemProp(processedItem, 'iconStyle')" [pBind]="getPTOptions(processedItem, index, 'itemIcon')"></span> <span [class]="cx('itemLabel')" *ngIf="processedItem.item?.escape !== false; else htmlLabel" [pBind]="getPTOptions(processedItem, index, 'itemLabel')">{{ getItemProp(processedItem, 'label') }}</span> <ng-template #htmlLabel><span [class]="cx('itemLabel')" [innerHTML]="getItemProp(processedItem, 'label')" [pBind]="getPTOptions(processedItem, index, 'itemLabel')"></span></ng-template> </a> <a *ngIf="getItemProp(processedItem, 'routerLink')" [routerLink]="getItemProp(processedItem, 'routerLink')" [queryParams]="getItemProp(processedItem, 'queryParams')" [routerLinkActive]="'p-panelmenu-item-link-active'" [routerLinkActiveOptions]="getItemProp(processedItem, 'routerLinkActiveOptions') || { exact: false }" [class]="cx('itemLink')" [target]="getItemProp(processedItem, 'target')" [attr.title]="getItemProp(processedItem, 'title')" [fragment]="getItemProp(processedItem, 'fragment')" [queryParamsHandling]="getItemProp(processedItem, 'queryParamsHandling')" [preserveFragment]="getItemProp(processedItem, 'preserveFragment')" [skipLocationChange]="getItemProp(processedItem, 'skipLocationChange')" [replaceUrl]="getItemProp(processedItem, 'replaceUrl')" [state]="getItemProp(processedItem, 'state')" [attr.tabindex]="!!parentExpanded ? '0' : '-1'" [pBind]="getPTOptions(processedItem, index, 'itemLink')" > <ng-container *ngIf="isItemGroup(processedItem)"> <ng-container *ngIf="!panelMenu.submenuIconTemplate && !panelMenu._submenuIconTemplate"> <svg data-p-icon="chevron-down" *ngIf="isItemActive(processedItem)" [class]="cn(cx('submenuIcon'), getItemProp(processedItem, 'icon'))" [ngStyle]="getItemProp(processedItem, 'iconStyle')" [pBind]="getPTOptions(processedItem, index, 'submenuIcon')" /> <svg data-p-icon="chevron-right" *ngIf="!isItemActive(processedItem)" [class]="cn(cx('submenuIcon'), getItemProp(processedItem, 'icon'))" [ngStyle]="getItemProp(processedItem, 'iconStyle')" [pBind]="getPTOptions(processedItem, index, 'submenuIcon')" /> </ng-container> <ng-template *ngTemplateOutlet="panelMenu.submenuIconTemplate && panelMenu._submenuIconTemplate"></ng-template> </ng-container> <span [class]="cn(cx('itemIcon'), getItemProp(processedItem, 'icon'))" *ngIf="processedItem.icon" [ngStyle]="getItemProp(processedItem, 'iconStyle')" [pBind]="getPTOptions(processedItem, index, 'itemIcon')"></span> <span *ngIf="getItemProp(processedItem, 'label')" [class]="cx('itemLabel')" [innerHTML]="getItemProp(processedItem, 'label')" [pBind]="getPTOptions(processedItem, index, 'itemLabel')"></span> <span [class]="cn(cx('badge'), getItemProp(processedItem, 'badgeStyleClass'))" *ngIf="processedItem.badge">{{ processedItem.badge }}</span> </a> </ng-container> <ng-container *ngIf="itemTemplate"> <ng-template *ngTemplateOutlet="itemTemplate; context: { $implicit: processedItem.item }"></ng-template> </ng-container> </div> <div [@submenu]="getAnimation(processedItem)"> <ul pPanelMenuSub *ngIf="isItemVisible(processedItem) && isItemGroup(processedItem) && isItemExpanded(processedItem)" [id]="getItemId(processedItem) + '_list'" [panelId]="panelId" [items]="processedItem?.items" [itemTemplate]="itemTemplate" [transitionOptions]="transitionOptions" [focusedItemId]="focusedItemId" [activeItemPath]="activeItemPath" [level]="level + 1" [pt]="pt()" [parentExpanded]="!!parentExpanded && isItemExpanded(processedItem)" (itemToggle)="onItemToggle($event)" ></ul> </div> </li> </ng-template> `, animations: [ trigger('submenu', [ state('hidden', style$2({ height: '0' })), state('visible', style$2({ height: '*' })), transition('visible <=> hidden', [animate('{{transitionParams}}')]), transition('void => *', animate(0)) ]) ], encapsulation: ViewEncapsulation.None, providers: [PanelMenuStyle, { provide: PANELMENUSUB_INSTANCE, useExisting: PanelMenuSub }, { provide: PARENT_INSTANCE, useExisting: PanelMenuSub }], host: { '[class]': 'root ? cn(cx("rootList"), cx("submenu")) : cx("submenu")', role: 'tree', '[tabindex]': '-1', '[attr.aria-activedescendant]': 'focusedItemId', '[attr.aria-hidden]': '!parentExpanded', '(focusin)': 'menuFocus.emit($event)', '(focusout)': 'menuBlur.emit($event)', '(keydown)': 'menuKeyDown.emit($event)' }, hostDirectives: [Bind] }] }], propDecorators: { panelId: [{ type: Input }], focusedItemId: [{ type: Input }], items: [{ type: Input }], itemTemplate: [{ type: Input }], level: [{ type: Input, args: [{ transform: numberAttribute }] }], activeItemPath: [{ type: Input }], root: [{ type: Input, args: [{ transform: booleanAttribute }] }], tabindex: [{ type: Input, args: [{ transform: numberAttribute }] }], transitionOptions: [{ type: Input }], parentExpanded: [{ type: Input, args: [{ transform: booleanAttribute }] }], itemToggle: [{ type: Output }], menuFocus: [{ type: Output }], menuBlur: [{ type: Output }], menuKeyDown: [{ type: Output }] } }); class PanelMenuList extends BaseComponent { panelId; id; items; itemTemplate; parentExpanded; expanded; transitionOptions; root; tabindex; activeItem; itemToggle = new EventEmitter(); headerFocus = new EventEmitter(); subMenuViewChild; searchTimeout; searchValue; focused; focusedItem = signal(null, ...(ngDevMode ? [{ debugName: "focusedItem" }] : [])); activeItemPath = signal([], ...(ngDevMode ? [{ debugName: "activeItemPath" }] : [])); processedItems = signal([], ...(ngDevMode ? [{ debugName: "processedItems" }] : [])); visibleItems = computed(() => { const processedItems = this.processedItems(); return this.flatItems(processedItems); }, ...(ngDevMode ? [{ debugName: "visibleItems" }] : [])); get focusedItemId() { const focusedItem = this.focusedItem(); return focusedItem && focusedItem.item?.id ? focusedItem.item.id : isNotEmpty(this.focusedItem()) ? `${this.panelId}_${this.focusedItem().key}` : undefined; } onChanges(changes) { this.processedItems.set(this.createProcessedItems(changes?.items?.currentValue || this.items || [])); } getItemProp(processedItem, name) { return processedItem && processedItem.item ? resolve(processedItem.item[name]) : undefined; } getItemLabel(processedItem) { return this.getItemProp(processedItem, 'label'); } isItemVisible(processedItem) { return this.getItemProp(processedItem, 'visible') !== false; } isItemDisabled(processedItem) { return this.getItemProp(processedItem, 'disabled'); } isItemActive(processedItem) { return this.activeItemPath().some((path) => path.key === processedItem.parentKey); } isItemGroup(processedItem) { return isNotEmpty(processedItem.items); } isElementInPanel(event, element) { const panel = event.currentTarget.closest('[data-pc-name="panelmenu"]'); return panel && panel.contains(element); } isItemMatched(processedItem) { return this.isValidItem(processedItem) && this.getItemLabel(processedItem).toLocaleLowerCase().startsWith(this.searchValue.toLocaleLowerCase()); } isVisibleItem(processedItem) { return !!processedItem && (processedItem.level === 0 || this.isItemActive(processedItem)) && this.isItemVisible(processedItem); } isValidItem(processedItem) { return !!processedItem && !this.isItemDisabled(processedItem) && !processedItem.separator; } findFirstItem() { return this.visibleItems().find((processedItem) => this.isValidItem(processedItem)); } findLastItem() { return findLast(this.visibleItems(), (processedItem) => this.isValidItem(processedItem)); } findItemByEventTarget(target) { let parentNode = target; while (parentNode && parentNode.tagName?.toLowerCase() !== 'li') { parentNode = parentNode?.parentNode; } return parentNode?.id && this.visibleItems().find((processedItem) => this.isValidItem(processedItem) && `${this.panelId}_${processedItem.key}` === parentNode.id); } createProcessedItems(items, level = 0, parent = {}, parentKey = '') { const processedItems = []; items && items.forEach((item, index) => { const key = (parentKey !== '' ? parentKey + '_' : '') + index; const newItem = { icon: item.icon, expanded: item.expanded, separator: item.separator, item, index, level, key, parent, parentKey }; newItem['items'] = this.createProcessedItems(item.items, level + 1, newItem, key); processedItems.push(newItem); }); return processedItems; } findProcessedItemByItemKey(key, processedItems, level = 0) { processedItems = processedItems || this.processedItems(); if (processedItems && processedItems.length) { for (let i = 0; i < processedItems.length; i++) { const processedItem = processedItems[i]; if (this.getItemProp(processedItem, 'key') === key) return processedItem; const matchedItem = this.findProcessedItemByItemKey(key, processedItem.items, level + 1); if (matchedItem) return matchedItem; } } } flatItems(processedItems, processedFlattenItems = []) { processedItems && processedItems.forEach((processedItem) => { if (this.isVisibleItem(processedItem)) { processedFlattenItems.push(processedItem); this.flatItems(processedItem.items, processedFlattenItems); } }); return processedFlattenItems; } changeFocusedItem(event) { const { originalEvent, processedItem, focusOnNext, selfCheck, allowHeaderFocus = true } = event; if (isNotEmpty(this.focusedItem()) && this.focusedItem().key !== processedItem.key) { this.focusedItem.set(processedItem); this.scrollInView(); } else if (allowHeaderFocus) { this.headerFocus.emit({ originalEvent, focusOnNext, selfCheck }); } } scrollInView() { const element = findSingle(this.subMenuViewChild.listViewChild.nativeElement, `li[id="${`${this.focusedItemId}`}"]`); if (element) { element.scrollIntoView && element.scrollIntoView({ block: 'nearest', inline: 'nearest' }); } } onFocus(event) { if (!this.focused) { this.focused = true; const focusedItem = this.focusedItem() || (this.isElementInPanel(event, event.relatedTarget) ? this.findItemByEventTarget(event.target) || this.findFirstItem() : this.findLastItem()); if (event.relatedTarget !== null) this.focusedItem.set(focusedItem); } } onBlur(event) { const target = event.relatedTarget; if (this.focused && !this.el.nativeElement.contains(target)) { this.focused = false; this.focusedItem.set(null); this.searchValue = ''; } } onItemToggle(event) { const { processedItem, expanded } = event; // Update the original item object's 'expanded' property if (processedItem.item) { processedItem.item.expanded = !processedItem.item.expanded; } // Recreate processedItems with updated 'expanded' states this.processedItems.set(this.createProcessedItems(this.items || [], 0, {}, '')); // Update activeItemPath const activeItemPath = this.activeItemPath().filter((p) => p.parentKey !== processedItem.parentKey); if (expanded) { activeItemPath.push(processedItem); } this.activeItemPath.set(activeItemPath); // Update focusedItem this.focusedItem.set(processedItem); } onKeyDown(event) { const metaKey = event.metaKey || event.ctrlKey; switch (event.code) { case 'ArrowDown': this.onArrowDownKey(event); break; case 'ArrowUp': this.onArrowUpKey(event); break; case 'ArrowLeft': this.onArrowLeftKey(event); break; case 'ArrowRight': this.onArrowRightKey(event); break; case 'Home': this.onHomeKey(event); break; case 'End': this.onEndKey(event); break; case 'Space': this.onSpaceKey(event); break; case 'Enter': this.onEnterKey(event); break; case 'Escape': case 'Tab': case 'PageDown': case 'PageUp': case 'Backspace': case 'ShiftLeft': case 'ShiftRight': //NOOP break; default: if (!metaKey && isPrintableCharacter(event.key)) { this.searchItems(event, event.key); } break; } } onArrowDownKey(event) { const processedItem = isNotEmpty(this.focusedItem()) ? this.findNextItem(this.focusedItem()) : this.findFirstItem(); this.changeFocusedItem({ originalEvent: event, processedItem, focusOnNext: true }); event.preventDefault(); } onArrowUpKey(event) { const processedItem = isNotEmpty(this.focusedItem()) ? this.findPrevItem(this.focusedItem()) : this.findLastItem(); this.changeFocusedItem({ originalEvent: event, processedItem, selfCheck: true }); event.preventDefault(); } onArrowLeftKey(event) { if (isNotEmpty(this.focusedItem())) { const matched = this.activeItemPath().some((p) => p.key === this.focusedItem().key); if (matched) { const activeItemPath = this.activeItemPath().filter((p) => p.key !== this.focusedItem().key); this.activeItemPath.set(activeItemPath); } else { const focusedItem = isNotEmpty(this.focusedItem().parent) ? this.focusedItem().parent : this.focusedItem(); this.focusedItem.set(focusedItem); } event.preventDefault(); } } onArrowRightKey(event) { if (isNotEmpty(this.focusedItem())) { const grouped = this.isItemGroup(this.focusedItem()); if (grouped) { const matched = this.activeItemPath().some((p) => p.key === this.focusedItem().key); if (matched) { this.onArrowDownKey(event); } else { const activeItemPath = this.activeItemPath().filter((p) => p.parentKey !== this.focusedItem().parentKey); activeItemPath.push(this.focusedItem()); this.activeItemPath.set(activeItemPath); } } event.preventDefault(); } } onHomeKey(event) { this.changeFocusedItem({ originalEvent: event, processedItem: this.findFirstItem(), allowHeaderFocus: false }); event.preventDefault(); } onEndKey(event) { this.changeFocusedItem({ originalEvent: event, processedItem: this.findLastItem(), focusOnNext: true, allowHeaderFocus: false }); event.preventDefault(); } onEnterKey(event) { if (isNotEmpty(this.focusedItem())) { const element = findSingle(this.subMenuViewChild.listViewChild.nativeElement, `li[id="${`${this.focusedItemId}`}"]`); const anchorElement = element && (findSingle(element, 'a') || findSingle(element, 'button')); anchorElement ? anchorElement.click() : element && element.click(); } event.preventDefault(); } onSpaceKey(event) { this.onEnterKey(event); } findNextItem(processedItem) { const index = this.visibleItems().findIndex((item) => item.key === processedItem.key); const matchedItem = index < this.visibleItems().length - 1 ? this.visibleItems() .slice(index + 1) .find((pItem) => this.isValidItem(pItem)) : undefined; return matchedItem || processedItem; } findPrevItem(processedItem) { const index = this.visibleItems().findIndex((item) => item.key === processedItem.key); const matchedItem = index > 0 ? findLast(this.visibleItems().slice(0, index), (pItem) => this.isValidItem(pItem)) : undefined; return matchedItem || processedItem; } searchItems(event, char) { this.searchValue = (this.searchValue || '') + char; let matchedItem = null; let matched = false; if (isNotEmpty(this.focusedItem())) { const focusedItemIndex = this.visibleItems().findIndex((processedItem) => processedItem.key === this.focusedItem().key); matchedItem = this.visibleItems() .slice(focusedItemIndex) .find((processedItem) => this.isItemMatched(processedItem)) || null; matchedItem = isEmpty(matchedItem) ? this.visibleItems() .slice(0, focusedItemIndex) .find((processedItem) => this.isItemMatched(processedItem)) || null : matchedItem; } else { matchedItem = this.visibleItems().find((processedItem) => this.isItemMatched(processedItem)) || null; } if (isNotEmpty(matchedItem)) { matched = true; } if (isEmpty(matchedItem) && isEmpty(this.focusedItem())) { matchedItem = this.findFirstItem() || null; } if (isNotEmpty(matchedItem)) { this.changeFocusedItem({ originalEvent: event, processedItem: matchedItem, allowHeaderFocus: false }); } if (this.searchTimeout) { clearTimeout(this.searchTimeout); } this.searchTimeout = setTimeout(() => { this.searchValue = ''; this.searchTimeout = null; }, 500); return matched; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.4", ngImport: i0, type: PanelMenuList, deps: null, target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "20.3.4", type: PanelMenuList, isStandalone: true, selector: "ul[pPanelMenuList]", inputs: { panelId: "panelId", id: "id", items: "items", itemTemplate: "itemTemplate", parentExpanded: ["parentExpanded", "parentExpanded", booleanAttribute], expanded: ["expanded", "expanded", booleanAttribute], transitionOptions: "transitionOptions", root: ["root", "root", booleanAttribute], tabindex: ["tabindex", "tabindex", numberAttribute], activeItem: "activeItem" }, outputs: { itemToggle: "itemToggle", headerFocus: "headerFocus" }, viewQueries: [{ propertyName: "subMenuViewChild", first: true, predicate: ["submenu"], descendants: true }], usesInheritance: true, ngImport: i0, template: ` <ul pPanelMenuSub #submenu [root]="root" [id]="panelId + '_list'" [panelId]="panelId" [tabindex]="tabindex" [itemTemplate]="itemTemplate" [focusedItemId]="focused ? focusedItemId : undefined" [activeItemPath]="activeItemPath()" [transitionOptions]="transitionOptions" [items]="processedItems()" [parentExpanded]="parentExpanded" (itemToggle)="onItemToggle($event)" (keydown)="onKeyDown($event)" (menuFocus)="onFocus($event)" (menuBlur)="onBlur($event)" [pt]="pt()" ></ul> `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: PanelMenuSub, selector: "ul[pPanelMenuSub]", inputs: ["panelId", "focusedItemId", "items", "itemTemplate", "level", "activeItemPath", "root", "tabindex", "transitionOptions", "parentExpanded"], outputs: ["itemToggle", "menuFocus", "menuBlur", "menuKeyDown"] }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: SharedMo