From c812268ac3eb27a69476d1ee59b34ec1d21bf8d2 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 31 Aug 2018 02:28:20 +0200 Subject: [PATCH] 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. --- e2e/components/menu-e2e.spec.ts | 2 +- src/demo-app/menu/menu-demo.html | 12 +++++------ src/e2e-app/menu/menu-e2e.html | 18 ++++++++++++---- src/lib/menu/_menu-theme.scss | 6 +++--- src/lib/menu/menu-animations.ts | 19 +++++------------ src/lib/menu/menu-directive.ts | 4 ++-- src/lib/menu/menu.scss | 4 ++-- src/lib/menu/menu.spec.ts | 36 ++++++++++++++------------------ 8 files changed, 49 insertions(+), 52 deletions(-) diff --git a/e2e/components/menu-e2e.spec.ts b/e2e/components/menu-e2e.spec.ts index 3e1aca71d25..b0516492f09 100644 --- a/e2e/components/menu-e2e.spec.ts +++ b/e2e/components/menu-e2e.spec.ts @@ -156,7 +156,7 @@ describe('menu', () => { await expectAlignedWith(page.menu(), '#trigger'); }); - it('should align overlay end to origin end when x-position is "before"', async() => { + it('should align overlay end to origin end when x-position is "before"', async () => { page.beforeTrigger().click(); const trigger = await page.beforeTrigger().getLocation(); diff --git a/src/demo-app/menu/menu-demo.html b/src/demo-app/menu/menu-demo.html index ec454c5475e..7d679932eda 100644 --- a/src/demo-app/menu/menu-demo.html +++ b/src/demo-app/menu/menu-demo.html @@ -137,7 +137,7 @@
-

overlapTrigger: false

+

overlapTrigger: true

- + @@ -153,7 +153,7 @@

- Position x: before, overlapTrigger: false + Position x: before, overlapTrigger: true

- +

- Position y: above, overlapTrigger: false + Position y: above, overlapTrigger: true

- + diff --git a/src/e2e-app/menu/menu-e2e.html b/src/e2e-app/menu/menu-e2e.html index 6c07798831a..e64c5f0f23b 100644 --- a/src/e2e-app/menu/menu-e2e.html +++ b/src/e2e-app/menu/menu-e2e.html @@ -5,7 +5,7 @@ - + @@ -15,20 +15,30 @@ - +
- + - + diff --git a/src/lib/menu/_menu-theme.scss b/src/lib/menu/_menu-theme.scss index b6175bc31ad..50b2f537629 100644 --- a/src/lib/menu/_menu-theme.scss +++ b/src/lib/menu/_menu-theme.scss @@ -40,9 +40,9 @@ @mixin mat-menu-typography($config) { .mat-menu-item { font: { - family: mat-font-family($config, subheading-2); - size: mat-font-size($config, subheading-2); - weight: mat-font-weight($config, subheading-2); + family: mat-font-family($config, body-1); + size: mat-font-size($config, body-1); + weight: mat-font-weight($config, body-1); } } } diff --git a/src/lib/menu/menu-animations.ts b/src/lib/menu/menu-animations.ts index 7ba329b2675..fb0114f52ae 100644 --- a/src/lib/menu/menu-animations.ts +++ b/src/lib/menu/menu-animations.ts @@ -14,7 +14,6 @@ import{ transition, query, group, - sequence, AnimationTriggerMetadata, } from '@angular/animations'; @@ -38,21 +37,13 @@ export const matMenuAnimations: { transformMenu: trigger('transformMenu', [ state('void', style({ opacity: 0, - // This starts off from 0.01, instead of 0, because there's an issue in the Angular animations - // as of 4.2, which causes the animation to be skipped if it starts from 0. - transform: 'scale(0.01, 0.01)' + transform: 'scale(0.8)' })), - transition('void => enter', sequence([ - query('.mat-menu-content', style({opacity: 0})), - animate('100ms linear', style({opacity: 1, transform: 'scale(1, 0.5)'})), - group([ - query('.mat-menu-content', animate('400ms cubic-bezier(0.55, 0, 0.55, 0.2)', - style({opacity: 1}) - )), - animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({transform: 'scale(1, 1)'})), - ]) + transition('void => enter', group([ + query('.mat-menu-content', animate('100ms linear', style({opacity: 1}))), + animate('120ms cubic-bezier(0, 0, 0.2, 1)', style({transform: 'scale(1)'})), ])), - transition('* => void', animate('150ms 50ms linear', style({opacity: 0}))) + transition('* => void', animate('100ms 25ms linear', style({opacity: 0}))) ]), diff --git a/src/lib/menu/menu-directive.ts b/src/lib/menu/menu-directive.ts index d9b665be666..008ce1056c6 100644 --- a/src/lib/menu/menu-directive.ts +++ b/src/lib/menu/menu-directive.ts @@ -69,7 +69,7 @@ export const MAT_MENU_DEFAULT_OPTIONS = /** @docs-private */ export function MAT_MENU_DEFAULT_OPTIONS_FACTORY(): MatMenuDefaultOptions { return { - overlapTrigger: true, + overlapTrigger: false, xPosition: 'after', yPosition: 'below', backdropClass: 'cdk-overlay-transparent-backdrop', @@ -79,7 +79,7 @@ export function MAT_MENU_DEFAULT_OPTIONS_FACTORY(): MatMenuDefaultOptions { * Start elevation for the menu panel. * @docs-private */ -const MAT_MENU_BASE_ELEVATION = 2; +const MAT_MENU_BASE_ELEVATION = 4; @Component({ diff --git a/src/lib/menu/menu.scss b/src/lib/menu/menu.scss index 177fbcdec97..255c5fa4714 100644 --- a/src/lib/menu/menu.scss +++ b/src/lib/menu/menu.scss @@ -5,11 +5,11 @@ @import '../../cdk/a11y/a11y'; $mat-menu-vertical-padding: 8px !default; -$mat-menu-border-radius: 2px !default; +$mat-menu-border-radius: 4px !default; $mat-menu-submenu-indicator-size: 10px !default; .mat-menu-panel { - @include mat-menu-base(2); + @include mat-menu-base(4); max-height: calc(100vh - #{$mat-menu-item-height}); border-radius: $mat-menu-border-radius; outline: 0; diff --git a/src/lib/menu/menu.spec.ts b/src/lib/menu/menu.spec.ts index 2bcce9d52f4..c1f18c6ae05 100644 --- a/src/lib/menu/menu.spec.ts +++ b/src/lib/menu/menu.spec.ts @@ -625,7 +625,7 @@ describe('MatMenu', () => { let panel = overlayContainerElement.querySelector('.mat-menu-panel') as HTMLElement; expect(Math.floor(panel.getBoundingClientRect().bottom)) - .toBe(Math.floor(trigger.getBoundingClientRect().bottom), 'Expected menu to open above'); + .toBe(Math.floor(trigger.getBoundingClientRect().top), 'Expected menu to open above'); fixture.componentInstance.trigger.closeMenu(); fixture.detectChanges(); @@ -638,7 +638,7 @@ describe('MatMenu', () => { panel = overlayContainerElement.querySelector('.mat-menu-panel') as HTMLElement; expect(Math.floor(panel.getBoundingClientRect().top)) - .toBe(Math.floor(trigger.getBoundingClientRect().top), 'Expected menu to open below'); + .toBe(Math.floor(trigger.getBoundingClientRect().bottom), 'Expected menu to open below'); }); }); @@ -671,7 +671,7 @@ describe('MatMenu', () => { // The y-position of the overlay should be unaffected, as it can already fit vertically expect(Math.floor(overlayRect.top)) - .toBe(Math.floor(triggerRect.top), + .toBe(Math.floor(triggerRect.bottom), `Expected menu top position to be unchanged if it can fit in the viewport.`); }); @@ -691,11 +691,8 @@ describe('MatMenu', () => { const triggerRect = trigger.getBoundingClientRect(); const overlayRect = overlayPane.getBoundingClientRect(); - // In "above" position, the bottom edges of the overlay and the origin are aligned. - // To find the overlay top, subtract the menu height from the origin's bottom edge. - const expectedTop = triggerRect.bottom - overlayRect.height; - expect(Math.floor(overlayRect.top)) - .toBe(Math.floor(expectedTop), + expect(Math.floor(overlayRect.bottom)) + .toBe(Math.floor(triggerRect.top), `Expected menu to open in "above" position if "below" position wouldn't fit.`); // The x-position of the overlay should be unaffected, as it can already fit horizontally @@ -722,14 +719,13 @@ describe('MatMenu', () => { const overlayRect = overlayPane.getBoundingClientRect(); const expectedLeft = triggerRect.right - overlayRect.width; - const expectedTop = triggerRect.bottom - overlayRect.height; expect(Math.floor(overlayRect.left)) .toBe(Math.floor(expectedLeft), `Expected menu to open in "before" position if "after" position wouldn't fit.`); - expect(Math.floor(overlayRect.top)) - .toBe(Math.floor(expectedTop), + expect(Math.floor(overlayRect.bottom)) + .toBe(Math.floor(triggerRect.top), `Expected menu to open in "above" position if "below" position wouldn't fit.`); }); @@ -753,7 +749,7 @@ describe('MatMenu', () => { // As designated "above" position won't fit on screen, the menu should fall back // to "below" mode, where the top edges of the overlay and trigger are aligned. expect(Math.floor(overlayRect.top)) - .toBe(Math.floor(triggerRect.top), + .toBe(Math.floor(triggerRect.bottom), `Expected menu to open in "below" position if "above" position wouldn't fit.`); }); @@ -1416,11 +1412,11 @@ describe('MatMenu', () => { const menus = overlay.querySelectorAll('.mat-menu-panel'); expect(menus[0].classList) - .toContain('mat-elevation-z2', 'Expected root menu to have base elevation.'); + .toContain('mat-elevation-z4', 'Expected root menu to have base elevation.'); expect(menus[1].classList) - .toContain('mat-elevation-z3', 'Expected first sub-menu to have base elevation + 1.'); + .toContain('mat-elevation-z5', 'Expected first sub-menu to have base elevation + 1.'); expect(menus[2].classList) - .toContain('mat-elevation-z4', 'Expected second sub-menu to have base elevation + 2.'); + .toContain('mat-elevation-z6', 'Expected second sub-menu to have base elevation + 2.'); }); it('should update the elevation when the same menu is opened at a different depth', @@ -1438,7 +1434,7 @@ describe('MatMenu', () => { let lastMenu = overlay.querySelectorAll('.mat-menu-panel')[2]; expect(lastMenu.classList) - .toContain('mat-elevation-z4', 'Expected menu to have the base elevation plus two.'); + .toContain('mat-elevation-z6', 'Expected menu to have the base elevation plus two.'); (overlay.querySelector('.cdk-overlay-backdrop')! as HTMLElement).click(); fixture.detectChanges(); @@ -1454,9 +1450,9 @@ describe('MatMenu', () => { lastMenu = overlay.querySelector('.mat-menu-panel') as HTMLElement; expect(lastMenu.classList) - .not.toContain('mat-elevation-z4', 'Expected menu not to maintain old elevation.'); + .not.toContain('mat-elevation-z6', 'Expected menu not to maintain old elevation.'); expect(lastMenu.classList) - .toContain('mat-elevation-z2', 'Expected menu to have the proper updated elevation.'); + .toContain('mat-elevation-z4', 'Expected menu to have the proper updated elevation.'); })); it('should not increase the elevation if the user specified a custom one', () => { @@ -1679,7 +1675,7 @@ describe('MatMenu default overrides', () => { declarations: [SimpleMenu, FakeIcon], providers: [{ provide: MAT_MENU_DEFAULT_OPTIONS, - useValue: {overlapTrigger: false, xPosition: 'before', yPosition: 'above'}, + useValue: {overlapTrigger: true, xPosition: 'before', yPosition: 'above'}, }], }).compileComponents(); })); @@ -1689,7 +1685,7 @@ describe('MatMenu default overrides', () => { fixture.detectChanges(); const menu = fixture.componentInstance.menu; - expect(menu.overlapTrigger).toBe(false); + expect(menu.overlapTrigger).toBe(true); expect(menu.xPosition).toBe('before'); expect(menu.yPosition).toBe('above'); });