UNPKG

double-ui-vue

Version:
843 lines (842 loc) 24.5 kB
import { openBlock, createElementBlock, createElementVNode, defineComponent, computed, isRef, createVNode, Transition, withDirectives, Fragment, vShow, render as render$3, reactive, watch, onBeforeUnmount, ref, getCurrentInstance, nextTick, onMounted, createTextVNode } from "vue"; var style$1 = ""; var V = (e, t) => { let r = e.tagName.toLocaleLowerCase(); return r === "body" || t.some((o) => o.toLocaleLowerCase() === r) ? e : V(e.parentNode, t); }, M = V; var _t = (e, t) => { let r = e.target; t && (r = M(r, [t])); let { clientWidth: o, scrollWidth: n } = r; n > o ? r.title = r.innerText : r.title = ""; }, Kt = _t; const _hoisted_1$2 = { viewBox: "0 0 16 16", xmlns: "http://www.w3.org/2000/svg" }; const _hoisted_2$2 = /* @__PURE__ */ createElementVNode("path", { d: "m8.39 5.988 2.96 3.7a.5.5 0 0 1-.39.812H5.04a.5.5 0 0 1-.39-.812l2.96-3.7a.5.5 0 0 1 .78 0Z", class: "svg-fill-grey-500" }, null, -1); const _hoisted_3$2 = [ _hoisted_2$2 ]; function render$2(_ctx, _cache) { return openBlock(), createElementBlock("svg", _hoisted_1$2, _hoisted_3$2); } var TriangleIcon = { render: render$2 }; const _hoisted_1$1 = { viewBox: "0 0 16 16", xmlns: "http://www.w3.org/2000/svg" }; const _hoisted_2$1 = /* @__PURE__ */ createElementVNode("path", { d: "M8 1a7 7 0 1 0 0 14A7 7 0 0 0 8 1Zm2.784 8.637a.656.656 0 0 1-.928.929L8 8.709l-1.856 1.857a.656.656 0 0 1-.928-.929l1.856-1.856-1.856-1.856a.656.656 0 0 1 .928-.928L8 6.853l1.856-1.856a.656.656 0 0 1 .928.928L8.928 7.781l1.856 1.856Z", class: "svg-fill-grey-500", "fill-rule": "evenodd" }, null, -1); const _hoisted_3$1 = [ _hoisted_2$1 ]; function render$1(_ctx, _cache) { return openBlock(), createElementBlock("svg", _hoisted_1$1, _hoisted_3$1); } var DeleteIcon = { render: render$1 }; const _hoisted_1 = { viewBox: "0 0 16 16", xmlns: "http://www.w3.org/2000/svg" }; const _hoisted_2 = /* @__PURE__ */ createElementVNode("path", { d: "m8.027 7.074 5.387-5.388 1.078 1.078L9.104 8.15l5.388 5.388-1.078 1.077L8.027 9.23l-5.388 5.387-1.077-1.077L6.949 8.15 1.562 2.764l1.077-1.078 5.388 5.388Z", class: "svg-fill-grey-500" }, null, -1); const _hoisted_3 = [ _hoisted_2 ]; function render(_ctx, _cache) { return openBlock(), createElementBlock("svg", _hoisted_1, _hoisted_3); } var CloseIcon = { render }; const GetScrollbarWidth = () => { const oDiv = document.createElement("div"); oDiv.style.cssText = "position:absolute;top:-1000px;width:100px;height:100px;overflow:hidden;opacity:0;"; const noScroll = document.body.appendChild(oDiv).clientWidth; oDiv.style.overflowY = "scroll"; const scroll = oDiv.clientWidth; document.body.removeChild(oDiv); const bw = noScroll - scroll; return bw < 6 ? 6 : bw; }; var style = ""; const TipModal = defineComponent({ name: "TipModal", props: { tag: { type: Object, default: () => ({}) }, countTag: { type: Object, default: () => ({}) }, position: { type: Boolean, default: false }, tipShow: { type: Boolean, default: false }, dropShow: { type: Boolean, default: false }, content: { type: String, default: "" }, split: { type: Boolean, default: true }, changeTipShow: { type: Function, default: () => { } }, tipHandle: { type: Function, default: () => { } } }, setup(props) { const getScrollWidth = (text) => { const maxWidth = 452; const div = document.createElement("div"); div.innerText = text; div.style.position = "absolute"; div.style.left = "0"; div.style.bottom = "0"; div.style.zIndex = "-100"; div.style.display = "inline-block"; div.style.height = "0"; div.style.opacity = "0"; div.style.overflow = "hidden"; div.style.whiteSpace = "nowrap"; div.style.fontSize = "14px"; document.body.appendChild(div); const { scrollWidth } = div; document.body.removeChild(div); return scrollWidth > maxWidth ? scrollWidth - maxWidth : 0; }; const contentArr = computed(() => { const content = isRef(props.content) ? props.content.value : props.content; if (!content) return []; return content.split("\u3001").map((d, i) => ({ id: `content-${i}`, text: d, scroll: d.length > 32 ? getScrollWidth(d) : 0 })); }); const popoverTipHandle = (str) => { if (!props.split) return; props.tipHandle(str); }; const contentEnter = () => { if (props.split) return; props.changeTipShow(false); }; return () => { const { split, content, tipShow, position } = props; return createVNode(Transition, { "name": position ? "selectDownUpExtend" : "selectDownUpExtendTop" }, { default: () => [withDirectives(createVNode("div", { "class": ["d-popover-tip", split ? "d-popover-tip-split" : "d-popover-tip-words", position ? "d-popover-tip-bottom" : "d-popover-tip-top"], "onWheel": (e) => e.stopPropagation(), "onMouseenter": () => popoverTipHandle("enter"), "onMouseleave": () => popoverTipHandle("leave") }, [createVNode("section", { "class": "d-popover-tip-content", "onMouseenter": contentEnter }, [split ? createVNode(Fragment, null, [contentArr.value.map((item) => createVNode("article", { "class": ["d-popover-tip-content-item", item.scroll && "d-popover-tip-content-item-before"] }, [createVNode("span", { "key": item.id, "class": "d-popover-tip-item-text", "style": { transform: `translateX(${-item.scroll}px)` } }, [item.text])]))]) : createVNode("article", { "class": "d-popover-tip-content-words" }, [isRef(content) ? content.value : content])]), createVNode("section", { "class": "d-popover-tip-triangle" }, null)]), [[vShow, tipShow]])] }); }; } }); const CountWh = (vm) => { const { content, split } = vm.component.props; const contentArr = (isRef(content) ? content.value : content).split("\u3001"); const { body } = document; const element = document.createElement("div"); element.className = "d-popover-tip"; element.style.left = "0"; element.style.bottom = "0"; element.style.opacity = "0"; element.style.zIndex = "-100"; let html = '<section class="d-popover-tip-content">'; if (split) { contentArr.forEach((d) => { html += `<article class="d-popover-tip-content-item"><span class="d-popover-tip-item-text">${d}</span></article>`; }); } else { html += `<article class="d-popover-tip-content-words">${content}</article>`; } html += "</section>"; element.innerHTML = html; body.appendChild(element); const { width, height } = element.getBoundingClientRect(); body.removeChild(element); const scrollWidth = GetScrollbarWidth(); return { width, height, scrollWidth }; }; const createArticle = (str) => { const article = document.createElement("article"); article.className = "d-popover-tip-content-item"; article.style.display = "inline-block"; article.style.height = "0"; article.style.opacity = "0"; article.innerHTML = `<span class="d-popover-tip-item-text">${str}</span>`; document.body.appendChild(article); const w = article.clientWidth + 4; document.body.removeChild(article); return w; }; const countContentWidth = (vm) => { const { component: { props: { content } } } = vm; const contentArr = (isRef(content) ? content.value : content).split("\u3001"); const numArr = []; const len = contentArr.length; let num = 0; for (let i = 0; i < len; i++) { const iw = createArticle(contentArr[i]); num += iw; if (num > 468) { numArr.push(num - iw); if (i === len - 1) numArr.push(num); else num = iw; } else if (num === 468) { return 468; } } return numArr && numArr.length ? Math.max(...numArr) : num; }; const CalcPopoverTipPosition = (triggerDom, targetHeight) => { const { clientHeight } = document.body; const { pageYOffset } = window; const { top, height } = triggerDom.getBoundingClientRect(); let targetOffsetY; let P = true; const triggerPositionTop = top - 8; const triggerPositionBtm = clientHeight - (top + height + 8); if (triggerPositionTop >= targetHeight) { targetOffsetY = triggerPositionTop - targetHeight + pageYOffset; P = false; } else if (triggerPositionBtm >= targetHeight) { targetOffsetY = top + height + 8 + pageYOffset; } else { targetOffsetY = clientHeight - targetHeight + pageYOffset; } return { Y: targetOffsetY, P }; }; const resetPosition = (instance) => { const { vm, tag, countTag } = instance; const isr = isRef(vm.component.props.content); if (!(isr ? vm.component.props.content.value : vm.component.props.content)) { return; } const { innerWidth, pageXOffset } = window; const tagEle = isRef(tag) ? tag.value : tag; const countTagEle = isRef(countTag) ? countTag.value : countTag; const { left: tagLeft, width: tagWidth } = tagEle.getBoundingClientRect(); const { left: cLeft, width: cWidth } = countTagEle.getBoundingClientRect(); if (innerWidth <= cLeft + cWidth / 2 || innerWidth <= cWidth || cLeft < 0) return; const { width, height, scrollWidth } = CountWh(vm); const { Y, P } = CalcPopoverTipPosition(tagEle, height); if (vm.component.props.split) { const maxWidth = countContentWidth(vm) + 13; vm.el.style.maxWidth = `${maxWidth}px`; } vm.component.props.position = P; vm.el.style.top = `${Y}px`; const triangle = vm.el.lastChild; let popoverLeft = 0; let triangleLeft; if (width === innerWidth) { if (pageXOffset > 0) popoverLeft = 0; triangleLeft = cLeft + cWidth / 2 - 6; } else { if (tagLeft === 0) { popoverLeft = 0; } else { const discoverWidth = innerWidth - tagLeft; const centerPlace = cLeft + cWidth / 2; const popoverLeftWidth = width / 2; if (centerPlace < popoverLeftWidth) { popoverLeft = 0; } else if (width <= tagWidth) { if (width <= discoverWidth) popoverLeft = centerPlace - popoverLeftWidth; else popoverLeft = innerWidth - width; } else { if (centerPlace >= popoverLeftWidth) { if (innerWidth - centerPlace <= popoverLeftWidth) { popoverLeft = innerWidth - width - scrollWidth; } else popoverLeft = centerPlace - popoverLeftWidth; } else { popoverLeft = 0; } } } triangleLeft = cLeft - popoverLeft + cWidth / 2 - 6; } vm.el.style.left = `${popoverLeft + pageXOffset}px`; triangle.style.left = `${triangleLeft}px`; instance.setShow(true); }; let dom; const TipModalHandle = (options) => { const { tipShow, props, changeTipShow, tipHandle } = options; const { tag, countTag } = props; if (!dom) { dom = document.createElement("div"); document.body.appendChild(dom); } const vm = createVNode(TipModal, { tipShow, ...props, changeTipShow, tipHandle }); const instance = { vm, tag, countTag, setContent(content) { vm.component.props.content = content; }, setShow: changeTipShow, resetPosition() { resetPosition(instance); }, remove() { if (vm.component.isUnmounted) return; render$3(null, dom); } }; render$3(vm, dom); return instance; }; const PopoverTip = defineComponent({ name: "PopoverTip", props: { tag: { type: Object, default: () => ({}) }, countTag: { type: Object, default: () => ({}) }, content: { type: String, default: "" }, split: { type: Boolean, default: true }, dropShow: { type: Boolean, default: false } }, setup(props, { slots }) { let tipModal; let enterTimer; let leaveTimer; const state = reactive({ tipShow: false }); const changeTipShow = (status) => { state.tipShow = status; if (tipModal) tipModal.vm.component.props.tipShow = status; }; PopoverTip.changeTipShow = changeTipShow; const tipHandle = (str) => { if (str === "enter") { clearTimeout(leaveTimer); leaveTimer = null; } else { leaveTimer = window.setTimeout(() => { changeTipShow(false); }, 500); } }; const mouseEnter = () => { if (leaveTimer) { clearTimeout(leaveTimer); leaveTimer = null; } if (!props.content || props.dropShow || state.tipShow) return; enterTimer = window.setTimeout(() => { if (tipModal) { tipModal.resetPosition(); } else { tipModal = TipModalHandle({ tipShow: state.tipShow, props, changeTipShow, tipHandle }); if (tipModal) tipModal.resetPosition(); PopoverTip.tipModal = tipModal; } }, 360); }; const mouseLeave = () => { if (!props.content) return; if (enterTimer) { clearTimeout(enterTimer); enterTimer = null; } leaveTimer = window.setTimeout(() => { if (tipModal) tipModal.setShow(false); }, 500); }; watch(() => props.content, (n, o) => { if (n === o || !tipModal) return; tipModal.vm.component.props.content = n; }); onBeforeUnmount(() => { if (enterTimer) clearTimeout(enterTimer); if (leaveTimer) clearTimeout(leaveTimer); if (tipModal) tipModal.remove(); }); return () => createVNode("span", { "onMouseenter": mouseEnter, "onMouseleave": mouseLeave }, [slots.default()]); } }); const GetCaptionWidth = (str) => { const { body } = document; const div = document.createElement("div"); div.className = "d-drop-trigger-caption"; div.innerText = str; div.style.position = "absolute"; div.style.zIndex = "-1"; div.style.left = "0"; div.style.bottom = "0"; div.style.height = "0px"; body.appendChild(div); const { width } = div.getBoundingClientRect(); const w = Math.ceil(width); body.removeChild(div); if (w > 98) return 98; return w; }; const GetPopoverContent = (data) => { if (data instanceof Array && JSON.stringify(data).length > 4) { const names = []; data.forEach((d) => { names.push(d.name); }); return names.toString().replace(/,/g, "\u3001"); } return ""; }; const DropTrigger = defineComponent({ name: "DropTrigger", props: { width: { type: [String, Number], default: "" }, type: { type: String, default: "normal" }, placeholder: { type: String, default: "\u8BF7\u9009\u62E9" }, caption: { type: String, default: "" }, disabled: { type: Boolean, default: false }, clearHide: { type: Boolean, default: false }, openSearch: { type: Boolean, default: true }, dropSearch: { type: Boolean, default: false }, multiple: { type: Boolean, default: false }, selectedData: { type: Object || Array, default: [] }, dropShow: { type: Boolean, default: false }, errorText: { type: String, default: "" }, errorShow: { type: Boolean, default: false }, onClick: { type: Function, default: () => { } }, onGetInputText: { type: Function, default: () => { } }, delHandle: { type: Function, default: () => { } } }, emits: ["getInputText", "click", "clearItem"], setup(props, { emit }) { const state = reactive({ inputText: "", readonlyActive: true, inputShow: false, inputStatus: null, captionWidth: 0, scrollbarWidth: 6, errorTop: 0, popoverTipContent: "" }); state.popoverTipContent = GetPopoverContent(props.selectedData); const tag = ref(null); const countTag = ref(null); const popoverTip = ref(null); const { proxy } = getCurrentInstance(); const hasColon = computed(() => { const { caption } = props; return caption.includes(":") || caption.includes("\uFF1A"); }); const hasSelected = computed(() => { const { multiple, selectedData = {} } = props; const len = JSON.stringify(selectedData).length; if (multiple) return len > 4; return len > 2; }); const tabMaxWidth = computed(() => { const { width = 120 } = props; const { scrollbarWidth = 6 } = state; const w = Number(width); return w - scrollbarWidth - 64; }); let timerInputText = null; watch(() => state.inputText, (n, o) => { if (n === o) return; if (timerInputText) clearTimeout(timerInputText); timerInputText = window.setTimeout(() => { emit("getInputText", n); }, 500); }); watch(() => props.caption, (n, o) => { if (n === o) return; if (props.type === "tag") return; if (n) state.captionWidth = GetCaptionWidth(n); }); watch(() => props.dropShow, (n, o) => { if (n === o) return; if (props.type === "tag") return; setTimeout(() => { state.inputShow = n; if (n) { if (!props.multiple || !popoverTip.value) return; popoverTip.value.$options.changeTipShow(false); } else { state.inputStatus = null; state.inputText = ""; } }, 300); }); watch(() => props.selectedData, (n, o) => { const nd = JSON.stringify(n); const od = JSON.stringify(o); if (nd === od) return; state.popoverTipContent = GetPopoverContent(n); const { type } = props; nextTick(() => { if (type === "tag") state.errorTop = proxy.$el.clientHeight + 6; }); }, { deep: true }); onMounted(() => { const { caption, type } = props; if (caption) state.captionWidth = GetCaptionWidth(caption); if (type === "tag") state.scrollbarWidth = GetScrollbarWidth(); }); const inputHandle = (e) => { const { data } = e; const { value } = e.target; state.inputStatus = data || value; state.inputText = value; }; const dropOpenClick = (flag) => { emit("click", flag); }; const triangleHandle = () => { dropOpenClick("triangle"); }; const delHandle = () => { state.inputStatus = null; props.delHandle(); }; const focusHandle = () => { state.readonlyActive = false; }; const blurHandle = () => { state.readonlyActive = true; }; const tagCloseHandle = (item) => { if (item.disabled) return; emit("clearItem", item); }; return () => { const { disabled, errorShow, type, width, caption, openSearch, dropSearch, placeholder, multiple, selectedData, dropShow, clearHide, errorText } = props; const { captionWidth, inputStatus, inputShow, readonlyActive, inputText, errorTop, popoverTipContent } = state; return createVNode("div", { "class": ["d-drop-trigger", `d-drop-trigger-${type}`, disabled ? "d-drop-trigger-disabled" : "d-drop-trigger-active", errorShow && "p-trigger-error"], "style": { width: `${width}px` } }, [createVNode("div", { "class": ["d-drop-trigger-main", `d-drop-trigger-main-${type}`], "onClick": () => { dropOpenClick(); } }, [caption && createVNode("div", { "class": "d-drop-trigger-caption d-drop-trigger-text-overflow", "style": { width: `${captionWidth}px` } }, [caption]), type === "normal" ? createVNode("section", { "class": { "d-drop-trigger-label": true, "d-drop-trigger-label-pl": caption && !hasColon.value }, "style": { width: `calc(100% - ${captionWidth}px)` } }, [!inputStatus && createVNode(Fragment, null, [hasSelected.value ? createVNode("span", { "class": { "d-drop-trigger-selected": true, "d-drop-trigger-selected-focus": !readonlyActive } }, [multiple ? createVNode(PopoverTip, { "ref": popoverTip, "tag": tag, "countTag": countTag, "content": popoverTipContent, "dropShow": dropShow }, { default: () => [createVNode("span", { "class": "d-drop-trigger-selected-m", "ref": tag }, [createTextVNode("\u5DF2\u9009\u62E9"), createVNode("span", { "class": "d-drop-trigger-selected-m-c", "ref": countTag }, [selectedData.length]), createTextVNode("\u9879")])] }) : createVNode("span", { "class": "d-drop-trigger-selected-s", "onMouseenter": Kt }, [selectedData.name])]) : createVNode("span", { "class": "d-drop-trigger-placeholder d-drop-trigger-text-overflow" }, [placeholder])]), openSearch && !disabled && !dropSearch && inputShow && createVNode("input", { "type": "text", "class": { "d-drop-trigger-input": true, "d-drop-trigger-text-overflow": true, "d-drop-trigger-input-readonly": readonlyActive && !dropShow, "d-drop-trigger-label-pl": caption && !hasColon.value }, "value": inputText, "onInput": inputHandle, "onFocus": focusHandle, "onBlur": blurHandle }, null)]) : createVNode(Fragment, null, [selectedData && JSON.stringify(selectedData).length > 4 ? createVNode("div", { "class": "d-drop-trigger-main-tag-box", "style": { width: `calc(100% - ${captionWidth}px)` } }, [createVNode("section", { "class": "d-drop-trigger-tag-list" }, [selectedData.map((sd) => createVNode("article", { "class": "d-drop-trigger-tag-list-item", "key": sd.id }, [createVNode("span", { "class": "d-drop-trigger-tag-list-text d-drop-trigger-text-overflow", "style": { maxWidth: `${tabMaxWidth.value}px` }, "onMouseenter": Kt }, [sd.name]), createVNode("i", { "class": ["d-drop-trigger-tag-list-svg", sd.disabled ? "d-drop-trigger-tag-list-svg-disabled" : "d-drop-trigger-tag-list-svg-normal"], "onClick": (e) => { e.stopPropagation(); tagCloseHandle(sd); } }, [createVNode(CloseIcon, null, null)])]))])]) : createVNode("section", { "class": "d-drop-trigger-label", "style": { width: `calc(100% - ${captionWidth}px)` } }, [createVNode("span", { "class": "d-drop-trigger-placeholder d-drop-trigger-text-overflow" }, [placeholder])])])]), createVNode("div", { "class": { "d-drop-trigger-icon": true, "d-drop-trigger-icon-clear": !clearHide && hasSelected.value && !disabled } }, [createVNode("i", { "class": { "d-drop-trigger-svg": true, "d-drop-trigger-tgl": true, "d-drop-trigger-tgl-open": !dropShow }, "onClick": (e) => { e.stopPropagation(); triangleHandle(); } }, [createVNode(TriangleIcon, null, null)]), createVNode("i", { "class": "d-drop-trigger-svg d-drop-trigger-del", "onClick": (e) => { e.stopPropagation(); delHandle(); } }, [createVNode(DeleteIcon, null, null)])]), errorShow && createVNode("span", { "class": "p-trigger-error-text", "style": { top: `${errorTop}px` } }, [errorText])]); }; } }); export { DropTrigger as default };