UNPKG

@progress/kendo-angular-toolbar

Version:

Kendo UI Angular Toolbar component - a single UI element that organizes buttons and other navigation elements

590 lines (585 loc) 24.8 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { Component, ElementRef, forwardRef, ViewChild, Input, EventEmitter, Output, QueryList, ViewChildren, isDevMode, Renderer2, NgZone } from '@angular/core'; import { ToolBarToolComponent } from './toolbar-tool.component'; import { DropDownButtonComponent } from '@progress/kendo-angular-buttons'; import { getValueForLocation, makePeeker, getIndexOfFocused, getPrevKey, getNextKey, seekFocusedIndex, areEqual } from '../util'; import { IconWrapperComponent } from '@progress/kendo-angular-icons'; import { NgClass, NgIf, NgFor } from '@angular/common'; import { take } from 'rxjs/operators'; import { ToolBarComponent } from '../toolbar.component'; import * as i0 from "@angular/core"; import * as i1 from "../toolbar.component"; /** * Represents the [Kendo UI ToolBar DropDownButton for Angular](slug:controltypes_toolbar#drop-down-buttons). */ export class ToolBarDropDownButtonComponent extends ToolBarToolComponent { zone; renderer; host; /** * Allows showing the default arrow icon or providing alternative one instead. * @default false */ arrowIcon = false; /** * Sets the `title` attribute of the underlying button element. * @default '' */ title = ''; // showText and showIcon showIcon should be declared first /** * Specifies the button text visibility. */ set showText(value) { this._showText = value; this.setTextDisplayMode(); } get showText() { return this._showText; } /** * Specifies the button icon visibility. */ set showIcon(value) { this._showIcon = value; } get showIcon() { return this._showIcon; } /** * Sets the text of the DropDownButton * ([see example](slug:controltypes_toolbar#toc-drop-down-buttons)). */ set text(text) { this._text = text; this.setTextDisplayMode(); } get text() { return this._text; } /** * Defines an icon that will be rendered next to the button text. */ set icon(icon) { this.toolbarOptions.icon = getValueForLocation(icon, this.showIcon, false); this.overflowOptions.icon = getValueForLocation(icon, this.showIcon, true); } /** * Defines an SVGIcon to be rendered within the button. * The input can take either an [existing Kendo SVG icon](slug:svgicon_list) or a custom one. */ set svgIcon(icon) { const isIconSet = this.toolbarOptions.icon || this.overflowOptions.icon; const isIconClassSet = this.toolbarOptions.iconClass || this.overflowOptions.iconClass; if (isDevMode() && icon && isIconSet && isIconClassSet) { throw new Error('Setting both icon/svgIcon and iconClass options at the same time is not supported.'); } this.toolbarOptions.svgIcon = getValueForLocation(icon, this.showIcon, false); this.overflowOptions.svgIcon = getValueForLocation(icon, this.showIcon, true); } /** * Defines an icon with a custom CSS class that will be rendered next to the button text. */ set iconClass(iconClass) { this.toolbarOptions.iconClass = getValueForLocation(iconClass, this.showIcon, false); this.overflowOptions.iconClass = getValueForLocation(iconClass, this.showIcon, true); } /** * Defines the location of an image that will be displayed next to the button text. */ set imageUrl(imageUrl) { this.toolbarOptions.imageUrl = getValueForLocation(imageUrl, this.showIcon, false); this.overflowOptions.imageUrl = getValueForLocation(imageUrl, this.showIcon, true); } /** * Configures the popup of the DropDownButton. * * The available options are: * - `animate:Boolean`&mdash;Controls the popup animation. By default, the open and close animations are enabled. * - `popupClass:String`&mdash;Specifies a list of CSS classes that are used to style the popup. */ set popupSettings(settings) { this._popupSettings = Object.assign({ animate: true, popupClass: '' }, settings); } get popupSettings() { return this._popupSettings; } /** * @hidden */ set look(look) { if (look) { this.fillMode = look === 'default' ? 'solid' : look; } } /** * @hidden */ set primary(primary) { this.themeColor = primary ? 'primary' : 'base'; } /** * The fillMode property specifies the background and border styles of the Button. * * The available values are: * * `solid` (default) * * `flat` * * `outline` * * `link` * * `null` */ fillMode = 'solid'; /** * The Button allows you to specify predefined theme colors. * The theme color will be applied as a background and border color while also amending the text color accordingly * ([see example]({% slug api_buttons_dropdownbuttoncomponent %}#toc-themeColor)). * * The possible values are: * * `base` &mdash;Applies coloring based on the `base` theme color. (default) * * `primary` &mdash;Applies coloring based on the `primary` theme color. * * `secondary`&mdash;Applies coloring based on the `secondary` theme color. * * `tertiary`&mdash; Applies coloring based on the `tertiary` theme color. * * `info`&mdash;Applies coloring based on the `info` theme color. * * `success`&mdash; Applies coloring based on the `success` theme color. * * `warning`&mdash; Applies coloring based on the `warning` theme color. * * `error`&mdash; Applies coloring based on the `error` theme color. * * `dark`&mdash; Applies coloring based on the `dark` theme color. * * `light`&mdash; Applies coloring based on the `light` theme color. * * `inverse`&mdash; Applies coloring based on the `inverse` theme color. * * `null` &mdash;Removes the default CSS class (no class would be rendered). */ themeColor = 'base'; /** * The CSS classes that will be rendered on the main button. * Supports the type of values that are supported by [`ngClass`](link:site.data.urls.angular['ngclassapi']). */ buttonClass; /** * Sets the data item field that represents the item text. * If the data contains only primitive values, do not define it. */ textField; /** * Sets the disabled state of the DropDownButton. */ disabled; /** * Sets the data of the DropDownButton * ([see example](slug:controltypes_toolbar#drop-down-buttons)). * * > The data has to be provided in an array-like list. */ set data(data) { this._data = data || []; } get data() { if (!this._data) { this.data = []; } return this._data; } /** * Fires each time the user clicks a DropDownButton item. * The event data contains the data item that is bound to the clicked list item. */ itemClick = new EventEmitter(); /** * Fires each time the popup is about to open. * This event is preventable. If you cancel the event, the popup will remain closed. */ open = new EventEmitter(); /** * Fires each time the popup is about to close. * This event is preventable. If you cancel the event, the popup will remain open. */ close = new EventEmitter(); dropdownButton; toolbarDropDownButton; sectionDropDownButton; overflowListItems; toolbarOptions = { text: '', icon: '', iconClass: '', svgIcon: null, imageUrl: '' }; overflowOptions = { text: '', icon: '', iconClass: '', svgIcon: null, imageUrl: '' }; get overflowButtons() { return [...this.overflowListItems.toArray().filter(el => !el.nativeElement.classList.contains('k-disabled'))]; } _data; _popupSettings = { animate: true, popupClass: '' }; focusedIndex = -1; _showText; _showIcon; _text; propertyChangeSub; getNextKey; getPrevKey; constructor(zone, renderer, host) { super(); this.zone = zone; this.renderer = renderer; this.host = host; this.getNextKey = getNextKey(); this.getPrevKey = getPrevKey(); this.isBuiltInTool = true; this.propertyChangeSub = this.host.propertyChange.subscribe(change => { if (change.property === 'showText' || change.property === 'showIcon') { this[change.property] = change.value; } }); } ngOnInit() { this.setTextDisplayMode(); } ngOnDestroy() { if (this.propertyChangeSub) { this.propertyChangeSub.unsubscribe(); this.propertyChangeSub = null; } } ngAfterViewInit() { this.zone.onStable.pipe(take(1)).subscribe(() => { const dropdownButton = this[`${this.location}DropDownButton`]; if (dropdownButton?.button) { this.renderer.addClass(dropdownButton.button.nativeElement, 'k-toolbar-menu-button'); } }); } /** * @hidden */ onButtonListClick(ev) { this.focusedIndex = this.overflowListItems .toArray() .findIndex(b => b.nativeElement.contains(ev.target)); } /** * @hidden */ get size() { return this.host.size; } /** * @hidden */ canFocus() { return !this.disabled; } /** * @hidden */ focus(ev = {}) { if (!this.overflows || this.location === 'section') { if (!ev.type || ev.type === 'focus' || ev.type === 'keydown') { this[`${this.location}DropDownButton`]?.focus(); } } else if (this.overflowButtons.length > 0) { this.focusedIndex = getIndexOfFocused(this.getPrevKey(), this.getNextKey(), this.overflowButtons.map(ob => ob.nativeElement))(ev); this.focusButton(this.focusedIndex, ev); } } /** * @hidden */ handleKey(ev) { if (!this.overflows && (ev.keyCode === this.getPrevKey(this.overflows) || ev.keyCode === this.getNextKey(this.overflows))) { return false; } if (this.overflows && this.location !== 'section') { const peekAtIndex = makePeeker(this.overflowButtons); const isUnmodified = areEqual(this.focusedIndex); this.focusedIndex = seekFocusedIndex(this.getPrevKey(), this.getNextKey(), peekAtIndex)(this.focusedIndex, ev); this.focusButton(this.focusedIndex, ev); return !isUnmodified(this.focusedIndex); } } /** * @hidden */ getText(dataItem) { if (dataItem) { return this.textField ? dataItem[this.textField] : dataItem.text || dataItem; } } /** * @hidden */ handleClick(ev, item, index) { this.onButtonListClick(ev); const dataItem = this.data[index]; if (item.click) { item.click(dataItem); } this.itemClick.emit(dataItem); } focusButton(index, ev) { if (!ev.type || ev.type === 'focus' || ev.type === 'keydown') { this.overflowButtons[index].nativeElement.focus(); } } setTextDisplayMode() { this.toolbarOptions.text = this.showText === 'menu' || this.showText === 'never' ? undefined : this.text; this.overflowOptions.text = this.showText === 'toolbar' || this.showText === 'never' ? undefined : this.text; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ToolBarDropDownButtonComponent, deps: [{ token: i0.NgZone }, { token: i0.Renderer2 }, { token: i1.ToolBarComponent }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ToolBarDropDownButtonComponent, isStandalone: true, selector: "kendo-toolbar-dropdownbutton", inputs: { arrowIcon: "arrowIcon", title: "title", showText: "showText", showIcon: "showIcon", text: "text", icon: "icon", svgIcon: "svgIcon", iconClass: "iconClass", imageUrl: "imageUrl", popupSettings: "popupSettings", look: "look", primary: "primary", fillMode: "fillMode", themeColor: "themeColor", buttonClass: "buttonClass", textField: "textField", disabled: "disabled", data: "data" }, outputs: { itemClick: "itemClick", open: "open", close: "close" }, providers: [{ provide: ToolBarToolComponent, useExisting: forwardRef(() => ToolBarDropDownButtonComponent) }], viewQueries: [{ propertyName: "dropdownButton", first: true, predicate: ["dropdownButton"], descendants: true, read: ElementRef, static: true }, { propertyName: "toolbarDropDownButton", first: true, predicate: ["toolbarDropDownButton"], descendants: true }, { propertyName: "sectionDropDownButton", first: true, predicate: ["sectionDropDownButton"], descendants: true }, { propertyName: "overflowListItems", predicate: ["listItem"], descendants: true }], exportAs: ["kendoToolBarDropDownButton"], usesInheritance: true, ngImport: i0, template: ` <ng-template #toolbarTemplate> <kendo-dropdownbutton #toolbarDropDownButton [icon]="toolbarOptions.icon" [iconClass]="toolbarOptions.iconClass" [svgIcon]="toolbarOptions.svgIcon" [imageUrl]="toolbarOptions.imageUrl" [arrowIcon]="arrowIcon" [buttonClass]="buttonClass" [disabled]="disabled" [size]="size" [tabIndex]="-1" [data]="data" [buttonAttributes]="{'title': title}" [textField]="textField" [popupSettings]="popupSettings" [fillMode]="fillMode" [themeColor]="fillMode ? themeColor : null" (open)="open.emit($event)" (close)="close.emit($event)" (itemClick)="itemClick.emit($event)" > {{ toolbarOptions.text }} </kendo-dropdownbutton> </ng-template> <ng-template #popupTemplate> <div tabindex="-1" role="menuitem" class="k-item k-menu-item k-disabled" [ngClass]="buttonClass"> <span [ngClass]="{'k-link': true, 'k-menu-link': true}" > <kendo-icon-wrapper *ngIf="overflowOptions.icon || overflowOptions.iconClass || overflowOptions.svgIcon" [name]="overflowOptions.icon" [customFontClass]="overflowOptions.iconClass" [svgIcon]="overflowOptions.svgIcon" ></kendo-icon-wrapper> <span *ngIf="overflowOptions.text" class="k-menu-link-text">{{overflowOptions.text}}</span> </span> </div> <ng-container *ngFor="let item of data; let i = index"> <div #listItem tabindex="-1" role="menuitem" class="k-item k-menu-item" [class.k-disabled]="disabled || item.disabled" (click)="handleClick($event, item, i)"> <span class="k-link k-menu-link" [ngClass]="item.cssClass" > <kendo-icon-wrapper *ngIf="item.icon || item.iconClass || item.svgIcon" [name]="item.icon" [customFontClass]="item.iconClass" [svgIcon]="item.svgIcon" ></kendo-icon-wrapper> <span *ngIf="getText(item)" class="k-menu-link-text">{{ getText(item) }}</span> </span> </div> </ng-container> </ng-template> <ng-template #sectionTemplate> <kendo-dropdownbutton #sectionDropDownButton [icon]="toolbarOptions.icon" [iconClass]="toolbarOptions.iconClass" [svgIcon]="toolbarOptions.svgIcon" [imageUrl]="toolbarOptions.imageUrl" [arrowIcon]="arrowIcon" [buttonClass]="buttonClass" [disabled]="disabled" [size]="size" [tabIndex]="-1" [data]="data" [buttonAttributes]="{'title': title}" [textField]="textField" [popupSettings]="popupSettings" [fillMode]="fillMode" [themeColor]="fillMode ? themeColor : null" (open)="open.emit($event)" (close)="close.emit($event)" (itemClick)="itemClick.emit($event)" > {{ toolbarOptions.text }} </kendo-dropdownbutton> </ng-template> `, isInline: true, dependencies: [{ kind: "component", type: DropDownButtonComponent, selector: "kendo-dropdownbutton", inputs: ["arrowIcon", "icon", "svgIcon", "iconClass", "imageUrl", "textField", "data", "size", "rounded", "fillMode", "themeColor", "buttonAttributes"], outputs: ["itemClick", "focus", "blur"], exportAs: ["kendoDropDownButton"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ToolBarDropDownButtonComponent, decorators: [{ type: Component, args: [{ exportAs: 'kendoToolBarDropDownButton', providers: [{ provide: ToolBarToolComponent, useExisting: forwardRef(() => ToolBarDropDownButtonComponent) }], selector: 'kendo-toolbar-dropdownbutton', template: ` <ng-template #toolbarTemplate> <kendo-dropdownbutton #toolbarDropDownButton [icon]="toolbarOptions.icon" [iconClass]="toolbarOptions.iconClass" [svgIcon]="toolbarOptions.svgIcon" [imageUrl]="toolbarOptions.imageUrl" [arrowIcon]="arrowIcon" [buttonClass]="buttonClass" [disabled]="disabled" [size]="size" [tabIndex]="-1" [data]="data" [buttonAttributes]="{'title': title}" [textField]="textField" [popupSettings]="popupSettings" [fillMode]="fillMode" [themeColor]="fillMode ? themeColor : null" (open)="open.emit($event)" (close)="close.emit($event)" (itemClick)="itemClick.emit($event)" > {{ toolbarOptions.text }} </kendo-dropdownbutton> </ng-template> <ng-template #popupTemplate> <div tabindex="-1" role="menuitem" class="k-item k-menu-item k-disabled" [ngClass]="buttonClass"> <span [ngClass]="{'k-link': true, 'k-menu-link': true}" > <kendo-icon-wrapper *ngIf="overflowOptions.icon || overflowOptions.iconClass || overflowOptions.svgIcon" [name]="overflowOptions.icon" [customFontClass]="overflowOptions.iconClass" [svgIcon]="overflowOptions.svgIcon" ></kendo-icon-wrapper> <span *ngIf="overflowOptions.text" class="k-menu-link-text">{{overflowOptions.text}}</span> </span> </div> <ng-container *ngFor="let item of data; let i = index"> <div #listItem tabindex="-1" role="menuitem" class="k-item k-menu-item" [class.k-disabled]="disabled || item.disabled" (click)="handleClick($event, item, i)"> <span class="k-link k-menu-link" [ngClass]="item.cssClass" > <kendo-icon-wrapper *ngIf="item.icon || item.iconClass || item.svgIcon" [name]="item.icon" [customFontClass]="item.iconClass" [svgIcon]="item.svgIcon" ></kendo-icon-wrapper> <span *ngIf="getText(item)" class="k-menu-link-text">{{ getText(item) }}</span> </span> </div> </ng-container> </ng-template> <ng-template #sectionTemplate> <kendo-dropdownbutton #sectionDropDownButton [icon]="toolbarOptions.icon" [iconClass]="toolbarOptions.iconClass" [svgIcon]="toolbarOptions.svgIcon" [imageUrl]="toolbarOptions.imageUrl" [arrowIcon]="arrowIcon" [buttonClass]="buttonClass" [disabled]="disabled" [size]="size" [tabIndex]="-1" [data]="data" [buttonAttributes]="{'title': title}" [textField]="textField" [popupSettings]="popupSettings" [fillMode]="fillMode" [themeColor]="fillMode ? themeColor : null" (open)="open.emit($event)" (close)="close.emit($event)" (itemClick)="itemClick.emit($event)" > {{ toolbarOptions.text }} </kendo-dropdownbutton> </ng-template> `, standalone: true, imports: [DropDownButtonComponent, NgClass, NgIf, IconWrapperComponent, NgFor] }] }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: i0.Renderer2 }, { type: i1.ToolBarComponent }]; }, propDecorators: { arrowIcon: [{ type: Input }], title: [{ type: Input }], showText: [{ type: Input }], showIcon: [{ type: Input }], text: [{ type: Input }], icon: [{ type: Input }], svgIcon: [{ type: Input }], iconClass: [{ type: Input }], imageUrl: [{ type: Input }], popupSettings: [{ type: Input }], look: [{ type: Input }], primary: [{ type: Input }], fillMode: [{ type: Input }], themeColor: [{ type: Input }], buttonClass: [{ type: Input }], textField: [{ type: Input }], disabled: [{ type: Input }], data: [{ type: Input }], itemClick: [{ type: Output }], open: [{ type: Output }], close: [{ type: Output }], dropdownButton: [{ type: ViewChild, args: ['dropdownButton', { read: ElementRef, static: true }] }], toolbarDropDownButton: [{ type: ViewChild, args: ['toolbarDropDownButton', { static: false }] }], sectionDropDownButton: [{ type: ViewChild, args: ['sectionDropDownButton', { static: false }] }], overflowListItems: [{ type: ViewChildren, args: ['listItem'] }] } });