Skip to content

Commit c812268

Browse files
crisbetojelbourn
authored andcommitted
feat(menu): align with 2018 material design spec (#12331)
Aligns the menu component with the latest version of the Material design spec. Includes making `overlapTrigger` false by default.
1 parent 2433b82 commit c812268

File tree

8 files changed

+49
-52
lines changed

8 files changed

+49
-52
lines changed

e2e/components/menu-e2e.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ describe('menu', () => {
156156
await expectAlignedWith(page.menu(), '#trigger');
157157
});
158158

159-
it('should align overlay end to origin end when x-position is "before"', async() => {
159+
it('should align overlay end to origin end when x-position is "before"', async () => {
160160
page.beforeTrigger().click();
161161

162162
const trigger = await page.beforeTrigger().getLocation();

src/demo-app/menu/menu-demo.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,31 +137,31 @@
137137

138138
<div class="demo-menu">
139139
<div class="demo-menu-section">
140-
<p>overlapTrigger: false</p>
140+
<p>overlapTrigger: true</p>
141141

142142
<mat-toolbar>
143143
<button mat-icon-button [mat-menu-trigger-for]="menuOverlay">
144144
<mat-icon>more_vert</mat-icon>
145145
</button>
146146
</mat-toolbar>
147147

148-
<mat-menu [overlapTrigger]="false" #menuOverlay="matMenu">
148+
<mat-menu [overlapTrigger]="true" #menuOverlay="matMenu">
149149
<button mat-menu-item *ngFor="let item of items" [disabled]="item.disabled">
150150
{{ item.text }}
151151
</button>
152152
</mat-menu>
153153
</div>
154154
<div class="demo-menu-section">
155155
<p>
156-
Position x: before, overlapTrigger: false
156+
Position x: before, overlapTrigger: true
157157
</p>
158158
<mat-toolbar class="demo-end-icon">
159159
<button mat-icon-button [mat-menu-trigger-for]="posXMenuOverlay">
160160
<mat-icon>more_vert</mat-icon>
161161
</button>
162162
</mat-toolbar>
163163

164-
<mat-menu xPosition="before" [overlapTrigger]="false" #posXMenuOverlay="matMenu">
164+
<mat-menu xPosition="before" [overlapTrigger]="true" #posXMenuOverlay="matMenu">
165165
<button mat-menu-item *ngFor="let item of iconItems" [disabled]="item.disabled">
166166
<mat-icon>{{ item.icon }}</mat-icon>
167167
{{ item.text }}
@@ -170,15 +170,15 @@
170170
</div>
171171
<div class="demo-menu-section">
172172
<p>
173-
Position y: above, overlapTrigger: false
173+
Position y: above, overlapTrigger: true
174174
</p>
175175
<mat-toolbar>
176176
<button mat-icon-button [mat-menu-trigger-for]="posYMenuOverlay">
177177
<mat-icon>more_vert</mat-icon>
178178
</button>
179179
</mat-toolbar>
180180

181-
<mat-menu yPosition="above" [overlapTrigger]="false" #posYMenuOverlay="matMenu">
181+
<mat-menu yPosition="above" [overlapTrigger]="true" #posYMenuOverlay="matMenu">
182182
<button mat-menu-item *ngFor="let item of items" [disabled]="item.disabled">
183183
{{ item.text }}
184184
</button>

src/e2e-app/menu/menu-e2e.html

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<button [matMenuTriggerFor]="menu" id="trigger">TRIGGER</button>
66
<button [matMenuTriggerFor]="menu" id="trigger-two">TRIGGER 2</button>
77

8-
<mat-menu #menu="matMenu" yPosition="below" class="custom">
8+
<mat-menu #menu="matMenu" yPosition="below" class="custom" overlapTrigger>
99
<button mat-menu-item (click)="selected='one'">One</button>
1010
<button mat-menu-item (click)="selected='two'">Two</button>
1111
<button mat-menu-item (click)="selected='three'" disabled>Three</button>
@@ -15,20 +15,30 @@
1515
<button [matMenuTriggerFor]="beforeMenu" id="before-t">
1616
BEFORE
1717
</button>
18-
<mat-menu xPosition="before" yPosition="below" class="before" #beforeMenu="matMenu">
18+
<mat-menu
19+
xPosition="before"
20+
yPosition="below"
21+
class="before"
22+
#beforeMenu="matMenu"
23+
overlapTrigger>
1924
<button mat-menu-item>Item</button>
2025
</mat-menu>
2126

2227
<div class="bottom-row">
2328
<button [matMenuTriggerFor]="aboveMenu" id="above-t">ABOVE</button>
24-
<mat-menu yPosition="above" class="above" #aboveMenu="matMenu">
29+
<mat-menu yPosition="above" class="above" #aboveMenu="matMenu" overlapTrigger>
2530
<button mat-menu-item>Item</button>
2631
</mat-menu>
2732

2833
<button [matMenuTriggerFor]="combined" id="combined-t">
2934
BOTH
3035
</button>
31-
<mat-menu xPosition="before" yPosition="above" class="combined" #combined="matMenu">
36+
<mat-menu
37+
xPosition="before"
38+
yPosition="above"
39+
class="combined"
40+
#combined="matMenu"
41+
overlapTrigger>
3242
<button mat-menu-item>Item</button>
3343
</mat-menu>
3444

src/lib/menu/_menu-theme.scss

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@
4040
@mixin mat-menu-typography($config) {
4141
.mat-menu-item {
4242
font: {
43-
family: mat-font-family($config, subheading-2);
44-
size: mat-font-size($config, subheading-2);
45-
weight: mat-font-weight($config, subheading-2);
43+
family: mat-font-family($config, body-1);
44+
size: mat-font-size($config, body-1);
45+
weight: mat-font-weight($config, body-1);
4646
}
4747
}
4848
}

src/lib/menu/menu-animations.ts

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import{
1414
transition,
1515
query,
1616
group,
17-
sequence,
1817
AnimationTriggerMetadata,
1918
} from '@angular/animations';
2019

@@ -38,21 +37,13 @@ export const matMenuAnimations: {
3837
transformMenu: trigger('transformMenu', [
3938
state('void', style({
4039
opacity: 0,
41-
// This starts off from 0.01, instead of 0, because there's an issue in the Angular animations
42-
// as of 4.2, which causes the animation to be skipped if it starts from 0.
43-
transform: 'scale(0.01, 0.01)'
40+
transform: 'scale(0.8)'
4441
})),
45-
transition('void => enter', sequence([
46-
query('.mat-menu-content', style({opacity: 0})),
47-
animate('100ms linear', style({opacity: 1, transform: 'scale(1, 0.5)'})),
48-
group([
49-
query('.mat-menu-content', animate('400ms cubic-bezier(0.55, 0, 0.55, 0.2)',
50-
style({opacity: 1})
51-
)),
52-
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({transform: 'scale(1, 1)'})),
53-
])
42+
transition('void => enter', group([
43+
query('.mat-menu-content', animate('100ms linear', style({opacity: 1}))),
44+
animate('120ms cubic-bezier(0, 0, 0.2, 1)', style({transform: 'scale(1)'})),
5445
])),
55-
transition('* => void', animate('150ms 50ms linear', style({opacity: 0})))
46+
transition('* => void', animate('100ms 25ms linear', style({opacity: 0})))
5647
]),
5748

5849

src/lib/menu/menu-directive.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export const MAT_MENU_DEFAULT_OPTIONS =
6969
/** @docs-private */
7070
export function MAT_MENU_DEFAULT_OPTIONS_FACTORY(): MatMenuDefaultOptions {
7171
return {
72-
overlapTrigger: true,
72+
overlapTrigger: false,
7373
xPosition: 'after',
7474
yPosition: 'below',
7575
backdropClass: 'cdk-overlay-transparent-backdrop',
@@ -79,7 +79,7 @@ export function MAT_MENU_DEFAULT_OPTIONS_FACTORY(): MatMenuDefaultOptions {
7979
* Start elevation for the menu panel.
8080
* @docs-private
8181
*/
82-
const MAT_MENU_BASE_ELEVATION = 2;
82+
const MAT_MENU_BASE_ELEVATION = 4;
8383

8484

8585
@Component({

src/lib/menu/menu.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
@import '../../cdk/a11y/a11y';
66

77
$mat-menu-vertical-padding: 8px !default;
8-
$mat-menu-border-radius: 2px !default;
8+
$mat-menu-border-radius: 4px !default;
99
$mat-menu-submenu-indicator-size: 10px !default;
1010

1111
.mat-menu-panel {
12-
@include mat-menu-base(2);
12+
@include mat-menu-base(4);
1313
max-height: calc(100vh - #{$mat-menu-item-height});
1414
border-radius: $mat-menu-border-radius;
1515
outline: 0;

src/lib/menu/menu.spec.ts

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ describe('MatMenu', () => {
625625
let panel = overlayContainerElement.querySelector('.mat-menu-panel') as HTMLElement;
626626

627627
expect(Math.floor(panel.getBoundingClientRect().bottom))
628-
.toBe(Math.floor(trigger.getBoundingClientRect().bottom), 'Expected menu to open above');
628+
.toBe(Math.floor(trigger.getBoundingClientRect().top), 'Expected menu to open above');
629629

630630
fixture.componentInstance.trigger.closeMenu();
631631
fixture.detectChanges();
@@ -638,7 +638,7 @@ describe('MatMenu', () => {
638638
panel = overlayContainerElement.querySelector('.mat-menu-panel') as HTMLElement;
639639

640640
expect(Math.floor(panel.getBoundingClientRect().top))
641-
.toBe(Math.floor(trigger.getBoundingClientRect().top), 'Expected menu to open below');
641+
.toBe(Math.floor(trigger.getBoundingClientRect().bottom), 'Expected menu to open below');
642642
});
643643

644644
});
@@ -671,7 +671,7 @@ describe('MatMenu', () => {
671671

672672
// The y-position of the overlay should be unaffected, as it can already fit vertically
673673
expect(Math.floor(overlayRect.top))
674-
.toBe(Math.floor(triggerRect.top),
674+
.toBe(Math.floor(triggerRect.bottom),
675675
`Expected menu top position to be unchanged if it can fit in the viewport.`);
676676
});
677677

@@ -691,11 +691,8 @@ describe('MatMenu', () => {
691691
const triggerRect = trigger.getBoundingClientRect();
692692
const overlayRect = overlayPane.getBoundingClientRect();
693693

694-
// In "above" position, the bottom edges of the overlay and the origin are aligned.
695-
// To find the overlay top, subtract the menu height from the origin's bottom edge.
696-
const expectedTop = triggerRect.bottom - overlayRect.height;
697-
expect(Math.floor(overlayRect.top))
698-
.toBe(Math.floor(expectedTop),
694+
expect(Math.floor(overlayRect.bottom))
695+
.toBe(Math.floor(triggerRect.top),
699696
`Expected menu to open in "above" position if "below" position wouldn't fit.`);
700697

701698
// The x-position of the overlay should be unaffected, as it can already fit horizontally
@@ -722,14 +719,13 @@ describe('MatMenu', () => {
722719
const overlayRect = overlayPane.getBoundingClientRect();
723720

724721
const expectedLeft = triggerRect.right - overlayRect.width;
725-
const expectedTop = triggerRect.bottom - overlayRect.height;
726722

727723
expect(Math.floor(overlayRect.left))
728724
.toBe(Math.floor(expectedLeft),
729725
`Expected menu to open in "before" position if "after" position wouldn't fit.`);
730726

731-
expect(Math.floor(overlayRect.top))
732-
.toBe(Math.floor(expectedTop),
727+
expect(Math.floor(overlayRect.bottom))
728+
.toBe(Math.floor(triggerRect.top),
733729
`Expected menu to open in "above" position if "below" position wouldn't fit.`);
734730
});
735731

@@ -753,7 +749,7 @@ describe('MatMenu', () => {
753749
// As designated "above" position won't fit on screen, the menu should fall back
754750
// to "below" mode, where the top edges of the overlay and trigger are aligned.
755751
expect(Math.floor(overlayRect.top))
756-
.toBe(Math.floor(triggerRect.top),
752+
.toBe(Math.floor(triggerRect.bottom),
757753
`Expected menu to open in "below" position if "above" position wouldn't fit.`);
758754
});
759755

@@ -1416,11 +1412,11 @@ describe('MatMenu', () => {
14161412
const menus = overlay.querySelectorAll('.mat-menu-panel');
14171413

14181414
expect(menus[0].classList)
1419-
.toContain('mat-elevation-z2', 'Expected root menu to have base elevation.');
1415+
.toContain('mat-elevation-z4', 'Expected root menu to have base elevation.');
14201416
expect(menus[1].classList)
1421-
.toContain('mat-elevation-z3', 'Expected first sub-menu to have base elevation + 1.');
1417+
.toContain('mat-elevation-z5', 'Expected first sub-menu to have base elevation + 1.');
14221418
expect(menus[2].classList)
1423-
.toContain('mat-elevation-z4', 'Expected second sub-menu to have base elevation + 2.');
1419+
.toContain('mat-elevation-z6', 'Expected second sub-menu to have base elevation + 2.');
14241420
});
14251421

14261422
it('should update the elevation when the same menu is opened at a different depth',
@@ -1438,7 +1434,7 @@ describe('MatMenu', () => {
14381434
let lastMenu = overlay.querySelectorAll('.mat-menu-panel')[2];
14391435

14401436
expect(lastMenu.classList)
1441-
.toContain('mat-elevation-z4', 'Expected menu to have the base elevation plus two.');
1437+
.toContain('mat-elevation-z6', 'Expected menu to have the base elevation plus two.');
14421438

14431439
(overlay.querySelector('.cdk-overlay-backdrop')! as HTMLElement).click();
14441440
fixture.detectChanges();
@@ -1454,9 +1450,9 @@ describe('MatMenu', () => {
14541450
lastMenu = overlay.querySelector('.mat-menu-panel') as HTMLElement;
14551451

14561452
expect(lastMenu.classList)
1457-
.not.toContain('mat-elevation-z4', 'Expected menu not to maintain old elevation.');
1453+
.not.toContain('mat-elevation-z6', 'Expected menu not to maintain old elevation.');
14581454
expect(lastMenu.classList)
1459-
.toContain('mat-elevation-z2', 'Expected menu to have the proper updated elevation.');
1455+
.toContain('mat-elevation-z4', 'Expected menu to have the proper updated elevation.');
14601456
}));
14611457

14621458
it('should not increase the elevation if the user specified a custom one', () => {
@@ -1679,7 +1675,7 @@ describe('MatMenu default overrides', () => {
16791675
declarations: [SimpleMenu, FakeIcon],
16801676
providers: [{
16811677
provide: MAT_MENU_DEFAULT_OPTIONS,
1682-
useValue: {overlapTrigger: false, xPosition: 'before', yPosition: 'above'},
1678+
useValue: {overlapTrigger: true, xPosition: 'before', yPosition: 'above'},
16831679
}],
16841680
}).compileComponents();
16851681
}));
@@ -1689,7 +1685,7 @@ describe('MatMenu default overrides', () => {
16891685
fixture.detectChanges();
16901686
const menu = fixture.componentInstance.menu;
16911687

1692-
expect(menu.overlapTrigger).toBe(false);
1688+
expect(menu.overlapTrigger).toBe(true);
16931689
expect(menu.xPosition).toBe('before');
16941690
expect(menu.yPosition).toBe('above');
16951691
});

0 commit comments

Comments
 (0)