UNPKG

vuetify

Version:

Vue Material Component Framework

226 lines (203 loc) 5.98 kB
import './VTooltip.sass' // Mixins import Activatable from '../../mixins/activatable' import Colorable from '../../mixins/colorable' import Delayable from '../../mixins/delayable' import Dependent from '../../mixins/dependent' import Detachable from '../../mixins/detachable' import Menuable from '../../mixins/menuable' import Toggleable from '../../mixins/toggleable' // Helpers import { convertToUnit, keyCodes, getSlotType } from '../../util/helpers' import { consoleError } from '../../util/console' // Types import { VNode } from 'vue' import mixins from '../../util/mixins' /* @vue/component */ export default mixins(Colorable, Delayable, Dependent, Detachable, Menuable, Toggleable).extend({ name: 'v-tooltip', props: { closeDelay: { type: [Number, String], default: 0, }, disabled: Boolean, fixed: { type: Boolean, default: true, }, openDelay: { type: [Number, String], default: 0, }, openOnHover: { type: Boolean, default: true, }, tag: { type: String, default: 'span', }, transition: String, }, data: () => ({ calculatedMinWidth: 0, closeDependents: false, }), computed: { calculatedLeft (): string { const { activator, content } = this.dimensions const unknown = !this.bottom && !this.left && !this.top && !this.right const activatorLeft = this.attach !== false ? activator.offsetLeft : activator.left let left = 0 if (this.top || this.bottom || unknown) { left = ( activatorLeft + (activator.width / 2) - (content.width / 2) ) } else if (this.left || this.right) { left = ( activatorLeft + (this.right ? activator.width : -content.width) + (this.right ? 10 : -10) ) } if (this.nudgeLeft) left -= parseInt(this.nudgeLeft) if (this.nudgeRight) left += parseInt(this.nudgeRight) return `${this.calcXOverflow(left, this.dimensions.content.width)}px` }, calculatedTop (): string { const { activator, content } = this.dimensions const activatorTop = this.attach !== false ? activator.offsetTop : activator.top let top = 0 if (this.top || this.bottom) { top = ( activatorTop + (this.bottom ? activator.height : -content.height) + (this.bottom ? 10 : -10) ) } else if (this.left || this.right) { top = ( activatorTop + (activator.height / 2) - (content.height / 2) ) } if (this.nudgeTop) top -= parseInt(this.nudgeTop) if (this.nudgeBottom) top += parseInt(this.nudgeBottom) return `${this.calcYOverflow(top + this.pageYOffset)}px` }, classes (): object { return { 'v-tooltip--top': this.top, 'v-tooltip--right': this.right, 'v-tooltip--bottom': this.bottom, 'v-tooltip--left': this.left, 'v-tooltip--attached': this.attach === '' || this.attach === true || this.attach === 'attach', } }, computedTransition (): string { if (this.transition) return this.transition return this.isActive ? 'scale-transition' : 'fade-transition' }, offsetY (): boolean { return this.top || this.bottom }, offsetX (): boolean { return this.left || this.right }, styles (): object { return { left: this.calculatedLeft, maxWidth: convertToUnit(this.maxWidth), minWidth: convertToUnit(this.minWidth), opacity: this.isActive ? 0.9 : 0, top: this.calculatedTop, zIndex: this.zIndex || this.activeZIndex, } }, }, beforeMount () { this.$nextTick(() => { this.value && this.callActivate() }) }, mounted () { if (getSlotType(this, 'activator', true) === 'v-slot') { consoleError(`v-tooltip's activator slot must be bound, try '<template #activator="data"><v-btn v-on="data.on>'`, this) } }, methods: { activate () { // Update coordinates and dimensions of menu // and its activator this.updateDimensions() // Start the transition requestAnimationFrame(this.startTransition) }, deactivate () { this.runDelay('close') }, genActivatorListeners () { const listeners = Activatable.options.methods.genActivatorListeners.call(this) listeners.focus = (e: Event) => { this.getActivator(e) this.runDelay('open') } listeners.blur = (e: Event) => { this.getActivator(e) this.runDelay('close') } listeners.keydown = (e: KeyboardEvent) => { if (e.keyCode === keyCodes.esc) { this.getActivator(e) this.runDelay('close') } } return listeners }, genTransition () { const content = this.genContent() if (!this.computedTransition) return content return this.$createElement('transition', { props: { name: this.computedTransition, }, }, [content]) }, genContent () { return this.$createElement( 'div', this.setBackgroundColor(this.color, { staticClass: 'v-tooltip__content', class: { [this.contentClass]: true, menuable__content__active: this.isActive, 'v-tooltip__content--fixed': this.activatorFixed, }, style: this.styles, attrs: this.getScopeIdAttrs(), directives: [{ name: 'show', value: this.isContentActive, }], ref: 'content', }), this.getContentSlot() ) }, }, render (h): VNode { return h(this.tag, { staticClass: 'v-tooltip', class: this.classes, }, [ this.showLazyContent(() => [this.genTransition()]), this.genActivator(), ]) }, })