diff --git a/demos/src/app/components/menu-surface/menu-surface.ts b/demos/src/app/components/menu-surface/menu-surface.ts index da98a1cdb..59da60c66 100644 --- a/demos/src/app/components/menu-surface/menu-surface.ts +++ b/demos/src/app/components/menu-surface/menu-surface.ts @@ -51,6 +51,7 @@ export class Api implements OnInit { {name: 'anchorElement: Element | mdcMenuSurfaceAnchor', summary: `Set to indicate an element the menu should be anchored to.`}, {name: 'fixed: boolean', summary: `Used to indicate that the menu is using fixed positioning.`}, {name: 'hoistToBody: boolean', summary: `Removes the menu-surface element from the DOM and appends it to the body element. Should be used to overcome overflow: hidden issues.`}, + {name: 'fullwidth: boolean', summary: `Sets the menu-surface's width to match that of its parent anchor. Do not use with 'fixed'.`}, ] }, ] diff --git a/demos/src/app/components/select/examples.html b/demos/src/app/components/select/examples.html index b0744ae4e..075ec39d2 100644 --- a/demos/src/app/components/select/examples.html +++ b/demos/src/app/components/select/examples.html @@ -10,6 +10,9 @@

Select

+ @@ -22,7 +25,7 @@

Select

- + Apple @@ -40,7 +43,7 @@

Select

No label

- + Apple @@ -67,7 +70,7 @@

Leading Icon

fastfood - + @@ -84,7 +87,7 @@

Custom Enhanced

- + @@ -97,7 +100,7 @@

Custom Enhanced

- + @@ -110,7 +113,7 @@

Custom Enhanced

- + @@ -129,7 +132,7 @@

Lazy Load

- + {{food.viewValue}} @@ -150,7 +153,7 @@

Lazy Load

Select with [compareWith]

- + {{fruit.name}} @@ -179,7 +182,7 @@

Select with ngModel

- + {{food.viewValue}} @@ -218,7 +221,7 @@

Select with FormControl

#formDirective="ngForm"> - + {{food.viewValue}} diff --git a/demos/src/styles/_select.scss b/demos/src/styles/_select.scss index d8222e305..a3b388b20 100644 --- a/demos/src/styles/_select.scss +++ b/demos/src/styles/_select.scss @@ -35,7 +35,3 @@ .custom-select-outline-shape-radius { @include select.outline-shape-radius(50%); } - -.demo-select-width { - width: 200px; -} diff --git a/packages/menu-surface/menu-surface-base.ts b/packages/menu-surface/menu-surface-base.ts index c1e558c92..6f06b50e0 100644 --- a/packages/menu-surface/menu-surface-base.ts +++ b/packages/menu-surface/menu-surface-base.ts @@ -5,8 +5,10 @@ import { EventEmitter, NgZone, Input, + OnChanges, Optional, - Output + Output, + SimpleChanges, } from '@angular/core'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {Platform} from '@angular/cdk/platform'; @@ -43,12 +45,16 @@ const ANCHOR_CORNER_MAP = { }; @Directive() -export abstract class MdcMenuSurfaceBase extends MDCComponent { +export abstract class MdcMenuSurfaceBase extends MDCComponent + implements OnChanges { /** Emits whenever the component is destroyed. */ private _destroy = new Subject(); + private _initialized = false; private _previousFocus?: Element; + _root!: Element; + @Input() get open(): boolean { return this._open; @@ -101,12 +107,7 @@ export abstract class MdcMenuSurfaceBase extends MDCComponent = new EventEmitter(); @@ -153,9 +164,9 @@ export abstract class MdcMenuSurfaceBase extends MDCComponent this._getHostElement().classList.add(className), - removeClass: (className: string) => this._getHostElement().classList.remove(className), - hasClass: (className: string) => this._getHostElement().classList.contains(className), + addClass: (className: string) => this._root.classList.add(className), + removeClass: (className: string) => this._root.classList.remove(className), + hasClass: (className: string) => this._root.classList.contains(className), hasAnchor: () => !!this.anchorElement, notifyClose: () => { this.closed.emit(); @@ -165,26 +176,36 @@ export abstract class MdcMenuSurfaceBase extends MDCComponent this._getHostElement() === el || this._getHostElement().contains(el), + isElementInContainer: (el: Element) => this._root === el || this._root.contains(el), isRtl: () => this.platform.isBrowser ? - window.getComputedStyle(this._getHostElement()).getPropertyValue('direction') === 'rtl' : false, + window.getComputedStyle(this._root).getPropertyValue('direction') === 'rtl' : false, setTransformOrigin: (origin: string) => this.platform.isBrowser ? - this._getHostElement().style[`${util.getTransformPropertyName(window)}-origin` as any] = origin : false, - isFocused: () => document?.activeElement === this._getHostElement() ?? false, + (this._root as HTMLElement).style[`${util.getTransformPropertyName(window)}-origin` as any] = origin : false, + isFocused: () => document?.activeElement === this._root ?? false, saveFocus: () => this._previousFocus = document?.activeElement ?? undefined, restoreFocus: () => { if (this.platform.isBrowser) { - if (this._getHostElement().contains(document.activeElement)) { + if (this._root.contains(document.activeElement)) { (this._previousFocus)?.focus(); } } }, getInnerDimensions: () => - ({width: this._getHostElement().offsetWidth, height: this._getHostElement().offsetHeight}), + ({ + width: (this._root as HTMLElement).offsetWidth, + height: (this._root as HTMLElement).offsetHeight + }), getAnchorDimensions: () => this.platform.isBrowser || !this.anchorElement ? - this._anchorElement!.getBoundingClientRect() : {top: 0, right: 0, bottom: 0, left: 0, width: 0, height: 0}, + this._anchorElement!.getBoundingClientRect() : { + top: 0, + right: 0, + bottom: 0, + left: 0, + width: 0, + height: 0 + }, getWindowDimensions: () => ({ width: this.platform.isBrowser ? window.innerWidth : 0, height: this.platform.isBrowser ? window.innerHeight : 0 @@ -198,12 +219,12 @@ export abstract class MdcMenuSurfaceBase extends MDCComponent { - this._getHostElement().style.left = 'left' in position ? `${position.left}px` : ''; - this._getHostElement().style.right = 'right' in position ? `${position.right}px` : ''; - this._getHostElement().style.top = 'top' in position ? `${position.top}px` : ''; - this._getHostElement().style.bottom = 'bottom' in position ? `${position.bottom}px` : ''; + (this._root as HTMLElement).style.left = 'left' in position ? `${position.left}px` : ''; + (this._root as HTMLElement).style.right = 'right' in position ? `${position.right}px` : ''; + (this._root as HTMLElement).style.top = 'top' in position ? `${position.top}px` : ''; + (this._root as HTMLElement).style.bottom = 'bottom' in position ? `${position.bottom}px` : ''; }, - setMaxHeight: (height: string) => this._getHostElement().style.maxHeight = height + setMaxHeight: (height: string) => (this._root as HTMLElement).style.maxHeight = height }; return new MDCMenuSurfaceFoundation(adapter); } @@ -214,11 +235,28 @@ export abstract class MdcMenuSurfaceBase extends MDCComponent) { super(elementRef); + + this._root = this.elementRef.nativeElement; + } + + ngOnChanges(changes: SimpleChanges) { + if (!this._initialized) { + return; + } + + if (changes['fixed']) { + this._syncSurfaceFixed(); + } + + if (changes['fullwidth']) { + this._syncSurfaceFullwidth(); + } } protected initMenuSurface(): void { + this._initialized = true; this._foundation.init(); - this.anchorElement = this._getHostElement().parentElement ?? this.anchorElement; + this.anchorElement = this._root.parentElement ?? this.anchorElement; this._registerKeydownListener(); } @@ -234,7 +272,24 @@ export abstract class MdcMenuSurfaceBase extends MDCComponent(this._getHostElement(), 'keydown') + fromEvent(this._root, 'keydown') .pipe(takeUntil(this._destroy)) .subscribe(evt => { this._foundation.handleKeydown(evt); @@ -280,9 +335,4 @@ export abstract class MdcMenuSurfaceBase extends MDCComponent