kui-vue
Version:
A lightweight desktop UI component library suitable for Vue.js 2.
254 lines (248 loc) • 7.47 kB
JSX
import {
defineComponent,
/*Transition,*/ ref,
/*cloneVNode,*/ nextTick,
watch,
onMounted,
onBeforeMount,
inject,
computed,
} from "vue";
import transfer from "../directives/transfer";
import { getChildren } from "../utils/vnode";
import { HelpCircle } from "kui-icons";
import Icon from "../icon";
import { Button } from "../button";
import { setPlacement } from "../utils/placement";
import { withInstall, cloneVNode } from "../utils/vue";
import zhCN from "../locale/zh-CN";
const Popconfirm = defineComponent({
name: "Popconfirm",
directives: {
transfer,
},
props: {
dark: Boolean,
show: Boolean,
title: [String, Number, Object, Array],
size: String,
width: [Number, String],
okText: { type: String },
cancelText: { type: String },
placement: {
validator(value) {
return [
"top",
"top-left",
"top-right",
"bottom",
"bottom-left",
"bottom-right",
"left",
"left-bottom",
"left-top",
"right",
"right-top",
"right-bottom",
].includes(value);
},
default: "top",
},
},
setup(ps, { slots, attrs, emit }) {
const injectedLocale = inject("locale", zhCN);
const locale = computed(() => {
return injectedLocale instanceof Object && "value" in injectedLocale
? injectedLocale.value
: injectedLocale;
});
const rendered = ref(false);
const visible = ref(false);
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 updatePosition = () => {
nextTick(() => {
setPlacement({
refSelection,
refPopper,
currentPlacement,
transOrigin,
top,
left,
});
});
};
onMounted(() => {
if (ps.show) {
updatePosition();
}
});
onBeforeMount(() => {
document.removeEventListener("click", outsideClick);
});
watch(
() => ps.show,
(nv, no) => {
visible.value = nv;
}
);
watch(
() => ps.title,
() => {
if (visible.value) {
updatePosition();
}
}
);
const updateShow = (value) => {
visible.value = value;
emit("update:show", value);
};
const outsideClick = (e) => {
const ctx = refSelection.value?.$el || refSelection.value;
if (
refPopper.value &&
!refPopper.value.contains(e.target) &&
ctx &&
!ctx.contains(e.target)
) {
updateShow(false);
}
};
const mouseEnter = () => {
if (!rendered.value) {
rendered.value = true;
document.addEventListener("click", outsideClick);
nextTick(() => {
updateShow(true);
updatePosition();
});
} else {
clearTimeout(showTimer.value);
updateShow(true);
updatePosition();
}
};
const ok = () => {
updateShow(false);
emit("ok");
};
const cancel = () => {
updateShow(false);
emit("cancel");
};
return () => {
const title = slots.title?.() || ps.title;
const preCls = "popconfirm";
const cls = [
`k-${preCls}`,
{
[`k-${preCls}-has-arrow`]: true,
[`k-${preCls}-dark`]: ps.dark,
},
];
const wpProps = {
ref: refSelection,
// onClick: mouseEnter, //for 3
on: {
click: mouseEnter,
},
};
const children = getChildren(slots.default?.());
const nodes = children?.map((node) => {
let pp = { attrs: { ...attrs } };
if (children.length == 1) {
pp = { ...pp, ...wpProps };
}
return cloneVNode(node, pp, true);
});
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);
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`}>
<div class={`k-${preCls}-body`}>
<Icon type={HelpCircle} />
<div class={`k-${preCls}-title`}>{title}</div>
</div>
<div class={`k-${preCls}-footer`}>
<Button size="small" onClick={cancel}>
{ps.cancelText || locale.value.k.common.cancel}
</Button>
<Button size="small" type="primary" onClick={ok}>
{ps.okText || locale.value.k.common.ok}
</Button>
</div>
<div class={`k-${preCls}-arrow`}>
<svg style={{ fill: "currentcolor" }} viewBox="0 0 24 8">
{/* <path id="ot" d="m24,0.97087l0,1c-4,0 -5.5,1 -7.5,3c-2,2 -2.5,3 -4.5,3c-2,0 -2.5,-1 -4.5,-3c-2,-2 -3.5,-3 -7.5,-3l0,-1l24,0z" /> */}
{/* <path stroke="currentcolor" id="in" d="m24,0l0,1c-4,0 -5.5,1 -7.5,3c-2,2 -2.5,3 -4.5,3c-2,0 -2.5,-1 -4.5,-3c-2,-2 -3.5,-3 -7.5,-3l0,-1l24,0z" /> */}
<path
d="M24,0.97087 L24,1.97087 C20,1.97087 18.5,2.97087 16.5,4.97087 C14.5,6.97087 14,7.97087 12,7.97087 C10,7.97087 9.5,6.97087 7.5,4.97087 C5.5,2.97087 4,1.97087 0,1.97087 L0,0.97087 L24,0.97087 Z"
id="ot"
/>
<path
d="M24,0 L24,1 C20.032328,1 18.1576594,1.985435 16.1576594,3.985435 C14.1576594,5.985435 13.3847825,7 12,7 C10.6152175,7 9.81306952,5.985435 7.81306952,3.985435 C5.81306952,1.985435 4.0114261,1 0,1 L0,0 L24,0 Z"
id="in"
stroke="currentcolor"
/>
{/* <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 <>{...childNodes}</>; //for 3
return cloneVNode(nodeWrapper, {}, true, overlay);
};
},
});
export default withInstall(Popconfirm);