From 439852ba8a44fdbd7695e9f99d1153ca27bc62e6 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Thu, 4 Aug 2022 12:20:47 -0700 Subject: [PATCH] feat(material/dialog): Switch dialog implementation to use MDC (#25352) * feat(material/dialog): Switch dialog implementation to use MDC Old implementation is still available under @angular/material/legacy-dialog BREAKING CHANGE: - DOM and CSS classes for mat-dialog have changes - Typescript API is largely the same but may have minor differences - See the MDC migration guide for more information about the changes and how to migrate your app (TODO: link when available) * fixup! feat(material/dialog): Switch dialog implementation to use MDC --- .github/CODEOWNERS | 6 +- .ng-dev/commit-message.mts | 4 +- CHANGELOG_ARCHIVE.md | 4 +- .../material/dialog/BUILD.bazel | 8 +- .../dialog-animations-example.ts | 6 +- .../dialog-content/dialog-content-example.ts | 4 +- .../dialog/dialog-data/dialog-data-example.ts | 6 +- .../dialog-elements-example.ts | 4 +- .../dialog-from-menu-example.ts | 4 +- .../dialog-harness-example.spec.ts | 20 +- .../dialog-harness/dialog-harness-example.ts | 6 +- .../dialog-overview-example.ts | 12 +- .../material/dialog/index.ts | 4 +- src/dev-app/dialog/BUILD.bazel | 2 +- src/dev-app/dialog/dialog-demo.ts | 30 +- src/dev-app/focus-trap/BUILD.bazel | 2 +- src/dev-app/focus-trap/focus-trap-demo.ts | 10 +- src/dev-app/mdc-dialog/BUILD.bazel | 2 +- src/dev-app/mdc-dialog/mdc-dialog-demo.scss | 4 +- src/dev-app/mdc-dialog/mdc-dialog-demo.ts | 2 +- src/dev-app/select/BUILD.bazel | 2 +- src/dev-app/select/select-demo.ts | 6 +- src/e2e-app/BUILD.bazel | 2 +- src/e2e-app/dialog/dialog-e2e-module.ts | 4 +- src/e2e-app/dialog/dialog-e2e.ts | 14 +- .../mdc-dialog/mdc-dialog-e2e-module.ts | 2 +- src/e2e-app/mdc-dialog/mdc-dialog-e2e.ts | 2 +- src/material-experimental/_index.scss | 3 - src/material-experimental/config.bzl | 2 - .../mdc-core/color/_all-color.import.scss | 1 - .../mdc-core/density/_all-density.import.scss | 1 - .../mdc-core/theming/BUILD.bazel | 2 +- .../mdc-core/theming/_all-theme.import.scss | 2 - .../mdc-core/theming/_all-theme.scss | 3 +- .../typography/_all-typography.import.scss | 1 - .../mdc-dialog/README.md | 74 -- .../mdc-dialog/_dialog-theme.import.scss | 1 - .../mdc-dialog/_dialog-theme.scss | 76 -- .../mdc-dialog/dialog-container.html | 5 - .../mdc-dialog/dialog-container.ts | 201 ------ .../mdc-dialog/dialog.scss | 96 --- .../mdc-dialog/public-api.ts | 23 - .../mdc-dialog/testing/dialog-harness.spec.ts | 7 - .../mdc-dialog/testing/dialog-harness.ts | 39 -- src/material/_index.scss | 3 + src/material/_theming.scss | 2 +- src/material/config.bzl | 2 + .../core/density/private/_all-density.scss | 8 +- src/material/core/theming/_all-theme.scss | 2 +- .../tests/test-css-variables-theme.scss | 2 - .../core/typography/_all-typography.scss | 2 +- src/material/dialog/BUILD.bazel | 31 +- src/material/dialog/README.md | 75 +- src/material/dialog/_dialog-legacy-index.scss | 2 - .../_dialog-legacy-padding.import.scss | 0 .../dialog}/_dialog-legacy-padding.scss | 0 src/material/dialog/_dialog-theme.import.scss | 11 +- src/material/dialog/_dialog-theme.scss | 59 +- ...mdc-dialog-structure-overrides.import.scss | 0 .../_mdc-dialog-structure-overrides.scss | 0 src/material/dialog/dialog-container.html | 6 +- src/material/dialog/dialog-container.ts | 191 +++-- .../dialog/dialog-content-directives.ts | 31 +- src/material/dialog/dialog-ref.ts | 10 +- src/material/dialog/dialog.e2e.spec.ts | 10 +- src/material/dialog/dialog.md | 2 +- src/material/dialog/dialog.scss | 118 ++-- src/material/dialog/dialog.spec.ts | 583 +++++++-------- src/material/dialog/dialog.ts | 31 +- .../mdc-dialog => material/dialog}/module.ts | 0 src/material/dialog/public-api.ts | 6 +- src/material/dialog/testing/BUILD.bazel | 20 +- .../dialog/testing/dialog-harness.spec.ts | 6 +- src/material/dialog/testing/dialog-harness.ts | 29 +- .../dialog/testing/dialog-opener.spec.ts | 2 +- src/material/dialog/testing/dialog-opener.ts | 10 +- src/material/dialog/testing/index.ts | 1 + src/material/dialog/testing/public-api.ts | 4 +- .../density/private/_all-density.scss | 2 + .../legacy-core/theming/_all-theme.scss | 2 + .../typography/_all-typography.scss | 2 + .../legacy-dialog}/BUILD.bazel | 51 +- src/material/legacy-dialog/README.md | 1 + .../legacy-dialog/_dialog-legacy-index.scss | 2 + .../legacy-dialog/_dialog-theme.import.scss | 10 + src/material/legacy-dialog/_dialog-theme.scss | 47 ++ .../legacy-dialog/dialog-animations.ts | 15 + .../legacy-dialog/dialog-container.html | 1 + .../legacy-dialog/dialog-container.ts | 123 ++++ .../dialog-content-directives.ts | 54 +- .../dialog-module.ts | 36 +- .../legacy-dialog}/dialog-ref.ts | 4 +- .../legacy-dialog}/dialog.e2e.spec.ts | 10 +- src/material/legacy-dialog/dialog.md | 173 +++++ src/material/legacy-dialog/dialog.scss | 76 ++ .../legacy-dialog}/dialog.spec.ts | 662 ++++++++++-------- .../legacy-dialog}/dialog.ts | 51 +- .../legacy-dialog}/index.ts | 0 src/material/legacy-dialog/public-api.ts | 25 + .../legacy-dialog}/testing/BUILD.bazel | 25 +- .../testing/dialog-harness.spec.ts | 7 + .../legacy-dialog/testing/dialog-harness.ts | 39 ++ .../testing/dialog-opener.spec.ts | 34 +- .../legacy-dialog}/testing/dialog-opener.ts | 30 +- .../legacy-dialog}/testing/index.ts | 0 .../legacy-dialog}/testing/public-api.ts | 4 +- .../testing/shared.spec.ts | 22 +- .../rules/ts-migration/import-replacements.ts | 4 +- .../kitchen-sink-mdc/kitchen-sink-mdc.ts | 2 +- .../kitchen-sink/kitchen-sink.ts | 6 +- .../material/dialog-testing.md | 9 +- tools/public_api_guard/material/dialog.md | 38 +- .../material/legacy-dialog-testing.md | 54 ++ .../material/legacy-dialog.md | 181 +++++ 114 files changed, 2113 insertions(+), 1657 deletions(-) delete mode 100644 src/material-experimental/mdc-dialog/README.md delete mode 100644 src/material-experimental/mdc-dialog/_dialog-theme.import.scss delete mode 100644 src/material-experimental/mdc-dialog/_dialog-theme.scss delete mode 100644 src/material-experimental/mdc-dialog/dialog-container.html delete mode 100644 src/material-experimental/mdc-dialog/dialog-container.ts delete mode 100644 src/material-experimental/mdc-dialog/dialog.scss delete mode 100644 src/material-experimental/mdc-dialog/public-api.ts delete mode 100644 src/material-experimental/mdc-dialog/testing/dialog-harness.spec.ts delete mode 100644 src/material-experimental/mdc-dialog/testing/dialog-harness.ts delete mode 100644 src/material/dialog/_dialog-legacy-index.scss rename src/{material-experimental/mdc-dialog => material/dialog}/_dialog-legacy-padding.import.scss (100%) rename src/{material-experimental/mdc-dialog => material/dialog}/_dialog-legacy-padding.scss (100%) rename src/{material-experimental/mdc-dialog => material/dialog}/_mdc-dialog-structure-overrides.import.scss (100%) rename src/{material-experimental/mdc-dialog => material/dialog}/_mdc-dialog-structure-overrides.scss (100%) rename src/{material-experimental/mdc-dialog => material/dialog}/module.ts (100%) rename src/{material-experimental/mdc-dialog => material/legacy-dialog}/BUILD.bazel (68%) create mode 100644 src/material/legacy-dialog/README.md create mode 100644 src/material/legacy-dialog/_dialog-legacy-index.scss create mode 100644 src/material/legacy-dialog/_dialog-theme.import.scss create mode 100644 src/material/legacy-dialog/_dialog-theme.scss create mode 100644 src/material/legacy-dialog/dialog-animations.ts create mode 100644 src/material/legacy-dialog/dialog-container.html create mode 100644 src/material/legacy-dialog/dialog-container.ts rename src/{material-experimental/mdc-dialog => material/legacy-dialog}/dialog-content-directives.ts (73%) rename src/material/{dialog => legacy-dialog}/dialog-module.ts (50%) rename src/{material-experimental/mdc-dialog => material/legacy-dialog}/dialog-ref.ts (65%) rename src/{material-experimental/mdc-dialog => material/legacy-dialog}/dialog.e2e.spec.ts (96%) create mode 100644 src/material/legacy-dialog/dialog.md create mode 100644 src/material/legacy-dialog/dialog.scss rename src/{material-experimental/mdc-dialog => material/legacy-dialog}/dialog.spec.ts (81%) rename src/{material-experimental/mdc-dialog => material/legacy-dialog}/dialog.ts (55%) rename src/{material-experimental/mdc-dialog => material/legacy-dialog}/index.ts (100%) create mode 100644 src/material/legacy-dialog/public-api.ts rename src/{material-experimental/mdc-dialog => material/legacy-dialog}/testing/BUILD.bazel (62%) create mode 100644 src/material/legacy-dialog/testing/dialog-harness.spec.ts create mode 100644 src/material/legacy-dialog/testing/dialog-harness.ts rename src/{material-experimental/mdc-dialog => material/legacy-dialog}/testing/dialog-opener.spec.ts (65%) rename src/{material-experimental/mdc-dialog => material/legacy-dialog}/testing/dialog-opener.ts (60%) rename src/{material-experimental/mdc-dialog => material/legacy-dialog}/testing/index.ts (100%) rename src/{material-experimental/mdc-dialog => material/legacy-dialog}/testing/public-api.ts (62%) rename src/material/{dialog => legacy-dialog}/testing/shared.spec.ts (90%) create mode 100644 tools/public_api_guard/material/legacy-dialog-testing.md create mode 100644 tools/public_api_guard/material/legacy-dialog.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7b6a9b88c63d..28ab11670608 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -9,7 +9,7 @@ /src/material/legacy-checkbox/** @andrewseguin @devversion /src/material/chips/** @andrewseguin /src/material/datepicker/** @mmalerba @crisbeto @zarend -/src/material/dialog/** @andrewseguin @crisbeto +/src/material/legacy-dialog/** @andrewseguin @crisbeto /src/material/divider/** @andrewseguin @crisbeto /src/material/expansion/** @andrewseguin /src/material/legacy-form-field/** @mmalerba @@ -116,7 +116,7 @@ /src/material/checkbox/** @mmalerba /src/material-experimental/mdc-chips/** @mmalerba /src/material-experimental/mdc-core/** @crisbeto -/src/material-experimental/mdc-dialog/** @devversion +/src/material/dialog/** @devversion /src/material/form-field/** @devversion @mmalerba /src/material-experimental/mdc-list/** @mmalerba @devversion /src/material-experimental/mdc-menu/** @crisbeto @@ -326,7 +326,7 @@ /tools/public_api_guard/material/chips/testing** @andrewseguin /tools/public_api_guard/material/core** @andrewseguin /tools/public_api_guard/material/datepicker** @mmalerba @crisbeto @zarend -/tools/public_api_guard/material/dialog** @andrewseguin @crisbeto +/tools/public_api_guard/material/legacy-dialog** @andrewseguin @crisbeto /tools/public_api_guard/material/divider** @andrewseguin @crisbeto /tools/public_api_guard/material/expansion** @andrewseguin /tools/public_api_guard/material/form-field** @mmalerba diff --git a/.ng-dev/commit-message.mts b/.ng-dev/commit-message.mts index 094869ddecac..da158c44527b 100644 --- a/.ng-dev/commit-message.mts +++ b/.ng-dev/commit-message.mts @@ -45,7 +45,7 @@ export const commitMessage: CommitMessageConfig = { 'material/checkbox', 'material-experimental/mdc-chips', 'material-experimental/mdc-core', - 'material-experimental/mdc-dialog', + 'material/dialog', 'material/form-field', 'material/input', 'material-experimental/mdc-list', @@ -79,7 +79,7 @@ export const commitMessage: CommitMessageConfig = { 'material/core', 'material/legacy-core', 'material/datepicker', - 'material/dialog', + 'material/legacy-dialog', 'material/divider', 'material/expansion', 'material/form-field', diff --git a/CHANGELOG_ARCHIVE.md b/CHANGELOG_ARCHIVE.md index da9a35f6b9ed..9262b504206c 100644 --- a/CHANGELOG_ARCHIVE.md +++ b/CHANGELOG_ARCHIVE.md @@ -1640,7 +1640,7 @@ We expect to have the tool ready when we release version 6.0.0. * **menu:** not closing when overlay is detached externally ([#8868](https://github.com/angular/material2/issues/8868)) ([534c797](https://github.com/angular/material2/commit/534c797)) * **overlay:** export OverlaySizeConfig ([#8932](https://github.com/angular/material2/issues/8932)) ([adfa31e](https://github.com/angular/material2/commit/adfa31e)) * **paginator:** set default display value ([#8455](https://github.com/angular/material2/issues/8455)) ([ccb325e](https://github.com/angular/material2/commit/ccb325e)), closes [#8454](https://github.com/angular/material2/issues/8454) -* **portal:** inaccurate hasAttahed result and portal being cleared if attached too early ([#8642](https://github.com/angular/material2/issues/8642)) ([93e6c53](https://github.com/angular/material2/commit/93e6c53)), closes [/github.com/angular/material2/blob/main/src/material/dialog/dialog-container.ts#L118](https://github.com//github.com/angular/material2/blob/main/src/material/dialog/dialog-container.ts/issues/L118) [#8628](https://github.com/angular/material2/issues/8628) +* **portal:** inaccurate hasAttahed result and portal being cleared if attached too early ([#8642](https://github.com/angular/material2/issues/8642)) ([93e6c53](https://github.com/angular/material2/commit/93e6c53)), closes [/github.com/angular/material2/blob/main/src/material/legacy-dialog/dialog-container.ts#L118](https://github.com//github.com/angular/material2/blob/main/src/material/legacy-dialog/dialog-container.ts/issues/L118) [#8628](https://github.com/angular/material2/issues/8628) * **select:** alt + arrow key not opening in single-selection mode ([#8910](https://github.com/angular/material2/issues/8910)) ([85f83f9](https://github.com/angular/material2/commit/85f83f9)) * **select:** change event emitted before data binding is updated ([#8740](https://github.com/angular/material2/issues/8740)) ([2493797](https://github.com/angular/material2/commit/2493797)), closes [#8739](https://github.com/angular/material2/issues/8739) * **select:** complete state change event ([#8777](https://github.com/angular/material2/issues/8777)) ([46411e3](https://github.com/angular/material2/commit/46411e3)) @@ -3889,4 +3889,4 @@ This inaugural release includes 6 components: As the alpha process continues, these components will continue to evolve. There *will* be breaking changes between alpha releases; the alpha releases are here for people that want an early look or who like to live on the edge and are very tolerant of breaking API and behavior -changes. \ No newline at end of file +changes. diff --git a/src/components-examples/material/dialog/BUILD.bazel b/src/components-examples/material/dialog/BUILD.bazel index b48fe5aa2942..5df673f914dd 100644 --- a/src/components-examples/material/dialog/BUILD.bazel +++ b/src/components-examples/material/dialog/BUILD.bazel @@ -16,8 +16,8 @@ ng_module( "//src/cdk/testing", "//src/cdk/testing/testbed", "//src/material/button", - "//src/material/dialog", - "//src/material/dialog/testing", + "//src/material/legacy-dialog", + "//src/material/legacy-dialog/testing", "//src/material/legacy-input", "//src/material/menu", "@npm//@angular/forms", @@ -43,8 +43,8 @@ ng_test_library( ":dialog", "//src/cdk/testing", "//src/cdk/testing/testbed", - "//src/material/dialog", - "//src/material/dialog/testing", + "//src/material/legacy-dialog", + "//src/material/legacy-dialog/testing", "@npm//@angular/platform-browser", "@npm//@angular/platform-browser-dynamic", ], diff --git a/src/components-examples/material/dialog/dialog-animations/dialog-animations-example.ts b/src/components-examples/material/dialog/dialog-animations/dialog-animations-example.ts index 81d23753fee9..9961c71b7036 100644 --- a/src/components-examples/material/dialog/dialog-animations/dialog-animations-example.ts +++ b/src/components-examples/material/dialog/dialog-animations/dialog-animations-example.ts @@ -1,5 +1,5 @@ import {Component} from '@angular/core'; -import {MatDialog, MatDialogRef} from '@angular/material/dialog'; +import {MatLegacyDialog, MatLegacyDialogRef} from '@angular/material/legacy-dialog'; /** * @title Dialog Animations @@ -10,7 +10,7 @@ import {MatDialog, MatDialogRef} from '@angular/material/dialog'; templateUrl: 'dialog-animations-example.html', }) export class DialogAnimationsExample { - constructor(public dialog: MatDialog) {} + constructor(public dialog: MatLegacyDialog) {} openDialog(enterAnimationDuration: string, exitAnimationDuration: string): void { this.dialog.open(DialogAnimationsExampleDialog, { @@ -26,5 +26,5 @@ export class DialogAnimationsExample { templateUrl: 'dialog-animations-example-dialog.html', }) export class DialogAnimationsExampleDialog { - constructor(public dialogRef: MatDialogRef) {} + constructor(public dialogRef: MatLegacyDialogRef) {} } diff --git a/src/components-examples/material/dialog/dialog-content/dialog-content-example.ts b/src/components-examples/material/dialog/dialog-content/dialog-content-example.ts index d4a8607df784..3bf714dd9fb5 100644 --- a/src/components-examples/material/dialog/dialog-content/dialog-content-example.ts +++ b/src/components-examples/material/dialog/dialog-content/dialog-content-example.ts @@ -1,5 +1,5 @@ import {Component} from '@angular/core'; -import {MatDialog} from '@angular/material/dialog'; +import {MatLegacyDialog} from '@angular/material/legacy-dialog'; /** * @title Dialog with header, scrollable content and actions @@ -9,7 +9,7 @@ import {MatDialog} from '@angular/material/dialog'; templateUrl: 'dialog-content-example.html', }) export class DialogContentExample { - constructor(public dialog: MatDialog) {} + constructor(public dialog: MatLegacyDialog) {} openDialog() { const dialogRef = this.dialog.open(DialogContentExampleDialog); diff --git a/src/components-examples/material/dialog/dialog-data/dialog-data-example.ts b/src/components-examples/material/dialog/dialog-data/dialog-data-example.ts index 3d7ff09f6edd..f185c512eb55 100644 --- a/src/components-examples/material/dialog/dialog-data/dialog-data-example.ts +++ b/src/components-examples/material/dialog/dialog-data/dialog-data-example.ts @@ -1,5 +1,5 @@ import {Component, Inject} from '@angular/core'; -import {MatDialog, MAT_DIALOG_DATA} from '@angular/material/dialog'; +import {MatLegacyDialog, MAT_LEGACY_DIALOG_DATA} from '@angular/material/legacy-dialog'; export interface DialogData { animal: 'panda' | 'unicorn' | 'lion'; @@ -13,7 +13,7 @@ export interface DialogData { templateUrl: 'dialog-data-example.html', }) export class DialogDataExample { - constructor(public dialog: MatDialog) {} + constructor(public dialog: MatLegacyDialog) {} openDialog() { this.dialog.open(DialogDataExampleDialog, { @@ -29,5 +29,5 @@ export class DialogDataExample { templateUrl: 'dialog-data-example-dialog.html', }) export class DialogDataExampleDialog { - constructor(@Inject(MAT_DIALOG_DATA) public data: DialogData) {} + constructor(@Inject(MAT_LEGACY_DIALOG_DATA) public data: DialogData) {} } diff --git a/src/components-examples/material/dialog/dialog-elements/dialog-elements-example.ts b/src/components-examples/material/dialog/dialog-elements/dialog-elements-example.ts index 9f7354b0acf5..f67966234dc9 100644 --- a/src/components-examples/material/dialog/dialog-elements/dialog-elements-example.ts +++ b/src/components-examples/material/dialog/dialog-elements/dialog-elements-example.ts @@ -1,5 +1,5 @@ import {Component} from '@angular/core'; -import {MatDialog} from '@angular/material/dialog'; +import {MatLegacyDialog} from '@angular/material/legacy-dialog'; /** * @title Dialog elements @@ -9,7 +9,7 @@ import {MatDialog} from '@angular/material/dialog'; templateUrl: 'dialog-elements-example.html', }) export class DialogElementsExample { - constructor(public dialog: MatDialog) {} + constructor(public dialog: MatLegacyDialog) {} openDialog() { this.dialog.open(DialogElementsExampleDialog); diff --git a/src/components-examples/material/dialog/dialog-from-menu/dialog-from-menu-example.ts b/src/components-examples/material/dialog/dialog-from-menu/dialog-from-menu-example.ts index 0f8e3f92d71d..c98260d9769b 100644 --- a/src/components-examples/material/dialog/dialog-from-menu/dialog-from-menu-example.ts +++ b/src/components-examples/material/dialog/dialog-from-menu/dialog-from-menu-example.ts @@ -1,5 +1,5 @@ import {Component, ViewChild} from '@angular/core'; -import {MatDialog} from '@angular/material/dialog'; +import {MatLegacyDialog} from '@angular/material/legacy-dialog'; import {MatMenuTrigger} from '@angular/material/menu'; /** * @title Dialog launched from a menu @@ -11,7 +11,7 @@ import {MatMenuTrigger} from '@angular/material/menu'; export class DialogFromMenuExample { @ViewChild('menuTrigger') menuTrigger: MatMenuTrigger; - constructor(public dialog: MatDialog) {} + constructor(public dialog: MatLegacyDialog) {} openDialog() { // #docregion focus-restoration diff --git a/src/components-examples/material/dialog/dialog-harness/dialog-harness-example.spec.ts b/src/components-examples/material/dialog/dialog-harness/dialog-harness-example.spec.ts index 6321a733bfba..50122d3659b1 100644 --- a/src/components-examples/material/dialog/dialog-harness/dialog-harness-example.spec.ts +++ b/src/components-examples/material/dialog/dialog-harness/dialog-harness-example.spec.ts @@ -1,8 +1,8 @@ import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; -import {MatDialogHarness} from '@angular/material/dialog/testing'; +import {MatLegacyDialogHarness} from '@angular/material/legacy-dialog/testing'; import {HarnessLoader} from '@angular/cdk/testing'; -import {MatDialogModule} from '@angular/material/dialog'; +import {MatLegacyDialogModule} from '@angular/material/legacy-dialog'; import {DialogHarnessExample} from './dialog-harness-example'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; @@ -12,7 +12,7 @@ describe('DialogHarnessExample', () => { beforeEach(waitForAsync(async () => { await TestBed.configureTestingModule({ - imports: [MatDialogModule, NoopAnimationsModule], + imports: [MatLegacyDialogModule, NoopAnimationsModule], declarations: [DialogHarnessExample], }).compileComponents(); fixture = TestBed.createComponent(DialogHarnessExample); @@ -22,24 +22,24 @@ describe('DialogHarnessExample', () => { it('should load harness for dialog', async () => { fixture.componentInstance.open(); - const dialogs = await loader.getAllHarnesses(MatDialogHarness); + const dialogs = await loader.getAllHarnesses(MatLegacyDialogHarness); expect(dialogs.length).toBe(1); }); it('should load harness for dialog with specific id', async () => { fixture.componentInstance.open({id: 'my-dialog'}); fixture.componentInstance.open({id: 'other'}); - let dialogs = await loader.getAllHarnesses(MatDialogHarness); + let dialogs = await loader.getAllHarnesses(MatLegacyDialogHarness); expect(dialogs.length).toBe(2); - dialogs = await loader.getAllHarnesses(MatDialogHarness.with({selector: '#my-dialog'})); + dialogs = await loader.getAllHarnesses(MatLegacyDialogHarness.with({selector: '#my-dialog'})); expect(dialogs.length).toBe(1); }); it('should be able to get role of dialog', async () => { fixture.componentInstance.open({role: 'alertdialog'}); fixture.componentInstance.open({role: 'dialog'}); - const dialogs = await loader.getAllHarnesses(MatDialogHarness); + const dialogs = await loader.getAllHarnesses(MatLegacyDialogHarness); expect(await dialogs[0].getRole()).toBe('alertdialog'); expect(await dialogs[1].getRole()).toBe('dialog'); }); @@ -47,17 +47,17 @@ describe('DialogHarnessExample', () => { it('should be able to close dialog', async () => { fixture.componentInstance.open({disableClose: true}); fixture.componentInstance.open(); - let dialogs = await loader.getAllHarnesses(MatDialogHarness); + let dialogs = await loader.getAllHarnesses(MatLegacyDialogHarness); expect(dialogs.length).toBe(2); await dialogs[0].close(); - dialogs = await loader.getAllHarnesses(MatDialogHarness); + dialogs = await loader.getAllHarnesses(MatLegacyDialogHarness); expect(dialogs.length).toBe(1); // should be a noop since "disableClose" is set to "true". await dialogs[0].close(); - dialogs = await loader.getAllHarnesses(MatDialogHarness); + dialogs = await loader.getAllHarnesses(MatLegacyDialogHarness); expect(dialogs.length).toBe(1); }); }); diff --git a/src/components-examples/material/dialog/dialog-harness/dialog-harness-example.ts b/src/components-examples/material/dialog/dialog-harness/dialog-harness-example.ts index ad14ccf51431..08a5a7a26ad7 100644 --- a/src/components-examples/material/dialog/dialog-harness/dialog-harness-example.ts +++ b/src/components-examples/material/dialog/dialog-harness/dialog-harness-example.ts @@ -1,5 +1,5 @@ import {Component, TemplateRef, ViewChild} from '@angular/core'; -import {MatDialog, MatDialogConfig} from '@angular/material/dialog'; +import {MatLegacyDialog, MatLegacyDialogConfig} from '@angular/material/legacy-dialog'; /** * @title Testing with MatDialogHarness @@ -11,9 +11,9 @@ import {MatDialog, MatDialogConfig} from '@angular/material/dialog'; export class DialogHarnessExample { @ViewChild(TemplateRef) dialogTemplate: TemplateRef; - constructor(readonly dialog: MatDialog) {} + constructor(readonly dialog: MatLegacyDialog) {} - open(config?: MatDialogConfig) { + open(config?: MatLegacyDialogConfig) { return this.dialog.open(this.dialogTemplate, config); } } diff --git a/src/components-examples/material/dialog/dialog-overview/dialog-overview-example.ts b/src/components-examples/material/dialog/dialog-overview/dialog-overview-example.ts index 80b6de9f8c43..d2bb965c480c 100644 --- a/src/components-examples/material/dialog/dialog-overview/dialog-overview-example.ts +++ b/src/components-examples/material/dialog/dialog-overview/dialog-overview-example.ts @@ -1,5 +1,9 @@ import {Component, Inject} from '@angular/core'; -import {MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog'; +import { + MatLegacyDialog, + MAT_LEGACY_DIALOG_DATA, + MatLegacyDialogRef, +} from '@angular/material/legacy-dialog'; export interface DialogData { animal: string; @@ -17,7 +21,7 @@ export class DialogOverviewExample { animal: string; name: string; - constructor(public dialog: MatDialog) {} + constructor(public dialog: MatLegacyDialog) {} openDialog(): void { const dialogRef = this.dialog.open(DialogOverviewExampleDialog, { @@ -38,8 +42,8 @@ export class DialogOverviewExample { }) export class DialogOverviewExampleDialog { constructor( - public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: DialogData, + public dialogRef: MatLegacyDialogRef, + @Inject(MAT_LEGACY_DIALOG_DATA) public data: DialogData, ) {} onNoClick(): void { diff --git a/src/components-examples/material/dialog/index.ts b/src/components-examples/material/dialog/index.ts index 2e020553c896..59bee530a9d4 100644 --- a/src/components-examples/material/dialog/index.ts +++ b/src/components-examples/material/dialog/index.ts @@ -2,7 +2,7 @@ import {CommonModule} from '@angular/common'; import {NgModule} from '@angular/core'; import {FormsModule} from '@angular/forms'; import {MatButtonModule} from '@angular/material/button'; -import {MatDialogModule} from '@angular/material/dialog'; +import {MatLegacyDialogModule} from '@angular/material/legacy-dialog'; import {MatLegacyInputModule} from '@angular/material/legacy-input'; import {MatMenuModule} from '@angular/material/menu'; import { @@ -64,7 +64,7 @@ const EXAMPLES = [ imports: [ CommonModule, MatButtonModule, - MatDialogModule, + MatLegacyDialogModule, MatLegacyInputModule, MatMenuModule, FormsModule, diff --git a/src/dev-app/dialog/BUILD.bazel b/src/dev-app/dialog/BUILD.bazel index 6873cc7814fe..f28c2caa4116 100644 --- a/src/dev-app/dialog/BUILD.bazel +++ b/src/dev-app/dialog/BUILD.bazel @@ -12,9 +12,9 @@ ng_module( deps = [ "//src/cdk/drag-drop", "//src/material/button", - "//src/material/dialog", "//src/material/legacy-card", "//src/material/legacy-checkbox", + "//src/material/legacy-dialog", "//src/material/legacy-form-field", "//src/material/legacy-input", "//src/material/legacy-select", diff --git a/src/dev-app/dialog/dialog-demo.ts b/src/dev-app/dialog/dialog-demo.ts index b9a2ec596d01..7ff1dac9f1ca 100644 --- a/src/dev-app/dialog/dialog-demo.ts +++ b/src/dev-app/dialog/dialog-demo.ts @@ -14,17 +14,17 @@ import {MatButtonModule} from '@angular/material/button'; import {MatLegacyCardModule} from '@angular/material/legacy-card'; import {MatLegacyCheckboxModule} from '@angular/material/legacy-checkbox'; import { - MAT_DIALOG_DATA, - MatDialog, - MatDialogConfig, - MatDialogRef, - MatDialogModule, -} from '@angular/material/dialog'; + MAT_LEGACY_DIALOG_DATA, + MatLegacyDialog, + MatLegacyDialogConfig, + MatLegacyDialogModule, + MatLegacyDialogRef, +} from '@angular/material/legacy-dialog'; import {MatLegacyFormFieldModule} from '@angular/material/legacy-form-field'; import {MatLegacyInputModule} from '@angular/material/legacy-input'; import {MatLegacySelectModule} from '@angular/material/legacy-select'; -const defaultDialogConfig = new MatDialogConfig(); +const defaultDialogConfig = new MatLegacyDialogConfig(); @Component({ selector: 'dialog-demo', @@ -36,14 +36,14 @@ const defaultDialogConfig = new MatDialogConfig(); MatButtonModule, MatLegacyCardModule, MatLegacyCheckboxModule, - MatDialogModule, + MatLegacyDialogModule, MatLegacyFormFieldModule, MatLegacyInputModule, MatLegacySelectModule, ], }) export class DialogDemo { - dialogRef: MatDialogRef | null; + dialogRef: MatLegacyDialogRef | null; lastAfterClosedResult: string; lastBeforeCloseResult: string; actionsAlignment: 'start' | 'center' | 'end'; @@ -74,7 +74,7 @@ export class DialogDemo { @ViewChild(TemplateRef) template: TemplateRef; - constructor(public dialog: MatDialog, @Inject(DOCUMENT) doc: any) { + constructor(public dialog: MatLegacyDialog, @Inject(DOCUMENT) doc: any) { // Possible useful example for the open and closeAll events. // Adding a class to the body if a dialog opens and // removing it after all open dialogs are closed @@ -137,8 +137,8 @@ export class JazzDialog { private _dimensionToggle = false; constructor( - public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: any, + public dialogRef: MatLegacyDialogRef, + @Inject(MAT_LEGACY_DIALOG_DATA) public data: any, ) {} togglePosition(): void { @@ -205,12 +205,12 @@ export class JazzDialog { `, standalone: true, - imports: [MatDialogModule, MatButtonModule], + imports: [MatLegacyDialogModule, MatButtonModule], }) export class ContentElementDialog { actionsAlignment: 'start' | 'center' | 'end'; - constructor(public dialog: MatDialog) {} + constructor(public dialog: MatLegacyDialog) {} showInStackedDialog() { this.dialog.open(IFrameDialog); @@ -227,7 +227,7 @@ export class ContentElementDialog { `, ], standalone: true, - imports: [MatDialogModule, MatButtonModule], + imports: [MatLegacyDialogModule, MatButtonModule], template: `

Neptune

diff --git a/src/dev-app/focus-trap/BUILD.bazel b/src/dev-app/focus-trap/BUILD.bazel index e207e44a8581..0f13efbe079d 100644 --- a/src/dev-app/focus-trap/BUILD.bazel +++ b/src/dev-app/focus-trap/BUILD.bazel @@ -15,8 +15,8 @@ ng_module( "//src/cdk/a11y", "//src/cdk/platform", "//src/material/button", - "//src/material/dialog", "//src/material/legacy-card", + "//src/material/legacy-dialog", "//src/material/toolbar", ], ) diff --git a/src/dev-app/focus-trap/focus-trap-demo.ts b/src/dev-app/focus-trap/focus-trap-demo.ts index 23e0fef3ed22..66c7c93a9a98 100644 --- a/src/dev-app/focus-trap/focus-trap-demo.ts +++ b/src/dev-app/focus-trap/focus-trap-demo.ts @@ -16,7 +16,7 @@ import { QueryList, } from '@angular/core'; import {A11yModule, CdkTrapFocus} from '@angular/cdk/a11y'; -import {MatDialog, MatDialogModule} from '@angular/material/dialog'; +import {MatLegacyDialog, MatLegacyDialogModule} from '@angular/material/legacy-dialog'; import {_supportsShadowDom} from '@angular/cdk/platform'; import {CommonModule} from '@angular/common'; import {MatButtonModule} from '@angular/material/button'; @@ -42,7 +42,7 @@ export class FocusTrapShadowDomDemo {} CommonModule, MatButtonModule, MatLegacyCardModule, - MatDialogModule, + MatLegacyDialogModule, MatToolbarModule, FocusTrapShadowDomDemo, ], @@ -56,7 +56,7 @@ export class FocusTrapDemo implements AfterViewInit { _supportsShadowDom = _supportsShadowDom(); - constructor(public dialog: MatDialog) {} + constructor(public dialog: MatLegacyDialog) {} ngAfterViewInit() { // We want all the traps to be disabled by default, but doing so while using the value in @@ -91,11 +91,11 @@ let dialogCount = 0; styleUrls: ['focus-trap-dialog-demo.css'], templateUrl: 'focus-trap-dialog-demo.html', standalone: true, - imports: [MatDialogModule], + imports: [MatLegacyDialogModule], }) export class FocusTrapDialogDemo { id = dialogCount++; - constructor(public dialog: MatDialog) {} + constructor(public dialog: MatLegacyDialog) {} openAnotherDialog() { this.dialog.open(FocusTrapDialogDemo); diff --git a/src/dev-app/mdc-dialog/BUILD.bazel b/src/dev-app/mdc-dialog/BUILD.bazel index ce934a5ca74c..460e6d4ccf2a 100644 --- a/src/dev-app/mdc-dialog/BUILD.bazel +++ b/src/dev-app/mdc-dialog/BUILD.bazel @@ -12,9 +12,9 @@ ng_module( deps = [ "//src/cdk/drag-drop", "//src/material-experimental/mdc-button", - "//src/material-experimental/mdc-dialog", "//src/material/card", "//src/material/checkbox", + "//src/material/dialog", "//src/material/form-field", "//src/material/input", "//src/material/select", diff --git a/src/dev-app/mdc-dialog/mdc-dialog-demo.scss b/src/dev-app/mdc-dialog/mdc-dialog-demo.scss index b3ce5d8261b6..efa378717390 100644 --- a/src/dev-app/mdc-dialog/mdc-dialog-demo.scss +++ b/src/dev-app/mdc-dialog/mdc-dialog-demo.scss @@ -1,4 +1,4 @@ -@use '@angular/material-experimental' as experimental; +@use '@angular/material' as mat; .demo-dialog-card { max-width: 600px; @@ -24,5 +24,5 @@ } .demo-dialog-legacy-padding { - @include experimental.mdc-dialog-legacy-padding(); + @include mat.dialog-legacy-padding(); } diff --git a/src/dev-app/mdc-dialog/mdc-dialog-demo.ts b/src/dev-app/mdc-dialog/mdc-dialog-demo.ts index bb8b4a9a48f3..0890f3afc373 100644 --- a/src/dev-app/mdc-dialog/mdc-dialog-demo.ts +++ b/src/dev-app/mdc-dialog/mdc-dialog-demo.ts @@ -14,7 +14,7 @@ import { MatDialogConfig, MatDialogRef, MatDialogModule, -} from '@angular/material-experimental/mdc-dialog'; +} from '@angular/material/dialog'; import {FormsModule} from '@angular/forms'; import {MatButtonModule} from '@angular/material-experimental/mdc-button'; import {MatCardModule} from '@angular/material/card'; diff --git a/src/dev-app/select/BUILD.bazel b/src/dev-app/select/BUILD.bazel index d7ff1386c0e3..6e11b9dc6861 100644 --- a/src/dev-app/select/BUILD.bazel +++ b/src/dev-app/select/BUILD.bazel @@ -11,9 +11,9 @@ ng_module( ], deps = [ "//src/material/button", - "//src/material/dialog", "//src/material/icon", "//src/material/legacy-card", + "//src/material/legacy-dialog", "//src/material/legacy-form-field", "//src/material/legacy-input", "//src/material/legacy-select", diff --git a/src/dev-app/select/select-demo.ts b/src/dev-app/select/select-demo.ts index 3f5788953dde..ddd8ecc942ad 100644 --- a/src/dev-app/select/select-demo.ts +++ b/src/dev-app/select/select-demo.ts @@ -12,7 +12,7 @@ import {FormControl, FormsModule, ReactiveFormsModule, Validators} from '@angula import {MatButtonModule} from '@angular/material/button'; import {MatLegacyCardModule} from '@angular/material/legacy-card'; import {ErrorStateMatcher, ThemePalette} from '@angular/material/core'; -import {MatDialog, MatDialogModule} from '@angular/material/dialog'; +import {MatLegacyDialog, MatLegacyDialogModule} from '@angular/material/legacy-dialog'; import {FloatLabelType, MatLegacyFormFieldModule} from '@angular/material/legacy-form-field'; import {MatIconModule} from '@angular/material/icon'; import {MatLegacyInputModule} from '@angular/material/legacy-input'; @@ -38,7 +38,7 @@ export class MyErrorStateMatcher implements ErrorStateMatcher { FormsModule, MatButtonModule, MatLegacyCardModule, - MatDialogModule, + MatLegacyDialogModule, MatLegacyFormFieldModule, MatIconModule, MatLegacyInputModule, @@ -152,7 +152,7 @@ export class SelectDemo { {value: 'indramon-5', viewValue: 'Indramon'}, ]; - constructor(private _dialog: MatDialog) {} + constructor(private _dialog: MatLegacyDialog) {} toggleDisabled() { this.foodControl.enabled ? this.foodControl.disable() : this.foodControl.enable(); diff --git a/src/e2e-app/BUILD.bazel b/src/e2e-app/BUILD.bazel index 44f950ef174c..659845b0b933 100644 --- a/src/e2e-app/BUILD.bazel +++ b/src/e2e-app/BUILD.bazel @@ -44,7 +44,6 @@ ng_module( "//src/components-examples/private", "//src/material-experimental/mdc-button", "//src/material-experimental/mdc-chips", - "//src/material-experimental/mdc-dialog", "//src/material-experimental/mdc-menu", "//src/material-experimental/mdc-progress-spinner", "//src/material-experimental/mdc-radio", @@ -61,6 +60,7 @@ ng_module( "//src/material/icon", "//src/material/input", "//src/material/legacy-checkbox", + "//src/material/legacy-dialog", "//src/material/legacy-form-field", "//src/material/legacy-input", "//src/material/legacy-progress-bar", diff --git a/src/e2e-app/dialog/dialog-e2e-module.ts b/src/e2e-app/dialog/dialog-e2e-module.ts index 6bb0d8c47f7e..0bf284ab8d5a 100644 --- a/src/e2e-app/dialog/dialog-e2e-module.ts +++ b/src/e2e-app/dialog/dialog-e2e-module.ts @@ -7,11 +7,11 @@ */ import {NgModule} from '@angular/core'; -import {MatDialogModule} from '@angular/material/dialog'; +import {MatLegacyDialogModule} from '@angular/material/legacy-dialog'; import {DialogE2E, TestDialog} from './dialog-e2e'; @NgModule({ - imports: [MatDialogModule], + imports: [MatLegacyDialogModule], declarations: [DialogE2E, TestDialog], }) export class DialogE2eModule {} diff --git a/src/e2e-app/dialog/dialog-e2e.ts b/src/e2e-app/dialog/dialog-e2e.ts index a46e3cc2d4c0..c1a247784000 100644 --- a/src/e2e-app/dialog/dialog-e2e.ts +++ b/src/e2e-app/dialog/dialog-e2e.ts @@ -1,18 +1,22 @@ import {Component, ViewChild, TemplateRef} from '@angular/core'; -import {MatDialog, MatDialogRef, MatDialogConfig} from '@angular/material/dialog'; +import { + MatLegacyDialog, + MatLegacyDialogConfig, + MatLegacyDialogRef, +} from '@angular/material/legacy-dialog'; @Component({ selector: 'dialog-e2e', templateUrl: 'dialog-e2e.html', }) export class DialogE2E { - dialogRef: MatDialogRef | null; + dialogRef: MatLegacyDialogRef | null; @ViewChild(TemplateRef) templateRef: TemplateRef; - constructor(private _dialog: MatDialog) {} + constructor(private _dialog: MatLegacyDialog) {} - private _openDialog(config?: MatDialogConfig) { + private _openDialog(config?: MatLegacyDialogConfig) { this.dialogRef = this._dialog.open(TestDialog, config); this.dialogRef.afterClosed().subscribe(() => (this.dialogRef = null)); } @@ -40,5 +44,5 @@ export class DialogE2E { `, }) export class TestDialog { - constructor(public dialogRef: MatDialogRef) {} + constructor(public dialogRef: MatLegacyDialogRef) {} } diff --git a/src/e2e-app/mdc-dialog/mdc-dialog-e2e-module.ts b/src/e2e-app/mdc-dialog/mdc-dialog-e2e-module.ts index ea4980ebfd64..3ae58cb86c27 100644 --- a/src/e2e-app/mdc-dialog/mdc-dialog-e2e-module.ts +++ b/src/e2e-app/mdc-dialog/mdc-dialog-e2e-module.ts @@ -7,7 +7,7 @@ */ import {NgModule} from '@angular/core'; -import {MatDialogModule} from '@angular/material-experimental/mdc-dialog'; +import {MatDialogModule} from '@angular/material/dialog'; import {MdcDialogE2E, TestDialog} from './mdc-dialog-e2e'; @NgModule({ diff --git a/src/e2e-app/mdc-dialog/mdc-dialog-e2e.ts b/src/e2e-app/mdc-dialog/mdc-dialog-e2e.ts index f75044363f8f..f33657dfe653 100644 --- a/src/e2e-app/mdc-dialog/mdc-dialog-e2e.ts +++ b/src/e2e-app/mdc-dialog/mdc-dialog-e2e.ts @@ -1,5 +1,5 @@ import {Component, ViewChild, TemplateRef} from '@angular/core'; -import {MatDialog, MatDialogRef, MatDialogConfig} from '@angular/material-experimental/mdc-dialog'; +import {MatDialog, MatDialogRef, MatDialogConfig} from '@angular/material/dialog'; @Component({ selector: 'mdc-dialog-e2e', diff --git a/src/material-experimental/_index.scss b/src/material-experimental/_index.scss index a1a328faa49e..ee96a2212f46 100644 --- a/src/material-experimental/_index.scss +++ b/src/material-experimental/_index.scss @@ -25,8 +25,6 @@ mdc-icon-button-typography, mdc-icon-button-density, mdc-icon-button-theme; @forward './mdc-chips/chips-theme' as mdc-chips-* show mdc-chips-color, mdc-chips-typography, mdc-chips-density, mdc-chips-theme; -@forward './mdc-dialog/dialog-theme' as mdc-dialog-* show mdc-dialog-color, mdc-dialog-typography, - mdc-dialog-density, mdc-dialog-theme; @forward './mdc-list/list-theme' as mdc-list-* show mdc-list-color, mdc-list-typography, mdc-list-density, mdc-list-theme; @forward './mdc-menu/menu-theme' as mdc-menu-* show mdc-menu-color, mdc-menu-typography, @@ -50,4 +48,3 @@ mdc-tabs-density, mdc-tabs-theme; // Additional public APIs for individual components -@forward './mdc-dialog/dialog-legacy-padding' as mdc-dialog-* show mdc-dialog-legacy-padding; diff --git a/src/material-experimental/config.bzl b/src/material-experimental/config.bzl index fffaf1284c66..e758cb3cee22 100644 --- a/src/material-experimental/config.bzl +++ b/src/material-experimental/config.bzl @@ -5,8 +5,6 @@ entryPoints = [ "mdc-chips", "mdc-chips/testing", "mdc-core", - "mdc-dialog", - "mdc-dialog/testing", "mdc-list", "mdc-list/testing", "mdc-menu", diff --git a/src/material-experimental/mdc-core/color/_all-color.import.scss b/src/material-experimental/mdc-core/color/_all-color.import.scss index e6016d664e33..647957115d39 100644 --- a/src/material-experimental/mdc-core/color/_all-color.import.scss +++ b/src/material-experimental/mdc-core/color/_all-color.import.scss @@ -38,7 +38,6 @@ $mat-mdc-table-mdc-data-table-sort-icon-active-color, $mat-mdc-table-mdc-data-ta $mat-mdc-table-mdc-data-table-stroke-color, $mat-mdc-table-mdc-data-table-table-divider-color; @forward '../../mdc-paginator/paginator-variables' as mat-mdc-paginator-*; @forward '../core-theme.import'; -@forward '../../mdc-dialog/dialog-theme' as mat-mdc-dialog-*; @forward '../../mdc-list/interactive-list-theme' as mat-mdc-*; @forward '../../mdc-list/list-option-theme' as mat-mdc-*; @forward '../../mdc-list/list-theme' as mat-mdc-list-*; diff --git a/src/material-experimental/mdc-core/density/_all-density.import.scss b/src/material-experimental/mdc-core/density/_all-density.import.scss index b9ed26e1992d..a86bc25012f5 100644 --- a/src/material-experimental/mdc-core/density/_all-density.import.scss +++ b/src/material-experimental/mdc-core/density/_all-density.import.scss @@ -38,7 +38,6 @@ $mat-mdc-table-mdc-data-table-sort-icon-active-color, $mat-mdc-table-mdc-data-ta $mat-mdc-table-mdc-data-table-stroke-color, $mat-mdc-table-mdc-data-table-table-divider-color; @forward '../../mdc-paginator/paginator-variables' as mat-mdc-paginator-*; @forward '../core-theme.import'; -@forward '../../mdc-dialog/dialog-theme' as mat-mdc-dialog-*; @forward '../../mdc-list/interactive-list-theme' as mat-mdc-*; @forward '../../mdc-list/list-option-theme' as mat-mdc-*; @forward '../../mdc-list/list-theme' as mat-mdc-list-*; diff --git a/src/material-experimental/mdc-core/theming/BUILD.bazel b/src/material-experimental/mdc-core/theming/BUILD.bazel index e6738e9823e6..0421dd8440ad 100644 --- a/src/material-experimental/mdc-core/theming/BUILD.bazel +++ b/src/material-experimental/mdc-core/theming/BUILD.bazel @@ -23,7 +23,6 @@ sass_library( "//src/material-experimental/mdc-button:mdc_button_scss_lib", "//src/material-experimental/mdc-chips:mdc_chips_scss_lib", "//src/material-experimental/mdc-core:mdc_core_scss_lib", - "//src/material-experimental/mdc-dialog:mdc_dialog_scss_lib", "//src/material-experimental/mdc-list:mdc_list_scss_lib", "//src/material-experimental/mdc-menu:mdc_menu_scss_lib", "//src/material-experimental/mdc-paginator:mdc_paginator_scss_lib", @@ -37,6 +36,7 @@ sass_library( "//src/material/autocomplete:autocomplete_scss_lib", "//src/material/card:card_scss_lib", "//src/material/checkbox:checkbox_scss_lib", + "//src/material/dialog:dialog_scss_lib", "//src/material/form-field:form_field_scss_lib", "//src/material/input:input_scss_lib", "//src/material/progress-bar:progress_bar_scss_lib", diff --git a/src/material-experimental/mdc-core/theming/_all-theme.import.scss b/src/material-experimental/mdc-core/theming/_all-theme.import.scss index ec483d326e96..b1d96e5a99aa 100644 --- a/src/material-experimental/mdc-core/theming/_all-theme.import.scss +++ b/src/material-experimental/mdc-core/theming/_all-theme.import.scss @@ -38,7 +38,6 @@ $mat-mdc-table-mdc-data-table-sort-icon-active-color, $mat-mdc-table-mdc-data-ta $mat-mdc-table-mdc-data-table-stroke-color, $mat-mdc-table-mdc-data-table-table-divider-color; @forward '../../mdc-paginator/paginator-variables' as mat-mdc-paginator-*; @forward '../core-theme.import'; -@forward '../../mdc-dialog/dialog-theme' as mat-mdc-dialog-*; @forward '../../mdc-list/interactive-list-theme' as mat-mdc-*; @forward '../../mdc-list/list-option-theme' as mat-mdc-*; @forward '../../mdc-list/list-theme' as mat-mdc-list-*; @@ -50,7 +49,6 @@ $mat-mdc-table-mdc-data-table-stroke-color, $mat-mdc-table-mdc-data-table-table- @import '../core-theme'; @import '../../mdc-button/button-theme'; @import '../../mdc-chips/chips-theme'; -@import '../../mdc-dialog/dialog-theme'; @import '../../mdc-list/list-theme'; @import '../../mdc-menu/menu-theme'; @import '../../mdc-radio/radio-theme'; diff --git a/src/material-experimental/mdc-core/theming/_all-theme.scss b/src/material-experimental/mdc-core/theming/_all-theme.scss index 613ed8178a60..8dd61c36560b 100644 --- a/src/material-experimental/mdc-core/theming/_all-theme.scss +++ b/src/material-experimental/mdc-core/theming/_all-theme.scss @@ -5,7 +5,6 @@ @use '../../mdc-button/fab-theme'; @use '../../mdc-button/icon-button-theme'; @use '../../mdc-chips/chips-theme'; -@use '../../mdc-dialog/dialog-theme'; @use '../../mdc-list/list-theme'; @use '../../mdc-menu/menu-theme'; @use '../../mdc-radio/radio-theme'; @@ -23,7 +22,7 @@ @include core-theme.theme($theme-or-color-config); @include mat.autocomplete-theme($theme-or-color-config); @include button-theme.theme($theme-or-color-config); - @include dialog-theme.theme($theme-or-color-config); + @include mat.dialog-theme($theme-or-color-config); @include fab-theme.theme($theme-or-color-config); @include icon-button-theme.theme($theme-or-color-config); @include mat.card-theme($theme-or-color-config); diff --git a/src/material-experimental/mdc-core/typography/_all-typography.import.scss b/src/material-experimental/mdc-core/typography/_all-typography.import.scss index 53b76821ded5..de47bfd36ce9 100644 --- a/src/material-experimental/mdc-core/typography/_all-typography.import.scss +++ b/src/material-experimental/mdc-core/typography/_all-typography.import.scss @@ -38,7 +38,6 @@ $mat-mdc-table-mdc-data-table-sort-icon-active-color, $mat-mdc-table-mdc-data-ta $mat-mdc-table-mdc-data-table-stroke-color, $mat-mdc-table-mdc-data-table-table-divider-color; @forward '../../mdc-paginator/paginator-variables' as mat-mdc-paginator-*; @forward '../core-theme.import'; -@forward '../../mdc-dialog/dialog-theme' as mat-mdc-dialog-*; @forward '../../mdc-list/interactive-list-theme' as mat-mdc-*; @forward '../../mdc-list/list-option-theme' as mat-mdc-*; @forward '../../mdc-list/list-theme' as mat-mdc-list-*; diff --git a/src/material-experimental/mdc-dialog/README.md b/src/material-experimental/mdc-dialog/README.md deleted file mode 100644 index 502462aef15a..000000000000 --- a/src/material-experimental/mdc-dialog/README.md +++ /dev/null @@ -1,74 +0,0 @@ -This is a prototype of an alternate version of `MatDialog` built on top of -[MDC Web](https://github.com/material-components/material-components-web). This component is -experimental and should not be used in production. - -## How to use - -Assuming your application is already up and running using Angular Material, you can add this -component by following these steps: - -1. Install `@angular/material-experimental` and MDC Web: - - ```bash - npm i material-components-web @angular/material-experimental - ``` - -2. In your `angular.json`, make sure `node_modules/` is listed as a Sass include path. This is - needed for the Sass compiler to be able to find the MDC Web Sass files. - - ```json - ... - "styles": [ - "src/styles.scss" - ], - "stylePreprocessorOptions": { - "includePaths": [ - "node_modules/" - ] - }, - ... - ``` - -3. Import the experimental `MatDialogModule` and add it to the module that declares your - component: - - ```ts - import {MatDialogModule} from '@angular/material-experimental/mdc-dialog'; - - @NgModule({ - declarations: [MyComponent], - imports: [MatDialogModule], - }) - export class MyModule {} - ``` - -4. Use the `MatDialog` service in your components by injecting the service, just like you would - use the normal dialog. - -5. Ensure color and typography styles for `@angular/material-experimental` are set up. Either - use a custom theme and use the `mat-mdc-dialog-theme` mixin, or use a prebuilt theme - from `@angular/material/core/theming/prebuilt`. - -## API differences - -The runtime API for the `MatDialog` service is fully compatible and no changes are needed. Visually -the dialog has changed a little bit with the MDC-based implementation. In concrete, the dialog no -longer has outer padding by default. - -If content elements such as `matDialogContent` or `matDialogTitle` are used though, the MDC dialog -will display as with the current non-experimental dialog. The padding change will only surface if -you have custom content within the dialog that is not wrapped with `matDialogContent`, -`matDialogActions` or `matDialogTitle`. - -We provide a backwards compatibility mixin that re-adds the outer padding. The use of this mixin -is generally not recommended as it results in inefficient CSS for the dialog because padding from -the content elements would need to be off set (to not have stacked padding). Ideally, if you have -custom content outside of the provided dialog sections, add the necessary padding to the element -directly through CSS, or move them into one of the defined sections the Angular Material dialog -provides. - -```scss -@use '@angular/material-experimental' as experimental; - -@include experimental.mdc-dialog-legacy-padding(); -``` diff --git a/src/material-experimental/mdc-dialog/_dialog-theme.import.scss b/src/material-experimental/mdc-dialog/_dialog-theme.import.scss deleted file mode 100644 index c8a1b77413ee..000000000000 --- a/src/material-experimental/mdc-dialog/_dialog-theme.import.scss +++ /dev/null @@ -1 +0,0 @@ -@forward 'dialog-theme' as mat-mdc-dialog-*; diff --git a/src/material-experimental/mdc-dialog/_dialog-theme.scss b/src/material-experimental/mdc-dialog/_dialog-theme.scss deleted file mode 100644 index f99c537a587d..000000000000 --- a/src/material-experimental/mdc-dialog/_dialog-theme.scss +++ /dev/null @@ -1,76 +0,0 @@ -@use 'sass:map'; -@use '@angular/material' as mat; -@use '@material/dialog' as mdc-dialog; -@use '@material/dialog/dialog-theme' as mdc-dialog-theme; -@use '@material/theme/theme-color' as mdc-theme-color; -@use '@material/typography' as mdc-typography; - -@mixin color($config-or-theme) { - $config: mat.get-color-config($config-or-theme); - - @include mat.private-using-mdc-theme($config) { - .mat-mdc-dialog-container { - $surface: mdc-theme-color.$surface; - $on-surface: mdc-theme-color.$on-surface; - $text-emphasis-high: mdc-theme-color.text-emphasis(high); - $text-emphasis-medium: mdc-theme-color.text-emphasis(medium); - - @include mdc-dialog-theme.theme(( - container-color: $surface, - container-elevation: 24, - container-shadow-color: $on-surface, - with-divider-divider-color: rgba($on-surface, mdc-dialog.$scroll-divider-opacity), - subhead-color: rgba($on-surface, $text-emphasis-high), - supporting-text-color: rgba($on-surface, $text-emphasis-medium), - )); - } - } -} - -@mixin typography($config-or-theme) { - $config: mat.private-typography-to-2018-config( - mat.get-typography-config($config-or-theme)); - @include mat.private-using-mdc-typography($config) { - .mat-mdc-dialog-container { - $styles: mdc-typography.$styles; - $headline6: map.get($styles, headline6); - - @include mdc-dialog-theme.theme(( - subhead-font: map.get($headline6, font-family), - subhead-line-height: map.get($styles, headline6, line-height), - subhead-size: map.get($styles, headline6, font-size), - subhead-weight: map.get($styles, headline6, font-weight), - subhead-tracking: map.get($styles, headline6, letter-spacing), - - supporting-text-font: map.get($styles, body1, font-family), - supporting-text-line-height: map.get($styles, body1, line-height), - supporting-text-size: map.get($styles, body1, font-size), - supporting-text-weight: map.get($styles, body1, font-weight), - supporting-text-tracking: map.get($styles, body1, letter-spacing), - )); - } - } -} - -@mixin density($config-or-theme) { - $density-scale: mat.get-density-config($config-or-theme); -} - -@mixin theme($theme-or-color-config) { - $theme: mat.private-legacy-get-theme($theme-or-color-config); - @include mat.private-check-duplicate-theme-styles($theme, 'mat-mdc-dialog') { - $color: mat.get-color-config($theme); - $density: mat.get-density-config($theme); - $typography: mat.get-typography-config($theme); - - @if $color != null { - @include color($color); - } - @if $density != null { - @include density($density); - } - @if $typography != null { - @include typography($typography); - } - } -} diff --git a/src/material-experimental/mdc-dialog/dialog-container.html b/src/material-experimental/mdc-dialog/dialog-container.html deleted file mode 100644 index bcb86f4c42d1..000000000000 --- a/src/material-experimental/mdc-dialog/dialog-container.html +++ /dev/null @@ -1,5 +0,0 @@ -
-
- -
-
diff --git a/src/material-experimental/mdc-dialog/dialog-container.ts b/src/material-experimental/mdc-dialog/dialog-container.ts deleted file mode 100644 index d7763849ef19..000000000000 --- a/src/material-experimental/mdc-dialog/dialog-container.ts +++ /dev/null @@ -1,201 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {FocusMonitor, FocusTrapFactory, InteractivityChecker} from '@angular/cdk/a11y'; -import {OverlayRef} from '@angular/cdk/overlay'; -import {DOCUMENT} from '@angular/common'; -import { - ChangeDetectionStrategy, - Component, - ElementRef, - Inject, - OnDestroy, - Optional, - ViewEncapsulation, - NgZone, -} from '@angular/core'; -import {MatDialogConfig, _MatDialogContainerBase} from '@angular/material/dialog'; -import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; -import {cssClasses, numbers} from '@material/dialog'; - -/** - * Internal component that wraps user-provided dialog content in a MDC dialog. - * @docs-private - */ -@Component({ - selector: 'mat-dialog-container', - templateUrl: 'dialog-container.html', - styleUrls: ['dialog.css'], - encapsulation: ViewEncapsulation.None, - // Disabled for consistency with the non-MDC dialog container. - // tslint:disable-next-line:validate-decorators - changeDetection: ChangeDetectionStrategy.Default, - host: { - 'class': 'mat-mdc-dialog-container mdc-dialog', - 'tabindex': '-1', - '[attr.aria-modal]': '_config.ariaModal', - '[id]': '_config.id', - '[attr.role]': '_config.role', - '[attr.aria-labelledby]': '_config.ariaLabel ? null : _ariaLabelledBy', - '[attr.aria-label]': '_config.ariaLabel', - '[attr.aria-describedby]': '_config.ariaDescribedBy || null', - '[class._mat-animation-noopable]': '!_animationsEnabled', - }, -}) -export class MatDialogContainer extends _MatDialogContainerBase implements OnDestroy { - /** Whether animations are enabled. */ - _animationsEnabled: boolean = this._animationMode !== 'NoopAnimations'; - - /** Host element of the dialog container component. */ - private _hostElement: HTMLElement = this._elementRef.nativeElement; - /** Duration of the dialog open animation. */ - private _openAnimationDuration = this._animationsEnabled - ? numbers.DIALOG_ANIMATION_OPEN_TIME_MS - : 0; - /** Duration of the dialog close animation. */ - private _closeAnimationDuration = this._animationsEnabled - ? numbers.DIALOG_ANIMATION_CLOSE_TIME_MS - : 0; - /** Current timer for dialog animations. */ - private _animationTimer: number | null = null; - - constructor( - elementRef: ElementRef, - focusTrapFactory: FocusTrapFactory, - @Optional() @Inject(DOCUMENT) document: any, - dialogConfig: MatDialogConfig, - checker: InteractivityChecker, - ngZone: NgZone, - overlayRef: OverlayRef, - @Optional() @Inject(ANIMATION_MODULE_TYPE) private _animationMode?: string, - focusMonitor?: FocusMonitor, - ) { - super( - elementRef, - focusTrapFactory, - document, - dialogConfig, - checker, - ngZone, - overlayRef, - focusMonitor, - ); - } - - protected override _contentAttached(): void { - // Delegate to the original dialog-container initialization (i.e. saving the - // previous element, setting up the focus trap and moving focus to the container). - super._contentAttached(); - - // Note: Usually we would be able to use the MDC dialog foundation here to handle - // the dialog animation for us, but there are a few reasons why we just leverage - // their styles and not use the runtime foundation code: - // 1. Foundation does not allow us to disable animations. - // 2. Foundation contains unnecessary features we don't need and aren't - // tree-shakeable. e.g. background scrim, keyboard event handlers for ESC button. - // 3. Foundation uses unnecessary timers for animations to work around limitations - // in React's `setState` mechanism. - // https://github.com/material-components/material-components-web/pull/3682. - this._startOpenAnimation(); - } - - override ngOnDestroy() { - super.ngOnDestroy(); - - if (this._animationTimer !== null) { - clearTimeout(this._animationTimer); - } - } - - /** Starts the dialog open animation if enabled. */ - private _startOpenAnimation() { - this._animationStateChanged.emit({state: 'opening', totalTime: this._openAnimationDuration}); - - if (this._animationsEnabled) { - // One would expect that the open class is added once the animation finished, but MDC - // uses the open class in combination with the opening class to start the animation. - this._hostElement.classList.add(cssClasses.OPENING); - this._hostElement.classList.add(cssClasses.OPEN); - this._waitForAnimationToComplete(this._openAnimationDuration, this._finishDialogOpen); - } else { - this._hostElement.classList.add(cssClasses.OPEN); - // Note: We could immediately finish the dialog opening here with noop animations, - // but we defer until next tick so that consumers can subscribe to `afterOpened`. - // Executing this immediately would mean that `afterOpened` emits synchronously - // on `dialog.open` before the consumer had a change to subscribe to `afterOpened`. - Promise.resolve().then(() => this._finishDialogOpen()); - } - } - - /** - * Starts the exit animation of the dialog if enabled. This method is - * called by the dialog ref. - */ - _startExitAnimation(): void { - this._animationStateChanged.emit({state: 'closing', totalTime: this._closeAnimationDuration}); - this._hostElement.classList.remove(cssClasses.OPEN); - - if (this._animationsEnabled) { - this._hostElement.classList.add(cssClasses.CLOSING); - this._waitForAnimationToComplete(this._closeAnimationDuration, this._finishDialogClose); - } else { - // This subscription to the `OverlayRef#backdropClick` observable in the `DialogRef` is - // set up before any user can subscribe to the backdrop click. The subscription triggers - // the dialog close and this method synchronously. If we'd synchronously emit the `CLOSED` - // animation state event if animations are disabled, the overlay would be disposed - // immediately and all other subscriptions to `DialogRef#backdropClick` would be silently - // skipped. We work around this by waiting with the dialog close until the next tick when - // all subscriptions have been fired as expected. This is not an ideal solution, but - // there doesn't seem to be any other good way. Alternatives that have been considered: - // 1. Deferring `DialogRef.close`. This could be a breaking change due to a new microtask. - // Also this issue is specific to the MDC implementation where the dialog could - // technically be closed synchronously. In the non-MDC one, Angular animations are used - // and closing always takes at least a tick. - // 2. Ensuring that user subscriptions to `backdropClick`, `keydownEvents` in the dialog - // ref are first. This would solve the issue, but has the risk of memory leaks and also - // doesn't solve the case where consumers call `DialogRef.close` in their subscriptions. - // Based on the fact that this is specific to the MDC-based implementation of the dialog - // animations, the defer is applied here. - Promise.resolve().then(() => this._finishDialogClose()); - } - } - - /** - * Completes the dialog open by clearing potential animation classes, trapping - * focus and emitting an opened event. - */ - private _finishDialogOpen = () => { - this._clearAnimationClasses(); - this._openAnimationDone(this._openAnimationDuration); - }; - - /** - * Completes the dialog close by clearing potential animation classes, restoring - * focus and emitting a closed event. - */ - private _finishDialogClose = () => { - this._clearAnimationClasses(); - this._animationStateChanged.emit({state: 'closed', totalTime: this._closeAnimationDuration}); - }; - - /** Clears all dialog animation classes. */ - private _clearAnimationClasses() { - this._hostElement.classList.remove(cssClasses.OPENING); - this._hostElement.classList.remove(cssClasses.CLOSING); - } - - private _waitForAnimationToComplete(duration: number, callback: () => void) { - if (this._animationTimer !== null) { - clearTimeout(this._animationTimer); - } - - // Note that we want this timer to run inside the NgZone, because we want - // the related events like `afterClosed` to be inside the zone as well. - this._animationTimer = setTimeout(callback, duration); - } -} diff --git a/src/material-experimental/mdc-dialog/dialog.scss b/src/material-experimental/mdc-dialog/dialog.scss deleted file mode 100644 index 24acb1663f78..000000000000 --- a/src/material-experimental/mdc-dialog/dialog.scss +++ /dev/null @@ -1,96 +0,0 @@ -@use '@angular/material' as mat; -@use '@material/dialog' as mdc-dialog; -@use '@material/dialog/dialog-theme' as mdc-dialog-theme; -@use './mdc-dialog-structure-overrides'; - -// Theme map with values for variables that will be overriden in the theme. -// MDC's theming system requires non-null values for the slots to be inserted -// and included as default values. -$_dialog-initial-theme: ( - // Color - container-color: white, - container-elevation: 24, - container-shadow-color: black, - with-divider-divider-color: black, - subhead-color: black, - supporting-text-color: black, - - // Typography - subhead-font: 'Arial', - subhead-line-height: 14px, - subhead-size: 14px, - subhead-weight: 500, - subhead-tracking: 1px, - supporting-text-font: 'Arial', - supporting-text-line-height: 14px, - supporting-text-size: 14px, - supporting-text-weight: 500, - supporting-text-tracking: 1px, -); - -// Dialog content max height. This has been copied from the standard dialog -// and is needed to make the dialog content scrollable. -$mat-dialog-content-max-height: 65vh !default; -// Dialog button horizontal margin. This has been extracted from MDC as they -// don't expose this value as variable. -$mat-dialog-button-horizontal-margin: 8px !default; - -@include mat.private-disable-mdc-fallback-declarations { - @include mdc-dialog.core-styles($query: mat.$private-mdc-base-styles-query); -} - -@include mdc-dialog-structure-overrides.private-dialog-structure-overrides( - $mat-dialog-content-max-height); - -.mat-mdc-dialog-container { - // Apply the theming slots to the container using an initial set of - // values that will be overridden in the theme styles. - @include mat.private-disable-mdc-fallback-declarations { - @include mdc-dialog-theme.theme-styles($_dialog-initial-theme); - } - - // The dialog container is focusable. We remove the default outline shown in browsers. - outline: 0; - - // Angular Material supports disabling all animations when NoopAnimationsModule is imported. - // TODO(devversion): Look into using MDC's Sass queries to separate the animation styles and - // conditionally add them. Consider the size cost and churn when deciding whether to switch. - &._mat-animation-noopable .mdc-dialog__container { - transition: none; - } -} - -// MDC sets the display behavior for title and actions, but not for content. Since we support -// using the `mdc-dialog__content` as custom element, we need to set the element to `block`. -.mat-mdc-dialog-content { - display: block; -} - -.mat-mdc-dialog-actions { - // For backwards compatibility, actions align at start by default. MDC usually - // aligns actions at the end of the container. - justify-content: start; - - // .mat-mdc-dialog-actions-align-{center|end} are set by directive input "align" - // [align='center'] and [align='right'] are kept for backwards compability - &.mat-mdc-dialog-actions-align-center, &[align='center'] { - justify-content: center; - } - &.mat-mdc-dialog-actions-align-end, &[align='end'] { - justify-content: flex-end; - } - - // MDC applies horizontal margin to buttons that have an explicit `mdc-dialog__button` - // class applied. We can't set this class for projected buttons that consumers of the - // dialog create. To workaround this, we select all Material Design buttons we know and - // add the necessary spacing similar to how MDC applies spacing. - .mat-button-base + .mat-button-base, - .mat-mdc-button-base + .mat-mdc-button-base { - margin-left: $mat-dialog-button-horizontal-margin; - - [dir='rtl'] & { - margin-left: 0; - margin-right: $mat-dialog-button-horizontal-margin; - } - } -} diff --git a/src/material-experimental/mdc-dialog/public-api.ts b/src/material-experimental/mdc-dialog/public-api.ts deleted file mode 100644 index 1f53cadb7a15..000000000000 --- a/src/material-experimental/mdc-dialog/public-api.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -export * from './dialog'; -export * from './dialog-ref'; -export * from './dialog-content-directives'; -export * from './dialog-container'; -export * from './module'; - -export { - AutoFocusTarget, - MatDialogState, - MatDialogConfig, - matDialogAnimations, - DialogRole, - DialogPosition, - MAT_DIALOG_SCROLL_STRATEGY_FACTORY, -} from '@angular/material/dialog'; diff --git a/src/material-experimental/mdc-dialog/testing/dialog-harness.spec.ts b/src/material-experimental/mdc-dialog/testing/dialog-harness.spec.ts deleted file mode 100644 index dce20ab11658..000000000000 --- a/src/material-experimental/mdc-dialog/testing/dialog-harness.spec.ts +++ /dev/null @@ -1,7 +0,0 @@ -import {MatDialog, MatDialogModule} from '@angular/material-experimental/mdc-dialog'; -import {runHarnessTests} from '@angular/material/dialog/testing/shared.spec'; -import {MatDialogHarness} from './dialog-harness'; - -describe('MDC-based MatDialog', () => { - runHarnessTests(MatDialogModule, MatDialogHarness as any, MatDialog as any); -}); diff --git a/src/material-experimental/mdc-dialog/testing/dialog-harness.ts b/src/material-experimental/mdc-dialog/testing/dialog-harness.ts deleted file mode 100644 index b9a6213f95ff..000000000000 --- a/src/material-experimental/mdc-dialog/testing/dialog-harness.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {ComponentHarnessConstructor, HarnessPredicate} from '@angular/cdk/testing'; -import {DialogHarnessFilters, _MatDialogHarnessBase} from '@angular/material/dialog/testing'; - -/** Selectors for different sections of the mat-dialog that can contain user content. */ -export const enum MatDialogSection { - TITLE = '.mat-mdc-dialog-title', - CONTENT = '.mat-mdc-dialog-content', - ACTIONS = '.mat-mdc-dialog-actions', -} - -/** Harness for interacting with a standard `MatDialog` in tests. */ -export class MatDialogHarness extends _MatDialogHarnessBase { - /** The selector for the host element of a `MatDialog` instance. */ - static hostSelector = '.mat-mdc-dialog-container'; - - /** - * Gets a `HarnessPredicate` that can be used to search for a dialog with specific attributes. - * @param options Options for filtering which dialog instances are considered a match. - * @return a `HarnessPredicate` configured with the given options. - */ - static with( - this: ComponentHarnessConstructor, - options: DialogHarnessFilters = {}, - ): HarnessPredicate { - return new HarnessPredicate(this, options); - } - - protected override _title = this.locatorForOptional(MatDialogSection.TITLE); - protected override _content = this.locatorForOptional(MatDialogSection.CONTENT); - protected override _actions = this.locatorForOptional(MatDialogSection.ACTIONS); -} diff --git a/src/material/_index.scss b/src/material/_index.scss index 0513c54c7bf4..1cc1f66557e3 100644 --- a/src/material/_index.scss +++ b/src/material/_index.scss @@ -94,7 +94,10 @@ @forward './chips/chips-theme' as chips-* show chips-theme, chips-color, chips-typography; @forward './datepicker/datepicker-theme' as datepicker-* show datepicker-theme, datepicker-color, datepicker-typography, datepicker-date-range-colors; +@forward './legacy-dialog/dialog-theme' as legacy-dialog-* show legacy-dialog-theme, + legacy-dialog-color, legacy-dialog-typography; @forward './dialog/dialog-theme' as dialog-* show dialog-theme, dialog-color, dialog-typography; +@forward './dialog/dialog-legacy-padding' as dialog-* show dialog-legacy-padding; @forward './divider/divider-theme' as divider-* show divider-theme, divider-color, divider-typography; @forward './expansion/expansion-theme' as expansion-* show expansion-theme, expansion-color, diff --git a/src/material/_theming.scss b/src/material/_theming.scss index 2e5d766d6983..90f6ce94d6fa 100644 --- a/src/material/_theming.scss +++ b/src/material/_theming.scss @@ -16,7 +16,7 @@ @forward './legacy-checkbox/checkbox-legacy-index'; @forward './chips/chips-legacy-index'; @forward './datepicker/datepicker-legacy-index'; -@forward './dialog/dialog-legacy-index'; +@forward './legacy-dialog/dialog-legacy-index'; @forward './divider/divider-legacy-index'; @forward './expansion/expansion-legacy-index'; @forward './legacy-form-field/form-field-legacy-index'; diff --git a/src/material/config.bzl b/src/material/config.bzl index 3074c3beacbb..c75fd52f2a08 100644 --- a/src/material/config.bzl +++ b/src/material/config.bzl @@ -27,6 +27,8 @@ entryPoints = [ "legacy-core/testing", "datepicker", "datepicker/testing", + "legacy-dialog", + "legacy-dialog/testing", "dialog", "dialog/testing", "divider", diff --git a/src/material/core/density/private/_all-density.scss b/src/material/core/density/private/_all-density.scss index 6a85cd81d2a8..9c393e507a3a 100644 --- a/src/material/core/density/private/_all-density.scss +++ b/src/material/core/density/private/_all-density.scss @@ -15,6 +15,7 @@ @use '../../../core/option/option-theme'; @use '../../../core/option/optgroup-theme'; @use '../../../select/select-theme'; +@use '../../../dialog/dialog-theme'; @mixin private-all-unmigrated-component-densities($config) { @include expansion-theme.density($config); @@ -23,9 +24,6 @@ @include tree-theme.density($config); @include paginator-theme.density($config); @include button-toggle-theme.density($config); - @include card-theme.density($config); - @include progress-bar-theme.density($config); - @include tooltip-theme.density($config); } // Includes all of the density styles. @@ -45,12 +43,16 @@ // mixin that is transitively loaded by the `all-theme` file, imports `all-density` which // would then load `all-theme` again. This ultimately results a circular dependency. @include form-field-theme.density($config); + @include card-theme.density($config); + @include progress-bar-theme.density($config); + @include tooltip-theme.density($config); @include input-theme.density($config); @include option-theme.density($config); @include optgroup-theme.density($config); @include select-theme.density($config); @include checkbox-theme.density($config); @include autocomplete-theme.density($config); + @include dialog-theme.density($config); @include private-all-unmigrated-component-densities($config); } diff --git a/src/material/core/theming/_all-theme.scss b/src/material/core/theming/_all-theme.scss index 22218c904f94..712a05392320 100644 --- a/src/material/core/theming/_all-theme.scss +++ b/src/material/core/theming/_all-theme.scss @@ -45,7 +45,6 @@ @include chips-theme.theme($theme-or-color-config); @include table-theme.theme($theme-or-color-config); @include datepicker-theme.theme($theme-or-color-config); - @include dialog-theme.theme($theme-or-color-config); @include divider-theme.theme($theme-or-color-config); @include expansion-theme.theme($theme-or-color-config); @include grid-list-theme.theme($theme-or-color-config); @@ -78,6 +77,7 @@ @include input-theme.theme($theme-or-color-config); @include select-theme.theme($theme-or-color-config); @include autocomplete-theme.theme($theme-or-color-config); + @include dialog-theme.theme($theme-or-color-config); @include private-all-unmigrated-component-themes($theme-or-color-config); } } diff --git a/src/material/core/theming/tests/test-css-variables-theme.scss b/src/material/core/theming/tests/test-css-variables-theme.scss index 572f0916a6ce..75edc94c7156 100644 --- a/src/material/core/theming/tests/test-css-variables-theme.scss +++ b/src/material/core/theming/tests/test-css-variables-theme.scss @@ -10,7 +10,6 @@ @use '../../../chips/chips-theme'; @use '../../../table/table-theme'; @use '../../../datepicker/datepicker-theme'; -@use '../../../dialog/dialog-theme'; @use '../../../divider/divider-theme'; @use '../../../expansion/expansion-theme'; @use '../../../grid-list/grid-list-theme'; @@ -65,7 +64,6 @@ @include chips-theme.theme($css-var-theme); @include table-theme.theme($css-var-theme); @include datepicker-theme.theme($css-var-theme); - @include dialog-theme.theme($css-var-theme); @include divider-theme.theme($css-var-theme); @include expansion-theme.theme($css-var-theme); @include grid-list-theme.theme($css-var-theme); diff --git a/src/material/core/typography/_all-typography.scss b/src/material/core/typography/_all-typography.scss index fcaf880b523e..f54457523338 100644 --- a/src/material/core/typography/_all-typography.scss +++ b/src/material/core/typography/_all-typography.scss @@ -48,7 +48,6 @@ @include divider-theme.typography($config); @include table-theme.typography($config); @include datepicker-theme.typography($config); - @include dialog-theme.typography($config); @include expansion-theme.typography($config); @include grid-list-theme.typography($config); @include icon-theme.typography($config); @@ -94,6 +93,7 @@ @include input-theme.typography($config); @include select-theme.typography($config); @include autocomplete-theme.typography($config); + @include dialog-theme.typography($config); } // @deprecated Use `all-component-typographies`. diff --git a/src/material/dialog/BUILD.bazel b/src/material/dialog/BUILD.bazel index 6d56e3a4bdf1..b6fc07c68ede 100644 --- a/src/material/dialog/BUILD.bazel +++ b/src/material/dialog/BUILD.bazel @@ -18,40 +18,41 @@ ng_module( ["**/*.ts"], exclude = ["**/*.spec.ts"], ), - assets = [":dialog.css"] + glob(["**/*.html"]), + assets = [":dialog_scss"] + glob(["**/*.html"]), deps = [ - "//src:dev_mode_types", - "//src/cdk/a11y", - "//src/cdk/bidi", "//src/cdk/dialog", - "//src/cdk/keycodes", "//src/cdk/overlay", - "//src/cdk/platform", "//src/cdk/portal", "//src/material/core", - "@npm//@angular/animations", - "@npm//@angular/core", - "@npm//rxjs", + "@npm//@material/dialog", ], ) sass_library( name = "dialog_scss_lib", srcs = glob(["**/_*.scss"]), - deps = ["//src/material/core:core_scss_lib"], + deps = [ + "//:mdc_sass_lib", + "//src/material/core:core_scss_lib", + ], ) sass_binary( name = "dialog_scss", src = "dialog.scss", deps = [ - "//src/cdk:sass_lib", + ":dialog_scss_lib", + "//:mdc_sass_lib", "//src/material/core:core_scss_lib", ], ) +########### +# Testing +########### + ng_test_library( - name = "unit_test_sources", + name = "dialog_tests_lib", srcs = glob( ["**/*.spec.ts"], exclude = ["**/*.e2e.spec.ts"], @@ -60,6 +61,7 @@ ng_test_library( ":dialog", "//src/cdk/a11y", "//src/cdk/bidi", + "//src/cdk/dialog", "//src/cdk/keycodes", "//src/cdk/overlay", "//src/cdk/platform", @@ -67,13 +69,16 @@ ng_test_library( "//src/cdk/testing/private", "@npm//@angular/common", "@npm//@angular/platform-browser", + "@npm//@material/dialog", "@npm//rxjs", ], ) ng_web_test_suite( name = "unit_tests", - deps = [":unit_test_sources"], + deps = [ + ":dialog_tests_lib", + ], ) ng_e2e_test_library( diff --git a/src/material/dialog/README.md b/src/material/dialog/README.md index b4753f6be5b7..8e1f9e05f6b6 100644 --- a/src/material/dialog/README.md +++ b/src/material/dialog/README.md @@ -1 +1,74 @@ -Please see the official documentation at https://material.angular.io/components/component/dialog +This is a prototype of an alternate version of `MatDialog` built on top of +[MDC Web](https://github.com/material-components/material-components-web). This component is +experimental and should not be used in production. + +## How to use + +Assuming your application is already up and running using Angular Material, you can add this +component by following these steps: + +1. Install `@angular/material` and MDC Web: + + ```bash + npm i material-components-web @angular/material + ``` + +2. In your `angular.json`, make sure `node_modules/` is listed as a Sass include path. This is + needed for the Sass compiler to be able to find the MDC Web Sass files. + + ```json + ... + "styles": [ + "src/styles.scss" + ], + "stylePreprocessorOptions": { + "includePaths": [ + "node_modules/" + ] + }, + ... + ``` + +3. Import the experimental `MatDialogModule` and add it to the module that declares your + component: + + ```ts + import {MatDialogModule} from '@angular/material/dialog'; + + @NgModule({ + declarations: [MyComponent], + imports: [MatDialogModule], + }) + export class MyModule {} + ``` + +4. Use the `MatDialog` service in your components by injecting the service, just like you would + use the normal dialog. + +5. Ensure color and typography styles for `@angular/material` are set up. Either + use a custom theme and use the `mat-dialog-theme` mixin, or use a prebuilt theme + from `@angular/material/mdc-core/theming/prebuilt`. + +## API differences + +The runtime API for the `MatDialog` service is fully compatible and no changes are needed. Visually +the dialog has changed a little bit with the MDC-based implementation. In concrete, the dialog no +longer has outer padding by default. + +If content elements such as `matDialogContent` or `matDialogTitle` are used though, the MDC dialog +will display as with the current non-experimental dialog. The padding change will only surface if +you have custom content within the dialog that is not wrapped with `matDialogContent`, +`matDialogActions` or `matDialogTitle`. + +We provide a backwards compatibility mixin that re-adds the outer padding. The use of this mixin +is generally not recommended as it results in inefficient CSS for the dialog because padding from +the content elements would need to be off set (to not have stacked padding). Ideally, if you have +custom content outside of the provided dialog sections, add the necessary padding to the element +directly through CSS, or move them into one of the defined sections the Angular Material dialog +provides. + +```scss +@use '@angular/material' as mat; + +@include mat.dialog-legacy-padding(); +``` diff --git a/src/material/dialog/_dialog-legacy-index.scss b/src/material/dialog/_dialog-legacy-index.scss deleted file mode 100644 index 0924173ad0b8..000000000000 --- a/src/material/dialog/_dialog-legacy-index.scss +++ /dev/null @@ -1,2 +0,0 @@ -@forward 'dialog-theme' hide color, theme, typography; -@forward 'dialog-theme' as mat-dialog-* hide mat-dialog-density; diff --git a/src/material-experimental/mdc-dialog/_dialog-legacy-padding.import.scss b/src/material/dialog/_dialog-legacy-padding.import.scss similarity index 100% rename from src/material-experimental/mdc-dialog/_dialog-legacy-padding.import.scss rename to src/material/dialog/_dialog-legacy-padding.import.scss diff --git a/src/material-experimental/mdc-dialog/_dialog-legacy-padding.scss b/src/material/dialog/_dialog-legacy-padding.scss similarity index 100% rename from src/material-experimental/mdc-dialog/_dialog-legacy-padding.scss rename to src/material/dialog/_dialog-legacy-padding.scss diff --git a/src/material/dialog/_dialog-theme.import.scss b/src/material/dialog/_dialog-theme.import.scss index 2b3782bcbcc2..c8a1b77413ee 100644 --- a/src/material/dialog/_dialog-theme.import.scss +++ b/src/material/dialog/_dialog-theme.import.scss @@ -1,10 +1 @@ -@forward '../core/style/private.import'; -@forward '../core/theming/theming.import'; -@forward '../core/typography/typography-utils.import'; -@forward 'dialog-theme' hide color, theme, typography; -@forward 'dialog-theme' as mat-dialog-* hide mat-dialog-density; - -@import '../core/style/private'; -@import '../core/theming/palette'; -@import '../core/theming/theming'; -@import '../core/typography/typography-utils'; +@forward 'dialog-theme' as mat-mdc-dialog-*; diff --git a/src/material/dialog/_dialog-theme.scss b/src/material/dialog/_dialog-theme.scss index 720def5357f4..725c335f7d40 100644 --- a/src/material/dialog/_dialog-theme.scss +++ b/src/material/dialog/_dialog-theme.scss @@ -1,31 +1,62 @@ @use 'sass:map'; -@use '../core/style/private'; +@use '@material/dialog' as mdc-dialog; +@use '@material/dialog/dialog-theme' as mdc-dialog-theme; +@use '@material/theme/theme-color' as mdc-theme-color; +@use '@material/typography' as mdc-typography; @use '../core/theming/theming'; +@use '../core/mdc-helpers/mdc-helpers'; @use '../core/typography/typography'; -@use '../core/typography/typography-utils'; - @mixin color($config-or-theme) { $config: theming.get-color-config($config-or-theme); - $background: map.get($config, background); - $foreground: map.get($config, foreground); - .mat-dialog-container { - @include private.private-theme-elevation(24, $config); - background: theming.get-color-from-palette($background, dialog); - color: theming.get-color-from-palette($foreground, text); + @include mdc-helpers.using-mdc-theme($config) { + .mat-mdc-dialog-container { + $surface: mdc-theme-color.$surface; + $on-surface: mdc-theme-color.$on-surface; + $text-emphasis-high: mdc-theme-color.text-emphasis(high); + $text-emphasis-medium: mdc-theme-color.text-emphasis(medium); + + @include mdc-dialog-theme.theme(( + container-color: $surface, + container-elevation: 24, + container-shadow-color: $on-surface, + with-divider-divider-color: rgba($on-surface, mdc-dialog.$scroll-divider-opacity), + subhead-color: rgba($on-surface, $text-emphasis-high), + supporting-text-color: rgba($on-surface, $text-emphasis-medium), + )); + } } } @mixin typography($config-or-theme) { - $config: typography.private-typography-to-2014-config( + $config: typography.private-typography-to-2018-config( theming.get-typography-config($config-or-theme)); - .mat-dialog-title { - @include typography-utils.typography-level($config, title); + @include mdc-helpers.using-mdc-typography($config) { + .mat-mdc-dialog-container { + $styles: mdc-typography.$styles; + $headline6: map.get($styles, headline6); + + @include mdc-dialog-theme.theme(( + subhead-font: map.get($headline6, font-family), + subhead-line-height: map.get($styles, headline6, line-height), + subhead-size: map.get($styles, headline6, font-size), + subhead-weight: map.get($styles, headline6, font-weight), + subhead-tracking: map.get($styles, headline6, letter-spacing), + + supporting-text-font: map.get($styles, body1, font-family), + supporting-text-line-height: map.get($styles, body1, line-height), + supporting-text-size: map.get($styles, body1, font-size), + supporting-text-weight: map.get($styles, body1, font-weight), + supporting-text-tracking: map.get($styles, body1, letter-spacing), + )); + } } } -@mixin _density($config-or-theme) {} +@mixin density($config-or-theme) { + $density-scale: theming.get-density-config($config-or-theme); +} @mixin theme($theme-or-color-config) { $theme: theming.private-legacy-get-theme($theme-or-color-config); @@ -38,7 +69,7 @@ @include color($color); } @if $density != null { - @include _density($density); + @include density($density); } @if $typography != null { @include typography($typography); diff --git a/src/material-experimental/mdc-dialog/_mdc-dialog-structure-overrides.import.scss b/src/material/dialog/_mdc-dialog-structure-overrides.import.scss similarity index 100% rename from src/material-experimental/mdc-dialog/_mdc-dialog-structure-overrides.import.scss rename to src/material/dialog/_mdc-dialog-structure-overrides.import.scss diff --git a/src/material-experimental/mdc-dialog/_mdc-dialog-structure-overrides.scss b/src/material/dialog/_mdc-dialog-structure-overrides.scss similarity index 100% rename from src/material-experimental/mdc-dialog/_mdc-dialog-structure-overrides.scss rename to src/material/dialog/_mdc-dialog-structure-overrides.scss diff --git a/src/material/dialog/dialog-container.html b/src/material/dialog/dialog-container.html index 215f0d9c55b3..bcb86f4c42d1 100644 --- a/src/material/dialog/dialog-container.html +++ b/src/material/dialog/dialog-container.html @@ -1 +1,5 @@ - +
+
+ +
+
diff --git a/src/material/dialog/dialog-container.ts b/src/material/dialog/dialog-container.ts index 3eb3565dbea1..9ac5179a5832 100644 --- a/src/material/dialog/dialog-container.ts +++ b/src/material/dialog/dialog-container.ts @@ -6,28 +6,27 @@ * found in the LICENSE file at https://angular.io/license */ -import {AnimationEvent} from '@angular/animations'; -import {CdkDialogContainer} from '@angular/cdk/dialog'; import {FocusMonitor, FocusTrapFactory, InteractivityChecker} from '@angular/cdk/a11y'; import {OverlayRef} from '@angular/cdk/overlay'; -import {_getFocusedElementPierceShadowDom} from '@angular/cdk/platform'; import {DOCUMENT} from '@angular/common'; import { ChangeDetectionStrategy, - ChangeDetectorRef, Component, ElementRef, EventEmitter, Inject, NgZone, + OnDestroy, Optional, ViewEncapsulation, } from '@angular/core'; -import {matDialogAnimations, defaultParams} from './dialog-animations'; import {MatDialogConfig} from './dialog-config'; +import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; +import {cssClasses, numbers} from '@material/dialog'; +import {CdkDialogContainer} from '@angular/cdk/dialog'; /** Event that captures the state of dialog container animations. */ -interface DialogAnimationEvent { +interface LegacyDialogAnimationEvent { state: 'opened' | 'opening' | 'closing' | 'closed'; totalTime: number; } @@ -40,7 +39,7 @@ interface DialogAnimationEvent { @Component({template: ''}) export abstract class _MatDialogContainerBase extends CdkDialogContainer { /** Emits when an animation state changes. */ - _animationStateChanged = new EventEmitter(); + _animationStateChanged = new EventEmitter(); constructor( elementRef: ElementRef, @@ -87,8 +86,7 @@ export abstract class _MatDialogContainerBase extends CdkDialogContainer this._finishDialogOpen()); + } + } + + /** + * Starts the exit animation of the dialog if enabled. This method is + * called by the dialog ref. + */ + _startExitAnimation(): void { + this._animationStateChanged.emit({state: 'closing', totalTime: this._closeAnimationDuration}); + this._hostElement.classList.remove(cssClasses.OPEN); + + if (this._animationsEnabled) { + this._hostElement.classList.add(cssClasses.CLOSING); + this._waitForAnimationToComplete(this._closeAnimationDuration, this._finishDialogClose); + } else { + // This subscription to the `OverlayRef#backdropClick` observable in the `DialogRef` is + // set up before any user can subscribe to the backdrop click. The subscription triggers + // the dialog close and this method synchronously. If we'd synchronously emit the `CLOSED` + // animation state event if animations are disabled, the overlay would be disposed + // immediately and all other subscriptions to `DialogRef#backdropClick` would be silently + // skipped. We work around this by waiting with the dialog close until the next tick when + // all subscriptions have been fired as expected. This is not an ideal solution, but + // there doesn't seem to be any other good way. Alternatives that have been considered: + // 1. Deferring `DialogRef.close`. This could be a breaking change due to a new microtask. + // Also this issue is specific to the MDC implementation where the dialog could + // technically be closed synchronously. In the non-MDC one, Angular animations are used + // and closing always takes at least a tick. + // 2. Ensuring that user subscriptions to `backdropClick`, `keydownEvents` in the dialog + // ref are first. This would solve the issue, but has the risk of memory leaks and also + // doesn't solve the case where consumers call `DialogRef.close` in their subscriptions. + // Based on the fact that this is specific to the MDC-based implementation of the dialog + // animations, the defer is applied here. + Promise.resolve().then(() => this._finishDialogClose()); + } + } + + /** + * Completes the dialog open by clearing potential animation classes, trapping + * focus and emitting an opened event. + */ + private _finishDialogOpen = () => { + this._clearAnimationClasses(); + this._openAnimationDone(this._openAnimationDuration); + }; + + /** + * Completes the dialog close by clearing potential animation classes, restoring + * focus and emitting a closed event. + */ + private _finishDialogClose = () => { + this._clearAnimationClasses(); + this._animationStateChanged.emit({state: 'closed', totalTime: this._closeAnimationDuration}); + }; + + /** Clears all dialog animation classes. */ + private _clearAnimationClasses() { + this._hostElement.classList.remove(cssClasses.OPENING); + this._hostElement.classList.remove(cssClasses.CLOSING); + } + + private _waitForAnimationToComplete(duration: number, callback: () => void) { + if (this._animationTimer !== null) { + clearTimeout(this._animationTimer); + } + + // Note that we want this timer to run inside the NgZone, because we want + // the related events like `afterClosed` to be inside the zone as well. + this._animationTimer = setTimeout(callback, duration); } } diff --git a/src/material/dialog/dialog-content-directives.ts b/src/material/dialog/dialog-content-directives.ts index 3fbdf6ec9c0d..e3cffcbb230f 100644 --- a/src/material/dialog/dialog-content-directives.ts +++ b/src/material/dialog/dialog-content-directives.ts @@ -8,15 +8,16 @@ import { Directive, + ElementRef, Input, OnChanges, OnInit, Optional, SimpleChanges, - ElementRef, } from '@angular/core'; + import {MatDialog} from './dialog'; -import {MatDialogRef, _closeDialogVia} from './dialog-ref'; +import {_closeDialogVia, MatDialogRef} from './dialog-ref'; /** Counter used to generate unique IDs for dialog elements. */ let dialogElementUid = 0; @@ -34,7 +35,7 @@ let dialogElementUid = 0; }, }) export class MatDialogClose implements OnInit, OnChanges { - /** Screen reader label for the button. */ + /** Screen-reader label for the button. */ @Input('aria-label') ariaLabel: string; /** Default to "button" to prevents accidental form submits. */ @@ -46,11 +47,6 @@ export class MatDialogClose implements OnInit, OnChanges { @Input('matDialogClose') _matDialogClose: any; constructor( - /** - * Reference to the containing dialog. - * @deprecated `dialogRef` property to become private. - * @breaking-change 13.0.0 - */ // The dialog title directive is always used in combination with a `MatDialogRef`. // tslint:disable-next-line: lightweight-tokens @Optional() public dialogRef: MatDialogRef, @@ -97,13 +93,12 @@ export class MatDialogClose implements OnInit, OnChanges { selector: '[mat-dialog-title], [matDialogTitle]', exportAs: 'matDialogTitle', host: { - 'class': 'mat-dialog-title', + 'class': 'mat-mdc-dialog-title mdc-dialog__title', '[id]': 'id', }, }) export class MatDialogTitle implements OnInit { - /** Unique id for the dialog title. If none is supplied, it will be auto-generated. */ - @Input() id: string = `mat-dialog-title-${dialogElementUid++}`; + @Input() id: string = `mat-mdc-dialog-title-${dialogElementUid++}`; constructor( // The dialog title directive is always used in combination with a `MatDialogRef`. @@ -135,7 +130,7 @@ export class MatDialogTitle implements OnInit { */ @Directive({ selector: `[mat-dialog-content], mat-dialog-content, [matDialogContent]`, - host: {'class': 'mat-dialog-content'}, + host: {'class': 'mat-mdc-dialog-content mdc-dialog__content'}, }) export class MatDialogContent {} @@ -146,9 +141,9 @@ export class MatDialogContent {} @Directive({ selector: `[mat-dialog-actions], mat-dialog-actions, [matDialogActions]`, host: { - 'class': 'mat-dialog-actions', - '[class.mat-dialog-actions-align-center]': 'align === "center"', - '[class.mat-dialog-actions-align-end]': 'align === "end"', + 'class': 'mat-mdc-dialog-actions mdc-dialog__actions', + '[class.mat-mdc-dialog-actions-align-center]': 'align === "center"', + '[class.mat-mdc-dialog-actions-align-end]': 'align === "end"', }, }) export class MatDialogActions { @@ -158,10 +153,6 @@ export class MatDialogActions { @Input() align?: 'start' | 'center' | 'end' = 'start'; } -// TODO(crisbeto): this utility shouldn't be necessary anymore, because the dialog ref is provided -// both to component and template dialogs through DI. We need to keep it around, because there are -// some internal wrappers around `MatDialog` that happened to work by accident, because we had this -// fallback logic in place. /** * Finds the closest MatDialogRef to an element by looking at the DOM. * @param element Element relative to which to look for a dialog. @@ -170,7 +161,7 @@ export class MatDialogActions { function getClosestDialog(element: ElementRef, openDialogs: MatDialogRef[]) { let parent: HTMLElement | null = element.nativeElement.parentElement; - while (parent && !parent.classList.contains('mat-dialog-container')) { + while (parent && !parent.classList.contains('mat-mdc-dialog-container')) { parent = parent.parentElement; } diff --git a/src/material/dialog/dialog-ref.ts b/src/material/dialog/dialog-ref.ts index 63cbaccb8894..2a58767597a0 100644 --- a/src/material/dialog/dialog-ref.ts +++ b/src/material/dialog/dialog-ref.ts @@ -6,16 +6,16 @@ * found in the LICENSE file at https://angular.io/license */ -import {DialogRef} from '@angular/cdk/dialog'; +/** Possible states of the lifecycle of a dialog. */ import {FocusOrigin} from '@angular/cdk/a11y'; -import {ESCAPE, hasModifierKey} from '@angular/cdk/keycodes'; -import {GlobalPositionStrategy} from '@angular/cdk/overlay'; import {merge, Observable, Subject} from 'rxjs'; -import {filter, take} from 'rxjs/operators'; +import {DialogRef} from '@angular/cdk/dialog'; import {DialogPosition, MatDialogConfig} from './dialog-config'; import {_MatDialogContainerBase} from './dialog-container'; +import {filter, take} from 'rxjs/operators'; +import {ESCAPE, hasModifierKey} from '@angular/cdk/keycodes'; +import {GlobalPositionStrategy} from '@angular/cdk/overlay'; -/** Possible states of the lifecycle of a dialog. */ export const enum MatDialogState { OPEN, CLOSING, diff --git a/src/material/dialog/dialog.e2e.spec.ts b/src/material/dialog/dialog.e2e.spec.ts index 0522de27a7e2..3a45ec94fabd 100644 --- a/src/material/dialog/dialog.e2e.spec.ts +++ b/src/material/dialog/dialog.e2e.spec.ts @@ -1,14 +1,14 @@ -import {browser, by, element, Key} from 'protractor'; import { - expectToExist, + clickElementAtPoint, expectFocusOn, + expectToExist, pressKeys, - clickElementAtPoint, waitForElement, } from '../../cdk/testing/private/e2e'; +import {browser, by, element, Key} from 'protractor'; -describe('dialog', () => { - beforeEach(async () => await browser.get('/dialog')); +describe('MDC-based dialog', () => { + beforeEach(async () => await browser.get('/mdc-dialog')); it('should open a dialog', async () => { await element(by.id('default')).click(); diff --git a/src/material/dialog/dialog.md b/src/material/dialog/dialog.md index c05b3c89cab2..8825ab5a7647 100644 --- a/src/material/dialog/dialog.md +++ b/src/material/dialog/dialog.md @@ -65,7 +65,7 @@ To access the data in your dialog component, you have to use the MAT_DIALOG_DATA ```ts import {Component, Inject} from '@angular/core'; -import {MAT_DIALOG_DATA} from '@angular/material/dialog'; +import {MAT_DIALOG_DATA} from '@angular/material/legacy-dialog'; @Component({ selector: 'your-dialog', diff --git a/src/material/dialog/dialog.scss b/src/material/dialog/dialog.scss index ce35574db15e..327fe75ca27b 100644 --- a/src/material/dialog/dialog.scss +++ b/src/material/dialog/dialog.scss @@ -1,76 +1,96 @@ -@use '@angular/cdk'; +@use '@material/dialog' as mdc-dialog; +@use '@material/dialog/dialog-theme' as mdc-dialog-theme; +@use './mdc-dialog-structure-overrides'; +@use '../core/mdc-helpers/mdc-helpers'; -$padding: 24px !default; -$border-radius: 4px !default; -$max-height: 65vh !default; -$button-margin: 8px !default; +// Theme map with values for variables that will be overriden in the theme. +// MDC's theming system requires non-null values for the slots to be inserted +// and included as default values. +$_dialog-initial-theme: ( + // Color + container-color: white, + container-elevation: 24, + container-shadow-color: black, + with-divider-divider-color: black, + subhead-color: black, + supporting-text-color: black, -.mat-dialog-container { - display: block; - padding: $padding; - border-radius: $border-radius; - box-sizing: border-box; - overflow: auto; - outline: 0; + // Typography + subhead-font: 'Arial', + subhead-line-height: 14px, + subhead-size: 14px, + subhead-weight: 500, + subhead-tracking: 1px, + supporting-text-font: 'Arial', + supporting-text-line-height: 14px, + supporting-text-size: 14px, + supporting-text-weight: 500, + supporting-text-tracking: 1px, +); + +// Dialog content max height. This has been copied from the standard dialog +// and is needed to make the dialog content scrollable. +$mat-dialog-content-max-height: 65vh !default; +// Dialog button horizontal margin. This has been extracted from MDC as they +// don't expose this value as variable. +$mat-dialog-button-horizontal-margin: 8px !default; - // The dialog container should completely fill its parent overlay element. - width: 100%; - height: 100%; +@include mdc-helpers.disable-mdc-fallback-declarations { + @include mdc-dialog.core-styles($query: mdc-helpers.$mdc-base-styles-query); +} - // Since the dialog won't stretch to fit the parent, if the height - // isn't set, we have to inherit the min and max values explicitly. - min-height: inherit; - max-height: inherit; +@include mdc-dialog-structure-overrides.private-dialog-structure-overrides( + $mat-dialog-content-max-height); - @include cdk.high-contrast(active, off) { - outline: solid 1px; +.mat-mdc-dialog-container { + // Apply the theming slots to the container using an initial set of + // values that will be overridden in the theme styles. + @include mdc-helpers.disable-mdc-fallback-declarations { + @include mdc-dialog-theme.theme-styles($_dialog-initial-theme); } -} -.mat-dialog-content { - display: block; - margin: 0 $padding * -1; - padding: 0 $padding; - max-height: $max-height; - overflow: auto; - -webkit-overflow-scrolling: touch; + // The dialog container is focusable. We remove the default outline shown in browsers. + outline: 0; + + // Angular Material supports disabling all animations when NoopAnimationsModule is imported. + // TODO(devversion): Look into using MDC's Sass queries to separate the animation styles and + // conditionally add them. Consider the size cost and churn when deciding whether to switch. + &._mat-animation-noopable .mdc-dialog__container { + transition: none; + } } -.mat-dialog-title { - margin: 0 0 20px; +// MDC sets the display behavior for title and actions, but not for content. Since we support +// using the `mdc-dialog__content` as custom element, we need to set the element to `block`. +.mat-mdc-dialog-content { display: block; } -.mat-dialog-actions { - padding: 8px 0; - display: flex; - flex-wrap: wrap; - min-height: 52px; - align-items: center; - - // Explicitly set a box-sizing since people commonly set `border-box` - // on all elements which will break the height of the dialog actions. - box-sizing: content-box; - - // Pull the actions down to avoid their padding stacking with the dialog's padding. - margin-bottom: -$padding; +.mat-mdc-dialog-actions { + // For backwards compatibility, actions align at start by default. MDC usually + // aligns actions at the end of the container. + justify-content: start; - // .mat-dialog-actions-align-{center|end} are set by directive input "align" + // .mat-mdc-dialog-actions-align-{center|end} are set by directive input "align" // [align='center'] and [align='right'] are kept for backwards compability - &.mat-dialog-actions-align-center, &[align='center'] { + &.mat-mdc-dialog-actions-align-center, &[align='center'] { justify-content: center; } - &.mat-dialog-actions-align-end, &[align='end'] { + &.mat-mdc-dialog-actions-align-end, &[align='end'] { justify-content: flex-end; } + // MDC applies horizontal margin to buttons that have an explicit `mdc-dialog__button` + // class applied. We can't set this class for projected buttons that consumers of the + // dialog create. To workaround this, we select all Material Design buttons we know and + // add the necessary spacing similar to how MDC applies spacing. .mat-button-base + .mat-button-base, .mat-mdc-button-base + .mat-mdc-button-base { - margin-left: $button-margin; + margin-left: $mat-dialog-button-horizontal-margin; [dir='rtl'] & { margin-left: 0; - margin-right: $button-margin; + margin-right: $mat-dialog-button-horizontal-margin; } } } diff --git a/src/material/dialog/dialog.spec.ts b/src/material/dialog/dialog.spec.ts index 428dd3b6f3af..5952877486e4 100644 --- a/src/material/dialog/dialog.spec.ts +++ b/src/material/dialog/dialog.spec.ts @@ -1,57 +1,57 @@ import {FocusMonitor, FocusOrigin} from '@angular/cdk/a11y'; +import {Directionality} from '@angular/cdk/bidi'; +import {A, ESCAPE} from '@angular/cdk/keycodes'; +import {Overlay, OverlayContainer, ScrollStrategy} from '@angular/cdk/overlay'; +import {_supportsShadowDom} from '@angular/cdk/platform'; +import {ScrollDispatcher} from '@angular/cdk/scrolling'; import { - ComponentFixture, - fakeAsync, - flushMicrotasks, - inject, - TestBed, - tick, - flush, -} from '@angular/core/testing'; + createKeyboardEvent, + dispatchEvent, + dispatchKeyboardEvent, + dispatchMouseEvent, + patchElementFocus, +} from '../../cdk/testing/private'; +import {Location} from '@angular/common'; +import {SpyLocation} from '@angular/common/testing'; import { ChangeDetectionStrategy, Component, + ComponentFactoryResolver, + createNgModuleRef, Directive, Inject, + Injectable, Injector, + NgModule, + NgZone, TemplateRef, ViewChild, ViewContainerRef, - ComponentFactoryResolver, - NgZone, ViewEncapsulation, - Injectable, - NgModule, - createNgModuleRef, } from '@angular/core'; +import { + ComponentFixture, + fakeAsync, + flush, + flushMicrotasks, + inject, + TestBed, + tick, +} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations'; -import {Location} from '@angular/common'; -import {SpyLocation} from '@angular/common/testing'; -import {Directionality} from '@angular/cdk/bidi'; -import {_supportsShadowDom} from '@angular/cdk/platform'; -import {MatDialogContainer} from './dialog-container'; -import {OverlayContainer, ScrollStrategy, Overlay} from '@angular/cdk/overlay'; -import {ScrollDispatcher} from '@angular/cdk/scrolling'; -import {A, ESCAPE} from '@angular/cdk/keycodes'; -import { - dispatchKeyboardEvent, - createKeyboardEvent, - dispatchEvent, - patchElementFocus, - dispatchMouseEvent, -} from '../../cdk/testing/private'; +import {numbers} from '@material/dialog'; +import {Subject} from 'rxjs'; import { - MAT_DIALOG_DATA, MatDialog, + MatDialogState, MatDialogModule, MatDialogRef, + MAT_DIALOG_DATA, MAT_DIALOG_DEFAULT_OPTIONS, - MatDialogState, } from './index'; -import {Subject} from 'rxjs'; -describe('MatDialog', () => { +describe('MDC-based MatDialog', () => { let dialog: MatDialog; let overlayContainerElement: HTMLElement; let scrolledSubject = new Subject(); @@ -78,9 +78,7 @@ describe('MatDialog', () => { {provide: Location, useClass: SpyLocation}, { provide: ScrollDispatcher, - useFactory: () => ({ - scrolled: () => scrolledSubject, - }), + useFactory: () => ({scrolled: () => scrolledSubject}), }, ], }); @@ -106,9 +104,7 @@ describe('MatDialog', () => { }); it('should open a dialog with a component', () => { - const dialogRef = dialog.open(PizzaMsg, { - viewContainerRef: testViewContainerRef, - }); + let dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); viewContainerFixture.detectChanges(); @@ -117,7 +113,7 @@ describe('MatDialog', () => { expect(dialogRef.componentInstance.dialogRef).toBe(dialogRef); viewContainerFixture.detectChanges(); - const dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; + let dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; expect(dialogContainerElement.getAttribute('role')).toBe('dialog'); }); @@ -128,7 +124,7 @@ describe('MatDialog', () => { const data = {value: 'Knees'}; - const dialogRef = dialog.open(templateRefFixture.componentInstance.templateRef, {data}); + let dialogRef = dialog.open(templateRefFixture.componentInstance.templateRef, {data}); viewContainerFixture.detectChanges(); @@ -137,7 +133,7 @@ describe('MatDialog', () => { viewContainerFixture.detectChanges(); - const dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; + let dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; expect(dialogContainerElement.getAttribute('role')).toBe('dialog'); dialogRef.close(); @@ -159,22 +155,23 @@ describe('MatDialog', () => { })); it('should use injector from viewContainerRef for DialogInjector', () => { - const dialogRef = dialog.open(PizzaMsg, { - viewContainerRef: testViewContainerRef, - }); + let dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); viewContainerFixture.detectChanges(); - const dialogInjector = dialogRef.componentInstance.dialogInjector; + let dialogInjector = dialogRef.componentInstance.dialogInjector; expect(dialogRef.componentInstance.dialogRef).toBe(dialogRef); - expect(dialogInjector.get(DirectiveWithViewContainer)).toBeTruthy( - 'Expected the dialog component to be created with the injector from the viewContainerRef.', - ); + expect(dialogInjector.get(DirectiveWithViewContainer)) + .withContext( + 'Expected the dialog component to be created with the injector from ' + + 'the viewContainerRef.', + ) + .toBeTruthy(); }); it('should open a dialog with a component and no ViewContainerRef', () => { - const dialogRef = dialog.open(PizzaMsg); + let dialogRef = dialog.open(PizzaMsg); viewContainerFixture.detectChanges(); @@ -183,7 +180,7 @@ describe('MatDialog', () => { expect(dialogRef.componentInstance.dialogRef).toBe(dialogRef); viewContainerFixture.detectChanges(); - const dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; + let dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; expect(dialogContainerElement.getAttribute('role')).toBe('dialog'); }); @@ -192,7 +189,7 @@ describe('MatDialog', () => { viewContainerFixture.detectChanges(); - const dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; + let dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; expect(dialogContainerElement.getAttribute('role')).toBe('alertdialog'); }); @@ -201,13 +198,13 @@ describe('MatDialog', () => { viewContainerFixture.detectChanges(); - const dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; + let dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; expect(dialogContainerElement.getAttribute('aria-describedby')).toBe('description-element'); }); it('should close a dialog and get back a result', fakeAsync(() => { - const dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); - const afterCloseCallback = jasmine.createSpy('afterClose callback'); + let dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); + let afterCloseCallback = jasmine.createSpy('afterClose callback'); dialogRef.afterClosed().subscribe(afterCloseCallback); dialogRef.close('Charmander'); @@ -295,9 +292,7 @@ describe('MatDialog', () => { })); it('should close a dialog via the escape key', fakeAsync(() => { - dialog.open(PizzaMsg, { - viewContainerRef: testViewContainerRef, - }); + dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); const event = dispatchKeyboardEvent(document.body, 'keydown', ESCAPE); viewContainerFixture.detectChanges(); @@ -308,9 +303,7 @@ describe('MatDialog', () => { })); it('should not close a dialog via the escape key with a modifier', fakeAsync(() => { - dialog.open(PizzaMsg, { - viewContainerRef: testViewContainerRef, - }); + dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); const event = createKeyboardEvent('keydown', ESCAPE, undefined, {alt: true}); dispatchEvent(document.body, event); @@ -349,13 +342,11 @@ describe('MatDialog', () => { })); it('should close when clicking on the overlay backdrop', fakeAsync(() => { - dialog.open(PizzaMsg, { - viewContainerRef: testViewContainerRef, - }); + dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); viewContainerFixture.detectChanges(); - const backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; + let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; backdrop.click(); viewContainerFixture.detectChanges(); @@ -365,16 +356,14 @@ describe('MatDialog', () => { })); it('should emit the backdropClick stream when clicking on the overlay backdrop', fakeAsync(() => { - const dialogRef = dialog.open(PizzaMsg, { - viewContainerRef: testViewContainerRef, - }); + const dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); const spy = jasmine.createSpy('backdropClick spy'); dialogRef.backdropClick().subscribe(spy); viewContainerFixture.detectChanges(); - const backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; + let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; backdrop.click(); expect(spy).toHaveBeenCalledTimes(1); @@ -395,8 +384,8 @@ describe('MatDialog', () => { viewContainerFixture.detectChanges(); - const backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; - const container = overlayContainerElement.querySelector('mat-dialog-container') as HTMLElement; + let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; + let container = overlayContainerElement.querySelector('mat-dialog-container') as HTMLElement; dispatchKeyboardEvent(document.body, 'keydown', A); dispatchKeyboardEvent(backdrop, 'keydown', A); dispatchKeyboardEvent(container, 'keydown', A); @@ -406,11 +395,7 @@ describe('MatDialog', () => { it('should notify the observers if a dialog has been opened', () => { dialog.afterOpened.subscribe(ref => { - expect( - dialog.open(PizzaMsg, { - viewContainerRef: testViewContainerRef, - }), - ).toBe(ref); + expect(dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef})).toBe(ref); }); }); @@ -442,37 +427,31 @@ describe('MatDialog', () => { }); it('should override the width of the overlay pane', () => { - dialog.open(PizzaMsg, { - width: '500px', - }); + dialog.open(PizzaMsg, {width: '500px'}); viewContainerFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.width).toBe('500px'); }); it('should override the height of the overlay pane', () => { - dialog.open(PizzaMsg, { - height: '100px', - }); + dialog.open(PizzaMsg, {height: '100px'}); viewContainerFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.height).toBe('100px'); }); it('should override the min-width of the overlay pane', () => { - dialog.open(PizzaMsg, { - minWidth: '500px', - }); + dialog.open(PizzaMsg, {minWidth: '500px'}); viewContainerFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.minWidth).toBe('500px'); }); @@ -494,9 +473,7 @@ describe('MatDialog', () => { viewContainerFixture.detectChanges(); flushMicrotasks(); - dialogRef = dialog.open(PizzaMsg, { - maxWidth: '100px', - }); + dialogRef = dialog.open(PizzaMsg, {maxWidth: '100px'}); viewContainerFixture.detectChanges(); @@ -506,95 +483,71 @@ describe('MatDialog', () => { })); it('should override the min-height of the overlay pane', () => { - dialog.open(PizzaMsg, { - minHeight: '300px', - }); + dialog.open(PizzaMsg, {minHeight: '300px'}); viewContainerFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.minHeight).toBe('300px'); }); it('should override the max-height of the overlay pane', () => { - dialog.open(PizzaMsg, { - maxHeight: '100px', - }); + dialog.open(PizzaMsg, {maxHeight: '100px'}); viewContainerFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.maxHeight).toBe('100px'); }); it('should override the top offset of the overlay pane', () => { - dialog.open(PizzaMsg, { - position: { - top: '100px', - }, - }); + dialog.open(PizzaMsg, {position: {top: '100px'}}); viewContainerFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.marginTop).toBe('100px'); }); it('should override the bottom offset of the overlay pane', () => { - dialog.open(PizzaMsg, { - position: { - bottom: '200px', - }, - }); + dialog.open(PizzaMsg, {position: {bottom: '200px'}}); viewContainerFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.marginBottom).toBe('200px'); }); it('should override the left offset of the overlay pane', () => { - dialog.open(PizzaMsg, { - position: { - left: '250px', - }, - }); + dialog.open(PizzaMsg, {position: {left: '250px'}}); viewContainerFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.marginLeft).toBe('250px'); }); it('should override the right offset of the overlay pane', () => { - dialog.open(PizzaMsg, { - position: { - right: '125px', - }, - }); + dialog.open(PizzaMsg, {position: {right: '125px'}}); viewContainerFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.marginRight).toBe('125px'); }); it('should allow for the position to be updated', () => { - const dialogRef = dialog.open(PizzaMsg, { - position: { - left: '250px', - }, - }); + let dialogRef = dialog.open(PizzaMsg, {position: {left: '250px'}}); viewContainerFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.marginLeft).toBe('250px'); @@ -604,11 +557,11 @@ describe('MatDialog', () => { }); it('should allow for the dimensions to be updated', () => { - const dialogRef = dialog.open(PizzaMsg, {width: '100px'}); + let dialogRef = dialog.open(PizzaMsg, {width: '100px'}); viewContainerFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.width).toBe('100px'); @@ -618,11 +571,11 @@ describe('MatDialog', () => { }); it('should reset the overlay dimensions to their initial size', () => { - const dialogRef = dialog.open(PizzaMsg); + let dialogRef = dialog.open(PizzaMsg); viewContainerFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.width).toBeFalsy(); expect(overlayPane.style.height).toBeFalsy(); @@ -643,7 +596,7 @@ describe('MatDialog', () => { viewContainerFixture.detectChanges(); - const overlayPane = overlayContainerElement.querySelector('.cdk-global-overlay-wrapper')!; + let overlayPane = overlayContainerElement.querySelector('.cdk-global-overlay-wrapper')!; expect(overlayPane.getAttribute('dir')).toBe('rtl'); }); @@ -693,19 +646,6 @@ describe('MatDialog', () => { expect(overlayContainerElement.querySelectorAll('mat-dialog-container').length).toBe(0); })); - it('should set the proper animation states', () => { - const dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); - const dialogContainer: MatDialogContainer = viewContainerFixture.debugElement.query( - By.directive(MatDialogContainer), - )!.componentInstance; - - expect(dialogContainer._state).toBe('enter'); - - dialogRef.close(); - - expect(dialogContainer._state).toBe('exit'); - }); - it('should close all dialogs when the user goes forwards/backwards in history', fakeAsync(() => { dialog.open(PizzaMsg); dialog.open(PizzaMsg); @@ -777,8 +717,8 @@ describe('MatDialog', () => { })); it('should have the componentInstance available in the afterClosed callback', fakeAsync(() => { - const dialogRef = dialog.open(PizzaMsg); - const spy = jasmine.createSpy('afterClosed spy'); + let dialogRef = dialog.open(PizzaMsg); + let spy = jasmine.createSpy('afterClosed spy'); flushMicrotasks(); viewContainerFixture.detectChanges(); @@ -829,14 +769,9 @@ describe('MatDialog', () => { describe('passing in data', () => { it('should be able to pass in data', () => { - const config = { - data: { - stringParam: 'hello', - dateParam: new Date(), - }, - }; + let config = {data: {stringParam: 'hello', dateParam: new Date()}}; - const instance = dialog.open(DialogWithInjectedData, config).componentInstance; + let instance = dialog.open(DialogWithInjectedData, config).componentInstance; expect(instance.data.stringParam).toBe(config.data.stringParam); expect(instance.data.dateParam).toBe(config.data.dateParam); @@ -844,14 +779,14 @@ describe('MatDialog', () => { it('should default to null if no data is passed', () => { expect(() => { - const dialogRef = dialog.open(DialogWithInjectedData); + let dialogRef = dialog.open(DialogWithInjectedData); expect(dialogRef.componentInstance.data).toBeNull(); }).not.toThrow(); }); }); it('should not keep a reference to the component after the dialog is closed', fakeAsync(() => { - const dialogRef = dialog.open(PizzaMsg); + let dialogRef = dialog.open(PizzaMsg); expect(dialogRef.componentInstance).toBeTruthy(); @@ -864,14 +799,14 @@ describe('MatDialog', () => { .toBeFalsy(); })); - it('should assign a unique id to each dialog', () => { + it('should assign a unique id to each dialog', fakeAsync(() => { const one = dialog.open(PizzaMsg); const two = dialog.open(PizzaMsg); expect(one.id).toBeTruthy(); expect(two.id).toBeTruthy(); expect(one.id).not.toBe(two.id); - }); + })); it('should allow for the id to be overwritten', () => { const dialogRef = dialog.open(PizzaMsg, {id: 'pizza'}); @@ -954,7 +889,7 @@ describe('MatDialog', () => { })); it('should add and remove classes while open', () => { - const dialogRef = dialog.open(PizzaMsg, { + let dialogRef = dialog.open(PizzaMsg, { disableClose: true, viewContainerRef: testViewContainerRef, }); @@ -974,16 +909,11 @@ describe('MatDialog', () => { describe('disableClose option', () => { it('should prevent closing via clicks on the backdrop', fakeAsync(() => { - dialog.open(PizzaMsg, { - disableClose: true, - viewContainerRef: testViewContainerRef, - }); + dialog.open(PizzaMsg, {disableClose: true, viewContainerRef: testViewContainerRef}); viewContainerFixture.detectChanges(); - const backdrop = overlayContainerElement.querySelector( - '.cdk-overlay-backdrop', - ) as HTMLElement; + let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; backdrop.click(); viewContainerFixture.detectChanges(); flush(); @@ -992,10 +922,7 @@ describe('MatDialog', () => { })); it('should prevent closing via the escape key', fakeAsync(() => { - dialog.open(PizzaMsg, { - disableClose: true, - viewContainerRef: testViewContainerRef, - }); + dialog.open(PizzaMsg, {disableClose: true, viewContainerRef: testViewContainerRef}); viewContainerFixture.detectChanges(); dispatchKeyboardEvent(document.body, 'keydown', ESCAPE); @@ -1006,16 +933,14 @@ describe('MatDialog', () => { })); it('should allow for the disableClose option to be updated while open', fakeAsync(() => { - const dialogRef = dialog.open(PizzaMsg, { + let dialogRef = dialog.open(PizzaMsg, { disableClose: true, viewContainerRef: testViewContainerRef, }); viewContainerFixture.detectChanges(); - const backdrop = overlayContainerElement.querySelector( - '.cdk-overlay-backdrop', - ) as HTMLElement; + let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; backdrop.click(); expect(overlayContainerElement.querySelector('mat-dialog-container')).toBeTruthy(); @@ -1028,6 +953,29 @@ describe('MatDialog', () => { expect(overlayContainerElement.querySelector('mat-dialog-container')).toBeFalsy(); })); + it('should recapture focus when clicking on the backdrop', fakeAsync(() => { + dialog.open(PizzaMsg, {disableClose: true, viewContainerRef: testViewContainerRef}); + + viewContainerFixture.detectChanges(); + flushMicrotasks(); + + let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; + let input = overlayContainerElement.querySelector('input') as HTMLInputElement; + + expect(document.activeElement) + .withContext('Expected input to be focused on open') + .toBe(input); + + input.blur(); // Programmatic clicks might not move focus so we simulate it. + backdrop.click(); + viewContainerFixture.detectChanges(); + flush(); + + expect(document.activeElement) + .withContext('Expected input to stay focused after click') + .toBe(input); + })); + it( 'should recapture focus to the first tabbable element when clicking on the backdrop with ' + 'autoFocus set to "first-tabbable" (the default)', @@ -1040,10 +988,10 @@ describe('MatDialog', () => { viewContainerFixture.detectChanges(); flushMicrotasks(); - const backdrop = overlayContainerElement.querySelector( + let backdrop = overlayContainerElement.querySelector( '.cdk-overlay-backdrop', ) as HTMLElement; - const input = overlayContainerElement.querySelector('input') as HTMLInputElement; + let input = overlayContainerElement.querySelector('input') as HTMLInputElement; expect(document.activeElement) .withContext('Expected input to be focused on open') @@ -1073,11 +1021,11 @@ describe('MatDialog', () => { viewContainerFixture.detectChanges(); flushMicrotasks(); - const backdrop = overlayContainerElement.querySelector( + let backdrop = overlayContainerElement.querySelector( '.cdk-overlay-backdrop', ) as HTMLElement; - const container = overlayContainerElement.querySelector( - '.mat-dialog-container', + let container = overlayContainerElement.querySelector( + '.mat-mdc-dialog-container', ) as HTMLInputElement; expect(document.activeElement) @@ -1094,84 +1042,77 @@ describe('MatDialog', () => { .toBe(container); }), ); + }); - it( - 'should recapture focus to the first header when clicking on the backdrop with ' + - 'autoFocus set to "first-heading"', - fakeAsync(() => { - dialog.open(ContentElementDialog, { - disableClose: true, - viewContainerRef: testViewContainerRef, - autoFocus: 'first-heading', - }); + it( + 'should recapture focus to the first header when clicking on the backdrop with ' + + 'autoFocus set to "first-heading"', + fakeAsync(() => { + dialog.open(ContentElementDialog, { + disableClose: true, + viewContainerRef: testViewContainerRef, + autoFocus: 'first-heading', + }); - viewContainerFixture.detectChanges(); - flushMicrotasks(); + viewContainerFixture.detectChanges(); + flushMicrotasks(); - let backdrop = overlayContainerElement.querySelector( - '.cdk-overlay-backdrop', - ) as HTMLElement; - let firstHeader = overlayContainerElement.querySelector( - '.mat-dialog-title[tabindex="-1"]', - ) as HTMLInputElement; + let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; + let firstHeader = overlayContainerElement.querySelector( + '.mat-mdc-dialog-title[tabindex="-1"]', + ) as HTMLInputElement; - expect(document.activeElement) - .withContext('Expected first header to be focused on open') - .toBe(firstHeader); + expect(document.activeElement) + .withContext('Expected first header to be focused on open') + .toBe(firstHeader); - firstHeader.blur(); // Programmatic clicks might not move focus so we simulate it. - backdrop.click(); - viewContainerFixture.detectChanges(); - flush(); + firstHeader.blur(); // Programmatic clicks might not move focus so we simulate it. + backdrop.click(); + viewContainerFixture.detectChanges(); + flush(); - expect(document.activeElement) - .withContext('Expected first header to stay focused after click') - .toBe(firstHeader); - }), - ); + expect(document.activeElement) + .withContext('Expected first header to stay focused after click') + .toBe(firstHeader); + }), + ); - it( - 'should recapture focus to the first element that matches the css selector when ' + - 'clicking on the backdrop with autoFocus set to a css selector', - fakeAsync(() => { - dialog.open(ContentElementDialog, { - disableClose: true, - viewContainerRef: testViewContainerRef, - autoFocus: 'button', - }); + it( + 'should recapture focus to the first element that matches the css selector when ' + + 'clicking on the backdrop with autoFocus set to a css selector', + fakeAsync(() => { + dialog.open(ContentElementDialog, { + disableClose: true, + viewContainerRef: testViewContainerRef, + autoFocus: 'button', + }); - viewContainerFixture.detectChanges(); - flushMicrotasks(); + viewContainerFixture.detectChanges(); + flushMicrotasks(); - let backdrop = overlayContainerElement.querySelector( - '.cdk-overlay-backdrop', - ) as HTMLElement; - let firstButton = overlayContainerElement.querySelector( - '[mat-dialog-close]', - ) as HTMLInputElement; + let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; + let firstButton = overlayContainerElement.querySelector( + '[mat-dialog-close]', + ) as HTMLInputElement; - expect(document.activeElement) - .withContext('Expected first button to be focused on open') - .toBe(firstButton); + expect(document.activeElement) + .withContext('Expected first button to be focused on open') + .toBe(firstButton); - firstButton.blur(); // Programmatic clicks might not move focus so we simulate it. - backdrop.click(); - viewContainerFixture.detectChanges(); - flush(); + firstButton.blur(); // Programmatic clicks might not move focus so we simulate it. + backdrop.click(); + viewContainerFixture.detectChanges(); + flush(); - expect(document.activeElement) - .withContext('Expected first button to stay focused after click') - .toBe(firstButton); - }), - ); - }); + expect(document.activeElement) + .withContext('Expected first button to stay focused after click') + .toBe(firstButton); + }), + ); describe('hasBackdrop option', () => { it('should have a backdrop', () => { - dialog.open(PizzaMsg, { - hasBackdrop: true, - viewContainerRef: testViewContainerRef, - }); + dialog.open(PizzaMsg, {hasBackdrop: true, viewContainerRef: testViewContainerRef}); viewContainerFixture.detectChanges(); @@ -1179,10 +1120,7 @@ describe('MatDialog', () => { }); it('should not have a backdrop', () => { - dialog.open(PizzaMsg, { - hasBackdrop: false, - viewContainerRef: testViewContainerRef, - }); + dialog.open(PizzaMsg, {hasBackdrop: false, viewContainerRef: testViewContainerRef}); viewContainerFixture.detectChanges(); @@ -1205,10 +1143,7 @@ describe('MatDialog', () => { describe('backdropClass option', () => { it('should have default backdrop class', () => { - dialog.open(PizzaMsg, { - backdropClass: '', - viewContainerRef: testViewContainerRef, - }); + dialog.open(PizzaMsg, {backdropClass: '', viewContainerRef: testViewContainerRef}); viewContainerFixture.detectChanges(); @@ -1233,9 +1168,7 @@ describe('MatDialog', () => { afterEach(() => overlayContainerElement.remove()); it('should focus the first tabbable element of the dialog on open (the default)', fakeAsync(() => { - dialog.open(PizzaMsg, { - viewContainerRef: testViewContainerRef, - }); + dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); viewContainerFixture.detectChanges(); flushMicrotasks(); @@ -1255,7 +1188,7 @@ describe('MatDialog', () => { flushMicrotasks(); let container = overlayContainerElement.querySelector( - '.mat-dialog-container', + '.mat-mdc-dialog-container', ) as HTMLInputElement; expect(document.activeElement) @@ -1302,7 +1235,7 @@ describe('MatDialog', () => { it('should attach the focus trap even if automatic focus is disabled', fakeAsync(() => { dialog.open(PizzaMsg, { viewContainerRef: testViewContainerRef, - autoFocus: false, + autoFocus: 'false', }); viewContainerFixture.detectChanges(); @@ -1315,12 +1248,12 @@ describe('MatDialog', () => { it('should re-focus trigger element when dialog closes', fakeAsync(() => { // Create a element that has focus before the dialog is opened. - const button = document.createElement('button'); + let button = document.createElement('button'); button.id = 'dialog-trigger'; document.body.appendChild(button); button.focus(); - const dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); + let dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); flushMicrotasks(); viewContainerFixture.detectChanges(); @@ -1334,7 +1267,7 @@ describe('MatDialog', () => { dialogRef.close(); expect(document.activeElement!.id).not.toBe( 'dialog-trigger', - 'Expcted the focus not to have changed before the animation finishes.', + 'Expected the focus not to have changed before the animation finishes.', ); flushMicrotasks(); @@ -1384,14 +1317,16 @@ describe('MatDialog', () => { button.focus(); // Patch the element focus after the initial and real focus, because otherwise the - // `activeElement` won't be set, and the dialog won't be able to restore focus to an element. + // `activeElement` won't be set, and the dialog won't be able to restore focus to an + // element. patchElementFocus(button); dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); tick(500); viewContainerFixture.detectChanges(); - expect(lastFocusOrigin!).toBe('program'); + flushMicrotasks(); + expect(lastFocusOrigin!).withContext('Expected the trigger button to be blurred').toBeNull(); dispatchKeyboardEvent(document.body, 'keydown', ESCAPE); @@ -1417,14 +1352,16 @@ describe('MatDialog', () => { button.focus(); // Patch the element focus after the initial and real focus, because otherwise the - // `activeElement` won't be set, and the dialog won't be able to restore focus to an element. + // `activeElement` won't be set, and the dialog won't be able to restore focus to an + // element. patchElementFocus(button); dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); tick(500); viewContainerFixture.detectChanges(); - expect(lastFocusOrigin!).toBe('program'); + flushMicrotasks(); + expect(lastFocusOrigin!).withContext('Expected the trigger button to be blurred').toBeNull(); const backdrop = overlayContainerElement.querySelector( '.cdk-overlay-backdrop', @@ -1452,17 +1389,15 @@ describe('MatDialog', () => { button.focus(); // Patch the element focus after the initial and real focus, because otherwise the - // `activeElement` won't be set, and the dialog won't be able to restore focus to an element. + // `activeElement` won't be set, and the dialog won't be able to restore focus to an + // element. patchElementFocus(button); - expect(lastFocusOrigin!) - .withContext('Expected the trigger button to be focused via program') - .toBe('program'); dialog.open(ContentElementDialog, {viewContainerRef: testViewContainerRef}); tick(500); viewContainerFixture.detectChanges(); - tick(500); + flushMicrotasks(); expect(lastFocusOrigin!).withContext('Expected the trigger button to be blurred').toBeNull(); const closeButton = overlayContainerElement.querySelector( @@ -1494,16 +1429,15 @@ describe('MatDialog', () => { button.focus(); // Patch the element focus after the initial and real focus, because otherwise the - // `activeElement` won't be set, and the dialog won't be able to restore focus to an element. + // `activeElement` won't be set, and the dialog won't be able to restore focus to an + // element. patchElementFocus(button); - expect(lastFocusOrigin!) - .withContext('Expected the trigger button to be focused via program') - .toBe('program'); dialog.open(ContentElementDialog, {viewContainerRef: testViewContainerRef}); - viewContainerFixture.detectChanges(); tick(500); + viewContainerFixture.detectChanges(); + flushMicrotasks(); expect(lastFocusOrigin!).withContext('Expected the trigger button to be blurred').toBeNull(); const closeButton = overlayContainerElement.querySelector( @@ -1528,8 +1462,8 @@ describe('MatDialog', () => { it('should allow the consumer to shift focus in afterClosed', fakeAsync(() => { // Create a element that has focus before the dialog is opened. - const button = document.createElement('button'); - const input = document.createElement('input'); + let button = document.createElement('button'); + let input = document.createElement('input'); button.id = 'dialog-trigger'; input.id = 'input-to-be-focused'; @@ -1538,7 +1472,7 @@ describe('MatDialog', () => { document.body.appendChild(input); button.focus(); - const dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); + let dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); tick(500); viewContainerFixture.detectChanges(); @@ -1678,43 +1612,50 @@ describe('MatDialog', () => { function runContentElementTests() { it('should close the dialog when clicking on the close button', fakeAsync(() => { - expect(overlayContainerElement.querySelectorAll('.mat-dialog-container').length).toBe(1); + expect(overlayContainerElement.querySelectorAll('.mat-mdc-dialog-container').length).toBe( + 1, + ); (overlayContainerElement.querySelector('button[mat-dialog-close]') as HTMLElement).click(); viewContainerFixture.detectChanges(); flush(); - expect(overlayContainerElement.querySelectorAll('.mat-dialog-container').length).toBe(0); + expect(overlayContainerElement.querySelectorAll('.mat-mdc-dialog-container').length).toBe( + 0, + ); })); it('should not close if [mat-dialog-close] is applied on a non-button node', () => { - expect(overlayContainerElement.querySelectorAll('.mat-dialog-container').length).toBe(1); + expect(overlayContainerElement.querySelectorAll('.mat-mdc-dialog-container').length).toBe( + 1, + ); (overlayContainerElement.querySelector('div[mat-dialog-close]') as HTMLElement).click(); - expect(overlayContainerElement.querySelectorAll('.mat-dialog-container').length).toBe(1); + expect(overlayContainerElement.querySelectorAll('.mat-mdc-dialog-container').length).toBe( + 1, + ); }); it('should allow for a user-specified aria-label on the close button', fakeAsync(() => { - const button = overlayContainerElement.querySelector('.close-with-aria-label')!; - + let button = overlayContainerElement.querySelector('.close-with-aria-label')!; expect(button.getAttribute('aria-label')).toBe('Best close button ever'); })); it('should set the "type" attribute of the close button if not set manually', () => { - const button = overlayContainerElement.querySelector('button[mat-dialog-close]')!; + let button = overlayContainerElement.querySelector('button[mat-dialog-close]')!; expect(button.getAttribute('type')).toBe('button'); }); it('should not override type attribute of the close button if set manually', () => { - const button = overlayContainerElement.querySelector('button.with-submit')!; + let button = overlayContainerElement.querySelector('button.with-submit')!; expect(button.getAttribute('type')).toBe('submit'); }); it('should return the [mat-dialog-close] result when clicking the close button', fakeAsync(() => { - const afterCloseCallback = jasmine.createSpy('afterClose callback'); + let afterCloseCallback = jasmine.createSpy('afterClose callback'); dialogRef.afterClosed().subscribe(afterCloseCallback); (overlayContainerElement.querySelector('button.close-with-true') as HTMLElement).click(); @@ -1725,8 +1666,8 @@ describe('MatDialog', () => { })); it('should set the aria-labelledby attribute to the id of the title', fakeAsync(() => { - const title = overlayContainerElement.querySelector('[mat-dialog-title]')!; - const container = overlayContainerElement.querySelector('mat-dialog-container')!; + let title = overlayContainerElement.querySelector('[mat-dialog-title]')!; + let container = overlayContainerElement.querySelector('mat-dialog-container')!; flush(); viewContainerFixture.detectChanges(); @@ -1741,12 +1682,11 @@ describe('MatDialog', () => { let actions = overlayContainerElement.querySelector('mat-dialog-actions')!; expect(actions) - .withContext('Expected action buttons to not have class mat-dialog-actions-align-center') - .not.toHaveClass('mat-dialog-actions-align-center'); - + .withContext('Expected action buttons to not have class align-center') + .not.toHaveClass('mat-mdc-dialog-actions-align-center'); expect(actions) - .withContext('Expected action buttons to have class mat-dialog-actions-align-end') - .toHaveClass('mat-dialog-actions-align-end'); + .withContext('Expected action buttons to have class align-end') + .toHaveClass('mat-mdc-dialog-actions-align-end'); }); } }); @@ -1791,8 +1731,8 @@ describe('MatDialog', () => { }); viewContainerFixture.detectChanges(); flush(); - const title = overlayContainerElement.querySelector('[mat-dialog-title]')!; - const container = overlayContainerElement.querySelector('mat-dialog-container')!; + let title = overlayContainerElement.querySelector('[mat-dialog-title]')!; + let container = overlayContainerElement.querySelector('mat-dialog-container')!; flush(); viewContainerFixture.detectChanges(); @@ -1804,10 +1744,7 @@ describe('MatDialog', () => { describe('aria-label', () => { it('should be able to set a custom aria-label', () => { - dialog.open(PizzaMsg, { - ariaLabel: 'Hello there', - viewContainerRef: testViewContainerRef, - }); + dialog.open(PizzaMsg, {ariaLabel: 'Hello there', viewContainerRef: testViewContainerRef}); viewContainerFixture.detectChanges(); const container = overlayContainerElement.querySelector('mat-dialog-container')!; @@ -1844,7 +1781,7 @@ describe('MatDialog', () => { })); }); -describe('MatDialog with a parent MatDialog', () => { +describe('MDC-based MatDialog with a parent MatDialog', () => { let parentDialog: MatDialog; let childDialog: MatDialog; let overlayContainerElement: HTMLElement; @@ -1853,7 +1790,7 @@ describe('MatDialog with a parent MatDialog', () => { beforeEach(fakeAsync(() => { TestBed.configureTestingModule({ imports: [MatDialogModule, NoopAnimationsModule], - declarations: [ComponentThatProvidesMatDialog, DirectiveWithViewContainer], + declarations: [ComponentThatProvidesMatDialog], providers: [ { provide: OverlayContainer, @@ -1945,7 +1882,7 @@ describe('MatDialog with a parent MatDialog', () => { })); }); -describe('MatDialog with default options', () => { +describe('MDC-based MatDialog with default options', () => { let dialog: MatDialog; let overlayContainerElement: HTMLElement; @@ -1962,15 +1899,13 @@ describe('MatDialog with default options', () => { minHeight: '50px', maxWidth: '150px', maxHeight: '150px', - enterAnimationDuration: '100ms', - exitAnimationDuration: '50ms', - autoFocus: false, + autoFocus: 'dialog', }; TestBed.configureTestingModule({ imports: [MatDialogModule, NoopAnimationsModule], - providers: [{provide: MAT_DIALOG_DEFAULT_OPTIONS, useValue: defaultConfig}], declarations: [ComponentWithChildViewContainer, DirectiveWithViewContainer], + providers: [{provide: MAT_DIALOG_DEFAULT_OPTIONS, useValue: defaultConfig}], }); TestBed.compileComponents(); @@ -2000,7 +1935,7 @@ describe('MatDialog with default options', () => { expect(document.activeElement!.tagName).not.toBe('INPUT'); - const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.width).toBe('100px'); expect(overlayPane.style.height).toBe('100px'); expect(overlayPane.style.minWidth).toBe('50px'); @@ -2028,7 +1963,7 @@ describe('MatDialog with default options', () => { })); }); -describe('MatDialog with animations enabled', () => { +describe('MDC-based MatDialog with animations enabled', () => { let dialog: MatDialog; let testViewContainerRef: ViewContainerRef; @@ -2043,18 +1978,33 @@ describe('MatDialog with animations enabled', () => { TestBed.compileComponents(); })); - beforeEach(inject([MatDialog, OverlayContainer], (d: MatDialog, oc: OverlayContainer) => { + beforeEach(inject([MatDialog], (d: MatDialog) => { dialog = d; + viewContainerFixture = TestBed.createComponent(ComponentWithChildViewContainer); viewContainerFixture.detectChanges(); testViewContainerRef = viewContainerFixture.componentInstance.childViewContainer; })); + it('should emit when dialog opening animation is complete', fakeAsync(() => { + const dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); + const spy = jasmine.createSpy('afterOpen spy'); + + dialogRef.afterOpened().subscribe(spy); + + viewContainerFixture.detectChanges(); + + // callback should not be called before animation is complete + expect(spy).not.toHaveBeenCalled(); + + tick(numbers.DIALOG_ANIMATION_OPEN_TIME_MS); + expect(spy).toHaveBeenCalled(); + })); + it('should return the current state of the dialog', fakeAsync(() => { const dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); - // Duration of the close animation in milliseconds. Extracted from the - // Angular animations definition of the dialog. - const dialogCloseDuration = 75; + // Duration of the close animation in milliseconds. + const dialogCloseDuration = numbers.DIALOG_ANIMATION_CLOSE_TIME_MS; expect(dialogRef.getState()).toBe(MatDialogState.OPEN); dialogRef.close(); @@ -2096,14 +2046,14 @@ describe('MatDialog with explicit injector provided', () => { fixture = TestBed.createComponent(ModuleBoundDialogParentComponent); }); - it('should use the standalone injector and render the dialog successfully', fakeAsync(() => { + it('should use the standalone injector and render the dialog successfully', () => { fixture.componentInstance.openDialog(); fixture.detectChanges(); expect( overlayContainerElement.querySelector('module-bound-dialog-child-component')!.innerHTML, ).toEqual('

Pasta

'); - })); + }); }); @Directive({selector: 'dir-with-view-container'}) @@ -2136,7 +2086,7 @@ class ComponentWithChildViewContainer { @Component({ selector: 'arbitrary-component-with-template-ref', template: ` - Cheese {{localValue}} {{data?.value}}{{setDialogRef(dialogRef)}}`, + Cheese {{localValue}} {{data?.value}}{{setDialogRef(dialogRef)}}`, }) class ComponentWithTemplateRef { localValue: string; @@ -2200,10 +2150,7 @@ class ComponentWithContentElementTemplateRef { @ViewChild(TemplateRef) templateRef: TemplateRef; } -@Component({ - template: '', - providers: [MatDialog], -}) +@Component({template: '', providers: [MatDialog]}) class ComponentThatProvidesMatDialog { constructor(public dialog: MatDialog) {} } diff --git a/src/material/dialog/dialog.ts b/src/material/dialog/dialog.ts index 24decc088de5..9e354704056f 100644 --- a/src/material/dialog/dialog.ts +++ b/src/material/dialog/dialog.ts @@ -6,10 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {Overlay, OverlayContainer, ScrollStrategy} from '@angular/cdk/overlay'; -import {ComponentType} from '@angular/cdk/portal'; +import {ComponentType, Overlay, OverlayContainer, ScrollStrategy} from '@angular/cdk/overlay'; import {Location} from '@angular/common'; import { + ANIMATION_MODULE_TYPE, Inject, Injectable, InjectionToken, @@ -20,32 +20,26 @@ import { TemplateRef, Type, } from '@angular/core'; -import {defer, Observable, Subject} from 'rxjs'; -import {startWith} from 'rxjs/operators'; import {MatDialogConfig} from './dialog-config'; -import {MatDialogContainer, _MatDialogContainerBase} from './dialog-container'; +import {_MatDialogContainerBase, MatDialogContainer} from './dialog-container'; import {MatDialogRef} from './dialog-ref'; -import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; +import {defer, Observable, Subject} from 'rxjs'; import {Dialog, DialogConfig} from '@angular/cdk/dialog'; +import {startWith} from 'rxjs/operators'; /** Injection token that can be used to access the data that was passed in to a dialog. */ -export const MAT_DIALOG_DATA = new InjectionToken('MatDialogData'); +export const MAT_DIALOG_DATA = new InjectionToken('MatMdcDialogData'); /** Injection token that can be used to specify default dialog options. */ export const MAT_DIALOG_DEFAULT_OPTIONS = new InjectionToken( - 'mat-dialog-default-options', + 'mat-mdc-dialog-default-options', ); /** Injection token that determines the scroll handling while the dialog is open. */ export const MAT_DIALOG_SCROLL_STRATEGY = new InjectionToken<() => ScrollStrategy>( - 'mat-dialog-scroll-strategy', + 'mat-mdc-dialog-scroll-strategy', ); -/** @docs-private */ -export function MAT_DIALOG_SCROLL_STRATEGY_FACTORY(overlay: Overlay): () => ScrollStrategy { - return () => overlay.scrollStrategies.block(); -} - /** @docs-private */ export function MAT_DIALOG_SCROLL_STRATEGY_PROVIDER_FACTORY( overlay: Overlay, @@ -60,6 +54,11 @@ export const MAT_DIALOG_SCROLL_STRATEGY_PROVIDER = { useFactory: MAT_DIALOG_SCROLL_STRATEGY_PROVIDER_FACTORY, }; +/** @docs-private */ +export function MAT_DIALOG_SCROLL_STRATEGY_FACTORY(overlay: Overlay): () => ScrollStrategy { + return () => overlay.scrollStrategies.block(); +} + // Counter for unique dialog ids. let uniqueId = 0; @@ -258,7 +257,7 @@ export class MatDialog extends _MatDialogBase { * @deprecated `_location` parameter to be removed. * @breaking-change 10.0.0 */ - @Optional() _location: Location, + @Optional() location: Location, @Optional() @Inject(MAT_DIALOG_DEFAULT_OPTIONS) defaultOptions: MatDialogConfig, @Inject(MAT_DIALOG_SCROLL_STRATEGY) scrollStrategy: any, @Optional() @SkipSelf() parentDialog: MatDialog, @@ -287,5 +286,7 @@ export class MatDialog extends _MatDialogBase { MAT_DIALOG_DATA, animationMode, ); + + this._idPrefix = 'mat-mdc-dialog-'; } } diff --git a/src/material-experimental/mdc-dialog/module.ts b/src/material/dialog/module.ts similarity index 100% rename from src/material-experimental/mdc-dialog/module.ts rename to src/material/dialog/module.ts diff --git a/src/material/dialog/public-api.ts b/src/material/dialog/public-api.ts index b09d626e2682..35273a8bcc3e 100644 --- a/src/material/dialog/public-api.ts +++ b/src/material/dialog/public-api.ts @@ -6,10 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -export * from './dialog-module'; export * from './dialog'; -export * from './dialog-container'; -export * from './dialog-content-directives'; export * from './dialog-config'; export * from './dialog-ref'; +export * from './dialog-content-directives'; +export * from './dialog-container'; +export * from './module'; export {matDialogAnimations} from './dialog-animations'; diff --git a/src/material/dialog/testing/BUILD.bazel b/src/material/dialog/testing/BUILD.bazel index 6de93e902fad..706d27852e6b 100644 --- a/src/material/dialog/testing/BUILD.bazel +++ b/src/material/dialog/testing/BUILD.bazel @@ -9,7 +9,6 @@ ts_library( exclude = ["**/*.spec.ts"], ), deps = [ - "//src/cdk/coercion", "//src/cdk/overlay", "//src/cdk/testing", "//src/material/dialog", @@ -24,19 +23,6 @@ filegroup( srcs = glob(["**/*.ts"]), ) -ng_test_library( - name = "harness_tests_lib", - srcs = ["shared.spec.ts"], - deps = [ - ":testing", - "//src/cdk/overlay", - "//src/cdk/testing", - "//src/cdk/testing/testbed", - "//src/material/dialog", - "@npm//@angular/platform-browser", - ], -) - ng_test_library( name = "unit_tests_lib", srcs = glob( @@ -44,14 +30,16 @@ ng_test_library( exclude = ["shared.spec.ts"], ), deps = [ - ":harness_tests_lib", ":testing", "//src/material/dialog", + "//src/material/legacy-dialog/testing:harness_tests_lib", "@npm//@angular/platform-browser", ], ) ng_web_test_suite( name = "unit_tests", - deps = [":unit_tests_lib"], + deps = [ + ":unit_tests_lib", + ], ) diff --git a/src/material/dialog/testing/dialog-harness.spec.ts b/src/material/dialog/testing/dialog-harness.spec.ts index ac266f417022..f8f1e1957649 100644 --- a/src/material/dialog/testing/dialog-harness.spec.ts +++ b/src/material/dialog/testing/dialog-harness.spec.ts @@ -1,7 +1,7 @@ import {MatDialog, MatDialogModule} from '@angular/material/dialog'; -import {runHarnessTests} from '@angular/material/dialog/testing/shared.spec'; +import {runHarnessTests} from '@angular/material/legacy-dialog/testing/shared.spec'; import {MatDialogHarness} from './dialog-harness'; -describe('Non-MDC-based MatDialogHarness', () => { - runHarnessTests(MatDialogModule, MatDialogHarness, MatDialog); +describe('MDC-based MatDialog', () => { + runHarnessTests(MatDialogModule, MatDialogHarness as any, MatDialog as any); }); diff --git a/src/material/dialog/testing/dialog-harness.ts b/src/material/dialog/testing/dialog-harness.ts index e14bbc471c75..49fb48be94f0 100644 --- a/src/material/dialog/testing/dialog-harness.ts +++ b/src/material/dialog/testing/dialog-harness.ts @@ -6,15 +6,20 @@ * found in the LICENSE file at https://angular.io/license */ -import {ContentContainerComponentHarness, HarnessPredicate, TestKey} from '@angular/cdk/testing'; -import {DialogRole} from '@angular/material/dialog'; +import { + ComponentHarnessConstructor, + ContentContainerComponentHarness, + HarnessPredicate, + TestKey, +} from '@angular/cdk/testing'; import {DialogHarnessFilters} from './dialog-harness-filters'; +import {DialogRole} from '@angular/material/dialog'; /** Selectors for different sections of the mat-dialog that can contain user content. */ export const enum MatDialogSection { - TITLE = '.mat-dialog-title', - CONTENT = '.mat-dialog-content', - ACTIONS = '.mat-dialog-actions', + TITLE = '.mat-mdc-dialog-title', + CONTENT = '.mat-mdc-dialog-content', + ACTIONS = '.mat-mdc-dialog-actions', } /** Base class for the `MatDialogHarness` implementation. */ @@ -86,18 +91,18 @@ export class _MatDialogHarnessBase /** Harness for interacting with a standard `MatDialog` in tests. */ export class MatDialogHarness extends _MatDialogHarnessBase { - // Developers can provide a custom component or template for the - // dialog. The canonical dialog parent is the "MatDialogContainer". /** The selector for the host element of a `MatDialog` instance. */ - static hostSelector = '.mat-dialog-container'; + static hostSelector = '.mat-mdc-dialog-container'; /** - * Gets a `HarnessPredicate` that can be used to search for a `MatDialogHarness` that meets - * certain criteria. + * Gets a `HarnessPredicate` that can be used to search for a dialog with specific attributes. * @param options Options for filtering which dialog instances are considered a match. * @return a `HarnessPredicate` configured with the given options. */ - static with(options: DialogHarnessFilters = {}): HarnessPredicate { - return new HarnessPredicate(MatDialogHarness, options); + static with( + this: ComponentHarnessConstructor, + options: DialogHarnessFilters = {}, + ): HarnessPredicate { + return new HarnessPredicate(this, options); } } diff --git a/src/material/dialog/testing/dialog-opener.spec.ts b/src/material/dialog/testing/dialog-opener.spec.ts index 5040f949149e..23c3e8c5f21f 100644 --- a/src/material/dialog/testing/dialog-opener.spec.ts +++ b/src/material/dialog/testing/dialog-opener.spec.ts @@ -1,5 +1,5 @@ import {Component, Inject} from '@angular/core'; -import {fakeAsync, flush, TestBed} from '@angular/core/testing'; +import {fakeAsync, TestBed, flush} from '@angular/core/testing'; import {MatTestDialogOpenerModule, MatTestDialogOpener} from '@angular/material/dialog/testing'; import {MAT_DIALOG_DATA, MatDialogRef, MatDialogState} from '@angular/material/dialog'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; diff --git a/src/material/dialog/testing/dialog-opener.ts b/src/material/dialog/testing/dialog-opener.ts index 3c1c03a22a7a..67f489634187 100644 --- a/src/material/dialog/testing/dialog-opener.ts +++ b/src/material/dialog/testing/dialog-opener.ts @@ -9,23 +9,23 @@ import {ComponentType} from '@angular/cdk/overlay'; import { ChangeDetectionStrategy, - Directive, Component, + Directive, NgModule, OnDestroy, ViewEncapsulation, } from '@angular/core'; import { - _MatDialogBase, - _MatDialogContainerBase, MatDialog, MatDialogConfig, MatDialogContainer, MatDialogModule, + _MatDialogBase, + _MatDialogContainerBase, MatDialogRef, } from '@angular/material/dialog'; -import {Subscription} from 'rxjs'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {Subscription} from 'rxjs'; /** Base class for a component that immediately opens a dialog when created. */ @Directive() @@ -67,7 +67,7 @@ export class _MatTestDialogOpenerBase } } -/** Test component that immediately opens a dialog when created. */ +/** Test component that immediately opens a dialog when bootstrapped. */ @Component({ selector: 'mat-test-dialog-opener', template: '', diff --git a/src/material/dialog/testing/index.ts b/src/material/dialog/testing/index.ts index 676ca90f1ffa..e1d43c50691f 100644 --- a/src/material/dialog/testing/index.ts +++ b/src/material/dialog/testing/index.ts @@ -7,3 +7,4 @@ */ export * from './public-api'; +export {_MatDialogHarnessBase} from './dialog-harness'; diff --git a/src/material/dialog/testing/public-api.ts b/src/material/dialog/testing/public-api.ts index cdda39f93035..15333c650f38 100644 --- a/src/material/dialog/testing/public-api.ts +++ b/src/material/dialog/testing/public-api.ts @@ -6,6 +6,6 @@ * found in the LICENSE file at https://angular.io/license */ -export * from './dialog-harness'; -export * from './dialog-harness-filters'; +export {DialogHarnessFilters} from './dialog-harness-filters'; +export {MatDialogHarness, MatDialogSection} from './dialog-harness'; export * from './dialog-opener'; diff --git a/src/material/legacy-core/density/private/_all-density.scss b/src/material/legacy-core/density/private/_all-density.scss index 3d8b8f5a9695..8aff6db663ca 100644 --- a/src/material/legacy-core/density/private/_all-density.scss +++ b/src/material/legacy-core/density/private/_all-density.scss @@ -1,5 +1,6 @@ @use '../../../core/theming/theming'; @use '../../../core/density/private/all-density'; +@use '../../../legacy-form-field/form-field-theme'; // Add legacy theme imports here, e.g.: // @use '../../..//-theme'; @@ -23,6 +24,7 @@ // Add legacy density includes here, e.g.: // @include -theme.density($config); + @include form-field-theme.density($config); @include all-density.private-all-unmigrated-component-densities($config); } diff --git a/src/material/legacy-core/theming/_all-theme.scss b/src/material/legacy-core/theming/_all-theme.scss index 2f596b718826..82560eb8c6a2 100644 --- a/src/material/legacy-core/theming/_all-theme.scss +++ b/src/material/legacy-core/theming/_all-theme.scss @@ -9,6 +9,7 @@ @use '../../legacy-checkbox/checkbox-theme'; @use '../../legacy-select/select-theme'; @use '../../legacy-autocomplete/autocomplete-theme'; +@use '../../legacy-dialog/dialog-theme'; // Create a theme. @mixin all-legacy-component-themes($theme-or-color-config) { @@ -23,6 +24,7 @@ @include select-theme.theme($theme-or-color-config); @include checkbox-theme.theme($theme-or-color-config); @include autocomplete-theme.theme($theme-or-color-config); + @include dialog-theme.theme($theme-or-color-config); @include all-theme.private-all-unmigrated-component-themes($theme-or-color-config); } } diff --git a/src/material/legacy-core/typography/_all-typography.scss b/src/material/legacy-core/typography/_all-typography.scss index dca93685f153..6a117ecdd963 100644 --- a/src/material/legacy-core/typography/_all-typography.scss +++ b/src/material/legacy-core/typography/_all-typography.scss @@ -11,6 +11,7 @@ @use '../../legacy-form-field/form-field-theme'; @use '../../legacy-select/select-theme'; @use '../../legacy-autocomplete/autocomplete-theme'; +@use '../../legacy-dialog/dialog-theme'; // Includes all of the typographic styles. @mixin all-legacy-component-typographies($config-or-theme: null) { @@ -39,6 +40,7 @@ @include select-theme.typography($config); @include checkbox-theme.typography($config); @include autocomplete-theme.typography($config); + @include dialog-theme.typography($config); } // @deprecated Use `all-legacy-component-typographies`. diff --git a/src/material-experimental/mdc-dialog/BUILD.bazel b/src/material/legacy-dialog/BUILD.bazel similarity index 68% rename from src/material-experimental/mdc-dialog/BUILD.bazel rename to src/material/legacy-dialog/BUILD.bazel index e59983db90e4..dc70d25253ad 100644 --- a/src/material-experimental/mdc-dialog/BUILD.bazel +++ b/src/material/legacy-dialog/BUILD.bazel @@ -1,6 +1,7 @@ load("//src/e2e-app:test_suite.bzl", "e2e_test_suite") load( "//tools:defaults.bzl", + "markdown_to_html", "ng_e2e_test_library", "ng_module", "ng_test_library", @@ -12,57 +13,54 @@ load( package(default_visibility = ["//visibility:public"]) ng_module( - name = "mdc-dialog", + name = "legacy-dialog", srcs = glob( ["**/*.ts"], exclude = ["**/*.spec.ts"], ), - assets = [":dialog_scss"] + glob(["**/*.html"]), + assets = [":dialog.css"] + glob(["**/*.html"]), deps = [ + "//src:dev_mode_types", + "//src/cdk/a11y", + "//src/cdk/bidi", + "//src/cdk/dialog", + "//src/cdk/keycodes", "//src/cdk/overlay", + "//src/cdk/platform", "//src/cdk/portal", "//src/material/core", "//src/material/dialog", - "@npm//@material/dialog", + "@npm//@angular/animations", + "@npm//@angular/core", + "@npm//rxjs", ], ) sass_library( - name = "mdc_dialog_scss_lib", + name = "legacy_dialog_scss_lib", srcs = glob(["**/_*.scss"]), - deps = [ - "//:mdc_sass_lib", - "//src/material:sass_lib", - "//src/material/core:core_scss_lib", - ], + deps = ["//src/material/core:core_scss_lib"], ) sass_binary( name = "dialog_scss", src = "dialog.scss", deps = [ - ":mdc_dialog_scss_lib", - "//:mdc_sass_lib", - "//src/material:sass_lib", + "//src/cdk:sass_lib", "//src/material/core:core_scss_lib", ], ) -########### -# Testing -########### - ng_test_library( - name = "dialog_tests_lib", + name = "unit_test_sources", srcs = glob( ["**/*.spec.ts"], exclude = ["**/*.e2e.spec.ts"], ), deps = [ - ":mdc-dialog", + ":legacy-dialog", "//src/cdk/a11y", "//src/cdk/bidi", - "//src/cdk/dialog", "//src/cdk/keycodes", "//src/cdk/overlay", "//src/cdk/platform", @@ -70,16 +68,13 @@ ng_test_library( "//src/cdk/testing/private", "@npm//@angular/common", "@npm//@angular/platform-browser", - "@npm//@material/dialog", "@npm//rxjs", ], ) ng_web_test_suite( name = "unit_tests", - deps = [ - ":dialog_tests_lib", - ], + deps = [":unit_test_sources"], ) ng_e2e_test_library( @@ -97,3 +92,13 @@ e2e_test_suite( "//src/cdk/testing/private/e2e", ], ) + +markdown_to_html( + name = "overview", + srcs = [":dialog.md"], +) + +filegroup( + name = "source-files", + srcs = glob(["**/*.ts"]), +) diff --git a/src/material/legacy-dialog/README.md b/src/material/legacy-dialog/README.md new file mode 100644 index 000000000000..b4753f6be5b7 --- /dev/null +++ b/src/material/legacy-dialog/README.md @@ -0,0 +1 @@ +Please see the official documentation at https://material.angular.io/components/component/dialog diff --git a/src/material/legacy-dialog/_dialog-legacy-index.scss b/src/material/legacy-dialog/_dialog-legacy-index.scss new file mode 100644 index 000000000000..9beac18f936a --- /dev/null +++ b/src/material/legacy-dialog/_dialog-legacy-index.scss @@ -0,0 +1,2 @@ +@forward 'dialog-theme' hide color, theme, typography; +@forward 'dialog-theme' as mat-legacy-dialog-* hide mat-legacy-dialog-density; diff --git a/src/material/legacy-dialog/_dialog-theme.import.scss b/src/material/legacy-dialog/_dialog-theme.import.scss new file mode 100644 index 000000000000..49ada2d16c1e --- /dev/null +++ b/src/material/legacy-dialog/_dialog-theme.import.scss @@ -0,0 +1,10 @@ +@forward '../core/style/private.import'; +@forward '../core/theming/theming.import'; +@forward '../core/typography/typography-utils.import'; +@forward 'dialog-theme' hide color, theme, typography; +@forward 'dialog-theme' as mat-legacy-dialog-* hide mat-legacy-dialog-density; + +@import '../core/style/private'; +@import '../core/theming/palette'; +@import '../core/theming/theming'; +@import '../core/typography/typography-utils'; diff --git a/src/material/legacy-dialog/_dialog-theme.scss b/src/material/legacy-dialog/_dialog-theme.scss new file mode 100644 index 000000000000..2272c8eaae88 --- /dev/null +++ b/src/material/legacy-dialog/_dialog-theme.scss @@ -0,0 +1,47 @@ +@use 'sass:map'; +@use '../core/style/private'; +@use '../core/theming/theming'; +@use '../core/typography/typography'; +@use '../core/typography/typography-utils'; + + +@mixin color($config-or-theme) { + $config: theming.get-color-config($config-or-theme); + $background: map.get($config, background); + $foreground: map.get($config, foreground); + + .mat-dialog-container { + @include private.private-theme-elevation(24, $config); + background: theming.get-color-from-palette($background, dialog); + color: theming.get-color-from-palette($foreground, text); + } +} + +@mixin typography($config-or-theme) { + $config: typography.private-typography-to-2014-config( + theming.get-typography-config($config-or-theme)); + .mat-dialog-title { + @include typography-utils.typography-level($config, title); + } +} + +@mixin _density($config-or-theme) {} + +@mixin theme($theme-or-color-config) { + $theme: theming.private-legacy-get-theme($theme-or-color-config); + @include theming.private-check-duplicate-theme-styles($theme, 'mat-legacy-dialog') { + $color: theming.get-color-config($theme); + $density: theming.get-density-config($theme); + $typography: theming.get-typography-config($theme); + + @if $color != null { + @include color($color); + } + @if $density != null { + @include _density($density); + } + @if $typography != null { + @include typography($typography); + } + } +} diff --git a/src/material/legacy-dialog/dialog-animations.ts b/src/material/legacy-dialog/dialog-animations.ts new file mode 100644 index 000000000000..7ec6829deec7 --- /dev/null +++ b/src/material/legacy-dialog/dialog-animations.ts @@ -0,0 +1,15 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/** + * Default parameters for the animation for backwards compatibility. + * @docs-private + */ +export const defaultParams = { + params: {enterAnimationDuration: '150ms', exitAnimationDuration: '75ms'}, +}; diff --git a/src/material/legacy-dialog/dialog-container.html b/src/material/legacy-dialog/dialog-container.html new file mode 100644 index 000000000000..215f0d9c55b3 --- /dev/null +++ b/src/material/legacy-dialog/dialog-container.html @@ -0,0 +1 @@ + diff --git a/src/material/legacy-dialog/dialog-container.ts b/src/material/legacy-dialog/dialog-container.ts new file mode 100644 index 000000000000..c6d2e87134c1 --- /dev/null +++ b/src/material/legacy-dialog/dialog-container.ts @@ -0,0 +1,123 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {AnimationEvent} from '@angular/animations'; +import {FocusMonitor, FocusTrapFactory, InteractivityChecker} from '@angular/cdk/a11y'; +import {OverlayRef} from '@angular/cdk/overlay'; +import {DOCUMENT} from '@angular/common'; +import { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + Inject, + NgZone, + Optional, + ViewEncapsulation, +} from '@angular/core'; +import {defaultParams} from './dialog-animations'; +import { + _MatDialogContainerBase, + MatDialogConfig, + matDialogAnimations, +} from '@angular/material/dialog'; + +/** + * Internal component that wraps user-provided dialog content. + * Animation is based on https://material.io/guidelines/motion/choreography.html. + * @docs-private + */ +@Component({ + selector: 'mat-dialog-container', + templateUrl: 'dialog-container.html', + styleUrls: ['dialog.css'], + encapsulation: ViewEncapsulation.None, + // Using OnPush for dialogs caused some G3 sync issues. Disabled until we can track them down. + // tslint:disable-next-line:validate-decorators + changeDetection: ChangeDetectionStrategy.Default, + animations: [matDialogAnimations.dialogContainer], + host: { + 'class': 'mat-dialog-container', + 'tabindex': '-1', + '[attr.aria-modal]': '_config.ariaModal', + '[id]': '_config.id', + '[attr.role]': '_config.role', + '[attr.aria-labelledby]': '_config.ariaLabel ? null : _ariaLabelledBy', + '[attr.aria-label]': '_config.ariaLabel', + '[attr.aria-describedby]': '_config.ariaDescribedBy || null', + '[@dialogContainer]': `_getAnimationState()`, + '(@dialogContainer.start)': '_onAnimationStart($event)', + '(@dialogContainer.done)': '_onAnimationDone($event)', + }, +}) +export class MatLegacyDialogContainer extends _MatDialogContainerBase { + /** State of the dialog animation. */ + _state: 'void' | 'enter' | 'exit' = 'enter'; + + /** Callback, invoked whenever an animation on the host completes. */ + _onAnimationDone({toState, totalTime}: AnimationEvent) { + if (toState === 'enter') { + this._openAnimationDone(totalTime); + } else if (toState === 'exit') { + this._animationStateChanged.next({state: 'closed', totalTime}); + } + } + + /** Callback, invoked when an animation on the host starts. */ + _onAnimationStart({toState, totalTime}: AnimationEvent) { + if (toState === 'enter') { + this._animationStateChanged.next({state: 'opening', totalTime}); + } else if (toState === 'exit' || toState === 'void') { + this._animationStateChanged.next({state: 'closing', totalTime}); + } + } + + /** Starts the dialog exit animation. */ + _startExitAnimation(): void { + this._state = 'exit'; + + // Mark the container for check so it can react if the + // view container is using OnPush change detection. + this._changeDetectorRef.markForCheck(); + } + + constructor( + elementRef: ElementRef, + focusTrapFactory: FocusTrapFactory, + @Optional() @Inject(DOCUMENT) document: any, + dialogConfig: MatDialogConfig, + checker: InteractivityChecker, + ngZone: NgZone, + overlayRef: OverlayRef, + private _changeDetectorRef: ChangeDetectorRef, + focusMonitor?: FocusMonitor, + ) { + super( + elementRef, + focusTrapFactory, + document, + dialogConfig, + checker, + ngZone, + overlayRef, + focusMonitor, + ); + } + + _getAnimationState() { + return { + value: this._state, + params: { + 'enterAnimationDuration': + this._config.enterAnimationDuration || defaultParams.params.enterAnimationDuration, + 'exitAnimationDuration': + this._config.exitAnimationDuration || defaultParams.params.exitAnimationDuration, + }, + }; + } +} diff --git a/src/material-experimental/mdc-dialog/dialog-content-directives.ts b/src/material/legacy-dialog/dialog-content-directives.ts similarity index 73% rename from src/material-experimental/mdc-dialog/dialog-content-directives.ts rename to src/material/legacy-dialog/dialog-content-directives.ts index 56ca6a06c6ad..e4f08a5b1fdf 100644 --- a/src/material-experimental/mdc-dialog/dialog-content-directives.ts +++ b/src/material/legacy-dialog/dialog-content-directives.ts @@ -8,18 +8,17 @@ import { Directive, - ElementRef, Input, OnChanges, OnInit, Optional, SimpleChanges, + ElementRef, } from '@angular/core'; +import {MatLegacyDialog} from './dialog'; +import {MatLegacyDialogRef} from './dialog-ref'; import {_closeDialogVia} from '@angular/material/dialog'; -import {MatDialog} from './dialog'; -import {MatDialogRef} from './dialog-ref'; - /** Counter used to generate unique IDs for dialog elements. */ let dialogElementUid = 0; @@ -35,8 +34,8 @@ let dialogElementUid = 0; '[attr.type]': 'type', }, }) -export class MatDialogClose implements OnInit, OnChanges { - /** Screen-reader label for the button. */ +export class MatLegacyDialogClose implements OnInit, OnChanges { + /** Screen reader label for the button. */ @Input('aria-label') ariaLabel: string; /** Default to "button" to prevents accidental form submits. */ @@ -48,11 +47,16 @@ export class MatDialogClose implements OnInit, OnChanges { @Input('matDialogClose') _matDialogClose: any; constructor( + /** + * Reference to the containing dialog. + * @deprecated `dialogRef` property to become private. + * @breaking-change 13.0.0 + */ // The dialog title directive is always used in combination with a `MatDialogRef`. // tslint:disable-next-line: lightweight-tokens - @Optional() public dialogRef: MatDialogRef, + @Optional() public dialogRef: MatLegacyDialogRef, private _elementRef: ElementRef, - private _dialog: MatDialog, + private _dialog: MatLegacyDialog, ) {} ngOnInit() { @@ -94,19 +98,20 @@ export class MatDialogClose implements OnInit, OnChanges { selector: '[mat-dialog-title], [matDialogTitle]', exportAs: 'matDialogTitle', host: { - 'class': 'mat-mdc-dialog-title mdc-dialog__title', + 'class': 'mat-dialog-title', '[id]': 'id', }, }) -export class MatDialogTitle implements OnInit { - @Input() id: string = `mat-mdc-dialog-title-${dialogElementUid++}`; +export class MatLegacyDialogTitle implements OnInit { + /** Unique id for the dialog title. If none is supplied, it will be auto-generated. */ + @Input() id: string = `mat-dialog-title-${dialogElementUid++}`; constructor( // The dialog title directive is always used in combination with a `MatDialogRef`. // tslint:disable-next-line: lightweight-tokens - @Optional() private _dialogRef: MatDialogRef, + @Optional() private _dialogRef: MatLegacyDialogRef, private _elementRef: ElementRef, - private _dialog: MatDialog, + private _dialog: MatLegacyDialog, ) {} ngOnInit() { @@ -131,9 +136,9 @@ export class MatDialogTitle implements OnInit { */ @Directive({ selector: `[mat-dialog-content], mat-dialog-content, [matDialogContent]`, - host: {'class': 'mat-mdc-dialog-content mdc-dialog__content'}, + host: {'class': 'mat-dialog-content'}, }) -export class MatDialogContent {} +export class MatLegacyDialogContent {} /** * Container for the bottom action buttons in a dialog. @@ -142,27 +147,34 @@ export class MatDialogContent {} @Directive({ selector: `[mat-dialog-actions], mat-dialog-actions, [matDialogActions]`, host: { - 'class': 'mat-mdc-dialog-actions mdc-dialog__actions', - '[class.mat-mdc-dialog-actions-align-center]': 'align === "center"', - '[class.mat-mdc-dialog-actions-align-end]': 'align === "end"', + 'class': 'mat-dialog-actions', + '[class.mat-dialog-actions-align-center]': 'align === "center"', + '[class.mat-dialog-actions-align-end]': 'align === "end"', }, }) -export class MatDialogActions { +export class MatLegacyDialogActions { /** * Horizontal alignment of action buttons. */ @Input() align?: 'start' | 'center' | 'end' = 'start'; } +// TODO(crisbeto): this utility shouldn't be necessary anymore, because the dialog ref is provided +// both to component and template dialogs through DI. We need to keep it around, because there are +// some internal wrappers around `MatDialog` that happened to work by accident, because we had this +// fallback logic in place. /** * Finds the closest MatDialogRef to an element by looking at the DOM. * @param element Element relative to which to look for a dialog. * @param openDialogs References to the currently-open dialogs. */ -function getClosestDialog(element: ElementRef, openDialogs: MatDialogRef[]) { +function getClosestDialog( + element: ElementRef, + openDialogs: MatLegacyDialogRef[], +) { let parent: HTMLElement | null = element.nativeElement.parentElement; - while (parent && !parent.classList.contains('mat-mdc-dialog-container')) { + while (parent && !parent.classList.contains('mat-dialog-container')) { parent = parent.parentElement; } diff --git a/src/material/dialog/dialog-module.ts b/src/material/legacy-dialog/dialog-module.ts similarity index 50% rename from src/material/dialog/dialog-module.ts rename to src/material/legacy-dialog/dialog-module.ts index 0748d3b4a2d8..5d6bba3014d8 100644 --- a/src/material/dialog/dialog-module.ts +++ b/src/material/legacy-dialog/dialog-module.ts @@ -11,32 +11,32 @@ import {OverlayModule} from '@angular/cdk/overlay'; import {PortalModule} from '@angular/cdk/portal'; import {NgModule} from '@angular/core'; import {MatCommonModule} from '@angular/material/core'; -import {MAT_DIALOG_SCROLL_STRATEGY_PROVIDER, MatDialog} from './dialog'; -import {MatDialogContainer} from './dialog-container'; +import {MAT_LEGACY_DIALOG_SCROLL_STRATEGY_PROVIDER, MatLegacyDialog} from './dialog'; +import {MatLegacyDialogContainer} from './dialog-container'; import { - MatDialogActions, - MatDialogClose, - MatDialogContent, - MatDialogTitle, + MatLegacyDialogActions, + MatLegacyDialogClose, + MatLegacyDialogContent, + MatLegacyDialogTitle, } from './dialog-content-directives'; @NgModule({ imports: [DialogModule, OverlayModule, PortalModule, MatCommonModule], exports: [ - MatDialogContainer, - MatDialogClose, - MatDialogTitle, - MatDialogContent, - MatDialogActions, + MatLegacyDialogContainer, + MatLegacyDialogClose, + MatLegacyDialogTitle, + MatLegacyDialogContent, + MatLegacyDialogActions, MatCommonModule, ], declarations: [ - MatDialogContainer, - MatDialogClose, - MatDialogTitle, - MatDialogActions, - MatDialogContent, + MatLegacyDialogContainer, + MatLegacyDialogClose, + MatLegacyDialogTitle, + MatLegacyDialogActions, + MatLegacyDialogContent, ], - providers: [MatDialog, MAT_DIALOG_SCROLL_STRATEGY_PROVIDER], + providers: [MatLegacyDialog, MAT_LEGACY_DIALOG_SCROLL_STRATEGY_PROVIDER], }) -export class MatDialogModule {} +export class MatLegacyDialogModule {} diff --git a/src/material-experimental/mdc-dialog/dialog-ref.ts b/src/material/legacy-dialog/dialog-ref.ts similarity index 65% rename from src/material-experimental/mdc-dialog/dialog-ref.ts rename to src/material/legacy-dialog/dialog-ref.ts index 4dc4ecc23236..4c40b29d2777 100644 --- a/src/material-experimental/mdc-dialog/dialog-ref.ts +++ b/src/material/legacy-dialog/dialog-ref.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {MatDialogRef as NonMdcDialogRef} from '@angular/material/dialog'; +import {MatDialogRef as NewDialogRef} from '@angular/material/dialog'; /** * Reference to a dialog opened via the MatDialog service. */ -export class MatDialogRef extends NonMdcDialogRef {} +export class MatLegacyDialogRef extends NewDialogRef {} diff --git a/src/material-experimental/mdc-dialog/dialog.e2e.spec.ts b/src/material/legacy-dialog/dialog.e2e.spec.ts similarity index 96% rename from src/material-experimental/mdc-dialog/dialog.e2e.spec.ts rename to src/material/legacy-dialog/dialog.e2e.spec.ts index 3a45ec94fabd..0522de27a7e2 100644 --- a/src/material-experimental/mdc-dialog/dialog.e2e.spec.ts +++ b/src/material/legacy-dialog/dialog.e2e.spec.ts @@ -1,14 +1,14 @@ +import {browser, by, element, Key} from 'protractor'; import { - clickElementAtPoint, - expectFocusOn, expectToExist, + expectFocusOn, pressKeys, + clickElementAtPoint, waitForElement, } from '../../cdk/testing/private/e2e'; -import {browser, by, element, Key} from 'protractor'; -describe('MDC-based dialog', () => { - beforeEach(async () => await browser.get('/mdc-dialog')); +describe('dialog', () => { + beforeEach(async () => await browser.get('/dialog')); it('should open a dialog', async () => { await element(by.id('default')).click(); diff --git a/src/material/legacy-dialog/dialog.md b/src/material/legacy-dialog/dialog.md new file mode 100644 index 000000000000..8825ab5a7647 --- /dev/null +++ b/src/material/legacy-dialog/dialog.md @@ -0,0 +1,173 @@ +The `MatDialog` service can be used to open modal dialogs with Material Design styling and +animations. + + + +A dialog is opened by calling the `open` method with a component to be loaded and an optional +config object. The `open` method will return an instance of `MatDialogRef`: + +```ts +let dialogRef = dialog.open(UserProfileComponent, { + height: '400px', + width: '600px', +}); +``` + +The `MatDialogRef` provides a handle on the opened dialog. It can be used to close the dialog and to +receive notifications when the dialog has been closed. Any notification Observables will complete when the dialog closes. + +```ts +dialogRef.afterClosed().subscribe(result => { + console.log(`Dialog result: ${result}`); // Pizza! +}); + +dialogRef.close('Pizza!'); +``` + +Components created via `MatDialog` can _inject_ `MatDialogRef` and use it to close the dialog +in which they are contained. When closing, an optional result value can be provided. This result +value is forwarded as the result of the `afterClosed` Observable. + +```ts +@Component({/* ... */}) +export class YourDialog { + constructor(public dialogRef: MatDialogRef) { } + + closeDialog() { + this.dialogRef.close('Pizza!'); + } +} +``` + +### Specifying global configuration defaults +Default dialog options can be specified by providing an instance of `MatDialogConfig` for +MAT_DIALOG_DEFAULT_OPTIONS in your application's root module. + +```ts +@NgModule({ + providers: [ + {provide: MAT_DIALOG_DEFAULT_OPTIONS, useValue: {hasBackdrop: false}} + ] +}) +``` + +### Sharing data with the Dialog component. +If you want to share data with your dialog, you can use the `data` +option to pass information to the dialog component. + +```ts +let dialogRef = dialog.open(YourDialog, { + data: { name: 'austin' }, +}); +``` + +To access the data in your dialog component, you have to use the MAT_DIALOG_DATA injection token: + +```ts +import {Component, Inject} from '@angular/core'; +import {MAT_DIALOG_DATA} from '@angular/material/legacy-dialog'; + +@Component({ + selector: 'your-dialog', + template: 'passed in {{ data.name }}', +}) +export class YourDialog { + constructor(@Inject(MAT_DIALOG_DATA) public data: {name: string}) { } +} +``` + +Note that if you're using a template dialog (one that was opened with a `TemplateRef`), the data +will be available implicitly in the template: + +```html + + Hello, {{data.name}} + +``` + + + +### Dialog content +Several directives are available to make it easier to structure your dialog content: + +| Name | Description | +|------------------------|---------------------------------------------------------------------------------------------------------------| +| `mat-dialog-title` | \[Attr] Dialog title, applied to a heading element (e.g., `

`, `

`) | +| `` | Primary scrollable content of the dialog. | +| `` | Container for action buttons at the bottom of the dialog. Button alignment can be controlled via the `align` attribute which can be set to `end` and `center`. | +| `mat-dialog-close` | \[Attr] Added to a ` + + + +``` + +Once a dialog opens, the dialog will automatically focus the first tabbable element. + +You can control which elements are tab stops with the `tabindex` attribute + +```html + +``` + + + +### Controlling the dialog animation +You can control the duration of the dialog's enter and exit animations using the +`enterAnimationDuration` and `exitAnimationDuration` options. If you want to disable the dialog's +animation completely, you can do so by setting the properties to `0ms`. + + + +### Accessibility + +`MatDialog` creates modal dialogs that implements the ARIA `role="dialog"` pattern by default. +You can change the dialog's role to `alertdialog` via `MatDialogConfig`. + +You should provide an accessible label to this root dialog element by setting the `ariaLabel` or +`ariaLabelledBy` properties of `MatDialogConfig`. You can additionally specify a description element +ID via the `ariaDescribedBy` property of `MatDialogConfig`. + +#### Keyboard interaction +By default, the escape key closes `MatDialog`. While you can disable this behavior via +the `disableClose` property of `MatDialogConfig`, doing this breaks the expected interaction +pattern for the ARIA `role="dialog"` pattern. + +#### Focus management + +When opened, `MatDialog` traps browser focus such that it cannot escape the root +`role="dialog"` element. By default, the first tabbable element in the dialog receives focus. +You can customize which element receives focus with the `autoFocus` property of +`MatDialogConfig`, which supports the following values. + +| Value | Behavior | +|------------------|--------------------------------------------------------------------------| +| `first-tabbable` | Focus the first tabbable element. This is the default setting. | +| `first-header` | Focus the first header element (`role="heading"`, `h1` through `h6`) | +| `dialog` | Focus the root `role="dialog"` element. | +| Any CSS selector | Focus the first element matching the given selector. | + +While the default setting applies the best behavior for most applications, special cases may benefit +from these alternatives. Always test your application to verify the behavior that works best for +your users. + +#### Focus restoration + +When closed, `MatDialog` restores focus to the element that previously held focus when the +dialog opened. However, if that previously focused element no longer exists, you must +add additional handling to return focus to an element that makes sense for the user's workflow. +Opening a dialog from a menu is one common pattern that causes this situation. The menu +closes upon clicking an item, thus the focused menu item is no longer in the DOM when the bottom +sheet attempts to restore focus. + +You can add handling for this situation with the `afterClosed()` observable from `MatDialogRef`. + + diff --git a/src/material/legacy-dialog/dialog.scss b/src/material/legacy-dialog/dialog.scss new file mode 100644 index 000000000000..ce35574db15e --- /dev/null +++ b/src/material/legacy-dialog/dialog.scss @@ -0,0 +1,76 @@ +@use '@angular/cdk'; + +$padding: 24px !default; +$border-radius: 4px !default; +$max-height: 65vh !default; +$button-margin: 8px !default; + +.mat-dialog-container { + display: block; + padding: $padding; + border-radius: $border-radius; + box-sizing: border-box; + overflow: auto; + outline: 0; + + // The dialog container should completely fill its parent overlay element. + width: 100%; + height: 100%; + + // Since the dialog won't stretch to fit the parent, if the height + // isn't set, we have to inherit the min and max values explicitly. + min-height: inherit; + max-height: inherit; + + @include cdk.high-contrast(active, off) { + outline: solid 1px; + } +} + +.mat-dialog-content { + display: block; + margin: 0 $padding * -1; + padding: 0 $padding; + max-height: $max-height; + overflow: auto; + -webkit-overflow-scrolling: touch; +} + +.mat-dialog-title { + margin: 0 0 20px; + display: block; +} + +.mat-dialog-actions { + padding: 8px 0; + display: flex; + flex-wrap: wrap; + min-height: 52px; + align-items: center; + + // Explicitly set a box-sizing since people commonly set `border-box` + // on all elements which will break the height of the dialog actions. + box-sizing: content-box; + + // Pull the actions down to avoid their padding stacking with the dialog's padding. + margin-bottom: -$padding; + + // .mat-dialog-actions-align-{center|end} are set by directive input "align" + // [align='center'] and [align='right'] are kept for backwards compability + &.mat-dialog-actions-align-center, &[align='center'] { + justify-content: center; + } + &.mat-dialog-actions-align-end, &[align='end'] { + justify-content: flex-end; + } + + .mat-button-base + .mat-button-base, + .mat-mdc-button-base + .mat-mdc-button-base { + margin-left: $button-margin; + + [dir='rtl'] & { + margin-left: 0; + margin-right: $button-margin; + } + } +} diff --git a/src/material-experimental/mdc-dialog/dialog.spec.ts b/src/material/legacy-dialog/dialog.spec.ts similarity index 81% rename from src/material-experimental/mdc-dialog/dialog.spec.ts rename to src/material/legacy-dialog/dialog.spec.ts index a0c383ab7b3e..aafa91587728 100644 --- a/src/material-experimental/mdc-dialog/dialog.spec.ts +++ b/src/material/legacy-dialog/dialog.spec.ts @@ -1,58 +1,57 @@ import {FocusMonitor, FocusOrigin} from '@angular/cdk/a11y'; -import {Directionality} from '@angular/cdk/bidi'; -import {A, ESCAPE} from '@angular/cdk/keycodes'; -import {Overlay, OverlayContainer, ScrollStrategy} from '@angular/cdk/overlay'; -import {_supportsShadowDom} from '@angular/cdk/platform'; -import {ScrollDispatcher} from '@angular/cdk/scrolling'; import { - createKeyboardEvent, - dispatchEvent, - dispatchKeyboardEvent, - dispatchMouseEvent, - patchElementFocus, -} from '../../cdk/testing/private'; -import {Location} from '@angular/common'; -import {SpyLocation} from '@angular/common/testing'; + ComponentFixture, + fakeAsync, + flushMicrotasks, + inject, + TestBed, + tick, + flush, +} from '@angular/core/testing'; import { ChangeDetectionStrategy, Component, - ComponentFactoryResolver, - createNgModuleRef, Directive, Inject, - Injectable, Injector, - NgModule, - NgZone, TemplateRef, ViewChild, ViewContainerRef, + ComponentFactoryResolver, + NgZone, ViewEncapsulation, + Injectable, + NgModule, + createNgModuleRef, } from '@angular/core'; -import { - ComponentFixture, - fakeAsync, - flush, - flushMicrotasks, - inject, - TestBed, - tick, -} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations'; -import {numbers} from '@material/dialog'; -import {Subject} from 'rxjs'; +import {Location} from '@angular/common'; +import {SpyLocation} from '@angular/common/testing'; +import {Directionality} from '@angular/cdk/bidi'; +import {_supportsShadowDom} from '@angular/cdk/platform'; +import {MatLegacyDialogContainer} from './dialog-container'; +import {OverlayContainer, ScrollStrategy, Overlay} from '@angular/cdk/overlay'; +import {ScrollDispatcher} from '@angular/cdk/scrolling'; +import {A, ESCAPE} from '@angular/cdk/keycodes'; import { - MatDialog, - MatDialogModule, - MatDialogRef, - MatDialogState, - MAT_DIALOG_DATA, - MAT_DIALOG_DEFAULT_OPTIONS, + dispatchKeyboardEvent, + createKeyboardEvent, + dispatchEvent, + patchElementFocus, + dispatchMouseEvent, +} from '../../cdk/testing/private'; +import { + MAT_LEGACY_DIALOG_DATA, + MatLegacyDialog, + MatLegacyDialogModule, + MAT_LEGACY_DIALOG_DEFAULT_OPTIONS, } from './index'; +import {Subject} from 'rxjs'; +import {MatLegacyDialogRef, MatLegacyDialogState} from '@angular/material/legacy-dialog'; -describe('MDC-based MatDialog', () => { - let dialog: MatDialog; +describe('MatDialog', () => { + let dialog: MatLegacyDialog; let overlayContainerElement: HTMLElement; let scrolledSubject = new Subject(); let focusMonitor: FocusMonitor; @@ -63,7 +62,7 @@ describe('MDC-based MatDialog', () => { beforeEach(fakeAsync(() => { TestBed.configureTestingModule({ - imports: [MatDialogModule, NoopAnimationsModule], + imports: [MatLegacyDialogModule, NoopAnimationsModule], declarations: [ ComponentWithChildViewContainer, ComponentWithTemplateRef, @@ -78,7 +77,9 @@ describe('MDC-based MatDialog', () => { {provide: Location, useClass: SpyLocation}, { provide: ScrollDispatcher, - useFactory: () => ({scrolled: () => scrolledSubject}), + useFactory: () => ({ + scrolled: () => scrolledSubject, + }), }, ], }); @@ -87,8 +88,8 @@ describe('MDC-based MatDialog', () => { })); beforeEach(inject( - [MatDialog, Location, OverlayContainer, FocusMonitor], - (d: MatDialog, l: Location, oc: OverlayContainer, fm: FocusMonitor) => { + [MatLegacyDialog, Location, OverlayContainer, FocusMonitor], + (d: MatLegacyDialog, l: Location, oc: OverlayContainer, fm: FocusMonitor) => { dialog = d; mockLocation = l as SpyLocation; overlayContainerElement = oc.getContainerElement(); @@ -104,7 +105,9 @@ describe('MDC-based MatDialog', () => { }); it('should open a dialog with a component', () => { - let dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); + const dialogRef = dialog.open(PizzaMsg, { + viewContainerRef: testViewContainerRef, + }); viewContainerFixture.detectChanges(); @@ -113,7 +116,7 @@ describe('MDC-based MatDialog', () => { expect(dialogRef.componentInstance.dialogRef).toBe(dialogRef); viewContainerFixture.detectChanges(); - let dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; + const dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; expect(dialogContainerElement.getAttribute('role')).toBe('dialog'); }); @@ -124,7 +127,7 @@ describe('MDC-based MatDialog', () => { const data = {value: 'Knees'}; - let dialogRef = dialog.open(templateRefFixture.componentInstance.templateRef, {data}); + const dialogRef = dialog.open(templateRefFixture.componentInstance.templateRef, {data}); viewContainerFixture.detectChanges(); @@ -133,7 +136,7 @@ describe('MDC-based MatDialog', () => { viewContainerFixture.detectChanges(); - let dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; + const dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; expect(dialogContainerElement.getAttribute('role')).toBe('dialog'); dialogRef.close(); @@ -155,23 +158,22 @@ describe('MDC-based MatDialog', () => { })); it('should use injector from viewContainerRef for DialogInjector', () => { - let dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); + const dialogRef = dialog.open(PizzaMsg, { + viewContainerRef: testViewContainerRef, + }); viewContainerFixture.detectChanges(); - let dialogInjector = dialogRef.componentInstance.dialogInjector; + const dialogInjector = dialogRef.componentInstance.dialogInjector; expect(dialogRef.componentInstance.dialogRef).toBe(dialogRef); - expect(dialogInjector.get(DirectiveWithViewContainer)) - .withContext( - 'Expected the dialog component to be created with the injector from ' + - 'the viewContainerRef.', - ) - .toBeTruthy(); + expect(dialogInjector.get(DirectiveWithViewContainer)).toBeTruthy( + 'Expected the dialog component to be created with the injector from the viewContainerRef.', + ); }); it('should open a dialog with a component and no ViewContainerRef', () => { - let dialogRef = dialog.open(PizzaMsg); + const dialogRef = dialog.open(PizzaMsg); viewContainerFixture.detectChanges(); @@ -180,7 +182,7 @@ describe('MDC-based MatDialog', () => { expect(dialogRef.componentInstance.dialogRef).toBe(dialogRef); viewContainerFixture.detectChanges(); - let dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; + const dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; expect(dialogContainerElement.getAttribute('role')).toBe('dialog'); }); @@ -189,7 +191,7 @@ describe('MDC-based MatDialog', () => { viewContainerFixture.detectChanges(); - let dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; + const dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; expect(dialogContainerElement.getAttribute('role')).toBe('alertdialog'); }); @@ -198,13 +200,13 @@ describe('MDC-based MatDialog', () => { viewContainerFixture.detectChanges(); - let dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; + const dialogContainerElement = overlayContainerElement.querySelector('mat-dialog-container')!; expect(dialogContainerElement.getAttribute('aria-describedby')).toBe('description-element'); }); it('should close a dialog and get back a result', fakeAsync(() => { - let dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); - let afterCloseCallback = jasmine.createSpy('afterClose callback'); + const dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); + const afterCloseCallback = jasmine.createSpy('afterClose callback'); dialogRef.afterClosed().subscribe(afterCloseCallback); dialogRef.close('Charmander'); @@ -292,7 +294,9 @@ describe('MDC-based MatDialog', () => { })); it('should close a dialog via the escape key', fakeAsync(() => { - dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); + dialog.open(PizzaMsg, { + viewContainerRef: testViewContainerRef, + }); const event = dispatchKeyboardEvent(document.body, 'keydown', ESCAPE); viewContainerFixture.detectChanges(); @@ -303,7 +307,9 @@ describe('MDC-based MatDialog', () => { })); it('should not close a dialog via the escape key with a modifier', fakeAsync(() => { - dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); + dialog.open(PizzaMsg, { + viewContainerRef: testViewContainerRef, + }); const event = createKeyboardEvent('keydown', ESCAPE, undefined, {alt: true}); dispatchEvent(document.body, event); @@ -342,11 +348,13 @@ describe('MDC-based MatDialog', () => { })); it('should close when clicking on the overlay backdrop', fakeAsync(() => { - dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); + dialog.open(PizzaMsg, { + viewContainerRef: testViewContainerRef, + }); viewContainerFixture.detectChanges(); - let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; + const backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; backdrop.click(); viewContainerFixture.detectChanges(); @@ -356,14 +364,16 @@ describe('MDC-based MatDialog', () => { })); it('should emit the backdropClick stream when clicking on the overlay backdrop', fakeAsync(() => { - const dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); + const dialogRef = dialog.open(PizzaMsg, { + viewContainerRef: testViewContainerRef, + }); const spy = jasmine.createSpy('backdropClick spy'); dialogRef.backdropClick().subscribe(spy); viewContainerFixture.detectChanges(); - let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; + const backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; backdrop.click(); expect(spy).toHaveBeenCalledTimes(1); @@ -384,8 +394,8 @@ describe('MDC-based MatDialog', () => { viewContainerFixture.detectChanges(); - let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; - let container = overlayContainerElement.querySelector('mat-dialog-container') as HTMLElement; + const backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; + const container = overlayContainerElement.querySelector('mat-dialog-container') as HTMLElement; dispatchKeyboardEvent(document.body, 'keydown', A); dispatchKeyboardEvent(backdrop, 'keydown', A); dispatchKeyboardEvent(container, 'keydown', A); @@ -395,7 +405,11 @@ describe('MDC-based MatDialog', () => { it('should notify the observers if a dialog has been opened', () => { dialog.afterOpened.subscribe(ref => { - expect(dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef})).toBe(ref); + expect( + dialog.open(PizzaMsg, { + viewContainerRef: testViewContainerRef, + }), + ).toBe(ref); }); }); @@ -427,31 +441,37 @@ describe('MDC-based MatDialog', () => { }); it('should override the width of the overlay pane', () => { - dialog.open(PizzaMsg, {width: '500px'}); + dialog.open(PizzaMsg, { + width: '500px', + }); viewContainerFixture.detectChanges(); - let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.width).toBe('500px'); }); it('should override the height of the overlay pane', () => { - dialog.open(PizzaMsg, {height: '100px'}); + dialog.open(PizzaMsg, { + height: '100px', + }); viewContainerFixture.detectChanges(); - let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.height).toBe('100px'); }); it('should override the min-width of the overlay pane', () => { - dialog.open(PizzaMsg, {minWidth: '500px'}); + dialog.open(PizzaMsg, { + minWidth: '500px', + }); viewContainerFixture.detectChanges(); - let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.minWidth).toBe('500px'); }); @@ -473,7 +493,9 @@ describe('MDC-based MatDialog', () => { viewContainerFixture.detectChanges(); flushMicrotasks(); - dialogRef = dialog.open(PizzaMsg, {maxWidth: '100px'}); + dialogRef = dialog.open(PizzaMsg, { + maxWidth: '100px', + }); viewContainerFixture.detectChanges(); @@ -483,71 +505,95 @@ describe('MDC-based MatDialog', () => { })); it('should override the min-height of the overlay pane', () => { - dialog.open(PizzaMsg, {minHeight: '300px'}); + dialog.open(PizzaMsg, { + minHeight: '300px', + }); viewContainerFixture.detectChanges(); - let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.minHeight).toBe('300px'); }); it('should override the max-height of the overlay pane', () => { - dialog.open(PizzaMsg, {maxHeight: '100px'}); + dialog.open(PizzaMsg, { + maxHeight: '100px', + }); viewContainerFixture.detectChanges(); - let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.maxHeight).toBe('100px'); }); it('should override the top offset of the overlay pane', () => { - dialog.open(PizzaMsg, {position: {top: '100px'}}); + dialog.open(PizzaMsg, { + position: { + top: '100px', + }, + }); viewContainerFixture.detectChanges(); - let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.marginTop).toBe('100px'); }); it('should override the bottom offset of the overlay pane', () => { - dialog.open(PizzaMsg, {position: {bottom: '200px'}}); + dialog.open(PizzaMsg, { + position: { + bottom: '200px', + }, + }); viewContainerFixture.detectChanges(); - let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.marginBottom).toBe('200px'); }); it('should override the left offset of the overlay pane', () => { - dialog.open(PizzaMsg, {position: {left: '250px'}}); + dialog.open(PizzaMsg, { + position: { + left: '250px', + }, + }); viewContainerFixture.detectChanges(); - let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.marginLeft).toBe('250px'); }); it('should override the right offset of the overlay pane', () => { - dialog.open(PizzaMsg, {position: {right: '125px'}}); + dialog.open(PizzaMsg, { + position: { + right: '125px', + }, + }); viewContainerFixture.detectChanges(); - let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.marginRight).toBe('125px'); }); it('should allow for the position to be updated', () => { - let dialogRef = dialog.open(PizzaMsg, {position: {left: '250px'}}); + const dialogRef = dialog.open(PizzaMsg, { + position: { + left: '250px', + }, + }); viewContainerFixture.detectChanges(); - let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.marginLeft).toBe('250px'); @@ -557,11 +603,11 @@ describe('MDC-based MatDialog', () => { }); it('should allow for the dimensions to be updated', () => { - let dialogRef = dialog.open(PizzaMsg, {width: '100px'}); + const dialogRef = dialog.open(PizzaMsg, {width: '100px'}); viewContainerFixture.detectChanges(); - let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.width).toBe('100px'); @@ -571,11 +617,11 @@ describe('MDC-based MatDialog', () => { }); it('should reset the overlay dimensions to their initial size', () => { - let dialogRef = dialog.open(PizzaMsg); + const dialogRef = dialog.open(PizzaMsg); viewContainerFixture.detectChanges(); - let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.width).toBeFalsy(); expect(overlayPane.style.height).toBeFalsy(); @@ -596,7 +642,7 @@ describe('MDC-based MatDialog', () => { viewContainerFixture.detectChanges(); - let overlayPane = overlayContainerElement.querySelector('.cdk-global-overlay-wrapper')!; + const overlayPane = overlayContainerElement.querySelector('.cdk-global-overlay-wrapper')!; expect(overlayPane.getAttribute('dir')).toBe('rtl'); }); @@ -646,6 +692,19 @@ describe('MDC-based MatDialog', () => { expect(overlayContainerElement.querySelectorAll('mat-dialog-container').length).toBe(0); })); + it('should set the proper animation states', () => { + const dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); + const dialogContainer: MatLegacyDialogContainer = viewContainerFixture.debugElement.query( + By.directive(MatLegacyDialogContainer), + )!.componentInstance; + + expect(dialogContainer._state).toBe('enter'); + + dialogRef.close(); + + expect(dialogContainer._state).toBe('exit'); + }); + it('should close all dialogs when the user goes forwards/backwards in history', fakeAsync(() => { dialog.open(PizzaMsg); dialog.open(PizzaMsg); @@ -717,8 +776,8 @@ describe('MDC-based MatDialog', () => { })); it('should have the componentInstance available in the afterClosed callback', fakeAsync(() => { - let dialogRef = dialog.open(PizzaMsg); - let spy = jasmine.createSpy('afterClosed spy'); + const dialogRef = dialog.open(PizzaMsg); + const spy = jasmine.createSpy('afterClosed spy'); flushMicrotasks(); viewContainerFixture.detectChanges(); @@ -769,9 +828,14 @@ describe('MDC-based MatDialog', () => { describe('passing in data', () => { it('should be able to pass in data', () => { - let config = {data: {stringParam: 'hello', dateParam: new Date()}}; + const config = { + data: { + stringParam: 'hello', + dateParam: new Date(), + }, + }; - let instance = dialog.open(DialogWithInjectedData, config).componentInstance; + const instance = dialog.open(DialogWithInjectedData, config).componentInstance; expect(instance.data.stringParam).toBe(config.data.stringParam); expect(instance.data.dateParam).toBe(config.data.dateParam); @@ -779,14 +843,14 @@ describe('MDC-based MatDialog', () => { it('should default to null if no data is passed', () => { expect(() => { - let dialogRef = dialog.open(DialogWithInjectedData); + const dialogRef = dialog.open(DialogWithInjectedData); expect(dialogRef.componentInstance.data).toBeNull(); }).not.toThrow(); }); }); it('should not keep a reference to the component after the dialog is closed', fakeAsync(() => { - let dialogRef = dialog.open(PizzaMsg); + const dialogRef = dialog.open(PizzaMsg); expect(dialogRef.componentInstance).toBeTruthy(); @@ -799,14 +863,14 @@ describe('MDC-based MatDialog', () => { .toBeFalsy(); })); - it('should assign a unique id to each dialog', fakeAsync(() => { + it('should assign a unique id to each dialog', () => { const one = dialog.open(PizzaMsg); const two = dialog.open(PizzaMsg); expect(one.id).toBeTruthy(); expect(two.id).toBeTruthy(); expect(one.id).not.toBe(two.id); - })); + }); it('should allow for the id to be overwritten', () => { const dialogRef = dialog.open(PizzaMsg, {id: 'pizza'}); @@ -889,7 +953,7 @@ describe('MDC-based MatDialog', () => { })); it('should add and remove classes while open', () => { - let dialogRef = dialog.open(PizzaMsg, { + const dialogRef = dialog.open(PizzaMsg, { disableClose: true, viewContainerRef: testViewContainerRef, }); @@ -909,11 +973,16 @@ describe('MDC-based MatDialog', () => { describe('disableClose option', () => { it('should prevent closing via clicks on the backdrop', fakeAsync(() => { - dialog.open(PizzaMsg, {disableClose: true, viewContainerRef: testViewContainerRef}); + dialog.open(PizzaMsg, { + disableClose: true, + viewContainerRef: testViewContainerRef, + }); viewContainerFixture.detectChanges(); - let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; + const backdrop = overlayContainerElement.querySelector( + '.cdk-overlay-backdrop', + ) as HTMLElement; backdrop.click(); viewContainerFixture.detectChanges(); flush(); @@ -922,7 +991,10 @@ describe('MDC-based MatDialog', () => { })); it('should prevent closing via the escape key', fakeAsync(() => { - dialog.open(PizzaMsg, {disableClose: true, viewContainerRef: testViewContainerRef}); + dialog.open(PizzaMsg, { + disableClose: true, + viewContainerRef: testViewContainerRef, + }); viewContainerFixture.detectChanges(); dispatchKeyboardEvent(document.body, 'keydown', ESCAPE); @@ -933,14 +1005,16 @@ describe('MDC-based MatDialog', () => { })); it('should allow for the disableClose option to be updated while open', fakeAsync(() => { - let dialogRef = dialog.open(PizzaMsg, { + const dialogRef = dialog.open(PizzaMsg, { disableClose: true, viewContainerRef: testViewContainerRef, }); viewContainerFixture.detectChanges(); - let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; + const backdrop = overlayContainerElement.querySelector( + '.cdk-overlay-backdrop', + ) as HTMLElement; backdrop.click(); expect(overlayContainerElement.querySelector('mat-dialog-container')).toBeTruthy(); @@ -953,29 +1027,6 @@ describe('MDC-based MatDialog', () => { expect(overlayContainerElement.querySelector('mat-dialog-container')).toBeFalsy(); })); - it('should recapture focus when clicking on the backdrop', fakeAsync(() => { - dialog.open(PizzaMsg, {disableClose: true, viewContainerRef: testViewContainerRef}); - - viewContainerFixture.detectChanges(); - flushMicrotasks(); - - let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; - let input = overlayContainerElement.querySelector('input') as HTMLInputElement; - - expect(document.activeElement) - .withContext('Expected input to be focused on open') - .toBe(input); - - input.blur(); // Programmatic clicks might not move focus so we simulate it. - backdrop.click(); - viewContainerFixture.detectChanges(); - flush(); - - expect(document.activeElement) - .withContext('Expected input to stay focused after click') - .toBe(input); - })); - it( 'should recapture focus to the first tabbable element when clicking on the backdrop with ' + 'autoFocus set to "first-tabbable" (the default)', @@ -988,10 +1039,10 @@ describe('MDC-based MatDialog', () => { viewContainerFixture.detectChanges(); flushMicrotasks(); - let backdrop = overlayContainerElement.querySelector( + const backdrop = overlayContainerElement.querySelector( '.cdk-overlay-backdrop', ) as HTMLElement; - let input = overlayContainerElement.querySelector('input') as HTMLInputElement; + const input = overlayContainerElement.querySelector('input') as HTMLInputElement; expect(document.activeElement) .withContext('Expected input to be focused on open') @@ -1021,11 +1072,11 @@ describe('MDC-based MatDialog', () => { viewContainerFixture.detectChanges(); flushMicrotasks(); - let backdrop = overlayContainerElement.querySelector( + const backdrop = overlayContainerElement.querySelector( '.cdk-overlay-backdrop', ) as HTMLElement; - let container = overlayContainerElement.querySelector( - '.mat-mdc-dialog-container', + const container = overlayContainerElement.querySelector( + '.mat-dialog-container', ) as HTMLInputElement; expect(document.activeElement) @@ -1042,77 +1093,84 @@ describe('MDC-based MatDialog', () => { .toBe(container); }), ); - }); - it( - 'should recapture focus to the first header when clicking on the backdrop with ' + - 'autoFocus set to "first-heading"', - fakeAsync(() => { - dialog.open(ContentElementDialog, { - disableClose: true, - viewContainerRef: testViewContainerRef, - autoFocus: 'first-heading', - }); + it( + 'should recapture focus to the first header when clicking on the backdrop with ' + + 'autoFocus set to "first-heading"', + fakeAsync(() => { + dialog.open(ContentElementDialog, { + disableClose: true, + viewContainerRef: testViewContainerRef, + autoFocus: 'first-heading', + }); - viewContainerFixture.detectChanges(); - flushMicrotasks(); + viewContainerFixture.detectChanges(); + flushMicrotasks(); - let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; - let firstHeader = overlayContainerElement.querySelector( - '.mat-mdc-dialog-title[tabindex="-1"]', - ) as HTMLInputElement; + let backdrop = overlayContainerElement.querySelector( + '.cdk-overlay-backdrop', + ) as HTMLElement; + let firstHeader = overlayContainerElement.querySelector( + '.mat-dialog-title[tabindex="-1"]', + ) as HTMLInputElement; - expect(document.activeElement) - .withContext('Expected first header to be focused on open') - .toBe(firstHeader); + expect(document.activeElement) + .withContext('Expected first header to be focused on open') + .toBe(firstHeader); - firstHeader.blur(); // Programmatic clicks might not move focus so we simulate it. - backdrop.click(); - viewContainerFixture.detectChanges(); - flush(); + firstHeader.blur(); // Programmatic clicks might not move focus so we simulate it. + backdrop.click(); + viewContainerFixture.detectChanges(); + flush(); - expect(document.activeElement) - .withContext('Expected first header to stay focused after click') - .toBe(firstHeader); - }), - ); + expect(document.activeElement) + .withContext('Expected first header to stay focused after click') + .toBe(firstHeader); + }), + ); - it( - 'should recapture focus to the first element that matches the css selector when ' + - 'clicking on the backdrop with autoFocus set to a css selector', - fakeAsync(() => { - dialog.open(ContentElementDialog, { - disableClose: true, - viewContainerRef: testViewContainerRef, - autoFocus: 'button', - }); + it( + 'should recapture focus to the first element that matches the css selector when ' + + 'clicking on the backdrop with autoFocus set to a css selector', + fakeAsync(() => { + dialog.open(ContentElementDialog, { + disableClose: true, + viewContainerRef: testViewContainerRef, + autoFocus: 'button', + }); - viewContainerFixture.detectChanges(); - flushMicrotasks(); + viewContainerFixture.detectChanges(); + flushMicrotasks(); - let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; - let firstButton = overlayContainerElement.querySelector( - '[mat-dialog-close]', - ) as HTMLInputElement; + let backdrop = overlayContainerElement.querySelector( + '.cdk-overlay-backdrop', + ) as HTMLElement; + let firstButton = overlayContainerElement.querySelector( + '[mat-dialog-close]', + ) as HTMLInputElement; - expect(document.activeElement) - .withContext('Expected first button to be focused on open') - .toBe(firstButton); + expect(document.activeElement) + .withContext('Expected first button to be focused on open') + .toBe(firstButton); - firstButton.blur(); // Programmatic clicks might not move focus so we simulate it. - backdrop.click(); - viewContainerFixture.detectChanges(); - flush(); + firstButton.blur(); // Programmatic clicks might not move focus so we simulate it. + backdrop.click(); + viewContainerFixture.detectChanges(); + flush(); - expect(document.activeElement) - .withContext('Expected first button to stay focused after click') - .toBe(firstButton); - }), - ); + expect(document.activeElement) + .withContext('Expected first button to stay focused after click') + .toBe(firstButton); + }), + ); + }); describe('hasBackdrop option', () => { it('should have a backdrop', () => { - dialog.open(PizzaMsg, {hasBackdrop: true, viewContainerRef: testViewContainerRef}); + dialog.open(PizzaMsg, { + hasBackdrop: true, + viewContainerRef: testViewContainerRef, + }); viewContainerFixture.detectChanges(); @@ -1120,7 +1178,10 @@ describe('MDC-based MatDialog', () => { }); it('should not have a backdrop', () => { - dialog.open(PizzaMsg, {hasBackdrop: false, viewContainerRef: testViewContainerRef}); + dialog.open(PizzaMsg, { + hasBackdrop: false, + viewContainerRef: testViewContainerRef, + }); viewContainerFixture.detectChanges(); @@ -1143,7 +1204,10 @@ describe('MDC-based MatDialog', () => { describe('backdropClass option', () => { it('should have default backdrop class', () => { - dialog.open(PizzaMsg, {backdropClass: '', viewContainerRef: testViewContainerRef}); + dialog.open(PizzaMsg, { + backdropClass: '', + viewContainerRef: testViewContainerRef, + }); viewContainerFixture.detectChanges(); @@ -1168,7 +1232,9 @@ describe('MDC-based MatDialog', () => { afterEach(() => overlayContainerElement.remove()); it('should focus the first tabbable element of the dialog on open (the default)', fakeAsync(() => { - dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); + dialog.open(PizzaMsg, { + viewContainerRef: testViewContainerRef, + }); viewContainerFixture.detectChanges(); flushMicrotasks(); @@ -1188,7 +1254,7 @@ describe('MDC-based MatDialog', () => { flushMicrotasks(); let container = overlayContainerElement.querySelector( - '.mat-mdc-dialog-container', + '.mat-dialog-container', ) as HTMLInputElement; expect(document.activeElement) @@ -1235,7 +1301,7 @@ describe('MDC-based MatDialog', () => { it('should attach the focus trap even if automatic focus is disabled', fakeAsync(() => { dialog.open(PizzaMsg, { viewContainerRef: testViewContainerRef, - autoFocus: 'false', + autoFocus: false, }); viewContainerFixture.detectChanges(); @@ -1248,12 +1314,12 @@ describe('MDC-based MatDialog', () => { it('should re-focus trigger element when dialog closes', fakeAsync(() => { // Create a element that has focus before the dialog is opened. - let button = document.createElement('button'); + const button = document.createElement('button'); button.id = 'dialog-trigger'; document.body.appendChild(button); button.focus(); - let dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); + const dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); flushMicrotasks(); viewContainerFixture.detectChanges(); @@ -1267,7 +1333,7 @@ describe('MDC-based MatDialog', () => { dialogRef.close(); expect(document.activeElement!.id).not.toBe( 'dialog-trigger', - 'Expected the focus not to have changed before the animation finishes.', + 'Expcted the focus not to have changed before the animation finishes.', ); flushMicrotasks(); @@ -1317,16 +1383,14 @@ describe('MDC-based MatDialog', () => { button.focus(); // Patch the element focus after the initial and real focus, because otherwise the - // `activeElement` won't be set, and the dialog won't be able to restore focus to an - // element. + // `activeElement` won't be set, and the dialog won't be able to restore focus to an element. patchElementFocus(button); dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); tick(500); viewContainerFixture.detectChanges(); - flushMicrotasks(); - expect(lastFocusOrigin!).withContext('Expected the trigger button to be blurred').toBeNull(); + expect(lastFocusOrigin!).toBe('program'); dispatchKeyboardEvent(document.body, 'keydown', ESCAPE); @@ -1352,16 +1416,14 @@ describe('MDC-based MatDialog', () => { button.focus(); // Patch the element focus after the initial and real focus, because otherwise the - // `activeElement` won't be set, and the dialog won't be able to restore focus to an - // element. + // `activeElement` won't be set, and the dialog won't be able to restore focus to an element. patchElementFocus(button); dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); tick(500); viewContainerFixture.detectChanges(); - flushMicrotasks(); - expect(lastFocusOrigin!).withContext('Expected the trigger button to be blurred').toBeNull(); + expect(lastFocusOrigin!).toBe('program'); const backdrop = overlayContainerElement.querySelector( '.cdk-overlay-backdrop', @@ -1389,15 +1451,17 @@ describe('MDC-based MatDialog', () => { button.focus(); // Patch the element focus after the initial and real focus, because otherwise the - // `activeElement` won't be set, and the dialog won't be able to restore focus to an - // element. + // `activeElement` won't be set, and the dialog won't be able to restore focus to an element. patchElementFocus(button); + expect(lastFocusOrigin!) + .withContext('Expected the trigger button to be focused via program') + .toBe('program'); dialog.open(ContentElementDialog, {viewContainerRef: testViewContainerRef}); tick(500); viewContainerFixture.detectChanges(); - flushMicrotasks(); + tick(500); expect(lastFocusOrigin!).withContext('Expected the trigger button to be blurred').toBeNull(); const closeButton = overlayContainerElement.querySelector( @@ -1429,15 +1493,16 @@ describe('MDC-based MatDialog', () => { button.focus(); // Patch the element focus after the initial and real focus, because otherwise the - // `activeElement` won't be set, and the dialog won't be able to restore focus to an - // element. + // `activeElement` won't be set, and the dialog won't be able to restore focus to an element. patchElementFocus(button); + expect(lastFocusOrigin!) + .withContext('Expected the trigger button to be focused via program') + .toBe('program'); dialog.open(ContentElementDialog, {viewContainerRef: testViewContainerRef}); - tick(500); viewContainerFixture.detectChanges(); - flushMicrotasks(); + tick(500); expect(lastFocusOrigin!).withContext('Expected the trigger button to be blurred').toBeNull(); const closeButton = overlayContainerElement.querySelector( @@ -1462,8 +1527,8 @@ describe('MDC-based MatDialog', () => { it('should allow the consumer to shift focus in afterClosed', fakeAsync(() => { // Create a element that has focus before the dialog is opened. - let button = document.createElement('button'); - let input = document.createElement('input'); + const button = document.createElement('button'); + const input = document.createElement('input'); button.id = 'dialog-trigger'; input.id = 'input-to-be-focused'; @@ -1472,7 +1537,7 @@ describe('MDC-based MatDialog', () => { document.body.appendChild(input); button.focus(); - let dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); + const dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); tick(500); viewContainerFixture.detectChanges(); @@ -1582,7 +1647,7 @@ describe('MDC-based MatDialog', () => { }); describe('dialog content elements', () => { - let dialogRef: MatDialogRef; + let dialogRef: MatLegacyDialogRef; describe('inside component dialog', () => { beforeEach(fakeAsync(() => { @@ -1612,50 +1677,43 @@ describe('MDC-based MatDialog', () => { function runContentElementTests() { it('should close the dialog when clicking on the close button', fakeAsync(() => { - expect(overlayContainerElement.querySelectorAll('.mat-mdc-dialog-container').length).toBe( - 1, - ); + expect(overlayContainerElement.querySelectorAll('.mat-dialog-container').length).toBe(1); (overlayContainerElement.querySelector('button[mat-dialog-close]') as HTMLElement).click(); viewContainerFixture.detectChanges(); flush(); - expect(overlayContainerElement.querySelectorAll('.mat-mdc-dialog-container').length).toBe( - 0, - ); + expect(overlayContainerElement.querySelectorAll('.mat-dialog-container').length).toBe(0); })); it('should not close if [mat-dialog-close] is applied on a non-button node', () => { - expect(overlayContainerElement.querySelectorAll('.mat-mdc-dialog-container').length).toBe( - 1, - ); + expect(overlayContainerElement.querySelectorAll('.mat-dialog-container').length).toBe(1); (overlayContainerElement.querySelector('div[mat-dialog-close]') as HTMLElement).click(); - expect(overlayContainerElement.querySelectorAll('.mat-mdc-dialog-container').length).toBe( - 1, - ); + expect(overlayContainerElement.querySelectorAll('.mat-dialog-container').length).toBe(1); }); it('should allow for a user-specified aria-label on the close button', fakeAsync(() => { - let button = overlayContainerElement.querySelector('.close-with-aria-label')!; + const button = overlayContainerElement.querySelector('.close-with-aria-label')!; + expect(button.getAttribute('aria-label')).toBe('Best close button ever'); })); it('should set the "type" attribute of the close button if not set manually', () => { - let button = overlayContainerElement.querySelector('button[mat-dialog-close]')!; + const button = overlayContainerElement.querySelector('button[mat-dialog-close]')!; expect(button.getAttribute('type')).toBe('button'); }); it('should not override type attribute of the close button if set manually', () => { - let button = overlayContainerElement.querySelector('button.with-submit')!; + const button = overlayContainerElement.querySelector('button.with-submit')!; expect(button.getAttribute('type')).toBe('submit'); }); it('should return the [mat-dialog-close] result when clicking the close button', fakeAsync(() => { - let afterCloseCallback = jasmine.createSpy('afterClose callback'); + const afterCloseCallback = jasmine.createSpy('afterClose callback'); dialogRef.afterClosed().subscribe(afterCloseCallback); (overlayContainerElement.querySelector('button.close-with-true') as HTMLElement).click(); @@ -1666,8 +1724,8 @@ describe('MDC-based MatDialog', () => { })); it('should set the aria-labelledby attribute to the id of the title', fakeAsync(() => { - let title = overlayContainerElement.querySelector('[mat-dialog-title]')!; - let container = overlayContainerElement.querySelector('mat-dialog-container')!; + const title = overlayContainerElement.querySelector('[mat-dialog-title]')!; + const container = overlayContainerElement.querySelector('mat-dialog-container')!; flush(); viewContainerFixture.detectChanges(); @@ -1682,11 +1740,12 @@ describe('MDC-based MatDialog', () => { let actions = overlayContainerElement.querySelector('mat-dialog-actions')!; expect(actions) - .withContext('Expected action buttons to not have class align-center') - .not.toHaveClass('mat-mdc-dialog-actions-align-center'); + .withContext('Expected action buttons to not have class mat-dialog-actions-align-center') + .not.toHaveClass('mat-dialog-actions-align-center'); + expect(actions) - .withContext('Expected action buttons to have class align-end') - .toHaveClass('mat-mdc-dialog-actions-align-end'); + .withContext('Expected action buttons to have class mat-dialog-actions-align-end') + .toHaveClass('mat-dialog-actions-align-end'); }); } }); @@ -1731,8 +1790,8 @@ describe('MDC-based MatDialog', () => { }); viewContainerFixture.detectChanges(); flush(); - let title = overlayContainerElement.querySelector('[mat-dialog-title]')!; - let container = overlayContainerElement.querySelector('mat-dialog-container')!; + const title = overlayContainerElement.querySelector('[mat-dialog-title]')!; + const container = overlayContainerElement.querySelector('mat-dialog-container')!; flush(); viewContainerFixture.detectChanges(); @@ -1744,7 +1803,10 @@ describe('MDC-based MatDialog', () => { describe('aria-label', () => { it('should be able to set a custom aria-label', () => { - dialog.open(PizzaMsg, {ariaLabel: 'Hello there', viewContainerRef: testViewContainerRef}); + dialog.open(PizzaMsg, { + ariaLabel: 'Hello there', + viewContainerRef: testViewContainerRef, + }); viewContainerFixture.detectChanges(); const container = overlayContainerElement.querySelector('mat-dialog-container')!; @@ -1781,16 +1843,16 @@ describe('MDC-based MatDialog', () => { })); }); -describe('MDC-based MatDialog with a parent MatDialog', () => { - let parentDialog: MatDialog; - let childDialog: MatDialog; +describe('MatDialog with a parent MatDialog', () => { + let parentDialog: MatLegacyDialog; + let childDialog: MatLegacyDialog; let overlayContainerElement: HTMLElement; let fixture: ComponentFixture; beforeEach(fakeAsync(() => { TestBed.configureTestingModule({ - imports: [MatDialogModule, NoopAnimationsModule], - declarations: [ComponentThatProvidesMatDialog], + imports: [MatLegacyDialogModule, NoopAnimationsModule], + declarations: [ComponentThatProvidesMatDialog, DirectiveWithViewContainer], providers: [ { provide: OverlayContainer, @@ -1806,7 +1868,7 @@ describe('MDC-based MatDialog with a parent MatDialog', () => { TestBed.compileComponents(); })); - beforeEach(inject([MatDialog], (d: MatDialog) => { + beforeEach(inject([MatLegacyDialog], (d: MatLegacyDialog) => { parentDialog = d; fixture = TestBed.createComponent(ComponentThatProvidesMatDialog); @@ -1882,8 +1944,8 @@ describe('MDC-based MatDialog with a parent MatDialog', () => { })); }); -describe('MDC-based MatDialog with default options', () => { - let dialog: MatDialog; +describe('MatDialog with default options', () => { + let dialog: MatLegacyDialog; let overlayContainerElement: HTMLElement; let testViewContainerRef: ViewContainerRef; @@ -1899,22 +1961,27 @@ describe('MDC-based MatDialog with default options', () => { minHeight: '50px', maxWidth: '150px', maxHeight: '150px', - autoFocus: 'dialog', + enterAnimationDuration: '100ms', + exitAnimationDuration: '50ms', + autoFocus: false, }; TestBed.configureTestingModule({ - imports: [MatDialogModule, NoopAnimationsModule], + imports: [MatLegacyDialogModule, NoopAnimationsModule], + providers: [{provide: MAT_LEGACY_DIALOG_DEFAULT_OPTIONS, useValue: defaultConfig}], declarations: [ComponentWithChildViewContainer, DirectiveWithViewContainer], - providers: [{provide: MAT_DIALOG_DEFAULT_OPTIONS, useValue: defaultConfig}], }); TestBed.compileComponents(); })); - beforeEach(inject([MatDialog, OverlayContainer], (d: MatDialog, oc: OverlayContainer) => { - dialog = d; - overlayContainerElement = oc.getContainerElement(); - })); + beforeEach(inject( + [MatLegacyDialog, OverlayContainer], + (d: MatLegacyDialog, oc: OverlayContainer) => { + dialog = d; + overlayContainerElement = oc.getContainerElement(); + }, + )); beforeEach(() => { viewContainerFixture = TestBed.createComponent(ComponentWithChildViewContainer); @@ -1935,7 +2002,7 @@ describe('MDC-based MatDialog with default options', () => { expect(document.activeElement!.tagName).not.toBe('INPUT'); - let overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; + const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement; expect(overlayPane.style.width).toBe('100px'); expect(overlayPane.style.height).toBe('100px'); expect(overlayPane.style.minWidth).toBe('50px'); @@ -1963,65 +2030,53 @@ describe('MDC-based MatDialog with default options', () => { })); }); -describe('MDC-based MatDialog with animations enabled', () => { - let dialog: MatDialog; +describe('MatDialog with animations enabled', () => { + let dialog: MatLegacyDialog; let testViewContainerRef: ViewContainerRef; let viewContainerFixture: ComponentFixture; beforeEach(fakeAsync(() => { TestBed.configureTestingModule({ - imports: [MatDialogModule, BrowserAnimationsModule], + imports: [MatLegacyDialogModule, BrowserAnimationsModule], declarations: [ComponentWithChildViewContainer, DirectiveWithViewContainer], }); TestBed.compileComponents(); })); - beforeEach(inject([MatDialog], (d: MatDialog) => { - dialog = d; - - viewContainerFixture = TestBed.createComponent(ComponentWithChildViewContainer); - viewContainerFixture.detectChanges(); - testViewContainerRef = viewContainerFixture.componentInstance.childViewContainer; - })); - - it('should emit when dialog opening animation is complete', fakeAsync(() => { - const dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); - const spy = jasmine.createSpy('afterOpen spy'); - - dialogRef.afterOpened().subscribe(spy); - - viewContainerFixture.detectChanges(); - - // callback should not be called before animation is complete - expect(spy).not.toHaveBeenCalled(); - - tick(numbers.DIALOG_ANIMATION_OPEN_TIME_MS); - expect(spy).toHaveBeenCalled(); - })); + beforeEach(inject( + [MatLegacyDialog, OverlayContainer], + (d: MatLegacyDialog, oc: OverlayContainer) => { + dialog = d; + viewContainerFixture = TestBed.createComponent(ComponentWithChildViewContainer); + viewContainerFixture.detectChanges(); + testViewContainerRef = viewContainerFixture.componentInstance.childViewContainer; + }, + )); it('should return the current state of the dialog', fakeAsync(() => { const dialogRef = dialog.open(PizzaMsg, {viewContainerRef: testViewContainerRef}); - // Duration of the close animation in milliseconds. - const dialogCloseDuration = numbers.DIALOG_ANIMATION_CLOSE_TIME_MS; + // Duration of the close animation in milliseconds. Extracted from the + // Angular animations definition of the dialog. + const dialogCloseDuration = 75; - expect(dialogRef.getState()).toBe(MatDialogState.OPEN); + expect(dialogRef.getState()).toBe(MatLegacyDialogState.OPEN); dialogRef.close(); viewContainerFixture.detectChanges(); - expect(dialogRef.getState()).toBe(MatDialogState.CLOSING); + expect(dialogRef.getState()).toBe(MatLegacyDialogState.CLOSING); // Ensure that the closing state is still set if half of the animation has // passed by. The dialog state should be only set to `closed` when the dialog // finished the close animation. tick(dialogCloseDuration / 2); - expect(dialogRef.getState()).toBe(MatDialogState.CLOSING); + expect(dialogRef.getState()).toBe(MatLegacyDialogState.CLOSING); // Flush the remaining duration of the closing animation. We flush all other remaining // tasks (e.g. the fallback close timeout) to avoid fakeAsync pending timer failures. flush(); - expect(dialogRef.getState()).toBe(MatDialogState.CLOSED); + expect(dialogRef.getState()).toBe(MatLegacyDialogState.CLOSED); })); }); @@ -2031,7 +2086,7 @@ describe('MatDialog with explicit injector provided', () => { beforeEach(fakeAsync(() => { TestBed.configureTestingModule({ - imports: [MatDialogModule, BrowserAnimationsModule], + imports: [MatLegacyDialogModule, BrowserAnimationsModule], declarations: [ModuleBoundDialogParentComponent], }); @@ -2046,14 +2101,14 @@ describe('MatDialog with explicit injector provided', () => { fixture = TestBed.createComponent(ModuleBoundDialogParentComponent); }); - it('should use the standalone injector and render the dialog successfully', () => { + it('should use the standalone injector and render the dialog successfully', fakeAsync(() => { fixture.componentInstance.openDialog(); fixture.detectChanges(); expect( overlayContainerElement.querySelector('module-bound-dialog-child-component')!.innerHTML, ).toEqual('

Pasta

'); - }); + })); }); @Directive({selector: 'dir-with-view-container'}) @@ -2086,15 +2141,15 @@ class ComponentWithChildViewContainer { @Component({ selector: 'arbitrary-component-with-template-ref', template: ` - Cheese {{localValue}} {{data?.value}}{{setDialogRef(dialogRef)}}`, + Cheese {{localValue}} {{data?.value}}{{setDialogRef(dialogRef)}}`, }) class ComponentWithTemplateRef { localValue: string; - dialogRef: MatDialogRef; + dialogRef: MatLegacyDialogRef; @ViewChild(TemplateRef) templateRef: TemplateRef; - setDialogRef(dialogRef: MatDialogRef): string { + setDialogRef(dialogRef: MatLegacyDialogRef): string { this.dialogRef = dialogRef; return ''; } @@ -2104,7 +2159,7 @@ class ComponentWithTemplateRef { @Component({template: '

Pizza

'}) class PizzaMsg { constructor( - public dialogRef: MatDialogRef, + public dialogRef: MatLegacyDialogRef, public dialogInjector: Injector, public directionality: Directionality, ) {} @@ -2150,15 +2205,18 @@ class ComponentWithContentElementTemplateRef { @ViewChild(TemplateRef) templateRef: TemplateRef; } -@Component({template: '', providers: [MatDialog]}) +@Component({ + template: '', + providers: [MatLegacyDialog], +}) class ComponentThatProvidesMatDialog { - constructor(public dialog: MatDialog) {} + constructor(public dialog: MatLegacyDialog) {} } /** Simple component for testing ComponentPortal. */ @Component({template: ''}) class DialogWithInjectedData { - constructor(@Inject(MAT_DIALOG_DATA) public data: any) {} + constructor(@Inject(MAT_LEGACY_DIALOG_DATA) public data: any) {} } @Component({template: '

Pasta

'}) @@ -2172,7 +2230,7 @@ class ShadowDomComponent {} @Component({template: ''}) class ModuleBoundDialogParentComponent { - constructor(private _injector: Injector, private _dialog: MatDialog) {} + constructor(private _injector: Injector, private _dialog: MatLegacyDialog) {} openDialog(): void { const ngModuleRef = createNgModuleRef( diff --git a/src/material-experimental/mdc-dialog/dialog.ts b/src/material/legacy-dialog/dialog.ts similarity index 55% rename from src/material-experimental/mdc-dialog/dialog.ts rename to src/material/legacy-dialog/dialog.ts index b45dc04a07d0..2b391ee990c8 100644 --- a/src/material-experimental/mdc-dialog/dialog.ts +++ b/src/material/legacy-dialog/dialog.ts @@ -8,51 +8,44 @@ import {Overlay, OverlayContainer, ScrollStrategy} from '@angular/cdk/overlay'; import {Location} from '@angular/common'; -import { - ANIMATION_MODULE_TYPE, - Inject, - Injectable, - InjectionToken, - Injector, - Optional, - SkipSelf, -} from '@angular/core'; +import {Inject, Injectable, InjectionToken, Injector, Optional, SkipSelf} from '@angular/core'; +import {MatLegacyDialogContainer} from './dialog-container'; +import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; import {_MatDialogBase, MatDialogConfig} from '@angular/material/dialog'; -import {MatDialogContainer} from './dialog-container'; -import {MatDialogRef} from './dialog-ref'; +import {MatLegacyDialogRef} from './dialog-ref'; /** Injection token that can be used to access the data that was passed in to a dialog. */ -export const MAT_DIALOG_DATA = new InjectionToken('MatMdcDialogData'); +export const MAT_LEGACY_DIALOG_DATA = new InjectionToken('MatDialogData'); /** Injection token that can be used to specify default dialog options. */ -export const MAT_DIALOG_DEFAULT_OPTIONS = new InjectionToken( - 'mat-mdc-dialog-default-options', +export const MAT_LEGACY_DIALOG_DEFAULT_OPTIONS = new InjectionToken( + 'mat-dialog-default-options', ); /** Injection token that determines the scroll handling while the dialog is open. */ -export const MAT_DIALOG_SCROLL_STRATEGY = new InjectionToken<() => ScrollStrategy>( - 'mat-mdc-dialog-scroll-strategy', +export const MAT_LEGACY_DIALOG_SCROLL_STRATEGY = new InjectionToken<() => ScrollStrategy>( + 'mat-dialog-scroll-strategy', ); /** @docs-private */ -export function MAT_DIALOG_SCROLL_STRATEGY_PROVIDER_FACTORY( +export function MAT_LEGACY_DIALOG_SCROLL_STRATEGY_PROVIDER_FACTORY( overlay: Overlay, ): () => ScrollStrategy { return () => overlay.scrollStrategies.block(); } /** @docs-private */ -export const MAT_DIALOG_SCROLL_STRATEGY_PROVIDER = { - provide: MAT_DIALOG_SCROLL_STRATEGY, +export const MAT_LEGACY_DIALOG_SCROLL_STRATEGY_PROVIDER = { + provide: MAT_LEGACY_DIALOG_SCROLL_STRATEGY, deps: [Overlay], - useFactory: MAT_DIALOG_SCROLL_STRATEGY_PROVIDER_FACTORY, + useFactory: MAT_LEGACY_DIALOG_SCROLL_STRATEGY_PROVIDER_FACTORY, }; /** * Service to open Material Design modal dialogs. */ @Injectable() -export class MatDialog extends _MatDialogBase { +export class MatLegacyDialog extends _MatDialogBase { constructor( overlay: Overlay, injector: Injector, @@ -60,10 +53,10 @@ export class MatDialog extends _MatDialogBase { * @deprecated `_location` parameter to be removed. * @breaking-change 10.0.0 */ - @Optional() location: Location, - @Optional() @Inject(MAT_DIALOG_DEFAULT_OPTIONS) defaultOptions: MatDialogConfig, - @Inject(MAT_DIALOG_SCROLL_STRATEGY) scrollStrategy: any, - @Optional() @SkipSelf() parentDialog: MatDialog, + @Optional() _location: Location, + @Optional() @Inject(MAT_LEGACY_DIALOG_DEFAULT_OPTIONS) defaultOptions: MatDialogConfig, + @Inject(MAT_LEGACY_DIALOG_SCROLL_STRATEGY) scrollStrategy: any, + @Optional() @SkipSelf() parentDialog: MatLegacyDialog, /** * @deprecated No longer used. To be removed. * @breaking-change 15.0.0 @@ -84,12 +77,10 @@ export class MatDialog extends _MatDialogBase { parentDialog, overlayContainer, scrollStrategy, - MatDialogRef, - MatDialogContainer, - MAT_DIALOG_DATA, + MatLegacyDialogRef, + MatLegacyDialogContainer, + MAT_LEGACY_DIALOG_DATA, animationMode, ); - - this._idPrefix = 'mat-mdc-dialog-'; } } diff --git a/src/material-experimental/mdc-dialog/index.ts b/src/material/legacy-dialog/index.ts similarity index 100% rename from src/material-experimental/mdc-dialog/index.ts rename to src/material/legacy-dialog/index.ts diff --git a/src/material/legacy-dialog/public-api.ts b/src/material/legacy-dialog/public-api.ts new file mode 100644 index 000000000000..c8d2989c8c80 --- /dev/null +++ b/src/material/legacy-dialog/public-api.ts @@ -0,0 +1,25 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +export * from './dialog-module'; +export * from './dialog'; +export * from './dialog-container'; +export * from './dialog-content-directives'; +export * from './dialog-ref'; +export { + _MatDialogBase as _MatLegacyDialogBase, + _MatDialogContainerBase as _MatLegacyDialogContainerBase, + AutoFocusTarget as LegacyAutoFocusTarget, + DialogRole as LegacyDialogRole, + DialogPosition as LegacyDialogPosition, + MatDialogConfig as MatLegacyDialogConfig, + _closeDialogVia as _closeLegacyDialogVia, + MatDialogState as MatLegacyDialogState, + matDialogAnimations as matLegacyDialogAnimations, + MAT_DIALOG_SCROLL_STRATEGY_FACTORY as MAT_LEGACY_DIALOG_SCROLL_STRATEGY_FACTORY, +} from '@angular/material/dialog'; diff --git a/src/material-experimental/mdc-dialog/testing/BUILD.bazel b/src/material/legacy-dialog/testing/BUILD.bazel similarity index 62% rename from src/material-experimental/mdc-dialog/testing/BUILD.bazel rename to src/material/legacy-dialog/testing/BUILD.bazel index 2771aee7c62a..325ef96d27f6 100644 --- a/src/material-experimental/mdc-dialog/testing/BUILD.bazel +++ b/src/material/legacy-dialog/testing/BUILD.bazel @@ -9,12 +9,14 @@ ts_library( exclude = ["**/*.spec.ts"], ), deps = [ + "//src/cdk/coercion", "//src/cdk/overlay", "//src/cdk/testing", - "//src/material-experimental/mdc-dialog", "//src/material/dialog/testing", + "//src/material/legacy-dialog", "@npm//@angular/core", "@npm//@angular/platform-browser", + "@npm//rxjs", ], ) @@ -23,6 +25,19 @@ filegroup( srcs = glob(["**/*.ts"]), ) +ng_test_library( + name = "harness_tests_lib", + srcs = ["shared.spec.ts"], + deps = [ + ":testing", + "//src/cdk/overlay", + "//src/cdk/testing", + "//src/cdk/testing/testbed", + "//src/material/legacy-dialog", + "@npm//@angular/platform-browser", + ], +) + ng_test_library( name = "unit_tests_lib", srcs = glob( @@ -30,16 +45,14 @@ ng_test_library( exclude = ["shared.spec.ts"], ), deps = [ + ":harness_tests_lib", ":testing", - "//src/material-experimental/mdc-dialog", - "//src/material/dialog/testing:harness_tests_lib", + "//src/material/legacy-dialog", "@npm//@angular/platform-browser", ], ) ng_web_test_suite( name = "unit_tests", - deps = [ - ":unit_tests_lib", - ], + deps = [":unit_tests_lib"], ) diff --git a/src/material/legacy-dialog/testing/dialog-harness.spec.ts b/src/material/legacy-dialog/testing/dialog-harness.spec.ts new file mode 100644 index 000000000000..77897881bca2 --- /dev/null +++ b/src/material/legacy-dialog/testing/dialog-harness.spec.ts @@ -0,0 +1,7 @@ +import {MatLegacyDialog, MatLegacyDialogModule} from '@angular/material/legacy-dialog'; +import {runHarnessTests} from '@angular/material/legacy-dialog/testing/shared.spec'; +import {MatLegacyDialogHarness} from './dialog-harness'; + +describe('Non-MDC-based MatDialogHarness', () => { + runHarnessTests(MatLegacyDialogModule, MatLegacyDialogHarness, MatLegacyDialog); +}); diff --git a/src/material/legacy-dialog/testing/dialog-harness.ts b/src/material/legacy-dialog/testing/dialog-harness.ts new file mode 100644 index 000000000000..492a4a0e6721 --- /dev/null +++ b/src/material/legacy-dialog/testing/dialog-harness.ts @@ -0,0 +1,39 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {HarnessPredicate} from '@angular/cdk/testing'; +import {_MatDialogHarnessBase, DialogHarnessFilters} from '@angular/material/dialog/testing'; + +/** Selectors for different sections of the mat-dialog that can contain user content. */ +export const enum MatLegacyDialogSection { + TITLE = '.mat-dialog-title', + CONTENT = '.mat-dialog-content', + ACTIONS = '.mat-dialog-actions', +} + +/** Harness for interacting with a standard `MatDialog` in tests. */ +export class MatLegacyDialogHarness extends _MatDialogHarnessBase { + // Developers can provide a custom component or template for the + // dialog. The canonical dialog parent is the "MatDialogContainer". + /** The selector for the host element of a `MatDialog` instance. */ + static hostSelector = '.mat-dialog-container'; + + /** + * Gets a `HarnessPredicate` that can be used to search for a `MatDialogHarness` that meets + * certain criteria. + * @param options Options for filtering which dialog instances are considered a match. + * @return a `HarnessPredicate` configured with the given options. + */ + static with(options: DialogHarnessFilters = {}): HarnessPredicate { + return new HarnessPredicate(MatLegacyDialogHarness, options); + } + + protected override _title = this.locatorForOptional(MatLegacyDialogSection.TITLE); + protected override _content = this.locatorForOptional(MatLegacyDialogSection.CONTENT); + protected override _actions = this.locatorForOptional(MatLegacyDialogSection.ACTIONS); +} diff --git a/src/material-experimental/mdc-dialog/testing/dialog-opener.spec.ts b/src/material/legacy-dialog/testing/dialog-opener.spec.ts similarity index 65% rename from src/material-experimental/mdc-dialog/testing/dialog-opener.spec.ts rename to src/material/legacy-dialog/testing/dialog-opener.spec.ts index 8cf84200b022..4be7b00931c0 100644 --- a/src/material-experimental/mdc-dialog/testing/dialog-opener.spec.ts +++ b/src/material/legacy-dialog/testing/dialog-opener.spec.ts @@ -1,20 +1,20 @@ import {Component, Inject} from '@angular/core'; -import {fakeAsync, TestBed, flush} from '@angular/core/testing'; +import {fakeAsync, flush, TestBed} from '@angular/core/testing'; import { - MatTestDialogOpenerModule, - MatTestDialogOpener, -} from '@angular/material-experimental/mdc-dialog/testing'; + MatTestLegacyDialogOpenerModule, + MatTestLegacyDialogOpener, +} from '@angular/material/legacy-dialog/testing'; import { - MAT_DIALOG_DATA, - MatDialogRef, - MatDialogState, -} from '@angular/material-experimental/mdc-dialog'; + MAT_LEGACY_DIALOG_DATA, + MatLegacyDialogRef, + MatLegacyDialogState, +} from '@angular/material/legacy-dialog'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; describe('MDC-based MatTestDialogOpener', () => { beforeEach(fakeAsync(() => { TestBed.configureTestingModule({ - imports: [MatTestDialogOpenerModule, NoopAnimationsModule], + imports: [MatTestLegacyDialogOpenerModule, NoopAnimationsModule], declarations: [ExampleComponent], }); @@ -22,21 +22,23 @@ describe('MDC-based MatTestDialogOpener', () => { })); it('should open a dialog when created', fakeAsync(() => { - const fixture = TestBed.createComponent(MatTestDialogOpener.withComponent(ExampleComponent)); + const fixture = TestBed.createComponent( + MatTestLegacyDialogOpener.withComponent(ExampleComponent), + ); flush(); - expect(fixture.componentInstance.dialogRef.getState()).toBe(MatDialogState.OPEN); + expect(fixture.componentInstance.dialogRef.getState()).toBe(MatLegacyDialogState.OPEN); expect(document.querySelector('mat-dialog-container')).toBeTruthy(); })); it('should throw an error if no dialog component is provided', () => { - expect(() => TestBed.createComponent(MatTestDialogOpener)).toThrow( + expect(() => TestBed.createComponent(MatTestLegacyDialogOpener)).toThrow( Error('MatTestDialogOpener does not have a component provided.'), ); }); it('should pass data to the component', fakeAsync(() => { const config = {data: 'test'}; - TestBed.createComponent(MatTestDialogOpener.withComponent(ExampleComponent, config)); + TestBed.createComponent(MatTestLegacyDialogOpener.withComponent(ExampleComponent, config)); flush(); const dialogContainer = document.querySelector('mat-dialog-container'); expect(dialogContainer!.innerHTML).toContain('Data: test'); @@ -45,7 +47,7 @@ describe('MDC-based MatTestDialogOpener', () => { it('should get closed result data', fakeAsync(() => { const config = {data: 'test'}; const fixture = TestBed.createComponent( - MatTestDialogOpener.withComponent( + MatTestLegacyDialogOpener.withComponent( ExampleComponent, config, ), @@ -71,8 +73,8 @@ interface ExampleDialogResult { }) class ExampleComponent { constructor( - public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: any, + public dialogRef: MatLegacyDialogRef, + @Inject(MAT_LEGACY_DIALOG_DATA) public data: any, ) {} close() { diff --git a/src/material-experimental/mdc-dialog/testing/dialog-opener.ts b/src/material/legacy-dialog/testing/dialog-opener.ts similarity index 60% rename from src/material-experimental/mdc-dialog/testing/dialog-opener.ts rename to src/material/legacy-dialog/testing/dialog-opener.ts index 6d21b1d1e3a8..9d9a16142bf2 100644 --- a/src/material-experimental/mdc-dialog/testing/dialog-opener.ts +++ b/src/material/legacy-dialog/testing/dialog-opener.ts @@ -8,44 +8,44 @@ import {ComponentType} from '@angular/cdk/overlay'; import {ChangeDetectionStrategy, Component, NgModule, ViewEncapsulation} from '@angular/core'; -import {_MatTestDialogOpenerBase} from '@angular/material/dialog/testing'; import { - MatDialog, - MatDialogContainer, - MatDialogModule, - MatDialogConfig, -} from '@angular/material-experimental/mdc-dialog'; + MatLegacyDialog, + MatLegacyDialogConfig, + MatLegacyDialogContainer, + MatLegacyDialogModule, +} from '@angular/material/legacy-dialog'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {_MatTestDialogOpenerBase} from '@angular/material/dialog/testing'; -/** Test component that immediately opens a dialog when bootstrapped. */ +/** Test component that immediately opens a dialog when created. */ @Component({ selector: 'mat-test-dialog-opener', template: '', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, }) -export class MatTestDialogOpener extends _MatTestDialogOpenerBase< - MatDialogContainer, +export class MatTestLegacyDialogOpener extends _MatTestDialogOpenerBase< + MatLegacyDialogContainer, T, R > { - constructor(dialog: MatDialog) { + constructor(dialog: MatLegacyDialog) { super(dialog); } /** Static method that prepares this class to open the provided component. */ static withComponent( component: ComponentType, - config?: MatDialogConfig, + config?: MatLegacyDialogConfig, ) { _MatTestDialogOpenerBase.component = component; _MatTestDialogOpenerBase.config = config; - return MatTestDialogOpener as ComponentType>; + return MatTestLegacyDialogOpener as ComponentType>; } } @NgModule({ - declarations: [MatTestDialogOpener], - imports: [MatDialogModule, NoopAnimationsModule], + declarations: [MatTestLegacyDialogOpener], + imports: [MatLegacyDialogModule, NoopAnimationsModule], }) -export class MatTestDialogOpenerModule {} +export class MatTestLegacyDialogOpenerModule {} diff --git a/src/material-experimental/mdc-dialog/testing/index.ts b/src/material/legacy-dialog/testing/index.ts similarity index 100% rename from src/material-experimental/mdc-dialog/testing/index.ts rename to src/material/legacy-dialog/testing/index.ts diff --git a/src/material-experimental/mdc-dialog/testing/public-api.ts b/src/material/legacy-dialog/testing/public-api.ts similarity index 62% rename from src/material-experimental/mdc-dialog/testing/public-api.ts rename to src/material/legacy-dialog/testing/public-api.ts index 6e56fd740d06..f357a4e9fe9a 100644 --- a/src/material-experimental/mdc-dialog/testing/public-api.ts +++ b/src/material/legacy-dialog/testing/public-api.ts @@ -6,6 +6,6 @@ * found in the LICENSE file at https://angular.io/license */ -export {DialogHarnessFilters} from '@angular/material/dialog/testing'; -export {MatDialogHarness, MatDialogSection} from './dialog-harness'; +export * from './dialog-harness'; export * from './dialog-opener'; +export {DialogHarnessFilters as LegacyDialogHarnessFilters} from '@angular/material/dialog/testing'; diff --git a/src/material/dialog/testing/shared.spec.ts b/src/material/legacy-dialog/testing/shared.spec.ts similarity index 90% rename from src/material/dialog/testing/shared.spec.ts rename to src/material/legacy-dialog/testing/shared.spec.ts index 360f0ea8ac11..29a68057e102 100644 --- a/src/material/dialog/testing/shared.spec.ts +++ b/src/material/legacy-dialog/testing/shared.spec.ts @@ -2,15 +2,19 @@ import {HarnessLoader} from '@angular/cdk/testing'; import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; import {Component, TemplateRef, ViewChild} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; -import {MatDialog, MatDialogConfig, MatDialogModule} from '@angular/material/dialog'; +import { + MatLegacyDialog, + MatLegacyDialogModule, + MatLegacyDialogConfig, +} from '@angular/material/legacy-dialog'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; -import {MatDialogHarness} from './dialog-harness'; +import {MatLegacyDialogHarness} from './dialog-harness'; /** Shared tests to run on both the original and MDC-based dialog's. */ export function runHarnessTests( - dialogModule: typeof MatDialogModule, - dialogHarness: typeof MatDialogHarness, - dialogService: typeof MatDialog, + dialogModule: typeof MatLegacyDialogModule, + dialogHarness: typeof MatLegacyDialogHarness, + dialogService: typeof MatLegacyDialog, ) { let fixture: ComponentFixture; let loader: HarnessLoader; @@ -21,7 +25,9 @@ export function runHarnessTests( // the existing instance of the specified dialog service. This allows us to run these // tests for the MDC-based version of the dialog too. const providers = - dialogService !== MatDialog ? [{provide: MatDialog, useExisting: dialogService}] : undefined; + dialogService !== MatLegacyDialog + ? [{provide: MatLegacyDialog, useExisting: dialogService}] + : undefined; await TestBed.configureTestingModule({ imports: [dialogModule, NoopAnimationsModule], declarations: [DialogHarnessTest], @@ -132,9 +138,9 @@ export function runHarnessTests( class DialogHarnessTest { @ViewChild(TemplateRef) dialogTmpl: TemplateRef; - constructor(readonly dialog: MatDialog) {} + constructor(readonly dialog: MatLegacyDialog) {} - open(config?: MatDialogConfig) { + open(config?: MatLegacyDialogConfig) { return this.dialog.open(this.dialogTmpl, config); } } diff --git a/src/material/schematics/ng-generate/mdc-migration/rules/ts-migration/import-replacements.ts b/src/material/schematics/ng-generate/mdc-migration/rules/ts-migration/import-replacements.ts index dcb55fe9841b..aafdbc3cbfab 100644 --- a/src/material/schematics/ng-generate/mdc-migration/rules/ts-migration/import-replacements.ts +++ b/src/material/schematics/ng-generate/mdc-migration/rules/ts-migration/import-replacements.ts @@ -24,8 +24,8 @@ export const IMPORT_REPLACEMENTS: {[component: string]: {old: string; new: strin new: '@angular/material-experimental/mdc-chips', }, 'dialog': { - old: '@angular/material/dialog', - new: '@angular/material-experimental/mdc-dialog', + old: '@angular/material/legacy-dialog', + new: '@angular/material/dialog', }, 'autocomplete': { old: '@angular/material/autocomplete', diff --git a/src/universal-app/kitchen-sink-mdc/kitchen-sink-mdc.ts b/src/universal-app/kitchen-sink-mdc/kitchen-sink-mdc.ts index be5fa5d04a1f..0c34abb52973 100644 --- a/src/universal-app/kitchen-sink-mdc/kitchen-sink-mdc.ts +++ b/src/universal-app/kitchen-sink-mdc/kitchen-sink-mdc.ts @@ -14,7 +14,7 @@ import {MatSlideToggleModule} from '@angular/material-experimental/mdc-slide-tog import {MatSliderModule} from '@angular/material-experimental/mdc-slider'; import {MatTabsModule} from '@angular/material-experimental/mdc-tabs'; import {MatTableModule} from '@angular/material-experimental/mdc-table'; -import {MatDialog, MatDialogModule} from '@angular/material-experimental/mdc-dialog'; +import {MatDialog, MatDialogModule} from '@angular/material/dialog'; import {MatIconModule} from '@angular/material/icon'; import {MatSnackBarModule, MatSnackBar} from '@angular/material-experimental/mdc-snack-bar'; import {MatProgressSpinnerModule} from '@angular/material-experimental/mdc-progress-spinner'; diff --git a/src/universal-app/kitchen-sink/kitchen-sink.ts b/src/universal-app/kitchen-sink/kitchen-sink.ts index 82e44b6b3b85..c439aaf668f7 100644 --- a/src/universal-app/kitchen-sink/kitchen-sink.ts +++ b/src/universal-app/kitchen-sink/kitchen-sink.ts @@ -12,7 +12,7 @@ import {MatLegacyCheckboxModule} from '@angular/material/legacy-checkbox'; import {MatChipsModule} from '@angular/material/chips'; import {MatTableModule} from '@angular/material/table'; import {MatDatepickerModule} from '@angular/material/datepicker'; -import {MatDialogModule, MatDialog} from '@angular/material/dialog'; +import {MatLegacyDialogModule, MatLegacyDialog} from '@angular/material/legacy-dialog'; import {MatExpansionModule} from '@angular/material/expansion'; import {MatGridListModule} from '@angular/material/grid-list'; import {MatIconModule} from '@angular/material/icon'; @@ -78,7 +78,7 @@ export class KitchenSink { constructor( snackBar: MatSnackBar, - dialog: MatDialog, + dialog: MatLegacyDialog, viewportRuler: ViewportRuler, focusMonitor: FocusMonitor, elementRef: ElementRef, @@ -107,7 +107,7 @@ export class KitchenSink { MatLegacyCheckboxModule, MatChipsModule, MatDatepickerModule, - MatDialogModule, + MatLegacyDialogModule, MatDividerModule, MatLegacyFormFieldModule, MatGridListModule, diff --git a/tools/public_api_guard/material/dialog-testing.md b/tools/public_api_guard/material/dialog-testing.md index e710b8cba903..e9fd4144e519 100644 --- a/tools/public_api_guard/material/dialog-testing.md +++ b/tools/public_api_guard/material/dialog-testing.md @@ -6,6 +6,7 @@ import { AsyncFactoryFn } from '@angular/cdk/testing'; import { BaseHarnessFilters } from '@angular/cdk/testing'; +import { ComponentHarnessConstructor } from '@angular/cdk/testing'; import { ComponentType } from '@angular/cdk/overlay'; import { ContentContainerComponentHarness } from '@angular/cdk/testing'; import { DialogRole } from '@angular/material/dialog'; @@ -26,7 +27,7 @@ export interface DialogHarnessFilters extends BaseHarnessFilters { // @public export class MatDialogHarness extends _MatDialogHarnessBase { static hostSelector: string; - static with(options?: DialogHarnessFilters): HarnessPredicate; + static with(this: ComponentHarnessConstructor, options?: DialogHarnessFilters): HarnessPredicate; } // @public @@ -52,11 +53,11 @@ export class _MatDialogHarnessBase extends ContentContainerComponentHarness { constructor(overlay: Overlay, injector: Injector, - _location: Location_2, defaultOptions: MatDialogConfig, scrollStrategy: any, parentDialog: MatDialog, + location: Location_2, defaultOptions: MatDialogConfig, scrollStrategy: any, parentDialog: MatDialog, overlayContainer: OverlayContainer, animationMode?: 'NoopAnimations' | 'BrowserAnimations'); // (undocumented) @@ -132,10 +130,9 @@ export abstract class _MatDialogBase implemen // @public export class MatDialogClose implements OnInit, OnChanges { - constructor( - dialogRef: MatDialogRef, _elementRef: ElementRef, _dialog: MatDialog); + constructor(dialogRef: MatDialogRef, _elementRef: ElementRef, _dialog: MatDialog); ariaLabel: string; - // @deprecated + // (undocumented) dialogRef: MatDialogRef; dialogResult: any; // (undocumented) @@ -186,30 +183,24 @@ export class MatDialogConfig { } // @public -export class MatDialogContainer extends _MatDialogContainerBase { - constructor(elementRef: ElementRef, focusTrapFactory: FocusTrapFactory, document: any, dialogConfig: MatDialogConfig, checker: InteractivityChecker, ngZone: NgZone, overlayRef: OverlayRef, _changeDetectorRef: ChangeDetectorRef, focusMonitor?: FocusMonitor); - // (undocumented) - _getAnimationState(): { - value: "enter" | "void" | "exit"; - params: { - enterAnimationDuration: string; - exitAnimationDuration: string; - }; - }; - _onAnimationDone({ toState, totalTime }: AnimationEvent_2): void; - _onAnimationStart({ toState, totalTime }: AnimationEvent_2): void; +export class MatDialogContainer extends _MatDialogContainerBase implements OnDestroy { + constructor(elementRef: ElementRef, focusTrapFactory: FocusTrapFactory, document: any, dialogConfig: MatDialogConfig, checker: InteractivityChecker, ngZone: NgZone, overlayRef: OverlayRef, _animationMode?: string | undefined, focusMonitor?: FocusMonitor); + _animationsEnabled: boolean; + // (undocumented) + protected _contentAttached(): void; + // (undocumented) + ngOnDestroy(): void; _startExitAnimation(): void; - _state: 'void' | 'enter' | 'exit'; // (undocumented) static ɵcmp: i0.ɵɵComponentDeclaration; // (undocumented) - static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵfac: i0.ɵɵFactoryDeclaration; } // @public export abstract class _MatDialogContainerBase extends CdkDialogContainer { constructor(elementRef: ElementRef, focusTrapFactory: FocusTrapFactory, _document: any, dialogConfig: MatDialogConfig, interactivityChecker: InteractivityChecker, ngZone: NgZone, overlayRef: OverlayRef, focusMonitor?: FocusMonitor); - _animationStateChanged: EventEmitter; + _animationStateChanged: EventEmitter; // (undocumented) protected _captureInitialFocus(): void; protected _openAnimationDone(totalTime: number): void; @@ -259,7 +250,7 @@ export class MatDialogRef { updateSize(width?: string, height?: string): this; } -// @public +// @public (undocumented) export const enum MatDialogState { // (undocumented) CLOSED = 2, @@ -272,6 +263,7 @@ export const enum MatDialogState { // @public export class MatDialogTitle implements OnInit { constructor(_dialogRef: MatDialogRef, _elementRef: ElementRef, _dialog: MatDialog); + // (undocumented) id: string; // (undocumented) ngOnInit(): void; diff --git a/tools/public_api_guard/material/legacy-dialog-testing.md b/tools/public_api_guard/material/legacy-dialog-testing.md new file mode 100644 index 000000000000..8cbc0409a24e --- /dev/null +++ b/tools/public_api_guard/material/legacy-dialog-testing.md @@ -0,0 +1,54 @@ +## API Report File for "components-srcs" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { AsyncFactoryFn } from '@angular/cdk/testing'; +import { ComponentType } from '@angular/cdk/overlay'; +import { HarnessPredicate } from '@angular/cdk/testing'; +import { DialogHarnessFilters as LegacyDialogHarnessFilters } from '@angular/material/dialog/testing'; +import { _MatDialogHarnessBase } from '@angular/material/dialog/testing'; +import { MatLegacyDialog } from '@angular/material/legacy-dialog'; +import { MatLegacyDialogConfig } from '@angular/material/legacy-dialog'; +import { MatLegacyDialogContainer } from '@angular/material/legacy-dialog'; +import { _MatTestDialogOpenerBase } from '@angular/material/dialog/testing'; +import { TestElement } from '@angular/cdk/testing'; + +export { LegacyDialogHarnessFilters } + +// @public +export class MatLegacyDialogHarness extends _MatDialogHarnessBase { + // (undocumented) + protected _actions: AsyncFactoryFn; + // (undocumented) + protected _content: AsyncFactoryFn; + static hostSelector: string; + // (undocumented) + protected _title: AsyncFactoryFn; + static with(options?: LegacyDialogHarnessFilters): HarnessPredicate; +} + +// @public +export const enum MatLegacyDialogSection { + // (undocumented) + ACTIONS = ".mat-dialog-actions", + // (undocumented) + CONTENT = ".mat-dialog-content", + // (undocumented) + TITLE = ".mat-dialog-title" +} + +// @public +export class MatTestLegacyDialogOpener extends _MatTestDialogOpenerBase { + constructor(dialog: MatLegacyDialog); + static withComponent(component: ComponentType, config?: MatLegacyDialogConfig): ComponentType>; +} + +// @public (undocumented) +export class MatTestLegacyDialogOpenerModule { +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/tools/public_api_guard/material/legacy-dialog.md b/tools/public_api_guard/material/legacy-dialog.md new file mode 100644 index 000000000000..4ab5315f2ec8 --- /dev/null +++ b/tools/public_api_guard/material/legacy-dialog.md @@ -0,0 +1,181 @@ +## API Report File for "components-srcs" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { AnimationEvent as AnimationEvent_2 } from '@angular/animations'; +import { ChangeDetectorRef } from '@angular/core'; +import { _closeDialogVia as _closeLegacyDialogVia } from '@angular/material/dialog'; +import { ElementRef } from '@angular/core'; +import { FocusMonitor } from '@angular/cdk/a11y'; +import { FocusTrapFactory } from '@angular/cdk/a11y'; +import * as i0 from '@angular/core'; +import * as i3 from '@angular/cdk/dialog'; +import * as i4 from '@angular/cdk/overlay'; +import * as i5 from '@angular/cdk/portal'; +import * as i6 from '@angular/material/core'; +import { InjectionToken } from '@angular/core'; +import { Injector } from '@angular/core'; +import { InteractivityChecker } from '@angular/cdk/a11y'; +import { AutoFocusTarget as LegacyAutoFocusTarget } from '@angular/material/dialog'; +import { DialogPosition as LegacyDialogPosition } from '@angular/material/dialog'; +import { DialogRole as LegacyDialogRole } from '@angular/material/dialog'; +import { Location as Location_2 } from '@angular/common'; +import { MAT_DIALOG_SCROLL_STRATEGY_FACTORY as MAT_LEGACY_DIALOG_SCROLL_STRATEGY_FACTORY } from '@angular/material/dialog'; +import { MatDialogRef } from '@angular/material/dialog'; +import { matDialogAnimations as matLegacyDialogAnimations } from '@angular/material/dialog'; +import { _MatDialogBase as _MatLegacyDialogBase } from '@angular/material/dialog'; +import { MatDialogConfig as MatLegacyDialogConfig } from '@angular/material/dialog'; +import { _MatDialogContainerBase as _MatLegacyDialogContainerBase } from '@angular/material/dialog'; +import { MatDialogState as MatLegacyDialogState } from '@angular/material/dialog'; +import { NgZone } from '@angular/core'; +import { OnChanges } from '@angular/core'; +import { OnInit } from '@angular/core'; +import { Overlay } from '@angular/cdk/overlay'; +import { OverlayContainer } from '@angular/cdk/overlay'; +import { OverlayRef } from '@angular/cdk/overlay'; +import { ScrollStrategy } from '@angular/cdk/overlay'; +import { SimpleChanges } from '@angular/core'; + +export { _closeLegacyDialogVia } + +export { LegacyAutoFocusTarget } + +export { LegacyDialogPosition } + +export { LegacyDialogRole } + +// @public +export const MAT_LEGACY_DIALOG_DATA: InjectionToken; + +// @public +export const MAT_LEGACY_DIALOG_DEFAULT_OPTIONS: InjectionToken>; + +// @public +export const MAT_LEGACY_DIALOG_SCROLL_STRATEGY: InjectionToken<() => ScrollStrategy>; + +export { MAT_LEGACY_DIALOG_SCROLL_STRATEGY_FACTORY } + +// @public +export const MAT_LEGACY_DIALOG_SCROLL_STRATEGY_PROVIDER: { + provide: InjectionToken<() => ScrollStrategy>; + deps: (typeof Overlay)[]; + useFactory: typeof MAT_LEGACY_DIALOG_SCROLL_STRATEGY_PROVIDER_FACTORY; +}; + +// @public +export function MAT_LEGACY_DIALOG_SCROLL_STRATEGY_PROVIDER_FACTORY(overlay: Overlay): () => ScrollStrategy; + +// @public +export class MatLegacyDialog extends _MatLegacyDialogBase { + constructor(overlay: Overlay, injector: Injector, + _location: Location_2, defaultOptions: MatLegacyDialogConfig, scrollStrategy: any, parentDialog: MatLegacyDialog, + overlayContainer: OverlayContainer, + animationMode?: 'NoopAnimations' | 'BrowserAnimations'); + // (undocumented) + static ɵfac: i0.ɵɵFactoryDeclaration; + // (undocumented) + static ɵprov: i0.ɵɵInjectableDeclaration; +} + +// @public +export class MatLegacyDialogActions { + align?: 'start' | 'center' | 'end'; + // (undocumented) + static ɵdir: i0.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: i0.ɵɵFactoryDeclaration; +} + +export { matLegacyDialogAnimations } + +export { _MatLegacyDialogBase } + +// @public +export class MatLegacyDialogClose implements OnInit, OnChanges { + constructor( + dialogRef: MatLegacyDialogRef, _elementRef: ElementRef, _dialog: MatLegacyDialog); + ariaLabel: string; + // @deprecated + dialogRef: MatLegacyDialogRef; + dialogResult: any; + // (undocumented) + _matDialogClose: any; + // (undocumented) + ngOnChanges(changes: SimpleChanges): void; + // (undocumented) + ngOnInit(): void; + // (undocumented) + _onButtonClick(event: MouseEvent): void; + type: 'submit' | 'button' | 'reset'; + // (undocumented) + static ɵdir: i0.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: i0.ɵɵFactoryDeclaration; +} + +export { MatLegacyDialogConfig } + +// @public +export class MatLegacyDialogContainer extends _MatLegacyDialogContainerBase { + constructor(elementRef: ElementRef, focusTrapFactory: FocusTrapFactory, document: any, dialogConfig: MatLegacyDialogConfig, checker: InteractivityChecker, ngZone: NgZone, overlayRef: OverlayRef, _changeDetectorRef: ChangeDetectorRef, focusMonitor?: FocusMonitor); + // (undocumented) + _getAnimationState(): { + value: "void" | "enter" | "exit"; + params: { + enterAnimationDuration: string; + exitAnimationDuration: string; + }; + }; + _onAnimationDone({ toState, totalTime }: AnimationEvent_2): void; + _onAnimationStart({ toState, totalTime }: AnimationEvent_2): void; + _startExitAnimation(): void; + _state: 'void' | 'enter' | 'exit'; + // (undocumented) + static ɵcmp: i0.ɵɵComponentDeclaration; + // (undocumented) + static ɵfac: i0.ɵɵFactoryDeclaration; +} + +export { _MatLegacyDialogContainerBase } + +// @public +export class MatLegacyDialogContent { + // (undocumented) + static ɵdir: i0.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: i0.ɵɵFactoryDeclaration; +} + +// @public (undocumented) +export class MatLegacyDialogModule { + // (undocumented) + static ɵfac: i0.ɵɵFactoryDeclaration; + // (undocumented) + static ɵinj: i0.ɵɵInjectorDeclaration; + // (undocumented) + static ɵmod: i0.ɵɵNgModuleDeclaration; +} + +// @public +export class MatLegacyDialogRef extends MatDialogRef { +} + +export { MatLegacyDialogState } + +// @public +export class MatLegacyDialogTitle implements OnInit { + constructor(_dialogRef: MatLegacyDialogRef, _elementRef: ElementRef, _dialog: MatLegacyDialog); + id: string; + // (undocumented) + ngOnInit(): void; + // (undocumented) + static ɵdir: i0.ɵɵDirectiveDeclaration; + // (undocumented) + static ɵfac: i0.ɵɵFactoryDeclaration; +} + +// (No @packageDocumentation comment for this package) + +```