UNPKG

@progress/kendo-angular-buttons

Version:
978 lines (973 loc) 36.9 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { AnimationBuilder } from '@angular/animations'; import { Component, ElementRef, EventEmitter, HostBinding, Input, Output, NgZone, Renderer2, ViewChild, ContentChild, TemplateRef } from '@angular/core'; import { merge, Subscription } from 'rxjs'; import { take } from 'rxjs/operators'; import { L10N_PREFIX, LocalizationService } from '@progress/kendo-angular-l10n'; import { validatePackage } from '@progress/kendo-licensing'; import { packageMetadata } from '../package-metadata'; import { guid, isDocumentAvailable } from '@progress/kendo-angular-common'; import { PopupService } from '@progress/kendo-angular-popup'; import { FocusService } from '../focusable/focus.service'; import { NavigationAction } from '../navigation/navigation-action'; import { NAVIGATION_CONFIG } from '../navigation/navigation-config'; import { NavigationService } from '../navigation/navigation.service'; import { closest, isPresent } from '../util'; import { getAnchorAlign, getPopupAlign } from './utils'; import { closeAnimation, openAnimation } from './animations/animations'; import { PreventableEvent } from '../preventable-event'; import { DialItemTemplateDirective } from './templates/dial-item-template.directive'; import { FloatingActionButtonTemplateDirective } from './templates/fab-template.directive'; import { DialListComponent } from './dial-list.component'; import { IconWrapperComponent } from '@progress/kendo-angular-icons'; import { EventsOutsideAngularDirective } from '@progress/kendo-angular-common'; import { NgClass, NgIf, NgTemplateOutlet } from '@angular/common'; import * as i0 from "@angular/core"; import * as i1 from "../focusable/focus.service"; import * as i2 from "../navigation/navigation.service"; import * as i3 from "@progress/kendo-angular-popup"; import * as i4 from "@angular/animations"; import * as i5 from "@progress/kendo-angular-l10n"; const NAVIGATION_SETTINGS = { useLeftRightArrows: false }; const NAVIGATION_SETTINGS_PROVIDER = { provide: NAVIGATION_CONFIG, useValue: NAVIGATION_SETTINGS }; 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 = '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. * */ export 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)&mdash;Applies coloring based on the `primary` theme color. * * `secondary`&mdash;Applies coloring based on the `secondary` theme color. * * `tertiary`&mdash; Applies coloring based on the `tertiary` theme color. * * `info`&mdash;Applies coloring based on the `info` theme color. * * `success`&mdash; Applies coloring based on the `success` theme color. * * `warning`&mdash; Applies coloring based on the `warning` theme color. * * `error`&mdash; Applies coloring based on the `error` theme color. * * `dark`&mdash; Applies coloring based on the `dark` theme color. * * `light`&mdash; Applies coloring based on the `light` theme color. * * `inverse`&mdash; Applies coloring based on the `inverse` theme color. * * `none`&mdash; Removes the 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; 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`&mdash;Positions the FloatingActionButton absolutely to its first positioned parent element. * * `fixed` (Default)&mdash;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`&mdash;Applies the default [`DialItemAnimation`]({% slug api_buttons_dialitemanimation %}) settings. * * `false` * * `DialItemAnimation` * * `duration`&mdash;Specifies the animation duration in milliseconds for each dial item. Defaults to `180ms`. * * `gap`&mdash;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; _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: i1.FocusService }, { token: i2.NavigationService }, { token: i0.NgZone }, { token: i3.PopupService }, { token: i4.AnimationBuilder }, { token: i5.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, 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, 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: i1.FocusService }, { type: i2.NavigationService }, { type: i0.NgZone }, { type: i3.PopupService }, { type: i4.AnimationBuilder }, { type: i5.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 }] } });