From 5877b8acf98ac637af55d3cf51500c00bb225dbe Mon Sep 17 00:00:00 2001 From: crisbeto Date: Sat, 31 Dec 2016 14:55:24 +0200 Subject: [PATCH] proposal(dialog): better handling of scrollable content Currently, the dialog's scrollable content (md-dialog-content) is limited to 65% of the viewport height, however on smaller screens the dialog still ends up being too high (see issue #2481). This proposal reworks the `md-dialog-content` to make it take up all of the remaining height, instead of being hardcoded to 65%. The max height is provided by the wrapper instead. The issue with this approach is that the direct parent of the `md-dialog-content` has to be `display: flex`, which can end up modifying the user's content. I see a couple of solutions, but I'm not sure which one to go with: 1. Conditionally add the flexbox styles, if the user has used `md-dialog-content`. That's what this PR is doing, however using `querySelector` to find out if the dialog content is there feels a little dirty. We're not able to use `@ViewChild` or `@ContentChild` to query for it. 2. Force the user to use our dialog content elements. This is what Material 1 was doing. --- src/lib/dialog/dialog-container.ts | 13 ++++++++++++- src/lib/dialog/dialog-content-directives.ts | 5 ++++- src/lib/dialog/dialog.scss | 14 +++++++++++--- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/lib/dialog/dialog-container.ts b/src/lib/dialog/dialog-container.ts index 6004809e8e05..957baa457538 100644 --- a/src/lib/dialog/dialog-container.ts +++ b/src/lib/dialog/dialog-container.ts @@ -5,10 +5,12 @@ import { ViewEncapsulation, NgZone, OnDestroy, + Renderer, } from '@angular/core'; import {BasePortalHost, ComponentPortal, PortalHostDirective, TemplatePortal} from '../core'; import {MdDialogConfig} from './dialog-config'; import {MdDialogRef} from './dialog-ref'; +import {MD_DIALOG_CONTENT_SELECTOR} from './dialog-content-directives'; import {MdDialogContentAlreadyAttachedError} from './dialog-errors'; import {FocusTrap} from '../core/a11y/focus-trap'; import 'rxjs/add/operator/first'; @@ -46,7 +48,7 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy { /** Reference to the open dialog. */ dialogRef: MdDialogRef; - constructor(private _ngZone: NgZone) { + constructor(private _ngZone: NgZone, private _renderer: Renderer) { super(); } @@ -60,6 +62,15 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy { } let attachResult = this._portalHost.attachComponentPortal(portal); + let componentElement = attachResult.location.nativeElement; + + // Add a class that we can use for styling the root element. + this._renderer.setElementClass(componentElement, 'md-dialog-root', true); + + if ('querySelector' in componentElement) { + this._renderer.setElementClass(componentElement, 'md-dialog-root-flex', + !!componentElement.querySelector(MD_DIALOG_CONTENT_SELECTOR)); + } // If were to attempt to focus immediately, then the content of the dialog would not yet be // ready in instances where change detection has to run first. To deal with this, we simply diff --git a/src/lib/dialog/dialog-content-directives.ts b/src/lib/dialog/dialog-content-directives.ts index a7c8e3875ef1..17804dc40b01 100644 --- a/src/lib/dialog/dialog-content-directives.ts +++ b/src/lib/dialog/dialog-content-directives.ts @@ -1,6 +1,9 @@ import {Directive, Input} from '@angular/core'; import {MdDialogRef} from './dialog-ref'; +export const MD_DIALOG_CONTENT_SELECTOR = '[md-dialog-content], md-dialog-content' + + ', [mat-dialog-content], mat-dialog-content'; + /** * Button that will close the current dialog. @@ -32,7 +35,7 @@ export class MdDialogTitle { } * Scrollable content container of a dialog. */ @Directive({ - selector: '[md-dialog-content], md-dialog-content, [mat-dialog-content], mat-dialog-content' + selector: MD_DIALOG_CONTENT_SELECTOR }) export class MdDialogContent { } diff --git a/src/lib/dialog/dialog.scss b/src/lib/dialog/dialog.scss index 71119a2d11f8..e53e81fe0834 100644 --- a/src/lib/dialog/dialog.scss +++ b/src/lib/dialog/dialog.scss @@ -5,7 +5,7 @@ $md-dialog-padding: 24px !default; $md-dialog-border-radius: 2px !default; $md-dialog-max-width: 80vw !default; -$md-dialog-max-height: 65vh !default; +$md-dialog-max-height: 80vh !default; md-dialog-container { @include md-elevation(24); @@ -15,7 +15,6 @@ md-dialog-container { border-radius: $md-dialog-border-radius; box-sizing: border-box; overflow: auto; - max-width: $md-dialog-max-width; // The dialog container should completely fill its parent overlay element. width: 100%; @@ -26,11 +25,20 @@ md-dialog-container { } } +.md-dialog-root { + max-height: calc(#{$md-dialog-max-height} - #{$md-dialog-padding * 2}); + max-width: $md-dialog-max-width; + + &.md-dialog-root-flex { + display: flex; + flex-flow: column; + } +} + md-dialog-content, [md-dialog-content], mat-dialog-content, [mat-dialog-content] { display: block; margin: 0 $md-dialog-padding * -1; padding: 0 $md-dialog-padding; - max-height: $md-dialog-max-height; overflow: auto; }