diff --git a/src/cdk/overlay/position/connected-position-strategy.spec.ts b/src/cdk/overlay/position/connected-position-strategy.spec.ts index 0ba80be29cd5..6195ea0ca8b6 100644 --- a/src/cdk/overlay/position/connected-position-strategy.spec.ts +++ b/src/cdk/overlay/position/connected-position-strategy.spec.ts @@ -326,6 +326,28 @@ describe('ConnectedPositionStrategy', () => { expect(Math.floor(overlayRect.left)).toBe(Math.floor(originRect.left)); }); + it('should allow for the fallback positions to specify their own offsets', () => { + originElement.style.bottom = '0'; + originRect = originElement.getBoundingClientRect(); + strategy = positionBuilder + .connectedTo( + fakeElementRef, + {originX: 'start', originY: 'top'}, + {overlayX: 'start', overlayY: 'top'}) + .withFallbackPosition( + {originX: 'start', originY: 'top'}, + {overlayX: 'start', overlayY: 'bottom'}, + -100, -100); + + strategy.withOffsetY(50).withOffsetY(50); + strategy.attach(fakeOverlayRef(overlayElement)); + strategy.apply(); + + let overlayRect = overlayElement.getBoundingClientRect(); + expect(Math.floor(overlayRect.bottom)).toBe(Math.floor(originRect.top - 100)); + expect(Math.floor(overlayRect.left)).toBe(Math.floor(originRect.left - 100)); + }); + }); it('should emit onPositionChange event when position changes', () => { diff --git a/src/cdk/overlay/position/connected-position-strategy.ts b/src/cdk/overlay/position/connected-position-strategy.ts index 3c26d310823b..a9a946524fd6 100644 --- a/src/cdk/overlay/position/connected-position-strategy.ts +++ b/src/cdk/overlay/position/connected-position-strategy.ts @@ -192,8 +192,12 @@ export class ConnectedPositionStrategy implements PositionStrategy { */ withFallbackPosition( originPos: OriginConnectionPosition, - overlayPos: OverlayConnectionPosition): this { - this._preferredPositions.push(new ConnectionPositionPair(originPos, overlayPos)); + overlayPos: OverlayConnectionPosition, + offsetX?: number, + offsetY?: number): this { + + const position = new ConnectionPositionPair(originPos, overlayPos, offsetX, offsetY); + this._preferredPositions.push(position); return this; } @@ -296,9 +300,13 @@ export class ConnectedPositionStrategy implements PositionStrategy { overlayStartY = pos.overlayY == 'top' ? 0 : -overlayRect.height; } + // The (x, y) offsets of the overlay based on the current position. + let offsetX = typeof pos.offsetX === 'undefined' ? this._offsetX : pos.offsetX; + let offsetY = typeof pos.offsetY === 'undefined' ? this._offsetY : pos.offsetY; + // The (x, y) coordinates of the overlay. - let x = originPoint.x + overlayStartX + this._offsetX; - let y = originPoint.y + overlayStartY + this._offsetY; + let x = originPoint.x + overlayStartX + offsetX; + let y = originPoint.y + overlayStartY + offsetY; // How much the overlay would overflow at this position, on each side. let leftOverflow = 0 - x; diff --git a/src/cdk/overlay/position/connected-position.ts b/src/cdk/overlay/position/connected-position.ts index 66cc66ce680e..ff9114fd8538 100644 --- a/src/cdk/overlay/position/connected-position.ts +++ b/src/cdk/overlay/position/connected-position.ts @@ -33,7 +33,12 @@ export class ConnectionPositionPair { overlayX: HorizontalConnectionPos; overlayY: VerticalConnectionPos; - constructor(origin: OriginConnectionPosition, overlay: OverlayConnectionPosition) { + constructor( + origin: OriginConnectionPosition, + overlay: OverlayConnectionPosition, + public offsetX?: number, + public offsetY?: number) { + this.originX = origin.originX; this.originY = origin.originY; this.overlayX = overlay.overlayX; diff --git a/src/lib/menu/menu-trigger.ts b/src/lib/menu/menu-trigger.ts index f135a8e63798..abc1a1a11998 100644 --- a/src/lib/menu/menu-trigger.ts +++ b/src/lib/menu/menu-trigger.ts @@ -354,9 +354,6 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy { // to the edges of the trigger, instead of overlapping it. overlayFallbackX = originX = this.menu.xPosition === 'before' ? 'start' : 'end'; originFallbackX = overlayX = originX === 'end' ? 'start' : 'end'; - - // TODO(crisbeto): this should be a function, once the overlay supports it. - // Right now it will be wrong for the fallback positions. offsetY = overlayY === 'bottom' ? MENU_PANEL_TOP_PADDING : -MENU_PANEL_TOP_PADDING; } else if (!this.menu.overlapTrigger) { originY = overlayY === 'top' ? 'bottom' : 'top'; @@ -372,10 +369,12 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy { {overlayX: overlayFallbackX, overlayY}) .withFallbackPosition( {originX, originY: originFallbackY}, - {overlayX, overlayY: overlayFallbackY}) + {overlayX, overlayY: overlayFallbackY}, + undefined, -offsetY) .withFallbackPosition( {originX: originFallbackX, originY: originFallbackY}, - {overlayX: overlayFallbackX, overlayY: overlayFallbackY}); + {overlayX: overlayFallbackX, overlayY: overlayFallbackY}, + undefined, -offsetY); } /** Cleans up the active subscriptions. */