@@ -15,6 +15,7 @@ import {
15
15
ScrollingVisibility ,
16
16
validateHorizontalPosition ,
17
17
validateVerticalPosition ,
18
+ ViewportMargin ,
18
19
} from './connected-position' ;
19
20
import { Observable , Subscription , Subject } from 'rxjs' ;
20
21
import { isElementScrolledOutsideView , isElementClippedByScrolling } from './scroll-clip' ;
@@ -106,8 +107,8 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
106
107
/** Cached container dimensions */
107
108
private _containerRect : Dimensions ;
108
109
109
- /** Amount of space that must be maintained between the overlay and the edge of the viewport. */
110
- private _viewportMargin = 0 ;
110
+ /** Amount of space that must be maintained between the overlay and the right edge of the viewport. */
111
+ private _viewportMargin : ViewportMargin = 0 ;
111
112
112
113
/** The Scrollable containers used to check scrollable view properties on position change. */
113
114
private _scrollables : CdkScrollable [ ] = [ ] ;
@@ -429,10 +430,11 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
429
430
}
430
431
431
432
/**
432
- * Sets a minimum distance the overlay may be positioned to the edge of the viewport.
433
- * @param margin Required margin between the overlay and the viewport edge in pixels.
433
+ * Sets a minimum distance the overlay may be positioned from the bottom edge of the viewport.
434
+ * @param margin Required margin between the overlay and the viewport.
435
+ * It can be a number to be applied to all directions, or an object to supply different values for each direction.
434
436
*/
435
- withViewportMargin ( margin : number ) : this {
437
+ withViewportMargin ( margin : ViewportMargin ) : this {
436
438
this . _viewportMargin = margin ;
437
439
return this ;
438
440
}
@@ -700,13 +702,17 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
700
702
if ( overlay . width <= viewport . width ) {
701
703
pushX = overflowLeft || - overflowRight ;
702
704
} else {
703
- pushX = start . x < this . _viewportMargin ? viewport . left - scrollPosition . left - start . x : 0 ;
705
+ pushX =
706
+ start . x < this . _getViewportMarginStart ( )
707
+ ? viewport . left - scrollPosition . left - start . x
708
+ : 0 ;
704
709
}
705
710
706
711
if ( overlay . height <= viewport . height ) {
707
712
pushY = overflowTop || - overflowBottom ;
708
713
} else {
709
- pushY = start . y < this . _viewportMargin ? viewport . top - scrollPosition . top - start . y : 0 ;
714
+ pushY =
715
+ start . y < this . _getViewportMarginTop ( ) ? viewport . top - scrollPosition . top - start . y : 0 ;
710
716
}
711
717
712
718
this . _previousPushAmount = { x : pushX , y : pushY } ;
@@ -795,13 +801,14 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
795
801
if ( position . overlayY === 'top' ) {
796
802
// Overlay is opening "downward" and thus is bound by the bottom viewport edge.
797
803
top = origin . y ;
798
- height = viewport . height - top + this . _viewportMargin ;
804
+ height = viewport . height - top + this . _getViewportMarginBottom ( ) ;
799
805
} else if ( position . overlayY === 'bottom' ) {
800
806
// Overlay is opening "upward" and thus is bound by the top viewport edge. We need to add
801
807
// the viewport margin back in, because the viewport rect is narrowed down to remove the
802
808
// margin, whereas the `origin` position is calculated based on its `DOMRect`.
803
- bottom = viewport . height - origin . y + this . _viewportMargin * 2 ;
804
- height = viewport . height - bottom + this . _viewportMargin ;
809
+ bottom =
810
+ viewport . height - origin . y + this . _getViewportMarginTop ( ) + this . _getViewportMarginBottom ( ) ;
811
+ height = viewport . height - bottom + this . _getViewportMarginTop ( ) ;
805
812
} else {
806
813
// If neither top nor bottom, it means that the overlay is vertically centered on the
807
814
// origin point. Note that we want the position relative to the viewport, rather than
@@ -833,11 +840,12 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
833
840
let width : number , left : number , right : number ;
834
841
835
842
if ( isBoundedByLeftViewportEdge ) {
836
- right = viewport . width - origin . x + this . _viewportMargin * 2 ;
837
- width = origin . x - this . _viewportMargin ;
843
+ right =
844
+ viewport . width - origin . x + this . _getViewportMarginStart ( ) + this . _getViewportMarginEnd ( ) ;
845
+ width = origin . x - this . _getViewportMarginStart ( ) ;
838
846
} else if ( isBoundedByRightViewportEdge ) {
839
847
left = origin . x ;
840
- width = viewport . right - origin . x ;
848
+ width = viewport . right - origin . x - this . _getViewportMarginEnd ( ) ;
841
849
} else {
842
850
// If neither start nor end, it means that the overlay is horizontally centered on the
843
851
// origin point. Note that we want the position relative to the viewport, rather than
@@ -1116,12 +1124,12 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
1116
1124
const scrollPosition = this . _viewportRuler . getViewportScrollPosition ( ) ;
1117
1125
1118
1126
return {
1119
- top : scrollPosition . top + this . _viewportMargin ,
1120
- left : scrollPosition . left + this . _viewportMargin ,
1121
- right : scrollPosition . left + width - this . _viewportMargin ,
1122
- bottom : scrollPosition . top + height - this . _viewportMargin ,
1123
- width : width - 2 * this . _viewportMargin ,
1124
- height : height - 2 * this . _viewportMargin ,
1127
+ top : scrollPosition . top + this . _getViewportMarginTop ( ) ,
1128
+ left : scrollPosition . left + this . _getViewportMarginStart ( ) ,
1129
+ right : scrollPosition . left + width - this . _getViewportMarginEnd ( ) ,
1130
+ bottom : scrollPosition . top + height - this . _getViewportMarginBottom ( ) ,
1131
+ width : width - this . _getViewportMarginStart ( ) - this . _getViewportMarginEnd ( ) ,
1132
+ height : height - this . _getViewportMarginTop ( ) - this . _getViewportMarginBottom ( ) ,
1125
1133
} ;
1126
1134
}
1127
1135
@@ -1186,6 +1194,42 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy {
1186
1194
}
1187
1195
}
1188
1196
1197
+ /**
1198
+ * Returns either the _viewportMargin directly (if it is a number) or its 'start' value.
1199
+ * @private
1200
+ */
1201
+ private _getViewportMarginStart ( ) : number {
1202
+ if ( typeof this . _viewportMargin === 'number' ) return this . _viewportMargin ;
1203
+ return this . _viewportMargin ?. start ?? 0 ;
1204
+ }
1205
+
1206
+ /**
1207
+ * Returns either the _viewportMargin directly (if it is a number) or its 'end' value.
1208
+ * @private
1209
+ */
1210
+ private _getViewportMarginEnd ( ) : number {
1211
+ if ( typeof this . _viewportMargin === 'number' ) return this . _viewportMargin ;
1212
+ return this . _viewportMargin ?. end ?? 0 ;
1213
+ }
1214
+
1215
+ /**
1216
+ * Returns either the _viewportMargin directly (if it is a number) or its 'top' value.
1217
+ * @private
1218
+ */
1219
+ private _getViewportMarginTop ( ) : number {
1220
+ if ( typeof this . _viewportMargin === 'number' ) return this . _viewportMargin ;
1221
+ return this . _viewportMargin ?. top ?? 0 ;
1222
+ }
1223
+
1224
+ /**
1225
+ * Returns either the _viewportMargin directly (if it is a number) or its 'bottom' value.
1226
+ * @private
1227
+ */
1228
+ private _getViewportMarginBottom ( ) : number {
1229
+ if ( typeof this . _viewportMargin === 'number' ) return this . _viewportMargin ;
1230
+ return this . _viewportMargin ?. bottom ?? 0 ;
1231
+ }
1232
+
1189
1233
/** Returns the DOMRect of the current origin. */
1190
1234
private _getOriginRect ( ) : Dimensions {
1191
1235
const origin = this . _origin ;
0 commit comments