UNPKG

winbox-ui-next

Version:

We Design Vue 2.0: A Vue.js 3 UI Library

257 lines (256 loc) 8.31 kB
import { defineComponent, toRefs, ref, computed, onMounted, watch, nextTick, createVNode } from "vue"; import { getTabListStyle } from "./utils.js"; import { getPrefixCls } from "../_utils/global-config.js"; import Tab from "./tabs-tab.js"; import TabsButton from "./tabs-button.js"; import TabsNavInk from "./tabs-nav-ink.js"; import IconHover from "../_components/icon-hover.js"; import IconPlus from "../icon/icon-plus/index.js"; import ResizeObserver from "../_components/resize-observer.js"; var TabsNav = defineComponent({ name: "TabsNav", props: { direction: { type: String, required: true }, type: { type: String, required: true }, activeTab: { type: String, required: true }, activeIndex: { type: Number, required: true }, tabs: { type: Array, required: true }, tabKeys: { type: Array, required: true }, tabPosition: { type: String, required: true }, size: { type: String, required: true }, showAddButton: { type: Boolean, default: false }, editable: { type: Boolean, default: false }, animation: { type: Boolean, required: true }, headerPadding: { type: Boolean, default: true } }, emits: ["click", "add", "delete"], setup(props, { emit, slots }) { const prefixCls = getPrefixCls("tabs-nav"); const { tabs, tabKeys, activeIndex, direction } = toRefs(props); const wrapperRef = ref(); const listRef = ref(); const tabsRef = ref({}); const wrapperLength = ref(0); const maxOffset = ref(0); const getWrapperLength = () => { var _a, _b, _c; return (_c = direction.value === "vertical" ? (_a = wrapperRef.value) == null ? void 0 : _a.offsetHeight : (_b = wrapperRef.value) == null ? void 0 : _b.offsetWidth) != null ? _c : 0; }; const getMaxOffset = () => { if (!listRef.value || !wrapperRef.value) { return 0; } if (direction.value === "vertical") { return listRef.value.offsetHeight - wrapperRef.value.offsetHeight; } return listRef.value.offsetWidth - wrapperRef.value.offsetWidth; }; const getTabEndOffsets = () => { return tabs.value.map((item) => { const ele = tabsRef.value[item.key]; if (direction.value === "vertical") { return ele.offsetTop + ele.offsetHeight; } return ele.offsetLeft + ele.offsetWidth; }); }; const getSize = () => { isScroll.value = isOverflow(); if (isScroll.value) { wrapperLength.value = getWrapperLength(); maxOffset.value = getMaxOffset(); tabEndOffsets.value = getTabEndOffsets(); if (offset.value > maxOffset.value) { offset.value = maxOffset.value; } } else { offset.value = 0; } }; const activeTabRef = computed(() => tabsRef.value[props.activeTab]); const isOverflow = () => { if (wrapperRef.value && listRef.value) { return props.direction === "vertical" ? listRef.value.offsetHeight > wrapperRef.value.offsetHeight : listRef.value.offsetWidth > wrapperRef.value.offsetWidth; } return false; }; const isScroll = ref(false); onMounted(() => { getSize(); }); const tabEndOffsets = ref([]); const offset = ref(0); const isInView = (index) => { var _a; return ((_a = tabEndOffsets.value[index - 1]) != null ? _a : 0) >= offset.value && tabEndOffsets.value[index] <= offset.value + wrapperLength.value; }; watch(activeIndex, (current, pre) => { nextTick(() => { var _a; if (isScroll.value) { if (current >= pre) { const offsetIndex = current < tabEndOffsets.value.length - 1 ? current + 1 : current; if (!isInView(offsetIndex)) { offset.value = tabEndOffsets.value[offsetIndex] - wrapperLength.value; } } else { const offsetIndex = current > 0 ? current - 1 : current; if (!isInView(offsetIndex)) { offset.value = (_a = tabEndOffsets.value[offsetIndex - 1]) != null ? _a : 0; } } } }); }); const mergedEditable = computed(() => props.editable && ["line", "card", "card-gutter"].includes(props.type)); const getNextOffset = (type) => { if (!wrapperRef.value) { return 0; } if (props.type === "capsule") { return type === "previous" ? offset.value + wrapperLength.value : offset.value - wrapperLength.value; } return type === "previous" ? offset.value - wrapperLength.value : offset.value + wrapperLength.value; }; const handleButtonClick = (type) => { offset.value = getValidOffset(getNextOffset(type)); }; const getValidOffset = (offset2) => { if (!wrapperRef.value || !listRef.value || offset2 < 0) { return 0; } if (offset2 > maxOffset.value) { return maxOffset.value; } return offset2; }; watch(tabs, () => { nextTick(() => { getSize(); }); }); const handleResize = () => { getSize(); if (inkRef.value) { inkRef.value.$forceUpdate(); } }; const renderAddBtn = () => { if (!mergedEditable.value || !props.showAddButton) { return null; } return createVNode("div", { "class": `${prefixCls}-add-btn`, "onClick": () => emit("add") }, [createVNode(IconHover, null, { default: () => [createVNode(IconPlus, null, null)] })]); }; const cls = computed(() => [prefixCls, `${prefixCls}-${props.direction}`, `${prefixCls}-${props.tabPosition}`, `${prefixCls}-size-${props.size}`, `${prefixCls}-type-${props.type}`]); const inkRef = ref(); return () => { var _a; return createVNode("div", { "class": cls.value }, [isScroll.value && createVNode(TabsButton, { "type": "previous", "direction": props.direction, "disabled": offset.value <= 0, "onClick": handleButtonClick }, null), createVNode(ResizeObserver, { "onResize": () => getSize() }, { default: () => [createVNode("div", { "class": `${prefixCls}-tab`, "ref": wrapperRef }, [createVNode(ResizeObserver, { "onResize": handleResize }, { default: () => [createVNode("div", { "class": [`${prefixCls}-tab-list`, { [`${prefixCls}-tab-list-no-padding`]: !props.headerPadding && props.direction === "horizontal" && ["line", "text"].includes(props.type) }], "style": getTabListStyle({ direction: props.direction, type: props.type, offset: offset.value }), "ref": listRef }, [props.tabs.map((tab, index) => createVNode(Tab, { "ref": (component) => { if (component == null ? void 0 : component.$el) { tabsRef.value[tab.key] = component.$el; } }, "isActive": props.activeIndex === index, "key": tab.key, "tab": tab, "editable": props.editable, "onClick": (key, e) => emit("click", key, e), "onDelete": (key) => emit("delete", key) }, { title: () => tab.title() })), props.type === "line" && activeTabRef.value && createVNode(TabsNavInk, { "ref": inkRef, "activeTabRef": activeTabRef.value, "direction": props.direction, "disabled": false, "animation": props.animation }, null)])] }), !isScroll.value && renderAddBtn()])] }), isScroll.value && createVNode(TabsButton, { "type": "next", "direction": props.direction, "disabled": offset.value >= maxOffset.value, "onClick": handleButtonClick }, null), createVNode("div", { "class": `${prefixCls}-extra` }, [isScroll.value && renderAddBtn(), (_a = slots.extra) == null ? void 0 : _a.call(slots)])]); }; } }); export { TabsNav as default };