UNPKG

@progress/kendo-angular-buttons

Version:
517 lines (516 loc) 19.6 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, 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` &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. * * `none` &mdash;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']] }] } });