@progress/kendo-angular-toolbar
Version:
Kendo UI Angular Toolbar component - a single UI element that organizes buttons and other navigation elements
603 lines (602 loc) • 25.7 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, forwardRef, ViewChild, Input, ElementRef, Output, EventEmitter, ViewChildren, QueryList, isDevMode } from '@angular/core';
import { SplitButtonComponent } from '@progress/kendo-angular-buttons';
import { ToolBarToolComponent } from './toolbar-tool.component';
import { getValueForLocation, makePeeker, getIndexOfFocused, getPrevKey, getNextKey, seekFocusedIndex, areEqual } from '../util';
import { caretAltDownIcon } from '@progress/kendo-svg-icons';
import { IconWrapperComponent } from '@progress/kendo-angular-icons';
import { NgClass, NgIf, NgFor } from '@angular/common';
import { ToolBarComponent } from '../toolbar.component';
import * as i0 from "@angular/core";
import * as i1 from "../toolbar.component";
/**
* Represents the [Kendo UI ToolBar SplitButton for Angular](slug:controltypes_toolbar#toc-split-buttons).
*/
export class ToolBarSplitButtonComponent extends ToolBarToolComponent {
host;
// 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;
this.setTextDisplayMode();
}
get showIcon() {
return this._showIcon;
}
/**
* Sets the text of the SplitButton ([see example](slug:controltypes_toolbar#toc-split-buttons)).
*/
set text(text) {
this._text = text;
this.setTextDisplayMode();
}
get text() {
return this._text;
}
/**
* Defines the icon that will be rendered next to the button text
* ([see example](slug:controltypes_toolbar#toc-split-buttons)).
*/
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 main 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);
}
/**
* When set to `true`, disables a SplitButton item.
*/
disabled;
/**
* Configures the popup of the SplitButton.
*
* 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(value) {
this._popupSettings = value;
}
get popupSettings() {
if (!this._popupSettings) {
this._popupSettings = { animate: true, popupClass: '' };
}
return this._popupSettings;
}
/**
* 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.
*
* 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';
/**
* @hidden
*/
set look(look) {
if (look) {
this.fillMode = look === 'default' ? 'solid' : look;
}
}
/**
* 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;
/**
* The CSS classes that will be rendered on the button which opens the popup.
* Supports the type of values that are supported by [`ngClass`](link:site.data.urls.angular['ngclassapi']).
*/
arrowButtonClass;
/**
* Specifies the name of the [font icon](slug:icons#icons-list) that will
* be rendered for the button which opens the popup.
*/
arrowButtonIcon = 'caret-alt-down';
/**
* Specifies the [`SVGIcon`](slug:api_icons_svgicon) that will
* be rendered for the button which opens the popup.
*/
arrowButtonSvgIcon = caretAltDownIcon;
/**
* Configures the text field of the button-list popup.
*/
textField = 'text';
/**
* Sets the data of the SplitButton ([see example](slug:controltypes_toolbar#toc-split-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 the main button.
*/
buttonClick = new EventEmitter();
/**
* Fires each time the user clicks the drop-down list.
* 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();
toolbarOptions = {
text: '',
icon: '',
iconClass: '',
svgIcon: null,
imageUrl: ''
};
overflowOptions = {
text: '',
icon: '',
iconClass: '',
svgIcon: null,
imageUrl: ''
};
ngOnInit() {
this.setTextDisplayMode();
}
ngOnDestroy() {
if (this.propertyChangeSub) {
this.propertyChangeSub.unsubscribe();
this.propertyChangeSub = null;
}
}
get overflowButtons() {
return [this.overflowMainButton, ...this.overflowListItems.toArray().filter(el => !el.nativeElement.classList.contains('k-disabled'))];
}
_data;
_popupSettings = { animate: true, popupClass: '' };
focusedIndex = -1;
_showText;
_showIcon;
_text;
propertyChangeSub;
getNextKey;
getPrevKey;
toolbarSplitButton;
sectionSplitButton;
overflowMainButton;
overflowListItems;
constructor(host) {
super();
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;
}
});
}
/**
* @hidden
*/
onButtonListClick(ev) {
this.focusedIndex = this.overflowButtons.findIndex(b => b.nativeElement.contains(ev.target));
}
/**
* @hidden
*/
onMainButtonClick(ev) {
this.buttonClick.emit(ev);
this.focusedIndex = 0;
}
/**
* @hidden
*/
canFocus() {
return !this.disabled;
}
/**
* @hidden
*/
get size() {
return this.host.size;
}
/**
* @hidden
*/
focus(ev = {}) {
if (!this.overflows || this.location === 'section') {
if (!ev.type || ev.type === 'focus' || ev.type === 'keydown') {
this[`${this.location}SplitButton`].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) {
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' || ev.type === 'click') && this.location !== 'section') {
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: ToolBarSplitButtonComponent, deps: [{ token: i1.ToolBarComponent }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ToolBarSplitButtonComponent, isStandalone: true, selector: "kendo-toolbar-splitbutton", inputs: { showText: "showText", showIcon: "showIcon", text: "text", icon: "icon", svgIcon: "svgIcon", iconClass: "iconClass", imageUrl: "imageUrl", disabled: "disabled", popupSettings: "popupSettings", fillMode: "fillMode", themeColor: "themeColor", look: "look", buttonClass: "buttonClass", arrowButtonClass: "arrowButtonClass", arrowButtonIcon: "arrowButtonIcon", arrowButtonSvgIcon: "arrowButtonSvgIcon", textField: "textField", data: "data" }, outputs: { buttonClick: "buttonClick", itemClick: "itemClick", open: "open", close: "close" }, providers: [{ provide: ToolBarToolComponent, useExisting: forwardRef(() => ToolBarSplitButtonComponent) }], viewQueries: [{ propertyName: "toolbarSplitButton", first: true, predicate: ["toolbarSplitButton"], descendants: true }, { propertyName: "sectionSplitButton", first: true, predicate: ["sectionSplitButton"], descendants: true }, { propertyName: "overflowMainButton", first: true, predicate: ["overflowMainButton"], descendants: true, read: ElementRef }, { propertyName: "overflowListItems", predicate: ["listItem"], descendants: true }], exportAs: ["kendoToolBarSplitButton"], usesInheritance: true, ngImport: i0, template: `
<ng-template #toolbarTemplate>
<kendo-splitbutton
#toolbarSplitButton
class="k-toolbar-split-button"
[data]="data"
[text]="toolbarOptions.text"
[icon]="toolbarOptions.icon"
[iconClass]="toolbarOptions.iconClass"
[svgIcon]="toolbarOptions.svgIcon"
[imageUrl]="toolbarOptions.imageUrl"
[buttonClass]="buttonClass"
[arrowButtonClass]="arrowButtonClass"
[arrowButtonIcon]="arrowButtonIcon"
[arrowButtonSvgIcon]="arrowButtonSvgIcon"
[disabled]="disabled"
[size]="size"
[tabIndex]="-1"
[textField]="textField"
[popupSettings]="popupSettings"
[fillMode]="fillMode"
[themeColor]="fillMode ? themeColor : null"
(buttonClick)="buttonClick.emit($event)"
(open)="open.emit($event)"
(close)="close.emit($event)"
(itemClick)="itemClick.emit($event)"
></kendo-splitbutton>
</ng-template>
<ng-template #popupTemplate>
<div #overflowMainButton
tabindex="-1"
role="menuitem"
class="k-item k-menu-item"
[class.k-disabled]="disabled"
[ngClass]="buttonClass"
(click)="onMainButtonClick($event)">
<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"
>
<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-splitbutton
#sectionSplitButton
class="k-toolbar-split-button"
[data]="data"
[text]="toolbarOptions.text"
[icon]="toolbarOptions.icon"
[iconClass]="toolbarOptions.iconClass"
[svgIcon]="toolbarOptions.svgIcon"
[imageUrl]="toolbarOptions.imageUrl"
[buttonClass]="buttonClass"
[arrowButtonClass]="arrowButtonClass"
[arrowButtonIcon]="arrowButtonIcon"
[arrowButtonSvgIcon]="arrowButtonSvgIcon"
[disabled]="disabled"
[size]="size"
[tabIndex]="-1"
[textField]="textField"
[popupSettings]="popupSettings"
[fillMode]="fillMode"
[themeColor]="fillMode ? themeColor : null"
(buttonClick)="buttonClick.emit($event)"
(open)="open.emit($event)"
(close)="close.emit($event)"
(itemClick)="itemClick.emit($event)"
></kendo-splitbutton>
</ng-template>
`, isInline: true, dependencies: [{ kind: "component", type: SplitButtonComponent, selector: "kendo-splitbutton", inputs: ["text", "icon", "svgIcon", "iconClass", "type", "imageUrl", "size", "rounded", "fillMode", "themeColor", "disabled", "popupSettings", "tabIndex", "textField", "data", "arrowButtonClass", "arrowButtonIcon", "arrowButtonSvgIcon", "buttonAttributes"], outputs: ["buttonClick", "itemClick", "focus", "blur", "open", "close"], exportAs: ["kendoSplitButton"] }, { 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: ToolBarSplitButtonComponent, decorators: [{
type: Component,
args: [{
exportAs: 'kendoToolBarSplitButton',
providers: [{ provide: ToolBarToolComponent, useExisting: forwardRef(() => ToolBarSplitButtonComponent) }],
selector: 'kendo-toolbar-splitbutton',
template: `
<ng-template #toolbarTemplate>
<kendo-splitbutton
#toolbarSplitButton
class="k-toolbar-split-button"
[data]="data"
[text]="toolbarOptions.text"
[icon]="toolbarOptions.icon"
[iconClass]="toolbarOptions.iconClass"
[svgIcon]="toolbarOptions.svgIcon"
[imageUrl]="toolbarOptions.imageUrl"
[buttonClass]="buttonClass"
[arrowButtonClass]="arrowButtonClass"
[arrowButtonIcon]="arrowButtonIcon"
[arrowButtonSvgIcon]="arrowButtonSvgIcon"
[disabled]="disabled"
[size]="size"
[tabIndex]="-1"
[textField]="textField"
[popupSettings]="popupSettings"
[fillMode]="fillMode"
[themeColor]="fillMode ? themeColor : null"
(buttonClick)="buttonClick.emit($event)"
(open)="open.emit($event)"
(close)="close.emit($event)"
(itemClick)="itemClick.emit($event)"
></kendo-splitbutton>
</ng-template>
<ng-template #popupTemplate>
<div #overflowMainButton
tabindex="-1"
role="menuitem"
class="k-item k-menu-item"
[class.k-disabled]="disabled"
[ngClass]="buttonClass"
(click)="onMainButtonClick($event)">
<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"
>
<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-splitbutton
#sectionSplitButton
class="k-toolbar-split-button"
[data]="data"
[text]="toolbarOptions.text"
[icon]="toolbarOptions.icon"
[iconClass]="toolbarOptions.iconClass"
[svgIcon]="toolbarOptions.svgIcon"
[imageUrl]="toolbarOptions.imageUrl"
[buttonClass]="buttonClass"
[arrowButtonClass]="arrowButtonClass"
[arrowButtonIcon]="arrowButtonIcon"
[arrowButtonSvgIcon]="arrowButtonSvgIcon"
[disabled]="disabled"
[size]="size"
[tabIndex]="-1"
[textField]="textField"
[popupSettings]="popupSettings"
[fillMode]="fillMode"
[themeColor]="fillMode ? themeColor : null"
(buttonClick)="buttonClick.emit($event)"
(open)="open.emit($event)"
(close)="close.emit($event)"
(itemClick)="itemClick.emit($event)"
></kendo-splitbutton>
</ng-template>
`,
standalone: true,
imports: [SplitButtonComponent, NgClass, NgIf, IconWrapperComponent, NgFor]
}]
}], ctorParameters: function () { return [{ type: i1.ToolBarComponent }]; }, propDecorators: { showText: [{
type: Input
}], showIcon: [{
type: Input
}], text: [{
type: Input
}], icon: [{
type: Input
}], svgIcon: [{
type: Input
}], iconClass: [{
type: Input
}], imageUrl: [{
type: Input
}], disabled: [{
type: Input
}], popupSettings: [{
type: Input
}], fillMode: [{
type: Input
}], themeColor: [{
type: Input
}], look: [{
type: Input
}], buttonClass: [{
type: Input
}], arrowButtonClass: [{
type: Input
}], arrowButtonIcon: [{
type: Input
}], arrowButtonSvgIcon: [{
type: Input
}], textField: [{
type: Input
}], data: [{
type: Input
}], buttonClick: [{
type: Output
}], itemClick: [{
type: Output
}], open: [{
type: Output
}], close: [{
type: Output
}], toolbarSplitButton: [{
type: ViewChild,
args: ['toolbarSplitButton', { static: false }]
}], sectionSplitButton: [{
type: ViewChild,
args: ['sectionSplitButton', { static: false }]
}], overflowMainButton: [{
type: ViewChild,
args: ['overflowMainButton', { read: ElementRef }]
}], overflowListItems: [{
type: ViewChildren,
args: ['listItem']
}] } });