UNPKG

@arco-design/web-vue

Version:

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

296 lines (295 loc) 9.88 kB
"use strict"; var vue = require("vue"); var utils = require("./utils.js"); var globalConfig = require("../_utils/global-config.js"); var tabsTab = require("./tabs-tab.js"); var tabsButton = require("./tabs-button.js"); var tabsNavInk = require("./tabs-nav-ink.js"); var iconHover = require("../_components/icon-hover.js"); var index = require("../icon/icon-plus/index.js"); var resizeObserver = require("../_components/resize-observer.js"); var is = require("../_utils/is.js"); var dom = require("../_utils/dom.js"); var TabsNav = vue.defineComponent({ name: "TabsNav", props: { tabs: { type: Array, required: true }, direction: { type: String, required: true }, type: { type: String, required: true }, activeKey: { type: [String, Number] }, activeIndex: { type: Number, required: true }, position: { 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 }, scrollPosition: { type: String, default: "auto" } }, emits: ["click", "add", "delete"], setup(props, { emit, slots }) { const { tabs, activeKey, activeIndex, direction, scrollPosition } = vue.toRefs(props); const prefixCls = globalConfig.getPrefixCls("tabs-nav"); const wrapperRef = vue.ref(); const listRef = vue.ref(); const tabsRef = vue.ref({}); const activeTabRef = vue.computed(() => { if (!is.isUndefined(activeKey.value)) { return tabsRef.value[activeKey.value]; } return void 0; }); const inkRef = vue.ref(); const mergedEditable = vue.computed(() => props.editable && ["line", "card", "card-gutter"].includes(props.type)); const isScroll = vue.ref(false); const wrapperLength = vue.ref(0); const maxOffset = vue.ref(0); const offset = vue.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 getSize = () => { isScroll.value = isOverflow(); if (isScroll.value) { wrapperLength.value = getWrapperLength(); maxOffset.value = getMaxOffset(); if (offset.value > maxOffset.value) { offset.value = maxOffset.value; } } else { offset.value = 0; } }; 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 setOffset = (newOffset) => { if (!wrapperRef.value || !listRef.value || newOffset < 0) { newOffset = 0; } offset.value = Math.min(newOffset, maxOffset.value); }; const setActiveTabOffset = () => { if (!activeTabRef.value || !wrapperRef.value || !isScroll.value) return; utils.updateScrollOffset(wrapperRef.value, direction.value); const isHorizontal = direction.value === "horizontal"; const offsetProperty = isHorizontal ? "offsetLeft" : "offsetTop"; const sizeProperty = isHorizontal ? "offsetWidth" : "offsetHeight"; const tabOffset = activeTabRef.value[offsetProperty]; const tabSize = activeTabRef.value[sizeProperty]; const wrapperSize = wrapperRef.value[sizeProperty]; const tabStyle = window.getComputedStyle(activeTabRef.value); const marginProperty = isHorizontal ? scrollPosition.value === "end" ? "marginRight" : "marginLeft" : scrollPosition.value === "end" ? "marginBottom" : "marginTop"; const tabMargin = parseFloat(tabStyle[marginProperty]) || 0; if (scrollPosition.value === "auto") { if (tabOffset < offset.value) { setOffset(tabOffset - tabMargin); } else if (tabOffset + tabSize > offset.value + wrapperSize) { setOffset(tabOffset + tabSize - wrapperSize + tabMargin); } } else if (scrollPosition.value === "center") { setOffset(tabOffset + (tabSize - wrapperSize + tabMargin) / 2); } else if (scrollPosition.value === "start") { setOffset(tabOffset - tabMargin); } else if (scrollPosition.value === "end") { setOffset(tabOffset + tabSize - wrapperSize + tabMargin); } else if (is.isNumber(scrollPosition.value)) { setOffset(tabOffset - scrollPosition.value); } }; const handleWheel = (ev) => { if (!isScroll.value) return; ev.preventDefault(); const { deltaX, deltaY } = ev; if (Math.abs(deltaX) > Math.abs(deltaY)) { setOffset(offset.value + deltaX); } else { setOffset(offset.value + deltaY); } }; const handleClick = (key, ev) => { emit("click", key, ev); }; const handleDelete = (key, ev) => { emit("delete", key, ev); vue.nextTick(() => { delete tabsRef.value[key]; }); }; const handleButtonClick = (type) => { const nextOffset = type === "previous" ? offset.value - wrapperLength.value : offset.value + wrapperLength.value; setOffset(nextOffset); }; const handleResize = () => { getSize(); if (inkRef.value) { inkRef.value.$forceUpdate(); } }; vue.watch(tabs, () => { vue.nextTick(() => { getSize(); }); }); vue.watch([activeIndex, scrollPosition], () => { setTimeout(() => { setActiveTabOffset(); }, 0); }); vue.onMounted(() => { getSize(); if (wrapperRef.value) { dom.on(wrapperRef.value, "wheel", handleWheel, { passive: false }); } }); vue.onUnmounted(() => { if (wrapperRef.value) { dom.off(wrapperRef.value, "wheel", handleWheel); } }); const renderAddBtn = () => { if (!mergedEditable.value || !props.showAddButton) { return null; } return vue.createVNode("div", { "class": `${prefixCls}-add-btn`, "onClick": (ev) => emit("add", ev) }, [vue.createVNode(iconHover, null, { default: () => [vue.createVNode(index, null, null)] })]); }; const cls = vue.computed(() => [prefixCls, `${prefixCls}-${props.direction}`, `${prefixCls}-${props.position}`, `${prefixCls}-size-${props.size}`, `${prefixCls}-type-${props.type}`]); const listCls = vue.computed(() => [`${prefixCls}-tab-list`, { [`${prefixCls}-tab-list-no-padding`]: !props.headerPadding && ["line", "text"].includes(props.type) && props.direction === "horizontal" }]); const listStyle = vue.computed(() => utils.getTabListStyle({ direction: props.direction, type: props.type, offset: offset.value })); const tabCls = vue.computed(() => [`${prefixCls}-tab`, { [`${prefixCls}-tab-scroll`]: isScroll.value }]); return () => { var _a; return vue.createVNode("div", { "class": cls.value }, [isScroll.value && vue.createVNode(tabsButton, { "type": "previous", "direction": props.direction, "disabled": offset.value <= 0, "onClick": handleButtonClick }, null), vue.createVNode(resizeObserver, { "onResize": () => getSize() }, { default: () => [vue.createVNode("div", { "class": tabCls.value, "ref": wrapperRef }, [vue.createVNode(resizeObserver, { "onResize": handleResize }, { default: () => [vue.createVNode("div", { "ref": listRef, "class": listCls.value, "style": listStyle.value }, [props.tabs.map((tab, index2) => vue.createVNode(tabsTab, { "key": tab.key, "ref": (component) => { if (component == null ? void 0 : component.$el) { tabsRef.value[tab.key] = component.$el; } }, "active": tab.key === activeKey.value, "tab": tab, "editable": props.editable, "onClick": handleClick, "onDelete": handleDelete }, { default: () => { var _a2, _b, _c; return [(_c = (_b = (_a2 = tab.slots).title) == null ? void 0 : _b.call(_a2)) != null ? _c : tab.title]; } })), props.type === "line" && activeTabRef.value && vue.createVNode(tabsNavInk, { "ref": inkRef, "activeTabRef": activeTabRef.value, "direction": props.direction, "disabled": false, "animation": props.animation }, null)])] }), !isScroll.value && renderAddBtn()])] }), isScroll.value && vue.createVNode(tabsButton, { "type": "next", "direction": props.direction, "disabled": offset.value >= maxOffset.value, "onClick": handleButtonClick }, null), vue.createVNode("div", { "class": `${prefixCls}-extra` }, [isScroll.value && renderAddBtn(), (_a = slots.extra) == null ? void 0 : _a.call(slots)])]); }; } }); module.exports = TabsNav;