@@ -117,11 +117,10 @@ export class ConnectedPositionStrategy implements PositionStrategy {
117117 // (top, left) coordinate for the overlay at `pos`.
118118 let originPoint = this . _getOriginConnectionPoint ( originRect , pos ) ;
119119 let overlayPoint = this . _getOverlayPoint ( originPoint , overlayRect , viewportRect , pos ) ;
120- let overlayDimensions = this . _getCSSDimensions ( overlayRect , overlayPoint , pos ) ;
121120
122121 // If the overlay in the calculated position fits on-screen, put it there and we're done.
123122 if ( overlayPoint . fitsInViewport ) {
124- this . _setElementPosition ( element , overlayDimensions ) ;
123+ this . _setElementPosition ( element , overlayRect , overlayPoint , pos ) ;
125124
126125 // Save the last connected position in case the position needs to be re-calculated.
127126 this . _lastConnectedPosition = pos ;
@@ -140,8 +139,7 @@ export class ConnectedPositionStrategy implements PositionStrategy {
140139
141140 // If none of the preferred positions were in the viewport, take the one
142141 // with the largest visible area.
143- let fallbackDimensions = this . _getCSSDimensions ( overlayRect , fallbackPoint , fallbackPosition ) ;
144- this . _setElementPosition ( element , fallbackDimensions ) ;
142+ this . _setElementPosition ( element , overlayRect , fallbackPoint , fallbackPosition ) ;
145143
146144 return Promise . resolve ( null ) ;
147145 }
@@ -159,8 +157,7 @@ export class ConnectedPositionStrategy implements PositionStrategy {
159157
160158 let originPoint = this . _getOriginConnectionPoint ( originRect , lastPosition ) ;
161159 let overlayPoint = this . _getOverlayPoint ( originPoint , overlayRect , viewportRect , lastPosition ) ;
162- let overlayPosition = this . _getCSSDimensions ( overlayRect , overlayPoint , lastPosition ) ;
163- this . _setElementPosition ( this . _pane , overlayPosition ) ;
160+ this . _setElementPosition ( this . _pane , overlayRect , overlayPoint , lastPosition ) ;
164161 }
165162
166163 /**
@@ -304,39 +301,6 @@ export class ConnectedPositionStrategy implements PositionStrategy {
304301 return { x, y, fitsInViewport, visibleArea} ;
305302 }
306303
307- /**
308- * Determines which CSS properties to use when positioning the overlay,
309- * depending on the direction the element would expand in, if extra content
310- * was added.
311- */
312- private _getCSSDimensions ( overlayRect : ClientRect , overlayPoint : Point ,
313- pos : ConnectionPositionPair ) : CSSDimensionPair {
314-
315- const viewport = this . _viewportRuler . getViewportRect ( ) ;
316- const x : CSSDimension = { property : null , value : null } ;
317- const y : CSSDimension = { property : pos . overlayY === 'bottom' ? 'bottom' : 'top' , value : null } ;
318-
319- if ( this . _dir === 'rtl' ) {
320- x . property = pos . overlayX === 'end' ? 'left' : 'right' ;
321- } else {
322- x . property = pos . overlayX === 'end' ? 'right' : 'left' ;
323- }
324-
325- if ( x . property === 'left' ) {
326- x . value = overlayPoint . x ;
327- } else {
328- x . value = viewport . width - ( overlayPoint . x + overlayRect . width ) ;
329- }
330-
331- if ( y . property === 'top' ) {
332- y . value = overlayPoint . y ;
333- } else {
334- y . value = viewport . height - ( overlayPoint . y + overlayRect . height ) ;
335- }
336-
337- return { x, y} ;
338- }
339-
340304 /**
341305 * Gets the view properties of the trigger and overlay, including whether they are clipped
342306 * or completely outside the view of any of the strategy's scrollables.
@@ -385,10 +349,47 @@ export class ConnectedPositionStrategy implements PositionStrategy {
385349 }
386350
387351 /** Physically positions the overlay element to the given coordinate. */
388- private _setElementPosition ( element : HTMLElement , dimensions : CSSDimensionPair ) {
389- [ 'top' , 'bottom' , 'left' , 'right' ] . forEach ( prop => element . style [ prop ] = null ) ;
390- element . style [ dimensions . x . property ] = dimensions . x . value + 'px' ;
391- element . style [ dimensions . y . property ] = dimensions . y . value + 'px' ;
352+ private _setElementPosition (
353+ element : HTMLElement ,
354+ overlayRect : ClientRect ,
355+ overlayPoint : Point ,
356+ pos : ConnectionPositionPair ) {
357+ const viewport = this . _viewportRuler . getViewportRect ( ) ;
358+
359+ // We want to set either `top` or `bottom` based on whether the overlay wants to appear above
360+ // or below the origin and the direction in which the element will expand.
361+ let verticalStyleProperty = pos . overlayY === 'bottom' ? 'bottom' : 'top' ;
362+
363+ // When using `bottom`, we adjust the y position such that it is the distance
364+ // from the bottom of the viewport rather than the top.
365+ let y = verticalStyleProperty === 'top' ?
366+ overlayPoint . y :
367+ viewport . height - ( overlayPoint . y + overlayRect . height ) ;
368+
369+ // We want to set either `left` or `right` based on whether the overlay wants to appear "before"
370+ // or "after" the origin, which determines the direction in which the element will expand.
371+ // For the horizontal axis, the meaning of "before" and "after" change based on whether the
372+ // page is in RTL or LTR.
373+ let horizontalStyleProperty : string ;
374+ if ( this . _dir === 'rtl' ) {
375+ horizontalStyleProperty = pos . overlayX === 'end' ? 'left' : 'right' ;
376+ } else {
377+ horizontalStyleProperty = pos . overlayX === 'end' ? 'right' : 'left' ;
378+ }
379+
380+ // When we're setting `right`, we adjust the x position such that it is the distance
381+ // from the right edge of the viewport rather than the left edge.
382+ let x = horizontalStyleProperty === 'left' ?
383+ overlayPoint . x :
384+ viewport . width - ( overlayPoint . x + overlayRect . width ) ;
385+
386+
387+ // Reset any existing styles. This is necessary in case the preferred position has
388+ // changed since the last `apply`.
389+ [ 'top' , 'bottom' , 'left' , 'right' ] . forEach ( p => element . style [ p ] = null ) ;
390+
391+ element . style [ verticalStyleProperty ] = `${ y } px` ;
392+ element . style [ horizontalStyleProperty ] = `${ x } px` ;
392393 }
393394
394395 /** Returns the bounding positions of the provided element with respect to the viewport. */
@@ -427,15 +428,3 @@ interface OverlayPoint extends Point {
427428 visibleArea ?: number ;
428429 fitsInViewport ?: boolean ;
429430}
430-
431- /** Key-value pair, representing a CSS dimension. */
432- interface CSSDimension {
433- property : 'top' | 'bottom' | 'left' | 'right' ;
434- value : number ;
435- }
436-
437- /** A combination of CSS dimensions for the x and y axis. */
438- interface CSSDimensionPair {
439- x : CSSDimension ;
440- y : CSSDimension ;
441- }
0 commit comments