buefy
Version:
Lightweight UI components for Vue.js (v3) based on Bulma
394 lines (389 loc) • 11.9 kB
JavaScript
'use strict';
var vue = require('vue');
var config = require('./config-DR826Ki2.js');
var helpers = require('./helpers.js');
var _pluginVue_exportHelper = require('./_plugin-vue_export-helper-Die8u8yB.js');
const TOOLTIP_POSITIONS = ["is-auto", "is-top", "is-bottom", "is-left", "is-right"];
var _sfc_main = vue.defineComponent({
name: "BTooltip",
props: {
active: {
type: Boolean,
default: true
},
type: {
type: String,
default: () => config.config.defaultTooltipType
},
label: String,
delay: {
type: Number,
default: () => config.config.defaultTooltipDelay
},
closeDelay: {
type: Number,
default: () => config.config.defaultTooltipCloseDelay
},
position: {
type: String,
default: "is-auto",
validator(value) {
return TOOLTIP_POSITIONS.indexOf(value) > -1;
}
},
triggers: {
type: Array,
default: () => ["hover"]
},
always: Boolean,
square: Boolean,
dashed: Boolean,
multilined: Boolean,
size: {
type: String,
default: "is-medium"
},
appendToBody: Boolean,
animated: {
type: Boolean,
default: true
},
animation: {
type: String,
default: "fade"
},
contentClass: String,
autoClose: {
type: [Array, Boolean],
default: true
}
},
emits: {
close: () => true,
open: () => true
},
data() {
return {
isActive: false,
triggerStyle: {},
timer: void 0,
_bodyEl: void 0,
// Used to append to body
resizeObserver: void 0,
resizeListener: void 0,
timeOutID: void 0,
controller: void 0,
dynamicPosition: void 0
// Computed once opened
};
},
computed: {
rootClasses() {
return ["b-tooltip", this.type, this.dynamicPosition, this.size, {
"is-square": this.square,
"is-always": this.always,
"is-multiline": this.multilined,
"is-dashed": this.dashed
}];
},
newAnimation() {
return this.animated ? this.animation : void 0;
}
},
watch: {
isActive() {
this.isActive ? this.$emit("open") : this.$emit("close");
if (this.appendToBody) {
this.updateAppendToBody();
}
}
},
methods: {
computePosition() {
if (this.position !== "is-auto") return this.position;
const trigger = this.$refs.trigger;
const bounds = trigger.getBoundingClientRect();
const dt = bounds.top;
const db = window.innerHeight - bounds.bottom;
const dl = bounds.left;
const dr = window.innerWidth - bounds.right;
const min = Math.min(dt, db, dl, dr);
if (min === dt) {
return "is-bottom";
} else if (min === db) {
return "is-top";
} else if (min === dl) {
return "is-right";
} else {
return "is-left";
}
},
updateAppendToBody() {
const tooltip = this.$refs.tooltip;
const trigger = this.$refs.trigger;
if (tooltip && trigger) {
const tooltipEl = this.$data._bodyEl.children[0];
tooltipEl.classList.forEach((item) => tooltipEl.classList.remove(item));
this.rootClasses.forEach((item) => {
if (typeof item === "object") {
const record = item;
for (const key in record) {
if (record[key]) {
tooltipEl.classList.add(key);
}
}
} else {
tooltipEl.classList.add(item);
}
});
const rect = trigger.getBoundingClientRect();
const top = rect.top + window.scrollY;
const left = rect.left + window.scrollX;
tooltipEl.style.position = "absolute";
this.dynamicPosition = this.computePosition();
switch (this.dynamicPosition) {
case "is-top":
tooltipEl.style.width = `${trigger.clientWidth}px`;
tooltipEl.style.height = "0px";
tooltipEl.style.top = "0px";
tooltipEl.style.left = "0px";
break;
case "is-bottom":
tooltipEl.style.width = `${trigger.clientWidth}px`;
tooltipEl.style.height = "0px";
tooltipEl.style.top = `${trigger.clientHeight}px`;
tooltipEl.style.left = "0px";
break;
case "is-left":
tooltipEl.style.width = "0px";
tooltipEl.style.height = `${trigger.clientHeight}px`;
tooltipEl.style.top = "0px";
tooltipEl.style.left = "0px";
break;
case "is-right":
tooltipEl.style.width = "0px";
tooltipEl.style.height = `${trigger.clientHeight}px`;
tooltipEl.style.top = "0px";
tooltipEl.style.left = `${trigger.clientWidth}px`;
break;
}
const wrapper = this.$data._bodyEl;
wrapper.style.position = "absolute";
wrapper.style.top = `${top}px`;
wrapper.style.left = `${left}px`;
wrapper.style.width = "0px";
wrapper.style.zIndex = this.isActive || this.always ? "99" : "-1";
this.triggerStyle = {
zIndex: this.isActive || this.always ? "100" : void 0
};
}
},
onClick() {
if (this.triggers.indexOf("click") < 0) return;
this.$nextTick(() => {
this.timeOutID = setTimeout(() => this.open());
});
},
onHover() {
if (this.triggers.indexOf("hover") < 0) return;
this.open();
},
onContextMenu(e) {
if (this.triggers.indexOf("contextmenu") < 0) return;
e.preventDefault();
this.open();
},
onFocus() {
if (this.triggers.indexOf("focus") < 0) return;
this.open();
},
open() {
this.dynamicPosition = this.computePosition();
if (this.delay) {
this.timer = setTimeout(() => {
this.isActive = true;
this.timer = void 0;
}, this.delay);
} else {
this.isActive = true;
}
},
close() {
if (typeof this.autoClose === "boolean") {
if (this.autoClose && this.timer) clearTimeout(this.timer);
if (this.closeDelay) {
this.timer = setTimeout(() => {
this.isActive = !this.autoClose;
this.timer = void 0;
}, this.closeDelay);
} else {
this.isActive = !this.autoClose;
}
}
},
/*
* Close tooltip if clicked outside.
*/
clickedOutside(event) {
if (this.isActive) {
if (Array.isArray(this.autoClose)) {
if (this.autoClose.includes("outside")) {
if (!this.isInWhiteList(event.target)) {
this.isActive = false;
return;
}
}
if (this.autoClose.includes("inside")) {
if (this.isInWhiteList(event.target)) this.isActive = false;
}
}
}
},
/*
* Keypress event that is bound to the document
*/
keyPress({ key }) {
if (this.isActive && (key === "Escape" || key === "Esc")) {
if (Array.isArray(this.autoClose)) {
if (this.autoClose.indexOf("escape") >= 0) this.isActive = false;
}
}
},
/*
* White-listed items to not close when clicked.
*/
isInWhiteList(el) {
if (el === this.$refs.content) return true;
if (this.$refs.content != null) {
const children = this.$refs.content.querySelectorAll("*");
for (const child of children) {
if (el === child) {
return true;
}
}
}
return false;
}
},
mounted() {
if (this.appendToBody && typeof window !== "undefined") {
this.controller = new window.AbortController();
this.$data._bodyEl = helpers.createAbsoluteElement(this.$refs.content);
this.updateAppendToBody();
const animation = this.$el.closest(".animation-content");
if (animation != null) {
const listener = () => {
this.updateAppendToBody();
animation.removeEventListener("transitionend", listener);
};
animation.addEventListener("transitionend", listener, {
signal: this.controller.signal
});
}
this.resizeListener = () => this.updateAppendToBody();
window.addEventListener("resize", this.resizeListener);
this.resizeObserver = new ResizeObserver(this.resizeListener);
if (this.$el.parentNode != null && this.$el.parentNode.nodeType === Node.ELEMENT_NODE) {
this.resizeObserver.observe(this.$el.parentNode);
}
}
if (this.always) {
this.dynamicPosition = this.computePosition();
}
},
created() {
if (typeof window !== "undefined") {
document.addEventListener("click", this.clickedOutside);
document.addEventListener("keyup", this.keyPress);
}
},
beforeUnmount() {
if (typeof window !== "undefined") {
document.removeEventListener("click", this.clickedOutside);
document.removeEventListener("keyup", this.keyPress);
}
if (this.resizeListener != null) {
window.removeEventListener("resize", this.resizeListener);
}
if (this.resizeObserver != null) {
this.resizeObserver.disconnect();
}
if (this.appendToBody) {
helpers.removeElement(this.$data._bodyEl);
}
if (this.controller != null) {
this.controller.abort();
}
clearTimeout(this.timer);
clearTimeout(this.timeOutID);
}
});
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
return vue.openBlock(), vue.createElementBlock(
"div",
{
ref: "tooltip",
class: vue.normalizeClass(_ctx.rootClasses)
},
[
vue.createVNode(vue.Transition, {
name: _ctx.newAnimation,
persisted: ""
}, {
default: vue.withCtx(() => [
vue.withDirectives(vue.createElementVNode(
"div",
{
ref: "content",
class: vue.normalizeClass(["tooltip-content", _ctx.contentClass])
},
[
_ctx.label ? (vue.openBlock(), vue.createElementBlock(
vue.Fragment,
{ key: 0 },
[
vue.createTextVNode(
vue.toDisplayString(_ctx.label),
1
/* TEXT */
)
],
64
/* STABLE_FRAGMENT */
)) : _ctx.$slots.content ? vue.renderSlot(_ctx.$slots, "content", { key: 1 }) : vue.createCommentVNode("v-if", true)
],
2
/* CLASS */
), [
[vue.vShow, _ctx.active && (_ctx.isActive || _ctx.always)]
])
]),
_: 3
/* FORWARDED */
}, 8, ["name"]),
vue.createElementVNode(
"div",
{
ref: "trigger",
class: "tooltip-trigger",
style: vue.normalizeStyle(_ctx.triggerStyle),
onClick: _cache[0] || (_cache[0] = (...args) => _ctx.onClick && _ctx.onClick(...args)),
onContextmenu: _cache[1] || (_cache[1] = (...args) => _ctx.onContextMenu && _ctx.onContextMenu(...args)),
onMouseenter: _cache[2] || (_cache[2] = (...args) => _ctx.onHover && _ctx.onHover(...args)),
onFocusCapture: _cache[3] || (_cache[3] = (...args) => _ctx.onFocus && _ctx.onFocus(...args)),
onBlurCapture: _cache[4] || (_cache[4] = (...args) => _ctx.close && _ctx.close(...args)),
onMouseleave: _cache[5] || (_cache[5] = (...args) => _ctx.close && _ctx.close(...args))
},
[
vue.renderSlot(_ctx.$slots, "default", { ref: "slot" })
],
36
/* STYLE, NEED_HYDRATION */
)
],
2
/* CLASS */
);
}
var Tooltip = /* @__PURE__ */ _pluginVue_exportHelper._export_sfc(_sfc_main, [["render", _sfc_render]]);
exports.Tooltip = Tooltip;