UNPKG

@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
/**----------------------------------------------------------------------------------------- * 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`&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(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` &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'; /** * @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'] }] } });