import { computed , defineComponent , PropType , ref } from 'vue' ; import { Direction , Size } from '../_utils/constant' ; import { Positions , Types } from './interface' ; import { getBooleanProp , getChildrenComponents , getValueFromSlotsOrProps , } from '../_utils/vue-utils' ; import { getPrefixCls } from '../_utils/global-config' ; import TabsNav from './tabs-nav' ; import usePickSlots from '../_hooks/use-pick-slots' ; export default defineComponent ( { name : 'Tabs' , props : { zh en vModel activeKey : { type : String , default : undefined } , zh en defaultActiveKey : { type : String , default : '' } , zh en values position : { type : String as PropType < Positions > , default : 'top' } , zh en values size : { type : String as PropType < Size > , default : 'medium' } , zh en values type : { type : String as PropType < Types > , default : 'line' } , zh en values direction : { type : String as PropType < Direction > , default : 'horizontal' } , zh en editable : { type : Boolean , default : false } , zh en showAddButton : { type : Boolean , default : false } , zh en destroyOnHide : { type : Boolean , default : false } , zh en lazyLoad : { type : Boolean , default : false } , zh en justify : { type : Boolean , default : false } , zh en animation : { type : Boolean , default : false } , zh en version headerPadding : { type : Boolean , default : true } } , emits : [ 'update:activeKey' , 'change' , 'tabClick' , 'add' , 'delete' , ] , zh en slot setup ( props , { emit , slots } ) { const prefixCls = getPrefixCls ( 'tabs' ) ; const mergedPosition = computed ( ( ) => props . direction === 'vertical' ? 'left' : props . position ) ; const mergedDirection = computed ( ( ) => [ 'left' , 'right' ] . includes ( mergedPosition . value ) ? 'vertical' : 'horizontal' ) ; const defaultSlot = usePickSlots ( slots , 'default' ) ; const children = computed ( ( ) => getChildrenComponents ( defaultSlot . value ?. ( ) ?? [ ] , 'TabPane' ) ) ; const tabs = computed ( ( ) => children . value . map ( ( vn ) => ( { title : getValueFromSlotsOrProps ( 'title' , vn . props , vn . children ) , key : String ( vn . key ) , disabled : getBooleanProp ( vn . props ?. disabled ) , closable : vn . props ?. closable !== false } ) ) ) ; const tabKeys = computed ( ( ) => tabs . value . map ( ( item ) => item . key ) ) ; const _activeTab = ref ( props . defaultActiveKey ) ; const computedActiveTab = computed ( ( ) => { const activeKey = props . activeKey ?? _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 < string > ( [ 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 ( < div key = { key } class = { [ `${ prefixCls }-content-item` , { [ `${ prefixCls }-content-item-active` ] : isActive } , ] } > { getIsRender ( isActive , key ) && vn } < /div>); } ) ; return ( < div class = { `${ prefixCls }-content` } > < div class = { [ `${ prefixCls }-content-list` , { [ `${ prefixCls }-content-animation` ] : props . animation } , ] } style = { { marginLeft : `-${ activeIndex . value * 100 }%` } } > { list } < /div> < /div>); } ; const cls = computed ( ( ) => [ prefixCls , `${ prefixCls }-${ mergedDirection . value }` , `${ prefixCls }-${ mergedPosition . value }` , `${ prefixCls }-type-${ props . type }` , `${ prefixCls }-size-${ props . size }` , { [ `${ prefixCls }-justify` ] : props . justify } , ] ) ; return ( ) => ( < div class = { cls . value } > { mergedPosition . value === 'bottom' && renderContent ( ) } < TabsNav v - slots = { { extra : slots . extra } } tabs = { tabs . value } tabKeys = { tabKeys . value } activeTab = { computedActiveTab . value } activeIndex = { activeIndex . value } direction = { mergedDirection . value } position = { 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 ) } /> { mergedPosition . value !== 'bottom' && renderContent ( ) } < /div>); } } ) ;