md-editor-v3
Version:
Markdown editor for vue3, developed in jsx and typescript, dark theme、beautify content by prettier、render articles directly、paste or clip the picture and upload it...
244 lines (243 loc) • 6.59 kB
JavaScript
import { defineComponent, reactive, ref, watch, onMounted, onBeforeUnmount, cloneVNode, createVNode, inject } from "vue";
import { p as prefix } from "./config.mjs";
import { g as getSlot } from "./vue-tsx.mjs";
const props$1 = {
overlay: {
type: [String, Object],
default: ""
},
visible: {
type: Boolean,
default: false
},
onChange: {
type: Function,
default: () => {
}
},
// 相对滚动的元素选择器
relative: {
type: String,
default: "html"
},
disabled: {
type: Boolean,
default: void 0
}
};
const Dropdown = /* @__PURE__ */ defineComponent({
name: `${prefix}-dropdown`,
props: props$1,
setup(props2, ctx) {
const HIDDEN_CLASS = `${prefix}-dropdown-hidden`;
const ctl = reactive({
overlayClass: [HIDDEN_CLASS],
overlayStyle: {},
triggerHover: false,
overlayHover: false
});
const triggerRef = ref();
const overlayRef = ref();
const triggerHandler = () => {
var _a, _b;
if (props2.disabled) {
return false;
}
ctl.triggerHover = true;
const triggerEle = triggerRef.value;
const overlayEle = overlayRef.value;
if (!triggerEle || !overlayEle) {
return;
}
const triggerInfo = triggerEle.getBoundingClientRect();
const triggerTop = triggerEle.offsetTop;
const triggerLeft = triggerEle.offsetLeft;
const triggerHeight = triggerInfo.height;
const triggerWidth = triggerInfo.width;
const rootNode = triggerEle.getRootNode();
const relativecrollLeft = ((_a = rootNode.querySelector(props2.relative)) == null ? void 0 : _a.scrollLeft) || 0;
const relativeWidth = ((_b = rootNode.querySelector(props2.relative)) == null ? void 0 : _b.clientWidth) || 0;
let left = triggerLeft - overlayEle.offsetWidth / 2 + triggerWidth / 2 - relativecrollLeft;
if (left + overlayEle.offsetWidth > relativecrollLeft + relativeWidth) {
left = relativecrollLeft + relativeWidth - overlayEle.offsetWidth;
}
if (left < 0) {
left = 0;
}
ctl.overlayStyle = {
...ctl.overlayStyle,
top: triggerTop + triggerHeight + "px",
left: left + "px"
};
props2.onChange(true);
};
const overlayHandler = () => {
if (props2.disabled) {
return false;
}
ctl.overlayHover = true;
};
watch(() => props2.visible, (newV) => {
if (newV) {
ctl.overlayClass = ctl.overlayClass.filter((classItem) => classItem !== HIDDEN_CLASS);
} else {
ctl.overlayClass.push(HIDDEN_CLASS);
}
});
let hiddenTimer = -1;
const leaveHidden = (e) => {
if (triggerRef.value === e.target) {
ctl.triggerHover = false;
} else {
ctl.overlayHover = false;
}
clearTimeout(hiddenTimer);
hiddenTimer = window.setTimeout(() => {
if (!ctl.overlayHover && !ctl.triggerHover) {
props2.onChange(false);
}
}, 10);
};
onMounted(() => {
triggerRef.value.addEventListener("mouseenter", triggerHandler);
triggerRef.value.addEventListener("mouseleave", leaveHidden);
overlayRef.value.addEventListener("mouseenter", overlayHandler);
overlayRef.value.addEventListener("mouseleave", leaveHidden);
});
onBeforeUnmount(() => {
triggerRef.value.removeEventListener("mouseenter", triggerHandler);
triggerRef.value.removeEventListener("mouseleave", leaveHidden);
overlayRef.value.removeEventListener("mouseenter", overlayHandler);
overlayRef.value.removeEventListener("mouseleave", leaveHidden);
});
return () => {
const slotDefault = getSlot({
ctx
});
const slotOverlay = getSlot({
props: props2,
ctx
}, "overlay");
const trigger = cloneVNode(slotDefault instanceof Array ? slotDefault[0] : slotDefault, {
ref: triggerRef,
key: "cloned-dropdown-trigger"
});
const overlay = createVNode("div", {
"class": [`${prefix}-dropdown`, ctl.overlayClass],
"style": ctl.overlayStyle,
"ref": overlayRef
}, [createVNode("div", {
"class": `${prefix}-dropdown-overlay`
}, [slotOverlay instanceof Array ? slotOverlay[0] : slotOverlay])]);
return [trigger, overlay];
};
}
});
const props = {
title: {
type: String,
default: ""
},
visible: {
type: Boolean,
default: void 0
},
/**
* 展示在工具栏的内容,通常是个图标
*
* @deprecated 使用默认插槽代替
*/
trigger: {
type: [String, Object],
default: void 0
},
onChange: {
type: Function,
default: void 0
},
// 下拉框中的内容
overlay: {
type: [String, Object],
default: void 0
},
/**
* ==没有意义,仅用于规避克隆组件自动嵌入insert方法时,传入的是该组件而产生的waring
*/
insert: {
type: Function,
default: void 0
},
language: {
type: String,
default: void 0
},
theme: {
type: String,
default: void 0
},
previewTheme: {
type: String,
default: void 0
},
codeTheme: {
type: String,
default: void 0
},
disabled: {
type: Boolean,
default: void 0
},
showToolbarName: {
type: Boolean,
default: void 0
}
/**
* ==结束
*/
};
const DropdownToolbar = /* @__PURE__ */ defineComponent({
name: "DropdownToolbar",
props,
emits: ["onChange"],
setup(props2, ctx) {
const editorId = inject("editorId");
return () => {
const Trigger = getSlot({
props: props2,
ctx
}, "trigger");
const Overlay = getSlot({
props: props2,
ctx
}, "overlay");
const Default = getSlot({
props: props2,
ctx
});
return createVNode(Dropdown, {
"relative": `#${editorId}-toolbar-wrapper`,
"visible": props2.visible,
"onChange": (v) => {
var _a;
(_a = props2.onChange) == null ? void 0 : _a.call(props2, v);
ctx.emit("onChange", v);
},
"overlay": Overlay,
"disabled": props2.disabled
}, {
default: () => [createVNode("div", {
"class": [`${prefix}-toolbar-item`, props2.disabled && `${prefix}-disabled`],
"title": props2.title || ""
}, [Default || Trigger])]
});
};
}
});
DropdownToolbar.install = (app) => {
app.component(DropdownToolbar.name, DropdownToolbar);
return app;
};
export {
DropdownToolbar as D,
Dropdown as a
};