@@ -22,6 +22,7 @@ import {coerceCssPixelValue, coerceArray} from '@angular/cdk/coercion';
2222import { Platform } from '@angular/cdk/platform' ;
2323import { OverlayContainer } from '../overlay-container' ;
2424import { OverlayRef } from '../overlay-ref' ;
25+ import { ViewportMargin } from './viewport-margin' ;
2526
2627// TODO: refactor clipping detection into a separate thing (part of scrolling module)
2728// TODO: doesn't handle both flexible width and height when it has to scroll along both axis.
@@ -88,8 +89,8 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
8889 /** Cached container dimensions */
8990 private _containerRect : Dimensions ;
9091
91- /** Amount of space that must be maintained between the overlay and the edge of the viewport. */
92- private _viewportMargin = 0 ;
92+ /** Amount of space that must be maintained between the overlay and the right edge of the viewport. */
93+ private _viewportMargin : ViewportMargin = 0 ;
9394
9495 /** The Scrollable containers used to check scrollable view properties on position change. */
9596 private _scrollables : CdkScrollable [ ] = [ ] ;
@@ -411,10 +412,11 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
411412 }
412413
413414 /**
414- * Sets a minimum distance the overlay may be positioned to the edge of the viewport.
415- * @param margin Required margin between the overlay and the viewport edge in pixels.
415+ * Sets a minimum distance the overlay may be positioned from the bottom edge of the viewport.
416+ * @param margin Required margin between the overlay and the viewport.
417+ * It can be a number to be applied to all directions, or an object to supply different values for each direction.
416418 */
417- withViewportMargin ( margin : number ) : this {
419+ withViewportMargin ( margin : ViewportMargin ) : this {
418420 this . _viewportMargin = margin ;
419421 return this ;
420422 }
@@ -682,13 +684,13 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
682684 if ( overlay . width <= viewport . width ) {
683685 pushX = overflowLeft || - overflowRight ;
684686 } else {
685- pushX = start . x < this . _viewportMargin ? viewport . left - scrollPosition . left - start . x : 0 ;
687+ pushX = start . x < this . _getViewportMarginStart ( ) ? viewport . left - scrollPosition . left - start . x : 0 ;
686688 }
687689
688690 if ( overlay . height <= viewport . height ) {
689691 pushY = overflowTop || - overflowBottom ;
690692 } else {
691- pushY = start . y < this . _viewportMargin ? viewport . top - scrollPosition . top - start . y : 0 ;
693+ pushY = start . y < this . _getViewportMarginTop ( ) ? viewport . top - scrollPosition . top - start . y : 0 ;
692694 }
693695
694696 this . _previousPushAmount = { x : pushX , y : pushY } ;
@@ -777,13 +779,13 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
777779 if ( position . overlayY === 'top' ) {
778780 // Overlay is opening "downward" and thus is bound by the bottom viewport edge.
779781 top = origin . y ;
780- height = viewport . height - top + this . _viewportMargin ;
782+ height = viewport . height - top + this . _getViewportMarginBottom ( ) ;
781783 } else if ( position . overlayY === 'bottom' ) {
782784 // Overlay is opening "upward" and thus is bound by the top viewport edge. We need to add
783785 // the viewport margin back in, because the viewport rect is narrowed down to remove the
784786 // margin, whereas the `origin` position is calculated based on its `DOMRect`.
785- bottom = viewport . height - origin . y + this . _viewportMargin * 2 ;
786- height = viewport . height - bottom + this . _viewportMargin ;
787+ bottom = viewport . height - origin . y + this . _getViewportMarginTop ( ) + this . _getViewportMarginBottom ( ) ;
788+ height = viewport . height - bottom + this . _getViewportMarginTop ( ) ;
787789 } else {
788790 // If neither top nor bottom, it means that the overlay is vertically centered on the
789791 // origin point. Note that we want the position relative to the viewport, rather than
@@ -815,11 +817,11 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
815817 let width : number , left : number , right : number ;
816818
817819 if ( isBoundedByLeftViewportEdge ) {
818- right = viewport . width - origin . x + this . _viewportMargin * 2 ;
819- width = origin . x - this . _viewportMargin ;
820+ right = viewport . width - origin . x + this . _getViewportMarginStart ( ) + this . _getViewportMarginEnd ( ) ;
821+ width = origin . x - this . _getViewportMarginStart ( ) ;
820822 } else if ( isBoundedByRightViewportEdge ) {
821823 left = origin . x ;
822- width = viewport . right - origin . x ;
824+ width = viewport . right - origin . x - this . _getViewportMarginEnd ( ) ;
823825 } else {
824826 // If neither start nor end, it means that the overlay is horizontally centered on the
825827 // origin point. Note that we want the position relative to the viewport, rather than
@@ -1098,12 +1100,12 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
10981100 const scrollPosition = this . _viewportRuler . getViewportScrollPosition ( ) ;
10991101
11001102 return {
1101- top : scrollPosition . top + this . _viewportMargin ,
1102- left : scrollPosition . left + this . _viewportMargin ,
1103- right : scrollPosition . left + width - this . _viewportMargin ,
1104- bottom : scrollPosition . top + height - this . _viewportMargin ,
1105- width : width - 2 * this . _viewportMargin ,
1106- height : height - 2 * this . _viewportMargin ,
1103+ top : scrollPosition . top + this . _getViewportMarginTop ( ) ,
1104+ left : scrollPosition . left + this . _getViewportMarginStart ( ) ,
1105+ right : scrollPosition . left + width - this . _getViewportMarginEnd ( ) ,
1106+ bottom : scrollPosition . top + height - this . _getViewportMarginBottom ( ) ,
1107+ width : width - this . _getViewportMarginStart ( ) - this . _getViewportMarginEnd ( ) ,
1108+ height : height - this . _getViewportMarginTop ( ) - this . _getViewportMarginBottom ( ) ,
11071109 } ;
11081110 }
11091111
@@ -1168,6 +1170,42 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
11681170 }
11691171 }
11701172
1173+ /**
1174+ * Returns either the _viewportMargin directly (if it is a number) or its 'start' value.
1175+ * @private
1176+ */
1177+ private _getViewportMarginStart ( ) : number {
1178+ if ( typeof this . _viewportMargin === 'number' ) return this . _viewportMargin ;
1179+ return this . _viewportMargin . start ?? 0
1180+ }
1181+
1182+ /**
1183+ * Returns either the _viewportMargin directly (if it is a number) or its 'end' value.
1184+ * @private
1185+ */
1186+ private _getViewportMarginEnd ( ) : number {
1187+ if ( typeof this . _viewportMargin === 'number' ) return this . _viewportMargin ;
1188+ return this . _viewportMargin . end ?? 0 ;
1189+ }
1190+
1191+ /**
1192+ * Returns either the _viewportMargin directly (if it is a number) or its 'top' value.
1193+ * @private
1194+ */
1195+ private _getViewportMarginTop ( ) : number {
1196+ if ( typeof this . _viewportMargin === 'number' ) return this . _viewportMargin ;
1197+ return this . _viewportMargin . top ?? 0 ;
1198+ }
1199+
1200+ /**
1201+ * Returns either the _viewportMargin directly (if it is a number) or its 'bottom' value.
1202+ * @private
1203+ */
1204+ private _getViewportMarginBottom ( ) : number {
1205+ if ( typeof this . _viewportMargin === 'number' ) return this . _viewportMargin ;
1206+ return this . _viewportMargin . bottom ?? 0 ;
1207+ }
1208+
11711209 /** Returns the DOMRect of the current origin. */
11721210 private _getOriginRect ( ) : Dimensions {
11731211 const origin = this . _origin ;
0 commit comments