@progress/kendo-angular-buttons
Version:
Buttons Package for Angular
5,811 lines • 221 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 * as i0 from '@angular/core';
import { Injectable, isDevMode, EventEmitter, Component, Optional, Input, Output, HostBinding, HostListener, ContentChildren, Directive, InjectionToken, Inject, ElementRef, ViewContainerRef, ViewChild, ContentChild, forwardRef, NgModule } from '@angular/core';
import { Subject, Subscription, fromEvent, merge } from 'rxjs';
import * as i12 from '@progress/kendo-angular-common';
import { isDocumentAvailable, isFirefox, isSafari, isChanged, hasObservers, Keys, TemplateContextDirective, MultiTabStop, guid, isPresent as isPresent$1, EventsOutsideAngularDirective, anyChanged, ToggleButtonTabStopDirective, ResizeBatchService, KENDO_TOGGLEBUTTONTABSTOP } from '@progress/kendo-angular-common';
export { ToggleButtonTabStopDirective } from '@progress/kendo-angular-common';
import { caretAltDownIcon, xCircleIcon, moreVerticalIcon } from '@progress/kendo-svg-icons';
import * as i1 from '@progress/kendo-angular-l10n';
import { LocalizationService, L10N_PREFIX, ComponentMessages } from '@progress/kendo-angular-l10n';
import { validatePackage } from '@progress/kendo-licensing';
import { IconWrapperComponent, IconsService } from '@progress/kendo-angular-icons';
import { NgIf, NgClass, NgStyle, NgFor, NgTemplateOutlet } from '@angular/common';
import { filter, tap, take } from 'rxjs/operators';
import * as i3 from '@progress/kendo-angular-popup';
import { PopupService } from '@progress/kendo-angular-popup';
import * as i4 from '@angular/animations';
import { sequence, query, style, stagger, animate } from '@angular/animations';
/**
* @hidden
*/
class KendoButtonService {
buttonClicked = new Subject();
buttonClicked$ = this.buttonClicked.asObservable();
click(button) {
this.buttonClicked.next(button);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: KendoButtonService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: KendoButtonService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: KendoButtonService, decorators: [{
type: Injectable
}] });
/**
* @hidden
*/
const packageMetadata = {
name: '@progress/kendo-angular-buttons',
productName: 'Kendo UI for Angular',
productCode: 'KENDOUIANGULAR',
productCodes: ['KENDOUIANGULAR'],
publishDate: 1745303781,
version: '18.5.2',
licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/'
};
/**
* @hidden
*/
const resolvedPromise = Promise.resolve(null);
/**
* @hidden
*/
const isPresent = (value) => value !== null && value !== undefined;
/**
* @hidden
*/
const tick = (f) => (resolvedPromise.then(f));
/**
* @hidden
*/
function isDocumentNode(container) {
return container.nodeType === 9;
}
/**
* @hidden
*/
function closest(element, selector) {
if (element.closest) {
return element.closest(selector);
}
const matches = Element.prototype.matches ?
(el, sel) => el.matches(sel)
: (el, sel) => el.msMatchesSelector(sel);
let node = element;
while (node && !isDocumentNode(node)) {
if (matches(node, selector)) {
return node;
}
node = node.parentNode;
}
}
/**
* @hidden
*/
const replaceMessagePlaceholder = (message, name, value) => message.replace(new RegExp(`\{\\s*${name}\\s*\}`, 'g'), value);
/**
* @hidden
*/
const SIZES = {
small: 'sm',
medium: 'md',
large: 'lg'
};
const ROUNDNESS = {
small: 'sm',
medium: 'md',
large: 'lg',
full: 'full'
};
/**
* @hidden
*
* Returns the styling classes to be added and removed
*/
const getStylingClasses = (componentType, stylingOption, previousValue, newValue) => {
switch (stylingOption) {
case 'size':
return {
toRemove: `k-${componentType}-${SIZES[previousValue]}`,
toAdd: newValue !== 'none' ? `k-${componentType}-${SIZES[newValue]}` : ''
};
case 'rounded':
return {
toRemove: `k-rounded-${ROUNDNESS[previousValue]}`,
toAdd: newValue !== 'none' ? `k-rounded-${ROUNDNESS[newValue]}` : ''
};
case 'fillMode':
return {
toRemove: `k-${componentType}-${previousValue}`,
toAdd: newValue !== 'none' ? `k-${componentType}-${newValue}` : ''
};
default:
break;
}
};
/**
* @hidden
*
* Returns the themeColor classes to be added and removed
*/
const getThemeColorClasses = (componentType, prevFillMode, fillMode, previousValue, newValue) => {
return {
toRemove: `k-${componentType}-${prevFillMode}-${previousValue}`,
toAdd: newValue !== 'none' ? `k-${componentType}-${fillMode}-${newValue}` : ''
};
};
/**
* @hidden
*
* Checks for an empty object - {}
*/
const isObjectEmpty = (obj) => obj && Object.keys(obj).length === 0 && obj.constructor === Object;
const DEFAULT_ROUNDED$3 = 'medium';
const DEFAULT_SIZE$2 = 'medium';
const DEFAULT_THEME_COLOR$2 = 'base';
const DEFAULT_FILL_MODE$3 = 'solid';
/**
* Represents the Kendo UI Button component for Angular.
*
* As of package v17, the `span[kendoButton]` and `kendo-button` selectors are removed.
* Please use the `button[kendoButton]` selector only.
*/
class ButtonComponent {
renderer;
service;
ngZone;
/**
* @hidden
* @default false
* required for DropDownButton arrow icon.
*/
arrowIcon = false;
/**
* Provides visual styling that indicates if the Button is active.
*
* @default false
*/
toggleable = false;
/**
* Backwards-compatible alias
*
* @hidden
*/
get togglable() {
return this.toggleable;
}
/**
* @hidden
*/
set togglable(value) {
this.toggleable = value;
}
/**
* Sets the selected state of the Button.
*
* @default false
*/
get selected() {
return this._selected || false;
}
set selected(value) {
this._selected = value;
}
/**
* @hidden
*/
set tabIndex(index) {
this.element.tabIndex = index;
}
get tabIndex() {
return this.element.tabIndex;
}
/**
* Defines a URL which is used for an `img` element inside the Button.
* The URL can be relative or absolute. If relative, it is evaluated with relation to the web page URL.
*/
imageUrl;
/**
* Defines a CSS class—or multiple classes separated by spaces—
* which are applied to a `span` element inside the Button. Allows the usage of custom icons.
*/
set iconClass(value) {
if (isDevMode() && value && (this.icon || this.svgIcon)) {
throw new Error('Setting both icon/svgIcon and iconClass options at the same time is not supported.');
}
this._iconClass = value;
}
get iconClass() {
return this._iconClass;
}
/**
* Defines the name for an existing font icon in the Kendo UI theme.
*/
set icon(name) {
if (isDevMode() && name && this.iconClass) {
throw new Error('Setting both icon/svgIcon and iconClass options at the same time is not supported.');
}
this._icon = name;
}
get icon() {
return this._icon;
}
/**
* If set to `true`, it disables the Button.
*
* @default false
*/
set disabled(disabled) {
//Required, because in FF focused buttons are not blurred on disabled
if (disabled && isDocumentAvailable() && isFirefox(navigator.userAgent)) {
this.blur();
}
this.isDisabled = disabled;
this.renderer.setProperty(this.element, 'disabled', disabled);
}
get disabled() {
return this.isDisabled;
}
/**
* The size property specifies the padding of the Button
* ([see example]({% slug appearance_button %}#toc-size)).
*
* @default 'medium'
*/
set size(size) {
const newSize = size ? size : DEFAULT_SIZE$2;
this.handleClasses(newSize, 'size');
this._size = newSize;
}
get size() {
return this._size;
}
/**
* The rounded property specifies the border radius of the Button
* ([see example](slug:appearance_button#toc-roundness)).
*
* @default 'medium'
*/
set rounded(rounded) {
const newRounded = rounded ? rounded : DEFAULT_ROUNDED$3;
this.handleClasses(newRounded, 'rounded');
this._rounded = newRounded;
}
get rounded() {
return this._rounded;
}
/**
* The fillMode property specifies the background and border styles of the Button
* ([see example](slug:appearance_button#toc-fill-mode)).
*
* @default 'solid'
*/
set fillMode(fillMode) {
const newFillMode = fillMode ? fillMode : DEFAULT_FILL_MODE$3;
this.handleClasses(newFillMode, 'fillMode');
this._fillMode = newFillMode;
}
get fillMode() {
return this._fillMode;
}
/**
* 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:appearance_button#toc-theme-colors)).
*
* @default 'base'
*/
set themeColor(themeColor) {
const newThemeColor = themeColor ? themeColor : DEFAULT_THEME_COLOR$2;
this.handleThemeColor(newThemeColor);
this._themeColor = newThemeColor;
}
get themeColor() {
return this._themeColor;
}
/**
* Defines an SVGIcon to be rendered within the button.
*/
set svgIcon(icon) {
if (isDevMode() && icon && this.iconClass) {
throw new Error('Setting both icon/svgIcon and iconClass options at the same time is not supported.');
}
this._svgIcon = icon;
}
get svgIcon() {
return this._svgIcon;
}
/**
* Fires each time the selected state of a toggleable button is changed.
*
* The event argument is the new selected state (boolean).
*/
selectedChange = new EventEmitter();
/**
* Fires each time the user clicks the button.
*/
click = new EventEmitter();
element;
isDisabled = false;
caretAltDownIcon = caretAltDownIcon;
_size = DEFAULT_SIZE$2;
_rounded = DEFAULT_ROUNDED$3;
_fillMode = DEFAULT_FILL_MODE$3;
_themeColor = DEFAULT_THEME_COLOR$2;
_focused = false;
direction;
_selected;
subs = new Subscription();
_iconClass;
_icon;
_svgIcon;
set isFocused(isFocused) {
this.toggleClass('k-focus', isFocused);
this._focused = isFocused;
}
get isFocused() {
return this._focused;
}
get classButton() {
return true;
}
get isToggleable() {
return this.toggleable;
}
get iconButtonClass() {
const hasIcon = this.icon || this.iconClass || this.imageUrl || this.svgIcon;
return hasIcon && !this.hasText;
}
get classDisabled() {
return this.isDisabled;
}
get classActive() {
return this.selected;
}
get getDirection() {
return this.direction;
}
/**
* @hidden
*/
onFocus() {
this.isFocused = true;
}
/**
* @hidden
*/
onBlur() {
this.isFocused = false;
}
/**
* @hidden
*/
set primary(value) {
this.themeColor = value ? 'primary' : 'base';
}
/**
* @hidden
*/
set look(value) {
switch (value) {
case 'default':
this.fillMode = 'solid';
break;
default:
this.fillMode = value;
break;
}
}
/**
* Alias for ElementRef.nativeElement to workaround
* ViewChild() selectors that used to return the host element before v11.
*
* @hidden
*/
get nativeElement() {
return this.element;
}
constructor(element, renderer, service, localization, ngZone) {
this.renderer = renderer;
this.service = service;
this.ngZone = ngZone;
validatePackage(packageMetadata);
this.direction = localization.rtl ? 'rtl' : 'ltr';
this.subs.add(localization.changes.subscribe(({ rtl }) => (this.direction = rtl ? 'rtl' : 'ltr')));
this.element = element.nativeElement;
}
ngOnInit() {
if (!this.element.hasAttribute('role') && this.togglable) {
this.toggleAriaPressed(this.toggleable);
}
this.ngZone.runOutsideAngular(() => {
this.subs.add(this.renderer.listen(this.element, 'click', this._onButtonClick.bind(this)));
this.subs.add(this.renderer.listen(this.element, 'mousedown', (event) => {
const isBrowserSafari = isDocumentAvailable() && isSafari(navigator.userAgent);
if (!this.isDisabled && isBrowserSafari) {
event.preventDefault();
this.element.focus();
}
}));
});
}
ngOnChanges(change) {
if (isChanged('togglable', change) || isChanged('toggleable', change)) {
this.toggleAriaPressed(this.toggleable);
}
}
ngAfterViewInit() {
const stylingOptions = ['size', 'rounded', 'fillMode'];
stylingOptions.forEach(input => {
this.handleClasses(this[input], input);
});
}
ngOnDestroy() {
this.subs.unsubscribe();
}
/**
* @hidden
*/
get hasText() {
return isDocumentAvailable() && this.element.textContent.trim().length > 0;
}
/**
* Focuses the Button component.
*/
focus() {
if (isDocumentAvailable()) {
this.element.focus();
this.isFocused = true;
}
}
/**
* Blurs the Button component.
*/
blur() {
if (isDocumentAvailable()) {
this.element.blur();
this.isFocused = false;
}
}
/**
* @hidden
*/
setAttribute(attribute, value) {
this.renderer.setAttribute(this.element, attribute, value);
}
/**
* @hidden
*/
removeAttribute(attribute) {
this.renderer.removeAttribute(this.element, attribute);
}
/**
* @hidden
*
* Internal setter that triggers selectedChange
*/
setSelected(value) {
const changed = this.selected !== value;
this.selected = value;
this.setAttribute('aria-pressed', this.selected.toString());
this.toggleClass('k-selected', this.selected);
if (changed && hasObservers(this.selectedChange)) {
this.ngZone.run(() => {
this.selectedChange.emit(value);
});
}
}
toggleAriaPressed(shouldSet) {
if (!isDocumentAvailable()) {
return;
}
if (shouldSet) {
this.setAttribute('aria-pressed', this.selected.toString());
}
else {
this.removeAttribute('aria-pressed');
}
}
toggleClass(className, add) {
if (add) {
this.renderer.addClass(this.element, className);
}
else {
this.renderer.removeClass(this.element, className);
}
}
_onButtonClick() {
if (!this.disabled && this.service) {
this.ngZone.run(() => {
this.service.click(this);
});
}
if (this.togglable && !this.service) {
this.setSelected(!this.selected);
}
}
handleClasses(value, input) {
const elem = this.element;
const classes = getStylingClasses('button', input, this[input], value);
if (input === 'fillMode') {
this.handleThemeColor(this.themeColor, this[input], value);
}
if (classes.toRemove) {
this.renderer.removeClass(elem, classes.toRemove);
}
if (classes.toAdd) {
this.renderer.addClass(elem, classes.toAdd);
}
}
handleThemeColor(value, prevFillMode, fillMode) {
const elem = this.element;
const removeFillMode = prevFillMode ? prevFillMode : this.fillMode;
const addFillMode = fillMode ? fillMode : this.fillMode;
const themeColorClass = getThemeColorClasses('button', removeFillMode, addFillMode, this.themeColor, value);
this.renderer.removeClass(elem, themeColorClass.toRemove);
if (addFillMode !== 'none' && fillMode !== 'none') {
if (themeColorClass.toAdd) {
this.renderer.addClass(elem, themeColorClass.toAdd);
}
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ButtonComponent, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: KendoButtonService, optional: true }, { token: i1.LocalizationService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ButtonComponent, isStandalone: true, selector: "button[kendoButton]", inputs: { arrowIcon: "arrowIcon", toggleable: "toggleable", togglable: "togglable", selected: "selected", tabIndex: "tabIndex", imageUrl: "imageUrl", iconClass: "iconClass", icon: "icon", disabled: "disabled", size: "size", rounded: "rounded", fillMode: "fillMode", themeColor: "themeColor", svgIcon: "svgIcon", primary: "primary", look: "look" }, outputs: { selectedChange: "selectedChange", click: "click" }, host: { listeners: { "focus": "onFocus()", "blur": "onBlur()" }, properties: { "class.k-button": "this.classButton", "class.k-toggle-button": "this.isToggleable", "class.k-icon-button": "this.iconButtonClass", "class.k-disabled": "this.classDisabled", "class.k-selected": "this.classActive", "attr.dir": "this.getDirection" } }, providers: [
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.button'
}
], exportAs: ["kendoButton"], usesOnChanges: true, ngImport: i0, template: `
<kendo-icon-wrapper
*ngIf="icon || svgIcon"
innerCssClass="k-button-icon"
[name]="icon"
[svgIcon]="svgIcon"></kendo-icon-wrapper>
<span *ngIf="imageUrl" class="k-button-icon k-icon">
<img [src]="imageUrl" class="k-image" role="presentation" />
</span>
<span *ngIf="iconClass" class="k-button-icon" [ngClass]="iconClass"></span>
<span class="k-button-text"><ng-content></ng-content></span>
<span *ngIf="$any(arrowIcon).iconClass" class="k-button-icon" [ngClass]="$any(arrowIcon).iconClass"></span>
<span *ngIf="arrowIcon && !$any(arrowIcon).iconClass" class="k-button-arrow">
<kendo-icon-wrapper
[name]="$any(arrowIcon).icon || 'caret-alt-down'"
[svgIcon]="$any(arrowIcon).svgIcon || caretAltDownIcon"></kendo-icon-wrapper>
</span>
`, isInline: true, dependencies: [{ 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: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ButtonComponent, decorators: [{
type: Component,
args: [{
exportAs: 'kendoButton',
providers: [
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.button'
}
],
selector: 'button[kendoButton]',
template: `
<kendo-icon-wrapper
*ngIf="icon || svgIcon"
innerCssClass="k-button-icon"
[name]="icon"
[svgIcon]="svgIcon"></kendo-icon-wrapper>
<span *ngIf="imageUrl" class="k-button-icon k-icon">
<img [src]="imageUrl" class="k-image" role="presentation" />
</span>
<span *ngIf="iconClass" class="k-button-icon" [ngClass]="iconClass"></span>
<span class="k-button-text"><ng-content></ng-content></span>
<span *ngIf="$any(arrowIcon).iconClass" class="k-button-icon" [ngClass]="$any(arrowIcon).iconClass"></span>
<span *ngIf="arrowIcon && !$any(arrowIcon).iconClass" class="k-button-arrow">
<kendo-icon-wrapper
[name]="$any(arrowIcon).icon || 'caret-alt-down'"
[svgIcon]="$any(arrowIcon).svgIcon || caretAltDownIcon"></kendo-icon-wrapper>
</span>
`,
standalone: true,
imports: [NgIf, IconWrapperComponent, NgClass]
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: KendoButtonService, decorators: [{
type: Optional
}] }, { type: i1.LocalizationService }, { type: i0.NgZone }]; }, propDecorators: { arrowIcon: [{
type: Input
}], toggleable: [{
type: Input
}], togglable: [{
type: Input
}], selected: [{
type: Input
}], tabIndex: [{
type: Input
}], imageUrl: [{
type: Input
}], iconClass: [{
type: Input
}], icon: [{
type: Input
}], disabled: [{
type: Input
}], size: [{
type: Input
}], rounded: [{
type: Input
}], fillMode: [{
type: Input
}], themeColor: [{
type: Input
}], svgIcon: [{
type: Input
}], selectedChange: [{
type: Output
}], click: [{
type: Output
}], classButton: [{
type: HostBinding,
args: ['class.k-button']
}], isToggleable: [{
type: HostBinding,
args: ['class.k-toggle-button']
}], iconButtonClass: [{
type: HostBinding,
args: ['class.k-icon-button']
}], classDisabled: [{
type: HostBinding,
args: ['class.k-disabled']
}], classActive: [{
type: HostBinding,
args: ['class.k-selected']
}], getDirection: [{
type: HostBinding,
args: ['attr.dir']
}], onFocus: [{
type: HostListener,
args: ['focus']
}], onBlur: [{
type: HostListener,
args: ['blur']
}], primary: [{
type: Input
}], look: [{
type: Input
}] } });
/**
* @hidden
*/
class PreventableEvent {
prevented = false;
/**
* Prevents the default action for a specified event.
* In this way, the source component suppresses the built-in behavior that follows the event.
*/
preventDefault() {
this.prevented = true;
}
/**
* If the event is prevented by any of its subscribers, returns `true`.
*
* @returns `true` if the default action was prevented. Otherwise, returns `false`.
*/
isDefaultPrevented() {
return this.prevented;
}
}
/**
* @hidden
*/
const tabindex = 'tabindex';
/**
* Represents the Kendo UI ButtonGroup component for Angular.
*/
class ButtonGroupComponent {
service;
renderer;
element;
/**
* By default, the ButtonGroup is enabled.
* To disable the whole group of buttons, set its `disabled` attribute to `true`.
*
* To disable a specific button, set its own `disabled` attribute to `true`
* and leave the `disabled` attribute of the ButtonGroup undefined.
* If you define the `disabled` attribute of the ButtonGroup, it will take
* precedence over the `disabled` attributes of the underlying buttons and they will be ignored.
*
* For more information on how to configure the Button, refer to
* its [API documentation]({% slug api_buttons_buttoncomponent %}).
*/
disabled;
/**
* The selection mode of the ButtonGroup.
* @default 'multiple'
*/
selection = 'multiple';
/**
* Sets the width of the ButtonGroup.
* If the width of the ButtonGroup is set:
* - The buttons resize automatically to fill the full width of the group wrapper.
* - The buttons acquire the same width.
*/
width;
/**
* Specifies the [`tabIndex`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex) of the component.
*/
set tabIndex(value) {
this._tabIndex = value;
this.currentTabIndex = value;
}
get tabIndex() {
return this._tabIndex;
}
/**
* When this option is set to `true` (default), the component is a single tab-stop,
* and focus is moved through the inner buttons via the arrow keys.
*
* When the option is set to `false`, the inner buttons are part of the natural tab sequence of the page.
*
* @default true
*/
navigable = true;
/**
* Fires every time keyboard navigation occurs.
*/
navigate = new EventEmitter();
buttons;
_tabIndex = 0;
currentTabIndex = 0;
lastFocusedIndex = -1;
direction;
subs = new Subscription();
wrapperClasses = true;
get disabledClass() {
return this.disabled;
}
get stretchedClass() {
return !!this.width;
}
role = 'group';
get dir() {
return this.direction;
}
get ariaDisabled() {
return this.disabled;
}
get wrapperWidth() {
return this.width;
}
get wrapperTabIndex() {
return this.disabled ? undefined : this.navigable ? this.currentTabIndex : undefined;
}
constructor(service, localization, renderer, element) {
this.service = service;
this.renderer = renderer;
this.element = element;
validatePackage(packageMetadata);
this.subs.add(localization.changes.subscribe(({ rtl }) => this.direction = rtl ? 'rtl' : 'ltr'));
}
ngOnInit() {
this.subs.add(this.service.buttonClicked$.subscribe((button) => {
let newSelectionValue;
if (this.isSelectionSingle()) {
newSelectionValue = true;
this.deactivate(this.buttons.filter(current => current !== button));
}
else {
if (this.navigable) {
this.defocus(this.buttons.toArray());
}
newSelectionValue = !button.selected;
}
if (button.togglable) {
button.setSelected(newSelectionValue);
}
if (this.navigable) {
this.currentTabIndex = -1;
this.renderer.setAttribute(button, tabindex, '0');
}
}));
this.handleSubs('focus', () => this.navigable, this.focusHandler);
this.handleSubs('keydown', () => this.navigable && !this.disabled, (event) => this.navigateFocus(event));
this.handleSubs('focusout', (event) => this.navigable && event.relatedTarget && event.relatedTarget.parentNode !== this.element.nativeElement, () => {
this.lastFocusedIndex = this.buttons.toArray().findIndex(button => button.tabIndex !== -1);
this.defocus(this.buttons.toArray());
this.currentTabIndex = this.tabIndex;
});
this.subs.add(fromEvent(this.element.nativeElement, 'focusout')
.pipe(filter((event) => this.navigable && event.relatedTarget && event.relatedTarget.parentNode !== this.element.nativeElement))
.subscribe(() => {
this.defocus(this.buttons.toArray());
this.currentTabIndex = this.tabIndex;
}));
}
ngOnChanges(changes) {
if (isChanged('disabled', changes)) {
this.buttons.forEach((button) => {
if (isPresent(this.disabled)) {
button.disabled = this.disabled;
}
});
}
if (isChanged('navigable', changes)) {
if (changes['navigable'].currentValue) {
this.defocus(this.buttons.toArray());
this.currentTabIndex = 0;
}
else {
this.currentTabIndex = -1;
this.buttons.forEach((button) => this.renderer.setAttribute(button, tabindex, '0'));
}
}
}
ngAfterContentInit() {
if (!this.navigable) {
return;
}
this.defocus(this.buttons.toArray());
}
ngAfterViewChecked() {
if (this.buttons.length) {
this.renderer.addClass(this.buttons.first.element, 'k-group-start');
this.renderer.addClass(this.buttons.last.element, 'k-group-end');
}
}
ngOnDestroy() {
this.subs.unsubscribe();
}
ngAfterContentChecked() {
this.verifySettings();
}
navigateFocus(event) {
const navigationButtons = this.buttons.toArray().filter(button => !button.disabled);
const focusedIndex = navigationButtons.findIndex(current => current.element.tabIndex !== -1);
const firstIndex = 0;
const lastIndex = navigationButtons.length - 1;
const eventArgs = new PreventableEvent();
if (event.keyCode === Keys.ArrowRight && focusedIndex < lastIndex) {
this.navigate.emit(eventArgs);
if (!eventArgs.isDefaultPrevented()) {
this.defocus(navigationButtons);
this.focus(navigationButtons.filter((_current, index) => {
return index === focusedIndex + 1;
}));
}
}
if (event.keyCode === Keys.ArrowLeft && focusedIndex > firstIndex) {
this.navigate.emit(eventArgs);
if (!eventArgs.isDefaultPrevented()) {
this.defocus(navigationButtons);
this.focus(navigationButtons.filter((_current, index) => {
return index === focusedIndex - 1;
}));
}
}
}
deactivate(buttons) {
buttons.forEach((button) => {
button.setSelected(false);
if (this.navigable) {
this.renderer.setAttribute(button, tabindex, '-1');
}
});
}
activate(buttons) {
buttons.forEach((button) => {
button.setSelected(true);
if (this.navigable) {
this.renderer.setAttribute(button, tabindex, '0');
}
button.focus();
});
}
defocus(buttons) {
buttons.forEach((button) => {
this.renderer.setAttribute(button, tabindex, '-1');
});
}
focus(buttons) {
buttons.forEach((button) => {
this.renderer.setAttribute(button, tabindex, '0');
button.focus();
});
}
verifySettings() {
if (isDevMode()) {
if (this.isSelectionSingle() && this.buttons.filter(button => button.selected).length > 1) {
throw new Error('Having multiple selected buttons with single selection mode is not supported');
}
}
}
isSelectionSingle() {
return this.selection === 'single';
}
handleSubs(eventName, predicate, handler) {
this.subs.add(fromEvent(this.element.nativeElement, eventName)
.pipe(filter(predicate))
.subscribe(handler));
}
focusHandler = () => {
this.currentTabIndex = -1;
this.defocus(this.buttons.toArray());
const firstFocusableIndex = this.buttons.toArray().findIndex(current => !current.disabled);
const index = this.lastFocusedIndex === -1 ? firstFocusableIndex : this.lastFocusedIndex;
this.focus(this.buttons.filter((_current, i) => {
return i === index;
}));
};
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ButtonGroupComponent, deps: [{ token: KendoButtonService }, { token: i1.LocalizationService }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ButtonGroupComponent, isStandalone: true, selector: "kendo-buttongroup", inputs: { disabled: "disabled", selection: "selection", width: "width", tabIndex: "tabIndex", navigable: "navigable" }, outputs: { navigate: "navigate" }, host: { properties: { "class.k-button-group": "this.wrapperClasses", "class.k-disabled": "this.disabledClass", "class.k-button-group-stretched": "this.stretchedClass", "attr.role": "this.role", "attr.dir": "this.dir", "attr.aria-disabled": "this.ariaDisabled", "style.width": "this.wrapperWidth", "attr.tabindex": "this.wrapperTabIndex" } }, providers: [
KendoButtonService,
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.buttongroup'
}
], queries: [{ propertyName: "buttons", predicate: ButtonComponent }], exportAs: ["kendoButtonGroup"], usesOnChanges: true, ngImport: i0, template: `
<ng-content select="[kendoButton]"></ng-content>
`, isInline: true });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ButtonGroupComponent, decorators: [{
type: Component,
args: [{
exportAs: 'kendoButtonGroup',
providers: [
KendoButtonService,
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.buttongroup'
}
],
selector: 'kendo-buttongroup',
template: `
<ng-content select="[kendoButton]"></ng-content>
`,
standalone: true
}]
}], ctorParameters: function () { return [{ type: KendoButtonService }, { type: i1.LocalizationService }, { type: i0.Renderer2 }, { type: i0.ElementRef }]; }, propDecorators: { disabled: [{
type: Input,
args: ['disabled']
}], selection: [{
type: Input,
args: ['selection']
}], width: [{
type: Input,
args: ['width']
}], tabIndex: [{
type: Input
}], navigable: [{
type: Input
}], navigate: [{
type: Output
}], buttons: [{
type: ContentChildren,
args: [ButtonComponent]
}], wrapperClasses: [{
type: HostBinding,
args: ['class.k-button-group']
}], disabledClass: [{
type: HostBinding,
args: ['class.k-disabled']
}], stretchedClass: [{
type: HostBinding,
args: ['class.k-button-group-stretched']
}], role: [{
type: HostBinding,
args: ['attr.role']
}], dir: [{
type: HostBinding,
args: ['attr.dir']
}], ariaDisabled: [{
type: HostBinding,
args: ['attr.aria-disabled']
}], wrapperWidth: [{
type: HostBinding,
args: ['style.width']
}], wrapperTabIndex: [{
type: HostBinding,
args: ['attr.tabindex']
}] } });
const DEFAULT_SIZE$1 = 'medium';
const DEFAULT_ROUNDED$2 = 'medium';
const DEFAULT_THEME_COLOR$1 = 'base';
const DEFAULT_FILL_MODE$2 = 'solid';
/**
* Displays a Chip that represents an input, attribute or an action.
*/
class ChipComponent {
element;
renderer;
ngZone;
localizationService;
/**
* Sets the label text of the Chip.
*/
label;
/**
* Defines the name for an existing icon in a Kendo UI theme.
* The icon is rendered inside the Chip by a `span.k-icon` element.
*/
icon;
/**
* Defines an [`SVGIcon`](slug:api_icons_svgicon) icon to be rendered inside the Chip using
* a [`KendoSVGIcon`](slug:api_icons_svgiconcomponent) component.
*/
svgIcon;
/**
* Defines a CSS class — or multiple classes separated by spaces —
* which are applied to a span element.
* Allows the usage of custom icons.
*/
iconClass;
/**
* Use these settings to render an avatar within the Chip.
*/
avatarSettings;
/**
* Specifies the selected state of the Chip.
* @default false
*/
selected = false;
/**
* Specifies if the Chip will be removable or not.
* If the property is set to `true`, the Chip renders a remove icon.
* @default false
*/
removable = false;
/**
* Specifies a custom remove font icon class that will be rendered when the Chip is removable.
* [see example]({% slug icons %})
*/
removeIcon;
/**
* Specifies a custom remove SVG icon that will be rendered when the Chip is removable.
*/
removeSvgIcon;
/**
* @hidden
*
* Determines whether the Chip has a menu.
*/
hasMenu = false;
/**
* @hidden
*
* Specifies a custom menu font icon class that will be rendered when the Chip has menu.
*/
menuIcon;
/**
* @hidden
*
* Specifies a custom menu SVG icon that will be rendered when the Chip has menu.
*/
menuSvgIcon;
/**
* If set to `true`, the Chip will be disabled.
* @default false
*/
disabled = false;
/**
* The size property specifies the padding of the Chip
* ([see example]({% slug appearance_chip %}#toc-size)).
*
* The possible values are:
* * `small`
* * `medium` (default)
* * `large`
* * `none`
*/
set size(size) {
const newSize = size ? size : DEFAULT_SIZE$1;
!this.sizeIsSet && (this.sizeIsSet = true);
this.handleClasses(newSize, 'size');
this._size = newSize;
}
get size() {
return this._size;
}
/**
* The rounded property specifies the border radius of the Chip
* ([see example](slug:appearance_chip#toc-roundness)).
*
* The possible values are:
* * `small`
* * `medium` (default)
* * `large`
* * `full`
* * `none`
*/
set rounded(rounded) {
const newRounded = rounded ? rounded : DEFAULT_ROUNDED$2;
this.handleClasses(newRounded, 'rounded');
this._rounded = newRounded;
}
get rounded() {
return this._rounded;
}
/**
* The fillMode property specifies the background and border styles of the Chip
* ([see example](slug:appearance_chip#toc-fill-mode)).
*
* The possible values are:
* * `solid` (default)
* * `outline`
* * `none`
*/
set fillMode(fillMode) {
const newFillMode = fillMode ? fillMode : DEFAULT_FILL_MODE$2;
this.handleClasses(newFillMode, 'fillMode');
this._fillMode = newFillMode;
}
get fillMode() {
return this._fillMode;
}
/**
* The Chip 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:appearance_chip#toc-theme-colors)).
*
* The possible values are:
* * `base` (default)
* * `info`
* * `success`
* * `warning`
* * `error`
* * `none`
*/
set themeColor(themeColor) {
const newThemeColor = themeColor ? themeColor : DEFAULT_THEME_COLOR$1;
this.handleThemeColor(newThemeColor);
this._themeColor = newThemeColor;
}
get themeColor() {
return this._themeColor;
}
/**
* Fires each time the user clicks the remove icon of the Chip.
*/
remove = new EventEmitter();
/**
* @hidden
*
* Fires each time the user clicks the menu icon of the Chip.
*/
menuToggle = new EventEmitter();
/**
* Fires each time the user clicks the content of the Chip.
*/
contentClick = new EventEmitter();
tabIndex = 0;
hostClass = true;
get hasIconClass() {
return Boolean(this.icon || this.iconClass || (this.avatarSettings && !isObjectEmpty(this.avatarSettings)));
}
get disabledClass() {
return this.disabled;
}
get selectedClass() {
return this.selected;
}
get focusedClass() {
return this.focused;
}
/**
* @hidden
*/
direction;
/**
* @hidden
*/
defaultRemoveIcon = xCircleIcon;
/**
* @hidden
*/
defaultMenuIcon = moreVerticalIcon;
/**
* @hidden
*/
sizeIsSet = false;
_size = 'medium';
_rounded = 'medium';
_fillMode = 'solid';
_themeColor = 'base';
focused = false;
subs = new Subscription();
constructor(element, renderer, ngZone, localizationService) {
this.element = element;
this.renderer = renderer;
this.ngZone = ngZone;
this.localizationService = localizationService;
validatePackage(packageMetadata);
this.direction = localizationService.rtl ? 'rtl' : 'ltr';
}
ngOnInit() {
this.subs.add(this.localizationService.changes
.subscribe(({ rtl }) => this.direction = rtl ? 'rtl' : 'ltr'));
this.renderer.setAttribute(this.element.nativeElement, 'role', 'button');
}
ngOnDestroy() {
this.subs.unsubscribe();
}
ngOnChanges(changes) {
if (changes && changes['selected']) {
const hasAriaSelected = this.element.nativeElement.hasAttribute('aria-selected');
if (!hasAriaSelected) {
this.renderer.setAttribute(this.element.nativeElement, 'aria-pressed', `${this.selected}`);
}
}
}
ngAfterViewInit() {
const chip = this.element.nativeElement;
const stylingOptions = ['size', 'rounded', 'fillMode'];
stylingOptions.forEach(input => {
this.handleClasses(this[input], input);
});
this.attachElementEventHandlers(chip);
}
/**
* @hidden
*/
get kendoIconClass() {
this.verifyIconSettings([this.iconClass]);
return `k-i-${this.icon}`;
}
/**
* @hidden
*/
get customIconClass() {
this.verifyIconSettings([this.icon]);
return this.iconClass;
}
/**
* @hidden
*/
get removeIconClass() {
return this.removeIcon ? this.removeIcon : 'k-i-x-circle';
}
/**
* Focuses the Chip component.
*/
focus() {
if (isDocumentAvailable()) {
this.element.nativeElement.focus();
}
}
/**
* Blurs the Chip component.
*/
blur() {
if (isDocumentAvailable()) {
this.element.nativeElement.blur();
}
}
/**
* @hidden
*/
onRemoveClick(e) {
if (this.removable) {
this.remove.emit({ sender: this, originalEvent: e });
}
}
/**
* @hidden
*/
onMenuClick(e) {
if (this.hasMenu) {
this.menuToggle.emit({ sender: this, originalEvent: e });
}
}
attachElementEventHandlers(chip) {
this.ngZone.runOutsideAngular(() => {
this.subs.add(this.renderer.listen(chip, 'focus', () => {
this.renderer.addClass(chip, 'k-focus');
}));
this.subs.add(this.renderer.listen(chip, 'blur', () => {
this.renderer.removeClass(chip, 'k-focus');
}));
this.subs.add(this.renderer.listen(chip, 'click', (e) => {
const isActionClicked = closest(e.target, '.k-chip-action');
if (!isActionClicked) {
this.ngZone.run(() => {
this.contentClick.emit({ sender: this, originalEvent: e });
});
}
}));
this.subs.add(this.renderer.listen(chip, 'keydown', this.keyDownHandler.bind(this)));
});
}
/**
* @hidden
*/
verifyIconSettings(iconsToCheck) {
if (isDevMode()) {
if (iconsToCheck.filter(icon => icon !== null && icon !== undefined).length > 0) {
this.renderer.removeClass(this.element.nativeElement, 'k-chip-has-icon');
throw new Error('Invalid configuration: Having multiple icons is not supported. Only a single icon on a chip can be displayed.');
}
}
}
handleClasses(value, input) {
const elem = this.element.nativeElement;
const classes = getStylingClasses('chip', input, this[input], value);
if (input === 'fillMode') {
this.handleThemeColor(this.themeColor, this[input], value);
}
if (classes.toRemove) {
this.renderer.removeClass(elem, classes.toRemove);
}
if (classes.toAdd) {
this.renderer.addClass(elem, classes.toAdd);
}
}
handleThemeColor(value, prevFillMode, fillMode) {
const elem = this.element.nativeElement;
const removeFillMode = prevFillMode ? prevFillMode : this.fillMode;
const addFillMode = fillMode ? fillMode : this.fillMode;
const themeColorClass = getThemeColorClasses('chip', removeFillMode, addFillMode, this.themeColor, value);
this.renderer.removeClass(elem, themeColorClass.toRemove);
if (addFillMode !== 'none' && fillMode !== 'none') {
if (themeColorClass.toAdd) {
this.renderer.addClass(elem, themeColorClass.toAdd);
}
}
}
keyDownHandler(e) {
const isEnterOrSpace = e.keyCode === Keys.Enter || e.keyCode === Keys.Space;
const isDeleteOrBackspace = e.keyCode === Keys.Delete || e.keyCode === Keys.Backspace;
if (this.disabled) {
return;
}
if (isEnterOrSpace) {
this.ngZone.run(() => {
this.contentClick.emit({ sender: this, originalEvent: e });
});
}
else if (isDeleteOrBackspace && this.removable) {
this.ngZone.run(() => {
this.remove.emit({ sender: this, originalEvent: e });
});
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ChipComponent, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ChipComponent, isStandalone: true, selector: "kendo-chip", inputs: { label: "label", icon: "icon", svgIcon: "svgIcon", iconClass: "iconClass", avatarSettings: "avatarSettings", selected: "selected", removable: "removable", removeIcon: "removeIcon", removeSvgIcon: "removeSvgIcon", hasMenu: "hasMenu", menuIcon: "menuIcon", menuSvgIcon: "menuSvgIcon", disabled: "disabled", size: "size", rounded: "rounded", fillMode: "fillMode", themeColor: "themeColor" }, outputs: { remove: "remove", menuToggle: "menuToggle", contentClick: "contentClick" }, host: { properties: { "attr.tabindex": "this.tabIndex", "class.k-chip": "this.hostClass", "class.k-chip-has-icon": "this.hasIconClass", "attr.aria-disabled": "this.disabledClass", "class.k-disabled": "this.disabledClass", "class.k-selected": "this.selectedClass", "class.k-focus": "this.focusedClass", "attr.dir": "this.direction" } }, providers: [
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.chip'
}
], usesOnChanges: true, ngImport: i0, template: `
<kendo-icon-wrapper
*ngIf="icon || svgIcon"
size="small"
innerCssClass="k-chip-icon"
[name]="icon"
[svgIcon]="svgIcon"></kendo-icon-wrapper>
<kendo-icon-wrapper
*ngIf="iconClass"
size="small"
innerCssClass="k-chip-icon"
[customFontClass]="customIconClass"></kendo-icon-wrapper>
<span
*ngIf="avatarSettings"
class="k-chip-avatar k-avatar k-avatar-sm k-avatar-solid k-avatar-solid-primary k-rounded-full"
[ngStyle]="avatarSettings.cssStyle">
<ng-container *ngIf="avatarSettings?.imageSrc">
<span class="k-avatar-image">
<img src="{{ avatarSettings.imageSrc }}" [ngStyle]="avatarSettings.imageCssStyle" [attr.alt]="avatarSettings.imageAltText" />
</span>
</ng-container>
<ng-container *ngIf="avatarSettings?.initials">
<span class="k-avatar-text" [ngStyle]="avatarSettings.initialsCssStyle">{{ avatarSettings.initials.substring(0, 2) }}</span>
</ng-container>
</span>
<span class="k-chip-content">
<span class="k-chip-label" *ngIf="label">
{{ label }}
</span>
<ng-content *ngIf="!label"></ng-content>
</span>
<span class="k-chip-actions" *ngIf="hasMenu || removable">
<span class="k-chip-action k-chip-more-action"
*ngIf="hasMenu"
(click)="onMenuClick($event)">
<kendo-icon-wrapper
name="more-vertical"
size="small"
[svgIcon]="defaultMenuIcon || menuSvgIcon"
[customFontClass]="menuIcon"></kendo-icon-wrapper>
</span>
<span class="k-chip-action k-chip-remove-action"
*ngIf="removable"
(click)="onRemoveClick($event)">
<kendo-icon-wrapper
name="x-circle"
size="small"
[svgIcon]="removeSvgIcon || defaultRemoveIcon"
[customFontClass]="removeIcon"></kendo-icon-wrapper>
</span>
</span>
`, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ChipComponent, decorators: [{
type: Component,
args: [{
selector: 'kendo-chip',
template: `
<kendo-icon-wrapper
*ngIf="icon || svgIcon"
size="small"
innerCssClass="k-chip-icon"
[name]="icon"
[svgIcon]="svgIcon"></kendo-icon-wrapper>
<kendo-icon-wrapper
*ngIf="iconClass"
size="small"
innerCssClass="k-chip-icon"
[customFontClass]="customIconClass"></kendo-icon-wrapper>
<span
*ngIf="avatarSettings"
class="k-chip-avatar k-avatar k-avatar-sm k-avatar-solid k-avatar-solid-primary k-rounded-full"
[ngStyle]="avatarSettings.cssStyle">
<ng-container *ngIf="avatarSettings?.imageSrc">
<span class="k-avatar-image">
<img src="{{ avatarSettings.imageSrc }}" [ngStyle]="avatarSettings.imageCssStyle" [attr.alt]="avatarSettings.imageAltText" />
</span>
</ng-container>
<ng-container *ngIf="avatarSettings?.initials">
<span class="k-avatar-text" [ngStyle]="avatarSettings.initialsCssStyle">{{ avatarSettings.initials.substring(0, 2) }}</span>
</ng-container>
</span>
<span class="k-chip-content">
<span class="k-chip-label" *ngIf="label">
{{ label }}
</span>
<ng-content *ngIf="!label"></ng-content>
</span>
<span class="k-chip-actions" *ngIf="hasMenu || removable">
<span class="k-chip-action k-chip-more-action"
*ngIf="hasMenu"
(click)="onMenuClick($event)">
<kendo-icon-wrapper
name="more-vertical"
size="small"
[svgIcon]="defaultMenuIcon || menuSvgIcon"
[customFontClass]="menuIcon"></kendo-icon-wrapper>
</span>
<span class="k-chip-action k-chip-remove-action"
*ngIf="removable"
(click)="onRemoveClick($event)">
<kendo-icon-wrapper
name="x-circle"
size="small"
[svgIcon]="removeSvgIcon || defaultRemoveIcon"
[customFontClass]="removeIcon"></kendo-icon-wrapper>
</span>
</span>
`,
providers: [
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.chip'
}
],
standalone: true,
imports: [NgIf, NgStyle, IconWrapperComponent, NgClass]
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: i1.LocalizationService }]; }, propDecorators: { label: [{
type: Input
}], icon: [{
type: Input
}], svgIcon: [{
type: Input
}], iconClass: [{
type: Input
}], avatarSettings: [{
type: Input
}], selected: [{
type: Input
}], removable: [{
type: Input
}], removeIcon: [{
type: Input
}], removeSvgIcon: [{
type: Input
}], hasMenu: [{
type: Input
}], menuIcon: [{
type: Input
}], menuSvgIcon: [{
type: Input
}], disabled: [{
type: Input
}], size: [{
type: Input
}], rounded: [{
type: Input
}], fillMode: [{
type: Input
}], themeColor: [{
type: Input
}], remove: [{
type: Output
}], menuToggle: [{
type: Output
}], contentClick: [{
type: Output
}], tabIndex: [{
type: HostBinding,
args: ['attr.tabindex']
}], hostClass: [{
type: HostBinding,
args: ['class.k-chip']
}], hasIconClass: [{
type: HostBinding,
args: ['class.k-chip-has-icon']
}], disabledClass: [{
type: HostBinding,
args: ['attr.aria-disabled']
}, {
type: HostBinding,
args: ['class.k-disabled']
}], selectedClass: [{
type: HostBinding,
args: ['class.k-selected']
}], focusedClass: [{
type: HostBinding,
args: ['class.k-focus']
}], direction: [{
type: HostBinding,
args: ['attr.dir']
}] } });
class ChipListComponent {
localizationService;
renderer;
element;
ngZone;
hostClass = true;
orientation = 'horizontal';
/**
* @hidden
*/
direction;
/**
* Sets the selection mode of the ChipList.
*
* The available values are:
* * `none` (default)
* * `single`
* * `multiple`
*/
selection = 'none';
/**
* The size property specifies the gap between the Chips in the ChipList
* ([see example]({% slug appearance_chiplist %}#toc-size)).
*
* The possible values are:
* * `'small'`
* * `'medium'` (default)
* * `'large'`
* * `none`
*/
set size(size) {
const sizeValue = size ? size : 'medium';
this.handleClasses(sizeValue, 'size');
this.chips?.forEach(chip => this.setChipSize(chip, sizeValue));
this._size = sizeValue;
}
get size() {
return this._size;
}
/**
* Fires each time when the ChipList selection is changed.
*/
selectedChange = new EventEmitter();
/**
* Fires each time the user clicks on the remove icon of the Chip.
*/
remove = new EventEmitter();
chips;
get single() {
return this.selection === 'single';
}
get multiple() {
return this.selection === 'multiple';
}
/**
* @hidden
*/
role = 'listbox';
dynamicRTLSubscription;
_size = 'medium';
subs = new Subscription();
_navigable = true;
/**
* @hidden
*/
onClick($event) {
const target = $event.target;
const isRemoveClicked = closest(target, '.k-chip-remove-action');
const clickedChip = closest(target, '.k-chip');
const chip = this.chips.find((chip) => clickedChip === chip.element.nativeElement);
this.currentActiveIndex = this.chips.toArray().indexOf(chip);
chip && chip.focus();
if (chip && this.navigable) {
this.chips.forEach((c) => {
this.renderer.setAttribute(c.element.nativeElement, 'tabindex', '-1');
});
this.renderer.setAttribute(chip.element.nativeElement, 'tabindex', '0');
}
if (isRemoveClicked && clickedChip) {
const removeEventArgs = { sender: this, originalEvent: $event, removedChip: chip };
this.remove.emit(removeEventArgs);
}
if (this.selection !== 'none' && clickedChip && !isRemoveClicked) {
this.setSelection(chip);
}
}
/**
* By default, keyboard navigation is available through arrow keys and roving tabindex.
* When set to `false`, all chips are part of the default tabbing sequence of the page.
*
* @default true
*/
set navigable(value) {
this._navigable = value;
this.chips?.forEach(c => this.renderer.setAttribute(c.element.nativeElement, 'tabindex', value ? '-1' : '0'));
this.chips?.first && this.renderer.setAttribute(this.chips.first.element.nativeElement, 'tabindex', '0');
}
get navigable() {
return this._navigable;
}
currentActiveIndex = 0;
constructor(localizationService, renderer, element, ngZone) {
this.localizationService = localizationService;
this.renderer = renderer;
this.element = element;
this.ngZone = ngZone;
validatePackage(packageMetadata);
this.direction = localizationService.rtl ? 'rtl' : 'ltr';
}
ngOnInit() {
this.dynamicRTLSubscription = this.localizationService.changes
.subscribe(({ rtl }) => this.direction = rtl ? 'rtl' : 'ltr');
}
ngAfterViewInit() {
const stylingInputs = ['size'];
stylingInputs.forEach(input => {
this.handleClasses(this[input], input);
});
this.attachElementEventHandlers();
this.updateChips();
}
ngAfterContentInit() {
this.subs.add(this.chips?.changes.subscribe(() => this.updateChips()));
}
ngOnDestroy() {
if (this.dynamicRTLSubscription) {
this.dynamicRTLSubscription.unsubscribe();
}
this.subs.unsubscribe();
}
selectedChips() {
return this.chips.reduce((acc, cur, idx) => { return cur.selected ? acc.concat(idx) : acc; }, []);
}
/**
* Updates the selection on click of a Chip. Emits events.
*/
setSelection(chip) {
if (this.selection === 'single') {
this.clearSelection(chip);
}
chip.selected = !chip.selected;
const chipEl = chip.element.nativeElement;
this.renderer.setAttribute(chipEl, 'aria-selected', `${chip.selected}`);
this.selectedChange.emit(this.selectedChips());
}
clearSelection(chip) {
this.chips.forEach((c) => {
if (chip !== c) {
c.selected = false;
this.renderer.setAttribute(c.element.nativeElement, 'aria-selected', 'false');
}
});
}
handleClasses(value, input) {
const elem = this.element.nativeElement;
const classes = getStylingClasses('chip-list', input, this[input], value);
if (classes.toRemove) {
this.renderer.removeClass(elem, classes.toRemove);
}
if (classes.toAdd) {
this.renderer.addClass(elem, classes.toAdd);
}
}
attachElementEventHandlers() {
const chiplist = this.element.nativeElement;
this.ngZone.runOutsideAngular(() => {
this.subs.add(this.renderer.listen(chiplist, 'keydown', this.keyDownHandler.bind(this)));
});
}
keyDownHandler(e) {
const isEnterOrSpace = e.keyCode === Keys.Enter || e.keyCode === Keys.Space;
const isDeleteOrBackspace = e.keyCode === Keys.Delete || e.keyCode === Keys.Backspace;
const isLeftArrow = e.keyCode === Keys.ArrowLeft;
const isRightArrow = e.keyCode === Keys.ArrowRight;
if (isEnterOrSpace) {
const target = e.target;
const clickedChip = closest(target, '.k-chip');
const chip = this.chips.find((chip) => clickedChip === chip.element.nativeElement);
this.currentActiveIndex = this.chips.toArray().findIndex((chip) => clickedChip === chip.element.nativeElement);
if (this.selection !== 'none' && clickedChip) {
this.ngZone.run(() => {
this.setSelection(chip);
});
}
}
else if (isDeleteOrBackspace) {
const target = e.target;
const clickedChip = closest(target, '.k-chip');
const chip = this.chips.find((chip) => clickedChip === chip.element.nativeElement);
if (clickedChip) {
const removeEventArgs = { sender: this, originalEvent: e, removedChip: chip };
this.ngZone.run(() => {
this.remove.emit(removeEventArgs);
});
}
}
else if (isLeftArrow) {
this.handleArrowKeys('left');
}
else if (isRightArrow) {
this.handleArrowKeys('right');
}
}
handleArrowKeys(direction) {
if (!this.navigable) {
return;
}
const directionDelta = direction === 'left' ? -1 : 1;
this.currentActiveIndex = this.currentActiveIndex + directionDelta;
if (this.currentActiveIndex >= this.chips.length) {
this.currentActiveIndex = 0;
}
else if (this.currentActiveIndex < 0) {
this.currentActiveIndex = this.chips.length - 1;
}
this.chips.forEach((chip, idx) => {
this.renderer.setAttribute(chip.element.nativeElement, 'tabindex', '-1');
if (idx === this.currentActiveIndex) {
this.renderer.setAttribute(chip.element.nativeElement, 'tabindex', '0');
chip.focus();
}
});
}
updateChips() {
this.normalizeActiveIndex();
this.chips.forEach((chip, idx) => {
const chipEl = chip.element.nativeElement;
this.renderer.removeAttribute(chipEl, 'aria-pressed');
this.renderer.setAttribute(chipEl, 'aria-selected', `${chip.selected}`);
this.role === 'listbox' && this.renderer.setAttribute(chipEl, 'role', 'option');
if (!this.navigable) {
return;
}
this.renderer.setAttribute(chipEl, 'tabindex', '-1');
if (idx === this.currentActiveIndex) {
this.renderer.setAttribute(chipEl, 'tabindex', '0');
if (isDocumentAvailable() && document.activeElement.closest('.k-chip-list')) {
chip.focus();
}
}
if (chip.removable) {
this.renderer.setAttribute(chipEl, 'aria-keyshortcuts', 'Enter Delete');
}
this.setChipSize(chip, this.size);
});
}
normalizeActiveIndex() {
if (this.currentActiveIndex >= this.chips.length) {
this.currentActiveIndex = Math.max(this.chips.length - 1, 0);
}
}
setChipSize(chip, size) {
const hasSize = chip.sizeIsSet;
!hasSize && chip.size !== size && (chip.size = size);
!hasSize && (chip.sizeIsSet = false);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ChipListComponent, deps: [{ token: i1.LocalizationService }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ChipListComponent, isStandalone: true, selector: "kendo-chiplist, kendo-chip-list", inputs: { selection: "selection", size: "size", role: "role", navigable: "navigable" }, outputs: { selectedChange: "selectedChange", remove: "remove" }, host: { listeners: { "click": "onClick($event)" }, properties: { "class.k-chip-list": "this.hostClass", "attr.aria-orientation": "this.orientation", "attr.dir": "this.direction", "class.k-selection-single": "this.single", "attr.aria-multiselectable": "this.multiple", "class.k-selection-multiple": "this.multiple", "attr.role": "this.role" } }, providers: [
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.chiplist'
}
], queries: [{ propertyName: "chips", predicate: ChipComponent }], ngImport: i0, template: `
<ng-content></ng-content>
`, isInline: true });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ChipListComponent, decorators: [{
type: Component,
args: [{
selector: 'kendo-chiplist, kendo-chip-list',
template: `
<ng-content></ng-content>
`,
providers: [
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.chiplist'
}
],
standalone: true
}]
}], ctorParameters: function () { return [{ type: i1.LocalizationService }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i0.NgZone }]; }, propDecorators: { hostClass: [{
type: HostBinding,
args: ['class.k-chip-list']
}], orientation: [{
type: HostBinding,
args: ['attr.aria-orientation']
}], direction: [{
type: HostBinding,
args: ['attr.dir']
}], selection: [{
type: Input
}], size: [{
type: Input
}], selectedChange: [{
type: Output
}], remove: [{
type: Output
}], chips: [{
type: ContentChildren,
args: [ChipComponent]
}], single: [{
type: HostBinding,
args: ['class.k-selection-single']
}], multiple: [{
type: HostBinding,
args: ['attr.aria-multiselectable']
}, {
type: HostBinding,
args: ['class.k-selection-multiple']
}], role: [{
type: HostBinding,
args: ['attr.role']
}, {
type: Input
}], onClick: [{
type: HostListener,
args: ['click', ['$event']]
}], navigable: [{
type: Input
}] } });
/**
* Used for rendering the list item content.
*
* To define the item template, nest a `<ng-template>` tag with the `kendo<ComponentName>ItemTemplate` directive inside the component tag.
*
* For the DropDownButton, use the `kendoDropDownButtonItemTemplate` directive.
* For the SplitButton, use the `kendoSplitButtonItemTemplate` directive.
*
* The template context is set to the current component. To get a reference to the current data item, use the `let-dataItem` directive.
*
* @example
* ```ts
* _@Component({
* selector: 'my-app',
* template: `
* <kendo-splitbutton [data]="listItems">
* <ng-template kendoSplitButtonItemTemplate let-dataItem>
* <span>{{dataItem}} option</span>
* </ng-template>
* </kendo-splitbutton>
* <kendo-dropdownbutton [data]="listItems">
* <ng-template kendoDropDownButtonItemTemplate let-dataItem>
* <span>{{dataItem}} option</span>
* </ng-template>
* </kendo-dropdownbutton>
* `
* })
* class AppComponent {
* public listItems: Array<any> = [{
* text: 'item1',
* icon: 'arrow-rotate-cw',
* disabled: false,
* click: (dataItem: any) => {
* //action
* }
* }, {
* text: 'item2',
* icon: 'arrow-rotate-cw',
* disabled: false,
* click: (dataItem: any) => {
* //action
* }
* }]
* }
* ```
*
* For more examples, refer to the article on the [DropDownButton templates](slug:itemstemplates_dropdownbutton).
*/
class ButtonItemTemplateDirective {
templateRef;
constructor(templateRef) {
this.templateRef = templateRef;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ButtonItemTemplateDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ButtonItemTemplateDirective, isStandalone: true, selector: "[kendoDropDownButtonItemTemplate],[kendoSplitButtonItemTemplate]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ButtonItemTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoDropDownButtonItemTemplate],[kendoSplitButtonItemTemplate]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } });
/**
* @hidden
*/
class FocusService {
onFocus = new EventEmitter();
focusedIndex;
isFocused(index) {
return index === this.focused;
}
focus(index) {
if (this.isFocused(index)) {
return;
}
this.focused = index;
this.onFocus.emit(index);
}
resetFocus() {
this.focused = -1;
}
get focused() {
return this.focusedIndex;
}
set focused(index) {
this.focusedIndex = index;
this.onFocus.emit(index);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FocusService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FocusService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FocusService, decorators: [{
type: Injectable
}] });
/**
* @hidden
*/
var KeyEvents;
(function (KeyEvents) {
KeyEvents[KeyEvents["keydown"] = 0] = "keydown";
KeyEvents[KeyEvents["keypress"] = 1] = "keypress";
KeyEvents[KeyEvents["keyup"] = 2] = "keyup";
})(KeyEvents || (KeyEvents = {}));
/**
* @hidden
*/
var NavigationAction;
(function (NavigationAction) {
// eslint-disable-next-line id-denylist
NavigationAction[NavigationAction["Undefined"] = 0] = "Undefined";
NavigationAction[NavigationAction["Open"] = 1] = "Open";
NavigationAction[NavigationAction["Close"] = 2] = "Close";
NavigationAction[NavigationAction["Enter"] = 3] = "Enter";
NavigationAction[NavigationAction["EnterPress"] = 4] = "EnterPress";
NavigationAction[NavigationAction["EnterUp"] = 5] = "EnterUp";
NavigationAction[NavigationAction["Tab"] = 6] = "Tab";
NavigationAction[NavigationAction["Esc"] = 7] = "Esc";
NavigationAction[NavigationAction["Navigate"] = 8] = "Navigate";
})(NavigationAction || (NavigationAction = {}));
/**
* @hidden
*/
const NAVIGATION_CONFIG = new InjectionToken('navigation.config');
/**
* @hidden
*/
class NavigationService {
navigate = new EventEmitter();
open = new EventEmitter();
close = new EventEmitter();
enter = new EventEmitter();
enterpress = new EventEmitter();
enterup = new EventEmitter();
tab = new EventEmitter();
esc = new EventEmitter();
useLeftRightArrows;
constructor(config) {
this.useLeftRightArrows = config.useLeftRightArrows;
}
process(args) {
const keyCode = args.keyCode;
const keyEvent = args.keyEvent;
let index;
let action = NavigationAction.Undefined;
if (keyEvent === KeyEvents.keyup) {
if (this.isEnterOrSpace(keyCode)) {
action = NavigationAction.EnterUp;
}
}
else {
if (args.altKey && keyCode === Keys.ArrowDown) {
action = NavigationAction.Open;
}
else if (args.altKey && keyCode === Keys.ArrowUp) {
action = NavigationAction.Close;
}
else if (this.isEnterOrSpace(keyCode)) {
action = NavigationAction.Enter;
}
else if (keyCode === Keys.Escape) {
action = NavigationAction.Esc;
}
else if (keyCode === Keys.Tab) {
action = NavigationAction.Tab;
}
else if (keyCode === Keys.ArrowUp || (this.useLeftRightArrows && keyCode === Keys.ArrowLeft)) {
const step = args.flipNavigation ? 1 : -1;
const start = args.flipNavigation ? args.min : args.max;
const end = args.flipNavigation ? args.max : args.min;
index = this.next({
current: args.current,
start: start,
end: end,
step: step
});
action = NavigationAction.Navigate;
}
else if (keyCode === Keys.ArrowDown || (this.useLeftRightArrows && keyCode === Keys.ArrowRight)) {
const step = args.flipNavigation ? -1 : 1;
const start = args.flipNavigation ? args.max : args.min;
const end = args.flipNavigation ? args.min : args.max;
index = this.next({
current: args.current,
start: start,
end: end,
step: step
});
action = NavigationAction.Navigate;
}
else if (keyCode === Keys.Home) {
index = args.min;
action = NavigationAction.Navigate;
}
else if (keyCode === Keys.End) {
index = args.max;
action = NavigationAction.Navigate;
}
}
if (action !== NavigationAction.Undefined) {
this[NavigationAction[action].toLowerCase()].emit({ index, target: args.target, esc: action === NavigationAction.Esc });
}
return action;
}
isEnterOrSpace(keyCode) {
return keyCode === Keys.Enter || keyCode === Keys.Space;
}
next(args) {
if (!isPresent(args.current)) {
return args.start;
}
else {
return args.current !== args.end ? args.current + args.step : args.end;
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NavigationService, deps: [{ token: NAVIGATION_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NavigationService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NavigationService, decorators: [{
type: Injectable
}], ctorParameters: function () { return [{ type: undefined, decorators: [{
type: Inject,
args: [NAVIGATION_CONFIG]
}] }]; } });
/**
* @hidden
*/
class PopupContainerService {
container;
template;
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PopupContainerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PopupContainerService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PopupContainerService, decorators: [{
type: Injectable
}] });
/**
* @hidden
*/
class FocusableDirective {
focusService;
renderer;
index;
element;
subs = new Subscription();
constructor(focusService, elementRef, renderer) {
this.focusService = focusService;
this.renderer = renderer;
this.element = elementRef.nativeElement;
this.subscribeEvents();
}
ngOnInit() {
if (this.index === this.focusService.focused) {
this.renderer.addClass(this.element, 'k-focus');
}
else {
this.renderer.removeClass(this.element, 'k-focus');
}
}
/**
* @hidden
*/
ngOnDestroy() {
this.subs.unsubscribe();
}
subscribeEvents() {
if (!isDocumentAvailable()) {
return;
}
this.subs.add(this.focusService.onFocus.subscribe((index) => {
if (this.index === index) {
this.renderer.addClass(this.element, 'k-focus');
this.renderer.setAttribute(this.element, 'tabindex', '0');
this.element.focus();
}
else {
this.renderer.setAttribute(this.element, 'tabindex', '-1');
this.renderer.removeClass(this.element, 'k-focus');
}
}));
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FocusableDirective, deps: [{ token: FocusService }, { token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: FocusableDirective, isStandalone: true, selector: "[kendoButtonFocusable]", inputs: { index: "index" }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FocusableDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoButtonFocusable]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: FocusService }, { type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { index: [{
type: Input
}] } });
/**
* @hidden
*/
class ListComponent {
data;
textField;
itemTemplate;
onItemClick = new EventEmitter();
onItemBlur = new EventEmitter();
set size(size) {
if (size) {
this.sizeClass = `k-menu-group-${SIZES[size]}`;
}
else {
this.sizeClass = '';
}
}
sizeClass = '';
constructor() {
validatePackage(packageMetadata);
}
getText(dataItem) {
if (dataItem) {
return this.textField ? dataItem[this.textField] : dataItem.text || dataItem;
}
return undefined;
}
getIconClasses(dataItem) {
const icon = dataItem.icon ? 'k-icon k-i-' + dataItem.icon : undefined;
const classes = {};
classes[icon || dataItem.iconClass] = true;
return classes;
}
onClick(index) {
this.onItemClick.emit(index);
}
onBlur() {
this.onItemBlur.emit();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ListComponent, isStandalone: true, selector: "kendo-button-list", inputs: { data: "data", textField: "textField", itemTemplate: "itemTemplate", size: "size" }, outputs: { onItemClick: "onItemClick", onItemBlur: "onItemBlur" }, ngImport: i0, template: `
<ul class="k-group k-menu-group k-reset" role="list" [ngClass]="sizeClass">
<li kendoButtonFocusable
*ngFor="let dataItem of data; let index = index;"
[index]="index"
tabindex="-1"
class="k-item k-menu-item"
role="listitem"
[attr.aria-disabled]="dataItem.disabled ? true : false"
(click)="$event.stopImmediatePropagation(); onClick(index);"
(blur)="onBlur()">
<ng-template [ngIf]="itemTemplate?.templateRef">
<span
class="k-link k-menu-link"
[class.k-disabled]="dataItem.disabled"
[ngClass]="dataItem.cssClass">
<ng-template
[templateContext]="{ templateRef: itemTemplate?.templateRef, $implicit: dataItem }"
></ng-template>
</span>
</ng-template>
<ng-template [ngIf]="!itemTemplate?.templateRef">
<span
class="k-link k-menu-link"
[class.k-disabled]="dataItem.disabled"
[ngClass]="dataItem.cssClass">
<kendo-icon-wrapper
*ngIf="dataItem.icon || dataItem.iconClass || dataItem.svgIcon"
[name]="dataItem.icon"
[svgIcon]="dataItem.svgIcon"
[customFontClass]="dataItem.iconClass"
></kendo-icon-wrapper>
<img
*ngIf="dataItem.imageUrl"
class="k-image"
[src]="dataItem.imageUrl"
[alt]="dataItem.imageAlt"
>
<span *ngIf="getText(dataItem)" class="k-menu-link-text">
{{ getText(dataItem) }}
</span>
</span>
</ng-template>
</li>
</ul>
`, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: FocusableDirective, selector: "[kendoButtonFocusable]", inputs: ["index"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: TemplateContextDirective, selector: "[templateContext]", inputs: ["templateContext"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ListComponent, decorators: [{
type: Component,
args: [{
selector: 'kendo-button-list',
template: `
<ul class="k-group k-menu-group k-reset" role="list" [ngClass]="sizeClass">
<li kendoButtonFocusable
*ngFor="let dataItem of data; let index = index;"
[index]="index"
tabindex="-1"
class="k-item k-menu-item"
role="listitem"
[attr.aria-disabled]="dataItem.disabled ? true : false"
(click)="$event.stopImmediatePropagation(); onClick(index);"
(blur)="onBlur()">
<ng-template [ngIf]="itemTemplate?.templateRef">
<span
class="k-link k-menu-link"
[class.k-disabled]="dataItem.disabled"
[ngClass]="dataItem.cssClass">
<ng-template
[templateContext]="{ templateRef: itemTemplate?.templateRef, $implicit: dataItem }"
></ng-template>
</span>
</ng-template>
<ng-template [ngIf]="!itemTemplate?.templateRef">
<span
class="k-link k-menu-link"
[class.k-disabled]="dataItem.disabled"
[ngClass]="dataItem.cssClass">
<kendo-icon-wrapper
*ngIf="dataItem.icon || dataItem.iconClass || dataItem.svgIcon"
[name]="dataItem.icon"
[svgIcon]="dataItem.svgIcon"
[customFontClass]="dataItem.iconClass"
></kendo-icon-wrapper>
<img
*ngIf="dataItem.imageUrl"
class="k-image"
[src]="dataItem.imageUrl"
[alt]="dataItem.imageAlt"
>
<span *ngIf="getText(dataItem)" class="k-menu-link-text">
{{ getText(dataItem) }}
</span>
</span>
</ng-template>
</li>
</ul>
`,
standalone: true,
imports: [NgClass, NgFor, FocusableDirective, NgIf, TemplateContextDirective, IconWrapperComponent]
}]
}], ctorParameters: function () { return []; }, propDecorators: { data: [{
type: Input
}], textField: [{
type: Input
}], itemTemplate: [{
type: Input
}], onItemClick: [{
type: Output
}], onItemBlur: [{
type: Output
}], size: [{
type: Input
}] } });
/**
* @hidden
*/
class ListButton extends MultiTabStop {
focusService;
navigationService;
wrapperRef;
_zone;
popupService;
elRef;
cdr;
containerService;
listId = guid();
buttonId = guid();
_data;
_open = false;
_disabled = false;
_active = false;
_popupSettings = { animate: true, popupClass: '' };
_isFocused = false;
_itemClick;
_blur;
wrapper;
subs = new Subscription();
direction;
popupRef;
popupSubs = new Subscription();
button;
buttonList;
popupTemplate;
container;
/**
* Sets the disabled state of the DropDownButton.
*/
set disabled(value) {
if (value && this.openState) {
this.openState = false;
}
this._disabled = value;
}
get disabled() {
return this._disabled;
}
/**
* Specifies the [`tabIndex`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex) of the component.
*/
tabIndex = 0;
/**
* 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;
/**
* 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();
/**
* Needed by the kendoToggleButtonTabStop directive
*
* @hidden
*/
escape = new EventEmitter();
/**
* @hidden
*/
get componentTabIndex() {
return this.disabled ? (-1) : this.tabIndex;
}
get appendTo() {
const { appendTo } = this.popupSettings;
if (!appendTo || appendTo === 'root') {
return undefined;
}
return appendTo === 'component' ? this.containerService.container : appendTo;
}
/**
* 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.
* - `appendTo: "root" | "component" | ViewContainerRef`—Specifies the component to which the popup will be appended.
* - `align: "left" | "center" | "right"`—Specifies the alignment of the popup.
*/
set popupSettings(settings) {
this._popupSettings = Object.assign({ animate: true, popupClass: '' }, settings);
}
get popupSettings() {
return this._popupSettings;
}
/**
* @hidden
*/
get anchorAlign() {
const align = { horizontal: this.popupSettings.align || 'left', vertical: 'bottom' };
if (this.direction === 'rtl' && !isPresent(this.popupSettings.align)) {
align.horizontal = 'right';
}
return align;
}
/**
* @hidden
*/
get popupAlign() {
const align = { horizontal: this.popupSettings.align || 'left', vertical: 'top' };
if (this.direction === 'rtl' && !isPresent(this.popupSettings.align)) {
align.horizontal = 'right';
}
return align;
}
isClosePrevented = false;
constructor(focusService, navigationService, wrapperRef, _zone, popupService, elRef, localization, cdr, containerService) {
super();
this.focusService = focusService;
this.navigationService = navigationService;
this.wrapperRef = wrapperRef;
this._zone = _zone;
this.popupService = popupService;
this.elRef = elRef;
this.cdr = cdr;
this.containerService = containerService;
validatePackage(packageMetadata);
this.focusService = focusService;
this.navigationService = navigationService;
this.wrapper = wrapperRef.nativeElement;
this.subs.add(localization.changes.subscribe(({ rtl }) => (this.direction = rtl ? 'rtl' : 'ltr')));
this.subscribeEvents();
}
ngOnChanges(changes) {
if (isChanged("popupSettings", changes) && isPresent(this.popupRef)) {
const popup = this.popupRef.popup.instance;
const newSettings = changes['popupSettings'].currentValue;
popup.popupClass = newSettings.popupClass;
popup.animate = newSettings.animate;
popup.popupAlign = this.popupAlign;
}
}
get popupClasses() {
const popupClasses = ['k-menu-popup'];
if (this._popupSettings.popupClass) {
popupClasses.push(this._popupSettings.popupClass);
}
return popupClasses.join(' ');
}
get openState() {
return this._open;
}
/**
* @hidden
*/
set openState(open) {
if (this.disabled) {
return;
}
this._open = open;
}
/**
* Returns the current open state of the popup.
*/
get isOpen() {
return this._open;
}
/**
* @hidden
*/
togglePopupVisibility() {
if (this._disabled) {
return;
}
this._toggle(!this.openState, true);
if (!this.isClosePrevented) {
this.focusService.focus(this.openState ? 0 : -1);
}
}
/**
* @hidden
*/
onItemClick(index) {
this.emitItemClickHandler(index);
this.togglePopupVisibility();
if (isDocumentAvailable() && !this.isClosePrevented) {
this.focusButton();
}
}
ngOnDestroy() {
this.openState = false;
this.subs.unsubscribe();
this.destroyPopup();
}
subscribeEvents() {
if (!isDocumentAvailable()) {
return;
}
this.subscribeListItemFocusEvent();
this.subscribeComponentBlurredEvent();
this.subscribeNavigationEvents();
}
subscribeListItemFocusEvent() {
this.subs.add(this.focusService.onFocus.subscribe(() => {
this._isFocused = true;
}));
}
subscribeComponentBlurredEvent() {
this._zone.runOutsideAngular(() => {
this.subs.add(this.navigationService.tab.pipe(filter(() => this._isFocused), tap(() => this.focusButton())).subscribe(this.handleTab.bind(this)));
this.subs.add(fromEvent(document, 'click')
.pipe(filter((event) => !this.wrapperContains(event.target)), filter(() => this._isFocused))
.subscribe(() => this._zone.run(() => this.blurWrapper())));
});
}
subscribeNavigationEvents() {
this.subs.add(this.navigationService.navigate
.subscribe(this.onArrowKeyNavigate.bind(this)));
this.subs.add(this.navigationService.enterup.subscribe(this.onNavigationEnterUp.bind(this)));
this.subs.add(this.navigationService.open.subscribe(this.onNavigationOpen.bind(this)));
this.subs.add(merge(this.navigationService.close, this.navigationService.esc).subscribe(this.onNavigationClose.bind(this)));
}
/**
* Toggles the visibility of the popup.
* If the `toggle` method is used to open or close the popup, the `open` and `close` events will not be fired.
*
* @param open - The state of the popup.
*/
toggle(open) {
if (this.disabled) {
return;
}
const value = open === undefined ? !this.openState : open;
this._toggle(value, false);
}
/**
* @hidden
*/
keyDownHandler(event, isHost) {
this.keyHandler(event, null, isHost);
}
/**
* @hidden
*/
keyUpHandler(event) {
this.keyHandler(event, KeyEvents.keyup);
}
/**
* @hidden
*/
keyHandler(event, keyEvent, isHost) {
if (this._disabled) {
return;
}
const eventData = event;
if (!isHost) {
eventData.stopImmediatePropagation();
}
const focused = this.focusService.focused || 0;
const action = this.navigationService.process({
altKey: eventData.altKey,
current: focused,
keyCode: eventData.keyCode,
keyEvent: keyEvent,
max: this._data ? this._data.length - 1 : 0,
min: 0,
target: event.target
});
if (action !== NavigationAction.Undefined &&
action !== NavigationAction.Tab &&
(action !== NavigationAction.Enter || (action === NavigationAction.Enter && this.openState))) {
if (!(event.keyCode === Keys.Space && action === NavigationAction.EnterUp)) {
eventData.preventDefault();
}
}
}
emitItemClickHandler(index) {
const dataItem = this._data[index];
if (this._itemClick && !dataItem.disabled) {
this._itemClick.emit(dataItem);
}
if (dataItem && dataItem.click && !dataItem.disabled) {
dataItem.click(dataItem);
}
this.focusService.focus(index);
}
focusWrapper() {
if (this.openState) {
this.togglePopupVisibility();
this.focusButton();
}
}
wrapperContains(element) {
return this.wrapper === element || this.wrapper.contains(element);
}
blurWrapper(emit = true) {
if (!this._isFocused) {
return;
}
if (this.openState) {
this.togglePopupVisibility();
}
this._isFocused = false;
if (emit) {
this._blur.emit();
this.cdr.markForCheck();
}
}
focusButton() {
if (this.button) {
this.button.nativeElement.focus();
}
}
handleTab() {
this.blurWrapper();
}
onNavigationEnterUp(_args) {
if (!this._disabled && !this.openState) {
this._active = false;
}
if (this.openState) {
const focused = this.focusService.focused;
if (isPresent(focused) && focused !== -1) {
this.emitItemClickHandler(focused);
}
}
this.togglePopupVisibility();
if (!this.openState && isDocumentAvailable()) {
this.button.nativeElement.focus();
}
}
onNavigationOpen() {
if (!this._disabled && !this.openState) {
this.togglePopupVisibility();
}
}
onNavigationClose(e) {
if (this.openState && !this.isClosePrevented) {
this.togglePopupVisibility();
if (isDocumentAvailable()) {
e?.esc && hasObservers(this.escape) && this.escape.emit();
this.button.nativeElement.focus();
}
}
}
onArrowKeyNavigate({ index }) {
this.focusService.focus(index);
}
_toggle(open, emitEvent) {
if (this.openState === open) {
return;
}
const eventArgs = new PreventableEvent();
if (emitEvent) {
if (open && !this.openState) {
this.open.emit(eventArgs);
}
else if (!open && this.openState) {
this.close.emit(eventArgs);
}
if (eventArgs.isDefaultPrevented()) {
this.isClosePrevented = true;
return;
}
}
this.openState = open;
this.destroyPopup();
if (this.openState) {
this.createPopup();
}
}
createPopup() {
this.popupRef = this.popupService.open({
anchor: this.elRef,
anchorAlign: this.anchorAlign,
animate: this.popupSettings.animate,
appendTo: this.appendTo,
content: this.containerService.template,
popupAlign: this.popupAlign,
popupClass: this.popupClasses
});
this.popupSubs = this.popupRef.popupAnchorViewportLeave.subscribe(() => {
this.togglePopupVisibility();
});
}
destroyPopup() {
if (this.popupRef) {
this.popupRef.close();
this.popupRef = null;
this.popupSubs.unsubscribe();
this.isClosePrevented = false;
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ListButton, deps: [{ token: FocusService }, { token: NavigationService }, { token: i0.ElementRef }, { token: i0.NgZone }, { token: i3.PopupService }, { token: i0.ElementRef }, { token: i1.LocalizationService }, { token: i0.ChangeDetectorRef }, { token: PopupContainerService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ListButton, selector: "ng-component", inputs: { disabled: "disabled", tabIndex: "tabIndex", buttonClass: "buttonClass", popupSettings: "popupSettings" }, outputs: { open: "open", close: "close", escape: "escape" }, viewQueries: [{ propertyName: "button", first: true, predicate: ["button"], descendants: true, read: ElementRef }, { propertyName: "buttonList", first: true, predicate: ["buttonList"], descendants: true }, { propertyName: "popupTemplate", first: true, predicate: ["popupTemplate"], descendants: true }, { propertyName: "container", first: true, predicate: ["container"], descendants: true, read: ViewContainerRef }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: '', isInline: true });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ListButton, decorators: [{
type: Component,
args: [{
template: ''
}]
}], ctorParameters: function () { return [{ type: FocusService }, { type: NavigationService }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: i3.PopupService }, { type: i0.ElementRef }, { type: i1.LocalizationService }, { type: i0.ChangeDetectorRef }, { type: PopupContainerService }]; }, propDecorators: { button: [{
type: ViewChild,
args: ['button', { read: ElementRef }]
}], buttonList: [{
type: ViewChild,
args: ['buttonList']
}], popupTemplate: [{
type: ViewChild,
args: ['popupTemplate']
}], container: [{
type: ViewChild,
args: ['container', { read: ViewContainerRef }]
}], disabled: [{
type: Input
}], tabIndex: [{
type: Input
}], buttonClass: [{
type: Input
}], open: [{
type: Output
}], close: [{
type: Output
}], escape: [{
type: Output
}], popupSettings: [{
type: Input
}] } });
const NAVIGATION_SETTINGS$2 = {
useLeftRightArrows: true
};
const NAVIGATION_SETTINGS_PROVIDER$2 = {
provide: NAVIGATION_CONFIG,
useValue: NAVIGATION_SETTINGS$2
};
const DEFAULT_FILL_MODE$1 = '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'
* }];
* }
* ```
*/
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$1;
_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$1(this.buttonAttributes) && isPresent$1(mainButton)) {
for (const attr in this.buttonAttributes) {
this.renderer.removeAttribute(mainButton, attr, this.buttonAttributes[attr]);
}
}
if (isPresent$1(newButtonAttributes) && isPresent$1(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: FocusService }, { token: NavigationService }, { token: i0.ElementRef }, { token: i0.NgZone }, { token: i3.PopupService }, { token: i0.ElementRef }, { token: i1.LocalizationService }, { token: i0.ChangeDetectorRef }, { token: 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$2,
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$2,
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: FocusService }, { type: NavigationService }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: i3.PopupService }, { type: i0.ElementRef }, { type: i1.LocalizationService }, { type: i0.ChangeDetectorRef }, { type: 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']]
}] } });
/**
* @hidden
*/
function getAnchorAlign(fabAlign, rtl) {
const align = { horizontal: (rtl ? 'right' : 'left'), vertical: 'bottom' };
if (fabAlign.horizontal === 'end') {
align.horizontal = rtl ? 'left' : 'right';
}
if (fabAlign.vertical === 'bottom') {
align.vertical = 'top';
}
if (fabAlign.vertical === 'bottom' && fabAlign.horizontal === 'end') {
align.horizontal = rtl ? 'left' : 'right';
align.vertical = 'top';
}
return align;
}
/**
* @hidden
*/
function getPopupAlign(fabAlign, rtl) {
const align = { horizontal: (rtl ? 'right' : 'left'), vertical: 'top' };
if (fabAlign.horizontal === 'end') {
align.horizontal = rtl ? 'left' : 'right';
}
if (fabAlign.vertical === 'bottom') {
align.vertical = 'bottom';
}
if (fabAlign.vertical === 'bottom' && fabAlign.horizontal === 'end') {
align.horizontal = rtl ? 'left' : 'right';
align.vertical = 'bottom';
}
return align;
}
/**
* @hidden
*/
function openAnimation(animationSettings) {
const isBottom = animationSettings.align.vertical === 'bottom';
const duration = animationSettings.duration;
const gap = animationSettings.gap;
return sequence([
query(`.k-fab-item`, [
style({ opacity: 0, transform: `translateY(${isBottom ? '8px' : '-8px'})` }),
stagger(gap, [animate(`${duration}ms ease-in`, style({ opacity: '*', transform: 'translateY(0)' }))])
], { optional: true })
]);
}
/**
* @hidden
*/
function closeAnimation(animationSettings) {
const isBottom = animationSettings.align.vertical === 'bottom';
const duration = animationSettings.duration;
const gap = animationSettings.gap;
return sequence([
query(`.k-fab-item`, [
style({ opacity: '*', transform: 'translateY(0)' }),
stagger(-gap, [animate(`${duration}ms ease-in`, style({ opacity: 0, transform: `translateY(${isBottom ? '8px' : '-8px'})` }))])
], { optional: true })
]);
}
/**
* Represents a template that defines the content of the whole dial item.
* To define the template, nest an `<ng-template>` tag
* with the `kendoDialItemTemplate` directive inside the `<kendo-floatingactionbutton>` tag
* ([see example]({% slug templates_floatingactionbutton %}#toc-dial-item-template)).
*/
class DialItemTemplateDirective {
templateRef;
constructor(templateRef) {
this.templateRef = templateRef;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DialItemTemplateDirective, deps: [{ token: i0.TemplateRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: DialItemTemplateDirective, isStandalone: true, selector: "[kendoDialItemTemplate]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DialItemTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoDialItemTemplate]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i0.TemplateRef, decorators: [{
type: Optional
}] }]; } });
/**
* Represents a template that defines the content of the FloatingActionButton.
* To define the template, nest an `<ng-template>` tag
* with the `kendoFloatingActionButtonTemplate` directive inside the `<kendo-floatingactionbutton>` tag
* ([see example]({% slug templates_floatingactionbutton %}#toc-floatingactionbutton-template)).
*/
class FloatingActionButtonTemplateDirective {
templateRef;
constructor(templateRef) {
this.templateRef = templateRef;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FloatingActionButtonTemplateDirective, deps: [{ token: i0.TemplateRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: FloatingActionButtonTemplateDirective, isStandalone: true, selector: "[kendoFloatingActionButtonTemplate]", ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FloatingActionButtonTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoFloatingActionButtonTemplate]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i0.TemplateRef, decorators: [{
type: Optional
}] }]; } });
/**
* @hidden
*/
class DialItemComponent {
element;
renderer;
localisationService;
hostClass = true;
role = 'menuitem';
get disabledClass() {
return this.item.disabled;
}
get title() {
const label = this.item.label;
return label || this.itemTitle;
}
get indexAttr() {
return this.index;
}
cssClass;
cssStyle;
isFocused;
index;
item;
dialItemTemplate;
align;
constructor(element, renderer, localisationService) {
this.element = element;
this.renderer = renderer;
this.localisationService = localisationService;
}
get iconClasses() {
const classes = [];
if (this.item.iconClass) {
classes.push(`${this.item.iconClass}`);
}
if (this.item.icon) {
classes.push(`k-fab-item-icon k-icon k-i-${this.item.icon}`);
}
return classes;
}
get itemTitle() {
const icon = this.item.icon;
const itemTitle = this.item.itemTitle;
return (icon && itemTitle) ? itemTitle : icon;
}
ngAfterViewInit() {
const element = this.element.nativeElement;
const rtl = this.localisationService.rtl;
const hAlign = this.align.horizontal;
this.renderer.addClass(element, this.getTextDirectionClass(rtl, hAlign));
}
getTextDirectionClass(rtl, hAlign) {
const dir = rtl ? 'rtl' : 'ltr';
const align = hAlign === 'end' ? 'end' : 'start';
const directions = {
rtl: { end: 'k-text-left', start: 'k-text-right' },
ltr: { start: 'k-text-left', end: 'k-text-right' }
};
return directions[dir][align];
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DialItemComponent, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DialItemComponent, isStandalone: true, selector: "[kendoDialItem]", inputs: { cssClass: "cssClass", cssStyle: "cssStyle", isFocused: "isFocused", index: "index", item: "item", dialItemTemplate: "dialItemTemplate", align: "align" }, host: { properties: { "class.k-fab-item": "this.hostClass", "attr.role": "this.role", "attr.aria-disabled": "this.disabledClass", "class.k-disabled": "this.disabledClass", "attr.title": "this.title", "attr.aria-label": "this.title", "attr.data-fab-item-index": "this.indexAttr" } }, ngImport: i0, template: `
<ng-template *ngIf="dialItemTemplate"
[ngTemplateOutlet]="dialItemTemplate"
[ngTemplateOutletContext]="{ $implicit: item, index: index, isFocused: isFocused }"
>
</ng-template>
<ng-container *ngIf="!dialItemTemplate">
<span *ngIf="item.label" class="k-fab-item-text">{{ item.label }}</span>
<kendo-icon-wrapper
*ngIf="item.icon || item.iconClass || item.svgIcon"
[name]="item.icon"
innerCssClass="k-fab-item-icon"
[customFontClass]="item.iconClass"
[svgIcon]="item.svgIcon"></kendo-icon-wrapper>
</ng-container>
`, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DialItemComponent, decorators: [{
type: Component,
args: [{
// eslint-disable-next-line @angular-eslint/component-selector
selector: '[kendoDialItem]',
template: `
<ng-template *ngIf="dialItemTemplate"
[ngTemplateOutlet]="dialItemTemplate"
[ngTemplateOutletContext]="{ $implicit: item, index: index, isFocused: isFocused }"
>
</ng-template>
<ng-container *ngIf="!dialItemTemplate">
<span *ngIf="item.label" class="k-fab-item-text">{{ item.label }}</span>
<kendo-icon-wrapper
*ngIf="item.icon || item.iconClass || item.svgIcon"
[name]="item.icon"
innerCssClass="k-fab-item-icon"
[customFontClass]="item.iconClass"
[svgIcon]="item.svgIcon"></kendo-icon-wrapper>
</ng-container>
`,
standalone: true,
imports: [NgIf, NgTemplateOutlet, IconWrapperComponent]
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i1.LocalizationService }]; }, propDecorators: { hostClass: [{
type: HostBinding,
args: ['class.k-fab-item']
}], role: [{
type: HostBinding,
args: ['attr.role']
}], disabledClass: [{
type: HostBinding,
args: ['attr.aria-disabled']
}, {
type: HostBinding,
args: ['class.k-disabled']
}], title: [{
type: HostBinding,
args: ['attr.title']
}, {
type: HostBinding,
args: ['attr.aria-label']
}], indexAttr: [{
type: HostBinding,
args: ['attr.data-fab-item-index']
}], cssClass: [{
type: Input
}], cssStyle: [{
type: Input
}], isFocused: [{
type: Input
}], index: [{
type: Input
}], item: [{
type: Input
}], dialItemTemplate: [{
type: Input
}], align: [{
type: Input
}] } });
/**
* @hidden
*/
class DialListComponent {
focusService;
cdr;
hostClass = true;
get bottomClass() {
return this.align.vertical === 'top' || this.align.vertical === 'middle';
}
get topClass() {
return this.align.vertical === 'bottom';
}
dialItems;
dialItemTemplate;
align;
subscriptions = new Subscription();
constructor(focusService, cdr) {
this.focusService = focusService;
this.cdr = cdr;
this.subscriptions.add(this.focusService.onFocus.subscribe(() => this.cdr.detectChanges()));
}
isFocused(index) {
return this.focusService.isFocused(index);
}
ngOnDestroy() {
this.subscriptions.unsubscribe();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DialListComponent, deps: [{ token: FocusService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DialListComponent, isStandalone: true, selector: "[kendoDialList]", inputs: { dialItems: "dialItems", dialItemTemplate: "dialItemTemplate", align: "align" }, host: { properties: { "class.k-fab-items": "this.hostClass", "class.k-fab-items-bottom": "this.bottomClass", "class.k-fab-items-top": "this.topClass" } }, ngImport: i0, template: `
<ng-container *ngFor='let item of dialItems; let idx = index'>
<li
kendoButtonFocusable
kendoDialItem
[item]="dialItems[idx]"
[index]="idx"
[dialItemTemplate]="dialItemTemplate"
[isFocused]="isFocused(idx)"
[ngClass]='item.cssClass'
[ngStyle]='item.cssStyle'
[align]="align"
>
</li>
</ng-container>
`, isInline: true, dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: FocusableDirective, selector: "[kendoButtonFocusable]", inputs: ["index"] }, { kind: "component", type: DialItemComponent, selector: "[kendoDialItem]", inputs: ["cssClass", "cssStyle", "isFocused", "index", "item", "dialItemTemplate", "align"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DialListComponent, decorators: [{
type: Component,
args: [{
// eslint-disable-next-line @angular-eslint/component-selector
selector: '[kendoDialList]',
template: `
<ng-container *ngFor='let item of dialItems; let idx = index'>
<li
kendoButtonFocusable
kendoDialItem
[item]="dialItems[idx]"
[index]="idx"
[dialItemTemplate]="dialItemTemplate"
[isFocused]="isFocused(idx)"
[ngClass]='item.cssClass'
[ngStyle]='item.cssStyle'
[align]="align"
>
</li>
</ng-container>
`,
standalone: true,
imports: [NgFor, FocusableDirective, DialItemComponent, NgClass, NgStyle]
}]
}], ctorParameters: function () { return [{ type: FocusService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { hostClass: [{
type: HostBinding,
args: ['class.k-fab-items']
}], bottomClass: [{
type: HostBinding,
args: ['class.k-fab-items-bottom']
}], topClass: [{
type: HostBinding,
args: ['class.k-fab-items-top']
}], dialItems: [{
type: Input
}], dialItemTemplate: [{
type: Input
}], align: [{
type: Input
}] } });
const NAVIGATION_SETTINGS$1 = {
useLeftRightArrows: false
};
const NAVIGATION_SETTINGS_PROVIDER$1 = {
provide: NAVIGATION_CONFIG,
useValue: NAVIGATION_SETTINGS$1
};
const SIZE_CLASSES = {
small: 'k-fab-sm',
medium: 'k-fab-md',
large: 'k-fab-lg'
};
const ROUNDED_CLASSES = {
small: 'k-rounded-sm',
medium: 'k-rounded-md',
large: 'k-rounded-lg',
full: 'k-rounded-full'
};
const FILLMODE_CLASS = 'k-fab-solid';
const DEFAULT_DURATION = 180;
const DEFAULT_ITEM_GAP = 90;
const DEFAULT_OFFSET = '16px';
const DEFAULT_ROUNDED$1 = 'full';
const DEFAULT_SIZE = 'medium';
const DEFAULT_THEME_COLOR = 'primary';
/**
*
* Represents the [Kendo UI FloatingActionButton component for Angular]({% slug overview_floatingactionbutton %}).
* Used to specify the primary or the most common action in an application.
*
*/
class FloatingActionButtonComponent {
renderer;
element;
focusService;
navigationService;
ngZone;
popupService;
builder;
localizationService;
get fixedClass() {
return this.positionMode === 'fixed';
}
get absoluteClass() {
return this.positionMode === 'absolute';
}
direction;
button;
popupTemplate;
dialItemTemplate;
fabTemplate;
/**
* Specifies the theme color of the FloatingActionButton
* ([see example](slug:appearance_floatingactionbutton#toc-theme-colors)).
* The theme color will be applied as background color of the component.
*
* The possible values are:
* * `primary` (Default)—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 built in theme color.
*/
set themeColor(themeColor) {
const newThemeColor = themeColor ? themeColor : DEFAULT_THEME_COLOR;
this.handleClasses(newThemeColor, 'themeColor');
this._themeColor = newThemeColor;
}
get themeColor() {
return this._themeColor;
}
/**
* Specifies the size of the FloatingActionButton
* ([see example]({% slug appearance_floatingactionbutton %}#toc-size)).
*
* The possible values are:
* * `small`
* * `medium` (Default)
* * `large`
* * `none`
*/
set size(size) {
const newSize = size ? size : DEFAULT_SIZE;
this.handleClasses(newSize, 'size');
this._size = newSize;
}
get size() {
return this._size;
}
/**
* The rounded property specifies the border radius of the FloatingActionButton.
*
* The possible values are:
* * `small`
* * `medium`
* * `large`
* * `full` (default)
* * `none`
*/
set rounded(rounded) {
const newRounded = rounded ? rounded : DEFAULT_ROUNDED$1;
this.handleClasses(newRounded, 'rounded');
this._rounded = newRounded;
}
get rounded() {
return this._rounded;
}
/**
* Specifies whether the FloatingActionButton is disabled.
*/
set disabled(disabled) {
this._disabled = disabled;
}
get disabled() {
return this._disabled;
}
/**
* Specifies the horizontal and vertical alignment of the FloatingActionButton
* ([see example](slug:positioning_floatingactionbutton#toc-alignment)).
*
* The possible values are:
* * `{ horizontal: 'start'|'center'|'end', vertical: 'top'|'middle'|'bottom' }`
*
* The default value is:
* * `{ horizontal: 'end', vertical: 'bottom' }`
*
*/
set align(align) {
this._align = Object.assign(this._align, align);
}
get align() {
return this._align;
}
/**
* Specifies the horizontal and vertical offset position of the FloatingActionButton
* ([see example]({% slug positioning_floatingactionbutton %}#toc-offset)).
*
* * The default value is:
* * `{ x: '16px', y: '16px' }`
*/
set offset(offset) {
this._offset = Object.assign(this._offset, offset);
this.offsetStyles();
}
get offset() {
return this._offset;
}
/**
* Specifies the positionMode of the FloatingActionButton
* ([see example](slug:positioning_floatingactionbutton#toc-position-mode)).
*
* * The possible values are:
* * `absolute`—Positions the FloatingActionButton absolutely to its first positioned parent element.
* * `fixed` (Default)—Positions the FloatingActionButton relative to the viewport. It always stays in the same place even if the page is scrolled.
*/
positionMode = 'fixed';
/**
* Defines the name of an existing icon in a Kendo UI theme.
* If provided, the icon will be rendered inside the FloatingActionButton by a `span.k-icon` element.
*/
icon;
/**
* Defines an [`SVGIcon`](slug:api_icons_svgicon) to be rendered within the FloatingActionButton.
*/
svgIcon;
/**
* Defines a CSS class or multiple classes separated by spaces which are applied to a `span` element.
* Allows the usage of custom icons, rendered inside the FloatingActionButton by a `span` element.
*/
iconClass;
/**
* 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 dial items `ul` element.
* Supports the type of values that are supported by [`ngClass`](link:site.data.urls.angular['ngclassapi']).
*/
dialClass;
/**
* Specifies the text content of the FloatingActionButton.
*/
text;
/**
* Specifies the animation settings of the FloatingActionButton dial items.
* ([see example]({% slug dialitems_floatingactionbutton %}#toc-animation)).
*
* The possible values are:
* * Boolean
* * (Default) `true`—Applies the default [`DialItemAnimation`]({% slug api_buttons_dialitemanimation %}) settings.
* * `false`
* * `DialItemAnimation`
* * `duration`—Specifies the animation duration in milliseconds for each dial item. Defaults to `180ms`.
* * `gap`—Specifies the animation duration gap in milliseconds after each dial item is animated. Defaults to `90ms`.
*/
dialItemAnimation = true;
/**
* Specifies the [`tabIndex`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex) of the FloatingActionButton.
*/
tabIndex = 0;
/**
* Specifies the collection of the dial items that will be rendered in the FloatingActionButton popup.
*/
dialItems = [];
/**
* Fires each time the FloatingActionButton gets blurred.
*/
onBlur = new EventEmitter();
/**
* Fires each time the FloatingActionButton gets focused.
*/
onFocus = new EventEmitter();
/**
* Fires each time a dial item is clicked.
*/
dialItemClick = 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
* ([more information and example](slug:events_floatingactionbutton)).
*/
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
* ([more information and example](slug:events_floatingactionbutton)).
*/
close = new EventEmitter();
/**
* @hidden
*/
get componentTabIndex() {
return this.disabled ? (-1) : this.tabIndex;
}
/**
* @hidden
*/
id = `k-${guid()}`;
/**
* @hidden
*/
dialListId = `k-dial-list-${guid()}`;
_themeColor = DEFAULT_THEME_COLOR;
_size = DEFAULT_SIZE;
_rounded = DEFAULT_ROUNDED$1;
_disabled = false;
_align = { horizontal: 'end', vertical: 'bottom' };
_offset = { x: DEFAULT_OFFSET, y: DEFAULT_OFFSET };
subscriptions = new Subscription();
popupMouseDownListener;
rtl = false;
animationEnd = new EventEmitter();
popupRef;
initialSetup = true;
focusChangedProgrammatically = false;
constructor(renderer, element, focusService, navigationService, ngZone, popupService, builder, localizationService) {
this.renderer = renderer;
this.element = element;
this.focusService = focusService;
this.navigationService = navigationService;
this.ngZone = ngZone;
this.popupService = popupService;
this.builder = builder;
this.localizationService = localizationService;
validatePackage(packageMetadata);
this.subscribeNavigationEvents();
this.subscriptions.add(this.localizationService.changes.subscribe(({ rtl }) => {
this.rtl = rtl;
this.direction = this.rtl ? 'rtl' : 'ltr';
}));
}
ngAfterViewInit() {
['size', 'rounded', 'themeColor'].forEach(option => this.handleClasses(this[option], option));
this.renderer.addClass(this.element.nativeElement, this.alignClass());
this.offsetStyles();
this.initialSetup = false;
}
ngOnDestroy() {
this.subscriptions.unsubscribe();
this.isOpen && this.toggleDial(false);
}
/**
* Indicates whether the FloatingActionButton is currently open.
*/
get isOpen() { return isPresent(this.popupRef); }
/**
* Focuses the FloatingActionButton.
*/
focus() {
if (isDocumentAvailable()) {
this.focusChangedProgrammatically = true;
this.button.nativeElement.focus();
this.focusChangedProgrammatically = false;
}
}
/**
* Blurs the FloatingActionButton.
*/
blur() {
if (isDocumentAvailable()) {
this.focusChangedProgrammatically = true;
this.button.nativeElement.blur();
this.focusChangedProgrammatically = false;
}
}
/**
* Toggles the visibility of the FloatingActionButton dial items popup.
*
* If you use the `toggleDial` method to open or close the dial items,
* the `open` and `close` events do not fire ([more information and examples](slug:openstate_floatingactionbutton)).
*
* @param open - The state of dial items popup.
*/
toggleDial(open) {
if (this.disabled || !this.hasDialItems) {
return;
}
const shouldOpen = isPresent(open) ? open : !this.isOpen;
if (this.disabled || shouldOpen === this.isOpen) {
return;
}
if (shouldOpen) {
setTimeout(() => this.openDial());
}
else {
this.closeDial();
}
}
/**
* @hidden
*/
get ariaExpanded() {
return this.hasDialItems ? this.isOpen : undefined;
}
/**
* @hidden
*/
get ariaHasPopup() {
return this.hasDialItems ? 'menu' : undefined;
}
/**
* @hidden
*/
get ariaControls() {
return this.hasDialItems ? this.isOpen ? this.dialListId : undefined : undefined;
}
/**
* @hidden
*/
get iconClasses() {
const classes = [];
if (this.iconClass) {
classes.push(`${this.iconClass}`);
}
if (this.icon) {
classes.push(`k-fab-icon k-icon k-i-${this.icon}`);
}
return classes;
}
/**
* @hidden
*/
clickHandler() {
if (this.disabled || !this.hasDialItems) {
return;
}
this.ngZone.run(() => {
const shouldOpen = !this.isOpen;
this.toggleDialWithEvents(shouldOpen);
});
}
/**
* @hidden
*/
pointerdownHandler(e) {
if (this.isOpen) {
e.preventDefault();
this.focus();
}
}
/**
* @hidden
*/
keyDownHandler(event) {
if (this.disabled) {
return;
}
const focused = this.focusService.focused || 0;
const keyCode = event.keyCode;
const action = this.navigationService.process({
altKey: event.altKey,
current: focused,
keyCode,
max: this.dialItems ? this.dialItems.length - 1 : 0,
min: 0,
flipNavigation: this.align.vertical === 'bottom'
});
if (action !== NavigationAction.Undefined && action !== NavigationAction.Tab) {
event.preventDefault();
}
if (action === NavigationAction.Tab && event.target.closest(`#${this.dialListId}`)) {
this.focus();
}
if (action === NavigationAction.EnterUp && !this.hasDialItems) {
this.button.nativeElement.click();
}
else if (action === NavigationAction.Open || action === NavigationAction.Close) {
const toggleDial = action === NavigationAction.Open;
this.ngZone.run(() => {
this.toggleDialWithEvents(toggleDial);
});
}
}
/**
* @hidden
*/
onItemClick(event) {
const item = closest(event.target, '.k-fab-item');
if (!item) {
return;
}
const index = parseInt(item.getAttribute('data-fab-item-index'));
this.emitItemClick(index);
}
/**
* @hidden
*/
focusHandler() {
if (!this.disabled && !this.focusChangedProgrammatically) {
this.onFocus.emit();
}
}
/**
* @hidden
*/
blurHandler(e) {
const focusInList = e.relatedTarget && (e.relatedTarget.closest(`#${this.dialListId}`));
if (focusInList) {
return;
}
!this.focusChangedProgrammatically && this.onBlur.emit();
this.toggleDialWithEvents(false);
}
/**
* @hidden
*/
focusOutHandler(e) {
const focusInList = e.relatedTarget && (e.relatedTarget.closest(`#${this.dialListId}`));
const focusOnButton = e.relatedTarget === this.button.nativeElement;
const shouldClose = !focusInList && !focusOnButton;
if (shouldClose) {
this.toggleDialWithEvents(false);
!this.focusChangedProgrammatically && this.onBlur.emit();
}
}
/**
* @hidden
*/
onNavigationEnterPress() {
this.ngZone.run(() => {
if (this.isOpen) {
const focusedIndex = this.focusService.focused;
const focusedItem = this.dialItems[focusedIndex];
if (focusedItem && focusedItem.disabled) {
return;
}
if (isPresent(focusedIndex) && focusedIndex !== -1) {
this.onEnterPressed();
return;
}
}
if (!this.isOpen && isDocumentAvailable()) {
this.toggleDialWithEvents(true);
this.focus();
}
});
}
/**
* @hidden
*/
onNavigationClose() {
if (this.isOpen) {
this.ngZone.run(() => {
this.toggleDialWithEvents(false);
this.focus();
});
}
}
handleClasses(inputValue, input) {
if (isPresent(this.button) && (this[input] !== inputValue || this.initialSetup)) {
const button = this.button.nativeElement;
const classesToRemove = {
themeColor: `${FILLMODE_CLASS}-${this.themeColor}`,
size: SIZE_CLASSES[this.size],
rounded: ROUNDED_CLASSES[this.rounded]
};
const classesToAdd = {
themeColor: inputValue !== 'none' ? `${FILLMODE_CLASS}-${inputValue}` : '',
size: SIZE_CLASSES[inputValue],
rounded: ROUNDED_CLASSES[inputValue]
};
this.renderer.removeClass(button, classesToRemove[input]);
if (classesToAdd[input]) {
this.renderer.addClass(button, classesToAdd[input]);
}
}
}
onEnterPressed() {
const index = this.focusService.focused;
this.emitItemClick(index);
}
emitItemClick(index) {
const item = this.dialItems[index];
if (item && !item.disabled) {
const clickEventArgs = { item: item, index: index };
this.dialItemClick.emit(clickEventArgs);
this.toggleDialWithEvents(false);
this.focusService.focused = index;
}
this.focus();
}
subscribeNavigationEvents() {
this.subscriptions.add(this.navigationService.navigate.subscribe(this.onArrowKeyNavigate.bind(this)));
this.subscriptions.add(this.navigationService.enter.subscribe(this.onNavigationEnterPress.bind(this)));
this.subscriptions.add(merge(this.navigationService.close, this.navigationService.esc).subscribe(this.onNavigationClose.bind(this)));
}
onArrowKeyNavigate({ index }) {
this.focusService.focus(index);
}
alignClass() {
return `k-pos-${this.align.vertical}-${this.align.horizontal}`;
}
toggleDialWithEvents(open) {
if (open === this.isOpen) {
return;
}
const event = new PreventableEvent();
if (open) {
this.open.emit(event);
}
else {
this.close.emit(event);
}
if (event.isDefaultPrevented()) {
return;
}
if (open) {
this.openDial();
}
else {
this.closeDial();
}
}
openPopup() {
if (this.isOpen) {
return;
}
const isIconFab = this.icon && !this.text;
const rtl = this.rtl;
const align = this.align;
this.popupRef = this.popupService.open({
anchor: this.element.nativeElement,
animate: false,
content: this.popupTemplate,
anchorAlign: getAnchorAlign(align, rtl),
popupAlign: getPopupAlign(align, rtl),
popupClass: 'k-fab-popup k-popup-transparent'
});
const popupElement = this.popupRef.popupElement;
this.renderer.setStyle(popupElement, 'box-shadow', 'none');
if (isIconFab) {
this.subscriptions.add(this.popupRef.popupOpen.subscribe(() => this.positionPopup()));
}
this.ngZone.runOutsideAngular(() => {
this.popupMouseDownListener = this.renderer.listen(popupElement, 'mousedown', (event) => {
event.preventDefault();
});
});
this.popupRef.popupAnchorViewportLeave.subscribe(() => this.toggleDialWithEvents(false));
}
closePopup() {
if (this.isOpen) {
if (this.popupMouseDownListener) {
this.popupMouseDownListener();
}
this.popupRef.close();
this.popupRef = null;
}
}
openDial() {
this.openPopup();
this.focusService.focus(0);
if (this.dialItemAnimation && this.isValidAnimation()) {
this.playAnimation(true);
}
this.renderer.setAttribute(this.button.nativeElement, 'aria-expanded', 'true');
}
closeDial() {
if (this.dialItemAnimation && this.isValidAnimation()) {
this.playAnimation(false);
this.animationEnd.pipe(take(1)).subscribe(() => this.closePopup());
}
else {
this.closePopup();
}
this.renderer.setAttribute(this.button.nativeElement, 'aria-expanded', 'false');
this.focusService.resetFocus();
}
isValidAnimation() {
const animation = this.dialItemAnimation;
if (typeof animation !== 'boolean') {
return animation.duration !== 0;
}
return true;
}
positionPopup() {
if (this.dialItemTemplate) {
return;
}
if (!this.popupRef) {
return;
}
const fab = this.element.nativeElement;
const fabWidth = fab.getBoundingClientRect().width;
const popupEl = this.popupRef.popupElement;
const icon = popupEl.querySelector('.k-fab-item-icon');
if (!icon) {
return;
}
const iconWidth = icon.getBoundingClientRect().width;
const left = (fabWidth / 2) - (iconWidth / 2);
const popupLeft = popupEl.getBoundingClientRect().left;
const isEndAlign = this.align.horizontal === 'end';
const leftValue = isEndAlign ? (popupLeft - left) : (left + popupLeft);
const rtlLeftValue = isEndAlign ? (left + popupLeft) : (popupLeft - left);
popupEl.style.left = this.rtl ? `${rtlLeftValue}px` : `${leftValue}px`;
}
offsetStyles() {
const hostElement = this.element.nativeElement;
this.renderer.setStyle(hostElement, this.horizontalPosition, this.horizontalOffset);
this.renderer.setStyle(hostElement, this.verticalPosition, this.verticalOffset);
}
get hasDialItems() {
return isPresent(this.dialItems) && this.dialItems.length !== 0;
}
/**
* Gets the CSS prop name of the selected vertical position (`top`/`bottom`);
*/
get verticalPosition() {
return {
top: 'top',
middle: 'top',
bottom: 'bottom'
}[this.align.vertical];
}
/**
* Gets the offset according to the selected vertical position.
*/
get verticalOffset() {
if (this.align.vertical === 'middle') {
return this.offset.y === DEFAULT_OFFSET ? '50%' : `calc(50% + ${this.offset.y})`;
}
return this.offset.y;
}
/**
* Gets the CSS prop name of the selected horizontal position (`left`/`right`);
*/
get horizontalPosition() {
const { horizontal } = this.align;
return {
end: this.rtl ? 'left' : 'right',
center: 'left',
start: this.rtl ? 'right' : 'left'
}[horizontal];
}
/**
* Gets the offset according to the selected horizontal position.
*/
get horizontalOffset() {
if (this.align.horizontal === 'center') {
return this.offset.x === DEFAULT_OFFSET ? '50%' : `calc(50% + ${this.offset.x})`;
}
return this.offset.x;
}
playerFor(element, animation) {
const factory = this.builder.build(animation);
return factory.create(element);
}
playAnimation(open) {
const durationSettings = this.durationSettings();
const animationSettings = {
duration: durationSettings.duration,
gap: durationSettings.gap,
align: this.align
};
const animation = open ? openAnimation(animationSettings) : closeAnimation(animationSettings);
let player = this.playerFor(this.popupRef.popupElement, animation);
player.play();
player.onDone(() => {
if (player) {
this.animationEnd.emit();
player.destroy();
player = null;
}
});
}
durationSettings() {
return {
duration: this.animationDuration(),
gap: this.animationGap()
};
}
animationGap() {
const animation = this.dialItemAnimation;
if (typeof animation !== 'boolean' && isPresent(animation.gap)) {
return animation.gap;
}
return DEFAULT_ITEM_GAP;
}
animationDuration() {
const animation = this.dialItemAnimation;
if (typeof animation !== 'boolean' && isPresent(animation.duration)) {
return animation.duration;
}
return DEFAULT_DURATION;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FloatingActionButtonComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }, { token: FocusService }, { token: NavigationService }, { token: i0.NgZone }, { token: i3.PopupService }, { token: i4.AnimationBuilder }, { token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: FloatingActionButtonComponent, isStandalone: true, selector: "kendo-floatingactionbutton", inputs: { themeColor: "themeColor", size: "size", rounded: "rounded", disabled: "disabled", align: "align", offset: "offset", positionMode: "positionMode", icon: "icon", svgIcon: "svgIcon", iconClass: "iconClass", buttonClass: "buttonClass", dialClass: "dialClass", text: "text", dialItemAnimation: "dialItemAnimation", tabIndex: "tabIndex", dialItems: "dialItems" }, outputs: { onBlur: "blur", onFocus: "focus", dialItemClick: "dialItemClick", open: "open", close: "close" }, host: { properties: { "class.k-pos-fixed": "this.fixedClass", "class.k-pos-absolute": "this.absoluteClass", "attr.dir": "this.direction" } }, providers: [
FocusService,
NavigationService,
NAVIGATION_SETTINGS_PROVIDER$1,
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.floatingactionbutton'
}
], queries: [{ propertyName: "dialItemTemplate", first: true, predicate: DialItemTemplateDirective, descendants: true }, { propertyName: "fabTemplate", first: true, predicate: FloatingActionButtonTemplateDirective, descendants: true }], viewQueries: [{ propertyName: "button", first: true, predicate: ["button"], descendants: true, static: true }, { propertyName: "popupTemplate", first: true, predicate: ["popupTemplate"], descendants: true, static: true }], ngImport: i0, template: `
<button
#button
[attr.id]="id"
[tabIndex]="componentTabIndex"
type="button"
class="k-fab k-fab-solid"
[class.k-disabled]="disabled"
[ngClass]="buttonClass"
[disabled]="disabled"
[attr.aria-disabled]="disabled"
[attr.aria-expanded]="ariaExpanded"
[attr.aria-haspopup]="ariaHasPopup"
[attr.aria-controls]="ariaControls"
(focus)="focusHandler()"
(blur)="blurHandler($event)"
[kendoEventsOutsideAngular]="{
keydown: keyDownHandler,
click: clickHandler,
pointerdown: pointerdownHandler
}"
[scope]="this"
>
<ng-template *ngIf="fabTemplate"
[ngTemplateOutlet]="fabTemplate?.templateRef"
>
</ng-template>
<ng-container *ngIf="!fabTemplate">
<kendo-icon-wrapper
*ngIf="icon || iconClass || svgIcon"
[name]="icon"
innerCssClass="k-fab-icon"
[customFontClass]="iconClass"
[svgIcon]="svgIcon"></kendo-icon-wrapper>
<span *ngIf="text" class="k-fab-text">{{ text }}</span>
</ng-container>
</button>
<ng-template #popupTemplate>
<ul
kendoDialList
role="menu"
[id]="dialListId"
[ngClass]="dialClass"
[dialItems]="dialItems"
[dialItemTemplate]='dialItemTemplate?.templateRef'
[align]="align"
[attr.aria-labelledby]="id"
(click)="onItemClick($event)"
[kendoEventsOutsideAngular]="{
keydown: keyDownHandler.bind(this),
focusout: focusOutHandler.bind(this)
}"
>
</ul>
</ng-template>
`, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: EventsOutsideAngularDirective, selector: "[kendoEventsOutsideAngular]", inputs: ["kendoEventsOutsideAngular", "scope"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }, { kind: "component", type: DialListComponent, selector: "[kendoDialList]", inputs: ["dialItems", "dialItemTemplate", "align"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FloatingActionButtonComponent, decorators: [{
type: Component,
args: [{
selector: 'kendo-floatingactionbutton',
providers: [
FocusService,
NavigationService,
NAVIGATION_SETTINGS_PROVIDER$1,
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.floatingactionbutton'
}
],
template: `
<button
#button
[attr.id]="id"
[tabIndex]="componentTabIndex"
type="button"
class="k-fab k-fab-solid"
[class.k-disabled]="disabled"
[ngClass]="buttonClass"
[disabled]="disabled"
[attr.aria-disabled]="disabled"
[attr.aria-expanded]="ariaExpanded"
[attr.aria-haspopup]="ariaHasPopup"
[attr.aria-controls]="ariaControls"
(focus)="focusHandler()"
(blur)="blurHandler($event)"
[kendoEventsOutsideAngular]="{
keydown: keyDownHandler,
click: clickHandler,
pointerdown: pointerdownHandler
}"
[scope]="this"
>
<ng-template *ngIf="fabTemplate"
[ngTemplateOutlet]="fabTemplate?.templateRef"
>
</ng-template>
<ng-container *ngIf="!fabTemplate">
<kendo-icon-wrapper
*ngIf="icon || iconClass || svgIcon"
[name]="icon"
innerCssClass="k-fab-icon"
[customFontClass]="iconClass"
[svgIcon]="svgIcon"></kendo-icon-wrapper>
<span *ngIf="text" class="k-fab-text">{{ text }}</span>
</ng-container>
</button>
<ng-template #popupTemplate>
<ul
kendoDialList
role="menu"
[id]="dialListId"
[ngClass]="dialClass"
[dialItems]="dialItems"
[dialItemTemplate]='dialItemTemplate?.templateRef'
[align]="align"
[attr.aria-labelledby]="id"
(click)="onItemClick($event)"
[kendoEventsOutsideAngular]="{
keydown: keyDownHandler.bind(this),
focusout: focusOutHandler.bind(this)
}"
>
</ul>
</ng-template>
`,
standalone: true,
imports: [NgClass, EventsOutsideAngularDirective, NgIf, NgTemplateOutlet, IconWrapperComponent, DialListComponent]
}]
}], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ElementRef }, { type: FocusService }, { type: NavigationService }, { type: i0.NgZone }, { type: i3.PopupService }, { type: i4.AnimationBuilder }, { type: i1.LocalizationService }]; }, propDecorators: { fixedClass: [{
type: HostBinding,
args: ['class.k-pos-fixed']
}], absoluteClass: [{
type: HostBinding,
args: ['class.k-pos-absolute']
}], direction: [{
type: HostBinding,
args: ['attr.dir']
}], button: [{
type: ViewChild,
args: ['button', { static: true }]
}], popupTemplate: [{
type: ViewChild,
args: ['popupTemplate', { static: true }]
}], dialItemTemplate: [{
type: ContentChild,
args: [DialItemTemplateDirective, { static: false }]
}], fabTemplate: [{
type: ContentChild,
args: [FloatingActionButtonTemplateDirective, { static: false }]
}], themeColor: [{
type: Input
}], size: [{
type: Input
}], rounded: [{
type: Input
}], disabled: [{
type: Input
}], align: [{
type: Input
}], offset: [{
type: Input
}], positionMode: [{
type: Input
}], icon: [{
type: Input
}], svgIcon: [{
type: Input
}], iconClass: [{
type: Input
}], buttonClass: [{
type: Input
}], dialClass: [{
type: Input
}], text: [{
type: Input
}], dialItemAnimation: [{
type: Input
}], tabIndex: [{
type: Input
}], dialItems: [{
type: Input
}], onBlur: [{
type: Output,
args: ['blur']
}], onFocus: [{
type: Output,
args: ['focus']
}], dialItemClick: [{
type: Output,
args: ['dialItemClick']
}], open: [{
type: Output
}], close: [{
type: Output
}] } });
/**
* @hidden
*/
class Messages extends ComponentMessages {
/**
* The text for the SplitButton aria-label.
*
* The text for the aria-label consists of a two-part message - the text of the SplitButton and a localizable string.
* For a SplitButton with text 'Reply', the default aria-label will be 'Reply splitbutton'.
*
* To allow reordering of the SplitButton text and the localizable part, the splitButtonLabel accepts a string with a
* placeholder for the button text - e.g. 'splitbutton for {buttonText}'. The '{buttonText}' placeholder will be replaced
* internally with the current SplitButton text, and the resulting aria-label will be rendered as 'splitbutton for Reply'.
*
* @example
*
* ```ts-no-run
* <kendo-splitbutton>
* <kendo-splitbutton-messages
* splitButtonLabel="splitbutton for {buttonText}"
* >
* </kendo-splitbutton-messages>
* </kendo-splitbutton>
* ```
*/
splitButtonLabel;
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: Messages, deps: null, target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: Messages, selector: "kendo-splitbutton-messages-base", inputs: { splitButtonLabel: "splitButtonLabel" }, usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: Messages, decorators: [{
type: Directive,
args: [{
// eslint-disable-next-line @angular-eslint/directive-selector
selector: 'kendo-splitbutton-messages-base'
}]
}], propDecorators: { splitButtonLabel: [{
type: Input
}] } });
/**
* Custom component messages override default component messages
* ([see example]({% slug rtl_buttons %}).
*/
class SplitButtonCustomMessagesComponent extends Messages {
service;
constructor(service) {
super();
this.service = service;
}
get override() {
return true;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SplitButtonCustomMessagesComponent, deps: [{ token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: SplitButtonCustomMessagesComponent, isStandalone: true, selector: "kendo-splitbutton-messages", providers: [{
provide: Messages,
useExisting: forwardRef(() => SplitButtonCustomMessagesComponent)
}], usesInheritance: true, ngImport: i0, template: ``, isInline: true });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SplitButtonCustomMessagesComponent, decorators: [{
type: Component,
args: [{
providers: [{
provide: Messages,
useExisting: forwardRef(() => SplitButtonCustomMessagesComponent)
}],
selector: 'kendo-splitbutton-messages',
template: ``,
standalone: true
}]
}], ctorParameters: function () { return [{ type: i1.LocalizationService }]; } });
/**
* @hidden
*/
class LocalizedSplitButtonMessagesDirective extends Messages {
service;
constructor(service) {
super();
this.service = service;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalizedSplitButtonMessagesDirective, deps: [{ token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: LocalizedSplitButtonMessagesDirective, isStandalone: true, selector: "[kendoSplitButtonLocalizedMessages]", providers: [
{
provide: Messages,
useExisting: forwardRef(() => LocalizedSplitButtonMessagesDirective)
}
], usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalizedSplitButtonMessagesDirective, decorators: [{
type: Directive,
args: [{
providers: [
{
provide: Messages,
useExisting: forwardRef(() => LocalizedSplitButtonMessagesDirective)
}
],
selector: '[kendoSplitButtonLocalizedMessages]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i1.LocalizationService }]; } });
const NAVIGATION_SETTINGS = {
useLeftRightArrows: true
};
const NAVIGATION_SETTINGS_PROVIDER = {
provide: NAVIGATION_CONFIG,
useValue: NAVIGATION_SETTINGS
};
const DEFAULT_ROUNDED = 'medium';
const DEFAULT_FILL_MODE = 'solid';
/**
* Represents the Kendo UI SplitButton component for Angular.
*
* @example
* ```ts
* _@Component({
* selector: 'my-app',
* template: `
* <kendo-splitbutton [data]="data" icon="clipboard"
* (itemClick)="onSplitButtonItemClick($event)"
* (buttonClick)="onSplitButtonClick()">Paste</kendo-splitbutton>
* `
* })
*
* class AppComponent {
* public data: Array<any> = [{
* text: 'Keep Text Only',
* icon: 'clipboard-text',
* click: () => { console.log('Keep Text Only click handler'); }
* }, {
* text: 'Paste as HTML',
* icon: 'clipboard-code'
* }, {
* text: 'Paste Markdown',
* icon: 'clipboard-markdown'
* }, {
* text: 'Set Default Paste'
* }];
*
* public onSplitButtonClick(dataItem: any): void {
* console.log('Paste');
* }
*
* public onSplitButtonItemClick(dataItem: any): void {
* if (dataItem) {
* console.log(dataItem.text);
* }
* }
* }
* ```
*/
class SplitButtonComponent extends ListButton {
localization;
renderer;
/**
* Sets the text of the SplitButton.
*/
text = '';
/**
* Defines an icon to be rendered next to the button text.
* ([see example]({% slug databinding_splitbutton %}#toc-arrays-of-complex-data)).
*/
icon = '';
/**
* Defines an SVGIcon to be rendered next to the button text.
*/
svgIcon;
/**
* Defines an icon with a custom CSS class to be rendered next to the button text
* ([see example]({% slug databinding_splitbutton %}#toc-arrays-of-complex-data)).
*/
iconClass;
/**
* Defines the type attribute of the main button
*/
type = 'button';
/**
* Defines the location of an image to be displayed next to the button text
* ([see example]({% slug databinding_splitbutton %}#toc-arrays-of-complex-data)).
*/
imageUrl = '';
/**
* The size property specifies the padding of the SplitButton
* ([see example]({% slug api_buttons_splitbuttoncomponent %}#toc-size)).
*
* The possible values are:
* * `small`
* * `medium` (default)
* * `large`
* * `none`
*/
size = 'medium';
/**
* The rounded property specifies the border radius of the SplitButton
* ([see example]({% slug api_buttons_splitbuttoncomponent %}#toc-rounded)).
*
* The possible values are:
* * `small`
* * `medium` (default)
* * `large`
* * `full`
* * `none`
*/
set rounded(rounded) {
const newRounded = rounded ? rounded : DEFAULT_ROUNDED;
this.handleClasses(newRounded, 'rounded');
this._rounded = newRounded;
}
get rounded() {
return this._rounded;
}
/**
* The fillMode property specifies the background and border styles of the SplitButton
* ([see example]({% slug api_buttons_splitbuttoncomponent %}#toc-fillMode)).
*
* The available values are:
* * `solid` (default)
* * `flat`
* * `outline`
* * `link`
*/
set fillMode(fillMode) {
const newFillMode = fillMode ? fillMode : DEFAULT_FILL_MODE;
this._fillMode = fillMode === 'clear' ? 'flat' : newFillMode;
}
get fillMode() {
return this._fillMode;
}
/**
* The SplitButton 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_splitbuttoncomponent %}#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 built in theme color.
*/
themeColor = 'base';
/**
* When set to `true`, disables a SplitButton item
* ([see example]({% slug databinding_splitbutton %}#toc-arrays-of-complex-data)).
*/
set disabled(value) {
if (this.isOpen) {
this.toggle(false);
}
this._disabled = value;
}
get disabled() {
return this._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.
* - `appendTo: "root" | "component" | ViewContainerRef`—Specifies the component to which the popup will be appended.
* - `align: "left" | "center" | "right"`—Specifies the alignment of the popup.
*/
set popupSettings(settings) {
this._popupSettings = Object.assign({ animate: true, popupClass: '' }, settings);
}
get popupSettings() {
return this._popupSettings;
}
/**
* Specifies the [`tabIndex`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex) of the component.
*/
tabIndex = 0;
/**
* Configures the text field of the button-list popup.
*/
textField;
/**
* Sets the data of the SplitButton.
*
* > 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;
}
/**
* 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;
/**
* 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 the main button.
*
* @example
* ```ts
* _@Component({
* selector: 'my-app',
* template: `
* <kendo-splitbutton (buttonClick)="onSplitButtonClick()" [data]="data">
* Reply
* </kendo-splitbutton>
* `
* })
* class AppComponent {
* public data: Array<any> = ['Reply All', 'Forward', 'Reply & Delete'];
*
* public onSplitButtonClick(): void {
* console.log('SplitButton click');
* }
* }
* ```
*
*/
buttonClick = new EventEmitter();
/**
* Fires each time the user clicks on the drop-down list. The event data contains the data item bound to the clicked list item.
*
* @example
* ```ts
* _@Component({
* selector: 'my-app',
* template: `
* <kendo-splitbutton (itemClick)="onSplitButtonItemClick($event)" [data]="data">
* Reply
* </kendo-splitbutton>
* `
* })
* class AppComponent {
* public data: Array<any> = ['Reply All', 'Forward', 'Reply & Delete'];
*
* public onSplitButtonItemClick(dataItem?: string): void {
* if (dataItem) {
* console.log(dataItem);
* }
* }
* }
* ```
*
*/
itemClick = new EventEmitter();
/**
* Fires each time the SplitButton gets focused.
*/
onFocus = new EventEmitter();
/**
* Fires each time the SplitButton gets blurred.
*/
onBlur = 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();
/**
* An item template that helps to customize the item content.
*/
itemTemplate;
activeArrow = false;
listId = guid();
/**
* @hidden
*/
get hasContent() {
return this.button?.nativeElement.childElementCount > 0;
}
/**
* @hidden
*/
get active() {
return this._active;
}
/**
* @hidden
*/
get componentTabIndex() {
return this.disabled ? -1 : this.tabIndex;
}
buttonText = '';
arrowButtonClicked = false;
_rounded = DEFAULT_ROUNDED;
_fillMode = DEFAULT_FILL_MODE;
_buttonAttributes = null;
documentMouseUpSub;
set isFocused(value) {
this._isFocused = value;
}
get isFocused() {
return this._isFocused && !this._disabled && isDocumentAvailable() && this.wrapperContains(document.activeElement);
}
get widgetClasses() {
return true;
}
get dir() {
return this.direction;
}
/**
* @hidden
*/
get ariaLabel() {
const localizationMsg = this.localization.get('splitButtonLabel') || '';
return replaceMessagePlaceholder(localizationMsg, 'buttonText', this.buttonText);
}
/**
* @hidden
*/
onButtonFocus(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
*/
onArrowButtonClick() {
this.togglePopupVisibility();
this.arrowButtonClicked = false;
if (!this.isOpen) {
this.focus();
}
}
/**
* @hidden
*/
toggleButtonActiveState(enable) {
this._active = enable;
}
/**
* @hidden
*/
toggleArrowButtonActiveState(enable) {
this.arrowButtonClicked = true;
this.activeArrow = enable;
}
/**
* @hidden
*/
onButtonClick() {
this.buttonClick.emit();
}
/**
* @hidden
*/
onButtonBlur() {
if (!this.isOpen && !this.arrowButtonClicked) {
this.blurWrapper();
}
}
/**
* @hidden
*/
keydown(event) {
this.keyDownHandler(event, true);
if (event.keyCode === Keys.Space) {
this._active = true;
}
}
/**
* @hidden
*/
keyup(event) {
this._active = false;
if (event.keyCode !== Keys.Space) {
this.keyUpHandler(event);
}
}
/**
* @hidden
*/
ngAfterViewInit() {
this.containerService.container = this.container;
this.containerService.template = this.popupTemplate;
this.updateButtonText();
this.handleClasses(this.rounded, 'rounded');
this.handleButtonAttributes(this.buttonAttributes);
}
/**
* @hidden
*/
ngOnChanges(changes) {
if (changes.hasOwnProperty('text')) {
this.updateButtonText();
}
if (anyChanged(['text', 'icon', 'svgIcon', 'iconClass', 'imageUrl'], changes)) {
this.toggleButtonIconClass();
}
if (isChanged('popupSettings', changes) && isPresent(this.popupRef)) {
const popup = this.popupRef.popup.instance;
const newSettings = changes['popupSettings'].currentValue;
popup.popupClass = newSettings.popupClass;
popup.animate = newSettings.animate;
popup.popupAlign = this.popupAlign;
}
}
/**
* @hidden
*/
ngOnDestroy() {
if (this.documentMouseUpSub) {
this.documentMouseUpSub();
}
}
/**
* @hidden
*/
onNavigationEnterUp(args) {
if (args.target !== this.button.nativeElement) {
super.onNavigationEnterUp(args);
}
}
/**
* @hidden
*/
togglePopupVisibility() {
if (isDocumentAvailable() && this.wrapperContains(document.activeElement) && this.arrowButtonClicked) {
this.button.nativeElement.focus();
}
super.togglePopupVisibility();
}
/**
* @hidden
*/
wrapperContains(element) {
return (this.wrapper === element || this.wrapper.contains(element));
}
/**
* @hidden
*/
get anchorAlign() {
const align = { horizontal: this.popupSettings.align || 'left', vertical: 'bottom' };
if (this.direction === 'rtl' && !isPresent(this.popupSettings.align)) {
align.horizontal = 'right';
}
return align;
}
/**
* @hidden
*/
get popupAlign() {
const align = { horizontal: this.popupSettings.align || 'left', vertical: 'top' };
if (this.direction === 'rtl' && !isPresent(this.popupSettings.align)) {
align.horizontal = 'right';
}
return align;
}
/**
* @hidden
*/
get isIconButton() {
const hasIcon = this.icon || this.svgIcon || this.iconClass || this.imageUrl;
const hasTextContent = isDocumentAvailable() && this.button?.nativeElement.textContent.trim().length > 0;
return hasIcon && !hasTextContent;
}
/**
* Focuses the SplitButton component.
*/
focus() {
if (isDocumentAvailable()) {
this.button.nativeElement.focus();
}
}
/**
* Blurs the SplitButton component.
*/
blur() {
if (isDocumentAvailable()) {
this.button.nativeElement.blur();
this.blurWrapper();
}
}
constructor(focusService, navigationService, wrapperRef, zone, popupService, elRef, localization, cdr, renderer, containerService) {
super(focusService, navigationService, wrapperRef, zone, popupService, elRef, localization, cdr, containerService);
this.localization = localization;
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);
}
if (this.activeArrow) {
zone.run(() => this.activeArrow = false);
}
});
});
}
/**
* Returns the current open state of the popup.
*/
get isOpen() {
return this.openState;
}
updateButtonText() {
if (isDocumentAvailable()) {
const innerText = this.wrapper.innerText
.split('\n')
.join('')
.trim();
//setTimeout is needed because of `Expression has changed after it was checked.` error;
setTimeout(() => (this.buttonText = innerText), 0);
}
}
handleClasses(value, input) {
const elem = this.wrapperRef.nativeElement;
const classes = getStylingClasses('button', input, this[input], value);
if (classes.toRemove) {
this.renderer.removeClass(elem, classes.toRemove);
}
if (classes.toAdd) {
this.renderer.addClass(elem, classes.toAdd);
}
}
toggleButtonIconClass() {
this.button.nativeElement.classList[this.isIconButton ? 'add' : 'remove']('k-button-icon');
}
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]);
}
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SplitButtonComponent, deps: [{ token: FocusService }, { token: NavigationService }, { token: i0.ElementRef }, { token: i0.NgZone }, { token: i3.PopupService }, { token: i0.ElementRef }, { token: i1.LocalizationService }, { token: i0.ChangeDetectorRef }, { token: i0.Renderer2 }, { token: PopupContainerService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: SplitButtonComponent, isStandalone: true, selector: "kendo-splitbutton", inputs: { text: "text", icon: "icon", svgIcon: "svgIcon", iconClass: "iconClass", type: "type", imageUrl: "imageUrl", size: "size", rounded: "rounded", fillMode: "fillMode", themeColor: "themeColor", disabled: "disabled", popupSettings: "popupSettings", tabIndex: "tabIndex", textField: "textField", data: "data", arrowButtonClass: "arrowButtonClass", arrowButtonIcon: "arrowButtonIcon", arrowButtonSvgIcon: "arrowButtonSvgIcon", buttonAttributes: "buttonAttributes" }, outputs: { buttonClick: "buttonClick", itemClick: "itemClick", onFocus: "focus", onBlur: "blur", open: "open", close: "close" }, host: { listeners: { "keydown": "keydown($event)", "keyup": "keyup($event)" }, properties: { "class.k-focus": "this.isFocused", "class.k-split-button": "this.widgetClasses", "class.k-button-group": "this.widgetClasses", "attr.dir": "this.dir" } }, providers: [
FocusService,
NavigationService,
NAVIGATION_SETTINGS_PROVIDER,
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.splitbutton'
},
PopupContainerService,
{
provide: MultiTabStop,
useExisting: forwardRef(() => SplitButtonComponent)
}
], queries: [{ propertyName: "itemTemplate", first: true, predicate: ButtonItemTemplateDirective, descendants: true }], exportAs: ["kendoSplitButton"], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `
<ng-container kendoSplitButtonLocalizedMessages
i18n-splitButtonLabel="kendo.splitbutton.splitButtonLabel|The text for the SplitButton aria-label"
splitButtonLabel="{{ '{buttonText} splitbutton' }}"
>
</ng-container>
<button
kendoButton
#button
[type]="type"
[tabindex]="componentTabIndex"
[disabled]="disabled"
[size]="size"
[rounded]="rounded"
[fillMode]="fillMode"
[themeColor]="themeColor"
[icon]="icon"
[svgIcon]="svgIcon"
[class.k-active]="active"
[iconClass]="iconClass"
[imageUrl]="imageUrl"
[ngClass]="buttonClass"
(focus)="onButtonFocus($event)"
(click)="onButtonClick()"
(blur)="onButtonBlur()"
(mousedown)="toggleButtonActiveState(true)"
(mouseup)="toggleButtonActiveState(false)"
[attr.aria-expanded]="openState"
[attr.aria-controls]="listId"
[attr.aria-label]="ariaLabel"
>
<span *ngIf="text" class="k-button-text">
{{ text }} </span><ng-content></ng-content>
</button>
<button kendoButton #arrowButton type="button"
class="k-split-button-arrow"
[class.k-active]="activeArrow"
[ngClass]="arrowButtonClass"
[disabled]="disabled"
[icon]="arrowButtonIcon"
[svgIcon]="arrowButtonSvgIcon"
[size]="size"
[rounded]="rounded"
[fillMode]="fillMode"
[themeColor]="themeColor"
[tabindex]="-1"
aria-hidden="true"
(click)="onArrowButtonClick()"
(mousedown)="toggleArrowButtonActiveState(true)"
(mouseup)="toggleArrowButtonActiveState(false)"
(keydown.enter)="$event.stopImmediatePropagation(); $event.preventDefault();"
></button>
<ng-template #popupTemplate>
<kendo-button-list
[id]="listId"
[data]="data"
[textField]="textField"
[itemTemplate]="itemTemplate"
(onItemClick)="onItemClick($event)"
(keydown)="keyDownHandler($event)"
(keyup)="keyUpHandler($event)"
[attr.dir]="dir"
[size]="size"
>
</kendo-button-list>
</ng-template>
<ng-container #container></ng-container>
`, isInline: true, dependencies: [{ kind: "directive", type: LocalizedSplitButtonMessagesDirective, selector: "[kendoSplitButtonLocalizedMessages]" }, { 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: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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: SplitButtonComponent, decorators: [{
type: Component,
args: [{
exportAs: 'kendoSplitButton',
providers: [
FocusService,
NavigationService,
NAVIGATION_SETTINGS_PROVIDER,
LocalizationService,
{
provide: L10N_PREFIX,
useValue: 'kendo.splitbutton'
},
PopupContainerService,
{
provide: MultiTabStop,
useExisting: forwardRef(() => SplitButtonComponent)
}
],
selector: 'kendo-splitbutton',
template: `
<ng-container kendoSplitButtonLocalizedMessages
i18n-splitButtonLabel="kendo.splitbutton.splitButtonLabel|The text for the SplitButton aria-label"
splitButtonLabel="{{ '{buttonText} splitbutton' }}"
>
</ng-container>
<button
kendoButton
#button
[type]="type"
[tabindex]="componentTabIndex"
[disabled]="disabled"
[size]="size"
[rounded]="rounded"
[fillMode]="fillMode"
[themeColor]="themeColor"
[icon]="icon"
[svgIcon]="svgIcon"
[class.k-active]="active"
[iconClass]="iconClass"
[imageUrl]="imageUrl"
[ngClass]="buttonClass"
(focus)="onButtonFocus($event)"
(click)="onButtonClick()"
(blur)="onButtonBlur()"
(mousedown)="toggleButtonActiveState(true)"
(mouseup)="toggleButtonActiveState(false)"
[attr.aria-expanded]="openState"
[attr.aria-controls]="listId"
[attr.aria-label]="ariaLabel"
>
<span *ngIf="text" class="k-button-text">
{{ text }} </span><ng-content></ng-content>
</button>
<button kendoButton #arrowButton type="button"
class="k-split-button-arrow"
[class.k-active]="activeArrow"
[ngClass]="arrowButtonClass"
[disabled]="disabled"
[icon]="arrowButtonIcon"
[svgIcon]="arrowButtonSvgIcon"
[size]="size"
[rounded]="rounded"
[fillMode]="fillMode"
[themeColor]="themeColor"
[tabindex]="-1"
aria-hidden="true"
(click)="onArrowButtonClick()"
(mousedown)="toggleArrowButtonActiveState(true)"
(mouseup)="toggleArrowButtonActiveState(false)"
(keydown.enter)="$event.stopImmediatePropagation(); $event.preventDefault();"
></button>
<ng-template #popupTemplate>
<kendo-button-list
[id]="listId"
[data]="data"
[textField]="textField"
[itemTemplate]="itemTemplate"
(onItemClick)="onItemClick($event)"
(keydown)="keyDownHandler($event)"
(keyup)="keyUpHandler($event)"
[attr.dir]="dir"
[size]="size"
>
</kendo-button-list>
</ng-template>
<ng-container #container></ng-container>
`,
standalone: true,
imports: [LocalizedSplitButtonMessagesDirective, ButtonComponent, NgClass, NgIf, ListComponent]
}]
}], ctorParameters: function () { return [{ type: FocusService }, { type: NavigationService }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: i3.PopupService }, { type: i0.ElementRef }, { type: i1.LocalizationService }, { type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }, { type: PopupContainerService }]; }, propDecorators: { text: [{
type: Input
}], icon: [{
type: Input
}], svgIcon: [{
type: Input
}], iconClass: [{
type: Input
}], type: [{
type: Input
}], imageUrl: [{
type: Input
}], size: [{
type: Input
}], rounded: [{
type: Input
}], fillMode: [{
type: Input
}], themeColor: [{
type: Input
}], disabled: [{
type: Input
}], popupSettings: [{
type: Input
}], tabIndex: [{
type: Input
}], textField: [{
type: Input
}], data: [{
type: Input
}], arrowButtonClass: [{
type: Input
}], arrowButtonIcon: [{
type: Input
}], arrowButtonSvgIcon: [{
type: Input
}], buttonAttributes: [{
type: Input
}], buttonClick: [{
type: Output
}], itemClick: [{
type: Output
}], onFocus: [{
type: Output,
args: ['focus']
}], onBlur: [{
type: Output,
args: ['blur']
}], open: [{
type: Output
}], close: [{
type: Output
}], itemTemplate: [{
type: ContentChild,
args: [ButtonItemTemplateDirective]
}], isFocused: [{
type: HostBinding,
args: ['class.k-focus']
}], widgetClasses: [{
type: HostBinding,
args: ['class.k-split-button']
}, {
type: HostBinding,
args: ['class.k-button-group']
}], dir: [{
type: HostBinding,
args: ['attr.dir']
}], keydown: [{
type: HostListener,
args: ['keydown', ['$event']]
}], keyup: [{
type: HostListener,
args: ['keyup', ['$event']]
}] } });
/**
* Utility array that contains all `Button` related components and directives
*/
const KENDO_BUTTON = [
ButtonComponent
];
/**
* Utility array that contains all `ButtonGroup` related components and directives
*/
const KENDO_BUTTONGROUP = [
ButtonComponent,
ButtonGroupComponent
];
/**
* Utility array that contains all `DropDownButton` related components and directives
*/
const KENDO_DROPDOWNBUTTON = [
DropDownButtonComponent,
ButtonItemTemplateDirective
];
/**
* Utility array that contains all `Chip` related components and directives
*/
const KENDO_CHIP = [
ChipComponent
];
/**
* Utility array that contains all `ChipList` related components and directives
*/
const KENDO_CHIPLIST = [
ChipComponent,
ChipListComponent
];
/**
* Utility array that contains all `FloatingActionButton` related components and directives
*/
const KENDO_FLOATINGACTIONBUTTON = [
FloatingActionButtonComponent,
DialItemTemplateDirective,
FloatingActionButtonTemplateDirective
];
/**
* Utility array that contains all `SplitButton` related components and directives
*/
const KENDO_SPLITBUTTON = [
SplitButtonComponent,
SplitButtonCustomMessagesComponent,
ToggleButtonTabStopDirective,
ButtonItemTemplateDirective
];
/**
* Utility array that contains all `@progress/kendo-angular-buttons` related components and directives
*/
const KENDO_BUTTONS = [
...KENDO_BUTTON,
...KENDO_BUTTONGROUP,
...KENDO_DROPDOWNBUTTON,
...KENDO_CHIP,
...KENDO_CHIPLIST,
...KENDO_FLOATINGACTIONBUTTON,
...KENDO_SPLITBUTTON
];
//IMPORTANT: NgModule export kept for backwards compatibility
/**
*
* The exported package module.
*
* The package exports:
* - `ButtonGroupComponent`—The ButtonGroup component class.
* - `ButtonComponent`—The Button component class.
*/
class ButtonGroupModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ButtonGroupModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: ButtonGroupModule, imports: [ButtonComponent, ButtonGroupComponent], exports: [ButtonComponent, ButtonGroupComponent] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ButtonGroupModule, providers: [IconsService], imports: [ButtonComponent] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ButtonGroupModule, decorators: [{
type: NgModule,
args: [{
exports: [...KENDO_BUTTONGROUP],
imports: [...KENDO_BUTTONGROUP],
providers: [IconsService]
}]
}] });
//IMPORTANT: NgModule export kept for backwards compatibility
/**
* Represents the [NgModule](link:site.data.urls.angular['ngmodules'])
* definition for the Button directive.
*
* @example
*
* ```ts-no-run
* // Import the Button module
* import { ButtonModule } from '@progress/kendo-angular-buttons';
*
* // The browser platform with a compiler
* import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
*
* import { NgModule } from '@angular/core';
*
* // Import the app component
* import { AppComponent } from './app.component';
*
* // Define the app module
* _@NgModule({
* declarations: [AppComponent], // declare app component
* imports: [BrowserModule, ButtonModule], // import Button module
* bootstrap: [AppComponent]
* })
* export class AppModule {}
*
* // Compile and launch the module
* platformBrowserDynamic().bootstrapModule(AppModule);
*
* ```
*/
class ButtonModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ButtonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: ButtonModule, imports: [ButtonComponent], exports: [ButtonComponent] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ButtonModule, providers: [IconsService], imports: [ButtonComponent] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ButtonModule, decorators: [{
type: NgModule,
args: [{
imports: [ButtonComponent],
exports: [ButtonComponent],
providers: [IconsService]
}]
}] });
//IMPORTANT: NgModule export kept for backwards compatibility
/**
* Represents the [NgModule](link:site.data.urls.angular['ngmodules'])
* definition for the Buttons components.
*
* @example
*
* ```ts-no-run
* // Import the Buttons module
* import { ButtonsModule } from '@progress/kendo-angular-buttons';
*
* // The browser platform with a compiler
* import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
*
* import { NgModule } from '@angular/core';
*
* // Import the app component
* import { AppComponent } from './app.component';
*
* // Define the app module
* _@NgModule({
* declarations: [AppComponent], // declare app component
* imports: [BrowserModule, ButtonsModule], // import Buttons module
* bootstrap: [AppComponent]
* })
* export class AppModule {}
*
* // Compile and launch the module
* platformBrowserDynamic().bootstrapModule(AppModule);
*
* ```
*/
class ButtonsModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ButtonsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: ButtonsModule, imports: [ButtonComponent, ButtonComponent, ButtonGroupComponent, DropDownButtonComponent, ButtonItemTemplateDirective, ChipComponent, ChipComponent, ChipListComponent, FloatingActionButtonComponent, DialItemTemplateDirective, FloatingActionButtonTemplateDirective, SplitButtonComponent, SplitButtonCustomMessagesComponent, i12.ToggleButtonTabStopDirective, ButtonItemTemplateDirective, i12.ToggleButtonTabStopDirective], exports: [ButtonComponent, ButtonComponent, ButtonGroupComponent, DropDownButtonComponent, ButtonItemTemplateDirective, ChipComponent, ChipComponent, ChipListComponent, FloatingActionButtonComponent, DialItemTemplateDirective, FloatingActionButtonTemplateDirective, SplitButtonComponent, SplitButtonCustomMessagesComponent, i12.ToggleButtonTabStopDirective, ButtonItemTemplateDirective, i12.ToggleButtonTabStopDirective] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ButtonsModule, providers: [IconsService, PopupService, ResizeBatchService], imports: [ButtonComponent, ButtonComponent, DropDownButtonComponent, ChipComponent, ChipComponent, FloatingActionButtonComponent, SplitButtonComponent] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ButtonsModule, decorators: [{
type: NgModule,
args: [{
imports: [...KENDO_BUTTONS, ...KENDO_TOGGLEBUTTONTABSTOP],
exports: [...KENDO_BUTTONS, ...KENDO_TOGGLEBUTTONTABSTOP],
providers: [IconsService, PopupService, ResizeBatchService]
}]
}] });
//IMPORTANT: NgModule export kept for backwards compatibility
/**
*
* The exported package module.
*
* The package exports:
* - `SplitButtonComponent`—The SplitButton component class.
* - `SplitButtonCustomMessagesComponent`—The SplitButton custom messages component class.
*/
class SplitButtonModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SplitButtonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: SplitButtonModule, imports: [SplitButtonComponent, SplitButtonCustomMessagesComponent, i12.ToggleButtonTabStopDirective, ButtonItemTemplateDirective, i12.ToggleButtonTabStopDirective], exports: [SplitButtonComponent, SplitButtonCustomMessagesComponent, i12.ToggleButtonTabStopDirective, ButtonItemTemplateDirective, i12.ToggleButtonTabStopDirective] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SplitButtonModule, providers: [IconsService, PopupService, ResizeBatchService], imports: [SplitButtonComponent] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SplitButtonModule, decorators: [{
type: NgModule,
args: [{
exports: [...KENDO_SPLITBUTTON, ...KENDO_TOGGLEBUTTONTABSTOP],
imports: [...KENDO_SPLITBUTTON, ...KENDO_TOGGLEBUTTONTABSTOP],
providers: [IconsService, PopupService, ResizeBatchService]
}]
}] });
//IMPORTANT: NgModule export kept for backwards compatibility
/**
*
* The exported package module.
*
* The package exports:
* - `DropDownButtonComponent`—The DropDownButtonComponent component class.
* - `ButtonItemTemplateDirective`—The Button item template directive.
*/
class DropDownButtonModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DropDownButtonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: DropDownButtonModule, imports: [DropDownButtonComponent, ButtonItemTemplateDirective], exports: [DropDownButtonComponent, ButtonItemTemplateDirective] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DropDownButtonModule, providers: [IconsService, PopupService, ResizeBatchService], imports: [DropDownButtonComponent] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DropDownButtonModule, decorators: [{
type: NgModule,
args: [{
exports: [...KENDO_DROPDOWNBUTTON],
imports: [...KENDO_DROPDOWNBUTTON],
providers: [IconsService, PopupService, ResizeBatchService]
}]
}] });
//IMPORTANT: NgModule export kept for backwards compatibility
/**
* Represents the [NgModule](link:site.data.urls.angular['ngmoduleapi'])
* definition for the Chip and ChipList components.
*
* @example
*
* ```ts-no-run
* // Import the Chip module
* import { ChipModule } from '@progress/kendo-angular-buttons';
*
* // The browser platform with a compiler
* import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
*
* import { NgModule } from '@angular/core';
*
* // Import the app component
* import { AppComponent } from './app.component';
*
* // Define the app module
* _@NgModule({
* declarations: [AppComponent], // declare app component
* imports: [BrowserModule, ChipModule], // import Chip module
* bootstrap: [AppComponent]
* })
* export class AppModule {}
*
* ```
*/
class ChipModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ChipModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: ChipModule, imports: [ChipComponent, ChipListComponent], exports: [ChipComponent, ChipListComponent] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ChipModule, providers: [IconsService], imports: [ChipComponent] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ChipModule, decorators: [{
type: NgModule,
args: [{
exports: [...KENDO_CHIPLIST],
imports: [...KENDO_CHIPLIST],
providers: [IconsService]
}]
}] });
//IMPORTANT: NgModule export kept for backwards compatibility
/**
* Represents the [NgModule](link:site.data.urls.angular['ngmoduleapi'])
* definition for the FloatingActionButton component.
*
* @example
*
* ```ts-no-run
* // Import the FloatingActionButton module
* import { FloatingActionButtonModule } from '@progress/kendo-angular-buttons';
*
* // The browser platform with a compiler
* import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
*
* import { NgModule } from '@angular/core';
*
* // Import the app component
* import { AppComponent } from './app.component';
*
* // Define the app module
* _@NgModule({
* declarations: [AppComponent], // declare app component
* imports: [BrowserModule, FloatingActionButtonModule], // import FloatingActionButton module
* bootstrap: [AppComponent]
* })
* export class AppModule {}
*
* ```
*/
class FloatingActionButtonModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FloatingActionButtonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: FloatingActionButtonModule, imports: [FloatingActionButtonComponent, DialItemTemplateDirective, FloatingActionButtonTemplateDirective], exports: [FloatingActionButtonComponent, DialItemTemplateDirective, FloatingActionButtonTemplateDirective] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FloatingActionButtonModule, providers: [IconsService, PopupService, ResizeBatchService], imports: [FloatingActionButtonComponent] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FloatingActionButtonModule, decorators: [{
type: NgModule,
args: [{
exports: [...KENDO_FLOATINGACTIONBUTTON],
imports: [...KENDO_FLOATINGACTIONBUTTON],
providers: [IconsService, PopupService, ResizeBatchService]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { ButtonComponent as Button, ButtonComponent, ButtonComponent as ButtonDirective, ButtonGroupComponent as ButtonGroup, ButtonGroupComponent, ButtonGroupModule, ButtonItemTemplateDirective, ButtonModule, ButtonsModule, ChipComponent, ChipListComponent, ChipModule, DialItemTemplateDirective, DropDownButtonComponent as DropDownButton, DropDownButtonComponent, DropDownButtonModule, FloatingActionButtonComponent, FloatingActionButtonModule, FloatingActionButtonTemplateDirective, FocusableDirective, KENDO_BUTTON, KENDO_BUTTONGROUP, KENDO_BUTTONS, KENDO_CHIP, KENDO_CHIPLIST, KENDO_DROPDOWNBUTTON, KENDO_FLOATINGACTIONBUTTON, KENDO_SPLITBUTTON, ListComponent, LocalizedSplitButtonMessagesDirective, PreventableEvent, SplitButtonComponent as SplitButton, SplitButtonComponent, SplitButtonCustomMessagesComponent, SplitButtonModule };