Skip to content

Commit

Permalink
feat(mdc-menu): Add support for quick-open.
Browse files Browse the repository at this point in the history
  • Loading branch information
pgbross authored and pgbross committed Mar 21, 2018
1 parent ed3d391 commit eace817
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 111 deletions.
64 changes: 32 additions & 32 deletions components/menu/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@
```javascript
var vm = new Vue({
methods: {
showMenu () {
this.$refs.menu.show()
showMenu() {
this.$refs.menu.show();
},
onSelect (selected) {
console.log('selected index: ' + selected.index)
onSelect(selected) {
console.log('selected index: ' + selected.index);
},
onCancel () {
console.log('menu cancelled')
onCancel() {
console.log('menu cancelled');
},
}
})
},
});
```

### Positioning
Expand All @@ -46,43 +46,43 @@ The anchor is a wrapper element that contains the actual visible element to atta

> for manual positioning see the [MDC docs](https://material.io/components/web/catalog/menus/#manual-positioning)

### Props

#### mdc-menu

| props | Type | Default | Description |
|-------|------|---------|-------------|
|`open-from-top-left`|Boolean| false | overrides opening point |
|`open-from-top-right`|Boolean| false | overrides opening point |
|`open-from-bottom-left`|Boolean| false | overrides opening point |
|`open-from-bottom-right`|Boolean| false | overrides opening point |
| props | Type | Default | Description |
| ------------------------ | ------- | ------- | ------------------------------------------------------------- |
| `open-from-top-left` | Boolean | false | overrides opening point |
| `open-from-top-right` | Boolean | false | overrides opening point |
| `open-from-bottom-left` | Boolean | false | overrides opening point |
| `open-from-bottom-right` | Boolean | false | overrides opening point |
| `quick-open` | Boolean | false | sets whether the menu should open and close without animation |

#### mdc-menu-item
| props | Type | Default | Description |
|-------|------|---------|-------------|
|`disabled`|Boolean| false | whether item is disabled |


| props | Type | Default | Description |
| ---------- | ------- | ------- | ------------------------ |
| `disabled` | Boolean | false | whether item is disabled |

### Events
| props | arg | Description |
|-------|-----|-------------|
|`@select`| `{ index: Number, item: HTMLElement }` | emitted when a menu item is selected |
|`@cancel`| | emitted when menu is cancelled |
### Events

> `select` event data specifies index and item :
| props | arg | Description |
| --------- | -------------------------------------- | ------------------------------------ |
| `@select` | `{ index: Number, item: HTMLElement }` | emitted when a menu item is selected |
| `@cancel` | | emitted when menu is cancelled |

> `select` event data specifies index and item :
### Methods

- `show({focusIndex: number} = {}) => void`
Shows the menu. Takes an options object containing a `focusIndex` property that
specifies the index of the menu item to be focused.
If the options object or `focusIndex` is omitted, no menu item will be focused.
* `show({focusIndex: number} = {}) => void`
Shows the menu. Takes an options object containing a `focusIndex` property that
specifies the index of the menu item to be focused.
If the options object or `focusIndex` is omitted, no menu item will be focused.

- `hide() => void`
Closes the menu.
* `hide() => void`
Closes the menu.

### Reference
- <https://material.io/components/web/catalog/menus>

* <https://material.io/components/web/catalog/menus>
151 changes: 83 additions & 68 deletions components/menu/mdc-menu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,142 +10,157 @@
</template>

<script>
import {MDCMenuFoundation} from '@material/menu/foundation'
import {getTransformPropertyName} from '@material/menu/util'
import {emitCustomEvent} from '../base'
import { MDCMenuFoundation } from '@material/menu/foundation';
import { getTransformPropertyName } from '@material/menu/util';
import { emitCustomEvent } from '../base';
export default {
name: 'mdc-menu',
props: {
'open-from-top-left': Boolean,
'open-from-top-right': Boolean,
'open-from-bottom-left': Boolean,
'open-from-bottom-right': Boolean
'open-from-bottom-right': Boolean,
'quick-open': Boolean,
},
data () {
data() {
return {
classes: {
'mdc-simple-menu--open-from-top-left': this.openFromTopLeft,
'mdc-simple-menu--open-from-top-right': this.openFromTopRight,
'mdc-simple-menu--open-from-bottom-left': this.openFromBottomLeft,
'mdc-simple-menu--open-from-bottom-right': this.openFromBottomRight
'mdc-simple-menu--open-from-bottom-right': this.openFromBottomRight,
},
styles: {},
items: []
}
items: [],
};
},
methods: {
show (options) {
this.foundation.open(options)
show(options) {
this.foundation.open(options);
},
hide () {
this.foundation.close()
hide() {
this.foundation.close();
},
isOpen() {
return this.foundation ? this.foundation.isOpen() : false;
},
isOpen () {
return this.foundation ? this.foundation.isOpen() : false
}
},
mounted () {
mounted() {
const refreshItems = () => {
this.items = [].slice.call(
this.$refs.items.querySelectorAll('.mdc-list-item[role]'))
this.$emit('update')
}
this.slotObserver = new MutationObserver(() => refreshItems())
this.slotObserver.observe(this.$el, { childList: true, subtree: true })
this.$refs.items.querySelectorAll('.mdc-list-item[role]'),
);
this.$emit('update');
};
this.slotObserver = new MutationObserver(() => refreshItems());
this.slotObserver.observe(this.$el, { childList: true, subtree: true });
this._previousFocus = undefined
this._previousFocus = undefined;
this.foundation = new MDCMenuFoundation({
addClass: (className) => this.$set(this.classes, className, true),
removeClass: (className) => this.$delete(this.classes, className),
hasClass: (className) => this.$refs.root.classList.contains(className),
addClass: className => this.$set(this.classes, className, true),
removeClass: className => this.$delete(this.classes, className),
hasClass: className => this.$refs.root.classList.contains(className),
hasNecessaryDom: () => Boolean(this.$refs.items),
getAttributeForEventTarget: (target, attributeName) =>
target.getAttribute(attributeName),
getInnerDimensions: () => ({
width: this.$refs.items.offsetWidth,
height: this.$refs.items.offsetHeight
height: this.$refs.items.offsetHeight,
}),
hasAnchor: () => this.$refs.root.parentElement &&
hasAnchor: () =>
this.$refs.root.parentElement &&
this.$refs.root.parentElement.classList.contains('mdc-menu-anchor'),
getAnchorDimensions: () =>
this.$refs.root.parentElement.getBoundingClientRect(),
getWindowDimensions: () => ({
width: window.innerWidth,
height: window.innerHeight
height: window.innerHeight,
}),
getNumberOfItems: () => this.items.length,
registerInteractionHandler: (type, handler) =>
this.$refs.root.addEventListener(type, handler),
deregisterInteractionHandler: (type, handler) =>
this.$refs.root.removeEventListener(type, handler),
registerBodyClickHandler: (handler) =>
registerBodyClickHandler: handler =>
document.body.addEventListener('click', handler),
deregisterBodyClickHandler: (handler) =>
deregisterBodyClickHandler: handler =>
document.body.removeEventListener('click', handler),
getIndexForEventTarget: (target) => this.items.indexOf(target),
notifySelected: (evtData) => {
getIndexForEventTarget: target => this.items.indexOf(target),
notifySelected: evtData => {
const evt = {
index: evtData.index,
item: this.items[evtData.index]
}
this.$emit('select', evt)
emitCustomEvent(this.$el,
item: this.items[evtData.index],
};
this.$emit('select', evt);
emitCustomEvent(
this.$el,
MDCMenuFoundation.strings.SELECTED_EVENT,
evt)
evt,
);
},
notifyCancel: () => {
this.$emit('cancel')
emitCustomEvent(this.$el,
MDCMenuFoundation.strings.CANCEL_EVENT,
{})
this.$emit('cancel');
emitCustomEvent(this.$el, MDCMenuFoundation.strings.CANCEL_EVENT, {});
},
saveFocus: () => {
this._previousFocus = document.activeElement;
},
saveFocus: () => { this._previousFocus = document.activeElement },
restoreFocus: () => {
if (this._previousFocus) {
this._previousFocus.focus()
this._previousFocus.focus();
}
},
isFocused: () => document.activeElement === this.$refs.root,
focus: () => this.$refs.root.focus(),
getFocusedItemIndex: () => this.items.indexOf(document.activeElement),
focusItemAtIndex: (index) => this.items[index].focus(),
isRtl: () => getComputedStyle(this.$refs.root)
.getPropertyValue('direction') === 'rtl',
setTransformOrigin: (origin) => {
this.$set(this.styles, `${getTransformPropertyName(window)}-origin`, origin)
focusItemAtIndex: index => this.items[index].focus(),
isRtl: () =>
getComputedStyle(this.$refs.root).getPropertyValue('direction') ===
'rtl',
setTransformOrigin: origin => {
this.$set(
this.styles,
`${getTransformPropertyName(window)}-origin`,
origin,
);
},
setPosition: (position) => {
this.$set(this.styles,'left', position.left)
this.$set(this.styles,'right', position.right)
this.$set(this.styles,'top', position.top)
this.$set(this.styles,'bottom', position.bottom)
setPosition: position => {
this.$set(this.styles, 'left', position.left);
this.$set(this.styles, 'right', position.right);
this.$set(this.styles, 'top', position.top);
this.$set(this.styles, 'bottom', position.bottom);
},
setMaxHeight: (height) => {
this.$set(this.styles,'max-height', height)
setMaxHeight: height => {
this.$set(this.styles, 'max-height', height);
},
setAttrForOptionAtIndex: (index, attr, value) => {
this.items[index].setAttribute(attr, value)
this.items[index].setAttribute(attr, value);
},
rmAttrForOptionAtIndex: (index, attr) => {
this.items[index].removeAttribute(attr)
this.items[index].removeAttribute(attr);
},
addClassForOptionAtIndex: (index, className) => {
this.items[index].classList.add(className)
this.items[index].classList.add(className);
},
rmClassForOptionAtIndex: (index, className) => {
this.items[index].classList.remove(className)
this.items[index].classList.remove(className);
},
})
});
refreshItems()
this.foundation.init()
refreshItems();
this.foundation.init();
},
watch: {
quickOpen(nv) {
this.foundation.setQuickOpen(nv);
},
},
beforeDestroy() {
this._previousFocus = null;
this.slotObserver.disconnect();
this.foundation.destroy();
},
beforeDestroy () {
this._previousFocus = null
this.slotObserver.disconnect()
this.foundation.destroy()
}
}
};
</script>
14 changes: 3 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,7 @@
"module": "dist/index.js",
"unpkg": "dist/vue-mdc-adapter.umd.min.js",
"jsdelivr": "dist/vue-mdc-adapter.umd.min.js",
"files": [
"components",
"dist",
"static",
"LICENSE",
"README.md"
],
"files": ["components", "dist", "static", "LICENSE", "README.md"],
"repository": {
"type": "git",
"url": "https://github.com/stasson/vue-mdc-adapter.git"
Expand All @@ -36,6 +30,7 @@
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server",
"test": "jest --runInBand",
"testnc": "NODE_ENV=test; jest --runInBand --no-cache",
"build": "run-s build:**",
"build:copy": "copyup components/styles.scss components/*/styles.scss dist",
"build:demo": "cross-env NODE_ENV=production webpack",
Expand Down Expand Up @@ -145,8 +140,5 @@
"node": ">= 4.0.0",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions"
]
"browserslist": ["> 1%", "last 2 versions"]
}

0 comments on commit eace817

Please sign in to comment.