2
0
mirror of https://github.com/tenrok/vue-context.git synced 2026-06-23 10:40:32 +03:00

Clickaway (#12)

This commit is contained in:
Randall Wilk
2018-10-23 12:47:26 -05:00
committed by GitHub
parent 22f582c3da
commit 50abb9633f
5 changed files with 1030 additions and 3758 deletions
+10
View File
@@ -1,5 +1,15 @@
# Changelog # Changelog
# 3.3.1 (Oct 23, 2018)
## Changed
- Context menu now closes via [clickaway](https://github.com/simplesmiler/vue-clickaway)
instead of blur event. Credit to [robjbrain](https://github.com/robjbrain)
for pointing it out.
## Updated
- Updated vue and other dev dependencies.
# 3.3.0 (Oct 15, 2018) # 3.3.0 (Oct 15, 2018)
## Added ## Added
+1 -1
View File
File diff suppressed because one or more lines are too long
+844 -3587
View File
File diff suppressed because it is too large Load Diff
+6 -5
View File
@@ -1,6 +1,6 @@
{ {
"name": "vue-context", "name": "vue-context",
"version": "3.3.0", "version": "3.3.1",
"description": "A simple vue context menu component.", "description": "A simple vue context menu component.",
"main": "dist/vue-context.js", "main": "dist/vue-context.js",
"scripts": { "scripts": {
@@ -26,12 +26,13 @@
}, },
"homepage": "https://github.com/rawilk/vue-context#readme", "homepage": "https://github.com/rawilk/vue-context#readme",
"dependencies": { "dependencies": {
"vue": "^2.5.16" "vue": "^2.5.17",
"vue-clickaway": "^2.2.2"
}, },
"devDependencies": { "devDependencies": {
"babel-preset-env": "^1.7.0", "babel-preset-env": "^1.7.0",
"cross-env": "^5.1.6", "cross-env": "^5.2.0",
"laravel-mix": "^2.1.11", "laravel-mix": "^2.1.14",
"node-sass": "^4.9.0" "node-sass": "^4.9.4"
} }
} }
+169 -165
View File
@@ -1,81 +1,85 @@
<template> <template>
<div class="v-context" <div class="v-context"
v-show="show" v-show="show"
:style="style" :style="style"
tabindex="-1" tabindex="-1"
@blur="close" v-on-clickaway="close"
@click="onClick" @click="onClick"
@contextmenu.capture.prevent @contextmenu.capture.prevent
> >
<slot :data="data"></slot> <slot :data="data"></slot>
</div> </div>
</template> </template>
<script> <script>
export default { import { mixin as clickaway } from 'vue-clickaway';
props: {
/**
* Close the menu on click.
*
* @type {boolean}
*/
closeOnClick: {
type: Boolean,
default: true
},
/** export default {
* Close the menu automatically on window scroll. mixins: [clickaway],
*
* @type {boolean}
*/
closeOnScroll: {
type: Boolean,
default: true
}
},
computed: { props: {
/** /**
* Generate the CSS styles for positioning the context menu. * Close the menu on click.
* *
* @returns {object|null} * @type {boolean}
*/ */
style () { closeOnClick: {
return this.show type: Boolean,
? { top: `${this.top}px`, left: `${this.left}px` } default: true
: null; },
}
},
data () { /**
return { * Close the menu automatically on window scroll.
top: null, *
left: null, * @type {boolean}
show: false, */
data: null closeOnScroll: {
}; type: Boolean,
}, default: true
}
},
mounted () { computed: {
if (this.closeOnScroll) { /**
this.addScrollEventListener(); * Generate the CSS styles for positioning the context menu.
} *
}, * @returns {object|null}
*/
style () {
return this.show
? { top: `${this.top}px`, left: `${this.left}px` }
: null;
}
},
beforeDestroy () { data () {
if (this.closeOnScroll) { return {
this.removeScrollEventListener(); top: null,
} left: null,
}, show: false,
data: null
};
},
methods: { mounted () {
/** if (this.closeOnScroll) {
* Add scroll event listener to close context menu. this.addScrollEventListener();
*/ }
addScrollEventListener () { },
window.addEventListener('scroll', this.close);
}, beforeDestroy () {
if (this.closeOnScroll) {
this.removeScrollEventListener();
}
},
methods: {
/**
* Add scroll event listener to close context menu.
*/
addScrollEventListener () {
window.addEventListener('scroll', this.close);
},
/** /**
* Close the context menu. * Close the context menu.
@@ -93,119 +97,119 @@
} }
}, },
/** /**
* Close the menu if `closeOnClick` is set to true. * Close the menu if `closeOnClick` is set to true.
*/ */
onClick () { onClick () {
if (this.closeOnClick) { if (this.closeOnClick) {
this.close(false); this.close(false);
} }
}, },
/** /**
* Open the context menu. * Open the context menu.
* *
* @param {MouseEvent} event * @param {MouseEvent} event
* @param {array|object|string} data User provided data for the menu * @param {array|object|string} data User provided data for the menu
*/ */
open (event, data) { open (event, data) {
this.data = data; this.data = data;
this.show = true; this.show = true;
this.$nextTick(() => { this.$nextTick(() => {
this.positionMenu(event.clientY, event.clientX); this.positionMenu(event.clientY, event.clientX);
this.$el.focus(); this.$el.focus();
this.$emit('open', event, this.data, this.top, this.left); this.$emit('open', event, this.data, this.top, this.left);
}); });
}, },
/** /**
* Set the context menu top and left positions. * Set the context menu top and left positions.
* *
* @param {number} top * @param {number} top
* @param {number} left * @param {number} left
*/ */
positionMenu (top, left) { positionMenu (top, left) {
const largestHeight = window.innerHeight - this.$el.offsetHeight - 25; const largestHeight = window.innerHeight - this.$el.offsetHeight - 25;
const largestWidth = window.innerWidth - this.$el.offsetWidth - 25; const largestWidth = window.innerWidth - this.$el.offsetWidth - 25;
if (top > largestHeight) { if (top > largestHeight) {
top = largestHeight; top = largestHeight;
} }
if (left > largestWidth) { if (left > largestWidth) {
left = largestWidth; left = largestWidth;
} }
this.top = top; this.top = top;
this.left = left; this.left = left;
}, },
/** /**
* Remove the scroll event listener to close the context menu. * Remove the scroll event listener to close the context menu.
*/ */
removeScrollEventListener () { removeScrollEventListener () {
window.removeEventListener('scroll', this.close); window.removeEventListener('scroll', this.close);
} }
}, },
watch: { watch: {
/** /**
* Add or remove the scroll event listener when the prop value changes. * Add or remove the scroll event listener when the prop value changes.
* *
* @param {boolean} value * @param {boolean} value
* @param {boolean} oldValue * @param {boolean} oldValue
*/ */
closeOnScroll (value, oldValue) { closeOnScroll (value, oldValue) {
if (value === oldValue) { if (value === oldValue) {
return; return;
} }
if (value) { if (value) {
this.addScrollEventListener(); this.addScrollEventListener();
} else { } else {
this.removeScrollEventListener(); this.removeScrollEventListener();
} }
} }
} }
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
$blue600: #1e88e5; $blue600: #1e88e5;
$gray74: #bdbdbd; $gray74: #bdbdbd;
$gray93: #ededed; $gray93: #ededed;
$gray98: #fafafa; $gray98: #fafafa;
.v-context { .v-context {
background: $gray98; background: $gray98;
border: 1px solid $gray74; border: 1px solid $gray74;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12); box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
display: block; display: block;
margin: 0; margin: 0;
padding: 0; padding: 0;
position: fixed; position: fixed;
width: 250px; width: 250px;
z-index: 99999; z-index: 99999;
ul { ul {
list-style: none; list-style: none;
padding: 10px 0; padding: 10px 0;
margin: 0; margin: 0;
font-size: 12px; font-size: 12px;
font-weight: 600; font-weight: 600;
li { li {
margin: 0; margin: 0;
padding: 10px 35px; padding: 10px 35px;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
background: $blue600; background: $blue600;
color: $gray98; color: $gray98;
} }
} }
} }
} }
</style> </style>