@progress/kendo-angular-buttons
Version:
Buttons Package for Angular
517 lines (516 loc) • 19.6 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, ContentChild, ElementRef, EventEmitter, HostBinding, HostListener, Input, Output, NgZone, ChangeDetectorRef, Renderer2 } from '@angular/core';
import { LocalizationService, L10N_PREFIX } from '@progress/kendo-angular-l10n';
import { PopupService } from '@progress/kendo-angular-popup';
import { isDocumentAvailable, Keys, isPresent } from '@progress/kendo-angular-common';
import { ButtonItemTemplateDirective } from '../listbutton/button-item-template.directive';
import { closest } from '../util';
import { ListButton } from '../listbutton/list-button';
import { ListComponent } from '../listbutton/list.component';
import { FocusService } from '../focusable/focus.service';
import { NavigationService } from '../navigation/navigation.service';
import { NAVIGATION_CONFIG } from '../navigation/navigation-config';
import { PopupContainerService } from '../listbutton/container.service';
import { NgClass } from '@angular/common';
import { ButtonComponent } from '../button/button.component';
import * as i0 from "@angular/core";
import * as i1 from "../focusable/focus.service";
import * as i2 from "../navigation/navigation.service";
import * as i3 from "@progress/kendo-angular-popup";
import * as i4 from "@progress/kendo-angular-l10n";
import * as i5 from "../listbutton/container.service";
const NAVIGATION_SETTINGS = {
useLeftRightArrows: true
};
const NAVIGATION_SETTINGS_PROVIDER = {
provide: NAVIGATION_CONFIG,
useValue: NAVIGATION_SETTINGS
};
const DEFAULT_FILL_MODE = 'solid';
/**
* Represents the Kendo UI DropDownButton component for Angular.
*
* @example
* ```ts
* _@Component({
* selector: 'my-app',
* template: `
* <kendo-dropdownbutton [data]="data">
* User Settings
* </kendo-dropdownbutton>
* `
* })
* class AppComponent {
* public data: Array<any> = [{
* text: 'My Profile'
* }, {
* text: 'Friend Requests'
* }, {
* text: 'Account Settings'
* }, {
* text: 'Support'
* }, {
* text: 'Log Out'
* }];
* }
* ```
*/
export class DropDownButtonComponent extends ListButton {
containerService;
renderer;
/**
* Allows showing the default arrow icon or providing alternative one instead.
* @default false
*/
arrowIcon = false;
/**
* Defines the name of an existing icon in the Kendo UI theme.
*/
icon = '';
/**
* Defines an [`SVGIcon`](slug:api_icons_svgicon) to be rendered within the button.
*/
svgIcon;
/**
* Defines the list of CSS classes which are used for styling the Button with custom icons.
*/
iconClass = '';
/**
* Defines a URL for styling the button with a custom image.
*/
imageUrl = '';
/**
* Sets the data item field that represents the item text.
* If the data contains only primitive values, do not define it.
*/
textField;
/**
* Sets or gets the data of the DropDownButton.
*
* > The data has to be provided in an array-like list.
*/
set data(data) {
this._data = data || [];
}
get data() {
return this._data;
}
/**
* The size property specifies the padding of the DropDownButton
* ([see example]({% slug api_buttons_dropdownbuttoncomponent %}#toc-size)).
*
* The possible values are:
* * `small`
* * `medium` (default)
* * `large`
* * `none`
*/
size = 'medium';
/**
* The rounded property specifies the border radius of the DropDownButton
* ([see example]({% slug api_buttons_dropdownbuttoncomponent %}#toc-rounded)).
*
* The possible values are:
* * `small`
* * `medium` (default)
* * `large`
* * `full`
* * `none`
*/
rounded = 'medium';
/**
* The fillMode property specifies the background and border styles of the DropDownButton
* ([see example]({% slug api_buttons_dropdownbuttoncomponent %}#toc-fillMode)).
*
* The available values are:
* * `solid` (default)
* * `flat`
* * `outline`
* * `link`
* * `none`
*/
set fillMode(fillMode) {
this._fillMode = fillMode === 'clear' ? 'flat' : fillMode;
}
get fillMode() {
return this._fillMode;
}
/**
* The DropDownButton 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.
* * `none` —Removes the default CSS class (no class would be rendered).
*/
themeColor = 'base';
/**
* Sets attributes to the main button.
*/
set buttonAttributes(buttonAttributes) {
const newButtonAttributes = buttonAttributes ? buttonAttributes : null;
this.handleButtonAttributes(newButtonAttributes);
this._buttonAttributes = newButtonAttributes;
}
get buttonAttributes() {
return this._buttonAttributes;
}
/**
* Fires each time the user clicks on a drop-down list item. The event data contains the data item bound to the clicked list item.
*/
itemClick = new EventEmitter();
/**
* Fires each time the DropDownButton gets focused.
*/
onFocus = new EventEmitter();
/**
* Fires each time the DropDownButton gets blurred.
*/
onBlur = new EventEmitter();
get focused() {
return this._isFocused && !this._disabled;
}
hostDisplayStyle = 'inline-flex';
get dir() {
return this.direction;
}
/**
* @hidden
*/
get active() {
return this._active;
}
itemTemplate;
_fillMode = DEFAULT_FILL_MODE;
_buttonAttributes = null;
documentMouseUpSub;
/**
* @hidden
*/
keydown(event) {
this.keyDownHandler(event, true);
if (event.keyCode === Keys.Space || event.keyCode === Keys.Enter) {
this._active = true;
}
if (event.keyCode === Keys.Enter) {
event.preventDefault();
}
}
/**
* @hidden
*/
keyup(event) {
this.keyUpHandler(event);
this._active = false;
}
/**
* @hidden
*/
mousedown(event) {
if (this._disabled) {
event.preventDefault();
}
else {
this._active = true;
}
}
/**
* @hidden
*/
mouseup(event) {
if (this._disabled) {
event.preventDefault();
}
this._active = false;
}
/**
* @hidden
*/
openPopup() {
this._isFocused = true;
this.togglePopupVisibility();
}
/**
* @hidden
*/
onButtonBlur() {
if (!this.openState) {
this.blurWrapper();
}
}
/**
* Focuses the DropDownButton component.
*/
focus() {
if (isDocumentAvailable()) {
this.button.nativeElement.focus();
}
}
/**
* Blurs the DropDownButton component.
*/
blur() {
if (isDocumentAvailable()) {
this.button.nativeElement.blur();
this.blurWrapper();
}
}
constructor(focusService, navigationService, wrapperRef, zone, popupService, elRef, localization, cdr, containerService, renderer) {
super(focusService, navigationService, wrapperRef, zone, popupService, elRef, localization, cdr, containerService);
this.containerService = containerService;
this.renderer = renderer;
this._itemClick = this.itemClick;
this._blur = this.onBlur;
zone.runOutsideAngular(() => {
this.documentMouseUpSub = this.renderer.listen('document', 'mouseup', () => {
if (this.active) {
zone.run(() => this._active = false);
}
});
});
}
ngAfterViewInit() {
this.containerService.container = this.container;
this.containerService.template = this.popupTemplate;
this.handleButtonAttributes(this.buttonAttributes);
const arrowWrapper = this.button.nativeElement.querySelector('.k-button-arrow');
if (arrowWrapper) {
this.renderer.addClass(arrowWrapper, 'k-menu-button-arrow');
}
}
/**
* @hidden
*/
handleFocus(event) {
if (!this._disabled) {
// eslint-disable-next-line no-unused-expressions
!this._isFocused && this.onFocus.emit();
this._isFocused = true;
this.focusService.resetFocus();
const relatedTargetInList = event.relatedTarget && closest(event.relatedTarget, '.k-popup kendo-button-list');
if (this.openState && !relatedTargetInList) {
this.focusService.focus(0);
}
}
}
/**
* @hidden
*/
wrapperContains(element) {
return this.wrapper === element
|| this.wrapper.contains(element)
|| (this.popupRef && this.popupRef.popupElement.contains(element));
}
handleButtonAttributes(newButtonAttributes) {
const mainButton = this.button?.nativeElement;
if (isPresent(this.buttonAttributes) && isPresent(mainButton)) {
for (const attr in this.buttonAttributes) {
this.renderer.removeAttribute(mainButton, attr, this.buttonAttributes[attr]);
}
}
if (isPresent(newButtonAttributes) && isPresent(mainButton)) {
for (const attr in newButtonAttributes) {
this.renderer.setAttribute(mainButton, attr, newButtonAttributes[attr]);
}
}
}
/**
* @hidden
*/
ngOnDestroy() {
if (this.documentMouseUpSub) {
this.documentMouseUpSub();
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DropDownButtonComponent, deps: [{ token: i1.FocusService }, { token: i2.NavigationService }, { token: i0.ElementRef }, { token: i0.NgZone }, { token: i3.PopupService }, { token: i0.ElementRef }, { token: i4.LocalizationService }, { token: i0.ChangeDetectorRef }, { token: i5.PopupContainerService }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DropDownButtonComponent, isStandalone: true, selector: "kendo-dropdownbutton", inputs: { arrowIcon: "arrowIcon", icon: "icon", svgIcon: "svgIcon", iconClass: "iconClass", imageUrl: "imageUrl", textField: "textField", data: "data", size: "size", rounded: "rounded", fillMode: "fillMode", themeColor: "themeColor", buttonAttributes: "buttonAttributes" }, outputs: { itemClick: "itemClick", onFocus: "focus", onBlur: "blur" }, host: { listeners: { "keydown": "keydown($event)", "keyup": "keyup($event)", "mousedown": "mousedown($event)", "mouseup": "mouseup($event)" }, properties: { "class.k-focus": "this.focused", "style.display": "this.hostDisplayStyle", "attr.dir": "this.dir" } }, providers: [
FocusService,
NavigationService,
NAVIGATION_SETTINGS_PROVIDER,
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.dropdownbutton'
},
PopupContainerService
], queries: [{ propertyName: "itemTemplate", first: true, predicate: ButtonItemTemplateDirective, descendants: true }], exportAs: ["kendoDropDownButton"], usesInheritance: true, ngImport: i0, template: `
<button kendoButton #button
type="button"
[id]="buttonId"
[tabindex]="componentTabIndex"
class="k-menu-button"
[class.k-active]="active"
[disabled]="disabled"
[icon]="icon"
[svgIcon]="svgIcon"
[arrowIcon]="arrowIcon"
[iconClass]="iconClass"
[imageUrl]="imageUrl"
[ngClass]="buttonClass"
[size]="size"
[rounded]="rounded"
[fillMode]="fillMode"
[themeColor]="fillMode ? themeColor : null"
(click)="openPopup()"
(focus)="handleFocus($event)"
(blur)="onButtonBlur()"
[attr.aria-disabled]="disabled"
[attr.aria-expanded]="openState"
[attr.aria-controls]="listId"
>
<ng-content></ng-content>
</button>
<ng-template #popupTemplate>
<kendo-button-list
#buttonList
[id]="listId"
[data]="data"
[textField]="textField"
[itemTemplate]="itemTemplate"
(onItemClick)="onItemClick($event)"
(keydown)="keyDownHandler($event)"
(keyup)="keyUpHandler($event)"
[attr.dir]="dir"
[attr.aria-labelledby]="buttonId"
[size]="size"
>
</kendo-button-list>
</ng-template>
<ng-container #container></ng-container>
`, isInline: true, dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ListComponent, selector: "kendo-button-list", inputs: ["data", "textField", "itemTemplate", "size"], outputs: ["onItemClick", "onItemBlur"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DropDownButtonComponent, decorators: [{
type: Component,
args: [{
exportAs: 'kendoDropDownButton',
providers: [
FocusService,
NavigationService,
NAVIGATION_SETTINGS_PROVIDER,
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.dropdownbutton'
},
PopupContainerService
],
selector: 'kendo-dropdownbutton',
template: `
<button kendoButton #button
type="button"
[id]="buttonId"
[tabindex]="componentTabIndex"
class="k-menu-button"
[class.k-active]="active"
[disabled]="disabled"
[icon]="icon"
[svgIcon]="svgIcon"
[arrowIcon]="arrowIcon"
[iconClass]="iconClass"
[imageUrl]="imageUrl"
[ngClass]="buttonClass"
[size]="size"
[rounded]="rounded"
[fillMode]="fillMode"
[themeColor]="fillMode ? themeColor : null"
(click)="openPopup()"
(focus)="handleFocus($event)"
(blur)="onButtonBlur()"
[attr.aria-disabled]="disabled"
[attr.aria-expanded]="openState"
[attr.aria-controls]="listId"
>
<ng-content></ng-content>
</button>
<ng-template #popupTemplate>
<kendo-button-list
#buttonList
[id]="listId"
[data]="data"
[textField]="textField"
[itemTemplate]="itemTemplate"
(onItemClick)="onItemClick($event)"
(keydown)="keyDownHandler($event)"
(keyup)="keyUpHandler($event)"
[attr.dir]="dir"
[attr.aria-labelledby]="buttonId"
[size]="size"
>
</kendo-button-list>
</ng-template>
<ng-container #container></ng-container>
`,
standalone: true,
imports: [ButtonComponent, NgClass, ListComponent]
}]
}], ctorParameters: function () { return [{ type: i1.FocusService }, { type: i2.NavigationService }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: i3.PopupService }, { type: i0.ElementRef }, { type: i4.LocalizationService }, { type: i0.ChangeDetectorRef }, { type: i5.PopupContainerService }, { type: i0.Renderer2 }]; }, propDecorators: { arrowIcon: [{
type: Input
}], icon: [{
type: Input
}], svgIcon: [{
type: Input
}], iconClass: [{
type: Input
}], imageUrl: [{
type: Input
}], textField: [{
type: Input
}], data: [{
type: Input
}], size: [{
type: Input
}], rounded: [{
type: Input
}], fillMode: [{
type: Input
}], themeColor: [{
type: Input
}], buttonAttributes: [{
type: Input
}], itemClick: [{
type: Output
}], onFocus: [{
type: Output,
args: ['focus']
}], onBlur: [{
type: Output,
args: ['blur']
}], focused: [{
type: HostBinding,
args: ['class.k-focus']
}], hostDisplayStyle: [{
type: HostBinding,
args: ['style.display']
}], dir: [{
type: HostBinding,
args: ['attr.dir']
}], itemTemplate: [{
type: ContentChild,
args: [ButtonItemTemplateDirective]
}], keydown: [{
type: HostListener,
args: ['keydown', ['$event']]
}], keyup: [{
type: HostListener,
args: ['keyup', ['$event']]
}], mousedown: [{
type: HostListener,
args: ['mousedown', ['$event']]
}], mouseup: [{
type: HostListener,
args: ['mouseup', ['$event']]
}] } });