@skyux/modals
Version:
This library was generated with [Nx](https://nx.dev).
1,471 lines • 101 kB
JavaScript
import { ReplaySubject, Subject, BehaviorSubject } from 'rxjs';
import * as i0 from '@angular/core';
import { NgModule, InjectionToken, ViewEncapsulation, Component, Injectable, input, inject, ChangeDetectorRef, ElementRef, HostListener, ViewChild, Input, HostBinding, Inject, EnvironmentInjector, ViewContainerRef, Directive } from '@angular/core';
import * as i1$1 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i1 from '@skyux/core';
import { SkyResponsiveHostDirective, SkyTrimModule, SkyCoreAdapterService, SkyDockService, SkyLiveAnnouncerService, SkyDockLocation, SkyIdModule, SkyLayoutHostDirective, SkyScrollShadowDirective, SkyIdService, SkyDynamicComponentService, SkyAppWindowRef, SKY_STACKING_CONTEXT } from '@skyux/core';
import * as i6 from '@skyux/i18n';
import { SkyLibResourcesService, SkyI18nModule } from '@skyux/i18n';
import * as i5 from '@skyux/theme';
import { SkyThemeModule, SkyThemeService, SkyTheme } from '@skyux/theme';
import { takeUntil, takeWhile } from 'rxjs/operators';
import * as i2 from '@skyux/help-inline';
import { SkyHelpInlineModule } from '@skyux/help-inline';
import * as i3 from '@skyux/icon';
import { SkyIconModule } from '@skyux/icon';
import { toSignal } from '@angular/core/rxjs-interop';
import { Router, NavigationStart, RouterModule } from '@angular/router';
import * as i3$1 from '@skyux/indicators';
import { SkyStatusIndicatorModule } from '@skyux/indicators';
class SkyConfirmInstance {
/**
* Fires when users select an action to close the dialog. This event
* returns a `SkyConfirmCloseEventArgs` object with information about the button that
* users select. It returns the `'cancel'` action when users press the <kbd>Escape</kbd> key.
*/
get closed() {
return this.#closedObs;
}
#closed = new ReplaySubject();
#closedObs = this.#closed.asObservable();
/**
* Closes the confirm instance.
* @param args Specifies an object to emit to subscribers of the `closed` event
* of the confirm instance.
*/
close(args) {
this.#closed.next(args);
this.#closed.complete();
}
}
var SkyConfirmType;
(function (SkyConfirmType) {
/**
* Allows you to define your own buttons using the `buttons` property of `SkyConfirmConfig`.
*/
SkyConfirmType[SkyConfirmType["Custom"] = 0] = "Custom";
/**
* Displays one button with an **OK** label and an `'ok'` action.
*/
SkyConfirmType[SkyConfirmType["OK"] = 1] = "OK";
/**
* Displays two buttons with **Yes** and **Cancel** labels.
* @deprecated Use the `Custom` type to follow the guidance that labels
* should clearly indicate the actions that occur when users select buttons.
*/
SkyConfirmType[SkyConfirmType["YesCancel"] = 2] = "YesCancel";
/**
* Displays three buttons with **Yes**, **No**, and **Cancel** labels.
* @deprecated Use the `Custom` type to follow the guidance that labels
* should clearly indicate the actions that occur when users select buttons.
*/
SkyConfirmType[SkyConfirmType["YesNoCancel"] = 3] = "YesNoCancel";
})(SkyConfirmType || (SkyConfirmType = {}));
/**
* @deprecated The `SkyConfirmModule` is no longer needed and can be removed from your application.
* @internal
*/
class SkyConfirmModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyConfirmModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: SkyConfirmModule }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyConfirmModule }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyConfirmModule, decorators: [{
type: NgModule,
args: [{}]
}] });
/**
* @internal
*/
const SKY_CONFIRM_CONFIG = new InjectionToken('SkyConfirmConfig');
/**
* Specifies content to display in the modal's body.
*/
class SkyModalContentComponent {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: SkyModalContentComponent, isStandalone: true, selector: "sky-modal-content", hostDirectives: [{ directive: i1.SkyResponsiveHostDirective }], ngImport: i0, template: "<ng-content />\n", styles: [".sky-modal:not(.sky-theme-modern *){--sky-override-modal-content-padding: 0}sky-modal-content{display:block;min-height:100%;padding:var(--sky-override-modal-content-padding, var(--sky-comp-modal-content-space-inset-top) var(--sky-comp-modal-content-space-inset-right) var(--sky-comp-modal-content-space-inset-bottom) var(--sky-comp-modal-content-space-inset-left))}\n"], encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalContentComponent, decorators: [{
type: Component,
args: [{ hostDirectives: [SkyResponsiveHostDirective], selector: 'sky-modal-content', encapsulation: ViewEncapsulation.None, template: "<ng-content />\n", styles: [".sky-modal:not(.sky-theme-modern *){--sky-override-modal-content-padding: 0}sky-modal-content{display:block;min-height:100%;padding:var(--sky-override-modal-content-padding, var(--sky-comp-modal-content-space-inset-top) var(--sky-comp-modal-content-space-inset-right) var(--sky-comp-modal-content-space-inset-bottom) var(--sky-comp-modal-content-space-inset-left))}\n"] }]
}] });
/**
* Properties about the modal close action and a method to close the modal.
*/
class SkyModalBeforeCloseHandler {
constructor(closeModal, closeArgs) {
this.closeArgs = closeArgs;
this.closeModal = closeModal;
}
}
/**
* Contains an object with the data passed from users when
* a modal is closed and the reason that the modal was closed.
*/
class SkyModalCloseArgs {
}
class SkyModalInstance {
/**
* An event that the modal instance emits when it is about to close.
* It emits a `SkyModalBeforeCloseHandler` object with a `closeModal` method
* that closes the modal. If a subscription exists for this event,
* the modal does not close until the subscriber calls the `closeModal` method.
*/
get beforeClose() {
return this.#_beforeClose;
}
/**
* An event that the modal instance emits when it closes.
* It emits a `SkyModalCloseArgs` object with a `data` property that includes
* data passed from users on close or save and a `reason` property that indicates
* whether the modal was saved or closed without saving.
* The `reason` property accepts any string value.
* Common examples include `"cancel"`, `"close"`, and `"save"`.
*/
get closed() {
return this.#_closed;
}
/**
* An event that the modal instance emits when users click
* the help inline button.
* If a `helpKey` parameter was specified, the `helpOpened` event broadcasts the `helpKey`.
* @deprecated
*/
get helpOpened() {
return this.#_helpOpened;
}
/**
* Sets the component adapter for the instance. This is used internally for actions such as scrolling the content.
* @internal
*/
set adapter(value) {
this.#adapter = value;
}
/**
* Sets the component ref for the instance. This is used to extract the component instance for the public API and the element ref for internal use.
* @internal
*/
set componentRef(value) {
this.componentInstance = value.instance;
this.#elementRef = value.location;
}
#_beforeClose = new Subject();
#_closed = new Subject();
/**
* @deprecated
*/
#_helpOpened = new Subject();
#adapter;
#elementRef;
/**
* Closes the modal instance.
* @param result Specifies an object to emit to subscribers of the `closed` event of the
* modal instance. The `SkyModalInstance` provider can be injected into a component's constructor
* so that this `close` function can be called from a button in the `sky-modal-footer`.
* @param reason Specifies the reason for the modal closing, with the default reason of `"close"`.
* @param ignoreBeforeClose Indicates whether to ignore the modal instance's `beforeClose` event.
*/
close(result, reason, ignoreBeforeClose) {
if (reason === undefined) {
reason = 'close';
}
this.#closeModal(reason, result, ignoreBeforeClose);
}
/**
* Closes the modal instance with `reason="cancel"`.
* @param result Specifies an object to emit to subscribers of the `closed` event of the modal
* instance. The `SkyModalInstance` provider can be injected into a component's constructor so
* that this cancel function can be called from a button in the `sky-modal-footer`.
*/
cancel(result) {
this.#closeModal('cancel', result);
}
/**
* Closes the modal instance with `reason="save"`.
* @param result Specifies an object to emit to subscribers of the `closed` event of the modal
* instance. The `SkyModalInstance` provider can be injected into a component's constructor so
* that this `save` function can be called from a button in `the sky-modal-footer`.
*/
save(result) {
this.#closeModal('save', result);
}
/**
* Scrolls the modal content area to the top of its scrollable area.
*/
scrollContentToTop() {
if (this.#adapter && this.#elementRef) {
this.#adapter.scrollContentToTop(this.#elementRef);
}
}
/**
* Triggers the `helpOpened` event that broadcasts a `helpKey` parameter to open
* when users click the help inline button.
* @param helpKey Specifies a string to emit to subscribers of
* the modal instance's `helpOpened` event. Consumers can inject the `SkyModalInstance` provider
* into a component's constructor to call the `openHelp` function in the modal template.
* @deprecated
*/
openHelp(helpKey) {
this.#_helpOpened.next(helpKey);
}
#closeModal(type, result, ignoreBeforeClose = false) {
const args = new SkyModalCloseArgs();
args.reason = type;
args.data = result;
if (this.#_beforeClose.observers.length === 0 || ignoreBeforeClose) {
this.#notifyClosed(args);
}
else {
this.#_beforeClose.next(new SkyModalBeforeCloseHandler(() => {
this.#notifyClosed(args);
}, args));
}
}
#notifyClosed(args) {
this.#_closed.next(args);
this.#_closed.complete();
this.#_beforeClose.complete();
this.#_helpOpened.complete();
}
}
/* istanbul ignore file */
/**
* NOTICE: DO NOT MODIFY THIS FILE!
* The contents of this file were automatically generated by
* the 'ng generate @skyux/i18n:lib-resources-module lib/modules/shared/sky-modals' schematic.
* To update this file, simply rerun the command.
*/
const RESOURCES = {
'EN-US': {
skyux_confirm_dialog_default_ok_text: { message: 'OK' },
skyux_confirm_dialog_default_yes_text: { message: 'Yes' },
skyux_confirm_dialog_default_no_text: { message: 'No' },
skyux_confirm_dialog_default_cancel_text: { message: 'Cancel' },
skyux_modal_close: { message: 'Close modal' },
skyux_modal_open_help: { message: 'Open Help' },
skyux_modal_footer_cancel_button: { message: 'Cancel' },
skyux_modal_footer_primary_button: { message: 'Save' },
skyux_modal_dirty_default_message: {
message: 'Are you sure you want to discard your changes?',
},
skyux_modal_dirty_default_discard_changes_text: {
message: 'Discard changes',
},
skyux_modal_dirty_default_keep_working_text: { message: 'Keep working' },
},
'FR-CA': {
skyux_confirm_dialog_default_ok_text: { message: 'OK' },
skyux_confirm_dialog_default_yes_text: { message: 'Oui' },
skyux_confirm_dialog_default_no_text: { message: 'Non' },
skyux_confirm_dialog_default_cancel_text: { message: 'Annuler' },
skyux_modal_close: { message: 'Fermer le modal' },
skyux_modal_open_help: { message: 'Ouvrir l’aide' },
skyux_modal_footer_cancel_button: { message: 'Annuler' },
skyux_modal_footer_primary_button: { message: 'Sauvegarder' },
skyux_modal_dirty_default_message: {
message: 'Êtes-vous certain de vouloir supprimer ces changements?',
},
skyux_modal_dirty_default_discard_changes_text: {
message: 'Supprimer les changements',
},
skyux_modal_dirty_default_keep_working_text: {
message: 'Continuer à travailler',
},
},
};
SkyLibResourcesService.addResources(RESOURCES);
/**
* Import into any component library module that needs to use resource strings.
*/
class SkyModalsResourcesModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalsResourcesModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: SkyModalsResourcesModule, exports: [SkyI18nModule] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalsResourcesModule, imports: [SkyI18nModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalsResourcesModule, decorators: [{
type: NgModule,
args: [{
exports: [SkyI18nModule],
}]
}] });
/**
* @internal
*/
class SkyModalComponentAdapterService {
handleWindowChange(modalEl) {
const boundedHeightEl = modalEl.nativeElement.querySelector('.sky-modal');
const fullPageModalEl = modalEl.nativeElement.querySelector('.sky-modal-full-page');
const modalStyle = getComputedStyle(boundedHeightEl);
const marginTopBottom = parseInt(modalStyle.marginTop, 10) +
parseInt(modalStyle.marginBottom, 10);
/*
Set modal height equal to max height of window (accounting for padding above and below modal)
*/
const newHeight = window.innerHeight - marginTopBottom;
boundedHeightEl.style.maxHeight = newHeight.toString() + 'px';
boundedHeightEl.style.setProperty('--sky-modal-content-max-height', boundedHeightEl.style.maxHeight);
if (fullPageModalEl) {
this.#setFullPageHeight(fullPageModalEl);
}
}
isFocusInFirstItem(event, list) {
/* istanbul ignore next */
/* sanity check */
const eventTarget = event.target || event.srcElement;
return list.length > 0 && eventTarget === list[0];
}
isFocusInLastItem(event, list) {
/* istanbul ignore next */
/* sanity check */
const eventTarget = event.target || event.srcElement;
return list.length > 0 && eventTarget === list[list.length - 1];
}
isModalFocused(event, modalEl) {
/* istanbul ignore next */
/* sanity check */
const eventTarget = event.target || event.srcElement;
return (modalEl &&
eventTarget === modalEl.nativeElement.querySelector('.sky-modal-dialog'));
}
focusLastElement(list) {
if (list.length > 0) {
list[list.length - 1].focus();
return true;
}
return false;
}
focusFirstElement(list) {
if (list.length > 0) {
list[0].focus();
return true;
}
return false;
}
modalContentHasDirectChildViewkeeper(modalContentEl) {
return !!modalContentEl.nativeElement.querySelector('sky-modal-content > .sky-viewkeeper-fixed');
}
#setFullPageHeight(fullPageModalEl) {
const windowHeight = window.innerHeight;
const fullPageModalStyle = getComputedStyle(fullPageModalEl);
const marginTopBottom = parseInt(fullPageModalStyle.marginTop, 10) +
parseInt(fullPageModalStyle.marginBottom, 10);
const fullPageModalHeight = windowHeight - marginTopBottom + 'px';
fullPageModalEl.style.height = fullPageModalHeight;
fullPageModalEl.style.maxHeight = fullPageModalHeight;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalComponentAdapterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalComponentAdapterService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalComponentAdapterService, decorators: [{
type: Injectable
}] });
/**
* @internal
*/
class SkyModalConfiguration {
constructor() {
this.size = 'medium';
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalConfiguration, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalConfiguration }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalConfiguration, decorators: [{
type: Injectable
}], ctorParameters: () => [] });
/**
* @internal
*/
class SkyModalErrorsService {
#formErrors = new BehaviorSubject(undefined);
constructor() {
this.formErrors = this.#formErrors.asObservable();
}
updateErrors(value) {
this.#formErrors.next(value);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalErrorsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalErrorsService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalErrorsService, decorators: [{
type: Injectable
}], ctorParameters: () => [] });
/**
* Specifies a header for the modal.
*/
class SkyModalHeaderComponent {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: SkyModalHeaderComponent, isStandalone: true, selector: "sky-modal-header", ngImport: i0, template: "<h2 class=\"sky-modal-heading\" skyTrim>\n <ng-content />\n</h2>\n<span class=\"sky-control-help-container\" skyTrim\n ><ng-content select=\".sky-control-help\"></ng-content\n></span>\n", styles: [".sky-modal-heading:not(.sky-theme-modern *){--sky-override-modal-h2-font-size: 16px;--sky-override-modal-h2-font-weight: 600;--sky-override-modal-h2-line-height: 1.2;--sky-override-modal-h2-font: inherit}h2.sky-modal-heading{display:inline;line-height:var(--sky-override-modal-h2-line-height, var(--sky-font-line_height-heading-2));font-size:var(--sky-override-modal-h2-font-size, var(--sky-font-size-heading-2));font-weight:var(--sky-override-modal-h2-font-weight, var(--sky-font-style-heading-2));font-family:var(--sky-override-modal-h2-font, var(--sky-font-family-heading-2))}\n"], dependencies: [{ kind: "ngmodule", type: SkyThemeModule }, { kind: "ngmodule", type: SkyTrimModule }, { kind: "directive", type: i1.λ4, selector: "[skyTrim]" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalHeaderComponent, decorators: [{
type: Component,
args: [{ selector: 'sky-modal-header', imports: [SkyThemeModule, SkyTrimModule], template: "<h2 class=\"sky-modal-heading\" skyTrim>\n <ng-content />\n</h2>\n<span class=\"sky-control-help-container\" skyTrim\n ><ng-content select=\".sky-control-help\"></ng-content\n></span>\n", styles: [".sky-modal-heading:not(.sky-theme-modern *){--sky-override-modal-h2-font-size: 16px;--sky-override-modal-h2-font-weight: 600;--sky-override-modal-h2-line-height: 1.2;--sky-override-modal-h2-font: inherit}h2.sky-modal-heading{display:inline;line-height:var(--sky-override-modal-h2-line-height, var(--sky-font-line_height-heading-2));font-size:var(--sky-override-modal-h2-font-size, var(--sky-font-size-heading-2));font-weight:var(--sky-override-modal-h2-font-weight, var(--sky-font-style-heading-2));font-family:var(--sky-override-modal-h2-font, var(--sky-font-family-heading-2))}\n"] }]
}] });
var _a;
const BASE_Z_INDEX = 1040;
const modalHosts = [];
const backdropZIndex = new BehaviorSubject(0);
const backdropZIndexObs = backdropZIndex.asObservable();
const openModalCount = new BehaviorSubject(0);
const openModalCountObs = openModalCount.asObservable();
/**
* @internal
*/
class SkyModalHostService {
static get openModalCountChange() {
return openModalCountObs;
}
static get backdropZIndexChange() {
return backdropZIndexObs;
}
/**
* @deprecated Subscribe to `openModalCountChange` instead.
*/
static get openModalCount() {
return modalHosts.length;
}
static get fullPageModalCount() {
const fullPageModals = modalHosts.filter((modal) => modal.fullPage);
return fullPageModals.length;
}
/**
* @deprecated Subscribe to `backdropZIndexChange` instead.
*/
static get backdropZIndex() {
return BASE_Z_INDEX + modalHosts.length * 10;
}
static get topModal() {
return modalHosts[modalHosts.length - 1];
}
constructor() {
this.close = new Subject();
this.fullPage = false;
/**
* @deprecated
*/
this.openHelp = new Subject();
this.zIndex = this.#calculateZIndex();
modalHosts.push(this);
this.#notifyBackdropZIndex();
this.#notifyOpenModalCount();
}
getModalZIndex() {
return this.zIndex;
}
onClose() {
this.close.next();
}
/**
* @deprecated
*/
onOpenHelp(helpKey) {
this.openHelp.next(helpKey);
}
destroy() {
modalHosts.splice(modalHosts.indexOf(this), 1);
this.#notifyBackdropZIndex();
this.#notifyOpenModalCount();
}
#calculateZIndex() {
const zIndexArray = modalHosts.map((hostService) => hostService.zIndex);
if (zIndexArray.length === 0) {
return BASE_Z_INDEX + 11;
}
else {
const currentMaxZIndex = Math.max(...zIndexArray);
return currentMaxZIndex + 10;
}
}
#notifyOpenModalCount() {
openModalCount.next(modalHosts.length);
}
#notifyBackdropZIndex() {
backdropZIndex.next(_a.backdropZIndex);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalHostService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalHostService, providedIn: 'root' }); }
}
_a = SkyModalHostService;
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalHostService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}], ctorParameters: () => [] });
const ARIA_ROLE_DEFAULT = 'dialog';
/**
* Provides a common look-and-feel for modal content with options to display
* a common modal header, specify body content, and display a common modal footer
* and buttons.
*/
class SkyModalComponent {
/**
* A list of form-level errors to display to the user.
*/
set formErrors(value) {
this.#errorsSvc.updateErrors(value);
}
/**
* Used by the confirm component to set a different role for the modal.
* @internal
*/
set ariaRole(value) {
this.ariaRoleOrDefault = value || ARIA_ROLE_DEFAULT;
}
/**
* Used by the confirm component to set descriptive text without using a
* modal header.
* @internal
*/
set ariaDescribedBy(id) {
this.#_ariaDescribedBy = id;
}
get ariaDescribedBy() {
return this.#_ariaDescribedBy;
}
/**
* Used by the confirm component to set descriptive text without using a
* modal header.
* @internal
*/
set ariaLabelledBy(id) {
this.#_ariaLabelledBy = id;
}
get ariaLabelledBy() {
return this.#_ariaLabelledBy;
}
#ngUnsubscribe;
#_ariaDescribedBy;
#_ariaLabelledBy;
#changeDetector;
#componentAdapter;
#coreAdapter;
#dockService;
#elRef;
#errorsSvc;
#hostService;
#liveAnnouncerSvc;
/**
* This provider is optional to account for situations where a modal component
* is implemented without the modal service. For example, when a consumer tests
* a component that uses the modal component but doesn't launch the modal from
* the modal service before executing assertions.
*/
#config;
#themeSvc;
constructor() {
this.ariaRoleOrDefault = ARIA_ROLE_DEFAULT;
this.layout = input('none', ...(ngDevMode ? [{ debugName: "layout" }] : []));
this.ariaOwns = null;
this.modalState = 'in';
this.scrollShadow = {
bottomShadow: 'none',
topShadow: 'none',
};
this.scrollShadowEnabled = false;
this.#ngUnsubscribe = new Subject();
this.#changeDetector = inject(ChangeDetectorRef);
this.#componentAdapter = inject(SkyModalComponentAdapterService);
this.#coreAdapter = inject(SkyCoreAdapterService);
this.#dockService = inject(SkyDockService, { host: true });
this.#elRef = inject(ElementRef);
this.#errorsSvc = inject(SkyModalErrorsService);
this.#hostService = inject(SkyModalHostService);
this.#liveAnnouncerSvc = inject(SkyLiveAnnouncerService);
/**
* This provider is optional to account for situations where a modal component
* is implemented without the modal service. For example, when a consumer tests
* a component that uses the modal component but doesn't launch the modal from
* the modal service before executing assertions.
*/
this.#config = inject(SkyModalConfiguration, { optional: true }) ??
new SkyModalConfiguration();
this.#themeSvc = inject(SkyThemeService, { optional: true });
this.ariaDescribedBy = this.#config.ariaDescribedBy;
this.ariaLabelledBy = this.#config.ariaLabelledBy;
this.ariaRole = this.#config.ariaRole;
this.legacyHelpKey = this.#config.helpKey;
this.tiledBody = this.#config.tiledBody;
this.wrapperClass = this.#config.wrapperClass;
this.size = this.#config.fullPage
? 'full-page'
: this.#config.size?.toLowerCase() || 'medium';
this.modalZIndex = this.#hostService.zIndex;
}
onDocumentKeyUp(event) {
/* istanbul ignore else */
/* sanity check */
if (SkyModalHostService.openModalCount > 0) {
const topModal = SkyModalHostService.topModal;
if (topModal && topModal === this.#hostService) {
if (event.which === 27) {
// Escape key up
event.preventDefault();
this.closeButtonClick();
}
}
}
}
onDocumentKeyDown(event) {
/* istanbul ignore else */
/* sanity check */
if (SkyModalHostService.openModalCount > 0) {
const topModal = SkyModalHostService.topModal;
if (topModal && topModal === this.#hostService) {
if (event.which === 9) {
// Tab pressed
let focusChanged = false;
const focusElementList = this.#coreAdapter.getFocusableChildren(this.#elRef.nativeElement);
if (event.shiftKey &&
(this.#componentAdapter.isFocusInFirstItem(event, focusElementList) ||
this.#componentAdapter.isModalFocused(event, this.#elRef))) {
focusChanged =
this.#componentAdapter.focusLastElement(focusElementList);
}
else if (!event.shiftKey &&
this.#componentAdapter.isFocusInLastItem(event, focusElementList)) {
focusChanged =
this.#componentAdapter.focusFirstElement(focusElementList);
}
if (focusChanged) {
event.preventDefault();
event.stopPropagation();
}
}
}
}
}
ngOnInit() {
this.#liveAnnouncerSvc.announcerElementChanged
.pipe(takeUntil(this.#ngUnsubscribe))
.subscribe((element) => {
if (element?.id) {
this.ariaOwns = element.id;
this.#changeDetector.markForCheck();
}
});
if (this.#themeSvc) {
this.#themeSvc.settingsChange
.pipe(takeUntil(this.#ngUnsubscribe))
.subscribe((themeSettings) => {
this.scrollShadowEnabled =
themeSettings.currentSettings.theme === SkyTheme.presets.modern;
});
}
}
ngAfterViewInit() {
this.#componentAdapter.handleWindowChange(this.#elRef);
this.#dockService.setDockOptions({
location: SkyDockLocation.ElementBottom,
referenceEl: this.modalContentWrapperElement.nativeElement,
zIndex: 5,
});
}
ngOnDestroy() {
this.#ngUnsubscribe.next();
this.#ngUnsubscribe.complete();
}
/**
* @deprecated
*/
helpButtonClick() {
if (this.legacyHelpKey) {
this.#hostService.onOpenHelp(this.legacyHelpKey);
}
}
closeButtonClick() {
this.#hostService.onClose();
}
windowResize() {
this.#componentAdapter.handleWindowChange(this.#elRef);
}
scrollShadowChange(args) {
this.scrollShadow = args;
}
viewkeeperEnabled() {
return this.#componentAdapter.modalContentHasDirectChildViewkeeper(this.#elRef);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: SkyModalComponent, isStandalone: true, selector: "sky-modal", inputs: { formErrors: { classPropertyName: "formErrors", publicName: "formErrors", isSignal: false, isRequired: false, transformFunction: null }, headingText: { classPropertyName: "headingText", publicName: "headingText", isSignal: false, isRequired: false, transformFunction: null }, helpKey: { classPropertyName: "helpKey", publicName: "helpKey", isSignal: false, isRequired: false, transformFunction: null }, helpPopoverContent: { classPropertyName: "helpPopoverContent", publicName: "helpPopoverContent", isSignal: false, isRequired: false, transformFunction: null }, helpPopoverTitle: { classPropertyName: "helpPopoverTitle", publicName: "helpPopoverTitle", isSignal: false, isRequired: false, transformFunction: null }, ariaRole: { classPropertyName: "ariaRole", publicName: "ariaRole", isSignal: false, isRequired: false, transformFunction: null }, tiledBody: { classPropertyName: "tiledBody", publicName: "tiledBody", isSignal: false, isRequired: false, transformFunction: null }, ariaDescribedBy: { classPropertyName: "ariaDescribedBy", publicName: "ariaDescribedBy", isSignal: false, isRequired: false, transformFunction: null }, ariaLabelledBy: { classPropertyName: "ariaLabelledBy", publicName: "ariaLabelledBy", isSignal: false, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "document:keyup": "onDocumentKeyUp($event)", "document:keydown": "onDocumentKeyDown($event)" }, properties: { "class": "this.wrapperClass" } }, providers: [
SkyModalComponentAdapterService,
SkyModalErrorsService,
SkyDockService,
], viewQueries: [{ propertyName: "modalContentWrapperElement", first: true, predicate: ["modalContentWrapper"], descendants: true, read: ElementRef }], ngImport: i0, template: "<div\n class=\"sky-modal-dialog\"\n aria-modal=\"true\"\n [attr.aria-describedby]=\"ariaDescribedBy || modalContentId.id\"\n [attr.aria-labelledby]=\"ariaLabelledBy || headerId.id\"\n [attr.aria-owns]=\"ariaOwns\"\n [attr.role]=\"ariaRoleOrDefault\"\n (window:resize)=\"windowResize()\"\n>\n <div\n class=\"sky-modal sky-shadow sky-box sky-elevation-16 sky-modal-{{ size }}\"\n tabindex=\"-1\"\n [ngClass]=\"{\n 'sky-modal-tiled': tiledBody,\n 'sky-modal-viewkeeper': viewkeeperEnabled()\n }\"\n [ngStyle]=\"{\n zIndex: modalZIndex\n }\"\n >\n <div\n class=\"sky-modal-header\"\n [ngStyle]=\"{\n 'box-shadow': scrollShadow?.topShadow\n }\"\n >\n <div #headerId=\"skyId\" class=\"sky-modal-header-content\" skyId>\n @if (headingText) {\n <sky-modal-header>\n {{ headingText }}\n @if (helpKey || helpPopoverContent) {\n <sky-help-inline\n class=\"sky-control-help\"\n [helpKey]=\"helpKey\"\n [labelText]=\"headingText\"\n [popoverContent]=\"helpPopoverContent\"\n [popoverTitle]=\"helpPopoverTitle\"\n />\n }\n </sky-modal-header>\n } @else {\n <ng-content select=\"sky-modal-header\" />\n }\n </div>\n <div class=\"sky-modal-header-buttons\">\n @if (legacyHelpKey) {\n <button\n class=\"sky-btn sky-modal-btn-help\"\n name=\"help-button\"\n type=\"button\"\n [attr.aria-label]=\"'skyux_modal_open_help' | skyLibResources\"\n (click)=\"helpButtonClick()\"\n >\n <sky-icon iconName=\"question-circle\" />\n </button>\n }\n\n <button\n type=\"button\"\n class=\"sky-btn sky-modal-btn-close\"\n [attr.aria-label]=\"'skyux_modal_close' | skyLibResources\"\n (click)=\"closeButtonClick()\"\n >\n <sky-icon iconName=\"close\" />\n </button>\n </div>\n </div>\n <div\n #modalContentId=\"skyId\"\n #modalContentWrapper\n class=\"sky-modal-content\"\n role=\"region\"\n tabindex=\"0\"\n skyId\n skyLayoutHost\n [layout]=\"layout()\"\n [attr.aria-labelledby]=\"headerId.id\"\n [skyScrollShadowEnabled]=\"scrollShadowEnabled\"\n [skyThemeClass]=\"{\n 'sky-padding-even-large': 'default'\n }\"\n (skyScrollShadow)=\"scrollShadowChange($event)\"\n >\n <ng-content select=\"sky-modal-content\" />\n </div>\n <div\n class=\"sky-modal-footer\"\n [ngStyle]=\"{\n 'box-shadow': scrollShadow?.bottomShadow\n }\"\n >\n <ng-content select=\"sky-modal-footer\" />\n </div>\n </div>\n</div>\n", styles: [".sky-modal:not(.sky-theme-modern *){--sky-override-modal-background-color: #fff;--sky-override-modal-border: 1px solid #cdcfd2;--sky-override-modal-dock-bottom: -15px;--sky-override-modal-dock-margin-left-right-bottom: -15px;--sky-override-modal-dock-padding-top: 15px;--sky-override-modal-dock-width: calc(100% + 30px) ;--sky-override-modal-full-page-margin-xs: 0;--sky-override-modal-full-page-margin: 0;--sky-override-modal-full-page-width: 100%;--sky-override-modal-header-bottom-border: 1px solid #e2e3e4;--sky-override-modal-header-padding: 9px 3px 9px 15px;--sky-override-modal-help-close-display: inline-block;--sky-override-modal-margin: 20px auto;--sky-override-modal-viewkept-toolbar-box-shadow: none;--sky-override-modal-viewkept-toolbar-padding-horizontal: 10px;--sky-override-modal-width-l: 900px;--sky-override-modal-width-m: 600px;--sky-override-modal-width-s: 300px;--sky-override-modal-xs-margin: 30px 10px 10px 10px}:host{--sky-viewport-top: 0;--sky-viewport-bottom: 0;--sky-viewport-left: 0;--sky-viewport-right: 0}.sky-modal{--sky-comp-override-list-header-background-color: initial;border:var(--sky-override-modal-border, var(--sky-border-width-container-base) solid var(--sky-color-border-container-base));position:fixed;width:auto;left:0;right:0;top:0;margin:var(--sky-override-modal-xs-margin, var(--sky-comp-modal-space-offset-xs-top) var(--sky-comp-modal-space-offset-xs-right) var(--sky-comp-modal-space-offset-xs-bottom) var(--sky-comp-modal-space-offset-xs-left));display:flex;flex-direction:column;overflow:hidden}.sky-modal:has(.sky-modal-content.sky-layout-host-fit){height:var(--sky-modal-content-max-height, 100%)}.sky-modal:focus{outline-style:dotted;outline-width:thin;outline-offset:-1px}.sky-modal-header:has(.sky-modal-header-content:empty){display:none}.sky-modal-btn-help,.sky-modal-btn-close{display:var(--sky-override-modal-help-close-display, none)}.sky-modal-full-page{width:var(--sky-override-modal-full-page-width, calc(100% - (var(--sky-override-modal-full-page-margin-xs, var(--sky-comp-modal-fullscreen-space-offset-xs-right)) + var(--sky-override-modal-full-page-margin-xs, var(--sky-comp-modal-fullscreen-space-offset-xs-left)))));margin:var(--sky-override-modal-full-page-margin-xs, var(--sky-comp-modal-fullscreen-space-offset-xs-top) var(--sky-comp-modal-fullscreen-space-offset-xs-right) var(--sky-comp-modal-fullscreen-space-offset-xs-bottom) var(--sky-comp-modal-fullscreen-space-offset-xs-left))}@media (min-width: 768px){.sky-modal:not(.sky-modal-full-page){margin:var(--sky-override-modal-margin, var(--sky-comp-modal-space-offset-sm-top) auto var(--sky-comp-modal-space-offset-sm-bottom))}.sky-modal-small{width:var(--sky-override-modal-width-s, var(--sky-size-width-modal-s))}.sky-modal-small .sky-modal-content,.sky-modal-small .sky-modal-header,.sky-modal-small .sky-modal-footer{max-width:var(--sky-override-modal-width-s, var(--sky-size-width-modal-s))}.sky-modal-medium{width:var(--sky-override-modal-width-m, var(--sky-size-width-modal-m))}.sky-modal-medium .sky-modal-content,.sky-modal-medium .sky-modal-header,.sky-modal-medium .sky-modal-footer{max-width:var(--sky-override-modal-width-m, var(--sky-size-width-modal-m))}.sky-modal-full-page{width:var(--sky-override-modal-full-page-width, calc(100% - (var(--sky-override-modal-full-page-margin, var(--sky-comp-modal-fullscreen-space-offset-sm-left)) + var(--sky-override-modal-full-page-margin, var(--sky-comp-modal-fullscreen-space-offset-sm-right)))));margin:var(--sky-override-modal-full-page-margin, var(--sky-comp-modal-fullscreen-space-offset-sm-top) var(--sky-comp-modal-fullscreen-space-offset-sm-right) var(--sky-comp-modal-fullscreen-space-offset-sm-bottom) var(--sky-comp-modal-fullscreen-space-offset-sm-left))}}@media (min-width: 920px){.sky-modal-large{width:var(--sky-override-modal-width-l, var(--sky-size-width-modal-l))}.sky-modal-large .sky-modal-content,.sky-modal-large .sky-modal-header,.sky-modal-large .sky-modal-footer{max-width:var(--sky-override-modal-width-l, var(--sky-size-width-modal-l))}}.sky-modal-content{background-color:var(--sky-override-modal-background-color, var(--sky-color-background-container-base));--sky-background-color-page-default: var( --sky-override-modal-background-color, var(--sky-color-background-container-base) )}.sky-modal-content:focus{outline-style:dotted;outline-width:thin;outline-offset:-1px}.sky-modal-content.sky-layout-host-fit{flex-grow:1;position:relative}.sky-modal-tiled .sky-modal-content{background-color:#eeeeef;--sky-background-color-page-default: $sky-background-color-neutral-light}.sky-modal-tiled .sky-modal-content ::ng-deep .sky-tile-title{font-family:BLKB Sans,Helvetica Neue,Arial,sans-serif;color:var(--sky-text-color-deemphasized);font-weight:300;font-size:19px}.sky-modal-header{padding:var(--sky-override-modal-header-padding, var(--sky-comp-modal-header-space-inset-top) var(--sky-comp-modal-header-space-inset-right) var(--sky-comp-modal-header-space-inset-bottom) var(--sky-comp-modal-header-space-inset-left));background-color:var(--sky-override-modal-background-color, var(--sky-color-background-container-base));border-bottom:var(--sky-override-modal-header-bottom-border);display:flex;align-items:baseline}.sky-modal-header-buttons{flex-shrink:.0001}.sky-modal-header-buttons .sky-btn{border:none;color:#686c73;cursor:pointer}.sky-modal-header-buttons .sky-btn:hover{color:#383a3d;transition:color .15s}.sky-modal-header-content{flex-grow:1}.sky-modal-header{flex-shrink:0;z-index:2}.sky-modal-content{overflow-y:auto}.sky-modal-footer{flex-shrink:0;z-index:2}.sky-modal-full-page .sky-modal-content{flex-grow:1}.sky-modal-content>::ng-deep sky-dock{bottom:var(--sky-override-modal-dock-bottom, 0);margin-left:var(--sky-override-modal-dock-margin-left-right-bottom, initial);margin-right:var(--sky-override-modal-dock-margin-left-right-bottom, initial);margin-bottom:var(--sky-override-modal-dock-margin-left-right-bottom, initial);padding-top:var(--sky-override-modal-dock-padding-top, initial);width:var(--sky-override-modal-dock-width, 100%)}.sky-modal-viewkeeper .sky-modal-header{box-shadow:none!important}.sky-modal-viewkeeper .sky-modal-content ::ng-deep sky-modal-content>.sky-viewkeeper-fixed{box-shadow:var(--sky-override-modal-viewkept-toolbar-box-shadow, var(--sky-elevation-overflow))}.sky-modal-viewkeeper .sky-modal-content ::ng-deep sky-modal-content>.sky-viewkeeper-fixed>sky-toolbar .sky-toolbar-container{background-color:var(--sky-override-modal-background-color, var(--sky-color-background-container-base));--sky-background-color-page-default: var( --sky-override-modal-background-color, var(--sky-color-background-container-base) );padding-left:var(--sky-override-modal-viewkept-toolbar-padding-horizontal, var(--sky-comp-modal-header-space-inset-left));padding-right:var(--sky-override-modal-viewkept-toolbar-padding-horizontal, var(--sky-comp-modal-header-space-inset-right))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: SkyHelpInlineModule }, { kind: "component", type: i2.λ1, selector: "sky-help-inline", inputs: ["ariaControls", "ariaExpanded", "ariaLabel", "helpKey", "labelledBy", "labelText", "popoverContent", "popoverTitle"], outputs: ["actionClick"] }, { kind: "ngmodule", type: SkyIconModule }, { kind: "component", type: i3.λ1, selector: "sky-icon", inputs: ["iconName", "variant", "iconSize"] }, { kind: "ngmodule", type: SkyIdModule }, { kind: "directive", type: i1.λ2, selector: "[skyId]", exportAs: ["skyId"] }, { kind: "directive", type: SkyLayoutHostDirective, selector: "[skyLayoutHost]", inputs: ["layout"] }, { kind: "component", type: SkyModalHeaderComponent, selector: "sky-modal-header" }, { kind: "ngmodule", type: SkyModalsResourcesModule }, { kind: "directive", type: SkyScrollShadowDirective, selector: "[skyScrollShadow]", inputs: ["skyScrollShadowEnabled"], outputs: ["skyScrollShadow"] }, { kind: "ngmodule", type: SkyThemeModule }, { kind: "directive", type: i5.λ2, selector: "[skyThemeClass]", inputs: ["class", "skyThemeClass"] }, { kind: "pipe", type: i6.SkyLibResourcesPipe, name: "skyLibResources" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalComponent, decorators: [{
type: Component,
args: [{ selector: 'sky-modal', providers: [
SkyModalComponentAdapterService,
SkyModalErrorsService,
SkyDockService,
], imports: [
CommonModule,
SkyHelpInlineModule,
SkyIconModule,
SkyIdModule,
SkyLayoutHostDirective,
SkyModalHeaderComponent,
SkyModalsResourcesModule,
SkyScrollShadowDirective,
SkyThemeModule,
], template: "<div\n class=\"sky-modal-dialog\"\n aria-modal=\"true\"\n [attr.aria-describedby]=\"ariaDescribedBy || modalContentId.id\"\n [attr.aria-labelledby]=\"ariaLabelledBy || headerId.id\"\n [attr.aria-owns]=\"ariaOwns\"\n [attr.role]=\"ariaRoleOrDefault\"\n (window:resize)=\"windowResize()\"\n>\n <div\n class=\"sky-modal sky-shadow sky-box sky-elevation-16 sky-modal-{{ size }}\"\n tabindex=\"-1\"\n [ngClass]=\"{\n 'sky-modal-tiled': tiledBody,\n 'sky-modal-viewkeeper': viewkeeperEnabled()\n }\"\n [ngStyle]=\"{\n zIndex: modalZIndex\n }\"\n >\n <div\n class=\"sky-modal-header\"\n [ngStyle]=\"{\n 'box-shadow': scrollShadow?.topShadow\n }\"\n >\n <div #headerId=\"skyId\" class=\"sky-modal-header-content\" skyId>\n @if (headingText) {\n <sky-modal-header>\n {{ headingText }}\n @if (helpKey || helpPopoverContent) {\n <sky-help-inline\n class=\"sky-control-help\"\n [helpKey]=\"helpKey\"\n [labelText]=\"headingText\"\n [popoverContent]=\"helpPopoverContent\"\n [popoverTitle]=\"helpPopoverTitle\"\n />\n }\n </sky-modal-header>\n } @else {\n <ng-content select=\"sky-modal-header\" />\n }\n </div>\n <div class=\"sky-modal-header-buttons\">\n @if (legacyHelpKey) {\n <button\n class=\"sky-btn sky-modal-btn-help\"\n name=\"help-button\"\n type=\"button\"\n [attr.aria-label]=\"'skyux_modal_open_help' | skyLibResources\"\n (click)=\"helpButtonClick()\"\n >\n <sky-icon iconName=\"question-circle\" />\n </button>\n }\n\n <button\n type=\"button\"\n class=\"sky-btn sky-modal-btn-close\"\n [attr.aria-label]=\"'skyux_modal_close' | skyLibResources\"\n (click)=\"closeButtonClick()\"\n >\n <sky-icon iconName=\"close\" />\n </button>\n </div>\n </div>\n <div\n #modalContentId=\"skyId\"\n #modalContentWrapper\n class=\"sky-modal-content\"\n role=\"region\"\n tabindex=\"0\"\n skyId\n skyLayoutHost\n [layout]=\"layout()\"\n [attr.aria-labelledby]=\"headerId.id\"\n [skyScrollShadowEnabled]=\"scrollShadowEnabled\"\n [skyThemeClass]=\"{\n 'sky-padding-even-large': 'default'\n }\"\n (skyScrollShadow)=\"scrollShadowChange($event)\"\n >\n <ng-content select=\"sky-modal-content\" />\n </div>\n <div\n class=\"sky-modal-footer\"\n [ngStyle]=\"{\n 'box-shadow': scrollShadow?.bottomShadow\n }\"\n >\n <ng-content select=\"sky-modal-footer\" />\n </div>\n </div>\n</div>\n", styles: [".sky-modal:not(.sky-theme-modern *){--sky-override-modal-background-color: #fff;--sky-override-modal-border: 1px solid #cdcfd2;--sky-override-modal-dock-bottom: -15px;--sky-override-modal-dock-margin-left-right-bottom: -15px;--sky-override-modal-dock-padding-top: 15px;--sky-override-modal-dock-width: calc(100% + 30px) ;--sky-override-modal-full-page-margin-xs: 0;--sky-override-modal-full-page-margin: 0;--sky-override-modal-full-page-width: 100%;--sky-override-modal-header-bottom-border: 1px solid #e2e3e4;--sky-override-modal-header-padding: 9px 3px 9px 15px;--sky-override-modal-help-close-display: inline-block;--sky-override-modal-margin: 20px auto;--sky-override-modal-viewkept-toolbar-box-shadow: none;--sky-override-modal-viewkept-toolbar-padding-horizontal: 10px;--sky-override-modal-width-l: 900px;--sky-override-modal-width-m: 600px;--sky-override-modal-width-s: 300px;--sky-override-modal-xs-margin: 30px 10px 10px 10px}:host{--sky-viewport-top: 0;--sky-viewport-bottom: 0;--sky-viewport-left: 0;--sky-viewport-right: 0}.sky-modal{--sky-comp-override-list-header-background-color: initial;border:var(--sky-override-modal-border, var(--sky-border-width-container-base) solid var(--sky-color-border-container-base));position:fixed;width:auto;left:0;right:0;top:0;margin:var(--sky-override-modal-xs-margin, var(--sky-comp-modal-space-offset-xs-top) var(--sky-comp-modal-space-offset-xs-right) var(--sky-comp-modal-space-offset-xs-bottom) var(--sky-comp-modal-space-offset-xs-left));display:flex;flex-direction:column;overflow:hidden}.sky-modal:has(.sky-modal-content.sky-layout-host-fit){height:var(--sky-modal-content-max-height, 100%)}.sky-modal:focus{outline-style:dotted;outline-width:thin;outline-offset:-1px}.sky-modal-header:has(.sky-modal-header-content:empty){display:none}.sky-modal-btn-help,.sky-modal-btn-close{display:var(--sky-override-modal-help-close-display, none)}.sky-modal-full-page{width:var(--sky-override-modal-full-page-width, calc(100% - (var(--sky-override-modal-full-page-margin-xs, var(--sky-comp-modal-fullscreen-space-offset-xs-right)) + var(--sky-override-modal-full-page-margin-xs, var(--sky-comp-modal-fullscreen-space-offset-xs-left)))));margin:var(--sky-override-modal-full-page-margin-xs, var(--sky-comp-modal-fullscreen-space-offset-xs-top) var(--sky-comp-modal-fullscreen-space-offset-xs-right) var(--sky-comp-modal-fullscreen-space-offset-xs-bottom) var(--sky-comp-modal-fullscreen-space-offset-xs-left))}@media (min-width: 768px){.sky-modal:not(.sky-modal-full-page){margin:var(--sky-override-modal-margin, var(--sky-comp-modal-space-offset-sm-top) auto var(--sky-comp-modal-space-offset-sm-bottom))}.sky-modal-small{width:var(--sky-override-modal-width-s, var(--sky-size-width-modal-s))}.sky-modal-small .sky-modal-content,.sky-modal-small .sky-modal-header,.sky-modal-small .sky-modal-footer{max-width:var(--sky-override-modal-width-s, var(--sky-size-width-modal-s))}.sky-modal-medium{width:var(--sky-override-modal-width-m, var(--sky-size-width-modal-m))}.sky-modal-medium .sky-modal-content,.sky-modal-medium .sky-modal-header,.sky-modal-medium .sky-modal-footer{max-width:var(--sky-override-modal-width-m, var(--sky-size-width-modal-m))}.sky-modal-full-page{width:var(--sky-override-modal-full-page-width, calc(100% - (var(--sky-override-modal-full-page-margin, var(--sky-comp-modal-fullscreen-space-offset-sm-left)) + var(--sky-override-modal-full-page-margin, var(--sky-comp-modal-fullscreen-space-offset-sm-right)))));margin:var(--sky-override-modal-full-page-margin, var(--sky-comp-modal-fullscreen-space-offset-sm-top) var(--sky-comp-modal-fullscreen-space-offset-sm-right) var(--sky-comp-modal-fullscreen-space-offset-sm-bottom) var(--sky-comp-modal-fullscreen-space-offset-sm-left))}}@media (min-width: 920px){.sky-modal-large{width:var(--sky-override-modal-width-l, var(--sky-size-width-modal-l))}.sky-modal-large .sky-modal-content,.sky-modal-large .sky-modal-header,.sky-modal-large .sky-modal-footer{max-width:var(--sky-override-modal-width-l, var(--sky-size-width-modal-l))}}.sky-modal-content{background-color:var(--sky-override-modal-background-color, var(--sky-color-background-container-base));--sky-background-color-page-default: var( --sky-override-modal-background-color, var(--sky-color-background-container-base) )}.sky-modal-content:focus{outline-style:dotted;outline-width:thin;outline-offset:-1px}.sky-modal-content.sky-layout-host-fit{flex-grow:1;position:relative}.sky-modal-tiled .sky-modal-content{background-color:#eeeeef;--sky-background-color-page-default: $sky-background-color-neutral-light}.sky-modal-tiled .sky-modal-content ::ng-deep .sky-tile-title{font-family:BLKB Sans,Helvetica Neue,Arial,sans-serif;color:var(--sky-text-color-deemphasized);font-weight:300;font-size:19px}.sky-modal-header{padding:var(--sky-override-modal-header-padding, var(--sky-comp-modal-header-space-inset-top) var(--sky-comp-modal-header-space-inset-right) var(--sky-comp-modal-header-space-inset-bottom) var(--sky-comp-modal-header-space-inset-left));background-color:var(--sky-override-modal-background-color, var(--sky-color-background-container-base));border-bottom:var(--sky-override-modal-header-bottom-border);display:flex;align-items:baseline}.sky-modal-header-buttons{flex-shrink:.0001}.sky-modal-header-buttons .sky-btn{border:none;color:#686c73;cursor:pointer}.sky-modal-header-buttons .sky-btn:hover{color:#383a3d;transition:color .15s}.sky-modal-header-content{flex-grow:1}.sky-modal-header{flex-shrink:0;z-index:2}.sky-modal-content{overflow-y:auto}.sky-modal-footer{flex-shrink:0;z-index:2}.sky-modal-full-page .sky-modal-content{flex-grow:1}.sky-modal-content>::ng-deep sky-dock{bottom:var(--sky-override-modal-dock-bottom, 0);margin-left:var(--sky-override-modal-dock-margin-left-right-bottom, initial);margin-right:var(--sky-override-modal-dock-margin-left-right-bottom, initial);margin-bottom:var(--sky-override-modal-dock-margin-left-right-bottom, initial);padding-top:var(--sky-override-modal-dock-padding-top, initial);width:var(--sky-override-modal-dock-width, 100%)}.sky-modal-viewkeeper .sky-modal-header{box-shadow:none!important}.sky-modal-viewkeeper .sky-modal-content ::ng-deep sky-modal-content>.sky-viewkeeper-fixed{box-shadow:var(--sky-override-modal-viewkept-toolbar-box-shadow, var(--sky-elevation-overflow))}.sky-modal-viewkeeper .sky-modal-content ::ng-deep sky-modal-content>.sky-viewkeeper-fixed>sky-toolbar .sky-toolbar-container{background-color:var(--sky-override-modal-background-color, var(--sky-color-background-container-base));--sky-background-color-page-default: var( --sky-override-modal-background-color, var(--sky-color-background-container-base) );padding-left:var(--sky-override-modal-viewkept-toolbar-padding-horizontal, var(--sky-comp-modal-header-space-inset-left));padding-right:var(--sky-override-modal-viewkept-toolbar-padding-horizontal, var(--sky-comp-modal-header-space-inset-right))}\n"] }]
}], ctorParameters: () => [], propDecorators: { wrapperClass: [{
type: HostBinding,
args: ['class']
}], formErrors: [{
type: Input
}], headingText: [{
type: Input
}], helpKey: [{
type: Input
}], helpPopoverContent: [{
type: Input
}], helpPopoverTitle: [{
type: Input
}], ariaRole: [{
type: Input
}], tiledBody: [{
type: Input
}], ariaDescribedBy: [{
type: Input
}], ariaLabelledBy: [{
type: Input
}], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: false }] }], modalContentWrapperElement: [{
type: ViewChild,
args: ['modalContentWrapper', { read: ElementRef }]
}], onDocumentKeyUp: [{
type: HostListener,
args: ['document:keyup', ['$event']]
}], onDocumentKeyDown: [{
type: HostListener,
args: ['document:keydown', ['$event']]
}] } });
/**
* @internal
*/
class SkyConfirmComponent {
#ngUnsubscribe;
#config;
#modalInstance;
#confirmInstance;
#resourcesSvc;
#idSvc;
constructor() {
this.isOkType = false;
this.preserveWhiteSpace = false;
this.#ngUnsubscribe = new Subject();
this.#config = inject(SKY_CONFIRM_CONFIG);
this.#modalInstance = inject(SkyModalInstance);
this.#confirmInstance = inject(SkyConfirmInstance);
this.#resourcesSvc = inject(SkyLibResourcesService);
this.#idSvc = inject(SkyIdService);
this.#config.type ??= SkyConfirmType.OK;
if (this.#config.type === SkyConfirmType.Custom &&
this.#config.buttons &&
this.#config.buttons.length > 0) {
this.buttons = this.#getCustomButtons(this.#config.buttons);
}
else {
this.#getPresetButtons()
.pipe(takeUntil(this.#ngUnsubscribe))
.subscribe((buttons) => {
this.buttons = buttons;
});
}
this.message = this.#config.message;
this.body = this.#config.body;
// Using the service here instead of the directive due to the confirm
// component's "body" container being conditional and thus a template
// variable being unavailable at an outer scope
this.bodyId = this.#idSvc.generateId();
this.preserveWhiteSpace = !!this.#config.preserveWhiteSpace;
this.isOkType = this.#config.type === SkyConfirmType.OK;
// Closes the modal when requested by the confirm instance.
this.#confirmInstance.closed.subscribe((args) => {
this.#modalInstance.close(args);
});
this.#modalInstance.closed.subscribe((args) => {
// Close the confirm when the "escape" key is pressed (passes 'undefined')
// since this behavior is handled by the underlying modal component.
if (args.data === undefined) {
this.#confirmInstance.close({
action: 'cancel',
});
}
});
}
ngOnDestroy() {
this.#ngUnsubscribe.next();
this.#ngUnsubscribe.complete();
}
close(button) {
const result = {
action: button.action,
};
this.#confirmInstance.close(result);
}
#getPresetButtons() {
const emitter = new ReplaySubject(1);
this.#resourcesSvc
.getStrings({
cancel: 'skyux_confirm_dialog_default_cancel_text',
no: 'skyux_confirm_dialog_default_no_text',
ok: 'skyux_confirm_dialog_default_ok_text',
yes: 'skyux_confirm_dialog_default_yes_text',
})
.pipe(takeUntil(this.#ngUnsubscribe))
.subscribe((values) => {
const confirmButtons = [];
switch (this.#config.type) {
case SkyConfirmType.YesNoCancel:
case SkyConfirmType.YesCancel:
confirmButtons.push({
text: values.yes,
autofocus: true,
styleType: 'primary',
action: 'yes',
});
if (this.#config.type === SkyConfirmType.YesNoCancel) {
confirmButtons.push({
text: values.no,
styleType: 'default',
action: 'no',
});
}
confirmButtons.push({
text: values.cancel,
styleType: 'link',
action: 'cancel',
});
break;
default:
confirmButtons.push({
text: values.ok,
autofocus: true,
styleType: 'primary',
action: 'ok',
});
}
emitter.next(confirmButtons);
});
return emitter.asObservable();
}
#getCustomButtons(buttonConfig) {
return buttonConfig.map((config) => ({
text: config.text,
action: config.action,
styleType: config.styleType || 'default',
autofocus: config.autofocus || false,
}));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyConfirmComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: SkyConfirmComponent, isStandalone: true, selector: "sky-confirm", ngImport: i0, template: "<div class=\"sky-confirm\" [ngClass]=\"{ 'sky-confirm-type-ok': isOkType }\">\n <sky-modal\n ariaRole=\"alertdialog\"\n [ariaLabelledBy]=\"confirmMessage.id\"\n [ariaDescribedBy]=\"body ? bodyId : undefined\"\n >\n <sky-modal-content class=\"sky-confirm-content\">\n <!--\n The following \"magic comment\" keeps Prettier from adding line breaks\n inside the div and causing leading and trailing whitespace when\n `preserveWhiteSpace` is `true`.\n https://prettier.io/blog/2018/11/07/1.15.0.html#whitespace-sensitive-formatting\n -->\n <!-- display: inline -->\n <div\n #confirmMessage=\"skyId\"\n class=\"sky-confirm-message\"\n skyId\n [ngClass]=\"{\n 'sky-confirm-preserve-white-space': preserveWhiteSpace\n }\"\n [skyThemeClass]=\"{\n 'sky-font-display-4': 'default'\n }\"\n >{{ message }}</div\n >\n\n @if (body) {\n <!--\n The following \"magic comment\" keeps Prettier from adding line breaks\n inside the div and causing leading and trailing whitespace when\n `preserveWhiteSpace` is `true`.\n https://prettier.io/blog/2018/11/07/1.15.0.html#whitespace-sensitive-formatting\n -->\n <!-- display: inline -->\n <div\n class=\"sky-confirm-body\"\n [id]=\"bodyId\"\n [ngClass]=\"{\n 'sky-confirm-preserve-white-space': preserveWhiteSpace\n }\"\n >{{ body }}</div\n >\n }\n\n <div class=\"sky-confirm-buttons\">\n @for (button of buttons; track button.text) {\n <button\n type=\"button\"\n class=\"sky-btn\"\n [ngClass]=\"'sky-btn-' + button.styleType\"\n [attr.autofocus]=\"button.autofocus ? 'autofocus' : null\"\n (click)=\"close(button)\"\n >\n {{ button.text }}\n </button>\n }\n </div>\n </sky-modal-content>\n </sky-modal>\n</div>\n", styles: [".sky-confirm:not(.sky-theme-modern *){--sky-override-confirm-body-padding: 8px 0 0;--sky-override-confirm-btn-spacing: 5px;--sky-override-confirm-footer-padding: 20px 0 0;--sky-override-confirm-header-font-size: 16px;--sky-override-confirm-message-padding: 5px 0 0}.sky-confirm-content{padding:0}.sky-confirm-message{padding:var(--sky-override-confirm-message-padding, var(--sky-comp-modal-header-space-inset-top) var(--sky-comp-modal-header-space-inset-right) var(--sky-comp-modal-header-space-inset-bottom) var(--sky-comp-modal-header-space-inset-left));color:var(--sky-color-text-heading);font-size:var(--sky-override-confirm-header-font-size, var(--sky-font-size-heading-2))}.sky-confirm-body{padding:var(--sky-override-confirm-body-padding, var(--sky-comp-modal-content-space-inset-top) var(--sky-comp-modal-content-space-inset-right) var(--sky-comp-modal-content-space-inset-bottom) var(--sky-comp-modal-content-space-inset-left))}.sky-confirm-buttons{padding:var(--sky-override-confirm-footer-padding, var(--sky-comp-modal-footer-space-inset-top) var(--sky-comp-modal-footer-space-inset-right) var(--sky-comp-modal-footer-space-inset-bottom) var(--sky-comp-modal-footer-space-inset-left))}.sky-confirm-preserve-white-space{white-space:pre-wrap}.sky-confirm .sky-btn{margin-right:var(--sky-override-confirm-btn-spacing, var(--sky-space-gap-action_group-m))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: SkyIdModule }, { kind: "directive", type: i1.λ2, selector: "[skyId]", exportAs: ["skyId"] }, { kind: "component", type: SkyModalComponent, selector: "sky-modal", inputs: ["formErrors", "headingText", "helpKey", "helpPopoverContent", "helpPopoverTitle", "ariaRole", "tiledBody", "ariaDescribedBy", "ariaLabelledBy", "layout"] }, { kind: "component", type: SkyModalContentComponent, selector: "sky-modal-content" }, { kind: "ngmodule", type: SkyModalsResourcesModule }, { kind: "ngmodule", type: SkyThemeModule }, { kind: "directive", type: i5.λ2, selector: "[skyThemeClass]", inputs: ["class", "skyThemeClass"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyConfirmComponent, decorators: [{
type: Component,
args: [{ selector: 'sky-confirm', imports: [
CommonModule,
SkyIdModule,
SkyModalComponent,
SkyModalContentComponent,
SkyModalsResourcesModule,
SkyThemeModule,
], template: "<div class=\"sky-confirm\" [ngClass]=\"{ 'sky-confirm-type-ok': isOkType }\">\n <sky-modal\n ariaRole=\"alertdialog\"\n [ariaLabelledBy]=\"confirmMessage.id\"\n [ariaDescribedBy]=\"body ? bodyId : undefined\"\n >\n <sky-modal-content class=\"sky-confirm-content\">\n <!--\n The following \"magic comment\" keeps Prettier from adding line breaks\n inside the div and causing leading and trailing whitespace when\n `preserveWhiteSpace` is `true`.\n https://prettier.io/blog/2018/11/07/1.15.0.html#whitespace-sensitive-formatting\n -->\n <!-- display: inline -->\n <div\n #confirmMessage=\"skyId\"\n class=\"sky-confirm-message\"\n skyId\n [ngClass]=\"{\n 'sky-confirm-preserve-white-space': preserveWhiteSpace\n }\"\n [skyThemeClass]=\"{\n 'sky-font-display-4': 'default'\n }\"\n >{{ message }}</div\n >\n\n @if (body) {\n <!--\n The following \"magic comment\" keeps Prettier from adding line breaks\n inside the div and causing leading and trailing whitespace when\n `preserveWhiteSpace` is `true`.\n https://prettier.io/blog/2018/11/07/1.15.0.html#whitespace-sensitive-formatting\n -->\n <!-- display: inline -->\n <div\n class=\"sky-confirm-body\"\n [id]=\"bodyId\"\n [ngClass]=\"{\n 'sky-confirm-preserve-white-space': preserveWhiteSpace\n }\"\n >{{ body }}</div\n >\n }\n\n <div class=\"sky-confirm-buttons\">\n @for (button of buttons; track button.text) {\n <button\n type=\"button\"\n class=\"sky-btn\"\n [ngClass]=\"'sky-btn-' + button.styleType\"\n [attr.autofocus]=\"button.autofocus ? 'autofocus' : null\"\n (click)=\"close(button)\"\n >\n {{ button.text }}\n </button>\n }\n </div>\n </sky-modal-content>\n </sky-modal>\n</div>\n", styles: [".sky-confirm:not(.sky-theme-modern *){--sky-override-confirm-body-padding: 8px 0 0;--sky-override-confirm-btn-spacing: 5px;--sky-override-confirm-footer-padding: 20px 0 0;--sky-override-confirm-header-font-size: 16px;--sky-override-confirm-message-padding: 5px 0 0}.sky-confirm-content{padding:0}.sky-confirm-message{padding:var(--sky-override-confirm-message-padding, var(--sky-comp-modal-header-space-inset-top) var(--sky-comp-modal-header-space-inset-right) var(--sky-comp-modal-header-space-inset-bottom) var(--sky-comp-modal-header-space-inset-left));color:var(--sky-color-text-heading);font-size:var(--sky-override-confirm-header-font-size, var(--sky-font-size-heading-2))}.sky-confirm-body{padding:var(--sky-override-confirm-body-padding, var(--sky-comp-modal-content-space-inset-top) var(--sky-comp-modal-content-space-inset-right) var(--sky-comp-modal-content-space-inset-bottom) var(--sky-comp-modal-content-space-inset-left))}.sky-confirm-buttons{padding:var(--sky-override-confirm-footer-padding, var(--sky-comp-modal-footer-space-inset-top) var(--sky-comp-modal-footer-space-inset-right) var(--sky-comp-modal-footer-space-inset-bottom) var(--sky-comp-modal-footer-space-inset-left))}.sky-confirm-preserve-white-space{white-space:pre-wrap}.sky-confirm .sky-btn{margin-right:var(--sky-override-confirm-btn-spacing, var(--sky-space-gap-action_group-m))}\n"] }]
}], ctorParameters: () => [] });
/**
* Provided by the modal service to give the modal host
* component additional context and features.
* @internal
*/
class SkyModalHostContext {
constructor(args) {
this.args = args;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalHostContext, deps: [{ token: 'SkyModalHostContextArgs' }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalHostContext }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalHostContext, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Inject,
args: ['SkyModalHostContextArgs']
}] }] });
/**
* @internal
*/
class SkyModalAdapterService {
static { this.MODAL_BODY_FULL_CLASS = 'sky-modal-body-full-page'; }
static { this.MODAL_BODY_CLASS = 'sky-modal-body-open'; }
#docRef;
#bodyEl;
#coreAdapter = inject(SkyCoreAdapterService);
#windowRef;
#hostSiblingAriaHiddenCache = new Map();
constructor(windowRef) {
this.#windowRef = windowRef;
this.#docRef = this.#windowRef.nativeWindow.document;
this.#bodyEl = this.#windowRef.nativeWindow.document.body;
}
toggleFullPageModalClass(isAddFull) {
if (isAddFull) {
this.#addClassToBody(SkyModalAdapterService.MODAL_BODY_FULL_CLASS);
}
else {
this.#removeClassFromBody(SkyModalAdapterService.MODAL_BODY_FULL_CLASS);
}
}
setPageScroll(isAdd) {
if (isAdd) {
this.#addClassToBody(SkyModalAdapterService.MODAL_BODY_CLASS);
}
else {
this.#removeClassFromBody(SkyModalAdapterService.MODAL_BODY_CLASS);
}
}
getModalOpener() {
return this.#docRef.activeElement;
}
#addClassToBody(className) {
this.#bodyEl.classList.add(className);
}
#removeClassFromBody(className) {
this.#bodyEl.classList.remove(className);
}
scrollContentToTop(element) {
element.nativeElement.querySelector('.sky-modal-content').scrollTop = 0;
}
/**
* Hides siblings of modal-host from screen readers
* @param hostElRef reference to modal-host element
*/
hideHostSiblingsFromScreenReaders(hostElRef) {
const hostElement = hostElRef.nativeElement;
const hostSiblings = hostElement.parentElement?.children;
if (hostSiblings) {
for (const element of hostSiblings) {
if (element.contains(document.activeElement)) {
document.body.focus();
}
if (element !== hostElement &&
!element.hasAttribute('aria-live') &&
element.nodeName.toLowerCase() !== 'script' &&
element.nodeName.toLowerCase() !== 'style') {
// preserve previous aria-hidden status of elements outside of modal host
this.#hostSiblingAriaHiddenCache.set(element, element.getAttribute('aria-hidden'));
element.setAttribute('aria-hidden', 'true');
}
}
}
}
focusFirstElement(modalEl) {
/* istanbul ignore else */
/* handle the case where somehow there is a focused element already in the modal */
if (!(document.activeElement &&
modalEl.nativeElement.contains(document.activeElement))) {
const currentScrollX = window.pageXOffset;
const currentScrollY = window.pageYOffset;
const inputWithAutofocus = modalEl.nativeElement.querySelector('[autofocus]');
if (inputWithAutofocus) {
inputWithAutofocus.focus();
}
else {
this.#coreAdapter.getFocusableChildrenAndApplyFocus(modalEl, '.sky-modal-content', true);
}
window.scrollTo(currentScrollX, currentScrollY);
}
}
/**
* Restores modal-host siblings to screen reader status prior to modals being opened
*/
unhideOrRestoreHostSiblingsFromScreenReaders() {
this.#hostSiblingAriaHiddenCache.forEach((previousValue, element) => {
// if element had aria-hidden status prior, restore status
if (element.parentElement) {
if (previousValue) {
element.setAttribute('aria-hidden', previousValue);
}
else {
element.removeAttribute('aria-hidden');
}
}
});
this.#hostSiblingAriaHiddenCache.clear();
}
hidePreviousModalFromScreenReaders(topModal) {
if (topModal && topModal.nativeElement.previousElementSibling) {
topModal.nativeElement.previousElementSibling.setAttribute('aria-hidden', 'true');
}
}
unhidePreviousModalFromScreenReaders(topModal) {
if (topModal && topModal.nativeElement.previousElementSibling) {
topModal.nativeElement.previousElementSibling.removeAttribute('aria-hidden');
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalAdapterService, deps: [{ token: i1.SkyAppWindowRef }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalAdapterService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalAdapterService, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: i1.SkyAppWindowRef }] });
/**
* @internal
*/
class SkyModalHostComponent {
constructor() {
this.backdropZIndex = toSignal(SkyModalHostService.backdropZIndexChange);
this.modalCount = toSignal(SkyModalHostService.openModalCountChange);
this.#modalInstances = [];
this.#adapter = inject(SkyModalAdapterService);
this.#changeDetector = inject(ChangeDetectorRef);
this.#dynamicComponentSvc = inject(SkyDynamicComponentService);
this.#elRef = inject(ElementRef);
this.#environmentInjector = inject(EnvironmentInjector);
this.#modalHostContext = inject(SkyModalHostContext);
this.#router = inject(Router, { optional: true });
this.#windowRef = inject(SkyAppWindowRef);
}
#modalInstances;
#adapter;
#changeDetector;
#dynamicComponentSvc;
#elRef;
#environmentInjector;
#modalHostContext;
#router;
#windowRef;
ngOnDestroy() {
// Close all modal instances before disposing of the host container.
this.#closeAllModalInstances();
this.#modalHostContext.args.teardownCallback();
}
open(modalInstance, component, config, environmentInjector) {
/* Ignore coverage as we specify the target element and so the view child should never be undefined unless
* we were to call the `open` method in an early lifecycle hook. */
/* istanbul ignore next */
if (!this.target) {
return;
}
const params = Object.assign({}, config);
const hostService = new SkyModalHostService();
hostService.fullPage = !!params.fullPage;
const adapter = this.#adapter;
const modalOpener = adapter.getModalOpener();
let isOpen = true;
params.providers ||= [];
params.providers.push({
provide: SkyModalHostService,
useValue: hostService,
}, {
provide: SkyModalConfiguration,
useValue: params,
}, {
provide: SKY_STACKING_CONTEXT,
useValue: {
zIndex: new BehaviorSubject(hostService.getModalZIndex())
.asObservable()
.pipe(takeUntil(modalInstance.closed)),
},
});
adapter.setPageScroll(SkyModalHostService.openModalCount > 0);
adapter.toggleFullPageModalClass(SkyModalHostService.fullPageModalCount > 0);
environmentInjector ||= this.#environmentInjector;
const modalComponentRef = this.#dynamicComponentSvc.createComponent(component, {
environmentInjector: environmentInjector,
providers: params.providers,
viewContainerRef: this.target,
});
// modal element that was just opened
const modalElement = modalComponentRef.location;
modalInstance.adapter = this.#adapter;
modalInstance.componentRef = modalComponentRef;
this.#registerModalInstance(modalInstance);
// Adding a timeout to avoid ExpressionChangedAfterItHasBeenCheckedError.
// https://stackoverflow.com/questions/40562845
this.#windowRef.nativeWindow.setTimeout(() => {
this.#adapter.focusFirstElement(modalElement);
// hiding all elements at the modal-host level from screen readers when the a modal is opened
this.#adapter.hideHostSiblingsFromScreenReaders(this.#elRef);
if (SkyModalHostService.openModalCount > 1 &&
SkyModalHostService.topModal === hostService) {
// hiding the lower modals when more than one modal is opened
this.#adapter.hidePreviousModalFromScreenReaders(modalElement);
}
});
const closeModal = () => {
// unhide siblings if last modal is closing
if (SkyModalHostService.openModalCount === 1) {
this.#adapter.unhideOrRestoreHostSiblingsFromScreenReaders();
}
else if (SkyModalHostService.topModal === hostService) {
// if there are more than 1 modal then unhide the one behind this one before closing it
this.#adapter.unhidePreviousModalFromScreenReaders(modalElement);
}
hostService.destroy();
adapter.setPageScroll(SkyModalHostService.openModalCount > 0);
adapter.toggleFullPageModalClass(SkyModalHostService.fullPageModalCount > 0);
/* istanbul ignore else */
/* sanity check */
if (modalOpener && modalOpener.focus) {
modalOpener.focus();
}
modalComponentRef.destroy();
};
hostService.openHelp.subscribe((helpKey) => {
modalInstance.openHelp(helpKey);
});
hostService.close.subscribe(() => {
modalInstance.close();
});
this.#router?.events.pipe(takeWhile(() => isOpen)).subscribe((event) => {
/* istanbul ignore else */
if (event instanceof NavigationStart) {
modalInstance.close();
}
});
modalInstance.closed.subscribe(() => {
isOpen = false;
this.#unregisterModalInstance(modalInstance);
closeModal();
});
// Necessary if the host was created via a consumer's lifecycle hook such as ngOnInit
this.#changeDetector.detectChanges();
}
#registerModalInstance(instance) {
this.#modalInstances.push(instance);
}
#unregisterModalInstance(instance) {
this.#modalInstances.slice(this.#modalInstances.indexOf(instance), 1);
}
#closeAllModalInstances() {
for (const instance of this.#modalInstances) {
instance.close();
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: SkyModalHostComponent, isStandalone: true, selector: "sky-modal-host", viewQueries: [{ propertyName: "target", first: true, predicate: ["target"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: "<div\n class=\"sky-modal-host-backdrop\"\n [hidden]=\"modalCount() === 0\"\n [ngStyle]=\"{\n zIndex: backdropZIndex()\n }\"\n></div>\n<div #target></div>\n", styles: [".sky-modal-host-backdrop:not(.sky-theme-modern *){--sky-override-modal-host-backdrop-color: rgba(0, 0, 0, .5)}.sky-modal-host-backdrop{background-color:var(--sky-override-modal-host-backdrop-color, var(--sky-color-background-scrim));position:fixed;inset:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: SkyModalsResourcesModule }], viewProviders: [SkyModalAdapterService] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalHostComponent, decorators: [{
type: Component,
args: [{ selector: 'sky-modal-host', viewProviders: [SkyModalAdapterService], imports: [CommonModule, RouterModule, SkyModalsResourcesModule], template: "<div\n class=\"sky-modal-host-backdrop\"\n [hidden]=\"modalCount() === 0\"\n [ngStyle]=\"{\n zIndex: backdropZIndex()\n }\"\n></div>\n<div #target></div>\n", styles: [".sky-modal-host-backdrop:not(.sky-theme-modern *){--sky-override-modal-host-backdrop-color: rgba(0, 0, 0, .5)}.sky-modal-host-backdrop{background-color:var(--sky-override-modal-host-backdrop-color, var(--sky-color-background-scrim));position:fixed;inset:0}\n"] }]
}], propDecorators: { target: [{
type: ViewChild,
args: ['target', {
read: ViewContainerRef,
static: true,
}]
}] } });
/**
* A service that launches modals.
*/
class SkyModalService {
#dynamicComponentService;
#environmentInjector = inject(EnvironmentInjector);
constructor(dynamicComponentService) {
this.#dynamicComponentService = dynamicComponentService;
}
/**
* @internal
* Removes the modal host from the DOM.
*/
dispose() {
if (SkyModalService.host) {
this.#dynamicComponentService.removeComponent(SkyModalService.host);
SkyModalService.host = undefined;
}
}
/**
* Opens a modal using the specified component.
* @param component Determines the component to render.
* @param {SkyModalConfigurationInterface} config Specifies configuration options for the modal.
*/
open(component, config) {
const modalInstance = new SkyModalInstance();
if (!SkyModalService.host) {
SkyModalService.host = this.#createHostComponent();
}
const params = this.#getConfigFromParameter(config);
params.providers ||= [];
params.providers.push({
provide: SkyModalInstance,
useValue: modalInstance,
});
if (SkyModalService.host) {
SkyModalService.host.instance.open(modalInstance, component, params, this.#environmentInjector);
}
return modalInstance;
}
#getConfigFromParameter(providersOrConfig) {
const defaultParams = {
providers: [],
fullPage: false,
size: 'medium',
tiledBody: false,
};
let params = {};
let method = undefined;
// Object Literal Lookup for backwards compatibility.
method = {
'providers?': Object.assign({}, defaultParams, {
providers: providersOrConfig,
}),
config: Object.assign({}, defaultParams, providersOrConfig),
};
if (Array.isArray(providersOrConfig) === true) {
params = method['providers?'];
}
else {
params = method['config'];
}
return params;
}
#createHostComponent() {
const componentRef = this.#dynamicComponentService.createComponent(SkyModalHostComponent, {
environmentInjector: this.#environmentInjector,
providers: [
{
provide: SkyModalHostContext,
useValue: new SkyModalHostContext({
teardownCallback: () => {
this.dispose();
},
}),
},
],
});
return componentRef;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalService, deps: [{ token: i1.SkyDynamicComponentService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}], ctorParameters: () => [{ type: i1.SkyDynamicComponentService }] });
/**
* A service that launches modals.
* @internal
* @deprecated Use `SkyModalService` to open a standalone component instead.
*/
class SkyModalLegacyService extends SkyModalService {
/* istanbul ignore next */
constructor(dynamicComponentSvc) {
super(dynamicComponentSvc);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalLegacyService, deps: [{ token: i1.SkyDynamicComponentLegacyService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalLegacyService, providedIn: 'any' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalLegacyService, decorators: [{
type: Injectable,
args: [{
// Must be 'any' so that the modal component is created in the context of its module's injector.
// If set to 'root', the component's dependency injections would only be derived from the root
// injector and may lose context if the modal was opened from within a lazy-loaded module.
providedIn: 'any',
}]
}], ctorParameters: () => [{ type: i1.SkyDynamicComponentLegacyService }] });
/**
* Launches a dialog.
*/
class SkyConfirmService {
#modalService;
constructor(modalService) {
this.#modalService = modalService;
}
/**
* Opens a dialog using the specified options.
* @param config Specifies configuration options for the dialog.
*/
open(config) {
const confirmInstance = new SkyConfirmInstance();
this.#modalService.open(SkyConfirmComponent, {
providers: [
{
provide: SKY_CONFIRM_CONFIG,
useValue: config,
},
{
provide: SkyConfirmInstance,
useValue: confirmInstance,
},
],
});
return confirmInstance;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyConfirmService, deps: [{ token: SkyModalService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyConfirmService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyConfirmService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}], ctorParameters: () => [{ type: SkyModalService }] });
/**
* Specifies content to display in the modal's footer.
*/
class SkyModalFooterComponent {
constructor() {
this.errorsSvc = inject(SkyModalErrorsService);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalFooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: SkyModalFooterComponent, isStandalone: true, selector: "sky-modal-footer", hostDirectives: [{ directive: i1.SkyResponsiveHostDirective }], ngImport: i0, template: "<div class=\"sky-modal-footer-container\">\n <div aria-live=\"polite\">\n @if (errorsSvc.formErrors | async; as formErrors) {\n @if (formErrors.length > 0) {\n <div\n class=\"sky-modal-footer-errors sky-margin-stacked-lg sky-errors-overflow\"\n tabindex=\"0\"\n >\n @for (formError of formErrors; track formError.message) {\n <sky-status-indicator\n descriptionType=\"error\"\n indicatorType=\"danger\"\n [ngClass]=\"{\n 'sky-margin-stacked-sm':\n formErrors.indexOf(formError) < formErrors.length - 1,\n 'footer-error': true\n }\"\n >\n {{ formError.message }}\n </sky-status-indicator>\n }\n </div>\n }\n }\n </div>\n <ng-content />\n</div>\n", styles: [".sky-modal-footer-container:not(.sky-theme-modern *){--sky-override-modal-footer-border-top: 1px solid #e2e3e4;--sky-override-modal-footer-btn-btn-link-margin: -2px;--sky-override-modal-footer-btn-btn-margin: 10px;--sky-override-modal-footer-padding: 15px}sky-modal-footer{display:block}.sky-modal-footer-container{background-color:var(--sky-override-modal-background-color, var(--sky-color-background-container-base));border-top:var(--sky-override-modal-footer-border-top, none);padding:var(--sky-override-modal-footer-padding, var(--sky-comp-modal-footer-space-inset-top) var(--sky-comp-modal-footer-space-inset-right) var(--sky-comp-modal-footer-space-inset-bottom) var(--sky-comp-modal-footer-space-inset-left))}.sky-modal-footer-container .sky-btn+.sky-btn{margin-left:var(--sky-override-modal-footer-btn-btn-margin, var(--sky-space-gap-action_group-m))}.sky-modal-footer-container .sky-btn+.sky-btn-link{margin-left:var(--sky-override-modal-footer-btn-btn-link-margin, var(--sky-space-gap-action_group-m))}.sky-modal-footer-container .sky-modal-footer-errors .footer-error{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: SkyStatusIndicatorModule }, { kind: "component", type: i3$1.λ10, selector: "sky-status-indicator", inputs: ["indicatorType", "descriptionType", "customDescription", "helpPopoverContent", "helpPopoverTitle", "helpKey"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }], encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalFooterComponent, decorators: [{
type: Component,
args: [{ hostDirectives: [SkyResponsiveHostDirective], selector: 'sky-modal-footer', encapsulation: ViewEncapsulation.None, imports: [CommonModule, SkyStatusIndicatorModule], template: "<div class=\"sky-modal-footer-container\">\n <div aria-live=\"polite\">\n @if (errorsSvc.formErrors | async; as formErrors) {\n @if (formErrors.length > 0) {\n <div\n class=\"sky-modal-footer-errors sky-margin-stacked-lg sky-errors-overflow\"\n tabindex=\"0\"\n >\n @for (formError of formErrors; track formError.message) {\n <sky-status-indicator\n descriptionType=\"error\"\n indicatorType=\"danger\"\n [ngClass]=\"{\n 'sky-margin-stacked-sm':\n formErrors.indexOf(formError) < formErrors.length - 1,\n 'footer-error': true\n }\"\n >\n {{ formError.message }}\n </sky-status-indicator>\n }\n </div>\n }\n }\n </div>\n <ng-content />\n</div>\n", styles: [".sky-modal-footer-container:not(.sky-theme-modern *){--sky-override-modal-footer-border-top: 1px solid #e2e3e4;--sky-override-modal-footer-btn-btn-link-margin: -2px;--sky-override-modal-footer-btn-btn-margin: 10px;--sky-override-modal-footer-padding: 15px}sky-modal-footer{display:block}.sky-modal-footer-container{background-color:var(--sky-override-modal-background-color, var(--sky-color-background-container-base));border-top:var(--sky-override-modal-footer-border-top, none);padding:var(--sky-override-modal-footer-padding, var(--sky-comp-modal-footer-space-inset-top) var(--sky-comp-modal-footer-space-inset-right) var(--sky-comp-modal-footer-space-inset-bottom) var(--sky-comp-modal-footer-space-inset-left))}.sky-modal-footer-container .sky-btn+.sky-btn{margin-left:var(--sky-override-modal-footer-btn-btn-margin, var(--sky-space-gap-action_group-m))}.sky-modal-footer-container .sky-btn+.sky-btn-link{margin-left:var(--sky-override-modal-footer-btn-btn-link-margin, var(--sky-space-gap-action_group-m))}.sky-modal-footer-container .sky-modal-footer-errors .footer-error{display:block}\n"] }]
}] });
/**
* Provides a way to mark a modal as "dirty" and displays a confirmation
* message when a user closes the modal without saving.
*/
class SkyModalIsDirtyDirective {
constructor() {
/**
* Whether the user edited an input on the modal.
* @required
*/
this.isDirty = false;
this.#ngUnsubscribe = new Subject();
this.#modalInstance = inject(SkyModalInstance);
this.#confirmSvc = inject(SkyConfirmService);
this.#resourcesSvc = inject(SkyLibResourcesService);
}
#ngUnsubscribe;
#modalInstance;
#confirmSvc;
#resourcesSvc;
ngOnInit() {
this.#modalInstance.beforeClose
.pipe(takeUntil(this.#ngUnsubscribe))
.subscribe((handler) => this.#promptIfDirty(handler));
}
ngOnDestroy() {
this.#ngUnsubscribe.next();
this.#ngUnsubscribe.complete();
}
#promptIfDirty(handler) {
if (this.isDirty &&
(handler.closeArgs.reason === 'close' ||
handler.closeArgs.reason === 'cancel')) {
this.#resourcesSvc
.getStrings({
message: 'skyux_modal_dirty_default_message',
discardActionText: 'skyux_modal_dirty_default_discard_changes_text',
keepActionText: 'skyux_modal_dirty_default_keep_working_text',
})
.subscribe((textValues) => {
const discardAction = 'discard';
const keepAction = 'keep';
this.#confirmSvc
.open({
message: textValues.message,
buttons: [
{
action: discardAction,
text: textValues.discardActionText,
styleType: 'primary',
},
{
action: keepAction,
text: textValues.keepActionText,
styleType: 'link',
},
],
type: SkyConfirmType.Custom,
})
.closed.subscribe((args) => {
if (args.action === discardAction) {
handler.closeModal();
}
});
});
}
else {
handler.closeModal();
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalIsDirtyDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.15", type: SkyModalIsDirtyDirective, isStandalone: true, selector: "sky-modal[isDirty]", inputs: { isDirty: "isDirty" }, host: { properties: { "attr.data-sky-modal-is-dirty": "this.isDirty" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalIsDirtyDirective, decorators: [{
type: Directive,
args: [{
// Since this is limited to sky-modal, it should be safe to
// leave off the sky prefix.
// eslint-disable-next-line @angular-eslint/directive-selector
selector: 'sky-modal[isDirty]',
}]
}], propDecorators: { isDirty: [{
type: Input
}, {
type: HostBinding,
args: ['attr.data-sky-modal-is-dirty']
}] } });
class SkyModalModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: SkyModalModule, imports: [SkyModalComponent,
SkyModalContentComponent,
SkyModalFooterComponent,
SkyModalHeaderComponent,
SkyModalIsDirtyDirective], exports: [SkyModalComponent,
SkyModalContentComponent,
SkyModalFooterComponent,
SkyModalHeaderComponent,
SkyModalIsDirtyDirective] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalModule, imports: [SkyModalComponent,
SkyModalFooterComponent,
SkyModalHeaderComponent] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SkyModalModule, decorators: [{
type: NgModule,
args: [{
imports: [
SkyModalComponent,
SkyModalContentComponent,
SkyModalFooterComponent,
SkyModalHeaderComponent,
SkyModalIsDirtyDirective,
],
exports: [
SkyModalComponent,
SkyModalContentComponent,
SkyModalFooterComponent,
SkyModalHeaderComponent,
SkyModalIsDirtyDirective,
],
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { SkyConfirmInstance, SkyConfirmModule, SkyConfirmService, SkyConfirmType, SkyModalBeforeCloseHandler, SkyModalCloseArgs, SkyModalConfiguration, SkyModalErrorsService, SkyModalHostService, SkyModalInstance, SkyModalLegacyService, SkyModalModule, SkyModalService, SkyConfirmComponent as λ1, SkyModalContentComponent as λ2, SkyModalFooterComponent as λ3, SkyModalHeaderComponent as λ4, SkyModalComponent as λ5, SkyModalIsDirtyDirective as λ6 };
//# sourceMappingURL=skyux-modals.mjs.map