Skip to content

Commit

Permalink
fix(menu-surface): Use superclass properties without trailing undersc…
Browse files Browse the repository at this point in the history
…ores

PiperOrigin-RevId: 312740498
  • Loading branch information
patrickrodee authored and copybara-github committed May 21, 2020
1 parent e6165eb commit 62abbc8
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 65 deletions.
74 changes: 42 additions & 32 deletions packages/mdc-menu-surface/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ export class MDCMenuSurface extends MDCComponent<MDCMenuSurfaceFoundation> {
private deregisterBodyClickListener_!: RegisterFunction; // assigned in initialSyncWithDOM()

initialSyncWithDOM() {
const parentEl = this.root_.parentElement;
const parentEl = this.root.parentElement;
this.anchorElement = parentEl && parentEl.classList.contains(cssClasses.ANCHOR) ? parentEl : null;

if (this.root_.classList.contains(cssClasses.FIXED)) {
if (this.root.classList.contains(cssClasses.FIXED)) {
this.setFixedPosition(true);
}

this.handleKeydown_ = (evt) => this.foundation_.handleKeydown(evt);
this.handleBodyClick_ = (evt) => this.foundation_.handleBodyClick(evt);
this.handleKeydown_ = (evt) => this.foundation.handleKeydown(evt);
this.handleBodyClick_ = (evt) => this.foundation.handleBodyClick(evt);

// capture so that no race between handleBodyClick and quickOpen when
// menusurface opened on button click which registers this listener
Expand All @@ -80,24 +80,24 @@ export class MDCMenuSurface extends MDCComponent<MDCMenuSurfaceFoundation> {
}

isOpen(): boolean {
return this.foundation_.isOpen();
return this.foundation.isOpen();
}

open() {
this.foundation_.open();
this.foundation.open();
}

close(skipRestoreFocus = false) {
this.foundation_.close(skipRestoreFocus);
this.foundation.close(skipRestoreFocus);
}

set quickOpen(quickOpen: boolean) {
this.foundation_.setQuickOpen(quickOpen);
this.foundation.setQuickOpen(quickOpen);
}

/** Sets the foundation to use page offsets for an positioning when the menu is hoisted to the body. */
setIsHoisted(isHoisted: boolean) {
this.foundation_.setIsHoisted(isHoisted);
this.foundation.setIsHoisted(isHoisted);
}

/** Sets the element that the menu-surface is anchored to. */
Expand All @@ -108,65 +108,73 @@ export class MDCMenuSurface extends MDCComponent<MDCMenuSurfaceFoundation> {
/** Sets the menu-surface to position: fixed. */
setFixedPosition(isFixed: boolean) {
if (isFixed) {
this.root_.classList.add(cssClasses.FIXED);
this.root.classList.add(cssClasses.FIXED);
} else {
this.root_.classList.remove(cssClasses.FIXED);
this.root.classList.remove(cssClasses.FIXED);
}

this.foundation_.setFixedPosition(isFixed);
this.foundation.setFixedPosition(isFixed);
}

/** Sets the absolute x/y position to position based on. Requires the menu to be hoisted. */
setAbsolutePosition(x: number, y: number) {
this.foundation_.setAbsolutePosition(x, y);
this.foundation.setAbsolutePosition(x, y);
this.setIsHoisted(true);
}

/**
* @param corner Default anchor corner alignment of top-left surface corner.
*/
setAnchorCorner(corner: Corner) {
this.foundation_.setAnchorCorner(corner);
this.foundation.setAnchorCorner(corner);
}

setAnchorMargin(margin: Partial<MDCMenuDistance>) {
this.foundation_.setAnchorMargin(margin);
this.foundation.setAnchorMargin(margin);
}

getDefaultFoundation() {
// DO NOT INLINE this variable. For backward compatibility, foundations take a Partial<MDCFooAdapter>.
// To ensure we don't accidentally omit any methods, we need a separate, strongly typed adapter variable.
// tslint:disable:object-literal-sort-keys Methods should be in the same order as the adapter interface.
const adapter: MDCMenuSurfaceAdapter = {
addClass: (className) => this.root_.classList.add(className),
removeClass: (className) => this.root_.classList.remove(className),
hasClass: (className) => this.root_.classList.contains(className),
addClass: (className) => this.root.classList.add(className),
removeClass: (className) => this.root.classList.remove(className),
hasClass: (className) => this.root.classList.contains(className),
hasAnchor: () => !!this.anchorElement,
notifyClose: () => this.emit(MDCMenuSurfaceFoundation.strings.CLOSED_EVENT, {}),
notifyOpen: () => this.emit(MDCMenuSurfaceFoundation.strings.OPENED_EVENT, {}),
isElementInContainer: (el) => this.root_.contains(el),
isRtl: () => getComputedStyle(this.root_).getPropertyValue('direction') === 'rtl',
notifyClose: () =>
this.emit(MDCMenuSurfaceFoundation.strings.CLOSED_EVENT, {}),
notifyOpen: () =>
this.emit(MDCMenuSurfaceFoundation.strings.OPENED_EVENT, {}),
isElementInContainer: (el) => this.root.contains(el),
isRtl: () =>
getComputedStyle(this.root).getPropertyValue('direction') === 'rtl',
setTransformOrigin: (origin) => {
const propertyName = `${util.getTransformPropertyName(window)}-origin`;
this.root_.style.setProperty(propertyName, origin);
(this.root as HTMLElement).style.setProperty(propertyName, origin);
},

isFocused: () => document.activeElement === this.root_,
isFocused: () => document.activeElement === this.root,
saveFocus: () => {
this.previousFocus_ = document.activeElement as HTMLElement | SVGElement | null;
},
restoreFocus: () => {
if (this.root_.contains(document.activeElement)) {
if (this.root.contains(document.activeElement)) {
if (this.previousFocus_ && this.previousFocus_.focus) {
this.previousFocus_.focus();
}
}
},

getInnerDimensions: () => {
return {width: this.root_.offsetWidth, height: this.root_.offsetHeight};
return {
width: (this.root as HTMLElement).offsetWidth,
height: (this.root as HTMLElement).offsetHeight
};
},
getAnchorDimensions: () => this.anchorElement ? this.anchorElement.getBoundingClientRect() : null,
getAnchorDimensions: () => this.anchorElement ?
this.anchorElement.getBoundingClientRect() :
null,
getWindowDimensions: () => {
return {width: window.innerWidth, height: window.innerHeight};
},
Expand All @@ -177,13 +185,15 @@ export class MDCMenuSurface extends MDCComponent<MDCMenuSurfaceFoundation> {
return {x: window.pageXOffset, y: window.pageYOffset};
},
setPosition: (position) => {
this.root_.style.left = 'left' in position ? `${position.left}px` : '';
this.root_.style.right = 'right' in position ? `${position.right}px` : '';
this.root_.style.top = 'top' in position ? `${position.top}px` : '';
this.root_.style.bottom = 'bottom' in position ? `${position.bottom}px` : '';
const rootHTML = this.root as HTMLElement;
rootHTML.style.left = 'left' in position ? `${position.left}px` : '';
rootHTML.style.right = 'right' in position ? `${position.right}px` : '';
rootHTML.style.top = 'top' in position ? `${position.top}px` : '';
rootHTML.style.bottom =
'bottom' in position ? `${position.bottom}px` : '';
},
setMaxHeight: (height) => {
this.root_.style.maxHeight = height;
(this.root as HTMLElement).style.maxHeight = height;
},
};
// tslint:enable:object-literal-sort-keys
Expand Down
73 changes: 40 additions & 33 deletions packages/mdc-menu-surface/foundation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,11 @@ export class MDCMenuSurfaceFoundation extends MDCFoundation<MDCMenuSurfaceAdapte
init() {
const {ROOT, OPEN} = MDCMenuSurfaceFoundation.cssClasses;

if (!this.adapter_.hasClass(ROOT)) {
if (!this.adapter.hasClass(ROOT)) {
throw new Error(`${ROOT} class required in root element.`);
}

if (this.adapter_.hasClass(OPEN)) {
if (this.adapter.hasClass(OPEN)) {
this.isOpen_ = true;
}
}
Expand Down Expand Up @@ -200,25 +200,25 @@ export class MDCMenuSurfaceFoundation extends MDCFoundation<MDCMenuSurfaceAdapte
return;
}

this.adapter_.saveFocus();
this.adapter.saveFocus();

if (this.isQuickOpen_) {
this.isOpen_ = true;
this.adapter_.addClass(MDCMenuSurfaceFoundation.cssClasses.OPEN);
this.dimensions_ = this.adapter_.getInnerDimensions();
this.adapter.addClass(MDCMenuSurfaceFoundation.cssClasses.OPEN);
this.dimensions_ = this.adapter.getInnerDimensions();
this.autoPosition_();
this.adapter_.notifyOpen();
this.adapter.notifyOpen();
} else {

this.adapter_.addClass(MDCMenuSurfaceFoundation.cssClasses.ANIMATING_OPEN);
this.adapter.addClass(MDCMenuSurfaceFoundation.cssClasses.ANIMATING_OPEN);
this.animationRequestId_ = requestAnimationFrame(() => {
this.adapter_.addClass(MDCMenuSurfaceFoundation.cssClasses.OPEN);
this.dimensions_ = this.adapter_.getInnerDimensions();
this.adapter.addClass(MDCMenuSurfaceFoundation.cssClasses.OPEN);
this.dimensions_ = this.adapter.getInnerDimensions();
this.autoPosition_();
this.openAnimationEndTimerId_ = setTimeout(() => {
this.openAnimationEndTimerId_ = 0;
this.adapter_.removeClass(MDCMenuSurfaceFoundation.cssClasses.ANIMATING_OPEN);
this.adapter_.notifyOpen();
this.adapter.removeClass(
MDCMenuSurfaceFoundation.cssClasses.ANIMATING_OPEN);
this.adapter.notifyOpen();
}, numbers.TRANSITION_OPEN_DURATION);
});

Expand All @@ -240,19 +240,23 @@ export class MDCMenuSurfaceFoundation extends MDCFoundation<MDCMenuSurfaceAdapte
this.maybeRestoreFocus_();
}

this.adapter_.removeClass(MDCMenuSurfaceFoundation.cssClasses.OPEN);
this.adapter_.removeClass(MDCMenuSurfaceFoundation.cssClasses.IS_OPEN_BELOW);
this.adapter_.notifyClose();
this.adapter.removeClass(MDCMenuSurfaceFoundation.cssClasses.OPEN);
this.adapter.removeClass(
MDCMenuSurfaceFoundation.cssClasses.IS_OPEN_BELOW);
this.adapter.notifyClose();

} else {
this.adapter_.addClass(MDCMenuSurfaceFoundation.cssClasses.ANIMATING_CLOSED);
this.adapter.addClass(
MDCMenuSurfaceFoundation.cssClasses.ANIMATING_CLOSED);
requestAnimationFrame(() => {
this.adapter_.removeClass(MDCMenuSurfaceFoundation.cssClasses.OPEN);
this.adapter_.removeClass(MDCMenuSurfaceFoundation.cssClasses.IS_OPEN_BELOW);
this.adapter.removeClass(MDCMenuSurfaceFoundation.cssClasses.OPEN);
this.adapter.removeClass(
MDCMenuSurfaceFoundation.cssClasses.IS_OPEN_BELOW);
this.closeAnimationEndTimerId_ = setTimeout(() => {
this.closeAnimationEndTimerId_ = 0;
this.adapter_.removeClass(MDCMenuSurfaceFoundation.cssClasses.ANIMATING_CLOSED);
this.adapter_.notifyClose();
this.adapter.removeClass(
MDCMenuSurfaceFoundation.cssClasses.ANIMATING_CLOSED);
this.adapter.notifyClose();
}, numbers.TRANSITION_CLOSE_DURATION);
});

Expand All @@ -267,7 +271,7 @@ export class MDCMenuSurfaceFoundation extends MDCFoundation<MDCMenuSurfaceAdapte
/** Handle clicks and close if not within menu-surface element. */
handleBodyClick(evt: MouseEvent) {
const el = evt.target as Element;
if (this.adapter_.isElementInContainer(el)) {
if (this.adapter.isElementInContainer(el)) {
return;
}
this.close();
Expand Down Expand Up @@ -310,24 +314,26 @@ export class MDCMenuSurfaceFoundation extends MDCFoundation<MDCMenuSurfaceAdapte
this.adjustPositionForHoistedElement_(position);
}

this.adapter_.setTransformOrigin(`${horizontalAlignment} ${verticalAlignment}`);
this.adapter_.setPosition(position);
this.adapter_.setMaxHeight(maxMenuSurfaceHeight ? maxMenuSurfaceHeight + 'px' : '');
this.adapter.setTransformOrigin(
`${horizontalAlignment} ${verticalAlignment}`);
this.adapter.setPosition(position);
this.adapter.setMaxHeight(
maxMenuSurfaceHeight ? maxMenuSurfaceHeight + 'px' : '');

// If it is opened from the top then add is-open-below class
if (!this.hasBit_(corner, CornerBit.BOTTOM)) {
this.adapter_.addClass(MDCMenuSurfaceFoundation.cssClasses.IS_OPEN_BELOW);
this.adapter.addClass(MDCMenuSurfaceFoundation.cssClasses.IS_OPEN_BELOW);
}
}

/**
* @return Measurements used to position menu surface popup.
*/
private getAutoLayoutMeasurements_(): AutoLayoutMeasurements {
let anchorRect = this.adapter_.getAnchorDimensions();
const bodySize = this.adapter_.getBodyDimensions();
const viewportSize = this.adapter_.getWindowDimensions();
const windowScroll = this.adapter_.getWindowScroll();
let anchorRect = this.adapter.getAnchorDimensions();
const bodySize = this.adapter.getBodyDimensions();
const viewportSize = this.adapter.getWindowDimensions();
const windowScroll = this.adapter.getWindowScroll();

if (!anchorRect) {
// tslint:disable:object-literal-sort-keys Positional properties are more readable when they're grouped together
Expand Down Expand Up @@ -395,7 +401,7 @@ export class MDCMenuSurfaceFoundation extends MDCFoundation<MDCMenuSurfaceAdapte
corner = this.setBit_(corner, CornerBit.BOTTOM);
}

const isRtl = this.adapter_.isRtl();
const isRtl = this.adapter.isRtl();
const isFlipRtl = this.hasBit_(this.anchorCorner_, CornerBit.FLIP_RTL);
const hasRightBit = this.hasBit_(this.anchorCorner_, CornerBit.RIGHT);

Expand Down Expand Up @@ -554,10 +560,11 @@ export class MDCMenuSurfaceFoundation extends MDCFoundation<MDCMenuSurfaceAdapte
* focused on or within the menu surface when it is closed.
*/
private maybeRestoreFocus_() {
const isRootFocused = this.adapter_.isFocused();
const childHasFocus = document.activeElement && this.adapter_.isElementInContainer(document.activeElement);
const isRootFocused = this.adapter.isFocused();
const childHasFocus = document.activeElement &&
this.adapter.isElementInContainer(document.activeElement);
if (isRootFocused || childHasFocus) {
this.adapter_.restoreFocus();
this.adapter.restoreFocus();
}
}

Expand Down

0 comments on commit 62abbc8

Please sign in to comment.