@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
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, 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`—Controls the popup animation. By default, the open and close animations are enabled.
* - `popupClass:String`—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` —Applies coloring based on the `base` theme color. (default)
* * `primary` —Applies coloring based on the `primary` theme color.
* * `secondary`—Applies coloring based on the `secondary` theme color.
* * `tertiary`— Applies coloring based on the `tertiary` theme color.
* * `info`—Applies coloring based on the `info` theme color.
* * `success`— Applies coloring based on the `success` theme color.
* * `warning`— Applies coloring based on the `warning` theme color.
* * `error`— Applies coloring based on the `error` theme color.
* * `dark`— Applies coloring based on the `dark` theme color.
* * `light`— Applies coloring based on the `light` theme color.
* * `inverse`— Applies coloring based on the `inverse` theme color.
* * `null` —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']
}] } });