UNPKG

element-plus

Version:

A Component Library for Vue 3

1 lines 13.9 kB
{"version":3,"file":"tabs.mjs","names":["computed","createVNode","defineComponent","getCurrentInstance","nextTick","provide","ref","renderSlot","watch","_createVNode","omit","buildProps","definePropType","getEventCode","isNumber","isString","isUndefined","EVENT_CODE","UPDATE_MODEL_EVENT","ElIcon","Plus","useNamespace","useOrderedChildren","tabsRootContextKey","TabNav","tabsProps","type","String","values","default","closable","Boolean","addable","modelValue","Number","defaultValue","editable","tabPosition","beforeLeave","Function","stretch","tabindex","isPaneName","value","tabsEmits","name","tabClick","pane","ev","Event","tabChange","edit","paneName","action","includes","tabRemove","tabAdd","Tabs","props","emits","setup","emit","slots","expose","ns","isVertical","children","panes","addChild","registerPane","removeChild","unregisterPane","ChildrenSorter","PanesSorter","nav$","currentName","setCurrentName","trigger","canLeave","result","Promise","isFocusInsidePane","find","item","removeFocus","focusActiveTab","handleTabClick","tab","tabName","event","disabled","handleTabRemove","stopPropagation","handleTabAdd","undefined","handleKeydown","code","enter","numpadEnter","swapChildren","vnode","actualFirstChild","el","firstChild","before","scrollToActiveTab","tabNavRef","addSlot","newButton","e","is","tabNav","header","$stable","panels","b","m"],"sources":["../../../../../../packages/components/tabs/src/tabs.tsx"],"sourcesContent":["import {\n computed,\n createVNode,\n defineComponent,\n getCurrentInstance,\n nextTick,\n provide,\n ref,\n renderSlot,\n watch,\n} from 'vue'\nimport { omit } from 'lodash-unified'\nimport {\n buildProps,\n definePropType,\n getEventCode,\n isNumber,\n isString,\n isUndefined,\n} from '@element-plus/utils'\nimport { EVENT_CODE, UPDATE_MODEL_EVENT } from '@element-plus/constants'\nimport ElIcon from '@element-plus/components/icon'\nimport { Plus } from '@element-plus/icons-vue'\nimport { useNamespace, useOrderedChildren } from '@element-plus/hooks'\nimport { tabsRootContextKey } from './constants'\nimport TabNav from './tab-nav'\n\nimport type { ExtractPropTypes, ExtractPublicPropTypes, VNode } from 'vue'\nimport type { Awaitable } from '@element-plus/utils'\nimport type { TabNavInstance } from './tab-nav'\nimport type { TabPaneName, TabsPaneContext } from './constants'\n\nexport const tabsProps = buildProps({\n /**\n * @description type of Tab\n */\n type: {\n type: String,\n values: ['card', 'border-card', ''],\n default: '',\n },\n /**\n * @description whether Tab is closable\n */\n closable: Boolean,\n /**\n * @description whether Tab is addable\n */\n addable: Boolean,\n /**\n * @description binding value, name of the selected tab\n */\n modelValue: {\n type: [String, Number],\n },\n /**\n * @description initial value when `model-value` is not set\n */\n defaultValue: {\n type: [String, Number],\n },\n /**\n * @description whether Tab is addable and closable\n */\n editable: Boolean,\n /**\n * @description position of tabs\n */\n tabPosition: {\n type: String,\n values: ['top', 'right', 'bottom', 'left'],\n default: 'top',\n },\n /**\n * @description hook function before switching tab. If `false` is returned or a `Promise` is returned and then is rejected, switching will be prevented\n */\n beforeLeave: {\n type: definePropType<\n (newName: TabPaneName, oldName: TabPaneName) => Awaitable<void | boolean>\n >(Function),\n default: () => true,\n },\n /**\n * @description whether width of tab automatically fits its container\n */\n stretch: Boolean,\n /**\n * @description tabs tabindex\n */\n tabindex: {\n type: [String, Number],\n default: 0,\n },\n} as const)\nexport type TabsProps = ExtractPropTypes<typeof tabsProps>\nexport type TabsPropsPublic = ExtractPublicPropTypes<typeof tabsProps>\n\nconst isPaneName = (value: unknown): value is string | number =>\n isString(value) || isNumber(value)\n\nexport const tabsEmits = {\n [UPDATE_MODEL_EVENT]: (name: TabPaneName) => isPaneName(name),\n tabClick: (pane: TabsPaneContext, ev: Event) => ev instanceof Event,\n tabChange: (name: TabPaneName) => isPaneName(name),\n edit: (paneName: TabPaneName | undefined, action: 'remove' | 'add') =>\n ['remove', 'add'].includes(action),\n tabRemove: (name: TabPaneName) => isPaneName(name),\n tabAdd: () => true,\n}\nexport type TabsEmits = typeof tabsEmits\n\nexport type TabsPanes = Record<number, TabsPaneContext>\n\nconst Tabs = defineComponent({\n name: 'ElTabs',\n\n props: tabsProps,\n emits: tabsEmits,\n\n setup(props, { emit, slots, expose }) {\n const ns = useNamespace('tabs')\n\n const isVertical = computed(() =>\n ['left', 'right'].includes(props.tabPosition)\n )\n\n const {\n children: panes,\n addChild: registerPane,\n removeChild: unregisterPane,\n ChildrenSorter: PanesSorter,\n } = useOrderedChildren<TabsPaneContext>(getCurrentInstance()!, 'ElTabPane')\n\n const nav$ = ref<TabNavInstance>()\n const currentName = ref<TabPaneName>(\n (isUndefined(props.modelValue) ? props.defaultValue : props.modelValue) ??\n '0'\n )\n\n const setCurrentName = async (value?: TabPaneName, trigger = false) => {\n // should do nothing.\n if (currentName.value === value || isUndefined(value)) return\n\n try {\n let canLeave\n if (props.beforeLeave) {\n const result = props.beforeLeave(value, currentName.value)\n canLeave = result instanceof Promise ? await result : result\n } else {\n canLeave = true\n }\n\n if (canLeave !== false) {\n const isFocusInsidePane = panes.value\n .find((item) => item.paneName === currentName.value)\n ?.isFocusInsidePane()\n\n currentName.value = value\n if (trigger) {\n emit(UPDATE_MODEL_EVENT, value)\n emit('tabChange', value)\n }\n\n nav$.value?.removeFocus?.()\n if (isFocusInsidePane) {\n nav$.value?.focusActiveTab()\n }\n }\n } catch {}\n }\n\n const handleTabClick = (\n tab: TabsPaneContext,\n tabName: TabPaneName,\n event: Event\n ) => {\n if (tab.props.disabled) return\n emit('tabClick', tab, event)\n setCurrentName(tabName, true)\n }\n\n const handleTabRemove = (pane: TabsPaneContext, ev: Event) => {\n if (pane.props.disabled || isUndefined(pane.props.name)) return\n ev.stopPropagation()\n emit('edit', pane.props.name, 'remove')\n emit('tabRemove', pane.props.name)\n }\n\n const handleTabAdd = () => {\n emit('edit', undefined, 'add')\n emit('tabAdd')\n }\n\n const handleKeydown = (event: KeyboardEvent) => {\n const code = getEventCode(event)\n if ([EVENT_CODE.enter, EVENT_CODE.numpadEnter].includes(code))\n handleTabAdd()\n }\n\n const swapChildren = (\n vnode: VNode & {\n el: HTMLDivElement\n children: VNode<HTMLDivElement>[]\n }\n ) => {\n const actualFirstChild = vnode.el.firstChild!\n const firstChild = ['bottom', 'right'].includes(props.tabPosition)\n ? vnode.children[0].el!\n : vnode.children[1].el!\n\n if (actualFirstChild !== firstChild) {\n actualFirstChild.before(firstChild)\n }\n }\n\n watch(\n () => props.modelValue,\n (modelValue) => setCurrentName(modelValue)\n )\n\n watch(currentName, async () => {\n await nextTick()\n nav$.value?.scrollToActiveTab()\n })\n\n provide(tabsRootContextKey, {\n props,\n currentName,\n registerPane,\n unregisterPane,\n nav$,\n })\n\n expose({\n currentName,\n get tabNavRef() {\n return omit(nav$.value, ['scheduleRender'])\n },\n })\n\n return () => {\n const addSlot = slots['add-icon']\n const newButton =\n props.editable || props.addable ? (\n <div\n class={[\n ns.e('new-tab'),\n isVertical.value && ns.e('new-tab-vertical'),\n ]}\n tabindex={props.tabindex}\n onClick={handleTabAdd}\n onKeydown={handleKeydown}\n >\n {addSlot ? (\n renderSlot(slots, 'add-icon')\n ) : (\n <ElIcon class={ns.is('icon-plus')}>\n <Plus />\n </ElIcon>\n )}\n </div>\n ) : null\n\n const tabNav = () => (\n <TabNav\n ref={nav$}\n currentName={currentName.value}\n editable={props.editable}\n type={props.type}\n panes={panes.value}\n stretch={props.stretch}\n onTabClick={handleTabClick}\n onTabRemove={handleTabRemove}\n />\n )\n\n const header = (\n <div\n class={[\n ns.e('header'),\n isVertical.value && ns.e('header-vertical'),\n ns.is(props.tabPosition),\n ]}\n >\n {createVNode(PanesSorter, null, {\n default: tabNav,\n $stable: true,\n })}\n {newButton}\n </div>\n )\n\n const panels = (\n <div class={ns.e('content')}>{renderSlot(slots, 'default')}</div>\n )\n\n return (\n <div\n class={[\n ns.b(),\n ns.m(props.tabPosition),\n {\n [ns.m('card')]: props.type === 'card',\n [ns.m('border-card')]: props.type === 'border-card',\n },\n ]}\n // @ts-ignore\n onVnodeMounted={swapChildren}\n onVnodeUpdated={swapChildren}\n >\n {panels}\n {header}\n </div>\n )\n }\n },\n})\n\nexport type TabsInstance = InstanceType<typeof Tabs> & {\n currentName: TabPaneName\n tabNavRef: TabNavInstance | undefined\n}\n\nexport default Tabs\n"],"mappings":"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"}