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