UNPKG

element3

Version:

A Component Library for Vue3

204 lines (182 loc) 5.47 kB
import { PopupManager } from '../../src/utils/popup' import { Popper } from '../utils/new-popper' // const PopperJS = Vue.prototype.$isServer ? function() {} : require('./popper') const stop = (e) => e.stopPropagation() /** * @param {HTMLElement} [reference=$refs.reference] - The reference element used to position the popper. * @param {HTMLElement} [popper=$refs.popper] - The HTML element used as popper, or a configuration used to generate the popper. * @param {String} [placement=button] - Placement of the popper accepted values: top(-start, -end), right(-start, -end), bottom(-start, -end), left(-start, -end) * @param {Number} [offset=0] - Amount of pixels the popper will be shifted (can be negative). * @param {Boolean} [visible=false] Visibility of the popup element. * @param {Boolean} [visible-arrow=false] Visibility of the arrow, no style. */ export default { props: { transformOrigin: { type: [Boolean, String], default: true }, placement: { type: String, default: 'bottom' }, boundariesPadding: { type: Number, default: 5 }, reference: {}, popper: {}, offset: { default: 0 }, value: Boolean, visibleArrow: Boolean, arrowOffset: { type: Number, default: 35 }, appendToBody: { type: Boolean, default: true }, popperOptions: { type: Object, default() { return { gpuAcceleration: false } } } }, data() { return { showPopper: false, currentPlacement: '' } }, watch: { value: { immediate: true, handler(val) { this.showPopper = val this.$emit('input', val) } }, showPopper(val) { if (this.disabled) return val ? this.updatePopper() : this.destroyPopper() this.$emit('input', val) } }, methods: { createPopper() { if (this.$isServer) return this.currentPlacement = this.currentPlacement || this.placement if ( !/^(top|bottom|left|right)(-start|-end)?$/g.test(this.currentPlacement) ) { return } const options = this.popperOptions const popper = (this.popperElm = this.popperElm || this.popper || this.$refs.popper) let reference = (this.referenceElm = this.referenceElm || this.reference || this.$refs.reference) if (!reference && this.$slots.reference && this.$slots.reference[0]) { reference = this.referenceElm = this.$slots.reference[0].elm } if (!popper || !reference) return if (this.visibleArrow) this.appendArrow(popper) if (this.appendToBody) document.body.appendChild(this.popperElm) if (this.popperJS && this.popperJS.destroy) { this.popperJS.destroy() } options.placement = this.currentPlacement options.offset = this.offset options.arrowOffset = this.arrowOffset this.popperJS = new Popper(reference, popper, options) this.popperJS.onCreate(() => { this.$emit('created', this) this.resetTransformOrigin() this.$nextTick(this.updatePopper) }) if (typeof options.onUpdate === 'function') { this.popperJS.onUpdate(options.onUpdate) } this.popperJS._popper.style.zIndex = PopupManager.nextZIndex() this.popperElm.addEventListener('click', stop) }, updatePopper() { const popperJS = this.popperJS if (popperJS) { popperJS.update() if (popperJS._popper) { popperJS._popper.style.zIndex = PopupManager.nextZIndex() } } else { this.createPopper() } }, doDestroy(forceDestroy) { /* istanbul ignore if */ if (!this.popperJS || (this.showPopper && !forceDestroy)) return this.popperJS.destroy() this.popperJS = null }, destroyPopper() { if (this.popperJS) { this.resetTransformOrigin() } }, resetTransformOrigin() { if (!this.transformOrigin) return const placementMap = { top: 'bottom', bottom: 'top', left: 'right', right: 'left' } const placement = this.popperJS._popper .getAttribute('x-placement') .split('-')[0] const origin = placementMap[placement] this.popperJS._popper.style.transformOrigin = typeof this.transformOrigin === 'string' ? this.transformOrigin : ['top', 'bottom'].indexOf(placement) > -1 ? `center ${origin}` : `${origin} center` }, appendArrow(element) { let hash if (this.appended) { return } this.appended = true for (const item in element.attributes) { if (/^_v-/.test(element.attributes[item].name)) { hash = element.attributes[item].name break } } const arrow = document.createElement('div') if (hash) { arrow.setAttribute(hash, '') } arrow.setAttribute('x-arrow', '') arrow.className = 'popper__arrow' element.appendChild(arrow) } }, beforeUnmount() { this.doDestroy(true) if (this.popperElm && this.popperElm.parentNode === document.body) { this.popperElm.removeEventListener('click', stop) document.body.removeChild(this.popperElm) } }, // call destroy in keep-alive mode deactivated() { this.$options.beforeUnmount[0].call(this) } }