carbon-components-angular
Version:
Next generation components
1,039 lines (1,020 loc) • 44.1 kB
JavaScript
import * as i0 from '@angular/core';
import { EventEmitter, Directive, Output, Input, inject, EnvironmentInjector, Injector, Injectable, Component, ViewChild, Inject, HostListener, HostBinding, Optional, NgModule } from '@angular/core';
import * as i1$1 from '@angular/common';
import { DOCUMENT, CommonModule } from '@angular/common';
import * as i3 from 'carbon-components-angular/forms';
import { ButtonModule } from 'carbon-components-angular/forms';
import { cycleTabs, getFocusElementList } from 'carbon-components-angular/common';
import { tap, delay } from 'rxjs/operators';
import * as i1 from 'carbon-components-angular/placeholder';
import { PlaceholderModule } from 'carbon-components-angular/placeholder';
import * as i1$2 from 'carbon-components-angular/i18n';
import { I18nModule } from 'carbon-components-angular/i18n';
import * as i4 from 'carbon-components-angular/icon';
import { IconModule } from 'carbon-components-angular/icon';
import { ExperimentalModule } from 'carbon-components-angular/experimental';
/**
* Extend `BaseModal` in your custom modal implementations to ensure consistent close behavior.
*
* `ModalService` depends on the `close` event to correctly clean up the component.
*/
class BaseModal {
constructor() {
/**
* Base event emitter to propagate close events
*/
this.close = new EventEmitter();
/**
* Controls the open state of the modal
*/
this.open = false;
}
/**
* Default method to handle closing the modal
*/
closeModal() {
this.close.emit();
}
}
BaseModal.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: BaseModal, deps: [], target: i0.ɵɵFactoryTarget.Directive });
BaseModal.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.3.0", type: BaseModal, selector: "[cdsBaseModal], [ibmBaseModal]", inputs: { open: "open" }, outputs: { close: "close" }, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: BaseModal, decorators: [{
type: Directive,
args: [{
selector: "[cdsBaseModal], [ibmBaseModal]"
}]
}], propDecorators: { close: [{
type: Output
}], open: [{
type: Input
}] } });
/**
* Modal service handles instantiating and destroying modal instances.
* Uses PlaceholderService to track open instances, and for it's placeholder view reference.
*/
class BaseModalService {
/**
* Creates an instance of `ModalService`.
*/
constructor(placeholderService) {
this.placeholderService = placeholderService;
/**
* Current module/component injection enviornment
* Allows modules to use providers from calling component
*
* Root Module/
* └── Lazy loaded Feature Module/
* ├── Provides Service & imports modules
* ├── Modal component (component that extends base component)
* └── Modal component launcher (dynamically creates modal component)
*
* Passing EnvironmentInjector in `createComponent` will look for provider declaration in feature
* module instead of root module. This is required to pass correct context in a lazy-loaded applications.
* Services injected in root, will also be available as feature module enviornment will also hierarchically inherit
* the root services.
*/
this.environment = inject(EnvironmentInjector);
}
/**
* Creates and renders the modal component that is passed in.
* `inputs` is an optional parameter of `data` that can be passed to the `Modal` component.
*/
create(data) {
let defaults = { inputs: {} };
data = Object.assign({}, defaults, data);
const inputProviders = Object.keys(data.inputs).map(inputName => ({
provide: inputName,
useValue: data.inputs[inputName]
}));
const injector = Injector.create({ providers: inputProviders });
const component = this.placeholderService.createComponent(data.component, injector, undefined, this.environment);
let focusedElement = document.activeElement;
setTimeout(() => {
component.instance.open = true;
});
component["previouslyFocusedElement"] = focusedElement; // used to return focus to previously focused element
component.instance.close.pipe(
// trigger the close animation
tap(() => {
component.instance.open = false;
}),
// delay closing by an arbitrary amount to allow the animation to finish
delay(240)).subscribe(() => {
this.placeholderService.destroyComponent(component);
// filter out our component
BaseModalService.modalList = BaseModalService.modalList.filter(c => c !== component);
});
component.onDestroy(() => {
focusedElement.focus();
});
BaseModalService.modalList.push(component);
return component;
}
/**
* Destroys the modal on the supplied index.
* When called without parameters it destroys the most recently created/top most modal.
*/
destroy(index = -1) {
// return if nothing to destroy because it's already destroyed
if (index >= BaseModalService.modalList.length || BaseModalService.modalList.length === 0) {
return;
}
// on negative index destroy the last on the list (top modal)
if (index < 0) {
index = BaseModalService.modalList.length - 1;
}
// Let animation finish before component is removed
setTimeout(() => {
if (BaseModalService.modalList[index]) {
this.placeholderService.destroyComponent(BaseModalService.modalList[index]);
BaseModalService.modalList.splice(index, 1);
}
}, 240);
}
}
// track all our open modals
BaseModalService.modalList = [];
BaseModalService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: BaseModalService, deps: [{ token: i1.PlaceholderService }], target: i0.ɵɵFactoryTarget.Injectable });
BaseModalService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: BaseModalService });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: BaseModalService, decorators: [{
type: Injectable
}], ctorParameters: function () { return [{ type: i1.PlaceholderService }]; } });
/**
* Component for the overlay object that acts as a backdrop to the `Modal` component.
*
* The main purpose for this component is to be able to handle click events that fall outside
* the bounds of the `Modal` component.
*/
class Overlay {
constructor() {
/**
* Classification of the modal.
*/
this.theme = "default";
this.open = false;
/**
* To emit the event where the user selects the overlay behind the `Modal`.
*/
this.overlaySelect = new EventEmitter();
}
/**
* Handles the user clicking on the `Overlay` which resides outside the `Modal` object.
*/
overlayClick(event) {
if (event.target !== this.overlay.nativeElement) {
return;
}
event.stopPropagation();
this.overlaySelect.emit(event);
}
}
Overlay.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Overlay, deps: [], target: i0.ɵɵFactoryTarget.Component });
Overlay.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: Overlay, selector: "cds-overlay, ibm-overlay", inputs: { theme: "theme", open: "open" }, outputs: { overlaySelect: "overlaySelect" }, viewQueries: [{ propertyName: "overlay", first: true, predicate: ["overlay"], descendants: true, static: true }], ngImport: i0, template: `
<section
class="cds--modal cds--modal-tall"
[ngClass]="{
'cds--modal--danger': theme === 'danger',
'is-visible': open
}"
(click)="overlayClick($event)"
#overlay>
<ng-content></ng-content>
</section>
`, isInline: true, dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Overlay, decorators: [{
type: Component,
args: [{
selector: "cds-overlay, ibm-overlay",
template: `
<section
class="cds--modal cds--modal-tall"
[ngClass]="{
'cds--modal--danger': theme === 'danger',
'is-visible': open
}"
(click)="overlayClick($event)"
#overlay>
<ng-content></ng-content>
</section>
`
}]
}], propDecorators: { theme: [{
type: Input
}], open: [{
type: Input
}], overlaySelect: [{
type: Output
}], overlay: [{
type: ViewChild,
args: ["overlay", { static: true }]
}] } });
/**
* Component to create modals for presenting content.
*
* [See demo](../../?path=/story/components-modal--basic)
*
* Using a modal in your application requires `cds-placeholder` which would generally be
* placed near the end of your app component template (app.component.ts or app.component.html) as:
*
```html
<cds-placeholder></cds-placeholder>
```
*
* A more complete example for `Modal` is given as follows:
*
* Example modal definition:
*
```typescript
@Component({
selector: "app-sample-modal",
template: `
<cds-modal size="xl" (overlaySelected)="closeModal()">
<cds-modal-header (closeSelect)="closeModal()">Header text</cds-modal-header>
<section class="modal-body">
<h1>Sample modal works.</h1>
<button class="btn--icon-link" nPopover="Hello there" title="Popover title" placement="right" appendInline="true">
<svg cdsIcon="info" size="sm"></svg>
</button>
{{modalText}}
</section>
<cds-modal-footer><button cdsButton="primary" (click)="closeModal()">Close</button></cds-modal-footer>
</cds-modal>`,
styleUrls: ["./sample-modal.component.scss"]
})
export class SampleModal extends BaseModal {
modalText: string;
constructor(protected injector: Injector) {
super();
this.modalText = this.injector.get("modalText");
}
}
```
*
* Example of opening the modal:
*
```typescript
@Component({
selector: "app-modal-demo",
template: `
<button cdsButton="primary" (click)="openModal('drill')">Drill-down modal</button>
<cds-placeholder></cds-placeholder>`
})
export class ModalDemo {
openModal() {
this.modalService.create({component: SampleModal, inputs: {modalText: "Hello universe."}});
}
}
```
*/
class Modal {
/**
* Creates an instance of `Modal`.
*/
constructor(modalService, document, renderer) {
this.modalService = modalService;
this.document = document;
this.renderer = renderer;
/**
* Size of the modal to display.
*/
this.size = "md";
/**
* Classification of the modal.
*/
this.theme = "default";
/**
* Label for the modal.
*/
this.ariaLabel = "default";
/**
* Controls the visibility of the modal when used directly in a template
*/
this.open = false;
/**
* Specify whether the modal contains scrolling content. This property overrides the automatic
* detection of the existence of scrolling content. Set this property to `true` to force
* overflow indicator to show up or to `false` to force overflow indicator to disappear.
* It is set to `null` by default which indicates not to override automatic detection.
*/
this.hasScrollingContent = null;
/**
* Emits event when click occurs within `n-overlay` element. This is to track click events occurring outside bounds of the `Modal` object.
*/
this.overlaySelected = new EventEmitter();
/**
* To emit the closing event of the modal window.
*/
this.close = new EventEmitter();
/**
* An element should have 'modal-primary-focus' as an attribute to receive initial focus within the `Modal` component.
*/
this.selectorPrimaryFocus = "[modal-primary-focus]";
}
ngOnChanges({ open, hasScrollingContent }) {
if (open) {
if (open.currentValue) {
// `100` is just enough time to allow the modal
// to become visible, so that we can set focus
setTimeout(() => this.focusInitialElement(), 100);
// Prevent scrolling on open
this.renderer.addClass(this.document.body, "cds--body--with-modal-open");
}
else if (!open.currentValue) {
// Enable scrolling on close
this.renderer.removeClass(this.document.body, "cds--body--with-modal-open");
}
else if (this.trigger) {
this.trigger.focus();
}
}
if (hasScrollingContent) {
this.updateScrollbar();
}
}
/**
* Set document focus to be on the modal component after it is initialized.
*/
ngAfterViewInit() {
this.focusInitialElement();
this.updateScrollbar();
}
/**
* Handle keyboard events to close modal and tab through the content within the modal.
*/
handleKeyboardEvent(event) {
switch (event.key) {
case "Escape": {
event.stopImmediatePropagation(); // prevents events being fired for multiple modals if more than 2 open
// Manually close modal
this.open = false;
this.close.emit();
this.modalService.destroy(); // destroy top (latest) modal
break;
}
case "Tab": {
cycleTabs(event, this.modal.nativeElement);
break;
}
}
}
/**
* This detects whether or not the modal contains scrolling content.
*
* To force trigger a detection (ie. on window resize), change or reset the value of the modal content.
*
* Use the `hasScrollingContent` input to manually override the overflow indicator.
*/
get shouldShowScrollbar() {
const modalContent = this.modal ? this.modal.nativeElement.querySelector(".cds--modal-content") : null;
if (modalContent) {
// get rounded value from height to match integer returned from scrollHeight
const modalContentHeight = Math.ceil(modalContent.getBoundingClientRect().height);
const modalContentScrollHeight = modalContent.scrollHeight;
return modalContentScrollHeight > modalContentHeight;
}
else {
return false;
}
}
// Remove class preventing scrolling
ngOnDestroy() {
this.renderer.removeClass(this.document.body, "cds--body--with-modal-open");
}
focusInitialElement() {
const primaryFocusElement = this.modal.nativeElement.querySelector(this.selectorPrimaryFocus);
if (primaryFocusElement && primaryFocusElement.focus) {
setTimeout(() => primaryFocusElement.focus());
}
else if (getFocusElementList(this.modal.nativeElement).length > 0) {
setTimeout(() => getFocusElementList(this.modal.nativeElement)[0].focus());
}
else {
setTimeout(() => this.modal.nativeElement.focus());
}
}
updateScrollbar() {
const modalContent = this.modal ? this.modal.nativeElement.querySelector(".cds--modal-content") : null;
const showScrollbar = this.hasScrollingContent !== null ? this.hasScrollingContent : this.shouldShowScrollbar;
if (modalContent) {
if (showScrollbar) {
this.renderer.addClass(modalContent, "cds--modal-scroll-content");
}
else {
this.renderer.removeClass(modalContent, "cds--modal-scroll-content");
}
}
}
}
Modal.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Modal, deps: [{ token: BaseModalService }, { token: DOCUMENT }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
Modal.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: Modal, selector: "cds-modal, ibm-modal", inputs: { size: "size", theme: "theme", ariaLabel: "ariaLabel", open: "open", trigger: "trigger", hasScrollingContent: "hasScrollingContent" }, outputs: { overlaySelected: "overlaySelected", close: "close" }, host: { listeners: { "keydown": "handleKeyboardEvent($event)" } }, viewQueries: [{ propertyName: "modal", first: true, predicate: ["modal"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: `
<cds-overlay
[theme]="theme"
[open]="open"
(overlaySelect)="overlaySelected.emit()">
<div
class="cds--modal-container"
[ngClass]="{
'cds--modal-container--xs': size === 'xs',
'cds--modal-container--sm': size === 'sm',
'cds--modal-container--md': size === 'md',
'cds--modal-container--lg': size === 'lg'
}"
role="dialog"
aria-modal="true"
style="z-index:1;"
[attr.aria-label]="ariaLabel"
#modal>
<ng-content></ng-content>
</div>
</cds-overlay>
`, isInline: true, dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: Overlay, selector: "cds-overlay, ibm-overlay", inputs: ["theme", "open"], outputs: ["overlaySelect"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Modal, decorators: [{
type: Component,
args: [{
selector: "cds-modal, ibm-modal",
template: `
<cds-overlay
[theme]="theme"
[open]="open"
(overlaySelect)="overlaySelected.emit()">
<div
class="cds--modal-container"
[ngClass]="{
'cds--modal-container--xs': size === 'xs',
'cds--modal-container--sm': size === 'sm',
'cds--modal-container--md': size === 'md',
'cds--modal-container--lg': size === 'lg'
}"
role="dialog"
aria-modal="true"
style="z-index:1;"
[attr.aria-label]="ariaLabel"
#modal>
<ng-content></ng-content>
</div>
</cds-overlay>
`
}]
}], ctorParameters: function () {
return [{ type: BaseModalService }, { type: Document, decorators: [{
type: Inject,
args: [DOCUMENT]
}] }, { type: i0.Renderer2 }];
}, propDecorators: { size: [{
type: Input
}], theme: [{
type: Input
}], ariaLabel: [{
type: Input
}], open: [{
type: Input
}], trigger: [{
type: Input
}], hasScrollingContent: [{
type: Input
}], overlaySelected: [{
type: Output
}], close: [{
type: Output
}], modal: [{
type: ViewChild,
args: ["modal", { static: true }]
}], handleKeyboardEvent: [{
type: HostListener,
args: ["keydown", ["$event"]]
}] } });
/**
* ***Inputs***
* ```html
* <cds-modal-header>Header text</cds-modal-header>
* ```
*
* ***Outputs***
* ```html
* <cds-modal-header (closeSelect)="closeModal()">Header text</cds-modal-header>
* ```
*/
class ModalHeader {
constructor(i18n) {
this.i18n = i18n;
/**
* @deprecated since v5
* Sets the style on the modal heading based on its category.
*/
this.theme = "default";
/**
* Accessible label for the header close button.
* Defaults to the `MODAL.CLOSE` value from the i18n service.
*/
this.closeLabel = this.i18n.get().MODAL.CLOSE;
/**
* Set to `false` to hide the close button.
*/
this.showCloseButton = true;
/**
* To emit the event of clicking on the close icon within the modal.
*/
this.closeSelect = new EventEmitter();
this.buttonNgClass = {
"cds--modal-close": true
};
this.buttonAttributes = {
"aria-label": this.i18n.get().MODAL.CLOSE
};
}
/**
* Handles click for the close icon button within the `Modal`.
*/
onClose() {
this.closeSelect.emit();
}
}
ModalHeader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalHeader, deps: [{ token: i1$2.I18n }], target: i0.ɵɵFactoryTarget.Component });
ModalHeader.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: ModalHeader, selector: "cds-modal-header, ibm-modal-header", inputs: { theme: "theme", closeLabel: "closeLabel", showCloseButton: "showCloseButton" }, outputs: { closeSelect: "closeSelect" }, ngImport: i0, template: `
<header class="cds--modal-header {{theme}}">
<ng-content></ng-content>
<div class="cds--modal-close-button">
<cds-icon-button
*ngIf="showCloseButton"
type="button"
[buttonNgClass]="buttonNgClass"
[buttonAttributes]="buttonAttributes"
align="left"
[description]="closeLabel"
(click)="onClose()">
<svg cdsIcon="close" size="20" class="cds--modal-close__icon"></svg>
</cds-icon-button>
</div>
</header>
`, isInline: true, dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.IconButton, selector: "cds-icon-button, ibm-icon-button", inputs: ["buttonNgClass", "buttonAttributes", "buttonId", "kind", "size", "type", "isExpressive", "disabled", "description", "showTooltipWhenDisabled"], outputs: ["click", "focus", "blur", "tooltipClick"] }, { kind: "directive", type: i4.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalHeader, decorators: [{
type: Component,
args: [{
selector: "cds-modal-header, ibm-modal-header",
template: `
<header class="cds--modal-header {{theme}}">
<ng-content></ng-content>
<div class="cds--modal-close-button">
<cds-icon-button
*ngIf="showCloseButton"
type="button"
[buttonNgClass]="buttonNgClass"
[buttonAttributes]="buttonAttributes"
align="left"
[description]="closeLabel"
(click)="onClose()">
<svg cdsIcon="close" size="20" class="cds--modal-close__icon"></svg>
</cds-icon-button>
</div>
</header>
`
}]
}], ctorParameters: function () { return [{ type: i1$2.I18n }]; }, propDecorators: { theme: [{
type: Input
}], closeLabel: [{
type: Input
}], showCloseButton: [{
type: Input
}], closeSelect: [{
type: Output
}] } });
class ModalFooter {
}
ModalFooter.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalFooter, deps: [], target: i0.ɵɵFactoryTarget.Component });
ModalFooter.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: ModalFooter, selector: "cds-modal-footer, ibm-modal-footer", ngImport: i0, template: `
<footer class="cds--modal-footer">
<ng-content></ng-content>
</footer>
`, isInline: true });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalFooter, decorators: [{
type: Component,
args: [{
selector: "cds-modal-footer, ibm-modal-footer",
template: `
<footer class="cds--modal-footer">
<ng-content></ng-content>
</footer>
`
}]
}] });
class ModalContent {
constructor() {
this.modalContentClass = true;
/**
* Provide whether the modal content has a form element.
* If `true` is used here, non-form child content should have `cds--modal-content__regular-content` class.
*/
this.hasForm = false;
}
}
ModalContent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalContent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
ModalContent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.3.0", type: ModalContent, selector: "[cdsModalContent], [ibmModalContent]", inputs: { hasForm: "hasForm" }, host: { properties: { "class.cds--modal-content": "this.modalContentClass", "class.cds--modal-content--with-form": "this.hasForm" } }, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalContent, decorators: [{
type: Directive,
args: [{
selector: "[cdsModalContent], [ibmModalContent]"
}]
}], propDecorators: { modalContentClass: [{
type: HostBinding,
args: ["class.cds--modal-content"]
}], hasForm: [{
type: HostBinding,
args: ["class.cds--modal-content--with-form"]
}, {
type: Input
}] } });
class ModalHeaderHeading {
constructor() {
this.modalHeaderHeadingClass = true;
}
}
ModalHeaderHeading.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalHeaderHeading, deps: [], target: i0.ɵɵFactoryTarget.Directive });
ModalHeaderHeading.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.3.0", type: ModalHeaderHeading, selector: "[cdsModalHeaderHeading], [ibmModalHeaderHeading]", host: { properties: { "class.cds--modal-header__heading": "this.modalHeaderHeadingClass" } }, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalHeaderHeading, decorators: [{
type: Directive,
args: [{
selector: "[cdsModalHeaderHeading], [ibmModalHeaderHeading]"
}]
}], propDecorators: { modalHeaderHeadingClass: [{
type: HostBinding,
args: ["class.cds--modal-header__heading"]
}] } });
class ModalHeaderLabel {
constructor() {
this.modalHeaderLabelClass = true;
}
}
ModalHeaderLabel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalHeaderLabel, deps: [], target: i0.ɵɵFactoryTarget.Directive });
ModalHeaderLabel.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.3.0", type: ModalHeaderLabel, selector: "[cdsModalHeaderLabel], [ibmModalHeaderLabel]", host: { properties: { "class.cds--modal-header__label": "this.modalHeaderLabelClass" } }, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalHeaderLabel, decorators: [{
type: Directive,
args: [{
selector: "[cdsModalHeaderLabel], [ibmModalHeaderLabel]"
}]
}], propDecorators: { modalHeaderLabelClass: [{
type: HostBinding,
args: ["class.cds--modal-header__label"]
}] } });
/**
* Component to create standard modals for presenting content or asking for user's input.
* It can show as a passive modal showing only text or show as a transactional modal with
* multiple buttons for different actions for the user to choose from.
*
* Using a modal in your application requires `cds-placeholder` which would generally be
* placed near the end of your app component template (app.component.ts or app.component.html) as:
*
* ```html
* <cds-placeholder></cds-placeholder>
* ```
*
* Example of opening the modal:
*
* ```typescript
* \@Component({
* selector: "app-modal-demo",
* template: `
* <button class="btn--primary" (click)="openModal()">Open modal</button>
* <cds-placeholder></cds-placeholder>`
* })
* export class ModalDemo {
* openModal() {
* this.modalService.show({
* modalType: "default",
* label: "optional header text",
* title: "Modal title",
* text: "Modal text",
* buttons: [{
* text: "Button text",
* type: "primary",
* click: clickFunction
* }]
* });
* }
* }
* ```
*/
class AlertModal extends BaseModal {
/**
* Creates an instance of `AlertModal`.
*/
constructor(type = "default", label, title, content, size, hasScrollingContent = null, buttons = [], onClose, showCloseButton = true) {
super();
this.type = type;
this.label = label;
this.title = title;
this.content = content;
this.size = size;
this.hasScrollingContent = hasScrollingContent;
this.buttons = buttons;
this.onClose = onClose;
this.showCloseButton = showCloseButton;
for (let i = 0; i < this.buttons.length; i++) {
const button = this.buttons[i];
if (!button.id) {
button.id = `alert-modal-button-${i}`;
}
if (!button.type) {
button.type = "secondary";
}
}
}
ngAfterViewInit() {
if (!this.modalContent) {
return false;
}
const element = this.modalContent.nativeElement;
if (element.scrollHeight > element.clientHeight) {
element.tabIndex = 0;
}
else {
element.tabIndex = -1;
}
}
buttonClicked(buttonIndex) {
const button = this.buttons[buttonIndex];
if (button.click) {
button.click();
}
this.closeModal();
}
dismissModal(trigger) {
if (this.onClose && this.onClose(trigger) === false) {
return;
}
this.closeModal();
}
}
AlertModal.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: AlertModal, deps: [{ token: "type", optional: true }, { token: "label", optional: true }, { token: "title", optional: true }, { token: "content", optional: true }, { token: "size", optional: true }, { token: "hasScrollingContent", optional: true }, { token: "buttons", optional: true }, { token: "close", optional: true }, { token: "showCloseButton", optional: true }], target: i0.ɵɵFactoryTarget.Component });
AlertModal.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: AlertModal, selector: "cds-alert-modal, ibm-alert-modal", viewQueries: [{ propertyName: "modalContent", first: true, predicate: ["modalContent"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: `
<cds-modal
[size]="size"
[theme]="type"
[ariaLabel]="title"
[hasScrollingContent]="hasScrollingContent"
[open]="open"
(overlaySelected)="dismissModal('overlay')">
<cds-modal-header (closeSelect)="dismissModal('close')" [showCloseButton]="showCloseButton">
<p cdsModalHeaderLabel class="cds--type-delta">{{label}}</p>
<p cdsModalHeaderHeading class="cds--type-beta">{{title}}</p>
</cds-modal-header>
<div cdsModalContent #modalContent>
<p [innerHTML]="content"></p>
</div>
<cds-modal-footer *ngIf="buttons.length > 0">
<ng-container *ngFor="let button of buttons; let i = index">
<button
[cdsButton]="button.type"
(click)="buttonClicked(i)"
[id]="button.id"
[attr.modal-primary-focus]="(button.type.indexOf('primary') !== -1 ? '' : null)">
{{button.text}}
</button>
</ng-container>
</cds-modal-footer>
</cds-modal>
`, isInline: true, dependencies: [{ kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.Button, selector: "[cdsButton], [ibmButton]", inputs: ["ibmButton", "cdsButton", "size", "skeleton", "iconOnly", "isExpressive"] }, { kind: "component", type: Modal, selector: "cds-modal, ibm-modal", inputs: ["size", "theme", "ariaLabel", "open", "trigger", "hasScrollingContent"], outputs: ["overlaySelected", "close"] }, { kind: "component", type: ModalHeader, selector: "cds-modal-header, ibm-modal-header", inputs: ["theme", "closeLabel", "showCloseButton"], outputs: ["closeSelect"] }, { kind: "component", type: ModalFooter, selector: "cds-modal-footer, ibm-modal-footer" }, { kind: "directive", type: ModalContent, selector: "[cdsModalContent], [ibmModalContent]", inputs: ["hasForm"] }, { kind: "directive", type: ModalHeaderHeading, selector: "[cdsModalHeaderHeading], [ibmModalHeaderHeading]" }, { kind: "directive", type: ModalHeaderLabel, selector: "[cdsModalHeaderLabel], [ibmModalHeaderLabel]" }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: AlertModal, decorators: [{
type: Component,
args: [{
selector: "cds-alert-modal, ibm-alert-modal",
template: `
<cds-modal
[size]="size"
[theme]="type"
[ariaLabel]="title"
[hasScrollingContent]="hasScrollingContent"
[open]="open"
(overlaySelected)="dismissModal('overlay')">
<cds-modal-header (closeSelect)="dismissModal('close')" [showCloseButton]="showCloseButton">
<p cdsModalHeaderLabel class="cds--type-delta">{{label}}</p>
<p cdsModalHeaderHeading class="cds--type-beta">{{title}}</p>
</cds-modal-header>
<div cdsModalContent #modalContent>
<p [innerHTML]="content"></p>
</div>
<cds-modal-footer *ngIf="buttons.length > 0">
<ng-container *ngFor="let button of buttons; let i = index">
<button
[cdsButton]="button.type"
(click)="buttonClicked(i)"
[id]="button.id"
[attr.modal-primary-focus]="(button.type.indexOf('primary') !== -1 ? '' : null)">
{{button.text}}
</button>
</ng-container>
</cds-modal-footer>
</cds-modal>
`
}]
}], ctorParameters: function () {
return [{ type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: ["type"]
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: ["label"]
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: ["title"]
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: ["content"]
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: ["size"]
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: ["hasScrollingContent"]
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: ["buttons"]
}] }, { type: Function, decorators: [{
type: Optional
}, {
type: Inject,
args: ["close"]
}] }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: ["showCloseButton"]
}] }];
}, propDecorators: { modalContent: [{
type: ViewChild,
args: ["modalContent", { static: true }]
}] } });
var AlertModalType;
(function (AlertModalType) {
AlertModalType["default"] = "default";
AlertModalType["danger"] = "danger";
})(AlertModalType || (AlertModalType = {}));
var ModalButtonType;
(function (ModalButtonType) {
ModalButtonType["primary"] = "primary";
ModalButtonType["secondary"] = "secondary";
ModalButtonType["tertiary"] = "tertiary";
ModalButtonType["ghost"] = "ghost";
ModalButtonType["danger"] = "danger";
ModalButtonType["danger_primary"] = "danger--primary";
})(ModalButtonType || (ModalButtonType = {}));
/**
* Extends Base Modal Service to create Alert Modal with a function call. Placed in a seperate service
* to prevent remote scoping (NG3003) which has side effects. Hence, import cycles are not allowed when
* compilationMode is set to `partial`.
*
*
* Modal service handles instantiating and destroying modal instances.
* Uses PlaceholderService to track open instances, and for it's placeholder view reference.
*/
class ModalService extends BaseModalService {
/**
* Creates an instance of `ModalService`.
*/
constructor(placeholderService) {
super(placeholderService);
this.placeholderService = placeholderService;
}
/**
* Creates and renders a new alert modal component.
* @param data You can pass in:
* `type` - "default" | "danger" = "default",
* `label` - a label shown over the title,
* `title` - modal's title,
* `content` - modal's content, could include HTML tags.
* `buttons` is an array of objects
* `close` custom close function
* ```
* {
* text: "Button text",
* type: "primary" | "secondary" | "tertiary" | "ghost" | "danger" | "danger--primary" = "primary",
* click: clickFunction,
* }
* ```
*/
show(data) {
return this.create({
component: AlertModal,
inputs: {
type: data.type,
label: data.label,
title: data.title,
content: data.content,
hasScrollingContent: data.hasScrollingContent !== undefined ? data.hasScrollingContent : null,
size: data.size,
buttons: data.buttons || [],
close: data.close || (() => { }),
showCloseButton: data.showCloseButton
}
});
}
}
ModalService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalService, deps: [{ token: i1.PlaceholderService }], target: i0.ɵɵFactoryTarget.Injectable });
ModalService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalService });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalService, decorators: [{
type: Injectable
}], ctorParameters: function () { return [{ type: i1.PlaceholderService }]; } });
class ModalContentText {
constructor() {
this.modalContentTextClass = true;
}
}
ModalContentText.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalContentText, deps: [], target: i0.ɵɵFactoryTarget.Directive });
ModalContentText.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.3.0", type: ModalContentText, selector: "[cdsModalContentText], [ibmModalContentText]", host: { properties: { "class.cds--modal-content__text": "this.modalContentTextClass" } }, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalContentText, decorators: [{
type: Directive,
args: [{
selector: "[cdsModalContentText], [ibmModalContentText]"
}]
}], propDecorators: { modalContentTextClass: [{
type: HostBinding,
args: ["class.cds--modal-content__text"]
}] } });
// modules
class ModalModule {
}
ModalModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
ModalModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: ModalModule, declarations: [AlertModal,
Modal,
ModalHeader,
ModalFooter,
Overlay,
ModalContent,
ModalContentText,
ModalHeaderHeading,
ModalHeaderLabel,
BaseModal], imports: [CommonModule,
ButtonModule,
I18nModule,
PlaceholderModule,
ExperimentalModule,
IconModule], exports: [AlertModal,
Modal,
ModalHeader,
ModalFooter,
ModalContent,
ModalContentText,
ModalHeaderHeading,
ModalHeaderLabel,
BaseModal] });
ModalModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalModule, providers: [BaseModalService, ModalService], imports: [CommonModule,
ButtonModule,
I18nModule,
PlaceholderModule,
ExperimentalModule,
IconModule] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: ModalModule, decorators: [{
type: NgModule,
args: [{
declarations: [
AlertModal,
Modal,
ModalHeader,
ModalFooter,
Overlay,
ModalContent,
ModalContentText,
ModalHeaderHeading,
ModalHeaderLabel,
BaseModal
],
exports: [
AlertModal,
Modal,
ModalHeader,
ModalFooter,
ModalContent,
ModalContentText,
ModalHeaderHeading,
ModalHeaderLabel,
BaseModal
],
providers: [BaseModalService, ModalService],
imports: [
CommonModule,
ButtonModule,
I18nModule,
PlaceholderModule,
ExperimentalModule,
IconModule
]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { AlertModal, AlertModalType, BaseModal, BaseModalService, Modal, ModalButtonType, ModalContent, ModalContentText, ModalFooter, ModalHeader, ModalHeaderHeading, ModalHeaderLabel, ModalModule, ModalService, Overlay };
//# sourceMappingURL=carbon-components-angular-modal.mjs.map