UNPKG

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,

422 lines (413 loc) 22.8 kB
export * from 'primeng/types/commandmenu'; import { NgTemplateOutlet } from '@angular/common'; import * as i0 from '@angular/core'; import { Injectable, inject, input, model, output, contentChild, viewChild, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, NgModule } from '@angular/core'; import { toSignal } from '@angular/core/rxjs-interop'; import { uuid, findSingle } from '@primeuix/utils'; import { SharedModule } from 'primeng/api'; import { BaseComponent, PARENT_INSTANCE } from 'primeng/basecomponent'; import * as i1 from 'primeng/bind'; import { Bind, BindModule } from 'primeng/bind'; import * as i2 from 'primeng/menu'; import { MenuModule } from 'primeng/menu'; import { style } from '@primeuix/styles/commandmenu'; import { BaseStyle } from 'primeng/base'; const classes = { root: 'p-commandmenu p-component', header: 'p-commandmenu-header', input: 'p-commandmenu-input', list: 'p-commandmenu-list', emptyMessage: 'p-commandmenu-empty-message', footer: 'p-commandmenu-footer' }; class CommandMenuStyle extends BaseStyle { name = 'commandmenu'; style = style; classes = classes; static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: CommandMenuStyle, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: CommandMenuStyle }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: CommandMenuStyle, decorators: [{ type: Injectable }] }); /** * * CommandMenu is a search-driven command palette component. * * [Live Demo](https://www.primeng.org/commandmenu/) * * @module commandmenustyle * */ var CommandMenuClasses; (function (CommandMenuClasses) { /** * Class name of the root element */ CommandMenuClasses["root"] = "p-commandmenu"; /** * Class name of the header element */ CommandMenuClasses["header"] = "p-commandmenu-header"; /** * Class name of the input element */ CommandMenuClasses["input"] = "p-commandmenu-input"; /** * Class name of the empty message element */ CommandMenuClasses["emptyMessage"] = "p-commandmenu-empty-message"; /** * Class name of the footer element */ CommandMenuClasses["footer"] = "p-commandmenu-footer"; })(CommandMenuClasses || (CommandMenuClasses = {})); /** * CommandMenu is a search-driven command palette component. * @group Components */ class CommandMenu extends BaseComponent { componentName = 'CommandMenu'; bindDirectiveInstance = inject(Bind, { self: true }); onAfterViewChecked() { this.bindDirectiveInstance.setAttrs(this.ptms(['host', 'root'])); } /** * An array of menu items to display. * @group Props */ model = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "model" }] : /* istanbul ignore next */ [])); /** * Two-way bound search value. * @group Props */ search = model('', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "search" }] : /* istanbul ignore next */ [])); /** * Custom filter function. Receives (item, search) and returns a number (0 = no match). * @group Props */ filter = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "filter" }] : /* istanbul ignore next */ [])); /** * Text to display when there are no results. Defaults to global value in i18n translation configuration. * @group Props */ emptyMessage = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "emptyMessage" }] : /* istanbul ignore next */ [])); /** * Placeholder text for the search input. * @group Props */ placeholder = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "placeholder" }] : /* istanbul ignore next */ [])); /** * Defines a string that labels the input for accessibility. * @group Props */ ariaLabel = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "ariaLabel" }] : /* istanbul ignore next */ [])); /** * Identifies the element that labels the input for accessibility. * @group Props */ ariaLabelledBy = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "ariaLabelledBy" }] : /* istanbul ignore next */ [])); /** * Inline style of the menu. * @group Props */ menuStyle = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "menuStyle" }] : /* istanbul ignore next */ [])); /** * Style class of the menu. * @group Props */ menuStyleClass = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "menuStyleClass" }] : /* istanbul ignore next */ [])); /** * Callback to invoke when the search value changes. * @param {CommandMenuSearchChangeEvent} event - Custom search change event. * @group Emits */ onSearchChange = output(); /** * Callback to invoke when a menu item is selected. * @param {CommandMenuItemSelectEvent} event - Custom item select event. * @group Emits */ onSelect = output(); /** * Custom item template. * @param {CommandMenuItemTemplateContext} context - item context. * @group Templates */ itemTemplate = contentChild('item', { ...(ngDevMode ? { debugName: "itemTemplate" } : /* istanbul ignore next */ {}), descendants: false }); /** * Custom header template. * @param {CommandMenuHeaderTemplateContext} context - header context. * @group Templates */ headerTemplate = contentChild('header', { ...(ngDevMode ? { debugName: "headerTemplate" } : /* istanbul ignore next */ {}), descendants: false }); /** * Custom footer template. * @param {CommandMenuFooterTemplateContext} context - footer context. * @group Templates */ footerTemplate = contentChild('footer', { ...(ngDevMode ? { debugName: "footerTemplate" } : /* istanbul ignore next */ {}), descendants: false }); /** * Custom empty message template. * @param {CommandMenuEmptyMessageTemplateContext} context - empty message context. * @group Templates */ emptyMessageTemplate = contentChild('emptyMessage', { ...(ngDevMode ? { debugName: "emptyMessageTemplate" } : /* istanbul ignore next */ {}), descendants: false }); menuViewChild = viewChild('menu', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "menuViewChild" }] : /* istanbul ignore next */ [])); searchInputViewChild = viewChild('searchInput', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "searchInputViewChild" }] : /* istanbul ignore next */ [])); _componentStyle = inject(CommandMenuStyle); _internalId = uuid('pn_id_'); $id = computed(() => this._internalId, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$id" }] : /* istanbul ignore next */ [])); listId = computed(() => `${this.$id()}_list`, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "listId" }] : /* istanbul ignore next */ [])); translation = toSignal(this.config.translationObserver, { initialValue: this.config.translation }); emptyMessageText = computed(() => { return this.emptyMessage() || this.translation()?.emptyMessage || ''; }, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "emptyMessageText" }] : /* istanbul ignore next */ [])); focusedOptionId = computed(() => { const menu = this.menuViewChild(); if (menu && menu.focusedOptionIndex() !== -1) { return menu.focusedOptionIndex(); } return null; }, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "focusedOptionId" }] : /* istanbul ignore next */ [])); /** * Filtered model: applies score-based filter with sorting by relevance. */ filteredModel = computed(() => { const searchVal = (this.search() ?? '').trim(); const items = this.model() || []; if (!searchVal) return items; const filterFn = this.filter() ?? this.defaultFilter; return items .map((item) => { if (item.items?.length) { const scored = item.items .map((child) => ({ item: child, score: filterFn(child, searchVal) })) .filter(({ score }) => score > 0) .sort((a, b) => b.score - a.score); if (scored.length === 0) return null; return { ...item, items: scored.map((s) => s.item) }; } else if (!item.separator) { const score = filterFn(item, searchVal); return score > 0 ? item : null; } return null; }) .filter(Boolean); }, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "filteredModel" }] : /* istanbul ignore next */ [])); menuModel = computed(() => { const wrap = (item) => { if (item.items?.length) { return { ...item, items: item.items.map(wrap) }; } if (item.separator) { return item; } const original = item.command; return { ...item, command: (event) => { original?.(event); this.onSelect.emit({ originalEvent: event?.originalEvent, item }); } }; }; return this.filteredModel().map(wrap); }, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "menuModel" }] : /* istanbul ignore next */ [])); hasVisibleItems = computed(() => { const model = this.filteredModel(); if (!model || model.length === 0) return false; return model.some((item) => (item.items?.length ?? 0) > 0 || (!item.separator && item.visible !== false)); }, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "hasVisibleItems" }] : /* istanbul ignore next */ [])); onSearchKeyDown(event) { const menu = this.menuViewChild(); if (menu) { menu.onListKeyDown(event); const focusedId = menu.focusedOptionIndex(); if (focusedId != null && focusedId !== -1) { requestAnimationFrame(() => { const el = findSingle(menu.containerViewChild()?.nativeElement, `li[id="${focusedId}"]`); el?.scrollIntoView({ block: 'nearest', inline: 'nearest' }); }); } } } onSearchInput(event) { const value = event.target.value; this.search.set(value); this.onSearchChange.emit({ originalEvent: event, query: value }); } defaultFilter(item, search) { const label = item.label ?? ''; const keywords = item.keywords; const extendValue = label + ' ' + (Array.isArray(keywords) ? keywords.join(' ') : ''); if (extendValue.toLowerCase().includes(search.toLowerCase())) return 1; return 0; } focusInput() { this.searchInputViewChild()?.nativeElement?.focus(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: CommandMenu, deps: null, target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: CommandMenu, isStandalone: true, selector: "p-commandmenu, p-command-menu", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: false, transformFunction: null }, search: { classPropertyName: "search", publicName: "search", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledBy: { classPropertyName: "ariaLabelledBy", publicName: "ariaLabelledBy", isSignal: true, isRequired: false, transformFunction: null }, menuStyle: { classPropertyName: "menuStyle", publicName: "menuStyle", isSignal: true, isRequired: false, transformFunction: null }, menuStyleClass: { classPropertyName: "menuStyleClass", publicName: "menuStyleClass", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { search: "searchChange", onSearchChange: "onSearchChange", onSelect: "onSelect" }, host: { properties: { "attr.id": "$id()", "class": "cx('root')" } }, providers: [CommandMenuStyle, { provide: PARENT_INSTANCE, useExisting: CommandMenu }], queries: [{ propertyName: "itemTemplate", first: true, predicate: ["item"], isSignal: true }, { propertyName: "headerTemplate", first: true, predicate: ["header"], isSignal: true }, { propertyName: "footerTemplate", first: true, predicate: ["footer"], isSignal: true }, { propertyName: "emptyMessageTemplate", first: true, predicate: ["emptyMessage"], isSignal: true }], viewQueries: [{ propertyName: "menuViewChild", first: true, predicate: ["menu"], descendants: true, isSignal: true }, { propertyName: "searchInputViewChild", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }], usesInheritance: true, hostDirectives: [{ directive: i1.Bind }], ngImport: i0, template: ` <div [class]="cx('header')" [pBind]="ptm('header')"> @if (headerTemplate()) { <ng-container *ngTemplateOutlet="headerTemplate(); context: { $implicit: search() }"></ng-container> } <input #searchInput type="text" role="combobox" [class]="cx('input')" [value]="search()" [placeholder]="placeholder()" [attr.aria-label]="ariaLabel()" [attr.aria-labelledby]="ariaLabelledBy()" [attr.aria-expanded]="true" [attr.aria-controls]="listId()" [attr.aria-activedescendant]="focusedOptionId()" autocomplete="off" autocorrect="off" spellcheck="false" (input)="onSearchInput($event)" (keydown)="onSearchKeyDown($event)" [pBind]="ptm('input')" /> </div> <div [class]="cx('list')" [pBind]="ptm('list')"> @if (hasVisibleItems()) { <p-menu #menu [model]="menuModel()" [tabindex]="-1" [style]="menuStyle()" [styleClass]="menuStyleClass()" [pt]="ptm('pcMenu')" [unstyled]="unstyled()"> @if (itemTemplate()) { <ng-template #item let-item> <ng-container *ngTemplateOutlet="itemTemplate()!; context: { $implicit: item }"></ng-container> </ng-template> } </p-menu> } @else { <div [class]="cx('emptyMessage')" [pBind]="ptm('emptyMessage')"> @if (emptyMessageTemplate()) { <ng-container *ngTemplateOutlet="emptyMessageTemplate(); context: { $implicit: search() }"></ng-container> } @else { {{ emptyMessageText() }} } </div> } </div> @if (footerTemplate()) { <div [class]="cx('footer')" [pBind]="ptm('footer')"> <ng-container *ngTemplateOutlet="footerTemplate(); context: { $implicit: search() }"></ng-container> </div> } `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: MenuModule }, { kind: "component", type: i2.Menu, selector: "p-menu", inputs: ["model", "popup", "style", "styleClass", "autoZIndex", "baseZIndex", "ariaLabel", "ariaLabelledBy", "id", "tabindex", "appendTo", "motionOptions", "expandedKeys"], outputs: ["expandedKeysChange", "onShow", "onHide", "onBlur", "onFocus"] }, { kind: "ngmodule", type: SharedModule }, { kind: "ngmodule", type: BindModule }, { kind: "directive", type: i1.Bind, selector: "[pBind]", inputs: ["pBind"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: CommandMenu, decorators: [{ type: Component, args: [{ selector: 'p-commandmenu, p-command-menu', standalone: true, imports: [NgTemplateOutlet, MenuModule, SharedModule, BindModule], template: ` <div [class]="cx('header')" [pBind]="ptm('header')"> @if (headerTemplate()) { <ng-container *ngTemplateOutlet="headerTemplate(); context: { $implicit: search() }"></ng-container> } <input #searchInput type="text" role="combobox" [class]="cx('input')" [value]="search()" [placeholder]="placeholder()" [attr.aria-label]="ariaLabel()" [attr.aria-labelledby]="ariaLabelledBy()" [attr.aria-expanded]="true" [attr.aria-controls]="listId()" [attr.aria-activedescendant]="focusedOptionId()" autocomplete="off" autocorrect="off" spellcheck="false" (input)="onSearchInput($event)" (keydown)="onSearchKeyDown($event)" [pBind]="ptm('input')" /> </div> <div [class]="cx('list')" [pBind]="ptm('list')"> @if (hasVisibleItems()) { <p-menu #menu [model]="menuModel()" [tabindex]="-1" [style]="menuStyle()" [styleClass]="menuStyleClass()" [pt]="ptm('pcMenu')" [unstyled]="unstyled()"> @if (itemTemplate()) { <ng-template #item let-item> <ng-container *ngTemplateOutlet="itemTemplate()!; context: { $implicit: item }"></ng-container> </ng-template> } </p-menu> } @else { <div [class]="cx('emptyMessage')" [pBind]="ptm('emptyMessage')"> @if (emptyMessageTemplate()) { <ng-container *ngTemplateOutlet="emptyMessageTemplate(); context: { $implicit: search() }"></ng-container> } @else { {{ emptyMessageText() }} } </div> } </div> @if (footerTemplate()) { <div [class]="cx('footer')" [pBind]="ptm('footer')"> <ng-container *ngTemplateOutlet="footerTemplate(); context: { $implicit: search() }"></ng-container> </div> } `, providers: [CommandMenuStyle, { provide: PARENT_INSTANCE, useExisting: CommandMenu }], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { '[attr.id]': '$id()', '[class]': "cx('root')" }, hostDirectives: [Bind] }] }], propDecorators: { model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: false }] }], search: [{ type: i0.Input, args: [{ isSignal: true, alias: "search", required: false }] }, { type: i0.Output, args: ["searchChange"] }], filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], ariaLabelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabelledBy", required: false }] }], menuStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "menuStyle", required: false }] }], menuStyleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "menuStyleClass", required: false }] }], onSearchChange: [{ type: i0.Output, args: ["onSearchChange"] }], onSelect: [{ type: i0.Output, args: ["onSelect"] }], itemTemplate: [{ type: i0.ContentChild, args: ['item', { ...{ descendants: false }, isSignal: true }] }], headerTemplate: [{ type: i0.ContentChild, args: ['header', { ...{ descendants: false }, isSignal: true }] }], footerTemplate: [{ type: i0.ContentChild, args: ['footer', { ...{ descendants: false }, isSignal: true }] }], emptyMessageTemplate: [{ type: i0.ContentChild, args: ['emptyMessage', { ...{ descendants: false }, isSignal: true }] }], menuViewChild: [{ type: i0.ViewChild, args: ['menu', { isSignal: true }] }], searchInputViewChild: [{ type: i0.ViewChild, args: ['searchInput', { isSignal: true }] }] } }); class CommandMenuModule { static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: CommandMenuModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.6", ngImport: i0, type: CommandMenuModule, imports: [CommandMenu, SharedModule], exports: [CommandMenu, SharedModule] }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: CommandMenuModule, imports: [CommandMenu, SharedModule, SharedModule] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: CommandMenuModule, decorators: [{ type: NgModule, args: [{ imports: [CommandMenu, SharedModule], exports: [CommandMenu, SharedModule] }] }] }); /** * Generated bundle index. Do not edit. */ export { CommandMenu, CommandMenuClasses, CommandMenuModule, CommandMenuStyle }; //# sourceMappingURL=primeng-commandmenu.mjs.map