83 lines
1.7 KiB
Vue
83 lines
1.7 KiB
Vue
<template>
|
|
<div
|
|
class="modal select-none fixed pin z-50 overflow-x-hidden overflow-y-auto"
|
|
>
|
|
<div class="relative mx-auto flex justify-center z-20 py-view">
|
|
<div v-on-clickaway="close"><slot /></div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { mixin as clickaway } from 'vue-clickaway'
|
|
import composedPath from '@/polyfills/composedPath'
|
|
|
|
export default {
|
|
mixins: [clickaway],
|
|
|
|
props: {
|
|
classWhitelist: [Array, String],
|
|
},
|
|
|
|
created() {
|
|
document.addEventListener('keydown', this.handleEscape)
|
|
document.body.classList.add('overflow-hidden')
|
|
|
|
const modalBg = document.createElement('div')
|
|
modalBg.classList = 'fixed pin bg-80 z-20 opacity-75'
|
|
|
|
this.modalBg = modalBg
|
|
|
|
document.body.appendChild(this.modalBg)
|
|
},
|
|
|
|
mounted() {
|
|
Nova.pauseShortcuts()
|
|
},
|
|
|
|
destroyed() {
|
|
document.removeEventListener('keydown', this.handleEscape)
|
|
document.body.classList.remove('overflow-hidden')
|
|
document.body.removeChild(this.modalBg)
|
|
|
|
Nova.resumeShortcuts()
|
|
},
|
|
|
|
data: () => ({ modalBg: null }),
|
|
|
|
methods: {
|
|
handleEscape(e) {
|
|
e.stopPropagation()
|
|
|
|
if (e.keyCode == 27) {
|
|
this.close(e)
|
|
}
|
|
},
|
|
|
|
close(e) {
|
|
if (!e.isTrusted) return
|
|
|
|
let classArray = Array.isArray(this.classWhitelist)
|
|
? this.classWhitelist
|
|
: [this.classWhitelist]
|
|
|
|
if (
|
|
_.filter(classArray, className => pathIncludesClass(e, className))
|
|
.length > 0
|
|
) {
|
|
return
|
|
}
|
|
|
|
this.$emit('modal-close', e)
|
|
},
|
|
},
|
|
}
|
|
|
|
function pathIncludesClass(event, className) {
|
|
return composedPath(event)
|
|
.filter(el => el !== document && el !== window)
|
|
.reduce((acc, e) => acc.concat([...e.classList]), [])
|
|
.includes(className)
|
|
}
|
|
</script>
|