@progress/kendo-angular-dropdowns
Version:
A wide variety of native Angular dropdown components including AutoComplete, ComboBox, DropDownList, DropDownTree, MultiColumnComboBox, MultiSelect, and MultiSelectTree
282 lines (281 loc) • 13 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the project root for more information
*-------------------------------------------------------------------------------------------*/
import { Component, Input, Output, EventEmitter, HostBinding, Renderer2, ElementRef } from '@angular/core';
import { TagTemplateDirective } from '../common/templates/tag-template.directive';
import { GroupTagTemplateDirective } from '../common/templates/group-tag-template.directive';
import { getSizeClass, getter, isPresent } from '../common/util';
import { xCircleIcon } from '@progress/kendo-svg-icons';
import { NgFor, NgClass, NgIf } from '@angular/common';
import { IconWrapperComponent } from '@progress/kendo-angular-icons';
import { TemplateContextDirective } from '@progress/kendo-angular-common';
import * as i0 from "@angular/core";
/**
* @hidden
*/
export class TagListComponent {
renderer;
hostElement;
/**
* @hidden
*/
xCircleIcon = xCircleIcon;
tags;
textField;
valueField;
valueDepth;
focused;
template;
groupTemplate;
disabled;
tagPrefix;
id;
set size(size) {
this.renderer.removeClass(this.hostElement.nativeElement, getSizeClass('chip-list', this.size));
if (size) {
this.renderer.addClass(this.hostElement.nativeElement, getSizeClass('chip-list', size));
}
this._size = size;
}
get size() {
return this._size;
}
rounded = 'medium';
fillMode = 'solid';
/**
* A collection with the disabled tags' indices.
*/
disabledIndices = new Set();
removeTag = new EventEmitter();
hostClass = true;
get hostId() {
return this.id;
}
taglistRole = 'listbox';
multiselectable = true;
_size = 'medium';
constructor(renderer, hostElement) {
this.renderer = renderer;
this.hostElement = hostElement;
}
tagProp(tag, prop, index) {
const propField = prop && this.getPropField(tag, prop, index);
return getter(tag, propField);
}
isTagDisabled(tag, positionIndex) {
if (this.isGroupTag(tag)) {
/** The `positionIndex` is used to determine after how many single tags is the group tag displayed =>
* => it is used to increment the indices inside the group tag so that we determine the actual position index
* of each group tag item as they appear in the `value` (important to check against `disabledIndices`)
* e.g. `disabledIndices = [0, 1]` && `tags = ['Small', ['Medium', 'Large']]` => without the incrementation with
* `positionIndex`, the group tag would yield [0, 1] as indices, while it should yield [1, 2]
*/
return tag.every((_tag, index) => this.disabledIndices.has(index + positionIndex));
}
return this.disabledIndices.has(positionIndex);
}
deleteTag(event, tag, index) {
event.preventDefault();
event.stopImmediatePropagation();
if (!this.disabled && event.which === 1) {
this.removeTag.emit({ tag, index });
}
}
itemId(tag, index) {
if (tag) { //because of custom values
return this.tagPrefix + "-" + index;
}
}
isGroupTag(tag) {
return tag instanceof Array;
}
tagAriaHidden(index) {
return isPresent(this.focused) && this.focused !== index;
}
getPropField(tag, prop, index) {
// Needed for MultiSelectTree value binding (Heterogeneous Data)
const fieldsCount = prop.length - 1;
if (typeof prop === 'string') {
return prop;
}
else if (this.valueDepth) {
const depth = this.valueDepth[index];
return fieldsCount < depth ? prop[fieldsCount] : prop[depth];
}
else {
return prop.find(item => item in tag);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TagListComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: TagListComponent, isStandalone: true, selector: "kendo-taglist", inputs: { tags: "tags", textField: "textField", valueField: "valueField", valueDepth: "valueDepth", focused: "focused", template: "template", groupTemplate: "groupTemplate", disabled: "disabled", tagPrefix: "tagPrefix", id: "id", size: "size", rounded: "rounded", fillMode: "fillMode", disabledIndices: "disabledIndices" }, outputs: { removeTag: "removeTag" }, host: { properties: { "class.k-chip-list": "this.hostClass", "attr.id": "this.hostId", "attr.role": "this.taglistRole", "attr.aria-multiselectable": "this.multiselectable" } }, ngImport: i0, template: `
<div
*ngFor="let tag of tags; let index = index;"
[attr.id]="itemId(tag, index)"
[attr.aria-selected]="true"
[attr.role]="'option'"
class="k-chip"
[ngClass]="{
'k-focus': index === focused,
'k-disabled': isTagDisabled(tag, index),
'k-chip-sm': size === 'small',
'k-chip-md': size === 'medium',
'k-chip-lg': size === 'large',
'k-rounded-sm': rounded === 'small',
'k-rounded-md': rounded === 'medium',
'k-rounded-lg': rounded === 'large',
'k-rounded-full': rounded === 'full',
'k-chip-solid k-chip-solid-base': fillMode === 'solid',
'k-chip-flat k-chip-flat-base': fillMode === 'flat',
'k-chip-outline k-chip-outline-base': fillMode === 'outline'
}"
>
<span class="k-chip-content">
<ng-template *ngIf="isGroupTag(tag); then groupTag else singleTag"></ng-template>
<ng-template #groupTag>
<span class="k-chip-label k-text-ellipsis">
<ng-template *ngIf="groupTemplate"
[templateContext]="{
templateRef: groupTemplate.templateRef,
$implicit: tag
}">
</ng-template>
<ng-template [ngIf]="!groupTemplate">{{ tag.length }} {{ tag.length === 1 ? 'item' : 'items' }} selected</ng-template>
</span>
</ng-template>
<ng-template #singleTag>
<span class="k-chip-label k-text-ellipsis">
<ng-template *ngIf="template"
[templateContext]="{
templateRef: template.templateRef,
$implicit: tag
}">
</ng-template>
<ng-template [ngIf]="!template">{{ tagProp(tag, textField, index) }}</ng-template>
</span>
</ng-template>
</span>
<span class="k-chip-actions">
<span aria-label="delete" [attr.aria-hidden]="index !== focused" class="k-chip-action k-chip-remove-action">
<kendo-icon-wrapper
(mousedown)="deleteTag($event, tag, index)"
name="x-circle"
[svgIcon]="xCircleIcon"
>
</kendo-icon-wrapper>
</span>
</span>
</div>
<ng-content></ng-content>
`, isInline: true, dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: TemplateContextDirective, selector: "[templateContext]", inputs: ["templateContext"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TagListComponent, decorators: [{
type: Component,
args: [{
selector: 'kendo-taglist',
template: `
<div
*ngFor="let tag of tags; let index = index;"
[attr.id]="itemId(tag, index)"
[attr.aria-selected]="true"
[attr.role]="'option'"
class="k-chip"
[ngClass]="{
'k-focus': index === focused,
'k-disabled': isTagDisabled(tag, index),
'k-chip-sm': size === 'small',
'k-chip-md': size === 'medium',
'k-chip-lg': size === 'large',
'k-rounded-sm': rounded === 'small',
'k-rounded-md': rounded === 'medium',
'k-rounded-lg': rounded === 'large',
'k-rounded-full': rounded === 'full',
'k-chip-solid k-chip-solid-base': fillMode === 'solid',
'k-chip-flat k-chip-flat-base': fillMode === 'flat',
'k-chip-outline k-chip-outline-base': fillMode === 'outline'
}"
>
<span class="k-chip-content">
<ng-template *ngIf="isGroupTag(tag); then groupTag else singleTag"></ng-template>
<ng-template #groupTag>
<span class="k-chip-label k-text-ellipsis">
<ng-template *ngIf="groupTemplate"
[templateContext]="{
templateRef: groupTemplate.templateRef,
$implicit: tag
}">
</ng-template>
<ng-template [ngIf]="!groupTemplate">{{ tag.length }} {{ tag.length === 1 ? 'item' : 'items' }} selected</ng-template>
</span>
</ng-template>
<ng-template #singleTag>
<span class="k-chip-label k-text-ellipsis">
<ng-template *ngIf="template"
[templateContext]="{
templateRef: template.templateRef,
$implicit: tag
}">
</ng-template>
<ng-template [ngIf]="!template">{{ tagProp(tag, textField, index) }}</ng-template>
</span>
</ng-template>
</span>
<span class="k-chip-actions">
<span aria-label="delete" [attr.aria-hidden]="index !== focused" class="k-chip-action k-chip-remove-action">
<kendo-icon-wrapper
(mousedown)="deleteTag($event, tag, index)"
name="x-circle"
[svgIcon]="xCircleIcon"
>
</kendo-icon-wrapper>
</span>
</span>
</div>
<ng-content></ng-content>
`,
standalone: true,
imports: [NgFor, NgClass, NgIf, TemplateContextDirective, IconWrapperComponent]
}]
}], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ElementRef }]; }, propDecorators: { tags: [{
type: Input
}], textField: [{
type: Input
}], valueField: [{
type: Input
}], valueDepth: [{
type: Input
}], focused: [{
type: Input
}], template: [{
type: Input
}], groupTemplate: [{
type: Input
}], disabled: [{
type: Input
}], tagPrefix: [{
type: Input
}], id: [{
type: Input
}], size: [{
type: Input
}], rounded: [{
type: Input
}], fillMode: [{
type: Input
}], disabledIndices: [{
type: Input
}], removeTag: [{
type: Output
}], hostClass: [{
type: HostBinding,
args: ['class.k-chip-list']
}], hostId: [{
type: HostBinding,
args: ['attr.id']
}], taglistRole: [{
type: HostBinding,
args: ['attr.role']
}], multiselectable: [{
type: HostBinding,
args: ['attr.aria-multiselectable']
}] } });