kui-vue
Version:
A lightweight desktop UI component library suitable for Vue.js 2.
222 lines (220 loc) • 6.08 kB
JSX
import {
defineComponent,
/*Transition,*/ ref,
/*cloneVNode,*/ nextTick,
watch,
onMounted,
} from "vue";
import { isColor } from "../utils/color";
import { setPlacement } from "../utils/placement";
import transfer from "../directives/transfer";
import { getChildren } from "../utils/vnode";
import { withInstall, cloneVNode } from "../utils/vue";
import { colors, placements } from "../const/var";
const Tooltip = defineComponent({
name: "Tooltip",
directives: {
transfer,
},
props: {
show: Boolean,
dark: Boolean,
title: [String, Number, Object, Array],
color: String,
disabled: Boolean,
size: String,
width: [Number, String],
placement: {
validator(value) {
return placements.includes(value);
},
default: "top",
},
show: Boolean,
},
setup(ps, { slots, attrs, emit }) {
const rendered = ref(ps.show);
const visible = ref(ps.show);
const refPopper = ref();
const refSelection = ref();
const left = ref(0);
const top = ref(0);
const currentPlacement = ref(ps.placement);
const transOrigin = ref("bottom");
const hideTimer = ref();
const showTimer = ref();
const updateShow = (value) => {
visible.value = value;
emit("update:show", value);
};
const updatePosition = () => {
nextTick(() => {
setPlacement({
refSelection,
refPopper,
currentPlacement,
transOrigin,
top,
left,
});
});
};
onMounted(() => {
if (ps.show) {
updatePosition();
}
});
watch(
() => ps.show,
(nv, no) => {
visible.value = nv;
}
);
// 监听 title 的变化
watch(
() => ps.title,
() => {
if (visible.value) {
updatePosition();
}
}
);
const mouseEnter = () => {
if (ps.disabled) return;
if (!rendered.value) {
rendered.value = true;
nextTick(() => {
updateShow(true);
updatePosition();
});
} else {
clearTimeout(showTimer.value);
updateShow(true);
updatePosition();
}
};
const hide = () => {
hideTimer.value = setTimeout(() => {
if (!ps.show) {
updateShow(false);
}
}, 300);
};
return () => {
const title = slots.title?.() || ps.title;
const preCls = "tooltip";
const { color } = ps;
const cls = [
`k-${preCls}`,
{
[`k-${preCls}-${color}`]: color && !isColor(color),
[`k-${preCls}-has-color`]: isColor(color),
[`k-${preCls}-has-arrow`]: true,
[`k-${preCls}-dark`]: ps.dark,
},
];
const wpProps = {
ref: refSelection,
on: {
touchstart: mouseEnter,
touchmove: updatePosition,
touchend: hide,
mouseenter: mouseEnter,
mouseleave: hide,
},
// onTouchstart: mouseEnter,
// onTouchend: hide,
// onMouseenter: mouseEnter,
// onMouseleave: hide,
};
const children = getChildren(slots.default?.());
const nodes = children?.map((node) => {
// let pp = { ...attrs }; //for 3
let pp = { attrs: { ...attrs } };
if (children.length == 1) {
pp = { ...pp, ...wpProps };
}
return cloneVNode(node, pp, true);
// return cloneVNode(node, pp, true, true); //for 3
});
const nodeWrapper =
nodes.length > 1 ? <span {...wpProps}>{...nodes}</span> : nodes[0];
const styles = {
left: `${left.value}px`,
top: `${top.value}px`,
transformOrigin: transOrigin.value,
};
// const childNodes = [nodeWrapper];
const props = {
// "k-placement": currentPlacement.value, //for 3
attrs: { "k-placement": currentPlacement.value },
style: styles,
ref: refPopper,
on: {
mouseenter: () => {
clearTimeout(hideTimer.value);
if (ps.disabled) return;
updateShow(true);
},
mouseleave: () => {
showTimer.value = setTimeout(() => {
if (!ps.show) {
updateShow(false);
}
}, 300);
},
},
// onMouseenter: () => {
// clearTimeout(hideTimer.value);
// updateShow(true)
// },
// onMouseleave: () => {
// showTimer.value = setTimeout(() => {
// if (!ps.show) {
// updateShow(false)
// }
// }, 300);
// },
};
// if (rendered.value) {
// childNodes.push(
const overlay = rendered.value ? (
<transition name={`k-${preCls}`}>
<div class={cls} v-transfer={true} v-show={visible.value} {...props}>
<div
class={`k-${preCls}-content`}
style={{
backgroundColor: isColor(color)
? colors.includes(color)
? `var(--kui-color-${color})`
: color
: null,
}}
>
<div class={`k-${preCls}-title`}>{title}</div>
<div class={`k-${preCls}-arrow`}>
<svg
style={{
fill: isColor(color)
? colors.includes(color)
? `var(--kui-color-${color})`
: color
: "currentcolor",
}}
viewBox="0 0 24 7"
>
<path d="M24 0V1C20 1 18.5 2 16.5 4C14.5 6 14 7 12 7C10 7 9.5 6 7.5 4C5.5 2 4 1 0 1V0H24Z"></path>
</svg>
</div>
</div>
</div>
</transition>
) : null;
// );
// }
return cloneVNode(nodeWrapper, {}, true, overlay);
// return <>{...childNodes}</>; // for 3
};
},
});
export default withInstall(Tooltip);