diff --git a/demos/menu.html b/demos/menu.html
index 184a56d6eef..594cb76190b 100644
--- a/demos/menu.html
+++ b/demos/menu.html
@@ -215,6 +215,9 @@
+
+
+
Menu Sizes:
@@ -265,6 +268,11 @@
menu.rememberSelection = evt.target.checked;
});
+ var animation = document.querySelector('input[name="animation"]');
+ animation.addEventListener('change', function(evt) {
+ menu.quickOpen = evt.target.checked;
+ });
+
var radios = document.querySelectorAll('input[name="position"]');
var anchor = document.querySelector('.mdc-menu-anchor');
// Initialize to top left.
diff --git a/packages/mdc-menu/README.md b/packages/mdc-menu/README.md
index 866234a46c0..d4380b438cd 100644
--- a/packages/mdc-menu/README.md
+++ b/packages/mdc-menu/README.md
@@ -139,6 +139,9 @@ CSS Class | Description
// Set Anchor Corner to Bottom End
menu.setAnchorCorner(Corner.BOTTOM_END);
+
+ // Turn off menu open animations
+ menu.quickOpen = false;
```
### `MDCMenu`
@@ -150,6 +153,7 @@ Property | Value Type | Description
`open` | Boolean | Proxies to the foundation's `isOpen`/(`open`, `close`) methods.
`items` | Array | Proxies to the foundation's container to query for all `.mdc-list-item[role]` elements.
`itemsContainer` | Element | Queries the foundation's root element for the `mdc-menu__items` container element.
+`quickOpen` | Boolean | Proxies to the foundation's `setQuickOpen()` method.
Method Signature | Description
--- | ---
@@ -201,6 +205,7 @@ Method Signature | Description
`open({focusIndex: ?number}) => void` | Opens the menu. Optionally accepts an object with a `focusIndex` parameter to indicate which list item should receive focus when the menu is opened.
`close(evt: ?Event)` | Closes the menu. Optionally accepts the event to check if the target is disabled before closing the menu.
`isOpen() => boolean` | Returns a boolean indicating whether the menu is open.
+`setQuickOpen(quickOpen: boolean) => void` | Sets whether the menu should open and close without animation when the `open`/`close` methods are called.
### Events
diff --git a/packages/mdc-menu/foundation.js b/packages/mdc-menu/foundation.js
index 4510d6f7124..a80b2daefbe 100644
--- a/packages/mdc-menu/foundation.js
+++ b/packages/mdc-menu/foundation.js
@@ -145,6 +145,8 @@ class MDCMenuFoundation extends MDCFoundation {
this.selectedIndex_ = -1;
/** @private {boolean} */
this.rememberSelection_ = false;
+ /** @private {boolean} */
+ this.quickOpen_ = false;
// A keyup event on the menu needs to have a corresponding keydown
// event on the menu. If the user opens the menu with a keydown event on a
@@ -208,6 +210,11 @@ class MDCMenuFoundation extends MDCFoundation {
this.setSelectedIndex(-1);
}
+ /** @param {boolean} quickOpen */
+ setQuickOpen(quickOpen) {
+ this.quickOpen_ = quickOpen;
+ }
+
/**
* @param {?number} focusIndex
* @private
@@ -555,7 +562,10 @@ class MDCMenuFoundation extends MDCFoundation {
*/
open({focusIndex = null} = {}) {
this.adapter_.saveFocus();
- this.adapter_.addClass(MDCMenuFoundation.cssClasses.ANIMATING_OPEN);
+
+ if (!this.quickOpen_) {
+ this.adapter_.addClass(MDCMenuFoundation.cssClasses.ANIMATING_OPEN);
+ }
this.animationRequestId_ = requestAnimationFrame(() => {
this.dimensions_ = this.adapter_.getInnerDimensions();
@@ -563,10 +573,12 @@ class MDCMenuFoundation extends MDCFoundation {
this.adapter_.addClass(MDCMenuFoundation.cssClasses.OPEN);
this.focusOnOpen_(focusIndex);
this.adapter_.registerBodyClickHandler(this.documentClickHandler_);
- this.openAnimationEndTimerId_ = setTimeout(() => {
- this.openAnimationEndTimerId_ = 0;
- this.adapter_.removeClass(MDCMenuFoundation.cssClasses.ANIMATING_OPEN);
- }, numbers.TRANSITION_OPEN_DURATION);
+ if (!this.quickOpen_) {
+ this.openAnimationEndTimerId_ = setTimeout(() => {
+ this.openAnimationEndTimerId_ = 0;
+ this.adapter_.removeClass(MDCMenuFoundation.cssClasses.ANIMATING_OPEN);
+ }, numbers.TRANSITION_OPEN_DURATION);
+ }
});
this.isOpen_ = true;
}
@@ -585,13 +597,19 @@ class MDCMenuFoundation extends MDCFoundation {
}
this.adapter_.deregisterBodyClickHandler(this.documentClickHandler_);
- this.adapter_.addClass(MDCMenuFoundation.cssClasses.ANIMATING_CLOSED);
+
+ if (!this.quickOpen_) {
+ this.adapter_.addClass(MDCMenuFoundation.cssClasses.ANIMATING_CLOSED);
+ }
+
requestAnimationFrame(() => {
this.adapter_.removeClass(MDCMenuFoundation.cssClasses.OPEN);
- this.closeAnimationEndTimerId_ = setTimeout(() => {
- this.closeAnimationEndTimerId_ = 0;
- this.adapter_.removeClass(MDCMenuFoundation.cssClasses.ANIMATING_CLOSED);
- }, numbers.TRANSITION_CLOSE_DURATION);
+ if (!this.quickOpen_) {
+ this.closeAnimationEndTimerId_ = setTimeout(() => {
+ this.closeAnimationEndTimerId_ = 0;
+ this.adapter_.removeClass(MDCMenuFoundation.cssClasses.ANIMATING_CLOSED);
+ }, numbers.TRANSITION_CLOSE_DURATION);
+ }
});
this.isOpen_ = false;
this.adapter_.restoreFocus();
diff --git a/packages/mdc-menu/index.js b/packages/mdc-menu/index.js
index ee6e507be66..83ac949ffe2 100644
--- a/packages/mdc-menu/index.js
+++ b/packages/mdc-menu/index.js
@@ -126,6 +126,11 @@ class MDCMenu extends MDCComponent {
this.foundation_.setRememberSelection(rememberSelection);
}
+ /** @param {boolean} quickOpen */
+ set quickOpen(quickOpen) {
+ this.foundation_.setQuickOpen(quickOpen);
+ }
+
/** @return {!MDCMenuFoundation} */
getDefaultFoundation() {
return new MDCMenuFoundation({
diff --git a/test/unit/mdc-menu/mdc-simple-menu.test.js b/test/unit/mdc-menu/mdc-simple-menu.test.js
index 545dfacd631..1650636c269 100644
--- a/test/unit/mdc-menu/mdc-simple-menu.test.js
+++ b/test/unit/mdc-menu/mdc-simple-menu.test.js
@@ -99,6 +99,12 @@ test('rememberSelection', () => {
// The method sets private variable on the foundation, nothing to verify.
});
+test('setQuickOpen', () => {
+ const {component} = setupTest();
+ component.quickOpen = false;
+ // The method sets private variable on the foundation, nothing to verify.
+});
+
test('items returns all menu items', () => {
const {root, component} = setupTest();
const items = [].slice.call(root.querySelectorAll('[role="menuitem"]'));
diff --git a/test/unit/mdc-menu/simple.foundation.test.js b/test/unit/mdc-menu/simple.foundation.test.js
index b25a2dfc35c..459427677e8 100644
--- a/test/unit/mdc-menu/simple.foundation.test.js
+++ b/test/unit/mdc-menu/simple.foundation.test.js
@@ -116,7 +116,15 @@ test('#init throws error when the necessary DOM is not present', () => {
testFoundation('#open adds the animation class to start an animation',
({foundation, mockAdapter}) => {
foundation.open();
- td.verify(mockAdapter.addClass(cssClasses.ANIMATING_OPEN));
+ td.verify(mockAdapter.addClass(cssClasses.ANIMATING_OPEN), {times: 1});
+ });
+
+testFoundation('#open does not add the animation class to start an animation when setQuickOpen is false',
+ ({foundation, mockAdapter}) => {
+ foundation.setQuickOpen(true);
+ foundation.open();
+ td.verify(mockAdapter.addClass(cssClasses.ANIMATING_OPEN), {times: 0});
+ td.verify(mockAdapter.removeClass(cssClasses.ANIMATING_OPEN), {times: 0});
});
testFoundation('#open adds the open class to the menu', ({foundation, mockAdapter, mockRaf}) => {
@@ -476,6 +484,13 @@ testFoundation('#close adds the animation class to start an animation', ({founda
td.verify(mockAdapter.addClass(cssClasses.ANIMATING_CLOSED));
});
+testFoundation('#close does not add animation class if quickOpen is set to true', ({foundation, mockAdapter}) => {
+ foundation.setQuickOpen(true);
+ foundation.close();
+ td.verify(mockAdapter.addClass(cssClasses.ANIMATING_CLOSED), {times: 0});
+ td.verify(mockAdapter.removeClass(cssClasses.ANIMATING_CLOSED), {times: 0});
+});
+
testFoundation('#close removes the open class from the menu', ({foundation, mockAdapter, mockRaf}) => {
foundation.close();
mockRaf.flush();
@@ -1229,4 +1244,3 @@ test('getSelectedValue should return the last selected item', () => {
assert.isTrue(foundation.getSelectedIndex() === expectedIndex);
clock.uninstall();
});
-