UNPKG

yuang-framework-ui-pc

Version:

yuang-framework-ui-pc Library

481 lines (480 loc) 15.6 kB
import { defineComponent, inject, ref, computed, shallowRef, onMounted, onBeforeUnmount, watch, nextTick, resolveComponent, openBlock, createBlock, mergeProps, createSlots, withCtx, createElementBlock, Fragment, renderList, createElementVNode, renderSlot, createTextVNode, toDisplayString, createVNode, createCommentVNode } from "vue"; import SortableJs from "sortablejs"; import { ElTabs, ElTabPane, ElIcon } from "element-plus"; import { CornerLeftFilled, CornerRightFilled } from "../icons"; import { pick, omit } from "../utils/core"; import { useTimer, useMousewheel, useTouchEvent } from "../utils/hook"; import EleDropdown from "../ele-dropdown/index"; import { tabsProps, tabsEmits, TAB_WRAP_KEY, tabPropKeys } from "./props"; const _sfc_main = defineComponent({ name: "EleTabs", components: { ElTabs, ElTabPane, ElIcon, EleDropdown, CornerLeftFilled, CornerRightFilled }, props: tabsProps, emits: tabsEmits, setup(props, { emit }) { let sortableIns = null; let currentSortItemId = null; let contextMenuTabItem = null; let contextMenuTabName = null; const wrapProps = inject(TAB_WRAP_KEY, null); const [startScrollTimer, _stopScrollTimer, scrollWaiting] = useTimer(320); const { bindMousewheel, unbindMousewheel } = useMousewheel((param) => { const { e, direction } = param; scrollTabs(direction === "up" ? "prev" : "next", () => { e.preventDefault(); e.stopPropagation(); }); }); const { bindTouchEvent, unbindTouchEvent } = useTouchEvent({ end: (param) => { if (param.distanceX && param.distanceX > 80) { scrollTabs("prev"); } else if (param.distanceX && param.distanceX < 80) { scrollTabs("next"); } } }); const [startGhostTimer] = useTimer(100); const tabRef = ref(null); const isOnlyTab = computed(() => wrapProps == null); const tabSize = computed( () => wrapProps == null ? props.size : wrapProps.size ); const tabType = computed( () => wrapProps == null ? props.type : wrapProps.type ); const tabProps = computed(() => { return pick(props, tabPropKeys); }); const ctxMenuDropdownRef = ref(null); const ctxMenuDropdownItems = shallowRef([]); const ctxMenuDropdownVirtualRef = ref(); const updateModelValue = (name) => { emit("update:modelValue", name); }; const handleContextmenu = (e) => { if (!props.contextMenu) { return; } const el = e.target; if (el && (el.classList.contains("is-icon-close") || el.classList.contains("el-tabs__nav") || el.classList.contains("el-tabs__item"))) { e.preventDefault(); } }; const handleTabClick = (pane, e) => { emit("tabClick", pane, e); }; const handleTabChange = (name) => { emit("tabChange", name); }; const handleTabRemove = (name) => { emit("tabRemove", name); }; const handleTabAdd = () => { emit("tabAdd"); }; const handleEdit = (name, action) => { emit("edit", name, action); }; const handleItemClick = (item, tabName, e) => { if (props.handleClick) { e.stopPropagation(); } emit("tabItemClick", { item, name: item ? item.name : tabName, active: props.modelValue }); }; const handleItemCtxMenuVisible = (visible) => { if (visible) { emit( "tabContextOpen", ctxMenuDropdownRef.value, contextMenuTabItem, contextMenuTabName ); } }; const handleItemCtxMenuClick = (command) => { if (contextMenuTabItem != null || contextMenuTabName != null) { emit("tabContextMenu", { command, item: contextMenuTabItem, name: contextMenuTabItem ? contextMenuTabItem.name : contextMenuTabName, active: props.modelValue }); } }; const getContextMenus = (item, tabName) => { if (typeof props.contextMenus === "function") { return props.contextMenus(item, tabName); } return props.contextMenus; }; const hideAllDropdown = () => { if (ctxMenuDropdownRef.value) { ctxMenuDropdownRef.value.handleClose(); } }; const showItemContextMenu = (item, tabName, itemEl) => { if (contextMenuTabItem != null && contextMenuTabItem === item || contextMenuTabName != null && contextMenuTabName === tabName) { return; } hideAllDropdown(); nextTick(() => { contextMenuTabItem = item; contextMenuTabName = tabName; ctxMenuDropdownItems.value = getContextMenus(item, tabName) || []; ctxMenuDropdownVirtualRef.value = itemEl; if (props.contextMenu && ctxMenuDropdownItems.value.length) { nextTick(() => { ctxMenuDropdownRef.value && ctxMenuDropdownRef.value.handleOpen(); }); } }); }; const handleItemContextmenu = (item, tabName, e) => { const itemEl = e.currentTarget; if (!props.contextMenu || ctxMenuDropdownVirtualRef.value === itemEl) { return; } e.preventDefault(); showItemContextMenu(item, tabName, itemEl); }; const getHeaderEl = () => { const tabEl = tabRef.value ? tabRef.value.$el : void 0; return tabEl ? tabEl.querySelector(".el-tabs__header") : void 0; }; const getNavEl = () => { const headerEl = getHeaderEl(); return headerEl ? headerEl.querySelector(".el-tabs__nav") : void 0; }; const updateActiveBar = () => { const el = getNavEl(); if (el) { const bar = el.querySelector(".el-tabs__active-bar"); if (bar) { bar.style.width = "0px"; } } }; const scrollTabs = (direction, done) => { const tabEl = getHeaderEl(); if (tabEl && !scrollWaiting.value) { const el = tabEl.querySelector(`.el-tabs__nav-${direction}`); if (el && !el.classList.contains("is-disabled")) { startScrollTimer(); done && done(); el.click(); } } }; const checkSortGhostTab = () => { const navEl = getNavEl(); if (navEl == null) { return; } if (currentSortItemId == null) { const el2 = navEl.querySelector(".el-tabs__item.sortable-ghost"); if (el2 != null) { el2.classList.remove("sortable-ghost"); } return; } const el = navEl.querySelector( `.el-tabs__item[id="${currentSortItemId}"]` ); if (el != null) { el.classList.add("sortable-ghost"); } }; const bindDragSort = () => { unbindDragSort(); const navEl = getNavEl(); if (!props.sortable || !navEl) { return; } sortableIns = new SortableJs(navEl, { draggable: ".el-tabs__item", delay: 20, onUpdate: ({ oldDraggableIndex, newDraggableIndex }) => { if (typeof oldDraggableIndex === "number" && typeof newDraggableIndex === "number") { const data = [...props.items]; data.splice( newDraggableIndex, 0, data.splice(oldDraggableIndex, 1)[0] ); emit("tabSortChange", data); } }, onStart: (e) => { currentSortItemId = e.item.getAttribute("id"); checkSortGhostTab(); startGhostTimer(() => { checkSortGhostTab(); }); }, onEnd: () => { currentSortItemId = null; checkSortGhostTab(); }, onChange: () => { checkSortGhostTab(); startGhostTimer(() => { checkSortGhostTab(); }); }, onMove: () => { checkSortGhostTab(); startGhostTimer(() => { checkSortGhostTab(); }); }, setData: () => { } }); }; const unbindDragSort = () => { sortableIns && sortableIns.destroy(); sortableIns = null; currentSortItemId = null; }; const initMousewheelEvent = () => { const el = getHeaderEl(); if (el != null) { unbindMousewheel(el); if (props.mousewheel) { bindMousewheel(el); } } }; const initTouchEvent = () => { const el = getHeaderEl(); if (el != null) { unbindTouchEvent(el); if (!props.sortable) { bindTouchEvent(el); } } }; if (wrapProps && wrapProps.setTabMethods) { wrapProps.setTabMethods({ triggerTabItemClick: handleItemClick, triggerItemContextMenu: handleItemContextmenu }); } onMounted(() => { initMousewheelEvent(); initTouchEvent(); bindDragSort(); }); onBeforeUnmount(() => { if (wrapProps && wrapProps.setTabMethods) { wrapProps.setTabMethods({ triggerTabItemClick: void 0, triggerItemContextMenu: void 0 }); } contextMenuTabItem = null; contextMenuTabName = null; const el = getHeaderEl(); if (el != null) { unbindMousewheel(el); unbindTouchEvent(el); } unbindDragSort(); }); watch( () => props.sortable, () => { bindDragSort(); initTouchEvent(); } ); watch( () => props.mousewheel, () => { initMousewheelEvent(); } ); return { omit, tabRef, isOnlyTab, tabSize, tabType, tabProps, ctxMenuDropdownRef, ctxMenuDropdownItems, ctxMenuDropdownVirtualRef, updateModelValue, handleContextmenu, handleTabClick, handleTabChange, handleTabRemove, handleTabAdd, handleEdit, handleItemClick, handleItemCtxMenuVisible, handleItemCtxMenuClick, handleItemContextmenu, hideAllDropdown, updateActiveBar, scrollTabs }; } }); const _export_sfc = (sfc, props) => { const target = sfc.__vccOpts || sfc; for (const [key, val] of props) { target[key] = val; } return target; }; const _hoisted_1 = ["onClick", "onContextmenu"]; function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { const _component_CornerLeftFilled = resolveComponent("CornerLeftFilled"); const _component_ElIcon = resolveComponent("ElIcon"); const _component_CornerRightFilled = resolveComponent("CornerRightFilled"); const _component_ElTabPane = resolveComponent("ElTabPane"); const _component_EleDropdown = resolveComponent("EleDropdown"); const _component_ElTabs = resolveComponent("ElTabs"); return openBlock(), createBlock(_component_ElTabs, mergeProps(_ctx.tabProps, { ref: "tabRef", type: _ctx.tabType === "card" || _ctx.tabType === "border-card" ? _ctx.tabType : void 0, class: [ "ele-tabs", { "ele-tabs-wrap": _ctx.isOnlyTab }, { "is-small": _ctx.tabSize === "small" }, { "is-large": _ctx.tabSize === "large" }, { "is-default": !_ctx.tabType || _ctx.tabType === "default" }, { "is-plain": _ctx.tabType === "plain" }, { "is-simple": _ctx.tabType === "simple" }, { "is-indicator": _ctx.tabType === "indicator" }, { "is-button": _ctx.tabType === "button" }, { "is-tag": _ctx.tabType === "tag" }, { "is-center": _ctx.center }, { "is-sortable": _ctx.sortable }, { "is-flex-table": _ctx.flexTable } ], "onUpdate:modelValue": _ctx.updateModelValue, onTabClick: _ctx.handleTabClick, onTabChange: _ctx.handleTabChange, onTabRemove: _ctx.handleTabRemove, onTabAdd: _ctx.handleTabAdd, onEdit: _ctx.handleEdit, onContextmenu: _ctx.handleContextmenu }), createSlots({ default: withCtx(() => [ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.items, (item, index2) => { return openBlock(), createBlock(_component_ElTabPane, mergeProps({ key: [ index2, item.name, item.label, !!item.closable, !!item.disabled, !!item.lazy ].join("-"), ref_for: true }, _ctx.omit(item, ["slot", "meta"])), createSlots({ label: withCtx(() => [ createElementVNode("div", { class: "ele-tab-title", onClick: (e) => _ctx.handleItemClick(item, void 0, e), onContextmenu: (e) => _ctx.handleItemContextmenu(item, void 0, e) }, [ renderSlot(_ctx.$slots, "label", { item, label: item.label, active: _ctx.modelValue }, () => [ createTextVNode(toDisplayString(item.label), 1) ]) ], 40, _hoisted_1), _ctx.tabType === "simple" || _ctx.tabType === "indicator" ? (openBlock(), createBlock(_component_ElIcon, { key: 0, class: "ele-tab-corner-left" }, { default: withCtx(() => [ createVNode(_component_CornerLeftFilled) ]), _: 1 })) : createCommentVNode("", true), _ctx.tabType === "simple" || _ctx.tabType === "indicator" ? (openBlock(), createBlock(_component_ElIcon, { key: 1, class: "ele-tab-corner-right" }, { default: withCtx(() => [ createVNode(_component_CornerRightFilled) ]), _: 1 })) : createCommentVNode("", true) ]), _: 2 }, [ item.name && _ctx.$slots[item.slot || item.name] ? { name: "default", fn: withCtx(() => [ renderSlot(_ctx.$slots, item.slot || item.name, { item }) ]), key: "0" } : void 0 ]), 1040); }), 128)), _ctx.contextMenu ? (openBlock(), createBlock(_component_EleDropdown, mergeProps( { key: 0, triggerKeys: [], persistent: false, placement: "bottom-start", popperClass: "ele-tab-popup", popperOptions: { modifiers: [{ name: "offset", options: { offset: [0, 8] } }] } }, !_ctx.contextMenu || typeof _ctx.contextMenu == "boolean" ? {} : _ctx.contextMenu, { ref: "ctxMenuDropdownRef", componentType: "pro", preventContextmenu: true, trigger: "contextmenu", virtualTriggering: true, virtualRef: _ctx.ctxMenuDropdownVirtualRef, disabled: !_ctx.ctxMenuDropdownItems.length, items: _ctx.ctxMenuDropdownItems, onCommand: _ctx.handleItemCtxMenuClick, onVisibleChange: _ctx.handleItemCtxMenuVisible } ), null, 16, ["virtualRef", "disabled", "items", "onCommand", "onVisibleChange"])) : createCommentVNode("", true) ]), _: 2 }, [ _ctx.$slots["add-icon"] ? { name: "add-icon", fn: withCtx(() => [ renderSlot(_ctx.$slots, "add-icon") ]), key: "0" } : _ctx.$slots.addIcon ? { name: "addIcon", fn: withCtx(() => [ renderSlot(_ctx.$slots, "addIcon") ]), key: "1" } : void 0 ]), 1040, ["type", "class", "onUpdate:modelValue", "onTabClick", "onTabChange", "onTabRemove", "onTabAdd", "onEdit", "onContextmenu"]); } const index = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]); export { index as default };