@progress/kendo-angular-dialog
Version:
Dialog Package for Angular
1,281 lines (1,257 loc) • 170 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 { TemplateRef, EventEmitter, Component, Input, Output, HostBinding, InjectionToken, Injectable, Inject, Optional, Directive, forwardRef, ContentChildren, ViewChildren, ViewChild, isDevMode, Renderer2, Host, HostListener, ContentChild, NgModule } from '@angular/core';
import { NgIf, NgFor, NgClass, NgTemplateOutlet, NgStyle } from '@angular/common';
import * as i2 from '@angular/animations';
import { style, animate, keyframes, trigger, state, transition } from '@angular/animations';
import * as i1 from '@progress/kendo-angular-buttons';
import { KENDO_BUTTON, ButtonComponent, Button } from '@progress/kendo-angular-buttons';
import * as i1$1 from '@progress/kendo-angular-l10n';
import { LocalizationService, L10N_PREFIX, RTL, ComponentMessages } from '@progress/kendo-angular-l10n';
import { take, delay, takeUntil, filter, map, share, tap, switchMap } from 'rxjs/operators';
import { xIcon, windowRestoreIcon, windowIcon, windowMinimizeIcon } from '@progress/kendo-svg-icons';
import { validatePackage } from '@progress/kendo-licensing';
import { of, Subscription, Subject, merge } from 'rxjs';
import * as i1$2 from '@progress/kendo-angular-common';
import { setHTMLAttributes, shouldShowValidationUI, isDocumentAvailable, focusableSelector, WatermarkOverlayComponent, DraggableDirective, isChanged } from '@progress/kendo-angular-common';
import { offset, scrollPosition, positionWithScroll, getDocumentElement, getWindowViewPort } from '@progress/kendo-popup-common';
import { IconWrapperComponent, IconsService } from '@progress/kendo-angular-icons';
/**
* Specifies the action buttons of the Dialog
* ([see example]({% slug actionbuttons_dialog %})).
*/
class DialogActionsComponent {
el;
/**
* Allows the declarative specification of the actions.
*/
set actions(value) {
if (value instanceof TemplateRef) {
this.actionsTemplate = value;
}
else if (Array.isArray(value)) {
this.actionsArray = value;
}
else {
throw new Error('"actions" must be either TemplateRef or DialogAction[] instance.');
}
}
/**
* @hidden
*/
actionsArray;
/**
* @hidden
*/
actionsTemplate;
/**
* Specifies the possible layout of the action buttons.
* @default 'stretched'
*/
layout = 'stretched';
/**
* Fires when the user clicks an action button.
*/
action = new EventEmitter();
hostClasses = true;
get startClassName() {
return this.layout === 'start';
}
get centerClassName() {
return this.layout === 'center';
}
get endClassName() {
return this.layout === 'end';
}
get stretchedClassName() {
return this.layout === 'stretched';
}
constructor(el) {
this.el = el;
}
/**
* @hidden
*/
onButtonClick(action, _e) {
this.action.emit(action);
}
/**
* @hidden
*/
isDivider(action) {
return action === 'spacer';
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DialogActionsComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DialogActionsComponent, isStandalone: true, selector: "kendo-dialog-actions", inputs: { actions: "actions", layout: "layout" }, outputs: { action: "action" }, host: { properties: { "class.k-actions": "this.hostClasses", "class.k-actions-horizontal": "this.hostClasses", "class.k-window-actions": "this.hostClasses", "class.k-dialog-actions": "this.hostClasses", "class.k-actions-start": "this.startClassName", "class.k-actions-center": "this.centerClassName", "class.k-actions-end": "this.endClassName", "class.k-actions-stretched": "this.stretchedClassName" } }, ngImport: i0, template: `
<ng-content *ngIf="!actions"></ng-content>
<ng-container *ngIf="actionsArray; else actionTemplate">
<ng-container *ngFor="let action of actionsArray">
<ng-container *ngIf="isDivider(action); else defaultAction">
<span class="k-spacer"></span>
</ng-container>
<ng-template #defaultAction>
<button
type="button"
kendoButton
[disabled]="action.disabled"
[fillMode]="action.fillMode"
[themeColor]="action.themeColor"
[ngClass]="action.cssClass"
(click)="onButtonClick(action, $event)"
[attr.aria-label]="action.text"
[svgIcon]="action.svgIcon"
[icon]="action.icon"
>
{{ action.text }}
</button>
</ng-template>
</ng-container>
</ng-container>
<ng-template #actionTemplate [ngTemplateOutlet]="actionsTemplate"></ng-template>
`, 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: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i1.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"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DialogActionsComponent, decorators: [{
type: Component,
args: [{
selector: 'kendo-dialog-actions',
template: `
<ng-content *ngIf="!actions"></ng-content>
<ng-container *ngIf="actionsArray; else actionTemplate">
<ng-container *ngFor="let action of actionsArray">
<ng-container *ngIf="isDivider(action); else defaultAction">
<span class="k-spacer"></span>
</ng-container>
<ng-template #defaultAction>
<button
type="button"
kendoButton
[disabled]="action.disabled"
[fillMode]="action.fillMode"
[themeColor]="action.themeColor"
[ngClass]="action.cssClass"
(click)="onButtonClick(action, $event)"
[attr.aria-label]="action.text"
[svgIcon]="action.svgIcon"
[icon]="action.icon"
>
{{ action.text }}
</button>
</ng-template>
</ng-container>
</ng-container>
<ng-template #actionTemplate [ngTemplateOutlet]="actionsTemplate"></ng-template>
`,
standalone: true,
imports: [NgIf, NgFor, NgClass, NgTemplateOutlet, KENDO_BUTTON]
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { actions: [{
type: Input
}], layout: [{
type: Input
}], action: [{
type: Output
}], hostClasses: [{
type: HostBinding,
args: ['class.k-actions']
}, {
type: HostBinding,
args: ['class.k-actions-horizontal']
}, {
type: HostBinding,
args: ['class.k-window-actions']
}, {
type: HostBinding,
args: ['class.k-dialog-actions']
}], startClassName: [{
type: HostBinding,
args: ['class.k-actions-start']
}], centerClassName: [{
type: HostBinding,
args: ['class.k-actions-center']
}], endClassName: [{
type: HostBinding,
args: ['class.k-actions-end']
}], stretchedClassName: [{
type: HostBinding,
args: ['class.k-actions-stretched']
}] } });
class PreventableEvent {
prevented = false;
/**
* @hidden
*/
constructor() { }
/**
* 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 DIALOG_LOCALIZATION_SERVICE = new InjectionToken('Dialog LocalizationService');
/**
* @hidden
*/
class TitleBarLocalizationService extends LocalizationService {
dialogLocalization;
constructor(prefix, messageService, rtl, dialogLocalization) {
super(prefix, messageService, rtl);
this.dialogLocalization = dialogLocalization;
}
get(shortKey) {
if (this.dialogLocalization) {
return this.dialogLocalization.get(shortKey);
}
return super.get(shortKey);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TitleBarLocalizationService, deps: [{ token: L10N_PREFIX }, { token: i1$1.MessageService, optional: true }, { token: RTL, optional: true }, { token: DIALOG_LOCALIZATION_SERVICE, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TitleBarLocalizationService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TitleBarLocalizationService, decorators: [{
type: Injectable
}], ctorParameters: function () { return [{ type: undefined, decorators: [{
type: Inject,
args: [L10N_PREFIX]
}] }, { type: i1$1.MessageService, decorators: [{
type: Optional
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [RTL]
}] }, { type: i1$1.LocalizationService, decorators: [{
type: Optional
}, {
type: Inject,
args: [DIALOG_LOCALIZATION_SERVICE]
}] }]; } });
/**
* @hidden
*/
class Messages extends ComponentMessages {
/**
* The title of the close button.
*/
closeTitle;
/**
* The title of the restore button.
*/
restoreTitle;
/**
* The title of the maximize button.
*/
maximizeTitle;
/**
* The title of the minimize button.
*/
minimizeTitle;
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-dialog-messages-base", inputs: { closeTitle: "closeTitle", restoreTitle: "restoreTitle", maximizeTitle: "maximizeTitle", minimizeTitle: "minimizeTitle" }, 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-dialog-messages-base'
}]
}], propDecorators: { closeTitle: [{
type: Input
}], restoreTitle: [{
type: Input
}], maximizeTitle: [{
type: Input
}], minimizeTitle: [{
type: Input
}] } });
/**
* @hidden
*/
class LocalizedMessagesDirective extends Messages {
service;
constructor(service) {
super();
this.service = service;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalizedMessagesDirective, deps: [{ token: i1$1.LocalizationService }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: LocalizedMessagesDirective, isStandalone: true, selector: "\n [kendoDialogLocalizedMessages],\n [kendoWindowLocalizedMessages],\n [kendoDialogTitleBarLocalizedMessages]\n ", providers: [
{
provide: Messages,
useExisting: forwardRef(() => LocalizedMessagesDirective)
}
], usesInheritance: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LocalizedMessagesDirective, decorators: [{
type: Directive,
args: [{
providers: [
{
provide: Messages,
useExisting: forwardRef(() => LocalizedMessagesDirective)
}
],
selector: `
[kendoDialogLocalizedMessages],
[kendoWindowLocalizedMessages],
[kendoDialogTitleBarLocalizedMessages]
`,
standalone: true
}]
}], ctorParameters: function () { return [{ type: i1$1.LocalizationService }]; } });
/**
* Represents the [Kendo UI DialogTitleBar component for Angular]({% slug api_dialog_dialogtitlebarcomponent %}).
*
* It is used as part of the Dialog content when the component is created dynamically by using an [Angular service]({% slug service_dialog %}).
*/
class DialogTitleBarComponent {
zone;
hostElement;
localizationService;
/**
* Fires when the close button of the title-bar is clicked.
*/
close = new EventEmitter();
/**
* @hidden
*/
id;
/**
* @hidden
*/
closeTitle;
get className() {
return true;
}
/**
* @hidden
*/
xIcon = xIcon;
constructor(zone, hostElement, localizationService) {
this.zone = zone;
this.hostElement = hostElement;
this.localizationService = localizationService;
}
get closeButtonTitle() {
return this.closeTitle || this.localizationService.get('closeTitle');
}
ngAfterViewInit() {
this.zone.onStable.pipe(take(1)).subscribe(() => {
const element = this.hostElement.nativeElement.querySelector('.k-dialog-title');
element.setAttribute('id', this.id);
});
}
/**
* @hidden
*/
onCloseClick(e) {
e.preventDefault();
const eventArgs = new PreventableEvent();
this.close.emit(eventArgs);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DialogTitleBarComponent, deps: [{ token: i0.NgZone }, { token: i0.ElementRef }, { token: i1$1.LocalizationService, optional: true }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DialogTitleBarComponent, isStandalone: true, selector: "kendo-dialog-titlebar", inputs: { id: "id", closeTitle: "closeTitle" }, outputs: { close: "close" }, host: { properties: { "class.k-window-titlebar": "this.className", "class.k-dialog-titlebar": "this.className" } }, providers: [
TitleBarLocalizationService,
{
provide: LocalizationService,
useExisting: TitleBarLocalizationService
},
{
provide: L10N_PREFIX,
useValue: 'kendo.dialog'
}
], ngImport: i0, template: `
<ng-container
kendoDialogTitleBarLocalizedMessages
i18n-closeTitle="kendo.dialog.closeTitle|The title of the close button"
closeTitle="Close"
>
<span class="k-window-title k-dialog-title">
<ng-content></ng-content>
</span>
<div class="k-window-titlebar-actions k-dialog-titlebar-actions">
<button
kendoButton
fillMode="flat"
type="button"
[attr.title]="closeButtonTitle"
[attr.aria-label]="closeButtonTitle"
icon="close"
[svgIcon]="xIcon"
class="k-window-titlebar-action k-dialog-titlebar-action"
(click)="onCloseClick($event)"
>
</button>
</div>
</ng-container>
`, isInline: true, dependencies: [{ kind: "directive", type: LocalizedMessagesDirective, selector: "\n [kendoDialogLocalizedMessages],\n [kendoWindowLocalizedMessages],\n [kendoDialogTitleBarLocalizedMessages]\n " }, { 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"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DialogTitleBarComponent, decorators: [{
type: Component,
args: [{
selector: 'kendo-dialog-titlebar',
providers: [
TitleBarLocalizationService,
{
provide: LocalizationService,
useExisting: TitleBarLocalizationService
},
{
provide: L10N_PREFIX,
useValue: 'kendo.dialog'
}
],
template: `
<ng-container
kendoDialogTitleBarLocalizedMessages
i18n-closeTitle="kendo.dialog.closeTitle|The title of the close button"
closeTitle="Close"
>
<span class="k-window-title k-dialog-title">
<ng-content></ng-content>
</span>
<div class="k-window-titlebar-actions k-dialog-titlebar-actions">
<button
kendoButton
fillMode="flat"
type="button"
[attr.title]="closeButtonTitle"
[attr.aria-label]="closeButtonTitle"
icon="close"
[svgIcon]="xIcon"
class="k-window-titlebar-action k-dialog-titlebar-action"
(click)="onCloseClick($event)"
>
</button>
</div>
</ng-container>
`,
standalone: true,
imports: [LocalizedMessagesDirective, ButtonComponent]
}]
}], ctorParameters: function () { return [{ type: i0.NgZone }, { type: i0.ElementRef }, { type: i1$1.LocalizationService, decorators: [{
type: Optional
}] }]; }, propDecorators: { close: [{
type: Output
}], id: [{
type: Input
}], closeTitle: [{
type: Input
}], className: [{
type: HostBinding,
args: ['class.k-window-titlebar']
}, {
type: HostBinding,
args: ['class.k-dialog-titlebar']
}] } });
/**
* @hidden
*/
const packageMetadata = {
name: '@progress/kendo-angular-dialog',
productName: 'Kendo UI for Angular',
productCode: 'KENDOUIANGULAR',
productCodes: ['KENDOUIANGULAR'],
publishDate: 1749540027,
version: '19.1.1',
licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/'
};
/**
* @hidden
*/
const isPresent = (value) => value !== null && value !== undefined;
/**
* @hidden
*/
const isTruthy = (value) => !!value;
const toClassList = (classNames) => String(classNames).trim().split(' ');
const focusableRegex = /^(?:a|input|select|textarea|button|object)$/i;
/**
* @hidden
*/
var Keys;
(function (Keys) {
Keys[Keys["esc"] = 27] = "esc";
Keys[Keys["tab"] = 9] = "tab";
Keys[Keys["enter"] = 13] = "enter";
Keys[Keys["space"] = 32] = "space";
Keys[Keys["ctrl"] = 17] = "ctrl";
Keys[Keys["shift"] = 16] = "shift";
Keys[Keys["left"] = 37] = "left";
Keys[Keys["up"] = 38] = "up";
Keys[Keys["right"] = 39] = "right";
Keys[Keys["down"] = 40] = "down";
})(Keys || (Keys = {}));
/**
* @hidden
*/
const DIALOG_ELEMENTS_HANDLING_ESC_KEY = 'k-dialog-wrapper k-actions k-dialog-titlebar-action';
/**
* @hidden
*/
const DIALOG_ELEMENTS_HANDLING_ARROWS = 'k-actions';
/**
* @hidden
*/
const WINDOW_CLASSES = 'k-window';
/**
* @hidden
*/
const WINDOW_ELEMENTS_HANDLING_ESC_KEY = 'k-window k-window-titlebar-action';
/**
* @hidden
*/
const hasClasses = (element, classNames) => {
const namesList = toClassList(classNames);
return Boolean(toClassList(element.className).find((className) => namesList.indexOf(className) >= 0));
};
/**
* @hidden
*/
const isVisible = (element) => {
const rect = element.getBoundingClientRect();
return !!(rect.width && rect.height) && window.getComputedStyle(element).visibility !== 'hidden';
};
/**
* @hidden
*/
const isFocusable = (element, checkVisibility = true) => {
if (element.tagName) {
const tagName = element.tagName.toLowerCase();
const tabIndex = element.getAttribute('tabIndex');
const validTabIndex = tabIndex !== null && !isNaN(tabIndex) && tabIndex > -1;
let focusable = false;
if (focusableRegex.test(tagName)) {
focusable = !element.disabled;
}
else {
focusable = validTabIndex;
}
return focusable && (!checkVisibility || isVisible(element));
}
return false;
};
/**
* Receives CSS class declarations either as an object, string or array and returns an array of the class names.
*
* @hidden
*/
const parseCSSClassNames = (value) => {
if (isObject(value)) {
return parseObjectClassNames(value);
}
if (isString(value)) {
return parseStringClassNames(value);
}
if (Array.isArray(value)) {
return parseArrayClassNames(value);
}
};
const parseObjectClassNames = (value) => {
const classes = [];
Object.keys(value).forEach(className => {
const currentClassName = splitStringToArray(className);
if (value[className] && currentClassName[0]) {
classes.push(...currentClassName);
}
});
return classes;
};
const parseStringClassNames = (value) => {
const classes = [];
const classesArray = splitStringToArray(value);
classesArray.forEach(className => {
classes.push(className);
});
return classes;
};
const parseArrayClassNames = (value) => {
const classes = [];
value.forEach((className) => {
const current = splitStringToArray(className);
if (current[0]) {
classes.push(...current);
}
});
return classes;
};
/**
* @hidden
*/
const preventDefault = ({ originalEvent: event }) => {
event.stopPropagation();
event.preventDefault();
};
/**
* @hidden
*/
const isWindowAvailable = () => {
return typeof window !== 'undefined';
};
/**
* @hidden
*/
const preventOnDblClick = release => (mouseDown) => of(mouseDown).pipe(delay(150), takeUntil(release));
/**
* @hidden
*/
const RESIZE_DIRECTIONS = ['n', 'e', 's', 'w', 'se', 'sw', 'ne', 'nw'];
/**
* @hidden
*/
const OFFSET_STYLES = ['top', 'left', 'width', 'height'];
/**
* @hidden
*/
const isString = (value) => value instanceof String || typeof value === 'string';
/**
* @hidden
*/
const isObject = (value) => isPresent(value) && !Array.isArray(value) && typeof value === 'object';
/**
* @hidden
*/
const isNumber = (value) => typeof value === 'number' && isFinite(value);
/**
* @hidden
*/
const createValueWithUnit = (value) => value + (isNumber(value) ? 'px' : '');
/**
* @hidden
*/
const splitStringToArray = (value) => value.trim().replace(/\s+/g, " ").split(' ');
/**
* @hidden
*/
const findPrimaryButton = (buttons) => {
for (let i = buttons.length - 1; i >= 0; i--) {
const classList = buttons[i].classList;
for (let j = 0; j < classList.length; j++) {
if (classList[j].endsWith('-primary')) {
return buttons[i];
}
}
}
};
/**
* Indicates that the **Close** button is clicked. Used when the results from
* the Dialogs that are opened through `DialogService` are filtered
* ([see example]({% slug api_dialog_dialogservice %}#toc-open)).
*/
class DialogCloseResult {
}
/**
* @hidden
*/
function animations(duration, direction, animationType) {
switch (animationType) {
case 'slide': {
const translate = direction === 'left' || direction === 'right' ? 'translateX' : 'translateY';
const start = direction === 'right' || direction === 'down' ? -100 : 100;
const end = 0;
return [
style({ transform: `${translate}(${start}%)` }),
animate(`${duration}ms ease-in`, style({ transform: `${translate}(${end}%)` }))
];
}
case 'expand': {
const scale = direction === 'up' || direction === 'down' ? 'scaleY' : 'scaleX';
const startScale = 0;
const endScale = 1;
let origin;
if (direction === 'down') {
origin = 'top';
}
else if (direction === 'left') {
origin = 'right';
}
else if (direction === 'right') {
origin = 'left';
}
else {
origin = 'bottom';
}
return [
style({ transform: `${scale}(${startScale})`, transformOrigin: origin }),
animate(`${duration}ms ease-in`, style({ transform: `${scale}(${endScale})` }))
];
}
case 'zoom': {
const startZoom = 0;
const endZoom = 1;
return [
animate(duration, keyframes([
style({ transform: `scale(${startZoom})` }),
style({ transform: `scale(${endZoom})` })
]))
];
}
case 'fade': {
const startFade = 0;
const endFade = 1;
return [
animate(duration, keyframes([
style({ opacity: `${startFade}` }),
style({ opacity: `${endFade}` })
]))
];
}
case 'translate':
return [
style({ transform: 'translate(0, -10%)' }),
animate(`${duration}ms cubic-bezier(.2, 1, .2, 1)`)
];
default:
return [
style({ transform: 'translate(0, -10%)' }),
animate(`${duration}ms cubic-bezier(.2, 1, .2, 1)`)
];
}
}
/**
* @hidden
*/
const createPlayer = (builder, animation, animatedElement) => {
const factory = builder.build(animation);
let player = factory.create(animatedElement);
player.onDone(() => {
if (player) {
player.destroy();
player = null;
}
});
return player;
};
/**
* @hidden
*/
const animateContent = (animation, defAnimationConfig, animatedElement, builder) => {
let animationConfig = defAnimationConfig;
if (typeof animation !== 'boolean') {
animationConfig = animation;
animationConfig.duration = animationConfig.duration ? animationConfig.duration : defAnimationConfig.duration;
}
const animationSpecs = animations(animationConfig.duration, animationConfig.direction, animationConfig.type);
const player = createPlayer(builder, animationSpecs, animatedElement);
player.play();
};
const DEFAULT_ANIMATION_CONFIG = { duration: 300, type: 'translate' };
/**
* Represents the [Kendo UI Dialog component for Angular]({% slug overview_dialog_dialogs %}).
*/
class DialogComponent {
wrapper;
renderer;
cdr;
ngZone;
builder;
/**
* Specifies the action buttons that will be rendered.
*/
actions;
/**
* Specifies the layout of the action buttons in the Dialog.
* This option is only applicable if the action buttons are specified through the `actions` options.
*
* @default 'stretched'
*/
actionsLayout = 'stretched';
/**
* Specifies the query selector used to set the initial focus ([see examples]({% slug initial_focus_dialog %})).
*/
autoFocusedElement;
/**
* Specifies the text that is rendered in the title bar.
*/
title;
/**
* Specifies the width of the Dialog.
* A numeric value sets the width in pixels.
* A string value sets the width in arbitrary units—for example, `50%`.
*/
width;
/**
* Specifies the minimum width of the Dialog.
* A numeric value sets the minimum width in pixels.
* A string value sets the minimum width in arbitrary units—for example, `50%`.
*/
minWidth;
/**
* Specifies the maximum width of the Dialog.
* A numeric value sets the maximum width in pixels.
* A string value sets the maximum width in arbitrary units—for example, `50%`.
*/
maxWidth;
/**
* Specifies the height of the Dialog.
* A numeric value sets the height in pixels.
* A string value sets the height in arbitrary units—for example, `50%`.
*/
height;
/**
* Specifies the minimum height of the Dialog.
* A numeric value sets the minimum height in pixels.
* A string value sets the minimum height in arbitrary units—for example, `50%`.
*/
minHeight;
/**
* Specifies the maximum height of the Dialog.
* A numeric value sets the maximum height in pixels.
* A string value sets the maximum height in arbitrary units—for example, `50%`.
*/
maxHeight;
/**
* Configures the Dialog opening animation ([see example]({% slug animations_dialog %})).
* By default the animation type is set to `translate` and its duration is `300ms`.
*
* @default true
*/
animation = true;
/**
* The Dialog allows you to specify predefined theme colors.
* The theme color will be applied as a background and border color to the titlebar while also amending the text color accordingly.
*
* The possible values are:
* * `primary`
* * `dark`
* * `light`
*/
set themeColor(themeColor) {
this.handleThemeColorClass(this.themeColor, themeColor);
this._themeColor = themeColor;
}
get themeColor() {
return this._themeColor;
}
/**
* @hidden
*/
set htmlAttributes(attributes) {
setHTMLAttributes(attributes, this.renderer, this.wrapper.nativeElement);
const el = this.wrapper.nativeElement;
const dir = el.getAttribute('dir');
const tIndex = el.getAttribute('tabindex');
if (this.direction !== dir && dir) {
this.direction = dir;
}
if (this.tabIndex !== tIndex && tIndex) {
this.tabIndex = tIndex;
}
this._htmlAttributes = attributes;
}
get htmlAttributes() {
return this._htmlAttributes;
}
/**
* @hidden
*/
set cssClass(classes) {
this.setServiceClasses(this._cssClass, classes);
this._cssClass = classes;
}
get cssClass() {
return this._cssClass;
}
/**
* @hidden
*/
contentTemplate;
/**
* @hidden
*/
titleId = null;
/**
* @hidden
*/
contentId = null;
/**
* @hidden
*/
closeTitle;
/**
* @hidden
*/
showLicenseWatermark = false;
/**
* Fires when the user clicks an action button of the Dialog.
* The event is fired only when the action buttons are specified through the `actions` options.
*/
action = new EventEmitter();
/**
* Fires when the user clicks the **Close** button of the Dialog or the **ESC** key.
*/
close = new EventEmitter();
get dir() {
return this.direction;
}
tabIndex = 0;
titlebarContent;
titlebarView;
actionsView;
dialog;
_htmlAttributes;
_cssClass;
_themeColor = null;
direction;
subscriptions = [];
domSubs = new Subscription();
constructor(wrapper, renderer, localization, cdr, ngZone, builder) {
this.wrapper = wrapper;
this.renderer = renderer;
this.cdr = cdr;
this.ngZone = ngZone;
this.builder = builder;
const isValid = validatePackage(packageMetadata);
this.showLicenseWatermark = shouldShowValidationUI(isValid);
this.direction = localization.rtl ? 'rtl' : 'ltr';
this.subscriptions.push(localization.changes.subscribe(({ rtl }) => (this.direction = rtl ? 'rtl' : 'ltr')));
this.titleId = this.generateTitleId();
this.contentId = this.generateContentId();
}
ngAfterContentInit() {
this.bubble('close', this.titlebarContent.first);
this.renderer.setAttribute(this.wrapper.nativeElement.querySelector('.k-dialog'), 'aria-describedby', this.contentId);
if (this.titlebarContent.first) {
this.titlebarContent.first.id = this.titleId;
}
else {
this.subscriptions.push(this.titlebarContent.changes.subscribe(() => {
if (isPresent(this.titlebarContent.first)) {
this.titlebarContent.first.id = this.titleId;
this.ngZone.onStable.pipe(take(1)).subscribe(() => {
this.bubble('close', this.titlebarContent.first);
this.renderer.setAttribute(this.wrapper.nativeElement.querySelector('.k-dialog'), 'aria-labelledby', this.titleId);
});
}
}));
}
}
ngAfterViewInit() {
if (!isDocumentAvailable()) {
return;
}
this.ngZone.onStable.pipe(take(1)).subscribe(() => {
this.handleInitialFocus();
});
this.bubble('close', this.titlebarView.first);
this.bubble('action', this.actionsView);
if (this.titlebarView.first || this.titlebarContent.first) {
//Needed for Dialogs created via service
this.renderer.setAttribute(this.wrapper.nativeElement.querySelector('.k-dialog'), 'aria-labelledby', this.titleId);
}
else {
this.subscriptions.push(this.titlebarView.changes.subscribe(() => {
if (isPresent(this.titlebarView.first)) {
this.titlebarView.first.id = this.titleId;
this.ngZone.onStable.pipe(take(1)).subscribe(() => {
this.bubble('close', this.titlebarView.first);
this.renderer.setAttribute(this.wrapper.nativeElement.querySelector('.k-dialog'), 'aria-labelledby', this.titleId);
});
}
}));
}
this.initDomEvents();
this.handleThemeColorClass(null, this.themeColor);
}
ngOnInit() {
if (this.animation) {
animateContent(this.animation, DEFAULT_ANIMATION_CONFIG, this.dialog.nativeElement, this.builder);
}
this.renderer.removeAttribute(this.wrapper.nativeElement, 'title');
this.cdr.detectChanges();
}
ngOnDestroy() {
this.subscriptions.forEach(s => s.unsubscribe());
this.subscriptions = [];
if (this.domSubs) {
this.domSubs.unsubscribe();
}
}
/**
* Focuses the wrapper of the Dialog component.
*/
focus() {
const wrapper = this.wrapper.nativeElement;
if (isPresent(wrapper)) {
wrapper.focus();
}
}
initDomEvents() {
if (!this.wrapper) {
return;
}
this.ngZone.runOutsideAngular(() => {
this.domSubs.add(this.renderer.listen(this.wrapper.nativeElement, 'keydown', (ev) => {
this.onKeyDown(ev);
}));
});
}
onKeyDown(event) {
const target = event.target;
const parent = target.parentElement;
if (hasClasses(target, DIALOG_ELEMENTS_HANDLING_ESC_KEY) || hasClasses(parent, DIALOG_ELEMENTS_HANDLING_ESC_KEY)) {
if (event.keyCode === Keys.esc) {
this.ngZone.run(() => {
this.close.emit(new DialogCloseResult());
});
}
}
if (hasClasses(target, 'k-button') && hasClasses(parent, DIALOG_ELEMENTS_HANDLING_ARROWS) &&
(event.keyCode === Keys.left || event.keyCode === Keys.right)) {
this.ngZone.run(() => {
this.handleActionButtonFocus(parent, event.keyCode);
});
}
if (event.keyCode === Keys.tab) {
this.ngZone.run(() => {
this.keepFocusWithinComponent(target, event);
});
}
}
setServiceClasses(prevValue, value) {
const el = this.wrapper.nativeElement;
if (prevValue) {
parseCSSClassNames(prevValue).forEach(className => {
this.renderer.removeClass(el, className);
});
}
if (value) {
parseCSSClassNames(value).forEach(className => {
this.renderer.addClass(el, className);
});
}
}
/**
* @hidden
*/
handleInitialFocus() {
const wrapper = this.wrapper.nativeElement;
const primaryButton = this.findPrimary(wrapper);
if (this.autoFocusedElement) {
const initiallyFocusedElement = wrapper.querySelector(this.autoFocusedElement);
if (initiallyFocusedElement) {
initiallyFocusedElement.focus();
}
}
else if (this.shouldFocusPrimary(primaryButton)) {
primaryButton.focus();
}
else {
wrapper.focus();
}
}
/**
* @hidden
*/
findPrimary(wrapper) {
const actionBtns = wrapper.querySelectorAll('.k-actions .k-button');
return findPrimaryButton(actionBtns);
}
/**
* @hidden
*/
handleActionButtonFocus(parent, key) {
const focusableActionButtons = this.getAllFocusableChildren(parent);
for (let i = 0; i < focusableActionButtons.length; i++) {
const current = focusableActionButtons[i];
if (current === document.activeElement) {
if (key === Keys.left && i > 0) {
focusableActionButtons[i - 1].focus();
break;
}
if (key === Keys.right && i < focusableActionButtons.length - 1) {
focusableActionButtons[i + 1].focus();
break;
}
}
}
}
/**
* @hidden
*/
keepFocusWithinComponent(target, event) {
const wrapper = this.wrapper.nativeElement;
const [firstFocusable, lastFocusable] = this.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();
}
}
/**
* @hidden
*/
shouldFocusPrimary(el) {
return isPresent(el) && isFocusable(el);
}
/**
* @hidden
*/
getAllFocusableChildren(parent) {
return parent.querySelectorAll(focusableSelector);
}
/**
* @hidden
*/
getFirstAndLastFocusable(parent) {
const all = this.getAllFocusableChildren(parent);
const firstFocusable = all.length > 0 ? all[0] : parent;
const lastFocusable = all.length > 0 ? all[all.length - 1] : parent;
return [firstFocusable, lastFocusable];
}
/**
* @hidden
*/
generateTitleId() {
return 'kendo-dialog-title-' + Math.ceil(Math.random() * 1000000).toString();
}
/**
* @hidden
*/
generateContentId() {
return 'kendo-dialog-content-' + Math.ceil(Math.random() * 1000000).toString();
}
get wrapperClass() {
return true;
}
get styles() {
const styles = {};
if (this.width) {
styles.width = createValueWithUnit(this.width);
}
if (this.height) {
styles.height = createValueWithUnit(this.height);
}
if (this.minWidth) {
styles.minWidth = createValueWithUnit(this.minWidth);
}
if (this.maxWidth) {
styles.maxWidth = createValueWithUnit(this.maxWidth);
}
if (this.minHeight) {
styles.minHeight = createValueWithUnit(this.minHeight);
}
if (this.maxHeight) {
styles.maxHeight = createValueWithUnit(this.maxHeight);
}
return styles;
}
bubble(eventName, component) {
if (component) {
const emit = e => this[eventName].emit(e);
const s = component[eventName].subscribe(emit);
this.subscriptions.push(s);
}
}
handleThemeColorClass(previousValue, currentValue) {
this.ngZone.onStable.pipe(take(1)).subscribe(() => {
const dialog = this.dialog.nativeElement;
if (previousValue) {
const classToRemove = `k-dialog-${previousValue}`;
this.renderer.removeClass(dialog, classToRemove);
}
if (currentValue) {
const classToAdd = `k-dialog-${currentValue}`;
this.renderer.addClass(dialog, classToAdd);
}
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DialogComponent, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i1$1.LocalizationService }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i2.AnimationBuilder }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DialogComponent, isStandalone: true, selector: "kendo-dialog", inputs: { actions: "actions", actionsLayout: "actionsLayout", autoFocusedElement: "autoFocusedElement", title: "title", width: "width", minWidth: "minWidth", maxWidth: "maxWidth", height: "height", minHeight: "minHeight", maxHeight: "maxHeight", animation: "animation", themeColor: "themeColor" }, outputs: { action: "action", close: "close" }, host: { properties: { "attr.dir": "this.dir", "attr.tabIndex": "this.tabIndex", "class.k-dialog-wrapper": "this.wrapperClass" } }, providers: [
LocalizationService,
{
provide: DIALOG_LOCALIZATION_SERVICE,
useExisting: LocalizationService
},
{
provide: L10N_PREFIX,
useValue: 'kendo.dialog'
}
], queries: [{ propertyName: "titlebarContent", predicate: DialogTitleBarComponent }], viewQueries: [{ propertyName: "actionsView", first: true, predicate: DialogActionsComponent, descendants: true }, { propertyName: "dialog", first: true, predicate: ["dialog"], descendants: true, static: true }, { propertyName: "titlebarView", predicate: DialogTitleBarComponent, descendants: true }], exportAs: ["kendoDialog"], ngImport: i0, template: `
<ng-container
kendoDialogLocalizedMessages
i18n-closeTitle="kendo.dialog.closeTitle|The title of the close button"
closeTitle="Close"
>
<div class="k-overlay" @overlayAppear></div>
<div #dialog class="k-window k-dialog" role="dialog" aria-modal="true" [ngStyle]="styles">
<kendo-dialog-titlebar *ngIf="title" [closeTitle]="closeTitle" [id]="titleId">{{ title }}</kendo-dialog-titlebar>
<ng-content select="kendo-dialog-titlebar" *ngIf="!title"></ng-content>
<div [id]="contentId" class="k-window-content k-dialog-content">
<ng-content *ngIf="!contentTemplate"></ng-content>
<ng-template [ngTemplateOutlet]="contentTemplate" *ngIf="contentTemplate"></ng-template>
</div>
<ng-content select="kendo-dialog-actions" *ngIf="!actions"></ng-content>
<kendo-dialog-actions *ngIf="actions" [actions]="actions" [layout]="actionsLayout"> </kendo-dialog-actions>
<div kendoWatermarkOverlay *ngIf="showLicenseWatermark"></div>
</div>
</ng-container>
`, isInline: true, dependencies: [{ kind: "directive", type: LocalizedMessagesDirective, selector: "\n [kendoDialogLocalizedMessages],\n [kendoWindowLocalizedMessages],\n [kendoDialogTitleBarLocalizedMessages]\n " }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: DialogTitleBarComponent, selector: "kendo-dialog-titlebar", inputs: ["id", "closeTitle"], outputs: ["close"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: DialogActionsComponent, selector: "kendo-dialog-actions", inputs: ["actions", "layout"], outputs: ["action"] }, { kind: "component", type: WatermarkOverlayComponent, selector: "div[kendoWatermarkOverlay]" }], animations: [
trigger('overlayAppear', [
state('in', style({ opacity: 1 })),
transition('void => *', [style({ opacity: 0.1 }), animate('.3s cubic-bezier(.2, .6, .4, 1)')])
])
] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DialogComponent, decorators: [{
type: Component,
args: [{
animations: [
trigger('overlayAppear', [
state('in', style({ opacity: 1 })),
transition('void => *', [style({ opacity: 0.1 }), animate('.3s cubic-bezier(.2, .6, .4, 1)')])
])
],
exportAs: 'kendoDialog',
providers: [
LocalizationService,
{
provide: DIALOG_LOCALIZATION_SERVICE,
useExisting: LocalizationService
},
{
provide: L10N_PREFIX,
useValue: 'kendo.dialog'
}
],
selector: 'kendo-dialog',
template: `
<ng-container
kendoDialogLocalizedMessages
i18n-closeTitle="kendo.dialog.closeTitle|The title of the close button"
closeTitle="Close"
>
<div class="k-overlay" @overlayAppear></div>
<div #dialog class="k-window k-dialog" role="dialog" aria-modal="true" [ngStyle]="styles">
<kendo-dialog-titlebar *ngIf="title" [closeTitle]="closeTitle" [id]="titleId">{{ title }}</kendo-dialog-titlebar>
<ng-content select="kendo-dialog-titlebar" *ngIf="!title"></ng-content>
<div [id]="contentId" class="k-window-content k-dialog-content">
<ng-content *ngIf="!contentTemplate"></ng-content>
<ng-template [ngTemplateOutlet]="contentTemplate" *ngIf="contentTemplate"></ng-template>
</div>
<ng-content select="kendo-dialog-actions" *ngIf="!actions"></ng-content>
<kendo-dialog-actions *ngIf="actions" [actions]="actions" [layout]="actionsLayout"> </kendo-dialog-actions>
<div kendoWatermarkOverlay *ngIf="showLicenseWatermark"></div>
</div>
</ng-container>
`,
standalone: true,
imports: [LocalizedMessa