Skip to content

Commit

Permalink
fix(menu): reposition menu if it would open off screen
Browse files Browse the repository at this point in the history
  • Loading branch information
kara committed Nov 11, 2016
1 parent f7012a4 commit 2c0f680
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 101 deletions.
40 changes: 0 additions & 40 deletions src/lib/core/style/_menu-common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -47,43 +47,3 @@ $md-menu-side-padding: 16px !default;
}
}
}

/**
* This mixin adds the correct panel transform styles based
* on the direction that the menu panel opens.
*/
@mixin md-menu-positions() {
&.md-menu-after.md-menu-below {
transform-origin: left top;
}

&.md-menu-after.md-menu-above {
transform-origin: left bottom;
}

&.md-menu-before.md-menu-below {
transform-origin: right top;
}

&.md-menu-before.md-menu-above {
transform-origin: right bottom;
}

[dir='rtl'] & {
&.md-menu-after.md-menu-below {
transform-origin: right top;
}

&.md-menu-after.md-menu-above {
transform-origin: right bottom;
}

&.md-menu-before.md-menu-below {
transform-origin: left top;
}

&.md-menu-before.md-menu-above {
transform-origin: left bottom;
}
}
}
15 changes: 2 additions & 13 deletions src/lib/menu/menu-directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ export class MdMenu implements AfterContentInit, MdMenuPanel, OnDestroy {
/** Subscription to tab events on the menu panel */
private _tabSubscription: Subscription;

selector = '.md-menu-panel';

/** Config object to be passed into the menu's ngClass */
_classList: any = {};

Expand All @@ -54,7 +56,6 @@ export class MdMenu implements AfterContentInit, MdMenuPanel, OnDestroy {
@Attribute('y-position') posY: MenuPositionY) {
if (posX) { this._setPositionX(posX); }
if (posY) { this._setPositionY(posY); }
this._setPositionClasses();
}

// TODO: internal
Expand Down Expand Up @@ -83,7 +84,6 @@ export class MdMenu implements AfterContentInit, MdMenuPanel, OnDestroy {
obj[className] = true;
return obj;
}, {});
this._setPositionClasses();
}

@Output() close = new EventEmitter<void>();
Expand Down Expand Up @@ -119,15 +119,4 @@ export class MdMenu implements AfterContentInit, MdMenuPanel, OnDestroy {
this.positionY = pos;
}

/**
* It's necessary to set position-based classes to ensure the menu panel animation
* folds out from the correct direction.
*/
private _setPositionClasses() {
this._classList['md-menu-before'] = this.positionX == 'before';
this._classList['md-menu-after'] = this.positionX == 'after';
this._classList['md-menu-above'] = this.positionY == 'above';
this._classList['md-menu-below'] = this.positionY == 'below';
}

}
1 change: 1 addition & 0 deletions src/lib/menu/menu-panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {MenuPositionX, MenuPositionY} from './menu-positions';
export interface MdMenuPanel {
positionX: MenuPositionX;
positionY: MenuPositionY;
selector: string;
templateRef: TemplateRef<any>;
close: EventEmitter<void>;
focusFirstItem: () => void;
Expand Down
40 changes: 31 additions & 9 deletions src/lib/menu/menu-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ import {
TemplatePortal,
ConnectedPositionStrategy,
HorizontalConnectionPos,
VerticalConnectionPos
VerticalConnectionPos,
OriginConnectionPosition,
OverlayConnectionPosition,
TransformOrigin
} from '../core';
import { Subscription } from 'rxjs/Subscription';

Expand Down Expand Up @@ -196,14 +199,33 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy {
* @returns ConnectedPositionStrategy
*/
private _getPosition(): ConnectedPositionStrategy {
const positionX: HorizontalConnectionPos = this.menu.positionX === 'before' ? 'end' : 'start';
const positionY: VerticalConnectionPos = this.menu.positionY === 'above' ? 'bottom' : 'top';

return this._overlay.position().connectedTo(
this._element,
{originX: positionX, originY: positionY},
{overlayX: positionX, overlayY: positionY}
);
const [posX, fallbackX]: HorizontalConnectionPos[] =
this.menu.positionX === 'before' ? ['end', 'start'] : ['start', 'end'];

const [posY, fallbackY]: VerticalConnectionPos[] =
this.menu.positionY === 'above' ? ['bottom', 'top'] : ['top', 'bottom'];
return this._overlay.position()
.connectedTo(this._element,
{originX: posX, originY: posY}, {overlayX: posX, overlayY: posY})
.withTransformOrigin(this.menu.selector, this._transformOrigin(posX, posY))
.withFallbackPosition(
{originX: fallbackX, originY: posY},
{overlayX: fallbackX, overlayY: posY},
this._transformOrigin(fallbackX, posY))
.withFallbackPosition(
{originX: posX, originY: fallbackY},
{overlayX: posX, overlayY: fallbackY},
this._transformOrigin(posX, fallbackY))
.withFallbackPosition(
{originX: fallbackX, originY: fallbackY},
{overlayX: fallbackX, overlayY: fallbackY},
this._transformOrigin(fallbackX, fallbackY));
}

/** Converts the designated point into a TransformOrigin. */
private _transformOrigin(x: HorizontalConnectionPos,
y: VerticalConnectionPos): TransformOrigin {
return `${x} ${y}` as TransformOrigin;
}

_handleMousedown(event: MouseEvent): void {
Expand Down
1 change: 0 additions & 1 deletion src/lib/menu/menu.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ $md-menu-vertical-padding: 8px !default;

.md-menu-panel {
@include md-menu-base();
@include md-menu-positions();

// max height must be 100% of the viewport height + one row height
max-height: calc(100vh + 48px);
Expand Down
Loading

0 comments on commit 2c0f680

Please sign in to comment.