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,

979 lines (976 loc) 74.5 kB
import { NgTemplateOutlet } from '@angular/common'; import * as i0 from '@angular/core'; import { Injectable, forwardRef, InjectionToken, inject, input, booleanAttribute, numberAttribute, output, computed, viewChild, contentChild, signal, effect, untracked, ViewEncapsulation, ChangeDetectionStrategy, Component, NgModule } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { uuid, isNotEmpty, getFocusableElements, getFirstFocusableElement, focus, getLastFocusableElement } from '@primeuix/utils'; import { SharedModule } from 'primeng/api'; import { AutoFocus } from 'primeng/autofocus'; import { PARENT_INSTANCE } from 'primeng/basecomponent'; import { BaseEditableHolder } from 'primeng/baseeditableholder'; import * as i1 from 'primeng/bind'; import { Bind } from 'primeng/bind'; import { Chip } from 'primeng/chip'; import { Fluid } from 'primeng/fluid'; import { ChevronDown } from '@primeicons/angular/chevron-down'; import { Times } from '@primeicons/angular/times'; import { Overlay } from 'primeng/overlay'; import { Tree } from 'primeng/tree'; import { style } from '@primeuix/styles/treeselect'; import { BaseStyle } from 'primeng/base'; export * from 'primeng/types/treeselect'; const inlineStyles = { root: ({ instance }) => ({ position: instance.$appendTo() === 'self' ? 'relative' : undefined }) }; const classes = { root: ({ instance }) => [ 'p-treeselect p-component p-inputwrapper', { 'p-treeselect-display-chip': instance.display() === 'chip', 'p-disabled': instance.$disabled(), 'p-invalid': instance.invalid(), 'p-focus': instance.focused(), 'p-variant-filled': instance.$variant() === 'filled', 'p-inputwrapper-filled': !instance.emptyValue(), 'p-inputwrapper-focus': instance.focused() || instance.overlayVisible(), 'p-treeselect-open': instance.overlayVisible(), 'p-treeselect-fluid': instance.hasFluid, 'p-treeselect-sm p-inputfield-sm': instance.size() === 'small', 'p-treeselect-lg p-inputfield-lg': instance.size() === 'large' } ], labelContainer: 'p-treeselect-label-container', label: ({ instance }) => [ 'p-treeselect-label', { 'p-placeholder': instance.label() === instance.placeholder(), 'p-treeselect-label-empty': !instance.placeholder() && instance.emptyValue() } ], clearIcon: 'p-treeselect-clear-icon', chip: 'p-treeselect-chip-item', pcChip: 'p-treeselect-chip', dropdown: 'p-treeselect-dropdown', dropdownIcon: 'p-treeselect-dropdown-icon', panel: 'p-treeselect-overlay p-component-overlay p-component', treeContainer: 'p-treeselect-tree-container', emptyMessage: 'p-treeselect-empty-message' }; class TreeSelectStyle extends BaseStyle { name = 'treeselect'; style = style; classes = classes; inlineStyles = inlineStyles; static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: TreeSelectStyle, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: TreeSelectStyle }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: TreeSelectStyle, decorators: [{ type: Injectable }] }); /** * * TreeSelect is a form component to choose from hierarchical data. * * [Live Demo](https://www.primeng.org/treeselect/) * * @module treeselectstyle * */ var TreeSelectClasses; (function (TreeSelectClasses) { /** * Class name of the root element */ TreeSelectClasses["root"] = "p-treeselect"; /** * Class name of the label container element */ TreeSelectClasses["labelContainer"] = "p-treeselect-label-container"; /** * Class name of the label element */ TreeSelectClasses["label"] = "p-treeselect-label"; /** * Class name of the chip item element */ TreeSelectClasses["chipItem"] = "p-treeselect-chip-item"; /** * Class name of the clear icon element */ TreeSelectClasses["clearIcon"] = "p-treeselect-clear-icon"; /** * Class name of the chip element */ TreeSelectClasses["pcChip"] = "p-treeselect-chip"; /** * Class name of the dropdown element */ TreeSelectClasses["dropdown"] = "p-treeselect-dropdown"; /** * Class name of the dropdown icon element */ TreeSelectClasses["dropdownIcon"] = "p-treeselect-dropdown-icon"; /** * Class name of the panel element */ TreeSelectClasses["panel"] = "p-treeselect-overlay"; /** * Class name of the tree container element */ TreeSelectClasses["treeContainer"] = "p-treeselect-tree-container"; /** * Class name of the empty message element */ TreeSelectClasses["emptyMessage"] = "p-treeselect-empty-message"; })(TreeSelectClasses || (TreeSelectClasses = {})); const TREESELECT_VALUE_ACCESSOR = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TreeSelect), multi: true }; const TREESELECT_INSTANCE = new InjectionToken('TREESELECT_INSTANCE'); /** * TreeSelect is a form component to choose from hierarchical data. * @group Components */ class TreeSelect extends BaseEditableHolder { componentName = 'TreeSelect'; $pcTreeSelect = inject(TREESELECT_INSTANCE, { optional: true, skipSelf: true }) ?? undefined; bindDirectiveInstance = inject(Bind, { self: true }); _componentStyle = inject(TreeSelectStyle); /** * Identifier of the underlying input element. * @group Props */ inputId = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "inputId" }] : /* istanbul ignore next */ [])); /** * Height of the viewport, a scrollbar is defined if height of list exceeds this value. * @group Props */ scrollHeight = input('400px', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "scrollHeight" }] : /* istanbul ignore next */ [])); /** * Defines how multiple items can be selected, when true metaKey needs to be pressed to select or unselect an item and when set to false selection of each item can be toggled individually. On touch enabled devices, metaKeySelection is turned off automatically. * @group Props */ metaKeySelection = input(false, { ...(ngDevMode ? { debugName: "metaKeySelection" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** * Defines how the selected items are displayed. * @group Props */ display = input('comma', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "display" }] : /* istanbul ignore next */ [])); /** * Defines the selection mode. * @group Props */ selectionMode = input('single', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "selectionMode" }] : /* istanbul ignore next */ [])); /** * Index of the element in tabbing order. * @group Props */ tabindex = input('0', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "tabindex" }] : /* 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 */ [])); /** * Establishes relationships between the component and label(s) where its value should be one or more element IDs. * @group Props */ ariaLabelledBy = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "ariaLabelledBy" }] : /* istanbul ignore next */ [])); /** * Label to display when there are no selections. * @group Props */ placeholder = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "placeholder" }] : /* istanbul ignore next */ [])); /** * Style class of the overlay panel. * @group Props */ panelClass = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "panelClass" }] : /* istanbul ignore next */ [])); /** * Inline style of the panel element. * @group Props */ panelStyle = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "panelStyle" }] : /* istanbul ignore next */ [])); /** * Style class of the panel element. * @group Props */ panelStyleClass = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "panelStyleClass" }] : /* istanbul ignore next */ [])); /** * Inline style of the label element. * @group Props */ labelStyle = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "labelStyle" }] : /* istanbul ignore next */ [])); /** * Style class of the label element. * @group Props */ labelStyleClass = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "labelStyleClass" }] : /* istanbul ignore next */ [])); /** * Specifies the options for the overlay. * @group Props */ overlayOptions = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "overlayOptions" }] : /* istanbul ignore next */ [])); /** * Text to display when there are no options available. Defaults to value from PrimeNG locale configuration. * @group Props */ emptyMessage = input('', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ [])); /** * When specified, displays an input field to filter the items. * @group Props */ filter = input(false, { ...(ngDevMode ? { debugName: "filter" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** * When filtering is enabled, filterBy decides which field or fields (comma separated) to search against. * @group Props */ filterBy = input('label', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "filterBy" }] : /* istanbul ignore next */ [])); /** * Mode for filtering valid values are "lenient" and "strict". Default is lenient. * @group Props */ filterMode = input('lenient', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "filterMode" }] : /* istanbul ignore next */ [])); /** * Placeholder text to show when filter input is empty. * @group Props */ filterPlaceholder = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "filterPlaceholder" }] : /* istanbul ignore next */ [])); /** * Locale to use in filtering. The default locale is the host environment's current locale. * @group Props */ filterLocale = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "filterLocale" }] : /* istanbul ignore next */ [])); /** * Determines whether the filter input should be automatically focused when the component is rendered. * @group Props */ filterInputAutoFocus = input(true, { ...(ngDevMode ? { debugName: "filterInputAutoFocus" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** * Whether checkbox selections propagate to descendant nodes. * @group Props */ propagateSelectionDown = input(true, { ...(ngDevMode ? { debugName: "propagateSelectionDown" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** * Whether checkbox selections propagate to ancestor nodes. * @group Props */ propagateSelectionUp = input(true, { ...(ngDevMode ? { debugName: "propagateSelectionUp" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** * When enabled, a clear icon is displayed to clear the value. * @group Props */ showClear = input(false, { ...(ngDevMode ? { debugName: "showClear" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** * Clears the filter value when hiding the dropdown. * @group Props */ resetFilterOnHide = input(true, { ...(ngDevMode ? { debugName: "resetFilterOnHide" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** * Whether the data should be loaded on demand during scroll. * @group Props */ virtualScroll = input(undefined, { ...(ngDevMode ? { debugName: "virtualScroll" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** * Height of an item in the list for VirtualScrolling. * @group Props */ virtualScrollItemSize = input(undefined, { ...(ngDevMode ? { debugName: "virtualScrollItemSize" } : /* istanbul ignore next */ {}), transform: numberAttribute }); /** * Whether to use the scroller feature. The properties of scroller component can be used like an object in it. * @group Props */ virtualScrollOptions = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "virtualScrollOptions" }] : /* istanbul ignore next */ [])); /** * When present, it specifies that the component should automatically get focus on load. * @group Props */ autofocus = input(undefined, { ...(ngDevMode ? { debugName: "autofocus" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** * An array of treenodes. * @defaultValue undefined * @group Props */ options = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "options" }] : /* istanbul ignore next */ [])); /** * Displays a loader to indicate data load is in progress. * @group Props */ loading = input(undefined, { ...(ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** * Loading mode display. * @group Props */ loadingMode = input('mask', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "loadingMode" }] : /* istanbul ignore next */ [])); /** * Specifies the size of the component. * @defaultValue undefined * @group Props */ size = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "size" }] : /* istanbul ignore next */ [])); /** * Specifies the input variant of the component. * @defaultValue undefined * @group Props */ variant = input(/* @ts-ignore */ ...(ngDevMode ? [undefined, { debugName: "variant" }] : /* istanbul ignore next */ [])); /** * Spans 100% width of the container when enabled. * @defaultValue undefined * @group Props */ fluid = input(undefined, { ...(ngDevMode ? { debugName: "fluid" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** * Target element to attach the overlay, valid values are "body" or a local ng-template variable of another element (note: use binding with brackets for template variables, e.g. [appendTo]="mydiv" for a div element having #mydiv as variable name). * @defaultValue 'self' * @group Props */ appendTo = input(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "appendTo" }] : /* istanbul ignore next */ [])); /** * The motion options. * @group Props */ motionOptions = input(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "motionOptions" }] : /* istanbul ignore next */ [])); /** * Callback to invoke when a node is expanded. * @param {TreeSelectNodeExpandEvent} event - Custom node expand event. * @group Emits */ onNodeExpand = output(); /** * Callback to invoke when a node is collapsed. * @param {TreeSelectNodeCollapseEvent} event - Custom node collapse event. * @group Emits */ onNodeCollapse = output(); /** * Callback to invoke when the overlay is shown. * @param {Event} event - Browser event. * @group Emits */ onShow = output(); /** * Callback to invoke when the overlay is hidden. * @param {Event} event - Browser event. * @group Emits */ onHide = output(); /** * Callback to invoke when input field is cleared. * @group Emits */ onClear = output(); /** * Callback to invoke when data is filtered. * @group Emits */ onFilter = output(); /** * Callback to invoke when treeselect gets focus. * @param {Event} event - Browser event. * @group Emits */ onFocus = output(); /** * Callback to invoke when treeselect loses focus. * @param {Event} event - Browser event. * @group Emits */ onBlur = output(); /** * Callback to invoke when a node is unselected. * @param {TreeNodeUnSelectEvent} event - node unselect event. * @group Emits */ onNodeUnselect = output(); /** * Callback to invoke when a node is selected. * @param {TreeNodeSelectEvent} event - node select event. * @group Emits */ onNodeSelect = output(); $appendTo = computed(() => this.appendTo() || this.config.overlayAppendTo(), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$appendTo" }] : /* istanbul ignore next */ [])); focusInputViewChild = viewChild('focusInput', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "focusInputViewChild" }] : /* istanbul ignore next */ [])); filterViewChild = viewChild('filter', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "filterViewChild" }] : /* istanbul ignore next */ [])); treeViewChild = viewChild('tree', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "treeViewChild" }] : /* istanbul ignore next */ [])); panelEl = viewChild('panel', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "panelEl" }] : /* istanbul ignore next */ [])); overlayViewChild = viewChild('overlay', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "overlayViewChild" }] : /* istanbul ignore next */ [])); firstHiddenFocusableElementOnOverlay = viewChild('firstHiddenFocusableEl', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "firstHiddenFocusableElementOnOverlay" }] : /* istanbul ignore next */ [])); lastHiddenFocusableElementOnOverlay = viewChild('lastHiddenFocusableEl', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "lastHiddenFocusableElementOnOverlay" }] : /* istanbul ignore next */ [])); $variant = computed(() => this.variant() || this.config.inputVariant(), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$variant" }] : /* istanbul ignore next */ [])); pcFluid = inject(Fluid, { optional: true, host: true, skipSelf: true }); get hasFluid() { return this.fluid() ?? !!this.pcFluid; } filteredNodes; filterValue = null; serializedValue; /** * Custom value template. * @param {TreeSelectValueTemplateContext} context - value context. * @see {@link TreeSelectValueTemplateContext} * @group Templates */ valueTemplate = contentChild('value', { ...(ngDevMode ? { debugName: "valueTemplate" } : /* istanbul ignore next */ {}), descendants: false }); /** * Custom header template. * @param {TreeSelectHeaderTemplateContext} context - header context. * @see {@link TreeSelectHeaderTemplateContext} * @group Templates */ headerTemplate = contentChild('header', { ...(ngDevMode ? { debugName: "headerTemplate" } : /* istanbul ignore next */ {}), descendants: false }); /** * Custom empty message template. * @group Templates */ emptyTemplate = contentChild('empty', { ...(ngDevMode ? { debugName: "emptyTemplate" } : /* istanbul ignore next */ {}), descendants: false }); /** * Custom footer template. * @param {TreeSelectHeaderTemplateContext} context - footer context. * @see {@link TreeSelectHeaderTemplateContext} * @group Templates */ footerTemplate = contentChild('footer', { ...(ngDevMode ? { debugName: "footerTemplate" } : /* istanbul ignore next */ {}), descendants: false }); /** * Custom clear icon template. * @group Templates */ clearIconTemplate = contentChild('clearicon', { ...(ngDevMode ? { debugName: "clearIconTemplate" } : /* istanbul ignore next */ {}), descendants: false }); /** * Custom trigger icon template. * @group Templates */ triggerIconTemplate = contentChild('triggericon', { ...(ngDevMode ? { debugName: "triggerIconTemplate" } : /* istanbul ignore next */ {}), descendants: false }); /** * Custom dropdown icon template. * @group Templates */ dropdownIconTemplate = contentChild('dropdownicon', { ...(ngDevMode ? { debugName: "dropdownIconTemplate" } : /* istanbul ignore next */ {}), descendants: false }); /** * Custom filter icon template. * @group Templates */ filterIconTemplate = contentChild('filtericon', { ...(ngDevMode ? { debugName: "filterIconTemplate" } : /* istanbul ignore next */ {}), descendants: false }); /** * Custom close icon template. * @group Templates */ closeIconTemplate = contentChild('closeicon', { ...(ngDevMode ? { debugName: "closeIconTemplate" } : /* istanbul ignore next */ {}), descendants: false }); /** * Custom item toggler icon template. * @param {TreeSelectItemTogglerIconTemplateContext} context - toggler icon context. * @see {@link TreeSelectItemTogglerIconTemplateContext} * @group Templates */ itemTogglerIconTemplate = contentChild('itemtogglericon', { ...(ngDevMode ? { debugName: "itemTogglerIconTemplate" } : /* istanbul ignore next */ {}), descendants: false }); /** * Custom item checkbox icon template. * @param {TreeSelectItemCheckboxIconTemplateContext} context - checkbox icon context. * @see {@link TreeSelectItemCheckboxIconTemplateContext} * @group Templates */ itemCheckboxIconTemplate = contentChild('itemcheckboxicon', { ...(ngDevMode ? { debugName: "itemCheckboxIconTemplate" } : /* istanbul ignore next */ {}), descendants: false }); /** * Custom item loading icon template. * @group Templates */ itemLoadingIconTemplate = contentChild('itemloadingicon', { ...(ngDevMode ? { debugName: "itemLoadingIconTemplate" } : /* istanbul ignore next */ {}), descendants: false }); focused = signal(false, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "focused" }] : /* istanbul ignore next */ [])); overlayVisible = signal(false, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "overlayVisible" }] : /* istanbul ignore next */ [])); _value = signal(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "_value" }] : /* istanbul ignore next */ [])); expandedNodes = []; _options = signal(undefined, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "_options" }] : /* istanbul ignore next */ [])); listId = ''; valueTemplateContext = computed(() => ({ $implicit: this._value(), placeholder: this.placeholder() }), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "valueTemplateContext" }] : /* istanbul ignore next */ [])); headerTemplateContext = computed(() => ({ $implicit: this._value(), options: this._options() }), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "headerTemplateContext" }] : /* istanbul ignore next */ [])); footerTemplateContext = computed(() => ({ $implicit: this._value(), options: this._options() }), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "footerTemplateContext" }] : /* istanbul ignore next */ [])); label = computed(() => { const value = this._value() || []; return value.length ? value.map((node) => node.label).join(', ') : this.selectionMode() === 'single' && this._value() ? this._value().label : this.placeholder(); }, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ [])); emptyValue = computed(() => !this._value() || Object.keys(this._value()).length === 0, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "emptyValue" }] : /* istanbul ignore next */ [])); emptyOptions = computed(() => !this._options() || this._options().length === 0, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "emptyOptions" }] : /* istanbul ignore next */ [])); $inputDisabledAttr = computed(() => (this.$disabled() ? '' : undefined), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$inputDisabledAttr" }] : /* istanbul ignore next */ [])); $inputTabindex = computed(() => (!this.$disabled() ? this.tabindex() : '-1'), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$inputTabindex" }] : /* istanbul ignore next */ [])); $ariaControls = computed(() => (this.overlayVisible() ? this.listId : null), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$ariaControls" }] : /* istanbul ignore next */ [])); $ariaExpanded = computed(() => this.overlayVisible() ?? false, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$ariaExpanded" }] : /* istanbul ignore next */ [])); $inputAriaLabel = computed(() => { const ariaLabel = this.ariaLabel(); const label = this.label(); return ariaLabel || (label === 'p-emptylabel' ? undefined : label); }, /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$inputAriaLabel" }] : /* istanbul ignore next */ [])); $showClearIcon = computed(() => this.checkValue() && !this.$disabled() && this.showClear(), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$showClearIcon" }] : /* istanbul ignore next */ [])); $showDefaultDropdownIcon = computed(() => !this.triggerIconTemplate() && !this.dropdownIconTemplate(), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$showDefaultDropdownIcon" }] : /* istanbul ignore next */ [])); $dropdownIconTemplate = computed(() => this.triggerIconTemplate() || this.dropdownIconTemplate(), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$dropdownIconTemplate" }] : /* istanbul ignore next */ [])); $labelText = computed(() => this.label() || 'empty', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$labelText" }] : /* istanbul ignore next */ [])); $placeholderText = computed(() => this.placeholder() || 'empty', /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$placeholderText" }] : /* istanbul ignore next */ [])); $treeContainerStyle = computed(() => ({ 'max-height': this.scrollHeight() }), /* @ts-ignore */ ...(ngDevMode ? [{ debugName: "$treeContainerStyle" }] : /* istanbul ignore next */ [])); constructor() { super(); // Handle options input changes effect(() => { const opts = this.options(); untracked(() => { this._options.set(opts); this.updateTreeState(); }); }); } onAfterViewChecked() { this.bindDirectiveInstance.setAttrs(this.ptms(['host', 'root'])); } onInit() { this.listId = uuid('pn_id_') + '_list'; this.updateTreeState(); } onOverlayBeforeEnter() { if (this.filter()) { isNotEmpty(this.filterValue) && this.treeViewChild()?._filter(this.filterValue); this.filterInputAutoFocus() && this.filterViewChild()?.nativeElement.focus(); } else { let focusableElements = getFocusableElements(this.panelEl()?.nativeElement); if (focusableElements && focusableElements.length > 0) { focusableElements[0].focus(); } } } onOverlayBeforeHide() { let focusableElements = getFocusableElements(this.el.nativeElement); if (focusableElements && focusableElements.length > 0) { focusableElements[0].focus(); } } onSelectionChange(event) { this._value.set(event); this.onModelChange(this._value()); } onClick(event) { if (this.$disabled()) { return; } const section = event.target?.getAttribute?.('data-pc-section'); if (event.target?.closest?.('[data-pc-section="clearicon"]')) { return; } if (!this.overlayViewChild()?.el?.nativeElement?.contains(event.target) && section !== 'box' && section !== 'icon') { if (this.overlayVisible()) { this.hide(); } else { this.show(); } this.focusInputViewChild()?.nativeElement.focus(); } } onKeyDown(event) { switch (event.code) { //down case 'ArrowDown': if (!this.overlayVisible()) { this.show(); event.preventDefault(); } this.onArrowDown(event); event.preventDefault(); break; //space case 'Space': case 'Enter': if (!this.overlayVisible()) { this.show(); event.preventDefault(); } break; //escape case 'Escape': if (this.overlayVisible()) { this.hide(); this.focusInputViewChild()?.nativeElement.focus(); event.preventDefault(); } break; //tab case 'Tab': this.onTabKey(event); break; default: break; } } onFilterInput(event) { this.filterValue = event.target.value; this.treeViewChild()?._filter(this.filterValue); this.onFilter.emit({ filter: this.filterValue, filteredValue: this.treeViewChild()?.filteredNodes }); setTimeout(() => { this.overlayViewChild()?.alignOverlay(); }); } onArrowDown(event) { if (this.overlayVisible() && this.panelEl()?.nativeElement) { let focusableElements = getFocusableElements(this.panelEl().nativeElement, '[data-pc-section="node"]'); if (focusableElements && focusableElements.length > 0) { focusableElements[0].focus(); } event.preventDefault(); } } onFirstHiddenFocus(event) { const focusableEl = event.relatedTarget === this.focusInputViewChild()?.nativeElement ? getFirstFocusableElement(this.overlayViewChild()?.overlayViewChild()?.nativeElement, ':not([data-p-hidden-focusable="true"])') : this.focusInputViewChild()?.nativeElement; focus(focusableEl); } onLastHiddenFocus(event) { const focusableEl = event.relatedTarget === this.focusInputViewChild()?.nativeElement ? getLastFocusableElement(this.overlayViewChild()?.overlayViewChild()?.nativeElement, ':not([data-p-hidden-focusable="true"])') : this.focusInputViewChild()?.nativeElement; focus(focusableEl); } show() { this.overlayVisible.set(true); } hide(event) { this.overlayVisible.set(false); this.resetFilter(); this.onHide.emit(event); } clear(event) { this._value.set(null); this.resetExpandedNodes(); this.resetPartialSelected(); this.onModelChange(this._value()); this.onClear.emit(null); event.stopPropagation(); } checkValue() { return this._value() !== null && isNotEmpty(this._value()); } onTabKey(event, pressedInInputText = false) { if (!pressedInInputText) { if (this.overlayVisible() && this.hasFocusableElements()) { focus(event.shiftKey ? this.lastHiddenFocusableElementOnOverlay()?.nativeElement : this.firstHiddenFocusableElementOnOverlay()?.nativeElement); event.preventDefault(); } else { this.overlayVisible() && this.hide(this.filter()); } } } hasFocusableElements() { return getFocusableElements(this.overlayViewChild()?.overlayViewChild()?.nativeElement, ':not([data-p-hidden-focusable="true"])').length > 0; } resetFilter() { if (this.filter() && !this.resetFilterOnHide()) { this.filteredNodes = this.treeViewChild()?.filteredNodes; this.treeViewChild()?.resetFilter(); } else { this.filterValue = null; } } updateTreeState() { if (this._value()) { let selectedNodes = this.selectionMode() === 'single' ? [this._value()] : [...this._value()]; this.resetExpandedNodes(); this.resetPartialSelected(); if (selectedNodes && this._options()) { this.updateTreeBranchState(null, null, selectedNodes); } } } updateTreeBranchState(node, path, selectedNodes) { if (node) { if (this.isSelected(node)) { this.expandPath(path); selectedNodes.splice(selectedNodes.indexOf(node), 1); } if (selectedNodes.length > 0 && node.children) { for (let childNode of node.children) { this.updateTreeBranchState(childNode, [...path, node], selectedNodes); } } } else { for (let childNode of this._options()) { this.updateTreeBranchState(childNode, [], selectedNodes); } } } expandPath(expandedNodes) { for (let node of expandedNodes) { node.expanded = true; } this.expandedNodes = [...expandedNodes]; } nodeExpand(event) { this.onNodeExpand.emit(event); this.expandedNodes.push(event.node); setTimeout(() => { this.overlayViewChild()?.alignOverlay(); }); } nodeCollapse(event) { this.onNodeCollapse.emit(event); this.expandedNodes.splice(this.expandedNodes.indexOf(event.node), 1); setTimeout(() => { this.overlayViewChild()?.alignOverlay(); }); } resetExpandedNodes() { for (let node of this.expandedNodes) { node.expanded = false; } this.expandedNodes = []; } resetPartialSelected(nodes = this._options()) { if (!nodes) { return; } for (let node of nodes) { node.partialSelected = false; if (node.children && node.children?.length > 0) { this.resetPartialSelected(node.children); } } } findSelectedNodes(node, keys, selectedNodes) { if (node) { if (this.isSelected(node)) { selectedNodes.push(node); delete keys[node.key]; } if (Object.keys(keys).length && node.children) { for (let childNode of node.children) { this.findSelectedNodes(childNode, keys, selectedNodes); } } } else { for (let childNode of this._options()) { this.findSelectedNodes(childNode, keys, selectedNodes); } } } isSelected(node) { return this.findIndexInSelection(node) != -1; } findIndexInSelection(node) { let index = -1; const value = this._value(); if (value) { if (this.selectionMode() === 'single') { let areNodesEqual = (value.key && value.key === node.key) || value == node; index = areNodesEqual ? 0 : -1; } else { for (let i = 0; i < value.length; i++) { let selectedNode = value[i]; let areNodesEqual = (selectedNode.key && selectedNode.key === node.key) || selectedNode == node; if (areNodesEqual) { index = i; break; } } } } return index; } onSelect(event) { this.onNodeSelect.emit(event); if (this.selectionMode() === 'single') { this.hide(); this.focusInputViewChild()?.nativeElement.focus(); } } onUnselect(event) { this.onNodeUnselect.emit(event); } onInputFocus(event) { if (this.$disabled()) { // For ScreenReaders return; } this.focused.set(true); this.onFocus.emit(event); } onInputBlur(event) { this.focused.set(false); this.onBlur.emit(event); this.onModelTouched(); } /** * @override * * @see {@link BaseEditableHolder.writeControlValue} * Writes the value to the control. */ writeControlValue(value) { this._value.set(value); this.updateTreeState(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: TreeSelect, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: TreeSelect, isStandalone: true, selector: "p-tree-select, p-treeselect", inputs: { inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null }, scrollHeight: { classPropertyName: "scrollHeight", publicName: "scrollHeight", isSignal: true, isRequired: false, transformFunction: null }, metaKeySelection: { classPropertyName: "metaKeySelection", publicName: "metaKeySelection", isSignal: true, isRequired: false, transformFunction: null }, display: { classPropertyName: "display", publicName: "display", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, tabindex: { classPropertyName: "tabindex", publicName: "tabindex", 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 }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, panelStyle: { classPropertyName: "panelStyle", publicName: "panelStyle", isSignal: true, isRequired: false, transformFunction: null }, panelStyleClass: { classPropertyName: "panelStyleClass", publicName: "panelStyleClass", isSignal: true, isRequired: false, transformFunction: null }, labelStyle: { classPropertyName: "labelStyle", publicName: "labelStyle", isSignal: true, isRequired: false, transformFunction: null }, labelStyleClass: { classPropertyName: "labelStyleClass", publicName: "labelStyleClass", isSignal: true, isRequired: false, transformFunction: null }, overlayOptions: { classPropertyName: "overlayOptions", publicName: "overlayOptions", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, filterBy: { classPropertyName: "filterBy", publicName: "filterBy", isSignal: true, isRequired: false, transformFunction: null }, filterMode: { classPropertyName: "filterMode", publicName: "filterMode", isSignal: true, isRequired: false, transformFunction: null }, filterPlaceholder: { classPropertyName: "filterPlaceholder", publicName: "filterPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, filterLocale: { classPropertyName: "filterLocale", publicName: "filterLocale", isSignal: true, isRequired: false, transformFunction: null }, filterInputAutoFocus: { classPropertyName: "filterInputAutoFocus", publicName: "filterInputAutoFocus", isSignal: true, isRequired: false, transformFunction: null }, propagateSelectionDown: { classPropertyName: "propagateSelectionDown", publicName: "propagateSelectionDown", isSignal: true, isRequired: false, transformFunction: null }, propagateSelectionUp: { classPropertyName: "propagateSelectionUp", publicName: "propagateSelectionUp", isSignal: true, isRequired: false, transformFunction: null }, showClear: { classPropertyName: "showClear", publicName: "showClear", isSignal: true, isRequired: false, transformFunction: null }, resetFilterOnHide: { classPropertyName: "resetFilterOnHide", publicName: "resetFilterOnHide", isSignal: true, isRequired: false, transformFunction: null }, virtualScroll: { classPropertyName: "virtualScroll", publicName: "virtualScroll", isSignal: true, isRequired: false, transformFunction: null }, virtualScrollItemSize: { classPropertyName: "virtualScrollItemSize", publicName: "virtualScrollItemSize", isSignal: true, isRequired: false, transformFunction: null }, virtualScrollOptions: { classPropertyName: "virtualScrollOptions", publicName: "virtualScrollOptions", isSignal: true, isRequired: false, transformFunction: null }, autofocus: { classPropertyName: "autofocus", publicName: "autofocus", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingMode: { classPropertyName: "loadingMode", publicName: "loadingMode", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, fluid: { classPropertyName: "fluid", publicName: "fluid", isSignal: true, isRequired: false, transformFunction: null }, appendTo: { classPropertyName: "appendTo", publicName: "appendTo", isSignal: true, isRequired: false, transformFunction: null }, motionOptions: { classPropertyName: "motionOptions", publicName: "motionOptions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onNodeExpand: "onNodeExpand", onNodeCollapse: "onNodeCollapse", onShow: "onShow", onHide: "onHide", onClear: "onClear", onFilter: "onFilter", onFocus: "onFocus", onBlur: "onBlur", onNodeUnselect: "onNodeUnselect", onNodeSelect: "onNodeSelect" }, host: { listeners: { "mousedown": "onClick($event)" }, properties: { "class": "cx('root')", "style": "sx('root')" } }, providers: [ TREESELECT_VALUE_ACCESSOR, TreeSelectStyle, { provide: TREESELECT_INSTANCE, useExisting: TreeSelect }, { provide: PARENT_INSTANCE, useExisting: TreeSelect } ], queries: [{ propertyName: "valueTemplate", first: true, predicate: ["value"], isSignal: true }, { propertyName: "headerTemplate", first: true, predicate: ["header"], isSignal: true }, { propertyName: "emptyTemplate", first: true, predicate: ["empty"], isSignal: true }, { propertyName: "footerTemplate", first: true, predicate: ["footer"], isSignal: true }, { propertyName: "clearIconTemplate", first: true, predicate: ["clearicon"], isSignal: true }, { propertyName: "triggerIconTemplate", first: true, predicate: ["triggericon"], isSignal: true }, { propertyName: "dropdownIconTemplate", first: true, predicate: ["dropdownicon"], isSignal: true }, { propertyName: "filterIconTemplate", first: true, predicate: ["filtericon"], isSignal: true }, { propertyName: "closeIconTemplate", first: true, predicate: ["closeicon"], isSignal: true }, { propertyName: "itemTogglerIconTemplate", first: true, predicate: ["itemtogglericon"], isSignal: true }, { propertyName: "itemCheckboxIconTemplate", first: true, predicate: ["itemcheckboxicon"], isSignal: true }, { propertyName: "itemLoadingIconTemplate", first: true, predicate: ["itemloadingicon"], isSignal: true }], viewQueries: [{ propertyName: "focusInputViewChild", first: true, predicate: ["focusInput"], descendants: true, isSignal: true }, { propertyName: "filterViewChild", first: true, predicate: ["filter"], descendants: true, isSignal: true }, { propertyName: "treeViewChild", first: true, predicate: ["tree"], descendants: true, isSignal: true }, { propertyName: "panelEl", first: true, predicate: ["panel"], descendants: true, isSignal: true }, { propertyName: "overlayViewChild", first: true, predicate: ["overlay"], descendants: true, isSignal: true }, { propertyName: "firstHiddenFocusableElementOnOverlay", first: true, predicate: ["firstHiddenFocusableEl"], descendants: true, isSignal: true }, { propertyName: "lastHiddenFocusableElementOnOverlay", first: true, predicate: ["lastHiddenFocusableEl"], descendants: true, isSignal: true }], usesInheritance: true, hostDirectives: [{ directive: i1.Bind }], ngImport: i0, template: ` <div class="p-hidden-accessible" [pBind]="ptm('hiddenInputContainer')" [attr.data-p-hidden-accessible]="true"> <input #focusInput type="text" role="combobox" [attr.id]="inputId()" readonly [attr.disabled]="$inputDisabledAttr()" (focus)="onInputFocus($event)" (blur)="onInputBlur($event)" (keydown)="onKeyDown($event)" [attr.tabindex]="$inputTabindex()" [attr.aria-controls]="$ariaControls()" [attr.aria-haspopup]="'tree'" [attr.aria-expanded]="$ariaExpanded()" [attr.aria-labelledby]="ariaLabelledBy()" [attr.aria-label]="$inputAriaLabel()" [pAutoFocus]="autofocus()" [pBind]="ptm('hiddenInput')" /> </div> <div [class]="cx('labelContainer')" [pBind]="ptm('labelContainer')"> <div [class]="cn(cx('label'), labelStyleClass())" [style]="labelStyle()" [pBind]="ptm('label')"> @if (valueTemplate()) { <ng-container *ngTemplateOutlet="valueTemplate(); context: valueTemplateContext()"></ng-container> } @else { @if (display() === 'comma') { {{ $labelText() }} } @else { @for (node of _value(); track node.key || $index) { <div [class]="cx('chipItem')" [pBind]="ptm('chipItem')"> <p-chip [unstyled]="unstyled()" [label]="node.label" [class]="cx('pcChip')" [pt]="ptm('pcChip')" /> </div> } @if (emptyValue()) { {{ $placeholderText() }} } } } </div> </div> @if ($showClearIcon()) { @if (!clearIconTemplate()) { <svg data-p-icon="times" [class]="cx('clearIcon')" (click)="clear($event)" [pBind]="ptm('clearIcon')" [attr.data-pc-section]="'clearicon'" /> } @else { <span [class]="cx('clearIcon')" (click)="clear($event)" [pBind]="ptm('clearIcon')" [attr.data-pc-section]="'clearicon'"> <ng-template *ngTemplateOutlet="clearIconTemplate()"></ng-template> </span> } } <div [class]="cx('dropdown')" role="button" aria-haspopup="tree" [attr.aria-expanded]="$ariaExpanded()" [attr.aria-label]="'treeselect trigger'" [pBind]="ptm('dropdown')"> @if ($showDefaultDropdownIcon()) { <svg data-p-icon="chevron-down" [class]="cx('dropdownIcon')" [pBind]="ptm('dropdownIcon')" /> } @else { <span [class]="cx('dropdownIcon')" [pBind]="ptm('dropdownIcon')"> <ng-template *ngTemplateOutlet="$dropdownIconTemplate()"></ng-template> </span> } </div> <p-overlay #overlay [hostAttrSelector]="$attrSelector" [visible]="overlayVisible()" (visibleChange)="overlayVisible.set($event)" [options]="overlayOptions()" [target]="'@parent'" [appendTo]="$appendTo()" [unstyled]="unstyled()" [pt]="ptm('pcOverlay')" [motionOptions]="motionOptions()" (onBeforeEnter)="onOverlayBeforeEnter()" (onBeforeHide)="onOverlayBeforeHide()" (onShow)="onShow.emit($event)" (onHide)="hide($event)" > <ng-template #content> <div #panel [attr.id]="listId" [class]="cn(cx('panel'), panelStyleClass(), panelClass())" [style]="panelStyle()" [pBind]="ptm('panel')"> <span #firstHiddenFocusableEl role="presentation" class="p-hidden-accessible p-hidden-focusable" [attr.tabindex]="0" (focus)="onFirstHiddenFocus($event)" [attr.data-p-hidden-accessible]="true" [attr.data-p-hidden-focusable]="true" [pBind]="ptm('hiddenFirstFocusableEl')" > </span> @if (headerTemplate()) { <ng-container *ngTemplateOutlet="headerTemplate(); context: headerTemplateContext()"></ng-container> } <div [class]="cx('treeContainer')" [style]="$treeContainerStyle()" [pBind]="ptm('treeContainer')"> <p-tree #tree