@skyux/modals 8.7.2 → 9.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/documentation.json +56 -56
  2. package/esm2022/lib/modules/confirm/confirm.component.mjs +112 -0
  3. package/{esm2020 → esm2022}/lib/modules/confirm/confirm.module.mjs +13 -13
  4. package/esm2022/lib/modules/confirm/confirm.service.mjs +54 -0
  5. package/esm2022/lib/modules/modal/modal-adapter.service.mjs +99 -0
  6. package/esm2022/lib/modules/modal/modal-component-adapter.service.mjs +101 -0
  7. package/{esm2020 → esm2022}/lib/modules/modal/modal-configuration.mjs +4 -4
  8. package/{esm2020 → esm2022}/lib/modules/modal/modal-content.component.mjs +4 -4
  9. package/esm2022/lib/modules/modal/modal-errors.service.mjs +21 -0
  10. package/{esm2020 → esm2022}/lib/modules/modal/modal-footer.component.mjs +4 -4
  11. package/{esm2020 → esm2022}/lib/modules/modal/modal-header.component.mjs +4 -4
  12. package/{esm2020 → esm2022}/lib/modules/modal/modal-host-context.mjs +4 -4
  13. package/esm2022/lib/modules/modal/modal-host.component.mjs +163 -0
  14. package/esm2022/lib/modules/modal/modal-host.service.mjs +62 -0
  15. package/esm2022/lib/modules/modal/modal-instance.mjs +123 -0
  16. package/esm2022/lib/modules/modal/modal-is-dirty.directive.mjs +94 -0
  17. package/esm2022/lib/modules/modal/modal-scroll-shadow.directive.mjs +129 -0
  18. package/esm2022/lib/modules/modal/modal.component.mjs +229 -0
  19. package/{esm2020 → esm2022}/lib/modules/modal/modal.module.mjs +29 -29
  20. package/esm2022/lib/modules/modal/modal.service.mjs +97 -0
  21. package/esm2022/lib/modules/shared/sky-modals-resources.module.mjs +61 -0
  22. package/esm2022/testing/confirm/confirm-button-harness.mjs +46 -0
  23. package/esm2022/testing/confirm/confirm-harness.mjs +90 -0
  24. package/esm2022/testing/modal/modal-harness.mjs +75 -0
  25. package/esm2022/testing/modal-fixture.mjs +143 -0
  26. package/{fesm2020 → fesm2022}/skyux-modals-testing.mjs +60 -73
  27. package/{fesm2020 → fesm2022}/skyux-modals-testing.mjs.map +1 -1
  28. package/fesm2022/skyux-modals.mjs +1502 -0
  29. package/{fesm2015 → fesm2022}/skyux-modals.mjs.map +1 -1
  30. package/lib/modules/modal/modal-is-dirty.directive.d.ts +1 -1
  31. package/lib/modules/modal/modal.component.d.ts +1 -1
  32. package/package.json +16 -24
  33. package/esm2020/lib/modules/confirm/confirm.component.mjs +0 -114
  34. package/esm2020/lib/modules/confirm/confirm.service.mjs +0 -57
  35. package/esm2020/lib/modules/modal/modal-adapter.service.mjs +0 -101
  36. package/esm2020/lib/modules/modal/modal-component-adapter.service.mjs +0 -104
  37. package/esm2020/lib/modules/modal/modal-errors.service.mjs +0 -24
  38. package/esm2020/lib/modules/modal/modal-host.component.mjs +0 -164
  39. package/esm2020/lib/modules/modal/modal-host.service.mjs +0 -65
  40. package/esm2020/lib/modules/modal/modal-instance.mjs +0 -127
  41. package/esm2020/lib/modules/modal/modal-is-dirty.directive.mjs +0 -93
  42. package/esm2020/lib/modules/modal/modal-scroll-shadow.directive.mjs +0 -127
  43. package/esm2020/lib/modules/modal/modal.component.mjs +0 -228
  44. package/esm2020/lib/modules/modal/modal.service.mjs +0 -99
  45. package/esm2020/lib/modules/shared/sky-modals-resources.module.mjs +0 -61
  46. package/esm2020/testing/confirm/confirm-button-harness.mjs +0 -46
  47. package/esm2020/testing/confirm/confirm-harness.mjs +0 -97
  48. package/esm2020/testing/modal/modal-harness.mjs +0 -81
  49. package/esm2020/testing/modal-fixture.mjs +0 -145
  50. package/fesm2015/skyux-modals-testing.mjs +0 -409
  51. package/fesm2015/skyux-modals-testing.mjs.map +0 -1
  52. package/fesm2015/skyux-modals.mjs +0 -1522
  53. package/fesm2020/skyux-modals.mjs +0 -1510
  54. package/fesm2020/skyux-modals.mjs.map +0 -1
  55. /package/{esm2020 → esm2022}/index.mjs +0 -0
  56. /package/{esm2020 → esm2022}/lib/modules/confirm/confirm-button-action.mjs +0 -0
  57. /package/{esm2020 → esm2022}/lib/modules/confirm/confirm-button-config.mjs +0 -0
  58. /package/{esm2020 → esm2022}/lib/modules/confirm/confirm-button-style-type.mjs +0 -0
  59. /package/{esm2020 → esm2022}/lib/modules/confirm/confirm-button.mjs +0 -0
  60. /package/{esm2020 → esm2022}/lib/modules/confirm/confirm-closed-event-args.mjs +0 -0
  61. /package/{esm2020 → esm2022}/lib/modules/confirm/confirm-config-token.mjs +0 -0
  62. /package/{esm2020 → esm2022}/lib/modules/confirm/confirm-config.mjs +0 -0
  63. /package/{esm2020 → esm2022}/lib/modules/confirm/confirm-instance.mjs +0 -0
  64. /package/{esm2020 → esm2022}/lib/modules/confirm/confirm-type.mjs +0 -0
  65. /package/{esm2020 → esm2022}/lib/modules/modal/modal-before-close-handler.mjs +0 -0
  66. /package/{esm2020 → esm2022}/lib/modules/modal/modal-close-args.mjs +0 -0
  67. /package/{esm2020 → esm2022}/lib/modules/modal/modal-error.mjs +0 -0
  68. /package/{esm2020 → esm2022}/lib/modules/modal/modal-host-context-args.mjs +0 -0
  69. /package/{esm2020 → esm2022}/lib/modules/modal/modal-scroll-shadow-event-args.mjs +0 -0
  70. /package/{esm2020 → esm2022}/lib/modules/modal/modal.interface.mjs +0 -0
  71. /package/{esm2020 → esm2022}/skyux-modals.mjs +0 -0
  72. /package/{esm2020 → esm2022}/testing/confirm/confirm-button-harness-filters.mjs +0 -0
  73. /package/{esm2020 → esm2022}/testing/modal/modal-harness-filters.mjs +0 -0
  74. /package/{esm2020 → esm2022}/testing/public-api.mjs +0 -0
  75. /package/{esm2020 → esm2022}/testing/skyux-modals-testing.mjs +0 -0
@@ -0,0 +1,1502 @@
1
+ import * as i0 from '@angular/core';
2
+ import { EventEmitter, NgModule, Component, ViewEncapsulation, Injectable, inject, Inject, Injector, ViewContainerRef, Optional, ViewChild, InjectionToken, Directive, Output, HostListener, ChangeDetectorRef, ElementRef, Host, HostBinding, Input } from '@angular/core';
3
+ import * as i1 from '@angular/common';
4
+ import { CommonModule } from '@angular/common';
5
+ import * as i3 from '@skyux/core';
6
+ import { SkyMediaQueryService, SkyResizeObserverMediaQueryService, SKY_STACKING_CONTEXT, SkyLiveAnnouncerService, SkyDockLocation, SkyDockService, SkyIdModule, SkyTrimModule } from '@skyux/core';
7
+ import * as i2$1 from '@skyux/theme';
8
+ import { SkyTheme, SkyThemeModule } from '@skyux/theme';
9
+ import * as i3$1 from '@angular/router';
10
+ import { NavigationStart, RouterModule } from '@angular/router';
11
+ import * as i2 from '@skyux/indicators';
12
+ import { SkyIconModule, SkyStatusIndicatorModule } from '@skyux/indicators';
13
+ import * as i2$2 from '@skyux/i18n';
14
+ import { getLibStringForLocale, SkyI18nModule, SKY_LIB_RESOURCES_PROVIDERS, SkyLibResourcesService } from '@skyux/i18n';
15
+ import { BehaviorSubject, Subject, ReplaySubject } from 'rxjs';
16
+ import { takeUntil, takeWhile, take } from 'rxjs/operators';
17
+
18
+ class SkyConfirmInstance {
19
+ constructor() {
20
+ /**
21
+ * Fires when users select an action to close the dialog. This event
22
+ * returns a `SkyConfirmCloseEventArgs` object with information about the button that
23
+ * users select. It returns the `'cancel'` action when users press the <kbd>Escape</kbd> key.
24
+ */
25
+ this.closed = new EventEmitter();
26
+ }
27
+ }
28
+
29
+ var SkyConfirmType;
30
+ (function (SkyConfirmType) {
31
+ /**
32
+ * Allows you to define your own buttons using the `buttons` property of `SkyConfirmConfig`.
33
+ */
34
+ SkyConfirmType[SkyConfirmType["Custom"] = 0] = "Custom";
35
+ /**
36
+ * Displays one button with an **OK** label and an `'ok'` action.
37
+ */
38
+ SkyConfirmType[SkyConfirmType["OK"] = 1] = "OK";
39
+ /**
40
+ * Displays two buttons with **Yes** and **Cancel** labels.
41
+ * @deprecated Use the `Custom` type to follow the guidance that labels
42
+ * should clearly indicate the actions that occur when users select buttons.
43
+ */
44
+ SkyConfirmType[SkyConfirmType["YesCancel"] = 2] = "YesCancel";
45
+ /**
46
+ * Displays three buttons with **Yes**, **No**, and **Cancel** labels.
47
+ * @deprecated Use the `Custom` type to follow the guidance that labels
48
+ * should clearly indicate the actions that occur when users select buttons.
49
+ */
50
+ SkyConfirmType[SkyConfirmType["YesNoCancel"] = 3] = "YesNoCancel";
51
+ })(SkyConfirmType || (SkyConfirmType = {}));
52
+
53
+ /**
54
+ * NOTICE: DO NOT MODIFY THIS FILE!
55
+ * The contents of this file were automatically generated by
56
+ * the 'ng generate @skyux/i18n:lib-resources-module lib/modules/shared/sky-modals' schematic.
57
+ * To update this file, simply rerun the command.
58
+ */
59
+ const RESOURCES = {
60
+ 'EN-US': {
61
+ skyux_confirm_dialog_default_ok_text: { message: 'OK' },
62
+ skyux_confirm_dialog_default_yes_text: { message: 'Yes' },
63
+ skyux_confirm_dialog_default_no_text: { message: 'No' },
64
+ skyux_confirm_dialog_default_cancel_text: { message: 'Cancel' },
65
+ skyux_modal_close: { message: 'Close modal' },
66
+ skyux_modal_open_help: { message: 'Open Help' },
67
+ skyux_modal_footer_cancel_button: { message: 'Cancel' },
68
+ skyux_modal_footer_primary_button: { message: 'Save' },
69
+ skyux_modal_dirty_default_message: {
70
+ message: 'Are you sure you want to discard your changes?',
71
+ },
72
+ skyux_modal_dirty_default_discard_changes_text: {
73
+ message: 'Discard changes',
74
+ },
75
+ skyux_modal_dirty_default_keep_working_text: { message: 'Keep working' },
76
+ },
77
+ };
78
+ class SkyModalsResourcesProvider {
79
+ getString(localeInfo, name) {
80
+ return getLibStringForLocale(RESOURCES, localeInfo.locale, name);
81
+ }
82
+ }
83
+ /**
84
+ * Import into any component library module that needs to use resource strings.
85
+ */
86
+ class SkyModalsResourcesModule {
87
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalsResourcesModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
88
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.1.7", ngImport: i0, type: SkyModalsResourcesModule, exports: [SkyI18nModule] }); }
89
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalsResourcesModule, providers: [
90
+ {
91
+ provide: SKY_LIB_RESOURCES_PROVIDERS,
92
+ useClass: SkyModalsResourcesProvider,
93
+ multi: true,
94
+ },
95
+ ], imports: [SkyI18nModule] }); }
96
+ }
97
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalsResourcesModule, decorators: [{
98
+ type: NgModule,
99
+ args: [{
100
+ exports: [SkyI18nModule],
101
+ providers: [
102
+ {
103
+ provide: SKY_LIB_RESOURCES_PROVIDERS,
104
+ useClass: SkyModalsResourcesProvider,
105
+ multi: true,
106
+ },
107
+ ],
108
+ }]
109
+ }] });
110
+
111
+ /**
112
+ * Specifies content to display in the modal's body.
113
+ */
114
+ class SkyModalContentComponent {
115
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
116
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.7", type: SkyModalContentComponent, selector: "sky-modal-content", ngImport: i0, template: "<ng-content></ng-content>\n", styles: ["sky-modal-content{display:block;min-height:100%}.sky-theme-modern sky-modal-content{padding:10px 30px 30px}\n"], encapsulation: i0.ViewEncapsulation.None }); }
117
+ }
118
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalContentComponent, decorators: [{
119
+ type: Component,
120
+ args: [{ selector: 'sky-modal-content', encapsulation: ViewEncapsulation.None, template: "<ng-content></ng-content>\n", styles: ["sky-modal-content{display:block;min-height:100%}.sky-theme-modern sky-modal-content{padding:10px 30px 30px}\n"] }]
121
+ }] });
122
+
123
+ /**
124
+ * @internal
125
+ */
126
+ class SkyModalErrorsService {
127
+ #formErrors = new BehaviorSubject(undefined);
128
+ constructor() {
129
+ this.formErrors = this.#formErrors.asObservable();
130
+ }
131
+ updateErrors(value) {
132
+ this.#formErrors.next(value);
133
+ }
134
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalErrorsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
135
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalErrorsService }); }
136
+ }
137
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalErrorsService, decorators: [{
138
+ type: Injectable
139
+ }], ctorParameters: function () { return []; } });
140
+
141
+ /**
142
+ * Specifies content to display in the modal's footer.
143
+ */
144
+ class SkyModalFooterComponent {
145
+ constructor() {
146
+ this.errorsSvc = inject(SkyModalErrorsService);
147
+ }
148
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalFooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
149
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.7", type: SkyModalFooterComponent, selector: "sky-modal-footer", ngImport: i0, template: "<div class=\"sky-modal-footer-container sky-padding-even-large\">\n <div aria-live=\"polite\">\n <div\n *ngIf=\"errorsSvc.formErrors | async as formErrors\"\n class=\"sky-modal-footer-errors sky-margin-stacked-lg\"\n >\n <sky-status-indicator\n *ngFor=\"let formError of formErrors\"\n [ngClass]=\"{\n 'sky-margin-stacked-lg':\n formErrors.indexOf(formError) < formErrors.length - 1,\n 'footer-error': true\n }\"\n descriptionType=\"error\"\n indicatorType=\"danger\"\n >\n {{ formError.message }}\n </sky-status-indicator>\n </div>\n </div>\n <ng-content></ng-content>\n</div>\n", styles: [".sky-modal-footer-container{background-color:#fff;border-top:1px solid #e2e3e4}.sky-modal-footer-container .sky-btn-link:first-child{margin-left:-12px}.sky-modal-footer-container .sky-btn+.sky-btn{margin-left:10px}.sky-modal-footer-container .sky-btn+.sky-btn-link{margin-left:-2px}.sky-modal-footer-container .sky-modal-footer-errors{max-height:100px;overflow-y:auto}.sky-modal-footer-container .sky-modal-footer-errors .footer-error{display:block}.sky-theme-modern .sky-modal-footer-container{border-top:none;padding:20px 30px}.sky-theme-modern .sky-modal-footer-container .sky-btn-link:first-child{margin-left:0}.sky-theme-modern .sky-modal-footer-container .sky-btn+.sky-btn-link{margin-left:var(--sky-compat-modal-footer-adjacent-btn-btn-link-margin, 10px)}.sky-theme-modern-dark .sky-modal-footer-container{background-color:transparent}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.λ10, selector: "sky-status-indicator", inputs: ["indicatorType", "descriptionType", "customDescription"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], encapsulation: i0.ViewEncapsulation.None }); }
150
+ }
151
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalFooterComponent, decorators: [{
152
+ type: Component,
153
+ args: [{ selector: 'sky-modal-footer', encapsulation: ViewEncapsulation.None, template: "<div class=\"sky-modal-footer-container sky-padding-even-large\">\n <div aria-live=\"polite\">\n <div\n *ngIf=\"errorsSvc.formErrors | async as formErrors\"\n class=\"sky-modal-footer-errors sky-margin-stacked-lg\"\n >\n <sky-status-indicator\n *ngFor=\"let formError of formErrors\"\n [ngClass]=\"{\n 'sky-margin-stacked-lg':\n formErrors.indexOf(formError) < formErrors.length - 1,\n 'footer-error': true\n }\"\n descriptionType=\"error\"\n indicatorType=\"danger\"\n >\n {{ formError.message }}\n </sky-status-indicator>\n </div>\n </div>\n <ng-content></ng-content>\n</div>\n", styles: [".sky-modal-footer-container{background-color:#fff;border-top:1px solid #e2e3e4}.sky-modal-footer-container .sky-btn-link:first-child{margin-left:-12px}.sky-modal-footer-container .sky-btn+.sky-btn{margin-left:10px}.sky-modal-footer-container .sky-btn+.sky-btn-link{margin-left:-2px}.sky-modal-footer-container .sky-modal-footer-errors{max-height:100px;overflow-y:auto}.sky-modal-footer-container .sky-modal-footer-errors .footer-error{display:block}.sky-theme-modern .sky-modal-footer-container{border-top:none;padding:20px 30px}.sky-theme-modern .sky-modal-footer-container .sky-btn-link:first-child{margin-left:0}.sky-theme-modern .sky-modal-footer-container .sky-btn+.sky-btn-link{margin-left:var(--sky-compat-modal-footer-adjacent-btn-btn-link-margin, 10px)}.sky-theme-modern-dark .sky-modal-footer-container{background-color:transparent}\n"] }]
154
+ }] });
155
+
156
+ /**
157
+ * Specifies a header for the modal.
158
+ */
159
+ class SkyModalHeaderComponent {
160
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
161
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.7", type: SkyModalHeaderComponent, selector: "sky-modal-header", ngImport: i0, template: "<h2\n class=\"sky-font-emphasized\"\n [skyThemeClass]=\"{\n 'sky-font-heading-4': 'default',\n 'sky-font-display-3': 'modern'\n }\"\n skyTrim\n>\n <ng-content></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: ["h2{margin:0;line-height:1.2;display:inline}:host-context(.sky-theme-modern.sky-theme-mode-dark) h2{color:#fbfcfe}.sky-theme-modern.sky-theme-mode-dark h2{color:#fbfcfe}\n"], dependencies: [{ kind: "directive", type: i2$1.λ2, selector: "[skyThemeClass]", inputs: ["class", "skyThemeClass"] }, { kind: "directive", type: i3.λ4, selector: "[skyTrim]" }] }); }
162
+ }
163
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalHeaderComponent, decorators: [{
164
+ type: Component,
165
+ args: [{ selector: 'sky-modal-header', template: "<h2\n class=\"sky-font-emphasized\"\n [skyThemeClass]=\"{\n 'sky-font-heading-4': 'default',\n 'sky-font-display-3': 'modern'\n }\"\n skyTrim\n>\n <ng-content></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: ["h2{margin:0;line-height:1.2;display:inline}:host-context(.sky-theme-modern.sky-theme-mode-dark) h2{color:#fbfcfe}.sky-theme-modern.sky-theme-mode-dark h2{color:#fbfcfe}\n"] }]
166
+ }] });
167
+
168
+ /**
169
+ * @internal
170
+ */
171
+ class SkyModalAdapterService {
172
+ static { this.MODAL_BODY_FULL_CLASS = 'sky-modal-body-full-page'; }
173
+ static { this.MODAL_BODY_CLASS = 'sky-modal-body-open'; }
174
+ #docRef;
175
+ #bodyEl;
176
+ #windowRef;
177
+ #hostSiblingAriaHiddenCache = new Map();
178
+ constructor(windowRef) {
179
+ this.#windowRef = windowRef;
180
+ this.#docRef = this.#windowRef.nativeWindow.document;
181
+ this.#bodyEl = this.#windowRef.nativeWindow.document.body;
182
+ }
183
+ toggleFullPageModalClass(isAddFull) {
184
+ if (isAddFull) {
185
+ this.#addClassToBody(SkyModalAdapterService.MODAL_BODY_FULL_CLASS);
186
+ }
187
+ else {
188
+ this.#removeClassFromBody(SkyModalAdapterService.MODAL_BODY_FULL_CLASS);
189
+ }
190
+ }
191
+ setPageScroll(isAdd) {
192
+ if (isAdd) {
193
+ this.#addClassToBody(SkyModalAdapterService.MODAL_BODY_CLASS);
194
+ }
195
+ else {
196
+ this.#removeClassFromBody(SkyModalAdapterService.MODAL_BODY_CLASS);
197
+ }
198
+ }
199
+ getModalOpener() {
200
+ return this.#docRef.activeElement;
201
+ }
202
+ #addClassToBody(className) {
203
+ this.#bodyEl.classList.add(className);
204
+ }
205
+ #removeClassFromBody(className) {
206
+ this.#bodyEl.classList.remove(className);
207
+ }
208
+ scrollContentToTop(element) {
209
+ element.nativeElement.querySelector('.sky-modal-content').scrollTop = 0;
210
+ }
211
+ /**
212
+ * Hides siblings of modal-host from screen readers
213
+ * @param hostElRef reference to modal-host element
214
+ */
215
+ hideHostSiblingsFromScreenReaders(hostElRef) {
216
+ const hostElement = hostElRef.nativeElement;
217
+ const hostSiblings = hostElement.parentElement.children;
218
+ for (let i = 0; i < hostSiblings.length; i++) {
219
+ const element = hostSiblings[i];
220
+ if (element !== hostElement &&
221
+ !element.hasAttribute('aria-live') &&
222
+ element.nodeName.toLowerCase() !== 'script' &&
223
+ element.nodeName.toLowerCase() !== 'style') {
224
+ // preserve previous aria-hidden status of elements outside of modal host
225
+ this.#hostSiblingAriaHiddenCache.set(element, element.getAttribute('aria-hidden'));
226
+ element.setAttribute('aria-hidden', 'true');
227
+ }
228
+ }
229
+ }
230
+ /**
231
+ * Restores modal-host siblings to screen reader status prior to modals being opened
232
+ */
233
+ unhideOrRestoreHostSiblingsFromScreenReaders() {
234
+ this.#hostSiblingAriaHiddenCache.forEach((previousValue, element) => {
235
+ // if element had aria-hidden status prior, restore status
236
+ if (element.parentElement) {
237
+ if (previousValue) {
238
+ element.setAttribute('aria-hidden', previousValue);
239
+ }
240
+ else {
241
+ element.removeAttribute('aria-hidden');
242
+ }
243
+ }
244
+ });
245
+ this.#hostSiblingAriaHiddenCache.clear();
246
+ }
247
+ hidePreviousModalFromScreenReaders(topModal) {
248
+ if (topModal && topModal.nativeElement.previousElementSibling) {
249
+ topModal.nativeElement.previousElementSibling.setAttribute('aria-hidden', 'true');
250
+ }
251
+ }
252
+ unhidePreviousModalFromScreenReaders(topModal) {
253
+ if (topModal && topModal.nativeElement.previousElementSibling) {
254
+ topModal.nativeElement.previousElementSibling.removeAttribute('aria-hidden');
255
+ }
256
+ }
257
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalAdapterService, deps: [{ token: i3.SkyAppWindowRef }], target: i0.ɵɵFactoryTarget.Injectable }); }
258
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalAdapterService }); }
259
+ }
260
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalAdapterService, decorators: [{
261
+ type: Injectable
262
+ }], ctorParameters: function () { return [{ type: i3.SkyAppWindowRef }]; } });
263
+
264
+ /**
265
+ * @internal
266
+ */
267
+ class SkyModalConfiguration {
268
+ constructor() {
269
+ this.size = 'medium';
270
+ }
271
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalConfiguration, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
272
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalConfiguration, providedIn: 'any' }); }
273
+ }
274
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalConfiguration, decorators: [{
275
+ type: Injectable,
276
+ args: [{
277
+ providedIn: 'any',
278
+ }]
279
+ }], ctorParameters: function () { return []; } });
280
+
281
+ const BASE_Z_INDEX = 1040;
282
+ const modalHosts = [];
283
+ /**
284
+ * @internal
285
+ * @dynamic
286
+ */
287
+ class SkyModalHostService {
288
+ static get openModalCount() {
289
+ return modalHosts.length;
290
+ }
291
+ static get fullPageModalCount() {
292
+ const fullPageModals = modalHosts.filter((modal) => modal.fullPage);
293
+ return fullPageModals.length;
294
+ }
295
+ static get backdropZIndex() {
296
+ return BASE_Z_INDEX + modalHosts.length * 10;
297
+ }
298
+ static get topModal() {
299
+ return modalHosts[modalHosts.length - 1];
300
+ }
301
+ constructor() {
302
+ this.close = new Subject();
303
+ this.fullPage = false;
304
+ this.openHelp = new Subject();
305
+ this.zIndex = this.#calculateZIndex();
306
+ modalHosts.push(this);
307
+ }
308
+ getModalZIndex() {
309
+ return this.zIndex;
310
+ }
311
+ onClose() {
312
+ this.close.next();
313
+ }
314
+ onOpenHelp(helpKey) {
315
+ this.openHelp.next(helpKey);
316
+ }
317
+ destroy() {
318
+ modalHosts.splice(modalHosts.indexOf(this), 1);
319
+ }
320
+ #calculateZIndex() {
321
+ const zIndexArray = modalHosts.map((hostService) => hostService.zIndex);
322
+ if (zIndexArray.length === 0) {
323
+ return BASE_Z_INDEX + 11;
324
+ }
325
+ else {
326
+ const currentMaxZIndex = Math.max(...zIndexArray);
327
+ return currentMaxZIndex + 10;
328
+ }
329
+ }
330
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalHostService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
331
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalHostService, providedIn: 'root' }); }
332
+ }
333
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalHostService, decorators: [{
334
+ type: Injectable,
335
+ args: [{
336
+ providedIn: 'root',
337
+ }]
338
+ }], ctorParameters: function () { return []; } });
339
+
340
+ /**
341
+ * Provided by the modal service to give the modal host
342
+ * component additional context and features.
343
+ * @internal
344
+ */
345
+ class SkyModalHostContext {
346
+ constructor(args) {
347
+ this.args = args;
348
+ }
349
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalHostContext, deps: [{ token: 'SkyModalHostContextArgs' }], target: i0.ɵɵFactoryTarget.Injectable }); }
350
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalHostContext }); }
351
+ }
352
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalHostContext, decorators: [{
353
+ type: Injectable
354
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
355
+ type: Inject,
356
+ args: ['SkyModalHostContextArgs']
357
+ }] }]; } });
358
+
359
+ /**
360
+ * @internal
361
+ */
362
+ class SkyModalHostComponent {
363
+ get modalOpen() {
364
+ return SkyModalHostService.openModalCount > 0;
365
+ }
366
+ get backdropZIndex() {
367
+ return SkyModalHostService.backdropZIndex;
368
+ }
369
+ #resolver;
370
+ #adapter;
371
+ #injector;
372
+ #router;
373
+ #changeDetector;
374
+ #modalHostContext;
375
+ #elRef;
376
+ #modalInstances = [];
377
+ constructor(resolver, adapter, injector, changeDetector, modalHostContext, elRef, router) {
378
+ this.#resolver = resolver;
379
+ this.#adapter = adapter;
380
+ this.#injector = injector;
381
+ this.#router = router;
382
+ this.#changeDetector = changeDetector;
383
+ this.#modalHostContext = modalHostContext;
384
+ this.#elRef = elRef;
385
+ }
386
+ ngOnDestroy() {
387
+ // Close all modal instances before disposing of the host container.
388
+ this.#closeAllModalInstances();
389
+ this.#modalHostContext.args.teardownCallback();
390
+ }
391
+ open(modalInstance, component, config) {
392
+ /* Ignore coverage as we specify the target element and so the view child should never be undefined unless
393
+ * we were to call the `open` method in an early lifecycle hook. */
394
+ /* istanbul ignore next */
395
+ if (!this.target) {
396
+ return;
397
+ }
398
+ const params = Object.assign({}, config);
399
+ const factory = this.#resolver.resolveComponentFactory(component);
400
+ const hostService = new SkyModalHostService();
401
+ hostService.fullPage = !!params.fullPage;
402
+ const adapter = this.#adapter;
403
+ const modalOpener = adapter.getModalOpener();
404
+ let isOpen = true;
405
+ params.providers ||= [];
406
+ params.providers.push({
407
+ provide: SkyModalHostService,
408
+ useValue: hostService,
409
+ }, {
410
+ provide: SkyModalConfiguration,
411
+ useValue: params,
412
+ }, {
413
+ provide: SkyMediaQueryService,
414
+ useExisting: SkyResizeObserverMediaQueryService,
415
+ }, {
416
+ provide: SKY_STACKING_CONTEXT,
417
+ useValue: {
418
+ zIndex: new BehaviorSubject(hostService.getModalZIndex())
419
+ .asObservable()
420
+ .pipe(takeUntil(modalInstance.closed)),
421
+ },
422
+ });
423
+ adapter.setPageScroll(SkyModalHostService.openModalCount > 0);
424
+ adapter.toggleFullPageModalClass(SkyModalHostService.fullPageModalCount > 0);
425
+ const providers = params.providers || /* istanbul ignore next */ [];
426
+ const injector = Injector.create({
427
+ providers,
428
+ parent: this.#injector,
429
+ });
430
+ const modalComponentRef = this.target.createComponent(factory, undefined, injector);
431
+ // modal element that was just opened
432
+ const modalElement = modalComponentRef.location;
433
+ modalInstance.adapter = this.#adapter;
434
+ modalInstance.componentRef = modalComponentRef;
435
+ this.#registerModalInstance(modalInstance);
436
+ // hiding all elements at the modal-host level from screen readers when the a modal is opened
437
+ this.#adapter.hideHostSiblingsFromScreenReaders(this.#elRef);
438
+ if (SkyModalHostService.openModalCount > 1 &&
439
+ SkyModalHostService.topModal === hostService) {
440
+ // hiding the lower modals when more than one modal is opened
441
+ this.#adapter.hidePreviousModalFromScreenReaders(modalElement);
442
+ }
443
+ const closeModal = () => {
444
+ // unhide siblings if last modal is closing
445
+ if (SkyModalHostService.openModalCount === 1) {
446
+ this.#adapter.unhideOrRestoreHostSiblingsFromScreenReaders();
447
+ }
448
+ else if (SkyModalHostService.topModal === hostService) {
449
+ // if there are more than 1 modal then unhide the one behind this one before closing it
450
+ this.#adapter.unhidePreviousModalFromScreenReaders(modalElement);
451
+ }
452
+ hostService.destroy();
453
+ adapter.setPageScroll(SkyModalHostService.openModalCount > 0);
454
+ adapter.toggleFullPageModalClass(SkyModalHostService.fullPageModalCount > 0);
455
+ /* istanbul ignore else */
456
+ /* sanity check */
457
+ if (modalOpener && modalOpener.focus) {
458
+ modalOpener.focus();
459
+ }
460
+ modalComponentRef.destroy();
461
+ };
462
+ hostService.openHelp.subscribe((helpKey) => {
463
+ modalInstance.openHelp(helpKey);
464
+ });
465
+ hostService.close.subscribe(() => {
466
+ modalInstance.close();
467
+ });
468
+ this.#router?.events.pipe(takeWhile(() => isOpen)).subscribe((event) => {
469
+ /* istanbul ignore else */
470
+ if (event instanceof NavigationStart) {
471
+ modalInstance.close();
472
+ }
473
+ });
474
+ modalInstance.closed.subscribe(() => {
475
+ isOpen = false;
476
+ this.#unregisterModalInstance(modalInstance);
477
+ closeModal();
478
+ });
479
+ // Necessary if the host was created via a consumer's lifecycle hook such as ngOnInit
480
+ this.#changeDetector.detectChanges();
481
+ }
482
+ #registerModalInstance(instance) {
483
+ this.#modalInstances.push(instance);
484
+ }
485
+ #unregisterModalInstance(instance) {
486
+ this.#modalInstances.slice(this.#modalInstances.indexOf(instance), 1);
487
+ }
488
+ #closeAllModalInstances() {
489
+ for (const instance of this.#modalInstances) {
490
+ instance.close();
491
+ }
492
+ }
493
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalHostComponent, deps: [{ token: i0.ComponentFactoryResolver }, { token: SkyModalAdapterService }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }, { token: SkyModalHostContext }, { token: i0.ElementRef }, { token: i3$1.Router, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
494
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.7", type: SkyModalHostComponent, 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]=\"!modalOpen\"\n [ngStyle]=\"{\n zIndex: backdropZIndex\n }\"\n></div>\n<div #target></div>\n", styles: [".sky-modal-host-backdrop{background-color:#00000080;position:fixed;inset:0}\n"], dependencies: [{ kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], viewProviders: [SkyModalAdapterService] }); }
495
+ }
496
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalHostComponent, decorators: [{
497
+ type: Component,
498
+ args: [{ selector: 'sky-modal-host', viewProviders: [SkyModalAdapterService], template: "<div\n class=\"sky-modal-host-backdrop\"\n [hidden]=\"!modalOpen\"\n [ngStyle]=\"{\n zIndex: backdropZIndex\n }\"\n></div>\n<div #target></div>\n", styles: [".sky-modal-host-backdrop{background-color:#00000080;position:fixed;inset:0}\n"] }]
499
+ }], ctorParameters: function () { return [{ type: i0.ComponentFactoryResolver }, { type: SkyModalAdapterService }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }, { type: SkyModalHostContext }, { type: i0.ElementRef }, { type: i3$1.Router, decorators: [{
500
+ type: Optional
501
+ }] }]; }, propDecorators: { target: [{
502
+ type: ViewChild,
503
+ args: ['target', {
504
+ read: ViewContainerRef,
505
+ static: true,
506
+ }]
507
+ }] } });
508
+
509
+ /**
510
+ * @internal
511
+ */
512
+ const SKY_CONFIRM_CONFIG = new InjectionToken('SkyConfirmConfig');
513
+
514
+ /**
515
+ * Properties about the modal close action and a method to close the modal.
516
+ */
517
+ class SkyModalBeforeCloseHandler {
518
+ constructor(closeModal, closeArgs) {
519
+ this.closeArgs = closeArgs;
520
+ this.closeModal = closeModal;
521
+ }
522
+ }
523
+
524
+ /**
525
+ * Contains an object with the data passed from users when
526
+ * a modal is closed and the reason that the modal was closed.
527
+ */
528
+ class SkyModalCloseArgs {
529
+ }
530
+
531
+ class SkyModalInstance {
532
+ /**
533
+ * An event that the modal instance emits when it is about to close.
534
+ * It emits a `SkyModalBeforeCloseHandler` object with a `closeModal` method
535
+ * that closes the modal. If a subscription exists for this event,
536
+ * the modal does not close until the subscriber calls the `closeModal` method.
537
+ */
538
+ get beforeClose() {
539
+ return this.#_beforeClose;
540
+ }
541
+ /**
542
+ * An event that the modal instance emits when it closes.
543
+ * It emits a `SkyModalCloseArgs` object with a `data` property that includes
544
+ * data passed from users on close or save and a `reason` property that indicates
545
+ * whether the modal was saved or closed without saving.
546
+ * The `reason` property accepts any string value.
547
+ * Common examples include `"cancel"`, `"close"`, and `"save"`.
548
+ */
549
+ get closed() {
550
+ return this.#_closed;
551
+ }
552
+ /**
553
+ * An event that the modal instance emits when users click
554
+ * the <i class="fa fa-question-circle" aria-hidden="true"></i> button.
555
+ * If a `helpKey` parameter was specified, the `helpOpened` event broadcasts the `helpKey`.
556
+ */
557
+ get helpOpened() {
558
+ return this.#_helpOpened;
559
+ }
560
+ /**
561
+ * Sets the component adapter for the instance. This is used internally for actions such as scrolling the content.
562
+ * @internal
563
+ */
564
+ set adapter(value) {
565
+ this.#adapter = value;
566
+ }
567
+ /**
568
+ * 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.
569
+ * @internal
570
+ */
571
+ set componentRef(value) {
572
+ this.componentInstance = value.instance;
573
+ this.#elementRef = value.location;
574
+ }
575
+ #_beforeClose = new Subject();
576
+ #_closed = new Subject();
577
+ #_helpOpened = new Subject();
578
+ #adapter;
579
+ #elementRef;
580
+ /**
581
+ * Closes the modal instance.
582
+ * @param result Specifies an object to emit to subscribers of the `closed` event of the
583
+ * modal instance. The `SkyModalInstance` provider can be injected into a component's constructor
584
+ * so that this `close` function can be called from a button in the `sky-modal-footer`.
585
+ * @param reason Specifies the reason for the modal closing, with the default reason of `"close"`.
586
+ * @param ignoreBeforeClose Indicates whether to ignore the modal instance's `beforeClose` event.
587
+ */
588
+ close(result, reason, ignoreBeforeClose) {
589
+ if (reason === undefined) {
590
+ reason = 'close';
591
+ }
592
+ this.#closeModal(reason, result, ignoreBeforeClose);
593
+ }
594
+ /**
595
+ * Closes the modal instance with `reason="cancel"`.
596
+ * @param result Specifies an object to emit to subscribers of the `closed` event of the modal
597
+ * instance. The `SkyModalInstance` provider can be injected into a component's constructor so
598
+ * that this cancel function can be called from a button in the `sky-modal-footer`.
599
+ */
600
+ cancel(result) {
601
+ this.#closeModal('cancel', result);
602
+ }
603
+ /**
604
+ * Closes the modal instance with `reason="save"`.
605
+ * @param result Specifies an object to emit to subscribers of the `closed` event of the modal
606
+ * instance. The `SkyModalInstance` provider can be injected into a component's constructor so
607
+ * that this `save` function can be called from a button in `the sky-modal-footer`.
608
+ */
609
+ save(result) {
610
+ this.#closeModal('save', result);
611
+ }
612
+ /**
613
+ * Scrolls the modal content area to the top of its scrollable area.
614
+ */
615
+ scrollContentToTop() {
616
+ if (this.#adapter && this.#elementRef) {
617
+ this.#adapter.scrollContentToTop(this.#elementRef);
618
+ }
619
+ }
620
+ /**
621
+ * Triggers the `helpOpened` event that broadcasts a `helpKey` parameter to open
622
+ * when users click the <i class="fa fa-question-circle" aria-hidden="true"></i> button.
623
+ * @param helpKey Specifies a string to emit to subscribers of
624
+ * the modal instance's `helpOpened` event. Consumers can inject the `SkyModalInstance` provider
625
+ * into a component's constructor to call the `openHelp` function in the modal template.
626
+ */
627
+ openHelp(helpKey) {
628
+ this.#_helpOpened.next(helpKey);
629
+ }
630
+ #closeModal(type, result, ignoreBeforeClose = false) {
631
+ const args = new SkyModalCloseArgs();
632
+ args.reason = type;
633
+ args.data = result;
634
+ if (this.#_beforeClose.observers.length === 0 || ignoreBeforeClose) {
635
+ this.#notifyClosed(args);
636
+ }
637
+ else {
638
+ this.#_beforeClose.next(new SkyModalBeforeCloseHandler(() => {
639
+ this.#notifyClosed(args);
640
+ }, args));
641
+ }
642
+ }
643
+ #notifyClosed(args) {
644
+ this.#_closed.next(args);
645
+ this.#_closed.complete();
646
+ this.#_beforeClose.complete();
647
+ this.#_helpOpened.complete();
648
+ }
649
+ }
650
+
651
+ /**
652
+ * @internal
653
+ */
654
+ class SkyModalComponentAdapterService {
655
+ #coreAdapter;
656
+ constructor(coreAdapter) {
657
+ this.#coreAdapter = coreAdapter;
658
+ }
659
+ handleWindowChange(modalEl) {
660
+ const boundedHeightEl = modalEl.nativeElement.querySelector('.sky-modal');
661
+ const fullPageModalEl = modalEl.nativeElement.querySelector('.sky-modal-full-page');
662
+ /*
663
+ Set modal height equal to max height of window (accounting for padding above and below modal)
664
+ */
665
+ const newHeight = window.innerHeight - 40;
666
+ boundedHeightEl.style.maxHeight = newHeight.toString() + 'px';
667
+ if (fullPageModalEl) {
668
+ this.#setFullPageHeight(fullPageModalEl);
669
+ }
670
+ else {
671
+ /*
672
+ IE11 doesn't handle flex and max-height correctly so we have to explicitly add
673
+ max-height to the content that accounts for standard header and footer height.
674
+ */
675
+ const modalContentEl = modalEl.nativeElement.querySelector('.sky-modal-content');
676
+ const contentHeight = newHeight - 114;
677
+ modalContentEl.style.maxHeight = contentHeight.toString() + 'px';
678
+ }
679
+ }
680
+ isFocusInFirstItem(event, list) {
681
+ /* istanbul ignore next */
682
+ /* sanity check */
683
+ const eventTarget = event.target || event.srcElement;
684
+ return list.length > 0 && eventTarget === list[0];
685
+ }
686
+ isFocusInLastItem(event, list) {
687
+ /* istanbul ignore next */
688
+ /* sanity check */
689
+ const eventTarget = event.target || event.srcElement;
690
+ return list.length > 0 && eventTarget === list[list.length - 1];
691
+ }
692
+ isModalFocused(event, modalEl) {
693
+ /* istanbul ignore next */
694
+ /* sanity check */
695
+ const eventTarget = event.target || event.srcElement;
696
+ return (modalEl &&
697
+ eventTarget === modalEl.nativeElement.querySelector('.sky-modal-dialog'));
698
+ }
699
+ focusLastElement(list) {
700
+ if (list.length > 0) {
701
+ list[list.length - 1].focus();
702
+ return true;
703
+ }
704
+ return false;
705
+ }
706
+ focusFirstElement(list) {
707
+ if (list.length > 0) {
708
+ list[0].focus();
709
+ return true;
710
+ }
711
+ return false;
712
+ }
713
+ modalContentHasDirectChildViewkeeper(modalContentEl) {
714
+ return !!modalContentEl.nativeElement.querySelector('sky-modal-content > .sky-viewkeeper-fixed');
715
+ }
716
+ modalOpened(modalEl) {
717
+ /* istanbul ignore else */
718
+ /* handle the case where somehow there is a focused element already in the modal */
719
+ if (!(document.activeElement &&
720
+ modalEl.nativeElement.contains(document.activeElement))) {
721
+ const currentScrollX = window.pageXOffset;
722
+ const currentScrollY = window.pageYOffset;
723
+ const inputWithAutofocus = modalEl.nativeElement.querySelector('[autofocus]');
724
+ if (inputWithAutofocus) {
725
+ inputWithAutofocus.focus();
726
+ }
727
+ else {
728
+ this.#coreAdapter.getFocusableChildrenAndApplyFocus(modalEl, '.sky-modal-content', true);
729
+ }
730
+ window.scrollTo(currentScrollX, currentScrollY);
731
+ }
732
+ }
733
+ #setFullPageHeight(fullPageModalEl) {
734
+ const windowHeight = window.innerHeight;
735
+ const fullPageModalStyle = getComputedStyle(fullPageModalEl);
736
+ const marginTopBottom = parseInt(fullPageModalStyle.marginTop, 10) +
737
+ parseInt(fullPageModalStyle.marginBottom, 10);
738
+ const fullPageModalHeight = windowHeight - marginTopBottom + 'px';
739
+ fullPageModalEl.style.height = fullPageModalHeight;
740
+ fullPageModalEl.style.maxHeight = fullPageModalHeight;
741
+ }
742
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalComponentAdapterService, deps: [{ token: i3.SkyCoreAdapterService }], target: i0.ɵɵFactoryTarget.Injectable }); }
743
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalComponentAdapterService }); }
744
+ }
745
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalComponentAdapterService, decorators: [{
746
+ type: Injectable
747
+ }], ctorParameters: function () { return [{ type: i3.SkyCoreAdapterService }]; } });
748
+
749
+ /**
750
+ * Raises an event when the box shadow for the modal header or footer should be adjusted
751
+ * based on the scroll position of the host element.
752
+ * @internal
753
+ */
754
+ class SkyModalScrollShadowDirective {
755
+ #currentShadow;
756
+ #currentTheme;
757
+ #mutationObserver;
758
+ #ngUnsubscribe;
759
+ #elRef;
760
+ #mutationObserverSvc;
761
+ #ngZone;
762
+ #themeSvc;
763
+ constructor(elRef, mutationObserverSvc, ngZone, themeSvc) {
764
+ this.skyModalScrollShadow = new EventEmitter();
765
+ this.#ngUnsubscribe = new Subject();
766
+ this.#elRef = elRef;
767
+ this.#mutationObserverSvc = mutationObserverSvc;
768
+ this.#ngZone = ngZone;
769
+ this.#themeSvc = themeSvc;
770
+ }
771
+ windowResize() {
772
+ this.#checkForShadow();
773
+ }
774
+ scroll() {
775
+ this.#checkForShadow();
776
+ }
777
+ ngOnInit() {
778
+ if (this.#themeSvc) {
779
+ this.#themeSvc.settingsChange
780
+ .pipe(takeUntil(this.#ngUnsubscribe))
781
+ .subscribe((themeSettings) => {
782
+ this.#currentTheme = themeSettings.currentSettings.theme;
783
+ if (this.#currentTheme === SkyTheme.presets.modern) {
784
+ this.#initMutationObserver();
785
+ }
786
+ else {
787
+ this.#emitShadow({
788
+ bottomShadow: 'none',
789
+ topShadow: 'none',
790
+ });
791
+ this.#destroyMutationObserver();
792
+ }
793
+ });
794
+ }
795
+ }
796
+ ngOnDestroy() {
797
+ this.#ngUnsubscribe.next();
798
+ this.#ngUnsubscribe.complete();
799
+ this.#destroyMutationObserver();
800
+ }
801
+ #initMutationObserver() {
802
+ if (!this.#mutationObserver) {
803
+ const el = this.#elRef.nativeElement;
804
+ // MutationObserver is patched by Zone.js and therefore becomes part of the
805
+ // Angular change detection cycle, but this can lead to infinite loops in some
806
+ // scenarios. This will keep MutationObserver from triggering change detection.
807
+ this.#ngZone.runOutsideAngular(() => {
808
+ this.#mutationObserver = this.#mutationObserverSvc.create(() => {
809
+ this.#checkForShadow();
810
+ });
811
+ this.#mutationObserver.observe(el, {
812
+ attributes: true,
813
+ characterData: true,
814
+ childList: true,
815
+ subtree: true,
816
+ });
817
+ });
818
+ }
819
+ }
820
+ #destroyMutationObserver() {
821
+ if (this.#mutationObserver) {
822
+ this.#mutationObserver.disconnect();
823
+ this.#mutationObserver = undefined;
824
+ }
825
+ }
826
+ #checkForShadow() {
827
+ if (this.#currentTheme === SkyTheme.presets.modern) {
828
+ const el = this.#elRef.nativeElement;
829
+ const topShadow = this.#buildShadowStyle(el.scrollTop);
830
+ const bottomShadow = this.#buildShadowStyle(el.scrollHeight - el.scrollTop - el.clientHeight);
831
+ this.#emitShadow({
832
+ bottomShadow,
833
+ topShadow,
834
+ });
835
+ }
836
+ }
837
+ #buildShadowStyle(pixelsFromEnd) {
838
+ // Progressively darken the shadow until the user scrolls 30 pixels from the top or bottom
839
+ // of the scrollable element, with a max opacity of 0.3.
840
+ const opacity = Math.min(pixelsFromEnd / 30, 1) * 0.3;
841
+ return opacity > 0 ? `0px 1px 8px 0px rgba(0, 0, 0, ${opacity})` : 'none';
842
+ }
843
+ #emitShadow(shadow) {
844
+ if (!this.#currentShadow ||
845
+ this.#currentShadow.bottomShadow !== shadow.bottomShadow ||
846
+ this.#currentShadow.topShadow !== shadow.topShadow) {
847
+ this.skyModalScrollShadow.emit(shadow);
848
+ this.#currentShadow = shadow;
849
+ }
850
+ }
851
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalScrollShadowDirective, deps: [{ token: i0.ElementRef }, { token: i3.SkyMutationObserverService }, { token: i0.NgZone }, { token: i2$1.SkyThemeService, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
852
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.1.7", type: SkyModalScrollShadowDirective, selector: "[skyModalScrollShadow]", outputs: { skyModalScrollShadow: "skyModalScrollShadow" }, host: { listeners: { "window:resize": "windowResize()", "scroll": "scroll()" } }, ngImport: i0 }); }
853
+ }
854
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalScrollShadowDirective, decorators: [{
855
+ type: Directive,
856
+ args: [{
857
+ selector: '[skyModalScrollShadow]',
858
+ }]
859
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i3.SkyMutationObserverService }, { type: i0.NgZone }, { type: i2$1.SkyThemeService, decorators: [{
860
+ type: Optional
861
+ }] }]; }, propDecorators: { skyModalScrollShadow: [{
862
+ type: Output
863
+ }], windowResize: [{
864
+ type: HostListener,
865
+ args: ['window:resize']
866
+ }], scroll: [{
867
+ type: HostListener,
868
+ args: ['scroll']
869
+ }] } });
870
+
871
+ const ARIA_ROLE_DEFAULT = 'dialog';
872
+ /**
873
+ * Provides a common look-and-feel for modal content with options to display
874
+ * a common modal header, specify body content, and display a common modal footer
875
+ * and buttons.
876
+ */
877
+ class SkyModalComponent {
878
+ /**
879
+ * A list of form-level errors to display to the user.
880
+ */
881
+ set formErrors(value) {
882
+ this.#errorsSvc.updateErrors(value);
883
+ }
884
+ /**
885
+ * @internal
886
+ */
887
+ set ariaRole(value) {
888
+ this.ariaRoleOrDefault = value || ARIA_ROLE_DEFAULT;
889
+ }
890
+ /**
891
+ * @internal
892
+ */
893
+ set ariaDescribedBy(id) {
894
+ this.#_ariaDescribedBy = id;
895
+ }
896
+ get ariaDescribedBy() {
897
+ return this.#_ariaDescribedBy;
898
+ }
899
+ /**
900
+ * @internal
901
+ */
902
+ set ariaLabelledBy(id) {
903
+ this.#_ariaLabelledBy = id;
904
+ }
905
+ get ariaLabelledBy() {
906
+ return this.#_ariaLabelledBy;
907
+ }
908
+ #hostService;
909
+ #elRef;
910
+ #windowRef;
911
+ #componentAdapter;
912
+ #coreAdapter;
913
+ #dockService;
914
+ #mediaQueryService;
915
+ #ngUnsubscribe;
916
+ #_ariaDescribedBy;
917
+ #_ariaLabelledBy;
918
+ #changeDetector;
919
+ #errorsSvc;
920
+ #liveAnnouncerSvc;
921
+ constructor(hostService, config, elRef, windowRef, componentAdapter, coreAdapter, dockService, mediaQueryService) {
922
+ this.ariaRoleOrDefault = ARIA_ROLE_DEFAULT;
923
+ this.ariaOwns = null;
924
+ this.modalState = 'in';
925
+ this.#ngUnsubscribe = new Subject();
926
+ this.#changeDetector = inject(ChangeDetectorRef);
927
+ this.#errorsSvc = inject(SkyModalErrorsService);
928
+ this.#liveAnnouncerSvc = inject(SkyLiveAnnouncerService);
929
+ this.#hostService = hostService;
930
+ this.#elRef = elRef;
931
+ this.#windowRef = windowRef;
932
+ this.#componentAdapter = componentAdapter;
933
+ this.#coreAdapter = coreAdapter;
934
+ this.#dockService = dockService;
935
+ this.#mediaQueryService = mediaQueryService;
936
+ this.ariaDescribedBy = config.ariaDescribedBy;
937
+ this.ariaLabelledBy = config.ariaLabelledBy;
938
+ this.ariaRole = config.ariaRole;
939
+ this.helpKey = config.helpKey;
940
+ this.tiledBody = config.tiledBody;
941
+ this.wrapperClass = config.wrapperClass;
942
+ this.size = config.fullPage
943
+ ? 'full-page'
944
+ : config.size?.toLowerCase() || 'medium';
945
+ this.modalZIndex = this.#hostService.zIndex;
946
+ }
947
+ onDocumentKeyUp(event) {
948
+ /* istanbul ignore else */
949
+ /* sanity check */
950
+ if (SkyModalHostService.openModalCount > 0) {
951
+ const topModal = SkyModalHostService.topModal;
952
+ if (topModal && topModal === this.#hostService) {
953
+ if (event.which === 27) {
954
+ // Escape key up
955
+ event.preventDefault();
956
+ this.closeButtonClick();
957
+ }
958
+ }
959
+ }
960
+ }
961
+ onDocumentKeyDown(event) {
962
+ /* istanbul ignore else */
963
+ /* sanity check */
964
+ if (SkyModalHostService.openModalCount > 0) {
965
+ const topModal = SkyModalHostService.topModal;
966
+ if (topModal && topModal === this.#hostService) {
967
+ if (event.which === 9) {
968
+ // Tab pressed
969
+ let focusChanged = false;
970
+ const focusElementList = this.#coreAdapter.getFocusableChildren(this.#elRef.nativeElement);
971
+ if (event.shiftKey &&
972
+ (this.#componentAdapter.isFocusInFirstItem(event, focusElementList) ||
973
+ this.#componentAdapter.isModalFocused(event, this.#elRef))) {
974
+ focusChanged =
975
+ this.#componentAdapter.focusLastElement(focusElementList);
976
+ }
977
+ else if (!event.shiftKey &&
978
+ this.#componentAdapter.isFocusInLastItem(event, focusElementList)) {
979
+ focusChanged =
980
+ this.#componentAdapter.focusFirstElement(focusElementList);
981
+ }
982
+ if (focusChanged) {
983
+ event.preventDefault();
984
+ event.stopPropagation();
985
+ }
986
+ }
987
+ }
988
+ }
989
+ }
990
+ ngOnInit() {
991
+ this.#liveAnnouncerSvc.announcerElementChanged
992
+ .pipe(takeUntil(this.#ngUnsubscribe))
993
+ .subscribe((element) => {
994
+ if (element?.id) {
995
+ this.ariaOwns = element.id;
996
+ this.#changeDetector.markForCheck();
997
+ }
998
+ });
999
+ }
1000
+ ngAfterViewInit() {
1001
+ this.#componentAdapter.handleWindowChange(this.#elRef);
1002
+ // Adding a timeout to avoid ExpressionChangedAfterItHasBeenCheckedError.
1003
+ // https://stackoverflow.com/questions/40562845
1004
+ this.#windowRef.nativeWindow.setTimeout(() => {
1005
+ this.#componentAdapter.modalOpened(this.#elRef);
1006
+ });
1007
+ this.#dockService.setDockOptions({
1008
+ location: SkyDockLocation.ElementBottom,
1009
+ referenceEl: this.modalContentWrapperElement.nativeElement,
1010
+ zIndex: 5,
1011
+ });
1012
+ /* istanbul ignore next */
1013
+ if (this.#mediaQueryService) {
1014
+ this.#mediaQueryService.observe(this.modalContentWrapperElement);
1015
+ }
1016
+ }
1017
+ ngOnDestroy() {
1018
+ /* istanbul ignore next */
1019
+ if (this.#mediaQueryService) {
1020
+ this.#mediaQueryService.unobserve();
1021
+ }
1022
+ this.#ngUnsubscribe.next();
1023
+ this.#ngUnsubscribe.complete();
1024
+ }
1025
+ helpButtonClick() {
1026
+ if (this.helpKey) {
1027
+ this.#hostService.onOpenHelp(this.helpKey);
1028
+ }
1029
+ }
1030
+ closeButtonClick() {
1031
+ this.#hostService.onClose();
1032
+ }
1033
+ windowResize() {
1034
+ this.#componentAdapter.handleWindowChange(this.#elRef);
1035
+ }
1036
+ scrollShadowChange(args) {
1037
+ this.scrollShadow = args;
1038
+ }
1039
+ viewkeeperEnabled() {
1040
+ return this.#componentAdapter.modalContentHasDirectChildViewkeeper(this.#elRef);
1041
+ }
1042
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalComponent, deps: [{ token: SkyModalHostService }, { token: SkyModalConfiguration }, { token: i0.ElementRef }, { token: i3.SkyAppWindowRef }, { token: SkyModalComponentAdapterService }, { token: i3.SkyCoreAdapterService }, { token: i3.SkyDockService, host: true }, { token: i3.SkyResizeObserverMediaQueryService, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
1043
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.7", type: SkyModalComponent, selector: "sky-modal", inputs: { formErrors: "formErrors", ariaRole: "ariaRole", tiledBody: "tiledBody", ariaDescribedBy: "ariaDescribedBy", ariaLabelledBy: "ariaLabelledBy" }, host: { listeners: { "document:keyup": "onDocumentKeyUp($event)", "document:keydown": "onDocumentKeyDown($event)" }, properties: { "class": "this.wrapperClass" } }, providers: [
1044
+ SkyModalComponentAdapterService,
1045
+ SkyModalErrorsService,
1046
+ SkyDockService,
1047
+ ], 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 [hidden]=\"!headerContent || !headerContent.children || headerContent.children.length &lt; 1\"\n [ngStyle]=\"{\n 'box-shadow': scrollShadow?.topShadow\n }\"\n >\n <div\n class=\"sky-modal-header-content\"\n skyId\n [ngClass]=\"{\n 'sky-font-heading-2': size === 'full-page'\n }\"\n #headerContent\n #headerId=\"skyId\"\n >\n <ng-content select=\"sky-modal-header\"></ng-content>\n </div>\n <div class=\"sky-modal-header-buttons\">\n <button\n *ngIf=\"helpKey\"\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 icon=\"question-circle\"></sky-icon>\n </button>\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 icon=\"close\"></sky-icon>\n </button>\n </div>\n </div>\n <div\n class=\"sky-modal-content sky-padding-even-large\"\n role=\"region\"\n tabindex=\"0\"\n skyId\n [attr.aria-labelledby]=\"headerId.id\"\n (skyModalScrollShadow)=\"scrollShadowChange($event)\"\n #modalContentId=\"skyId\"\n #modalContentWrapper\n >\n <ng-content select=\"sky-modal-content\"></ng-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\"></ng-content>\n </div>\n </div>\n</div>\n", styles: [".sky-modal{border-top:1px solid #cdcfd2;border-bottom:1px solid #cdcfd2;border-left:1px solid #cdcfd2;border-right:1px solid #cdcfd2;position:fixed;width:auto;left:0;right:0;top:20px;margin:10px;display:flex;flex-direction:column;overflow:hidden}.sky-modal:focus{outline:none}@media (min-width: 768px){.sky-modal:not(.sky-modal-large){margin:0 auto}.sky-modal-small{width:300px}.sky-modal-small .sky-modal-content,.sky-modal-small .sky-modal-header,.sky-modal-small .sky-modal-footer{max-width:300px}.sky-modal-medium{width:600px}.sky-modal-medium .sky-modal-content,.sky-modal-medium .sky-modal-header,.sky-modal-medium .sky-modal-footer{max-width:600px}}@media (min-width: 920px){.sky-modal-large{margin:0 auto;width:900px}.sky-modal-large .sky-modal-content,.sky-modal-large .sky-modal-header,.sky-modal-large .sky-modal-footer{max-width:900px}}.sky-modal-content{background-color:#fff;--sky-background-color-page-default: #fff}.sky-modal-content:focus{outline-style:dotted;outline-width:thin;outline-offset:-1px}.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:9px 3px 9px 15px;background-color:#fff;display:flex;align-items:baseline;border-bottom:1px solid #e2e3e4}.sky-modal-header-buttons{flex-shrink:.0001}.sky-modal-header-buttons .sky-btn{border:none;color:#cdcfd2;cursor:pointer}.sky-modal-header-buttons .sky-btn:hover{color:#979ba2;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{width:100%;top:0;margin:0}.sky-modal-full-page .sky-modal-header-buttons sky-icon[icon=close]{font-size:20px}.sky-modal-full-page .sky-modal-content{flex-grow:1}:host ::ng-deep .sky-sectioned-form{min-height:460px;margin:-15px}.sky-modal-content>::ng-deep sky-dock{bottom:-15px;margin-left:-15px;margin-bottom:-15px;padding-top:15px;width:calc(100% + 30px)}:host-context(.sky-theme-modern) .sky-modal-header{border:none;padding:20px 30px}:host-context(.sky-theme-modern) .sky-modal-btn-help,:host-context(.sky-theme-modern) .sky-modal-btn-close{display:none}:host-context(.sky-theme-modern) .sky-modal-content{padding:0}:host-context(.sky-theme-modern) .sky-modal-full-page{width:calc(100% - 60px);margin:30px}:host-context(.sky-theme-modern) .sky-modal-content>::ng-deep sky-dock{bottom:0;margin-left:initial;margin-bottom:initial;padding-top:initial;width:100%}:host-context(.sky-theme-modern) .sky-modal-viewkeeper .sky-modal-header{box-shadow:none!important}:host-context(.sky-theme-modern) .sky-modal-viewkeeper .sky-modal-content ::ng-deep sky-modal-content>.sky-viewkeeper-fixed{box-shadow:0 4px 8px -4px #0000004d}:host-context(.sky-theme-modern) .sky-modal-viewkeeper .sky-modal-content ::ng-deep sky-modal-content>.sky-viewkeeper-fixed>sky-toolbar .sky-toolbar-container{background-color:#fff;--sky-background-color-page-default: #fff;padding-left:30px;padding-right:30px}.sky-theme-modern .sky-modal-header{border:none;padding:20px 30px}.sky-theme-modern .sky-modal-btn-help,.sky-theme-modern .sky-modal-btn-close{display:none}.sky-theme-modern .sky-modal-content{padding:0}.sky-theme-modern .sky-modal-full-page{width:calc(100% - 60px);margin:30px}.sky-theme-modern .sky-modal-content>::ng-deep sky-dock{bottom:0;margin-left:initial;margin-bottom:initial;padding-top:initial;width:100%}.sky-theme-modern .sky-modal-viewkeeper .sky-modal-header{box-shadow:none!important}.sky-theme-modern .sky-modal-viewkeeper .sky-modal-content ::ng-deep sky-modal-content>.sky-viewkeeper-fixed{box-shadow:0 4px 8px -4px #0000004d}.sky-theme-modern .sky-modal-viewkeeper .sky-modal-content ::ng-deep sky-modal-content>.sky-viewkeeper-fixed>sky-toolbar .sky-toolbar-container{background-color:#fff;--sky-background-color-page-default: #fff;padding-left:30px;padding-right:30px}:host-context(.sky-theme-modern.sky-theme-mode-dark) .sky-modal{border-color:#121212}:host-context(.sky-theme-modern.sky-theme-mode-dark) .sky-modal-header{color:#fbfcfe}:host-context(.sky-theme-modern.sky-theme-mode-dark) .sky-modal-header,:host-context(.sky-theme-modern.sky-theme-mode-dark) .sky-modal-content{background-color:transparent;--sky-background-color-page-default: $sky-theme-modern-mode-dark-background-color-page-default}.sky-theme-modern.sky-theme-mode-dark .sky-modal{border-color:#121212}.sky-theme-modern.sky-theme-mode-dark .sky-modal-header{color:#fbfcfe}.sky-theme-modern.sky-theme-mode-dark .sky-modal-header,.sky-theme-modern.sky-theme-mode-dark .sky-modal-content{background-color:transparent;--sky-background-color-page-default: $sky-theme-modern-mode-dark-background-color-page-default}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i2.λ4, selector: "sky-icon", inputs: ["icon", "iconType", "size", "fixedWidth", "variant"] }, { kind: "directive", type: i3.λ2, selector: "[skyId]", exportAs: ["skyId"] }, { kind: "directive", type: SkyModalScrollShadowDirective, selector: "[skyModalScrollShadow]", outputs: ["skyModalScrollShadow"] }, { kind: "pipe", type: i2$2.SkyLibResourcesPipe, name: "skyLibResources" }] }); }
1048
+ }
1049
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalComponent, decorators: [{
1050
+ type: Component,
1051
+ args: [{ selector: 'sky-modal', providers: [
1052
+ SkyModalComponentAdapterService,
1053
+ SkyModalErrorsService,
1054
+ SkyDockService,
1055
+ ], 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 [hidden]=\"!headerContent || !headerContent.children || headerContent.children.length &lt; 1\"\n [ngStyle]=\"{\n 'box-shadow': scrollShadow?.topShadow\n }\"\n >\n <div\n class=\"sky-modal-header-content\"\n skyId\n [ngClass]=\"{\n 'sky-font-heading-2': size === 'full-page'\n }\"\n #headerContent\n #headerId=\"skyId\"\n >\n <ng-content select=\"sky-modal-header\"></ng-content>\n </div>\n <div class=\"sky-modal-header-buttons\">\n <button\n *ngIf=\"helpKey\"\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 icon=\"question-circle\"></sky-icon>\n </button>\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 icon=\"close\"></sky-icon>\n </button>\n </div>\n </div>\n <div\n class=\"sky-modal-content sky-padding-even-large\"\n role=\"region\"\n tabindex=\"0\"\n skyId\n [attr.aria-labelledby]=\"headerId.id\"\n (skyModalScrollShadow)=\"scrollShadowChange($event)\"\n #modalContentId=\"skyId\"\n #modalContentWrapper\n >\n <ng-content select=\"sky-modal-content\"></ng-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\"></ng-content>\n </div>\n </div>\n</div>\n", styles: [".sky-modal{border-top:1px solid #cdcfd2;border-bottom:1px solid #cdcfd2;border-left:1px solid #cdcfd2;border-right:1px solid #cdcfd2;position:fixed;width:auto;left:0;right:0;top:20px;margin:10px;display:flex;flex-direction:column;overflow:hidden}.sky-modal:focus{outline:none}@media (min-width: 768px){.sky-modal:not(.sky-modal-large){margin:0 auto}.sky-modal-small{width:300px}.sky-modal-small .sky-modal-content,.sky-modal-small .sky-modal-header,.sky-modal-small .sky-modal-footer{max-width:300px}.sky-modal-medium{width:600px}.sky-modal-medium .sky-modal-content,.sky-modal-medium .sky-modal-header,.sky-modal-medium .sky-modal-footer{max-width:600px}}@media (min-width: 920px){.sky-modal-large{margin:0 auto;width:900px}.sky-modal-large .sky-modal-content,.sky-modal-large .sky-modal-header,.sky-modal-large .sky-modal-footer{max-width:900px}}.sky-modal-content{background-color:#fff;--sky-background-color-page-default: #fff}.sky-modal-content:focus{outline-style:dotted;outline-width:thin;outline-offset:-1px}.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:9px 3px 9px 15px;background-color:#fff;display:flex;align-items:baseline;border-bottom:1px solid #e2e3e4}.sky-modal-header-buttons{flex-shrink:.0001}.sky-modal-header-buttons .sky-btn{border:none;color:#cdcfd2;cursor:pointer}.sky-modal-header-buttons .sky-btn:hover{color:#979ba2;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{width:100%;top:0;margin:0}.sky-modal-full-page .sky-modal-header-buttons sky-icon[icon=close]{font-size:20px}.sky-modal-full-page .sky-modal-content{flex-grow:1}:host ::ng-deep .sky-sectioned-form{min-height:460px;margin:-15px}.sky-modal-content>::ng-deep sky-dock{bottom:-15px;margin-left:-15px;margin-bottom:-15px;padding-top:15px;width:calc(100% + 30px)}:host-context(.sky-theme-modern) .sky-modal-header{border:none;padding:20px 30px}:host-context(.sky-theme-modern) .sky-modal-btn-help,:host-context(.sky-theme-modern) .sky-modal-btn-close{display:none}:host-context(.sky-theme-modern) .sky-modal-content{padding:0}:host-context(.sky-theme-modern) .sky-modal-full-page{width:calc(100% - 60px);margin:30px}:host-context(.sky-theme-modern) .sky-modal-content>::ng-deep sky-dock{bottom:0;margin-left:initial;margin-bottom:initial;padding-top:initial;width:100%}:host-context(.sky-theme-modern) .sky-modal-viewkeeper .sky-modal-header{box-shadow:none!important}:host-context(.sky-theme-modern) .sky-modal-viewkeeper .sky-modal-content ::ng-deep sky-modal-content>.sky-viewkeeper-fixed{box-shadow:0 4px 8px -4px #0000004d}:host-context(.sky-theme-modern) .sky-modal-viewkeeper .sky-modal-content ::ng-deep sky-modal-content>.sky-viewkeeper-fixed>sky-toolbar .sky-toolbar-container{background-color:#fff;--sky-background-color-page-default: #fff;padding-left:30px;padding-right:30px}.sky-theme-modern .sky-modal-header{border:none;padding:20px 30px}.sky-theme-modern .sky-modal-btn-help,.sky-theme-modern .sky-modal-btn-close{display:none}.sky-theme-modern .sky-modal-content{padding:0}.sky-theme-modern .sky-modal-full-page{width:calc(100% - 60px);margin:30px}.sky-theme-modern .sky-modal-content>::ng-deep sky-dock{bottom:0;margin-left:initial;margin-bottom:initial;padding-top:initial;width:100%}.sky-theme-modern .sky-modal-viewkeeper .sky-modal-header{box-shadow:none!important}.sky-theme-modern .sky-modal-viewkeeper .sky-modal-content ::ng-deep sky-modal-content>.sky-viewkeeper-fixed{box-shadow:0 4px 8px -4px #0000004d}.sky-theme-modern .sky-modal-viewkeeper .sky-modal-content ::ng-deep sky-modal-content>.sky-viewkeeper-fixed>sky-toolbar .sky-toolbar-container{background-color:#fff;--sky-background-color-page-default: #fff;padding-left:30px;padding-right:30px}:host-context(.sky-theme-modern.sky-theme-mode-dark) .sky-modal{border-color:#121212}:host-context(.sky-theme-modern.sky-theme-mode-dark) .sky-modal-header{color:#fbfcfe}:host-context(.sky-theme-modern.sky-theme-mode-dark) .sky-modal-header,:host-context(.sky-theme-modern.sky-theme-mode-dark) .sky-modal-content{background-color:transparent;--sky-background-color-page-default: $sky-theme-modern-mode-dark-background-color-page-default}.sky-theme-modern.sky-theme-mode-dark .sky-modal{border-color:#121212}.sky-theme-modern.sky-theme-mode-dark .sky-modal-header{color:#fbfcfe}.sky-theme-modern.sky-theme-mode-dark .sky-modal-header,.sky-theme-modern.sky-theme-mode-dark .sky-modal-content{background-color:transparent;--sky-background-color-page-default: $sky-theme-modern-mode-dark-background-color-page-default}\n"] }]
1056
+ }], ctorParameters: function () { return [{ type: SkyModalHostService }, { type: SkyModalConfiguration }, { type: i0.ElementRef }, { type: i3.SkyAppWindowRef }, { type: SkyModalComponentAdapterService }, { type: i3.SkyCoreAdapterService }, { type: i3.SkyDockService, decorators: [{
1057
+ type: Host
1058
+ }] }, { type: i3.SkyResizeObserverMediaQueryService, decorators: [{
1059
+ type: Optional
1060
+ }] }]; }, propDecorators: { wrapperClass: [{
1061
+ type: HostBinding,
1062
+ args: ['class']
1063
+ }], formErrors: [{
1064
+ type: Input
1065
+ }], ariaRole: [{
1066
+ type: Input
1067
+ }], tiledBody: [{
1068
+ type: Input
1069
+ }], ariaDescribedBy: [{
1070
+ type: Input
1071
+ }], ariaLabelledBy: [{
1072
+ type: Input
1073
+ }], modalContentWrapperElement: [{
1074
+ type: ViewChild,
1075
+ args: ['modalContentWrapper', { read: ElementRef }]
1076
+ }], onDocumentKeyUp: [{
1077
+ type: HostListener,
1078
+ args: ['document:keyup', ['$event']]
1079
+ }], onDocumentKeyDown: [{
1080
+ type: HostListener,
1081
+ args: ['document:keydown', ['$event']]
1082
+ }] } });
1083
+
1084
+ class SkyConfirmComponent {
1085
+ #config;
1086
+ #modal;
1087
+ #resourcesService;
1088
+ constructor(config, modal, resourcesService, idService) {
1089
+ this.preserveWhiteSpace = false;
1090
+ this.isOkType = false;
1091
+ this.#config = config;
1092
+ this.#modal = modal;
1093
+ this.#resourcesService = resourcesService;
1094
+ if (config.type === SkyConfirmType.Custom &&
1095
+ config.buttons &&
1096
+ config.buttons.length > 0) {
1097
+ this.buttons = this.#getCustomButtons(config.buttons);
1098
+ }
1099
+ else {
1100
+ this.#getPresetButtons()
1101
+ .pipe(take(1))
1102
+ .subscribe((buttons) => {
1103
+ this.buttons = buttons;
1104
+ });
1105
+ }
1106
+ this.message = config.message;
1107
+ this.body = config.body;
1108
+ // 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
1109
+ this.bodyId = idService.generateId();
1110
+ this.preserveWhiteSpace = !!config.preserveWhiteSpace;
1111
+ this.isOkType = config.type === SkyConfirmType.OK;
1112
+ }
1113
+ close(button) {
1114
+ const result = {
1115
+ action: button.action,
1116
+ };
1117
+ this.#modal.close(result);
1118
+ }
1119
+ #getPresetButtons() {
1120
+ const emitter = new ReplaySubject(1);
1121
+ this.#resourcesService
1122
+ .getStrings({
1123
+ cancel: 'skyux_confirm_dialog_default_cancel_text',
1124
+ no: 'skyux_confirm_dialog_default_no_text',
1125
+ ok: 'skyux_confirm_dialog_default_ok_text',
1126
+ yes: 'skyux_confirm_dialog_default_yes_text',
1127
+ })
1128
+ .subscribe((values) => {
1129
+ const confirmButtons = [];
1130
+ switch (this.#config.type) {
1131
+ case SkyConfirmType.YesNoCancel:
1132
+ case SkyConfirmType.YesCancel:
1133
+ confirmButtons.push({
1134
+ text: values.yes,
1135
+ autofocus: true,
1136
+ styleType: 'primary',
1137
+ action: 'yes',
1138
+ });
1139
+ if (this.#config.type === SkyConfirmType.YesNoCancel) {
1140
+ confirmButtons.push({
1141
+ text: values.no,
1142
+ styleType: 'default',
1143
+ action: 'no',
1144
+ });
1145
+ }
1146
+ confirmButtons.push({
1147
+ text: values.cancel,
1148
+ styleType: 'link',
1149
+ action: 'cancel',
1150
+ });
1151
+ break;
1152
+ default:
1153
+ confirmButtons.push({
1154
+ text: values.ok,
1155
+ autofocus: true,
1156
+ styleType: 'primary',
1157
+ action: 'ok',
1158
+ });
1159
+ }
1160
+ emitter.next(confirmButtons);
1161
+ });
1162
+ return emitter.asObservable();
1163
+ }
1164
+ #getCustomButtons(buttonConfig) {
1165
+ return buttonConfig.map((config) => ({
1166
+ text: config.text,
1167
+ action: config.action,
1168
+ styleType: config.styleType || 'default',
1169
+ autofocus: config.autofocus || false,
1170
+ }));
1171
+ }
1172
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyConfirmComponent, deps: [{ token: SKY_CONFIRM_CONFIG }, { token: SkyModalInstance }, { token: i2$2.SkyLibResourcesService }, { token: i3.SkyIdService }], target: i0.ɵɵFactoryTarget.Component }); }
1173
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.7", type: SkyConfirmComponent, 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 class=\"sky-confirm-message\"\n [ngClass]=\"{\n 'sky-confirm-preserve-white-space': preserveWhiteSpace\n }\"\n [skyThemeClass]=\"{\n 'sky-font-display-4': 'default',\n 'sky-font-heading-1 sky-font-display-3': 'modern'\n }\"\n skyId\n #confirmMessage=\"skyId\"\n >{{ message }}</div\n >\n\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 *ngIf=\"body\"\n class=\"sky-confirm-body\"\n [id]=\"bodyId\"\n [ngClass]=\"{\n 'sky-confirm-preserve-white-space': preserveWhiteSpace\n }\"\n >{{ body }}</div\n >\n\n <div class=\"sky-confirm-buttons\">\n <button\n *ngFor=\"let button of buttons\"\n type=\"button\"\n class=\"sky-btn\"\n [ngClass]=\"'sky-btn-' + button.styleType\"\n [skyThemeClass]=\"{\n 'sky-margin-inline-sm': 'modern',\n 'sky-margin-inline-compact': 'default'\n }\"\n (click)=\"close(button)\"\n [attr.autofocus]=\"button.autofocus ? 'autofocus' : null\"\n >\n {{ button.text }}\n </button>\n </div>\n </sky-modal-content>\n </sky-modal>\n</div>\n", styles: [".sky-confirm{--sky-confirm-body-margin-top: var(--sky-margin-stacked-sm);--sky-confirm-buttons-margin-top: var(--sky-margin-stacked-xl);--sky-confirm-content-padding: 0;--sky-confirm-message-padding-bottom: 0}:host-context(.sky-theme-modern) .sky-confirm{--sky-confirm-body-margin-top: 0;--sky-confirm-buttons-margin-top: var(--sky-margin-stacked-lg);--sky-confirm-content-padding: var(--sky-margin-stacked-lg) var(--sky-margin-inline-xl);--sky-confirm-message-padding-bottom: var(--sky-margin-stacked-lg)}.sky-theme-modern .sky-confirm{--sky-confirm-body-margin-top: 0;--sky-confirm-buttons-margin-top: var(--sky-margin-stacked-lg);--sky-confirm-content-padding: var(--sky-margin-stacked-lg) var(--sky-margin-inline-xl);--sky-confirm-message-padding-bottom: var(--sky-margin-stacked-lg)}.sky-confirm-content{padding:var(--sky-confirm-content-padding)}.sky-confirm-message{margin-top:var(--sky-margin-stacked-xs);padding-bottom:var(--sky-confirm-message-padding-bottom)}.sky-confirm-body{margin-top:var(--sky-confirm-body-margin-top)}.sky-confirm-buttons{margin-top:var(--sky-confirm-buttons-margin-top)}.sky-confirm-preserve-white-space{white-space:pre-wrap}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.λ2, selector: "[skyId]", exportAs: ["skyId"] }, { kind: "component", type: SkyModalComponent, selector: "sky-modal", inputs: ["formErrors", "ariaRole", "tiledBody", "ariaDescribedBy", "ariaLabelledBy"] }, { kind: "component", type: SkyModalContentComponent, selector: "sky-modal-content" }, { kind: "directive", type: i2$1.λ2, selector: "[skyThemeClass]", inputs: ["class", "skyThemeClass"] }] }); }
1174
+ }
1175
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyConfirmComponent, decorators: [{
1176
+ type: Component,
1177
+ args: [{ selector: 'sky-confirm', 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 class=\"sky-confirm-message\"\n [ngClass]=\"{\n 'sky-confirm-preserve-white-space': preserveWhiteSpace\n }\"\n [skyThemeClass]=\"{\n 'sky-font-display-4': 'default',\n 'sky-font-heading-1 sky-font-display-3': 'modern'\n }\"\n skyId\n #confirmMessage=\"skyId\"\n >{{ message }}</div\n >\n\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 *ngIf=\"body\"\n class=\"sky-confirm-body\"\n [id]=\"bodyId\"\n [ngClass]=\"{\n 'sky-confirm-preserve-white-space': preserveWhiteSpace\n }\"\n >{{ body }}</div\n >\n\n <div class=\"sky-confirm-buttons\">\n <button\n *ngFor=\"let button of buttons\"\n type=\"button\"\n class=\"sky-btn\"\n [ngClass]=\"'sky-btn-' + button.styleType\"\n [skyThemeClass]=\"{\n 'sky-margin-inline-sm': 'modern',\n 'sky-margin-inline-compact': 'default'\n }\"\n (click)=\"close(button)\"\n [attr.autofocus]=\"button.autofocus ? 'autofocus' : null\"\n >\n {{ button.text }}\n </button>\n </div>\n </sky-modal-content>\n </sky-modal>\n</div>\n", styles: [".sky-confirm{--sky-confirm-body-margin-top: var(--sky-margin-stacked-sm);--sky-confirm-buttons-margin-top: var(--sky-margin-stacked-xl);--sky-confirm-content-padding: 0;--sky-confirm-message-padding-bottom: 0}:host-context(.sky-theme-modern) .sky-confirm{--sky-confirm-body-margin-top: 0;--sky-confirm-buttons-margin-top: var(--sky-margin-stacked-lg);--sky-confirm-content-padding: var(--sky-margin-stacked-lg) var(--sky-margin-inline-xl);--sky-confirm-message-padding-bottom: var(--sky-margin-stacked-lg)}.sky-theme-modern .sky-confirm{--sky-confirm-body-margin-top: 0;--sky-confirm-buttons-margin-top: var(--sky-margin-stacked-lg);--sky-confirm-content-padding: var(--sky-margin-stacked-lg) var(--sky-margin-inline-xl);--sky-confirm-message-padding-bottom: var(--sky-margin-stacked-lg)}.sky-confirm-content{padding:var(--sky-confirm-content-padding)}.sky-confirm-message{margin-top:var(--sky-margin-stacked-xs);padding-bottom:var(--sky-confirm-message-padding-bottom)}.sky-confirm-body{margin-top:var(--sky-confirm-body-margin-top)}.sky-confirm-buttons{margin-top:var(--sky-confirm-buttons-margin-top)}.sky-confirm-preserve-white-space{white-space:pre-wrap}\n"] }]
1178
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
1179
+ type: Inject,
1180
+ args: [SKY_CONFIRM_CONFIG]
1181
+ }] }, { type: SkyModalInstance }, { type: i2$2.SkyLibResourcesService }, { type: i3.SkyIdService }]; } });
1182
+
1183
+ /**
1184
+ * A service that launches modals.
1185
+ * @dynamic
1186
+ */
1187
+ class SkyModalService {
1188
+ #dynamicComponentService;
1189
+ constructor(dynamicComponentService) {
1190
+ this.#dynamicComponentService = dynamicComponentService;
1191
+ }
1192
+ /**
1193
+ * @internal
1194
+ * Removes the modal host from the DOM.
1195
+ */
1196
+ dispose() {
1197
+ if (SkyModalService.host) {
1198
+ this.#dynamicComponentService.removeComponent(SkyModalService.host);
1199
+ SkyModalService.host = undefined;
1200
+ }
1201
+ }
1202
+ /**
1203
+ * Opens a modal using the specified component.
1204
+ * @param component Determines the component to render.
1205
+ * @param {SkyModalConfigurationInterface} config Specifies configuration options for the modal.
1206
+ */
1207
+ open(component, config) {
1208
+ const modalInstance = new SkyModalInstance();
1209
+ this.#createHostComponent();
1210
+ const params = this.#getConfigFromParameter(config);
1211
+ params.providers ||= [];
1212
+ params.providers.push({
1213
+ provide: SkyModalInstance,
1214
+ useValue: modalInstance,
1215
+ });
1216
+ if (SkyModalService.host) {
1217
+ SkyModalService.host.instance.open(modalInstance, component, params);
1218
+ }
1219
+ return modalInstance;
1220
+ }
1221
+ #getConfigFromParameter(providersOrConfig) {
1222
+ const defaultParams = {
1223
+ providers: [],
1224
+ fullPage: false,
1225
+ size: 'medium',
1226
+ tiledBody: false,
1227
+ };
1228
+ let params = {};
1229
+ let method = undefined;
1230
+ // Object Literal Lookup for backwards compatibility.
1231
+ method = {
1232
+ 'providers?': Object.assign({}, defaultParams, {
1233
+ providers: providersOrConfig,
1234
+ }),
1235
+ config: Object.assign({}, defaultParams, providersOrConfig),
1236
+ };
1237
+ if (Array.isArray(providersOrConfig) === true) {
1238
+ params = method['providers?'];
1239
+ }
1240
+ else {
1241
+ params = method['config'];
1242
+ }
1243
+ return params;
1244
+ }
1245
+ #createHostComponent() {
1246
+ if (!SkyModalService.host) {
1247
+ SkyModalService.host = this.#dynamicComponentService.createComponent(SkyModalHostComponent, {
1248
+ providers: [
1249
+ {
1250
+ provide: SkyModalHostContext,
1251
+ useValue: new SkyModalHostContext({
1252
+ teardownCallback: () => {
1253
+ this.dispose();
1254
+ },
1255
+ }),
1256
+ },
1257
+ ],
1258
+ });
1259
+ }
1260
+ }
1261
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalService, deps: [{ token: i3.SkyDynamicComponentService }], target: i0.ɵɵFactoryTarget.Injectable }); }
1262
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalService, providedIn: 'any' }); }
1263
+ }
1264
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalService, decorators: [{
1265
+ type: Injectable,
1266
+ args: [{
1267
+ // Must be 'any' so that the modal component is created in the context of its module's injector.
1268
+ // If set to 'root', the component's dependency injections would only be derived from the root
1269
+ // injector and may lose context if the modal was opened from within a lazy-loaded module.
1270
+ providedIn: 'any',
1271
+ }]
1272
+ }], ctorParameters: function () { return [{ type: i3.SkyDynamicComponentService }]; } });
1273
+
1274
+ /**
1275
+ * Launches a dialog.
1276
+ */
1277
+ class SkyConfirmService {
1278
+ #modalService;
1279
+ constructor(modalService) {
1280
+ this.#modalService = modalService;
1281
+ }
1282
+ /**
1283
+ * Opens a dialog using the specified options.
1284
+ * @param config Specifies configuration options for the dialog.
1285
+ */
1286
+ open(config) {
1287
+ const modalInstance = this.#modalService.open(SkyConfirmComponent, {
1288
+ providers: [
1289
+ {
1290
+ provide: SKY_CONFIRM_CONFIG,
1291
+ useValue: config,
1292
+ },
1293
+ ],
1294
+ });
1295
+ const confirmInstance = new SkyConfirmInstance();
1296
+ modalInstance.closed.subscribe((args) => {
1297
+ let result = args.data;
1298
+ // The modal was closed using the ESC key.
1299
+ if (result === undefined) {
1300
+ result = {
1301
+ action: 'cancel',
1302
+ };
1303
+ }
1304
+ confirmInstance.closed.emit(result);
1305
+ confirmInstance.closed.complete();
1306
+ });
1307
+ return confirmInstance;
1308
+ }
1309
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyConfirmService, deps: [{ token: SkyModalService }], target: i0.ɵɵFactoryTarget.Injectable }); }
1310
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyConfirmService, providedIn: 'any' }); }
1311
+ }
1312
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyConfirmService, decorators: [{
1313
+ type: Injectable,
1314
+ args: [{
1315
+ // Must be 'any' so that the modal component is created in the context of its module's injector.
1316
+ // If set to 'root', the component's dependency injections would only be derived from the root
1317
+ // injector and may loose context if the modal was opened from within a lazy-loaded module.
1318
+ providedIn: 'any',
1319
+ }]
1320
+ }], ctorParameters: function () { return [{ type: SkyModalService }]; } });
1321
+
1322
+ /**
1323
+ * Provides a way to mark a modal as "dirty" and displays a confirmation
1324
+ * message when a user closes the modal without saving.
1325
+ */
1326
+ class SkyModalIsDirtyDirective {
1327
+ constructor() {
1328
+ /**
1329
+ * Whether the user edited an input on the modal.
1330
+ * @required
1331
+ */
1332
+ this.isDirty = false;
1333
+ this.#ngUnsubscribe = new Subject();
1334
+ this.#modalInstance = inject(SkyModalInstance);
1335
+ this.#confirmSvc = inject(SkyConfirmService);
1336
+ this.#resourcesSvc = inject(SkyLibResourcesService);
1337
+ }
1338
+ #ngUnsubscribe;
1339
+ #modalInstance;
1340
+ #confirmSvc;
1341
+ #resourcesSvc;
1342
+ ngOnInit() {
1343
+ this.#modalInstance.beforeClose
1344
+ .pipe(takeUntil(this.#ngUnsubscribe))
1345
+ .subscribe((handler) => this.#promptIfDirty(handler));
1346
+ }
1347
+ ngOnDestroy() {
1348
+ this.#ngUnsubscribe.next();
1349
+ this.#ngUnsubscribe.complete();
1350
+ }
1351
+ #promptIfDirty(handler) {
1352
+ if (this.isDirty && handler.closeArgs.reason === 'close') {
1353
+ this.#resourcesSvc
1354
+ .getStrings({
1355
+ message: 'skyux_modal_dirty_default_message',
1356
+ discardActionText: 'skyux_modal_dirty_default_discard_changes_text',
1357
+ keepActionText: 'skyux_modal_dirty_default_keep_working_text',
1358
+ })
1359
+ .subscribe((textValues) => {
1360
+ const discardAction = 'discard';
1361
+ const keepAction = 'keep';
1362
+ this.#confirmSvc
1363
+ .open({
1364
+ message: textValues.message,
1365
+ buttons: [
1366
+ {
1367
+ action: discardAction,
1368
+ text: textValues.discardActionText,
1369
+ styleType: 'primary',
1370
+ },
1371
+ {
1372
+ action: keepAction,
1373
+ text: textValues.keepActionText,
1374
+ styleType: 'link',
1375
+ },
1376
+ ],
1377
+ type: SkyConfirmType.Custom,
1378
+ })
1379
+ .closed.subscribe((args) => {
1380
+ if (args.action === discardAction) {
1381
+ handler.closeModal();
1382
+ }
1383
+ });
1384
+ });
1385
+ }
1386
+ else {
1387
+ handler.closeModal();
1388
+ }
1389
+ }
1390
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalIsDirtyDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1391
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.1.7", type: SkyModalIsDirtyDirective, selector: "sky-modal[isDirty]", inputs: { isDirty: "isDirty" }, host: { properties: { "attr.data-sky-modal-is-dirty": "this.isDirty" } }, ngImport: i0 }); }
1392
+ }
1393
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalIsDirtyDirective, decorators: [{
1394
+ type: Directive,
1395
+ args: [{
1396
+ // Since this is limited to sky-modal, it should be safe to
1397
+ // leave off the sky prefix.
1398
+ // eslint-disable-next-line @angular-eslint/directive-selector
1399
+ selector: 'sky-modal[isDirty]',
1400
+ }]
1401
+ }], propDecorators: { isDirty: [{
1402
+ type: Input
1403
+ }, {
1404
+ type: HostBinding,
1405
+ args: ['attr.data-sky-modal-is-dirty']
1406
+ }] } });
1407
+
1408
+ class SkyModalModule {
1409
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
1410
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.1.7", ngImport: i0, type: SkyModalModule, declarations: [SkyModalComponent,
1411
+ SkyModalContentComponent,
1412
+ SkyModalFooterComponent,
1413
+ SkyModalHeaderComponent,
1414
+ SkyModalHostComponent,
1415
+ SkyModalIsDirtyDirective,
1416
+ SkyModalScrollShadowDirective], imports: [CommonModule,
1417
+ RouterModule,
1418
+ SkyIconModule,
1419
+ SkyIdModule,
1420
+ SkyModalsResourcesModule,
1421
+ SkyStatusIndicatorModule,
1422
+ SkyThemeModule,
1423
+ SkyTrimModule], exports: [SkyModalComponent,
1424
+ SkyModalContentComponent,
1425
+ SkyModalFooterComponent,
1426
+ SkyModalHeaderComponent,
1427
+ SkyModalIsDirtyDirective] }); }
1428
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalModule, imports: [CommonModule,
1429
+ RouterModule,
1430
+ SkyIconModule,
1431
+ SkyIdModule,
1432
+ SkyModalsResourcesModule,
1433
+ SkyStatusIndicatorModule,
1434
+ SkyThemeModule,
1435
+ SkyTrimModule] }); }
1436
+ }
1437
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyModalModule, decorators: [{
1438
+ type: NgModule,
1439
+ args: [{
1440
+ declarations: [
1441
+ SkyModalComponent,
1442
+ SkyModalContentComponent,
1443
+ SkyModalFooterComponent,
1444
+ SkyModalHeaderComponent,
1445
+ SkyModalHostComponent,
1446
+ SkyModalIsDirtyDirective,
1447
+ SkyModalScrollShadowDirective,
1448
+ ],
1449
+ imports: [
1450
+ CommonModule,
1451
+ RouterModule,
1452
+ SkyIconModule,
1453
+ SkyIdModule,
1454
+ SkyModalsResourcesModule,
1455
+ SkyStatusIndicatorModule,
1456
+ SkyThemeModule,
1457
+ SkyTrimModule,
1458
+ ],
1459
+ exports: [
1460
+ SkyModalComponent,
1461
+ SkyModalContentComponent,
1462
+ SkyModalFooterComponent,
1463
+ SkyModalHeaderComponent,
1464
+ SkyModalIsDirtyDirective,
1465
+ ],
1466
+ }]
1467
+ }] });
1468
+
1469
+ class SkyConfirmModule {
1470
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyConfirmModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
1471
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.1.7", ngImport: i0, type: SkyConfirmModule, declarations: [SkyConfirmComponent], imports: [CommonModule,
1472
+ SkyIdModule,
1473
+ SkyModalModule,
1474
+ SkyModalsResourcesModule,
1475
+ SkyThemeModule], exports: [SkyConfirmComponent] }); }
1476
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyConfirmModule, imports: [CommonModule,
1477
+ SkyIdModule,
1478
+ SkyModalModule,
1479
+ SkyModalsResourcesModule,
1480
+ SkyThemeModule] }); }
1481
+ }
1482
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.7", ngImport: i0, type: SkyConfirmModule, decorators: [{
1483
+ type: NgModule,
1484
+ args: [{
1485
+ declarations: [SkyConfirmComponent],
1486
+ imports: [
1487
+ CommonModule,
1488
+ SkyIdModule,
1489
+ SkyModalModule,
1490
+ SkyModalsResourcesModule,
1491
+ SkyThemeModule,
1492
+ ],
1493
+ exports: [SkyConfirmComponent],
1494
+ }]
1495
+ }] });
1496
+
1497
+ /**
1498
+ * Generated bundle index. Do not edit.
1499
+ */
1500
+
1501
+ export { SkyConfirmInstance, SkyConfirmModule, SkyConfirmService, SkyConfirmType, SkyModalBeforeCloseHandler, SkyModalCloseArgs, SkyModalConfiguration, SkyModalErrorsService, SkyModalHostService, SkyModalInstance, SkyModalModule, SkyModalService, SkyConfirmComponent as λ1, SkyModalContentComponent as λ2, SkyModalFooterComponent as λ3, SkyModalHeaderComponent as λ4, SkyModalComponent as λ5, SkyModalIsDirtyDirective as λ6 };
1502
+ //# sourceMappingURL=skyux-modals.mjs.map