UNPKG

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
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 };