@progress/kendo-angular-layout
Version:
Kendo UI for Angular Layout Package - a collection of components to create professional application layoyts
452 lines (443 loc) • 17.2 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the project root for more information
*-------------------------------------------------------------------------------------------*/
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Component, ContentChild, ElementRef, EventEmitter, HostBinding, Input, Output, isDevMode } from '@angular/core';
import { validatePackage } from '@progress/kendo-licensing';
import { packageMetadata } from '../package-metadata';
import { DrawerTemplateDirective, DrawerItemTemplateDirective, DrawerHeaderTemplateDirective, DrawerFooterTemplateDirective } from './template-directives';
import { DrawerService } from './drawer.service';
import { isPresent } from '../common/util';
import { AnimationBuilder } from '@angular/animations';
import { collapseAnimation, expandAnimation } from './animations';
import { take } from 'rxjs/operators';
import { L10N_PREFIX, LocalizationService } from '@progress/kendo-angular-l10n';
import { shouldShowValidationUI, WatermarkOverlayComponent } from '@progress/kendo-angular-common';
import { DrawerListComponent } from './list.component';
import { NgIf, NgTemplateOutlet } from '@angular/common';
import * as i0 from "@angular/core";
import * as i1 from "@angular/animations";
import * as i2 from "@progress/kendo-angular-l10n";
import * as i3 from "./drawer.service";
const DEFAULT_ANIMATION = { type: 'slide', duration: 200 };
/**
* Represents the [Kendo UI Drawer component for Angular]({% slug overview_drawer %}).
*
* @example
* ```ts-preview
* _@Component({
* selector: 'my-app',
* template: `
* <kendo-drawer-container>
* <kendo-drawer #drawer
* [items]="items"
* mode="overlay"
* [(expanded)]="expanded">
* </kendo-drawer>
* <kendo-drawer-content>
* <button class="k-button" (click)="drawer.toggle()">Open the Drawer</button>
* </kendo-drawer-content>
* </kendo-drawer-container>
* `
* })
* class AppComponent {
* public expanded = false;
*
* public items: any[] = [
* { text: 'Inbox', icon: 'k-i-inbox' },
* { text: 'Notifications', icon: 'k-i-bell' },
* { text: 'Date', icon: 'k-i-calendar' }
* ];
* }
* ```
*/
export class DrawerComponent {
element;
builder;
localizationService;
drawerService;
hostClasses = true;
get startPositionClass() {
return this.position === 'start';
}
get endPositionClass() {
return this.position === 'end';
}
get overlayTransofrmStyles() {
if (this.mode === 'push') {
return;
}
if (this.expanded || this.minimized) {
return `translateX(0px)`;
}
return `translateX(-100%)`;
}
get flexStyles() {
if (this.mode === 'overlay') {
return;
}
if (!this.expanded && !this.minimized) {
return 0;
}
return this.drawerWidth;
}
/**
* Specifies the mode in which the Drawer will be displayed.
*
* The possible values are:
* * (Default) `overlay`
* * `push`
*/
mode = 'overlay';
/**
* Specifies the position of the Drawer
* ([see example]({% slug positioning_drawer %})).
*
* The possible values are:
* * (Default) `start`
* * `end`
*/
position = 'start';
/**
* Enables the mini (compact) view of the Drawer which is displayed when the component is collapsed
* ([see example]({% slug expandmodespositions_drawer %}#toc-mini-view)).
*/
mini = false;
/**
* Specifies the state of the Drawer.
*/
expanded = false;
/**
* Defines the width of the Drawer when it is expanded.
* Defaults to `240`.
*/
width = 240;
/**
* Defines the width of the Drawer when the mini view is enabled
* and the component is collapsed. Defaults to `60`.
*/
miniWidth = 50;
/**
* Specifies if the Drawer will be automatically collapsed when an item
* or the overlay is clicked. Defaults to `true`.
*/
autoCollapse = true;
/**
* The collection of items that will be rendered in the Drawer.
*/
items = [];
/**
* Defines a callback function which determines if an item should be expanded.
*/
set isItemExpanded(fn) {
if (isDevMode && isPresent(fn) && typeof fn !== 'function') {
throw new Error(`isItemExpanded must be a function, but received ${JSON.stringify(fn)}.`);
}
this.drawerService.isItemExpanded = fn;
}
get isItemExpanded() {
return this.drawerService.isItemExpanded;
}
/**
* @hidden
*/
direction;
/**
* Specifies the animation settings of the Drawer.
* ([see example]({% slug interaction_drawer %}#toc-toggling-between-states)).
*
* The possible values are:
* * Boolean
* * (Default) `true`
* * `false`
* * `DrawerAnimation`
* * (Default) `type?: 'slide'`
* * `duration`—Accepts a number in milliseconds. Defaults to `300ms`.
*/
animation = DEFAULT_ANIMATION;
/**
* Fires when the Drawer is expanded and its animation is complete.
*/
expand = new EventEmitter();
/**
* Fires when the Drawer is collapsed and its animation is complete.
*/
collapse = new EventEmitter();
/**
* Fires when a Drawer item is selected. This event is preventable.
*/
select = new EventEmitter();
/**
* Fires when the `expanded` property of the component was updated.
* Used to provide a two-way binding for the `expanded` property.
*/
expandedChange = new EventEmitter();
/**
* @hidden
*/
drawerTemplate;
/**
* @hidden
*/
footerTemplate;
/**
* @hidden
*/
headerTemplate;
/**
* @hidden
*/
itemTemplate;
/**
* @hidden
*/
showLicenseWatermark = false;
viewItems;
animationEnd = new EventEmitter();
dynamicRTLSubscription;
rtl = false;
constructor(element, builder, localizationService, drawerService) {
this.element = element;
this.builder = builder;
this.localizationService = localizationService;
this.drawerService = drawerService;
const isValid = validatePackage(packageMetadata);
this.showLicenseWatermark = shouldShowValidationUI(isValid);
this.dynamicRTLSubscription = this.localizationService.changes.subscribe(({ rtl }) => {
this.rtl = rtl;
this.direction = this.rtl ? 'rtl' : 'ltr';
});
this.drawerService.owner = this;
}
ngOnChanges(changes) {
if (changes && changes['items']) {
this.drawerService.resetSelection();
this.drawerService.init();
this.viewItems = this.drawerService.view;
}
}
ngOnDestroy() {
if (this.dynamicRTLSubscription) {
this.dynamicRTLSubscription.unsubscribe();
}
}
/**
* @hidden
*/
get minimized() {
return this.mini && !this.expanded;
}
/**
* @hidden
*/
get drawerWidth() {
return this.minimized ? this.miniWidth : this.width;
}
/**
* Toggles the visibility of the Drawer.
*
* @param expanded? - Boolean. Specifies if the Drawer will be expanded or collapsed.
*/
toggle(expanded) {
const previous = this.expanded;
const current = isPresent(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.animate(current);
}
else {
this[current ? 'expand' : 'collapse'].emit();
}
}
/**
* @hidden
*/
onSelect(e) {
this.select.emit(Object.assign(e, { sender: this }));
}
onAnimationEnd(currentExpanded) {
if (currentExpanded) {
this.expand.emit();
}
else {
this.setExpanded(false);
this.collapse.emit();
}
}
setExpanded(value) {
this.expanded = value;
this.expandedChange.emit(value);
}
animate(expanded) {
const settings = {
mode: this.mode,
mini: this.mini,
miniWidth: this.miniWidth,
width: this.width,
rtl: this.rtl,
position: this.position,
animation: (typeof this.animation !== 'boolean') ? this.animation : DEFAULT_ANIMATION
};
const animation = expanded ? expandAnimation(settings) : collapseAnimation(settings);
const player = this.createPlayer(animation, this.element.nativeElement);
player.play();
}
createPlayer(animation, animatedElement) {
const factory = this.builder.build(animation);
let player = factory.create(animatedElement);
player.onDone(() => {
if (player) {
this.animationEnd.emit();
player.destroy();
player = null;
}
});
return player;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DrawerComponent, deps: [{ token: i0.ElementRef }, { token: i1.AnimationBuilder }, { token: i2.LocalizationService }, { token: i3.DrawerService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DrawerComponent, isStandalone: true, selector: "kendo-drawer", inputs: { mode: "mode", position: "position", mini: "mini", expanded: "expanded", width: "width", miniWidth: "miniWidth", autoCollapse: "autoCollapse", items: "items", isItemExpanded: "isItemExpanded", animation: "animation" }, outputs: { expand: "expand", collapse: "collapse", select: "select", expandedChange: "expandedChange" }, host: { properties: { "class.k-drawer": "this.hostClasses", "class.k-drawer-start": "this.startPositionClass", "class.k-drawer-end": "this.endPositionClass", "style.transform": "this.overlayTransofrmStyles", "style.flexBasis.px": "this.flexStyles", "attr.dir": "this.direction" } }, providers: [
LocalizationService,
DrawerService,
{
provide: L10N_PREFIX,
useValue: 'kendo.drawer'
}
], queries: [{ propertyName: "drawerTemplate", first: true, predicate: DrawerTemplateDirective, descendants: true }, { propertyName: "footerTemplate", first: true, predicate: DrawerFooterTemplateDirective, descendants: true }, { propertyName: "headerTemplate", first: true, predicate: DrawerHeaderTemplateDirective, descendants: true }, { propertyName: "itemTemplate", first: true, predicate: DrawerItemTemplateDirective, descendants: true }], exportAs: ["kendoDrawer"], usesOnChanges: true, ngImport: i0, template: `
<div class="k-drawer-wrapper" *ngIf="expanded || mini" [style.width.px]="drawerWidth">
<ng-container *ngIf="!drawerTemplate">
<ng-template *ngIf="headerTemplate"
[ngTemplateOutlet]="headerTemplate?.templateRef">
</ng-template>
<ul kendoDrawerList
role="menubar"
orientation="vertical"
(select)="onSelect($event)"
[mini]="mini"
[expanded]="expanded"
[view]="viewItems"
[itemTemplate]="itemTemplate?.templateRef"
class="k-drawer-items">
</ul>
<ng-template *ngIf="footerTemplate"
[ngTemplateOutlet]="footerTemplate?.templateRef">
</ng-template>
</ng-container>
<ng-template *ngIf="drawerTemplate"
[ngTemplateOutlet]="drawerTemplate?.templateRef">
</ng-template>
</div>
<div kendoWatermarkOverlay *ngIf="showLicenseWatermark"></div>
`, 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: DrawerListComponent, selector: "[kendoDrawerList]", inputs: ["itemTemplate", "mini", "expanded", "view"], outputs: ["select"] }, { kind: "component", type: WatermarkOverlayComponent, selector: "div[kendoWatermarkOverlay]" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DrawerComponent, decorators: [{
type: Component,
args: [{
exportAs: 'kendoDrawer',
providers: [
LocalizationService,
DrawerService,
{
provide: L10N_PREFIX,
useValue: 'kendo.drawer'
}
],
selector: 'kendo-drawer',
template: `
<div class="k-drawer-wrapper" *ngIf="expanded || mini" [style.width.px]="drawerWidth">
<ng-container *ngIf="!drawerTemplate">
<ng-template *ngIf="headerTemplate"
[ngTemplateOutlet]="headerTemplate?.templateRef">
</ng-template>
<ul kendoDrawerList
role="menubar"
orientation="vertical"
(select)="onSelect($event)"
[mini]="mini"
[expanded]="expanded"
[view]="viewItems"
[itemTemplate]="itemTemplate?.templateRef"
class="k-drawer-items">
</ul>
<ng-template *ngIf="footerTemplate"
[ngTemplateOutlet]="footerTemplate?.templateRef">
</ng-template>
</ng-container>
<ng-template *ngIf="drawerTemplate"
[ngTemplateOutlet]="drawerTemplate?.templateRef">
</ng-template>
</div>
<div kendoWatermarkOverlay *ngIf="showLicenseWatermark"></div>
`,
standalone: true,
imports: [NgIf, NgTemplateOutlet, DrawerListComponent, WatermarkOverlayComponent]
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.AnimationBuilder }, { type: i2.LocalizationService }, { type: i3.DrawerService }]; }, propDecorators: { hostClasses: [{
type: HostBinding,
args: ['class.k-drawer']
}], startPositionClass: [{
type: HostBinding,
args: ['class.k-drawer-start']
}], endPositionClass: [{
type: HostBinding,
args: ['class.k-drawer-end']
}], overlayTransofrmStyles: [{
type: HostBinding,
args: ['style.transform']
}], flexStyles: [{
type: HostBinding,
args: ['style.flexBasis.px']
}], mode: [{
type: Input
}], position: [{
type: Input
}], mini: [{
type: Input
}], expanded: [{
type: Input
}], width: [{
type: Input
}], miniWidth: [{
type: Input
}], autoCollapse: [{
type: Input
}], items: [{
type: Input
}], isItemExpanded: [{
type: Input
}], direction: [{
type: HostBinding,
args: ['attr.dir']
}], animation: [{
type: Input
}], expand: [{
type: Output
}], collapse: [{
type: Output
}], select: [{
type: Output
}], expandedChange: [{
type: Output
}], drawerTemplate: [{
type: ContentChild,
args: [DrawerTemplateDirective]
}], footerTemplate: [{
type: ContentChild,
args: [DrawerFooterTemplateDirective]
}], headerTemplate: [{
type: ContentChild,
args: [DrawerHeaderTemplateDirective]
}], itemTemplate: [{
type: ContentChild,
args: [DrawerItemTemplateDirective]
}] } });