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
JavaScript
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')">
(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')">
(hasVisibleItems()) {
<p-menu #menu [model]="menuModel()" [tabindex]="-1" [style]="menuStyle()" [styleClass]="menuStyleClass()" [pt]="ptm('pcMenu')" [unstyled]="unstyled()">
(itemTemplate()) {
<ng-template #item let-item>
<ng-container *ngTemplateOutlet="itemTemplate()!; context: { $implicit: item }"></ng-container>
</ng-template>
}
</p-menu>
} {
<div [class]="cx('emptyMessage')" [pBind]="ptm('emptyMessage')">
(emptyMessageTemplate()) {
<ng-container *ngTemplateOutlet="emptyMessageTemplate(); context: { $implicit: search() }"></ng-container>
} {
{{ emptyMessageText() }}
}
</div>
}
</div>
(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')">
(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')">
(hasVisibleItems()) {
<p-menu #menu [model]="menuModel()" [tabindex]="-1" [style]="menuStyle()" [styleClass]="menuStyleClass()" [pt]="ptm('pcMenu')" [unstyled]="unstyled()">
(itemTemplate()) {
<ng-template #item let-item>
<ng-container *ngTemplateOutlet="itemTemplate()!; context: { $implicit: item }"></ng-container>
</ng-template>
}
</p-menu>
} {
<div [class]="cx('emptyMessage')" [pBind]="ptm('emptyMessage')">
(emptyMessageTemplate()) {
<ng-container *ngTemplateOutlet="emptyMessageTemplate(); context: { $implicit: search() }"></ng-container>
} {
{{ emptyMessageText() }}
}
</div>
}
</div>
(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