@@ -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,17 @@ 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  = 
688+         start . x  <  this . _getViewportMarginStart ( ) 
689+           ? viewport . left  -  scrollPosition . left  -  start . x 
690+           : 0 ; 
686691    } 
687692
688693    if  ( overlay . height  <=  viewport . height )  { 
689694      pushY  =  overflowTop  ||  - overflowBottom ; 
690695    }  else  { 
691-       pushY  =  start . y  <  this . _viewportMargin  ? viewport . top  -  scrollPosition . top  -  start . y  : 0 ; 
696+       pushY  = 
697+         start . y  <  this . _getViewportMarginTop ( )  ? viewport . top  -  scrollPosition . top  -  start . y  : 0 ; 
692698    } 
693699
694700    this . _previousPushAmount  =  { x : pushX ,  y : pushY } ; 
@@ -777,13 +783,14 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
777783    if  ( position . overlayY  ===  'top' )  { 
778784      // Overlay is opening "downward" and thus is bound by the bottom viewport edge. 
779785      top  =  origin . y ; 
780-       height  =  viewport . height  -  top  +  this . _viewportMargin ; 
786+       height  =  viewport . height  -  top  +  this . _getViewportMarginBottom ( ) ; 
781787    }  else  if  ( position . overlayY  ===  'bottom' )  { 
782788      // Overlay is opening "upward" and thus is bound by the top viewport edge. We need to add 
783789      // the viewport margin back in, because the viewport rect is narrowed down to remove the 
784790      // 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 ; 
791+       bottom  = 
792+         viewport . height  -  origin . y  +  this . _getViewportMarginTop ( )  +  this . _getViewportMarginBottom ( ) ; 
793+       height  =  viewport . height  -  bottom  +  this . _getViewportMarginTop ( ) ; 
787794    }  else  { 
788795      // If neither top nor bottom, it means that the overlay is vertically centered on the 
789796      // origin point. Note that we want the position relative to the viewport, rather than 
@@ -815,11 +822,12 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
815822    let  width : number ,  left : number ,  right : number ; 
816823
817824    if  ( isBoundedByLeftViewportEdge )  { 
818-       right  =  viewport . width  -  origin . x  +  this . _viewportMargin  *  2 ; 
819-       width  =  origin . x  -  this . _viewportMargin ; 
825+       right  = 
826+         viewport . width  -  origin . x  +  this . _getViewportMarginStart ( )  +  this . _getViewportMarginEnd ( ) ; 
827+       width  =  origin . x  -  this . _getViewportMarginStart ( ) ; 
820828    }  else  if  ( isBoundedByRightViewportEdge )  { 
821829      left  =  origin . x ; 
822-       width  =  viewport . right  -  origin . x ; 
830+       width  =  viewport . right  -  origin . x   -   this . _getViewportMarginEnd ( ) ; 
823831    }  else  { 
824832      // If neither start nor end, it means that the overlay is horizontally centered on the 
825833      // origin point. Note that we want the position relative to the viewport, rather than 
@@ -1098,12 +1106,12 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
10981106    const  scrollPosition  =  this . _viewportRuler . getViewportScrollPosition ( ) ; 
10991107
11001108    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 , 
1109+       top : scrollPosition . top  +  this . _getViewportMarginTop ( ) , 
1110+       left : scrollPosition . left  +  this . _getViewportMarginStart ( ) , 
1111+       right : scrollPosition . left  +  width  -  this . _getViewportMarginEnd ( ) , 
1112+       bottom : scrollPosition . top  +  height  -  this . _getViewportMarginBottom ( ) , 
1113+       width : width  -  this . _getViewportMarginStart ( )   -  this . _getViewportMarginEnd ( ) , 
1114+       height : height  -  this . _getViewportMarginTop ( )   -  this . _getViewportMarginBottom ( ) , 
11071115    } ; 
11081116  } 
11091117
@@ -1168,6 +1176,42 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
11681176    } 
11691177  } 
11701178
1179+   /** 
1180+    * Returns either the _viewportMargin directly (if it is a number) or its 'start' value. 
1181+    * @private  
1182+    */ 
1183+   private  _getViewportMarginStart ( ) : number  { 
1184+     if  ( typeof  this . _viewportMargin  ===  'number' )  return  this . _viewportMargin ; 
1185+     return  this . _viewportMargin ?. start  ??  0 ; 
1186+   } 
1187+ 
1188+   /** 
1189+    * Returns either the _viewportMargin directly (if it is a number) or its 'end' value. 
1190+    * @private  
1191+    */ 
1192+   private  _getViewportMarginEnd ( ) : number  { 
1193+     if  ( typeof  this . _viewportMargin  ===  'number' )  return  this . _viewportMargin ; 
1194+     return  this . _viewportMargin ?. end  ??  0 ; 
1195+   } 
1196+ 
1197+   /** 
1198+    * Returns either the _viewportMargin directly (if it is a number) or its 'top' value. 
1199+    * @private  
1200+    */ 
1201+   private  _getViewportMarginTop ( ) : number  { 
1202+     if  ( typeof  this . _viewportMargin  ===  'number' )  return  this . _viewportMargin ; 
1203+     return  this . _viewportMargin ?. top  ??  0 ; 
1204+   } 
1205+ 
1206+   /** 
1207+    * Returns either the _viewportMargin directly (if it is a number) or its 'bottom' value. 
1208+    * @private  
1209+    */ 
1210+   private  _getViewportMarginBottom ( ) : number  { 
1211+     if  ( typeof  this . _viewportMargin  ===  'number' )  return  this . _viewportMargin ; 
1212+     return  this . _viewportMargin ?. bottom  ??  0 ; 
1213+   } 
1214+ 
11711215  /** Returns the DOMRect of the current origin. */ 
11721216  private  _getOriginRect ( ) : Dimensions  { 
11731217    const  origin  =  this . _origin ; 
0 commit comments