winbox-ui-next
Version:
We Design Vue 2.0: A Vue.js 3 UI Library
172 lines (171 loc) • 5.18 kB
JavaScript
import { defineComponent, computed, ref, createVNode } from "vue";
import { getChildrenComponents, getValueFromSlotsOrProps, getBooleanProp } from "../_utils/vue-utils.js";
import { getPrefixCls } from "../_utils/global-config.js";
import TabsNav from "./tabs-nav.js";
import usePickSlots from "../_hooks/use-pick-slots.js";
var _Tabs = defineComponent({
name: "Tabs",
props: {
activeKey: {
type: String,
default: void 0
},
defaultActiveKey: {
type: String,
default: ""
},
tabPosition: {
type: String,
default: "top"
},
size: {
type: String,
default: "default"
},
type: {
type: String,
default: "line"
},
direction: {
type: String,
default: "horizontal"
},
editable: {
type: Boolean,
default: false
},
showAddButton: {
type: Boolean,
default: false
},
destroyOnHide: {
type: Boolean,
default: false
},
lazyLoad: {
type: Boolean,
default: false
},
justify: {
type: Boolean,
default: false
},
animation: {
type: Boolean,
default: false
},
headerPadding: {
type: Boolean,
default: true
}
},
emits: [
"update:activeKey",
"change",
"tabClick",
"add",
"delete"
],
setup(props, {
emit,
slots
}) {
const prefixCls = getPrefixCls("tabs");
const mergedPosition = computed(() => props.direction === "vertical" ? "left" : props.tabPosition);
const mergedDirection = computed(() => ["left", "right"].includes(mergedPosition.value) ? "vertical" : "horizontal");
const defaultSlot = usePickSlots(slots, "default");
const children = computed(() => {
var _a, _b;
return getChildrenComponents((_b = (_a = defaultSlot.value) == null ? void 0 : _a.call(defaultSlot)) != null ? _b : [], "TabPane");
});
const tabs = computed(() => children.value.map((vn) => {
var _a, _b;
return {
title: getValueFromSlotsOrProps("title", vn.props, vn.children),
key: String(vn.key),
disabled: getBooleanProp((_a = vn.props) == null ? void 0 : _a.disabled),
closable: ((_b = vn.props) == null ? void 0 : _b.closable) !== false
};
}));
const tabKeys = computed(() => tabs.value.map((item) => item.key));
const _activeTab = ref(props.defaultActiveKey);
const computedActiveTab = computed(() => {
var _a;
const activeKey = (_a = props.activeKey) != null ? _a : _activeTab.value;
if (tabKeys.value.includes(activeKey)) {
return activeKey;
}
return tabKeys.value[0];
});
const activeIndex = computed(() => tabKeys.value.indexOf(computedActiveTab.value));
const loadedTabs = new Set([computedActiveTab.value]);
const handleClick = (key, e) => {
if (key !== computedActiveTab.value) {
_activeTab.value = key;
loadedTabs.add(key);
emit("update:activeKey", key);
emit("change", key);
}
emit("tabClick", key, e);
};
const getIsRender = (isActive, key) => {
if (isActive) {
return true;
}
if (props.lazyLoad) {
return loadedTabs.has(key);
}
return !props.destroyOnHide;
};
const handleAdd = () => {
emit("add");
};
const renderContent = () => {
const list = children.value.map((vn, index) => {
const key = String(vn.key);
const isActive = index === activeIndex.value;
return createVNode("div", {
"key": key,
"class": [`${prefixCls}-content-item`, {
[`${prefixCls}-content-item-active`]: isActive
}]
}, [getIsRender(isActive, key) && vn]);
});
return createVNode("div", {
"class": `${prefixCls}-content`
}, [createVNode("div", {
"class": [`${prefixCls}-content-list`, {
[`${prefixCls}-content-animation`]: props.animation
}],
"style": {
marginLeft: `-${activeIndex.value * 100}%`
}
}, [list])]);
};
const cls = computed(() => [prefixCls, `${prefixCls}-${mergedDirection.value}`, `${prefixCls}-${mergedPosition.value}`, `${prefixCls}-type-${props.type}`, `${prefixCls}-size-${props.size}`, {
[`${prefixCls}-justify`]: props.justify
}]);
return () => createVNode("div", {
"class": cls.value
}, [mergedPosition.value === "bottom" && renderContent(), createVNode(TabsNav, {
"tabs": tabs.value,
"tabKeys": tabKeys.value,
"activeTab": computedActiveTab.value,
"activeIndex": activeIndex.value,
"direction": mergedDirection.value,
"tabPosition": mergedPosition.value,
"editable": props.editable,
"animation": props.animation,
"showAddButton": props.showAddButton,
"headerPadding": props.headerPadding,
"size": props.size,
"type": props.type,
"onClick": handleClick,
"onAdd": handleAdd,
"onDelete": (key) => emit("delete", key)
}, {
extra: slots.extra
}), mergedPosition.value !== "bottom" && renderContent()]);
}
});
export { _Tabs as default };