Skip to content

Commit

Permalink
feat(material-experimental): MDC-based version of dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
devversion authored and mmalerba committed Aug 4, 2020
1 parent 3d2ecc0 commit d137848
Show file tree
Hide file tree
Showing 49 changed files with 3,552 additions and 182 deletions.
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Expand Up @@ -174,6 +174,7 @@
/src/dev-app/mdc-card/** @mmalerba
/src/dev-app/mdc-checkbox/** @mmalerba
/src/dev-app/mdc-chips/** @mmalerba
/src/dev-app/mdc-dialog/** @devversion
/src/dev-app/mdc-input/** @devversion @mmalerba
/src/dev-app/mdc-list/** @mmalerba
/src/dev-app/mdc-menu/** @crisbeto
Expand Down Expand Up @@ -235,6 +236,7 @@
/src/e2e-app/mdc-card/** @mmalerba
/src/e2e-app/mdc-checkbox/** @mmalerba
/src/e2e-app/mdc-chips/** @mmalerba
/src/e2e-app/mdc-dialog/** @devversion
/src/e2e-app/mdc-input/** @devversion
/src/e2e-app/mdc-menu/** @crisbeto
/src/e2e-app/mdc-progress-bar/** @crisbeto
Expand Down
27 changes: 19 additions & 8 deletions src/cdk-experimental/dialog/dialog-container.ts
Expand Up @@ -17,6 +17,7 @@ import {
} from '@angular/cdk/portal';
import {DOCUMENT} from '@angular/common';
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
Expand Down Expand Up @@ -72,7 +73,7 @@ export function throwDialogContentAlreadyAttachedError() {
'(@dialog.done)': '_animationDone.next($event)',
},
})
export class CdkDialogContainer extends BasePortalOutlet implements OnDestroy {
export class CdkDialogContainer extends BasePortalOutlet implements OnDestroy, AfterViewInit {
private readonly _document: Document;

/** State of the dialog animation. */
Expand Down Expand Up @@ -150,6 +151,16 @@ export class CdkDialogContainer extends BasePortalOutlet implements OnDestroy {
});
}

/** If the dialog view completes initialization, the open animation starts. */
ngAfterViewInit() {
// Save the previously focused element. This element will be re-focused
// when the dialog closes.
this._savePreviouslyFocusedElement();
// Move focus onto the dialog immediately in order to prevent the user
// from accidentally opening multiple dialogs at the same time.
this._focusDialogContainer();
}

/** Destroy focus trap to place focus back to the element focused before the dialog opened. */
ngOnDestroy() {
this._focusTrap.destroy();
Expand All @@ -165,7 +176,6 @@ export class CdkDialogContainer extends BasePortalOutlet implements OnDestroy {
throwDialogContentAlreadyAttachedError();
}

this._savePreviouslyFocusedElement();
return this._portalHost.attachComponentPortal(portal);
}

Expand All @@ -178,7 +188,6 @@ export class CdkDialogContainer extends BasePortalOutlet implements OnDestroy {
throwDialogContentAlreadyAttachedError();
}

this._savePreviouslyFocusedElement();
return this._portalHost.attachTemplatePortal(portal);
}

Expand All @@ -193,7 +202,6 @@ export class CdkDialogContainer extends BasePortalOutlet implements OnDestroy {
throwDialogContentAlreadyAttachedError();
}

this._savePreviouslyFocusedElement();
return this._portalHost.attachDomPortal(portal);
}

Expand Down Expand Up @@ -222,11 +230,14 @@ export class CdkDialogContainer extends BasePortalOutlet implements OnDestroy {
private _savePreviouslyFocusedElement() {
if (this._document) {
this._elementFocusedBeforeDialogWasOpened = this._document.activeElement as HTMLElement;
}
}

// Move focus onto the dialog immediately in order to prevent the user from accidentally
// opening multiple dialogs at the same time. Needs to be async, because the element
// may not be focusable immediately.
Promise.resolve().then(() => this._elementRef.nativeElement.focus());
/** Focuses the dialog container. */
private _focusDialogContainer() {
// Note that there is no focus method when rendering on the server.
if (this._elementRef.nativeElement.focus) {
this._elementRef.nativeElement.focus();
}
}

Expand Down
1 change: 1 addition & 0 deletions src/dev-app/BUILD.bazel
Expand Up @@ -50,6 +50,7 @@ ng_module(
"//src/dev-app/mdc-card",
"//src/dev-app/mdc-checkbox",
"//src/dev-app/mdc-chips",
"//src/dev-app/mdc-dialog",
"//src/dev-app/mdc-input",
"//src/dev-app/mdc-list",
"//src/dev-app/mdc-menu",
Expand Down
1 change: 1 addition & 0 deletions src/dev-app/dev-app/dev-app-layout.ts
Expand Up @@ -78,6 +78,7 @@ export class DevAppLayout {
{name: 'MDC Card', route: '/mdc-card'},
{name: 'MDC Checkbox', route: '/mdc-checkbox'},
{name: 'MDC Chips', route: '/mdc-chips'},
{name: 'MDC Dialog', route: '/mdc-dialog'},
{name: 'MDC Input', route: '/mdc-input'},
{name: 'MDC List', route: '/mdc-list'},
{name: 'MDC Menu', route: '/mdc-menu'},
Expand Down
1 change: 1 addition & 0 deletions src/dev-app/dev-app/routes.ts
Expand Up @@ -80,6 +80,7 @@ export const DEV_APP_ROUTES: Routes = [
loadChildren: 'mdc-progress-bar/mdc-progress-bar-demo-module#MdcProgressBarDemoModule'
},
{path: 'mdc-chips', loadChildren: 'mdc-chips/mdc-chips-demo-module#MdcChipsDemoModule'},
{path: 'mdc-dialog', loadChildren: 'mdc-dialog/mdc-dialog-demo-module#MdcDialogDemoModule'},
{path: 'mdc-input', loadChildren: 'mdc-input/mdc-input-demo-module#MdcInputDemoModule'},
{path: 'mdc-list', loadChildren: 'mdc-list/mdc-list-demo-module#MdcListDemoModule'},
{path: 'mdc-menu', loadChildren: 'mdc-menu/mdc-menu-demo-module#MdcMenuDemoModule'},
Expand Down
29 changes: 29 additions & 0 deletions src/dev-app/mdc-dialog/BUILD.bazel
@@ -0,0 +1,29 @@
load("//tools:defaults.bzl", "ng_module", "sass_binary")

package(default_visibility = ["//visibility:public"])

ng_module(
name = "mdc-dialog",
srcs = glob(["**/*.ts"]),
assets = [
"mdc-dialog-demo.html",
":mdc_dialog_demo_scss",
],
deps = [
"//src/material-experimental/mdc-dialog",
"//src/material/button",
"//src/material/card",
"//src/material/checkbox",
"//src/material/form-field",
"//src/material/input",
"//src/material/select",
"@npm//@angular/router",
],
)

sass_binary(
name = "mdc_dialog_demo_scss",
src = "mdc-dialog-demo.scss",
include_paths = ["external/npm/node_modules"],
deps = ["//src/material-experimental/mdc-dialog:mdc_dialog_scss_lib"],
)
36 changes: 36 additions & 0 deletions src/dev-app/mdc-dialog/mdc-dialog-demo-module.ts
@@ -0,0 +1,36 @@
/**
* @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 {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {MatDialogModule} from '@angular/material-experimental/mdc-dialog';
import {MatButtonModule} from '@angular/material/button';
import {MatCardModule} from '@angular/material/card';
import {MatCheckboxModule} from '@angular/material/checkbox';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatInputModule} from '@angular/material/input';
import {MatSelectModule} from '@angular/material/select';
import {RouterModule} from '@angular/router';
import {ContentElementDialog, DialogDemo, IFrameDialog, JazzDialog} from './mdc-dialog-demo';

@NgModule({
imports: [
FormsModule,
MatButtonModule,
MatCardModule,
MatCheckboxModule,
MatDialogModule,
MatFormFieldModule,
MatInputModule,
MatSelectModule,
RouterModule.forChild([{path: '', component: DialogDemo}]),
],
declarations: [ContentElementDialog, DialogDemo, IFrameDialog, JazzDialog],
})
export class MdcDialogDemoModule {
}
137 changes: 137 additions & 0 deletions src/dev-app/mdc-dialog/mdc-dialog-demo.html
@@ -0,0 +1,137 @@
<h1>Dialog demo</h1>

<button mat-raised-button color="primary" (click)="openJazz()" class="demo-dialog-button">
Open dialog
</button>
<button mat-raised-button color="accent" (click)="openContentElement()" class="demo-dialog-button">
Open dialog with content elements
</button>
<button mat-raised-button color="accent" (click)="openTemplate()" class="demo-dialog-button">
Open dialog with template content
</button>

<p>
<mat-checkbox [(ngModel)]="enableLegacyPadding">Enable legacy padding</mat-checkbox>
</p>

<mat-card class="demo-dialog-card">
<mat-card-content>
<h2>Dialog dimensions</h2>

<p>
<mat-form-field>
<mat-label>Width</mat-label>
<input matInput [(ngModel)]="config.width">
</mat-form-field>
<mat-form-field>
<mat-label>Height</mat-label>
<input matInput [(ngModel)]="config.height">
</mat-form-field>
</p>

<p>
<mat-form-field>
<mat-label>Min width</mat-label>
<input matInput [(ngModel)]="config.minWidth">
</mat-form-field>
<mat-form-field>
<mat-label>Min height</mat-label>
<input matInput [(ngModel)]="config.minHeight">
</mat-form-field>
</p>

<p>
<mat-form-field>
<mat-label>Max width</mat-label>
<input matInput [(ngModel)]="config.maxWidth">
</mat-form-field>
<mat-form-field>
<mat-label>Max height</mat-label>
<input matInput [(ngModel)]="config.maxHeight">
</mat-form-field>
</p>

<h2>Dialog position</h2>

<p>
<mat-form-field>
<mat-label>Top</mat-label>
<input matInput [(ngModel)]="config.position.top" (change)="config.position.bottom = ''">
</mat-form-field>
<mat-form-field>
<mat-label>Bottom</mat-label>
<input matInput [(ngModel)]="config.position.bottom" (change)="config.position.top = ''">
</mat-form-field>
</p>

<p>
<mat-form-field>
<mat-label>Left</mat-label>
<input matInput [(ngModel)]="config.position.left" (change)="config.position.right = ''">
</mat-form-field>
<mat-form-field>
<mat-label>Right</mat-label>
<input matInput [(ngModel)]="config.position.right" (change)="config.position.left = ''">
</mat-form-field>
</p>

<h2>Dialog backdrop</h2>

<p>
<mat-form-field>
<mat-label>Backdrop class</mat-label>
<input matInput [(ngModel)]="config.backdropClass">
</mat-form-field>
</p>

<mat-checkbox [(ngModel)]="config.hasBackdrop">Has backdrop</mat-checkbox>

<h2>Other options</h2>

<p>
<mat-form-field>
<mat-label>Button alignment</mat-label>
<mat-select [(ngModel)]="actionsAlignment">
<mat-option>Start</mat-option>
<mat-option value="end">End</mat-option>
<mat-option value="center">Center</mat-option>
</mat-select>
</mat-form-field>
</p>

<p>
<mat-form-field>
<mat-label>Dialog message</mat-label>
<input matInput [(ngModel)]="config.data.message">
</mat-form-field>
</p>

<p>
<mat-checkbox [(ngModel)]="config.disableClose">Disable close</mat-checkbox>
</p>
</mat-card-content>
</mat-card>

<p>Last afterClosed result: {{lastAfterClosedResult}}</p>
<p>Last beforeClose result: {{lastBeforeCloseResult}}</p>

<ng-template let-data let-dialogRef="dialogRef">
I'm a template dialog. I've been opened {{numTemplateOpens}} times!

<p>It's Jazz!</p>

<mat-form-field>
<mat-label>How much?</mat-label>
<input matInput #howMuch>
</mat-form-field>

<p> {{ data.message }} </p>
<button type="button" (click)="dialogRef.close(howMuch.value)" class="demo-dialog-button"
cdkFocusInitial>
Close dialog
</button>
<button (click)="dialogRef.updateSize('500px', '500px').updatePosition({top: '25px', left: '25px'});"
class="demo-dialog-button">
Change dimensions
</button>
</ng-template>
19 changes: 19 additions & 0 deletions src/dev-app/mdc-dialog/mdc-dialog-demo.scss
@@ -0,0 +1,19 @@
@import '../../material-experimental/mdc-dialog/dialog-legacy-padding';

.demo-dialog-card {
max-width: 405px;
margin: 20px 0;
}

.demo-dialog-button {
margin-right: 8px;

[dir='rtl'] & {
margin-left: 8px;
margin-right: 0;
}
}

.demo-dialog-legacy-padding {
@include mat-mdc-dialog-legacy-padding();
}

0 comments on commit d137848

Please sign in to comment.