mirror of
https://github.com/frappe/books.git
synced 2024-12-23 03:19:01 +00:00
fix: Refactor Popover to use Portal and Popper.js
This commit is contained in:
parent
df6ace3b8d
commit
466622f074
@ -63,9 +63,10 @@
|
||||
"frappe-charts": "^1.2.4",
|
||||
"frappejs": "https://github.com/frappe/frappejs",
|
||||
"nodemailer": "^4.7.0",
|
||||
"popper.js": "^1.14.4",
|
||||
"vue-color": "^2.7.0",
|
||||
"vue-toasted": "^1.1.25"
|
||||
"vue-toasted": "^1.1.25",
|
||||
"portal-vue": "2.1.6",
|
||||
"popper.js": "1.16.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron-builder": "^21.2.0"
|
||||
|
@ -4,6 +4,7 @@
|
||||
<database-selector v-if="showDatabaseSelector" @file="connectToDBFile" />
|
||||
<setup-wizard v-if="showSetupWizard" />
|
||||
<Settings v-if="showSettings" />
|
||||
<portal-target name="popovers" multiple></portal-target>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Popover :right="true" @hide="emitFilterChange">
|
||||
<Popover @close="emitFilterChange" right>
|
||||
<template v-slot:target="{ toggleDropdown }">
|
||||
<Button :icon="true" @click="toggleDropdown()">
|
||||
<span class="flex items-center">
|
||||
@ -19,7 +19,7 @@
|
||||
<div class="p-3">
|
||||
<template v-if="filters.length">
|
||||
<div
|
||||
:key="filter.fieldname + filter.conditions + filter.value"
|
||||
:key="frappe.getRandomString()"
|
||||
v-for="(filter, i) in filters"
|
||||
class="flex items-center justify-between text-base"
|
||||
:class="i !== 0 && 'mt-2'"
|
||||
|
@ -1,43 +1,91 @@
|
||||
<template>
|
||||
<div class="relative" v-on-outside-click="() => toggleDropdown(false)">
|
||||
<div ref="reference">
|
||||
<div class="h-full">
|
||||
<slot name="target" :toggleDropdown="toggleDropdown"></slot>
|
||||
</div>
|
||||
<portal to="popovers">
|
||||
<div
|
||||
:class="right ? 'right-0' : 'left-0'"
|
||||
class="mt-1 absolute z-10 bg-white rounded-5px border min-w-40 shadow-md"
|
||||
v-if="isShown"
|
||||
ref="popover"
|
||||
:class="popoverClass"
|
||||
class="mt-1 bg-white rounded-5px border min-w-40 shadow-md"
|
||||
v-show="isOpen"
|
||||
>
|
||||
<slot name="content"></slot>
|
||||
<slot name="content" :toggleDropdown="toggleDropdown"></slot>
|
||||
</div>
|
||||
</portal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Popper from 'popper.js';
|
||||
|
||||
export default {
|
||||
name: 'Popover',
|
||||
props: ['right'],
|
||||
props: {
|
||||
right: Boolean,
|
||||
popoverClass: [String, Object, Array]
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isShown: false
|
||||
isOpen: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
isShown(newVal, oldVal) {
|
||||
if (newVal === false) {
|
||||
this.$emit('hide');
|
||||
}
|
||||
if (newVal === true) {
|
||||
this.$emit('show');
|
||||
}
|
||||
mounted() {
|
||||
let listener = e => {
|
||||
let $els = [this.$refs.reference, this.$refs.popover];
|
||||
let insideClick = $els.some(
|
||||
$el => $el && (e.target === $el || $el.contains(e.target))
|
||||
);
|
||||
if (insideClick) {
|
||||
return;
|
||||
}
|
||||
this.close();
|
||||
};
|
||||
document.addEventListener('click', listener);
|
||||
this.$once('hook:beforeDestroy', () => {
|
||||
document.removeEventListener('click', listener);
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.popper.destroy();
|
||||
},
|
||||
methods: {
|
||||
toggleDropdown(flag, from) {
|
||||
if (flag == null) {
|
||||
flag = !this.isShown;
|
||||
setupPopper() {
|
||||
if (!this.popper) {
|
||||
this.popper = new Popper(this.$refs.reference, this.$refs.popover, {
|
||||
placement: this.right ? 'bottom-end' : 'bottom-start'
|
||||
});
|
||||
} else {
|
||||
this.popper.scheduleUpdate();
|
||||
}
|
||||
this.isShown = Boolean(flag);
|
||||
},
|
||||
toggleDropdown(flag) {
|
||||
if (flag == null) {
|
||||
flag = !this.isOpen;
|
||||
}
|
||||
flag = Boolean(flag);
|
||||
if (flag) {
|
||||
this.open();
|
||||
} else {
|
||||
this.close();
|
||||
}
|
||||
},
|
||||
open() {
|
||||
if (this.isOpen) {
|
||||
return;
|
||||
}
|
||||
this.isOpen = true;
|
||||
this.$nextTick(() => {
|
||||
this.setupPopper();
|
||||
});
|
||||
this.$emit('open');
|
||||
},
|
||||
close() {
|
||||
if (!this.isOpen) {
|
||||
return;
|
||||
}
|
||||
this.isOpen = false;
|
||||
this.$emit('close');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -11,6 +11,7 @@ import { ipcRenderer } from 'electron';
|
||||
|
||||
// vue imports
|
||||
import Vue from 'vue';
|
||||
import PortalVue from 'portal-vue';
|
||||
import App from './App';
|
||||
import router from './router';
|
||||
|
||||
@ -215,6 +216,7 @@ import router from './router';
|
||||
Vue.config.productionTip = false;
|
||||
Vue.component('feather-icon', FeatherIcon);
|
||||
Vue.directive('on-outside-click', outsideClickDirective);
|
||||
Vue.use(PortalVue);
|
||||
Vue.mixin({
|
||||
computed: {
|
||||
frappe() {
|
||||
|
Loading…
Reference in New Issue
Block a user