@clr/angular
Version:
Angular components for Clarity
618 lines (606 loc) • 37.8 kB
JavaScript
import { trigger, transition, style, animate } from '@angular/animations';
import * as i0 from '@angular/core';
import { PLATFORM_ID, Inject, Injectable, EventEmitter, ViewChild, ContentChild, Input, Output, HostBinding, Component, Directive, NgModule, HostListener } from '@angular/core';
import * as i1 from '@clr/angular/utils';
import { Keys, uniqueIdFactory, ScrollingService, CdkTrapFocusModule } from '@clr/angular/utils';
import * as i4 from '@angular/common';
import { isPlatformBrowser, CommonModule } from '@angular/common';
import * as i5 from '@clr/angular/icon';
import { ClarityIcons, windowCloseIcon, ClrIcon } from '@clr/angular/icon';
/*
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
* This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project.
*/
class ModalStackService {
constructor(platformId) {
this.platformId = platformId;
this.modalStack = [];
this.keyUpEventListener = this.onKeyUp.bind(this);
}
trackModalOpen(openedModal) {
if (this.modalStack.includes(openedModal) === false) {
this.modalStack.unshift(openedModal);
}
if (isPlatformBrowser(this.platformId)) {
document.body.addEventListener('keyup', this.keyUpEventListener);
}
}
trackModalClose(closedModal) {
const closedModalIndex = this.modalStack.indexOf(closedModal);
if (closedModalIndex > -1) {
this.modalStack.splice(closedModalIndex, 1);
}
if (this.modalStack.length === 0 && isPlatformBrowser(this.platformId)) {
document.body.removeEventListener('keyup', this.keyUpEventListener);
}
}
onKeyUp(event) {
if (this.modalStack.length && event.key === Keys.Escape) {
// We blur the active element because escaping with an input element in focus could cause
// an ExpressionChangedAfterItHasBeenCheckedError for the touched state. (CDE-1662)
document.activeElement.blur();
this.modalStack[0].close();
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ModalStackService, deps: [{ token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ModalStackService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ModalStackService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Inject,
args: [PLATFORM_ID]
}] }] });
/*
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
* This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project.
*/
class ClrModalConfigurationService {
constructor() {
this.fadeMove = 'fadeDown';
this.backdrop = true;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrModalConfigurationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrModalConfigurationService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrModalConfigurationService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}] });
/*
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
* This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project.
*/
class ClrModal {
constructor(_scrollingService, commonStrings, modalStackService, configuration) {
this._scrollingService = _scrollingService;
this.commonStrings = commonStrings;
this.modalStackService = modalStackService;
this.configuration = configuration;
this.modalId = uniqueIdFactory();
this._open = false;
this._openChanged = new EventEmitter(false);
this.closable = true;
this.closeButtonAriaLabel = this.commonStrings.keys.close;
this.size = 'md';
this.staticBackdrop = true;
this.skipAnimation = false;
this.stopClose = false;
this.altClose = new EventEmitter(false);
// presently this is only used by inline wizards
this.bypassScrollService = false;
}
get fadeMove() {
return this.skipAnimation ? '' : this.configuration.fadeMove;
}
set fadeMove(move) {
this.configuration.fadeMove = move;
}
get backdrop() {
return this.configuration.backdrop;
}
// Detect when _open is set to true and set no-scrolling to true
ngOnChanges(changes) {
if (!this.bypassScrollService && changes && Object.prototype.hasOwnProperty.call(changes, '_open')) {
if (changes._open.currentValue) {
this._scrollingService.stopScrolling();
this.modalStackService.trackModalOpen(this);
}
else {
this._scrollingService.resumeScrolling();
}
}
}
ngOnDestroy() {
this._scrollingService.resumeScrolling();
}
open() {
if (this._open) {
return;
}
this._open = true;
this._openChanged.emit(true);
this.modalStackService.trackModalOpen(this);
}
backdropClick() {
if (this.staticBackdrop) {
return;
}
this.close();
}
close() {
if (this.stopClose) {
this.altClose.emit(false);
return;
}
if (!this.closable || !this._open) {
return;
}
this._open = false;
}
fadeDone(e) {
if (e.toState === 'void') {
// TODO: Investigate if we can decouple from animation events
this._openChanged.emit(false);
this.modalStackService.trackModalClose(this);
}
}
scrollTop() {
this.bodyElementRef.nativeElement.scrollTo(0, 0);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrModal, deps: [{ token: i1.ScrollingService }, { token: i1.ClrCommonStringsService }, { token: ModalStackService }, { token: ClrModalConfigurationService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: ClrModal, isStandalone: false, selector: "clr-modal", inputs: { _open: ["clrModalOpen", "_open"], closable: ["clrModalClosable", "closable"], closeButtonAriaLabel: ["clrModalCloseButtonAriaLabel", "closeButtonAriaLabel"], size: ["clrModalSize", "size"], staticBackdrop: ["clrModalStaticBackdrop", "staticBackdrop"], skipAnimation: ["clrModalSkipAnimation", "skipAnimation"], stopClose: ["clrModalPreventClose", "stopClose"], labelledBy: ["clrModalLabelledById", "labelledBy"], bypassScrollService: ["clrModalOverrideScrollService", "bypassScrollService"] }, outputs: { _openChanged: "clrModalOpenChange", altClose: "clrModalAlternateClose" }, host: { properties: { "class.open": "this._open" } }, queries: [{ propertyName: "modalContentTemplate", first: true, predicate: ["clrInternalModalContentTemplate"], descendants: true }], viewQueries: [{ propertyName: "title", first: true, predicate: ["title"], descendants: true }, { propertyName: "bodyElementRef", first: true, predicate: ["body"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<!--\n ~ Copyright (c) 2016-2026 Broadcom. All Rights Reserved.\n ~ The term \"Broadcom\" refers to Broadcom Inc. and/or its subsidiaries.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n@if (_open) {\n<div class=\"modal\" [class.modal-full-screen]=\"size == 'full-screen'\">\n <!--fixme: revisit when ngClass works with exit animation-->\n <div\n cdkTrapFocus\n [cdkTrapFocusAutoCapture]=\"true\"\n [@fadeMove]=\"fadeMove\"\n (@fadeMove.done)=\"fadeDone($event)\"\n class=\"modal-dialog\"\n [class.modal-sm]=\"size == 'sm'\"\n [class.modal-lg]=\"size == 'lg'\"\n [class.modal-xl]=\"size == 'xl'\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-hidden]=\"!_open\"\n [attr.aria-labelledby]=\"labelledBy || modalId\"\n >\n <div class=\"clr-sr-only\">{{commonStrings.keys.modalContentStart}}</div>\n <!-- This wizard is tightly coupled to the modal styles, so changes here could require changes in the wizard. -->\n @if (!modalContentTemplate) {\n <div class=\"modal-content-wrapper\">\n <div class=\"modal-content\">\n <div class=\"modal-header--accessible\">\n <ng-content select=\".leading-button\"></ng-content>\n <div class=\"modal-title-wrapper\" #title [id]=\"modalId\" cdkFocusInitial tabindex=\"-1\">\n <ng-content select=\".modal-title\"></ng-content>\n </div>\n @if (closable) {\n <button\n type=\"button\"\n [attr.aria-label]=\"closeButtonAriaLabel || commonStrings.keys.close\"\n class=\"close\"\n (click)=\"close()\"\n >\n <cds-icon shape=\"window-close\"></cds-icon>\n </button>\n }\n </div>\n <div #body class=\"modal-body-wrapper\">\n <ng-content select=\".modal-body\"></ng-content>\n </div>\n <ng-content select=\".modal-footer\"></ng-content>\n </div>\n </div>\n } @else {\n <ng-template [ngTemplateOutlet]=\"modalContentTemplate\"></ng-template>\n }\n </div>\n <div class=\"clr-sr-only\">{{commonStrings.keys.modalContentEnd}}</div>\n @if (backdrop) {\n <div\n [@fade]\n class=\"modal-backdrop\"\n [class.static]=\"staticBackdrop\"\n aria-hidden=\"true\"\n (click)=\"backdropClick()\"\n ></div>\n }\n</div>\n}\n", styles: [":host{display:none}:host.open{display:inline}\n"], dependencies: [{ kind: "directive", type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.CdkTrapFocusModule_CdkTrapFocus, selector: "[cdkTrapFocus]" }, { kind: "component", type: i5.ClrIcon, selector: "clr-icon, cds-icon", inputs: ["shape", "size", "direction", "flip", "solid", "status", "inverse", "badge"] }], viewProviders: [ScrollingService], animations: [
trigger('fadeMove', [
transition('* => fadeDown', [
style({ opacity: 0, transform: 'translate(0, -25%)' }),
animate('0.2s ease-in-out'),
]),
transition('fadeDown => *', [
animate('0.2s ease-in-out', style({ opacity: 0, transform: 'translate(0, -25%)' })),
]),
transition('* => fadeLeft', [style({ opacity: 0, transform: 'translate(25%, 0)' }), animate('0.2s ease-in-out')]),
transition('fadeLeft => *', [animate('0.2s ease-in-out', style({ opacity: 0, transform: 'translate(25%, 0)' }))]),
transition('* => fadeUp', [style({ opacity: 0, transform: 'translate(0, 50%)' }), animate('0.2s ease-in-out')]),
transition('fadeUp => *', [animate('0.2s ease-in-out', style({ opacity: 0, transform: 'translate(0, 50%)' }))]),
]),
trigger('fade', [
transition('void => *', [style({ opacity: 0 }), animate('0.2s ease-in-out', style({ opacity: 0.85 }))]),
transition('* => void', [animate('0.2s ease-in-out', style({ opacity: 0 }))]),
]),
] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrModal, decorators: [{
type: Component,
args: [{ selector: 'clr-modal', viewProviders: [ScrollingService], animations: [
trigger('fadeMove', [
transition('* => fadeDown', [
style({ opacity: 0, transform: 'translate(0, -25%)' }),
animate('0.2s ease-in-out'),
]),
transition('fadeDown => *', [
animate('0.2s ease-in-out', style({ opacity: 0, transform: 'translate(0, -25%)' })),
]),
transition('* => fadeLeft', [style({ opacity: 0, transform: 'translate(25%, 0)' }), animate('0.2s ease-in-out')]),
transition('fadeLeft => *', [animate('0.2s ease-in-out', style({ opacity: 0, transform: 'translate(25%, 0)' }))]),
transition('* => fadeUp', [style({ opacity: 0, transform: 'translate(0, 50%)' }), animate('0.2s ease-in-out')]),
transition('fadeUp => *', [animate('0.2s ease-in-out', style({ opacity: 0, transform: 'translate(0, 50%)' }))]),
]),
trigger('fade', [
transition('void => *', [style({ opacity: 0 }), animate('0.2s ease-in-out', style({ opacity: 0.85 }))]),
transition('* => void', [animate('0.2s ease-in-out', style({ opacity: 0 }))]),
]),
], standalone: false, template: "<!--\n ~ Copyright (c) 2016-2026 Broadcom. All Rights Reserved.\n ~ The term \"Broadcom\" refers to Broadcom Inc. and/or its subsidiaries.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n@if (_open) {\n<div class=\"modal\" [class.modal-full-screen]=\"size == 'full-screen'\">\n <!--fixme: revisit when ngClass works with exit animation-->\n <div\n cdkTrapFocus\n [cdkTrapFocusAutoCapture]=\"true\"\n [@fadeMove]=\"fadeMove\"\n (@fadeMove.done)=\"fadeDone($event)\"\n class=\"modal-dialog\"\n [class.modal-sm]=\"size == 'sm'\"\n [class.modal-lg]=\"size == 'lg'\"\n [class.modal-xl]=\"size == 'xl'\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-hidden]=\"!_open\"\n [attr.aria-labelledby]=\"labelledBy || modalId\"\n >\n <div class=\"clr-sr-only\">{{commonStrings.keys.modalContentStart}}</div>\n <!-- This wizard is tightly coupled to the modal styles, so changes here could require changes in the wizard. -->\n @if (!modalContentTemplate) {\n <div class=\"modal-content-wrapper\">\n <div class=\"modal-content\">\n <div class=\"modal-header--accessible\">\n <ng-content select=\".leading-button\"></ng-content>\n <div class=\"modal-title-wrapper\" #title [id]=\"modalId\" cdkFocusInitial tabindex=\"-1\">\n <ng-content select=\".modal-title\"></ng-content>\n </div>\n @if (closable) {\n <button\n type=\"button\"\n [attr.aria-label]=\"closeButtonAriaLabel || commonStrings.keys.close\"\n class=\"close\"\n (click)=\"close()\"\n >\n <cds-icon shape=\"window-close\"></cds-icon>\n </button>\n }\n </div>\n <div #body class=\"modal-body-wrapper\">\n <ng-content select=\".modal-body\"></ng-content>\n </div>\n <ng-content select=\".modal-footer\"></ng-content>\n </div>\n </div>\n } @else {\n <ng-template [ngTemplateOutlet]=\"modalContentTemplate\"></ng-template>\n }\n </div>\n <div class=\"clr-sr-only\">{{commonStrings.keys.modalContentEnd}}</div>\n @if (backdrop) {\n <div\n [@fade]\n class=\"modal-backdrop\"\n [class.static]=\"staticBackdrop\"\n aria-hidden=\"true\"\n (click)=\"backdropClick()\"\n ></div>\n }\n</div>\n}\n", styles: [":host{display:none}:host.open{display:inline}\n"] }]
}], ctorParameters: () => [{ type: i1.ScrollingService }, { type: i1.ClrCommonStringsService }, { type: ModalStackService }, { type: ClrModalConfigurationService }], propDecorators: { title: [{
type: ViewChild,
args: ['title']
}], _open: [{
type: Input,
args: ['clrModalOpen']
}, {
type: HostBinding,
args: ['class.open']
}], _openChanged: [{
type: Output,
args: ['clrModalOpenChange']
}], closable: [{
type: Input,
args: ['clrModalClosable']
}], closeButtonAriaLabel: [{
type: Input,
args: ['clrModalCloseButtonAriaLabel']
}], size: [{
type: Input,
args: ['clrModalSize']
}], staticBackdrop: [{
type: Input,
args: ['clrModalStaticBackdrop']
}], skipAnimation: [{
type: Input,
args: ['clrModalSkipAnimation']
}], stopClose: [{
type: Input,
args: ['clrModalPreventClose']
}], altClose: [{
type: Output,
args: ['clrModalAlternateClose']
}], labelledBy: [{
type: Input,
args: ['clrModalLabelledById']
}], bypassScrollService: [{
type: Input,
args: ['clrModalOverrideScrollService']
}], modalContentTemplate: [{
type: ContentChild,
args: ['clrInternalModalContentTemplate']
}], bodyElementRef: [{
type: ViewChild,
args: ['body']
}] } });
/*
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
* This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project.
*/
/**
* Allows modal overflow area to be scrollable via keyboard.
* The modal body will focus with keyboard navigation only.
* This allows inner focusable items to be focused without
* the overflow scroll being focused.
*/
class ClrModalBody {
constructor(renderer, host, ngZone) {
this.renderer = renderer;
this.host = host;
this.tabindex = '0';
this.unlisteners = [];
ngZone.runOutsideAngular(() => {
this.observer = new ResizeObserver(() => this.addOrRemoveTabIndex());
this.observer.observe(host.nativeElement);
this.unlisteners.push(renderer.listen(host.nativeElement, 'mouseup', () => {
// set the tabindex binding back when click is completed with mouseup
this.addOrRemoveTabIndex();
}), renderer.listen(host.nativeElement, 'mousedown', () => {
// tabindex = 0 binding should be removed
// so it won't be focused when click starts with mousedown
this.removeTabIndex();
}));
});
}
ngOnDestroy() {
while (this.unlisteners.length) {
this.unlisteners.pop()();
}
this.observer.disconnect();
this.observer = null;
}
addTabIndex() {
this.renderer.setAttribute(this.host.nativeElement, 'tabindex', this.tabindex);
}
removeTabIndex() {
this.renderer.removeAttribute(this.host.nativeElement, 'tabindex');
}
addOrRemoveTabIndex() {
const modalBody = this.host.nativeElement.parentElement;
if (modalBody && modalBody.clientHeight < modalBody.scrollHeight) {
this.addTabIndex();
}
else {
this.removeTabIndex();
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrModalBody, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.3", type: ClrModalBody, isStandalone: false, selector: ".modal-body", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrModalBody, decorators: [{
type: Directive,
args: [{
selector: '.modal-body',
standalone: false,
}]
}], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i0.NgZone }] });
/*
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
* This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project.
*/
class ClrModalHostComponent {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrModalHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.3", type: ClrModalHostComponent, isStandalone: false, selector: "[clrModalHost]", host: { properties: { "class.clr-modal-host": "true" } }, ngImport: i0, template: `
<div class="clr-modal-host-scrollable">
<ng-content></ng-content>
</div>
`, isInline: true }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrModalHostComponent, decorators: [{
type: Component,
args: [{
selector: '[clrModalHost]',
host: { '[class.clr-modal-host]': 'true' },
template: `
<div class="clr-modal-host-scrollable">
<ng-content></ng-content>
</div>
`,
standalone: false,
}]
}] });
/*
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
* This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project.
*/
const CLR_MODAL_DIRECTIVES = [ClrModal, ClrModalBody, ClrModalHostComponent];
class ClrModalModule {
constructor() {
ClarityIcons.addIcons(windowCloseIcon);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrModalModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: ClrModalModule, declarations: [ClrModal, ClrModalBody, ClrModalHostComponent], imports: [CommonModule, CdkTrapFocusModule, ClrIcon], exports: [ClrModal, ClrModalBody, ClrModalHostComponent, ClrIcon] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrModalModule, imports: [CommonModule, CdkTrapFocusModule, ClrIcon] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrModalModule, decorators: [{
type: NgModule,
args: [{
imports: [CommonModule, CdkTrapFocusModule, ClrIcon],
declarations: [CLR_MODAL_DIRECTIVES],
exports: [CLR_MODAL_DIRECTIVES, ClrIcon],
}]
}], ctorParameters: () => [] });
/*
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
* This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project.
*/
class ClrSidePanel {
constructor(element, configuration, commonStrings) {
this.element = element;
this.configuration = configuration;
this.commonStrings = commonStrings;
this.openChange = new EventEmitter(false);
this.skipAnimation = false;
this.staticBackdrop = false;
this.closable = true;
this.preventClose = false;
this.altClose = new EventEmitter(false);
this._pinnable = false;
this._pinned = false;
this._position = 'right';
this.__open = false;
this._size = 'md';
}
get _open() {
return this.__open;
}
set _open(open) {
if (open !== this.__open) {
this.__open = open;
if (this.pinned) {
this.updateModalState();
}
}
}
get size() {
return this._size;
}
set size(value) {
if (!value) {
value = 'md';
}
if (this._size !== value) {
this._size = value;
if (this.pinned) {
this.updateModalState();
}
}
}
get position() {
return this._position;
}
set position(position) {
if (position && position !== this._position) {
this._position = position;
if (this._position === 'right') {
this.configuration.fadeMove = 'fadeLeft';
}
else if (this._position === 'bottom') {
this.configuration.fadeMove = 'fadeUp';
}
}
}
get pinned() {
return this._pinned;
}
set pinned(pinned) {
this._pinned = pinned;
if (this.modal) {
this.updateModalState();
}
}
get clrSidePanelBackdrop() {
return this.configuration.backdrop;
}
set clrSidePanelBackdrop(backdrop) {
if (backdrop !== undefined) {
this.configuration.backdrop = backdrop;
}
}
get clrSidePanelPinnable() {
return this._pinnable;
}
set clrSidePanelPinnable(pinnable) {
this._pinnable = pinnable;
}
get modal() {
return this._modal;
}
set modal(modal) {
this._modal = modal;
this.originalStopClose = this.modal.stopClose;
this.updateModalState();
}
get hostElement() {
return this.element.nativeElement.closest('.clr-modal-host') || document.body;
}
get bottomPositionCssClass() {
return this.position === 'bottom';
}
ngOnInit() {
this.configuration.fadeMove = 'fadeLeft';
if (this.position === 'bottom') {
this.configuration.fadeMove = 'fadeUp';
}
}
ngOnDestroy() {
this.cleanupPinnedClasses();
}
handleModalOpen(open) {
if (open) {
this.updateModalState();
}
else {
this.cleanupPinnedClasses();
}
this.openChange.emit(open);
}
open() {
this.modal.open();
}
close() {
this.modal.close();
}
togglePinned() {
this.pinned = !this.pinned;
}
documentClick(event) {
if (!this.element.nativeElement.contains(event.target) &&
this.modal._open &&
!this.configuration.backdrop) {
this.modal.close();
}
}
updateModalState() {
if (!this.modal) {
return;
}
if (this.pinned) {
this.modal.stopClose = true;
this.updatePinnedClasses();
}
else {
this.modal.stopClose = this.originalStopClose;
this.cleanupPinnedClasses();
}
}
cleanupPinnedClasses() {
[this.hostElement, document.body].forEach(host => {
host.classList.forEach(className => {
if (className.startsWith('clr-side-panel-pinned-')) {
host.classList.remove(className);
}
});
});
}
updatePinnedClasses() {
this.cleanupPinnedClasses();
this.hostElement.classList.add(`clr-side-panel-pinned-${this.position}-${this.size}`);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrSidePanel, deps: [{ token: i0.ElementRef }, { token: ClrModalConfigurationService }, { token: i1.ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: ClrSidePanel, isStandalone: false, selector: "clr-side-panel", inputs: { closeButtonAriaLabel: ["clrSidePanelCloseButtonAriaLabel", "closeButtonAriaLabel"], skipAnimation: ["clrSidePanelSkipAnimation", "skipAnimation"], labelledById: ["clrSidePanelLabelledById", "labelledById"], staticBackdrop: ["clrSidePanelStaticBackdrop", "staticBackdrop"], closable: ["clrSidePanelClosable", "closable"], preventClose: ["clrSidePanelPreventClose", "preventClose"], _open: ["clrSidePanelOpen", "_open"], size: ["clrSidePanelSize", "size"], position: ["clrSidePanelPosition", "position"], pinned: ["clrSidePanelPinned", "pinned"], clrSidePanelBackdrop: "clrSidePanelBackdrop", clrSidePanelPinnable: "clrSidePanelPinnable" }, outputs: { openChange: "clrSidePanelOpenChange", altClose: "clrSidePanelAlternateClose" }, host: { listeners: { "document:pointerup": "documentClick($event)" }, properties: { "class.side-panel": "true", "class.side-panel-bottom": "this.bottomPositionCssClass" } }, viewQueries: [{ propertyName: "modal", first: true, predicate: ClrModal, descendants: true }], ngImport: i0, template: "<!--\n ~ Copyright (c) 2016-2026 Broadcom. All Rights Reserved.\n ~ The term \"Broadcom\" refers to Broadcom Inc. and/or its subsidiaries.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n<clr-modal\n [clrModalOpen]=\"_open\"\n (clrModalOpenChange)=\"handleModalOpen($event)\"\n [clrModalCloseButtonAriaLabel]=\"closeButtonAriaLabel\"\n [clrModalSize]=\"size\"\n [clrModalSkipAnimation]=\"skipAnimation\"\n [clrModalStaticBackdrop]=\"staticBackdrop\"\n [clrModalLabelledById]=\"labelledById\"\n [clrModalPreventClose]=\"preventClose\"\n [clrModalClosable]=\"closable\"\n (clrModalAlternateClose)=\"altClose.emit($event)\"\n [clrModalOverrideScrollService]=\"true\"\n>\n @if (clrSidePanelPinnable) {\n <button\n type=\"button\"\n [attr.aria-label]=\"commonStrings.keys.sidePanelPin\"\n class=\"leading-button pinnable\"\n (click)=\"togglePinned()\"\n >\n <cds-icon [shape]=\"pinned ? 'unpin' : 'pin'\"></cds-icon>\n </button>\n }\n <div class=\"modal-title\"><ng-content select=\".side-panel-title\"></ng-content></div>\n <div class=\"modal-body\"><ng-content select=\".side-panel-body\"></ng-content></div>\n <div class=\"modal-footer\"><ng-content select=\".side-panel-footer\"></ng-content></div>\n</clr-modal>\n", dependencies: [{ kind: "component", type: i5.ClrIcon, selector: "clr-icon, cds-icon", inputs: ["shape", "size", "direction", "flip", "solid", "status", "inverse", "badge"] }, { kind: "component", type: ClrModal, selector: "clr-modal", inputs: ["clrModalOpen", "clrModalClosable", "clrModalCloseButtonAriaLabel", "clrModalSize", "clrModalStaticBackdrop", "clrModalSkipAnimation", "clrModalPreventClose", "clrModalLabelledById", "clrModalOverrideScrollService"], outputs: ["clrModalOpenChange", "clrModalAlternateClose"] }, { kind: "directive", type: ClrModalBody, selector: ".modal-body" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrSidePanel, decorators: [{
type: Component,
args: [{ selector: 'clr-side-panel', host: {
'[class.side-panel]': 'true',
}, standalone: false, template: "<!--\n ~ Copyright (c) 2016-2026 Broadcom. All Rights Reserved.\n ~ The term \"Broadcom\" refers to Broadcom Inc. and/or its subsidiaries.\n ~ This software is released under MIT license.\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n<clr-modal\n [clrModalOpen]=\"_open\"\n (clrModalOpenChange)=\"handleModalOpen($event)\"\n [clrModalCloseButtonAriaLabel]=\"closeButtonAriaLabel\"\n [clrModalSize]=\"size\"\n [clrModalSkipAnimation]=\"skipAnimation\"\n [clrModalStaticBackdrop]=\"staticBackdrop\"\n [clrModalLabelledById]=\"labelledById\"\n [clrModalPreventClose]=\"preventClose\"\n [clrModalClosable]=\"closable\"\n (clrModalAlternateClose)=\"altClose.emit($event)\"\n [clrModalOverrideScrollService]=\"true\"\n>\n @if (clrSidePanelPinnable) {\n <button\n type=\"button\"\n [attr.aria-label]=\"commonStrings.keys.sidePanelPin\"\n class=\"leading-button pinnable\"\n (click)=\"togglePinned()\"\n >\n <cds-icon [shape]=\"pinned ? 'unpin' : 'pin'\"></cds-icon>\n </button>\n }\n <div class=\"modal-title\"><ng-content select=\".side-panel-title\"></ng-content></div>\n <div class=\"modal-body\"><ng-content select=\".side-panel-body\"></ng-content></div>\n <div class=\"modal-footer\"><ng-content select=\".side-panel-footer\"></ng-content></div>\n</clr-modal>\n" }]
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: ClrModalConfigurationService }, { type: i1.ClrCommonStringsService }], propDecorators: { openChange: [{
type: Output,
args: ['clrSidePanelOpenChange']
}], closeButtonAriaLabel: [{
type: Input,
args: ['clrSidePanelCloseButtonAriaLabel']
}], skipAnimation: [{
type: Input,
args: ['clrSidePanelSkipAnimation']
}], labelledById: [{
type: Input,
args: ['clrSidePanelLabelledById']
}], staticBackdrop: [{
type: Input,
args: ['clrSidePanelStaticBackdrop']
}], closable: [{
type: Input,
args: ['clrSidePanelClosable']
}], preventClose: [{
type: Input,
args: ['clrSidePanelPreventClose']
}], altClose: [{
type: Output,
args: ['clrSidePanelAlternateClose']
}], _open: [{
type: Input,
args: ['clrSidePanelOpen']
}], size: [{
type: Input,
args: ['clrSidePanelSize']
}], position: [{
type: Input,
args: ['clrSidePanelPosition']
}], pinned: [{
type: Input,
args: ['clrSidePanelPinned']
}], clrSidePanelBackdrop: [{
type: Input
}], clrSidePanelPinnable: [{
type: Input
}], modal: [{
type: ViewChild,
args: [ClrModal]
}], bottomPositionCssClass: [{
type: HostBinding,
args: ['class.side-panel-bottom']
}], documentClick: [{
type: HostListener,
args: ['document:pointerup', ['$event']]
}] } });
/*
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
* This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project.
*/
const CLR_SIDEPANEL_DIRECTIVES = [ClrSidePanel];
class ClrSidePanelModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrSidePanelModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.3", ngImport: i0, type: ClrSidePanelModule, declarations: [ClrSidePanel], imports: [CommonModule, CdkTrapFocusModule, ClrIcon, ClrModalModule], exports: [ClrSidePanel, ClrModalModule, ClrIcon] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrSidePanelModule, imports: [CommonModule, CdkTrapFocusModule, ClrIcon, ClrModalModule, ClrModalModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: ClrSidePanelModule, decorators: [{
type: NgModule,
args: [{
imports: [CommonModule, CdkTrapFocusModule, ClrIcon, ClrModalModule],
declarations: [CLR_SIDEPANEL_DIRECTIVES],
exports: [CLR_SIDEPANEL_DIRECTIVES, ClrModalModule, ClrIcon],
}]
}] });
/*
* Copyright (c) 2016-2026 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
* This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project.
*/
/**
* Generated bundle index. Do not edit.
*/
export { CLR_MODAL_DIRECTIVES, CLR_SIDEPANEL_DIRECTIVES, ClrModal, ClrModalBody, ClrModalConfigurationService, ClrModalHostComponent, ClrModalModule, ClrSidePanel, ClrSidePanelModule, ModalStackService };
//# sourceMappingURL=clr-angular-modal.mjs.map