@ng-bootstrap/ng-bootstrap
Version:
Angular powered Bootstrap
808 lines (797 loc) • 34.2 kB
JavaScript
import * as i0 from '@angular/core';
import { inject, Injectable, ElementRef, NgZone, Injector, ChangeDetectorRef, afterNextRender, Input, ViewEncapsulation, Component, DOCUMENT, EventEmitter, Output, ViewChild, ApplicationRef, EnvironmentInjector, createComponent, TemplateRef, NgModule } from '@angular/core';
import { NgbConfig } from '@ng-bootstrap/ng-bootstrap/config';
import { Subject, of, zip, fromEvent } from 'rxjs';
import { ngbRunTransition, reflow, isDefined, isPromise, isString, getFocusableBoundaryElements, ScrollBar, ngbFocusTrap, ContentRef } from './_ngb-ngbootstrap-utilities.mjs';
import { takeUntil, filter, tap, switchMap, take } from 'rxjs/operators';
/**
* A configuration service for the [`NgbModal`](#/components/modal/api#NgbModal) service.
*
* You can inject this service, typically in your root component, and customize the values of its properties in
* order to provide default values for all modals used in the application.
*
* @since 3.1.0
*/
class NgbModalConfig {
constructor() {
this._ngbConfig = inject(NgbConfig);
this.backdrop = true;
this.fullscreen = false;
this.keyboard = true;
this.role = 'dialog';
}
get animation() {
return this._animation ?? this._ngbConfig.animation;
}
set animation(animation) {
this._animation = animation;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgbModalConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgbModalConfig, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgbModalConfig, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}] });
const BACKDROP_ATTRIBUTES = ['animation', 'backdropClass'];
class NgbModalBackdrop {
constructor() {
this._nativeElement = inject(ElementRef).nativeElement;
this._zone = inject(NgZone);
this._injector = inject(Injector);
this._cdRef = inject(ChangeDetectorRef);
}
ngOnInit() {
afterNextRender({
mixedReadWrite: () => ngbRunTransition(this._zone, this._nativeElement, (element, animation) => {
if (animation) {
reflow(element);
}
element.classList.add('show');
}, { animation: this.animation, runningTransition: 'continue' }),
}, { injector: this._injector });
}
hide() {
return ngbRunTransition(this._zone, this._nativeElement, ({ classList }) => classList.remove('show'), {
animation: this.animation,
runningTransition: 'stop',
});
}
updateOptions(options) {
BACKDROP_ATTRIBUTES.forEach((optionName) => {
if (isDefined(options[optionName])) {
this[optionName] = options[optionName];
}
});
this._cdRef.markForCheck();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgbModalBackdrop, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.4", type: NgbModalBackdrop, isStandalone: true, selector: "ngb-modal-backdrop", inputs: { animation: "animation", backdropClass: "backdropClass" }, host: { properties: { "class": "\"modal-backdrop\" + (backdropClass ? \" \" + backdropClass : \"\")", "class.show": "!animation", "class.fade": "animation" }, styleAttribute: "z-index: 1055" }, ngImport: i0, template: '', isInline: true, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgbModalBackdrop, decorators: [{
type: Component,
args: [{
selector: 'ngb-modal-backdrop',
encapsulation: ViewEncapsulation.None,
template: '',
host: {
'[class]': '"modal-backdrop" + (backdropClass ? " " + backdropClass : "")',
'[class.show]': '!animation',
'[class.fade]': 'animation',
style: 'z-index: 1055',
},
}]
}], propDecorators: { animation: [{
type: Input
}], backdropClass: [{
type: Input
}] } });
/**
* A reference to the currently opened (active) modal.
*
* Instances of this class can be injected into your component passed as modal content.
* So you can `.update()`, `.close()` or `.dismiss()` the modal window from your component.
*/
class NgbActiveModal {
/**
* Updates options of an opened modal.
*
* @since 14.2.0
*/
update(options) { }
/**
* Closes the modal with an optional `result` value.
*
* The `NgbModalRef.result` promise will be resolved with the provided value.
*/
close(result) { }
/**
* Dismisses the modal with an optional `reason` value.
*
* The `NgbModalRef.result` promise will be rejected with the provided value.
*/
dismiss(reason) { }
}
/**
* A reference to the newly opened modal returned by the `NgbModal.open()` method.
*/
class NgbModalRef {
/**
* Updates options of an opened modal.
*
* @since 14.2.0
*/
update(options) {
this._windowCmptRef.instance.updateOptions(options);
if (this._backdropCmptRef && this._backdropCmptRef.instance) {
this._backdropCmptRef.instance.updateOptions(options);
}
}
/**
* The instance of a component used for the modal content.
*
* When a `TemplateRef` is used as the content or when the modal is closed, will return `undefined`.
*/
get componentInstance() {
if (this._contentRef && this._contentRef.componentRef) {
return this._contentRef.componentRef.instance;
}
}
/**
* The observable that emits when the modal is closed via the `.close()` method.
*
* It will emit the result passed to the `.close()` method.
*
* @since 8.0.0
*/
get closed() {
return this._closed.asObservable().pipe(takeUntil(this._hidden));
}
/**
* The observable that emits when the modal is dismissed via the `.dismiss()` method.
*
* It will emit the reason passed to the `.dismissed()` method by the user, or one of the internal
* reasons like backdrop click or ESC key press.
*
* @since 8.0.0
*/
get dismissed() {
return this._dismissed.asObservable().pipe(takeUntil(this._hidden));
}
/**
* The observable that emits when both modal window and backdrop are closed and animations were finished.
* At this point modal and backdrop elements will be removed from the DOM tree.
*
* This observable will be completed after emitting.
*
* @since 8.0.0
*/
get hidden() {
return this._hidden.asObservable();
}
/**
* The observable that emits when modal is fully visible and animation was finished.
* Modal DOM element is always available synchronously after calling 'modal.open()' service.
*
* This observable will be completed after emitting.
* It will not emit, if modal is closed before open animation is finished.
*
* @since 8.0.0
*/
get shown() {
return this._windowCmptRef.instance.shown.asObservable();
}
constructor(_windowCmptRef, _contentRef, _backdropCmptRef, _beforeDismiss) {
this._windowCmptRef = _windowCmptRef;
this._contentRef = _contentRef;
this._backdropCmptRef = _backdropCmptRef;
this._beforeDismiss = _beforeDismiss;
this._closed = new Subject();
this._dismissed = new Subject();
this._hidden = new Subject();
_windowCmptRef.instance.dismissEvent.subscribe((reason) => {
this.dismiss(reason);
});
this.result = new Promise((resolve, reject) => {
this._resolve = resolve;
this._reject = reject;
});
this.result.then(null, () => { });
}
/**
* Closes the modal with an optional `result` value.
*
* The `NgbMobalRef.result` promise will be resolved with the provided value.
*/
close(result) {
if (this._windowCmptRef) {
this._closed.next(result);
this._resolve(result);
this._removeModalElements();
}
}
_dismiss(reason) {
this._dismissed.next(reason);
this._reject(reason);
this._removeModalElements();
}
/**
* Dismisses the modal with an optional `reason` value.
*
* The `NgbModalRef.result` promise will be rejected with the provided value.
*/
dismiss(reason) {
if (this._windowCmptRef) {
if (!this._beforeDismiss) {
this._dismiss(reason);
}
else {
const dismiss = this._beforeDismiss();
if (isPromise(dismiss)) {
dismiss.then((result) => {
if (result !== false) {
this._dismiss(reason);
}
}, () => { });
}
else if (dismiss !== false) {
this._dismiss(reason);
}
}
}
}
_removeModalElements() {
const windowTransition$ = this._windowCmptRef.instance.hide();
const backdropTransition$ = this._backdropCmptRef ? this._backdropCmptRef.instance.hide() : of(undefined);
// hiding window
windowTransition$.subscribe(() => {
const { nativeElement } = this._windowCmptRef.location;
nativeElement.parentNode.removeChild(nativeElement);
this._windowCmptRef.destroy();
this._contentRef?.viewRef?.destroy();
this._windowCmptRef = null;
this._contentRef = null;
});
// hiding backdrop
backdropTransition$.subscribe(() => {
if (this._backdropCmptRef) {
const { nativeElement } = this._backdropCmptRef.location;
nativeElement.parentNode.removeChild(nativeElement);
this._backdropCmptRef.destroy();
this._backdropCmptRef = null;
}
});
// all done
zip(windowTransition$, backdropTransition$).subscribe(() => {
this._hidden.next();
this._hidden.complete();
});
}
}
var ModalDismissReasons;
(function (ModalDismissReasons) {
ModalDismissReasons[ModalDismissReasons["BACKDROP_CLICK"] = 0] = "BACKDROP_CLICK";
ModalDismissReasons[ModalDismissReasons["ESC"] = 1] = "ESC";
})(ModalDismissReasons || (ModalDismissReasons = {}));
const WINDOW_ATTRIBUTES = [
'animation',
'ariaLabelledBy',
'ariaDescribedBy',
'backdrop',
'centered',
'fullscreen',
'keyboard',
'role',
'scrollable',
'size',
'windowClass',
'modalDialogClass',
];
class NgbModalWindow {
constructor() {
this._document = inject(DOCUMENT);
this._elRef = inject((ElementRef));
this._zone = inject(NgZone);
this._injector = inject(Injector);
this._cdRef = inject(ChangeDetectorRef);
this._closed$ = new Subject();
this._elWithFocus = null; // element that is focused prior to modal opening
this.backdrop = true;
this.keyboard = true;
this.role = 'dialog';
this.dismissEvent = new EventEmitter();
this.shown = new Subject();
this.hidden = new Subject();
}
get fullscreenClass() {
return this.fullscreen === true
? ' modal-fullscreen'
: isString(this.fullscreen)
? ` modal-fullscreen-${this.fullscreen}-down`
: '';
}
dismiss(reason) {
this.dismissEvent.emit(reason);
}
ngOnInit() {
this._elWithFocus = this._document.activeElement;
afterNextRender({ mixedReadWrite: () => this._show() }, { injector: this._injector });
}
ngOnDestroy() {
this._disableEventHandling();
}
hide() {
const { nativeElement } = this._elRef;
const context = { animation: this.animation, runningTransition: 'stop' };
const windowTransition$ = ngbRunTransition(this._zone, nativeElement, () => nativeElement.classList.remove('show'), context);
const dialogTransition$ = ngbRunTransition(this._zone, this._dialogEl.nativeElement, () => { }, context);
const transitions$ = zip(windowTransition$, dialogTransition$);
transitions$.subscribe(() => {
this.hidden.next();
this.hidden.complete();
});
this._disableEventHandling();
this._restoreFocus();
return transitions$;
}
updateOptions(options) {
WINDOW_ATTRIBUTES.forEach((optionName) => {
if (isDefined(options[optionName])) {
this[optionName] = options[optionName];
}
});
this._cdRef.markForCheck();
}
_show() {
const context = { animation: this.animation, runningTransition: 'continue' };
const windowTransition$ = ngbRunTransition(this._zone, this._elRef.nativeElement, (element, animation) => {
if (animation) {
reflow(element);
}
element.classList.add('show');
}, context);
const dialogTransition$ = ngbRunTransition(this._zone, this._dialogEl.nativeElement, () => { }, context);
zip(windowTransition$, dialogTransition$).subscribe(() => {
this.shown.next();
this.shown.complete();
});
this._enableEventHandling();
this._setFocus();
}
_enableEventHandling() {
const { nativeElement } = this._elRef;
this._zone.runOutsideAngular(() => {
fromEvent(nativeElement, 'keydown')
.pipe(takeUntil(this._closed$), filter((e) => e.key === 'Escape'))
.subscribe((event) => {
if (this.keyboard) {
requestAnimationFrame(() => {
if (!event.defaultPrevented) {
this._zone.run(() => this.dismiss(ModalDismissReasons.ESC));
}
});
}
else if (this.backdrop === 'static') {
this._bumpBackdrop();
}
});
// We're listening to 'mousedown' and 'mouseup' to prevent modal from closing when pressing the mouse
// inside the modal dialog and releasing it outside
let preventClose = false;
fromEvent(this._dialogEl.nativeElement, 'mousedown')
.pipe(takeUntil(this._closed$), tap(() => (preventClose = false)), switchMap(() => fromEvent(nativeElement, 'mouseup').pipe(takeUntil(this._closed$), take(1))), filter(({ target }) => nativeElement === target))
.subscribe(() => {
preventClose = true;
});
// We're listening to 'click' to dismiss modal on modal window click, except when:
// 1. clicking on modal dialog itself
// 2. closing was prevented by mousedown/up handlers
// 3. clicking on scrollbar when the viewport is too small and modal doesn't fit (click is not triggered at all)
fromEvent(nativeElement, 'click')
.pipe(takeUntil(this._closed$))
.subscribe(({ target }) => {
if (nativeElement === target) {
if (this.backdrop === 'static') {
this._bumpBackdrop();
}
else if (this.backdrop === true && !preventClose) {
this._zone.run(() => this.dismiss(ModalDismissReasons.BACKDROP_CLICK));
}
}
preventClose = false;
});
});
}
_disableEventHandling() {
this._closed$.next();
}
_setFocus() {
const { nativeElement } = this._elRef;
if (!nativeElement.contains(document.activeElement)) {
const autoFocusable = nativeElement.querySelector(`[ngbAutofocus]`);
const firstFocusable = getFocusableBoundaryElements(nativeElement)[0];
const elementToFocus = autoFocusable || firstFocusable || nativeElement;
elementToFocus.focus();
}
}
_restoreFocus() {
const body = this._document.body;
const elWithFocus = this._elWithFocus;
let elementToFocus;
if (elWithFocus && elWithFocus['focus'] && body.contains(elWithFocus)) {
elementToFocus = elWithFocus;
}
else {
elementToFocus = body;
}
this._zone.runOutsideAngular(() => {
setTimeout(() => elementToFocus.focus());
this._elWithFocus = null;
});
}
_bumpBackdrop() {
if (this.backdrop === 'static') {
ngbRunTransition(this._zone, this._elRef.nativeElement, ({ classList }) => {
classList.add('modal-static');
return () => classList.remove('modal-static');
}, { animation: this.animation, runningTransition: 'continue' });
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgbModalWindow, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.4", type: NgbModalWindow, isStandalone: true, selector: "ngb-modal-window", inputs: { animation: "animation", ariaLabelledBy: "ariaLabelledBy", ariaDescribedBy: "ariaDescribedBy", backdrop: "backdrop", centered: "centered", fullscreen: "fullscreen", keyboard: "keyboard", role: "role", scrollable: "scrollable", size: "size", windowClass: "windowClass", modalDialogClass: "modalDialogClass" }, outputs: { dismissEvent: "dismiss" }, host: { attributes: { "tabindex": "-1" }, properties: { "class": "\"modal d-block\" + (windowClass ? \" \" + windowClass : \"\")", "class.fade": "animation", "attr.aria-modal": "true", "attr.aria-labelledby": "ariaLabelledBy", "attr.aria-describedby": "ariaDescribedBy", "attr.role": "role" } }, viewQueries: [{ propertyName: "_dialogEl", first: true, predicate: ["dialog"], descendants: true, static: true }], ngImport: i0, template: `
<div
#dialog
[class]="
'modal-dialog' +
(size ? ' modal-' + size : '') +
(centered ? ' modal-dialog-centered' : '') +
fullscreenClass +
(scrollable ? ' modal-dialog-scrollable' : '') +
(modalDialogClass ? ' ' + modalDialogClass : '')
"
role="document"
>
<div class="modal-content"><ng-content /></div>
</div>
`, isInline: true, styles: ["ngb-modal-window .component-host-scrollable{display:flex;flex-direction:column;overflow:hidden}\n"], encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgbModalWindow, decorators: [{
type: Component,
args: [{ selector: 'ngb-modal-window', host: {
'[class]': '"modal d-block" + (windowClass ? " " + windowClass : "")',
'[class.fade]': 'animation',
tabindex: '-1',
'[attr.aria-modal]': 'true',
'[attr.aria-labelledby]': 'ariaLabelledBy',
'[attr.aria-describedby]': 'ariaDescribedBy',
'[attr.role]': 'role',
}, template: `
<div
#dialog
[class]="
'modal-dialog' +
(size ? ' modal-' + size : '') +
(centered ? ' modal-dialog-centered' : '') +
fullscreenClass +
(scrollable ? ' modal-dialog-scrollable' : '') +
(modalDialogClass ? ' ' + modalDialogClass : '')
"
role="document"
>
<div class="modal-content"><ng-content /></div>
</div>
`, encapsulation: ViewEncapsulation.None, styles: ["ngb-modal-window .component-host-scrollable{display:flex;flex-direction:column;overflow:hidden}\n"] }]
}], propDecorators: { _dialogEl: [{
type: ViewChild,
args: ['dialog', { static: true }]
}], animation: [{
type: Input
}], ariaLabelledBy: [{
type: Input
}], ariaDescribedBy: [{
type: Input
}], backdrop: [{
type: Input
}], centered: [{
type: Input
}], fullscreen: [{
type: Input
}], keyboard: [{
type: Input
}], role: [{
type: Input
}], scrollable: [{
type: Input
}], size: [{
type: Input
}], windowClass: [{
type: Input
}], modalDialogClass: [{
type: Input
}], dismissEvent: [{
type: Output,
args: ['dismiss']
}] } });
class NgbModalStack {
constructor() {
this._applicationRef = inject(ApplicationRef);
this._injector = inject(Injector);
this._environmentInjector = inject(EnvironmentInjector);
this._document = inject(DOCUMENT);
this._scrollBar = inject(ScrollBar);
this._activeWindowCmptHasChanged = new Subject();
this._ariaHiddenValues = new Map();
this._scrollBarRestoreFn = null;
this._modalRefs = [];
this._windowCmpts = [];
this._activeInstances = new EventEmitter();
const ngZone = inject(NgZone);
// Trap focus on active WindowCmpt
this._activeWindowCmptHasChanged.subscribe(() => {
if (this._windowCmpts.length) {
const activeWindowCmpt = this._windowCmpts[this._windowCmpts.length - 1];
ngbFocusTrap(ngZone, activeWindowCmpt.location.nativeElement, this._activeWindowCmptHasChanged);
this._revertAriaHidden();
this._setAriaHidden(activeWindowCmpt.location.nativeElement);
}
});
}
_restoreScrollBar() {
const scrollBarRestoreFn = this._scrollBarRestoreFn;
if (scrollBarRestoreFn) {
this._scrollBarRestoreFn = null;
scrollBarRestoreFn();
}
}
_hideScrollBar() {
if (!this._scrollBarRestoreFn) {
this._scrollBarRestoreFn = this._scrollBar.hide();
}
}
open(contentInjector, content, options) {
const containerEl = options.container instanceof HTMLElement
? options.container
: isDefined(options.container)
? this._document.querySelector(options.container)
: this._document.body;
if (!containerEl) {
throw new Error(`The specified modal container "${options.container || 'body'}" was not found in the DOM.`);
}
this._hideScrollBar();
const activeModal = new NgbActiveModal();
contentInjector = options.injector || contentInjector;
const environmentInjector = contentInjector.get(EnvironmentInjector, null) || this._environmentInjector;
const contentRef = this._getContentRef(contentInjector, environmentInjector, content, activeModal, options);
let backdropCmptRef = options.backdrop !== false ? this._attachBackdrop(containerEl) : undefined;
let windowCmptRef = this._attachWindowComponent(containerEl, contentRef.nodes);
let ngbModalRef = new NgbModalRef(windowCmptRef, contentRef, backdropCmptRef, options.beforeDismiss);
this._registerModalRef(ngbModalRef);
this._registerWindowCmpt(windowCmptRef);
// We have to cleanup DOM after the last modal when BOTH 'hidden' was emitted and 'result' promise was resolved:
// - with animations OFF, 'hidden' emits synchronously, then 'result' is resolved asynchronously
// - with animations ON, 'result' is resolved asynchronously, then 'hidden' emits asynchronously
ngbModalRef.hidden.pipe(take(1)).subscribe(() => Promise.resolve(true).then(() => {
if (!this._modalRefs.length) {
this._document.body.classList.remove('modal-open');
this._restoreScrollBar();
this._revertAriaHidden();
}
}));
activeModal.close = (result) => {
ngbModalRef.close(result);
};
activeModal.dismiss = (reason) => {
ngbModalRef.dismiss(reason);
};
activeModal.update = (options) => {
ngbModalRef.update(options);
};
ngbModalRef.update(options);
if (this._modalRefs.length === 1) {
this._document.body.classList.add('modal-open');
}
if (backdropCmptRef && backdropCmptRef.instance) {
backdropCmptRef.changeDetectorRef.detectChanges();
}
windowCmptRef.changeDetectorRef.detectChanges();
return ngbModalRef;
}
get activeInstances() {
return this._activeInstances;
}
dismissAll(reason) {
this._modalRefs.forEach((ngbModalRef) => ngbModalRef.dismiss(reason));
}
hasOpenModals() {
return this._modalRefs.length > 0;
}
_attachBackdrop(containerEl) {
let backdropCmptRef = createComponent(NgbModalBackdrop, {
environmentInjector: this._applicationRef.injector,
elementInjector: this._injector,
});
this._applicationRef.attachView(backdropCmptRef.hostView);
containerEl.appendChild(backdropCmptRef.location.nativeElement);
return backdropCmptRef;
}
_attachWindowComponent(containerEl, projectableNodes) {
let windowCmptRef = createComponent(NgbModalWindow, {
environmentInjector: this._applicationRef.injector,
elementInjector: this._injector,
projectableNodes,
});
this._applicationRef.attachView(windowCmptRef.hostView);
containerEl.appendChild(windowCmptRef.location.nativeElement);
return windowCmptRef;
}
_getContentRef(contentInjector, environmentInjector, content, activeModal, options) {
if (!content) {
return new ContentRef([]);
}
else if (content instanceof TemplateRef) {
return this._createFromTemplateRef(content, activeModal);
}
else if (isString(content)) {
return this._createFromString(content);
}
else {
return this._createFromComponent(contentInjector, environmentInjector, content, activeModal, options);
}
}
_createFromTemplateRef(templateRef, activeModal) {
const context = {
$implicit: activeModal,
close(result) {
activeModal.close(result);
},
dismiss(reason) {
activeModal.dismiss(reason);
},
};
const viewRef = templateRef.createEmbeddedView(context);
this._applicationRef.attachView(viewRef);
return new ContentRef([viewRef.rootNodes], viewRef);
}
_createFromString(content) {
const component = this._document.createTextNode(`${content}`);
return new ContentRef([[component]]);
}
_createFromComponent(contentInjector, environmentInjector, componentType, context, options) {
const elementInjector = Injector.create({
providers: [{ provide: NgbActiveModal, useValue: context }],
parent: contentInjector,
});
const componentRef = createComponent(componentType, {
environmentInjector,
elementInjector,
});
const componentNativeEl = componentRef.location.nativeElement;
if (options.scrollable) {
componentNativeEl.classList.add('component-host-scrollable');
}
this._applicationRef.attachView(componentRef.hostView);
// FIXME: we should here get rid of the component nativeElement
// and use `[Array.from(componentNativeEl.childNodes)]` instead and remove the above CSS class.
return new ContentRef([[componentNativeEl]], componentRef.hostView, componentRef);
}
_setAriaHidden(element) {
const parent = element.parentElement;
if (parent && element !== this._document.body) {
Array.from(parent.children).forEach((sibling) => {
if (sibling !== element && sibling.nodeName !== 'SCRIPT') {
this._ariaHiddenValues.set(sibling, sibling.getAttribute('aria-hidden'));
sibling.setAttribute('aria-hidden', 'true');
}
});
this._setAriaHidden(parent);
}
}
_revertAriaHidden() {
this._ariaHiddenValues.forEach((value, element) => {
if (value) {
element.setAttribute('aria-hidden', value);
}
else {
element.removeAttribute('aria-hidden');
}
});
this._ariaHiddenValues.clear();
}
_registerModalRef(ngbModalRef) {
const unregisterModalRef = () => {
const index = this._modalRefs.indexOf(ngbModalRef);
if (index > -1) {
this._modalRefs.splice(index, 1);
this._activeInstances.emit(this._modalRefs);
}
};
this._modalRefs.push(ngbModalRef);
this._activeInstances.emit(this._modalRefs);
ngbModalRef.result.then(unregisterModalRef, unregisterModalRef);
}
_registerWindowCmpt(ngbWindowCmpt) {
this._windowCmpts.push(ngbWindowCmpt);
this._activeWindowCmptHasChanged.next();
ngbWindowCmpt.onDestroy(() => {
const index = this._windowCmpts.indexOf(ngbWindowCmpt);
if (index > -1) {
this._windowCmpts.splice(index, 1);
this._activeWindowCmptHasChanged.next();
}
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgbModalStack, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgbModalStack, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgbModalStack, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}], ctorParameters: () => [] });
/**
* A service for opening modal windows.
*
* Creating a modal is straightforward: create a component or a template and pass it as an argument to
* the `.open()` method.
*/
class NgbModal {
constructor() {
this._injector = inject(Injector);
this._modalStack = inject(NgbModalStack);
this._config = inject(NgbModalConfig);
}
/**
* Opens a new modal window with the specified content and supplied options.
*
* Content can be provided as a `TemplateRef` or a component type. If you pass a component type as content,
* then instances of those components can be injected with an instance of the `NgbActiveModal` class. You can then
* use `NgbActiveModal` methods to close / dismiss modals from "inside" of your component.
*
* Also see the [`NgbModalOptions`](#/components/modal/api#NgbModalOptions) for the list of supported options.
*/
open(content, options = {}) {
const combinedOptions = { ...this._config, animation: this._config.animation, ...options };
return this._modalStack.open(this._injector, content, combinedOptions);
}
/**
* Returns an observable that holds the active modal instances.
*/
get activeInstances() {
return this._modalStack.activeInstances;
}
/**
* Dismisses all currently displayed modal windows with the supplied reason.
*
* @since 3.1.0
*/
dismissAll(reason) {
this._modalStack.dismissAll(reason);
}
/**
* Indicates if there are currently any open modal windows in the application.
*
* @since 3.3.0
*/
hasOpenModals() {
return this._modalStack.hasOpenModals();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgbModal, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgbModal, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgbModal, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}] });
class NgbModalModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgbModalModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.0.4", ngImport: i0, type: NgbModalModule }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgbModalModule, providers: [NgbModal] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.4", ngImport: i0, type: NgbModalModule, decorators: [{
type: NgModule,
args: [{ providers: [NgbModal] }]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { ModalDismissReasons, NgbActiveModal, NgbModal, NgbModalConfig, NgbModalModule, NgbModalRef };
//# sourceMappingURL=ng-bootstrap-ng-bootstrap-modal.mjs.map