UNPKG

@progress/kendo-angular-navigation

Version:

Kendo UI Navigation for Angular

1,184 lines (1,162 loc) 137 kB
/**----------------------------------------------------------------------------------------- * 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 { Component, HostBinding, Input, Directive, Optional, EventEmitter, Output, ViewChild, ContentChildren, forwardRef, ContentChild, Host, ViewChildren, isDevMode, ElementRef, NgModule } from '@angular/core'; import * as i1 from '@progress/kendo-angular-l10n'; import { LocalizationService, L10N_PREFIX } from '@progress/kendo-angular-l10n'; import { validatePackage } from '@progress/kendo-licensing'; import { focusableSelector, closestInScope as closestInScope$1, isPresent as isPresent$1, isDocumentAvailable, Keys, ResizeSensorComponent, ResizeBatchService } from '@progress/kendo-angular-common'; import { NgIf, NgTemplateOutlet, NgFor, NgClass, NgStyle, AsyncPipe } from '@angular/common'; import { Subscription, fromEvent, merge, ReplaySubject, Subject } from 'rxjs'; import * as i2 from '@angular/animations'; import { style, animate } from '@angular/animations'; import { take, filter, map, startWith, share } from 'rxjs/operators'; import { IconWrapperComponent, IconsService } from '@progress/kendo-angular-icons'; import { ButtonDirective } from '@progress/kendo-angular-buttons'; import { chevronRightIcon, chevronLeftIcon } from '@progress/kendo-svg-icons'; /** * @hidden */ const packageMetadata = { name: '@progress/kendo-angular-navigation', productName: 'Kendo UI for Angular', productCode: 'KENDOUIANGULAR', productCodes: ['KENDOUIANGULAR'], publishDate: 1756992643, version: '20.0.3', licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/' }; const DEFAULT_THEME_COLOR = 'light'; const DEFAULT_POSITION = 'top'; const DEFAULT_POSITION_MODE = 'static'; /** * Represents the [Kendo UI AppBar component for Angular]({% slug overview_appbar %}). * * Use the AppBar component to display information, actions, brand titles, and additional navigation on the current screen. * * @example * ```html * <kendo-appbar> * <kendo-appbar-section> * <h2>Page Title</h2> * </kendo-appbar-section> * </kendo-appbar> * ``` * * @remarks * Supported children components are: {@link AppBarSectionComponent}, {@link AppBarSpacerComponent} */ class AppBarComponent { localizationService; host; renderer; hostClass = true; /** * @hidden */ direction; /** * Specifies the position of the AppBar * ([see example]({% slug positioning_appbar %}#toc-position)). * * @default 'top' */ set position(position) { const newPosition = position ? position : DEFAULT_POSITION; this.handleHostClasses(newPosition, this.position); this._position = newPosition; } get position() { return this._position; } /** * Sets the position mode of the AppBar ([see example](slug:positioning_appbar#toc-position-mode)). * * @default 'static' */ set positionMode(positionMode) { const newPositionMode = positionMode ? positionMode : DEFAULT_POSITION_MODE; this.handleHostClasses(newPositionMode, this.positionMode); this._positionMode = newPositionMode; } get positionMode() { return this._positionMode; } /** * Sets the theme color of the AppBar. The theme color is applied as the background color of the component. * * @default 'light' */ set themeColor(themeColor) { const newThemeColor = themeColor ? themeColor : DEFAULT_THEME_COLOR; this.handleHostClasses(newThemeColor, this.themeColor); this._themeColor = newThemeColor; } get themeColor() { return this._themeColor; } dynamicRTLSubscription; rtl = false; _themeColor = DEFAULT_THEME_COLOR; _position = DEFAULT_POSITION; _positionMode = DEFAULT_POSITION_MODE; constructor(localizationService, host, renderer) { this.localizationService = localizationService; this.host = host; this.renderer = renderer; validatePackage(packageMetadata); this.dynamicRTLSubscription = this.localizationService.changes.subscribe(({ rtl }) => { this.rtl = rtl; this.direction = this.rtl ? 'rtl' : 'ltr'; }); } ngAfterViewInit() { const stylingOptions = ['position', 'positionMode', 'themeColor']; stylingOptions.forEach(input => { this.handleHostClasses(this[input]); }); } ngOnDestroy() { if (this.dynamicRTLSubscription) { this.dynamicRTLSubscription.unsubscribe(); } } handleHostClasses(newValue, previousValue) { const elem = this.host.nativeElement; if (previousValue && newValue === previousValue) { return; } if (previousValue) { this.renderer.removeClass(elem, `k-appbar-${previousValue}`); } if (newValue) { this.renderer.addClass(elem, `k-appbar-${newValue}`); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppBarComponent, deps: [{ token: i1.LocalizationService }, { token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: AppBarComponent, isStandalone: true, selector: "kendo-appbar", inputs: { position: "position", positionMode: "positionMode", themeColor: "themeColor" }, host: { properties: { "class.k-appbar": "this.hostClass", "attr.dir": "this.direction" } }, providers: [ LocalizationService, { provide: L10N_PREFIX, useValue: 'kendo.appbar.component' } ], exportAs: ["kendoAppBar"], ngImport: i0, template: ` <ng-content></ng-content> `, isInline: true }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppBarComponent, decorators: [{ type: Component, args: [{ exportAs: 'kendoAppBar', selector: 'kendo-appbar', template: ` <ng-content></ng-content> `, providers: [ LocalizationService, { provide: L10N_PREFIX, useValue: 'kendo.appbar.component' } ], standalone: true }] }], ctorParameters: function () { return [{ type: i1.LocalizationService }, { type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { hostClass: [{ type: HostBinding, args: ['class.k-appbar'] }], direction: [{ type: HostBinding, args: ['attr.dir'] }], position: [{ type: Input }], positionMode: [{ type: Input }], themeColor: [{ type: Input }] } }); /** * Represents the [Kendo UI AppBarSection component for Angular]({% slug contentarrangement_appbar %}#toc-sections). * * Use the AppBarSection component to group content, actions, or navigation items within the AppBar. * * @example * ```html * <kendo-appbar> * <kendo-appbar-section> * <h2>Page Title</h2> * </kendo-appbar-section> * </kendo-appbar> * ``` */ class AppBarSectionComponent { hostClass = true; static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppBarSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: AppBarSectionComponent, isStandalone: true, selector: "kendo-appbar-section", host: { properties: { "class.k-appbar-section": "this.hostClass" } }, ngImport: i0, template: ` <ng-content></ng-content> `, isInline: true }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppBarSectionComponent, decorators: [{ type: Component, args: [{ selector: 'kendo-appbar-section', template: ` <ng-content></ng-content> `, standalone: true }] }], propDecorators: { hostClass: [{ type: HostBinding, args: ['class.k-appbar-section'] }] } }); /** * @hidden */ const isPresent = (value) => value !== null && value !== undefined; /** * @hidden */ const outerWidth = (element) => { const style = getComputedStyle(element); let width = parseFloat(style.width); width += (parseFloat(style.marginLeft) || 0) + (parseFloat(style.marginRight) || 0); return width; }; /** * @hidden */ const getFirstAndLastFocusable = (parent) => { const all = getAllFocusableChildren(parent); const firstFocusable = all.length > 0 ? all[0] : parent; const lastFocusable = all.length > 0 ? all[all.length - 1] : parent; return [firstFocusable, lastFocusable]; }; /** * @hidden */ const getAllFocusableChildren = (parent) => { return parent.querySelectorAll(focusableSelector); }; /** * @hidden */ let idx = 0; /** * @hidden */ const hexColorRegex = /^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/; /** * @hidden */ const getId = (prefix) => { return `${prefix}${++idx}`; }; /** * @hidden */ const ACTIONSHEET_ITEM_INDEX_ATTRIBUTE = 'kendo-actionsheet-item-index'; /** * @hidden */ const getActionSheetItemIndex = (target, targetAttr, scope) => { const item = closestItem$1(target, targetAttr, scope); if (item) { return itemIndex$1(item, targetAttr); } }; const itemIndex$1 = (item, indexAttr) => +item.getAttribute(indexAttr); const hasItemIndex$1 = (item, indexAttr) => isPresent(item.getAttribute(indexAttr)); const closestItem$1 = (target, targetAttr, scope) => closestInScope$1(target, el => hasItemIndex$1(el, targetAttr), scope); /** * Represents the [Kendo UI AppBarSpacer component for Angular]({% slug contentarrangement_appbar %}#toc-spacings). * * Use the AppBarSpacer component to add white space between AppBar sections and customize its width. * * @example * ```html * <kendo-appbar> * <kendo-appbar-section> * <button kendoButton fillMode="flat" [svgIcon]="menuIcon"></button> * </kendo-appbar-section> * * <kendo-appbar-spacer></kendo-appbar-spacer> * * <kendo-appbar-section> * <h2>Page Title</h2> * </kendo-appbar-section> * </kendo-appbar> * ``` */ class AppBarSpacerComponent { renderer; element; hostClass = true; get sizedClass() { return isPresent(this.width); } /** * Specifies the width of the AppBarSpacer. * * If not set, the AppBarSpacer will take all of the available space. */ width; constructor(renderer, element) { this.renderer = renderer; this.element = element; } ngAfterViewInit() { if (isPresent(this.width)) { const element = this.element.nativeElement; this.renderer.setStyle(element, 'flexBasis', this.width); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppBarSpacerComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: AppBarSpacerComponent, isStandalone: true, selector: "kendo-appbar-spacer", inputs: { width: "width" }, host: { properties: { "class.k-spacer": "this.hostClass", "class.k-spacer-sized": "this.sizedClass" } }, ngImport: i0, template: ``, isInline: true }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppBarSpacerComponent, decorators: [{ type: Component, args: [{ selector: 'kendo-appbar-spacer', template: ``, standalone: true }] }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ElementRef }]; }, propDecorators: { hostClass: [{ type: HostBinding, args: ['class.k-spacer'] }], sizedClass: [{ type: HostBinding, args: ['class.k-spacer-sized'] }], width: [{ type: Input }] } }); /** * Provides the event data for the `itemClick` event of the ActionSheet component. * * Use this event to access the clicked item and the original DOM event. */ class ActionSheetItemClickEvent { /** * Provides the ActionSheet item that was clicked. */ item; /** * Represents the original DOM event that triggered the `itemClick` event. */ originalEvent; } /** * Represents a template for customizing the header content of the ActionSheet. If you implement this template, it will override the `title` and `subtitle` of the ActionSheet. * To define the template, nest an `<ng-template>` tag * with the `kendoActionSheetHeaderTemplate` directive inside the `<kendo-actionsheet>` tag. * * @example * ```html * <kendo-actionsheet> * <ng-template kendoActionSheetHeaderTemplate> * <h3>Custom Header</h3> * </ng-template> * </kendo-actionsheet> * ``` */ class ActionSheetHeaderTemplateDirective { templateRef; constructor(templateRef) { this.templateRef = templateRef; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ActionSheetHeaderTemplateDirective, deps: [{ token: i0.TemplateRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ActionSheetHeaderTemplateDirective, isStandalone: true, selector: "[kendoActionSheetHeaderTemplate]", ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ActionSheetHeaderTemplateDirective, decorators: [{ type: Directive, args: [{ selector: '[kendoActionSheetHeaderTemplate]', standalone: true }] }], ctorParameters: function () { return [{ type: i0.TemplateRef, decorators: [{ type: Optional }] }]; } }); /** * Represents a template for customizing the content of each ActionSheet item. * To define the template, nest an `<ng-template>` tag * with the `kendoActionSheetItemTemplate` directive inside the `<kendo-actionsheet>` tag. * * @example * ```html * <kendo-actionsheet [items]="items"> * <ng-template kendoActionSheetItemTemplate let-item> * <span>{{ item.title }} (custom)</span> * </ng-template> * </kendo-actionsheet> * ``` */ class ActionSheetItemTemplateDirective { templateRef; constructor(templateRef) { this.templateRef = templateRef; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ActionSheetItemTemplateDirective, deps: [{ token: i0.TemplateRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ActionSheetItemTemplateDirective, isStandalone: true, selector: "[kendoActionSheetItemTemplate]", ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ActionSheetItemTemplateDirective, decorators: [{ type: Directive, args: [{ selector: '[kendoActionSheetItemTemplate]', standalone: true }] }], ctorParameters: function () { return [{ type: i0.TemplateRef, decorators: [{ type: Optional }] }]; } }); /** * Represents a template for customizing the list content of the ActionSheet items. * To define the template, nest an `<ng-template>` tag * with the `kendoActionSheetContentTemplate` directive inside the `<kendo-actionsheet>` tag. * * @example * ```html * <kendo-actionsheet [items]="items"> * <ng-template kendoActionSheetContentTemplate> * <div>Custom content here</div> * </ng-template> * </kendo-actionsheet> * ``` */ class ActionSheetContentTemplateDirective { templateRef; constructor(templateRef) { this.templateRef = templateRef; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ActionSheetContentTemplateDirective, deps: [{ token: i0.TemplateRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ActionSheetContentTemplateDirective, isStandalone: true, selector: "[kendoActionSheetContentTemplate]", ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ActionSheetContentTemplateDirective, decorators: [{ type: Directive, args: [{ selector: '[kendoActionSheetContentTemplate]', standalone: true }] }], ctorParameters: function () { return [{ type: i0.TemplateRef, decorators: [{ type: Optional }] }]; } }); /** * Represents a template for customizing the footer of the ActionSheet. * To define the template, nest an `<ng-template>` tag * with the `kendoActionSheetFooterTemplate` directive inside the `<kendo-actionsheet>` tag. * * @example * ```html * <kendo-actionsheet> * <ng-template kendoActionSheetFooterTemplate> * <button kendoButton>Custom Footer Button</button> * </ng-template> * </kendo-actionsheet> * ``` */ class ActionSheetFooterTemplateDirective { templateRef; constructor(templateRef) { this.templateRef = templateRef; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ActionSheetFooterTemplateDirective, deps: [{ token: i0.TemplateRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ActionSheetFooterTemplateDirective, isStandalone: true, selector: "[kendoActionSheetFooterTemplate]", ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ActionSheetFooterTemplateDirective, decorators: [{ type: Directive, args: [{ selector: '[kendoActionSheetFooterTemplate]', standalone: true }] }], ctorParameters: function () { return [{ type: i0.TemplateRef, decorators: [{ type: Optional }] }]; } }); /** * Represents a template for customizing the overall content of the ActionSheet. * To define the template, nest an `<ng-template>` tag * with the `kendoActionSheetTemplate` directive inside the `<kendo-actionsheet>` tag. * * @example * ```html * <kendo-actionsheet> * <ng-template kendoActionSheetTemplate> * <div>Custom ActionSheet content</div> * </ng-template> * </kendo-actionsheet> * ``` */ class ActionSheetTemplateDirective { templateRef; constructor(templateRef) { this.templateRef = templateRef; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ActionSheetTemplateDirective, deps: [{ token: i0.TemplateRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ActionSheetTemplateDirective, isStandalone: true, selector: "[kendoActionSheetTemplate]", ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ActionSheetTemplateDirective, decorators: [{ type: Directive, args: [{ selector: '[kendoActionSheetTemplate]', standalone: true }] }], ctorParameters: function () { return [{ type: i0.TemplateRef, decorators: [{ type: Optional }] }]; } }); /** * @hidden */ function slideUp(duration, height) { return [ style({ overflow: 'hidden', display: 'block', height: 0 }), animate(`${duration}ms ease-in`, style({ height: `${height}` })) ]; } /** * @hidden */ function slideDown(duration, height) { return [ style({ overflow: 'hidden', height: `${height}` }), animate(`${duration}ms ease-in`, style({ overflow: 'hidden', height: 0 })) ]; } /** * @hidden */ class ActionSheetItemComponent { itemTemplate; item; pointerClass = true; manageIconClasses(item) { const classes = ['k-actionsheet-item-icon']; const isHexColor = isPresent(item.iconColor) && hexColorRegex.test(item.iconColor); const isThemeColor = isPresent(item.iconColor) && item.iconColor !== '' && !isHexColor; if (isThemeColor) { classes.push(`k-text-${item.iconColor}`); } return classes.join(' '); } manageIconStyles(item) { const isHexColor = isPresent(item.iconColor) && hexColorRegex.test(item.iconColor); const isSizeSet = isPresent(item.iconSize) && item.iconSize !== ''; const styles = {}; if (isHexColor) { styles.color = item.iconColor; } if (isSizeSet) { styles.fontSize = item.iconSize; } return styles; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ActionSheetItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ActionSheetItemComponent, isStandalone: true, selector: "[kendoActionSheetItem]", inputs: { itemTemplate: "itemTemplate", item: "item" }, host: { properties: { "class.k-cursor-pointer": "this.pointerClass" } }, ngImport: i0, template: ` <ng-template *ngIf="itemTemplate; else defaultTemplate" [ngTemplateOutlet]="itemTemplate" [ngTemplateOutletContext]="{ $implicit: item }"> </ng-template> <ng-template #defaultTemplate> <span class="k-actionsheet-action"> <span *ngIf="item.icon || item.iconClass || item.svgIcon" class="k-icon-wrap"> <kendo-icon-wrapper [name]="item.icon" [customFontClass]="item.iconClass" [class]="manageIconClasses(item)" [svgIcon]="item.svgIcon" [style]="manageIconStyles(item)" > </kendo-icon-wrapper> </span> <span *ngIf="item.title || item.description" class="k-actionsheet-item-text"> <span *ngIf="item.title" class="k-actionsheet-item-title">{{item.title}}</span> <span *ngIf="item.description" class="k-actionsheet-item-description">{{item.description}}</span> </span> </span> </ng-template> `, 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: ActionSheetItemComponent, decorators: [{ type: Component, args: [{ // eslint-disable-next-line @angular-eslint/component-selector selector: '[kendoActionSheetItem]', template: ` <ng-template *ngIf="itemTemplate; else defaultTemplate" [ngTemplateOutlet]="itemTemplate" [ngTemplateOutletContext]="{ $implicit: item }"> </ng-template> <ng-template #defaultTemplate> <span class="k-actionsheet-action"> <span *ngIf="item.icon || item.iconClass || item.svgIcon" class="k-icon-wrap"> <kendo-icon-wrapper [name]="item.icon" [customFontClass]="item.iconClass" [class]="manageIconClasses(item)" [svgIcon]="item.svgIcon" [style]="manageIconStyles(item)" > </kendo-icon-wrapper> </span> <span *ngIf="item.title || item.description" class="k-actionsheet-item-text"> <span *ngIf="item.title" class="k-actionsheet-item-title">{{item.title}}</span> <span *ngIf="item.description" class="k-actionsheet-item-description">{{item.description}}</span> </span> </span> </ng-template> `, standalone: true, imports: [NgIf, NgTemplateOutlet, IconWrapperComponent] }] }], propDecorators: { itemTemplate: [{ type: Input }], item: [{ type: Input }], pointerClass: [{ type: HostBinding, args: ['class.k-cursor-pointer'] }] } }); /** * @hidden */ class ActionSheetListComponent { renderer; ngZone; element; groupItems = []; allItems = []; itemTemplate; itemClick = new EventEmitter(); subscriptions = new Subscription(); constructor(renderer, ngZone, element) { this.renderer = renderer; this.ngZone = ngZone; this.element = element; } ngAfterViewInit() { this.initDomEvents(); } ngOnDestroy() { this.subscriptions.unsubscribe(); } initDomEvents() { if (!this.element) { return; } this.ngZone.runOutsideAngular(() => { const nativeElement = this.element.nativeElement; this.subscriptions.add(this.renderer.listen(nativeElement, 'click', this.clickHandler.bind(this))); }); } clickHandler(e) { const itemIndex = getActionSheetItemIndex(e.target, ACTIONSHEET_ITEM_INDEX_ATTRIBUTE, this.element.nativeElement); const item = this.allItems[itemIndex]; if (!item) { return; } if (item.disabled) { e.preventDefault(); return; } this.ngZone.run(() => { this.itemClick.emit({ item, originalEvent: e }); }); } setAttrIndex(item) { return this.allItems.indexOf(item); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ActionSheetListComponent, deps: [{ token: i0.Renderer2 }, { token: i0.NgZone }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ActionSheetListComponent, isStandalone: true, selector: "[kendoActionSheetList]", inputs: { groupItems: "groupItems", allItems: "allItems", itemTemplate: "itemTemplate" }, outputs: { itemClick: "itemClick" }, ngImport: i0, template: "\n <span *ngFor=\"let item of groupItems\" kendoActionSheetItem\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-disabled]=\"item.disabled\"\n [class.k-actionsheet-item]=\"true\"\n [attr.kendo-actionsheet-item-index]=\"setAttrIndex(item)\"\n [class.k-disabled]=\"item.disabled\"\n [ngClass]=\"item.cssClass\"\n [ngStyle]=\"item.cssStyle\"\n [itemTemplate]=\"itemTemplate\"\n [item]=\"item\">\n </span>\n ", isInline: true, dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ActionSheetItemComponent, selector: "[kendoActionSheetItem]", inputs: ["itemTemplate", "item"] }, { 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: ActionSheetListComponent, decorators: [{ type: Component, args: [{ // eslint-disable-next-line @angular-eslint/component-selector selector: '[kendoActionSheetList]', template: ` <span *ngFor="let item of groupItems" kendoActionSheetItem tabindex="0" role="button" [attr.aria-disabled]="item.disabled" [class.k-actionsheet-item]="true" [attr.${ACTIONSHEET_ITEM_INDEX_ATTRIBUTE}]="setAttrIndex(item)" [class.k-disabled]="item.disabled" [ngClass]="item.cssClass" [ngStyle]="item.cssStyle" [itemTemplate]="itemTemplate" [item]="item"> </span> `, standalone: true, imports: [NgFor, ActionSheetItemComponent, NgClass, NgStyle] }] }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.NgZone }, { type: i0.ElementRef }]; }, propDecorators: { groupItems: [{ type: Input }], allItems: [{ type: Input }], itemTemplate: [{ type: Input }], itemClick: [{ type: Output }] } }); const DEFAULT_ANIMATION_CONFIG = { duration: 300 }; /** * Represents the [Kendo UI ActionSheet component for Angular](slug:overview_actionsheet). * Use this component to display a set of choices related to a user-initiated task in a modal sheet that slides up from the bottom of the screen. * * @example * ```html * <kendo-actionsheet [items]="actionItems" [expanded]="true"> * </kendo-actionsheet> * ``` */ class ActionSheetComponent { element; ngZone; renderer; localizationService; builder; cdr; /** * @hidden */ currentView = 1; /** * @hidden */ get hostClass() { return this.expanded; } /** * @hidden */ direction; /** * Specifies the action buttons displayed in the ActionSheet footer. */ actions; /** * Configures the layout of the action buttons in the footer. By default, actions are arranged horizontally and stretched to fill the container. */ actionsLayout = { orientation: 'horizontal', alignment: 'stretched' }; /** * Determines whether the ActionSheet closes when the overlay is clicked. * * @default false */ overlayClickClose = false; /** * Sets the title text displayed in the ActionSheet header. */ title; /** * Sets the subtitle text displayed below the title in the header. */ subtitle; /** * Provides the collection of items rendered in the ActionSheet content area. */ items; /** * Applies CSS classes to the inner ActionSheet element. Accepts any value supported by [`ngClass`](link:site.data.urls.angular['ngclassapi']). */ cssClass; /** * Applies inline styles to the inner ActionSheet element. Accepts any value supported by [`ngStyle`](link:site.data.urls.angular['ngstyleapi']). */ cssStyle; /** * Configures the opening and closing animations for the ActionSheet ([see example](slug:animations_actionsheet)). * * @default true */ animation = true; /** * Controls whether the ActionSheet is expanded or collapsed. * * @default false */ expanded = false; /** * Sets the `aria-labelledby` attribute of the ActionSheet wrapper element. * Use this option when the built-in header element is replaced through the [`ActionSheetHeaderTemplate`](slug:api_navigation_actionsheetheadertemplatedirective) * or [`ActionSheetContentTemplate`](slug:api_navigation_actionsheetcontenttemplatedirective). */ titleId = getId('k-actionsheet-title'); /** * @hidden * * Determines if the ActionSheet should focus the first focusable element when opened. */ initialFocus = true; /** * Fires when the `expanded` property of the component is updated. * You can use this event to provide two-way binding for the `expanded` property. */ expandedChange = new EventEmitter(); /** * Fires when any of the ActionSheet action buttons is clicked. */ action = new EventEmitter(); /** * Fires when the ActionSheet is expanded and its animation is complete. */ expand = new EventEmitter(); /** * Fires when the ActionSheet is collapsed and its animation is complete. */ collapse = new EventEmitter(); /** * Fires when an ActionSheet item is clicked. */ itemClick = new EventEmitter(); /** * Fires when the modal overlay is clicked. */ overlayClick = new EventEmitter(); /** * @hidden */ childContainer; /** * @hidden */ actionSheetViews; /** * @hidden */ actionSheetTemplate; /** * @hidden */ headerTemplate; /** * @hidden */ contentTemplate; /** * @hidden */ itemTemplate; /** * @hidden */ footerTemplate; dynamicRTLSubscription; rtl = false; domSubs = new Subscription(); player; animationEnd = new EventEmitter(); constructor(element, ngZone, renderer, localizationService, builder, cdr) { this.element = element; this.ngZone = ngZone; this.renderer = renderer; this.localizationService = localizationService; this.builder = builder; this.cdr = cdr; validatePackage(packageMetadata); this.dynamicRTLSubscription = this.localizationService.changes.subscribe(({ rtl }) => { this.rtl = rtl; this.direction = this.rtl ? 'rtl' : 'ltr'; }); } ngAfterViewInit() { this.initDomEvents(); this.setCssVariables(); } ngOnChanges(changes) { if (changes['expanded'] && this.expanded) { this.setExpanded(true); } } ngOnDestroy() { this.domSubs.unsubscribe(); if (this.dynamicRTLSubscription) { this.dynamicRTLSubscription.unsubscribe(); } if (this.player) { this.player.destroy(); } } /** * @hidden * Navigates to the next view. */ nextView() { if (this.currentView < this.actionSheetViews.length) { this.currentView += 1; } } /** * @hidden * Navigates to the previous view. */ prevView() { if (this.currentView > 1) { this.currentView -= 1; } } /** * Toggles the visibility of the ActionSheet. * * @param expanded? - Boolean. Specifies if the ActionSheet will be expanded or collapsed. */ toggle(expanded) { const previous = this.expanded; const current = isPresent$1(expanded) ? expanded : !previous; if (current === previous) { return; } if (current === true) { this.setExpanded(true); } else if (current === false && !this.animation) { this.setExpanded(false); } if (this.animation) { this.animationEnd.pipe(take(1)) .subscribe(() => { this.onAnimationEnd(current); }); this.playAnimation(current); } else { this[current ? 'expand' : 'collapse'].emit(); } } /** * @hidden */ get orientationClass() { return this.actionsLayout.orientation ? `k-actions-${this.actionsLayout.orientation}` : ''; } /** * @hidden */ get alignmentClass() { return this.actionsLayout.alignment ? `k-actions-${this.actionsLayout.alignment}` : ''; } /** * @hidden */ get topGroupItems() { return this.items?.filter(item => !item.group || item.group === 'top'); } /** * @hidden */ get bottomGroupItems() { return this.items?.filter(item => item.group === 'bottom'); } /** * @hidden */ onItemClick(ev) { this.itemClick.emit(ev); } /** * @hidden */ onOverlayClick() { this.overlayClick.emit(); if (this.overlayClickClose) { this.toggle(false); } } /** * @hidden */ get shouldRenderSeparator() { return this.topGroupItems?.length > 0 && this.bottomGroupItems?.length > 0; } initDomEvents() { if (!this.element) { return; } this.ngZone.runOutsideAngular(() => { this.domSubs.add(this.renderer.listen(this.element.nativeElement, 'keydown', (ev) => { this.onKeyDown(ev); })); }); } setCssVariables() { if (!this.element || !isDocumentAvailable()) { return; } // The following syntax is used as it does not violate CSP compliance this.element.nativeElement.style.setProperty('--kendo-actionsheet-height', 'auto'); this.element.nativeElement.style.setProperty('--kendo-actionsheet-max-height', 'none'); } onKeyDown(event) { const target = event.target; if (event.code === Keys.Tab) { this.ngZone.run(() => { this.keepFocusWithinComponent(target, event); }); } if (event.code === Keys.Escape) { this.ngZone.run(() => { this.overlayClick.emit(); }); } if (event.code === Keys.Enter || event.code === Keys.NumpadEnter) { this.ngZone.run(() => { this.triggerItemClick(target, event); }); } } handleInitialFocus() { const [firstFocusable] = getFirstAndLastFocusable(this.element.nativeElement); if (firstFocusable && this.initialFocus) { firstFocusable.focus(); } } keepFocusWithinComponent(target, event) { const wrapper = this.element.nativeElement; const [firstFocusable, lastFocusable] = getFirstAndLastFocusable(wrapper); const tabAfterLastFocusable = !event.shiftKey && target === lastFocusable; const shiftTabAfterFirstFocusable = event.shiftKey && target === firstFocusable; if (tabAfterLastFocusable) { event.preventDefault(); firstFocusable.focus(); } if (shiftTabAfterFirstFocusable) { event.preventDefault(); lastFocusable.focus(); } } triggerItemClick(target, event) { const itemIndex = getActionSheetItemIndex(target, ACTIONSHEET_ITEM_INDEX_ATTRIBUTE, this.element.nativeElement); const item = isPresent$1(itemIndex) ? this.items[itemIndex] : null; if (!item || item.disabled) { return; } this.itemClick.emit({ item, originalEvent: event }); } setExpanded(value) { this.expanded = value; this.expandedChange.emit(value); if (this.expanded) { this.cdr.detectChanges(); this.handleInitialFocus(); } } onAnimationEnd(currentExpanded) { if (currentExpanded) { this.expand.emit(); } else { this.setExpanded(false); this.collapse.emit(); } } playAnimation(expanded) { const duration = typeof this.animation !== 'boolean' && this.animation.duration ? this.animation.duration : DEFAULT_ANIMATION_CONFIG.duration; const contentHeight = getComputedStyle(this.childContainer.nativeElement).height; const animation = expanded ? slideUp(duration, contentHeight) : slideDown(duration, contentHeight); const factory = this.builder.build(animation); this.player = factory.create(this.childContainer.nativeElement); this.player.onDone(() => { if (this.player) { this.animationEnd.emit(); this.player.destroy(); this.player = null; } }); this.player.play(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ActionSheetComponent, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }, { token: i0.Renderer2 }, { token: i1.LocalizationService }, { token: i2.AnimationBuilder }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ActionSheetComponent, isStandalone: true, selector: "kendo-actionsheet", inputs: { actions: "actions", actionsLayout: "actionsLayout", overlayClickClose: "overlayClickClose", title: "title", subtitle: "subtitle", items: "items", cssClass: "cssClass", cssStyle: "cssStyle", animation: "animation", expanded: "expanded", titleId: "titleId", initialFocus: "initialFocus" }, outputs: { expandedChange: "expandedChange", action: "action", expand: "expand", collapse: "collapse", itemClick: "itemClick", overlayClick: "overlayClick" }, host: { properties: { "class.k-actionsheet-container": "this.hostClass", "attr.dir": "this.direction" } }, providers: [ LocalizationService, { provide: L10N_PREFIX, useValue: 'kendo.actionsheet.component' } ], queries: [{ propertyName: "actionSheetTemplate", first: true, predicate: ActionSheetTemplateDirective, descendants: true }, { propertyName: "headerTemplate", first: true, predicate: ActionSheetHeaderTemplateDirective, descendants: true }, { propertyName: "contentTemplate", first: true, predicate: ActionSheetContentTemplateDirective, descendants: true }, { propertyName: "itemTemplate", first: true, predicate: ActionSheetItemTemplateDirective, descendants: true }, { propertyName: "footerTemplate", first: true, predicate: ActionSheetFooterTemplateDirective, descendants: true }, { propertyName: "actionSheetViews", predicate: i0.forwardRef(function () { return ActionSheetViewComponent; }) }], viewQueries: [{ propertyName: "childContainer", first: true, predicate: ["childContainer"], descendants: true }], exportAs: ["kendoActionSheet"], usesOnChanges: true, ngImport: i0, template: ` <ng-container *ngIf="expanded"> <div class="k-overlay" (click)="onOverlayClick()"></div> <div class="k-animation-container k-animation-container-shown"> <div #childContainer class="k-child-animation-container" [style]="'bottom: 0px; width: 100%;'"> <div class="k-actionsheet k-actionsheet-bottom" [ngClass]="cssClass" [ngStyle]="cssStyle" role="dialog" aria-modal="true" [attr.aria-labelledby]="titleId" [style.--kendo-actionsheet-view-current]="actionSheetViews?.length > 0 ? currentView : null" > <ng-content *ngIf="actionSheetViews?.length > 0" select="kendo-actionsheet-view"></ng-content> <div *ngIf="actionSheetViews?.length === 0" class="k-actionsheet-view"> <ng-template *ngIf="actionSheetTemplate; else defaultTemplate" [ngTemplateOutlet]="actionSheetTemplate?.templateRef"> </ng-template> <ng-template #defaultTemplate> <div *ngIf="title || subtitle || headerTemplate" class="k-actionsheet-titlebar"> <ng-template *ngIf="headerTemplate; else defaultHeaderTemplate" [ngTemplateOutlet]="headerTemplate?.templateRef"> </ng-template> <ng-template #defaultHeaderTemplate> <div class="k-actionsheet-titlebar-group k-hbox"> <div class="k-actionsheet-title" [id]="titleId"> <div *ngIf="title" class="k-text-center">{{title}}</div> <div *ngIf="subtitle" class="k-actionsheet-subtitle k-text-center">{{subtitle}}</div> </div> </div> </ng-template> </div> <div *ngIf="items || contentTemplate" class="k-actionsheet-content"> <ng-template *ngIf="contentTemplate; else defaultContentTemplate" [ngTemplateOutlet]="contentTemplate?.templateRef"> </ng-template> <ng-template #defaultContentTemplate> <div *ngIf="topGroupItems" kendoActionSheetList class="k-list-ul" role="group" [groupItems]="topGroupItems" [allItems]="items" [itemTemplate]="itemTemplate?.templateRef" (itemClick)="onItemClick($event)"> </div> <hr *ngIf="shouldRenderSeparator" class="k-hr"/> <div *ngIf="bottomGroupItems" kendoActionSheetList class="k-list-ul" role="group" [groupItems]="bottomGroupItems" [allItems]="items" [itemTemplate]="itemTemplate?.templateRef" (itemClick)="onItemClick($event)"> </div> </ng-template> </div> <div *ngIf="footerTemplate || actions" [ngClass]="[orientationClass, alignmentClass, 'k-actions', 'k-actionsheet-footer']"> <ng-template *ngIf="footerTemplate" [ngTemplateOutlet]="footerTemplate?.templateRef"> </ng-template> <ng-container *ngIf="!footerTemplate && actions"> <button *ngFor="let actionButton of actions" kendoButton type="button" [icon]="actionButton.icon" [title]="actionButton.title" [svgIcon]="actionButton.svgIcon" [themeColor]="actionButton.themeColor" [fillMode]="actionButton.fillMode" [size]="actionButton.size" [attr.aria-label]="actionButton.text" (click)="action.emit(actionButton)" > {{ actionButton.text }} </button> </ng-container> </div> </ng-template> </div> </div> </div> </div> </ng-container> `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext"