Skip to content

Commit

Permalink
fix(menu): wrong offset for nested menu in a fallback position (#7562)
Browse files Browse the repository at this point in the history
* Adds the ability to set offsets on connected position fallbacks.
* Fixes wrong positioning of nested menu if they're in a fallback position.

Fixes #7549.
  • Loading branch information
crisbeto authored and andrewseguin committed Oct 12, 2017
1 parent f0f6a74 commit 074f6ce
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 10 deletions.
22 changes: 22 additions & 0 deletions src/cdk/overlay/position/connected-position-strategy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
16 changes: 12 additions & 4 deletions src/cdk/overlay/position/connected-position-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down
7 changes: 6 additions & 1 deletion src/cdk/overlay/position/connected-position.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 4 additions & 5 deletions src/lib/menu/menu-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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. */
Expand Down

0 comments on commit 074f6ce

Please sign in to comment.