quasar
Version:
Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
218 lines (183 loc) • 5.48 kB
JavaScript
import Vue from 'vue'
import AnchorMixin from '../../mixins/anchor.js'
import ModelToggleMixin from '../../mixins/model-toggle.js'
import PortalMixin from '../../mixins/portal.js'
import TransitionMixin from '../../mixins/transition.js'
import { getScrollTarget } from '../../utils/scroll.js'
import { listenOpts } from '../../utils/event.js'
import slot from '../../utils/slot.js'
import {
validatePosition, validateOffset, setPosition, parsePosition
} from '../../utils/position-engine.js'
const { passive } = listenOpts
export default Vue.extend({
name: 'QTooltip',
mixins: [ AnchorMixin, ModelToggleMixin, PortalMixin, TransitionMixin ],
props: {
maxHeight: {
type: String,
default: null
},
maxWidth: {
type: String,
default: null
},
transitionShow: {
default: 'jump-down'
},
transitionHide: {
default: 'jump-up'
},
anchor: {
type: String,
default: 'bottom middle',
validator: validatePosition
},
self: {
type: String,
default: 'top middle',
validator: validatePosition
},
offset: {
type: Array,
default: () => [14, 14],
validator: validateOffset
},
delay: {
type: Number,
default: 0
}
},
computed: {
anchorOrigin () {
return parsePosition(this.anchor)
},
selfOrigin () {
return parsePosition(this.self)
},
hideOnRouteChange () {
return this.persistent !== true
}
},
methods: {
__show (evt) {
this.__showPortal()
this.__nextTick(() => {
this.updatePosition()
this.__configureScrollTarget()
})
this.__setTimeout(() => {
this.$emit('show', evt)
}, 300)
},
__hide (evt) {
this.__anchorCleanup()
this.__setTimeout(() => {
this.__hidePortal()
this.$emit('hide', evt)
}, 300)
},
__anchorCleanup () {
this.__unconfigureScrollTarget()
},
updatePosition () {
if (this.anchorEl === void 0 || this.__portal === void 0) {
return
}
const el = this.__portal.$el
if (el.nodeType === 8) { // IE replaces the comment with delay
setTimeout(this.updatePosition, 25)
return
}
setPosition({
el,
offset: this.offset,
anchorEl: this.anchorEl,
anchorOrigin: this.anchorOrigin,
selfOrigin: this.selfOrigin,
maxHeight: this.maxHeight,
maxWidth: this.maxWidth
})
},
__delayShow (evt) {
this.$q.platform.is.mobile === true && document.body.classList.add('non-selectable')
this.__setTimeout(() => {
this.show(evt)
}, this.delay)
},
__delayHide (evt) {
this.__clearTimeout()
this.$q.platform.is.mobile === true && document.body.classList.remove('non-selectable')
this.hide(evt)
},
__unconfigureAnchorEl () {
if (this.anchorEl === void 0) {
return
}
// mobile hover ref https://stackoverflow.com/a/22444532
if (this.$q.platform.is.mobile === true) {
this.anchorEl.removeEventListener('touchstart', this.__delayShow, passive)
;['touchcancel', 'touchmove', 'click'].forEach(evt => {
this.anchorEl.removeEventListener(evt, this.__delayHide, passive)
})
}
else {
this.anchorEl.removeEventListener('mouseenter', this.__delayShow, passive)
}
if (this.$q.platform.is.ios !== true) {
this.anchorEl.removeEventListener('mouseleave', this.__delayHide, passive)
}
},
__configureAnchorEl () {
if (this.noParentEvent === true || this.anchorEl === void 0) { return }
// mobile hover ref https://stackoverflow.com/a/22444532
if (this.$q.platform.is.mobile) {
this.anchorEl.addEventListener('touchstart', this.__delayShow, passive)
;['touchcancel', 'touchmove', 'click'].forEach(evt => {
this.anchorEl.addEventListener(evt, this.__delayHide, passive)
})
}
else {
this.anchorEl.addEventListener('mouseenter', this.__delayShow, passive)
}
if (this.$q.platform.is.ios !== true) {
this.anchorEl.addEventListener('mouseleave', this.__delayHide, passive)
}
},
__unconfigureScrollTarget () {
if (this.scrollTarget !== void 0) {
this.scrollTarget.removeEventListener('scroll', this.hide, passive)
this.scrollTarget = void 0
}
window.removeEventListener('scroll', this.updatePosition, passive)
},
__configureScrollTarget () {
if (this.anchorEl !== void 0) {
this.scrollTarget = getScrollTarget(this.anchorEl)
if (this.noParentEvent !== true) {
this.scrollTarget.addEventListener('scroll', this.hide, passive)
}
if (this.noParentEvent === true || this.scrollTarget !== window) {
window.addEventListener('scroll', this.updatePosition, passive)
}
}
},
__renderPortal (h) {
return h('transition', {
props: { name: this.transition }
}, [
this.showing === true ? h('div', {
staticClass: 'q-tooltip no-pointer-events',
class: this.contentClass,
style: this.contentStyle,
attrs: {
role: 'complementary'
}
}, slot(this, 'default')) : null
])
}
},
mounted () {
this.__processModelChange(this.value)
}
})