@zhsz/cool-design-crud
Version:
216 lines (215 loc) • 5.82 kB
JavaScript
import { h, render, defineComponent, ref, reactive, onMounted, createVNode, nextTick } from "vue";
import { contains, removeClass, isString, addClass } from "../../utils/index.mjs";
import "../../utils/test.mjs";
import { useRefs } from "../../hooks/core.mjs";
import "@formily/core";
import { isFunction } from "lodash-es";
import "../../hooks/table.mjs";
const isComponent = (obj) => {
if (obj && typeof obj.render === "function") {
return true;
} else {
return false;
}
};
const ClContextMenu = /* @__PURE__ */ defineComponent({
name: "cl-context-menu",
props: {
show: Boolean,
options: {
type: Object,
default: () => {
return {};
}
},
customVnode: [Function, Object],
customClass: String,
event: {
type: Object,
default: () => {
return {};
}
}
},
setup(props, {
expose,
slots
}) {
const {
refs,
setRefs
} = useRefs();
const visible = ref(props.show || false);
const list = ref([]);
const style = reactive({
left: "0px",
top: "0px"
});
const customVnode = ref(false);
const customClass = ref("");
const ids = ref("");
function stopDefault(e) {
if (e.preventDefault) {
e.preventDefault();
}
if (e.stopPropagation) {
e.stopPropagation();
}
}
function parseList(list2) {
function deep(list3) {
list3.forEach((e) => {
e.showChildren = false;
if (e.children) {
deep(e.children);
}
});
}
deep(list2);
return list2;
}
let targetEl = null;
function close() {
visible.value = false;
ids.value = "";
removeClass(targetEl, "cl-context-menu__target");
}
function open(event, options) {
let left = event.pageX;
let top = event.pageY;
if (!options) {
options = {};
}
if (options.hover) {
const d = options.hover === true ? {} : options.hover;
targetEl = event.target;
if (targetEl && isString(targetEl.className)) {
if (d.target) {
while (!targetEl.className.includes(d.target)) {
targetEl = targetEl.parentNode;
}
}
addClass(targetEl, d.className || "cl-context-menu__target");
}
}
if (options.list) {
list.value = parseList(options.list);
}
if (options.customVnode) {
if (isFunction(options.customVnode)) {
customVnode.value = options.customVnode();
}
if (isComponent(options.customVnode)) {
customVnode.value = h(options.customVnode);
}
}
if (options.customClass) {
customClass.value = options.customClass;
}
stopDefault(event);
visible.value = true;
nextTick(() => {
const {
clientHeight: h1,
clientWidth: w1
} = event.target.ownerDocument.body;
const {
clientHeight: h2,
clientWidth: w2
} = refs["context-menu"].querySelector(".cl-context-menu__box");
if (top + h2 > h1) {
top = h1 - h2 - 5;
}
if (left + w2 > w1) {
left = w1 - w2 - 5;
}
style.left = `${left}px`;
style.top = `${top}px`;
});
return {
close
};
}
function rowClick(item, id) {
ids.value = id;
if (item.disabled) {
return false;
}
if (item.callback) {
return item.callback(close);
}
if (item.children) {
item.showChildren = !item.showChildren;
} else {
close();
}
}
expose({
open,
close
});
onMounted(() => {
if (visible.value) {
const {
body,
documentElement
} = props.event.target.ownerDocument;
body.appendChild(refs["context-menu"]);
(documentElement || body).addEventListener("mousedown", (e) => {
const el = refs["context-menu"];
if (!contains(el, e.target) && el !== e.target) {
close();
}
});
open(props.event, props.options);
}
});
return () => {
function deep(list2, pId, level) {
return createVNode("div", {
"class": ["cl-context-menu__box", level > 1 && "is-append"]
}, [list2.filter((e) => !e.hidden).map((e, i) => {
const id = `${pId}-${i}`;
return createVNode("div", {
"class": {
"is-active": ids.value.includes(id),
"is-ellipsis": e.ellipsis,
"is-disabled": e.disabled
}
}, [e.prefixIcon && createVNode("i", {
"class": e.prefixIcon
}, null), createVNode("span", {
"onClick": () => {
rowClick(e, id);
}
}, [e.label]), e.suffixIcon && createVNode("i", {
"class": e.suffixIcon
}, null), e.children && e.showChildren && deep(e.children, id, level + 1)]);
})]);
}
return visible.value && createVNode("div", {
"class": ["cl-context-menu", `${customClass.value}_parent`],
"ref": setRefs("context-menu"),
"style": style,
"onContextmenu": stopDefault
}, [slots.default ? slots.default() : customVnode.value === false ? deep(list.value, "0", 1) : createVNode("div", {
"class": ["cl-context-menu__box", customClass.value]
}, [customVnode.value])]);
};
}
});
const ContextMenu = {
open(event, options) {
const vm = h(ClContextMenu, {
show: true,
event,
options
});
render(vm, event.target.ownerDocument.createElement("div"));
}
};
export {
ContextMenu,
ClContextMenu as default,
isComponent
};