feat: add leftExtra rightExtra
parent
eec9939a98
commit
ba8a128943
|
@ -0,0 +1,20 @@
|
|||
import type { Ref, ComponentPublicInstance } from 'vue';
|
||||
import { onBeforeUpdate, ref } from 'vue';
|
||||
import type { Key } from '../type';
|
||||
|
||||
type RefType = HTMLElement | ComponentPublicInstance;
|
||||
export type RefsValue = Map<Key, RefType>;
|
||||
type UseRef = [(key: Key) => (el: RefType) => void, Ref<RefsValue>];
|
||||
const useRefs = (): UseRef => {
|
||||
const refs = ref<RefsValue>(new Map());
|
||||
|
||||
const setRef = (key: Key) => (el: RefType) => {
|
||||
refs.value.set(key, el);
|
||||
};
|
||||
onBeforeUpdate(() => {
|
||||
refs.value = new Map();
|
||||
});
|
||||
return [setRef, refs];
|
||||
};
|
||||
|
||||
export default useRefs;
|
|
@ -0,0 +1,36 @@
|
|||
<docs>
|
||||
---
|
||||
order: 2
|
||||
title:
|
||||
zh-CN: 居中
|
||||
en-US: Centered
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
标签居中展示。
|
||||
|
||||
## en-US
|
||||
|
||||
Centered tabs.
|
||||
|
||||
</docs>
|
||||
|
||||
<template>
|
||||
<a-tabs v-model:activeKey="activeKey" centered>
|
||||
<a-tab-pane key="1" tab="Tab 1">Content of Tab Pane 1</a-tab-pane>
|
||||
<a-tab-pane key="2" tab="Tab 2" force-render>Content of Tab Pane 2</a-tab-pane>
|
||||
<a-tab-pane key="3" tab="Tab 3">Content of Tab Pane 3</a-tab-pane>
|
||||
</a-tabs>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue';
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
return {
|
||||
activeKey: ref('1'),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -33,7 +33,7 @@ import { defineComponent, ref } from 'vue';
|
|||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const panes = ref([
|
||||
const panes = ref<{ title: string; content: string; key: string; closable?: boolean }[]>([
|
||||
{ title: 'Tab 1', content: 'Content of Tab 1', key: '1' },
|
||||
{ title: 'Tab 2', content: 'Content of Tab 2', key: '2' },
|
||||
]);
|
||||
|
|
|
@ -16,17 +16,13 @@ Customized bar of tab.
|
|||
</docs>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div style="height: 2000px">
|
||||
<a-tabs v-model:activeKey="activeKey">
|
||||
<a-tab-pane key="1" tab="Tab 1" style="height: 200px">Content of Tab Pane 1</a-tab-pane>
|
||||
<a-tab-pane key="2" tab="Tab 2" force-render>Content of Tab Pane 2</a-tab-pane>
|
||||
<a-tab-pane key="3" tab="Tab 3">Content of Tab Pane 3</a-tab-pane>
|
||||
<template #renderTabBar="{ DefaultTabBar, ...props }">
|
||||
<component
|
||||
:is="DefaultTabBar"
|
||||
v-bind="props"
|
||||
:style="{ zIndex: 1, background: '#fff', textAlign: 'right' }"
|
||||
/>
|
||||
<component :is="DefaultTabBar" v-bind="props" :style="{ opacity: 0.5 }" />
|
||||
</template>
|
||||
</a-tabs>
|
||||
</div>
|
||||
|
|
|
@ -21,8 +21,11 @@ You can add extra actions to the right of Tabs.
|
|||
<a-tab-pane key="1" tab="Tab 1">Content of tab 1</a-tab-pane>
|
||||
<a-tab-pane key="2" tab="Tab 2">Content of tab 2</a-tab-pane>
|
||||
<a-tab-pane key="3" tab="Tab 3">Content of tab 3</a-tab-pane>
|
||||
<template #tabBarExtraContent>
|
||||
<a-button>Extra Action</a-button>
|
||||
<template #leftExtra>
|
||||
<a-button class="tabs-extra-demo-button">Left Extra Action</a-button>
|
||||
</template>
|
||||
<template #rightExtra>
|
||||
<a-button>Right Extra Action</a-button>
|
||||
</template>
|
||||
</a-tabs>
|
||||
</template>
|
||||
|
@ -37,3 +40,13 @@ export default defineComponent({
|
|||
},
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
.tabs-extra-demo-button {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.ant-row-rtl .tabs-extra-demo-button {
|
||||
margin-right: 0;
|
||||
margin-left: 16px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -19,18 +19,19 @@ Ant Design has 3 types of Tabs for different situations.
|
|||
|
||||
### Tabs
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| activeKey(v-model) | Current TabPane's key | string | - |
|
||||
| animated | Whether to change tabs with animation. Only works while `tabPosition="top"\|"bottom"` | boolean \| {inkBar:boolean, tabPane:boolean} | `true`, `false` when `type="card"` |
|
||||
| defaultActiveKey | Initial active TabPane's key, if `activeKey` is not set. | string | - |
|
||||
| hideAdd | Hide plus icon or not. Only works while `type="editable-card"` | boolean | `false` |
|
||||
| size | preset tab bar size | `large` \| `default` \| `small` | `default` |
|
||||
| tabBarExtraContent | Extra content in tab bar | slot | - |
|
||||
| tabBarStyle | Tab bar style object | object | - |
|
||||
| tabPosition | Position of tabs | `top` \| `right` \| `bottom` \| `left` | `top` |
|
||||
| type | Basic style of tabs | `line` \| `card` \| `editable-card` | `line` |
|
||||
| tabBarGutter | The gap between tabs | number | - |
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| activeKey(v-model) | Current TabPane's key | string | - | |
|
||||
| animated | Whether to change tabs with animation. Only works while `tabPosition="top"\|"bottom"` | boolean \| {inkBar:boolean, tabPane:boolean} | `true`, `false` when `type="card"` | |
|
||||
| defaultActiveKey | Initial active TabPane's key, if `activeKey` is not set. | string | - | |
|
||||
| hideAdd | Hide plus icon or not. Only works while `type="editable-card"` | boolean | `false` | } |
|
||||
| size | preset tab bar size | `large` \| `default` \| `small` | `default` | |
|
||||
| leftExtra | Extra content in tab bar left | v-slot:leftExtra | - | 3.0 |
|
||||
| rightExtra | Extra content in tab bar right | v-slot:rightExtra | - | 3.0 |
|
||||
| tabBarStyle | Tab bar style object | object | - | |
|
||||
| tabPosition | Position of tabs | `top` \| `right` \| `bottom` \| `left` | `top` | |
|
||||
| type | Basic style of tabs | `line` \| `card` \| `editable-card` | `line` | |
|
||||
| tabBarGutter | The gap between tabs | number | - | |
|
||||
|
||||
### Events
|
||||
|
||||
|
|
|
@ -22,18 +22,19 @@ Ant Design 依次提供了三级选项卡,分别用于不同的场景。
|
|||
|
||||
### Tabs
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| activeKey(v-model) | 当前激活 tab 面板的 key | string | 无 |
|
||||
| animated | 是否使用动画切换 Tabs,在 `tabPosition=top | bottom` 时有效 | boolean \| {inkBar:boolean, tabPane:boolean} | true, 当 type="card" 时为 false |
|
||||
| defaultActiveKey | 初始化选中面板的 key,如果没有设置 activeKey | string | 第一个面板 |
|
||||
| hideAdd | 是否隐藏加号图标,在 `type="editable-card"` 时有效 | boolean | false |
|
||||
| size | 大小,提供 `large` `default` 和 `small` 三种大小 | string | 'default' |
|
||||
| tabBarExtraContent | tab bar 上额外的元素 | slot | 无 |
|
||||
| tabBarStyle | tab bar 的样式对象 | object | - |
|
||||
| tabPosition | 页签位置,可选值有 `top` `right` `bottom` `left` | string | 'top' |
|
||||
| type | 页签的基本样式,可选 `line`、`card` `editable-card` 类型 | string | 'line' |
|
||||
| tabBarGutter | tabs 之间的间隙 | number | 无 |
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| activeKey(v-model) | 当前激活 tab 面板的 key | string | 无 | |
|
||||
| animated | 是否使用动画切换 Tabs,在 `tabPosition=top | bottom` 时有效 | boolean \| {inkBar:boolean, tabPane:boolean} | true, 当 type="card" 时为 false | |
|
||||
| defaultActiveKey | 初始化选中面板的 key,如果没有设置 activeKey | string | 第一个面板 | |
|
||||
| hideAdd | 是否隐藏加号图标,在 `type="editable-card"` 时有效 | boolean | false | |
|
||||
| size | 大小,提供 `large` `default` 和 `small` 三种大小 | string | 'default' | |
|
||||
| leftExtra | tab bar 上左侧额外的元素 | v-slot:leftExtra | - | 3.0 |
|
||||
| rightExtra | tab bar 上右侧额外的元素 | v-slot:rightExtra | - | 3.0 |
|
||||
| tabBarStyle | tab bar 的样式对象 | object | - | |
|
||||
| tabPosition | 页签位置,可选值有 `top` `right` `bottom` `left` | string | 'top' | |
|
||||
| type | 页签的基本样式,可选 `line`、`card` `editable-card` 类型 | string | 'line' | |
|
||||
| tabBarGutter | tabs 之间的间隙 | number | 无 | |
|
||||
|
||||
### 事件
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ export default defineComponent({
|
|||
}}
|
||||
onFocus={onFocus}
|
||||
>
|
||||
{tab}
|
||||
{typeof tab === 'function' ? tab() : tab}
|
||||
</div>
|
||||
|
||||
{/* Remove Button */}
|
||||
|
@ -127,7 +127,7 @@ export default defineComponent({
|
|||
onRemoveTab(e);
|
||||
}}
|
||||
>
|
||||
{closeIcon || editable.removeIcon || '×'}
|
||||
{closeIcon?.() || editable.removeIcon?.() || '×'}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -35,7 +35,6 @@ const tabNavListProps = () => {
|
|||
activeKey: { type: [String, Number] },
|
||||
rtl: { type: Boolean },
|
||||
animated: { type: Object as PropType<AnimatedConfig>, default: undefined as AnimatedConfig },
|
||||
extra: PropTypes.any,
|
||||
editable: { type: Object as PropType<EditableConfig> },
|
||||
moreIcon: PropTypes.any,
|
||||
moreTransitionName: { type: String },
|
||||
|
@ -55,14 +54,14 @@ export type TabNavListProps = Partial<ExtractPropTypes<ReturnType<typeof tabNavL
|
|||
interface ExtraContentProps {
|
||||
position: TabBarExtraPosition;
|
||||
prefixCls: string;
|
||||
extra?: TabBarExtraContent;
|
||||
extra?: (info?: { position: 'left' | 'right' }) => TabBarExtraContent;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TabNavList',
|
||||
inheritAttrs: false,
|
||||
props: tabNavListProps(),
|
||||
slots: ['moreIcon', 'extra'],
|
||||
slots: ['moreIcon', 'leftExtra', 'rightExtra', 'tabBarExtraContent'],
|
||||
emits: ['tabClick', 'tabScroll'],
|
||||
setup(props, { attrs, slots }) {
|
||||
const { tabs, prefixCls } = useInjectTabs();
|
||||
|
@ -387,9 +386,7 @@ export default defineComponent({
|
|||
|
||||
const ExtraContent = ({ position, prefixCls, extra }: ExtraContentProps) => {
|
||||
if (!extra) return null;
|
||||
|
||||
const content = slots.extra?.({ position });
|
||||
|
||||
const content = extra?.({ position });
|
||||
return content ? <div class={`${prefixCls}-extra-content`}>{content}</div> : null;
|
||||
};
|
||||
|
||||
|
@ -404,7 +401,6 @@ export default defineComponent({
|
|||
animated,
|
||||
activeKey,
|
||||
rtl,
|
||||
extra,
|
||||
editable,
|
||||
locale,
|
||||
tabPosition,
|
||||
|
@ -489,7 +485,7 @@ export default defineComponent({
|
|||
doLockAnimation();
|
||||
}}
|
||||
>
|
||||
<ExtraContent position="left" extra={extra} prefixCls={pre} />
|
||||
<ExtraContent position="left" prefixCls={pre} extra={slots.leftExtra} />
|
||||
|
||||
<ResizeObserver onResize={onListHolderResize}>
|
||||
<div
|
||||
|
@ -540,7 +536,8 @@ export default defineComponent({
|
|||
class={!hasDropdown && operationsHiddenClassName.value}
|
||||
/>
|
||||
|
||||
<ExtraContent position="right" extra={extra} prefixCls={pre} />
|
||||
<ExtraContent position="right" prefixCls={pre} extra={slots.rightExtra} />
|
||||
<ExtraContent position="right" prefixCls={pre} extra={slots.tabBarExtraContent} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@ export interface TabPaneProps {
|
|||
disabled?: boolean;
|
||||
forceRender?: boolean;
|
||||
closable?: boolean;
|
||||
closeIcon?: VueNode;
|
||||
closeIcon?: () => VueNode;
|
||||
|
||||
// Pass by TabPaneList
|
||||
prefixCls?: string;
|
||||
|
|
|
@ -23,6 +23,7 @@ import devWarning from '../../vc-util/devWarning';
|
|||
import type { SizeType } from '../../config-provider';
|
||||
import { useProvideTabs } from './TabContext';
|
||||
import type { Key } from '../../_util/type';
|
||||
import pick from 'lodash-es/pick';
|
||||
|
||||
export type TabsType = 'line' | 'card' | 'editable-card';
|
||||
export type TabsPosition = 'top' | 'right' | 'bottom' | 'left';
|
||||
|
@ -121,7 +122,15 @@ const InternalTabs = defineComponent({
|
|||
}),
|
||||
tabs: { type: Array as PropType<Tab[]> },
|
||||
},
|
||||
slots: ['tabBarExtraContent', 'moreIcon', 'addIcon', 'removeIcon'],
|
||||
slots: [
|
||||
'tabBarExtraContent',
|
||||
'leftExtra',
|
||||
'rightExtra',
|
||||
'moreIcon',
|
||||
'addIcon',
|
||||
'removeIcon',
|
||||
'renderTabBar',
|
||||
],
|
||||
emits: ['tabClick', 'tabScroll', 'change', 'update:activeKey'],
|
||||
setup(props, { attrs, slots }) {
|
||||
devWarning(
|
||||
|
@ -129,6 +138,11 @@ const InternalTabs = defineComponent({
|
|||
'Tabs',
|
||||
'`onPrevClick / @prevClick` and `onNextClick / @nextClick` has been removed. Please use `onTabScroll / @tabScroll` instead.',
|
||||
);
|
||||
devWarning(
|
||||
!(slots.tabBarExtraContent !== undefined),
|
||||
'Tabs',
|
||||
'`tabBarExtraContent` slot is deprecated. Please use `rightExtra` instead.',
|
||||
);
|
||||
const { prefixCls, direction, size, rootPrefixCls } = useConfigInject('tabs', props);
|
||||
const rtl = computed(() => direction.value === 'rtl');
|
||||
const mergedAnimated = computed<AnimatedConfig>(() => {
|
||||
|
@ -218,7 +232,7 @@ const InternalTabs = defineComponent({
|
|||
tabBarStyle,
|
||||
locale,
|
||||
destroyInactiveTabPane,
|
||||
renderTabBar,
|
||||
renderTabBar = slots.renderTabBar,
|
||||
onTabScroll,
|
||||
hideAdd,
|
||||
centered,
|
||||
|
@ -259,15 +273,12 @@ const InternalTabs = defineComponent({
|
|||
};
|
||||
|
||||
if (renderTabBar) {
|
||||
tabNavBar = renderTabBar(tabNavBarProps, TabNavList);
|
||||
tabNavBar = renderTabBar({ ...tabNavBarProps, DefaultTabBar: TabNavList });
|
||||
} else {
|
||||
tabNavBar = (
|
||||
<TabNavList
|
||||
{...tabNavBarProps}
|
||||
v-slots={{
|
||||
moreIcon: slots.moreIcon,
|
||||
extra: slots.tabBarExtraContent,
|
||||
}}
|
||||
v-slots={pick(slots, ['moreIcon', 'leftExtra', 'rightExtra', 'tabBarExtraContent'])}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -281,7 +292,7 @@ const InternalTabs = defineComponent({
|
|||
pre,
|
||||
`${pre}-${mergedTabPosition.value}`,
|
||||
{
|
||||
[`${pre}-${size}`]: size.value,
|
||||
[`${pre}-${size.value}`]: size.value,
|
||||
[`${pre}-card`]: ['card', 'editable-card'].includes(type as string),
|
||||
[`${pre}-editable-card`]: type === 'editable-card',
|
||||
[`${pre}-centered`]: centered,
|
||||
|
@ -314,7 +325,15 @@ export default defineComponent({
|
|||
tabPane: false,
|
||||
},
|
||||
}),
|
||||
slots: ['tabBarExtraContent', 'moreIcon', 'addIcon', 'removeIcon'],
|
||||
slots: [
|
||||
'tabBarExtraContent',
|
||||
'leftExtra',
|
||||
'rightExtra',
|
||||
'moreIcon',
|
||||
'addIcon',
|
||||
'removeIcon',
|
||||
'renderTabBar',
|
||||
],
|
||||
emits: ['tabClick', 'tabScroll', 'change', 'update:activeKey'],
|
||||
setup(props, { attrs, slots, emit }) {
|
||||
const handleChange = (key: string) => {
|
||||
|
|
|
@ -19,7 +19,7 @@ export interface Tab extends TabPaneProps {
|
|||
node: VueNode;
|
||||
}
|
||||
|
||||
export type RenderTabBar = (props: any, DefaultTabBar: any) => VueNode;
|
||||
export type RenderTabBar = (props: { DefaultTabBar: any; [key: string]: any }) => VueNode;
|
||||
|
||||
export interface TabsLocale {
|
||||
dropdownAriaLabel?: string;
|
||||
|
|
Loading…
Reference in New Issue