@angular/cdk-experimental 14.0.0-next.10 → 14.0.0-next.11
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.
- package/dialog/dialog-config.d.ts +69 -40
- package/dialog/dialog-container.d.ts +47 -51
- package/dialog/dialog-injectors.d.ts +6 -12
- package/dialog/dialog-ref.d.ts +45 -38
- package/dialog/dialog.d.ts +59 -56
- package/esm2020/column-resize/column-resize-directives/column-resize-flex.mjs +4 -4
- package/esm2020/column-resize/column-resize-directives/column-resize.mjs +4 -4
- package/esm2020/column-resize/column-resize-directives/default-enabled-column-resize-flex.mjs +4 -4
- package/esm2020/column-resize/column-resize-directives/default-enabled-column-resize.mjs +4 -4
- package/esm2020/column-resize/column-resize-module.mjs +9 -9
- package/esm2020/column-resize/column-resize-notifier.mjs +7 -7
- package/esm2020/column-resize/column-resize.mjs +4 -4
- package/esm2020/column-resize/column-size-store.mjs +4 -4
- package/esm2020/column-resize/event-dispatcher.mjs +4 -4
- package/esm2020/column-resize/overlay-handle.mjs +4 -4
- package/esm2020/column-resize/resizable.mjs +4 -4
- package/esm2020/column-resize/resize-strategy.mjs +10 -10
- package/esm2020/combobox/combobox-module.mjs +5 -5
- package/esm2020/combobox/combobox-popup.mjs +4 -4
- package/esm2020/combobox/combobox.mjs +4 -4
- package/esm2020/dialog/dialog-config.mjs +33 -22
- package/esm2020/dialog/dialog-container.mjs +107 -152
- package/esm2020/dialog/dialog-injectors.mjs +6 -10
- package/esm2020/dialog/dialog-module.mjs +7 -21
- package/esm2020/dialog/dialog-ref.mjs +49 -88
- package/esm2020/dialog/dialog.mjs +187 -154
- package/esm2020/listbox/listbox-module.mjs +5 -5
- package/esm2020/listbox/listbox.mjs +7 -7
- package/esm2020/menu/context-menu-trigger.mjs +7 -7
- package/esm2020/menu/menu-aim.mjs +7 -7
- package/esm2020/menu/menu-bar.mjs +4 -4
- package/esm2020/menu/menu-base.mjs +4 -4
- package/esm2020/menu/menu-group.mjs +4 -4
- package/esm2020/menu/menu-item-checkbox.mjs +4 -4
- package/esm2020/menu/menu-item-radio.mjs +4 -4
- package/esm2020/menu/menu-item-selectable.mjs +4 -4
- package/esm2020/menu/menu-item.mjs +4 -4
- package/esm2020/menu/menu-module.mjs +5 -5
- package/esm2020/menu/menu-stack.mjs +4 -4
- package/esm2020/menu/menu-trigger-base.mjs +4 -4
- package/esm2020/menu/menu-trigger.mjs +4 -4
- package/esm2020/menu/menu.mjs +4 -4
- package/esm2020/popover-edit/edit-event-dispatcher.mjs +4 -4
- package/esm2020/popover-edit/edit-ref.mjs +4 -4
- package/esm2020/popover-edit/edit-services.mjs +4 -4
- package/esm2020/popover-edit/focus-dispatcher.mjs +4 -4
- package/esm2020/popover-edit/focus-escape-notifier.mjs +4 -4
- package/esm2020/popover-edit/lens-directives.mjs +10 -10
- package/esm2020/popover-edit/popover-edit-module.mjs +5 -5
- package/esm2020/popover-edit/popover-edit-position-strategy-factory.mjs +7 -7
- package/esm2020/popover-edit/table-directives.mjs +16 -16
- package/esm2020/scrolling/auto-size-virtual-scroll.mjs +4 -4
- package/esm2020/scrolling/scrolling-module.mjs +5 -5
- package/esm2020/selection/row-selection.mjs +4 -4
- package/esm2020/selection/select-all.mjs +4 -4
- package/esm2020/selection/selection-column.mjs +4 -4
- package/esm2020/selection/selection-module.mjs +5 -5
- package/esm2020/selection/selection-toggle.mjs +4 -4
- package/esm2020/selection/selection.mjs +4 -4
- package/esm2020/table-scroll-container/table-scroll-container-module.mjs +5 -5
- package/esm2020/table-scroll-container/table-scroll-container.mjs +4 -4
- package/esm2020/version.mjs +1 -1
- package/fesm2015/cdk-experimental.mjs +1 -1
- package/fesm2015/cdk-experimental.mjs.map +1 -1
- package/fesm2015/column-resize.mjs +50 -50
- package/fesm2015/column-resize.mjs.map +1 -1
- package/fesm2015/combobox.mjs +10 -10
- package/fesm2015/combobox.mjs.map +1 -1
- package/fesm2015/dialog.mjs +376 -443
- package/fesm2015/dialog.mjs.map +1 -1
- package/fesm2015/listbox.mjs +10 -10
- package/fesm2015/listbox.mjs.map +1 -1
- package/fesm2015/menu.mjs +49 -49
- package/fesm2015/menu.mjs.map +1 -1
- package/fesm2015/popover-edit.mjs +49 -49
- package/fesm2015/popover-edit.mjs.map +1 -1
- package/fesm2015/scrolling.mjs +7 -7
- package/fesm2015/scrolling.mjs.map +1 -1
- package/fesm2015/selection.mjs +19 -19
- package/fesm2015/selection.mjs.map +1 -1
- package/fesm2015/table-scroll-container.mjs +7 -7
- package/fesm2015/table-scroll-container.mjs.map +1 -1
- package/fesm2020/cdk-experimental.mjs +1 -1
- package/fesm2020/cdk-experimental.mjs.map +1 -1
- package/fesm2020/column-resize.mjs +50 -50
- package/fesm2020/column-resize.mjs.map +1 -1
- package/fesm2020/combobox.mjs +10 -10
- package/fesm2020/combobox.mjs.map +1 -1
- package/fesm2020/dialog.mjs +378 -435
- package/fesm2020/dialog.mjs.map +1 -1
- package/fesm2020/listbox.mjs +10 -10
- package/fesm2020/listbox.mjs.map +1 -1
- package/fesm2020/menu.mjs +49 -49
- package/fesm2020/menu.mjs.map +1 -1
- package/fesm2020/popover-edit.mjs +49 -49
- package/fesm2020/popover-edit.mjs.map +1 -1
- package/fesm2020/scrolling.mjs +7 -7
- package/fesm2020/scrolling.mjs.map +1 -1
- package/fesm2020/selection.mjs +19 -19
- package/fesm2020/selection.mjs.map +1 -1
- package/fesm2020/table-scroll-container.mjs +7 -7
- package/fesm2020/table-scroll-container.mjs.map +1 -1
- package/package.json +2 -2
package/fesm2015/dialog.mjs
CHANGED
|
@@ -1,70 +1,72 @@
|
|
|
1
|
-
import { trigger, state, style, transition, group, animate, query, animateChild } from '@angular/animations';
|
|
2
1
|
import { _getFocusedElementPierceShadowDom } from '@angular/cdk/platform';
|
|
3
2
|
import * as i3 from '@angular/cdk/portal';
|
|
4
3
|
import { BasePortalOutlet, CdkPortalOutlet, ComponentPortal, TemplatePortal, PortalModule } from '@angular/cdk/portal';
|
|
5
|
-
import * as i2 from '@angular/common';
|
|
6
4
|
import { DOCUMENT } from '@angular/common';
|
|
7
5
|
import * as i0 from '@angular/core';
|
|
8
|
-
import { Component, ViewEncapsulation, ChangeDetectionStrategy, Optional, Inject, ViewChild, InjectionToken, Injector, InjectFlags, Injectable, SkipSelf, NgModule } from '@angular/core';
|
|
9
|
-
import { Subject, defer, of } from 'rxjs';
|
|
10
|
-
import { distinctUntilChanged, filter, map, startWith } from 'rxjs/operators';
|
|
6
|
+
import { Component, ViewEncapsulation, ChangeDetectionStrategy, Optional, Inject, ViewChild, InjectionToken, Injector, TemplateRef, InjectFlags, Injectable, SkipSelf, NgModule } from '@angular/core';
|
|
11
7
|
import * as i1 from '@angular/cdk/a11y';
|
|
12
8
|
import { A11yModule } from '@angular/cdk/a11y';
|
|
9
|
+
import * as i1$1 from '@angular/cdk/overlay';
|
|
10
|
+
import { Overlay, OverlayConfig, OverlayRef, OverlayModule } from '@angular/cdk/overlay';
|
|
13
11
|
import { ESCAPE, hasModifierKey } from '@angular/cdk/keycodes';
|
|
12
|
+
import { Subject, defer, of } from 'rxjs';
|
|
14
13
|
import { Directionality } from '@angular/cdk/bidi';
|
|
15
|
-
import
|
|
16
|
-
import { Overlay, OverlayConfig, OverlayModule } from '@angular/cdk/overlay';
|
|
14
|
+
import { startWith } from 'rxjs/operators';
|
|
17
15
|
|
|
16
|
+
/**
|
|
17
|
+
* @license
|
|
18
|
+
* Copyright Google LLC All Rights Reserved.
|
|
19
|
+
*
|
|
20
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
21
|
+
* found in the LICENSE file at https://angular.io/license
|
|
22
|
+
*/
|
|
23
|
+
/** Configuration for opening a modal dialog. */
|
|
18
24
|
class DialogConfig {
|
|
19
25
|
constructor() {
|
|
20
|
-
/** The ARIA role of the dialog. */
|
|
26
|
+
/** The ARIA role of the dialog element. */
|
|
21
27
|
this.role = 'dialog';
|
|
22
|
-
/**
|
|
28
|
+
/** Optional CSS class or classes applied to the overlay panel. */
|
|
23
29
|
this.panelClass = '';
|
|
24
|
-
/** Whether the dialog has a
|
|
30
|
+
/** Whether the dialog has a backdrop. */
|
|
25
31
|
this.hasBackdrop = true;
|
|
26
|
-
/**
|
|
32
|
+
/** Optional CSS class or classes applied to the overlay backdrop. */
|
|
27
33
|
this.backdropClass = '';
|
|
28
|
-
/** Whether the dialog
|
|
34
|
+
/** Whether the dialog closes with the escape key or pointer events outside the panel element. */
|
|
29
35
|
this.disableClose = false;
|
|
30
|
-
/**
|
|
36
|
+
/** Width of the dialog. */
|
|
31
37
|
this.width = '';
|
|
32
|
-
/**
|
|
38
|
+
/** Height of the dialog. */
|
|
33
39
|
this.height = '';
|
|
34
|
-
/**
|
|
35
|
-
this.minWidth = '';
|
|
36
|
-
/** The minimum height of the dialog. */
|
|
37
|
-
this.minHeight = '';
|
|
38
|
-
/** The maximum width of the dialog. */
|
|
39
|
-
this.maxWidth = '80vw';
|
|
40
|
-
/** The maximum height of the dialog. */
|
|
41
|
-
this.maxHeight = '';
|
|
42
|
-
/** Data to be injected into the dialog content. */
|
|
40
|
+
/** Data being injected into the child component. */
|
|
43
41
|
this.data = null;
|
|
44
42
|
/** ID of the element that describes the dialog. */
|
|
45
43
|
this.ariaDescribedBy = null;
|
|
46
|
-
/**
|
|
44
|
+
/** ID of the element that labels the dialog. */
|
|
45
|
+
this.ariaLabelledBy = null;
|
|
46
|
+
/** Dialog label applied via `aria-label` */
|
|
47
47
|
this.ariaLabel = null;
|
|
48
|
+
/** Whether this a modal dialog. Used to set the `aria-modal` attribute. */
|
|
49
|
+
this.ariaModal = true;
|
|
48
50
|
/**
|
|
49
51
|
* Where the dialog should focus on open.
|
|
50
52
|
* @breaking-change 14.0.0 Remove boolean option from autoFocus. Use string or
|
|
51
53
|
* AutoFocusTarget instead.
|
|
52
54
|
*/
|
|
53
55
|
this.autoFocus = 'first-tabbable';
|
|
54
|
-
/**
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Whether the dialog should restore focus to the
|
|
58
|
+
* previously-focused element upon closing.
|
|
59
|
+
*/
|
|
60
|
+
this.restoreFocus = true;
|
|
61
|
+
/**
|
|
62
|
+
* Whether the dialog should close when the user navigates backwards or forwards through browser
|
|
63
|
+
* history. This does not apply to navigation via anchor element unless using URL-hash based
|
|
64
|
+
* routing (`HashLocationStrategy` in the Angular router).
|
|
65
|
+
*/
|
|
66
|
+
this.closeOnNavigation = true;
|
|
58
67
|
}
|
|
59
68
|
}
|
|
60
69
|
|
|
61
|
-
/**
|
|
62
|
-
* @license
|
|
63
|
-
* Copyright Google LLC All Rights Reserved.
|
|
64
|
-
*
|
|
65
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
66
|
-
* found in the LICENSE file at https://angular.io/license
|
|
67
|
-
*/
|
|
68
70
|
function throwDialogContentAlreadyAttachedError() {
|
|
69
71
|
throw Error('Attempting to attach dialog content after content is already attached');
|
|
70
72
|
}
|
|
@@ -73,32 +75,23 @@ function throwDialogContentAlreadyAttachedError() {
|
|
|
73
75
|
* @docs-private
|
|
74
76
|
*/
|
|
75
77
|
class CdkDialogContainer extends BasePortalOutlet {
|
|
76
|
-
constructor(_elementRef, _focusTrapFactory,
|
|
77
|
-
/** The dialog configuration. */
|
|
78
|
-
_config) {
|
|
78
|
+
constructor(_elementRef, _focusTrapFactory, _document, _config, _interactivityChecker, _ngZone, _overlayRef, _focusMonitor) {
|
|
79
79
|
super();
|
|
80
80
|
this._elementRef = _elementRef;
|
|
81
81
|
this._focusTrapFactory = _focusTrapFactory;
|
|
82
|
-
this.
|
|
82
|
+
this._config = _config;
|
|
83
83
|
this._interactivityChecker = _interactivityChecker;
|
|
84
84
|
this._ngZone = _ngZone;
|
|
85
|
-
this.
|
|
86
|
-
|
|
87
|
-
this._state = 'enter';
|
|
85
|
+
this._overlayRef = _overlayRef;
|
|
86
|
+
this._focusMonitor = _focusMonitor;
|
|
88
87
|
/** Element that was focused before the dialog was opened. Save this to restore upon close. */
|
|
89
88
|
this._elementFocusedBeforeDialogWasOpened = null;
|
|
90
|
-
/**
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
this.
|
|
96
|
-
/** A subject emitting before the dialog exits the view. */
|
|
97
|
-
this._beforeExit = new Subject();
|
|
98
|
-
/** A subject emitting after the dialog exits the view. */
|
|
99
|
-
this._afterExit = new Subject();
|
|
100
|
-
/** Stream of animation `done` events. */
|
|
101
|
-
this._animationDone = new Subject();
|
|
89
|
+
/**
|
|
90
|
+
* Type of interaction that led to the dialog being closed. This is used to determine
|
|
91
|
+
* whether the focus style will be applied when returning focus to its original location
|
|
92
|
+
* after the dialog is closed.
|
|
93
|
+
*/
|
|
94
|
+
this._closeInteractionType = null;
|
|
102
95
|
/**
|
|
103
96
|
* Attaches a DOM portal to the dialog container.
|
|
104
97
|
* @param portal Portal to be attached.
|
|
@@ -106,97 +99,48 @@ class CdkDialogContainer extends BasePortalOutlet {
|
|
|
106
99
|
* @breaking-change 10.0.0
|
|
107
100
|
*/
|
|
108
101
|
this.attachDomPortal = (portal) => {
|
|
109
|
-
if (this.
|
|
102
|
+
if (this._portalOutlet.hasAttached() && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
110
103
|
throwDialogContentAlreadyAttachedError();
|
|
111
104
|
}
|
|
112
|
-
return this.
|
|
105
|
+
return this._portalOutlet.attachDomPortal(portal);
|
|
113
106
|
};
|
|
107
|
+
this._ariaLabelledBy = this._config.ariaLabelledBy || null;
|
|
114
108
|
this._document = _document;
|
|
115
|
-
// We use a Subject with a distinctUntilChanged, rather than a callback attached to .done,
|
|
116
|
-
// because some browsers fire the done event twice and we don't want to emit duplicate events.
|
|
117
|
-
// See: https://github.com/angular/angular/issues/24084
|
|
118
|
-
this._animationDone
|
|
119
|
-
.pipe(distinctUntilChanged((x, y) => {
|
|
120
|
-
return x.fromState === y.fromState && x.toState === y.toState;
|
|
121
|
-
}))
|
|
122
|
-
.subscribe(event => {
|
|
123
|
-
// Emit lifecycle events based on animation `done` callback.
|
|
124
|
-
if (event.toState === 'enter') {
|
|
125
|
-
this._autoFocus();
|
|
126
|
-
this._afterEnter.next();
|
|
127
|
-
this._afterEnter.complete();
|
|
128
|
-
}
|
|
129
|
-
if (event.fromState === 'enter' && (event.toState === 'void' || event.toState === 'exit')) {
|
|
130
|
-
this._returnFocusAfterDialog();
|
|
131
|
-
this._afterExit.next();
|
|
132
|
-
this._afterExit.complete();
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
109
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
110
|
+
ngAfterViewInit() {
|
|
111
|
+
this._initializeFocusTrap();
|
|
112
|
+
this._handleBackdropClicks();
|
|
113
|
+
this._captureInitialFocus();
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Can be used by child classes to customize the initial focus
|
|
117
|
+
* capturing behavior (e.g. if it's tied to an animation).
|
|
118
|
+
*/
|
|
119
|
+
_captureInitialFocus() {
|
|
120
|
+
this._trapFocus();
|
|
144
121
|
}
|
|
145
|
-
/** Destroy focus trap to place focus back to the element focused before the dialog opened. */
|
|
146
122
|
ngOnDestroy() {
|
|
147
|
-
this.
|
|
148
|
-
this._animationDone.complete();
|
|
123
|
+
this._restoreFocus();
|
|
149
124
|
}
|
|
150
125
|
/**
|
|
151
126
|
* Attach a ComponentPortal as content to this dialog container.
|
|
152
127
|
* @param portal Portal to be attached as the dialog content.
|
|
153
128
|
*/
|
|
154
129
|
attachComponentPortal(portal) {
|
|
155
|
-
if (this.
|
|
130
|
+
if (this._portalOutlet.hasAttached() && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
156
131
|
throwDialogContentAlreadyAttachedError();
|
|
157
132
|
}
|
|
158
|
-
return this.
|
|
133
|
+
return this._portalOutlet.attachComponentPortal(portal);
|
|
159
134
|
}
|
|
160
135
|
/**
|
|
161
136
|
* Attach a TemplatePortal as content to this dialog container.
|
|
162
137
|
* @param portal Portal to be attached as the dialog content.
|
|
163
138
|
*/
|
|
164
139
|
attachTemplatePortal(portal) {
|
|
165
|
-
if (this.
|
|
140
|
+
if (this._portalOutlet.hasAttached() && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
166
141
|
throwDialogContentAlreadyAttachedError();
|
|
167
142
|
}
|
|
168
|
-
return this.
|
|
169
|
-
}
|
|
170
|
-
/** Emit lifecycle events based on animation `start` callback. */
|
|
171
|
-
_onAnimationStart(event) {
|
|
172
|
-
if (event.toState === 'enter') {
|
|
173
|
-
this._beforeEnter.next();
|
|
174
|
-
this._beforeEnter.complete();
|
|
175
|
-
}
|
|
176
|
-
if (event.fromState === 'enter' && (event.toState === 'void' || event.toState === 'exit')) {
|
|
177
|
-
this._beforeExit.next();
|
|
178
|
-
this._beforeExit.complete();
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
/** Starts the dialog exit animation. */
|
|
182
|
-
_startExiting() {
|
|
183
|
-
this._state = 'exit';
|
|
184
|
-
// Mark the container for check so it can react if the
|
|
185
|
-
// view container is using OnPush change detection.
|
|
186
|
-
this._changeDetectorRef.markForCheck();
|
|
187
|
-
}
|
|
188
|
-
/** Saves a reference to the element that was focused before the dialog was opened. */
|
|
189
|
-
_savePreviouslyFocusedElement() {
|
|
190
|
-
if (this._document) {
|
|
191
|
-
this._elementFocusedBeforeDialogWasOpened = _getFocusedElementPierceShadowDom();
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
/** Focuses the dialog container. */
|
|
195
|
-
_focusDialogContainer() {
|
|
196
|
-
// Note that there is no focus method when rendering on the server.
|
|
197
|
-
if (this._elementRef.nativeElement.focus) {
|
|
198
|
-
this._elementRef.nativeElement.focus();
|
|
199
|
-
}
|
|
143
|
+
return this._portalOutlet.attachTemplatePortal(portal);
|
|
200
144
|
}
|
|
201
145
|
/**
|
|
202
146
|
* Focuses the provided element. If the element is not focusable, it will add a tabIndex
|
|
@@ -230,10 +174,10 @@ class CdkDialogContainer extends BasePortalOutlet {
|
|
|
230
174
|
}
|
|
231
175
|
}
|
|
232
176
|
/**
|
|
233
|
-
*
|
|
234
|
-
*
|
|
177
|
+
* Moves the focus inside the focus trap. When autoFocus is not set to 'dialog', if focus
|
|
178
|
+
* cannot be moved then focus will go to the dialog container.
|
|
235
179
|
*/
|
|
236
|
-
|
|
180
|
+
_trapFocus() {
|
|
237
181
|
const element = this._elementRef.nativeElement;
|
|
238
182
|
// If were to attempt to focus immediately, then the content of the dialog would not yet be
|
|
239
183
|
// ready in instances where change detection has to run first. To deal with this, we simply
|
|
@@ -243,21 +187,22 @@ class CdkDialogContainer extends BasePortalOutlet {
|
|
|
243
187
|
switch (this._config.autoFocus) {
|
|
244
188
|
case false:
|
|
245
189
|
case 'dialog':
|
|
246
|
-
const activeElement = _getFocusedElementPierceShadowDom();
|
|
247
190
|
// Ensure that focus is on the dialog container. It's possible that a different
|
|
248
191
|
// component tried to move focus while the open animation was running. See:
|
|
249
192
|
// https://github.com/angular/components/issues/16215. Note that we only want to do this
|
|
250
193
|
// if the focus isn't inside the dialog already, because it's possible that the consumer
|
|
251
194
|
// turned off `autoFocus` in order to move focus themselves.
|
|
252
|
-
if (
|
|
195
|
+
if (!this._containsFocus()) {
|
|
253
196
|
element.focus();
|
|
254
197
|
}
|
|
255
198
|
break;
|
|
256
199
|
case true:
|
|
257
200
|
case 'first-tabbable':
|
|
258
|
-
this._focusTrap.focusInitialElementWhenReady().then(
|
|
259
|
-
|
|
260
|
-
|
|
201
|
+
this._focusTrap.focusInitialElementWhenReady().then(focusedSuccessfully => {
|
|
202
|
+
// If we weren't able to find a focusable element in the dialog, then focus the dialog
|
|
203
|
+
// container instead.
|
|
204
|
+
if (!focusedSuccessfully) {
|
|
205
|
+
this._focusDialogContainer();
|
|
261
206
|
}
|
|
262
207
|
});
|
|
263
208
|
break;
|
|
@@ -269,11 +214,13 @@ class CdkDialogContainer extends BasePortalOutlet {
|
|
|
269
214
|
break;
|
|
270
215
|
}
|
|
271
216
|
}
|
|
272
|
-
/**
|
|
273
|
-
|
|
274
|
-
const
|
|
217
|
+
/** Restores focus to the element that was focused before the dialog opened. */
|
|
218
|
+
_restoreFocus() {
|
|
219
|
+
const previousElement = this._elementFocusedBeforeDialogWasOpened;
|
|
275
220
|
// We need the extra check, because IE can set the `activeElement` to null in some cases.
|
|
276
|
-
if (
|
|
221
|
+
if (this._config.restoreFocus &&
|
|
222
|
+
previousElement &&
|
|
223
|
+
typeof previousElement.focus === 'function') {
|
|
277
224
|
const activeElement = _getFocusedElementPierceShadowDom();
|
|
278
225
|
const element = this._elementRef.nativeElement;
|
|
279
226
|
// Make sure that focus is still inside the dialog or is on the body (usually because a
|
|
@@ -284,65 +231,77 @@ class CdkDialogContainer extends BasePortalOutlet {
|
|
|
284
231
|
activeElement === this._document.body ||
|
|
285
232
|
activeElement === element ||
|
|
286
233
|
element.contains(activeElement)) {
|
|
287
|
-
|
|
234
|
+
if (this._focusMonitor) {
|
|
235
|
+
this._focusMonitor.focusVia(previousElement, this._closeInteractionType);
|
|
236
|
+
this._closeInteractionType = null;
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
previousElement.focus();
|
|
240
|
+
}
|
|
288
241
|
}
|
|
289
242
|
}
|
|
243
|
+
if (this._focusTrap) {
|
|
244
|
+
this._focusTrap.destroy();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/** Focuses the dialog container. */
|
|
248
|
+
_focusDialogContainer() {
|
|
249
|
+
// Note that there is no focus method when rendering on the server.
|
|
250
|
+
if (this._elementRef.nativeElement.focus) {
|
|
251
|
+
this._elementRef.nativeElement.focus();
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/** Returns whether focus is inside the dialog. */
|
|
255
|
+
_containsFocus() {
|
|
256
|
+
const element = this._elementRef.nativeElement;
|
|
257
|
+
const activeElement = _getFocusedElementPierceShadowDom();
|
|
258
|
+
return element === activeElement || element.contains(activeElement);
|
|
259
|
+
}
|
|
260
|
+
/** Sets up the focus trap. */
|
|
261
|
+
_initializeFocusTrap() {
|
|
262
|
+
this._focusTrap = this._focusTrapFactory.create(this._elementRef.nativeElement);
|
|
263
|
+
// Save the previously focused element. This element will be re-focused
|
|
264
|
+
// when the dialog closes.
|
|
265
|
+
if (this._document) {
|
|
266
|
+
this._elementFocusedBeforeDialogWasOpened = _getFocusedElementPierceShadowDom();
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/** Sets up the listener that handles clicks on the dialog backdrop. */
|
|
270
|
+
_handleBackdropClicks() {
|
|
271
|
+
// Clicking on the backdrop will move focus out of dialog.
|
|
272
|
+
// Recapture it if closing via the backdrop is disabled.
|
|
273
|
+
this._overlayRef.backdropClick().subscribe(() => {
|
|
274
|
+
if (this._config.disableClose && !this._containsFocus()) {
|
|
275
|
+
this._trapFocus();
|
|
276
|
+
}
|
|
277
|
+
});
|
|
290
278
|
}
|
|
291
279
|
}
|
|
292
|
-
CdkDialogContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
293
|
-
CdkDialogContainer.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
294
|
-
|
|
295
|
-
state('enter', style({ opacity: 1 })),
|
|
296
|
-
state('exit, void', style({ opacity: 0 })),
|
|
297
|
-
transition('* => enter', group([
|
|
298
|
-
animate('{{enterAnimationDuration}}'),
|
|
299
|
-
query('@*', animateChild(), { optional: true }),
|
|
300
|
-
])),
|
|
301
|
-
transition('* => exit, * => void', group([
|
|
302
|
-
animate('{{exitAnimationDuration}}'),
|
|
303
|
-
query('@*', animateChild(), { optional: true }),
|
|
304
|
-
])),
|
|
305
|
-
]),
|
|
306
|
-
], changeDetection: i0.ChangeDetectionStrategy.Default, encapsulation: i0.ViewEncapsulation.None });
|
|
307
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9", ngImport: i0, type: CdkDialogContainer, decorators: [{
|
|
280
|
+
CdkDialogContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.13", ngImport: i0, type: CdkDialogContainer, deps: [{ token: i0.ElementRef }, { token: i1.FocusTrapFactory }, { token: DOCUMENT, optional: true }, { token: DialogConfig }, { token: i1.InteractivityChecker }, { token: i0.NgZone }, { token: i1$1.OverlayRef }, { token: i1.FocusMonitor }], target: i0.ɵɵFactoryTarget.Component });
|
|
281
|
+
CdkDialogContainer.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "14.0.0-next.13", type: CdkDialogContainer, selector: "cdk-dialog-container", host: { attributes: { "tabindex": "-1" }, properties: { "attr.id": "_config.id || null", "attr.role": "_config.role", "attr.aria-modal": "_config.ariaModal", "attr.aria-labelledby": "_config.ariaLabel ? null : _ariaLabelledBy", "attr.aria-label": "_config.ariaLabel", "attr.aria-describedby": "_config.ariaDescribedBy || null" }, classAttribute: "cdk-dialog-container" }, viewQueries: [{ propertyName: "_portalOutlet", first: true, predicate: CdkPortalOutlet, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<ng-template cdkPortalOutlet></ng-template>\n", directives: [{ type: i3.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.Default, encapsulation: i0.ViewEncapsulation.None });
|
|
282
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.13", ngImport: i0, type: CdkDialogContainer, decorators: [{
|
|
308
283
|
type: Component,
|
|
309
|
-
args: [{ selector: 'cdk-dialog-container', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.Default,
|
|
310
|
-
|
|
311
|
-
state('enter', style({ opacity: 1 })),
|
|
312
|
-
state('exit, void', style({ opacity: 0 })),
|
|
313
|
-
transition('* => enter', group([
|
|
314
|
-
animate('{{enterAnimationDuration}}'),
|
|
315
|
-
query('@*', animateChild(), { optional: true }),
|
|
316
|
-
])),
|
|
317
|
-
transition('* => exit, * => void', group([
|
|
318
|
-
animate('{{exitAnimationDuration}}'),
|
|
319
|
-
query('@*', animateChild(), { optional: true }),
|
|
320
|
-
])),
|
|
321
|
-
]),
|
|
322
|
-
], host: {
|
|
323
|
-
'[@dialog]': `{
|
|
324
|
-
value: _state,
|
|
325
|
-
params: {
|
|
326
|
-
enterAnimationDuration: _config.enterAnimationDuration,
|
|
327
|
-
exitAnimationDuration: _config.exitAnimationDuration
|
|
328
|
-
}
|
|
329
|
-
}`,
|
|
330
|
-
'(@dialog.start)': '_onAnimationStart($event)',
|
|
331
|
-
'(@dialog.done)': '_animationDone.next($event)',
|
|
284
|
+
args: [{ selector: 'cdk-dialog-container', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.Default, host: {
|
|
285
|
+
'class': 'cdk-dialog-container',
|
|
332
286
|
'tabindex': '-1',
|
|
287
|
+
'[attr.id]': '_config.id || null',
|
|
333
288
|
'[attr.role]': '_config.role',
|
|
334
|
-
'aria-modal': '
|
|
335
|
-
'[attr.aria-
|
|
336
|
-
'[attr.aria-
|
|
337
|
-
|
|
289
|
+
'[attr.aria-modal]': '_config.ariaModal',
|
|
290
|
+
'[attr.aria-labelledby]': '_config.ariaLabel ? null : _ariaLabelledBy',
|
|
291
|
+
'[attr.aria-label]': '_config.ariaLabel',
|
|
292
|
+
'[attr.aria-describedby]': '_config.ariaDescribedBy || null',
|
|
293
|
+
}, template: "<ng-template cdkPortalOutlet></ng-template>\n" }]
|
|
338
294
|
}], ctorParameters: function () {
|
|
339
|
-
return [{ type: i0.ElementRef }, { type: i1.FocusTrapFactory }, { type:
|
|
295
|
+
return [{ type: i0.ElementRef }, { type: i1.FocusTrapFactory }, { type: undefined, decorators: [{
|
|
340
296
|
type: Optional
|
|
341
297
|
}, {
|
|
342
298
|
type: Inject,
|
|
343
299
|
args: [DOCUMENT]
|
|
344
|
-
}] }, { type:
|
|
345
|
-
|
|
300
|
+
}] }, { type: undefined, decorators: [{
|
|
301
|
+
type: Inject,
|
|
302
|
+
args: [DialogConfig]
|
|
303
|
+
}] }, { type: i1.InteractivityChecker }, { type: i0.NgZone }, { type: i1$1.OverlayRef }, { type: i1.FocusMonitor }];
|
|
304
|
+
}, propDecorators: { _portalOutlet: [{
|
|
346
305
|
type: ViewChild,
|
|
347
306
|
args: [CdkPortalOutlet, { static: true }]
|
|
348
307
|
}] } });
|
|
@@ -354,110 +313,71 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9",
|
|
|
354
313
|
* Use of this source code is governed by an MIT-style license that can be
|
|
355
314
|
* found in the LICENSE file at https://angular.io/license
|
|
356
315
|
*/
|
|
357
|
-
/** Unique id for the created dialog. */
|
|
358
|
-
let uniqueId = 0;
|
|
359
316
|
/**
|
|
360
317
|
* Reference to a dialog opened via the Dialog service.
|
|
361
318
|
*/
|
|
362
319
|
class DialogRef {
|
|
363
|
-
constructor(
|
|
364
|
-
this.
|
|
365
|
-
this.
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
this.afterClosed().subscribe(() => {
|
|
379
|
-
this._overlayRef.detach();
|
|
380
|
-
this._overlayRef.dispose();
|
|
381
|
-
this.componentInstance = null;
|
|
320
|
+
constructor(overlayRef, config) {
|
|
321
|
+
this.overlayRef = overlayRef;
|
|
322
|
+
this.config = config;
|
|
323
|
+
/** Emits when the dialog has been closed. */
|
|
324
|
+
this.closed = new Subject();
|
|
325
|
+
this.disableClose = config.disableClose;
|
|
326
|
+
this.backdropClick = overlayRef.backdropClick();
|
|
327
|
+
this.keydownEvents = overlayRef.keydownEvents();
|
|
328
|
+
this.outsidePointerEvents = overlayRef.outsidePointerEvents();
|
|
329
|
+
this.id = config.id; // By the time the dialog is created we are guaranteed to have an ID.
|
|
330
|
+
this.keydownEvents.subscribe(event => {
|
|
331
|
+
if (event.keyCode === ESCAPE && !this.disableClose && !hasModifierKey(event)) {
|
|
332
|
+
event.preventDefault();
|
|
333
|
+
this.close(undefined, { focusOrigin: 'keyboard' });
|
|
334
|
+
}
|
|
382
335
|
});
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
return event.keyCode === ESCAPE && !this.disableClose && !hasModifierKey(event);
|
|
388
|
-
}))
|
|
389
|
-
.subscribe(event => {
|
|
390
|
-
event.preventDefault();
|
|
391
|
-
this.close();
|
|
336
|
+
this.backdropClick.subscribe(() => {
|
|
337
|
+
if (!this.disableClose) {
|
|
338
|
+
this.close(undefined, { focusOrigin: 'mouse' });
|
|
339
|
+
}
|
|
392
340
|
});
|
|
393
341
|
}
|
|
394
|
-
/** Gets an observable that emits when the overlay's backdrop has been clicked. */
|
|
395
|
-
backdropClick() {
|
|
396
|
-
return this._overlayRef.backdropClick();
|
|
397
|
-
}
|
|
398
342
|
/**
|
|
399
343
|
* Close the dialog.
|
|
400
|
-
* @param
|
|
344
|
+
* @param result Optional result to return to the dialog opener.
|
|
345
|
+
* @param options Additional options to customize the closing behavior.
|
|
401
346
|
*/
|
|
402
|
-
close(
|
|
403
|
-
this.
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
updatePosition(position) {
|
|
411
|
-
let strategy = this._getPositionStrategy();
|
|
412
|
-
if (position && (position.left || position.right)) {
|
|
413
|
-
position.left ? strategy.left(position.left) : strategy.right(position.right);
|
|
414
|
-
}
|
|
415
|
-
else {
|
|
416
|
-
strategy.centerHorizontally();
|
|
347
|
+
close(result, options) {
|
|
348
|
+
if (this.containerInstance) {
|
|
349
|
+
const closedSubject = this.closed;
|
|
350
|
+
this.containerInstance._closeInteractionType = (options === null || options === void 0 ? void 0 : options.focusOrigin) || 'program';
|
|
351
|
+
this.overlayRef.dispose();
|
|
352
|
+
closedSubject.next(result);
|
|
353
|
+
closedSubject.complete();
|
|
354
|
+
this.componentInstance = this.containerInstance = null;
|
|
417
355
|
}
|
|
418
|
-
if (position && (position.top || position.bottom)) {
|
|
419
|
-
position.top ? strategy.top(position.top) : strategy.bottom(position.bottom);
|
|
420
|
-
}
|
|
421
|
-
else {
|
|
422
|
-
strategy.centerVertically();
|
|
423
|
-
}
|
|
424
|
-
this._overlayRef.updatePosition();
|
|
425
|
-
return this;
|
|
426
356
|
}
|
|
427
|
-
/**
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
return this._overlayRef.keydownEvents();
|
|
357
|
+
/** Updates the dialog's position. */
|
|
358
|
+
updatePosition() {
|
|
359
|
+
this.overlayRef.updatePosition();
|
|
360
|
+
return this;
|
|
432
361
|
}
|
|
433
362
|
/**
|
|
434
|
-
* Updates the dialog's width and height
|
|
435
|
-
* @param
|
|
363
|
+
* Updates the dialog's width and height.
|
|
364
|
+
* @param width New width of the dialog.
|
|
365
|
+
* @param height New height of the dialog.
|
|
436
366
|
*/
|
|
437
|
-
updateSize(
|
|
438
|
-
this.
|
|
439
|
-
this.
|
|
367
|
+
updateSize(width = '', height = '') {
|
|
368
|
+
this.overlayRef.updateSize({ width, height });
|
|
369
|
+
this.overlayRef.updatePosition();
|
|
440
370
|
return this;
|
|
441
371
|
}
|
|
442
|
-
/**
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
/** Gets an observable that emits when dialog begins opening. */
|
|
447
|
-
beforeOpened() {
|
|
448
|
-
return this._containerInstance._beforeEnter;
|
|
449
|
-
}
|
|
450
|
-
/** Gets an observable that emits when dialog is finished opening. */
|
|
451
|
-
afterOpened() {
|
|
452
|
-
return this._containerInstance._afterEnter;
|
|
453
|
-
}
|
|
454
|
-
/** Gets an observable that emits when dialog begins closing. */
|
|
455
|
-
beforeClosed() {
|
|
456
|
-
return this._containerInstance._beforeExit.pipe(map(() => this._result));
|
|
372
|
+
/** Add a CSS class or an array of classes to the overlay pane. */
|
|
373
|
+
addPanelClass(classes) {
|
|
374
|
+
this.overlayRef.addPanelClass(classes);
|
|
375
|
+
return this;
|
|
457
376
|
}
|
|
458
|
-
/**
|
|
459
|
-
|
|
460
|
-
|
|
377
|
+
/** Remove a CSS class or an array of classes from the overlay pane. */
|
|
378
|
+
removePanelClass(classes) {
|
|
379
|
+
this.overlayRef.removePanelClass(classes);
|
|
380
|
+
return this;
|
|
461
381
|
}
|
|
462
382
|
}
|
|
463
383
|
|
|
@@ -472,21 +392,17 @@ class DialogRef {
|
|
|
472
392
|
const DIALOG_SCROLL_STRATEGY = new InjectionToken('DialogScrollStrategy');
|
|
473
393
|
/** Injection token for the Dialog's Data. */
|
|
474
394
|
const DIALOG_DATA = new InjectionToken('DialogData');
|
|
475
|
-
/** Injection token for the
|
|
476
|
-
const
|
|
477
|
-
/** Injection token for the DialogConfig. */
|
|
478
|
-
const DIALOG_CONFIG = new InjectionToken('DialogConfig');
|
|
479
|
-
/** Injection token for the Dialog's DialogContainer component. */
|
|
480
|
-
const DIALOG_CONTAINER = new InjectionToken('DialogContainer');
|
|
395
|
+
/** Injection token that can be used to provide default options for the dialog module. */
|
|
396
|
+
const DEFAULT_DIALOG_CONFIG = new InjectionToken('DefaultDialogConfig');
|
|
481
397
|
/** @docs-private */
|
|
482
|
-
function
|
|
398
|
+
function DIALOG_SCROLL_STRATEGY_PROVIDER_FACTORY(overlay) {
|
|
483
399
|
return () => overlay.scrollStrategies.block();
|
|
484
400
|
}
|
|
485
401
|
/** @docs-private */
|
|
486
|
-
const
|
|
402
|
+
const DIALOG_SCROLL_STRATEGY_PROVIDER = {
|
|
487
403
|
provide: DIALOG_SCROLL_STRATEGY,
|
|
488
404
|
deps: [Overlay],
|
|
489
|
-
useFactory:
|
|
405
|
+
useFactory: DIALOG_SCROLL_STRATEGY_PROVIDER_FACTORY,
|
|
490
406
|
};
|
|
491
407
|
|
|
492
408
|
/**
|
|
@@ -496,112 +412,90 @@ const MAT_DIALOG_SCROLL_STRATEGY_PROVIDER = {
|
|
|
496
412
|
* Use of this source code is governed by an MIT-style license that can be
|
|
497
413
|
* found in the LICENSE file at https://angular.io/license
|
|
498
414
|
*/
|
|
499
|
-
/**
|
|
500
|
-
|
|
501
|
-
*/
|
|
415
|
+
/** Unique id for the created dialog. */
|
|
416
|
+
let uniqueId = 0;
|
|
502
417
|
class Dialog {
|
|
503
|
-
constructor(_overlay, _injector,
|
|
504
|
-
// TODO(crisbeto): the `any` here can be replaced
|
|
505
|
-
// with the proper type once we start using Ivy.
|
|
506
|
-
scrollStrategy, _parentDialog, location) {
|
|
418
|
+
constructor(_overlay, _injector, _defaultOptions, _parentDialog, _overlayContainer, scrollStrategy) {
|
|
507
419
|
this._overlay = _overlay;
|
|
508
420
|
this._injector = _injector;
|
|
509
|
-
this.
|
|
421
|
+
this._defaultOptions = _defaultOptions;
|
|
510
422
|
this._parentDialog = _parentDialog;
|
|
511
|
-
this.
|
|
512
|
-
|
|
423
|
+
this._overlayContainer = _overlayContainer;
|
|
424
|
+
this._openDialogsAtThisLevel = [];
|
|
425
|
+
this._afterAllClosedAtThisLevel = new Subject();
|
|
426
|
+
this._afterOpenedAtThisLevel = new Subject();
|
|
427
|
+
this._ariaHiddenElements = new Map();
|
|
428
|
+
/**
|
|
429
|
+
* Stream that emits when all open dialog have finished closing.
|
|
430
|
+
* Will emit on subscribe if there are no open dialogs to begin with.
|
|
431
|
+
*/
|
|
513
432
|
this.afterAllClosed = defer(() => this.openDialogs.length
|
|
514
433
|
? this._getAfterAllClosed()
|
|
515
434
|
: this._getAfterAllClosed().pipe(startWith(undefined)));
|
|
516
|
-
this._afterOpened = new Subject();
|
|
517
|
-
this._openDialogs = [];
|
|
518
|
-
// Close all of the dialogs when the user goes forwards/backwards in history or when the
|
|
519
|
-
// location hash changes. Note that this usually doesn't include clicking on links (unless
|
|
520
|
-
// the user is using the `HashLocationStrategy`).
|
|
521
|
-
if (!_parentDialog && location) {
|
|
522
|
-
location.subscribe(() => this.closeAll());
|
|
523
|
-
}
|
|
524
435
|
this._scrollStrategy = scrollStrategy;
|
|
525
436
|
}
|
|
526
|
-
/**
|
|
527
|
-
_getAfterAllClosed() {
|
|
528
|
-
return this._parentDialog ? this._parentDialog.afterAllClosed : this._afterAllClosedBase;
|
|
529
|
-
}
|
|
530
|
-
/** Stream that emits when a dialog is opened. */
|
|
531
|
-
get afterOpened() {
|
|
532
|
-
return this._parentDialog ? this._parentDialog.afterOpened : this._afterOpened;
|
|
533
|
-
}
|
|
534
|
-
/** Stream that emits when a dialog is opened. */
|
|
437
|
+
/** Keeps track of the currently-open dialogs. */
|
|
535
438
|
get openDialogs() {
|
|
536
|
-
return this._parentDialog ? this._parentDialog.openDialogs : this.
|
|
439
|
+
return this._parentDialog ? this._parentDialog.openDialogs : this._openDialogsAtThisLevel;
|
|
537
440
|
}
|
|
538
|
-
/**
|
|
539
|
-
|
|
540
|
-
return this.
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
if (config.id && this.getById(config.id) && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
441
|
+
/** Stream that emits when a dialog has been opened. */
|
|
442
|
+
get afterOpened() {
|
|
443
|
+
return this._parentDialog ? this._parentDialog.afterOpened : this._afterOpenedAtThisLevel;
|
|
444
|
+
}
|
|
445
|
+
open(componentOrTemplateRef, config) {
|
|
446
|
+
const defaults = (this._defaultOptions || new DialogConfig());
|
|
447
|
+
config = Object.assign(Object.assign({}, defaults), config);
|
|
448
|
+
config.id = config.id || `cdk-dialog-${uniqueId++}`;
|
|
449
|
+
if (config.id &&
|
|
450
|
+
this.getDialogById(config.id) &&
|
|
451
|
+
(typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
550
452
|
throw Error(`Dialog with id "${config.id}" exists already. The dialog id must be unique.`);
|
|
551
453
|
}
|
|
552
|
-
const
|
|
553
|
-
const
|
|
554
|
-
const dialogRef =
|
|
555
|
-
this.
|
|
556
|
-
dialogContainer
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
config = this._applyConfigDefaults(config);
|
|
562
|
-
if (config.id && this.getById(config.id) && (typeof ngDevMode === 'undefined' || ngDevMode)) {
|
|
563
|
-
throw Error(`Dialog with id "${config.id}" exists already. The dialog id must be unique.`);
|
|
454
|
+
const overlayConfig = this._getOverlayConfig(config);
|
|
455
|
+
const overlayRef = this._overlay.create(overlayConfig);
|
|
456
|
+
const dialogRef = new DialogRef(overlayRef, config);
|
|
457
|
+
const dialogContainer = this._attachContainer(overlayRef, dialogRef, config);
|
|
458
|
+
dialogRef.containerInstance = dialogContainer;
|
|
459
|
+
this._attachDialogContent(componentOrTemplateRef, dialogRef, dialogContainer, config);
|
|
460
|
+
// If this is the first dialog that we're opening, hide all the non-overlay content.
|
|
461
|
+
if (!this.openDialogs.length) {
|
|
462
|
+
this._hideNonDialogContentFromAssistiveTechnology();
|
|
564
463
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
this._registerDialogRef(dialogRef);
|
|
569
|
-
dialogContainer._initializeWithAttachedContent();
|
|
464
|
+
this.openDialogs.push(dialogRef);
|
|
465
|
+
dialogRef.closed.subscribe(() => this._removeOpenDialog(dialogRef));
|
|
466
|
+
this.afterOpened.next(dialogRef);
|
|
570
467
|
return dialogRef;
|
|
571
468
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
469
|
+
/**
|
|
470
|
+
* Closes all of the currently-open dialogs.
|
|
471
|
+
*/
|
|
472
|
+
closeAll() {
|
|
473
|
+
this._closeDialogs(this.openDialogs);
|
|
575
474
|
}
|
|
576
475
|
/**
|
|
577
|
-
*
|
|
476
|
+
* Finds an open dialog by its id.
|
|
477
|
+
* @param id ID to use when looking up the dialog.
|
|
578
478
|
*/
|
|
579
|
-
|
|
580
|
-
this.openDialogs.
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
this._openDialogs.splice(dialogIndex, 1);
|
|
589
|
-
}
|
|
590
|
-
if (!this._openDialogs.length) {
|
|
591
|
-
this._afterAllClosedBase.next();
|
|
592
|
-
dialogCloseSub.unsubscribe();
|
|
593
|
-
}
|
|
594
|
-
});
|
|
479
|
+
getDialogById(id) {
|
|
480
|
+
return this.openDialogs.find(dialog => dialog.id === id);
|
|
481
|
+
}
|
|
482
|
+
ngOnDestroy() {
|
|
483
|
+
// Only close the dialogs at this level on destroy
|
|
484
|
+
// since the parent service may still be active.
|
|
485
|
+
this._closeDialogs(this._openDialogsAtThisLevel);
|
|
486
|
+
this._afterAllClosedAtThisLevel.complete();
|
|
487
|
+
this._afterOpenedAtThisLevel.complete();
|
|
595
488
|
}
|
|
596
489
|
/**
|
|
597
490
|
* Creates an overlay config from a dialog config.
|
|
598
491
|
* @param config The dialog configuration.
|
|
599
492
|
* @returns The overlay configuration.
|
|
600
493
|
*/
|
|
601
|
-
|
|
602
|
-
const
|
|
603
|
-
positionStrategy:
|
|
604
|
-
|
|
494
|
+
_getOverlayConfig(config) {
|
|
495
|
+
const state = new OverlayConfig({
|
|
496
|
+
positionStrategy: config.positionStrategy ||
|
|
497
|
+
this._overlay.position().global().centerHorizontally().centerVertically(),
|
|
498
|
+
scrollStrategy: config.scrollStrategy || this._scrollStrategy(),
|
|
605
499
|
panelClass: config.panelClass,
|
|
606
500
|
hasBackdrop: config.hasBackdrop,
|
|
607
501
|
direction: config.direction,
|
|
@@ -609,83 +503,92 @@ class Dialog {
|
|
|
609
503
|
minHeight: config.minHeight,
|
|
610
504
|
maxWidth: config.maxWidth,
|
|
611
505
|
maxHeight: config.maxHeight,
|
|
506
|
+
width: config.width,
|
|
507
|
+
height: config.height,
|
|
508
|
+
disposeOnNavigation: config.closeOnNavigation,
|
|
612
509
|
});
|
|
613
510
|
if (config.backdropClass) {
|
|
614
|
-
|
|
511
|
+
state.backdropClass = config.backdropClass;
|
|
615
512
|
}
|
|
616
|
-
return
|
|
513
|
+
return state;
|
|
617
514
|
}
|
|
618
515
|
/**
|
|
619
|
-
* Attaches
|
|
516
|
+
* Attaches a dialog container to a dialog's already-created overlay.
|
|
620
517
|
* @param overlay Reference to the dialog's underlying overlay.
|
|
621
518
|
* @param config The dialog configuration.
|
|
622
519
|
* @returns A promise resolving to a ComponentRef for the attached container.
|
|
623
520
|
*/
|
|
624
|
-
|
|
521
|
+
_attachContainer(overlay, dialogRef, config) {
|
|
625
522
|
var _a, _b;
|
|
626
|
-
const container = config.containerComponent || this._injector.get(DIALOG_CONTAINER);
|
|
627
523
|
const userInjector = (_a = config.injector) !== null && _a !== void 0 ? _a : (_b = config.viewContainerRef) === null || _b === void 0 ? void 0 : _b.injector;
|
|
628
|
-
const
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
524
|
+
const providers = [
|
|
525
|
+
{ provide: DialogConfig, useValue: config },
|
|
526
|
+
{ provide: DialogRef, useValue: dialogRef },
|
|
527
|
+
{ provide: OverlayRef, useValue: overlay },
|
|
528
|
+
];
|
|
529
|
+
let containerType;
|
|
530
|
+
if (config.container) {
|
|
531
|
+
if (typeof config.container === 'function') {
|
|
532
|
+
containerType = config.container;
|
|
533
|
+
}
|
|
534
|
+
else {
|
|
535
|
+
containerType = config.container.type;
|
|
536
|
+
providers.push(...config.container.providers(config));
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
else {
|
|
540
|
+
containerType = CdkDialogContainer;
|
|
541
|
+
}
|
|
542
|
+
const containerPortal = new ComponentPortal(containerType, config.viewContainerRef, Injector.create({ parent: userInjector || this._injector, providers }), config.componentFactoryResolver);
|
|
633
543
|
const containerRef = overlay.attach(containerPortal);
|
|
634
|
-
containerRef.instance._config = config;
|
|
635
544
|
return containerRef.instance;
|
|
636
545
|
}
|
|
637
546
|
/**
|
|
638
|
-
* Attaches the user-provided component to the already-created
|
|
547
|
+
* Attaches the user-provided component to the already-created dialog container.
|
|
639
548
|
* @param componentOrTemplateRef The type of component being loaded into the dialog,
|
|
640
549
|
* or a TemplateRef to instantiate as the content.
|
|
641
|
-
* @param
|
|
642
|
-
* @param
|
|
643
|
-
* @param config
|
|
644
|
-
* @returns A promise resolving to the MatDialogRef that should be returned to the user.
|
|
550
|
+
* @param dialogRef Reference to the dialog being opened.
|
|
551
|
+
* @param dialogContainer Component that is going to wrap the dialog content.
|
|
552
|
+
* @param config Configuration used to open the dialog.
|
|
645
553
|
*/
|
|
646
|
-
|
|
647
|
-
// Create a reference to the dialog we're creating in order to give the user a handle
|
|
648
|
-
// to modify and close it.
|
|
649
|
-
const dialogRef = this._createDialogRef(overlayRef, dialogContainer, config);
|
|
554
|
+
_attachDialogContent(componentOrTemplateRef, dialogRef, dialogContainer, config) {
|
|
650
555
|
const injector = this._createInjector(config, dialogRef, dialogContainer);
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
_attachDialogContentForTemplate(componentOrTemplateRef, dialogContainer, overlayRef, config) {
|
|
665
|
-
// Create a reference to the dialog we're creating in order to give the user a handle
|
|
666
|
-
// to modify and close it.
|
|
667
|
-
const dialogRef = this._createDialogRef(overlayRef, dialogContainer, config);
|
|
668
|
-
dialogContainer.attachTemplatePortal(new TemplatePortal(componentOrTemplateRef, null, {
|
|
669
|
-
$implicit: config.data,
|
|
670
|
-
dialogRef,
|
|
671
|
-
}));
|
|
672
|
-
return dialogRef;
|
|
556
|
+
if (componentOrTemplateRef instanceof TemplateRef) {
|
|
557
|
+
let context = { $implicit: config.data, dialogRef };
|
|
558
|
+
if (config.templateContext) {
|
|
559
|
+
context = Object.assign(Object.assign({}, context), (typeof config.templateContext === 'function'
|
|
560
|
+
? config.templateContext()
|
|
561
|
+
: config.templateContext));
|
|
562
|
+
}
|
|
563
|
+
dialogContainer.attachTemplatePortal(new TemplatePortal(componentOrTemplateRef, null, context, injector));
|
|
564
|
+
}
|
|
565
|
+
else {
|
|
566
|
+
const contentRef = dialogContainer.attachComponentPortal(new ComponentPortal(componentOrTemplateRef, config.viewContainerRef, injector, config.componentFactoryResolver));
|
|
567
|
+
dialogRef.componentInstance = contentRef.instance;
|
|
568
|
+
}
|
|
673
569
|
}
|
|
674
570
|
/**
|
|
675
571
|
* Creates a custom injector to be used inside the dialog. This allows a component loaded inside
|
|
676
572
|
* of a dialog to close itself and, optionally, to return a value.
|
|
677
573
|
* @param config Config object that is used to construct the dialog.
|
|
678
|
-
* @param dialogRef Reference to the dialog.
|
|
679
|
-
* @param
|
|
574
|
+
* @param dialogRef Reference to the dialog being opened.
|
|
575
|
+
* @param dialogContainer Component that is going to wrap the dialog content.
|
|
680
576
|
* @returns The custom injector that can be used inside the dialog.
|
|
681
577
|
*/
|
|
682
578
|
_createInjector(config, dialogRef, dialogContainer) {
|
|
683
579
|
const userInjector = config && config.viewContainerRef && config.viewContainerRef.injector;
|
|
684
580
|
const providers = [
|
|
685
|
-
{ provide: this._injector.get(DIALOG_REF), useValue: dialogRef },
|
|
686
|
-
{ provide: this._injector.get(DIALOG_CONTAINER), useValue: dialogContainer },
|
|
687
581
|
{ provide: DIALOG_DATA, useValue: config.data },
|
|
582
|
+
{ provide: DialogRef, useValue: dialogRef },
|
|
688
583
|
];
|
|
584
|
+
if (config.providers) {
|
|
585
|
+
if (typeof config.providers === 'function') {
|
|
586
|
+
providers.push(...config.providers(dialogRef, config, dialogContainer));
|
|
587
|
+
}
|
|
588
|
+
else {
|
|
589
|
+
providers.push(...config.providers);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
689
592
|
if (config.direction &&
|
|
690
593
|
(!userInjector ||
|
|
691
594
|
!userInjector.get(Directionality, null, InjectFlags.Optional))) {
|
|
@@ -696,39 +599,81 @@ class Dialog {
|
|
|
696
599
|
}
|
|
697
600
|
return Injector.create({ parent: userInjector || this._injector, providers });
|
|
698
601
|
}
|
|
699
|
-
/** Creates a new dialog ref. */
|
|
700
|
-
_createDialogRef(overlayRef, dialogContainer, config) {
|
|
701
|
-
const dialogRef = new this._dialogRefConstructor(overlayRef, dialogContainer, config.id);
|
|
702
|
-
dialogRef.disableClose = config.disableClose;
|
|
703
|
-
dialogRef.updateSize(config).updatePosition(config.position);
|
|
704
|
-
return dialogRef;
|
|
705
|
-
}
|
|
706
602
|
/**
|
|
707
|
-
*
|
|
708
|
-
*
|
|
603
|
+
* Removes a dialog from the array of open dialogs.
|
|
604
|
+
* @param dialogRef Dialog to be removed.
|
|
709
605
|
*/
|
|
710
|
-
|
|
711
|
-
const
|
|
712
|
-
|
|
606
|
+
_removeOpenDialog(dialogRef) {
|
|
607
|
+
const index = this.openDialogs.indexOf(dialogRef);
|
|
608
|
+
if (index > -1) {
|
|
609
|
+
this.openDialogs.splice(index, 1);
|
|
610
|
+
// If all the dialogs were closed, remove/restore the `aria-hidden`
|
|
611
|
+
// to a the siblings and emit to the `afterAllClosed` stream.
|
|
612
|
+
if (!this.openDialogs.length) {
|
|
613
|
+
this._ariaHiddenElements.forEach((previousValue, element) => {
|
|
614
|
+
if (previousValue) {
|
|
615
|
+
element.setAttribute('aria-hidden', previousValue);
|
|
616
|
+
}
|
|
617
|
+
else {
|
|
618
|
+
element.removeAttribute('aria-hidden');
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
this._ariaHiddenElements.clear();
|
|
622
|
+
this._getAfterAllClosed().next();
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
/** Hides all of the content that isn't an overlay from assistive technology. */
|
|
627
|
+
_hideNonDialogContentFromAssistiveTechnology() {
|
|
628
|
+
const overlayContainer = this._overlayContainer.getContainerElement();
|
|
629
|
+
// Ensure that the overlay container is attached to the DOM.
|
|
630
|
+
if (overlayContainer.parentElement) {
|
|
631
|
+
const siblings = overlayContainer.parentElement.children;
|
|
632
|
+
for (let i = siblings.length - 1; i > -1; i--) {
|
|
633
|
+
const sibling = siblings[i];
|
|
634
|
+
if (sibling !== overlayContainer &&
|
|
635
|
+
sibling.nodeName !== 'SCRIPT' &&
|
|
636
|
+
sibling.nodeName !== 'STYLE' &&
|
|
637
|
+
!sibling.hasAttribute('aria-live')) {
|
|
638
|
+
this._ariaHiddenElements.set(sibling, sibling.getAttribute('aria-hidden'));
|
|
639
|
+
sibling.setAttribute('aria-hidden', 'true');
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
/** Closes all of the dialogs in an array. */
|
|
645
|
+
_closeDialogs(dialogs) {
|
|
646
|
+
let i = dialogs.length;
|
|
647
|
+
while (i--) {
|
|
648
|
+
// The `_openDialogs` property isn't updated after close until the rxjs subscription
|
|
649
|
+
// runs on the next microtask, in addition to modifying the array as we're going
|
|
650
|
+
// through it. We loop through all of them and call close without assuming that
|
|
651
|
+
// they'll be removed from the list instantaneously.
|
|
652
|
+
dialogs[i].close();
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
_getAfterAllClosed() {
|
|
656
|
+
const parent = this._parentDialog;
|
|
657
|
+
return parent ? parent._getAfterAllClosed() : this._afterAllClosedAtThisLevel;
|
|
713
658
|
}
|
|
714
659
|
}
|
|
715
|
-
Dialog.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
716
|
-
Dialog.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
717
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
660
|
+
Dialog.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.13", ngImport: i0, type: Dialog, deps: [{ token: i1$1.Overlay }, { token: i0.Injector }, { token: DEFAULT_DIALOG_CONFIG, optional: true }, { token: Dialog, optional: true, skipSelf: true }, { token: i1$1.OverlayContainer }, { token: DIALOG_SCROLL_STRATEGY }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
661
|
+
Dialog.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.13", ngImport: i0, type: Dialog });
|
|
662
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.13", ngImport: i0, type: Dialog, decorators: [{
|
|
718
663
|
type: Injectable
|
|
719
664
|
}], ctorParameters: function () {
|
|
720
|
-
return [{ type: i1$1.Overlay }, { type: i0.Injector }, { type:
|
|
721
|
-
type:
|
|
722
|
-
|
|
723
|
-
}] }, { type: undefined, decorators: [{
|
|
665
|
+
return [{ type: i1$1.Overlay }, { type: i0.Injector }, { type: DialogConfig, decorators: [{
|
|
666
|
+
type: Optional
|
|
667
|
+
}, {
|
|
724
668
|
type: Inject,
|
|
725
|
-
args: [
|
|
669
|
+
args: [DEFAULT_DIALOG_CONFIG]
|
|
726
670
|
}] }, { type: Dialog, decorators: [{
|
|
727
671
|
type: Optional
|
|
728
672
|
}, {
|
|
729
673
|
type: SkipSelf
|
|
730
|
-
}] }, { type:
|
|
731
|
-
type:
|
|
674
|
+
}] }, { type: i1$1.OverlayContainer }, { type: undefined, decorators: [{
|
|
675
|
+
type: Inject,
|
|
676
|
+
args: [DIALOG_SCROLL_STRATEGY]
|
|
732
677
|
}] }];
|
|
733
678
|
} });
|
|
734
679
|
|
|
@@ -741,24 +686,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9",
|
|
|
741
686
|
*/
|
|
742
687
|
class DialogModule {
|
|
743
688
|
}
|
|
744
|
-
DialogModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
745
|
-
DialogModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
689
|
+
DialogModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.13", ngImport: i0, type: DialogModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
690
|
+
DialogModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "14.0.0-next.13", ngImport: i0, type: DialogModule, declarations: [CdkDialogContainer], imports: [OverlayModule, PortalModule, A11yModule], exports: [
|
|
746
691
|
// Re-export the PortalModule so that people extending the `CdkDialogContainer`
|
|
747
692
|
// don't have to remember to import it or be faced with an unhelpful error.
|
|
748
693
|
PortalModule,
|
|
749
694
|
CdkDialogContainer
|
|
750
695
|
] });
|
|
751
|
-
DialogModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
752
|
-
Dialog,
|
|
753
|
-
MAT_DIALOG_SCROLL_STRATEGY_PROVIDER,
|
|
754
|
-
{ provide: DIALOG_REF, useValue: DialogRef },
|
|
755
|
-
{ provide: DIALOG_CONTAINER, useValue: CdkDialogContainer },
|
|
756
|
-
{ provide: DIALOG_CONFIG, useValue: DialogConfig },
|
|
757
|
-
], imports: [[OverlayModule, PortalModule, A11yModule],
|
|
696
|
+
DialogModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.0-next.13", ngImport: i0, type: DialogModule, providers: [Dialog, DIALOG_SCROLL_STRATEGY_PROVIDER], imports: [[OverlayModule, PortalModule, A11yModule],
|
|
758
697
|
// Re-export the PortalModule so that people extending the `CdkDialogContainer`
|
|
759
698
|
// don't have to remember to import it or be faced with an unhelpful error.
|
|
760
699
|
PortalModule] });
|
|
761
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
700
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.13", ngImport: i0, type: DialogModule, decorators: [{
|
|
762
701
|
type: NgModule,
|
|
763
702
|
args: [{
|
|
764
703
|
imports: [OverlayModule, PortalModule, A11yModule],
|
|
@@ -769,13 +708,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9",
|
|
|
769
708
|
CdkDialogContainer,
|
|
770
709
|
],
|
|
771
710
|
declarations: [CdkDialogContainer],
|
|
772
|
-
providers: [
|
|
773
|
-
Dialog,
|
|
774
|
-
MAT_DIALOG_SCROLL_STRATEGY_PROVIDER,
|
|
775
|
-
{ provide: DIALOG_REF, useValue: DialogRef },
|
|
776
|
-
{ provide: DIALOG_CONTAINER, useValue: CdkDialogContainer },
|
|
777
|
-
{ provide: DIALOG_CONFIG, useValue: DialogConfig },
|
|
778
|
-
],
|
|
711
|
+
providers: [Dialog, DIALOG_SCROLL_STRATEGY_PROVIDER],
|
|
779
712
|
}]
|
|
780
713
|
}] });
|
|
781
714
|
|
|
@@ -799,5 +732,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.9",
|
|
|
799
732
|
* Generated bundle index. Do not edit.
|
|
800
733
|
*/
|
|
801
734
|
|
|
802
|
-
export { CdkDialogContainer,
|
|
735
|
+
export { CdkDialogContainer, DEFAULT_DIALOG_CONFIG, DIALOG_DATA, DIALOG_SCROLL_STRATEGY, DIALOG_SCROLL_STRATEGY_PROVIDER, DIALOG_SCROLL_STRATEGY_PROVIDER_FACTORY, Dialog, DialogConfig, DialogModule, DialogRef, throwDialogContentAlreadyAttachedError };
|
|
803
736
|
//# sourceMappingURL=dialog.mjs.map
|